bk://linux-scsi.bkbits.net/scsi-misc-2.6 rddunlap@osdl.org|ChangeSet|20040504142505|11061 rddunlap # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/05/04 09:30:28-05:00 akpm@osdl.org # [PATCH] support swsusp for aic7xxx # # From: Pavel Machek # # Marks threads as needed for suspend. # DESC # aic79xx_osm.c build fix # EDESC # # drivers/scsi/aic7xxx/aic79xx_osm.c: In function `ahd_linux_dv_thread': # drivers/scsi/aic7xxx/aic79xx_osm.c:2594: `PF_IOTHREAD' undeclared (first use in this function) # # drivers/scsi/aic7xxx/aic7xxx_osm.c # 2004/04/26 01:09:37-05:00 akpm@osdl.org +1 -0 # support swsusp for aic7xxx # # drivers/scsi/aic7xxx/aic79xx_osm.c # 2004/04/26 01:09:37-05:00 akpm@osdl.org +1 -0 # support swsusp for aic7xxx # # ChangeSet # 2004/05/04 09:25:05-05:00 rddunlap@osdl.org # [PATCH] (3/5) ncr53c8x: use kernel.h min/max # # From: Michael Veeck # Subject: [Kernel-janitors] [PATCH] drivers/scsi/53c* MIN/MAX removal # # # Patch (against 2.6.6-rc1) removes unnecessary min/max macros and changes # calls to use kernel.h macros instead. # # # drivers/scsi/ncr53c8xx.c | 6 +++--- # drivers/scsi/sym53c8xx_comm.h | 5 +---- # 2 files changed, 4 insertions(+), 7 deletions(-) # # drivers/scsi/sym53c8xx_comm.h # 2004/04/23 00:32:08-05:00 rddunlap@osdl.org +1 -4 # (3/5) ncr53c8x: use kernel.h min/max # # drivers/scsi/ncr53c8xx.c # 2004/04/23 00:32:08-05:00 rddunlap@osdl.org +3 -3 # (3/5) ncr53c8x: use kernel.h min/max # # ChangeSet # 2004/05/04 09:24:23-05:00 rddunlap@osdl.org # [PATCH] (4/5) nsp32 (ninja): use kernel.h min/max/ARRAY_SIZE # # From: Michael Veeck # Subject: [Kernel-janitors] [PATCH] drivers/scsi/nsp MIN/MAX/NUMBER removal # # Patch (against 2.6.6-rc1) removes unnecessary min/max/number macros and # changes calls to use kernel.h macros instead. # # # drivers/scsi/nsp32.c | 24 ++++++++++++------------ # drivers/scsi/nsp32.h | 4 ---- # 2 files changed, 12 insertions(+), 16 deletions(-) # # drivers/scsi/nsp32.h # 2004/04/23 00:34:00-05:00 rddunlap@osdl.org +0 -4 # (4/5) nsp32 (ninja): use kernel.h min/max/ARRAY_SIZE # # drivers/scsi/nsp32.c # 2004/04/23 00:34:00-05:00 rddunlap@osdl.org +12 -12 # (4/5) nsp32 (ninja): use kernel.h min/max/ARRAY_SIZE # # ChangeSet # 2004/05/04 09:23:43-05:00 rddunlap@osdl.org # [PATCH] (2/5) aic7xyz_old: use kernel.h min/max/ARRAY_SIZE # # From: Michael Veeck # Subject: [Kernel-janitors] [PATCH] drivers/scsi/aic7xxx_old MIN/MAX/NUMBER # removal # # Patch (against 2.6.6-rc1) removes unnecessary min/max/number macros and # changes calls to use kernel.h macros instead. # # # drivers/scsi/aic7xxx_old.c | 43 ++++++++++++++------------------ # drivers/scsi/aic7xxx_old/aic7xxx_proc.c | 6 ++-- # 2 files changed, 23 insertions(+), 26 deletions(-) # # drivers/scsi/aic7xxx_old/aic7xxx_proc.c # 2004/04/23 00:31:11-05:00 rddunlap@osdl.org +3 -3 # (2/5) aic7xyz_old: use kernel.h min/max/ARRAY_SIZE # # drivers/scsi/aic7xxx_old.c # 2004/04/23 00:31:11-05:00 rddunlap@osdl.org +20 -23 # (2/5) aic7xyz_old: use kernel.h min/max/ARRAY_SIZE # # ChangeSet # 2004/05/04 09:22:56-05:00 rddunlap@osdl.org # [PATCH] (5/5) pcmcia/nsp: use kernel.h min/max/ARRAY_SIZE # # From: Michael Veeck # Subject: [Kernel-janitors] [PATCH] drivers/scsi/pcmcia MIN/MAX/NUMBER removal # # # Patch (against 2.6.6-rc1) removes unnecessary min/max/number macros and # changes calls to use kernel.h macros instead. # # # drivers/scsi/pcmcia/nsp_cs.c | 12 ++++++------ # drivers/scsi/pcmcia/nsp_cs.h | 2 -- # 2 files changed, 6 insertions(+), 8 deletions(-) # # drivers/scsi/pcmcia/nsp_cs.h # 2004/04/23 00:34:49-05:00 rddunlap@osdl.org +0 -2 # (5/5) pcmcia/nsp: use kernel.h min/max/ARRAY_SIZE # # drivers/scsi/pcmcia/nsp_cs.c # 2004/04/23 00:34:49-05:00 rddunlap@osdl.org +6 -6 # (5/5) pcmcia/nsp: use kernel.h min/max/ARRAY_SIZE # # ChangeSet # 2004/05/04 09:21:23-05:00 akpm@osdl.org # [PATCH] aic7xxx deadlock fix # # We cannot call del_timer_sync() from within that timer's handler function! # # drivers/scsi/aic7xxx/aic7xxx_osm.c # 2004/04/26 01:09:29-05:00 akpm@osdl.org +9 -3 # aic7xxx deadlock fix # # ChangeSet # 2004/05/04 09:19:18-05:00 jeremy@sgi.com # [PATCH] minor changes to qla1280 driver # # On one of our big machines we found a problem with posted writes while # running AIM. # # Two writes of the Request Queue In pointer went out of order, making # the chip think that it had a queue wrap. # # I took advantage of this opportunity to add relaxed reads, which helps # the Altix. It should not affect other arches. All reads are relaxed # except for the read of the Semaphore register. # # drivers/scsi/qla1280.h # 2004/04/22 14:26:22-05:00 jeremy@sgi.com +2 -1 # minor changes to qla1280 driver # # drivers/scsi/qla1280.c # 2004/04/22 14:26:22-05:00 jeremy@sgi.com +4 -1 # minor changes to qla1280 driver # # ChangeSet # 2004/05/04 09:17:25-05:00 stern@rowland.harvard.edu # [PATCH] PATCH: (as255) Handle Unit Attention during INQUIRY better # # Some buggy USB storage devices can return Unit Attention status for # INQUIRY commands. The current code in scsi_scan.c checks for ASC = 0x28 = # Not ready to ready transition, but these devices can also return ASC = # 0x29 = Power-on or reset occurred. In addition, the code doesn't retry # the INQUIRY when these codes are received. # # drivers/scsi/scsi_scan.c # 2004/04/21 12:04:15-05:00 stern@rowland.harvard.edu +13 -7 # PATCH: (as255) Handle Unit Attention during INQUIRY better # # ChangeSet # 2004/05/04 09:12:32-05:00 rct@gherkin.frus.com # [PATCH] sym53c500_cs PCMCIA SCSI driver (round 5) # # Fifth attempt at a PCMCIA SCSI driver for the Symbios 53c500 # controller. This version has all the cleanup Christoph has requested # to date, including removal of support for the obsolete (in 2.6) # proc_info functionality. # # Support for additional sysfs class device attributes has been added: # two are read-only (irq, ioport), one is read-write (fast_pio). The # read-write attribute is a per-instance flag indicating the PIO speed # of the particular HBA: valid values are 1 (enabled -- default) and 0 # (disabled). # # Documentation/scsi/sym53c500_cs.txt # 2004/05/03 16:08:26-05:00 rct@gherkin.frus.com +23 -0 # sym53c500_cs PCMCIA SCSI driver (round 5) # # drivers/scsi/pcmcia/Makefile # 2004/05/03 16:08:26-05:00 rct@gherkin.frus.com +1 -0 # sym53c500_cs PCMCIA SCSI driver (round 5) # # drivers/scsi/pcmcia/Kconfig # 2004/05/03 16:08:26-05:00 rct@gherkin.frus.com +10 -0 # sym53c500_cs PCMCIA SCSI driver (round 5) # # Documentation/scsi/sym53c500_cs.txt # 2004/05/03 16:08:26-05:00 rct@gherkin.frus.com +0 -0 # BitKeeper file /home/jejb/BK/scsi-misc-2.6/Documentation/scsi/sym53c500_cs.txt # # Documentation/scsi/00-INDEX # 2004/05/03 16:08:26-05:00 rct@gherkin.frus.com +2 -0 # sym53c500_cs PCMCIA SCSI driver (round 5) # # drivers/scsi/pcmcia/sym53c500_cs.c # 2004/05/03 19:18:28-05:00 rct@gherkin.frus.com +1076 -0 # sym53c500_cs PCMCIA SCSI driver (round 5) # # drivers/scsi/pcmcia/sym53c500_cs.c # 2004/05/03 19:18:28-05:00 rct@gherkin.frus.com +0 -0 # BitKeeper file /home/jejb/BK/scsi-misc-2.6/drivers/scsi/pcmcia/sym53c500_cs.c # # ChangeSet # 2004/04/30 18:36:06-05:00 jejb@mulgrave.(none) # Fix errors in [PATCH] aic7xxx: fix oops whe hardware is not present # # This patch was causing a boot panic. Now fixed. # # drivers/scsi/aic7xxx/aic7xxx_osm.h # 2004/04/30 18:35:30-05:00 jejb@mulgrave.(none) +12 -0 # Fix errors in [PATCH] aic7xxx: fix oops whe hardware is not present # # drivers/scsi/aic7xxx/aic7xxx_osm.c # 2004/04/30 18:35:30-05:00 jejb@mulgrave.(none) +10 -21 # Fix errors in [PATCH] aic7xxx: fix oops whe hardware is not present # # drivers/scsi/aic7xxx/aic7770_osm.c # 2004/04/30 18:35:30-05:00 jejb@mulgrave.(none) +4 -4 # Fix errors in [PATCH] aic7xxx: fix oops whe hardware is not present # # ChangeSet # 2004/04/29 15:58:03-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi # # MAINTAINERS # 2004/04/29 15:58:00-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/28 11:32:17-05:00 jejb@mulgrave.(none) # Cset exclude: jejb@mulgrave.(none)|ChangeSet|20040404150128|05866 # # scsi_get_device needs no NULL check # # drivers/scsi/scsi.c # 2004/04/28 11:32:09-05:00 jejb@mulgrave.(none) +0 -0 # scsi_get_device needs no NULL check # # ChangeSet # 2004/04/26 09:06:21-05:00 akpm@osdl.org # [PATCH] scsi_disk_release() warning fix # # drivers/scsi/sd.c: In function `scsi_disk_release': # drivers/scsi/sd.c:1477: warning: unused variable `sdev' # # drivers/scsi/sd.c # 2004/04/26 01:17:21-05:00 akpm@osdl.org +0 -1 # scsi_disk_release() warning fix # # ChangeSet # 2004/04/25 22:05:57-05:00 andmike@us.ibm.com # [PATCH] fix module unload problem in sd # # Move scsi_device_get out of sd probe path to allow module to be unloaded # when devices are not open. # # drivers/scsi/sd.c # 2004/04/22 00:20:13-05:00 andmike@us.ibm.com +15 -10 # fix module unload problem in sd # # ChangeSet # 2004/04/25 09:23:51-05:00 aradford@amcc.com # [PATCH] 3ware driver update # # This patch includes the following driver changes: # # 1.26.00.038 - Roll driver minor version to 26 to denote kernel 2.6. # Add support for cmds_per_lun module parameter. # 1.26.00.039 - Fix bug in tw_chrdev_ioctl() polling code. # Fix data_buffer_length usage in tw_chrdev_ioctl(). # Update contact information. # # drivers/scsi/3w-xxxx.h # 2004/04/21 17:27:30-05:00 aradford@amcc.com +4 -4 # 3ware driver update # # drivers/scsi/3w-xxxx.c # 2004/04/21 17:27:29-05:00 aradford@amcc.com +26 -22 # 3ware driver update # # ChangeSet # 2004/04/25 09:20:56-05:00 garloff@suse.de # [PATCH] scsi: don't attach device if PQ indicates not connected # # include/scsi/scsi_device.h # 2004/04/21 11:55:21-05:00 garloff@suse.de +1 -0 # don't attach device if PQ indicates not connected # # include/scsi/scsi.h # 2004/04/21 11:54:43-05:00 garloff@suse.de +7 -0 # don't attach device if PQ indicates not connected # # drivers/scsi/scsi_sysfs.c # 2004/04/21 11:56:33-05:00 garloff@suse.de +2 -1 # don't attach device if PQ indicates not connected # # drivers/scsi/scsi_scan.c # 2004/04/21 11:56:02-05:00 garloff@suse.de +5 -10 # don't attach device if PQ indicates not connected # # ChangeSet # 2004/04/25 09:13:40-05:00 chrisw@osdl.org # [PATCH] Update aacraid MAINTAINERS entry # # MAINTAINERS # 2004/04/19 07:59:12-05:00 chrisw@osdl.org +2 -4 # Update aacraid MAINTAINERS entry # # ChangeSet # 2004/04/25 09:12:06-05:00 jejb@mulgrave.(none) # aic7xxx: compile fix for EISA only case # # We can't refer to PCI functions for a pure # EISA machine. # # drivers/scsi/aic7xxx/aic7xxx_osm.c # 2004/04/25 09:11:53-05:00 jejb@mulgrave.(none) +2 -0 # aic7xxx: compile fix for EISA only case # # ChangeSet # 2004/04/25 09:10:30-05:00 akpm@osdl.org # [PATCH] aic7xxx: fix oops whe hardware is not present # # From: Herbert Xu # # This is because aic7xxx does not unregister itself properly if no devices # are found. This patch fixes the problem. # # drivers/scsi/aic7xxx/aic7xxx_osm.h # 2004/04/06 23:09:31-05:00 akpm@osdl.org +1 -1 # aic7xxx: fix oops whe hardware is not present # # drivers/scsi/aic7xxx/aic7xxx_osm.c # 2004/04/06 23:09:31-05:00 akpm@osdl.org +19 -4 # aic7xxx: fix oops whe hardware is not present # # drivers/scsi/aic7xxx/aic7770_osm.c # 2004/04/06 23:09:31-05:00 akpm@osdl.org +12 -13 # aic7xxx: fix oops whe hardware is not present # # ChangeSet # 2004/04/25 09:08:55-05:00 Kai.Makisara@kolumbus.fi # [PATCH] SCSI tape log message fixes # # This patch changes the st console/log messages: # # - __GFP_NOWARN added to buffer allocation to suppress useless messages # when having to use smaller than default segments # - move log message from enlarge_buffer() to caller so that the tape name # can be printed and remove some debugging messages; now the st messages # should include drive name where applicable (a problem reported by # Hironobu Ishii) # - setting options is logged only when debugging; the most important # options are now seen in sysfs # # drivers/scsi/st.c # 2004/04/04 07:39:34-05:00 Kai.Makisara@kolumbus.fi +54 -66 # SCSI tape log message fixes # # ChangeSet # 2004/04/25 09:05:51-05:00 praka@users.sourceforge.net # [PATCH] qla2xxx set current state fixes # # - always set_current_state(TASK_UNINTERRUBTIBLE) unless we explicitly # check for signals. # # - make all timeouts take HZ based values. # # drivers/scsi/qla2xxx/qla_os.c # 2004/03/31 15:56:30-06:00 praka@users.sourceforge.net +14 -14 # qla2xxx set current state fixes # # drivers/scsi/qla2xxx/qla_init.c # 2004/03/31 15:48:53-06:00 praka@users.sourceforge.net +1 -1 # qla2xxx set current state fixes # # ChangeSet # 2004/04/25 09:04:26-05:00 aris@cathedrallabs.org # [PATCH] qlogic_cs: use qlogicfas408 module # # this patch kills qlogic_core.c and I guess the same idea can be # applied to other pcmcia scsi drivers. comments? # # drivers/scsi/pcmcia/qlogic_stub.c # 2004/03/30 13:46:44-06:00 aris@cathedrallabs.org +35 -30 # qlogic_cs: use qlogicfas408 module # # drivers/scsi/pcmcia/Makefile # 2004/03/30 13:04:19-06:00 aris@cathedrallabs.org +1 -1 # qlogic_cs: use qlogicfas408 module # # BitKeeper/deleted/.del-qlogic_core.c~5bf1eee84f4e0415 # 2004/04/25 09:04:14-05:00 aris@cathedrallabs.org +0 -0 # Delete: drivers/scsi/pcmcia/qlogic_core.c # # ChangeSet # 2004/04/25 09:02:48-05:00 aris@cathedrallabs.org # [PATCH] qlogicfas: split and create a new module # # drivers/scsi/qlogicfas408.h # 2004/03/30 10:49:32-06:00 aris@cathedrallabs.org +27 -31 # qlogicfas: split and create a new module with only # # drivers/scsi/qlogicfas408.c # 2004/04/25 09:02:28-05:00 aris@cathedrallabs.org +637 -0 # # drivers/scsi/qlogicfas.c # 2004/03/30 10:51:19-06:00 aris@cathedrallabs.org +50 -571 # qlogicfas: split and create a new module with only # # drivers/scsi/Makefile # 2004/03/30 06:54:40-06:00 aris@cathedrallabs.org +2 -1 # qlogicfas: split and create a new module with only # # drivers/scsi/qlogicfas408.c # 2004/04/25 09:02:28-05:00 aris@cathedrallabs.org +0 -0 # BitKeeper file /home/jejb/BK/scsi-misc-2.6/drivers/scsi/qlogicfas408.c # # ChangeSet # 2004/04/25 09:00:34-05:00 aris@cathedrallabs.org # [PATCH] qlogicfas: kill horrible irq probing # # this patch kills irq probe and also I/O because isn't useful to # probe I/O if we can't probe irq later. # # drivers/scsi/qlogicfas.c # 2004/03/18 05:31:52-06:00 aris@cathedrallabs.org +26 -45 # qlogicfas: kill horrible irq probing # # ChangeSet # 2004/04/25 08:44:44-05:00 jejb@mulgrave.(none) # MPT Fusion add back FC909 support # # From: "Moore, Eric Dean" # # drivers/message/fusion/mptscsih.c # 2004/04/25 08:44:31-05:00 jejb@mulgrave.(none) +23 -10 # MPT Fusion add back FC909 support # # drivers/message/fusion/mptctl.h # 2004/04/25 08:44:31-05:00 jejb@mulgrave.(none) +31 -0 # MPT Fusion add back FC909 support # # drivers/message/fusion/mptctl.c # 2004/04/25 08:44:31-05:00 jejb@mulgrave.(none) +52 -26 # MPT Fusion add back FC909 support # # drivers/message/fusion/mptbase.h # 2004/04/25 08:44:31-05:00 jejb@mulgrave.(none) +2 -2 # MPT Fusion add back FC909 support # # drivers/message/fusion/mptbase.c # 2004/04/25 08:44:31-05:00 jejb@mulgrave.(none) +157 -0 # MPT Fusion add back FC909 support # # ChangeSet # 2004/04/12 21:02:39-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-scsi # # drivers/scsi/sr.c # 2004/04/12 21:02:36-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/scsi_transport_spi.c # 2004/04/12 21:02:36-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/dpt_i2o.c # 2004/04/12 21:02:36-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/Kconfig # 2004/04/12 21:02:36-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/08 15:01:18-07:00 akpm@bix.(none) # Merge bk://linux-scsi.bkbits.net/scsi-misc-2.6 # into bix.(none):/usr/src/bk-scsi # # drivers/scsi/scsi_transport_spi.c # 2004/04/08 15:01:15-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/04/07 00:02:57-07:00 akpm@bix.(none) # Merge bk://linux-scsi.bkbits.net/scsi-misc-2.6 # into bix.(none):/usr/src/bk-scsi # # drivers/scsi/sr.c # 2004/04/07 00:02:54-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/scsi_transport_spi.c # 2004/04/07 00:02:54-07:00 akpm@bix.(none) +0 -1 # Auto merged # # drivers/scsi/dpt_i2o.c # 2004/04/07 00:02:54-07:00 akpm@bix.(none) +0 -0 # Auto merged # # drivers/scsi/Kconfig # 2004/04/07 00:02:53-07:00 akpm@bix.(none) +0 -0 # Auto merged # diff -Nru a/Documentation/scsi/00-INDEX b/Documentation/scsi/00-INDEX --- a/Documentation/scsi/00-INDEX Tue May 4 22:18:43 2004 +++ b/Documentation/scsi/00-INDEX Tue May 4 22:18:43 2004 @@ -62,6 +62,8 @@ - info on API between SCSI layer and low level drivers st.txt - info on scsi tape driver +sym53c500_cs.txt + - info on PCMCIA driver for Symbios Logic 53c500 based adapters sym53c8xx_2.txt - info on second generation driver for sym53c8xx based adapters tmscsim.txt diff -Nru a/Documentation/scsi/sym53c500_cs.txt b/Documentation/scsi/sym53c500_cs.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/scsi/sym53c500_cs.txt Tue May 4 22:18:43 2004 @@ -0,0 +1,23 @@ +The sym53c500_cs driver originated as an add-on to David Hinds' pcmcia-cs +package, and was written by Tom Corner (tcorner@via.at). A rewrite was +long overdue, and the current version addresses the following concerns: + + (1) extensive kernel changes between 2.4 and 2.6. + (2) deprecated PCMCIA support outside the kernel. + +All the USE_BIOS code has been ripped out. It was never used, and could +not have worked anyway. The USE_DMA code is likewise gone. Many thanks +to YOKOTA Hiroshi (nsp_cs driver) and David Hinds (qlogic_cs driver) for +the code fragments I shamelessly adapted for this work. Thanks also to +Christoph Hellwig for his patient tutelage while I stumbled about. + +The Symbios Logic 53c500 chip was used in the "newer" (circa 1997) version +of the New Media Bus Toaster PCMCIA SCSI controller. Presumably there are +other products using this chip, but I've never laid eyes (much less hands) +on one. + +Through the years, there have been a number of downloads of the pcmcia-cs +version of this driver, and I guess it worked for those users. It worked +for Tom Corner, and it works for me. Your mileage will probably vary. + +--Bob Tracy (rct@frus.com) diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Tue May 4 22:18:43 2004 +++ b/MAINTAINERS Tue May 4 22:18:43 2004 @@ -168,10 +168,8 @@ AACRAID SCSI RAID DRIVER P: Adaptec OEM Raid Solutions -M: linux-aacraid-devel@dell.com -L: linux-aacraid-devel@dell.com -L: linux-aacraid-announce@dell.com -W: http://domsch.com/linux +L: linux-scsi@vger.kernel.org +W: http://linux.dell.com/storage.shtml S: Supported ACPI diff -Nru a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c --- a/drivers/message/fusion/mptbase.c Tue May 4 22:18:43 2004 +++ b/drivers/message/fusion/mptbase.c Tue May 4 22:18:43 2004 @@ -223,6 +223,7 @@ //int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers); +static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf); static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info); static void mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info); @@ -263,6 +264,8 @@ */ static struct pci_device_id mptbase_pci_table[] = { + { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC909, + PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929, PCI_ANY_ID, PCI_ANY_ID }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919, @@ -389,6 +392,12 @@ else mpt_sp_log_info(ioc, log_info); } + if (ioc_stat & MPI_IOCSTATUS_MASK) { + if ((int)ioc->chip_type <= (int)FC929) + ; + else + mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf); + } } else { /* * Process turbo (context) reply... @@ -1350,6 +1359,10 @@ } ioc->chip_type = FCUNK; + if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) { + ioc->chip_type = FC909; + ioc->prod_name = "LSIFC909"; + } if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) { ioc->chip_type = FC929; ioc->prod_name = "LSIFC929"; @@ -6086,9 +6099,153 @@ case 0x00080000: desc = "Outbound DMA Overrun"; break; + + case 0x00090000: + desc = "Task Management"; + break; + + case 0x000A0000: + desc = "Device Problem"; + break; + + case 0x000B0000: + desc = "Invalid Phase Change"; + break; + + case 0x000C0000: + desc = "Untagged Table Size"; + break; + } printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC. + * @ioc: Pointer to MPT_ADAPTER structure + * @ioc_status: U32 IOCStatus word from IOC + * @mf: Pointer to MPT request frame + * + * Refer to lsi/mpi.h. + */ +static void +mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) +{ + u32 status = ioc_status & MPI_IOCSTATUS_MASK; + char *desc = ""; + + switch (status) { + case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */ + desc = "Invalid Function"; + break; + + case MPI_IOCSTATUS_BUSY: /* 0x0002 */ + desc = "Busy"; + break; + + case MPI_IOCSTATUS_INVALID_SGL: /* 0x0003 */ + desc = "Invalid SGL"; + break; + + case MPI_IOCSTATUS_INTERNAL_ERROR: /* 0x0004 */ + desc = "Internal Error"; + break; + + case MPI_IOCSTATUS_RESERVED: /* 0x0005 */ + desc = "Reserved"; + break; + + case MPI_IOCSTATUS_INSUFFICIENT_RESOURCES: /* 0x0006 */ + desc = "Insufficient Resources"; + break; + + case MPI_IOCSTATUS_INVALID_FIELD: /* 0x0007 */ + desc = "Invalid Field"; + break; + + case MPI_IOCSTATUS_INVALID_STATE: /* 0x0008 */ + desc = "Invalid State"; + break; + + case MPI_IOCSTATUS_CONFIG_INVALID_ACTION: /* 0x0020 */ + case MPI_IOCSTATUS_CONFIG_INVALID_TYPE: /* 0x0021 */ + case MPI_IOCSTATUS_CONFIG_INVALID_PAGE: /* 0x0022 */ + case MPI_IOCSTATUS_CONFIG_INVALID_DATA: /* 0x0023 */ + case MPI_IOCSTATUS_CONFIG_NO_DEFAULTS: /* 0x0024 */ + case MPI_IOCSTATUS_CONFIG_CANT_COMMIT: /* 0x0025 */ + /* No message for Config IOCStatus values */ + break; + + case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ + /* No message for recovered error + desc = "SCSI Recovered Error"; + */ + break; + + case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */ + desc = "SCSI Invalid Bus"; + break; + + case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */ + desc = "SCSI Invalid TargetID"; + break; + + case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ + { + SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf; + U8 cdb = pScsiReq->CDB[0]; + if (cdb != 0x12) { /* Inquiry is issued for device scanning */ + desc = "SCSI Device Not There"; + } + break; + } + + case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */ + desc = "SCSI Data Overrun"; + break; + + case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ + /* This error is checked in scsi_io_done(). Skip. + desc = "SCSI Data Underrun"; + */ + break; + + case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */ + desc = "SCSI I/O Data Error"; + break; + + case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */ + desc = "SCSI Protocol Error"; + break; + + case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ + desc = "SCSI Task Terminated"; + break; + + case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ + desc = "SCSI Residual Mismatch"; + break; + + case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */ + desc = "SCSI Task Management Failed"; + break; + + case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */ + desc = "SCSI IOC Terminated"; + break; + + case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */ + desc = "SCSI Ext Terminated"; + break; + + default: + desc = "Others"; + break; + } + if (desc != "") + printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff -Nru a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h --- a/drivers/message/fusion/mptbase.h Tue May 4 22:18:43 2004 +++ b/drivers/message/fusion/mptbase.h Tue May 4 22:18:43 2004 @@ -81,8 +81,8 @@ #define COPYRIGHT "Copyright (c) 1999-2004 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.01.03" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.01.03" +#define MPT_LINUX_VERSION_COMMON "3.01.05" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.01.05" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ diff -Nru a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c --- a/drivers/message/fusion/mptctl.c Tue May 4 22:18:43 2004 +++ b/drivers/message/fusion/mptctl.c Tue May 4 22:18:43 2004 @@ -1199,7 +1199,7 @@ mptctl_getiocinfo (unsigned long arg, unsigned int data_size) { struct mpt_ioctl_iocinfo *uarg = (struct mpt_ioctl_iocinfo *) arg; - struct mpt_ioctl_iocinfo karg; + struct mpt_ioctl_iocinfo *karg; MPT_ADAPTER *ioc; struct pci_dev *pdev; struct Scsi_Host *sh; @@ -1219,34 +1219,46 @@ */ if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev0)) cim_rev = 0; - else if (data_size == sizeof(struct mpt_ioctl_iocinfo)) + else if (data_size == sizeof(struct mpt_ioctl_iocinfo_rev1)) cim_rev = 1; + else if (data_size == sizeof(struct mpt_ioctl_iocinfo)) + cim_rev = 2; else if (data_size == (sizeof(struct mpt_ioctl_iocinfo_rev0)+12)) cim_rev = 0; /* obsolete */ else return -EFAULT; - - if (copy_from_user(&karg, uarg, data_size)) { + + karg = kmalloc(data_size, GFP_KERNEL); + if (karg == NULL) { + printk(KERN_ERR "%s::mpt_ioctl_iocinfo() @%d - no memory available!\n", + __FILE__, __LINE__); + return -ENOMEM; + } + + if (copy_from_user(karg, uarg, data_size)) { printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " "Unable to read in mpt_ioctl_iocinfo struct @ %p\n", __FILE__, __LINE__, (void*)uarg); + kfree(karg); return -EFAULT; } - if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { dctlprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); + kfree(karg); return -ENODEV; } /* Verify the data transfer size is correct. * Ignore the port setting. */ - if (karg.hdr.maxDataSize != data_size) { + if (karg->hdr.maxDataSize != data_size) { printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " "Structure size mismatch. Command not completed.\n", __FILE__, __LINE__); + kfree(karg); return -EFAULT; } @@ -1254,29 +1266,37 @@ * program */ if ((int)ioc->chip_type <= (int) FC929) - karg.adapterType = MPT_IOCTL_INTERFACE_FC; + karg->adapterType = MPT_IOCTL_INTERFACE_FC; else - karg.adapterType = MPT_IOCTL_INTERFACE_SCSI; + karg->adapterType = MPT_IOCTL_INTERFACE_SCSI; - port = karg.hdr.port; + port = karg->hdr.port; - karg.port = port; + karg->port = port; pdev = (struct pci_dev *) ioc->pcidev; - karg.pciId = pdev->device; + karg->pciId = pdev->device; pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); - karg.hwRev = revision; + karg->hwRev = revision; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - karg.subSystemDevice = pdev->subsystem_device; - karg.subSystemVendor = pdev->subsystem_vendor; + karg->subSystemDevice = pdev->subsystem_device; + karg->subSystemVendor = pdev->subsystem_vendor; #endif if (cim_rev == 1) { /* Get the PCI bus, device, and function numbers for the IOC */ - karg.pciInfo.u.bits.busNumber = pdev->bus->number; - karg.pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn ); - karg.pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn ); + karg->pciInfo.u.bits.busNumber = pdev->bus->number; + karg->pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn ); + karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn ); + } else if (cim_rev == 2) { + /* Get the PCI bus, device, function and segment ID numbers + for the IOC */ + karg->pciInfo.u.bits.busNumber = pdev->bus->number; + karg->pciInfo.u.bits.deviceNumber = PCI_SLOT( pdev->devfn ); + karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn ); + karg->pciInfo.u.bits.functionNumber = PCI_FUNC( pdev->devfn ); + karg->pciInfo.segmentID = pci_domain_nr(pdev->bus); } /* Get number of devices @@ -1297,31 +1317,33 @@ } } } - karg.numDevices = numDevices; + karg->numDevices = numDevices; /* Set the BIOS and FW Version */ - karg.FWVersion = ioc->facts.FWVersion.Word; - karg.BIOSVersion = ioc->biosVersion; + karg->FWVersion = ioc->facts.FWVersion.Word; + karg->BIOSVersion = ioc->biosVersion; /* Set the Version Strings. */ - strncpy (karg.driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH); - karg.driverVersion[MPT_IOCTL_VERSION_LENGTH-1]='\0'; + strncpy (karg->driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH); + karg->driverVersion[MPT_IOCTL_VERSION_LENGTH-1]='\0'; - karg.busChangeEvent = 0; - karg.hostId = ioc->pfacts[port].PortSCSIID; - karg.rsvd[0] = karg.rsvd[1] = 0; + karg->busChangeEvent = 0; + karg->hostId = ioc->pfacts[port].PortSCSIID; + karg->rsvd[0] = karg->rsvd[1] = 0; /* Copy the data from kernel memory to user memory */ - if (copy_to_user((char *)arg, &karg, data_size)) { + if (copy_to_user((char *)arg, karg, data_size)) { printk(KERN_ERR "%s@%d::mptctl_getiocinfo - " "Unable to write out mpt_ioctl_iocinfo struct @ %p\n", __FILE__, __LINE__, (void*)uarg); + kfree(karg); return -EFAULT; } + kfree(karg); return 0; } @@ -2909,6 +2931,8 @@ if (++where && err) goto out_fail; err = register_ioctl32_conversion(MPTIOCINFO1, compat_mptctl_ioctl); if (++where && err) goto out_fail; + err = register_ioctl32_conversion(MPTIOCINFO2, compat_mptctl_ioctl); + if (++where && err) goto out_fail; err = register_ioctl32_conversion(MPTTARGETINFO, compat_mptctl_ioctl); if (++where && err) goto out_fail; err = register_ioctl32_conversion(MPTTEST, compat_mptctl_ioctl); @@ -2968,6 +2992,7 @@ " (%d:err=%d)\n", where, err); unregister_ioctl32_conversion(MPTIOCINFO); unregister_ioctl32_conversion(MPTIOCINFO1); + unregister_ioctl32_conversion(MPTIOCINFO2); unregister_ioctl32_conversion(MPTTARGETINFO); unregister_ioctl32_conversion(MPTTEST); unregister_ioctl32_conversion(MPTEVENTQUERY); @@ -3018,6 +3043,7 @@ #ifdef CONFIG_COMPAT unregister_ioctl32_conversion(MPTIOCINFO); unregister_ioctl32_conversion(MPTIOCINFO1); + unregister_ioctl32_conversion(MPTIOCINFO2); unregister_ioctl32_conversion(MPTTARGETINFO); unregister_ioctl32_conversion(MPTTEST); unregister_ioctl32_conversion(MPTEVENTQUERY); diff -Nru a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h --- a/drivers/message/fusion/mptctl.h Tue May 4 22:18:43 2004 +++ b/drivers/message/fusion/mptctl.h Tue May 4 22:18:43 2004 @@ -91,6 +91,7 @@ #define MPTIOCINFO _IOWR(MPT_MAGIC_NUMBER,17,struct mpt_ioctl_iocinfo) #define MPTIOCINFO1 _IOWR(MPT_MAGIC_NUMBER,17,struct mpt_ioctl_iocinfo_rev0) +#define MPTIOCINFO2 _IOWR(MPT_MAGIC_NUMBER,17,struct mpt_ioctl_iocinfo_rev1) #define MPTTARGETINFO _IOWR(MPT_MAGIC_NUMBER,18,struct mpt_ioctl_targetinfo) #define MPTTEST _IOWR(MPT_MAGIC_NUMBER,19,struct mpt_ioctl_test) #define MPTEVENTQUERY _IOWR(MPT_MAGIC_NUMBER,21,struct mpt_ioctl_eventquery) @@ -165,6 +166,18 @@ } u; }; +struct mpt_ioctl_pci_info2 { + union { + struct { + unsigned int deviceNumber : 5; + unsigned int functionNumber : 3; + unsigned int busNumber : 24; + } bits; + unsigned int asUlong; + } u; + int segmentID; +}; + /* * Adapter Information Page * Read only. @@ -175,6 +188,24 @@ #define MPT_IOCTL_VERSION_LENGTH (32) struct mpt_ioctl_iocinfo { + mpt_ioctl_header hdr; + int adapterType; /* SCSI or FCP */ + int port; /* port number */ + int pciId; /* PCI Id. */ + int hwRev; /* hardware revision */ + int subSystemDevice; /* PCI subsystem Device ID */ + int subSystemVendor; /* PCI subsystem Vendor ID */ + int numDevices; /* number of devices */ + int FWVersion; /* FW Version (integer) */ + int BIOSVersion; /* BIOS Version (integer) */ + char driverVersion[MPT_IOCTL_VERSION_LENGTH]; /* Driver Version (string) */ + char busChangeEvent; + char hostId; + char rsvd[2]; + struct mpt_ioctl_pci_info2 pciInfo; /* Added Rev 2 */ +}; + +struct mpt_ioctl_iocinfo_rev1 { mpt_ioctl_header hdr; int adapterType; /* SCSI or FCP */ int port; /* port number */ diff -Nru a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c --- a/drivers/message/fusion/mptscsih.c Tue May 4 22:18:43 2004 +++ b/drivers/message/fusion/mptscsih.c Tue May 4 22:18:43 2004 @@ -805,6 +805,14 @@ if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) copy_sense_data(sc, hd, mf, pScsiReply); + + /* + * Look for + dump FCP ResponseInfo[]! + */ + if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) { + printk(KERN_NOTICE " FCP_ResponseInfo=%08xh\n", + le32_to_cpu(pScsiReply->ResponseInfo)); + } switch(status) { case MPI_IOCSTATUS_BUSY: /* 0x0002 */ @@ -1106,16 +1114,21 @@ * Do OS callback * Free driver resources (chain, msg buffers) */ - if (SCpnt->use_sg) { - pci_unmap_sg(hd->ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer, - SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); - } else if (SCpnt->request_bufflen) { - scPrivate *my_priv; - - my_priv = (scPrivate *) &SCpnt->SCp; - pci_unmap_single(hd->ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1, - SCpnt->request_bufflen, - scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + if (scsi_device_online(SCpnt->device)) { + if (SCpnt->use_sg) { + pci_unmap_sg(hd->ioc->pcidev, + (struct scatterlist *) SCpnt->request_buffer, + SCpnt->use_sg, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + } else if (SCpnt->request_bufflen) { + scPrivate *my_priv; + + my_priv = (scPrivate *) &SCpnt->SCp; + pci_unmap_single(hd->ioc->pcidev, + (dma_addr_t)(ulong)my_priv->p1, + SCpnt->request_bufflen, + scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); + } } SCpnt->result = DID_RESET << 16; SCpnt->host_scribble = NULL; diff -Nru a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c --- a/drivers/scsi/3w-xxxx.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/3w-xxxx.c Tue May 4 22:18:43 2004 @@ -1,12 +1,12 @@ /* 3w-xxxx.c -- 3ware Storage Controller device driver for Linux. - Written By: Adam Radford + Written By: Adam Radford Modifications By: Joel Jacobson Arnaldo Carvalho de Melo Brad Strand - Copyright (C) 1999-2003 3ware Inc. + Copyright (C) 1999-2004 3ware Inc. Kernel compatiblity By: Andre Hedrick Non-Copyright (C) 2000 Andre Hedrick @@ -47,10 +47,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Bugs/Comments/Suggestions should be mailed to: - linux@3ware.com + linuxraid@amcc.com For more information, goto: - http://www.3ware.com + http://www.amcc.com History ------- @@ -179,6 +179,11 @@ 1.02.00.036 - Increase character ioctl timeout to 60 seconds. 1.02.00.037 - Fix tw_ioctl() to handle all non-data ATA passthru cmds for 'smartmontools' support. + 1.26.00.038 - Roll driver minor version to 26 to denote kernel 2.6. + Add support for cmds_per_lun module parameter. + 1.26.00.039 - Fix bug in tw_chrdev_ioctl() polling code. + Fix data_buffer_length usage in tw_chrdev_ioctl(). + Update contact information. */ #include @@ -205,6 +210,7 @@ #include #include #include +#include #include #include @@ -242,10 +248,15 @@ }; /* Globals */ -char *tw_driver_version="1.02.00.037"; +char *tw_driver_version="1.26.00.039"; TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; int tw_device_extension_count = 0; static int twe_major = -1; +static int cmds_per_lun; + +/* Module parameters */ +module_param(cmds_per_lun, int, 0); +MODULE_PARM_DESC(cmds_per_lun, "Maximum commands per LUN"); /* Functions */ @@ -683,7 +694,7 @@ break; case TW_OP_AEN_LISTEN: dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_AEN_LISTEN.\n"); - memset(tw_ioctl->data_buffer, 0, tw_ioctl->data_buffer_length); + memset(tw_ioctl->data_buffer, 0, data_buffer_length); spin_lock_irqsave(tw_dev->host->host_lock, flags); if (tw_dev->aen_head == tw_dev->aen_tail) { @@ -738,7 +749,7 @@ timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ; /* Now wait for the command to complete */ - wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); + timeout = wait_event_interruptible_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); /* Check if we timed out, got a signal, or didn't get an interrupt */ @@ -777,7 +788,7 @@ } /* Now copy the response to userspace */ - error = copy_to_user((void *)arg, tw_ioctl, sizeof(TW_New_Ioctl) + tw_ioctl->data_buffer_length - 1); + error = copy_to_user((void *)arg, tw_ioctl, sizeof(TW_New_Ioctl) + data_buffer_length - 1); if (error == 0) retval = 0; out2: @@ -1141,14 +1152,6 @@ /* Set card status as online */ tw_dev->online = 1; -#ifdef CONFIG_3W_XXXX_CMD_PER_LUN - tw_host->cmd_per_lun = CONFIG_3W_XXXX_CMD_PER_LUN; - if (tw_host->cmd_per_lun > TW_MAX_CMDS_PER_LUN) - tw_host->cmd_per_lun = TW_MAX_CMDS_PER_LUN; -#else - /* Use SHT cmd_per_lun here */ - tw_host->cmd_per_lun = TW_MAX_CMDS_PER_LUN; -#endif tw_dev->free_head = TW_Q_START; tw_dev->free_tail = TW_Q_START; tw_dev->free_wrap = TW_Q_LENGTH - 1; @@ -3386,13 +3389,13 @@ dprintk(KERN_WARNING "3w-xxxx: tw_slave_configure()\n"); -#ifdef CONFIG_3W_XXXX_CMD_PER_LUN - max_cmds = CONFIG_3W_XXXX_CMD_PER_LUN; - if (max_cmds > TW_MAX_CMDS_PER_LUN) + if (cmds_per_lun) { + max_cmds = cmds_per_lun; + if (max_cmds > TW_MAX_CMDS_PER_LUN) + max_cmds = TW_MAX_CMDS_PER_LUN; + } else { max_cmds = TW_MAX_CMDS_PER_LUN; -#else - max_cmds = TW_MAX_CMDS_PER_LUN; -#endif + } scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, max_cmds); return 0; @@ -3488,6 +3491,7 @@ .eh_abort_handler = tw_scsi_eh_abort, .eh_host_reset_handler = tw_scsi_eh_reset, .bios_param = tw_scsi_biosparam, + .slave_configure = tw_slave_configure, .can_queue = TW_Q_LENGTH-2, .this_id = -1, .sg_tablesize = TW_MAX_SGL_LENGTH, diff -Nru a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h --- a/drivers/scsi/3w-xxxx.h Tue May 4 22:18:43 2004 +++ b/drivers/scsi/3w-xxxx.h Tue May 4 22:18:43 2004 @@ -1,12 +1,12 @@ /* 3w-xxxx.h -- 3ware Storage Controller device driver for Linux. - Written By: Adam Radford + Written By: Adam Radford Modifications By: Joel Jacobson Arnaldo Carvalho de Melo Brad Strand - Copyright (C) 1999-2003 3ware Inc. + Copyright (C) 1999-2004 3ware Inc. Kernel compatiblity By: Andre Hedrick Non-Copyright (C) 2000 Andre Hedrick @@ -45,10 +45,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Bugs/Comments/Suggestions should be mailed to: - linux@3ware.com + linuxraid@amcc.com For more information, goto: - http://www.3ware.com + http://www.amcc.com */ #ifndef _3W_XXXX_H diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile Tue May 4 22:18:43 2004 +++ b/drivers/scsi/Makefile Tue May 4 22:18:43 2004 @@ -75,7 +75,8 @@ obj-$(CONFIG_SCSI_NCR_D700) += 53c700.o NCR_D700.o obj-$(CONFIG_SCSI_NCR_Q720) += NCR_Q720_mod.o obj-$(CONFIG_SCSI_SYM53C416) += sym53c416.o -obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas.o +obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o +obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o obj-$(CONFIG_SCSI_QLOGIC_ISP) += qlogicisp.o obj-$(CONFIG_SCSI_QLOGIC_FC) += qlogicfc.o obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o diff -Nru a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c --- a/drivers/scsi/aic7xxx/aic7770_osm.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/aic7xxx/aic7770_osm.c Tue May 4 22:18:43 2004 @@ -73,7 +73,7 @@ static int aic7770_linux_config(struct aic7770_identity *entry, aic7770_dev_t dev, u_int eisaBase); -void +int ahc_linux_eisa_init(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) @@ -82,7 +82,7 @@ int i; if (aic7xxx_probe_eisa_vl == 0) - return; + return -ENODEV; /* * Linux requires the EISA IDs to be specified in @@ -93,7 +93,7 @@ (ahc_num_aic7770_devs + 1), M_DEVBUF, M_NOWAIT); if (aic7770_driver.id_table == NULL) - return; + return -ENOMEM; for (eid = (struct eisa_device_id *)aic7770_driver.id_table, id = aic7770_ident_table, i = 0; @@ -109,15 +109,16 @@ } eid->sig[0] = 0; - eisa_driver_register(&aic7770_driver); + return eisa_driver_register(&aic7770_driver); #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) */ struct aic7770_identity *entry; u_int slot; u_int eisaBase; u_int i; + int ret = -ENODEV; if (aic7xxx_probe_eisa_vl == 0) - return; + return ret; eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET; for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) { @@ -146,24 +147,22 @@ continue; /* no EISA card in slot */ entry = aic7770_find_device(eisa_id); - if (entry != NULL) + if (entry != NULL) { aic7770_linux_config(entry, NULL, eisaBase); + ret = 0; + } } + return ret; #endif } void ahc_linux_eisa_exit(void) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - if (aic7xxx_probe_eisa_vl == 0) - return; - - if (aic7770_driver.id_table != NULL) { + if(aic7xxx_probe_eisa_vl != 0 && aic7770_driver.id_table != NULL) { eisa_driver_unregister(&aic7770_driver); free(aic7770_driver.id_table, M_DEVBUF); } -#endif } static int diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c --- a/drivers/scsi/aic7xxx/aic79xx_osm.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c Tue May 4 22:18:43 2004 @@ -2591,6 +2591,7 @@ sprintf(current->comm, "ahd_dv_%d", ahd->unit); #else daemonize("ahd_dv_%d", ahd->unit); + current->flags |= PF_FREEZE; #endif unlock_kernel(); diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c Tue May 4 22:18:43 2004 @@ -843,7 +843,8 @@ ahc_linux_detect(Scsi_Host_Template *template) { struct ahc_softc *ahc; - int found; + int found = 0; + int eisa_err, pci_err; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* @@ -891,28 +892,29 @@ */ ahc_list_lockinit(); -#ifdef CONFIG_PCI - ahc_linux_pci_init(); -#endif + pci_err = ahc_linux_pci_init(); + eisa_err = ahc_linux_eisa_init(); + + if(pci_err && eisa_err) + goto out; -#ifdef CONFIG_EISA - ahc_linux_eisa_init(); -#endif /* * Register with the SCSI layer all * controllers we've found. */ - found = 0; TAILQ_FOREACH(ahc, &ahc_tailq, links) { if (ahc_linux_register_host(ahc, template) == 0) found++; } +out: + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) spin_lock_irq(&io_request_lock); #endif aic7xxx_detect_complete++; + return (found); } @@ -1534,6 +1536,7 @@ /* Still equal. Sort by BIOS address, ioport, or bus/slot/func. */ switch (rvalue) { +#ifdef CONFIG_PCI case AHC_PCI: { char primary_channel; @@ -1566,6 +1569,7 @@ value = 1; break; } +#endif case AHC_EISA: if ((rahc->flags & AHC_BIOS_ENABLED) != 0) { value = rahc->platform_data->bios_address @@ -2296,6 +2300,7 @@ sprintf(current->comm, "ahc_dv_%d", ahc->unit); #else daemonize("ahc_dv_%d", ahc->unit); + current->flags |= PF_FREEZE; #endif unlock_kernel(); @@ -3969,11 +3974,10 @@ } static void -ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) +__ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) { struct ahc_linux_target *targ; - del_timer_sync(&dev->timer); targ = dev->target; targ->devices[dev->lun] = NULL; free(dev, M_DEVBUF); @@ -3983,6 +3987,13 @@ ahc_linux_free_target(ahc, targ); } +static void +ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) +{ + del_timer_sync(&dev->timer); + __ahc_linux_free_device(ahc, dev); +} + void ahc_send_async(struct ahc_softc *ahc, char channel, u_int target, u_int lun, ac_code code, void *arg) @@ -4693,7 +4704,7 @@ ahc_linux_run_device_queue(ahc, dev); if (TAILQ_EMPTY(&dev->busyq) && dev->active == 0) - ahc_linux_free_device(ahc, dev); + __ahc_linux_free_device(ahc, dev); ahc_unlock(ahc, &s); } @@ -5067,11 +5078,17 @@ } } +static void ahc_linux_exit(void); + static int __init ahc_linux_init(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - return (ahc_linux_detect(&aic7xxx_driver_template) ? 0 : -ENODEV); + int rc = ahc_linux_detect(&aic7xxx_driver_template); + if (rc) + return rc; + ahc_linux_exit(); + return -ENODEV; #else scsi_register_module(MODULE_SCSI_HA, &aic7xxx_driver_template); if (aic7xxx_driver_template.present == 0) { @@ -5084,7 +5101,7 @@ #endif } -static void __exit +static void ahc_linux_exit(void) { struct ahc_softc *ahc; @@ -5111,12 +5128,8 @@ */ scsi_unregister_module(MODULE_SCSI_HA, &aic7xxx_driver_template); #endif -#ifdef CONFIG_PCI ahc_linux_pci_exit(); -#endif -#ifdef CONFIG_EISA ahc_linux_eisa_exit(); -#endif } module_init(ahc_linux_init); diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h Tue May 4 22:18:43 2004 +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h Tue May 4 22:18:43 2004 @@ -840,11 +840,17 @@ #ifdef CONFIG_EISA extern uint32_t aic7xxx_probe_eisa_vl; -void ahc_linux_eisa_init(void); +int ahc_linux_eisa_init(void); void ahc_linux_eisa_exit(void); int aic7770_map_registers(struct ahc_softc *ahc, u_int port); int aic7770_map_int(struct ahc_softc *ahc, u_int irq); +#else +static inline int ahc_linux_eisa_init(void) { + return -ENODEV; +} +static inline void ahc_linux_eisa_exit(void) { +} #endif /******************************* PCI Routines *********************************/ @@ -931,6 +937,12 @@ ahc_get_pci_bus(ahc_dev_softc_t pci) { return (pci->bus->number); +} +#else +static inline int ahc_linux_pci_init(void) { + return -ENODEV; +} +static inline void ahc_linux_pci_exit(void) { } #endif 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 Tue May 4 22:18:43 2004 +++ b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c Tue May 4 22:18:43 2004 @@ -319,13 +319,13 @@ aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total); size += sprintf(BLS, "%s\n", HDRB); size += sprintf(BLS, " Reads:"); - for (i = 0; i < NUMBER(aic_dev->r_bins); i++) + for (i = 0; i < ARRAY_SIZE(aic_dev->r_bins); i++) { size += sprintf(BLS, " %10ld", aic_dev->r_bins[i]); } size += sprintf(BLS, "\n"); size += sprintf(BLS, " Writes:"); - for (i = 0; i < NUMBER(aic_dev->w_bins); i++) + for (i = 0; i < ARRAY_SIZE(aic_dev->w_bins); i++) { size += sprintf(BLS, " %10ld", aic_dev->w_bins[i]); } @@ -347,7 +347,7 @@ else { *start = buffer; - length = MIN(length, size - offset); + length = min_t(int, length, size - offset); memcpy(buffer, &aic7xxx_buffer[offset], length); } diff -Nru a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c --- a/drivers/scsi/aic7xxx_old.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/aic7xxx_old.c Tue May 4 22:18:43 2004 @@ -254,9 +254,6 @@ #define AIC7XXX_C_VERSION "5.2.6" -#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define ALL_TARGETS -1 #define ALL_CHANNELS -1 #define ALL_LUNS -1 @@ -1376,7 +1373,7 @@ while ((p = strsep(&s, ",.")) != NULL) { - for (i = 0; i < NUMBER(options); i++) + for (i = 0; i < ARRAY_SIZE(options); i++) { n = strlen(options[i].name); if (!strncmp(options[i].name, p, n)) @@ -1423,7 +1420,7 @@ else if (instance >= 0) instance++; if ( (device >= MAX_TARGETS) || - (instance >= NUMBER(aic7xxx_tag_info)) ) + (instance >= ARRAY_SIZE(aic7xxx_tag_info)) ) done = TRUE; tok++; if (!done) @@ -1447,7 +1444,7 @@ } } if ( (instance >= 0) && (device >= 0) && - (instance < NUMBER(aic7xxx_tag_info)) && + (instance < ARRAY_SIZE(aic7xxx_tag_info)) && (device < MAX_TARGETS) ) aic7xxx_tag_info[instance].tag_commands[device] = simple_strtoul(tok, NULL, 0) & 0xff; @@ -1658,7 +1655,7 @@ { int end_addr; - end_addr = MIN(address, skip_addr); + end_addr = min_t(int, address, skip_addr); address_offset += end_addr - i; i = skip_addr; } @@ -1884,7 +1881,7 @@ if(!(p->features & AHC_ULTRA3)) { *options = 0; - maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2); + maxsync = max_t(unsigned int, maxsync, AHC_SYNCRATE_ULTRA2); } break; case MSG_EXT_PPR_OPTION_DT_CRC_QUICK: @@ -1892,7 +1889,7 @@ if(!(p->features & AHC_ULTRA3)) { *options = 0; - maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2); + maxsync = max_t(unsigned int, maxsync, AHC_SYNCRATE_ULTRA2); } else { @@ -1916,7 +1913,7 @@ break; default: *options = 0; - maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2); + maxsync = max_t(unsigned int, maxsync, AHC_SYNCRATE_ULTRA2); break; } syncrate = &aic7xxx_syncrates[maxsync]; @@ -2057,7 +2054,7 @@ else maxoffset = MAX_OFFSET_8BIT; } - *offset = MIN(*offset, maxoffset); + *offset = min(*offset, maxoffset); } /*+F************************************************************************* @@ -2570,7 +2567,7 @@ break; } } - scb_count = MIN( (i-1), p->scb_data->maxscbs - p->scb_data->numscbs); + scb_count = min( (i-1), p->scb_data->maxscbs - p->scb_data->numscbs); scb_ap = (struct aic7xxx_scb *)kmalloc(sizeof (struct aic7xxx_scb) * scb_count + sizeof(struct aic7xxx_scb_dma), GFP_ATOMIC); if (scb_ap == NULL) @@ -5042,7 +5039,7 @@ if(p->user[tindex].offset) { aic_dev->needsdtr_copy = 1; - aic_dev->goal.period = MAX(10,p->user[tindex].period); + aic_dev->goal.period = max_t(unsigned char, 10,p->user[tindex].period); if(p->features & AHC_ULTRA2) { aic_dev->goal.offset = MAX_OFFSET_ULTRA2; @@ -5086,8 +5083,8 @@ * the device isn't allowed to send values greater than the ones * we first sent to it. */ - new_period = MAX(period, aic_dev->goal.period); - new_offset = MIN(offset, aic_dev->goal.offset); + new_period = max_t(unsigned int, period, aic_dev->goal.period); + new_offset = min_t(unsigned int, offset, aic_dev->goal.offset); } /* @@ -5208,7 +5205,7 @@ if(p->user[tindex].offset) { aic_dev->needsdtr_copy = 1; - aic_dev->goal.period = MAX(10,p->user[tindex].period); + aic_dev->goal.period = max_t(unsigned char, 10, p->user[tindex].period); if(p->features & AHC_ULTRA2) { aic_dev->goal.offset = MAX_OFFSET_ULTRA2; @@ -6413,7 +6410,7 @@ unsigned char errno = aic_inb(p, ERROR); printk(KERN_ERR "(scsi%d) BRKADRINT error(0x%x):\n", p->host_no, errno); - for (i = 0; i < NUMBER(hard_error); i++) + for (i = 0; i < ARRAY_SIZE(hard_error); i++) { if (errno & hard_error[i].errno) { @@ -6562,7 +6559,7 @@ else { aic_dev->needsdtr = aic_dev->needsdtr_copy = 1; - aic_dev->goal.period = MAX(10, aic_dev->goal.period); + aic_dev->goal.period = max_t(unsigned char, 10, aic_dev->goal.period); aic_dev->goal.options = 0; } } @@ -6673,7 +6670,7 @@ } else { - if (p->instance >= NUMBER(aic7xxx_tag_info)) + if (p->instance >= ARRAY_SIZE(aic7xxx_tag_info)) { static int print_warning = TRUE; if(print_warning) @@ -6850,7 +6847,7 @@ buf[i] = inb(base + i); } - for (i = 0; i < NUMBER(AIC7xxx); i++) + for (i = 0; i < ARRAY_SIZE(AIC7xxx); i++) { /* * Signature match on enabled card? @@ -9199,7 +9196,7 @@ unsigned int devconfig, i, oldverbose; struct pci_dev *pdev = NULL; - for (i = 0; i < NUMBER(aic_pdevs); i++) + for (i = 0; i < ARRAY_SIZE(aic_pdevs); i++) { pdev = NULL; while ((pdev = pci_find_device(aic_pdevs[i].vendor_id, @@ -9698,7 +9695,7 @@ * EISA/VL-bus card signature probe. */ slot = MINSLOT; - while ( (slot <= MAXSLOT) && + while ( (slot <= MAXSLOT) && !(aic7xxx_no_probe) ) { base = SLOTBASE(slot) + MINREG; @@ -10097,7 +10094,7 @@ int i; left = found; - for (i=0; icdb_buf, cmd->cmnd, MIN(cmd->cmd_len, sizeof(cp->cdb_buf))); + memcpy(cp->cdb_buf, cmd->cmnd, min_t(int, cmd->cmd_len, sizeof(cp->cdb_buf))); cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, cdb_buf[0])); cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len); @@ -5172,7 +5172,7 @@ ** Copy back sense data to caller's buffer. */ memcpy(cmd->sense_buffer, cp->sense_buf, - MIN(sizeof(cmd->sense_buffer), sizeof(cp->sense_buf))); + min(sizeof(cmd->sense_buffer), sizeof(cp->sense_buf))); if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) { u_char * p = (u_char*) & cmd->sense_buffer; diff -Nru a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c --- a/drivers/scsi/nsp32.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/nsp32.c Tue May 4 22:18:43 2004 @@ -859,7 +859,7 @@ * or current nexus is not existed, unexpected * reselection is occurred. Send reject message. */ - if (newid >= NUMBER(data->lunt) || newlun >= NUMBER(data->lunt[0])) { + if (newid >= ARRAY_SIZE(data->lunt) || newlun >= ARRAY_SIZE(data->lunt[0])) { nsp32_msg(KERN_WARNING, "unknown id/lun"); return FALSE; } else if(data->lunt[newid][newlun].SCpnt == NULL) { @@ -1568,7 +1568,7 @@ SPRINTF("SDTR status\n"); - for(id = 0; id < NUMBER(data->target); id++) { + for (id = 0; id < ARRAY_SIZE(data->target); id++) { SPRINTF("id %d: ", id); @@ -1610,7 +1610,7 @@ } - thislength = MIN(thislength, length); + thislength = min(thislength, length); *start = buffer + offset; return thislength; @@ -2753,17 +2753,17 @@ case CLOCK_4: /* If data->clock is CLOCK_4, then select 40M sync table. */ data->synct = nsp32_sync_table_40M; - data->syncnum = NUMBER(nsp32_sync_table_40M); + data->syncnum = ARRAY_SIZE(nsp32_sync_table_40M); break; case CLOCK_2: /* If data->clock is CLOCK_2, then select 20M sync table. */ data->synct = nsp32_sync_table_20M; - data->syncnum = NUMBER(nsp32_sync_table_20M); + data->syncnum = ARRAY_SIZE(nsp32_sync_table_20M); break; case PCICLK: /* If data->clock is PCICLK, then select pci sync table. */ data->synct = nsp32_sync_table_pci; - data->syncnum = NUMBER(nsp32_sync_table_pci); + data->syncnum = ARRAY_SIZE(nsp32_sync_table_pci); break; default: nsp32_msg(KERN_WARNING, @@ -2771,7 +2771,7 @@ /* Use default value CLOCK_4 */ data->clock = CLOCK_4; data->synct = nsp32_sync_table_40M; - data->syncnum = NUMBER(nsp32_sync_table_40M); + data->syncnum = ARRAY_SIZE(nsp32_sync_table_40M); } /* @@ -2805,9 +2805,9 @@ goto free_autoparam; } - for (i = 0; i < NUMBER(data->lunt); i++) { - for (j = 0; j < NUMBER(data->lunt[0]); j++) { - int offset = i * NUMBER(data->lunt[0]) + j; + for (i = 0; i < ARRAY_SIZE(data->lunt); i++) { + for (j = 0; j < ARRAY_SIZE(data->lunt[0]); j++) { + int offset = i * ARRAY_SIZE(data->lunt[0]) + j; nsp32_lunt tmp = { .SCpnt = NULL, .save_datp = 0, @@ -2825,7 +2825,7 @@ /* * setup target */ - for (i = 0; i < NUMBER(data->target); i++) { + for (i = 0; i < ARRAY_SIZE(data->target); i++) { nsp32_target *target = &(data->target[i]); target->limit_entry = 0; @@ -3021,7 +3021,7 @@ * fall back to asynchronous transfer mode * initialize SDTR negotiation flag */ - for (i = 0; i < NUMBER(data->target); i++) { + for (i = 0; i < ARRAY_SIZE(data->target); i++) { nsp32_target *target = &data->target[i]; target->sync_flag = 0; diff -Nru a/drivers/scsi/nsp32.h b/drivers/scsi/nsp32.h --- a/drivers/scsi/nsp32.h Tue May 4 22:18:43 2004 +++ b/drivers/scsi/nsp32.h Tue May 4 22:18:43 2004 @@ -70,11 +70,7 @@ /* * MACRO */ -#define NUMBER(arr) ((int) (sizeof(arr) / sizeof(arr[0]))) #define BIT(x) (1UL << (x)) -#ifndef MIN -# define MIN(a,b) ((a) > (b) ? (b) : (a)) -#endif /* * BASIC Definitions diff -Nru a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig --- a/drivers/scsi/pcmcia/Kconfig Tue May 4 22:18:43 2004 +++ b/drivers/scsi/pcmcia/Kconfig Tue May 4 22:18:43 2004 @@ -69,4 +69,14 @@ To compile this driver as a module, choose M here: the module will be called qlogic_cs. +config PCMCIA_SYM53C500 + tristate "Symbios 53c500 PCMCIA support" + depends on m + help + Say Y here if you have a New Media Bus Toaster or other PCMCIA + SCSI adapter based on the Symbios 53c500 controller. + + To compile this driver as a module, choose M here: the + module will be called sym53c500_cs. + endmenu diff -Nru a/drivers/scsi/pcmcia/Makefile b/drivers/scsi/pcmcia/Makefile --- a/drivers/scsi/pcmcia/Makefile Tue May 4 22:18:43 2004 +++ b/drivers/scsi/pcmcia/Makefile Tue May 4 22:18:43 2004 @@ -6,7 +6,8 @@ obj-$(CONFIG_PCMCIA_FDOMAIN) += fdomain_cs.o obj-$(CONFIG_PCMCIA_AHA152X) += aha152x_cs.o obj-$(CONFIG_PCMCIA_NINJA_SCSI) += nsp_cs.o +obj-$(CONFIG_PCMCIA_SYM53C500) += sym53c500_cs.o aha152x_cs-objs := aha152x_stub.o aha152x_core.o fdomain_cs-objs := fdomain_stub.o fdomain_core.o -qlogic_cs-objs := qlogic_stub.o qlogic_core.o +qlogic_cs-objs := qlogic_stub.o diff -Nru a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c --- a/drivers/scsi/pcmcia/nsp_cs.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/pcmcia/nsp_cs.c Tue May 4 22:18:43 2004 @@ -315,7 +315,7 @@ int i; /* setup sync data */ - for ( i = 0; i < NUMBER(data->Sync); i++ ) { + for ( i = 0; i < ARRAY_SIZE(data->Sync); i++ ) { data->Sync[i] = tmp_sync; } } @@ -600,7 +600,7 @@ unsigned int base = SCpnt->device->host->io_port; nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; char *buf = data->MsgBuffer; - int len = MIN(MSGBUF_SIZE, data->MsgLen); + int len = min(MSGBUF_SIZE, data->MsgLen); int ptr; int ret; @@ -774,7 +774,7 @@ continue; } - res = MIN(res, SCpnt->SCp.this_residual); + res = min(res, SCpnt->SCp.this_residual); switch (data->TransferMode) { case MODE_IO32: @@ -868,7 +868,7 @@ continue; } - res = MIN(SCpnt->SCp.this_residual, WFIFO_CRIT); + res = min(SCpnt->SCp.this_residual, WFIFO_CRIT); //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res); switch (data->TransferMode) { @@ -1490,7 +1490,7 @@ spin_unlock_irqrestore(&(data->Lock), flags); SPRINTF("SDTR status\n"); - for(id = 0; id < NUMBER(data->Sync); id++) { + for(id = 0; id < ARRAY_SIZE(data->Sync); id++) { SPRINTF("id %d: ", id); @@ -1534,7 +1534,7 @@ } - thislength = MIN(thislength, length); + thislength = min(thislength, length); *start = buffer + offset; return thislength; diff -Nru a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h --- a/drivers/scsi/pcmcia/nsp_cs.h Tue May 4 22:18:43 2004 +++ b/drivers/scsi/pcmcia/nsp_cs.h Tue May 4 22:18:43 2004 @@ -26,9 +26,7 @@ /************************************ * Some useful macros... */ -#define NUMBER(arr) ((int) (sizeof(arr) / sizeof(arr[0]))) /* from XtNumber() in /usr/X11R6/include/X11/Intrinsic.h */ #define BIT(x) (1L << (x)) -#define MIN(a,b) ((a) > (b) ? (b) : (a)) /* SCSI initiator must be ID 7 */ #define NSP_INITIATOR_ID 7 diff -Nru a/drivers/scsi/pcmcia/qlogic_core.c b/drivers/scsi/pcmcia/qlogic_core.c --- a/drivers/scsi/pcmcia/qlogic_core.c Tue May 4 22:18:43 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,2 +0,0 @@ -#define PCMCIA 1 -#include "qlogicfas.c" diff -Nru a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c --- a/drivers/scsi/pcmcia/qlogic_stub.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/pcmcia/qlogic_stub.c Tue May 4 22:18:43 2004 @@ -47,7 +47,7 @@ #include "scsi.h" #include "hosts.h" -#include "../qlogicfas.h" +#include "../qlogicfas408.h" #include #include @@ -56,13 +56,13 @@ #include #include +/* Set the following to 2 to use normal interrupt (active high/totempole- + * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open + * drain + */ +#define INT_TYPE 0 -extern Scsi_Host_Template qlogicfas_driver_template; -extern void qlogicfas_preset(int port, int irq); -extern int qlogicfas_bus_reset(Scsi_Cmnd *); -extern irqreturn_t do_ql_ihandl(int irq, void *dev_id, struct pt_regs *regs); - -static char *qlogic_name = "qlogic_cs"; +static char qlogic_name[] = "qlogic_cs"; #ifdef PCMCIA_DEBUG static int pc_debug = PCMCIA_DEBUG; @@ -73,6 +73,24 @@ #define DEBUG(n, args...) #endif +static Scsi_Host_Template qlogicfas_driver_template = { + .module = THIS_MODULE, + .name = qlogic_name, + .proc_name = qlogic_name, + .info = qlogicfas408_info, + .queuecommand = qlogicfas408_queuecommand, + .eh_abort_handler = qlogicfas408_abort, + .eh_bus_reset_handler = qlogicfas408_bus_reset, + .eh_device_reset_handler= qlogicfas408_device_reset, + .eh_host_reset_handler = qlogicfas408_host_reset, + .bios_param = qlogicfas408_biosparam, + .can_queue = 1, + .this_id = -1, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING, +}; + /*====================================================================*/ /* Parameters that can be set with 'insmod' */ @@ -110,29 +128,17 @@ int qltyp; /* type of chip */ int qinitid; struct Scsi_Host *shost; /* registered host structure */ - qlogicfas_priv_t priv; + struct qlogicfas408_priv *priv; - qltyp = inb(qbase + 0xe) & 0xf8; + qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE); qinitid = host->this_id; if (qinitid < 0) qinitid = 7; /* if no ID, use 7 */ - outb(1, qbase + 8); /* set for PIO pseudo DMA */ - REG0; - outb(0x40 | qlcfg8 | qinitid, qbase + 8); /* (ini) bus id, disable scsi rst */ - outb(qlcfg5, qbase + 5); /* select timer */ - outb(qlcfg9, qbase + 9); /* prescaler */ - -#if QL_RESET_AT_START - outb(3, qbase + 3); - REG1; - /* FIXME: timeout */ - while (inb(qbase + 0xf) & 4) - cpu_relax(); - REG0; -#endif + + qlogicfas408_setup(qbase, qinitid, INT_TYPE); host->name = qlogic_name; - shost = scsi_host_alloc(host, sizeof(struct qlogicfas_priv)); + shost = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv)); if (!shost) goto err; shost->io_port = qbase; @@ -141,12 +147,14 @@ if (qlirq != -1) shost->irq = qlirq; - priv = (qlogicfas_priv_t)&(shost->hostdata[0]); + priv = get_priv_by_host(shost); priv->qlirq = qlirq; priv->qbase = qbase; priv->qinitid = qinitid; + priv->shost = shost; + priv->int_type = INT_TYPE; - if (request_irq(qlirq, do_ql_ihandl, 0, qlogic_name, shost)) + if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogic_name, shost)) goto free_scsi_host; sprintf(priv->qinfo, @@ -307,9 +315,6 @@ outb(0x04, link->io.BasePort1 + 0xd); } - qlogicfas_driver_template.name = qlogic_name; - qlogicfas_driver_template.proc_name = qlogic_name; - /* The KXL-810AN has a bigger IO port window */ if (link->io.NumPorts1 == 32) host = qlogic_detect(&qlogicfas_driver_template, link, @@ -402,7 +407,7 @@ outb(0x04, link->io.BasePort1 + 0xd); } /* Ugggglllyyyy!!! */ - qlogicfas_bus_reset(NULL); + qlogicfas408_bus_reset(NULL); } break; } diff -Nru a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/pcmcia/sym53c500_cs.c Tue May 4 22:18:43 2004 @@ -0,0 +1,1076 @@ +/* +* sym53c500_cs.c Bob Tracy (rct@frus.com) +* +* A rewrite of the pcmcia-cs add-on driver for newer (circa 1997) +* New Media Bus Toaster PCMCIA SCSI cards using the Symbios Logic +* 53c500 controller: intended for use with 2.6 and later kernels. +* The pcmcia-cs add-on version of this driver is not supported +* beyond 2.4. It consisted of three files with history/copyright +* information as follows: +* +* SYM53C500.h +* Bob Tracy (rct@frus.com) +* Original by Tom Corner (tcorner@via.at). +* Adapted from NCR53c406a.h which is Copyrighted (C) 1994 +* Normunds Saumanis (normunds@rx.tech.swh.lv) +* +* SYM53C500.c +* Bob Tracy (rct@frus.com) +* Original driver by Tom Corner (tcorner@via.at) was adapted +* from NCR53c406a.c which is Copyrighted (C) 1994, 1995, 1996 +* Normunds Saumanis (normunds@fi.ibm.com) +* +* sym53c500.c +* Bob Tracy (rct@frus.com) +* Original by Tom Corner (tcorner@via.at) was adapted from a +* driver for the Qlogic SCSI card written by +* David Hinds (dhinds@allegro.stanford.edu). +* +* 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, 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. +*/ + +#define SYM53C500_DEBUG 0 +#define VERBOSE_SYM53C500_DEBUG 0 + +/* +* Set this to 0 if you encounter kernel lockups while transferring +* data in PIO mode. Note this can be changed via "sysfs". +*/ +#define USE_FAST_PIO 1 + +/* =============== End of user configurable parameters ============== */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* ================================================================== */ + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +module_param(pc_debug, int, 0); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = +"sym53c500_cs.c 0.9a 2004/05/04 (Bob Tracy)"; +#else +#define DEBUG(n, args...) +#endif + +/* ================================================================== */ + +/* Parameters that can be set with 'insmod' */ + +/* Bit map of interrupts to choose from */ +static unsigned int irq_mask = 0xdeb8; /* 3, 6, 7, 9-12, 14, 15 */ +static int irq_list[4] = { -1 }; +static int num_irqs = 1; + +module_param(irq_mask, int, 0); +MODULE_PARM_DESC(irq_mask, "IRQ mask bits (default: 0xdeb8)"); +module_param_array(irq_list, int, num_irqs, 0); +MODULE_PARM_DESC(irq_list, "Comma-separated list of up to 4 IRQs to try (default: auto select)."); + +/* ================================================================== */ + +#define SYNC_MODE 0 /* Synchronous transfer mode */ + +/* Default configuration */ +#define C1_IMG 0x07 /* ID=7 */ +#define C2_IMG 0x48 /* FE SCSI2 */ +#define C3_IMG 0x20 /* CDB */ +#define C4_IMG 0x04 /* ANE */ +#define C5_IMG 0xa4 /* ? changed from b6= AA PI SIE POL */ +#define C7_IMG 0x80 /* added for SYM53C500 t. corner */ + +/* Hardware Registers: offsets from io_port (base) */ + +/* Control Register Set 0 */ +#define TC_LSB 0x00 /* transfer counter lsb */ +#define TC_MSB 0x01 /* transfer counter msb */ +#define SCSI_FIFO 0x02 /* scsi fifo register */ +#define CMD_REG 0x03 /* command register */ +#define STAT_REG 0x04 /* status register */ +#define DEST_ID 0x04 /* selection/reselection bus id */ +#define INT_REG 0x05 /* interrupt status register */ +#define SRTIMOUT 0x05 /* select/reselect timeout reg */ +#define SEQ_REG 0x06 /* sequence step register */ +#define SYNCPRD 0x06 /* synchronous transfer period */ +#define FIFO_FLAGS 0x07 /* indicates # of bytes in fifo */ +#define SYNCOFF 0x07 /* synchronous offset register */ +#define CONFIG1 0x08 /* configuration register */ +#define CLKCONV 0x09 /* clock conversion register */ +/* #define TESTREG 0x0A */ /* test mode register */ +#define CONFIG2 0x0B /* configuration 2 register */ +#define CONFIG3 0x0C /* configuration 3 register */ +#define CONFIG4 0x0D /* configuration 4 register */ +#define TC_HIGH 0x0E /* transfer counter high */ +/* #define FIFO_BOTTOM 0x0F */ /* reserve FIFO byte register */ + +/* Control Register Set 1 */ +/* #define JUMPER_SENSE 0x00 */ /* jumper sense port reg (r/w) */ +/* #define SRAM_PTR 0x01 */ /* SRAM address pointer reg (r/w) */ +/* #define SRAM_DATA 0x02 */ /* SRAM data register (r/w) */ +#define PIO_FIFO 0x04 /* PIO FIFO registers (r/w) */ +/* #define PIO_FIFO1 0x05 */ /* */ +/* #define PIO_FIFO2 0x06 */ /* */ +/* #define PIO_FIFO3 0x07 */ /* */ +#define PIO_STATUS 0x08 /* PIO status (r/w) */ +/* #define ATA_CMD 0x09 */ /* ATA command/status reg (r/w) */ +/* #define ATA_ERR 0x0A */ /* ATA features/error reg (r/w) */ +#define PIO_FLAG 0x0B /* PIO flag interrupt enable (r/w) */ +#define CONFIG5 0x09 /* configuration 5 register */ +/* #define SIGNATURE 0x0E */ /* signature register (r) */ +/* #define CONFIG6 0x0F */ /* configuration 6 register (r) */ +#define CONFIG7 0x0d + +/* select register set 0 */ +#define REG0(x) (outb(C4_IMG, (x) + CONFIG4)) +/* select register set 1 */ +#define REG1(x) outb(C7_IMG, (x) + CONFIG7); outb(C5_IMG, (x) + CONFIG5) + +#if SYM53C500_DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + +#if VERBOSE_SYM53C500_DEBUG +#define VDEB(x) x +#else +#define VDEB(x) +#endif + +#define LOAD_DMA_COUNT(x, count) \ + outb(count & 0xff, (x) + TC_LSB); \ + outb((count >> 8) & 0xff, (x) + TC_MSB); \ + outb((count >> 16) & 0xff, (x) + TC_HIGH); + +/* Chip commands */ +#define DMA_OP 0x80 + +#define SCSI_NOP 0x00 +#define FLUSH_FIFO 0x01 +#define CHIP_RESET 0x02 +#define SCSI_RESET 0x03 +#define RESELECT 0x40 +#define SELECT_NO_ATN 0x41 +#define SELECT_ATN 0x42 +#define SELECT_ATN_STOP 0x43 +#define ENABLE_SEL 0x44 +#define DISABLE_SEL 0x45 +#define SELECT_ATN3 0x46 +#define RESELECT3 0x47 +#define TRANSFER_INFO 0x10 +#define INIT_CMD_COMPLETE 0x11 +#define MSG_ACCEPT 0x12 +#define TRANSFER_PAD 0x18 +#define SET_ATN 0x1a +#define RESET_ATN 0x1b +#define SEND_MSG 0x20 +#define SEND_STATUS 0x21 +#define SEND_DATA 0x22 +#define DISCONN_SEQ 0x23 +#define TERMINATE_SEQ 0x24 +#define TARG_CMD_COMPLETE 0x25 +#define DISCONN 0x27 +#define RECV_MSG 0x28 +#define RECV_CMD 0x29 +#define RECV_DATA 0x2a +#define RECV_CMD_SEQ 0x2b +#define TARGET_ABORT_DMA 0x04 + +/* ================================================================== */ + +struct scsi_info_t { + dev_link_t link; + dev_node_t node; + struct Scsi_Host *host; + unsigned short manf_id; +}; + +/* +* Repository for per-instance host data. +*/ +struct sym53c500_data { + struct scsi_cmnd *current_SC; + int fast_pio; +}; + +enum Phase { + idle, + data_out, + data_in, + command_ph, + status_ph, + message_out, + message_in +}; + +/* ================================================================== */ + +/* +* Global (within this module) variables other than +* sym53c500_driver_template (the scsi_host_template). +*/ +static dev_link_t *dev_list; +static dev_info_t dev_info = "sym53c500_cs"; + +/* ================================================================== */ + +static void +chip_init(int io_port) +{ + REG1(io_port); + outb(0x01, io_port + PIO_STATUS); + outb(0x00, io_port + PIO_FLAG); + + outb(C4_IMG, io_port + CONFIG4); /* REG0(io_port); */ + outb(C3_IMG, io_port + CONFIG3); + outb(C2_IMG, io_port + CONFIG2); + outb(C1_IMG, io_port + CONFIG1); + + outb(0x05, io_port + CLKCONV); /* clock conversion factor */ + outb(0x9C, io_port + SRTIMOUT); /* Selection timeout */ + outb(0x05, io_port + SYNCPRD); /* Synchronous transfer period */ + outb(SYNC_MODE, io_port + SYNCOFF); /* synchronous mode */ +} + +static void +SYM53C500_int_host_reset(int io_port) +{ + outb(C4_IMG, io_port + CONFIG4); /* REG0(io_port); */ + outb(CHIP_RESET, io_port + CMD_REG); + outb(SCSI_NOP, io_port + CMD_REG); /* required after reset */ + outb(SCSI_RESET, io_port + CMD_REG); + chip_init(io_port); +} + +static __inline__ int +SYM53C500_pio_read(int fast_pio, int base, unsigned char *request, unsigned int reqlen) +{ + int i; + int len; /* current scsi fifo size */ + + REG1(base); + while (reqlen) { + i = inb(base + PIO_STATUS); + /* VDEB(printk("pio_status=%x\n", i)); */ + if (i & 0x80) + return 0; + + switch (i & 0x1e) { + default: + case 0x10: /* fifo empty */ + len = 0; + break; + case 0x0: + len = 1; + break; + case 0x8: /* fifo 1/3 full */ + len = 42; + break; + case 0xc: /* fifo 2/3 full */ + len = 84; + break; + case 0xe: /* fifo full */ + len = 128; + break; + } + + if ((i & 0x40) && len == 0) { /* fifo empty and interrupt occurred */ + return 0; + } + + if (len) { + if (len > reqlen) + len = reqlen; + + if (fast_pio && len > 3) { + insl(base + PIO_FIFO, request, len >> 2); + request += len & 0xfc; + reqlen -= len & 0xfc; + } else { + while (len--) { + *request++ = inb(base + PIO_FIFO); + reqlen--; + } + } + } + } + return 0; +} + +static __inline__ int +SYM53C500_pio_write(int fast_pio, int base, unsigned char *request, unsigned int reqlen) +{ + int i = 0; + int len; /* current scsi fifo size */ + + REG1(base); + while (reqlen && !(i & 0x40)) { + i = inb(base + PIO_STATUS); + /* VDEB(printk("pio_status=%x\n", i)); */ + if (i & 0x80) /* error */ + return 0; + + switch (i & 0x1e) { + case 0x10: + len = 128; + break; + case 0x0: + len = 84; + break; + case 0x8: + len = 42; + break; + case 0xc: + len = 1; + break; + default: + case 0xe: + len = 0; + break; + } + + if (len) { + if (len > reqlen) + len = reqlen; + + if (fast_pio && len > 3) { + outsl(base + PIO_FIFO, request, len >> 2); + request += len & 0xfc; + reqlen -= len & 0xfc; + } else { + while (len--) { + outb(*request++, base + PIO_FIFO); + reqlen--; + } + } + } + } + return 0; +} + +static irqreturn_t +SYM53C500_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + struct Scsi_Host *dev = dev_id; + DEB(unsigned char fifo_size;) + DEB(unsigned char seq_reg;) + unsigned char status, int_reg; + unsigned char pio_status; + struct scatterlist *sglist; + unsigned int sgcount; + int port_base = dev->io_port; + struct sym53c500_data *data = + (struct sym53c500_data *)dev->hostdata; + struct scsi_cmnd *curSC = data->current_SC; + int fast_pio = data->fast_pio; + + spin_lock_irqsave(dev->host_lock, flags); + + VDEB(printk("SYM53C500_intr called\n")); + + REG1(port_base); + pio_status = inb(port_base + PIO_STATUS); + REG0(port_base); + status = inb(port_base + STAT_REG); + DEB(seq_reg = inb(port_base + SEQ_REG)); + int_reg = inb(port_base + INT_REG); + DEB(fifo_size = inb(port_base + FIFO_FLAGS) & 0x1f); + +#if SYM53C500_DEBUG + printk("status=%02x, seq_reg=%02x, int_reg=%02x, fifo_size=%02x", + status, seq_reg, int_reg, fifo_size); + printk(", pio=%02x\n", pio_status); +#endif /* SYM53C500_DEBUG */ + + if (int_reg & 0x80) { /* SCSI reset intr */ + DEB(printk("SYM53C500: reset intr received\n")); + curSC->result = DID_RESET << 16; + goto idle_out; + } + + if (pio_status & 0x80) { + printk("SYM53C500: Warning: PIO error!\n"); + curSC->result = DID_ERROR << 16; + goto idle_out; + } + + if (status & 0x20) { /* Parity error */ + printk("SYM53C500: Warning: parity error!\n"); + curSC->result = DID_PARITY << 16; + goto idle_out; + } + + if (status & 0x40) { /* Gross error */ + printk("SYM53C500: Warning: gross error!\n"); + curSC->result = DID_ERROR << 16; + goto idle_out; + } + + if (int_reg & 0x20) { /* Disconnect */ + DEB(printk("SYM53C500: disconnect intr received\n")); + if (curSC->SCp.phase != message_in) { /* Unexpected disconnect */ + curSC->result = DID_NO_CONNECT << 16; + } else { /* Command complete, return status and message */ + curSC->result = (curSC->SCp.Status & 0xff) + | ((curSC->SCp.Message & 0xff) << 8) | (DID_OK << 16); + } + goto idle_out; + } + + switch (status & 0x07) { /* scsi phase */ + case 0x00: /* DATA-OUT */ + if (int_reg & 0x10) { /* Target requesting info transfer */ + curSC->SCp.phase = data_out; + VDEB(printk("SYM53C500: Data-Out phase\n")); + outb(FLUSH_FIFO, port_base + CMD_REG); + LOAD_DMA_COUNT(port_base, curSC->request_bufflen); /* Max transfer size */ + outb(TRANSFER_INFO | DMA_OP, port_base + CMD_REG); + if (!curSC->use_sg) /* Don't use scatter-gather */ + SYM53C500_pio_write(fast_pio, port_base, curSC->request_buffer, curSC->request_bufflen); + else { /* use scatter-gather */ + sgcount = curSC->use_sg; + sglist = curSC->request_buffer; + while (sgcount--) { + SYM53C500_pio_write(fast_pio, port_base, page_address(sglist->page) + sglist->offset, sglist->length); + sglist++; + } + } + REG0(port_base); + } + break; + + case 0x01: /* DATA-IN */ + if (int_reg & 0x10) { /* Target requesting info transfer */ + curSC->SCp.phase = data_in; + VDEB(printk("SYM53C500: Data-In phase\n")); + outb(FLUSH_FIFO, port_base + CMD_REG); + LOAD_DMA_COUNT(port_base, curSC->request_bufflen); /* Max transfer size */ + outb(TRANSFER_INFO | DMA_OP, port_base + CMD_REG); + if (!curSC->use_sg) /* Don't use scatter-gather */ + SYM53C500_pio_read(fast_pio, port_base, curSC->request_buffer, curSC->request_bufflen); + else { /* Use scatter-gather */ + sgcount = curSC->use_sg; + sglist = curSC->request_buffer; + while (sgcount--) { + SYM53C500_pio_read(fast_pio, port_base, page_address(sglist->page) + sglist->offset, sglist->length); + sglist++; + } + } + REG0(port_base); + } + break; + + case 0x02: /* COMMAND */ + curSC->SCp.phase = command_ph; + printk("SYM53C500: Warning: Unknown interrupt occurred in command phase!\n"); + break; + + case 0x03: /* STATUS */ + curSC->SCp.phase = status_ph; + VDEB(printk("SYM53C500: Status phase\n")); + outb(FLUSH_FIFO, port_base + CMD_REG); + outb(INIT_CMD_COMPLETE, port_base + CMD_REG); + break; + + case 0x04: /* Reserved */ + case 0x05: /* Reserved */ + printk("SYM53C500: WARNING: Reserved phase!!!\n"); + break; + + case 0x06: /* MESSAGE-OUT */ + DEB(printk("SYM53C500: Message-Out phase\n")); + curSC->SCp.phase = message_out; + outb(SET_ATN, port_base + CMD_REG); /* Reject the message */ + outb(MSG_ACCEPT, port_base + CMD_REG); + break; + + case 0x07: /* MESSAGE-IN */ + VDEB(printk("SYM53C500: Message-In phase\n")); + curSC->SCp.phase = message_in; + + curSC->SCp.Status = inb(port_base + SCSI_FIFO); + curSC->SCp.Message = inb(port_base + SCSI_FIFO); + + VDEB(printk("SCSI FIFO size=%d\n", inb(port_base + FIFO_FLAGS) & 0x1f)); + DEB(printk("Status = %02x Message = %02x\n", curSC->SCp.Status, curSC->SCp.Message)); + + if (curSC->SCp.Message == SAVE_POINTERS || curSC->SCp.Message == DISCONNECT) { + outb(SET_ATN, port_base + CMD_REG); /* Reject message */ + DEB(printk("Discarding SAVE_POINTERS message\n")); + } + outb(MSG_ACCEPT, port_base + CMD_REG); + break; + } +out: + spin_unlock_irqrestore(dev->host_lock, flags); + return IRQ_HANDLED; + +idle_out: + curSC->SCp.phase = idle; + curSC->scsi_done(curSC); + goto out; +} + +static void +SYM53C500_release(dev_link_t *link) +{ + struct scsi_info_t *info = link->priv; + struct Scsi_Host *shost = info->host; + + DEBUG(0, "SYM53C500_release(0x%p)\n", link); + + /* + * Do this before releasing/freeing resources. + */ + scsi_remove_host(shost); + + /* + * Interrupts getting hosed on card removal. Try + * the following code, mostly from qlogicfas.c. + */ + if (shost->irq) + free_irq(shost->irq, shost); + if (shost->dma_channel != 0xff) + free_dma(shost->dma_channel); + if (shost->io_port && shost->n_io_port) + release_region(shost->io_port, shost->n_io_port); + + link->dev = NULL; + + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; + + scsi_host_put(shost); +} /* SYM53C500_release */ + +static const char* +SYM53C500_info(struct Scsi_Host *SChost) +{ + static char info_msg[256]; + struct sym53c500_data *data = + (struct sym53c500_data *)SChost->hostdata; + + DEB(printk("SYM53C500_info called\n")); + (void)snprintf(info_msg, sizeof(info_msg), + "SYM53C500 at 0x%lx, IRQ %d, %s PIO mode.", + SChost->io_port, SChost->irq, data->fast_pio ? "fast" : "slow"); + return (info_msg); +} + +static int +SYM53C500_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) +{ + int i; + int port_base = SCpnt->device->host->io_port; + struct sym53c500_data *data = + (struct sym53c500_data *)SCpnt->device->host->hostdata; + + VDEB(printk("SYM53C500_queue called\n")); + + DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", + SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->device->id, + SCpnt->device->lun, SCpnt->request_bufflen)); + + VDEB(for (i = 0; i < SCpnt->cmd_len; i++) + printk("cmd[%d]=%02x ", i, SCpnt->cmnd[i])); + VDEB(printk("\n")); + + data->current_SC = SCpnt; + data->current_SC->scsi_done = done; + data->current_SC->SCp.phase = command_ph; + data->current_SC->SCp.Status = 0; + data->current_SC->SCp.Message = 0; + + /* We are locked here already by the mid layer */ + REG0(port_base); + outb(SCpnt->device->id, port_base + DEST_ID); /* set destination */ + outb(FLUSH_FIFO, port_base + CMD_REG); /* reset the fifos */ + + for (i = 0; i < SCpnt->cmd_len; i++) { + outb(SCpnt->cmnd[i], port_base + SCSI_FIFO); + } + outb(SELECT_NO_ATN, port_base + CMD_REG); + + return 0; +} + +static int +SYM53C500_host_reset(struct scsi_cmnd *SCpnt) +{ + int port_base = SCpnt->device->host->io_port; + + DEB(printk("SYM53C500_host_reset called\n")); + SYM53C500_int_host_reset(port_base); + + return SUCCESS; +} + +static int +SYM53C500_biosparm(struct scsi_device *disk, + struct block_device *dev, + sector_t capacity, int *info_array) +{ + int size; + + DEB(printk("SYM53C500_biosparm called\n")); + + size = capacity; + info_array[0] = 64; /* heads */ + info_array[1] = 32; /* sectors */ + info_array[2] = size >> 11; /* cylinders */ + if (info_array[2] > 1024) { /* big disk */ + info_array[0] = 255; + info_array[1] = 63; + info_array[2] = size / (255 * 63); + } + return 0; +} + +static ssize_t +SYM53C500_show_irq(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *SHp = class_to_shost(cdev); + + return snprintf(buf, 4, "%d\n", SHp->irq); +} + +static ssize_t +SYM53C500_show_ioport(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *SHp = class_to_shost(cdev); + + return snprintf(buf, 8, "0x%lx\n", SHp->io_port); +} + +static ssize_t +SYM53C500_show_pio(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *SHp = class_to_shost(cdev); + struct sym53c500_data *data = + (struct sym53c500_data *)SHp->hostdata; + + return snprintf(buf, 4, "%d\n", data->fast_pio); +} + +static ssize_t +SYM53C500_store_pio(struct class_device *cdev, const char *buf, size_t count) +{ + int pio; + struct Scsi_Host *SHp = class_to_shost(cdev); + struct sym53c500_data *data = + (struct sym53c500_data *)SHp->hostdata; + + pio = simple_strtoul(buf, NULL, 0); + if (pio == 0 || pio == 1) { + data->fast_pio = pio; + return count; + } + else + return -EINVAL; +} + +/* +* SCSI HBA device attributes we want to +* make available via sysfs. +*/ +static struct class_device_attribute SYM53C500_irq_attr = { + .attr = { + .name = "irq", + .mode = S_IRUGO, + }, + .show = SYM53C500_show_irq, +}; + +static struct class_device_attribute SYM53C500_ioport_attr = { + .attr = { + .name = "ioport", + .mode = S_IRUGO, + }, + .show = SYM53C500_show_ioport, +}; + +static struct class_device_attribute SYM53C500_pio_attr = { + .attr = { + .name = "fast_pio", + .mode = (S_IRUGO | S_IWUSR), + }, + .show = SYM53C500_show_pio, + .store = SYM53C500_store_pio, +}; + +static struct class_device_attribute *SYM53C500_shost_attrs[] = { + &SYM53C500_irq_attr, + &SYM53C500_ioport_attr, + &SYM53C500_pio_attr, + NULL, +}; + +/* +* scsi_host_template initializer +*/ +static struct scsi_host_template sym53c500_driver_template = { + .module = THIS_MODULE, + .name = "SYM53C500", + .info = SYM53C500_info, + .queuecommand = SYM53C500_queue, + .eh_host_reset_handler = SYM53C500_host_reset, + .bios_param = SYM53C500_biosparm, + .proc_name = "SYM53C500", + .can_queue = 1, + .this_id = 7, + .sg_tablesize = 32, + .cmd_per_lun = 1, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = SYM53C500_shost_attrs +}; + +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) + +static void +SYM53C500_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + struct scsi_info_t *info = link->priv; + tuple_t tuple; + cisparse_t parse; + int i, last_ret, last_fn; + int irq_level, port_base; + unsigned short tuple_data[32]; + struct Scsi_Host *host; + struct scsi_host_template *tpnt = &sym53c500_driver_template; + struct sym53c500_data *data; + + DEBUG(0, "SYM53C500_config(0x%p)\n", link); + + tuple.TupleData = (cisdata_t *)tuple_data; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + link->conf.ConfigBase = parse.config.base; + + tuple.DesiredTuple = CISTPL_MANFID; + if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) && + (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS)) + info->manf_id = le16_to_cpu(tuple.TupleData[0]); + + /* Configure card */ + link->state |= DEV_CONFIG; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + while (1) { + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + goto next_entry; + link->conf.ConfigIndex = parse.cftable_entry.index; + link->io.BasePort1 = parse.cftable_entry.io.win[0].base; + link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; + + if (link->io.BasePort1 != 0) { + i = pcmcia_request_io(handle, &link->io); + if (i == CS_SUCCESS) + break; + } +next_entry: + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); + } + + CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); + + /* + * That's the trouble with copying liberally from another driver. + * Some things probably aren't relevant, and I suspect this entire + * section dealing with manufacturer IDs can be scrapped. --rct + */ + if ((info->manf_id == MANFID_MACNICA) || + (info->manf_id == MANFID_PIONEER) || + (info->manf_id == 0x0098)) { + /* set ATAcmd */ + outb(0xb4, link->io.BasePort1 + 0xd); + outb(0x24, link->io.BasePort1 + 0x9); + outb(0x04, link->io.BasePort1 + 0xd); + } + + /* + * irq_level == 0 implies tpnt->can_queue == 0, which + * is not supported in 2.6. Thus, only irq_level > 0 + * will be allowed. + * + * Possible port_base values are as follows: + * + * 0x130, 0x230, 0x280, 0x290, + * 0x320, 0x330, 0x340, 0x350 + */ + port_base = link->io.BasePort1; + irq_level = link->irq.AssignedIRQ; + + DEB(printk("SYM53C500: port_base=0x%x, irq=%d, fast_pio=%d\n", + port_base, irq_level, USE_FAST_PIO);) + + chip_init(port_base); + + host = scsi_host_alloc(tpnt, sizeof(struct sym53c500_data)); + if (!host) { + printk("SYM53C500: Unable to register host, giving up.\n"); + goto err_release; + } + + data = (struct sym53c500_data *)host->hostdata; + + if (irq_level > 0) { + if (request_irq(irq_level, SYM53C500_intr, 0, "SYM53C500", host)) { + printk("SYM53C500: unable to allocate IRQ %d\n", irq_level); + goto err_free_scsi; + } + DEB(printk("SYM53C500: allocated IRQ %d\n", irq_level)); + } else if (irq_level == 0) { + DEB(printk("SYM53C500: No interrupts detected\n")); + goto err_free_scsi; + } else { + DEB(printk("SYM53C500: Shouldn't get here!\n")); + goto err_free_scsi; + } + + host->unique_id = port_base; + host->irq = irq_level; + host->io_port = port_base; + host->n_io_port = 0x10; + host->dma_channel = -1; + + /* + * Note fast_pio is set to USE_FAST_PIO by + * default, but can be changed via "sysfs". + */ + data->fast_pio = USE_FAST_PIO; + + sprintf(info->node.dev_name, "scsi%d", host->host_no); + link->dev = &info->node; + info->host = host; + + if (scsi_add_host(host, NULL)) + goto err_free_irq; + + scsi_scan_host(host); + + goto out; /* SUCCESS */ + +err_free_irq: + free_irq(irq_level, host); +err_free_scsi: + scsi_host_put(host); +err_release: + release_region(port_base, 0x10); + printk(KERN_INFO "sym53c500_cs: no SCSI devices found\n"); + +out: + link->state &= ~DEV_CONFIG_PENDING; + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + SYM53C500_release(link); + return; +} /* SYM53C500_config */ + +static int +SYM53C500_event(event_t event, int priority, event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + struct scsi_info_t *info = link->priv; + + DEBUG(1, "SYM53C500_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) + SYM53C500_release(link); + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + SYM53C500_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + pcmcia_release_configuration(link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + pcmcia_request_configuration(link->handle, &link->conf); + /* See earlier comment about manufacturer IDs. */ + if ((info->manf_id == MANFID_MACNICA) || + (info->manf_id == MANFID_PIONEER) || + (info->manf_id == 0x0098)) { + outb(0x80, link->io.BasePort1 + 0xd); + outb(0x24, link->io.BasePort1 + 0x9); + outb(0x04, link->io.BasePort1 + 0xd); + } + /* + * If things don't work after a "resume", + * this is a good place to start looking. + */ + SYM53C500_int_host_reset(link->io.BasePort1); + } + break; + } + return 0; +} /* SYM53C500_event */ + +static void +SYM53C500_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "SYM53C500_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (*linkp == NULL) + return; + + if (link->state & DEV_CONFIG) + SYM53C500_release(link); + + if (link->handle) + pcmcia_deregister_client(link->handle); + + /* Unlink device structure, free bits. */ + *linkp = link->next; + kfree(link->priv); + link->priv = NULL; +} /* SYM53C500_detach */ + +static dev_link_t * +SYM53C500_attach(void) +{ + struct scsi_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + DEBUG(0, "SYM53C500_attach()\n"); + + /* Create new SCSI device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return NULL; + memset(info, 0, sizeof(*info)); + link = &info->link; + link->priv = info; + link->io.NumPorts1 = 16; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 10; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.Present = PRESENT_OPTION; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.event_handler = &SYM53C500_event; + client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = pcmcia_register_client(&link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + SYM53C500_detach(link); + return NULL; + } + + return link; +} /* SYM53C500_attach */ + +MODULE_AUTHOR("Bob Tracy "); +MODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver"); +MODULE_LICENSE("GPL"); + +static struct pcmcia_driver sym53c500_cs_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "sym53c500_cs", + }, + .attach = SYM53C500_attach, + .detach = SYM53C500_detach, +}; + +static int __init +init_sym53c500_cs(void) +{ + return pcmcia_register_driver(&sym53c500_cs_driver); +} + +static void __exit +exit_sym53c500_cs(void) +{ + pcmcia_unregister_driver(&sym53c500_cs_driver); +} + +module_init(init_sym53c500_cs); +module_exit(exit_sym53c500_cs); diff -Nru a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c --- a/drivers/scsi/qla1280.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/qla1280.c Tue May 4 22:18:43 2004 @@ -3371,6 +3371,7 @@ sp->flags |= SRB_SENT; ha->actthreads++; WRT_REG_WORD(®->mailbox4, ha->req_ring_index); + (void) RD_REG_WORD(®->mailbox4); /* PCI posted write flush */ out: if (status) @@ -3639,6 +3640,7 @@ sp->flags |= SRB_SENT; ha->actthreads++; WRT_REG_WORD(®->mailbox4, ha->req_ring_index); + (void) RD_REG_WORD(®->mailbox4); /* PCI posted write flush */ out: if (status) @@ -3750,6 +3752,7 @@ /* Set chip new ring index. */ WRT_REG_WORD(®->mailbox4, ha->req_ring_index); + (void) RD_REG_WORD(®->mailbox4); /* PCI posted write flush */ LEAVE("qla1280_isp_cmd"); } @@ -3788,7 +3791,7 @@ /* Check for mailbox interrupt. */ - mailbox[0] = RD_REG_WORD(®->semaphore); + mailbox[0] = RD_REG_WORD_dmasync(®->semaphore); if (mailbox[0] & BIT_0) { /* Get mailbox data. */ diff -Nru a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h --- a/drivers/scsi/qla1280.h Tue May 4 22:18:43 2004 +++ b/drivers/scsi/qla1280.h Tue May 4 22:18:43 2004 @@ -57,7 +57,8 @@ #define BIT_31 0x80000000 #if MEMORY_MAPPED_IO -#define RD_REG_WORD(addr) readw(addr) +#define RD_REG_WORD(addr) readw_relaxed(addr) +#define RD_REG_WORD_dmasync(addr) readw(addr) #define WRT_REG_WORD(addr, data) writew(data, addr) #else /* MEMORY_MAPPED_IO */ #define RD_REG_WORD(addr) inw((unsigned long)addr) diff -Nru a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c --- a/drivers/scsi/qla2xxx/qla_init.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/qla2xxx/qla_init.c Tue May 4 22:18:43 2004 @@ -946,7 +946,7 @@ break; /* Delay for a while */ - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ / 2); DEBUG3(printk("scsi(%ld): fw_state=%x curr time=%lx.\n", diff -Nru a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c --- a/drivers/scsi/qla2xxx/qla_os.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/qla2xxx/qla_os.c Tue May 4 22:18:43 2004 @@ -914,7 +914,7 @@ spin_unlock_irq(ha->host->host_lock); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(2*HZ); spin_lock_irq(ha->host->host_lock); @@ -962,7 +962,7 @@ test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) && time_before(jiffies, wait_online)) { - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ); } if (ha->flags.online == TRUE) @@ -1005,7 +1005,7 @@ atomic_read(&ha->loop_state) == LOOP_DOWN) || test_bit(CFG_ACTIVE, &ha->cfg_flags) || atomic_read(&ha->loop_state) != LOOP_READY) { - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ); if (time_after_eq(jiffies, loop_timeout)) { return_status = QLA_FUNCTION_FAILED; @@ -2125,8 +2125,8 @@ qla2x00_check_fabric_devices(ha); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(5); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/100); } pci_set_drvdata(pdev, ha); @@ -2868,7 +2868,7 @@ "Memory Allocation failed - request_ring\n"); qla2x00_mem_free(ha); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); continue; @@ -2882,7 +2882,7 @@ "Memory Allocation failed - response_ring\n"); qla2x00_mem_free(ha); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); continue; @@ -2896,7 +2896,7 @@ "Memory Allocation failed - init_cb\n"); qla2x00_mem_free(ha); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); continue; @@ -2909,7 +2909,7 @@ "Memory Allocation failed - ioctl_mem\n"); qla2x00_mem_free(ha); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); continue; @@ -2921,7 +2921,7 @@ "qla2x00_allocate_sp_pool()\n"); qla2x00_mem_free(ha); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); continue; @@ -2938,7 +2938,7 @@ "Memory Allocation failed - sns_cmd\n"); qla2x00_mem_free(ha); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); continue; @@ -2954,7 +2954,7 @@ "Memory Allocation failed - ms_iocb\n"); qla2x00_mem_free(ha); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); continue; @@ -2973,7 +2973,7 @@ "Memory Allocation failed - ct_sns\n"); qla2x00_mem_free(ha); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); continue; @@ -2990,7 +2990,7 @@ "Memory Allocation failed - iodesc_pd\n"); qla2x00_mem_free(ha); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); continue; diff -Nru a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c --- a/drivers/scsi/qlogicfas.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/qlogicfas.c Tue May 4 22:18:43 2004 @@ -1,43 +1,19 @@ -/*----------------------------------------------------------------*/ /* - Qlogic linux driver - work in progress. No Warranty express or implied. - Use at your own risk. Support Tort Reform so you won't have to read all - these silly disclaimers. - - Copyright 1994, Tom Zerucha. - tz@execpc.com - - Additional Code, and much appreciated help by - Michael A. Griffith - grif@cs.ucr.edu - - Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA - help respectively, and for suffering through my foolishness during the - debugging process. - - Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994 - (you can reference it, but it is incomplete and inaccurate in places) - - Version 0.46 1/30/97 - kernel 1.2.0+ - - Functions as standalone, loadable, and PCMCIA driver, the latter from - Dave Hinds' PCMCIA package. - - Cleaned up 26/10/2002 by Alan Cox as part of the 2.5 - SCSI driver cleanup and audit. This driver still needs work on the - following - - Non terminating hardware waits - - Some layering violations with its pcmcia stub - - Redistributable under terms of the GNU General Public License - - For the avoidance of doubt the "preferred form" of this code is one which - is in an open non patent encumbered format. Where cryptographic key signing - forms part of the process of creating an executable the information - including keys needed to generate an equivalently functional executable - are deemed to be part of the source code. - -*/ + * Qlogic FAS408 ISA card driver + * + * Copyright 1994, Tom Zerucha. + * tz@execpc.com + * + * Redistributable under terms of the GNU General Public License + * + * For the avoidance of doubt the "preferred form" of this code is one which + * is in an open non patent encumbered format. Where cryptographic key signing + * forms part of the process of creating an executable the information + * including keys needed to generate an equivalently functional executable + * are deemed to be part of the source code. + * + * Check qlogicfas408.c for more credits and info. + */ #include #include /* to get disk capacity */ @@ -57,429 +33,28 @@ #include "scsi.h" #include "hosts.h" -#include "qlogicfas.h" - -/*----------------------------------------------------------------*/ -int qlcfg5 = (XTALFREQ << 5); /* 15625/512 */ -int qlcfg6 = SYNCXFRPD; -int qlcfg7 = SYNCOFFST; -int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4); -int qlcfg9 = ((XTALFREQ + 4) / 5); -int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4); - -static char qlogicfas_name[] = "qlogicfas"; - -int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)); - -/*----------------------------------------------------------------*/ - -/*----------------------------------------------------------------*/ -/* local functions */ -/*----------------------------------------------------------------*/ - -/* error recovery - reset everything */ - -static void ql_zap(qlogicfas_priv_t priv) -{ - int x; - int qbase = priv->qbase; - - x = inb(qbase + 0xd); - REG0; - outb(3, qbase + 3); /* reset SCSI */ - outb(2, qbase + 3); /* reset chip */ - if (x & 0x80) - REG1; -} - -/* - * Do a pseudo-dma tranfer - */ - -static int ql_pdma(qlogicfas_priv_t priv, int phase, char *request, int reqlen) -{ - int j; - int qbase = priv->qbase; - j = 0; - if (phase & 1) { /* in */ -#if QL_TURBO_PDMA - rtrc(4) - /* empty fifo in large chunks */ - if (reqlen >= 128 && (inb(qbase + 8) & 2)) { /* full */ - insl(qbase + 4, request, 32); - reqlen -= 128; - request += 128; - } - while (reqlen >= 84 && !(j & 0xc0)) /* 2/3 */ - if ((j = inb(qbase + 8)) & 4) - { - insl(qbase + 4, request, 21); - reqlen -= 84; - request += 84; - } - if (reqlen >= 44 && (inb(qbase + 8) & 8)) { /* 1/3 */ - insl(qbase + 4, request, 11); - reqlen -= 44; - request += 44; - } -#endif - /* until both empty and int (or until reclen is 0) */ - rtrc(7) - j = 0; - while (reqlen && !((j & 0x10) && (j & 0xc0))) - { - /* while bytes to receive and not empty */ - j &= 0xc0; - while (reqlen && !((j = inb(qbase + 8)) & 0x10)) - { - *request++ = inb(qbase + 4); - reqlen--; - } - if (j & 0x10) - j = inb(qbase + 8); - - } - } else { /* out */ -#if QL_TURBO_PDMA - rtrc(4) - if (reqlen >= 128 && inb(qbase + 8) & 0x10) { /* empty */ - outsl(qbase + 4, request, 32); - reqlen -= 128; - request += 128; - } - while (reqlen >= 84 && !(j & 0xc0)) /* 1/3 */ - if (!((j = inb(qbase + 8)) & 8)) { - outsl(qbase + 4, request, 21); - reqlen -= 84; - request += 84; - } - if (reqlen >= 40 && !(inb(qbase + 8) & 4)) { /* 2/3 */ - outsl(qbase + 4, request, 10); - reqlen -= 40; - request += 40; - } -#endif - /* until full and int (or until reclen is 0) */ - rtrc(7) - j = 0; - while (reqlen && !((j & 2) && (j & 0xc0))) { - /* while bytes to send and not full */ - while (reqlen && !((j = inb(qbase + 8)) & 2)) - { - outb(*request++, qbase + 4); - reqlen--; - } - if (j & 2) - j = inb(qbase + 8); - } - } - /* maybe return reqlen */ - return inb(qbase + 8) & 0xc0; -} - -/* - * Wait for interrupt flag (polled - not real hardware interrupt) - */ - -static int ql_wai(qlogicfas_priv_t priv) -{ - int k; - int qbase = priv->qbase; - unsigned long i; - - k = 0; - i = jiffies + WATCHDOG; - while (time_before(jiffies, i) && !priv->qabort && - !((k = inb(qbase + 4)) & 0xe0)) { - barrier(); - cpu_relax(); - } - if (time_after_eq(jiffies, i)) - return (DID_TIME_OUT); - if (priv->qabort) - return (priv->qabort == 1 ? DID_ABORT : DID_RESET); - if (k & 0x60) - ql_zap(priv); - if (k & 0x20) - return (DID_PARITY); - if (k & 0x40) - return (DID_ERROR); - return 0; -} - -/* - * Initiate scsi command - queueing handler - * caller must hold host lock - */ - -static void ql_icmd(Scsi_Cmnd * cmd) -{ - qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); - int qbase = priv->qbase; - unsigned int i; - - priv->qabort = 0; - - REG0; - /* clearing of interrupts and the fifo is needed */ - - inb(qbase + 5); /* clear interrupts */ - if (inb(qbase + 5)) /* if still interrupting */ - outb(2, qbase + 3); /* reset chip */ - else if (inb(qbase + 7) & 0x1f) - outb(1, qbase + 3); /* clear fifo */ - while (inb(qbase + 5)); /* clear ints */ - REG1; - outb(1, qbase + 8); /* set for PIO pseudo DMA */ - outb(0, qbase + 0xb); /* disable ints */ - inb(qbase + 8); /* clear int bits */ - REG0; - outb(0x40, qbase + 0xb); /* enable features */ - - /* configurables */ - outb(qlcfgc, qbase + 0xc); - /* config: no reset interrupt, (initiator) bus id */ - outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8); - outb(qlcfg7, qbase + 7); - outb(qlcfg6, qbase + 6); - /**/ outb(qlcfg5, qbase + 5); /* select timer */ - outb(qlcfg9 & 7, qbase + 9); /* prescaler */ -/* outb(0x99, qbase + 5); */ - outb(cmd->device->id, qbase + 4); - - for (i = 0; i < cmd->cmd_len; i++) - outb(cmd->cmnd[i], qbase + 2); - - priv->qlcmd = cmd; - outb(0x41, qbase + 3); /* select and send command */ -} - -/* - * Process scsi command - usually after interrupt - */ - -static unsigned int ql_pcmd(Scsi_Cmnd * cmd) -{ - unsigned int i, j; - unsigned long k; - unsigned int result; /* ultimate return result */ - unsigned int status; /* scsi returned status */ - unsigned int message; /* scsi returned message */ - unsigned int phase; /* recorded scsi phase */ - unsigned int reqlen; /* total length of transfer */ - struct scatterlist *sglist; /* scatter-gather list pointer */ - unsigned int sgcount; /* sg counter */ - char *buf; - qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); - int qbase = priv->qbase; - - rtrc(1) - j = inb(qbase + 6); - i = inb(qbase + 5); - if (i == 0x20) { - return (DID_NO_CONNECT << 16); - } - i |= inb(qbase + 5); /* the 0x10 bit can be set after the 0x08 */ - if (i != 0x18) { - printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i); - ql_zap(priv); - return (DID_BAD_INTR << 16); - } - j &= 7; /* j = inb( qbase + 7 ) >> 5; */ - - /* correct status is supposed to be step 4 */ - /* it sometimes returns step 3 but with 0 bytes left to send */ - /* We can try stuffing the FIFO with the max each time, but we will get a - sequence of 3 if any bytes are left (but we do flush the FIFO anyway */ - - if (j != 3 && j != 4) { - printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", - j, i, inb(qbase + 7) & 0x1f); - ql_zap(priv); - return (DID_ERROR << 16); - } - result = DID_OK; - if (inb(qbase + 7) & 0x1f) /* if some bytes in fifo */ - outb(1, qbase + 3); /* clear fifo */ - /* note that request_bufflen is the total xfer size when sg is used */ - reqlen = cmd->request_bufflen; - /* note that it won't work if transfers > 16M are requested */ - if (reqlen && !((phase = inb(qbase + 4)) & 6)) { /* data phase */ - rtrc(2) - outb(reqlen, qbase); /* low-mid xfer cnt */ - outb(reqlen >> 8, qbase + 1); /* low-mid xfer cnt */ - outb(reqlen >> 16, qbase + 0xe); /* high xfer cnt */ - outb(0x90, qbase + 3); /* command do xfer */ - /* PIO pseudo DMA to buffer or sglist */ - REG1; - if (!cmd->use_sg) - ql_pdma(priv, phase, cmd->request_buffer, - cmd->request_bufflen); - else { - sgcount = cmd->use_sg; - sglist = cmd->request_buffer; - while (sgcount--) { - if (priv->qabort) { - REG0; - return ((priv->qabort == 1 ? - DID_ABORT : DID_RESET) << 16); - } - buf = page_address(sglist->page) + sglist->offset; - if (ql_pdma(priv, phase, buf, sglist->length)) - break; - sglist++; - } - } - REG0; - rtrc(2) - /* - * Wait for irq (split into second state of irq handler - * if this can take time) - */ - if ((k = ql_wai(priv))) - return (k << 16); - k = inb(qbase + 5); /* should be 0x10, bus service */ - } - - /* - * Enter Status (and Message In) Phase - */ - - k = jiffies + WATCHDOG; - - while (time_before(jiffies, k) && !priv->qabort && - !(inb(qbase + 4) & 6)) - cpu_relax(); /* wait for status phase */ - - if (time_after_eq(jiffies, k)) { - ql_zap(priv); - return (DID_TIME_OUT << 16); - } - - /* FIXME: timeout ?? */ - while (inb(qbase + 5)) - cpu_relax(); /* clear pending ints */ - - if (priv->qabort) - return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16); - - outb(0x11, qbase + 3); /* get status and message */ - if ((k = ql_wai(priv))) - return (k << 16); - i = inb(qbase + 5); /* get chip irq stat */ - j = inb(qbase + 7) & 0x1f; /* and bytes rec'd */ - status = inb(qbase + 2); - message = inb(qbase + 2); - - /* - * Should get function complete int if Status and message, else - * bus serv if only status - */ - if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) { - printk(KERN_ERR "Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j); - result = DID_ERROR; - } - outb(0x12, qbase + 3); /* done, disconnect */ - rtrc(1) - if ((k = ql_wai(priv))) - return (k << 16); - - /* - * Should get bus service interrupt and disconnect interrupt - */ - - i = inb(qbase + 5); /* should be bus service */ - while (!priv->qabort && ((i & 0x20) != 0x20)) { - barrier(); - cpu_relax(); - i |= inb(qbase + 5); - } - rtrc(0) - - if (priv->qabort) - return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16); - - return (result << 16) | (message << 8) | (status & STATUS_MASK); -} +#include "qlogicfas408.h" -/* - * Interrupt handler +/* Set the following to 2 to use normal interrupt (active high/totempole- + * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open + * drain */ +#define INT_TYPE 2 -static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs) -{ - Scsi_Cmnd *icmd; - struct Scsi_Host *host = (struct Scsi_Host *)dev_id; - qlogicfas_priv_t priv = (qlogicfas_priv_t)&(host->hostdata[0]); - int qbase = priv->qbase; - REG0; - - if (!(inb(qbase + 4) & 0x80)) /* false alarm? */ - return; - - if (priv->qlcmd == NULL) { /* no command to process? */ - int i; - i = 16; - while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */ - return; - } - icmd = priv->qlcmd; - icmd->result = ql_pcmd(icmd); - priv->qlcmd = NULL; - /* - * If result is CHECK CONDITION done calls qcommand to request - * sense - */ - (icmd->scsi_done) (icmd); -} - -irqreturn_t do_ql_ihandl(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long flags; - struct Scsi_Host *host = dev_id; - - spin_lock_irqsave(host->host_lock, flags); - ql_ihandl(irq, dev_id, regs); - spin_unlock_irqrestore(host->host_lock, flags); - return IRQ_HANDLED; -} - -/* - * Queued command - */ - -int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) -{ - qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); - if (cmd->device->id == priv->qinitid) { - cmd->result = DID_BAD_TARGET << 16; - done(cmd); - return 0; - } - - cmd->scsi_done = done; - /* wait for the last command's interrupt to finish */ - while (priv->qlcmd != NULL) { - barrier(); - cpu_relax(); - } - ql_icmd(cmd); - return 0; -} +static char qlogicfas_name[] = "qlogicfas"; -#ifndef PCMCIA /* * Look for qlogic card and init if found */ -struct Scsi_Host *__qlogicfas_detect(Scsi_Host_Template *host, int qbase, +static struct Scsi_Host *__qlogicfas_detect(Scsi_Host_Template *host, + int qbase, int qlirq) { - int i, j; /* these are only used by IRQ detect */ int qltyp; /* type of chip */ int qinitid; struct Scsi_Host *hreg; /* registered host structure */ - qlogicfas_priv_t priv; + struct qlogicfas408_priv *priv; /* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself * decodes the address - I check 230 first since MIDI cards are @@ -490,70 +65,36 @@ * the second card, but I haven't tested this. */ - if (!qbase) { - for (qbase = 0x230; qbase < 0x430; qbase += 0x100) { - if (!request_region(qbase, 0x10, qlogicfas_name)) - continue; - REG1; - if (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) - && ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7)) - break; - release_region(qbase, 0x10); - } - if (qbase == 0x430) - return NULL; - } else - printk(KERN_INFO "Ql: Using preset base address of %03x\n", qbase); + if (!qbase || qlirq == -1) + goto err; + + if (!request_region(qbase, 0x10, qlogicfas_name)) { + printk(KERN_INFO "%s: address %#x is busy\n", qlogicfas_name, + qbase); + goto err; + } + + if (!qlogicfas408_detect(qbase, INT_TYPE)) { + printk(KERN_WARNING "%s: probe failed for %#x\n", + qlogicfas_name, + qbase); + goto err_release_mem; + } - qltyp = inb(qbase + 0xe) & 0xf8; + printk(KERN_INFO "%s: Using preset base address of %03x," + " IRQ %d\n", qlogicfas_name, qbase, qlirq); + + qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE); qinitid = host->this_id; if (qinitid < 0) qinitid = 7; /* if no ID, use 7 */ - outb(1, qbase + 8); /* set for PIO pseudo DMA */ - REG0; - outb(0x40 | qlcfg8 | qinitid, qbase + 8); /* (ini) bus id, disable scsi rst */ - outb(qlcfg5, qbase + 5); /* select timer */ - outb(qlcfg9, qbase + 9); /* prescaler */ - -#if QL_RESET_AT_START - outb(3, qbase + 3); - REG1; - /* FIXME: timeout */ - while (inb(qbase + 0xf) & 4) - cpu_relax(); - REG0; -#endif - - /* - * IRQ probe - toggle pin and check request pending - */ - if (qlirq == -1) { - i = 0xffff; - j = 3; - outb(0x90, qbase + 3); /* illegal command - cause interrupt */ - REG1; - outb(10, 0x20); /* access pending interrupt map */ - outb(10, 0xa0); - while (j--) { - outb(0xb0 | QL_INT_ACTIVE_HIGH, qbase + 0xd); /* int pin off */ - i &= ~(inb(0x20) | (inb(0xa0) << 8)); /* find IRQ off */ - outb(0xb4 | QL_INT_ACTIVE_HIGH, qbase + 0xd); /* int pin on */ - i &= inb(0x20) | (inb(0xa0) << 8); /* find IRQ on */ - } - REG0; - while (inb(qbase + 5)); /* purge int */ - j = -1; - while (i) /* find on bit */ - i >>= 1, j++; /* should check for exactly 1 on */ - qlirq = j; - } else - printk(KERN_INFO "Ql: Using preset IRQ %d\n", qlirq); + qlogicfas408_setup(qbase, qinitid, INT_TYPE); - hreg = scsi_host_alloc(host, sizeof(struct qlogicfas_priv)); + hreg = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv)); if (!hreg) goto err_release_mem; - priv = (qlogicfas_priv_t)&(hreg->hostdata[0]); + priv = get_priv_by_host(hreg); hreg->io_port = qbase; hreg->n_io_port = 16; hreg->dma_channel = -1; @@ -563,13 +104,14 @@ priv->qlirq = qlirq; priv->qinitid = qinitid; priv->shost = hreg; + priv->int_type = INT_TYPE; sprintf(priv->qinfo, "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d", qltyp, qbase, qlirq, QL_TURBO_PDMA); host->name = qlogicfas_name; - if (request_irq(qlirq, do_ql_ihandl, 0, qlogicfas_name, hreg)) + if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogicfas_name, hreg)) goto free_scsi_host; if (scsi_add_host(hreg, NULL)) @@ -587,11 +129,12 @@ err_release_mem: release_region(qbase, 0x10); +err: return NULL; } #define MAX_QLOGICFAS 8 -static qlogicfas_priv_t cards; +static struct qlogicfas408_priv *cards; static int iobase[MAX_QLOGICFAS]; static int irq[MAX_QLOGICFAS] = { [0 ... MAX_QLOGICFAS-1] = -1 }; MODULE_PARM(iobase, "1-" __MODULE_STRING(MAX_QLOGICFAS) "i"); @@ -599,23 +142,21 @@ MODULE_PARM_DESC(iobase, "I/O address"); MODULE_PARM_DESC(irq, "IRQ"); -int __devinit qlogicfas_detect(Scsi_Host_Template *sht) +static int __devinit qlogicfas_detect(Scsi_Host_Template *sht) { - struct Scsi_Host *shost; - qlogicfas_priv_t priv; - int i, - num = 0; + struct Scsi_Host *shost; + struct qlogicfas408_priv *priv; + int num; - for (i = 0; i < MAX_QLOGICFAS; i++) { + for (num = 0; num < MAX_QLOGICFAS; num++) { shost = __qlogicfas_detect(sht, iobase[num], irq[num]); if (shost == NULL) { /* no more devices */ break; } - priv = (qlogicfas_priv_t)&(shost->hostdata[0]); + priv = get_priv_by_host(shost); priv->next = cards; cards = priv; - num++; } return num; @@ -623,13 +164,10 @@ static int qlogicfas_release(struct Scsi_Host *shost) { - qlogicfas_priv_t priv = (qlogicfas_priv_t)&(shost->hostdata[0]); - int qbase = priv->qbase; + struct qlogicfas408_priv *priv = get_priv_by_host(shost); if (shost->irq) { - REG1; - outb(0, qbase + 0xb); /* disable ints */ - + qlogicfas408_disable_ints(priv); free_irq(shost->irq, shost); } if (shost->dma_channel != 0xff) @@ -641,100 +179,21 @@ return 0; } -#endif /* ifndef PCMCIA */ - -/* - * Return bios parameters - */ - -int qlogicfas_biosparam(struct scsi_device * disk, - struct block_device *dev, - sector_t capacity, int ip[]) -{ -/* This should mimic the DOS Qlogic driver's behavior exactly */ - ip[0] = 0x40; - ip[1] = 0x20; - ip[2] = (unsigned long) capacity / (ip[0] * ip[1]); - if (ip[2] > 1024) { - ip[0] = 0xff; - ip[1] = 0x3f; - ip[2] = (unsigned long) capacity / (ip[0] * ip[1]); -#if 0 - if (ip[2] > 1023) - ip[2] = 1023; -#endif - } - return 0; -} - -/* - * Abort a command in progress - */ - -static int qlogicfas_abort(Scsi_Cmnd * cmd) -{ - qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); - priv->qabort = 1; - ql_zap(priv); - return SUCCESS; -} - -/* - * Reset SCSI bus - * FIXME: This function is invoked with cmd = NULL directly by - * the PCMCIA qlogic_stub code. This wants fixing - */ - -int qlogicfas_bus_reset(Scsi_Cmnd * cmd) -{ - qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); - priv->qabort = 2; - ql_zap(priv); - return SUCCESS; -} - -/* - * Reset SCSI host controller - */ - -static int qlogicfas_host_reset(Scsi_Cmnd * cmd) -{ - return FAILED; -} - -/* - * Reset SCSI device - */ - -static int qlogicfas_device_reset(Scsi_Cmnd * cmd) -{ - return FAILED; -} - -/* - * Return info string - */ - -static const char *qlogicfas_info(struct Scsi_Host *host) -{ - qlogicfas_priv_t priv = (qlogicfas_priv_t)&(host->hostdata[0]); - return priv->qinfo; -} /* * The driver template is also needed for PCMCIA */ -Scsi_Host_Template qlogicfas_driver_template = { +static Scsi_Host_Template qlogicfas_driver_template = { .module = THIS_MODULE, .name = qlogicfas_name, .proc_name = qlogicfas_name, - .info = qlogicfas_info, - .queuecommand = qlogicfas_queuecommand, - .eh_abort_handler = qlogicfas_abort, - .eh_bus_reset_handler = qlogicfas_bus_reset, - .eh_device_reset_handler= qlogicfas_device_reset, - .eh_host_reset_handler = qlogicfas_host_reset, - .bios_param = qlogicfas_biosparam, + .info = qlogicfas408_info, + .queuecommand = qlogicfas408_queuecommand, + .eh_abort_handler = qlogicfas408_abort, + .eh_bus_reset_handler = qlogicfas408_bus_reset, + .eh_device_reset_handler= qlogicfas408_device_reset, + .eh_host_reset_handler = qlogicfas408_host_reset, + .bios_param = qlogicfas408_biosparam, .can_queue = 1, .this_id = -1, .sg_tablesize = SG_ALL, @@ -742,11 +201,13 @@ .use_clustering = DISABLE_CLUSTERING, }; -#ifndef PCMCIA static __init int qlogicfas_init(void) { if (!qlogicfas_detect(&qlogicfas_driver_template)) { /* no cards found */ + printk(KERN_INFO "%s: no cards were found, please specify " + "I/O address and IRQ using iobase= and irq= " + "options", qlogicfas_name); return -ENODEV; } @@ -755,16 +216,15 @@ static __exit void qlogicfas_exit(void) { - qlogicfas_priv_t priv; + struct qlogicfas408_priv *priv; for (priv = cards; priv != NULL; priv = priv->next) qlogicfas_release(priv->shost); } MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); -MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers"); +MODULE_DESCRIPTION("Driver for the Qlogic FAS408 based ISA card"); MODULE_LICENSE("GPL"); module_init(qlogicfas_init); module_exit(qlogicfas_exit); -#endif /* ifndef PCMCIA */ diff -Nru a/drivers/scsi/qlogicfas.h b/drivers/scsi/qlogicfas.h --- a/drivers/scsi/qlogicfas.h Tue May 4 22:18:43 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,124 +0,0 @@ -/* to be used by qlogicfas and qlogic_cs */ -#ifndef __QLOGICFAS_H -#define __QLOGICFAS_H - -/*----------------------------------------------------------------*/ -/* Configuration */ - -/* Set the following to 2 to use normal interrupt (active high/totempole- - tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open - drain */ - -#define QL_INT_ACTIVE_HIGH 2 - -/* Set the following to max out the speed of the PIO PseudoDMA transfers, - again, 0 tends to be slower, but more stable. */ - -#define QL_TURBO_PDMA 1 - -/* This should be 1 to enable parity detection */ - -#define QL_ENABLE_PARITY 1 - -/* This will reset all devices when the driver is initialized (during bootup). - The other linux drivers don't do this, but the DOS drivers do, and after - using DOS or some kind of crash or lockup this will bring things back - without requiring a cold boot. It does take some time to recover from a - reset, so it is slower, and I have seen timeouts so that devices weren't - recognized when this was set. */ - -#define QL_RESET_AT_START 0 - -/* crystal frequency in megahertz (for offset 5 and 9) - Please set this for your card. Most Qlogic cards are 40 Mhz. The - Control Concepts ISA (not VLB) is 24 Mhz */ - -#define XTALFREQ 40 - -/**********/ -/* DANGER! modify these at your own risk */ -/* SLOWCABLE can usually be reset to zero if you have a clean setup and - proper termination. The rest are for synchronous transfers and other - advanced features if your device can transfer faster than 5Mb/sec. - If you are really curious, email me for a quick howto until I have - something official */ -/**********/ - -/*****/ -/* config register 1 (offset 8) options */ -/* This needs to be set to 1 if your cabling is long or noisy */ -#define SLOWCABLE 1 - -/*****/ -/* offset 0xc */ -/* This will set fast (10Mhz) synchronous timing when set to 1 - For this to have an effect, FASTCLK must also be 1 */ -#define FASTSCSI 0 - -/* This when set to 1 will set a faster sync transfer rate */ -#define FASTCLK 0 /*(XTALFREQ>25?1:0)*/ - -/*****/ -/* offset 6 */ -/* This is the sync transfer divisor, XTALFREQ/X will be the maximum - achievable data rate (assuming the rest of the system is capable - and set properly) */ -#define SYNCXFRPD 5 /*(XTALFREQ/5)*/ - -/*****/ -/* offset 7 */ -/* This is the count of how many synchronous transfers can take place - i.e. how many reqs can occur before an ack is given. - The maximum value for this is 15, the upper bits can modify - REQ/ACK assertion and deassertion during synchronous transfers - If this is 0, the bus will only transfer asynchronously */ -#define SYNCOFFST 0 -/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles - of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will - cause the deassertion to be early by 1/2 clock. Bits 5&4 control - the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */ - -/*----------------------------------------------------------------*/ -#ifdef PCMCIA -#undef QL_INT_ACTIVE_HIGH -#define QL_INT_ACTIVE_HIGH 0 -#endif - -struct qlogicfas_priv; -typedef struct qlogicfas_priv *qlogicfas_priv_t; -struct qlogicfas_priv { - int qbase; /* Port */ - int qinitid; /* initiator ID */ - int qabort; /* Flag to cause an abort */ - int qlirq; /* IRQ being used */ - char qinfo[80]; /* description */ - Scsi_Cmnd *qlcmd; /* current command being processed */ - struct Scsi_Host *shost; /* pointer back to host */ - qlogicfas_priv_t next; /* next private struct */ -}; - -extern int qlcfg5; -extern int qlcfg6; -extern int qlcfg7; -extern int qlcfg8; -extern int qlcfg9; -extern int qlcfgc; - -/* The qlogic card uses two register maps - These macros select which one */ -#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd )) -#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd )) - -/* following is watchdog timeout in microseconds */ -#define WATCHDOG 5000000 - -/*----------------------------------------------------------------*/ -/* the following will set the monitor border color (useful to find - where something crashed or gets stuck at and as a simple profiler) */ - -#if 0 -#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);} -#else -#define rtrc(i) {} -#endif -#endif /* __QLOGICFAS_H */ - diff -Nru a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/qlogicfas408.c Tue May 4 22:18:43 2004 @@ -0,0 +1,637 @@ +/*----------------------------------------------------------------*/ +/* + Qlogic linux driver - work in progress. No Warranty express or implied. + Use at your own risk. Support Tort Reform so you won't have to read all + these silly disclaimers. + + Copyright 1994, Tom Zerucha. + tz@execpc.com + + Additional Code, and much appreciated help by + Michael A. Griffith + grif@cs.ucr.edu + + Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA + help respectively, and for suffering through my foolishness during the + debugging process. + + Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994 + (you can reference it, but it is incomplete and inaccurate in places) + + Version 0.46 1/30/97 - kernel 1.2.0+ + + Functions as standalone, loadable, and PCMCIA driver, the latter from + Dave Hinds' PCMCIA package. + + Cleaned up 26/10/2002 by Alan Cox as part of the 2.5 + SCSI driver cleanup and audit. This driver still needs work on the + following + - Non terminating hardware waits + - Some layering violations with its pcmcia stub + + Redistributable under terms of the GNU General Public License + + For the avoidance of doubt the "preferred form" of this code is one which + is in an open non patent encumbered format. Where cryptographic key signing + forms part of the process of creating an executable the information + including keys needed to generate an equivalently functional executable + are deemed to be part of the source code. + +*/ + +#include +#include /* to get disk capacity */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "scsi.h" +#include "hosts.h" +#include "qlogicfas408.h" + +/*----------------------------------------------------------------*/ +static int qlcfg5 = (XTALFREQ << 5); /* 15625/512 */ +static int qlcfg6 = SYNCXFRPD; +static int qlcfg7 = SYNCOFFST; +static int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4); +static int qlcfg9 = ((XTALFREQ + 4) / 5); +static int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4); + +/*----------------------------------------------------------------*/ + +/*----------------------------------------------------------------*/ +/* local functions */ +/*----------------------------------------------------------------*/ + +/* error recovery - reset everything */ + +static void ql_zap(struct qlogicfas408_priv *priv) +{ + int x; + int qbase = priv->qbase; + int int_type = priv->int_type; + + x = inb(qbase + 0xd); + REG0; + outb(3, qbase + 3); /* reset SCSI */ + outb(2, qbase + 3); /* reset chip */ + if (x & 0x80) + REG1; +} + +/* + * Do a pseudo-dma tranfer + */ + +static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request, int reqlen) +{ + int j; + int qbase = priv->qbase; + j = 0; + if (phase & 1) { /* in */ +#if QL_TURBO_PDMA + rtrc(4) + /* empty fifo in large chunks */ + if (reqlen >= 128 && (inb(qbase + 8) & 2)) { /* full */ + insl(qbase + 4, request, 32); + reqlen -= 128; + request += 128; + } + while (reqlen >= 84 && !(j & 0xc0)) /* 2/3 */ + if ((j = inb(qbase + 8)) & 4) + { + insl(qbase + 4, request, 21); + reqlen -= 84; + request += 84; + } + if (reqlen >= 44 && (inb(qbase + 8) & 8)) { /* 1/3 */ + insl(qbase + 4, request, 11); + reqlen -= 44; + request += 44; + } +#endif + /* until both empty and int (or until reclen is 0) */ + rtrc(7) + j = 0; + while (reqlen && !((j & 0x10) && (j & 0xc0))) + { + /* while bytes to receive and not empty */ + j &= 0xc0; + while (reqlen && !((j = inb(qbase + 8)) & 0x10)) + { + *request++ = inb(qbase + 4); + reqlen--; + } + if (j & 0x10) + j = inb(qbase + 8); + + } + } else { /* out */ +#if QL_TURBO_PDMA + rtrc(4) + if (reqlen >= 128 && inb(qbase + 8) & 0x10) { /* empty */ + outsl(qbase + 4, request, 32); + reqlen -= 128; + request += 128; + } + while (reqlen >= 84 && !(j & 0xc0)) /* 1/3 */ + if (!((j = inb(qbase + 8)) & 8)) { + outsl(qbase + 4, request, 21); + reqlen -= 84; + request += 84; + } + if (reqlen >= 40 && !(inb(qbase + 8) & 4)) { /* 2/3 */ + outsl(qbase + 4, request, 10); + reqlen -= 40; + request += 40; + } +#endif + /* until full and int (or until reclen is 0) */ + rtrc(7) + j = 0; + while (reqlen && !((j & 2) && (j & 0xc0))) { + /* while bytes to send and not full */ + while (reqlen && !((j = inb(qbase + 8)) & 2)) + { + outb(*request++, qbase + 4); + reqlen--; + } + if (j & 2) + j = inb(qbase + 8); + } + } + /* maybe return reqlen */ + return inb(qbase + 8) & 0xc0; +} + +/* + * Wait for interrupt flag (polled - not real hardware interrupt) + */ + +static int ql_wai(struct qlogicfas408_priv *priv) +{ + int k; + int qbase = priv->qbase; + unsigned long i; + + k = 0; + i = jiffies + WATCHDOG; + while (time_before(jiffies, i) && !priv->qabort && + !((k = inb(qbase + 4)) & 0xe0)) { + barrier(); + cpu_relax(); + } + if (time_after_eq(jiffies, i)) + return (DID_TIME_OUT); + if (priv->qabort) + return (priv->qabort == 1 ? DID_ABORT : DID_RESET); + if (k & 0x60) + ql_zap(priv); + if (k & 0x20) + return (DID_PARITY); + if (k & 0x40) + return (DID_ERROR); + return 0; +} + +/* + * Initiate scsi command - queueing handler + * caller must hold host lock + */ + +static void ql_icmd(Scsi_Cmnd * cmd) +{ + struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); + int qbase = priv->qbase; + int int_type = priv->int_type; + unsigned int i; + + priv->qabort = 0; + + REG0; + /* clearing of interrupts and the fifo is needed */ + + inb(qbase + 5); /* clear interrupts */ + if (inb(qbase + 5)) /* if still interrupting */ + outb(2, qbase + 3); /* reset chip */ + else if (inb(qbase + 7) & 0x1f) + outb(1, qbase + 3); /* clear fifo */ + while (inb(qbase + 5)); /* clear ints */ + REG1; + outb(1, qbase + 8); /* set for PIO pseudo DMA */ + outb(0, qbase + 0xb); /* disable ints */ + inb(qbase + 8); /* clear int bits */ + REG0; + outb(0x40, qbase + 0xb); /* enable features */ + + /* configurables */ + outb(qlcfgc, qbase + 0xc); + /* config: no reset interrupt, (initiator) bus id */ + outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8); + outb(qlcfg7, qbase + 7); + outb(qlcfg6, qbase + 6); + /**/ outb(qlcfg5, qbase + 5); /* select timer */ + outb(qlcfg9 & 7, qbase + 9); /* prescaler */ +/* outb(0x99, qbase + 5); */ + outb(cmd->device->id, qbase + 4); + + for (i = 0; i < cmd->cmd_len; i++) + outb(cmd->cmnd[i], qbase + 2); + + priv->qlcmd = cmd; + outb(0x41, qbase + 3); /* select and send command */ +} + +/* + * Process scsi command - usually after interrupt + */ + +static unsigned int ql_pcmd(Scsi_Cmnd * cmd) +{ + unsigned int i, j; + unsigned long k; + unsigned int result; /* ultimate return result */ + unsigned int status; /* scsi returned status */ + unsigned int message; /* scsi returned message */ + unsigned int phase; /* recorded scsi phase */ + unsigned int reqlen; /* total length of transfer */ + struct scatterlist *sglist; /* scatter-gather list pointer */ + unsigned int sgcount; /* sg counter */ + char *buf; + struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); + int qbase = priv->qbase; + int int_type = priv->int_type; + + rtrc(1) + j = inb(qbase + 6); + i = inb(qbase + 5); + if (i == 0x20) { + return (DID_NO_CONNECT << 16); + } + i |= inb(qbase + 5); /* the 0x10 bit can be set after the 0x08 */ + if (i != 0x18) { + printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i); + ql_zap(priv); + return (DID_BAD_INTR << 16); + } + j &= 7; /* j = inb( qbase + 7 ) >> 5; */ + + /* correct status is supposed to be step 4 */ + /* it sometimes returns step 3 but with 0 bytes left to send */ + /* We can try stuffing the FIFO with the max each time, but we will get a + sequence of 3 if any bytes are left (but we do flush the FIFO anyway */ + + if (j != 3 && j != 4) { + printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", + j, i, inb(qbase + 7) & 0x1f); + ql_zap(priv); + return (DID_ERROR << 16); + } + result = DID_OK; + if (inb(qbase + 7) & 0x1f) /* if some bytes in fifo */ + outb(1, qbase + 3); /* clear fifo */ + /* note that request_bufflen is the total xfer size when sg is used */ + reqlen = cmd->request_bufflen; + /* note that it won't work if transfers > 16M are requested */ + if (reqlen && !((phase = inb(qbase + 4)) & 6)) { /* data phase */ + rtrc(2) + outb(reqlen, qbase); /* low-mid xfer cnt */ + outb(reqlen >> 8, qbase + 1); /* low-mid xfer cnt */ + outb(reqlen >> 16, qbase + 0xe); /* high xfer cnt */ + outb(0x90, qbase + 3); /* command do xfer */ + /* PIO pseudo DMA to buffer or sglist */ + REG1; + if (!cmd->use_sg) + ql_pdma(priv, phase, cmd->request_buffer, + cmd->request_bufflen); + else { + sgcount = cmd->use_sg; + sglist = cmd->request_buffer; + while (sgcount--) { + if (priv->qabort) { + REG0; + return ((priv->qabort == 1 ? + DID_ABORT : DID_RESET) << 16); + } + buf = page_address(sglist->page) + sglist->offset; + if (ql_pdma(priv, phase, buf, sglist->length)) + break; + sglist++; + } + } + REG0; + rtrc(2) + /* + * Wait for irq (split into second state of irq handler + * if this can take time) + */ + if ((k = ql_wai(priv))) + return (k << 16); + k = inb(qbase + 5); /* should be 0x10, bus service */ + } + + /* + * Enter Status (and Message In) Phase + */ + + k = jiffies + WATCHDOG; + + while (time_before(jiffies, k) && !priv->qabort && + !(inb(qbase + 4) & 6)) + cpu_relax(); /* wait for status phase */ + + if (time_after_eq(jiffies, k)) { + ql_zap(priv); + return (DID_TIME_OUT << 16); + } + + /* FIXME: timeout ?? */ + while (inb(qbase + 5)) + cpu_relax(); /* clear pending ints */ + + if (priv->qabort) + return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16); + + outb(0x11, qbase + 3); /* get status and message */ + if ((k = ql_wai(priv))) + return (k << 16); + i = inb(qbase + 5); /* get chip irq stat */ + j = inb(qbase + 7) & 0x1f; /* and bytes rec'd */ + status = inb(qbase + 2); + message = inb(qbase + 2); + + /* + * Should get function complete int if Status and message, else + * bus serv if only status + */ + if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) { + printk(KERN_ERR "Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j); + result = DID_ERROR; + } + outb(0x12, qbase + 3); /* done, disconnect */ + rtrc(1) + if ((k = ql_wai(priv))) + return (k << 16); + + /* + * Should get bus service interrupt and disconnect interrupt + */ + + i = inb(qbase + 5); /* should be bus service */ + while (!priv->qabort && ((i & 0x20) != 0x20)) { + barrier(); + cpu_relax(); + i |= inb(qbase + 5); + } + rtrc(0) + + if (priv->qabort) + return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16); + + return (result << 16) | (message << 8) | (status & STATUS_MASK); +} + +/* + * Interrupt handler + */ + +static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs) +{ + Scsi_Cmnd *icmd; + struct Scsi_Host *host = (struct Scsi_Host *)dev_id; + struct qlogicfas408_priv *priv = get_priv_by_host(host); + int qbase = priv->qbase; + REG0; + + if (!(inb(qbase + 4) & 0x80)) /* false alarm? */ + return; + + if (priv->qlcmd == NULL) { /* no command to process? */ + int i; + i = 16; + while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */ + return; + } + icmd = priv->qlcmd; + icmd->result = ql_pcmd(icmd); + priv->qlcmd = NULL; + /* + * If result is CHECK CONDITION done calls qcommand to request + * sense + */ + (icmd->scsi_done) (icmd); +} + +irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + struct Scsi_Host *host = dev_id; + + spin_lock_irqsave(host->host_lock, flags); + ql_ihandl(irq, dev_id, regs); + spin_unlock_irqrestore(host->host_lock, flags); + return IRQ_HANDLED; +} + +/* + * Queued command + */ + +int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) +{ + struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); + if (cmd->device->id == priv->qinitid) { + cmd->result = DID_BAD_TARGET << 16; + done(cmd); + return 0; + } + + cmd->scsi_done = done; + /* wait for the last command's interrupt to finish */ + while (priv->qlcmd != NULL) { + barrier(); + cpu_relax(); + } + ql_icmd(cmd); + return 0; +} + +/* + * Return bios parameters + */ + +int qlogicfas408_biosparam(struct scsi_device * disk, + struct block_device *dev, + sector_t capacity, int ip[]) +{ +/* This should mimic the DOS Qlogic driver's behavior exactly */ + ip[0] = 0x40; + ip[1] = 0x20; + ip[2] = (unsigned long) capacity / (ip[0] * ip[1]); + if (ip[2] > 1024) { + ip[0] = 0xff; + ip[1] = 0x3f; + ip[2] = (unsigned long) capacity / (ip[0] * ip[1]); +#if 0 + if (ip[2] > 1023) + ip[2] = 1023; +#endif + } + return 0; +} + +/* + * Abort a command in progress + */ + +int qlogicfas408_abort(Scsi_Cmnd * cmd) +{ + struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); + priv->qabort = 1; + ql_zap(priv); + return SUCCESS; +} + +/* + * Reset SCSI bus + * FIXME: This function is invoked with cmd = NULL directly by + * the PCMCIA qlogic_stub code. This wants fixing + */ + +int qlogicfas408_bus_reset(Scsi_Cmnd * cmd) +{ + struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); + priv->qabort = 2; + ql_zap(priv); + return SUCCESS; +} + +/* + * Reset SCSI host controller + */ + +int qlogicfas408_host_reset(Scsi_Cmnd * cmd) +{ + return FAILED; +} + +/* + * Reset SCSI device + */ + +int qlogicfas408_device_reset(Scsi_Cmnd * cmd) +{ + return FAILED; +} + +/* + * Return info string + */ + +char *qlogicfas408_info(struct Scsi_Host *host) +{ + struct qlogicfas408_priv *priv = get_priv_by_host(host); + return priv->qinfo; +} + +/* + * Get type of chip + */ + +int qlogicfas408_get_chip_type(int qbase, int int_type) +{ + REG1; + return inb(qbase + 0xe) & 0xf8; +} + +/* + * Perform initialization tasks + */ + +void qlogicfas408_setup(int qbase, int id, int int_type) +{ + outb(1, qbase + 8); /* set for PIO pseudo DMA */ + REG0; + outb(0x40 | qlcfg8 | id, qbase + 8); /* (ini) bus id, disable scsi rst */ + outb(qlcfg5, qbase + 5); /* select timer */ + outb(qlcfg9, qbase + 9); /* prescaler */ + +#if QL_RESET_AT_START + outb(3, qbase + 3); + + REG1; + /* FIXME: timeout */ + while (inb(qbase + 0xf) & 4) + cpu_relax(); + + REG0; +#endif +} + +/* + * Checks if this is a QLogic FAS 408 + */ + +int qlogicfas408_detect(int qbase, int int_type) +{ + REG1; + return (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) && + ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7)); +} + +/* + * Disable interrupts + */ + +void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv) +{ + int qbase = priv->qbase; + int int_type = priv->int_type; + + REG1; + outb(0, qbase + 0xb); /* disable ints */ +} + +/* + * Init and exit functions + */ + +static int __init qlogicfas408_init(void) +{ + return 0; +} + +static void __exit qlogicfas408_exit(void) +{ + +} + +MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); +MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers"); +MODULE_LICENSE("GPL"); +module_init(qlogicfas408_init); +module_exit(qlogicfas408_exit); + +EXPORT_SYMBOL(qlogicfas408_info); +EXPORT_SYMBOL(qlogicfas408_queuecommand); +EXPORT_SYMBOL(qlogicfas408_abort); +EXPORT_SYMBOL(qlogicfas408_bus_reset); +EXPORT_SYMBOL(qlogicfas408_device_reset); +EXPORT_SYMBOL(qlogicfas408_host_reset); +EXPORT_SYMBOL(qlogicfas408_biosparam); +EXPORT_SYMBOL(qlogicfas408_ihandl); +EXPORT_SYMBOL(qlogicfas408_get_chip_type); +EXPORT_SYMBOL(qlogicfas408_setup); +EXPORT_SYMBOL(qlogicfas408_detect); +EXPORT_SYMBOL(qlogicfas408_disable_ints); + diff -Nru a/drivers/scsi/qlogicfas408.h b/drivers/scsi/qlogicfas408.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/qlogicfas408.h Tue May 4 22:18:43 2004 @@ -0,0 +1,120 @@ +/* to be used by qlogicfas and qlogic_cs */ +#ifndef __QLOGICFAS408_H +#define __QLOGICFAS408_H + +/*----------------------------------------------------------------*/ +/* Configuration */ + +/* Set the following to max out the speed of the PIO PseudoDMA transfers, + again, 0 tends to be slower, but more stable. */ + +#define QL_TURBO_PDMA 1 + +/* This should be 1 to enable parity detection */ + +#define QL_ENABLE_PARITY 1 + +/* This will reset all devices when the driver is initialized (during bootup). + The other linux drivers don't do this, but the DOS drivers do, and after + using DOS or some kind of crash or lockup this will bring things back + without requiring a cold boot. It does take some time to recover from a + reset, so it is slower, and I have seen timeouts so that devices weren't + recognized when this was set. */ + +#define QL_RESET_AT_START 0 + +/* crystal frequency in megahertz (for offset 5 and 9) + Please set this for your card. Most Qlogic cards are 40 Mhz. The + Control Concepts ISA (not VLB) is 24 Mhz */ + +#define XTALFREQ 40 + +/**********/ +/* DANGER! modify these at your own risk */ +/* SLOWCABLE can usually be reset to zero if you have a clean setup and + proper termination. The rest are for synchronous transfers and other + advanced features if your device can transfer faster than 5Mb/sec. + If you are really curious, email me for a quick howto until I have + something official */ +/**********/ + +/*****/ +/* config register 1 (offset 8) options */ +/* This needs to be set to 1 if your cabling is long or noisy */ +#define SLOWCABLE 1 + +/*****/ +/* offset 0xc */ +/* This will set fast (10Mhz) synchronous timing when set to 1 + For this to have an effect, FASTCLK must also be 1 */ +#define FASTSCSI 0 + +/* This when set to 1 will set a faster sync transfer rate */ +#define FASTCLK 0 /*(XTALFREQ>25?1:0)*/ + +/*****/ +/* offset 6 */ +/* This is the sync transfer divisor, XTALFREQ/X will be the maximum + achievable data rate (assuming the rest of the system is capable + and set properly) */ +#define SYNCXFRPD 5 /*(XTALFREQ/5)*/ + +/*****/ +/* offset 7 */ +/* This is the count of how many synchronous transfers can take place + i.e. how many reqs can occur before an ack is given. + The maximum value for this is 15, the upper bits can modify + REQ/ACK assertion and deassertion during synchronous transfers + If this is 0, the bus will only transfer asynchronously */ +#define SYNCOFFST 0 +/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles + of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will + cause the deassertion to be early by 1/2 clock. Bits 5&4 control + the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */ + +/*----------------------------------------------------------------*/ + +struct qlogicfas408_priv { + int qbase; /* Port */ + int qinitid; /* initiator ID */ + int qabort; /* Flag to cause an abort */ + int qlirq; /* IRQ being used */ + int int_type; /* type of irq, 2 for ISA board, 0 for PCMCIA */ + char qinfo[80]; /* description */ + Scsi_Cmnd *qlcmd; /* current command being processed */ + struct Scsi_Host *shost; /* pointer back to host */ + struct qlogicfas408_priv *next; /* next private struct */ +}; + +/* The qlogic card uses two register maps - These macros select which one */ +#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd )) +#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | int_type, qbase + 0xd )) + +/* following is watchdog timeout in microseconds */ +#define WATCHDOG 5000000 + +/*----------------------------------------------------------------*/ +/* the following will set the monitor border color (useful to find + where something crashed or gets stuck at and as a simple profiler) */ + +#define rtrc(i) {} + +#define get_priv_by_cmd(x) (struct qlogicfas408_priv *)&((x)->device->host->hostdata[0]) +#define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0]) + +irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs); +int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)); +int qlogicfas408_biosparam(struct scsi_device * disk, + struct block_device *dev, + sector_t capacity, int ip[]); +int qlogicfas408_abort(Scsi_Cmnd * cmd); +int qlogicfas408_bus_reset(Scsi_Cmnd * cmd); +int qlogicfas408_host_reset(Scsi_Cmnd * cmd); +int qlogicfas408_device_reset(Scsi_Cmnd * cmd); +char *qlogicfas408_info(struct Scsi_Host *host); +int qlogicfas408_get_chip_type(int qbase, int int_type); +void qlogicfas408_setup(int qbase, int id, int int_type); +int qlogicfas408_detect(int qbase, int int_type); +void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv); +#endif /* __QLOGICFAS408_H */ + diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c --- a/drivers/scsi/scsi.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/scsi.c Tue May 4 22:18:43 2004 @@ -977,8 +977,6 @@ */ int scsi_device_get(struct scsi_device *sdev) { - if(!sdev) - return -ENXIO; if (sdev->sdev_state == SDEV_DEL || sdev->sdev_state == SDEV_CANCEL) return -ENXIO; if (!get_device(&sdev->sdev_gendev)) diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/scsi_scan.c Tue May 4 22:18:43 2004 @@ -330,6 +330,7 @@ struct scsi_device *sdev = sreq->sr_device; /* a bit ugly */ unsigned char scsi_cmd[MAX_COMMAND_SIZE]; int possible_inq_resp_len; + int count = 0; *bflags = 0; repeat_inquiry: @@ -350,19 +351,24 @@ SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: 1st INQUIRY %s with" " code 0x%x\n", sreq->sr_result ? "failed" : "successful", sreq->sr_result)); + ++count; if (sreq->sr_result) { if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) != 0 && (sreq->sr_sense_buffer[2] & 0xf) == UNIT_ATTENTION && - sreq->sr_sense_buffer[12] == 0x28 && + (sreq->sr_sense_buffer[12] == 0x28 || + sreq->sr_sense_buffer[12] == 0x29) && sreq->sr_sense_buffer[13] == 0) { - /* not-ready to ready transition - good */ + /* not-ready to ready transition or power-on - good */ /* dpg: bogus? INQUIRY never returns UNIT_ATTENTION */ - } else - /* - * assume no peripheral if any other sort of error - */ - return; + /* Supposedly, but many buggy devices do so anyway */ + if (count < 3) + goto repeat_inquiry; + } + /* + * assume no peripheral if any other sort of error + */ + return; } /* @@ -543,17 +549,12 @@ * 011 the same. Stay compatible with previous code, and create a * Scsi_Device for a PQ of 1 * - * XXX Save the PQ field let the upper layers figure out if they - * want to attach or not to this device, do not set online FALSE; - * otherwise, offline devices still get an sd allocated, and they - * use up an sd slot. - */ - if (((inq_result[0] >> 5) & 7) == 1) { - SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: peripheral" - " qualifier of 1, device offlined\n")); - scsi_device_set_state(sdev, SDEV_OFFLINE); - } + * Don't set the device offline here; rather let the upper + * level drivers eval the PQ to decide whether they should + * attach. So remove ((inq_result[0] >> 5) & 7) == 1 check. + */ + sdev->inq_periph_qual = (inq_result[0] >> 5) & 7; sdev->removable = (0x80 & inq_result[1]) >> 7; sdev->lockable = sdev->removable; sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2); diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c --- a/drivers/scsi/scsi_sysfs.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/scsi_sysfs.c Tue May 4 22:18:43 2004 @@ -181,7 +181,8 @@ /* all probing is done in the individual ->probe routines */ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv) { - return 1; + struct scsi_device *sdp = to_scsi_device(dev); + return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0; } struct bus_type scsi_bus_type = { diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/sd.c Tue May 4 22:18:43 2004 @@ -179,7 +179,16 @@ goto out; sdkp = scsi_disk(disk); if (!kref_get(&sdkp->kref)) - sdkp = NULL; + goto out_sdkp; + if (scsi_device_get(sdkp->device)) + goto out_put; + up(&sd_ref_sem); + return sdkp; + + out_put: + kref_put(&sdkp->kref); + out_sdkp: + sdkp = NULL; out: up(&sd_ref_sem); return sdkp; @@ -188,6 +197,7 @@ static void scsi_disk_put(struct scsi_disk *sdkp) { down(&sd_ref_sem); + scsi_device_put(sdkp->device); kref_put(&sdkp->kref); up(&sd_ref_sem); } @@ -1342,16 +1352,13 @@ if ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD)) goto out; - if ((error = scsi_device_get(sdp)) != 0) - goto out; - SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n", sdp->host->host_no, sdp->channel, sdp->id, sdp->lun)); error = -ENOMEM; sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL); if (!sdkp) - goto out_put_sdev; + goto out; memset (sdkp, 0, sizeof(*sdkp)); kref_init(&sdkp->kref, scsi_disk_release); @@ -1427,8 +1434,6 @@ put_disk(gd); out_free: kfree(sdkp); -out_put_sdev: - scsi_device_put(sdp); out: return error; } @@ -1450,7 +1455,9 @@ del_gendisk(sdkp->disk); sd_shutdown(dev); - scsi_disk_put(sdkp); + down(&sd_ref_sem); + kref_put(&sdkp->kref); + up(&sd_ref_sem); return 0; } @@ -1467,7 +1474,6 @@ static void scsi_disk_release(struct kref *kref) { struct scsi_disk *sdkp = to_scsi_disk(kref); - struct scsi_device *sdev = sdkp->device; struct gendisk *disk = sdkp->disk; spin_lock(&sd_index_lock); @@ -1479,8 +1485,6 @@ put_disk(disk); kfree(sdkp); - - scsi_device_put(sdev); } /* diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c --- a/drivers/scsi/st.c Tue May 4 22:18:43 2004 +++ b/drivers/scsi/st.c Tue May 4 22:18:43 2004 @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch Devfs support */ -static char *verstr = "20040318"; +static char *verstr = "20040403"; #include @@ -1031,7 +1031,8 @@ /* See that we have at least a one page buffer available */ if (!enlarge_buffer(STp->buffer, PAGE_SIZE, STp->restr_dma)) { - printk(KERN_WARNING "%s: Can't allocate tape buffer.\n", name); + printk(KERN_WARNING "%s: Can't allocate one page tape buffer.\n", + name); retval = (-EOVERFLOW); goto err_out; } @@ -1318,6 +1319,8 @@ bufsize = count; if (bufsize > STbp->buffer_size && !enlarge_buffer(STbp, bufsize, STp->restr_dma)) { + printk(KERN_WARNING "%s: Can't allocate %d byte tape buffer.\n", + tape_name(STp), bufsize); retval = (-EOVERFLOW); goto out; } @@ -1960,26 +1963,29 @@ +DEB( /* Set the driver options */ static void st_log_options(Scsi_Tape * STp, ST_mode * STm, char *name) { - printk(KERN_INFO - "%s: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", - name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, - STm->do_read_ahead); - printk(KERN_INFO - "%s: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", - name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); - printk(KERN_INFO - "%s: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", - name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, - STp->scsi2_logical); - printk(KERN_INFO - "%s: sysv: %d nowait: %d\n", name, STm->sysv, STp->immediate); - DEB(printk(KERN_INFO - "%s: debugging: %d\n", - name, debugging);) + if (debugging) { + printk(KERN_INFO + "%s: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", + name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, + STm->do_read_ahead); + printk(KERN_INFO + "%s: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", + name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); + printk(KERN_INFO + "%s: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", + name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, + STp->scsi2_logical); + printk(KERN_INFO + "%s: sysv: %d nowait: %d\n", name, STm->sysv, STp->immediate); + printk(KERN_INFO "%s: debugging: %d\n", + name, debugging); + } } + ) static int st_set_options(Scsi_Tape *STp, long options) @@ -2017,8 +2023,8 @@ STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; STp->immediate = (options & MT_ST_NOWAIT) != 0; STm->sysv = (options & MT_ST_SYSV) != 0; - DEB( debugging = (options & MT_ST_DEBUGGING) != 0; ) - st_log_options(STp, STm, name); + DEB( debugging = (options & MT_ST_DEBUGGING) != 0; + st_log_options(STp, STm, name); ) } else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { value = (code == MT_ST_SETBOOLEANS); if ((options & MT_ST_BUFFER_WRITES) != 0) @@ -2050,19 +2056,19 @@ STm->sysv = value; DEB( if ((options & MT_ST_DEBUGGING) != 0) - debugging = value; ) - st_log_options(STp, STm, name); + debugging = value; + st_log_options(STp, STm, name); ) } else if (code == MT_ST_WRITE_THRESHOLD) { /* Retained for compatibility */ } else if (code == MT_ST_DEF_BLKSIZE) { value = (options & ~MT_ST_OPTIONS); if (value == ~MT_ST_OPTIONS) { STm->default_blksize = (-1); - printk(KERN_INFO "%s: Default block size disabled.\n", name); + DEBC( printk(KERN_INFO "%s: Default block size disabled.\n", name)); } else { STm->default_blksize = value; - printk(KERN_INFO "%s: Default block size set to %d bytes.\n", - name, STm->default_blksize); + DEBC( printk(KERN_INFO "%s: Default block size set to %d bytes.\n", + name, STm->default_blksize)); if (STp->ready == ST_READY) { STp->blksize_changed = FALSE; set_mode_densblk(STp, STm); @@ -2072,12 +2078,12 @@ value = (options & ~MT_ST_OPTIONS); if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) { STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ; - printk(KERN_INFO "%s: Long timeout set to %d seconds.\n", name, - (value & ~MT_ST_SET_LONG_TIMEOUT)); + DEBC( printk(KERN_INFO "%s: Long timeout set to %d seconds.\n", name, + (value & ~MT_ST_SET_LONG_TIMEOUT))); } else { STp->timeout = value * HZ; - printk(KERN_INFO "%s: Normal timeout set to %d seconds.\n", - name, value); + DEBC( printk(KERN_INFO "%s: Normal timeout set to %d seconds.\n", + name, value) ); } } else if (code == MT_ST_SET_CLN) { value = (options & ~MT_ST_OPTIONS) & 0xff; @@ -2096,12 +2102,12 @@ if (code == MT_ST_DEF_DENSITY) { if (value == MT_ST_CLEAR_DEFAULT) { STm->default_density = (-1); - printk(KERN_INFO "%s: Density default disabled.\n", - name); + DEBC( printk(KERN_INFO "%s: Density default disabled.\n", + name)); } else { STm->default_density = value & 0xff; - printk(KERN_INFO "%s: Density default set to %x\n", - name, STm->default_density); + DEBC( printk(KERN_INFO "%s: Density default set to %x\n", + name, STm->default_density)); if (STp->ready == ST_READY) { STp->density_changed = FALSE; set_mode_densblk(STp, STm); @@ -2110,31 +2116,31 @@ } else if (code == MT_ST_DEF_DRVBUFFER) { if (value == MT_ST_CLEAR_DEFAULT) { STp->default_drvbuffer = 0xff; - printk(KERN_INFO - "%s: Drive buffer default disabled.\n", name); + DEBC( printk(KERN_INFO + "%s: Drive buffer default disabled.\n", name)); } else { STp->default_drvbuffer = value & 7; - printk(KERN_INFO + DEBC( printk(KERN_INFO "%s: Drive buffer default set to %x\n", - name, STp->default_drvbuffer); + name, STp->default_drvbuffer)); if (STp->ready == ST_READY) st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer); } } else if (code == MT_ST_DEF_COMPRESSION) { if (value == MT_ST_CLEAR_DEFAULT) { STm->default_compression = ST_DONT_TOUCH; - printk(KERN_INFO - "%s: Compression default disabled.\n", name); + DEBC( printk(KERN_INFO + "%s: Compression default disabled.\n", name)); } else { if ((value & 0xff00) != 0) { STp->c_algo = (value & 0xff00) >> 8; - printk(KERN_INFO "%s: Compression algorithm set to 0x%x.\n", - name, STp->c_algo); + DEBC( printk(KERN_INFO "%s: Compression algorithm set to 0x%x.\n", + name, STp->c_algo)); } if ((value & 0xff) != 0xff) { STm->default_compression = (value & 1 ? ST_YES : ST_NO); - printk(KERN_INFO "%s: Compression default set to %x\n", - name, (value & 1)); + DEBC( printk(KERN_INFO "%s: Compression default set to %x\n", + name, (value & 1))); if (STp->ready == ST_READY) { STp->compression_changed = FALSE; st_compression(STp, (STm->default_compression == ST_YES)); @@ -3465,7 +3471,7 @@ if (nbr <= 0) return FALSE; - priority = GFP_KERNEL; + priority = GFP_KERNEL | __GFP_NOWARN; if (need_dma) priority |= GFP_DMA; for (b_size = PAGE_SIZE, order=0; @@ -3482,8 +3488,6 @@ order--; continue; } - printk(KERN_NOTICE "st: failed to enlarge buffer to %d bytes.\n", - new_size); DEB(STbuffer->buffer_size = got); normalize_buffer(STbuffer); return FALSE; @@ -3495,9 +3499,6 @@ segs++; } STbuffer->b_data = page_address(STbuffer->frp[0].page); - DEBC(printk(ST_DEB_MSG - "st: Succeeded to enlarge buffer at %p to %d bytes (segs %d->%d, %d).\n", - STbuffer, got, STbuffer->orig_frp_segs, STbuffer->frp_segs, b_size)); return TRUE; } @@ -3513,11 +3514,6 @@ __free_pages(STbuffer->frp[i].page, order); STbuffer->buffer_size -= STbuffer->frp[i].length; } - DEB( - if (debugging && STbuffer->orig_frp_segs < STbuffer->frp_segs) - printk(ST_DEB_MSG "st: Buffer at %p normalized to %d bytes (segs %d->%d).\n", - STbuffer, STbuffer->buffer_size, STbuffer->frp_segs, STbuffer->orig_frp_segs); - ) /* end DEB */ STbuffer->frp_segs = STbuffer->orig_frp_segs; STbuffer->frp_sg_current = 0; } @@ -3547,11 +3543,9 @@ ubp += cnt; offset = 0; } - if (do_count) { /* Should never happen */ - printk(KERN_WARNING "st: append_to_buffer overflow (left %d).\n", - do_count); + if (do_count) /* Should never happen */ return (-EIO); - } + return 0; } @@ -3581,11 +3575,9 @@ ubp += cnt; offset = 0; } - if (do_count) { /* Should never happen */ - printk(KERN_WARNING "st: from_buffer overflow (left %d).\n", - do_count); + if (do_count) /* Should never happen */ return (-EIO); - } + return 0; } @@ -3605,10 +3597,6 @@ if (src_offset < st_bp->frp[src_seg].length) break; offset -= st_bp->frp[src_seg].length; - } - if (src_seg == st_bp->frp_segs) { /* Should never happen */ - printk(KERN_WARNING "st: move_buffer offset overflow.\n"); - return; } st_bp->buffer_bytes = st_bp->read_pointer = total; diff -Nru a/drivers/scsi/sym53c8xx_comm.h b/drivers/scsi/sym53c8xx_comm.h --- a/drivers/scsi/sym53c8xx_comm.h Tue May 4 22:18:43 2004 +++ b/drivers/scsi/sym53c8xx_comm.h Tue May 4 22:18:43 2004 @@ -59,11 +59,8 @@ ** sym53c8xx and ncr53c8xx drivers should share. ** The sharing will be achieved in a further version ** of the driver bundle. For now, only the ncr53c8xx -** driver includes this file. +** driver includes this file. */ - -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) /*========================================================== ** diff -Nru a/include/scsi/scsi.h b/include/scsi/scsi.h --- a/include/scsi/scsi.h Tue May 4 22:18:43 2004 +++ b/include/scsi/scsi.h Tue May 4 22:18:43 2004 @@ -362,6 +362,13 @@ #define SCSI_2 3 #define SCSI_3 4 +/* + * INQ PERIPHERAL QUALIFIERS + */ +#define SCSI_INQ_PQ_CON 0x00 +#define SCSI_INQ_PQ_NOT_CON 0x01 +#define SCSI_INQ_PQ_NOT_CAP 0x03 + /* * Here are some scsi specific ioctl commands which are sometimes useful. diff -Nru a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h --- a/include/scsi/scsi_device.h Tue May 4 22:18:43 2004 +++ b/include/scsi/scsi_device.h Tue May 4 22:18:43 2004 @@ -63,6 +63,7 @@ char devfs_name[256]; /* devfs junk */ char type; char scsi_level; + char inq_periph_qual; /* PQ from INQUIRY data */ unsigned char inquiry_len; /* valid bytes in 'inquiry' */ unsigned char * inquiry; /* INQUIRY response data */ char * vendor; /* [back_compat] point into 'inquiry' ... */