bk://linux-scsi.bkbits.net/scsi-misc-2.6 bunk@stusta.de|ChangeSet|20041126175043|38157 bunk # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/11/27 13:45:31-08:00 akpm@bix.(none) # Merge bk://linux-scsi.bkbits.net/scsi-misc-2.6 # into bix.(none):/usr/src/bk-scsi # # drivers/scsi/hosts.c # 2004/11/27 13:45:26-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/11/26 11:50:43-06:00 bunk@stusta.de # [PATCH] remove bouncing email address of Deanna Bonds # # The patch below (applies against both 2.4 and 2.6) removes the bouncing # email address of Deanna Bonds (I didn't find a nmore recent address). # # Signed-off-by: Adrian Bunk # Signed-off-by: James Bottomley # # drivers/scsi/dpti.h # 2004/11/24 12:23:56-06:00 bunk@stusta.de +0 -1 # remove bouncing email address of Deanna Bonds # # drivers/scsi/dpt_i2o.c # 2004/11/24 12:24:37-06:00 bunk@stusta.de +0 -1 # remove bouncing email address of Deanna Bonds # # drivers/scsi/dpt/dpti_ioctl.h # 2004/11/24 12:24:27-06:00 bunk@stusta.de +0 -1 # remove bouncing email address of Deanna Bonds # # drivers/scsi/aacraid/README # 2004/11/24 12:24:16-06:00 bunk@stusta.de +1 -1 # remove bouncing email address of Deanna Bonds # # ChangeSet # 2004/11/26 11:47:06-06:00 bunk@stusta.de # [PATCH] SCSI aic7xxx_old.c: make a function static # # The patch below makes the needlessly global function aic7xxx_info # static. # # Signed-off-by: Adrian Bunk # Signed-off-by: James Bottomley # # drivers/scsi/aic7xxx_old/aic7xxx_proc.c # 2004/11/13 10:16:45-06:00 bunk@stusta.de +1 -1 # SCSI aic7xxx_old.c: make a function static # # drivers/scsi/aic7xxx_old.c # 2004/11/13 10:16:12-06:00 bunk@stusta.de +1 -1 # SCSI aic7xxx_old.c: make a function static # # ChangeSet # 2004/11/26 11:45:27-06:00 jejb@mulgrave.(none) # LSI Logic - SAS and FC PCI ID's # # From: Moore, Eric Dean # # Here are new PCI ID's for SAS and Fibre Channel # LSI Logic controllers. # # Signed-off-by: Eric Moore # Signed-off-by: James Bottomley # # include/linux/pci_ids.h # 2004/11/26 11:44:15-06:00 jejb@mulgrave.(none) +10 -0 # LSI Logic - SAS and FC PCI ID's # # ChangeSet # 2004/11/26 11:33:06-06:00 jejb@mulgrave.(none) # fixup dynamic scan aids EXPORT_SYMBOL mismerge # # OK, so I exported the wrong symbols ... # # Signed-off-by: James Bottomley # # drivers/scsi/scsi_scan.c # 2004/11/26 11:31:38-06:00 jejb@mulgrave.(none) +2 -1 # fixup dynamic scan aids EXPORT_SYMBOL mismerge # # ChangeSet # 2004/11/26 10:16:03-06:00 jejb@mulgrave.(none) # scsi: LLDD dynamic scan aids # # From: James.Smart@Emulex.Com # # With rejection fixes around the removal of scsi_syms.c # Signed-off-by: James Bottomley # # include/scsi/scsi_host.h # 2004/11/26 10:15:26-06:00 jejb@mulgrave.(none) +3 -0 # scsi: LLDD dynamic scan aids # # drivers/scsi/scsi_scan.c # 2004/11/26 10:15:26-06:00 jejb@mulgrave.(none) +13 -0 # scsi: LLDD dynamic scan aids # # ChangeSet # 2004/11/26 10:10:46-06:00 axboe@suse.de # [PATCH] kill locking around scsi_done() # # Lets show the mid layer as a good example and remove the host lock # around the scsi_done() call. # # Signed-off-by: Jens Axboe # Signed-off-by: James Bottomley # # ===== drivers/scsi/scsi.c 1.148 vs edited ===== # # drivers/scsi/scsi.c # 2004/11/20 16:25:38-06:00 axboe@suse.de +0 -2 # kill locking around scsi_done() # # ChangeSet # 2004/11/26 10:07:03-06:00 bunk@stusta.de # [PATCH] kill scsi_syms.c # # The patch below removes scsi_syms.c and moves the EXPORT_SYMBOL's to the # files where the actual functions are. # # Signed-off-by: Adrian Bunk # Signed-off-by: James Bottomley # # drivers/scsi/scsicam.c # 2004/11/20 14:31:54-06:00 bunk@stusta.de +3 -0 # kill scsi_syms.c # # drivers/scsi/scsi_sysfs.c # 2004/11/20 14:44:12-06:00 bunk@stusta.de +3 -0 # kill scsi_syms.c # # drivers/scsi/scsi_scan.c # 2004/11/20 14:43:37-06:00 bunk@stusta.de +5 -0 # kill scsi_syms.c # # drivers/scsi/scsi_lib.c # 2004/11/20 14:46:26-06:00 bunk@stusta.de +9 -1 # kill scsi_syms.c # # drivers/scsi/scsi_ioctl.c # 2004/11/20 14:36:32-06:00 bunk@stusta.de +3 -0 # kill scsi_syms.c # # drivers/scsi/scsi_error.c # 2004/11/20 14:46:48-06:00 bunk@stusta.de +6 -0 # kill scsi_syms.c # # drivers/scsi/scsi.c # 2004/11/20 14:46:12-06:00 bunk@stusta.de +11 -0 # kill scsi_syms.c # # drivers/scsi/hosts.c # 2004/11/20 14:30:51-06:00 bunk@stusta.de +8 -0 # kill scsi_syms.c # # drivers/scsi/constants.c # 2004/11/20 14:35:16-06:00 bunk@stusta.de +9 -0 # kill scsi_syms.c # # drivers/scsi/Makefile # 2004/11/20 14:26:17-06:00 bunk@stusta.de +1 -1 # kill scsi_syms.c # # Documentation/scsi/scsi_mid_low_api.txt # 2004/11/20 14:25:56-06:00 bunk@stusta.de +2 -2 # kill scsi_syms.c # # BitKeeper/deleted/.del-scsi_syms.c~8c75b2d48ed73d87 # 2004/11/26 10:06:12-06:00 bunk@stusta.de +0 -0 # Delete: drivers/scsi/scsi_syms.c # # ChangeSet # 2004/11/26 00:46:18-08:00 akpm@bix.(none) # Merge bk://linux-scsi.bkbits.net/scsi-misc-2.6 # into bix.(none):/usr/src/bk-scsi # # drivers/scsi/hosts.c # 2004/11/26 00:46:13-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/Kconfig # 2004/11/26 00:46:13-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/11/25 12:07:52-06:00 jejb@mulgrave.(none) # convert eata to pass pointers around # # From: Christoph Hellwig # # pass pointers to Scsi_Host and the private data around instead of using # indices into global arrays all over the place. # # Signed-off-by: James Bottomley # # drivers/scsi/eata.c # 2004/11/25 12:05:43-06:00 jejb@mulgrave.(none) +291 -298 # convert eata to pass pointers around # # ChangeSet # 2004/11/25 11:54:54-06:00 hch@lst.de # [PATCH] feed eata.c through Lindent # # the driver oopses on load for me currently, but to debug it I need to # actually be able to read the source.. # # Signed-off-by: James Bottomley # # drivers/scsi/eata.c # 2004/11/02 07:28:36-06:00 hch@lst.de +1770 -1568 # feed eata.c through Lindent # # ChangeSet # 2004/11/25 11:08:32-06:00 jejb@mulgrave.(none) # Merge ssh://linux-scsi@linux-scsi.bkbits.net/scsi-misc-2.6 # into mulgrave.(none):/home/jejb/BK/scsi-misc-2.6 # # drivers/scsi/hosts.c # 2004/11/25 11:08:25-06:00 jejb@mulgrave.(none) +0 -0 # Auto merged # # drivers/scsi/Kconfig # 2004/11/25 11:08:25-06:00 jejb@mulgrave.(none) +0 -0 # Auto merged # # ChangeSet # 2004/11/19 20:11:31-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi # # drivers/scsi/megaraid/megaraid_mbox.h # 2004/11/19 20:11:27-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/megaraid/megaraid_mbox.c # 2004/11/19 20:11:27-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/hosts.c # 2004/11/19 20:11:26-08:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/Kconfig # 2004/11/19 20:11:26-08:00 akpm@bix.(none) +0 -0 # Auto merged # # Documentation/scsi/ChangeLog.megaraid # 2004/11/19 20:11:26-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/11/17 10:34:09-06:00 akpm@osdl.org # [PATCH] iscsi_transport build fix # # drivers/scsi/scsi_transport_iscsi.c:176: structure has no member named `sin6_addr' # # Older gcc's dont support anonymous unions. # # Signed-off-by: Andrew Morton # Signed-off-by: James Bottomley # # include/scsi/scsi_transport_iscsi.h # 2004/11/17 03:55:50-06:00 akpm@osdl.org +3 -3 # iscsi_transport build fix # # ChangeSet # 2004/11/16 16:05:58-06:00 jejb@mulgrave.(none) # SCSI: Add missing state transition BLOCK->OFFLINE # # From: James.Smart@Emulex.Com # # Signed-off-by: James Bottomley # # drivers/scsi/scsi_lib.c # 2004/11/16 16:05:38-06:00 jejb@mulgrave.(none) +1 -0 # SCSI: Add missing state transition BLOCK->OFFLINE # # ChangeSet # 2004/11/16 16:01:31-06:00 dougg@torque.net # SCSI: descriptor sense format, mid-level # # - generalize sense data logic to cope with both fixed and # descriptor format # - use KERN_INFO on most printk()s to limit console noise # - retire mid-level usage of sense_class(), sense_error() and # sense_valid() macros which are SCSI-1 remnants. Now only # cpqfcTSinit.c seems to use them # # Signed-off-by: James Bottomley # # drivers/scsi/scsi_scan.c # 2004/11/08 02:33:25-06:00 dougg@torque.net +21 -12 # descriptor sense format, mid-level # # drivers/scsi/scsi_lib.c # 2004/11/08 01:14:41-06:00 dougg@torque.net +16 -12 # descriptor sense format, mid-level # # drivers/scsi/scsi_ioctl.c # 2004/11/08 04:56:44-06:00 dougg@torque.net +18 -12 # descriptor sense format, mid-level # # drivers/scsi/scsi_error.c # 2004/11/08 00:43:52-06:00 dougg@torque.net +35 -12 # descriptor sense format, mid-level # # ChangeSet # 2004/11/16 15:23:21-06:00 michaelc@cs.wisc.edu # [PATCH] iSCSI transport class # # The attached patch adds an iSCSI transport class. It was # built against scsi-misc-2.6. It allows the software/virtual # iSCSI driver to remove at least one of its ioctl commands. # The patch also assumes the no multipath/failover rule in # llds applies to iSCSI drivers, so when we remove our # portal/portal_group failover support it will allow us to # kill all our ioctl commands execpt the session creation one # (that will take more thought). # # We would like to build some functions like the # unblock/block capabilites into the iscsi transport class # like James Smart has done with FC class. but initially we # would like to begin with this smaller patch that only provides # an iscsi sysfs interface. # # Signed-off-by: James Bottomley # # include/scsi/scsi_transport_iscsi.h # 2004/10/29 05:55:13-05:00 michaelc@cs.wisc.edu +178 -0 # iSCSI transport class # # include/scsi/scsi_transport_iscsi.h # 2004/10/29 05:55:13-05:00 michaelc@cs.wisc.edu +0 -0 # BitKeeper file /home/jejb/BK/scsi-misc-2.6/include/scsi/scsi_transport_iscsi.h # # drivers/scsi/scsi_transport_iscsi.c # 2004/10/29 06:30:20-05:00 michaelc@cs.wisc.edu +355 -0 # iSCSI transport class # # drivers/scsi/Makefile # 2004/10/28 22:57:11-05:00 michaelc@cs.wisc.edu +1 -1 # iSCSI transport class # # drivers/scsi/Kconfig # 2004/10/28 22:57:11-05:00 michaelc@cs.wisc.edu +8 -0 # iSCSI transport class # # drivers/scsi/scsi_transport_iscsi.c # 2004/10/29 06:30:20-05:00 michaelc@cs.wisc.edu +0 -0 # BitKeeper file /home/jejb/BK/scsi-misc-2.6/drivers/scsi/scsi_transport_iscsi.c # # ChangeSet # 2004/11/16 13:49:34-06:00 jejb@mulgrave.(none) # SCSI: Add transport destructors # # From: James.Smart@Emulex.Com # # This patch adds host/target/sdev destructor functions to the transport # template. The FC transport is updated to utilize them to cancel any # outstanding timer. It slightly rearranges the slave_xxx functions so # the transport is always involved prior to the LLDD. # # Minor rejection fixes and # Signed-off-by: James Bottomley # # include/scsi/scsi_transport.h # 2004/11/16 13:48:01-06:00 jejb@mulgrave.(none) +5 -0 # SCSI: Add transport destructors # # drivers/scsi/scsi_transport_fc.c # 2004/11/16 13:48:01-06:00 jejb@mulgrave.(none) +16 -0 # SCSI: Add transport destructors # # drivers/scsi/scsi_sysfs.c # 2004/11/16 13:48:01-06:00 jejb@mulgrave.(none) +5 -0 # SCSI: Add transport destructors # # drivers/scsi/scsi_scan.c # 2004/11/16 13:48:01-06:00 jejb@mulgrave.(none) +13 -6 # SCSI: Add transport destructors # # drivers/scsi/hosts.c # 2004/11/16 13:48:01-06:00 jejb@mulgrave.(none) +6 -1 # SCSI: Add transport destructors # # ChangeSet # 2004/11/16 13:42:53-06:00 jejb@mulgrave.(none) # SCSI: updates to constants.c # # From: Douglas Gilbert # # - bring opcode names, asc/ascq strings and sense format # into line with SPC-3 rev 21 (22 September 2004) # - drop SCSI-1 sense buffer decoding [still output it in hex] # - opcode names include those that depend on service actions # including variable length commands ** # - decodes both fixed and descriptor sense data formats # - use KERN_INFO on printk()s that start on new lines # - flag vendor specific asc and acsq codes # - print all bytes of a cdb after the name (previously skipped # the first byte) # - cleanup file, tab to 8 spaces # # Signed-off-by: James Bottomley # # drivers/scsi/constants.c # 2004/11/16 13:41:26-06:00 jejb@mulgrave.(none) +578 -339 # SCSI: updates to constants.c # # ChangeSet # 2004/11/16 13:29:04-06:00 jejb@mulgrave.(none) # update the fc_transport_class to use a workqueue instead of a timeout # # The amount of work that has to be done in the timeout routines is really # a bit much if there's a large number of LUNS. Plus the # device_for_each_child needs user context to get the bus semaphore, so # the solution is to migrate them from a timer to delayed work. # # There's still a race here in that the timer may still be ticking when # the device is destroyed ... To fix this, I think we may need to # introduce a destroy callback to the transport class. # # Signed-off-by: James Bottomley # # include/scsi/scsi_transport_fc.h # 2004/11/16 13:26:54-06:00 jejb@mulgrave.(none) +6 -6 # update the fc_transport_class to use a workqueue instead of a timeout # # drivers/scsi/scsi_transport_fc.c # 2004/11/16 13:26:54-06:00 jejb@mulgrave.(none) +17 -17 # update the fc_transport_class to use a workqueue instead of a timeout # # ChangeSet # 2004/11/14 21:35:57-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi # # drivers/scsi/qla1280.c # 2004/11/14 21:35:54-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/11/11 15:07:32-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi # # drivers/scsi/qla1280.c # 2004/11/11 15:07:28-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/10/24 22:09:45-07:00 akpm@bix.(none) # Merge bk://linux-scsi.bkbits.net/scsi-misc-2.6 # into bix.(none):/usr/src/bk-scsi # # drivers/scsi/megaraid/megaraid_mbox.c # 2004/10/24 22:09:40-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/10/24 16:48:01-05:00 jejb@mulgrave.(none) # scsi_debug v 1.75 # # From: Douglas Gilbert # # - fix highmem data transfers # - fix kunmap_atomic() argument # - disable clustering # - allow every_nth < 0 for error continuously once # count is reached # - minor sense buffer handling cleanup # # Signed-off-by: James Bottomley # # drivers/scsi/scsi_debug.c # 2004/10/24 16:47:49-05:00 jejb@mulgrave.(none) +265 -214 # scsi_debug v 1.75 # # ChangeSet # 2004/10/21 00:22:42-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi # # drivers/scsi/megaraid/megaraid_mbox.h # 2004/10/21 00:22:38-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/megaraid/megaraid_mbox.c # 2004/10/21 00:22:38-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/10/19 22:12:26-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi # # drivers/scsi/megaraid/megaraid_mbox.c # 2004/10/19 22:12:23-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/10/15 22:40:42-07:00 akpm@bix.(none) # Merge bk://linux-scsi.bkbits.net/scsi-misc-2.6 # into bix.(none):/usr/src/bk-scsi # # drivers/scsi/megaraid/megaraid_mbox.h # 2004/10/15 22:40:38-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/megaraid/megaraid_mbox.c # 2004/10/15 22:40:38-07:00 akpm@bix.(none) +0 -0 # Auto merged # # Documentation/scsi/ChangeLog.megaraid # 2004/10/15 22:40:38-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/10/13 13:38:51-07:00 akpm@bix.(none) # foo # # Documentation/scsi/ChangeLog.megaraid # 2004/10/13 13:38:44-07:00 akpm@bix.(none) +0 -8 # foo # # drivers/scsi/megaraid/megaraid_mbox.h # 2004/10/13 13:32:32-07:00 akpm@bix.(none) +0 -2 # Auto merged # # drivers/scsi/megaraid/megaraid_mbox.c # 2004/10/13 13:32:32-07:00 akpm@bix.(none) +0 -3 # Auto merged # diff -Nru a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt --- a/Documentation/scsi/scsi_mid_low_api.txt 2004-11-29 21:56:02 -08:00 +++ b/Documentation/scsi/scsi_mid_low_api.txt 2004-11-29 21:56:02 -08:00 @@ -363,8 +363,8 @@ Mid level supplied functions ============================ These functions are supplied by the SCSI mid level for use by LLDs. -The names (i.e. entry points) of these functions are exported (mainly in -scsi_syms.c) so an LLD that is a module can access them. The kernel will +The names (i.e. entry points) of these functions are exported +so an LLD that is a module can access them. The kernel will arrange for the SCSI mid level to be loaded and initialized before any LLD is initialized. The functions below are listed alphabetically and their names all start with "scsi_". diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/Kconfig 2004-11-29 21:56:02 -08:00 @@ -203,6 +203,14 @@ each attached FiberChannel device to sysfs, say Y. Otherwise, say N. +config SCSI_ISCSI_ATTRS + tristate "iSCSI Transport Attributes" + depends on SCSI + help + If you wish to export transport-specific information about + each attached iSCSI device to sysfs, say Y. + Otherwise, say N. + endmenu menu "SCSI low-level drivers" diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/Makefile 2004-11-29 21:56:02 -08:00 @@ -28,7 +28,7 @@ # -------------------------- obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o - +obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o @@ -143,7 +143,7 @@ scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \ scsicam.o scsi_error.o scsi_lib.o \ - scsi_scan.o scsi_syms.o scsi_sysfs.o \ + scsi_scan.o scsi_sysfs.o \ scsi_devinfo.o scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o diff -Nru a/drivers/scsi/aacraid/README b/drivers/scsi/aacraid/README --- a/drivers/scsi/aacraid/README 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/aacraid/README 2004-11-29 21:56:02 -08:00 @@ -42,7 +42,7 @@ Christoph Hellwig (updates for new-style PCI probing and SCSI host registration, small cleanups/fixes) Matt Domsch (revision ioctl, adapter messages) -Deanna Bonds (non-DASD support, PAE fibs and 64 bit, added new adaptec controllers +Deanna Bonds (non-DASD support, PAE fibs and 64 bit, added new adaptec controllers added new ioctls, changed scsi interface to use new error handler, increased the number of fibs and outstanding commands to a container) diff -Nru a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c --- a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c 2004-11-29 21:56:02 -08:00 @@ -64,7 +64,7 @@ * Description: * Set parameters for the driver from the /proc filesystem. *-F*************************************************************************/ -int +static int aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) { proc_debug("aic7xxx_set_info(): %s\n", buffer); diff -Nru a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c --- a/drivers/scsi/aic7xxx_old.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/aic7xxx_old.c 2004-11-29 21:56:02 -08:00 @@ -1838,7 +1838,7 @@ * Description: * Return a string describing the driver. *-F*************************************************************************/ -const char * +static const char * aic7xxx_info(struct Scsi_Host *dooh) { static char buffer[256]; diff -Nru a/drivers/scsi/constants.c b/drivers/scsi/constants.c --- a/drivers/scsi/constants.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/constants.c 2004-11-29 21:56:02 -08:00 @@ -4,6 +4,7 @@ * Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422) * Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002) * by D. Gilbert and aeb (20020609) + * Additions for SPC-3 T10/1416-D Rev 21 22 Sept 2004, D. Gilbert 20041025 */ #include @@ -15,96 +16,78 @@ #include #include #include +#include -#define CONST_COMMAND 0x01 -#define CONST_STATUS 0x02 -#define CONST_SENSE 0x04 -#define CONST_XSENSE 0x08 -#define CONST_CMND 0x10 -#define CONST_MSG 0x20 -#define CONST_HOST 0x40 -#define CONST_DRIVER 0x80 -static const char unknown[] = "UNKNOWN"; +/* Commands with service actions that change the command name */ +#define MAINTENANCE_IN 0xa3 +#define MAINTENANCE_OUT 0xa4 +#define SERVICE_ACTION_IN_12 0xab +#define SERVICE_ACTION_OUT_12 0xa9 +#define SERVICE_ACTION_IN_16 0x9e +#define SERVICE_ACTION_OUT_16 0x9f +#define VARIABLE_LENGTH_CMD 0x7f -#ifdef CONFIG_SCSI_CONSTANTS -#ifdef CONSTANTS -#undef CONSTANTS -#endif -#define CONSTANTS (CONST_COMMAND | CONST_STATUS | CONST_SENSE | CONST_XSENSE \ - | CONST_CMND | CONST_MSG | CONST_HOST | CONST_DRIVER) -#else -#define CONSTANTS 0 -#endif - -#if (CONSTANTS & CONST_COMMAND) -static const char * group_0_commands[] = { -/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense", -/* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks", -/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown, -/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry", -/* 13-16 */ "Verify", "Recover Buffered Data", "Mode Select", "Reserve", -/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", -/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", -/* 1e-1f */ "Prevent/Allow Medium Removal", unknown, -}; -static const char *group_1_commands[] = { -/* 20-22 */ unknown, unknown, unknown, -/* 23-28 */ unknown, "Define window parameters", "Read Capacity", - unknown, unknown, "Read (10)", -/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase", +#ifdef CONFIG_SCSI_CONSTANTS +static const char * cdb_byte0_names[] = { +/* 00-03 */ "Test Unit Ready", "Rezero Unit/Rewind", NULL, "Request Sense", +/* 04-07 */ "Format Unit/Medium", "Read Block Limits", NULL, + "Reasssign Blocks", +/* 08-0d */ "Read (6)", NULL, "Write (6)", "Seek (6)", NULL, NULL, +/* 0e-12 */ NULL, "Read Reverse", "Write Filemarks", "Space", "Inquiry", +/* 13-16 */ "Verify (6)", "Recover Buffered Data", "Mode Select (6)", + "Reserve (6)", +/* 17-1a */ "Release (6)", "Copy", "Erase", "Mode Sense (6)", +/* 1b-1d */ "Start/Stop Unit", "Receive Diagnostic", "Send Diagnostic", +/* 1e-1f */ "Prevent/Allow Medium Removal", NULL, +/* 20-22 */ NULL, NULL, NULL, +/* 23-28 */ "Read Format Capacities", "Set Window", + "Read Capacity (10)", NULL, NULL, "Read (10)", +/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase (10)", "Read updated block", -/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", -/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", -/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", +/* 2e-31 */ "Write Verify (10)", "Verify (10)", "Search High", "Search Equal", +/* 32-34 */ "Search Low", "Set Limits", "Prefetch/Read Position", +/* 35-37 */ "Synchronize Cache (10)", "Lock/Unlock Cache (10)", + "Read Defect Data(10)", /* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", "Read Buffer", -/* 3d-3f */ "Update Block", "Read Long", "Write Long", -}; - - -static const char *group_2_commands[] = { -/* 40-41 */ "Change Definition", "Write Same", -/* 42-48 */ "Read sub-channel", "Read TOC", "Read header", +/* 3d-3f */ "Update Block", "Read Long (10)", "Write Long (10)", +/* 40-41 */ "Change Definition", "Write Same (10)", +/* 42-48 */ "Read sub-channel", "Read TOC/PMA/ATIP", "Read density support", "Play audio (10)", "Get configuration", "Play audio msf", "Play audio track/index", /* 49-4f */ "Play track relative (10)", "Get event status notification", "Pause/resume", "Log Select", "Log Sense", "Stop play/scan", - unknown, + NULL, /* 50-55 */ "Xdwrite", "Xpwrite, Read disk info", "Xdread, Read track info", - "Reserve track", "Send OPC onfo", "Mode Select (10)", + "Reserve track", "Send OPC info", "Mode Select (10)", /* 56-5b */ "Reserve (10)", "Release (10)", "Repair track", "Read master cue", "Mode Sense (10)", "Close track/session", /* 5c-5f */ "Read buffer capacity", "Send cue sheet", "Persistent reserve in", "Persistent reserve out", -}; - - -/* The following are 16 byte commands in group 4 */ -static const char *group_4_commands[] = { +/* 60-67 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/* 68-6f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/* 70-77 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Variable length", /* 80-84 */ "Xdwrite (16)", "Rebuild (16)", "Regenerate (16)", "Extended copy", "Receive copy results", /* 85-89 */ "Memory Export In (16)", "Access control in", "Access control out", "Read (16)", "Memory Export Out (16)", -/* 8a-8f */ "Write (16)", unknown, "Read attributes", "Write attributes", +/* 8a-8f */ "Write (16)", NULL, "Read attributes", "Write attributes", "Write and verify (16)", "Verify (16)", /* 90-94 */ "Pre-fetch (16)", "Synchronize cache (16)", - "Lock/unlock cache (16)", "Write same (16)", unknown, -/* 95-99 */ unknown, unknown, unknown, unknown, unknown, -/* 9a-9f */ unknown, unknown, unknown, unknown, "Service action in", - "Service action out", -}; - -/* The following are 12 byte commands in group 5 */ -static const char *group_5_commands[] = { -/* a0-a5 */ "Report luns", "Blank", "Send event", "Maintenance (in)", - "Maintenance (out)", "Move medium/play audio(12)", + "Lock/unlock cache (16)", "Write same (16)", NULL, +/* 95-99 */ NULL, NULL, NULL, NULL, NULL, +/* 9a-9f */ NULL, NULL, NULL, NULL, "Service action in (16)", + "Service action out (16)", +/* a0-a5 */ "Report luns", "Blank", "Send event", "Maintenance in", + "Maintenance out", "Move medium/play audio(12)", /* a6-a9 */ "Exchange medium", "Move medium attached", "Read(12)", "Play track relative(12)", -/* aa-ae */ "Write(12)", unknown, "Erase(12), Get Performance", +/* aa-ae */ "Write(12)", NULL, "Erase(12), Get Performance", "Read DVD structure", "Write and verify(12)", /* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)", /* b2-b4 */ "Search data low(12)", "Set limits(12)", @@ -112,57 +95,279 @@ /* b5-b6 */ "Request volume element address", "Send volume tag, set streaming", /* b7-b9 */ "Read defect data(12)", "Read element status", "Read CD msf", /* ba-bc */ "Redundancy group (in), Scan", - "Redundancy group (out), Set cd-rom speed", "Spare (in), Play cd", -/* bd-bf */ "Spare (out), Mechanism status", "Volume set (in), Read cd", - "Volume set (out), Send DVD structure", + "Redundancy group (out), Set cd-rom speed", "Spare in, Play cd", +/* bd-bf */ "Spare out, Mechanism status", "Volume set in, Read cd", + "Volume set out, Send DVD structure", +}; + +struct value_name_pair { + int value; + const char * name; +}; + +static const struct value_name_pair maint_in_arr[] = { + {0x5, "Report device identifier"}, + {0xa, "Report target port groups"}, + {0xb, "Report aliases"}, + {0xc, "Report supported operation codes"}, + {0xd, "Report supported task management functions"}, + {0xe, "Report priority"}, +}; +#define MAINT_IN_SZ \ + (int)(sizeof(maint_in_arr) / sizeof(maint_in_arr[0])) + +static const struct value_name_pair maint_out_arr[] = { + {0x6, "Set device identifier"}, + {0xa, "Set target port groups"}, + {0xb, "Change aliases"}, + {0xe, "Set priority"}, }; +#define MAINT_OUT_SZ \ + (int)(sizeof(maint_out_arr) / sizeof(maint_out_arr[0])) +static const struct value_name_pair serv_in12_arr[] = { + {0x1, "Read media serial number"}, +}; +#define SERV_IN12_SZ \ + (int)(sizeof(serv_in12_arr) / sizeof(serv_in12_arr[0])) +static const struct value_name_pair serv_out12_arr[] = { + {-1, "dummy entry"}, +}; +#define SERV_OUT12_SZ \ + (int)(sizeof(serv_out12_arr) / sizeof(serv_in12_arr[0])) -#define group(opcode) (((opcode) >> 5) & 7) +static const struct value_name_pair serv_in16_arr[] = { + {0x10, "Read capacity(16)"}, + {0x11, "Read long(16)"}, +}; +#define SERV_IN16_SZ \ + (int)(sizeof(serv_in16_arr) / sizeof(serv_in16_arr[0])) -#define RESERVED_GROUP 0 -#define VENDOR_GROUP 1 +static const struct value_name_pair serv_out16_arr[] = { + {0x11, "Write long(16)"}, + {0x1f, "Notify data transfer device(16)"}, +}; +#define SERV_OUT16_SZ \ + (int)(sizeof(serv_out16_arr) / sizeof(serv_in16_arr[0])) -static const char **commands[] = { - group_0_commands, group_1_commands, group_2_commands, - (const char **) RESERVED_GROUP, group_4_commands, - group_5_commands, (const char **) VENDOR_GROUP, - (const char **) VENDOR_GROUP +static const struct value_name_pair variable_length_arr[] = { + {0x1, "Rebuild(32)"}, + {0x2, "Regenerate(32)"}, + {0x3, "Xdread(32)"}, + {0x4, "Xdwrite(32)"}, + {0x5, "Xdwrite extended(32)"}, + {0x6, "Xpwrite(32)"}, + {0x7, "Xdwriteread(32)"}, + {0x8, "Xdwrite extended(64)"}, + {0x9, "Read(32)"}, + {0xa, "Verify(32)"}, + {0xb, "Write(32)"}, + {0xc, "Write an verify(32)"}, + {0xd, "Write same(32)"}, + {0x8801, "Format OSD"}, + {0x8802, "Create (osd)"}, + {0x8803, "List (osd)"}, + {0x8805, "Read (osd)"}, + {0x8806, "Write (osd)"}, + {0x8807, "Append (osd)"}, + {0x8808, "Flush (osd)"}, + {0x880a, "Remove (osd)"}, + {0x880b, "Create partition (osd)"}, + {0x880c, "Remove partition (osd)"}, + {0x880e, "Get attributes (osd)"}, + {0x880f, "Set attributes (osd)"}, + {0x8812, "Create and write (osd)"}, + {0x8815, "Create collection (osd)"}, + {0x8816, "Remove collection (osd)"}, + {0x8817, "List collection (osd)"}, + {0x8818, "Set key (osd)"}, + {0x8819, "Set master key (osd)"}, + {0x881a, "Flush collection (osd)"}, + {0x881b, "Flush partition (osd)"}, + {0x881c, "Flush OSD"}, + {0x8f7e, "Perform SCSI command (osd)"}, + {0x8f7f, "Perform task management function (osd)"}, }; +#define VARIABLE_LENGTH_SZ \ + (int)(sizeof(variable_length_arr) / sizeof(variable_length_arr[0])) -static const char reserved[] = "RESERVED"; -static const char vendor[] = "VENDOR SPECIFIC"; +static const char * get_sa_name(const struct value_name_pair * arr, + int arr_sz, int service_action) +{ + int k; -static void print_opcode(int opcode) { - const char **table = commands[ group(opcode) ]; - switch ((unsigned long) table) { - case RESERVED_GROUP: - printk("%s(0x%02x) ", reserved, opcode); - break; - case VENDOR_GROUP: - printk("%s(0x%02x) ", vendor, opcode); - break; - default: - if (table[opcode & 0x1f] != unknown) - printk("%s ",table[opcode & 0x1f]); - else - printk("%s(0x%02x) ", unknown, opcode); - break; - } + for (k = 0; k < arr_sz; ++k, ++arr) { + if (service_action == arr->value) + break; + } + return (k < arr_sz) ? arr->name : NULL; } -#else /* CONST & CONST_COMMAND */ -static void print_opcode(int opcode) { - printk("0x%02x ", opcode); + +/* attempt to guess cdb length if cdb_len==0 . No trailing linefeed. */ +static void print_opcode_name(unsigned char * cdbp, int cdb_len, + int start_of_line) +{ + int sa, len, cdb0; + const char * name; + const char * leadin = start_of_line ? KERN_INFO : ""; + + cdb0 = cdbp[0]; + switch(cdb0) { + case VARIABLE_LENGTH_CMD: + len = cdbp[7] + 8; + if (len < 10) { + printk("%sshort variable length command, " + "len=%d ext_len=%d", leadin, len, cdb_len); + break; + } + sa = (cdbp[8] << 8) + cdbp[9]; + name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa); + if (name) { + printk("%s%s", leadin, name); + if ((cdb_len > 0) && (len != cdb_len)) + printk(", in_cdb_len=%d, ext_len=%d", + len, cdb_len); + } else { + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); + if ((cdb_len > 0) && (len != cdb_len)) + printk(", in_cdb_len=%d, ext_len=%d", + len, cdb_len); + } + break; + case MAINTENANCE_IN: + sa = cdbp[1] & 0x1f; + name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa); + if (name) + printk("%s%s", leadin, name); + else + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); + break; + case MAINTENANCE_OUT: + sa = cdbp[1] & 0x1f; + name = get_sa_name(maint_out_arr, MAINT_OUT_SZ, sa); + if (name) + printk("%s%s", leadin, name); + else + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); + break; + case SERVICE_ACTION_IN_12: + sa = cdbp[1] & 0x1f; + name = get_sa_name(serv_in12_arr, SERV_IN12_SZ, sa); + if (name) + printk("%s%s", leadin, name); + else + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); + break; + case SERVICE_ACTION_OUT_12: + sa = cdbp[1] & 0x1f; + name = get_sa_name(serv_out12_arr, SERV_OUT12_SZ, sa); + if (name) + printk("%s%s", leadin, name); + else + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); + break; + case SERVICE_ACTION_IN_16: + sa = cdbp[1] & 0x1f; + name = get_sa_name(serv_in16_arr, SERV_IN16_SZ, sa); + if (name) + printk("%s%s", leadin, name); + else + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); + break; + case SERVICE_ACTION_OUT_16: + sa = cdbp[1] & 0x1f; + name = get_sa_name(serv_out16_arr, SERV_OUT16_SZ, sa); + if (name) + printk("%s%s", leadin, name); + else + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); + break; + default: + if (cdb0 < 0xc0) { + name = cdb_byte0_names[cdb0]; + if (name) + printk("%s%s", leadin, name); + else + printk("%scdb[0]=0x%x (reserved)", + leadin, cdb0); + } else + printk("%scdb[0]=0x%x (vendor)", leadin, cdb0); + break; + } +} + +#else /* ifndef CONFIG_SCSI_CONSTANTS */ + +static void print_opcode_name(unsigned char * cdbp, int cdb_len, + int start_of_line) +{ + int sa, len, cdb0; + const char * leadin = start_of_line ? KERN_INFO : ""; + + cdb0 = cdbp[0]; + switch(cdb0) { + case VARIABLE_LENGTH_CMD: + len = cdbp[7] + 8; + if (len < 10) { + printk("%sshort opcode=0x%x command, len=%d " + "ext_len=%d", leadin, cdb0, len, cdb_len); + break; + } + sa = (cdbp[8] << 8) + cdbp[9]; + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); + if (len != cdb_len) + printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len); + break; + case MAINTENANCE_IN: + case MAINTENANCE_OUT: + case SERVICE_ACTION_IN_12: + case SERVICE_ACTION_OUT_12: + case SERVICE_ACTION_IN_16: + case SERVICE_ACTION_OUT_16: + sa = cdbp[1] & 0x1f; + printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa); + break; + default: + if (cdb0 < 0xc0) + printk("%scdb[0]=0x%x", leadin, cdb0); + else + printk("%scdb[0]=0x%x (vendor)", leadin, cdb0); + break; + } } #endif -void __scsi_print_command (unsigned char *command) { - int i,s; - print_opcode(command[0]); - for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) - printk("%02x ", command[i]); - printk("\n"); +void __scsi_print_command(unsigned char *command) +{ + int k, len; + + print_opcode_name(command, 0, 1); + if (VARIABLE_LENGTH_CMD == command[0]) + len = command[7] + 8; + else + len = COMMAND_SIZE(command[0]); + /* print out all bytes in cdb */ + for (k = 0; k < len; ++k) + printk(" %02x", command[k]); + printk("\n"); +} +EXPORT_SYMBOL(__scsi_print_command); + +/* This function (perhaps with the addition of peripheral device type) + * is more approriate than __scsi_print_command(). Perhaps that static + * can be dropped later if it replaces the __scsi_print_command version. + */ +static void scsi_print_cdb(unsigned char *cdb, int cdb_len, int start_of_line) +{ + int k; + + print_opcode_name(cdb, cdb_len, start_of_line); + /* print out all bytes in cdb */ + printk(":"); + for (k = 0; k < cdb_len; ++k) + printk(" %02x", cdb[k]); + printk("\n"); } /** @@ -177,7 +382,7 @@ **/ void scsi_print_status(unsigned char scsi_status) { -#if (CONSTANTS & CONST_STATUS) +#ifdef CONFIG_SCSI_CONSTANTS const char * ccp; switch (scsi_status) { @@ -194,13 +399,14 @@ case 0x40: ccp = "Task Aborted"; break; default: ccp = "Unknown status"; } - printk("%s", ccp); + printk(KERN_INFO "%s", ccp); #else - printk("0x%0x", scsi_status); + printk(KERN_INFO "0x%0x", scsi_status); #endif } +EXPORT_SYMBOL(scsi_print_status); -#if (CONSTANTS & CONST_XSENSE) +#ifdef CONFIG_SCSI_CONSTANTS struct error_info { unsigned short code12; /* 0x0302 looks better than 0x03,0x02 */ @@ -253,6 +459,8 @@ {0x040C, "Logical unit not accessible, target port in unavailable " "state"}, {0x0410, "Logical unit not ready, auxiliary memory not accessible"}, + {0x0411, "Logical unit not ready, notify (enable spinup) required"}, + {0x0412, "Logical unit not ready, offline"}, {0x0500, "Logical unit does not respond to selection"}, @@ -300,7 +508,14 @@ {0x0D04, "Copy target device data underrun"}, {0x0D05, "Copy target device data overrun"}, + {0x0E00, "Invalid information unit"}, + {0x0E01, "Information unit too short"}, + {0x0E02, "Information unit too long"}, + {0x1000, "Id CRC or ECC error"}, + {0x1001, "Data block guard check failed"}, + {0x1002, "Data block application tag check failed"}, + {0x1003, "Data block reference tag check failed"}, {0x1100, "Unrecovered read error"}, {0x1101, "Read retries exhausted"}, @@ -407,8 +622,10 @@ {0x2400, "Invalid field in cdb"}, {0x2401, "CDB decryption error"}, - {0x2402, "Obsolete"}, - {0x2403, "Obsolete"}, + {0x2404, "Security audit value frozen"}, + {0x2405, "Security working key frozen"}, + {0x2406, "Nonce not unique"}, + {0x2407, "Nonce timestamp out of range"}, {0x2500, "Logical unit not supported"}, @@ -426,6 +643,8 @@ {0x260B, "Inline data length exceeded"}, {0x260C, "Invalid operation for copy source or destination"}, {0x260D, "Copy segment granularity violation"}, + {0x260E, "Invalid parameter while port is enabled"}, + {0x260F, "Invalid data-out buffer integrity"}, {0x2700, "Write protected"}, {0x2701, "Hardware write protected"}, @@ -455,6 +674,8 @@ {0x2A05, "Registrations preempted"}, {0x2A06, "Asymmetric access state changed"}, {0x2A07, "Implicit asymmetric access state transition failed"}, + {0x2A08, "Priority changed"}, + {0x2A09, "Capacity data has changed"}, {0x2B00, "Copy cannot execute since host cannot disconnect"}, @@ -468,6 +689,8 @@ {0x2C07, "Previous busy status"}, {0x2C08, "Previous task set full status"}, {0x2C09, "Previous reservation conflict status"}, + {0x2C0A, "Partition or collection contains user objects"}, + {0x2C0B, "Not reserved"}, {0x2D00, "Overwrite error on update in place"}, @@ -485,6 +708,8 @@ {0x3007, "Cleaning failure"}, {0x3008, "Cannot write - application code mismatch"}, {0x3009, "Current session not fixated for append"}, + {0x300A, "Cleaning request rejected"}, + {0x300C, "WORM medium, overwrite attempted"}, {0x3010, "Medium not formatted"}, {0x3100, "Medium format corrupted"}, @@ -503,6 +728,7 @@ {0x3502, "Enclosure services unavailable"}, {0x3503, "Enclosure services transfer failure"}, {0x3504, "Enclosure services transfer refused"}, + {0x3505, "Enclosure services checksum error"}, {0x3600, "Ribbon, ink, or toner failure"}, @@ -543,6 +769,7 @@ {0x3B14, "Medium magazine locked"}, {0x3B15, "Medium magazine unlocked"}, {0x3B16, "Mechanical positioning or changer error"}, + {0x3B17, "Read past end of user object"}, {0x3D00, "Invalid bits in identify message"}, @@ -570,14 +797,12 @@ {0x3F0F, "Echo buffer overwritten"}, {0x3F10, "Medium loadable"}, {0x3F11, "Medium auxiliary memory accessible"}, - -#if 0 - {0x40NN, "Ram failure"}, - {0x40NN, "Diagnostic failure on component nn"}, - {0x41NN, "Data path failure"}, - {0x42NN, "Power-on or self-test failure"}, -#endif - +/* + * {0x40NN, "Ram failure"}, + * {0x40NN, "Diagnostic failure on component nn"}, + * {0x41NN, "Data path failure"}, + * {0x42NN, "Power-on or self-test failure"}, + */ {0x4300, "Message error"}, {0x4400, "Internal target failure"}, @@ -592,6 +817,7 @@ {0x4703, "Information unit CRC error detected"}, {0x4704, "Asynchronous information protection error detected"}, {0x4705, "Protocol service CRC error"}, + {0x477f, "Some commands cleared by iSCSI Protocol event"}, {0x4800, "Initiator detected error message received"}, @@ -600,13 +826,17 @@ {0x4A00, "Command phase error"}, {0x4B00, "Data phase error"}, + {0x4B01, "Invalid target port transfer tag received"}, + {0x4B02, "Too much write data"}, + {0x4B03, "Ack/nak timeout"}, + {0x4B04, "Nak received"}, + {0x4B05, "Data offset error"}, + {0x4B06, "Initiator response timeout"}, {0x4C00, "Logical unit failed self-configuration"}, - -#if 0 - {0x4DNN, "Tagged overlapped commands (nn = queue tag)"}, -#endif - +/* + * {0x4DNN, "Tagged overlapped commands (nn = queue tag)"}, + */ {0x4E00, "Overlapped commands attempted"}, {0x5000, "Write append error"}, @@ -631,6 +861,7 @@ {0x5504, "Insufficient registration resources"}, {0x5505, "Insufficient access control resources"}, {0x5506, "Auxiliary memory out of space"}, + {0x5507, "Quota error"}, {0x5700, "Unable to recover table-of-contents"}, @@ -806,11 +1037,9 @@ {0x6F03, "Read of scrambled sector without authentication"}, {0x6F04, "Media region code is mismatched to logical unit region"}, {0x6F05, "Drive region must be permanent/region reset count error"}, - -#if 0 - {0x70NN, "Decompression exception short algorithm id of nn"}, -#endif - +/* + * {0x70NN, "Decompression exception short algorithm id of nn"}, + */ {0x7100, "Decompression exception long algorithm id"}, {0x7200, "Session fixation error"}, @@ -845,9 +1074,7 @@ {0x70,0x00,0xff,"Decompression exception short algorithm id of %x"}, {0, 0, 0, NULL} }; -#endif -#if (CONSTANTS & CONST_SENSE) /* description of the sense key values */ static const char *snstext[] = { "No Sense", /* 0: There is no sense information */ @@ -858,11 +1085,11 @@ "Hardware Error", /* 4: Controller or device failure */ "Illegal Request", /* 5: Error in request */ "Unit Attention", /* 6: Removable medium was changed, or - the target has been reset */ + the target has been reset, or ... */ "Data Protect", /* 7: Access to the data is blocked */ "Blank Check", /* 8: Reached unexpected written or unwritten region of the medium */ - "Vendor Specific", /* 9: Vendor specific */ + "Vendor Specific(9)", "Copy Aborted", /* A: COPY or COMPARE was aborted */ "Aborted Command", /* B: The target aborted the command */ "Equal", /* C: A SEARCH DATA command found data equal */ @@ -875,20 +1102,21 @@ /* Get sense key string or NULL if not available */ const char * scsi_sense_key_string(unsigned char key) { -#if (CONSTANTS & CONST_SENSE) +#ifdef CONFIG_SCSI_CONSTANTS if (key <= 0xE) return snstext[key]; #endif return NULL; } +EXPORT_SYMBOL(scsi_sense_key_string); /* - * Get extended sense key string or NULL if not available. - * This string may contain a %x and must be printed with ascq as arg. + * Get additional sense code string or NULL if not available. + * This string may contain a "%x" and should be printed with ascq as arg. */ const char * scsi_extd_sense_format(unsigned char asc, unsigned char ascq) { -#if (CONSTANTS & CONST_XSENSE) +#ifdef CONFIG_SCSI_CONSTANTS int i; unsigned short code = ((asc << 8) | ascq); @@ -903,18 +1131,27 @@ #endif return NULL; } +EXPORT_SYMBOL(scsi_extd_sense_format); -/* Print extended sense information */ +/* Print extended sense information; no leadin, no linefeed */ static void -scsi_show_extd_sense(unsigned char asc, unsigned char ascq) { +scsi_show_extd_sense(unsigned char asc, unsigned char ascq) +{ const char *extd_sense_fmt = scsi_extd_sense_format(asc, ascq); if (extd_sense_fmt) { - printk("Additional sense: "); - printk(extd_sense_fmt, ascq); - printk("\n"); + if (strstr(extd_sense_fmt, "%x")) { + printk("Additional sense: "); + printk(extd_sense_fmt, ascq); + } else + printk("Additional sense: %s", extd_sense_fmt); } else { - printk("ASC=%2x ASCQ=%2x\n", asc, ascq); + if (asc >= 0x80) + printk("<> ASC=0x%x ASCQ=0x%x", asc, ascq); + if (ascq >= 0x80) + printk("ASC=0x%x <> ASCQ=0x%x", asc, ascq); + else + printk("ASC=0x%x ASCQ=0x%x", asc, ascq); } } @@ -922,112 +1159,117 @@ static void print_sense_internal(const char *devclass, const unsigned char *sense_buffer, + int sense_len, struct request *req) { - int s, sense_class, valid, code, info; - const char *error = NULL; - unsigned char asc, ascq; + int k, num, res; + unsigned int info; + const char *error; const char *sense_txt; const char *name = req->rq_disk ? req->rq_disk->disk_name : devclass; + struct scsi_sense_hdr ssh; - sense_class = (sense_buffer[0] >> 4) & 0x07; - code = sense_buffer[0] & 0xf; - valid = sense_buffer[0] & 0x80; - - if (sense_class == 7) { /* extended sense data */ - s = sense_buffer[7] + 8; - if (s > SCSI_SENSE_BUFFERSIZE) - s = SCSI_SENSE_BUFFERSIZE; - - info = ((sense_buffer[3] << 24) | (sense_buffer[4] << 16) | - (sense_buffer[5] << 8) | sense_buffer[6]); - if (info || valid) { - printk("Info fld=0x%x", info); - if (!valid) /* info data not according to standard */ - printk(" (nonstd)"); - printk(", "); - } - if (sense_buffer[2] & 0x80) - printk( "FMK "); /* current command has read a filemark */ - if (sense_buffer[2] & 0x40) - printk( "EOM "); /* end-of-medium condition exists */ - if (sense_buffer[2] & 0x20) - printk( "ILI "); /* incorrect block length requested */ - - switch (code) { - case 0x0: - error = "Current"; /* error concerns current command */ - break; - case 0x1: - error = "Deferred"; /* error concerns some earlier command */ - /* e.g., an earlier write to disk cache succeeded, but - now the disk discovers that it cannot write the data */ - break; - default: - error = "Invalid"; + res = scsi_normalize_sense(sense_buffer, sense_len, &ssh); + if (0 == res) { + /* this may be SCSI-1 sense data */ + num = (sense_len < 32) ? sense_len : 32; + printk(KERN_INFO "Unrecognized sense data (in hex):"); + for (k = 0; k < num; ++k) { + if (0 == (k % 16)) { + printk("\n"); + printk(KERN_INFO " "); + } + printk("%02x ", sense_buffer[k]); } + printk("\n"); + return; + } - printk("%s ", error); + /* An example of deferred is when an earlier write to disk cache + * succeeded, but now the disk discovers that it cannot write the + * data to the magnetic media. + */ + error = scsi_sense_is_deferred(&ssh) ? + "<>" : "Current"; + printk(KERN_INFO "%s: %s", name, error); + if (ssh.response_code >= 0x72) + printk(" [descriptor]"); + + sense_txt = scsi_sense_key_string(ssh.sense_key); + if (sense_txt) + printk(": sense key: %s\n", sense_txt); + else + printk(": sense key=0x%x\n", ssh.sense_key); + printk(KERN_INFO " "); + scsi_show_extd_sense(ssh.asc, ssh.ascq); + printk("\n"); - sense_txt = scsi_sense_key_string(sense_buffer[2]); - if (sense_txt) - printk("%s: sense key %s\n", name, sense_txt); - else - printk("%s: sense = %2x %2x\n", name, - sense_buffer[0], sense_buffer[2]); + if (ssh.response_code < 0x72) { + /* only decode extras for "fixed" format now */ + char buff[80]; + int blen, fixed_valid; - asc = ascq = 0; - if (sense_buffer[7] + 7 >= 13) { - asc = sense_buffer[12]; - ascq = sense_buffer[13]; + fixed_valid = sense_buffer[0] & 0x80; + info = ((sense_buffer[3] << 24) | (sense_buffer[4] << 16) | + (sense_buffer[5] << 8) | sense_buffer[6]); + res = 0; + memset(buff, 0, sizeof(buff)); + blen = sizeof(buff) - 1; + if (fixed_valid) + res += snprintf(buff + res, blen - res, + "Info fld=0x%x", info); + if (sense_buffer[2] & 0x80) { + /* current command has read a filemark */ + if (res > 0) + res += snprintf(buff + res, blen - res, ", "); + res += snprintf(buff + res, blen - res, "FMK"); } - if (asc || ascq) - scsi_show_extd_sense(asc, ascq); - - } else { /* non-extended sense data */ - - /* - * Standard says: - * sense_buffer[0] & 0200 : address valid - * sense_buffer[0] & 0177 : vendor-specific error code - * sense_buffer[1] & 0340 : vendor-specific - * sense_buffer[1..3] : 21-bit logical block address - */ - - sense_txt = scsi_sense_key_string(sense_buffer[0]); - if (sense_txt) - printk("%s: old sense key %s\n", name, sense_txt); - else - printk("%s: sense = %2x %2x\n", name, - sense_buffer[0], sense_buffer[2]); - - printk("Non-extended sense class %d code 0x%0x\n", - sense_class, code); - s = 4; - } - -#if !(CONSTANTS & CONST_SENSE) - { - int i; - printk("Raw sense data:"); - for (i = 0; i < s; ++i) - printk("0x%02x ", sense_buffer[i]); - printk("\n"); + if (sense_buffer[2] & 0x40) { + /* end-of-medium condition exists */ + if (res > 0) + res += snprintf(buff + res, blen - res, ", "); + res += snprintf(buff + res, blen - res, "EOM"); + } + if (sense_buffer[2] & 0x20) { + /* incorrect block length requested */ + if (res > 0) + res += snprintf(buff + res, blen - res, ", "); + res += snprintf(buff + res, blen - res, "ILI"); + } + if (res > 0) + printk(KERN_INFO "%s\n", buff); + } else if (ssh.additional_length > 0) { + /* descriptor format with sense descriptors */ + num = 8 + ssh.additional_length; + num = (sense_len < num) ? sense_len : num; + printk(KERN_INFO "Descriptor sense data with sense " + "descriptors (in hex):"); + for (k = 0; k < num; ++k) { + if (0 == (k % 16)) { + printk("\n"); + printk(KERN_INFO " "); + } + printk("%02x ", sense_buffer[k]); + } + printk("\n"); } -#endif } void scsi_print_sense(const char *devclass, struct scsi_cmnd *cmd) { - print_sense_internal(devclass, cmd->sense_buffer, cmd->request); + print_sense_internal(devclass, cmd->sense_buffer, + SCSI_SENSE_BUFFERSIZE, cmd->request); } +EXPORT_SYMBOL(scsi_print_sense); void scsi_print_req_sense(const char *devclass, struct scsi_request *sreq) { - print_sense_internal(devclass, sreq->sr_sense_buffer, sreq->sr_request); + print_sense_internal(devclass, sreq->sr_sense_buffer, + SCSI_SENSE_BUFFERSIZE, sreq->sr_request); } +EXPORT_SYMBOL(scsi_print_req_sense); -#if (CONSTANTS & CONST_MSG) +#ifdef CONFIG_SCSI_CONSTANTS static const char *one_byte_msgs[] = { /* 0x00 */ "Command Complete", NULL, "Save Pointers", /* 0x03 */ "Restore Pointers", "Disconnect", "Initiator Error", @@ -1036,161 +1278,167 @@ /* 0x0c */ "Bus device reset", "Abort Tag", "Clear Queue", /* 0x0f */ "Initiate Recovery", "Release Recovery" }; - #define NO_ONE_BYTE_MSGS (sizeof(one_byte_msgs) / sizeof (const char *)) static const char *two_byte_msgs[] = { /* 0x20 */ "Simple Queue Tag", "Head of Queue Tag", "Ordered Queue Tag" /* 0x23 */ "Ignore Wide Residue" }; - #define NO_TWO_BYTE_MSGS (sizeof(two_byte_msgs) / sizeof (const char *)) static const char *extended_msgs[] = { /* 0x00 */ "Modify Data Pointer", "Synchronous Data Transfer Request", /* 0x02 */ "SCSI-I Extended Identify", "Wide Data Transfer Request" }; - #define NO_EXTENDED_MSGS (sizeof(two_byte_msgs) / sizeof (const char *)) -#endif /* (CONSTANTS & CONST_MSG) */ -int scsi_print_msg (const unsigned char *msg) { - int len = 0, i; - if (msg[0] == EXTENDED_MESSAGE) { - len = 3 + msg[1]; -#if (CONSTANTS & CONST_MSG) - if (msg[2] < NO_EXTENDED_MSGS) - printk ("%s ", extended_msgs[msg[2]]); - else - printk ("Extended Message, reserved code (0x%02x) ", (int) msg[2]); - switch (msg[2]) { - case EXTENDED_MODIFY_DATA_POINTER: - printk("pointer = %d", (int) (msg[3] << 24) | (msg[4] << 16) | - (msg[5] << 8) | msg[6]); - break; - case EXTENDED_SDTR: - printk("period = %d ns, offset = %d", (int) msg[3] * 4, (int) - msg[4]); - break; - case EXTENDED_WDTR: - printk("width = 2^%d bytes", msg[3]); - break; - default: - for (i = 2; i < len; ++i) - printk("%02x ", msg[i]); - } -#else - for (i = 0; i < len; ++i) - printk("%02x ", msg[i]); -#endif + +int scsi_print_msg (const unsigned char *msg) +{ + int len = 0, i; + if (msg[0] == EXTENDED_MESSAGE) { + len = 3 + msg[1]; + if (msg[2] < NO_EXTENDED_MSGS) + printk ("%s ", extended_msgs[msg[2]]); + else + printk ("Extended Message, reserved code (0x%02x) ", + (int) msg[2]); + switch (msg[2]) { + case EXTENDED_MODIFY_DATA_POINTER: + printk("pointer = %d", (int) (msg[3] << 24) | + (msg[4] << 16) | (msg[5] << 8) | msg[6]); + break; + case EXTENDED_SDTR: + printk("period = %d ns, offset = %d", + (int) msg[3] * 4, (int) msg[4]); + break; + case EXTENDED_WDTR: + printk("width = 2^%d bytes", msg[3]); + break; + default: + for (i = 2; i < len; ++i) + printk("%02x ", msg[i]); + } /* Identify */ - } else if (msg[0] & 0x80) { -#if (CONSTANTS & CONST_MSG) - printk("Identify disconnect %sallowed %s %d ", - (msg[0] & 0x40) ? "" : "not ", - (msg[0] & 0x20) ? "target routine" : "lun", - msg[0] & 0x7); -#else - printk("%02x ", msg[0]); -#endif - len = 1; + } else if (msg[0] & 0x80) { + printk("Identify disconnect %sallowed %s %d ", + (msg[0] & 0x40) ? "" : "not ", + (msg[0] & 0x20) ? "target routine" : "lun", + msg[0] & 0x7); + len = 1; /* Normal One byte */ - } else if (msg[0] < 0x1f) { -#if (CONSTANTS & CONST_MSG) - if (msg[0] < NO_ONE_BYTE_MSGS) - printk(one_byte_msgs[msg[0]]); - else - printk("reserved (%02x) ", msg[0]); -#else - printk("%02x ", msg[0]); -#endif - len = 1; + } else if (msg[0] < 0x1f) { + if (msg[0] < NO_ONE_BYTE_MSGS) + printk(one_byte_msgs[msg[0]]); + else + printk("reserved (%02x) ", msg[0]); + len = 1; /* Two byte */ - } else if (msg[0] <= 0x2f) { -#if (CONSTANTS & CONST_MSG) - if ((msg[0] - 0x20) < NO_TWO_BYTE_MSGS) - printk("%s %02x ", two_byte_msgs[msg[0] - 0x20], - msg[1]); - else - printk("reserved two byte (%02x %02x) ", - msg[0], msg[1]); -#else - printk("%02x %02x", msg[0], msg[1]); -#endif - len = 2; - } else -#if (CONSTANTS & CONST_MSG) - printk(reserved); -#else - printk("%02x ", msg[0]); -#endif - return len; + } else if (msg[0] <= 0x2f) { + if ((msg[0] - 0x20) < NO_TWO_BYTE_MSGS) + printk("%s %02x ", two_byte_msgs[msg[0] - 0x20], + msg[1]); + else + printk("reserved two byte (%02x %02x) ", + msg[0], msg[1]); + len = 2; + } else + printk("reserved"); + return len; } +EXPORT_SYMBOL(scsi_print_msg); -void scsi_print_command(struct scsi_cmnd *cmd) { - printk("scsi%d : destination target %d, lun %d\n", - cmd->device->host->host_no, - cmd->device->id, - cmd->device->lun); - printk(" command = "); - __scsi_print_command(cmd->cmnd); +#else /* ifndef CONFIG_SCSI_CONSTANTS */ + +int scsi_print_msg (const unsigned char *msg) +{ + int len = 0, i; + + if (msg[0] == EXTENDED_MESSAGE) { + len = 3 + msg[1]; + for (i = 0; i < len; ++i) + printk("%02x ", msg[i]); + /* Identify */ + } else if (msg[0] & 0x80) { + printk("%02x ", msg[0]); + len = 1; + /* Normal One byte */ + } else if (msg[0] < 0x1f) { + printk("%02x ", msg[0]); + len = 1; + /* Two byte */ + } else if (msg[0] <= 0x2f) { + printk("%02x %02x", msg[0], msg[1]); + len = 2; + } else + printk("%02x ", msg[0]); + return len; +} +EXPORT_SYMBOL(scsi_print_msg); +#endif /* ! CONFIG_SCSI_CONSTANTS */ + +void scsi_print_command(struct scsi_cmnd *cmd) +{ + /* Assume appended output (i.e. not at start of line) */ + printk("scsi%d : destination target %d, lun %d\n", + cmd->device->host->host_no, + cmd->device->id, + cmd->device->lun); + printk(KERN_INFO " command: "); + scsi_print_cdb(cmd->cmnd, cmd->cmd_len, 0); } +EXPORT_SYMBOL(scsi_print_command); + +#ifdef CONFIG_SCSI_CONSTANTS -#if (CONSTANTS & CONST_HOST) static const char * hostbyte_table[]={ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", -"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", NULL}; +"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY"}; +#define NUM_HOSTBYTE_STRS (sizeof(hostbyte_table) / sizeof(const char *)) void scsi_print_hostbyte(int scsiresult) -{ static int maxcode=0; - int i; - - if(!maxcode) { - for(i=0;hostbyte_table[i];i++) ; - maxcode=i-1; - } - printk("Hostbyte=0x%02x",host_byte(scsiresult)); - if(host_byte(scsiresult)>maxcode) { - printk("is invalid "); - return; - } - printk("(%s) ",hostbyte_table[host_byte(scsiresult)]); +{ + int hb = host_byte(scsiresult); + + printk("Hostbyte=0x%02x", hb); + if (hb < NUM_HOSTBYTE_STRS) + printk("(%s) ", hostbyte_table[hb]); + else + printk("is invalid "); } #else void scsi_print_hostbyte(int scsiresult) -{ printk("Hostbyte=0x%02x ",host_byte(scsiresult)); +{ + printk("Hostbyte=0x%02x ", host_byte(scsiresult)); } #endif -#if (CONSTANTS & CONST_DRIVER) +#ifdef CONFIG_SCSI_CONSTANTS + static const char * driverbyte_table[]={ "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR", -"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD",NULL }; +"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"}; +#define NUM_DRIVERBYTE_STRS (sizeof(driverbyte_table) / sizeof(const char *)) static const char * driversuggest_table[]={"SUGGEST_OK", "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE", -unknown,unknown,unknown, "SUGGEST_SENSE",NULL}; - +"SUGGEST_5", "SUGGEST_6", "SUGGEST_7", "SUGGEST_SENSE"}; +#define NUM_SUGGEST_STRS (sizeof(driversuggest_table) / sizeof(const char *)) void scsi_print_driverbyte(int scsiresult) -{ static int driver_max=0,suggest_max=0; - int i,dr=driver_byte(scsiresult)&DRIVER_MASK, - su=(driver_byte(scsiresult)&SUGGEST_MASK)>>4; - - if(!driver_max) { - for(i=0;driverbyte_table[i];i++) ; - driver_max=i; - for(i=0;driversuggest_table[i];i++) ; - suggest_max=i; - } - printk("Driverbyte=0x%02x",driver_byte(scsiresult)); - printk("(%s,%s) ", - dr> 4); + + printk("Driverbyte=0x%02x ", driver_byte(scsiresult)); + printk("(%s,%s) ", + (dr < NUM_DRIVERBYTE_STRS ? driverbyte_table[dr] : "invalid"), + (su < NUM_SUGGEST_STRS ? driversuggest_table[su] : "invalid")); } #else void scsi_print_driverbyte(int scsiresult) -{ printk("Driverbyte=0x%02x ",driver_byte(scsiresult)); +{ + printk("Driverbyte=0x%02x ", driver_byte(scsiresult)); } #endif diff -Nru a/drivers/scsi/dpt/dpti_ioctl.h b/drivers/scsi/dpt/dpti_ioctl.h --- a/drivers/scsi/dpt/dpti_ioctl.h 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/dpt/dpti_ioctl.h 2004-11-29 21:56:02 -08:00 @@ -3,7 +3,6 @@ ------------------- begin : Thu Sep 7 2000 copyright : (C) 2001 by Adaptec - email : deanna_bonds@adaptec.com See Documentation/scsi/dpti.txt for history, notes, license info and credits diff -Nru a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c --- a/drivers/scsi/dpt_i2o.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/dpt_i2o.c 2004-11-29 21:56:02 -08:00 @@ -3,7 +3,6 @@ ------------------- begin : Thu Sep 7 2000 copyright : (C) 2000 by Adaptec - email : deanna_bonds@adaptec.com July 30, 2001 First version being submitted for inclusion in the kernel. V2.4 diff -Nru a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h --- a/drivers/scsi/dpti.h 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/dpti.h 2004-11-29 21:56:02 -08:00 @@ -3,7 +3,6 @@ ------------------- begin : Thu Sep 7 2000 copyright : (C) 2001 by Adaptec - email : deanna_bonds@adaptec.com See Documentation/scsi/dpti.txt for history, notes, license info and credits diff -Nru a/drivers/scsi/eata.c b/drivers/scsi/eata.c --- a/drivers/scsi/eata.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/eata.c 2004-11-29 21:56:02 -08:00 @@ -505,28 +505,29 @@ static int eata2x_detect(struct scsi_host_template *); static int eata2x_release(struct Scsi_Host *); static int eata2x_queuecommand(struct scsi_cmnd *, - void (*done)(struct scsi_cmnd *)); + void (*done) (struct scsi_cmnd *)); static int eata2x_eh_abort(struct scsi_cmnd *); static int eata2x_eh_host_reset(struct scsi_cmnd *); static int eata2x_bios_param(struct scsi_device *, struct block_device *, - sector_t, int *); + sector_t, int *); static int eata2x_slave_configure(struct scsi_device *); static struct scsi_host_template driver_template = { - .name = "EATA/DMA 2.0x rev. 8.10.00 ", - .detect = eata2x_detect, - .release = eata2x_release, - .queuecommand = eata2x_queuecommand, - .eh_abort_handler = eata2x_eh_abort, - .eh_device_reset_handler = NULL, - .eh_bus_reset_handler = NULL, - .eh_host_reset_handler = eata2x_eh_host_reset, - .bios_param = eata2x_bios_param, - .slave_configure = eata2x_slave_configure, - .this_id = 7, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING - }; + .name = "EATA/DMA 2.0x rev. 8.10.00 ", + .detect = eata2x_detect, + .release = eata2x_release, + .queuecommand = eata2x_queuecommand, + .eh_abort_handler = eata2x_eh_abort, + .eh_device_reset_handler = NULL, + .eh_bus_reset_handler = NULL, + .eh_host_reset_handler = eata2x_eh_host_reset, + .bios_param = eata2x_bios_param, + .slave_configure = eata2x_slave_configure, + .this_id = 7, + .unchecked_isa_dma = 1, + .use_clustering = ENABLE_CLUSTERING +}; + #if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD) #error "Adjust your defines" #endif @@ -618,188 +619,224 @@ /* Board info structure */ struct eata_info { - u_int32_t data_len; /* Number of valid bytes after this field */ - u_int32_t sign; /* ASCII "EATA" signature */ + u_int32_t data_len; /* Number of valid bytes after this field */ + u_int32_t sign; /* ASCII "EATA" signature */ #if defined(__BIG_ENDIAN_BITFIELD) - unchar version:4, :4; - unchar haaval:1, ata:1, drqvld:1, dmasup:1, morsup:1, trnxfr:1, tarsup:1, - ocsena:1; + unchar version : 4, + : 4; + unchar haaval : 1, + ata : 1, + drqvld : 1, + dmasup : 1, + morsup : 1, + trnxfr : 1, + tarsup : 1, + ocsena : 1; #else - unchar :4, /* unused low nibble */ - version:4; /* EATA version, should be 0x1 */ - unchar ocsena:1, /* Overlap Command Support Enabled */ - tarsup:1, /* Target Mode Supported */ - trnxfr:1, /* Truncate Transfer Cmd NOT Necessary */ - morsup:1, /* More Supported */ - dmasup:1, /* DMA Supported */ - drqvld:1, /* DRQ Index (DRQX) is valid */ - ata:1, /* This is an ATA device */ - haaval:1; /* Host Adapter Address Valid */ -#endif - - ushort cp_pad_len; /* Number of pad bytes after cp_len */ - unchar host_addr[4]; /* Host Adapter SCSI ID for channels 3, 2, 1, 0 */ - u_int32_t cp_len; /* Number of valid bytes in cp */ - u_int32_t sp_len; /* Number of valid bytes in sp */ - ushort queue_size; /* Max number of cp that can be queued */ - ushort unused; - ushort scatt_size; /* Max number of entries in scatter/gather table */ + unchar : 4, /* unused low nibble */ + version : 4; /* EATA version, should be 0x1 */ + unchar ocsena : 1, /* Overlap Command Support Enabled */ + tarsup : 1, /* Target Mode Supported */ + trnxfr : 1, /* Truncate Transfer Cmd NOT Necessary */ + morsup : 1, /* More Supported */ + dmasup : 1, /* DMA Supported */ + drqvld : 1, /* DRQ Index (DRQX) is valid */ + ata : 1, /* This is an ATA device */ + haaval : 1; /* Host Adapter Address Valid */ +#endif + + ushort cp_pad_len; /* Number of pad bytes after cp_len */ + unchar host_addr[4]; /* Host Adapter SCSI ID for channels 3, 2, 1, 0 */ + u_int32_t cp_len; /* Number of valid bytes in cp */ + u_int32_t sp_len; /* Number of valid bytes in sp */ + ushort queue_size; /* Max number of cp that can be queued */ + ushort unused; + ushort scatt_size; /* Max number of entries in scatter/gather table */ #if defined(__BIG_ENDIAN_BITFIELD) - unchar drqx:2, second:1, irq_tr:1, irq:4; - unchar sync; - unchar :4, res1:1, large_sg:1, forcaddr:1, isaena:1; - unchar max_chan:3, max_id:5; - unchar max_lun; - unchar eisa:1, pci:1, idquest:1, m1:1, :4; + unchar drqx : 2, + second : 1, + irq_tr : 1, + irq : 4; + unchar sync; + unchar : 4, + res1 : 1, + large_sg : 1, + forcaddr : 1, + isaena : 1; + unchar max_chan : 3, + max_id : 5; + unchar max_lun; + unchar eisa : 1, + pci : 1, + idquest : 1, + m1 : 1, + : 4; #else - unchar irq:4, /* Interrupt Request assigned to this controller */ - irq_tr:1, /* 0 for edge triggered, 1 for level triggered */ - second:1, /* 1 if this is a secondary (not primary) controller */ - drqx:2; /* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */ - unchar sync; /* 1 if scsi target id 7...0 is running sync scsi */ - - /* Structure extension defined in EATA 2.0B */ - unchar isaena:1, /* ISA i/o addressing is disabled/enabled */ - forcaddr:1, /* Port address has been forced */ - large_sg:1, /* 1 if large SG lists are supported */ - res1:1, - :4; - unchar max_id:5, /* Max SCSI target ID number */ - max_chan:3; /* Max SCSI channel number on this board */ - - /* Structure extension defined in EATA 2.0C */ - unchar max_lun; /* Max SCSI LUN number */ - unchar :4, - m1:1, /* This is a PCI with an M1 chip installed */ - idquest:1, /* RAIDNUM returned is questionable */ - pci:1, /* This board is PCI */ - eisa:1; /* This board is EISA */ + unchar irq : 4, /* Interrupt Request assigned to this controller */ + irq_tr : 1, /* 0 for edge triggered, 1 for level triggered */ + second : 1, /* 1 if this is a secondary (not primary) controller */ + drqx : 2; /* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */ + unchar sync; /* 1 if scsi target id 7...0 is running sync scsi */ + + /* Structure extension defined in EATA 2.0B */ + unchar isaena : 1, /* ISA i/o addressing is disabled/enabled */ + forcaddr : 1, /* Port address has been forced */ + large_sg : 1, /* 1 if large SG lists are supported */ + res1 : 1, + : 4; + unchar max_id : 5, /* Max SCSI target ID number */ + max_chan : 3; /* Max SCSI channel number on this board */ + + /* Structure extension defined in EATA 2.0C */ + unchar max_lun; /* Max SCSI LUN number */ + unchar + : 4, + m1 : 1, /* This is a PCI with an M1 chip installed */ + idquest : 1, /* RAIDNUM returned is questionable */ + pci : 1, /* This board is PCI */ + eisa : 1; /* This board is EISA */ #endif - unchar raidnum; /* Uniquely identifies this HBA in a system */ - unchar notused; + unchar raidnum; /* Uniquely identifies this HBA in a system */ + unchar notused; - ushort ipad[247]; - }; + ushort ipad[247]; +}; /* Board config structure */ struct eata_config { - ushort len; /* Number of bytes following this field */ + ushort len; /* Number of bytes following this field */ #if defined(__BIG_ENDIAN_BITFIELD) - unchar :4, tarena:1, mdpena:1, ocena:1, edis:1; + unchar : 4, + tarena : 1, + mdpena : 1, + ocena : 1, + edis : 1; #else - unchar edis:1, /* Disable EATA interface after config command */ - ocena:1, /* Overlapped Commands Enabled */ - mdpena:1, /* Transfer all Modified Data Pointer Messages */ - tarena:1, /* Target Mode Enabled for this controller */ - :4; + unchar edis : 1, /* Disable EATA interface after config command */ + ocena : 1, /* Overlapped Commands Enabled */ + mdpena : 1, /* Transfer all Modified Data Pointer Messages */ + tarena : 1, /* Target Mode Enabled for this controller */ + : 4; #endif - - unchar cpad[511]; - }; + unchar cpad[511]; +}; /* Returned status packet structure */ struct mssp { - #if defined(__BIG_ENDIAN_BITFIELD) - unchar eoc:1, adapter_status:7; + unchar eoc : 1, + adapter_status : 7; #else - unchar adapter_status:7, /* State related to current command */ - eoc:1; /* End Of Command (1 = command completed) */ + unchar adapter_status : 7, /* State related to current command */ + eoc : 1; /* End Of Command (1 = command completed) */ #endif - - unchar target_status; /* SCSI status received after data transfer */ - unchar unused[2]; - u_int32_t inv_res_len; /* Number of bytes not transferred */ - u_int32_t cpp_index; /* Index of address set in cp */ - char mess[12]; - }; + unchar target_status; /* SCSI status received after data transfer */ + unchar unused[2]; + u_int32_t inv_res_len; /* Number of bytes not transferred */ + u_int32_t cpp_index; /* Index of address set in cp */ + char mess[12]; +}; struct sg_list { - unsigned int address; /* Segment Address */ - unsigned int num_bytes; /* Segment Length */ - }; + unsigned int address; /* Segment Address */ + unsigned int num_bytes; /* Segment Length */ +}; /* MailBox SCSI Command Packet */ struct mscp { - #if defined(__BIG_ENDIAN_BITFIELD) - unchar din:1, dout:1, interp:1, :1, sg:1, reqsen:1, init:1, sreset:1; - unchar sense_len; - unchar unused[3]; - unchar :7, fwnest:1; - unchar :5, hbaci:1, iat:1, phsunit:1; - unchar channel:3, target:5; - unchar one:1, dispri:1, luntar:1, lun:5; + unchar din : 1, + dout : 1, + interp : 1, + : 1, + sg : 1, + reqsen :1, + init : 1, + sreset : 1; + unchar sense_len; + unchar unused[3]; + unchar : 7, + fwnest : 1; + unchar : 5, + hbaci : 1, + iat : 1, + phsunit : 1; + unchar channel : 3, + target : 5; + unchar one : 1, + dispri : 1, + luntar : 1, + lun : 5; #else - unchar sreset:1, /* SCSI Bus Reset Signal should be asserted */ - init:1, /* Re-initialize controller and self test */ - reqsen:1, /* Transfer Request Sense Data to addr using DMA */ - sg:1, /* Use Scatter/Gather */ - :1, - interp:1, /* The controller interprets cp, not the target */ - dout:1, /* Direction of Transfer is Out (Host to Target) */ - din:1; /* Direction of Transfer is In (Target to Host) */ - unchar sense_len; /* Request Sense Length */ - unchar unused[3]; - unchar fwnest:1, /* Send command to a component of an Array Group */ - :7; - unchar phsunit:1, /* Send to Target Physical Unit (bypass RAID) */ - iat:1, /* Inhibit Address Translation */ - hbaci:1, /* Inhibit HBA Caching for this command */ - :5; - unchar target:5, /* SCSI target ID */ - channel:3; /* SCSI channel number */ - unchar lun:5, /* SCSI logical unit number */ - luntar:1, /* This cp is for Target (not LUN) */ - dispri:1, /* Disconnect Privilege granted */ - one:1; /* 1 */ -#endif - - unchar mess[3]; /* Massage to/from Target */ - unchar cdb[12]; /* Command Descriptor Block */ - u_int32_t data_len; /* If sg=0 Data Length, if sg=1 sglist length */ - u_int32_t cpp_index; /* Index of address to be returned in sp */ - u_int32_t data_address; /* If sg=0 Data Address, if sg=1 sglist address */ - u_int32_t sp_dma_addr; /* Address where sp is DMA'ed when cp completes */ - u_int32_t sense_addr; /* Address where Sense Data is DMA'ed on error */ - - /* Additional fields begin here. */ - struct scsi_cmnd *SCpnt; - - /* All the cp structure is zero filled by queuecommand except the - following CP_TAIL_SIZE bytes, initialized by detect */ - dma_addr_t cp_dma_addr; /* dma handle for this cp structure */ - struct sg_list *sglist; /* pointer to the allocated SG list */ - }; + unchar sreset :1, /* SCSI Bus Reset Signal should be asserted */ + init :1, /* Re-initialize controller and self test */ + reqsen :1, /* Transfer Request Sense Data to addr using DMA */ + sg :1, /* Use Scatter/Gather */ + :1, + interp :1, /* The controller interprets cp, not the target */ + dout :1, /* Direction of Transfer is Out (Host to Target) */ + din :1; /* Direction of Transfer is In (Target to Host) */ + unchar sense_len; /* Request Sense Length */ + unchar unused[3]; + unchar fwnest : 1, /* Send command to a component of an Array Group */ + : 7; + unchar phsunit : 1, /* Send to Target Physical Unit (bypass RAID) */ + iat : 1, /* Inhibit Address Translation */ + hbaci : 1, /* Inhibit HBA Caching for this command */ + : 5; + unchar target : 5, /* SCSI target ID */ + channel : 3; /* SCSI channel number */ + unchar lun : 5, /* SCSI logical unit number */ + luntar : 1, /* This cp is for Target (not LUN) */ + dispri : 1, /* Disconnect Privilege granted */ + one : 1; /* 1 */ +#endif + + unchar mess[3]; /* Massage to/from Target */ + unchar cdb[12]; /* Command Descriptor Block */ + u_int32_t data_len; /* If sg=0 Data Length, if sg=1 sglist length */ + u_int32_t cpp_index; /* Index of address to be returned in sp */ + u_int32_t data_address; /* If sg=0 Data Address, if sg=1 sglist address */ + u_int32_t sp_dma_addr; /* Address where sp is DMA'ed when cp completes */ + u_int32_t sense_addr; /* Address where Sense Data is DMA'ed on error */ + + /* Additional fields begin here. */ + struct scsi_cmnd *SCpnt; + + /* All the cp structure is zero filled by queuecommand except the + following CP_TAIL_SIZE bytes, initialized by detect */ + dma_addr_t cp_dma_addr; /* dma handle for this cp structure */ + struct sg_list *sglist; /* pointer to the allocated SG list */ +}; #define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t)) struct hostdata { - struct mscp cp[MAX_MAILBOXES]; /* Mailboxes for this board */ - unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */ - unsigned int last_cp_used; /* Index of last mailbox used */ - unsigned int iocount; /* Total i/o done for this board */ - int board_number; /* Number of this board */ - char board_name[16]; /* Name of this board */ - int in_reset; /* True if board is doing a reset */ - int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */ - int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If 1 redo i/o on target */ - unsigned int retries; /* Number of internal retries */ - unsigned long last_retried_pid; /* Pid of last retried command */ - unsigned char subversion; /* Bus type, either ISA or EISA/PCI */ - unsigned char protocol_rev; /* EATA 2.0 rev., 'A' or 'B' or 'C' */ - unsigned char is_pci; /* 1 is bus type is PCI */ - struct pci_dev *pdev; /* pdev for PCI bus, NULL otherwise */ - struct mssp *sp_cpu_addr; /* cpu addr for DMA buffer sp */ - dma_addr_t sp_dma_addr; /* dma handle for DMA buffer sp */ - struct mssp sp; /* Local copy of sp buffer */ - }; + struct mscp cp[MAX_MAILBOXES]; /* Mailboxes for this board */ + unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */ + unsigned int last_cp_used; /* Index of last mailbox used */ + unsigned int iocount; /* Total i/o done for this board */ + int board_number; /* Number of this board */ + char board_name[16]; /* Name of this board */ + int in_reset; /* True if board is doing a reset */ + int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */ + int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If 1 redo i/o on target */ + unsigned int retries; /* Number of internal retries */ + unsigned long last_retried_pid; /* Pid of last retried command */ + unsigned char subversion; /* Bus type, either ISA or EISA/PCI */ + unsigned char protocol_rev; /* EATA 2.0 rev., 'A' or 'B' or 'C' */ + unsigned char is_pci; /* 1 is bus type is PCI */ + struct pci_dev *pdev; /* pdev for PCI bus, NULL otherwise */ + struct mssp *sp_cpu_addr; /* cpu addr for DMA buffer sp */ + dma_addr_t sp_dma_addr; /* dma handle for DMA buffer sp */ + struct mssp sp; /* Local copy of sp buffer */ +}; -static struct Scsi_Host *sh[MAX_BOARDS + 1]; +static struct Scsi_Host *sh[MAX_BOARDS]; static const char *driver_name = "EATA"; static char sha[MAX_BOARDS]; static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; @@ -809,30 +846,27 @@ static unsigned long io_port[] = { - /* Space for MAX_INT_PARAM ports usable while loading as a module */ - SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, - SKIP, SKIP, - - /* First ISA */ - 0x1f0, - - /* Space for MAX_PCI ports possibly reported by PCI_BIOS */ - SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, - SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, - - /* MAX_EISA ports */ - 0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88, - 0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88, - - /* Other (MAX_ISA - 1) ports */ - 0x170, 0x230, 0x330, - - /* End of list */ - 0x0 - }; - -#define HD(board) ((struct hostdata *) &sh[board]->hostdata) -#define BN(board) (HD(board)->board_name) + /* Space for MAX_INT_PARAM ports usable while loading as a module */ + SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, + SKIP, SKIP, + + /* First ISA */ + 0x1f0, + + /* Space for MAX_PCI ports possibly reported by PCI_BIOS */ + SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, + SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, + + /* MAX_EISA ports */ + 0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88, + 0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88, + + /* Other (MAX_ISA - 1) ports */ + 0x170, 0x230, 0x330, + + /* End of list */ + 0x0 +}; /* Device is Big Endian */ #define H2DEV(x) cpu_to_be32(x) @@ -844,7 +878,8 @@ #define REG2H(x) le16_to_cpu(x) static irqreturn_t do_interrupt_handler(int, void *, struct pt_regs *); -static void flush_dev(struct scsi_device *, unsigned long, unsigned int, unsigned int); +static void flush_dev(struct scsi_device *, unsigned long, struct hostdata *, + unsigned int); static int do_trace = 0; static int setup_done = 0; static int link_statistics; @@ -896,1531 +931,1691 @@ #include module_param_string(eata, boot_options, MAX_BOOT_OPTIONS_SIZE, 0); -MODULE_PARM_DESC(eata, " equivalent to the \"eata=...\" kernel boot option." \ -" Example: modprobe eata \"eata=0x7410,0x230,lc:y,tm:0,mq:4,ep:n\""); +MODULE_PARM_DESC(eata, " equivalent to the \"eata=...\" kernel boot option." + " Example: modprobe eata \"eata=0x7410,0x230,lc:y,tm:0,mq:4,ep:n\""); MODULE_AUTHOR("Dario Ballabio"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("EATA/DMA SCSI Driver"); #endif -static int eata2x_slave_configure(struct scsi_device *dev) { - int j, tqd, utqd; - char *tag_suffix, *link_suffix; - struct Scsi_Host *host = dev->host; - - j = ((struct hostdata *) host->hostdata)->board_number; - - utqd = MAX_CMD_PER_LUN; - tqd = max_queue_depth; - - if (TLDEV(dev->type) && dev->tagged_supported) - - if (tag_mode == TAG_SIMPLE) { - scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd); - tag_suffix = ", simple tags"; - } - else if (tag_mode == TAG_ORDERED) { - scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, tqd); - tag_suffix = ", ordered tags"; - } - else { - scsi_adjust_queue_depth(dev, 0, tqd); - tag_suffix = ", no tags"; - } - - else if (TLDEV(dev->type) && linked_comm) { - scsi_adjust_queue_depth(dev, 0, tqd); - tag_suffix = ", untagged"; - } - - else { - scsi_adjust_queue_depth(dev, 0, utqd); - tag_suffix = ""; - } - - if (TLDEV(dev->type) && linked_comm && dev->queue_depth > 2) - link_suffix = ", sorted"; - else if (TLDEV(dev->type)) - link_suffix = ", unsorted"; - else - link_suffix = ""; - - printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n", - BN(j), host->host_no, dev->channel, dev->id, dev->lun, - dev->queue_depth, link_suffix, tag_suffix); - - return 0; -} - -static int wait_on_busy(unsigned long iobase, unsigned int loop) { - - while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED) { - udelay(1L); - if (--loop == 0) return 1; - } - - return 0; -} - -static int do_dma(unsigned long iobase, unsigned long addr, unchar cmd) { - unsigned char *byaddr; - unsigned long devaddr; +static int eata2x_slave_configure(struct scsi_device *dev) +{ + int tqd, utqd; + char *tag_suffix, *link_suffix; + struct Scsi_Host *shost = dev->host; + struct hostdata *ha = (struct hostdata *)shost->hostdata; + + utqd = MAX_CMD_PER_LUN; + tqd = max_queue_depth; + + if (TLDEV(dev->type) && dev->tagged_supported) { + if (tag_mode == TAG_SIMPLE) { + scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd); + tag_suffix = ", simple tags"; + } else if (tag_mode == TAG_ORDERED) { + scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, tqd); + tag_suffix = ", ordered tags"; + } else { + scsi_adjust_queue_depth(dev, 0, tqd); + tag_suffix = ", no tags"; + } + } else if (TLDEV(dev->type) && linked_comm) { + scsi_adjust_queue_depth(dev, 0, tqd); + tag_suffix = ", untagged"; + } else { + scsi_adjust_queue_depth(dev, 0, utqd); + tag_suffix = ""; + } + + if (TLDEV(dev->type) && linked_comm && dev->queue_depth > 2) + link_suffix = ", sorted"; + else if (TLDEV(dev->type)) + link_suffix = ", unsorted"; + else + link_suffix = ""; + + printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n", + ha->board_name, shost->host_no, dev->channel, dev->id, dev->lun, + dev->queue_depth, link_suffix, tag_suffix); + + return 0; +} + +static int wait_on_busy(unsigned long iobase, unsigned int loop) +{ + while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED) { + udelay(1L); + if (--loop == 0) + return 1; + } + return 0; +} + +static int do_dma(unsigned long iobase, unsigned long addr, unchar cmd) +{ + unsigned char *byaddr; + unsigned long devaddr; + + if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP))) + return 1; + + if (addr) { + devaddr = H2DEV(addr); + byaddr = (unsigned char *)&devaddr; + outb(byaddr[3], iobase + REG_LOW); + outb(byaddr[2], iobase + REG_LM); + outb(byaddr[1], iobase + REG_MID); + outb(byaddr[0], iobase + REG_MSB); + } + + outb(cmd, iobase + REG_CMD); + return 0; +} + +static int read_pio(unsigned long iobase, ushort * start, ushort * end) +{ + unsigned int loop = MAXLOOP; + ushort *p; + + for (p = start; p <= end; p++) { + while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) { + udelay(1L); + if (--loop == 0) + return 1; + } + loop = MAXLOOP; + *p = REG2H(inw(iobase)); + } - if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP))) return 1; - - if (addr) { - devaddr = H2DEV(addr); - byaddr = (unsigned char *) &devaddr; - outb(byaddr[3], iobase + REG_LOW); - outb(byaddr[2], iobase + REG_LM); - outb(byaddr[1], iobase + REG_MID); - outb(byaddr[0], iobase + REG_MSB); - } - - outb(cmd, iobase + REG_CMD); - return 0; + return 0; } -static int read_pio(unsigned long iobase, ushort *start, ushort *end) { - unsigned int loop = MAXLOOP; - ushort *p; - - for (p = start; p <= end; p++) { - - while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) { - udelay(1L); - if (--loop == 0) return 1; - } - - loop = MAXLOOP; - *p = REG2H(inw(iobase)); - } - - return 0; -} - -static struct pci_dev *get_pci_dev(unsigned long port_base) { - +static struct pci_dev *get_pci_dev(unsigned long port_base) +{ #if defined(CONFIG_PCI) + unsigned int addr; + struct pci_dev *dev = NULL; - unsigned int addr; - struct pci_dev *dev = NULL; - - while((dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) { - addr = pci_resource_start (dev, 0); + while ((dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) { + addr = pci_resource_start(dev, 0); #if defined(DEBUG_PCI_DETECT) - printk("%s: get_pci_dev, bus %d, devfn 0x%x, addr 0x%x.\n", - driver_name, dev->bus->number, dev->devfn, addr); + printk("%s: get_pci_dev, bus %d, devfn 0x%x, addr 0x%x.\n", + driver_name, dev->bus->number, dev->devfn, addr); #endif - /* we are in so much trouble for a pci hotplug system with this driver - * anyway, so doing this at least lets people unload the driver and not - * cause memory problems, but in general this is a bad thing to do (this - * driver needs to be converted to the proper PCI api someday... */ - pci_dev_put(dev); - if (addr + PCI_BASE_ADDRESS_0 == port_base) return dev; - } - -#endif /* end CONFIG_PCI */ - - return NULL; + /* we are in so much trouble for a pci hotplug system with this driver + * anyway, so doing this at least lets people unload the driver and not + * cause memory problems, but in general this is a bad thing to do (this + * driver needs to be converted to the proper PCI api someday... */ + pci_dev_put(dev); + if (addr + PCI_BASE_ADDRESS_0 == port_base) + return dev; + } +#endif /* end CONFIG_PCI */ + return NULL; } -static void enable_pci_ports(void) { - +static void enable_pci_ports(void) +{ #if defined(CONFIG_PCI) + struct pci_dev *dev = NULL; - struct pci_dev *dev = NULL; - - while((dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) { - + while ((dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) { #if defined(DEBUG_PCI_DETECT) - printk("%s: enable_pci_ports, bus %d, devfn 0x%x.\n", - driver_name, dev->bus->number, dev->devfn); + printk("%s: enable_pci_ports, bus %d, devfn 0x%x.\n", + driver_name, dev->bus->number, dev->devfn); #endif - if (pci_enable_device (dev)) - printk("%s: warning, pci_enable_device failed, bus %d devfn 0x%x.\n", - driver_name, dev->bus->number, dev->devfn); - } - -#endif /* end CONFIG_PCI */ -} - -static int port_detect \ - (unsigned long port_base, unsigned int j, struct scsi_host_template *tpnt) { - unsigned char irq, dma_channel, subversion, i, is_pci = 0; - unsigned char protocol_rev; - struct eata_info info; - char *bus_type, dma_name[16]; - struct pci_dev *pdev; - - /* Allowed DMA channels for ISA (0 indicates reserved) */ - unsigned char dma_channel_table[4] = { 5, 6, 7, 0 }; + if (pci_enable_device(dev)) + printk + ("%s: warning, pci_enable_device failed, bus %d devfn 0x%x.\n", + driver_name, dev->bus->number, dev->devfn); + } + +#endif /* end CONFIG_PCI */ +} + +static int port_detect(unsigned long port_base, unsigned int j, + struct scsi_host_template *tpnt) +{ + unsigned char irq, dma_channel, subversion, i, is_pci = 0; + unsigned char protocol_rev; + struct eata_info info; + char *bus_type, dma_name[16]; + struct pci_dev *pdev; + /* Allowed DMA channels for ISA (0 indicates reserved) */ + unsigned char dma_channel_table[4] = { 5, 6, 7, 0 }; + struct Scsi_Host *shost; + struct hostdata *ha; + char name[16]; - char name[16]; + sprintf(name, "%s%d", driver_name, j); - sprintf(name, "%s%d", driver_name, j); - - if (!request_region(port_base, REGION_SIZE, driver_name)) { + if (!request_region(port_base, REGION_SIZE, driver_name)) { #if defined(DEBUG_DETECT) - printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base); + printk("%s: address 0x%03lx in use, skipping probe.\n", name, + port_base); #endif - goto fail; - } + goto fail; + } - spin_lock_irq(&driver_lock); + spin_lock_irq(&driver_lock); - if (do_dma(port_base, 0, READ_CONFIG_PIO)) { + if (do_dma(port_base, 0, READ_CONFIG_PIO)) { #if defined(DEBUG_DETECT) - printk("%s: detect, do_dma failed at 0x%03lx.\n", name, port_base); + printk("%s: detect, do_dma failed at 0x%03lx.\n", name, + port_base); #endif - goto freelock; - } + goto freelock; + } - /* Read the info structure */ - if (read_pio(port_base, (ushort *)&info, (ushort *)&info.ipad[0])) { + /* Read the info structure */ + if (read_pio(port_base, (ushort *) & info, (ushort *) & info.ipad[0])) { #if defined(DEBUG_DETECT) - printk("%s: detect, read_pio failed at 0x%03lx.\n", name, port_base); + printk("%s: detect, read_pio failed at 0x%03lx.\n", name, + port_base); #endif - goto freelock; - } + goto freelock; + } - info.data_len = DEV2H(info.data_len); - info.sign = DEV2H(info.sign); - info.cp_pad_len = DEV2H16(info.cp_pad_len); - info.cp_len = DEV2H(info.cp_len); - info.sp_len = DEV2H(info.sp_len); - info.scatt_size = DEV2H16(info.scatt_size); - info.queue_size = DEV2H16(info.queue_size); + info.data_len = DEV2H(info.data_len); + info.sign = DEV2H(info.sign); + info.cp_pad_len = DEV2H16(info.cp_pad_len); + info.cp_len = DEV2H(info.cp_len); + info.sp_len = DEV2H(info.sp_len); + info.scatt_size = DEV2H16(info.scatt_size); + info.queue_size = DEV2H16(info.queue_size); - /* Check the controller "EATA" signature */ - if (info.sign != EATA_SIG_BE) { + /* Check the controller "EATA" signature */ + if (info.sign != EATA_SIG_BE) { #if defined(DEBUG_DETECT) - printk("%s: signature 0x%04x discarded.\n", name, info.sign); + printk("%s: signature 0x%04x discarded.\n", name, info.sign); #endif - goto freelock; - } - - if (info.data_len < EATA_2_0A_SIZE) { - printk("%s: config structure size (%d bytes) too short, detaching.\n", - name, info.data_len); - goto freelock; - } - else if (info.data_len == EATA_2_0A_SIZE) - protocol_rev = 'A'; - else if (info.data_len == EATA_2_0B_SIZE) - protocol_rev = 'B'; - else - protocol_rev = 'C'; - - if (protocol_rev != 'A' && info.forcaddr) { - printk("%s: warning, port address has been forced.\n", name); - bus_type = "PCI"; - is_pci = 1; - subversion = ESA; - } - else if (port_base > MAX_EISA_ADDR || (protocol_rev == 'C' && info.pci)) { - bus_type = "PCI"; - is_pci = 1; - subversion = ESA; - } - else if (port_base >= MIN_EISA_ADDR || (protocol_rev == 'C' && info.eisa)) { - bus_type = "EISA"; - subversion = ESA; - } - else if (protocol_rev == 'C' && !info.eisa && !info.pci) { - bus_type = "ISA"; - subversion = ISA; - } - else if (port_base > MAX_ISA_ADDR) { - bus_type = "PCI"; - is_pci = 1; - subversion = ESA; - } - else { - bus_type = "ISA"; - subversion = ISA; - } - - if (!info.haaval || info.ata) { - printk("%s: address 0x%03lx, unusable %s board (%d%d), detaching.\n", - name, port_base, bus_type, info.haaval, info.ata); - goto freelock; - } - - if (info.drqvld) { - - if (subversion == ESA) - printk("%s: warning, weird %s board using DMA.\n", name, bus_type); - - subversion = ISA; - dma_channel = dma_channel_table[3 - info.drqx]; - } - else { - - if (subversion == ISA) - printk("%s: warning, weird %s board not using DMA.\n", name, bus_type); - - subversion = ESA; - dma_channel = NO_DMA; - } - - if (!info.dmasup) - printk("%s: warning, DMA protocol support not asserted.\n", name); - - irq = info.irq; - - if (subversion == ESA && !info.irq_tr) - printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n", - name, irq); - - if (is_pci) { - pdev = get_pci_dev(port_base); - if (!pdev) - printk("%s: warning, failed to get pci_dev structure.\n", name); - } - else - pdev = NULL; - - if (pdev && (irq != pdev->irq)) { - printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, pdev->irq); - irq = pdev->irq; - } - - /* Board detected, allocate its IRQ */ - if (request_irq(irq, do_interrupt_handler, - SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0), - driver_name, (void *) &sha[j])) { - printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq); - goto freelock; - } - - if (subversion == ISA && request_dma(dma_channel, driver_name)) { - printk("%s: unable to allocate DMA channel %u, detaching.\n", - name, dma_channel); - goto freeirq; - } + goto freelock; + } + if (info.data_len < EATA_2_0A_SIZE) { + printk + ("%s: config structure size (%d bytes) too short, detaching.\n", + name, info.data_len); + goto freelock; + } else if (info.data_len == EATA_2_0A_SIZE) + protocol_rev = 'A'; + else if (info.data_len == EATA_2_0B_SIZE) + protocol_rev = 'B'; + else + protocol_rev = 'C'; + + if (protocol_rev != 'A' && info.forcaddr) { + printk("%s: warning, port address has been forced.\n", name); + bus_type = "PCI"; + is_pci = 1; + subversion = ESA; + } else if (port_base > MAX_EISA_ADDR + || (protocol_rev == 'C' && info.pci)) { + bus_type = "PCI"; + is_pci = 1; + subversion = ESA; + } else if (port_base >= MIN_EISA_ADDR + || (protocol_rev == 'C' && info.eisa)) { + bus_type = "EISA"; + subversion = ESA; + } else if (protocol_rev == 'C' && !info.eisa && !info.pci) { + bus_type = "ISA"; + subversion = ISA; + } else if (port_base > MAX_ISA_ADDR) { + bus_type = "PCI"; + is_pci = 1; + subversion = ESA; + } else { + bus_type = "ISA"; + subversion = ISA; + } + + if (!info.haaval || info.ata) { + printk + ("%s: address 0x%03lx, unusable %s board (%d%d), detaching.\n", + name, port_base, bus_type, info.haaval, info.ata); + goto freelock; + } + + if (info.drqvld) { + if (subversion == ESA) + printk("%s: warning, weird %s board using DMA.\n", name, + bus_type); + + subversion = ISA; + dma_channel = dma_channel_table[3 - info.drqx]; + } else { + if (subversion == ISA) + printk("%s: warning, weird %s board not using DMA.\n", + name, bus_type); + + subversion = ESA; + dma_channel = NO_DMA; + } + + if (!info.dmasup) + printk("%s: warning, DMA protocol support not asserted.\n", + name); + + irq = info.irq; + + if (subversion == ESA && !info.irq_tr) + printk + ("%s: warning, LEVEL triggering is suggested for IRQ %u.\n", + name, irq); + + if (is_pci) { + pdev = get_pci_dev(port_base); + if (!pdev) + printk + ("%s: warning, failed to get pci_dev structure.\n", + name); + } else + pdev = NULL; + + if (pdev && (irq != pdev->irq)) { + printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, + pdev->irq); + irq = pdev->irq; + } + + /* Board detected, allocate its IRQ */ + if (request_irq(irq, do_interrupt_handler, + SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0), + driver_name, (void *)&sha[j])) { + printk("%s: unable to allocate IRQ %u, detaching.\n", name, + irq); + goto freelock; + } + + if (subversion == ISA && request_dma(dma_channel, driver_name)) { + printk("%s: unable to allocate DMA channel %u, detaching.\n", + name, dma_channel); + goto freeirq; + } #if defined(FORCE_CONFIG) - { - struct eata_config *cf; - dma_addr_t cf_dma_addr; - - cf = pci_alloc_consistent(pdev, sizeof(struct eata_config), &cf_dma_addr); - - if (!cf) { - printk("%s: config, pci_alloc_consistent failed, detaching.\n", name); - goto freedma; - } - - /* Set board configuration */ - memset((char *)cf, 0, sizeof(struct eata_config)); - cf->len = (ushort) H2DEV16((ushort)510); - cf->ocena = 1; - - if (do_dma(port_base, cf_dma_addr, SET_CONFIG_DMA)) { - printk("%s: busy timeout sending configuration, detaching.\n", name); - pci_free_consistent(pdev, sizeof(struct eata_config), cf, cf_dma_addr); - goto freedma; - } - - } -#endif - - spin_unlock_irq(&driver_lock); - sh[j] = scsi_register(tpnt, sizeof(struct hostdata)); - spin_lock_irq(&driver_lock); - - if (sh[j] == NULL) { - printk("%s: unable to register host, detaching.\n", name); - goto freedma; - } - - sh[j]->io_port = port_base; - sh[j]->unique_id = port_base; - sh[j]->n_io_port = REGION_SIZE; - sh[j]->dma_channel = dma_channel; - sh[j]->irq = irq; - sh[j]->sg_tablesize = (ushort) info.scatt_size; - sh[j]->this_id = (ushort) info.host_addr[3]; - sh[j]->can_queue = (ushort) info.queue_size; - sh[j]->cmd_per_lun = MAX_CMD_PER_LUN; - memset(HD(j), 0, sizeof(struct hostdata)); - HD(j)->subversion = subversion; - HD(j)->protocol_rev = protocol_rev; - HD(j)->is_pci = is_pci; - HD(j)->pdev = pdev; - HD(j)->board_number = j; - - if (HD(j)->subversion == ESA) - sh[j]->unchecked_isa_dma = 0; - else { - unsigned long flags; - sh[j]->unchecked_isa_dma = 1; - - flags=claim_dma_lock(); - disable_dma(dma_channel); - clear_dma_ff(dma_channel); - set_dma_mode(dma_channel, DMA_MODE_CASCADE); - enable_dma(dma_channel); - release_dma_lock(flags); - - } - - strcpy(BN(j), name); - - /* DPT PM2012 does not allow to detect sg_tablesize correctly */ - if (sh[j]->sg_tablesize > MAX_SGLIST || sh[j]->sg_tablesize < 2) { - printk("%s: detect, wrong n. of SG lists %d, fixed.\n", - BN(j), sh[j]->sg_tablesize); - sh[j]->sg_tablesize = MAX_SGLIST; - } - - /* DPT PM2012 does not allow to detect can_queue correctly */ - if (sh[j]->can_queue > MAX_MAILBOXES || sh[j]->can_queue < 2) { - printk("%s: detect, wrong n. of mbox %d, fixed.\n", - BN(j), sh[j]->can_queue); - sh[j]->can_queue = MAX_MAILBOXES; - } - - if (protocol_rev != 'A') { - - if (info.max_chan > 0 && info.max_chan < MAX_CHANNEL) - sh[j]->max_channel = info.max_chan; - - if (info.max_id > 7 && info.max_id < MAX_TARGET) - sh[j]->max_id = info.max_id + 1; - - if (info.large_sg && sh[j]->sg_tablesize == MAX_SGLIST) - sh[j]->sg_tablesize = MAX_LARGE_SGLIST; - } - - if (protocol_rev == 'C') { - - if (info.max_lun > 7 && info.max_lun < MAX_LUN) - sh[j]->max_lun = info.max_lun + 1; - } - - if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST"); - else sprintf(dma_name, "DMA %u", dma_channel); - - spin_unlock_irq(&driver_lock); - - for (i = 0; i < sh[j]->can_queue; i++) - HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev, - &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); - - for (i = 0; i < sh[j]->can_queue; i++) - if (! ((&HD(j)->cp[i])->sglist = kmalloc( - sh[j]->sg_tablesize * sizeof(struct sg_list), - (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) { - printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i); - goto release; - } - - if (! (HD(j)->sp_cpu_addr = pci_alloc_consistent(HD(j)->pdev, - sizeof(struct mssp), &HD(j)->sp_dma_addr))) { - printk("%s: pci_alloc_consistent failed, detaching.\n", BN(j)); - goto release; - } - - if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN) - max_queue_depth = MAX_TAGGED_CMD_PER_LUN; - - if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN; - - if (tag_mode != TAG_DISABLED && tag_mode != TAG_SIMPLE) - tag_mode = TAG_ORDERED; - - if (j == 0) { - printk("EATA/DMA 2.0x: Copyright (C) 1994-2003 Dario Ballabio.\n"); - printk("%s config options -> tm:%d, lc:%c, mq:%d, rs:%c, et:%c, "\ - "ip:%c, ep:%c, pp:%c.\n", driver_name, tag_mode, - YESNO(linked_comm), max_queue_depth, YESNO(rev_scan), - YESNO(ext_tran), YESNO(isa_probe), YESNO(eisa_probe), - YESNO(pci_probe)); - } - - printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n", - BN(j), HD(j)->protocol_rev, bus_type, (unsigned long)sh[j]->io_port, - sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue); - - if (sh[j]->max_id > 8 || sh[j]->max_lun > 8) - printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n", - BN(j), sh[j]->max_id, sh[j]->max_lun); - - for (i = 0; i <= sh[j]->max_channel; i++) - printk("%s: SCSI channel %u enabled, host target ID %d.\n", - BN(j), i, info.host_addr[3 - i]); + { + struct eata_config *cf; + dma_addr_t cf_dma_addr; + + cf = pci_alloc_consistent(pdev, sizeof(struct eata_config), + &cf_dma_addr); + + if (!cf) { + printk + ("%s: config, pci_alloc_consistent failed, detaching.\n", + name); + goto freedma; + } + + /* Set board configuration */ + memset((char *)cf, 0, sizeof(struct eata_config)); + cf->len = (ushort) H2DEV16((ushort) 510); + cf->ocena = 1; + + if (do_dma(port_base, cf_dma_addr, SET_CONFIG_DMA)) { + printk + ("%s: busy timeout sending configuration, detaching.\n", + name); + pci_free_consistent(pdev, sizeof(struct eata_config), + cf, cf_dma_addr); + goto freedma; + } + + } +#endif + + spin_unlock_irq(&driver_lock); + sh[j] = shost = scsi_register(tpnt, sizeof(struct hostdata)); + spin_lock_irq(&driver_lock); + + if (shost == NULL) { + printk("%s: unable to register host, detaching.\n", name); + goto freedma; + } + + shost->io_port = port_base; + shost->unique_id = port_base; + shost->n_io_port = REGION_SIZE; + shost->dma_channel = dma_channel; + shost->irq = irq; + shost->sg_tablesize = (ushort) info.scatt_size; + shost->this_id = (ushort) info.host_addr[3]; + shost->can_queue = (ushort) info.queue_size; + shost->cmd_per_lun = MAX_CMD_PER_LUN; + + ha = (struct hostdata *)shost->hostdata; + + memset(ha, 0, sizeof(struct hostdata)); + ha->subversion = subversion; + ha->protocol_rev = protocol_rev; + ha->is_pci = is_pci; + ha->pdev = pdev; + ha->board_number = j; + + if (ha->subversion == ESA) + shost->unchecked_isa_dma = 0; + else { + unsigned long flags; + shost->unchecked_isa_dma = 1; + + flags = claim_dma_lock(); + disable_dma(dma_channel); + clear_dma_ff(dma_channel); + set_dma_mode(dma_channel, DMA_MODE_CASCADE); + enable_dma(dma_channel); + release_dma_lock(flags); + + } + + strcpy(ha->board_name, name); + + /* DPT PM2012 does not allow to detect sg_tablesize correctly */ + if (shost->sg_tablesize > MAX_SGLIST || shost->sg_tablesize < 2) { + printk("%s: detect, wrong n. of SG lists %d, fixed.\n", + ha->board_name, shost->sg_tablesize); + shost->sg_tablesize = MAX_SGLIST; + } + + /* DPT PM2012 does not allow to detect can_queue correctly */ + if (shost->can_queue > MAX_MAILBOXES || shost->can_queue < 2) { + printk("%s: detect, wrong n. of mbox %d, fixed.\n", + ha->board_name, shost->can_queue); + shost->can_queue = MAX_MAILBOXES; + } + + if (protocol_rev != 'A') { + if (info.max_chan > 0 && info.max_chan < MAX_CHANNEL) + shost->max_channel = info.max_chan; + + if (info.max_id > 7 && info.max_id < MAX_TARGET) + shost->max_id = info.max_id + 1; + + if (info.large_sg && shost->sg_tablesize == MAX_SGLIST) + shost->sg_tablesize = MAX_LARGE_SGLIST; + } + + if (protocol_rev == 'C') { + if (info.max_lun > 7 && info.max_lun < MAX_LUN) + shost->max_lun = info.max_lun + 1; + } + + if (dma_channel == NO_DMA) + sprintf(dma_name, "%s", "BMST"); + else + sprintf(dma_name, "DMA %u", dma_channel); + + spin_unlock_irq(&driver_lock); + + for (i = 0; i < shost->can_queue; i++) + ha->cp[i].cp_dma_addr = pci_map_single(ha->pdev, + &ha->cp[i], + sizeof(struct mscp), + PCI_DMA_BIDIRECTIONAL); + + for (i = 0; i < shost->can_queue; i++) { + size_t sz = shost->sg_tablesize *sizeof(struct sg_list); + unsigned int gfp_mask = (shost->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC; + ha->cp[i].sglist = kmalloc(sz, gfp_mask); + if (!ha->cp[i].sglist) { + printk + ("%s: kmalloc SGlist failed, mbox %d, detaching.\n", + ha->board_name, i); + goto release; + } + } + + if (!(ha->sp_cpu_addr = pci_alloc_consistent(ha->pdev, + sizeof(struct mssp), + &ha->sp_dma_addr))) { + printk("%s: pci_alloc_consistent failed, detaching.\n", ha->board_name); + goto release; + } + + if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN) + max_queue_depth = MAX_TAGGED_CMD_PER_LUN; + + if (max_queue_depth < MAX_CMD_PER_LUN) + max_queue_depth = MAX_CMD_PER_LUN; + + if (tag_mode != TAG_DISABLED && tag_mode != TAG_SIMPLE) + tag_mode = TAG_ORDERED; + + if (j == 0) { + printk + ("EATA/DMA 2.0x: Copyright (C) 1994-2003 Dario Ballabio.\n"); + printk + ("%s config options -> tm:%d, lc:%c, mq:%d, rs:%c, et:%c, " + "ip:%c, ep:%c, pp:%c.\n", driver_name, tag_mode, + YESNO(linked_comm), max_queue_depth, YESNO(rev_scan), + YESNO(ext_tran), YESNO(isa_probe), YESNO(eisa_probe), + YESNO(pci_probe)); + } + + printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n", + ha->board_name, ha->protocol_rev, bus_type, + (unsigned long)shost->io_port, shost->irq, dma_name, + shost->sg_tablesize, shost->can_queue); + + if (shost->max_id > 8 || shost->max_lun > 8) + printk + ("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n", + ha->board_name, shost->max_id, shost->max_lun); + + for (i = 0; i <= shost->max_channel; i++) + printk("%s: SCSI channel %u enabled, host target ID %d.\n", + ha->board_name, i, info.host_addr[3 - i]); #if defined(DEBUG_DETECT) - printk("%s: Vers. 0x%x, ocs %u, tar %u, trnxfr %u, more %u, SYNC 0x%x, "\ - "sec. %u, infol %d, cpl %d spl %d.\n", name, info.version, - info.ocsena, info.tarsup, info.trnxfr, info.morsup, info.sync, - info.second, info.data_len, info.cp_len, - info.sp_len); - - if (protocol_rev == 'B' || protocol_rev == 'C') - printk("%s: isaena %u, forcaddr %u, max_id %u, max_chan %u, "\ - "large_sg %u, res1 %u.\n", name, info.isaena, info.forcaddr, - info.max_id, info.max_chan, info.large_sg, info.res1); - - if (protocol_rev == 'C') - printk("%s: max_lun %u, m1 %u, idquest %u, pci %u, eisa %u, "\ - "raidnum %u.\n", name, info.max_lun, info.m1, info.idquest, - info.pci, info.eisa, info.raidnum); -#endif - - if (HD(j)->pdev) { - pci_set_master(HD(j)->pdev); - if (pci_set_dma_mask(HD(j)->pdev, 0xffffffff)) - printk("%s: warning, pci_set_dma_mask failed.\n", BN(j)); - } - - return 1; - -freedma: - if (subversion == ISA) free_dma(dma_channel); -freeirq: - free_irq(irq, &sha[j]); -freelock: - spin_unlock_irq(&driver_lock); - release_region(port_base, REGION_SIZE); -fail: - return 0; - -release: - eata2x_release(sh[j]); - return 0; -} - -static void internal_setup(char *str, int *ints) { - int i, argc = ints[0]; - char *cur = str, *pc; - - if (argc > 0) { - - if (argc > MAX_INT_PARAM) argc = MAX_INT_PARAM; - - for (i = 0; i < argc; i++) io_port[i] = ints[i + 1]; - - io_port[i] = 0; - setup_done = 1; - } - - while (cur && (pc = strchr(cur, ':'))) { - int val = 0, c = *++pc; - - if (c == 'n' || c == 'N') val = 0; - else if (c == 'y' || c == 'Y') val = 1; - else val = (int) simple_strtoul(pc, NULL, 0); - - if (!strncmp(cur, "lc:", 3)) linked_comm = val; - else if (!strncmp(cur, "tm:", 3)) tag_mode = val; - else if (!strncmp(cur, "tc:", 3)) tag_mode = val; - else if (!strncmp(cur, "mq:", 3)) max_queue_depth = val; - else if (!strncmp(cur, "ls:", 3)) link_statistics = val; - else if (!strncmp(cur, "et:", 3)) ext_tran = val; - else if (!strncmp(cur, "rs:", 3)) rev_scan = val; - else if (!strncmp(cur, "ip:", 3)) isa_probe = val; - else if (!strncmp(cur, "ep:", 3)) eisa_probe = val; - else if (!strncmp(cur, "pp:", 3)) pci_probe = val; - - if ((cur = strchr(cur, ','))) ++cur; - } - - return; -} - -static int option_setup(char *str) { - int ints[MAX_INT_PARAM]; - char *cur = str; - int i = 1; - - while (cur && isdigit(*cur) && i <= MAX_INT_PARAM) { - ints[i++] = simple_strtoul(cur, NULL, 0); - - if ((cur = strchr(cur, ',')) != NULL) cur++; - } - - ints[0] = i - 1; - internal_setup(cur, ints); - return 1; + printk("%s: Vers. 0x%x, ocs %u, tar %u, trnxfr %u, more %u, SYNC 0x%x, " + "sec. %u, infol %d, cpl %d spl %d.\n", name, info.version, + info.ocsena, info.tarsup, info.trnxfr, info.morsup, info.sync, + info.second, info.data_len, info.cp_len, info.sp_len); + + if (protocol_rev == 'B' || protocol_rev == 'C') + printk("%s: isaena %u, forcaddr %u, max_id %u, max_chan %u, " + "large_sg %u, res1 %u.\n", name, info.isaena, + info.forcaddr, info.max_id, info.max_chan, info.large_sg, + info.res1); + + if (protocol_rev == 'C') + printk("%s: max_lun %u, m1 %u, idquest %u, pci %u, eisa %u, " + "raidnum %u.\n", name, info.max_lun, info.m1, + info.idquest, info.pci, info.eisa, info.raidnum); +#endif + + if (ha->pdev) { + pci_set_master(ha->pdev); + if (pci_set_dma_mask(ha->pdev, 0xffffffff)) + printk("%s: warning, pci_set_dma_mask failed.\n", + ha->board_name); + } + + return 1; + + freedma: + if (subversion == ISA) + free_dma(dma_channel); + freeirq: + free_irq(irq, &sha[j]); + freelock: + spin_unlock_irq(&driver_lock); + release_region(port_base, REGION_SIZE); + fail: + return 0; + + release: + eata2x_release(shost); + return 0; +} + +static void internal_setup(char *str, int *ints) +{ + int i, argc = ints[0]; + char *cur = str, *pc; + + if (argc > 0) { + if (argc > MAX_INT_PARAM) + argc = MAX_INT_PARAM; + + for (i = 0; i < argc; i++) + io_port[i] = ints[i + 1]; + + io_port[i] = 0; + setup_done = 1; + } + + while (cur && (pc = strchr(cur, ':'))) { + int val = 0, c = *++pc; + + if (c == 'n' || c == 'N') + val = 0; + else if (c == 'y' || c == 'Y') + val = 1; + else + val = (int)simple_strtoul(pc, NULL, 0); + + if (!strncmp(cur, "lc:", 3)) + linked_comm = val; + else if (!strncmp(cur, "tm:", 3)) + tag_mode = val; + else if (!strncmp(cur, "tc:", 3)) + tag_mode = val; + else if (!strncmp(cur, "mq:", 3)) + max_queue_depth = val; + else if (!strncmp(cur, "ls:", 3)) + link_statistics = val; + else if (!strncmp(cur, "et:", 3)) + ext_tran = val; + else if (!strncmp(cur, "rs:", 3)) + rev_scan = val; + else if (!strncmp(cur, "ip:", 3)) + isa_probe = val; + else if (!strncmp(cur, "ep:", 3)) + eisa_probe = val; + else if (!strncmp(cur, "pp:", 3)) + pci_probe = val; + + if ((cur = strchr(cur, ','))) + ++cur; + } + + return; +} + +static int option_setup(char *str) +{ + int ints[MAX_INT_PARAM]; + char *cur = str; + int i = 1; + + while (cur && isdigit(*cur) && i <= MAX_INT_PARAM) { + ints[i++] = simple_strtoul(cur, NULL, 0); + + if ((cur = strchr(cur, ',')) != NULL) + cur++; + } + + ints[0] = i - 1; + internal_setup(cur, ints); + return 1; } -static void add_pci_ports(void) { - +static void add_pci_ports(void) +{ #if defined(CONFIG_PCI) + unsigned int addr, k; + struct pci_dev *dev = NULL; - unsigned int addr, k; - - struct pci_dev *dev = NULL; - - for (k = 0; k < MAX_PCI; k++) { - - if (!(dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) break; + for (k = 0; k < MAX_PCI; k++) { - if (pci_enable_device (dev)) { + if (!(dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) + break; + if (pci_enable_device(dev)) { #if defined(DEBUG_PCI_DETECT) - printk("%s: detect, bus %d, devfn 0x%x, pci_enable_device failed.\n", - driver_name, dev->bus->number, dev->devfn); + printk + ("%s: detect, bus %d, devfn 0x%x, pci_enable_device failed.\n", + driver_name, dev->bus->number, dev->devfn); #endif - continue; - } + continue; + } - addr = pci_resource_start (dev, 0); + addr = pci_resource_start(dev, 0); #if defined(DEBUG_PCI_DETECT) - printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n", - driver_name, k, dev->bus->number, dev->devfn, addr); + printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n", + driver_name, k, dev->bus->number, dev->devfn, addr); #endif - /* Order addresses according to rev_scan value */ - io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] = - addr + PCI_BASE_ADDRESS_0; - } + /* Order addresses according to rev_scan value */ + io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] = + addr + PCI_BASE_ADDRESS_0; + } - pci_dev_put(dev); -#endif /* end CONFIG_PCI */ - - return; + pci_dev_put(dev); +#endif /* end CONFIG_PCI */ } -static int eata2x_detect(struct scsi_host_template *tpnt) { - unsigned int j = 0, k; +static int eata2x_detect(struct scsi_host_template *tpnt) +{ + unsigned int j = 0, k; - tpnt->proc_name = "eata2x"; + tpnt->proc_name = "eata2x"; - if(strlen(boot_options)) option_setup(boot_options); + if (strlen(boot_options)) + option_setup(boot_options); #if defined(MODULE) - /* io_port could have been modified when loading as a module */ - if(io_port[0] != SKIP) { - setup_done = 1; - io_port[MAX_INT_PARAM] = 0; - } -#endif - - for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL; - - for (k = MAX_INT_PARAM; io_port[k]; k++) - if (io_port[k] == SKIP) continue; - else if (io_port[k] <= MAX_ISA_ADDR) { - if (!isa_probe) io_port[k] = SKIP; - } - else if (io_port[k] >= MIN_EISA_ADDR && io_port[k] <= MAX_EISA_ADDR) { - if (!eisa_probe) io_port[k] = SKIP; - } - - if (pci_probe) { - if (!setup_done) add_pci_ports(); - else enable_pci_ports(); - } - - for (k = 0; io_port[k]; k++) { - - if (io_port[k] == SKIP) continue; - - if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++; - } - - num_boards = j; - return j; -} - -static void map_dma(unsigned int i, unsigned int j) { - unsigned int k, count, pci_dir; - struct scatterlist *sgpnt; - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; - pci_dir = SCpnt->sc_data_direction; - - if (SCpnt->sense_buffer) - cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer, - sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE)); - - cpp->sense_len = sizeof SCpnt->sense_buffer; - - if (!SCpnt->use_sg) { + /* io_port could have been modified when loading as a module */ + if (io_port[0] != SKIP) { + setup_done = 1; + io_port[MAX_INT_PARAM] = 0; + } +#endif + + for (k = MAX_INT_PARAM; io_port[k]; k++) + if (io_port[k] == SKIP) + continue; + else if (io_port[k] <= MAX_ISA_ADDR) { + if (!isa_probe) + io_port[k] = SKIP; + } else if (io_port[k] >= MIN_EISA_ADDR + && io_port[k] <= MAX_EISA_ADDR) { + if (!eisa_probe) + io_port[k] = SKIP; + } + + if (pci_probe) { + if (!setup_done) + add_pci_ports(); + else + enable_pci_ports(); + } + + for (k = 0; io_port[k]; k++) { + + if (io_port[k] == SKIP) + continue; + + if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) + j++; + } + + num_boards = j; + return j; +} + +static void map_dma(unsigned int i, struct hostdata *ha) +{ + unsigned int k, count, pci_dir; + struct scatterlist *sgpnt; + struct mscp *cpp; + struct scsi_cmnd *SCpnt; + + cpp = &ha->cp[i]; + SCpnt = cpp->SCpnt; + pci_dir = SCpnt->sc_data_direction; + + if (SCpnt->sense_buffer) + cpp->sense_addr = + H2DEV(pci_map_single(ha->pdev, SCpnt->sense_buffer, + sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE)); + + cpp->sense_len = sizeof SCpnt->sense_buffer; + + if (!SCpnt->use_sg) { + + /* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */ + if (!SCpnt->request_bufflen) + pci_dir = PCI_DMA_BIDIRECTIONAL; + + if (SCpnt->request_buffer) + cpp->data_address = H2DEV(pci_map_single(ha->pdev, + SCpnt-> + request_buffer, + SCpnt-> + request_bufflen, + pci_dir)); + + cpp->data_len = H2DEV(SCpnt->request_bufflen); + return; + } + + sgpnt = (struct scatterlist *)SCpnt->request_buffer; + count = pci_map_sg(ha->pdev, sgpnt, SCpnt->use_sg, pci_dir); + + for (k = 0; k < count; k++) { + cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k])); + cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k])); + } + + cpp->sg = 1; + cpp->data_address = H2DEV(pci_map_single(ha->pdev, cpp->sglist, + SCpnt->use_sg * + sizeof(struct sg_list), + pci_dir)); + cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list))); +} + +static void unmap_dma(unsigned int i, struct hostdata *ha) +{ + unsigned int pci_dir; + struct mscp *cpp; + struct scsi_cmnd *SCpnt; + + cpp = &ha->cp[i]; + SCpnt = cpp->SCpnt; + pci_dir = SCpnt->sc_data_direction; + + if (DEV2H(cpp->sense_addr)) + pci_unmap_single(ha->pdev, DEV2H(cpp->sense_addr), + DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); + + if (SCpnt->use_sg) + pci_unmap_sg(ha->pdev, SCpnt->request_buffer, SCpnt->use_sg, + pci_dir); + + if (!DEV2H(cpp->data_len)) + pci_dir = PCI_DMA_BIDIRECTIONAL; + + if (DEV2H(cpp->data_address)) + pci_unmap_single(ha->pdev, DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); +} + +static void sync_dma(unsigned int i, struct hostdata *ha) +{ + unsigned int pci_dir; + struct mscp *cpp; + struct scsi_cmnd *SCpnt; + + cpp = &ha->cp[i]; + SCpnt = cpp->SCpnt; + pci_dir = SCpnt->sc_data_direction; + + if (DEV2H(cpp->sense_addr)) + pci_dma_sync_single_for_cpu(ha->pdev, DEV2H(cpp->sense_addr), + DEV2H(cpp->sense_len), + PCI_DMA_FROMDEVICE); + + if (SCpnt->use_sg) + pci_dma_sync_sg_for_cpu(ha->pdev, SCpnt->request_buffer, + SCpnt->use_sg, pci_dir); + + if (!DEV2H(cpp->data_len)) + pci_dir = PCI_DMA_BIDIRECTIONAL; + + if (DEV2H(cpp->data_address)) + pci_dma_sync_single_for_cpu(ha->pdev, + DEV2H(cpp->data_address), + DEV2H(cpp->data_len), pci_dir); +} + +static void scsi_to_dev_dir(unsigned int i, struct hostdata *ha) +{ + unsigned int k; + + static const unsigned char data_out_cmds[] = { + 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e, + 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40, + 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b, 0x5d + }; + + static const unsigned char data_none_cmds[] = { + 0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e, + 0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47, + 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00 + }; + + struct mscp *cpp; + struct scsi_cmnd *SCpnt; + + cpp = &ha->cp[i]; + SCpnt = cpp->SCpnt; + + if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) { + cpp->din = 1; + cpp->dout = 0; + return; + } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) { + cpp->din = 0; + cpp->dout = 1; + return; + } else if (SCpnt->sc_data_direction == DMA_NONE) { + cpp->din = 0; + cpp->dout = 0; + return; + } + + if (SCpnt->sc_data_direction != DMA_BIDIRECTIONAL) + panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", + ha->board_name); + + for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) + if (SCpnt->cmnd[0] == data_out_cmds[k]) { + cpp->dout = 1; + break; + } + + if ((cpp->din = !cpp->dout)) + for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) + if (SCpnt->cmnd[0] == data_none_cmds[k]) { + cpp->din = 0; + break; + } + +} + +static int eata2x_queuecommand(struct scsi_cmnd *SCpnt, + void (*done) (struct scsi_cmnd *)) +{ + struct Scsi_Host *shost = SCpnt->device->host; + struct hostdata *ha = (struct hostdata *)shost->hostdata; + unsigned int i, k; + struct mscp *cpp; + + if (SCpnt->host_scribble) + panic("%s: qcomm, pid %ld, SCpnt %p already active.\n", + ha->board_name, SCpnt->pid, SCpnt); + + /* i is the mailbox number, look for the first free mailbox + starting from last_cp_used */ + i = ha->last_cp_used + 1; + + for (k = 0; k < shost->can_queue; k++, i++) { + if (i >= shost->can_queue) + i = 0; + if (ha->cp_stat[i] == FREE) { + ha->last_cp_used = i; + break; + } + } + + if (k == shost->can_queue) { + printk("%s: qcomm, no free mailbox.\n", ha->board_name); + return 1; + } + + /* Set pointer to control packet structure */ + cpp = &ha->cp[i]; + + memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE); + + /* Set pointer to status packet structure, Big Endian format */ + cpp->sp_dma_addr = H2DEV(ha->sp_dma_addr); + + SCpnt->scsi_done = done; + cpp->cpp_index = i; + SCpnt->host_scribble = (unsigned char *)&cpp->cpp_index; + + if (do_trace) + printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n", + ha->board_name, i, SCpnt->device->channel, SCpnt->device->id, + SCpnt->device->lun, SCpnt->pid); - /* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */ - if (!SCpnt->request_bufflen) pci_dir = PCI_DMA_BIDIRECTIONAL; - - if (SCpnt->request_buffer) - cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, - SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir)); - - cpp->data_len = H2DEV(SCpnt->request_bufflen); - return; - } - - sgpnt = (struct scatterlist *) SCpnt->request_buffer; - count = pci_map_sg(HD(j)->pdev, sgpnt, SCpnt->use_sg, pci_dir); - - for (k = 0; k < count; k++) { - cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k])); - cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k])); - } - - cpp->sg = 1; - cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist, - SCpnt->use_sg * sizeof(struct sg_list), pci_dir)); - cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list))); -} - -static void unmap_dma(unsigned int i, unsigned int j) { - unsigned int pci_dir; - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; - pci_dir = SCpnt->sc_data_direction; - - if (DEV2H(cpp->sense_addr)) - pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr), - DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - - if (SCpnt->use_sg) - pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); - - if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; - - if (DEV2H(cpp->data_address)) - pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); -} - -static void sync_dma(unsigned int i, unsigned int j) { - unsigned int pci_dir; - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; - pci_dir = SCpnt->sc_data_direction; - - if (DEV2H(cpp->sense_addr)) - pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->sense_addr), - DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - - if (SCpnt->use_sg) - pci_dma_sync_sg_for_cpu(HD(j)->pdev, SCpnt->request_buffer, - SCpnt->use_sg, pci_dir); - - if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; - - if (DEV2H(cpp->data_address)) - pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); -} - -static void scsi_to_dev_dir(unsigned int i, unsigned int j) { - unsigned int k; - - static const unsigned char data_out_cmds[] = { - 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e, - 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40, - 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b, 0x5d - }; - - static const unsigned char data_none_cmds[] = { - 0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e, - 0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47, - 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00 - }; - - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; - - if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) { - cpp->din = 1; - cpp->dout = 0; - return; - } - else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) { - cpp->din = 0; - cpp->dout = 1; - return; - } - else if (SCpnt->sc_data_direction == DMA_NONE) { - cpp->din = 0; - cpp->dout = 0; - return; - } - - if (SCpnt->sc_data_direction != DMA_BIDIRECTIONAL) - panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j)); - - for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) - if (SCpnt->cmnd[0] == data_out_cmds[k]) { - cpp->dout = 1; - break; - } - - if ((cpp->din = !cpp->dout)) - for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) - if (SCpnt->cmnd[0] == data_none_cmds[k]) { - cpp->din = 0; - break; - } - -} - -static int eata2x_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { - unsigned int i, j, k; - struct mscp *cpp; - - /* j is the board number */ - j = ((struct hostdata *) SCpnt->device->host->hostdata)->board_number; - - if (SCpnt->host_scribble) - panic("%s: qcomm, pid %ld, SCpnt %p already active.\n", - BN(j), SCpnt->pid, SCpnt); - - /* i is the mailbox number, look for the first free mailbox - starting from last_cp_used */ - i = HD(j)->last_cp_used + 1; - - for (k = 0; k < sh[j]->can_queue; k++, i++) { - - if (i >= sh[j]->can_queue) i = 0; - - if (HD(j)->cp_stat[i] == FREE) { - HD(j)->last_cp_used = i; - break; - } - } - - if (k == sh[j]->can_queue) { - printk("%s: qcomm, no free mailbox.\n", BN(j)); - return 1; - } - - /* Set pointer to control packet structure */ - cpp = &HD(j)->cp[i]; - - memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE); - - /* Set pointer to status packet structure, Big Endian format */ - cpp->sp_dma_addr = H2DEV(HD(j)->sp_dma_addr); - - SCpnt->scsi_done = done; - cpp->cpp_index = i; - SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index; - - if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n", - BN(j), i, SCpnt->device->channel, SCpnt->device->id, - SCpnt->device->lun, SCpnt->pid); - - cpp->reqsen = 1; - cpp->dispri = 1; + cpp->reqsen = 1; + cpp->dispri = 1; #if 0 - if (SCpnt->device->type == TYPE_TAPE) cpp->hbaci = 1; + if (SCpnt->device->type == TYPE_TAPE) + cpp->hbaci = 1; #endif - cpp->one = 1; - cpp->channel = SCpnt->device->channel; - cpp->target = SCpnt->device->id; - cpp->lun = SCpnt->device->lun; - cpp->SCpnt = SCpnt; - memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len); - - /* Use data transfer direction SCpnt->sc_data_direction */ - scsi_to_dev_dir(i, j); - - /* Map DMA buffers and SG list */ - map_dma(i, j); - - if (linked_comm && SCpnt->device->queue_depth > 2 - && TLDEV(SCpnt->device->type)) { - HD(j)->cp_stat[i] = READY; - flush_dev(SCpnt->device, SCpnt->request->sector, j, 0); - return 0; - } - - /* Send control packet to the board */ - if (do_dma(sh[j]->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { - unmap_dma(i, j); - SCpnt->host_scribble = NULL; - printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n", - BN(j), SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun, SCpnt->pid); - return 1; - } - - HD(j)->cp_stat[i] = IN_USE; - return 0; -} - -static int eata2x_eh_abort(struct scsi_cmnd *SCarg) { - unsigned int i, j; - - j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number; - - if (SCarg->host_scribble == NULL) { - printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n", - BN(j), SCarg->device->channel, SCarg->device->id, SCarg->device->lun, SCarg->pid); - return SUCCESS; - } - - i = *(unsigned int *)SCarg->host_scribble; - printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n", - BN(j), i, SCarg->device->channel, SCarg->device->id, SCarg->device->lun, SCarg->pid); - - if (i >= sh[j]->can_queue) - panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j)); - - if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { - printk("%s: abort, timeout error.\n", BN(j)); - return FAILED; - } - - if (HD(j)->cp_stat[i] == FREE) { - printk("%s: abort, mbox %d is free.\n", BN(j), i); - return SUCCESS; - } - - if (HD(j)->cp_stat[i] == IN_USE) { - printk("%s: abort, mbox %d is in use.\n", BN(j), i); - - if (SCarg != HD(j)->cp[i].SCpnt) - panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n", - BN(j), i, SCarg, HD(j)->cp[i].SCpnt); - - if (inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED) - printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i); - - if (SCarg->eh_state == SCSI_STATE_TIMEOUT) { - unmap_dma(i, j); - SCarg->host_scribble = NULL; - HD(j)->cp_stat[i] = FREE; - printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n", - BN(j), i, SCarg->pid); - return SUCCESS; - } - - return FAILED; - } - - if (HD(j)->cp_stat[i] == IN_RESET) { - printk("%s: abort, mbox %d is in reset.\n", BN(j), i); - return FAILED; - } - - if (HD(j)->cp_stat[i] == LOCKED) { - printk("%s: abort, mbox %d is locked.\n", BN(j), i); - return SUCCESS; - } - - if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) { - unmap_dma(i, j); - SCarg->result = DID_ABORT << 16; - SCarg->host_scribble = NULL; - HD(j)->cp_stat[i] = FREE; - printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n", - BN(j), i, SCarg->pid); - SCarg->scsi_done(SCarg); - return SUCCESS; - } - - panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i); -} - -static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) { - unsigned int i, j, time, k, c, limit = 0; - int arg_done = 0; - struct scsi_cmnd *SCpnt; - - j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number; - printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n", - BN(j), SCarg->device->channel, SCarg->device->id, SCarg->device->lun, SCarg->pid); - - if (SCarg->host_scribble == NULL) - printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid); - - if (HD(j)->in_reset) { - printk("%s: reset, exit, already in reset.\n", BN(j)); - return FAILED; - } - - if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { - printk("%s: reset, exit, timeout error.\n", BN(j)); - return FAILED; - } - - HD(j)->retries = 0; - - for (c = 0; c <= sh[j]->max_channel; c++) - for (k = 0; k < sh[j]->max_id; k++) { - HD(j)->target_redo[k][c] = 1; - HD(j)->target_to[k][c] = 0; - } - - for (i = 0; i < sh[j]->can_queue; i++) { - - if (HD(j)->cp_stat[i] == FREE) continue; - - if (HD(j)->cp_stat[i] == LOCKED) { - HD(j)->cp_stat[i] = FREE; - printk("%s: reset, locked mbox %d forced free.\n", BN(j), i); - continue; - } - - if (!(SCpnt = HD(j)->cp[i].SCpnt)) - panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i); - - if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) { - HD(j)->cp_stat[i] = ABORTING; - printk("%s: reset, mbox %d aborting, pid %ld.\n", - BN(j), i, SCpnt->pid); - } - - else { - HD(j)->cp_stat[i] = IN_RESET; - printk("%s: reset, mbox %d in reset, pid %ld.\n", - BN(j), i, SCpnt->pid); - } - - if (SCpnt->host_scribble == NULL) - panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i); - - if (*(unsigned int *)SCpnt->host_scribble != i) - panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i); - - if (SCpnt->scsi_done == NULL) - panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i); - - if (SCpnt == SCarg) arg_done = 1; - } - - if (do_dma(sh[j]->io_port, 0, RESET_PIO)) { - printk("%s: reset, cannot reset, timeout error.\n", BN(j)); - return FAILED; - } + cpp->one = 1; + cpp->channel = SCpnt->device->channel; + cpp->target = SCpnt->device->id; + cpp->lun = SCpnt->device->lun; + cpp->SCpnt = SCpnt; + memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len); + + /* Use data transfer direction SCpnt->sc_data_direction */ + scsi_to_dev_dir(i, ha); + + /* Map DMA buffers and SG list */ + map_dma(i, ha); + + if (linked_comm && SCpnt->device->queue_depth > 2 + && TLDEV(SCpnt->device->type)) { + ha->cp_stat[i] = READY; + flush_dev(SCpnt->device, SCpnt->request->sector, ha, 0); + return 0; + } + + /* Send control packet to the board */ + if (do_dma(shost->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { + unmap_dma(i, ha); + SCpnt->host_scribble = NULL; + printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n", + ha->board_name, SCpnt->device->channel, SCpnt->device->id, + SCpnt->device->lun, SCpnt->pid); + return 1; + } + + ha->cp_stat[i] = IN_USE; + return 0; +} + +static int eata2x_eh_abort(struct scsi_cmnd *SCarg) +{ + struct Scsi_Host *shost = SCarg->device->host; + struct hostdata *ha = (struct hostdata *)shost->hostdata; + unsigned int i; + + if (SCarg->host_scribble == NULL) { + printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n", + ha->board_name, SCarg->device->channel, SCarg->device->id, + SCarg->device->lun, SCarg->pid); + return SUCCESS; + } + + i = *(unsigned int *)SCarg->host_scribble; + printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n", + ha->board_name, i, SCarg->device->channel, SCarg->device->id, + SCarg->device->lun, SCarg->pid); + + if (i >= shost->can_queue) + panic("%s: abort, invalid SCarg->host_scribble.\n", ha->board_name); + + if (wait_on_busy(shost->io_port, MAXLOOP)) { + printk("%s: abort, timeout error.\n", ha->board_name); + return FAILED; + } + + if (ha->cp_stat[i] == FREE) { + printk("%s: abort, mbox %d is free.\n", ha->board_name, i); + return SUCCESS; + } + + if (ha->cp_stat[i] == IN_USE) { + printk("%s: abort, mbox %d is in use.\n", ha->board_name, i); + + if (SCarg != ha->cp[i].SCpnt) + panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n", + ha->board_name, i, SCarg, ha->cp[i].SCpnt); + + if (inb(shost->io_port + REG_AUX_STATUS) & IRQ_ASSERTED) + printk("%s: abort, mbox %d, interrupt pending.\n", + ha->board_name, i); + + if (SCarg->eh_state == SCSI_STATE_TIMEOUT) { + unmap_dma(i, ha); + SCarg->host_scribble = NULL; + ha->cp_stat[i] = FREE; + printk + ("%s, abort, mbox %d, eh_state timeout, pid %ld.\n", + ha->board_name, i, SCarg->pid); + return SUCCESS; + } + + return FAILED; + } + + if (ha->cp_stat[i] == IN_RESET) { + printk("%s: abort, mbox %d is in reset.\n", ha->board_name, i); + return FAILED; + } + + if (ha->cp_stat[i] == LOCKED) { + printk("%s: abort, mbox %d is locked.\n", ha->board_name, i); + return SUCCESS; + } + + if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) { + unmap_dma(i, ha); + SCarg->result = DID_ABORT << 16; + SCarg->host_scribble = NULL; + ha->cp_stat[i] = FREE; + printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n", + ha->board_name, i, SCarg->pid); + SCarg->scsi_done(SCarg); + return SUCCESS; + } + + panic("%s: abort, mbox %d, invalid cp_stat.\n", ha->board_name, i); +} + +static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) +{ + unsigned int i, time, k, c, limit = 0; + int arg_done = 0; + struct scsi_cmnd *SCpnt; + struct Scsi_Host *shost = SCarg->device->host; + struct hostdata *ha = (struct hostdata *)shost->hostdata; + + printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n", + ha->board_name, SCarg->device->channel, SCarg->device->id, + SCarg->device->lun, SCarg->pid); + + if (SCarg->host_scribble == NULL) + printk("%s: reset, pid %ld inactive.\n", ha->board_name, SCarg->pid); + + if (ha->in_reset) { + printk("%s: reset, exit, already in reset.\n", ha->board_name); + return FAILED; + } + + if (wait_on_busy(shost->io_port, MAXLOOP)) { + printk("%s: reset, exit, timeout error.\n", ha->board_name); + return FAILED; + } + + ha->retries = 0; + + for (c = 0; c <= shost->max_channel; c++) + for (k = 0; k < shost->max_id; k++) { + ha->target_redo[k][c] = 1; + ha->target_to[k][c] = 0; + } + + for (i = 0; i < shost->can_queue; i++) { + + if (ha->cp_stat[i] == FREE) + continue; + + if (ha->cp_stat[i] == LOCKED) { + ha->cp_stat[i] = FREE; + printk("%s: reset, locked mbox %d forced free.\n", + ha->board_name, i); + continue; + } + + if (!(SCpnt = ha->cp[i].SCpnt)) + panic("%s: reset, mbox %d, SCpnt == NULL.\n", ha->board_name, i); + + if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) { + ha->cp_stat[i] = ABORTING; + printk("%s: reset, mbox %d aborting, pid %ld.\n", + ha->board_name, i, SCpnt->pid); + } + + else { + ha->cp_stat[i] = IN_RESET; + printk("%s: reset, mbox %d in reset, pid %ld.\n", + ha->board_name, i, SCpnt->pid); + } + + if (SCpnt->host_scribble == NULL) + panic("%s: reset, mbox %d, garbled SCpnt.\n", ha->board_name, i); + + if (*(unsigned int *)SCpnt->host_scribble != i) + panic("%s: reset, mbox %d, index mismatch.\n", ha->board_name, i); + + if (SCpnt->scsi_done == NULL) + panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", + ha->board_name, i); + + if (SCpnt == SCarg) + arg_done = 1; + } + + if (do_dma(shost->io_port, 0, RESET_PIO)) { + printk("%s: reset, cannot reset, timeout error.\n", ha->board_name); + return FAILED; + } - printk("%s: reset, board reset done, enabling interrupts.\n", BN(j)); + printk("%s: reset, board reset done, enabling interrupts.\n", ha->board_name); #if defined(DEBUG_RESET) - do_trace = 1; + do_trace = 1; #endif - HD(j)->in_reset = 1; + ha->in_reset = 1; - spin_unlock_irq(sh[j]->host_lock); - time = jiffies; - while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L); - spin_lock_irq(sh[j]->host_lock); + spin_unlock_irq(shost->host_lock); + time = jiffies; + while ((jiffies - time) < (10 * HZ) && limit++ < 200000) + udelay(100L); + spin_lock_irq(shost->host_lock); - printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit); + printk("%s: reset, interrupts disabled, loops %d.\n", ha->board_name, limit); - for (i = 0; i < sh[j]->can_queue; i++) { + for (i = 0; i < shost->can_queue; i++) { - if (HD(j)->cp_stat[i] == IN_RESET) { - SCpnt = HD(j)->cp[i].SCpnt; - unmap_dma(i, j); - SCpnt->result = DID_RESET << 16; - SCpnt->host_scribble = NULL; + if (ha->cp_stat[i] == IN_RESET) { + SCpnt = ha->cp[i].SCpnt; + unmap_dma(i, ha); + SCpnt->result = DID_RESET << 16; + SCpnt->host_scribble = NULL; - /* This mailbox is still waiting for its interrupt */ - HD(j)->cp_stat[i] = LOCKED; + /* This mailbox is still waiting for its interrupt */ + ha->cp_stat[i] = LOCKED; - printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n", - BN(j), i, SCpnt->pid); - } + printk + ("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n", + ha->board_name, i, SCpnt->pid); + } - else if (HD(j)->cp_stat[i] == ABORTING) { - SCpnt = HD(j)->cp[i].SCpnt; - unmap_dma(i, j); - SCpnt->result = DID_RESET << 16; - SCpnt->host_scribble = NULL; + else if (ha->cp_stat[i] == ABORTING) { + SCpnt = ha->cp[i].SCpnt; + unmap_dma(i, ha); + SCpnt->result = DID_RESET << 16; + SCpnt->host_scribble = NULL; - /* This mailbox was never queued to the adapter */ - HD(j)->cp_stat[i] = FREE; + /* This mailbox was never queued to the adapter */ + ha->cp_stat[i] = FREE; - printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n", - BN(j), i, SCpnt->pid); - } + printk + ("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n", + ha->board_name, i, SCpnt->pid); + } - else + else + /* Any other mailbox has already been set free by interrupt */ + continue; - /* Any other mailbox has already been set free by interrupt */ - continue; + SCpnt->scsi_done(SCpnt); + } - SCpnt->scsi_done(SCpnt); - } + ha->in_reset = 0; + do_trace = 0; - HD(j)->in_reset = 0; - do_trace = 0; + if (arg_done) + printk("%s: reset, exit, pid %ld done.\n", ha->board_name, SCarg->pid); + else + printk("%s: reset, exit.\n", ha->board_name); - if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->pid); - else printk("%s: reset, exit.\n", BN(j)); - - return SUCCESS; + return SUCCESS; } int eata2x_bios_param(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int *dkinfo) { - unsigned int size = capacity; - - if (ext_tran || (scsicam_bios_param(bdev, capacity, dkinfo) < 0)) { - dkinfo[0] = 255; - dkinfo[1] = 63; - dkinfo[2] = size / (dkinfo[0] * dkinfo[1]); - } - + sector_t capacity, int *dkinfo) +{ + unsigned int size = capacity; + + if (ext_tran || (scsicam_bios_param(bdev, capacity, dkinfo) < 0)) { + dkinfo[0] = 255; + dkinfo[1] = 63; + dkinfo[2] = size / (dkinfo[0] * dkinfo[1]); + } #if defined (DEBUG_GEOMETRY) - printk ("%s: bios_param, head=%d, sec=%d, cyl=%d.\n", driver_name, - dkinfo[0], dkinfo[1], dkinfo[2]); + printk("%s: bios_param, head=%d, sec=%d, cyl=%d.\n", driver_name, + dkinfo[0], dkinfo[1], dkinfo[2]); #endif - return 0; + return 0; } static void sort(unsigned long sk[], unsigned int da[], unsigned int n, - unsigned int rev) { - unsigned int i, j, k, y; - unsigned long x; - - for (i = 0; i < n - 1; i++) { - k = i; - - for (j = k + 1; j < n; j++) - if (rev) { - if (sk[j] > sk[k]) k = j; - } - else { - if (sk[j] < sk[k]) k = j; - } - - if (k != i) { - x = sk[k]; sk[k] = sk[i]; sk[i] = x; - y = da[k]; da[k] = da[i]; da[i] = y; - } - } - - return; - } - -static int reorder(unsigned int j, unsigned long cursec, - unsigned int ihdlr, unsigned int il[], unsigned int n_ready) { - struct scsi_cmnd *SCpnt; - struct mscp *cpp; - unsigned int k, n; - unsigned int rev = 0, s = 1, r = 1; - unsigned int input_only = 1, overlap = 0; - unsigned long sl[n_ready], pl[n_ready], ll[n_ready]; - unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0; - unsigned long ioseek = 0; - - static unsigned int flushcount = 0, batchcount = 0, sortcount = 0; - static unsigned int readycount = 0, ovlcount = 0, inputcount = 0; - static unsigned int readysorted = 0, revcount = 0; - static unsigned long seeksorted = 0, seeknosort = 0; - - if (link_statistics && !(++flushcount % link_statistics)) - printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\ - " av %ldK as %ldK.\n", flushcount, batchcount, inputcount, - ovlcount, readycount, readysorted, sortcount, revcount, - seeknosort / (readycount + 1), - seeksorted / (readycount + 1)); - - if (n_ready <= 1) return 0; - - for (n = 0; n < n_ready; n++) { - k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - - if (!cpp->din) input_only = 0; - - if (SCpnt->request->sector < minsec) minsec = SCpnt->request->sector; - if (SCpnt->request->sector > maxsec) maxsec = SCpnt->request->sector; - - sl[n] = SCpnt->request->sector; - ioseek += SCpnt->request->nr_sectors; - - if (!n) continue; - - if (sl[n] < sl[n - 1]) s = 0; - if (sl[n] > sl[n - 1]) r = 0; - - if (link_statistics) { - if (sl[n] > sl[n - 1]) - seek += sl[n] - sl[n - 1]; - else - seek += sl[n - 1] - sl[n]; - } - - } - - if (link_statistics) { - if (cursec > sl[0]) seek += cursec - sl[0]; else seek += sl[0] - cursec; - } - - if (cursec > ((maxsec + minsec) / 2)) rev = 1; - - if (ioseek > ((maxsec - minsec) / 2)) rev = 0; - - if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev); - - if (!input_only) for (n = 0; n < n_ready; n++) { - k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->pid; - - if (!n) continue; - - if ((sl[n] == sl[n - 1]) || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n])) - || (rev && ((sl[n] + ll[n]) > sl[n - 1]))) overlap = 1; - } - - if (overlap) sort(pl, il, n_ready, 0); - - if (link_statistics) { - if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec; - batchcount++; readycount += n_ready; seeknosort += seek / 1024; - if (input_only) inputcount++; - if (overlap) { ovlcount++; seeksorted += iseek / 1024; } - else seeksorted += (iseek + maxsec - minsec) / 1024; - if (rev && !r) { revcount++; readysorted += n_ready; } - if (!rev && !s) { sortcount++; readysorted += n_ready; } - } - + unsigned int rev) +{ + unsigned int i, j, k, y; + unsigned long x; + + for (i = 0; i < n - 1; i++) { + k = i; + + for (j = k + 1; j < n; j++) + if (rev) { + if (sk[j] > sk[k]) + k = j; + } else { + if (sk[j] < sk[k]) + k = j; + } + + if (k != i) { + x = sk[k]; + sk[k] = sk[i]; + sk[i] = x; + y = da[k]; + da[k] = da[i]; + da[i] = y; + } + } + + return; +} + +static int reorder(struct hostdata *ha, unsigned long cursec, + unsigned int ihdlr, unsigned int il[], unsigned int n_ready) +{ + struct scsi_cmnd *SCpnt; + struct mscp *cpp; + unsigned int k, n; + unsigned int rev = 0, s = 1, r = 1; + unsigned int input_only = 1, overlap = 0; + unsigned long sl[n_ready], pl[n_ready], ll[n_ready]; + unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0; + unsigned long ioseek = 0; + + static unsigned int flushcount = 0, batchcount = 0, sortcount = 0; + static unsigned int readycount = 0, ovlcount = 0, inputcount = 0; + static unsigned int readysorted = 0, revcount = 0; + static unsigned long seeksorted = 0, seeknosort = 0; + + if (link_statistics && !(++flushcount % link_statistics)) + printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d" + " av %ldK as %ldK.\n", flushcount, batchcount, + inputcount, ovlcount, readycount, readysorted, sortcount, + revcount, seeknosort / (readycount + 1), + seeksorted / (readycount + 1)); + + if (n_ready <= 1) + return 0; + + for (n = 0; n < n_ready; n++) { + k = il[n]; + cpp = &ha->cp[k]; + SCpnt = cpp->SCpnt; + + if (!cpp->din) + input_only = 0; + + if (SCpnt->request->sector < minsec) + minsec = SCpnt->request->sector; + if (SCpnt->request->sector > maxsec) + maxsec = SCpnt->request->sector; + + sl[n] = SCpnt->request->sector; + ioseek += SCpnt->request->nr_sectors; + + if (!n) + continue; + + if (sl[n] < sl[n - 1]) + s = 0; + if (sl[n] > sl[n - 1]) + r = 0; + + if (link_statistics) { + if (sl[n] > sl[n - 1]) + seek += sl[n] - sl[n - 1]; + else + seek += sl[n - 1] - sl[n]; + } + + } + + if (link_statistics) { + if (cursec > sl[0]) + seek += cursec - sl[0]; + else + seek += sl[0] - cursec; + } + + if (cursec > ((maxsec + minsec) / 2)) + rev = 1; + + if (ioseek > ((maxsec - minsec) / 2)) + rev = 0; + + if (!((rev && r) || (!rev && s))) + sort(sl, il, n_ready, rev); + + if (!input_only) + for (n = 0; n < n_ready; n++) { + k = il[n]; + cpp = &ha->cp[k]; + SCpnt = cpp->SCpnt; + ll[n] = SCpnt->request->nr_sectors; + pl[n] = SCpnt->pid; + + if (!n) + continue; + + if ((sl[n] == sl[n - 1]) + || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n])) + || (rev && ((sl[n] + ll[n]) > sl[n - 1]))) + overlap = 1; + } + + if (overlap) + sort(pl, il, n_ready, 0); + + if (link_statistics) { + if (cursec > sl[0]) + iseek = cursec - sl[0]; + else + iseek = sl[0] - cursec; + batchcount++; + readycount += n_ready; + seeknosort += seek / 1024; + if (input_only) + inputcount++; + if (overlap) { + ovlcount++; + seeksorted += iseek / 1024; + } else + seeksorted += (iseek + maxsec - minsec) / 1024; + if (rev && !r) { + revcount++; + readysorted += n_ready; + } + if (!rev && !s) { + sortcount++; + readysorted += n_ready; + } + } #if defined(DEBUG_LINKED_COMMANDS) - if (link_statistics && (overlap || !(flushcount % link_statistics))) - for (n = 0; n < n_ready; n++) { - k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld"\ - " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", - (ihdlr ? "ihdlr" : "qcomm"), SCpnt->device->channel, SCpnt->device->id, - SCpnt->device->lun, SCpnt->pid, k, flushcount, n_ready, - SCpnt->request->sector, SCpnt->request->nr_sectors, cursec, - YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), - YESNO(overlap), cpp->din); - } -#endif - return overlap; -} - -static void flush_dev(struct scsi_device *dev, unsigned long cursec, unsigned int j, - unsigned int ihdlr) { - struct scsi_cmnd *SCpnt; - struct mscp *cpp; - unsigned int k, n, n_ready = 0, il[MAX_MAILBOXES]; - - for (k = 0; k < sh[j]->can_queue; k++) { + if (link_statistics && (overlap || !(flushcount % link_statistics))) + for (n = 0; n < n_ready; n++) { + k = il[n]; + cpp = &ha->cp[k]; + SCpnt = cpp->SCpnt; + printk + ("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld" + " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", + (ihdlr ? "ihdlr" : "qcomm"), + SCpnt->device->channel, SCpnt->device->id, + SCpnt->device->lun, SCpnt->pid, k, flushcount, + n_ready, SCpnt->request->sector, + SCpnt->request->nr_sectors, cursec, YESNO(s), + YESNO(r), YESNO(rev), YESNO(input_only), + YESNO(overlap), cpp->din); + } +#endif + return overlap; +} + +static void flush_dev(struct scsi_device *dev, unsigned long cursec, + struct hostdata *ha, unsigned int ihdlr) +{ + struct scsi_cmnd *SCpnt; + struct mscp *cpp; + unsigned int k, n, n_ready = 0, il[MAX_MAILBOXES]; + + for (k = 0; k < dev->host->can_queue; k++) { + + if (ha->cp_stat[k] != READY && ha->cp_stat[k] != IN_USE) + continue; + + cpp = &ha->cp[k]; + SCpnt = cpp->SCpnt; + + if (SCpnt->device != dev) + continue; + + if (ha->cp_stat[k] == IN_USE) + return; + + il[n_ready++] = k; + } + + if (reorder(ha, cursec, ihdlr, il, n_ready)) + n_ready = 1; + + for (n = 0; n < n_ready; n++) { + k = il[n]; + cpp = &ha->cp[k]; + SCpnt = cpp->SCpnt; + + if (do_dma(dev->host->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { + printk + ("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter" + " busy, will abort.\n", ha->board_name, + (ihdlr ? "ihdlr" : "qcomm"), + SCpnt->device->channel, SCpnt->device->id, + SCpnt->device->lun, SCpnt->pid, k); + ha->cp_stat[k] = ABORTING; + continue; + } + + ha->cp_stat[k] = IN_USE; + } +} + +static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost) +{ + struct scsi_cmnd *SCpnt; + unsigned int i, k, c, status, tstatus, reg; + struct mssp *spp; + struct mscp *cpp; + struct hostdata *ha = (struct hostdata *)shost->hostdata; + + if (shost->irq != irq) + panic("%s: ihdlr, irq %d, shost->irq %d.\n", ha->board_name, irq, + shost->irq); + + /* Check if this board need to be serviced */ + if (!(inb(shost->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)) + goto none; + + ha->iocount++; + + if (do_trace) + printk("%s: ihdlr, enter, irq %d, count %d.\n", ha->board_name, irq, + ha->iocount); + + /* Check if this board is still busy */ + if (wait_on_busy(shost->io_port, 20 * MAXLOOP)) { + reg = inb(shost->io_port + REG_STATUS); + printk + ("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n", + ha->board_name, irq, reg, ha->iocount); + goto none; + } + + spp = &ha->sp; - if (HD(j)->cp_stat[k] != READY && HD(j)->cp_stat[k] != IN_USE) continue; - - cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - - if (SCpnt->device != dev) continue; - - if (HD(j)->cp_stat[k] == IN_USE) return; - - il[n_ready++] = k; - } - - if (reorder(j, cursec, ihdlr, il, n_ready)) n_ready = 1; - - for (n = 0; n < n_ready; n++) { - k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - - if (do_dma(sh[j]->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { - printk("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"\ - " busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"), - SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun, SCpnt->pid, k); - HD(j)->cp_stat[k] = ABORTING; - continue; - } - - HD(j)->cp_stat[k] = IN_USE; - } - -} + /* Make a local copy just before clearing the interrupt indication */ + memcpy(spp, ha->sp_cpu_addr, sizeof(struct mssp)); -static irqreturn_t ihdlr(int irq, unsigned int j) { - struct scsi_cmnd *SCpnt; - unsigned int i, k, c, status, tstatus, reg; - struct mssp *spp; - struct mscp *cpp; + /* Clear the completion flag and cp pointer on the dynamic copy of sp */ + memset(ha->sp_cpu_addr, 0, sizeof(struct mssp)); - if (sh[j]->irq != irq) - panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq); - - /* Check if this board need to be serviced */ - if (!(inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)) goto none; - - HD(j)->iocount++; - - if (do_trace) printk("%s: ihdlr, enter, irq %d, count %d.\n", BN(j), irq, - HD(j)->iocount); - - /* Check if this board is still busy */ - if (wait_on_busy(sh[j]->io_port, 20 * MAXLOOP)) { - reg = inb(sh[j]->io_port + REG_STATUS); - printk("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n", - BN(j), irq, reg, HD(j)->iocount); - goto none; - } - - spp = &HD(j)->sp; - - /* Make a local copy just before clearing the interrupt indication */ - memcpy(spp, HD(j)->sp_cpu_addr, sizeof(struct mssp)); - - /* Clear the completion flag and cp pointer on the dynamic copy of sp */ - memset(HD(j)->sp_cpu_addr, 0, sizeof(struct mssp)); - - /* Read the status register to clear the interrupt indication */ - reg = inb(sh[j]->io_port + REG_STATUS); + /* Read the status register to clear the interrupt indication */ + reg = inb(shost->io_port + REG_STATUS); #if defined (DEBUG_INTERRUPT) - { - unsigned char *bytesp; - int cnt; - bytesp= (unsigned char *) spp; - if (HD(j)->iocount < 200) { - printk("sp[] ="); - for (cnt=0; cnt < 15; cnt++) printk(" 0x%x", bytesp[cnt]); - printk("\n"); - } - } -#endif - - /* Reject any sp with supspect data */ - if (spp->eoc == 0 && HD(j)->iocount > 1) - printk("%s: ihdlr, spp->eoc == 0, irq %d, reg 0x%x, count %d.\n", - BN(j), irq, reg, HD(j)->iocount); - if (spp->cpp_index < 0 || spp->cpp_index >= sh[j]->can_queue) - printk("%s: ihdlr, bad spp->cpp_index %d, irq %d, reg 0x%x, count %d.\n", - BN(j), spp->cpp_index, irq, reg, HD(j)->iocount); - if (spp->eoc == 0 || spp->cpp_index < 0 - || spp->cpp_index >= sh[j]->can_queue) goto handled; + { + unsigned char *bytesp; + int cnt; + bytesp = (unsigned char *)spp; + if (ha->iocount < 200) { + printk("sp[] ="); + for (cnt = 0; cnt < 15; cnt++) + printk(" 0x%x", bytesp[cnt]); + printk("\n"); + } + } +#endif + + /* Reject any sp with supspect data */ + if (spp->eoc == 0 && ha->iocount > 1) + printk + ("%s: ihdlr, spp->eoc == 0, irq %d, reg 0x%x, count %d.\n", + ha->board_name, irq, reg, ha->iocount); + if (spp->cpp_index < 0 || spp->cpp_index >= shost->can_queue) + printk + ("%s: ihdlr, bad spp->cpp_index %d, irq %d, reg 0x%x, count %d.\n", + ha->board_name, spp->cpp_index, irq, reg, ha->iocount); + if (spp->eoc == 0 || spp->cpp_index < 0 + || spp->cpp_index >= shost->can_queue) + goto handled; - /* Find the mailbox to be serviced on this board */ - i = spp->cpp_index; + /* Find the mailbox to be serviced on this board */ + i = spp->cpp_index; - cpp = &(HD(j)->cp[i]); + cpp = &(ha->cp[i]); #if defined(DEBUG_GENERATE_ABORTS) - if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) goto handled; + if ((ha->iocount > 500) && ((ha->iocount % 500) < 3)) + goto handled; #endif - if (HD(j)->cp_stat[i] == IGNORE) { - HD(j)->cp_stat[i] = FREE; - goto handled; - } - else if (HD(j)->cp_stat[i] == LOCKED) { - HD(j)->cp_stat[i] = FREE; - printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j), i, - HD(j)->iocount); - goto handled; - } - else if (HD(j)->cp_stat[i] == FREE) { - printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j), i, - HD(j)->iocount); - goto handled; - } - else if (HD(j)->cp_stat[i] == IN_RESET) - printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i); - else if (HD(j)->cp_stat[i] != IN_USE) - panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n", - BN(j), i, HD(j)->cp_stat[i]); - - HD(j)->cp_stat[i] = FREE; - SCpnt = cpp->SCpnt; - - if (SCpnt == NULL) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i); - - if (SCpnt->host_scribble == NULL) - panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i, - SCpnt->pid, SCpnt); - - if (*(unsigned int *)SCpnt->host_scribble != i) - panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n", - BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble); - - sync_dma(i, j); - - if (linked_comm && SCpnt->device->queue_depth > 2 - && TLDEV(SCpnt->device->type)) - flush_dev(SCpnt->device, SCpnt->request->sector, j, 1); + if (ha->cp_stat[i] == IGNORE) { + ha->cp_stat[i] = FREE; + goto handled; + } else if (ha->cp_stat[i] == LOCKED) { + ha->cp_stat[i] = FREE; + printk("%s: ihdlr, mbox %d unlocked, count %d.\n", ha->board_name, i, + ha->iocount); + goto handled; + } else if (ha->cp_stat[i] == FREE) { + printk("%s: ihdlr, mbox %d is free, count %d.\n", ha->board_name, i, + ha->iocount); + goto handled; + } else if (ha->cp_stat[i] == IN_RESET) + printk("%s: ihdlr, mbox %d is in reset.\n", ha->board_name, i); + else if (ha->cp_stat[i] != IN_USE) + panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n", + ha->board_name, i, ha->cp_stat[i]); + + ha->cp_stat[i] = FREE; + SCpnt = cpp->SCpnt; + + if (SCpnt == NULL) + panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", ha->board_name, i); + + if (SCpnt->host_scribble == NULL) + panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", ha->board_name, + i, SCpnt->pid, SCpnt); + + if (*(unsigned int *)SCpnt->host_scribble != i) + panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n", + ha->board_name, i, SCpnt->pid, + *(unsigned int *)SCpnt->host_scribble); + + sync_dma(i, ha); + + if (linked_comm && SCpnt->device->queue_depth > 2 + && TLDEV(SCpnt->device->type)) + flush_dev(SCpnt->device, SCpnt->request->sector, ha, 1); - tstatus = status_byte(spp->target_status); + tstatus = status_byte(spp->target_status); #if defined(DEBUG_GENERATE_ERRORS) - if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 200) < 2)) - spp->adapter_status = 0x01; + if ((ha->iocount > 500) && ((ha->iocount % 200) < 2)) + spp->adapter_status = 0x01; #endif - switch (spp->adapter_status) { - case ASOK: /* status OK */ + switch (spp->adapter_status) { + case ASOK: /* status OK */ - /* Forces a reset if a disk drive keeps returning BUSY */ - if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE) - status = DID_ERROR << 16; - - /* If there was a bus reset, redo operation on each target */ - else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK - && HD(j)->target_redo[SCpnt->device->id][SCpnt->device->channel]) - status = DID_BUS_BUSY << 16; - - /* Works around a flaw in scsi.c */ - else if (tstatus == CHECK_CONDITION - && SCpnt->device->type == TYPE_DISK - && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR) - status = DID_BUS_BUSY << 16; - - else - status = DID_OK << 16; - - if (tstatus == GOOD) - HD(j)->target_redo[SCpnt->device->id][SCpnt->device->channel] = 0; - - if (spp->target_status && SCpnt->device->type == TYPE_DISK && - (!(tstatus == CHECK_CONDITION && HD(j)->iocount <= 1000 && - (SCpnt->sense_buffer[2] & 0xf) == NOT_READY))) - printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\ - "target_status 0x%x, sense key 0x%x.\n", BN(j), - SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun, - SCpnt->pid, spp->target_status, - SCpnt->sense_buffer[2]); - - HD(j)->target_to[SCpnt->device->id][SCpnt->device->channel] = 0; - - if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0; - - break; - case ASST: /* Selection Time Out */ - case 0x02: /* Command Time Out */ - - if (HD(j)->target_to[SCpnt->device->id][SCpnt->device->channel] > 1) - status = DID_ERROR << 16; - else { - status = DID_TIME_OUT << 16; - HD(j)->target_to[SCpnt->device->id][SCpnt->device->channel]++; - } - - break; - - /* Perform a limited number of internal retries */ - case 0x03: /* SCSI Bus Reset Received */ - case 0x04: /* Initial Controller Power-up */ - - for (c = 0; c <= sh[j]->max_channel; c++) - for (k = 0; k < sh[j]->max_id; k++) - HD(j)->target_redo[k][c] = 1; + /* Forces a reset if a disk drive keeps returning BUSY */ + if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE) + status = DID_ERROR << 16; + + /* If there was a bus reset, redo operation on each target */ + else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK + && ha->target_redo[SCpnt->device->id][SCpnt-> + device-> + channel]) + status = DID_BUS_BUSY << 16; + + /* Works around a flaw in scsi.c */ + else if (tstatus == CHECK_CONDITION + && SCpnt->device->type == TYPE_DISK + && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR) + status = DID_BUS_BUSY << 16; + + else + status = DID_OK << 16; + + if (tstatus == GOOD) + ha->target_redo[SCpnt->device->id][SCpnt->device-> + channel] = 0; + + if (spp->target_status && SCpnt->device->type == TYPE_DISK && + (!(tstatus == CHECK_CONDITION && ha->iocount <= 1000 && + (SCpnt->sense_buffer[2] & 0xf) == NOT_READY))) + printk("%s: ihdlr, target %d.%d:%d, pid %ld, " + "target_status 0x%x, sense key 0x%x.\n", + ha->board_name, + SCpnt->device->channel, SCpnt->device->id, + SCpnt->device->lun, SCpnt->pid, + spp->target_status, SCpnt->sense_buffer[2]); + + ha->target_to[SCpnt->device->id][SCpnt->device->channel] = 0; + + if (ha->last_retried_pid == SCpnt->pid) + ha->retries = 0; + + break; + case ASST: /* Selection Time Out */ + case 0x02: /* Command Time Out */ + + if (ha->target_to[SCpnt->device->id][SCpnt->device->channel] > 1) + status = DID_ERROR << 16; + else { + status = DID_TIME_OUT << 16; + ha->target_to[SCpnt->device->id][SCpnt->device-> + channel]++; + } + + break; + + /* Perform a limited number of internal retries */ + case 0x03: /* SCSI Bus Reset Received */ + case 0x04: /* Initial Controller Power-up */ + + for (c = 0; c <= shost->max_channel; c++) + for (k = 0; k < shost->max_id; k++) + ha->target_redo[k][c] = 1; - if (SCpnt->device->type != TYPE_TAPE - && HD(j)->retries < MAX_INTERNAL_RETRIES) { + if (SCpnt->device->type != TYPE_TAPE + && ha->retries < MAX_INTERNAL_RETRIES) { #if defined(DID_SOFT_ERROR) - status = DID_SOFT_ERROR << 16; + status = DID_SOFT_ERROR << 16; #else - status = DID_BUS_BUSY << 16; + status = DID_BUS_BUSY << 16; #endif - HD(j)->retries++; - HD(j)->last_retried_pid = SCpnt->pid; - } - else - status = DID_ERROR << 16; - - break; - case 0x05: /* Unexpected Bus Phase */ - case 0x06: /* Unexpected Bus Free */ - case 0x07: /* Bus Parity Error */ - case 0x08: /* SCSI Hung */ - case 0x09: /* Unexpected Message Reject */ - case 0x0a: /* SCSI Bus Reset Stuck */ - case 0x0b: /* Auto Request-Sense Failed */ - case 0x0c: /* Controller Ram Parity Error */ - default: - status = DID_ERROR << 16; - break; - } + ha->retries++; + ha->last_retried_pid = SCpnt->pid; + } else + status = DID_ERROR << 16; + + break; + case 0x05: /* Unexpected Bus Phase */ + case 0x06: /* Unexpected Bus Free */ + case 0x07: /* Bus Parity Error */ + case 0x08: /* SCSI Hung */ + case 0x09: /* Unexpected Message Reject */ + case 0x0a: /* SCSI Bus Reset Stuck */ + case 0x0b: /* Auto Request-Sense Failed */ + case 0x0c: /* Controller Ram Parity Error */ + default: + status = DID_ERROR << 16; + break; + } - SCpnt->result = status | spp->target_status; + SCpnt->result = status | spp->target_status; #if defined(DEBUG_INTERRUPT) - if (SCpnt->result || do_trace) + if (SCpnt->result || do_trace) #else - if ((spp->adapter_status != ASOK && HD(j)->iocount > 1000) || - (spp->adapter_status != ASOK && - spp->adapter_status != ASST && HD(j)->iocount <= 1000) || - do_trace || msg_byte(spp->target_status)) -#endif - printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\ - " target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n", - BN(j), i, spp->adapter_status, spp->target_status, - SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun, SCpnt->pid, - reg, HD(j)->iocount); - - unmap_dma(i, j); - - /* Set the command state to inactive */ - SCpnt->host_scribble = NULL; - - SCpnt->scsi_done(SCpnt); - - if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j), irq, - HD(j)->iocount); - -handled: - return IRQ_HANDLED; -none: - return IRQ_NONE; + if ((spp->adapter_status != ASOK && ha->iocount > 1000) || + (spp->adapter_status != ASOK && + spp->adapter_status != ASST && ha->iocount <= 1000) || + do_trace || msg_byte(spp->target_status)) +#endif + printk("%s: ihdlr, mbox %2d, err 0x%x:%x," + " target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n", + ha->board_name, i, spp->adapter_status, spp->target_status, + SCpnt->device->channel, SCpnt->device->id, + SCpnt->device->lun, SCpnt->pid, reg, ha->iocount); + + unmap_dma(i, ha); + + /* Set the command state to inactive */ + SCpnt->host_scribble = NULL; + + SCpnt->scsi_done(SCpnt); + + if (do_trace) + printk("%s: ihdlr, exit, irq %d, count %d.\n", ha->board_name, + irq, ha->iocount); + + handled: + return IRQ_HANDLED; + none: + return IRQ_NONE; } static irqreturn_t do_interrupt_handler(int irq, void *shap, - struct pt_regs *regs) { - unsigned int j; - unsigned long spin_flags; - irqreturn_t ret; - - /* Check if the interrupt must be processed by this handler */ - if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return IRQ_NONE; - - spin_lock_irqsave(sh[j]->host_lock, spin_flags); - ret = ihdlr(irq, j); - spin_unlock_irqrestore(sh[j]->host_lock, spin_flags); - return ret; -} - -static int eata2x_release(struct Scsi_Host *shpnt) { - unsigned int i, j; - - for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++); - - if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n", - driver_name); - - for (i = 0; i < sh[j]->can_queue; i++) - if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist); - - for (i = 0; i < sh[j]->can_queue; i++) - pci_unmap_single(HD(j)->pdev, HD(j)->cp[i].cp_dma_addr, - sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); - - if (HD(j)->sp_cpu_addr) - pci_free_consistent(HD(j)->pdev, sizeof(struct mssp), - HD(j)->sp_cpu_addr, HD(j)->sp_dma_addr); - - free_irq(sh[j]->irq, &sha[j]); - - if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel); - - release_region(sh[j]->io_port, sh[j]->n_io_port); - scsi_unregister(sh[j]); - return 0; + struct pt_regs *regs) +{ + struct Scsi_Host *shost; + unsigned int j; + unsigned long spin_flags; + irqreturn_t ret; + + /* Check if the interrupt must be processed by this handler */ + if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) + return IRQ_NONE; + shost = sh[j]; + + spin_lock_irqsave(shost->host_lock, spin_flags); + ret = ihdlr(irq, shost); + spin_unlock_irqrestore(shost->host_lock, spin_flags); + return ret; +} + +static int eata2x_release(struct Scsi_Host *shost) +{ + struct hostdata *ha = (struct hostdata *)shost->hostdata; + unsigned int i; + + for (i = 0; i < shost->can_queue; i++) + if ((&ha->cp[i])->sglist) + kfree((&ha->cp[i])->sglist); + + for (i = 0; i < shost->can_queue; i++) + pci_unmap_single(ha->pdev, ha->cp[i].cp_dma_addr, + sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); + + if (ha->sp_cpu_addr) + pci_free_consistent(ha->pdev, sizeof(struct mssp), + ha->sp_cpu_addr, ha->sp_dma_addr); + + free_irq(shost->irq, &sha[ha->board_number]); + + if (shost->dma_channel != NO_DMA) + free_dma(shost->dma_channel); + + release_region(shost->io_port, shost->n_io_port); + scsi_unregister(shost); + return 0; } #include "scsi_module.c" #ifndef MODULE __setup("eata=", option_setup); -#endif /* end MODULE */ +#endif /* end MODULE */ diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c --- a/drivers/scsi/hosts.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/hosts.c 2004-11-29 21:56:02 -08:00 @@ -79,11 +79,14 @@ set_bit(SHOST_DEL, &shost->shost_state); + if (shost->transportt->host_destroy) + shost->transportt->host_destroy(shost); class_device_unregister(&shost->shost_classdev); if (shost->transport_classdev.class) class_device_unregister(&shost->transport_classdev); device_del(&shost->shost_gendev); } +EXPORT_SYMBOL(scsi_remove_host); /** * scsi_add_host - add a scsi host @@ -133,11 +136,14 @@ error = scsi_sysfs_add_host(shost); if (error) - goto out_del_classdev; + goto out_destroy_host; scsi_proc_host_add(shost); return error; + out_destroy_host: + if (shost->transportt->host_destroy) + shost->transportt->host_destroy(shost); out_del_classdev: class_device_del(&shost->shost_classdev); out_del_gendev: @@ -145,6 +151,7 @@ out: return error; } +EXPORT_SYMBOL(scsi_add_host); static void scsi_host_dev_release(struct device *dev) { @@ -301,6 +308,7 @@ kfree(shost); return NULL; } +EXPORT_SYMBOL(scsi_host_alloc); struct Scsi_Host *scsi_register(struct scsi_host_template *sht, int privsize) { @@ -316,12 +324,14 @@ list_add_tail(&shost->sht_legacy_list, &sht->legacy_hosts); return shost; } +EXPORT_SYMBOL(scsi_register); void scsi_unregister(struct Scsi_Host *shost) { list_del(&shost->sht_legacy_list); scsi_host_put(shost); } +EXPORT_SYMBOL(scsi_unregister); /** * scsi_host_lookup - get a reference to a Scsi_Host by host no @@ -349,6 +359,7 @@ return shost; } +EXPORT_SYMBOL(scsi_host_lookup); /** * scsi_host_get - inc a Scsi_Host ref count @@ -361,6 +372,7 @@ return NULL; return shost; } +EXPORT_SYMBOL(scsi_host_get); /** * scsi_host_put - dec a Scsi_Host ref count @@ -370,6 +382,7 @@ { put_device(&shost->shost_gendev); } +EXPORT_SYMBOL(scsi_host_put); int scsi_init_hosts(void) { diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c --- a/drivers/scsi/scsi.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/scsi.c 2004-11-29 21:56:02 -08:00 @@ -98,6 +98,9 @@ * After the system is up, you may enable logging via the /proc interface. */ unsigned int scsi_logging_level; +#if defined(CONFIG_SCSI_LOGGING) +EXPORT_SYMBOL(scsi_logging_level); +#endif const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = { "Direct-Access ", @@ -115,6 +118,7 @@ "RAID ", "Enclosure ", }; +EXPORT_SYMBOL(scsi_device_types); /* * Function: scsi_allocate_request @@ -147,6 +151,7 @@ return sreq; } +EXPORT_SYMBOL(scsi_allocate_request); void __scsi_release_request(struct scsi_request *sreq) { @@ -187,6 +192,7 @@ __scsi_release_request(sreq); kfree(sreq); } +EXPORT_SYMBOL(scsi_release_request); struct scsi_host_cmd_pool { kmem_cache_t *slab; @@ -269,6 +275,7 @@ return cmd; } +EXPORT_SYMBOL(scsi_get_command); /* * Function: scsi_put_command() @@ -305,6 +312,7 @@ put_device(&sdev->sdev_gendev); } +EXPORT_SYMBOL(scsi_put_command); /* * Function: scsi_setup_command_freelist() @@ -606,9 +614,7 @@ printk("queuecommand : command too long.\n")); cmd->result = (DID_ABORT << 16); - spin_lock_irqsave(host->host_lock, flags); scsi_done(cmd); - spin_unlock_irqrestore(host->host_lock, flags); goto out; } @@ -961,6 +967,7 @@ spin_unlock(sdev->request_queue->queue_lock); spin_unlock_irqrestore(&device_request_lock, flags); } +EXPORT_SYMBOL(scsi_adjust_queue_depth); /* * Function: scsi_track_queue_full() @@ -1011,6 +1018,7 @@ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth); return depth; } +EXPORT_SYMBOL(scsi_track_queue_full); /** * scsi_device_get - get an addition reference to a scsi_device @@ -1177,6 +1185,7 @@ return 0; } +EXPORT_SYMBOL(scsi_device_cancel); #ifdef CONFIG_HOTPLUG_CPU static int scsi_cpu_notify(struct notifier_block *self, diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c --- a/drivers/scsi/scsi_debug.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/scsi_debug.c 2004-11-29 21:56:02 -08:00 @@ -55,8 +55,8 @@ #include "scsi_logging.h" #include "scsi_debug.h" -#define SCSI_DEBUG_VERSION "1.74" -static const char * scsi_debug_version_date = "20040829"; +#define SCSI_DEBUG_VERSION "1.75" +static const char * scsi_debug_version_date = "20041023"; /* Additional Sense Code (ASC) used */ #define NO_ADDED_SENSE 0x0 @@ -82,7 +82,7 @@ #define DEF_EVERY_NTH 0 #define DEF_NUM_PARTS 0 #define DEF_OPTS 0 -#define DEF_SCSI_LEVEL 4 /* SPC-2 */ +#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */ #define DEF_PTYPE 0 #define DEF_D_SENSE 0 @@ -95,6 +95,13 @@ * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set * - a RECOVERED_ERROR is simulated on successful read and write * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. + * + * When "every_nth" < 0 then after "- every_nth" commands: + * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set + * - a RECOVERED_ERROR is simulated on successful read and write + * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. + * This will continue until some other action occurs (e.g. the user + * writing a new value (other than -1 or 1) to every_nth via sysfs). */ /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this @@ -195,14 +202,12 @@ .cmd_per_lun = 3, .max_sectors = 4096, .unchecked_isa_dma = 0, - .use_clustering = ENABLE_CLUSTERING, + .use_clustering = DISABLE_CLUSTERING, .module = THIS_MODULE, }; static unsigned char * fake_storep; /* ramdisk storage */ -static unsigned char spare_buff[SDEBUG_SENSE_LEN]; - static int num_aborts = 0; static int num_dev_resets = 0; static int num_bus_resets = 0; @@ -228,21 +233,28 @@ (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; /* function declarations */ -static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff, - int bufflen, struct sdebug_dev_info * devip); -static int resp_mode_sense(unsigned char * cmd, int target, - unsigned char * buff, int bufflen, +static int resp_inquiry(struct scsi_cmnd * SCpnt, int target, + struct sdebug_dev_info * devip); +static int resp_requests(struct scsi_cmnd * SCpnt, + struct sdebug_dev_info * devip); +static int resp_readcap(struct scsi_cmnd * SCpnt, + struct sdebug_dev_info * devip); +static int resp_mode_sense(struct scsi_cmnd * SCpnt, int target, struct sdebug_dev_info * devip); static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, int num, struct sdebug_dev_info * devip); static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block, int num, struct sdebug_dev_info * devip); -static int resp_report_luns(unsigned char * cmd, unsigned char * buff, - int bufflen, struct sdebug_dev_info * devip); +static int resp_report_luns(struct scsi_cmnd * SCpnt, + struct sdebug_dev_info * devip); +static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, + int arr_len); +static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, + int max_arr_len); static void timer_intr_handler(unsigned long); static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev); static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, - int asc, int asq, int inbandLen); + int asc, int asq); static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); static int schedule_resp(struct scsi_cmnd * cmnd, @@ -264,49 +276,20 @@ static struct device pseudo_primary; static struct bus_type pseudo_lld_bus; -static unsigned char * scatg2virt(const struct scatterlist * sclp) -{ - if (NULL == sclp) - return NULL; - else if (sclp->page) - return (unsigned char *)page_address(sclp->page) + - sclp->offset; - else - return NULL; -} static int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) { unsigned char *cmd = (unsigned char *) SCpnt->cmnd; int block, upper_blk, num, k; - unsigned char *buff; int errsts = 0; int target = SCpnt->device->id; - int bufflen = SCpnt->request_bufflen; - unsigned long capac; struct sdebug_dev_info * devip = NULL; - unsigned char * sbuff; int inj_recovered = 0; if (done == NULL) return 0; /* assume mid level reprocessing command */ - if (SCpnt->use_sg) { /* just use first element */ - struct scatterlist *sgpnt = (struct scatterlist *) - SCpnt->request_buffer; - - buff = scatg2virt(&sgpnt[0]); - bufflen = sgpnt[0].length; - /* READ and WRITE process scatterlist themselves */ - } - else - buff = (unsigned char *) SCpnt->request_buffer; - if (NULL == buff) { - buff = spare_buff; /* assume cmd moves no data */ - bufflen = SDEBUG_SENSE_LEN; - } - if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { printk(KERN_INFO "scsi_debug: cmd "); for (k = 0, num = SCpnt->cmd_len; k < num; ++k) @@ -328,9 +311,11 @@ return schedule_resp(SCpnt, NULL, done, DID_NO_CONNECT << 16, 0); - if ((scsi_debug_every_nth > 0) && - (++scsi_debug_cmnd_count >= scsi_debug_every_nth)) { - scsi_debug_cmnd_count =0; + if ((scsi_debug_every_nth != 0) && + (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) { + scsi_debug_cmnd_count = 0; + if (scsi_debug_every_nth < -1) + scsi_debug_every_nth = -1; if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) return 0; /* ignore command causing timeout */ else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) @@ -339,23 +324,14 @@ switch (*cmd) { case INQUIRY: /* mandatory, ignore unit attention */ - errsts = resp_inquiry(cmd, target, buff, bufflen, devip); + errsts = resp_inquiry(SCpnt, target, devip); break; case REQUEST_SENSE: /* mandatory, ignore unit attention */ - if (devip) { - sbuff = devip->sense_buff; - memcpy(buff, sbuff, (bufflen < SDEBUG_SENSE_LEN) ? - bufflen : SDEBUG_SENSE_LEN); - mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0, 7); - } else { - memset(buff, 0, bufflen); - buff[0] = 0x70; - } + errsts = resp_requests(SCpnt, devip); break; case REZERO_UNIT: /* actually this is REWIND for SSC */ case START_STOP: errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; case ALLOW_MEDIUM_REMOVAL: if ((errsts = check_reset(SCpnt, devip))) @@ -366,40 +342,24 @@ break; case SEND_DIAGNOSTIC: /* mandatory */ errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; case TEST_UNIT_READY: /* mandatory */ errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; case RESERVE: errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; case RESERVE_10: errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; case RELEASE: errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; case RELEASE_10: errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; case READ_CAPACITY: - errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); - if (bufflen > 7) { - capac = (unsigned long)sdebug_capacity - 1; - buff[0] = (capac >> 24); - buff[1] = (capac >> 16) & 0xff; - buff[2] = (capac >> 8) & 0xff; - buff[3] = capac & 0xff; - buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; - buff[7] = SECT_SIZE_PER(target) & 0xff; - } + errsts = resp_readcap(SCpnt, devip); break; case READ_16: case READ_12: @@ -432,12 +392,15 @@ errsts = resp_read(SCpnt, upper_blk, block, num, devip); if (inj_recovered && (0 == errsts)) { mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHHOLD_EXCEEDED, 0, 18); + THRESHHOLD_EXCEEDED, 0); errsts = check_condition_result; } break; case REPORT_LUNS: /* mandatory, ignore unit attention */ - errsts = resp_report_luns(cmd, buff, bufflen, devip); + errsts = resp_report_luns(SCpnt, devip); + break; + case VERIFY: /* 10 byte SBC-2 command */ + errsts = check_reset(SCpnt, devip); break; case WRITE_16: case WRITE_12: @@ -470,19 +433,16 @@ errsts = resp_write(SCpnt, upper_blk, block, num, devip); if (inj_recovered && (0 == errsts)) { mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHHOLD_EXCEEDED, 0, 18); + THRESHHOLD_EXCEEDED, 0); errsts = check_condition_result; } break; case MODE_SENSE: case MODE_SENSE_10: - if ((errsts = check_reset(SCpnt, devip))) - break; - errsts = resp_mode_sense(cmd, target, buff, bufflen, devip); + errsts = resp_mode_sense(SCpnt, target, devip); break; case SYNCHRONIZE_CACHE: errsts = check_reset(SCpnt, devip); - memset(buff, 0, bufflen); break; default: if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) @@ -490,7 +450,7 @@ "supported\n", *cmd); if ((errsts = check_reset(SCpnt, devip))) break; /* Unit attention takes precedence */ - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0, 18); + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); errsts = check_condition_result; break; } @@ -513,18 +473,105 @@ printk(KERN_INFO "scsi_debug: Reporting Unit " "attention: power on reset\n"); devip->reset = 0; - mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0, 18); + mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0); return check_condition_result; } return 0; } -#define SDEBUG_LONG_INQ_SZ 96 -#define SDEBUG_MAX_INQ_ARR_SZ 128 +/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ +static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, + int arr_len) +{ + int k, req_len, act_len, len, active; + void * kaddr; + void * kaddr_off; + struct scatterlist * sgpnt; + + if (0 == scp->request_bufflen) + return 0; + if (NULL == scp->request_buffer) + return (DID_ERROR << 16); + if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || + (scp->sc_data_direction == DMA_FROM_DEVICE))) + return (DID_ERROR << 16); + if (0 == scp->use_sg) { + req_len = scp->request_bufflen; + act_len = (req_len < arr_len) ? req_len : arr_len; + memcpy(scp->request_buffer, arr, act_len); + scp->resid = req_len - act_len; + return 0; + } + sgpnt = (struct scatterlist *)scp->request_buffer; + active = 1; + for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sgpnt) { + if (active) { + kaddr = (unsigned char *) + kmap_atomic(sgpnt->page, KM_USER0); + if (NULL == kaddr) + return (DID_ERROR << 16); + kaddr_off = (unsigned char *)kaddr + sgpnt->offset; + len = sgpnt->length; + if ((req_len + len) > arr_len) { + active = 0; + len = arr_len - req_len; + } + memcpy(kaddr_off, arr + req_len, len); + kunmap_atomic(kaddr, KM_USER0); + act_len += len; + } + req_len += sgpnt->length; + } + scp->resid = req_len - act_len; + return 0; +} -static const char * vendor_id = "Linux "; -static const char * product_id = "scsi_debug "; -static const char * product_rev = "0004"; +/* Returns number of bytes fetched into 'arr' or -1 if error. */ +static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, + int max_arr_len) +{ + int k, req_len, len, fin; + void * kaddr; + void * kaddr_off; + struct scatterlist * sgpnt; + + if (0 == scp->request_bufflen) + return 0; + if (NULL == scp->request_buffer) + return -1; + if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || + (scp->sc_data_direction == DMA_TO_DEVICE))) + return -1; + if (0 == scp->use_sg) { + req_len = scp->request_bufflen; + len = (req_len < max_arr_len) ? req_len : max_arr_len; + memcpy(arr, scp->request_buffer, len); + return len; + } + sgpnt = (struct scatterlist *)scp->request_buffer; + for (k = 0, req_len = 0, fin = 0; k < scp->use_sg; ++k, ++sgpnt) { + kaddr = (unsigned char *)kmap_atomic(sgpnt->page, KM_USER0); + if (NULL == kaddr) + return -1; + kaddr_off = (unsigned char *)kaddr + sgpnt->offset; + len = sgpnt->length; + if ((req_len + len) > max_arr_len) { + len = max_arr_len - req_len; + fin = 1; + } + memcpy(arr + req_len, kaddr_off, len); + kunmap_atomic(kaddr, KM_USER0); + if (fin) + return req_len + len; + req_len += sgpnt->length; + } + return req_len; +} + + +static const char * inq_vendor_id = "Linux "; +static const char * inq_product_id = "scsi_debug "; +static const char * inq_product_rev = "0004"; static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, const char * dev_id_str, int dev_id_str_len) @@ -536,8 +583,8 @@ arr[0] = 0x2; /* ASCII */ arr[1] = 0x1; arr[2] = 0x0; - memcpy(&arr[4], vendor_id, 8); - memcpy(&arr[12], product_id, 16); + memcpy(&arr[4], inq_vendor_id, 8); + memcpy(&arr[12], inq_product_id, 16); memcpy(&arr[28], dev_id_str, dev_id_str_len); num = 8 + 16 + dev_id_str_len; arr[3] = num; @@ -558,24 +605,25 @@ return num + 12; } -static int resp_inquiry(unsigned char * cmd, int target, unsigned char * buff, - int bufflen, struct sdebug_dev_info * devip) + +#define SDEBUG_LONG_INQ_SZ 96 +#define SDEBUG_MAX_INQ_ARR_SZ 128 + +static int resp_inquiry(struct scsi_cmnd * scp, int target, + struct sdebug_dev_info * devip) { unsigned char pq_pdt; unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ]; - int min_len = bufflen > SDEBUG_MAX_INQ_ARR_SZ ? - SDEBUG_MAX_INQ_ARR_SZ : bufflen; + unsigned char *cmd = (unsigned char *)scp->cmnd; + int alloc_len; - if (bufflen < cmd[4]) - printk(KERN_INFO "scsi_debug: inquiry: bufflen=%d " - "< alloc_length=%d\n", bufflen, (int)cmd[4]); - memset(buff, 0, bufflen); + alloc_len = (cmd[3] << 8) + cmd[4]; memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ); pq_pdt = (scsi_debug_ptype & 0x1f); arr[0] = pq_pdt; if (0x2 & cmd[1]) { /* CMDDT bit set */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0, 18); + 0); return check_condition_result; } else if (0x1 & cmd[1]) { /* EVPD bit set */ int dev_id_num, len; @@ -600,11 +648,11 @@ } else { /* Illegal request, invalid field in cdb */ mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0, 18); + INVALID_FIELD_IN_CDB, 0); return check_condition_result; } - memcpy(buff, arr, min_len); - return 0; + return fill_from_dev_buffer(scp, arr, + min(alloc_len, SDEBUG_MAX_INQ_ARR_SZ)); } /* drops through here for a standard inquiry */ arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ @@ -612,20 +660,67 @@ arr[3] = 2; /* response_data_format==2 */ arr[4] = SDEBUG_LONG_INQ_SZ - 5; arr[6] = 0x1; /* claim: ADDR16 */ + /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */ - memcpy(&arr[8], vendor_id, 8); - memcpy(&arr[16], product_id, 16); - memcpy(&arr[32], product_rev, 4); + memcpy(&arr[8], inq_vendor_id, 8); + memcpy(&arr[16], inq_product_id, 16); + memcpy(&arr[32], inq_product_rev, 4); /* version descriptors (2 bytes each) follow */ arr[58] = 0x0; arr[59] = 0x40; /* SAM-2 */ - arr[60] = 0x2; arr[61] = 0x60; /* SPC-2 */ + arr[60] = 0x3; arr[61] = 0x0; /* SPC-3 */ if (scsi_debug_ptype == 0) { - arr[62] = 0x1; arr[63] = 0x80; /* SBC */ + arr[62] = 0x1; arr[63] = 0x80; /* SBC */ } else if (scsi_debug_ptype == 1) { - arr[62] = 0x2; arr[63] = 0x00; /* SSC */ + arr[62] = 0x2; arr[63] = 0x00; /* SSC */ } - memcpy(buff, arr, min_len); - return 0; + return fill_from_dev_buffer(scp, arr, + min(alloc_len, SDEBUG_LONG_INQ_SZ)); +} + +static int resp_requests(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + unsigned char * sbuff; + unsigned char *cmd = (unsigned char *)scp->cmnd; + unsigned char arr[SDEBUG_SENSE_LEN]; + int len = 18; + + memset(arr, 0, SDEBUG_SENSE_LEN); + if (devip->reset == 1) + mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0); + sbuff = devip->sense_buff; + if ((cmd[1] & 1) && (! scsi_debug_dsense)) { + /* DESC bit set and sense_buff in fixed format */ + arr[0] = 0x72; + arr[1] = sbuff[2]; /* sense key */ + arr[2] = sbuff[12]; /* asc */ + arr[3] = sbuff[13]; /* ascq */ + len = 8; + } else + memcpy(arr, sbuff, SDEBUG_SENSE_LEN); + mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0); + return fill_from_dev_buffer(scp, arr, len); +} + +#define SDEBUG_READCAP_ARR_SZ 8 +static int resp_readcap(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + unsigned char arr[SDEBUG_READCAP_ARR_SZ]; + unsigned long capac; + int errsts; + + if ((errsts = check_reset(scp, devip))) + return errsts; + memset(arr, 0, SDEBUG_READCAP_ARR_SZ); + capac = (unsigned long)sdebug_capacity - 1; + arr[0] = (capac >> 24); + arr[1] = (capac >> 16) & 0xff; + arr[2] = (capac >> 8) & 0xff; + arr[3] = capac & 0xff; + arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; + arr[7] = SECT_SIZE_PER(target) & 0xff; + return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); } /* <> */ @@ -706,34 +801,29 @@ #define SDEBUG_MAX_MSENSE_SZ 256 -static int resp_mode_sense(unsigned char * cmd, int target, - unsigned char * buff, int bufflen, +static int resp_mode_sense(struct scsi_cmnd * scp, int target, struct sdebug_dev_info * devip) { unsigned char dbd; int pcontrol, pcode, subpcode; unsigned char dev_spec; - int alloc_len, msense_6, offset, len; + int alloc_len, msense_6, offset, len, errsts; unsigned char * ap; unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; - int min_len = bufflen > SDEBUG_MAX_MSENSE_SZ ? - SDEBUG_MAX_MSENSE_SZ : bufflen; + unsigned char *cmd = (unsigned char *)scp->cmnd; - SCSI_LOG_LLQUEUE(3, printk("Mode sense ...(%p %d)\n", buff, bufflen)); + if ((errsts = check_reset(scp, devip))) + return errsts; dbd = cmd[1] & 0x8; pcontrol = (cmd[2] & 0xc0) >> 6; pcode = cmd[2] & 0x3f; subpcode = cmd[3]; msense_6 = (MODE_SENSE == cmd[0]); alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); - if (bufflen < alloc_len) - printk(KERN_INFO "scsi_debug: mode_sense: bufflen=%d " - "< alloc_length=%d\n", bufflen, alloc_len); - memset(buff, 0, bufflen); memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); if (0x3 == pcontrol) { /* Saving values not supported */ mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, - 0, 18); + 0); return check_condition_result; } dev_spec = DEV_READONLY(target) ? 0x80 : 0x0; @@ -748,7 +838,7 @@ if (0 != subpcode) { /* TODO: Control Extension page */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0, 18); + 0); return check_condition_result; } switch (pcode) { @@ -787,146 +877,104 @@ break; default: mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0, 18); + 0); return check_condition_result; } if (msense_6) arr[0] = offset - 1; else { - offset -= 2; - arr[0] = (offset >> 8) & 0xff; - arr[1] = offset & 0xff; + arr[0] = ((offset - 2) >> 8) & 0xff; + arr[1] = (offset - 2) & 0xff; } - memcpy(buff, arr, min_len); - return 0; + return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); } static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, int num, struct sdebug_dev_info * devip) { - unsigned char *buff = (unsigned char *) SCpnt->request_buffer; - int nbytes, sgcount; - struct scatterlist *sgpnt = NULL; - int bufflen = SCpnt->request_bufflen; unsigned long iflags; + int ret; if (upper_blk || (block + num > sdebug_capacity)) { mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, - 0, 18); + 0); return check_condition_result; } if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && (block <= OPT_MEDIUM_ERR_ADDR) && ((block + num) > OPT_MEDIUM_ERR_ADDR)) { mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, - 0, 18); + 0); /* claim unrecoverable read error */ return check_condition_result; } read_lock_irqsave(&atomic_rw, iflags); - sgcount = 0; - nbytes = bufflen; - /* printk(KERN_INFO "scsi_debug_read: block=%d, tot_bufflen=%d\n", - block, bufflen); */ - if (SCpnt->use_sg) { - sgcount = 0; - sgpnt = (struct scatterlist *) buff; - buff = scatg2virt(&sgpnt[sgcount]); - bufflen = sgpnt[sgcount].length; - } - do { - memcpy(buff, fake_storep + (block * SECT_SIZE), bufflen); - nbytes -= bufflen; - if (SCpnt->use_sg) { - block += bufflen >> POW2_SECT_SIZE; - sgcount++; - if (nbytes) { - buff = scatg2virt(&sgpnt[sgcount]); - bufflen = sgpnt[sgcount].length; - } - } else if (nbytes > 0) - printk(KERN_WARNING "scsi_debug:resp_read: unexpected " - "nbytes=%d\n", nbytes); - } while (nbytes); + ret = fill_from_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE), + num * SECT_SIZE); read_unlock_irqrestore(&atomic_rw, iflags); - return 0; + return ret; } static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block, int num, struct sdebug_dev_info * devip) { - unsigned char *buff = (unsigned char *) SCpnt->request_buffer; - int nbytes, sgcount; - struct scatterlist *sgpnt = NULL; - int bufflen = SCpnt->request_bufflen; unsigned long iflags; + int res; if (upper_blk || (block + num > sdebug_capacity)) { mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, - 0, 18); + 0); return check_condition_result; } write_lock_irqsave(&atomic_rw, iflags); - sgcount = 0; - nbytes = bufflen; - if (SCpnt->use_sg) { - sgcount = 0; - sgpnt = (struct scatterlist *) buff; - buff = scatg2virt(&sgpnt[sgcount]); - bufflen = sgpnt[sgcount].length; - } - do { - memcpy(fake_storep + (block * SECT_SIZE), buff, bufflen); - - nbytes -= bufflen; - if (SCpnt->use_sg) { - block += bufflen >> POW2_SECT_SIZE; - sgcount++; - if (nbytes) { - buff = scatg2virt(&sgpnt[sgcount]); - bufflen = sgpnt[sgcount].length; - } - } else if (nbytes > 0) - printk(KERN_WARNING "scsi_debug:resp_write: " - "unexpected nbytes=%d\n", nbytes); - } while (nbytes); + res = fetch_to_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE), + num * SECT_SIZE); write_unlock_irqrestore(&atomic_rw, iflags); + if (-1 == res) + return (DID_ERROR << 16); + else if ((res < (num * SECT_SIZE)) && + (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) + printk(KERN_INFO "scsi_debug: write: cdb indicated=%d, " + " IO sent=%d bytes\n", num * SECT_SIZE, res); return 0; } -static int resp_report_luns(unsigned char * cmd, unsigned char * buff, - int bufflen, struct sdebug_dev_info * devip) +#define SDEBUG_RLUN_ARR_SZ 128 + +static int resp_report_luns(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) { unsigned int alloc_len; int lun_cnt, i, upper; + unsigned char *cmd = (unsigned char *)scp->cmnd; int select_report = (int)cmd[2]; struct scsi_lun *one_lun; + unsigned char arr[SDEBUG_RLUN_ARR_SZ]; alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); if ((alloc_len < 16) || (select_report > 2)) { mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0, 18); + 0); return check_condition_result; } - if (bufflen > 8) { /* can produce response with up to 16k luns - (lun 0 to lun 16383) */ - memset(buff, 0, bufflen); - lun_cnt = scsi_debug_max_luns; - buff[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff; - buff[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff; - lun_cnt = min((int)((bufflen - 8) / sizeof(struct scsi_lun)), - lun_cnt); - one_lun = (struct scsi_lun *) &buff[8]; - for (i = 0; i < lun_cnt; i++) { - upper = (i >> 8) & 0x3f; - if (upper) - one_lun[i].scsi_lun[0] = - (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); - one_lun[i].scsi_lun[1] = i & 0xff; - } + /* can produce response with up to 16k luns (lun 0 to lun 16383) */ + memset(arr, 0, SDEBUG_RLUN_ARR_SZ); + lun_cnt = scsi_debug_max_luns; + arr[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff; + arr[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff; + lun_cnt = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / + sizeof(struct scsi_lun)), lun_cnt); + one_lun = (struct scsi_lun *) &arr[8]; + for (i = 0; i < lun_cnt; i++) { + upper = (i >> 8) & 0x3f; + if (upper) + one_lun[i].scsi_lun[0] = + (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); + one_lun[i].scsi_lun[1] = i & 0xff; } - return 0; + return fill_from_dev_buffer(scp, arr, + min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); } /* When timer goes off this function is called. */ @@ -1041,14 +1089,19 @@ open_devip->reset = 1; open_devip->used = 1; memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); - open_devip->sense_buff[0] = 0x70; + if (scsi_debug_dsense) + open_devip->sense_buff[0] = 0x72; + else { + open_devip->sense_buff[0] = 0x70; + open_devip->sense_buff[7] = 0xa; + } return open_devip; } return NULL; } static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, - int asc, int asq, int inbandLen) + int asc, int asq) { unsigned char * sbuff; @@ -1060,11 +1113,9 @@ sbuff[2] = asc; sbuff[3] = asq; } else { - if (inbandLen > SDEBUG_SENSE_LEN) - inbandLen = SDEBUG_SENSE_LEN; sbuff[0] = 0x70; /* fixed, current */ sbuff[2] = key; - sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0; + sbuff[7] = 0xa; /* implies 18 byte sense buffer */ sbuff[12] = asc; sbuff[13] = asq; } @@ -1355,7 +1406,7 @@ MODULE_PARM_DESC(num_tgts, "number of SCSI targets per host to simulate"); MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->..."); MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); -MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=4[SPC-2])"); +MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); static char sdebug_info[256]; @@ -1391,7 +1442,7 @@ if (1 != sscanf(arr, "%d", &pos)) return -EINVAL; scsi_debug_opts = pos; - if (scsi_debug_every_nth > 0) + if (scsi_debug_every_nth != 0) scsi_debug_cmnd_count = 0; return length; } @@ -1547,7 +1598,7 @@ { int nth; - if ((count > 0) && (1 == sscanf(buf, "%d", &nth)) && (nth >= 0)) { + if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { scsi_debug_every_nth = nth; scsi_debug_cmnd_count = 0; return count; diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c --- a/drivers/scsi/scsi_error.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/scsi_error.c 2004-11-29 21:56:02 -08:00 @@ -125,6 +125,7 @@ add_timer(&scmd->eh_timeout); } +EXPORT_SYMBOL(scsi_add_timer); /** * scsi_delete_timer - Delete/cancel timer for a given function. @@ -152,6 +153,7 @@ return rtn; } +EXPORT_SYMBOL(scsi_delete_timer); /** * scsi_times_out - Timeout function for normal scsi commands. @@ -214,6 +216,7 @@ return online; } +EXPORT_SYMBOL(scsi_block_when_processing_errors); #ifdef CONFIG_SCSI_LOGGING /** @@ -268,16 +271,42 @@ * * Return value: * SUCCESS or FAILED or NEEDS_RETRY + * + * Notes: + * When a deferred error is detected the current command has + * not been executed and needs retrying. **/ static int scsi_check_sense(struct scsi_cmnd *scmd) { - if (!SCSI_SENSE_VALID(scmd)) - return FAILED; + struct scsi_sense_hdr sshdr; - if (scmd->sense_buffer[2] & 0xe0) - return SUCCESS; + if (! scsi_command_normalize_sense(scmd, &sshdr)) + return FAILED; /* no valid sense data */ - switch (scmd->sense_buffer[2] & 0xf) { + if (scsi_sense_is_deferred(&sshdr)) + return NEEDS_RETRY; + + /* + * Previous logic looked for FILEMARK, EOM or ILI which are + * mainly associated with tapes and returned SUCCESS. + */ + if (sshdr.response_code == 0x70) { + /* fixed format */ + if (scmd->sense_buffer[2] & 0xe0) + return SUCCESS; + } else { + /* + * descriptor format: look for "stream commands sense data + * descriptor" (see SSC-3). Assume single sense data + * descriptor. Ignore ILI from SBC-2 READ LONG and WRITE LONG. + */ + if ((sshdr.additional_length > 3) && + (scmd->sense_buffer[8] == 0x4) && + (scmd->sense_buffer[11] & 0xe0)) + return SUCCESS; + } + + switch (sshdr.sense_key) { case NO_SENSE: return SUCCESS; case RECOVERED_ERROR: @@ -301,19 +330,15 @@ * if the device is in the process of becoming ready, we * should retry. */ - if ((scmd->sense_buffer[12] == 0x04) && - (scmd->sense_buffer[13] == 0x01)) { + if ((sshdr.asc == 0x04) && (sshdr.ascq == 0x01)) return NEEDS_RETRY; - } /* * if the device is not started, we need to wake * the error handler to start the motor */ if (scmd->device->allow_restart && - (scmd->sense_buffer[12] == 0x04) && - (scmd->sense_buffer[13] == 0x02)) { + (sshdr.asc == 0x04) && (sshdr.ascq == 0x02)) return FAILED; - } return SUCCESS; /* these three are not supported */ @@ -1358,7 +1383,8 @@ return SUCCESS; case RESERVATION_CONFLICT: - printk("scsi%d (%d,%d,%d) : reservation conflict\n", + printk(KERN_INFO "scsi: reservation conflict: host" + " %d channel %d id %d lun %d\n", scmd->device->host->host_no, scmd->device->channel, scmd->device->id, scmd->device->lun); return SUCCESS; /* causes immediate i/o error */ @@ -1729,6 +1755,7 @@ } } } +EXPORT_SYMBOL(scsi_report_bus_reset); /* * Function: scsi_report_device_reset() @@ -1764,6 +1791,7 @@ } } } +EXPORT_SYMBOL(scsi_report_device_reset); static void scsi_reset_provider_done_command(struct scsi_cmnd *scmd) @@ -1843,6 +1871,7 @@ scsi_next_command(scmd); return rtn; } +EXPORT_SYMBOL(scsi_reset_provider); /** * scsi_normalize_sense - normalize main elements from either fixed or diff -Nru a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c --- a/drivers/scsi/scsi_ioctl.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/scsi_ioctl.c 2004-11-29 21:56:02 -08:00 @@ -21,6 +21,7 @@ #include #include #include +#include #include "scsi_logging.h" @@ -94,12 +95,13 @@ { struct scsi_request *sreq; int result; + struct scsi_sense_hdr sshdr; SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd)); sreq = scsi_allocate_request(sdev, GFP_KERNEL); if (!sreq) { - printk("SCSI internal ioctl failed, no memory\n"); + printk(KERN_WARNING "SCSI internal ioctl failed, no memory\n"); return -ENOMEM; } @@ -108,17 +110,21 @@ SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", sreq->sr_result)); - if (driver_byte(sreq->sr_result)) { - switch (sreq->sr_sense_buffer[2] & 0xf) { + if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && + (scsi_request_normalize_sense(sreq, &sshdr))) { + switch (sshdr.sense_key) { case ILLEGAL_REQUEST: if (cmd[0] == ALLOW_MEDIUM_REMOVAL) sdev->lockable = 0; else - printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); + printk(KERN_INFO "ioctl_internal_command: " + "ILLEGAL REQUEST asc=0x%x ascq=0x%x\n", + sshdr.asc, sshdr.ascq); break; case NOT_READY: /* This happens if there is no disc in drive */ if (sdev->removable && (cmd[0] != TEST_UNIT_READY)) { - printk(KERN_INFO "Device not ready. Make sure there is a disc in the drive.\n"); + printk(KERN_INFO "Device not ready. Make sure" + " there is a disc in the drive.\n"); break; } case UNIT_ATTENTION: @@ -128,16 +134,15 @@ break; } default: /* Fall through for non-removable media */ - printk("SCSI error: host %d id %d lun %d return code = %x\n", + printk(KERN_INFO "ioctl_internal_command: <%d %d %d " + "%d> return code = %x\n", sdev->host->host_no, + sdev->channel, sdev->id, sdev->lun, sreq->sr_result); - printk("\tSense class %x, sense error %x, extended sense %x\n", - sense_class(sreq->sr_sense_buffer[0]), - sense_error(sreq->sr_sense_buffer[0]), - sreq->sr_sense_buffer[2] & 0xf); - + scsi_print_req_sense(" ", sreq); + break; } } @@ -168,6 +173,7 @@ sdev->locked = (state == SCSI_REMOVAL_PREVENT); return ret; } +EXPORT_SYMBOL(scsi_set_medium_removal); /* * This interface is deprecated - users should use the scsi generic (sg) @@ -349,6 +355,7 @@ kfree(buf); return result; } +EXPORT_SYMBOL(scsi_ioctl_send_command); /* * The scsi_ioctl_get_pci() function places into arg the value @@ -401,7 +408,8 @@ case SCSI_IOCTL_SYNC: case SCSI_IOCTL_START_UNIT: case SCSI_IOCTL_STOP_UNIT: - printk(KERN_WARNING "program %s is using a deprecated SCSI ioctl, please convert it to SG_IO\n", current->comm); + printk(KERN_WARNING "program %s is using a deprecated SCSI " + "ioctl, please convert it to SG_IO\n", current->comm); break; default: break; @@ -457,6 +465,7 @@ } return -EINVAL; } +EXPORT_SYMBOL(scsi_ioctl); /* * the scsi_nonblock_ioctl() function is designed for ioctls which may diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/scsi_lib.c 2004-11-29 21:56:02 -08:00 @@ -233,7 +233,8 @@ */ scsi_insert_special_req(sreq, 1); } - +EXPORT_SYMBOL(scsi_do_req); + static void scsi_wait_done(struct scsi_cmnd *cmd) { struct request *req = cmd->request; @@ -267,6 +268,7 @@ __scsi_release_request(sreq); } +EXPORT_SYMBOL(scsi_wait_req); /* * Function: scsi_init_cmd_errh() @@ -718,7 +720,7 @@ clear_errors = 0; if (scsi_command_normalize_sense(cmd, &sshdr)) { /* - * SG_IO wants to know about deferred errors + * SG_IO wants current and deferred errors */ int len = 8 + cmd->sense_buffer[7]; @@ -844,9 +846,10 @@ cmd = scsi_end_request(cmd, 0, this_count, 1); return; case VOLUME_OVERFLOW: - printk("scsi%d: ERROR on channel %d, id %d, lun %d, CDB: ", - cmd->device->host->host_no, (int) cmd->device->channel, - (int) cmd->device->id, (int) cmd->device->lun); + printk(KERN_INFO "Volume overflow <%d %d %d %d> CDB: ", + cmd->device->host->host_no, + (int)cmd->device->channel, + (int)cmd->device->id, (int)cmd->device->lun); __scsi_print_command(cmd->data_cmnd); scsi_print_sense("", cmd); cmd = scsi_end_request(cmd, 0, block_bytes, 1); @@ -865,8 +868,8 @@ return; } if (result) { - printk("SCSI error : <%d %d %d %d> return code = 0x%x\n", - cmd->device->host->host_no, + printk(KERN_INFO "SCSI error : <%d %d %d %d> return code " + "= 0x%x\n", cmd->device->host->host_no, cmd->device->channel, cmd->device->id, cmd->device->lun, result); @@ -884,6 +887,7 @@ cmd = scsi_end_request(cmd, 0, block_bytes, 1); } } +EXPORT_SYMBOL(scsi_io_completion); /* * Function: scsi_init_io() @@ -1344,6 +1348,7 @@ return bounce_limit; } +EXPORT_SYMBOL(scsi_calculate_bounce_limit); struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) { @@ -1393,6 +1398,7 @@ { shost->host_self_blocked = 1; } +EXPORT_SYMBOL(scsi_block_requests); /* * Function: scsi_unblock_requests() @@ -1419,6 +1425,7 @@ shost->host_self_blocked = 0; scsi_run_host_queues(shost); } +EXPORT_SYMBOL(scsi_unblock_requests); int __init scsi_init_queue(void) { @@ -1553,6 +1560,7 @@ return sreq->sr_result; } +EXPORT_SYMBOL(__scsi_mode_sense); /** * scsi_mode_sense - issue a mode sense, falling back from 10 to @@ -1587,6 +1595,7 @@ return ret; } +EXPORT_SYMBOL(scsi_mode_sense); int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries) @@ -1604,12 +1613,15 @@ sreq->sr_data_direction = DMA_NONE; scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); - if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && - ((sreq->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION || - (sreq->sr_sense_buffer[2] & 0x0f) == NOT_READY) && - sdev->removable) { - sdev->changed = 1; - sreq->sr_result = 0; + if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && sdev->removable) { + struct scsi_sense_hdr sshdr; + + if ((scsi_request_normalize_sense(sreq, &sshdr)) && + ((sshdr.sense_key == UNIT_ATTENTION) || + (sshdr.sense_key == NOT_READY))) { + sdev->changed = 1; + sreq->sr_result = 0; + } } result = sreq->sr_result; scsi_release_request(sreq); @@ -1668,6 +1680,7 @@ case SDEV_CREATED: case SDEV_RUNNING: case SDEV_QUIESCE: + case SDEV_BLOCK: break; default: goto illegal; diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/scsi_scan.c 2004-11-29 21:56:02 -08:00 @@ -39,6 +39,7 @@ #include #include #include +#include #include "scsi_priv.h" #include "scsi_logging.h" @@ -253,6 +254,11 @@ sdev->request_queue->queuedata = sdev; scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); + if (shost->transportt->device_setup) { + if (shost->transportt->device_setup(sdev)) + goto out_free_queue; + } + if (shost->hostt->slave_alloc) { ret = shost->hostt->slave_alloc(sdev); if (ret) { @@ -262,15 +268,10 @@ */ if (ret == -ENXIO) display_failure_msg = 0; - goto out_free_queue; + goto out_device_destroy; } } - if (shost->transportt->device_setup) { - if (shost->transportt->device_setup(sdev)) - goto out_cleanup_slave; - } - if (scsi_sysfs_device_initialize(sdev) != 0) goto out_cleanup_slave; @@ -290,6 +291,9 @@ out_cleanup_slave: if (shost->hostt->slave_destroy) shost->hostt->slave_destroy(sdev); +out_device_destroy: + if (shost->transportt->device_destroy) + shost->transportt->device_destroy(sdev); out_free_queue: scsi_free_queue(sdev->request_queue); out_free_dev: @@ -322,6 +326,7 @@ int first_inquiry_len, try_inquiry_len, next_inquiry_len; int response_len = 0; int pass, count; + struct scsi_sense_hdr sshdr; *bflags = 0; @@ -357,17 +362,20 @@ sreq->sr_result)); if (sreq->sr_result) { - - /* not-ready to ready transition or power-on - good */ - /* dpg: bogus? INQUIRY never returns UNIT_ATTENTION */ - /* Supposedly, but many buggy devices do so anyway. */ + /* + * not-ready to ready transition [asc/ascq=0x28/0x0] + * or power-on, reset [asc/ascq=0x29/0x0], continue. + * INQUIRY should not yield UNIT_ATTENTION + * but many buggy devices do so anyway. + */ if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && - (sreq->sr_sense_buffer[2] & 0xf) == - UNIT_ATTENTION && - (sreq->sr_sense_buffer[12] == 0x28 || - sreq->sr_sense_buffer[12] == 0x29) && - sreq->sr_sense_buffer[13] == 0) - continue; + scsi_request_normalize_sense(sreq, &sshdr)) { + if ((sshdr.sense_key == UNIT_ATTENTION) && + ((sshdr.asc == 0x28) || + (sshdr.asc == 0x29)) && + (sshdr.ascq == 0)) + continue; + } } break; } @@ -741,6 +749,8 @@ } else { if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); + if (sdev->host->transportt->device_destroy) + sdev->host->transportt->device_destroy(sdev); put_device(&sdev->sdev_gendev); } out: @@ -893,6 +903,7 @@ struct scsi_lun *lunp, *lun_data; struct scsi_request *sreq; u8 *data; + struct scsi_sense_hdr sshdr; /* * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set. @@ -970,9 +981,12 @@ " %s (try %d) result 0x%x\n", sreq->sr_result ? "failed" : "successful", retries, sreq->sr_result)); - if (sreq->sr_result == 0 || - sreq->sr_sense_buffer[2] != UNIT_ATTENTION) + if (sreq->sr_result == 0) break; + else if (scsi_request_normalize_sense(sreq, &sshdr)) { + if (sshdr.sense_key != UNIT_ATTENTION) + break; + } } if (sreq->sr_result) { @@ -1082,6 +1096,7 @@ return sdev; } +EXPORT_SYMBOL(__scsi_add_device); void scsi_rescan_device(struct device *dev) { @@ -1097,6 +1112,7 @@ module_put(drv->owner); } } +EXPORT_SYMBOL(scsi_rescan_device); /** * scsi_scan_target - scan a target id, possibly including all LUNs on the @@ -1225,6 +1241,20 @@ scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD, SCAN_WILD_CARD, 0); } +EXPORT_SYMBOL(scsi_scan_host); + +/** + * scsi_scan_single_target - scan the given SCSI target + * @shost: adapter to scan + * @chan: channel to scan + * @id: target id to scan + **/ +void scsi_scan_single_target(struct Scsi_Host *shost, + unsigned int chan, unsigned int id) +{ + scsi_scan_host_selected(shost, chan, id, SCAN_WILD_CARD, 1); +} +EXPORT_SYMBOL(scsi_scan_single_target); void scsi_forget_host(struct Scsi_Host *shost) { @@ -1279,6 +1309,7 @@ } return sdev; } +EXPORT_SYMBOL(scsi_get_host_dev); /* * Function: scsi_free_host_dev() @@ -1299,5 +1330,9 @@ if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); + if (sdev->host->transportt->device_destroy) + sdev->host->transportt->device_destroy(sdev); put_device(&sdev->sdev_gendev); } +EXPORT_SYMBOL(scsi_free_host_dev); + diff -Nru a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c --- a/drivers/scsi/scsi_syms.c 2004-11-29 21:56:02 -08:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,97 +0,0 @@ -/* - * We should not even be trying to compile this if we are not doing - * a module. - */ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi_logging.h" - - -/* - * This source file contains the symbol table used by scsi loadable - * modules. - */ -EXPORT_SYMBOL(scsi_register_driver); -EXPORT_SYMBOL(scsi_register_interface); -EXPORT_SYMBOL(scsi_host_alloc); -EXPORT_SYMBOL(scsi_add_host); -EXPORT_SYMBOL(scsi_scan_host); -EXPORT_SYMBOL(scsi_remove_host); -EXPORT_SYMBOL(scsi_host_get); -EXPORT_SYMBOL(scsi_host_put); -EXPORT_SYMBOL(scsi_host_lookup); -EXPORT_SYMBOL(scsi_register); -EXPORT_SYMBOL(scsi_unregister); -EXPORT_SYMBOL(scsicam_bios_param); -EXPORT_SYMBOL(scsi_partsize); -EXPORT_SYMBOL(scsi_bios_ptable); -EXPORT_SYMBOL(scsi_ioctl); -EXPORT_SYMBOL(scsi_print_command); -EXPORT_SYMBOL(__scsi_print_command); -EXPORT_SYMBOL(scsi_print_sense); -EXPORT_SYMBOL(scsi_print_req_sense); -EXPORT_SYMBOL(scsi_print_msg); -EXPORT_SYMBOL(scsi_print_status); -EXPORT_SYMBOL(scsi_sense_key_string); -EXPORT_SYMBOL(scsi_extd_sense_format); -EXPORT_SYMBOL(scsi_block_when_processing_errors); -EXPORT_SYMBOL(scsi_ioctl_send_command); -EXPORT_SYMBOL(scsi_set_medium_removal); -#if defined(CONFIG_SCSI_LOGGING) /* { */ -EXPORT_SYMBOL(scsi_logging_level); -#endif - -EXPORT_SYMBOL(scsi_allocate_request); -EXPORT_SYMBOL(scsi_release_request); -EXPORT_SYMBOL(scsi_wait_req); -EXPORT_SYMBOL(scsi_do_req); -EXPORT_SYMBOL(scsi_get_command); -EXPORT_SYMBOL(scsi_put_command); - -EXPORT_SYMBOL(scsi_report_bus_reset); -EXPORT_SYMBOL(scsi_report_device_reset); -EXPORT_SYMBOL(scsi_block_requests); -EXPORT_SYMBOL(scsi_unblock_requests); -EXPORT_SYMBOL(scsi_adjust_queue_depth); -EXPORT_SYMBOL(scsi_track_queue_full); - -EXPORT_SYMBOL(scsi_get_host_dev); -EXPORT_SYMBOL(scsi_free_host_dev); - -EXPORT_SYMBOL(scsi_io_completion); - -EXPORT_SYMBOL(__scsi_add_device); -EXPORT_SYMBOL(scsi_remove_device); -EXPORT_SYMBOL(scsi_device_cancel); - -EXPORT_SYMBOL(__scsi_mode_sense); -EXPORT_SYMBOL(scsi_mode_sense); - -/* - * This symbol is for the highlevel drivers (e.g. sg) only. - */ -EXPORT_SYMBOL(scsi_reset_provider); - -EXPORT_SYMBOL(scsi_device_types); - -/* - * This is for st to find the bounce limit - */ -EXPORT_SYMBOL(scsi_calculate_bounce_limit); - -/* - * Externalize timers so that HBAs can safely start/restart commands. - */ -EXPORT_SYMBOL(scsi_add_timer); -EXPORT_SYMBOL(scsi_delete_timer); diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c --- a/drivers/scsi/scsi_sysfs.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/scsi_sysfs.c 2004-11-29 21:56:02 -08:00 @@ -169,7 +169,10 @@ if (delete) { struct scsi_target *starget = to_scsi_target(parent); + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); if (!starget->create) { + if (shost->transportt->target_destroy) + shost->transportt->target_destroy(starget); device_del(parent); if (starget->transport_classdev.class) class_device_unregister(&starget->transport_classdev); @@ -601,11 +604,14 @@ scsi_device_set_state(sdev, SDEV_DEL); if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); + if (sdev->host->transportt->device_destroy) + sdev->host->transportt->device_destroy(sdev); put_device(&sdev->sdev_gendev); out: up(&shost->scan_mutex); } +EXPORT_SYMBOL(scsi_remove_device); int scsi_register_driver(struct device_driver *drv) { @@ -613,6 +619,7 @@ return driver_register(drv); } +EXPORT_SYMBOL(scsi_register_driver); int scsi_register_interface(struct class_interface *intf) { @@ -620,6 +627,7 @@ return class_interface_register(intf); } +EXPORT_SYMBOL(scsi_register_interface); static struct class_device_attribute *class_attr_overridden( diff -Nru a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c --- a/drivers/scsi/scsi_transport_fc.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/scsi_transport_fc.c 2004-11-29 21:56:02 -08:00 @@ -29,6 +29,8 @@ static void transport_class_release(struct class_device *class_dev); static void host_class_release(struct class_device *class_dev); +static void fc_timeout_blocked_host(void *data); +static void fc_timeout_blocked_tgt(void *data); #define FC_STARGET_NUM_ATTRS 4 /* increase this if you add attributes */ #define FC_STARGET_OTHER_ATTRS 0 /* increase this if you add "always on" @@ -87,10 +89,18 @@ fc_starget_port_name(starget) = -1; fc_starget_port_id(starget) = -1; fc_starget_dev_loss_tmo(starget) = -1; - init_timer(&fc_starget_dev_loss_timer(starget)); + INIT_WORK(&fc_starget_dev_loss_work(starget), + fc_timeout_blocked_tgt, starget); return 0; } +static void fc_destroy_starget(struct scsi_target *starget) +{ + /* Stop the target timer */ + if (cancel_delayed_work(&fc_starget_dev_loss_work(starget))) + flush_scheduled_work(); +} + static int fc_setup_host_transport_attrs(struct Scsi_Host *shost) { /* @@ -99,10 +109,18 @@ * all transport attributes to valid values per host. */ fc_host_link_down_tmo(shost) = -1; - init_timer(&fc_host_link_down_timer(shost)); + INIT_WORK(&fc_host_link_down_work(shost), + fc_timeout_blocked_host, shost); return 0; } +static void fc_destroy_host(struct Scsi_Host *shost) +{ + /* Stop the host timer */ + if (cancel_delayed_work(&fc_host_link_down_work(shost))) + flush_scheduled_work(); +} + static void transport_class_release(struct class_device *class_dev) { struct scsi_target *starget = transport_class_to_starget(class_dev); @@ -277,11 +295,13 @@ i->t.target_attrs = &i->starget_attrs[0]; i->t.target_class = &fc_transport_class; i->t.target_setup = &fc_setup_starget_transport_attrs; + i->t.target_destroy = &fc_destroy_starget; i->t.target_size = sizeof(struct fc_starget_attrs); i->t.host_attrs = &i->host_attrs[0]; i->t.host_class = &fc_host_class; i->t.host_setup = &fc_setup_host_transport_attrs; + i->t.host_destroy = &fc_destroy_host; i->t.host_size = sizeof(struct fc_host_attrs); i->f = ft; @@ -353,7 +373,7 @@ * that fail to recover in the alloted time. * @data: scsi target that failed to reappear in the alloted time. **/ -static void fc_timeout_blocked_tgt(unsigned long data) +static void fc_timeout_blocked_tgt(void *data) { struct scsi_target *starget = (struct scsi_target *)data; @@ -388,7 +408,7 @@ fc_target_block(struct scsi_target *starget) { int timeout = fc_starget_dev_loss_tmo(starget); - struct timer_list *timer = &fc_starget_dev_loss_timer(starget); + struct work_struct *work = &fc_starget_dev_loss_work(starget); if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT) return -EINVAL; @@ -396,10 +416,7 @@ device_for_each_child(&starget->dev, NULL, fc_device_block); /* The scsi lld blocks this target for the timeout period only. */ - timer->data = (unsigned long)starget; - timer->expires = jiffies + timeout * HZ; - timer->function = fc_timeout_blocked_tgt; - add_timer(timer); + schedule_delayed_work(work, timeout * HZ); return 0; } @@ -424,7 +441,8 @@ * failure as the state machine state change will validate the * transaction. */ - del_timer_sync(&fc_starget_dev_loss_timer(starget)); + if (cancel_delayed_work(&fc_starget_dev_loss_work(starget))) + flush_scheduled_work(); device_for_each_child(&starget->dev, NULL, fc_device_unblock); } @@ -436,7 +454,7 @@ * @data: scsi host that failed to recover its devices in the alloted * time. **/ -static void fc_timeout_blocked_host(unsigned long data) +static void fc_timeout_blocked_host(void *data) { struct Scsi_Host *shost = (struct Scsi_Host *)data; struct scsi_device *sdev; @@ -475,7 +493,7 @@ { struct scsi_device *sdev; int timeout = fc_host_link_down_tmo(shost); - struct timer_list *timer = &fc_host_link_down_timer(shost); + struct work_struct *work = &fc_host_link_down_work(shost); if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT) return -EINVAL; @@ -484,11 +502,7 @@ scsi_internal_device_block(sdev); } - /* The scsi lld blocks this host for the timeout period only. */ - timer->data = (unsigned long)shost; - timer->expires = jiffies + timeout * HZ; - timer->function = fc_timeout_blocked_host; - add_timer(timer); + schedule_delayed_work(work, timeout * HZ); return 0; } @@ -516,7 +530,9 @@ * failure as the state machine state change will validate the * transaction. */ - del_timer_sync(&fc_host_link_down_timer(shost)); + if (cancel_delayed_work(&fc_host_link_down_work(shost))) + flush_scheduled_work(); + shost_for_each_device(sdev, shost) { scsi_internal_device_unblock(sdev); } diff -Nru a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/scsi/scsi_transport_iscsi.c 2004-11-29 21:56:02 -08:00 @@ -0,0 +1,355 @@ +/* + * iSCSI transport class definitions + * + * Copyright (C) IBM Corporation, 2004 + * Copyright (C) Mike Christie, 2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include +#include +#include +#include +#include +#include + +#define ISCSI_SESSION_ATTRS 20 +#define ISCSI_HOST_ATTRS 2 + +struct iscsi_internal { + struct scsi_transport_template t; + struct iscsi_function_template *fnt; + /* + * We do not have any private or other attrs. + */ + struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1]; + struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1]; +}; + +#define to_iscsi_internal(tmpl) container_of(tmpl, struct iscsi_internal, t) + +static void iscsi_transport_class_release(struct class_device *class_dev) +{ + struct scsi_target *starget = transport_class_to_starget(class_dev); + put_device(&starget->dev); +} + +struct class iscsi_transport_class = { + .name = "iscsi_transport_class", + .release = iscsi_transport_class_release, +}; + +static void iscsi_host_class_release(struct class_device *class_dev) +{ + struct Scsi_Host *shost = transport_class_to_shost(class_dev); + put_device(&shost->shost_gendev); +} + +struct class iscsi_host_class = { + .name = "iscsi_host", + .release = iscsi_host_class_release, +}; + +/* + * iSCSI target and session attrs + */ +#define iscsi_session_show_fn(field, format) \ + \ +static ssize_t \ +show_session_##field(struct class_device *cdev, char *buf) \ +{ \ + struct scsi_target *starget = transport_class_to_starget(cdev); \ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ + struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \ + \ + if (i->fnt->get_##field) \ + i->fnt->get_##field(starget); \ + return snprintf(buf, 20, format"\n", iscsi_##field(starget)); \ +} + +#define iscsi_session_rd_attr(field, format) \ + iscsi_session_show_fn(field, format) \ +static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_##field, NULL); + +iscsi_session_rd_attr(tpgt, "%hu"); +iscsi_session_rd_attr(tsih, "%2x"); +iscsi_session_rd_attr(max_recv_data_segment_len, "%u"); +iscsi_session_rd_attr(max_burst_len, "%u"); +iscsi_session_rd_attr(first_burst_len, "%u"); +iscsi_session_rd_attr(def_time2wait, "%hu"); +iscsi_session_rd_attr(def_time2retain, "%hu"); +iscsi_session_rd_attr(max_outstanding_r2t, "%hu"); +iscsi_session_rd_attr(erl, "%d"); + + +#define iscsi_session_show_bool_fn(field) \ + \ +static ssize_t \ +show_session_bool_##field(struct class_device *cdev, char *buf) \ +{ \ + struct scsi_target *starget = transport_class_to_starget(cdev); \ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ + struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \ + \ + if (i->fnt->get_##field) \ + i->fnt->get_##field(starget); \ + \ + if (iscsi_##field(starget)) \ + return sprintf(buf, "Yes\n"); \ + return sprintf(buf, "No\n"); \ +} + +#define iscsi_session_rd_bool_attr(field) \ + iscsi_session_show_bool_fn(field) \ +static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_bool_##field, NULL); + +iscsi_session_rd_bool_attr(initial_r2t); +iscsi_session_rd_bool_attr(immediate_data); +iscsi_session_rd_bool_attr(data_pdu_in_order); +iscsi_session_rd_bool_attr(data_sequence_in_order); + +#define iscsi_session_show_digest_fn(field) \ + \ +static ssize_t \ +show_##field(struct class_device *cdev, char *buf) \ +{ \ + struct scsi_target *starget = transport_class_to_starget(cdev); \ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ + struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \ + \ + if (i->fnt->get_##field) \ + i->fnt->get_##field(starget); \ + \ + if (iscsi_##field(starget)) \ + return sprintf(buf, "CRC32C\n"); \ + return sprintf(buf, "None\n"); \ +} + +#define iscsi_session_rd_digest_attr(field) \ + iscsi_session_show_digest_fn(field) \ +static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); + +iscsi_session_rd_digest_attr(header_digest); +iscsi_session_rd_digest_attr(data_digest); + +static ssize_t +show_port(struct class_device *cdev, char *buf) +{ + struct scsi_target *starget = transport_class_to_starget(cdev); + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct iscsi_internal *i = to_iscsi_internal(shost->transportt); + + if (i->fnt->get_port) + i->fnt->get_port(starget); + + return snprintf(buf, 20, "%hu\n", ntohs(iscsi_port(starget))); +} +static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL); + +static ssize_t +show_ip_address(struct class_device *cdev, char *buf) +{ + struct scsi_target *starget = transport_class_to_starget(cdev); + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct iscsi_internal *i = to_iscsi_internal(shost->transportt); + + if (i->fnt->get_ip_address) + i->fnt->get_ip_address(starget); + + if (iscsi_addr_type(starget) == AF_INET) + return sprintf(buf, "%u.%u.%u.%u\n", + NIPQUAD(iscsi_sin_addr(starget))); + else if(iscsi_addr_type(starget) == AF_INET6) + return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + NIP6(iscsi_sin6_addr(starget))); + return -EINVAL; +} +static CLASS_DEVICE_ATTR(ip_address, S_IRUGO, show_ip_address, NULL); + +static ssize_t +show_isid(struct class_device *cdev, char *buf) +{ + struct scsi_target *starget = transport_class_to_starget(cdev); + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct iscsi_internal *i = to_iscsi_internal(shost->transportt); + + if (i->fnt->get_isid) + i->fnt->get_isid(starget); + + return sprintf(buf, "%02x%02x%02x%02x%02x%02x\n", + iscsi_isid(starget)[0], iscsi_isid(starget)[1], + iscsi_isid(starget)[2], iscsi_isid(starget)[3], + iscsi_isid(starget)[4], iscsi_isid(starget)[5]); +} +static CLASS_DEVICE_ATTR(isid, S_IRUGO, show_isid, NULL); + +/* + * This is used for iSCSI names. Normally, we follow + * the transport class convention of having the lld + * set the field, but in these cases the value is + * too large. + */ +#define iscsi_session_show_str_fn(field) \ + \ +static ssize_t \ +show_session_str_##field(struct class_device *cdev, char *buf) \ +{ \ + ssize_t ret = 0; \ + struct scsi_target *starget = transport_class_to_starget(cdev); \ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ + struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \ + \ + if (i->fnt->get_##field) \ + ret = i->fnt->get_##field(starget, buf, PAGE_SIZE); \ + return ret; \ +} + +#define iscsi_session_rd_str_attr(field) \ + iscsi_session_show_str_fn(field) \ +static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_str_##field, NULL); + +iscsi_session_rd_str_attr(target_name); +iscsi_session_rd_str_attr(target_alias); + +/* + * iSCSI host attrs + */ + +/* + * Again, this is used for iSCSI names. Normally, we follow + * the transport class convention of having the lld set + * the field, but in these cases the value is too large. + */ +#define iscsi_host_show_str_fn(field) \ + \ +static ssize_t \ +show_host_str_##field(struct class_device *cdev, char *buf) \ +{ \ + int ret = 0; \ + struct Scsi_Host *shost = transport_class_to_shost(cdev); \ + struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \ + \ + if (i->fnt->get_##field) \ + ret = i->fnt->get_##field(shost, buf, PAGE_SIZE); \ + return ret; \ +} + +#define iscsi_host_rd_str_attr(field) \ + iscsi_host_show_str_fn(field) \ +static CLASS_DEVICE_ATTR(field, S_IRUGO, show_host_str_##field, NULL); + +iscsi_host_rd_str_attr(initiator_name); +iscsi_host_rd_str_attr(initiator_alias); + +#define SETUP_SESSION_RD_ATTR(field) \ + if (i->fnt->show_##field) { \ + i->session_attrs[count] = &class_device_attr_##field; \ + count++; \ + } + +#define SETUP_HOST_RD_ATTR(field) \ + if (i->fnt->show_##field) { \ + i->host_attrs[count] = &class_device_attr_##field; \ + count++; \ + } + +struct scsi_transport_template * +iscsi_attach_transport(struct iscsi_function_template *fnt) +{ + struct iscsi_internal *i = kmalloc(sizeof(struct iscsi_internal), + GFP_KERNEL); + int count = 0; + + if (unlikely(!i)) + return NULL; + + memset(i, 0, sizeof(struct iscsi_internal)); + i->fnt = fnt; + + i->t.target_attrs = &i->session_attrs[0]; + i->t.target_class = &iscsi_transport_class; + i->t.target_setup = NULL; + i->t.target_size = sizeof(struct iscsi_class_session); + + SETUP_SESSION_RD_ATTR(tsih); + SETUP_SESSION_RD_ATTR(isid); + SETUP_SESSION_RD_ATTR(header_digest); + SETUP_SESSION_RD_ATTR(data_digest); + SETUP_SESSION_RD_ATTR(target_name); + SETUP_SESSION_RD_ATTR(target_alias); + SETUP_SESSION_RD_ATTR(port); + SETUP_SESSION_RD_ATTR(tpgt); + SETUP_SESSION_RD_ATTR(ip_address); + SETUP_SESSION_RD_ATTR(initial_r2t); + SETUP_SESSION_RD_ATTR(immediate_data); + SETUP_SESSION_RD_ATTR(max_recv_data_segment_len); + SETUP_SESSION_RD_ATTR(max_burst_len); + SETUP_SESSION_RD_ATTR(first_burst_len); + SETUP_SESSION_RD_ATTR(def_time2wait); + SETUP_SESSION_RD_ATTR(def_time2retain); + SETUP_SESSION_RD_ATTR(max_outstanding_r2t); + SETUP_SESSION_RD_ATTR(data_pdu_in_order); + SETUP_SESSION_RD_ATTR(data_sequence_in_order); + SETUP_SESSION_RD_ATTR(erl); + + BUG_ON(count > ISCSI_SESSION_ATTRS); + i->session_attrs[count] = NULL; + + i->t.host_attrs = &i->host_attrs[0]; + i->t.host_class = &iscsi_host_class; + i->t.host_setup = NULL; + i->t.host_size = 0; + + count = 0; + SETUP_HOST_RD_ATTR(initiator_name); + SETUP_HOST_RD_ATTR(initiator_alias); + + BUG_ON(count > ISCSI_HOST_ATTRS); + i->host_attrs[count] = NULL; + + return &i->t; +} + +EXPORT_SYMBOL(iscsi_attach_transport); + +void iscsi_release_transport(struct scsi_transport_template *t) +{ + struct iscsi_internal *i = to_iscsi_internal(t); + kfree(i); +} + +EXPORT_SYMBOL(iscsi_release_transport); + +static __init int iscsi_transport_init(void) +{ + int err = class_register(&iscsi_transport_class); + + if (err) + return err; + return class_register(&iscsi_host_class); +} + +static void __exit iscsi_transport_exit(void) +{ + class_unregister(&iscsi_host_class); + class_unregister(&iscsi_transport_class); +} + +module_init(iscsi_transport_init); +module_exit(iscsi_transport_exit); + +MODULE_AUTHOR("Mike Christie"); +MODULE_DESCRIPTION("iSCSI Transport Attributes"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c --- a/drivers/scsi/scsicam.c 2004-11-29 21:56:02 -08:00 +++ b/drivers/scsi/scsicam.c 2004-11-29 21:56:02 -08:00 @@ -41,6 +41,7 @@ } return res; } +EXPORT_SYMBOL(scsi_bios_ptable); /* * Function : int scsicam_bios_param (struct block_device *bdev, ector_t capacity, int *ip) @@ -94,6 +95,7 @@ return 0; } +EXPORT_SYMBOL(scsicam_bios_param); /* * Function : static int scsi_partsize(unsigned char *buf, unsigned long @@ -175,6 +177,7 @@ } return -1; } +EXPORT_SYMBOL(scsi_partsize); /* * Function : static int setsize(unsigned long capacity,unsigned int *cyls, diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h 2004-11-29 21:56:02 -08:00 +++ b/include/linux/pci_ids.h 2004-11-29 21:56:02 -08:00 @@ -176,10 +176,20 @@ #define PCI_DEVICE_ID_LSI_FC919 0x0624 #define PCI_DEVICE_ID_LSI_FC919_LAN 0x0625 #define PCI_DEVICE_ID_LSI_FC929X 0x0626 +#define PCI_DEVICE_ID_LSI_FC939X 0x0642 +#define PCI_DEVICE_ID_LSI_FC949X 0x0640 #define PCI_DEVICE_ID_LSI_FC919X 0x0628 #define PCI_DEVICE_ID_NCR_YELLOWFIN 0x0701 #define PCI_DEVICE_ID_LSI_61C102 0x0901 #define PCI_DEVICE_ID_LSI_63C815 0x1000 +#define PCI_DEVICE_ID_LSI_SAS1064 0x0050 +#define PCI_DEVICE_ID_LSI_SAS1066 0x005E +#define PCI_DEVICE_ID_LSI_SAS1068 0x0054 +#define PCI_DEVICE_ID_LSI_SAS1064A 0x005C +#define PCI_DEVICE_ID_LSI_SAS1064E 0x0056 +#define PCI_DEVICE_ID_LSI_SAS1066E 0x005A +#define PCI_DEVICE_ID_LSI_SAS1068E 0x0058 +#define PCI_DEVICE_ID_LSI_SAS1078 0x0060 #define PCI_VENDOR_ID_ATI 0x1002 /* Mach64 */ diff -Nru a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h --- a/include/scsi/scsi_host.h 2004-11-29 21:56:02 -08:00 +++ b/include/scsi/scsi_host.h 2004-11-29 21:56:02 -08:00 @@ -527,6 +527,9 @@ extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int); extern int __must_check scsi_add_host(struct Scsi_Host *, struct device *); extern void scsi_scan_host(struct Scsi_Host *); +extern void scsi_scan_single_target(struct Scsi_Host *, unsigned int, + unsigned int); +extern void scsi_rescan_device(struct device *); extern void scsi_remove_host(struct Scsi_Host *); extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *); extern void scsi_host_put(struct Scsi_Host *t); diff -Nru a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h --- a/include/scsi/scsi_transport.h 2004-11-29 21:56:02 -08:00 +++ b/include/scsi/scsi_transport.h 2004-11-29 21:56:02 -08:00 @@ -40,6 +40,11 @@ int (*target_setup)(struct scsi_target *); int (*host_setup)(struct Scsi_Host *); + /* Destructor functions */ + void (*device_destroy)(struct scsi_device *); + void (*target_destroy)(struct scsi_target *); + void (*host_destroy)(struct Scsi_Host *); + /* The size of the specific transport attribute structure (a * space of this size will be left at the end of the * scsi_* structure */ diff -Nru a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h --- a/include/scsi/scsi_transport_fc.h 2004-11-29 21:56:02 -08:00 +++ b/include/scsi/scsi_transport_fc.h 2004-11-29 21:56:02 -08:00 @@ -29,7 +29,7 @@ uint64_t node_name; uint64_t port_name; uint32_t dev_loss_tmo; /* Remote Port loss timeout in seconds. */ - struct timer_list dev_loss_timer; + struct work_struct dev_loss_work; }; #define fc_starget_port_id(x) \ @@ -40,18 +40,18 @@ (((struct fc_starget_attrs *)&(x)->starget_data)->port_name) #define fc_starget_dev_loss_tmo(x) \ (((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_tmo) -#define fc_starget_dev_loss_timer(x) \ - (((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_timer) +#define fc_starget_dev_loss_work(x) \ + (((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_work) struct fc_host_attrs { uint32_t link_down_tmo; /* Link Down timeout in seconds. */ - struct timer_list link_down_timer; + struct work_struct link_down_work; }; #define fc_host_link_down_tmo(x) \ (((struct fc_host_attrs *)(x)->shost_data)->link_down_tmo) -#define fc_host_link_down_timer(x) \ - (((struct fc_host_attrs *)(x)->shost_data)->link_down_timer) +#define fc_host_link_down_work(x) \ + (((struct fc_host_attrs *)(x)->shost_data)->link_down_work) /* The functions by which the transport class and the driver communicate */ diff -Nru a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/scsi/scsi_transport_iscsi.h 2004-11-29 21:56:02 -08:00 @@ -0,0 +1,178 @@ +/* + * iSCSI transport class definitions + * + * Copyright (C) IBM Corporation, 2004 + * Copyright (C) Mike Christie, 2004 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef SCSI_TRANSPORT_ISCSI_H +#define SCSI_TRANSPORT_ISCSI_H + +#include +#include +#include + +struct scsi_transport_template; + +struct iscsi_class_session { + uint8_t isid[6]; + uint16_t tsih; + int header_digest; /* 1 CRC32, 0 None */ + int data_digest; /* 1 CRC32, 0 None */ + uint16_t tpgt; + union { + struct in6_addr sin6_addr; + struct in_addr sin_addr; + } u; + sa_family_t addr_type; /* must be AF_INET or AF_INET6 */ + uint16_t port; /* must be in network byte order */ + int initial_r2t; /* 1 Yes, 0 No */ + int immediate_data; /* 1 Yes, 0 No */ + uint32_t max_recv_data_segment_len; + uint32_t max_burst_len; + uint32_t first_burst_len; + uint16_t def_time2wait; + uint16_t def_time2retain; + uint16_t max_outstanding_r2t; + int data_pdu_in_order; /* 1 Yes, 0 No */ + int data_sequence_in_order; /* 1 Yes, 0 No */ + int erl; +}; + +/* + * accessor macros + */ +#define iscsi_isid(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->isid) +#define iscsi_tsih(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->tsih) +#define iscsi_header_digest(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->header_digest) +#define iscsi_data_digest(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->data_digest) +#define iscsi_port(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->port) +#define iscsi_addr_type(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->addr_type) +#define iscsi_sin_addr(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->u.sin_addr) +#define iscsi_sin6_addr(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->u.sin6_addr) +#define iscsi_tpgt(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->tpgt) +#define iscsi_initial_r2t(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->initial_r2t) +#define iscsi_immediate_data(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->immediate_data) +#define iscsi_max_recv_data_segment_len(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->max_recv_data_segment_len) +#define iscsi_max_burst_len(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->max_burst_len) +#define iscsi_first_burst_len(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->first_burst_len) +#define iscsi_def_time2wait(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->def_time2wait) +#define iscsi_def_time2retain(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->def_time2retain) +#define iscsi_max_outstanding_r2t(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->max_outstanding_r2t) +#define iscsi_data_pdu_in_order(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->data_pdu_in_order) +#define iscsi_data_sequence_in_order(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->data_sequence_in_order) +#define iscsi_erl(x) \ + (((struct iscsi_class_session *)&(x)->starget_data)->erl) + +/* + * The functions by which the transport class and the driver communicate + */ +struct iscsi_function_template { + /* + * target attrs + */ + void (*get_isid)(struct scsi_target *); + void (*get_tsih)(struct scsi_target *); + void (*get_header_digest)(struct scsi_target *); + void (*get_data_digest)(struct scsi_target *); + void (*get_port)(struct scsi_target *); + void (*get_tpgt)(struct scsi_target *); + /* + * In get_ip_address the lld must set the address and + * the address type + */ + void (*get_ip_address)(struct scsi_target *); + /* + * The lld should snprintf the name or alias to the buffer + */ + ssize_t (*get_target_name)(struct scsi_target *, char *, ssize_t); + ssize_t (*get_target_alias)(struct scsi_target *, char *, ssize_t); + void (*get_initial_r2t)(struct scsi_target *); + void (*get_immediate_data)(struct scsi_target *); + void (*get_max_recv_data_segment_len)(struct scsi_target *); + void (*get_max_burst_len)(struct scsi_target *); + void (*get_first_burst_len)(struct scsi_target *); + void (*get_def_time2wait)(struct scsi_target *); + void (*get_def_time2retain)(struct scsi_target *); + void (*get_max_outstanding_r2t)(struct scsi_target *); + void (*get_data_pdu_in_order)(struct scsi_target *); + void (*get_data_sequence_in_order)(struct scsi_target *); + void (*get_erl)(struct scsi_target *); + + /* + * host atts + */ + + /* + * The lld should snprintf the name or alias to the buffer + */ + ssize_t (*get_initiator_alias)(struct Scsi_Host *, char *, ssize_t); + ssize_t (*get_initiator_name)(struct Scsi_Host *, char *, ssize_t); + /* + * The driver sets these to tell the transport class it + * wants the attributes displayed in sysfs. If the show_ flag + * is not set, the attribute will be private to the transport + * class. We could probably just test if a get_ fn was set + * since we only use the values for sysfs but this is how + * fc does it too. + */ + unsigned long show_isid:1; + unsigned long show_tsih:1; + unsigned long show_header_digest:1; + unsigned long show_data_digest:1; + unsigned long show_port:1; + unsigned long show_tpgt:1; + unsigned long show_ip_address:1; + unsigned long show_target_name:1; + unsigned long show_target_alias:1; + unsigned long show_initial_r2t:1; + unsigned long show_immediate_data:1; + unsigned long show_max_recv_data_segment_len:1; + unsigned long show_max_burst_len:1; + unsigned long show_first_burst_len:1; + unsigned long show_def_time2wait:1; + unsigned long show_def_time2retain:1; + unsigned long show_max_outstanding_r2t:1; + unsigned long show_data_pdu_in_order:1; + unsigned long show_data_sequence_in_order:1; + unsigned long show_erl:1; + unsigned long show_initiator_name:1; + unsigned long show_initiator_alias:1; +}; + +struct scsi_transport_template *iscsi_attach_transport(struct iscsi_function_template *); +void iscsi_release_transport(struct scsi_transport_template *); + +#endif