Add Promise SuperTrak EX 'stex' driver
PATCH 1/1 Add Promise SuperTrak EX 'stex' driver
Adds the 'stex' driver for Promise SuperTrak EX storage controllers. These controllers present themselves as SCSI, though like 3ware, megaraid and others, the underlying storage may or may not be SCSI.
As discussed, the block tagging stuff is a post-merge todo item.
drivers/scsi/Kconfig +7 -0
@@ -1053,6 +1053,13 @@ config 53C700_LE_ON_BE depends on SCSI_LASI700 default y +config SCSI_STEX + tristate "Promise SuperTrak EX Series support" + depends on PCI && SCSI + ---help--- + This driver supports Promise SuperTrak EX8350/8300/16350/16300 + Storage controllers. + config SCSI_SYM53C8XX_2 tristate "SYM53C8XX Version 2 SCSI support" depends on PCI && SCSI
drivers/scsi/Makefile +1 -0
@@ -122,6 +122,7 @@ obj-$(CONFIG_SCSI_LASI700) += 53c700.o l obj-$(CONFIG_SCSI_NSP32) += nsp32.o obj-$(CONFIG_SCSI_IPR) += ipr.o obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/ +obj-$(CONFIG_SCSI_STEX) += stex.o obj-$(CONFIG_SCSI_SATA_AHCI) += libata.o ahci.o obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o
drivers/scsi/stex.c new file +1267 -0
1,267 lines not on this page · raw message
Quoted 5 lines · Jeff Garzik
Adds the 'stex' driver for Promise SuperTrak EX storage controllers. These controllers present themselves as SCSI, though like 3ware, megaraid and others, the underlying storage may or may not be SCSI.
As discussed, the block tagging stuff is a post-merge todo item.
That's not exactly my recollection of the discussion: I thought we were still discussing the chicken and egg issue (which is we have APIs to do this per host tagging which stex duplicates on the grounds no-one's using the current APIs). Jens and I seem to be in agreement that stex should try the API's and well make any changes that become necessary to block or SCSI happen.
drivers/scsi/stex.c line 528
Quoted 10 lines
drivers/scsi/stex.c new file +10
-0+switch (cmd->cmnd[0 ]) { +case MODE_SENSE_10 : + { +static char mode_sense10[8 ] = {0 ,6 ,0 ,0 ,0 ,0 ,0 ,0 }; + +stex_direct_copy (cmd, mode_sense10,sizeof (mode_sense10)); + cmd->result =DID_OK <<16 |COMMAND_COMPLETE <<8 ; +done (cmd); +return 0 ; + }
This looks like it will trick the sd driver into reading uninitialised data for the drive caching parameters ... there are obviously faults on both sides, but I think when you ask for a mode page and you get a success return, you're entitled to think you got it ...
drivers/scsi/stex.c line 538
Quoted 10 lines
drivers/scsi/stex.c new file +10
-0+case INQUIRY : +if (id !=ST_MAX_ARRAY_SUPPORTED ) +break ; +if (lun ==0 && (cmd->cmnd[1 ] &INQUIRY_EVPD ) ==0 ) { +stex_direct_copy (cmd, console_inq_page, +sizeof (console_inq_page)); + cmd->result =DID_OK <<16 |COMMAND_COMPLETE <<8 ; + }else + cmd->result =DID_ERROR <<16 |COMMAND_COMPLETE <<8 ; +done (cmd);
The error return isn't correct you should never use DID_ERROR for an uncorrectable error because it will cause a retry (which you'll fail again). For an unsupported inquiry the correct return should be Check Condition/Illegal Request/Invalid Field in CDB
drivers/scsi/stex.c line 538
Quoted 10 lines
drivers/scsi/stex.c new file +10
-0+case INQUIRY : +if (id !=ST_MAX_ARRAY_SUPPORTED ) +break ; +if (lun ==0 && (cmd->cmnd[1 ] &INQUIRY_EVPD ) ==0 ) { +stex_direct_copy (cmd, console_inq_page, +sizeof (console_inq_page)); + cmd->result =DID_OK <<16 |COMMAND_COMPLETE <<8 ; + }else + cmd->result =DID_ERROR <<16 |COMMAND_COMPLETE <<8 ; +done (cmd);
The error return here looks like it shouldn't be DID_ERROR either. I assume the error is a format one and uncorrectable by a retry?
drivers/scsi/stex.c line 1103
Quoted 10 lines
drivers/scsi/stex.c new file +10
-0+ } + + hba->dma_mem =pci_alloc_consistent (pdev, +STEX_BUFFER_SIZE , &hba->dma_handle); +if (!hba->dma_mem) { + err = -ENOMEM ; + printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n", + pci_name(pdev)); + goto out_iounmap; + }
This should be dma_alloc_coherent, not pci_alloc_consistent.
James
Some more I missed in the first glance through:
drivers/scsi/stex.c line 1125
Quoted 1 line
drivers/scsi/stex.c new file +1
-0+ err =request_irq (pdev->irq, stex_intr,SA_SHIRQ ,DRV_NAME , hba);
Needs to be IRQF_SHARED now.
Quoted 9 lines
drivers/scsi/stex.c new file +9
-0+static int stex_reset (struct scsi_cmnd *cmd) +{ +struct st_hba *hba; +int tag; +int i =0 ; +unsigned long flags; + hba = (struct st_hba *) &cmd->device->host->hostdata[0 ]; + +wait_cmds:
drivers/scsi/stex.c line 937
Quoted 10 lines
drivers/scsi/stex.c new file +10
-0+spin_lock_irqsave (hba->host->host_lock, flags); +for (tag =0 ; tag <MU_MAX_REQUEST ; tag++) +if ((hba->tag & (1 << tag)) && hba->ccb[tag].req !=NULL ) +break ; +spin_unlock_irqrestore (hba->host->host_lock, flags); +if (tag <MU_MAX_REQUEST ) { +ssleep (1 ); +if (++i <10 ) + goto wait_cmds; + }
This implementation isn't correct. Either a reset is triggered as part of error handling, in which case every command is guaranteed to be completed or timed out, or it's been done from sg in which case the user wants an immediate reset. In either case, you shouldn't be waiting another 10 seconds for active commands.
drivers/scsi/stex.c line 954
Quoted 2 lines
drivers/scsi/stex.c new file +2
-0+if (hba->cardtype == st_shasta) +stex_hard_reset (hba);
Don't you also want some type of processing for st_vsc? Otherwise it looks like it will drop straight through the error handler and be offlined.
stex_handshake is touching the doorbell without locking, is that OK? It looks like it might be since it only happens either at start of day or after reset, but what happens (as the kexec people will remind us) if the bios hasn't quesced the card (the handshake is done after the interrupt is added ... it could fire immediately)?
Quoted 18 lines
drivers/scsi/stex.c new file +18
-0+static void stex_hba_stop (struct st_hba *hba) +{ +unsigned long flags; +int i; +u16 tag; + +spin_lock_irqsave (hba->host->host_lock, flags); +if ((tag =stex_alloc_tag ((unsigned long *)&hba->tag)) + ==TAG_BITMAP_LENGTH ) { +spin_unlock_irqrestore (hba->host->host_lock, flags); + printk(KERN_ERR DRV_NAME "(%s): unable to alloc tag\n", + pci_name(hba->pdev)); +return ; + } +for (i=0 ; i<(ST_MAX_ARRAY_SUPPORTED *ST_MAX_LUN_PER_TARGET *2 ); i++) { +stex_internal_flush (hba, i, tag); +spin_unlock_irqrestore (hba->host->host_lock, flags); +
drivers/scsi/stex.c line 1193
Quoted 10 lines
drivers/scsi/stex.c new file +10
-0+wait_event_timeout (hba->waitq, + !(hba->ccb[tag].req_type),ST_INTERNAL_TIMEOUT *HZ ); +if (hba->ccb[tag].req_type &PASSTHRU_REQ_TYPE ) +return ; +spin_lock_irqsave (hba->host->host_lock, flags); + } + +stex_free_tag ((unsigned long *)&hba->tag, tag); +spin_unlock_irqrestore (hba->host->host_lock, flags); +}
This is really inefficient (looping over all targets whether present or not). Just implement slave destroy, it will keep track of allocated in-use targets for you.
James
Quoted 5 lines · James Bottomley
Quoted 4 lines · Jeff Garzik
Adds the 'stex' driver for Promise SuperTrak EX storage controllers. These controllers present themselves as SCSI, though like 3ware, megaraid and others, the underlying storage may or may not be SCSI.
Quoted 8 lines
Quoted 1 line
As discussed, the block tagging stuff is a post-merge todo item.
That's not exactly my recollection of the discussion: I thought we were still discussing the chicken and egg issue (which is we have APIs to do this per host tagging which stex duplicates on the grounds no-one's using the current APIs). Jens and I seem to be in agreement that stex should try the API's and well make any changes that become necessary to block or SCSI happen.
Please re-read the end of the thread. The last word was "ok, let's go ahead and get this merged."
It is unreasonable to require use of an API that no-one else uses, for initial merge. That has higher potential to take a working driver to a non-working state.
If you use the API _after_ the initial merge, then you can easily debug the problem with 'git bisect' should the driver stop working. With your suggested path, it causes needless delay and reduces the useful information a tester can give us to "it works" or "it doesn't work." With my way, the tester can give us "<this> change broke the driver" information.
Quoted 15 lines
Quoted 10 lines
(quoted diff) +1
-0+ switch (cmd->cmnd[0]) {Review
Quoted 9 lines
(quoted diff) +9
-0+ case MODE_SENSE_10: + { + static char mode_sense10[8] = { 0, 6, 0, 0, 0, 0, 0, 0 }; + + stex_direct_copy(cmd, mode_sense10, sizeof(mode_sense10)); + cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + done(cmd); + return 0; + }This looks like it will trick the sd driver into reading uninitialised data for the drive caching parameters ... there are obviously faults on both sides, but I think when you ask for a mode page and you get a success return, you're entitled to think you got it ...
Agreed.
Quoted 15 lines
Quoted 10 lines
(quoted diff) +1
-0+ case INQUIRY:Review
Quoted 9 lines
(quoted diff) +9
-0+ if (id != ST_MAX_ARRAY_SUPPORTED) + break; + if (lun == 0 && (cmd->cmnd[1] & INQUIRY_EVPD) == 0) { + stex_direct_copy(cmd, console_inq_page, + sizeof(console_inq_page)); + cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + } else + cmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; + done(cmd);The error return isn't correct you should never use
DID_ERRORfor an uncorrectable error because it will cause a retry (which you'll fail again). For an unsupported inquiry the correct return should be Check Condition/Illegal Request/Invalid Field in CDB
Fixed.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
(quoted diff) +5
-0+ case INQUIRY: + if (id != ST_MAX_ARRAY_SUPPORTED) + break; + if (lun == 0 && (cmd->cmnd[1] & INQUIRY_EVPD) == 0) { + stex_direct_copy(cmd, console_inq_page,
Quoted 8 lines
Quoted 5 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+ sizeof(console_inq_page)); + cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + } else + cmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; + done(cmd);The error return here looks like it shouldn't be
DID_ERROReither. I assume the error is a format one and uncorrectable by a retry?
There is only one 'case INQUIRY' in the entire driver, so I assume you accidentally responded to the same code segment twice.
Quoted 4 lines
Quoted 4 lines
(quoted diff) +4
-0+ } + + hba->dma_mem = pci_alloc_consistent(pdev, + STEX_BUFFER_SIZE, &hba->dma_handle);
Quoted 8 lines
Review
Quoted 6 lines
(quoted diff) +6
-0+ if (!hba->dma_mem) { + err = -ENOMEM; + printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n", + pci_name(pdev)); + goto out_iounmap; + }This should be
dma_alloc_coherent, notpci_alloc_consistent.
This is perfectly normal and proper in a PCI-only driver. pci_xxx is not a deprecated API, it is a convenience API.
Using dma_xxx only causes needless work.
For the INQUIRY and irq flags fix, I checked in the attached patch to 'stex' branch of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
Jeff
commit 43ebb4ccf4bf705e7963b8b7162812a8ebd64e22
Author: Jeff Garzik <[email protected]> Date: Tue Aug 8 18:41:31 2006 -0400
[SCSI] stex: minor fixes: irq flag, error return value
- Don't use deprecated SA_SHIRQ irq flag.
- Return CHECK CONDITION (invalid field in CDB) where warranted.
43ebb4ccf4bf705e7963b8b7162812a8ebd64e22
drivers/scsi/stex.c +22 -3
@@ -334,6 +334,25 @@ static struct status_msg *stex_get_statureturn status; } +static void stex_set_sense (struct scsi_cmnd *cmd,u8 sk,u8 asc,u8 ascq) +{ + cmd->result = (DRIVER_SENSE <<24 ) |SAM_STAT_CHECK_CONDITION ; + + cmd->sense_buffer[0 ] =0x70 ;/* fixed format, current */ + cmd->sense_buffer[2 ] = sk; + cmd->sense_buffer[7 ] =18 -8 ;/* additional sense length */ + cmd->sense_buffer[12 ] = asc; + cmd->sense_buffer[13 ] = ascq; +} + +static void stex_invalid_field (struct scsi_cmnd *cmd, +void (*done)(struct scsi_cmnd *)) +{ +/* "Invalid field in cbd" */ +stex_set_sense (cmd,ILLEGAL_REQUEST ,0x24 ,0x0 ); +done (cmd); +} +static struct req_msg *stex_alloc_req (struct st_hba *hba) { struct req_msg *req = ((struct req_msg *)hba->dma_mem) +
@@ -533,9 +552,9 @@ stex_queuecommand(struct scsi_cmnd *cmd,stex_direct_copy (cmd, console_inq_page,sizeof (console_inq_page)); cmd->result =DID_OK <<16 |COMMAND_COMPLETE <<8 ; +done (cmd); }else - cmd->result =DID_ERROR <<16 |COMMAND_COMPLETE <<8 ; -done (cmd); +stex_invalid_field (cmd, done);return 0 ;case PASSTHRU_CMD :if (cmd->cmnd[1 ] ==PASSTHRU_GET_DRVVER ) {
@@ -1122,7 +1141,7 @@ stex_probe(struct pci_dev *pdev, const s hba->pdev = pdev;init_waitqueue_head (&hba->waitq); - err =request_irq (pdev->irq, stex_intr,SA_SHIRQ ,DRV_NAME , hba); + err =request_irq (pdev->irq, stex_intr,IRQF_SHARED ,DRV_NAME , hba);if (err) { printk(KERN_ERR DRV_NAME "(%s): request irq failed\n", pci_name(pdev));
Quoted 15 lines · Jeff Garzik
Quoted 5 lines · James Bottomley
Quoted 4 lines · Jeff Garzik
Adds the 'stex' driver for Promise SuperTrak EX storage controllers. These controllers present themselves as SCSI, though like 3ware, megaraid and others, the underlying storage may or may not be SCSI.
Quoted 8 lines
Quoted 1 line
As discussed, the block tagging stuff is a post-merge todo item.
That's not exactly my recollection of the discussion: I thought we were still discussing the chicken and egg issue (which is we have APIs to do this per host tagging which stex duplicates on the grounds no-one's using the current APIs). Jens and I seem to be in agreement that stex should try the API's and well make any changes that become necessary to block or SCSI happen.
Quoted 2 lines
Please re-read the end of the thread. The last word was "ok, let's go ahead and get this merged."
Those weren't my last words ...
However, I'll take on some of this ... I'll convert the aic7xxx driver which is our current shared host tag driver ... then you only need copy it to do stex.
Quoted 5 lines
Quoted 2 lines
The error return here looks like it shouldn't be
DID_ERROReither. I assume the error is a format one and uncorrectable by a retry?There is only one 'case INQUIRY' in the entire driver, so I assume you accidentally responded to the same code segment twice.
No, sorry, misquoted ... the above comment applies to the case PASSTHRU_CMD, which has the same problem (it would repeat a malformed command).
Quoted 6 lines
Quoted 1 line
This should be
dma_alloc_coherent, notpci_alloc_consistent.This is perfectly normal and proper in a PCI-only driver.
pci_xxxis not a deprecated API, it is a convenience API.Using
dma_xxxonly causes needless work.
What work? it's an exact drop in replacement. However, the only usage of pci_xxx I'm requiring to be fixed is the pci_alloc_consistent, primarily because pci_alloc_consistent *is* deprecated: it forces a GFP_ATOMIC allocation of a potentially large amount of data. dma_alloc_coherent allows you to specify gfp flags, which, in this case, should be GFP_KERNEL.
James
Quoted 3 lines · James Bottomley
However, I'll take on some of this ... I'll convert the aic7xxx driver which is our current shared host tag driver ... then you only need copy it to do stex.
No, that approach still has the problems outlined for stex.
You are taking a WORKING, IN-TREE driver and modifying it. Thus 'git bisect' can easily identify any problems you introduce.
As has been stated repeatedly, stex should have the same conditions you are giving yourself: take a working, in-tree driver and update it to use host-wide tags.
Otherwise, you deny testers and developers the utility of 'git bisect' if there are problems that do not show up immediately.
Quoted 3 lines
No, sorry, misquoted ... the above comment applies to the case
PASSTHRU_CMD, which has the same problem (it would repeat a malformed command).
DID_ERROR is not flagging a malformed command.
PASSTHRU_CMD either (a) passes the command to the firmware, using normal queue/complete paths, or (b) handles the command in the driver.
For the (b) case, DID_ERROR is only asserted if scsi_kmap_atomic_sg() returns NULL -- presumably a transient condition.
Quoted 6 lines
Quoted 4 lines
Quoted 1 line
This should be
dma_alloc_coherent, notpci_alloc_consistent.This is perfectly normal and proper in a PCI-only driver.
pci_xxxis not a deprecated API, it is a convenience API.Using
dma_xxxonly causes needless work.What work? it's an exact drop in replacement. However, the only usage
No, it's not. Using struct device rather than struct pci_dev introduces additional indirection into the driver, rather than hiding it in a convenience layer. Nice and clean 'pdev' reference becomes '&pdev->dev' or 'to_pci_dev(dev)'.
Quoted 5 lines
of
pci_xxxI'm requiring to be fixed is thepci_alloc_consistent, primarily becausepci_alloc_consistent*is* deprecated: it forces aGFP_ATOMICallocation of a potentially large amount of data.dma_alloc_coherentallows you to specify gfp flags, which, in this case, should beGFP_KERNEL.
Good point, I had forgotten about GFP_KERNEL. Agreed. Updated as shown in the attached patch.
Sounds like we need a pci_{alloc,free}_coherent wrapper API.
Jeff
commit 5b5464d78665b1b2199b02d827a3c5f85dbe2c4b
Author: Jeff Garzik <[email protected]> Date: Tue Aug 8 21:34:17 2006 -0400
[SCSI] stex: use dma_alloc_coherent()
pci_alloc_consistent() API prevents us from using GFP_KERNEL.
5b5464d78665b1b2199b02d827a3c5f85dbe2c4b
drivers/scsi/stex.c +6 -6
@@ -1112,8 +1112,8 @@ stex_probe(struct pci_dev *pdev, const s goto out_iounmap; } - hba->dma_mem =pci_alloc_consistent (pdev, -STEX_BUFFER_SIZE , &hba->dma_handle); + hba->dma_mem =dma_alloc_coherent (&pdev->dev, +STEX_BUFFER_SIZE , &hba->dma_handle,GFP_KERNEL );if (!hba->dma_mem) { err = -ENOMEM ; printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n",
@@ -1168,8 +1168,8 @@ stex_probe(struct pci_dev *pdev, const s out_free_irq:free_irq (pdev->irq, hba); out_pci_free: -pci_free_consistent (pdev,STEX_BUFFER_SIZE , - hba->dma_mem, hba->dma_handle); +dma_free_coherent (&pdev->dev,STEX_BUFFER_SIZE , + hba->dma_mem, hba->dma_handle); out_iounmap:iounmap (hba->mmio_base); out_release_regions:
@@ -1219,8 +1219,8 @@ static void stex_hba_free(struct st_hbapci_release_regions (hba->pdev); -pci_free_consistent (hba->pdev,STEX_BUFFER_SIZE , - hba->dma_mem, hba->dma_handle); +dma_free_coherent (&hba->pdev->dev,STEX_BUFFER_SIZE , + hba->dma_mem, hba->dma_handle); }static void stex_remove (struct pci_dev *pdev)