Add hpsa driver for HP Smart Array controllers.
Subsystems (2)
PATCH 1/1 Add hpsa driver for HP Smart Array controllers.
Add hpsa driver for HP Smart Array controllers.
This driver supports a subset of HP Smart Array Controllers. It is a SCSI alternative to the cciss driver.
---
drivers/scsi/Kconfig | 10 drivers/scsi/Makefile | 1 drivers/scsi/hpsa.c | 3444 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/hpsa.h | 268 ++++ drivers/scsi/hpsa_cmd.h | 303 ++++ 5 files changed, 4026 insertions(+), 0 deletions(-) create mode 100644 drivers/scsi/hpsa.c create mode 100644 drivers/scsi/hpsa.h create mode 100644 drivers/scsi/hpsa_cmd.h
drivers/scsi/Kconfig +10 -0
@@ -387,6 +387,16 @@ config BLK_DEV_3W_XXXX_RAID Please read the comments at the top of <file:drivers/scsi/3w-xxxx.c>. +config SCSI_HPSA + tristate "HP Smart Array SCSI driver" + depends on PCI && SCSI + help + This driver supports HP Smart Array Controllers (circa 2009). + It is a SCSI alternative to the cciss driver, which is a block + driver. Anyone wishing to use HP Smart Array controllers who + would prefer the devices be presented to linux as SCSI devices, + rather than as generic block devices should say Y here. + config SCSI_3W_9XXX tristate "3ware 9xxx SATA-RAID support" depends on PCI && SCSI
drivers/scsi/Makefile +1 -0
@@ -89,6 +89,7 @@ obj-$(CONFIG_SCSI_LPFC) += lpfc/ obj-$(CONFIG_SCSI_PAS16) += pas16.o obj-$(CONFIG_SCSI_T128) += t128.o obj-$(CONFIG_SCSI_DMX3191D) += dmx3191d.o +obj-$(CONFIG_SCSI_HPSA) += hpsa.o obj-$(CONFIG_SCSI_DTC3280) += dtc.o obj-$(CONFIG_SCSI_SYM53C8XX_2) += sym53c8xx_2/ obj-$(CONFIG_SCSI_ZALON) += zalon7xx.o
drivers/scsi/hpsa.c new file +3444 -0
2,977 lines not on this page · raw message
drivers/scsi/hpsa.h new file +268 -0
268 lines not on this page · raw message
drivers/scsi/hpsa_cmd.h new file +303 -0
303 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Part of the diff is not shown here. View the raw message.
Quoted 4 lines · On Thu, 01 Oct 2009 16:25:30 -0500 "Stephen M. Cameron"…
Add hpsa driver for HP Smart Array controllers.
This driver supports a subset of HP Smart Array Controllers. It is a SCSI alternative to the cciss driver.
Does it support all the devices which cciss supports?
IOW, do we have a plan here to remove the cciss driver or must we maintain both drivers indefinitely?
Quoted 5 lines · Andrew Morton
Quoted 2 lines · On Thu, 01 Oct 2009 16:25:30 -0500 "Stephen M. Cameron"…
Add hpsa driver for HP Smart Array controllers.
Quoted 7 lines
Quoted 2 lines
This driver supports a subset of HP Smart Array Controllers. It is a SCSI alternative to the cciss driver.
Does it support all the devices which cciss supports?
IOW, do we have a plan here to remove the cciss driver or must we maintain both drivers indefinitely?
Andrew,
The hpsa driver supports only the latest generation of Smart Array controllers plus the P400 and P800. The goal was to have minimal overlap but if we included only the very latest I suspect little testing would be done because of the availability of new hardware.
No new controllers will be added to cciss once hpsa is accepted. We're looking at supporting both drivers for 3 or 4 years until cciss can be phased out completely.
-- mikem
Quoted 19 lines · Mike Miller
Quoted 11 lines · Andrew Morton
Quoted 4 lines · On Thu, 01 Oct 2009 16:25:30 -0500 "Stephen M. Cameron"…
Add hpsa driver for HP Smart Array controllers.
This driver supports a subset of HP Smart Array Controllers. It is a SCSI alternative to the cciss driver.
Does it support all the devices which cciss supports?
IOW, do we have a plan here to remove the cciss driver or must we maintain both drivers indefinitely?
Andrew,
The hpsa driver supports only the latest generation of Smart Array controllers plus the P400 and P800. The goal was to have minimal overlap but if we included only the very latest I suspect little testing would be done because of the availability of new hardware.
Quoted 4 lines
No new controllers will be added to cciss once hpsa is accepted. We're looking at supporting both drivers for 3 or 4 years until cciss can be phased out completely.
Yeah!
Thanks, Mike and Stephen, for the effort you put into this. Very much appreciated.
Cheers,
Hannes
Signature · 8 lines
Dr. Hannes Reinecke zSeries & Storage [email protected] +49 911 74053 688 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: Markus Rex, HRB 16746 (AG Nürnberg) -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 5 lines · Andrew Morton
Quoted 2 lines · On Thu, 01 Oct 2009 16:25:30 -0500 "Stephen M. Cameron"…
Add hpsa driver for HP Smart Array controllers.
Quoted 7 lines
Quoted 2 lines
This driver supports a subset of HP Smart Array Controllers. It is a SCSI alternative to the cciss driver.
Does it support all the devices which cciss supports?
IOW, do we have a plan here to remove the cciss driver or must we maintain both drivers indefinitely?
Andrew, et al.,
Quoted 1 line
From the lack of response I'm guessing my reply about phasing cciss out
completely did not go over well. Or is that what the question meant?
We purposely limited controller support in hpsa to try and prevent problems in the field. What's needed to get hpsa accepted? Add support for all hardware?
While we do not want to maintain 2 drivers indefinitely we (HP) must continue to support cciss for some years to come.
Any guidance is appreciated.
-- mikem
Quoted 18 lines · On Fri, 2 Oct 2009 14:16:26 -0500 Mike Miller <[email protected]> wrote:
Quoted 5 lines · Andrew Morton
Quoted 2 lines · On Thu, 01 Oct 2009 16:25:30 -0500 "Stephen M. Cameron"…
Add hpsa driver for HP Smart Array controllers.
Quoted 7 lines
Quoted 2 lines
This driver supports a subset of HP Smart Array Controllers. It is a SCSI alternative to the cciss driver.
Does it support all the devices which cciss supports?
IOW, do we have a plan here to remove the cciss driver or must we maintain both drivers indefinitely?
Andrew, et al.,
Quoted 1 line
From the lack of response I'm guessing my reply about phasing cciss out
completely did not go over well. Or is that what the question meant?
Quoted 9 lines
We purposely limited controller support in hpsa to try and prevent problems in the field. What's needed to get hpsa accepted? Add support for all hardware?
While we do not want to maintain 2 drivers indefinitely we (HP) must continue to support cciss for some years to come.
Any guidance is appreciated.
Well, obviously it's neater if we can retire the old driver. Sometimes life isn't neat. We had a similar situation with e1000-vs-e1000e. And with e100-vs-eepro100, although eepro100 went away after many years.
drivers/scsi/hpsa.c line 217
Quoted 4 lines · Stephen M. Cameron
drivers/scsi/hpsa.c new file +4
-0+static const char *raid_label[] = {"0" ,"4" ,"1(1+0)" ,"5" ,"5+1" ,"ADG" , +"UNKNOWN" +}; +#define RAID_UNKNOWN (sizeof(raid_label) / sizeof(raid_label[0]) - 1)
(ARRAY_SIZE(raid_label) - 1)
Quoted 21 lines
drivers/scsi/hpsa.c new file +21
-0+ +static ssize_t raid_level_show (struct device *dev, +struct device_attribute *attr,char *buf) +{ +ssize_t l =0 ; +int rlevel; +struct ctlr_info *h; +struct scsi_device *sdev; +struct hpsa_scsi_dev_t *hdev; +unsigned long flags; + + sdev =to_scsi_device (dev); + h = (struct ctlr_info *) sdev->host->hostdata[0 ]; +spin_lock_irqsave (&h->lock, flags); + hdev = sdev->hostdata; +if (!hdev) { +spin_unlock_irqrestore (&h->lock, flags); +return -ENODEV ; + } + +/* Is this even a logical drive? */
drivers/scsi/hpsa.c line 248
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+if (!is_logical_dev_addr_mode (hdev->scsi3addr)) { +spin_unlock_irqrestore (&h->lock, flags); + l =snprintf (buf,PAGE_SIZE ,"N/A\n" ); +return l; + } + + rlevel = hdev->raid_level; +spin_unlock_irqrestore (&h->lock, flags); +if (rlevel <0 || rlevel >RAID_UNKNOWN ) + rlevel =RAID_UNKNOWN ;
How about making raid_level an unsigned int, the check for less than zero could go away then.
drivers/scsi/hpsa.c line 421
Quoted 10 lines
drivers/scsi/hpsa.c new file +9
-0+/* Remove an entry from h->dev[] array. */ +static void hpsa_scsi_remove_entry (struct ctlr_info *h,int hostno,int entry, + struct hpsa_scsi_dev_t *removed[], int *nremoved) +{ +/* assumes h->devlock is held */ +int i; +struct hpsa_scsi_dev_t *sd; + +if (entry <0 || entry >=HPSA_MAX_SCSI_DEVS_PER_HBA ) +BUG ();
BUG_ON(entry < 0 || entry >= HPSA_MAX_SCSI_DEVS_PER_HBA);
Quoted 8 lines
drivers/scsi/hpsa.c new file +8
-0+static int adjust_hpsa_scsi_table (struct ctlr_info *h,int hostno, +struct hpsa_scsi_dev_t *sd[],int nsds) +{ +/* sd contains scsi3 addresses and devtypes, and inquiry +* data. This function takes what's in sd to be the current +* reality and updates h->dev[] to reflect that reality. +*/ +int i, entry, device_change, changes =0 ;
drivers/scsi/hpsa.c line 543
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+struct hpsa_scsi_dev_t *csd; +unsigned long flags; +struct hpsa_scsi_dev_t **added, **removed; +int nadded, nremoved; +struct Scsi_Host *sh =NULL ; + + added =kzalloc (sizeof (*added) *HPSA_MAX_SCSI_DEVS_PER_HBA , +GFP_KERNEL ); + removed =kzalloc (sizeof (*removed) *HPSA_MAX_SCSI_DEVS_PER_HBA , +GFP_KERNEL );
kcalloc()
drivers/scsi/hpsa.c line 549
Quoted 5 lines
drivers/scsi/hpsa.c new file +5
-0+if (!added || !removed) { +dev_warn (&h->pdev->dev,"out of memory in " +"adjust_hpsa_scsi_table\n" ); + goto free_and_out; + }
You should better return ENOMEM instead of 0 now. On the other hand the only caller of this function does not check the return value anyway so this function could also be void.
drivers/scsi/hpsa.c line 701
Quoted 12 lines
drivers/scsi/hpsa.c new file +12
-0+static void hpsa_slave_destroy (struct scsi_device *sdev) +{ +return ;/* nothing to do. */ +} + +static void hpsa_scsi_setup (struct ctlr_info *h) +{ + h->ndevices =0 ; + h->scsi_host =NULL ; +spin_lock_init (&h->devlock); +return ; +}
Those return statements are completely superfluous.
Quoted 26 lines
drivers/scsi/hpsa.c new file +26
-0+static int hpsa_scsi_detect (struct ctlr_info *h) +{ +struct Scsi_Host *sh; +int error; + + sh =scsi_host_alloc (&hpsa_driver_template,sizeof (*h)); +if (sh ==NULL ) + goto fail; + + sh->io_port =0 ; + sh->n_io_port =0 ; + sh->this_id =-1 ; + sh->max_channel =3 ; + sh->max_cmd_len =MAX_COMMAND_SIZE ; + sh->max_lun =HPSA_MAX_LUN ; + sh->max_id =HPSA_MAX_LUN ; + h->scsi_host = sh; + sh->hostdata[0 ] = (unsigned long ) h; + sh->irq = h->intr[SIMPLE_MODE_INT ]; + sh->unique_id = sh->irq; + error =scsi_add_host (sh, &h->pdev->dev); +if (error) + goto fail_host_put; +scsi_scan_host (sh); +return 0 ; +
drivers/scsi/hpsa.c line 923
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+ fail_host_put: +dev_err (&h->pdev->dev,"hpsa_scsi_detect: scsi_add_host" +" failed for controller %d\n" , h->ctlr); +scsi_host_put (sh); +return -1 ; + fail: +dev_err (&h->pdev->dev,"hpsa_scsi_detect: scsi_host_alloc" +" failed for controller %d\n" , h->ctlr); +return -1 ; +}
You should forward the error code of scsi_add_host() here and return ENOMEM if scsi_host_alloc() failed, that would make debugging probably easier.
Quoted 22 lines
drivers/scsi/hpsa.c new file +22
-0+static void hpsa_unmap_one (struct pci_dev *pdev, +struct CommandList *cp, +size_t buflen, +int data_direction) +{ +union u64bit addr64; + + addr64.val32.lower = cp->SG[0 ].Addr.lower; + addr64.val32.upper = cp->SG[0 ].Addr.upper; +pci_unmap_single (pdev, (dma_addr_t ) addr64.val, + buflen, data_direction); +} + +static void hpsa_map_one (struct pci_dev *pdev, +struct CommandList *cp, +unsigned char *buf, +size_t buflen, +int data_direction) +{ +__u64 addr64; + +if (buflen ==0 || data_direction ==PCI_DMA_NONE ) {
drivers/scsi/hpsa.c line 956
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+ cp->Header.SGList =0 ; + cp->Header.SGTotal =0 ; +return ; + } + + addr64 = (__u64 )pci_map_single (pdev, buf, buflen, data_direction); + cp->SG[0 ].Addr.lower = + (__u32) (addr64 & (__u64 )0x00000000FFFFFFFF ); + cp->SG[0 ].Addr.upper = + (__u32) ((addr64 >>32 ) & (__u64 )0x00000000FFFFFFFF );
You want to use upper_32_bits() and lower_32_bits() from linux/kernel.h, I'm sure. ;)
Quoted 4 lines
drivers/scsi/hpsa.c new file +3
-0+static int hpsa_scsi_do_inquiry (struct ctlr_info *h,unsigned char *scsi3addr, + unsigned char page, unsigned char *buf, +unsigned char bufsize) +{
drivers/scsi/hpsa.c line 1046
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+int rc; +struct CommandList *c; +struct ErrorInfo *ei; + + c =cmd_special_alloc (h); + +if (c ==NULL ) {/* trouble... */ +dev_warn (&h->pdev->dev,"cmd_special_alloc returned NULL!\n" ); +return -1 ; + }
-ENOMEM
drivers/scsi/hpsa.c line 1058
Quoted 11 lines
drivers/scsi/hpsa.c new file +11
-0+ rc =fill_cmd (c,HPSA_INQUIRY , h, buf, bufsize, page, scsi3addr, +TYPE_CMD ); +if (rc ==0 ) { +hpsa_scsi_do_simple_cmd_core (h, c); +hpsa_unmap_one (h->pdev, c, bufsize,PCI_DMA_FROMDEVICE ); + + ei = c->err_info; +if (ei->CommandStatus !=0 && + ei->CommandStatus !=CMD_DATA_UNDERRUN ) { +hpsa_scsi_interpret_error (c); + rc =-1 ;
-EINVAL or whatever
Quoted 8 lines
drivers/scsi/hpsa.c new file +8
-0+ } + } +cmd_special_free (h, c); +return rc; +} + +static int hpsa_send_reset (struct ctlr_info *h,unsigned char *scsi3addr) +{
drivers/scsi/hpsa.c line 1076
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+int rc; +struct CommandList *c; +struct ErrorInfo *ei; + + c =cmd_special_alloc (h); + +if (c ==NULL ) {/* trouble... */ +dev_warn (&h->pdev->dev,"cmd_special_alloc returned NULL!\n" ); +return -1 ; + }
-ENOMEM
drivers/scsi/hpsa.c line 1090
Quoted 13 lines
drivers/scsi/hpsa.c new file +13
-0+ rc =fill_cmd (c,HPSA_DEVICE_RESET_MSG , h,NULL ,0 ,0 , scsi3addr, +TYPE_MSG ); +if (rc !=0 ) + goto out; + +hpsa_scsi_do_simple_cmd_core (h, c); +/* no unmap needed here because no data xfer. */ + + ei = c->err_info; +if (ei->CommandStatus !=0 ) { +hpsa_scsi_interpret_error (c); + rc =-1 ; + }
-EINVAL
More of those follows.
Quoted 6 lines
drivers/scsi/hpsa.c new file +6
-0+static int hpsa_scsi_do_report_luns (struct ctlr_info *h,int logical, +struct ReportLUNdata *buf,int bufsize, +int extended_response) +{ +int rc; +struct CommandList *c;
drivers/scsi/hpsa.c line 1149
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+unsigned char scsi3addr[8 ]; +struct ErrorInfo *ei; + + c =cmd_special_alloc (h); +if (c ==NULL ) {/* trouble... */ +dev_err (&h->pdev->dev,"cmd_special_alloc returned NULL!\n" ); +return -1 ; + } + +memset (&scsi3addr[0 ],0 ,8 );/* address the controller */
memset(scsi3addr, 0, sizeof(scsi3addr));
drivers/scsi/hpsa.c line 1182
Quoted 12 lines
drivers/scsi/hpsa.c new file +12
-0+static inline int hpsa_scsi_do_report_phys_luns (struct ctlr_info *h, +struct ReportLUNdata *buf, +int bufsize,int extended_response) +{ +return hpsa_scsi_do_report_luns (h,0 , buf, bufsize, extended_response); +} + +static inline int hpsa_scsi_do_report_log_luns (struct ctlr_info *h, +struct ReportLUNdata *buf,int bufsize) +{ +return hpsa_scsi_do_report_luns (h,1 , buf, bufsize,0 ); +}
Given that these two functions are both absolutely trivial and only called from one place each they should be open coded there.
drivers/scsi/hpsa.c line 1196
Quoted 5 lines
drivers/scsi/hpsa.c new file +5
-0+static int hpsa_update_device_info (struct ctlr_info *h, +unsigned char scsi3addr[],struct hpsa_scsi_dev_t *this_device) +{ +#define OBDR_TAPE_INQ_SIZE 49 +unsigned char *inq_buff =NULL ;
No need to initialize as you overwrite that anyway.
drivers/scsi/hpsa.c line 1202
Quoted 5 lines
drivers/scsi/hpsa.c new file +5
-0+ inq_buff =kmalloc (OBDR_TAPE_INQ_SIZE ,GFP_KERNEL ); +if (!inq_buff) + goto bail_out; + +memset (inq_buff,0 ,OBDR_TAPE_INQ_SIZE );
kzalloc()
Quoted 4 lines
drivers/scsi/hpsa.c new file +4
-0+/* Do an inquiry to the device to see what it is. */ +if (hpsa_scsi_do_inquiry (h, scsi3addr,0 , inq_buff, + (unsigned char )OBDR_TAPE_INQ_SIZE ) !=0 ) { +/* Inquiry failed (msg printed already) */
drivers/scsi/hpsa.c line 1216
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+dev_err (&h->pdev->dev, +"hpsa_update_device_info: inquiry failed\n" ); + goto bail_out; + } + +/* As a side effect, record the firmware version number +* if we happen to be talking to the RAID controller. +*/ +if (is_hba_lunid (scsi3addr)) +memcpy (h->firm_ver, &inq_buff[32 ],4 );
I've not looked into the details but you might need le32_to_cpu() or something here.
drivers/scsi/hpsa.c line 1262
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+static int is_msa2xxx (struct ctlr_info *h,struct hpsa_scsi_dev_t *device) +{ +int i; + +for (i =0 ; msa2xxx_model[i]; i++) +if (strncmp (device->model, msa2xxx_model[i], +strlen (msa2xxx_model[i])) ==0 ) +return 1 ; +return 0 ; +}
This could probably be bool instead of int.
drivers/scsi/hpsa.c line 1275
Quoted 5 lines
drivers/scsi/hpsa.c new file +5
-0+static void figure_bus_target_lun (struct ctlr_info *h, +__u8 *lunaddrbytes,int *bus,int *target,int *lun, +struct hpsa_scsi_dev_t *device) +{ +
Extra newline.
drivers/scsi/hpsa.c line 1281
Quoted 6 lines
drivers/scsi/hpsa.c new file +6
-0+__u32 lunid; + +if (is_logical_dev_addr_mode (lunaddrbytes)) { +/* logical device */ +memcpy (&lunid, lunaddrbytes,sizeof (lunid)); + lunid =le32_to_cpu (lunid);
Why not "lunid = le32_to_cpu(*((__le32 *)lunaddrbytes))"
drivers/scsi/hpsa.c line 1361
Quoted 11 lines
drivers/scsi/hpsa.c new file +11
-0+static int hpsa_gather_lun_info (struct ctlr_info *h, +int reportlunsize, +struct ReportLUNdata *physdev,__u32 *nphysicals, +struct ReportLUNdata *logdev,__u32 *nlogicals) +{ +if (hpsa_scsi_do_report_phys_luns (h, physdev, reportlunsize,0 )) { +dev_err (&h->pdev->dev,"report physical LUNs failed.\n" ); +return -1 ; + } +memcpy (nphysicals, &physdev->LUNListLength[0 ],sizeof (*nphysicals)); + *nphysicals =be32_to_cpu (*nphysicals) /8 ;
*nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / 8;
There are also some more of these will I will not mark all by themself.
drivers/scsi/hpsa.c line 1364
Quoted 3 lines
drivers/scsi/hpsa.c new file +3
-0+#ifdef DEBUG +dev_info (&h->pdev->dev,"number of physical luns is %d\n" , *nphysicals); +#endif
dev_dbg(...), some more times, too.
Quoted 2 lines
drivers/scsi/hpsa.c new file +2
-0+static void hpsa_update_scsi_devices (struct ctlr_info *h,int hostno) +{
[...]
drivers/scsi/hpsa.c line 1547
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+out: +kfree (tmpdevice); +for (i =0 ; i < ndev_allocated; i++) +kfree (currentsd[i]); +kfree (currentsd); +kfree (inq_buff); +kfree (physdev_list); +kfree (logdev_list); +return ; +}
Superfluous return.
Quoted 19 lines
drivers/scsi/hpsa.c new file +19
-0+/* hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci +* dma mapping and fills in the scatter gather entries of the +* hpsa command, cp. +*/ +static int hpsa_scatter_gather (struct pci_dev *pdev, +struct CommandList *cp, +struct scsi_cmnd *cmd) +{ +unsigned int len; +struct scatterlist *sg; +__u64 addr64; +int use_sg, i; + +BUG_ON (scsi_sg_count (cmd) >MAXSGENTRIES ); + + use_sg =scsi_dma_map (cmd); +if (use_sg <0 ) +return use_sg; +
drivers/scsi/hpsa.c line 1577
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+if (!use_sg) + goto sglist_finished; + +scsi_for_each_sg (cmd, sg, use_sg, i) { + addr64 = (__u64 )sg_dma_address (sg); + len =sg_dma_len (sg); + cp->SG[i].Addr.lower = + (__u32) (addr64 & (__u64 )0x00000000FFFFFFFF ); + cp->SG[i].Addr.upper = + (__u32) ((addr64 >>32 ) & (__u64 )0x00000000FFFFFFFF );
upper_32_bits/lower_32_bits
Quoted 28 lines
drivers/scsi/hpsa.c new file +28
-0+static int wait_for_device_to_become_ready (struct ctlr_info *h, +unsigned char lunaddr[]) +{ +int rc; +int count =0 ; +int waittime =HZ ; +struct CommandList *c; + + c =cmd_special_alloc (h); +if (!c) { +dev_warn (&h->pdev->dev,"out of memory in " +"wait_for_device_to_become_ready.\n" ); +return IO_ERROR ; + } + +/* Send test unit ready until device ready, or give up. */ +while (count <HPSA_TUR_RETRY_LIMIT ) { + +/* Wait for a bit. do this first, because if we send +* the TUR right away, the reset will just abort it. +*/ +set_current_state (TASK_UNINTERRUPTIBLE ); +schedule_timeout (waittime); + count++; + +/* Increase wait time with each try, up to a point. */ +if (waittime < (HZ *HPSA_MAX_WAIT_INTERVAL_SECS )) + waittime = waittime *2 ;
drivers/scsi/hpsa.c line 1742
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+ +/* Send the Test Unit Ready */ + rc =fill_cmd (c,TEST_UNIT_READY , h,NULL ,0 ,0 , + lunaddr,TYPE_CMD ); +if (rc !=0 ) { +/* We don't expect to get in here */ +dev_warn (&h->pdev->dev,"fill_cmd failed at %s:%d\n" , + __FILE__, __LINE__); +break ; + }
Maybe __func__ is more informative.
drivers/scsi/hpsa.c line 1913
Quoted 11 lines
drivers/scsi/hpsa.c new file +11
-0+#ifdef CONFIG_COMPAT + +static int do_ioctl (struct scsi_device *dev,int cmd,void *arg) +{ +int ret; + +lock_kernel (); + ret =hpsa_ioctl (dev, cmd, arg); +unlock_kernel (); +return ret; +}
Are you sure you really need the BKL? I don't think new code that relies on that is a good idea anyway.
Quoted 23 lines
drivers/scsi/hpsa.c new file +22
-0+static int hpsa_ioctl32_passthru (struct scsi_device *dev,int cmd,void *arg) +{ +IOCTL32_Command_struct __user *arg32 = + (IOCTL32_Command_struct __user *) arg; +IOCTL_Command_struct arg64; +IOCTL_Command_struct __user *p =compat_alloc_user_space (sizeof (arg64)); +int err; +u32 cp; + + err =0 ; + err |=copy_from_user (&arg64.LUN_info, &arg32->LUN_info, +sizeof (arg64.LUN_info)); + err |=copy_from_user (&arg64.Request, &arg32->Request, +sizeof (arg64.Request)); + err |=copy_from_user (&arg64.error_info, &arg32->error_info, +sizeof (arg64.error_info)); + err |=get_user (arg64.buf_size, &arg32->buf_size); + err |=get_user (cp, &arg32->buf); + arg64.buf =compat_ptr (cp); + err |=copy_to_user (p, &arg64,sizeof (arg64)); + +if (err) +return -EFAULT ;
drivers/scsi/hpsa.c line 1981
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+ + err =do_ioctl (dev,CCISS_PASSTHRU , (void *)p); +if (err) +return err; + err |=copy_in_user (&arg32->error_info, &p->error_info, +sizeof (arg32->error_info)); +if (err) +return -EFAULT ; +return err; +}
return 0;
Quoted 34 lines
drivers/scsi/hpsa.c new file +34
-0+static int hpsa_big_passthru_ioctl (struct ctlr_info *h,void __user *argp) +{ +BIG_IOCTL_Command_struct *ioc; +struct CommandList *c; +unsigned char **buff =NULL ; +int *buff_size =NULL ; +union u64bit temp64; +BYTE sg_used =0 ; +int status =0 ; +int i; +DECLARE_COMPLETION_ONSTACK (wait); +__u32 left; +__u32 sz; +BYTE __user *data_ptr; + +if (!argp) +return -EINVAL ; +if (!capable (CAP_SYS_RAWIO )) +return -EPERM ; + ioc = (BIG_IOCTL_Command_struct *) +kmalloc (sizeof (*ioc),GFP_KERNEL ); +if (!ioc) { + status = -ENOMEM ; + goto cleanup1; + } +if (copy_from_user (ioc, argp,sizeof (*ioc))) { + status = -EFAULT ; + goto cleanup1; + } +if ((ioc->buf_size <1 ) && + (ioc->Request.Type.Direction !=XFER_NONE )) { + status = -EINVAL ; + goto cleanup1; + }
drivers/scsi/hpsa.c line 2198
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+/* Check kmalloc limits using all SGs */ +if (ioc->malloc_size >MAX_KMALLOC_SIZE ) { + status = -EINVAL ; + goto cleanup1; + } +if (ioc->buf_size > ioc->malloc_size *MAXSGENTRIES ) { + status = -EINVAL ; + goto cleanup1; + } + buff =kzalloc (MAXSGENTRIES *sizeof (char *),GFP_KERNEL );
kcalloc()?
drivers/scsi/hpsa.c line 2623
Quoted 11 lines
drivers/scsi/hpsa.c new file +11
-0+/* +* Map (physical) PCI mem into (virtual) kernel space +*/ +static void __iomem *remap_pci_mem (ulong base,ulong size) +{ +ulong page_base = ((ulong ) base) &PAGE_MASK ; +ulong page_offs = ((ulong ) base) - page_base; +void __iomem *page_remapped =ioremap (page_base, page_offs + size); + +return page_remapped ? (page_remapped + page_offs) :NULL ; +}
You should simply use pci_iomap() and remove this one entirely.
Quoted 34 lines
drivers/scsi/hpsa.c new file +34
-0+static int hpsa_pci_init (struct ctlr_info *h,struct pci_dev *pdev) +{ +ushort subsystem_vendor_id, subsystem_device_id, command; +__u32 board_id, scratchpad =0 ; +__u64 cfg_offset; +__u32 cfg_base_addr; +__u64 cfg_base_addr_index; +int i, prod_index, err; + + subsystem_vendor_id = pdev->subsystem_vendor; + subsystem_device_id = pdev->subsystem_device; + board_id = (((__u32) (subsystem_device_id <<16 ) &0xffff0000 ) | + subsystem_vendor_id); + +for (i =0 ; i <ARRAY_SIZE (products); i++) +if (board_id == products[i].board_id) +break ; + + prod_index = i; + +if (prod_index ==ARRAY_SIZE (products)) { + prod_index--; +if (subsystem_vendor_id == !PCI_VENDOR_ID_HP || + !hpsa_allow_any) { +dev_warn (&pdev->dev,"unrecognized board ID:" +" 0x%08lx, ignoring.\n" , + (unsigned long ) board_id); +return -ENODEV ; + } + } +/* check to see if controller has been disabled +* BEFORE trying to enable it +*/ + (void )pci_read_config_word (pdev,PCI_COMMAND , &command);
drivers/scsi/hpsa.c line 3104
Quoted 10 lines
drivers/scsi/hpsa.c new file +10
-0+if (!(command &0x02 )) { +dev_warn (&pdev->dev,"controller appears to be disabled\n" ); +return -ENODEV ; + } + + err =pci_enable_device (pdev); +if (err) { +dev_warn (&pdev->dev,"unable to enable PCI device\n" ); +return err; + }
I usually suggest at this place to take a look at devres (Documentation/driver-model/devres.txt) as that would make some resource tracking much easier.
drivers/scsi/hpsa.c line 3236
Quoted 8 lines
drivers/scsi/hpsa.c new file +8
-0+err_out_free_res: +/* +* Deliberately omit pci_disable_device(): it does something nasty to +* Smart Array controllers that pci_enable_device does not undo +*/ +pci_release_regions (pdev); +return err; +}
That sounds interesting. Maybe the PCI folks would like to hear about that.
Quoted 8 lines
drivers/scsi/hpsa.h new file +8
-0+static unsigned long SA5_completed (struct ctlr_info *h) +{ +unsigned long register_value + =readl (h->vaddr +SA5_REPLY_PORT_OFFSET ); + +if (register_value !=FIFO_EMPTY ) + h->commands_outstanding--; +
drivers/scsi/hpsa.h line 233
Quoted 10 lines
drivers/scsi/hpsa.h new file +10
-0+#ifdef HPSA_DEBUG +if (register_value !=FIFO_EMPTY ) +printk (KERN_INFO "hpsa: Read %lx back from board\n" , + register_value); +else +printk (KERN_INFO "hpsa: FIFO Empty read\n" ); +#endif + +return register_value; +}
I don't think all those stuff should be implemented in a header file.
drivers/scsi/hpsa_cmd.h line 94
Quoted 9 lines
drivers/scsi/hpsa_cmd.h new file +9
-0+struct vals32 { +__u32 lower; +__u32 upper; +}; + +union u64bit { +struct vals32 val32; +__u64 val; +};
There are helpers to access both 32 bit halves of a 64 bit value and other nice things. Do you really need those struct things?
Quoted 2 lines
+/* The size of this structure needs to be divisible by 8
+ * od on all architectures, because the controller uses 2
^^
??
Greetings,
Eike