25-akpm/Documentation/scsi/aic79xx.txt | 314 ++- 25-akpm/Documentation/scsi/aic7xxx.txt | 141 + 25-akpm/drivers/scsi/aic7xxx/Kconfig.aic7xxx | 8 25-akpm/drivers/scsi/aic7xxx/Makefile | 24 25-akpm/drivers/scsi/aic7xxx/aic7770.c | 17 25-akpm/drivers/scsi/aic7xxx/aic7770_osm.c | 215 +- 25-akpm/drivers/scsi/aic7xxx/aic79xx.h | 86 25-akpm/drivers/scsi/aic7xxx/aic79xx.reg | 61 25-akpm/drivers/scsi/aic7xxx/aic79xx.seq | 152 + 25-akpm/drivers/scsi/aic7xxx/aic79xx_core.c | 1420 ++++++++++---- 25-akpm/drivers/scsi/aic7xxx/aic79xx_inline.h | 82 25-akpm/drivers/scsi/aic7xxx/aic79xx_osm.c | 1425 +++++++-------- 25-akpm/drivers/scsi/aic7xxx/aic79xx_osm.h | 904 --------- 25-akpm/drivers/scsi/aic7xxx/aic79xx_osm_pci.c | 128 - 25-akpm/drivers/scsi/aic7xxx/aic79xx_pci.c | 168 - 25-akpm/drivers/scsi/aic7xxx/aic79xx_proc.c | 25 25-akpm/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped | 135 - 25-akpm/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped | 129 - 25-akpm/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped | 737 +++---- 25-akpm/drivers/scsi/aic7xxx/aic7xxx.h | 43 25-akpm/drivers/scsi/aic7xxx/aic7xxx.reg | 4 25-akpm/drivers/scsi/aic7xxx/aic7xxx.seq | 5 25-akpm/drivers/scsi/aic7xxx/aic7xxx_93cx6.c | 38 25-akpm/drivers/scsi/aic7xxx/aic7xxx_core.c | 653 +++++- 25-akpm/drivers/scsi/aic7xxx/aic7xxx_inline.h | 26 25-akpm/drivers/scsi/aic7xxx/aic7xxx_osm.c | 1393 +++++++------- 25-akpm/drivers/scsi/aic7xxx/aic7xxx_osm.h | 873 --------- 25-akpm/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 122 - 25-akpm/drivers/scsi/aic7xxx/aic7xxx_pci.c | 184 + 25-akpm/drivers/scsi/aic7xxx/aic7xxx_proc.c | 32 25-akpm/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped | 6 25-akpm/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped | 22 25-akpm/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped | 933 ++++----- 25-akpm/drivers/scsi/aic7xxx/aicasm/Makefile | 8 25-akpm/drivers/scsi/aic7xxx/aicasm/aicasm.c | 23 25-akpm/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l | 3 25-akpm/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l | 16 25-akpm/drivers/scsi/aic7xxx/aiclib.c | 343 +++ 25-akpm/drivers/scsi/aic7xxx/aiclib.h | 1281 +++++++++++++ 25-akpm/drivers/scsi/aic7xxx/aiclib_pci.c | 79 40 files changed, 6933 insertions(+), 5325 deletions(-) diff -puN Documentation/scsi/aic79xx.txt~aic7xxx-aic79xx-update Documentation/scsi/aic79xx.txt --- 25/Documentation/scsi/aic79xx.txt~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/Documentation/scsi/aic79xx.txt Wed Dec 24 12:15:38 2003 @@ -1,5 +1,5 @@ ==================================================================== -= Adaptec Ultra320 Family Manager Set v1.3.0 = += Adaptec Ultra320 Family Manager Set v2.0.5 = = = = README for = = The Linux Operating System = @@ -19,57 +19,274 @@ The following information is available i The following Adaptec SCSI Host Adapters are supported by this driver set. - Ultra320 Adapters Description + Ultra320 ASIC Description ---------------------------------------------------------------- - Adaptec SCSI Card 39320 Dual Channel 64-bit PCI-X 133MHz to - Ultra320 SCSI Card (one external - 68-pin, two internal 68-pin) - Adaptec SCSI Card 39320D Dual Channel 64-bit PCI-X 133MHz to - Ultra320 SCSI Card (two external VHDC - and one internal 68-pin) - Adaptec SCSI Card 39320D Dual Channel 64-bit PCI-X 133MHz to - Ultra320 SCSI Card (two external VHDC - and one internal 68-pin) based on the - AIC-7902B ASIC - Adaptec SCSI Card 29320 Single Channel 64-bit PCI-X 133MHz to - Ultra320 SCSI Card (one external - 68-pin, two internal 68-pin, one - internal 50-pin) - Adaptec SCSI Card 29320LP Single Channel 64-bit Low Profile - PCI-X 133MHz to Ultra320 SCSI Card - (One external VHDC, one internal - 68-pin) - AIC-7901A Single Channel 64-bit PCI-X 133MHz to - Ultra320 SCSI ASIC - AIC-7902A4 Dual Channel 64-bit PCI-X 133MHz to - Ultra320 SCSI ASIC - AIC-7902B Dual Channel 64-bit PCI-X 133MHz to - Ultra320 SCSI ASIC - + AIC-7901A Single Channel 64-bit PCI-X 133MHz to + Ultra320 SCSI ASIC + AIC-7901B Single Channel 64-bit PCI-X 133MHz to + Ultra320 SCSI ASIC with Retained Training + AIC-7902A4 Dual Channel 64-bit PCI-X 133MHz to + Ultra320 SCSI ASIC + AIC-7902B Dual Channel 64-bit PCI-X 133MHz to + Ultra320 SCSI ASIC with Retained Training + + Ultra320 Adapters Description ASIC + -------------------------------------------------------------------------- + Adaptec SCSI Card 39320 Dual Channel 64-bit PCI-X 133MHz to 7902A4/7902B + Ultra320 SCSI Card (one external + 68-pin, two internal 68-pin) + Adaptec SCSI Card 39320A Dual Channel 64-bit PCI-X 133MHz to 7902B + Ultra320 SCSI Card (one external + 68-pin, two internal 68-pin) + Adaptec SCSI Card 39320D Dual Channel 64-bit PCI-X 133MHz to 7902A4 + Ultra320 SCSI Card (two external VHDC + and one internal 68-pin) + Adaptec SCSI Card 39320D Dual Channel 64-bit PCI-X 133MHz to 7902A4 + Ultra320 SCSI Card (two external VHDC + and one internal 68-pin) based on the + AIC-7902B ASIC + Adaptec SCSI Card 29320 Single Channel 64-bit PCI-X 133MHz to 7901A + Ultra320 SCSI Card (one external + 68-pin, two internal 68-pin, one + internal 50-pin) + Adaptec SCSI Card 29320A Single Channel 64-bit PCI-X 133MHz to 7901B + Ultra320 SCSI Card (one external + 68-pin, two internal 68-pin, one + internal 50-pin) + Adaptec SCSI Card 29320LP Single Channel 64-bit Low Profile 7901A + PCI-X 133MHz to Ultra320 SCSI Card + (One external VHDC, one internal + 68-pin) + Adaptec SCSI Card 29320ALP Single Channel 64-bit Low Profile 7901B + PCI-X 133MHz to Ultra320 SCSI Card + (One external VHDC, one internal + 68-pin) 2. Version History - (V1.3.0, January 2003) Full regression testing for all U320 products - completed. - - (V1.3.0 ALPHA, November 2002) Initial Alpha release. - Added abort and target/lun reset error recovery handler and - interrupt coalessing. - - (V1.2.0, November 2002) Added support for Domain Validation and - Hewlett-Packard version of the 39320D and AIC-7902 adapters. - Support for previous adapters has not been fully tested and should - only be used at the customer's own risk. - - (V1.1.1, September 2002) Added support for the Linux 2.5.X kernel series - - (V1.1.0, August 2002) Added support for four additional SCSI - products: ASC-39320, ASC-29320, ASC-29320LP, AIC-7901. - - (V1.1, August 2002) Added support for four additional SCSI - products: ASC-39320, ASC-29320, ASC-29320LP, AIC-7901. + 2.0.5 (December 22nd, 2003) + - Correct a bug preventing the driver from renegotiating + during auto-request operations when a check condition + occurred for a zero length command. + - Sniff sense information returned by targets for unit + attention errors that may indicate that the device has + been changed. If we see such status for non Domain + Validation related commands, start a DV scan for the + target. In the past, DV would only occur for hot-plugged + devices if no target had been previously probed for a + particular ID. This change guarantees that the DV process + will occur even if the user swaps devices without any + interveining I/O to tell us that a device has gone missing. + The old behavior, among other things, would fail to spin up + drives that were hot-plugged since the Linux mid-layer + will only spin-up drives on initial attach. + - Correct several issues in the rundown of the good status + FIFO during error recovery. The typical failure scenario + evidenced by this defect was the loss of several commands + under high load when several queue full conditions occured + back to back. + + 2.0.4 (November 6th, 2003) + - Support the 2.6.0-test9 kernel + - Fix rare deadlock caused by using del_timer_sync from within + a timer handler. + + 2.0.3 (October 21st, 2003) + - On 7902A4 hardware, use the slow slew rate for transfer + rates slower than U320. This behavior matches the Windows + driver. + - Fix some issues with the ahd_flush_qoutfifo() routine. + - Add a delay in the loop waiting for selection activity + to cease. Otherwise we may exhaust the loop counter too + quickly on fast machines. + - Return to processing bad status completions through the + qoutfifo. This reduces the amount of time the controller + is paused for these kinds of errors. + - Move additional common routines to the aiclib OSM library + to reduce code duplication. + - Leave removal of softcs from the global list of softcs to + the OSM. This allows us to avoid holding the list_lock during + device destruction. + - Enforce a bus settle delay for bus resets that the + driver initiates. + - Fall back to basic DV for U160 devices that lack an + echo buffer. + + 2.0.2 (September 4th, 2003) + - Move additional common routines to the aiclib OSM library + to reduce code duplication. + - Avoid an inadvertant reset of the controller during the + memory mapped I/O test should the controller be left in + the reset state prior to driver initialization. On some + systems, this extra reset resulted in a system hang due + to a chip access that occurred too soon after reset. + - Correct an endian bug in ahd_swap_with_next_hscb. This + corrects strong-arm support. + - Reset the bus for transactions that timeout waiting for + the bus to go free after a disconnect or command complete + message. + + 2.0.1 (August 26th, 2003) + - Add magic sysrq handler that causes a card dump to be output + to the console for each controller. + - Avoid waking the mid-layer's error recovery handler during + timeout recovery by returning DID_ERROR instead of DID_TIMEOUT + for timed-out commands that have been aborted. + - Move additional common routines to the aiclib OSM library + to reduce code duplication. + + 2.0.0 (August 20th, 2003) + - Remove MMAPIO definition and allow memory mapped + I/O for any platform that supports PCI. + - Avoid clearing ENBUSFREE during single stepping to avoid + spurious "unexpected busfree while idle" messages. + - Correct deadlock in ahd_run_qoutfifo() processing. + - Optimize support for the 7901B. + - Correct a few cases where an explicit flush of pending + register writes was required to ensure acuracy in delays. + - Correct problems in manually flushing completed commands + on the controller. The FIFOs are now flushed to ensure + that completed commands that are still draining to the + host are completed correctly. + - Correct incomplete CDB delivery detection on the 790XB. + - Ignore the cmd->underflow field since userland applications + using the legacy command pass-thru interface do not set + it correctly. Honoring this field led to spurious errors + when users used the "scsi_unique_id" program. + - Perform timeout recovery within the driver instead of relying + on the Linux SCSI mid-layer to perform this function. The + mid-layer does not know the full state of the SCSI bus and + is therefore prone to looping for several minutes to effect + recovery. The new scheme recovers within 15 seconds of the + failure. + - Correct support for manual termination settings. + - Increase maximum wait time for serial eeprom writes allowing + writes to function correctly. + + 1.3.12 (August 11, 2003) + - Implement new error recovery thread that supercedes the existing + Linux SCSI error recovery code. + - Fix termination logic for 29320ALP. + - Fix SEEPROM delay to compensate for write ops taking longer. + + 1.3.11 (July 11, 2003) + - Fix several deadlock issues. + - Add 29320ALP and 39320B Id's. + + 1.3.10 (June 3rd, 2003) + - Align the SCB_TAG field on a 16byte boundary. This avoids + SCB corruption on some PCI-33 busses. + - Correct non-zero luns on Rev B. hardware. + - Update for change in 2.5.X SCSI proc FS interface. + - When negotiation async via an 8bit WDTR message, send + an SDTR with an offset of 0 to be sure the target + knows we are async. This works around a firmware defect + in the Quantum Atlas 10K. + - Implement controller susupend and resume. + - Clear PCI error state during driver attach so that we + don't disable memory mapped I/O due to a stray write + by some other driver probe that occurred before we + claimed the controller. + + 1.3.9 (May 22nd, 2003) + - Fix compiler errors. + - Remove S/G splitting for segments that cross a 4GB boundary. + This is guaranteed not to happen in Linux. + - Add support for scsi_report_device_reset() found in + 2.5.X kernels. + - Add 7901B support. + - Simplify handling of the packtized lun Rev A workaround. + - Correct and simplify handling of the ignore wide residue + message. The previous code would fail to report a residual + if the transaction data length was even and we received + an IWR message. + + 1.3.8 (April 29th, 2003) + - Fix types accessed via the command line interface code. + - Perform a few firmware optimizations. + - Fix "Unexpected PKT busfree" errors. + - Use a sequencer interrupt to notify the host of + commands with bad status. We defer the notification + until there are no outstanding selections to ensure + that the host is interrupted for as short a time as + possible. + - Remove pre-2.2.X support. + - Add support for new 2.5.X interrupt API. + - Correct big-endian architecture support. + + 1.3.7 (April 16th, 2003) + - Use del_timer_sync() to ensure that no timeouts + are pending during controller shutdown. + - For pre-2.5.X kernels, carefully adjust our segment + list size to avoid SCSI malloc pool fragmentation. + - Cleanup channel display in our /proc output. + - Workaround duplicate device entries in the mid-layer + devlice list during add-single-device. + + 1.3.6 (March 28th, 2003) + - Correct a double free in the Domain Validation code. + - Correct a reference to free'ed memory during controller + shutdown. + - Reset the bus on an SE->LVD change. This is required + to reset our transcievers. + + 1.3.5 (March 24th, 2003) + - Fix a few register window mode bugs. + - Include read streaming in the PPR flags we display in + diagnostics as well as /proc. + - Add PCI hot plug support for 2.5.X kernels. + - Correct default precompensation value for RevA hardware. + - Fix Domain Validation thread shutdown. + - Add a firmware workaround to make the LED blink + brighter during packetized operations on the H2A4. + - Correct /proc display of user read streaming settings. + - Simplify driver locking by releasing the io_request_lock + upon driver entry from the mid-layer. + - Cleanup command line parsing and move much of this code + to aiclib. + + 1.3.4 (February 28th, 2003) + - Correct a race condition in our error recovery handler. + - Allow Test Unit Ready commands to take a full 5 seconds + during Domain Validation. + + 1.3.2 (February 19th, 2003) + - Correct a Rev B. regression due to the GEM318 + compatibility fix included in 1.3.1. + + 1.3.1 (February 11th, 2003) + - Add support for the 39320A. + - Improve recovery for certain PCI-X errors. + - Fix handling of LQ/DATA/LQ/DATA for the + same write transaction that can occur without + interveining training. + - Correct compatibility issues with the GEM318 + enclosure services device. + - Correct data corruption issue that occurred under + high tag depth write loads. + - Adapt to a change in the 2.5.X daemonize() API. + - Correct a "Missing case in ahd_handle_scsiint" panic. + + 1.3.0 (January 21st, 2003) + - Full regression testing for all U320 products completed. + - Added abort and target/lun reset error recovery handler and + interrupt coalessing. + + 1.2.0 (November 14th, 2002) + - Added support for Domain Validation + - Add support for the Hewlett-Packard version of the 39320D + and AIC-7902 adapters. + Support for previous adapters has not been fully tested and should + only be used at the customer's own risk. + + 1.1.1 (September 24th, 2002) + - Added support for the Linux 2.5.X kernel series + + 1.1.0 (September 17th, 2002) + - Added support for four additional SCSI products: + ASC-39320, ASC-29320, ASC-29320LP, AIC-7901. - (V1.0, May 2002) This is the initial release of the - Ultra320 FMS. The following is a list of supported features: + 1.0.0 (May 30th, 2002) + - Initial driver release. 2.1. Software/Hardware Features - Support for the SPI-4 "Ultra320" standard: @@ -82,6 +299,7 @@ The following information is available i supported) - Support for the PCI-X standard up to 133MHz - Support for the PCI v2.2 standard + - Domain Validation 2.2. Operating System Support: - Redhat Linux 7.2, 7.3, 8.0, Advanced Server 2.1 diff -puN Documentation/scsi/aic7xxx.txt~aic7xxx-aic79xx-update Documentation/scsi/aic7xxx.txt --- 25/Documentation/scsi/aic7xxx.txt~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/Documentation/scsi/aic7xxx.txt Wed Dec 24 12:15:38 2003 @@ -1,5 +1,5 @@ ==================================================================== -= Adaptec Aic7xxx Fast -> Ultra160 Family Manager Set v6.2.28 = += Adaptec Aic7xxx Fast -> Ultra160 Family Manager Set v6.3.4 = = README for = = The Linux Operating System = ==================================================================== @@ -132,26 +132,127 @@ The following information is available i 2. Version History - 6.2.34 - Fix locking regression instroduced in 6.2.29 that - could cuase a lock order reversal between the io_request_lock - and our per-softc lock. This was only possible on RH9, - SuSE, and kernel.org 2.4.X kernels. - - 6.2.33 - Dynamically disable PCI parity error reporting after - 10 errors are reported to the user. These errors are - the result of some other device issuing PCI transactions - with bad parity. Once the user has been informed of the - problem, continuing to report the errors just degrades - our performance. - - 6.2.32 - Dynamically sized S/G lists to avoid SCSI malloc - pool fragmentation and SCSI mid-layer deadlock. - - 6.2.28 - Domain Validation Fixes - PCI parity error disable - Enhanced Memory Mapped I/O probe + 6.3.4 (December 22nd, 2003) + - Provide a better description string for the 2915/30LP. + - Sniff sense information returned by targets for unit + attention errors that may indicate that the device has + been changed. If we see such status for non Domain + Validation related commands, start a DV scan for the + target. In the past, DV would only occur for hot-plugged + devices if no target had been previously probed for a + particular ID. This change guarantees that the DV process + will occur even if the user swaps devices without any + interveining I/O to tell us that a device has gone missing. + The old behavior, among other things, would fail to spin up + drives that were hot-plugged since the Linux mid-layer + will only spin-up drives on initial attach. + + 6.3.3 (November 6th, 2003) + - Support the 2.6.0-test9 kernel + - Fix rare deadlock caused by using del_timer_sync from within + a timer handler. + + 6.3.2 (October 28th, 2003) + - Enforce a bus settle delay for bus resets that the + driver initiates. + - Fall back to basic DV for U160 devices that lack an + echo buffer. + - Correctly detect that left over BIOS data has not + been initialized when the CHPRST status bit is set + during driver initialization. + + 6.3.1 (October 21st, 2003) + - Fix a compiler error when building with only EISA or PCI + support compiled into the kernel. + - Add chained dependencies to both the driver and aicasm Makefiles + to avoid problems with parallel builds. + - Move additional common routines to the aiclib OSM library + to reduce code duplication. + - Fix a bug in the testing of the AHC_TMODE_WIDEODD_BUG that + could cause target mode operations to hang. + - Leave removal of softcs from the global list of softcs to + the OSM. This allows us to avoid holding the list_lock during + device destruction. + + 6.3.0 (September 8th, 2003) + - Move additional common routines to the aiclib OSM library + to reduce code duplication. + - Bump minor number to reflect change in error recovery strategy. + + 6.2.38 (August 31st, 2003) + - Avoid an inadvertant reset of the controller during the + memory mapped I/O test should the controller be left in + the reset state prior to driver initialization. On some + systems, this extra reset resulted in a system hang due + to a chip access that occurred too soon after reset. + - Move additional common routines to the aiclib OSM library + to reduce code duplication. + - Add magic sysrq handler that causes a card dump to be output + to the console for each controller. + + 6.2.37 (August 12th, 2003) + - Perform timeout recovery within the driver instead of relying + on the Linux SCSI mid-layer to perform this function. The + mid-layer does not know the full state of the SCSI bus and + is therefore prone to looping for several minutes to effect + recovery. The new scheme recovers within 15 seconds of the + failure. + - Support writing 93c56/66 SEEPROM on newer cards. + - Avoid clearing ENBUSFREE during single stepping to avoid + spurious "unexpected busfree while idle" messages. + - Enable the use of the "Auto-Access-Pause" feature on the + aic7880 and aic7870 chips. It was disabled due to an + oversight. Using this feature drastically reduces command + delivery latency. + + 6.2.36 (June 3rd, 2003) + - Correct code that disables PCI parity error checking. + - Correct and simplify handling of the ignore wide residue + message. The previous code would fail to report a residual + if the transaction data length was even and we received + an IWR message. + - Add support for the 2.5.X EISA framework. + - Update for change in 2.5.X SCSI proc FS interface. + - Correct Domain Validation command-line option parsing. + - When negotiation async via an 8bit WDTR message, send + an SDTR with an offset of 0 to be sure the target + knows we are async. This works around a firmware defect + in the Quantum Atlas 10K. + - Clear PCI error state during driver attach so that we + don't disable memory mapped I/O due to a stray write + by some other driver probe that occurred before we + claimed the controller. + + 6.2.35 (May 14th, 2003) + - Fix a few GCC 3.3 compiler warnings. + - Correct operation on EISA Twin Channel controller. + - Add support for 2.5.X's scsi_report_device_reset(). + + 6.2.34 (May 5th, 2003) + - Fix locking regression instroduced in 6.2.29 that + could cuase a lock order reversal between the io_request_lock + and our per-softc lock. This was only possible on RH9, + SuSE, and kernel.org 2.4.X kernels. + + 6.2.33 (April 30th, 2003) + - Dynamically disable PCI parity error reporting after + 10 errors are reported to the user. These errors are + the result of some other device issuing PCI transactions + with bad parity. Once the user has been informed of the + problem, continuing to report the errors just degrades + our performance. + + 6.2.32 (March 28th, 2003) + - Dynamically sized S/G lists to avoid SCSI malloc + pool fragmentation and SCSI mid-layer deadlock. + + 6.2.28 (January 20th, 2003) + - Domain Validation Fixes + - Add ability to disable PCI parity error checking. + - Enhanced Memory Mapped I/O probe - 6.2.20 - Added Domain Validation + 6.2.20 (November 7th, 2002) + - Added Domain Validation. 3. Command Line Options diff -puN drivers/scsi/aic7xxx/aic7770.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7770.c --- 25/drivers/scsi/aic7xxx/aic7770.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7770.c Wed Dec 24 12:15:38 2003 @@ -37,9 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#30 $ - * - * $FreeBSD$ + * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#34 $ */ #ifdef __linux__ @@ -47,6 +45,8 @@ #include "aic7xxx_inline.h" #include "aic7xxx_93cx6.h" #else +#include +__FBSDID("$FreeBSD$"); #include #include #include @@ -67,8 +67,7 @@ static ahc_device_setup_t ahc_aic7770_VL static ahc_device_setup_t ahc_aic7770_EISA_setup;; static ahc_device_setup_t ahc_aic7770_setup; - -struct aic7770_identity aic7770_ident_table [] = +struct aic7770_identity aic7770_ident_table[] = { { ID_AHA_274x, @@ -83,6 +82,12 @@ struct aic7770_identity aic7770_ident_ta ahc_aic7770_VL_setup }, { + ID_AHA_284x, + 0xFFFFFFFE, + "Adaptec 284X SCSI adapter (BIOS Disabled)", + ahc_aic7770_VL_setup + }, + { ID_OLV_274x, 0xFFFFFFFF, "Adaptec (Olivetti OEM) 274X SCSI adapter", @@ -154,7 +159,7 @@ aic7770_config(struct ahc_softc *ahc, st ahc->bus_suspend = aic7770_suspend; ahc->bus_resume = aic7770_resume; - error = ahc_reset(ahc); + error = ahc_reset(ahc, /*reinit*/FALSE); if (error != 0) return (error); diff -puN drivers/scsi/aic7xxx/aic7770_osm.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7770_osm.c --- 25/drivers/scsi/aic7xxx/aic7770_osm.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7770_osm.c Wed Dec 24 12:15:38 2003 @@ -1,7 +1,7 @@ /* * Linux driver attachment glue for aic7770 based controllers. * - * Copyright (c) 2000-2001 Adaptec Inc. + * Copyright (c) 2000-2003 Adaptec Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,27 +36,90 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7770_osm.c#13 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7770_osm.c#16 $ */ #include "aic7xxx_osm.h" +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#include +#include + +#define EISA_MFCTR_CHAR0(ID) (char)(((ID>>26) & 0x1F) | '@') /* Bits 26-30 */ +#define EISA_MFCTR_CHAR1(ID) (char)(((ID>>21) & 0x1F) | '@') /* Bits 21-25 */ +#define EISA_MFCTR_CHAR2(ID) (char)(((ID>>16) & 0x1F) | '@') /* Bits 16-20 */ +#define EISA_PRODUCT_ID(ID) (short)((ID>>4) & 0xFFF) /* Bits 4-15 */ +#define EISA_REVISION_ID(ID) (uint8_t)(ID & 0x0F) /* Bits 0-3 */ + +static int aic7770_eisa_dev_probe(struct device *dev); +static int aic7770_eisa_dev_remove(struct device *dev); +static struct eisa_driver aic7770_driver = { + .driver = { + .name = "aic7xxx", + .probe = aic7770_eisa_dev_probe, + .remove = aic7770_eisa_dev_remove, + } +}; + +typedef struct device *aic7770_dev_t; +#else #define MINSLOT 1 #define NUMSLOTS 16 #define IDOFFSET 0x80 -int -aic7770_linux_probe(Scsi_Host_Template *template) +typedef void *aic7770_dev_t; +#endif + +static int aic7770_linux_config(struct aic7770_identity *entry, + aic7770_dev_t dev, u_int eisaBase); + +void +ahc_linux_eisa_init(void) { -#if defined(__i386__) || defined(__alpha__) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + struct eisa_device_id *eid; + struct aic7770_identity *id; + int i; + + if (aic7xxx_probe_eisa_vl == 0) + return; + + /* + * Linux requires the EISA IDs to be specified in + * the EISA ID string format. Perform the conversion + * and setup a table with a NUL terminal entry. + */ + aic7770_driver.id_table = malloc(sizeof(struct eisa_device_id) * + (ahc_num_aic7770_devs + 1), + M_DEVBUF, M_NOWAIT); + if (aic7770_driver.id_table == NULL) + return; + + for (eid = (struct eisa_device_id *)aic7770_driver.id_table, + id = aic7770_ident_table, i = 0; + i < ahc_num_aic7770_devs; eid++, id++, i++) { + + sprintf(eid->sig, "%c%c%c%03X%01X", + EISA_MFCTR_CHAR0(id->full_id), + EISA_MFCTR_CHAR1(id->full_id), + EISA_MFCTR_CHAR2(id->full_id), + EISA_PRODUCT_ID(id->full_id), + EISA_REVISION_ID(id->full_id)); + eid->driver_data = i; + } + eid->sig[0] = 0; + + eisa_driver_register(&aic7770_driver); +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) */ struct aic7770_identity *entry; - struct ahc_softc *ahc; - int i, slot; - int eisaBase; - int found; + u_int slot; + u_int eisaBase; + u_int i; + + if (aic7xxx_probe_eisa_vl == 0) + return; eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET; - found = 0; for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) { uint32_t eisa_id; size_t id_size; @@ -83,45 +146,65 @@ aic7770_linux_probe(Scsi_Host_Template * continue; /* no EISA card in slot */ entry = aic7770_find_device(eisa_id); - if (entry != NULL) { - char buf[80]; - char *name; - int error; - - /* - * Allocate a softc for this card and - * set it up for attachment by our - * common detect routine. - */ - sprintf(buf, "ahc_eisa:%d", slot); - name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); - if (name == NULL) - break; - strcpy(name, buf); - ahc = ahc_alloc(template, name); - if (ahc == NULL) { - /* - * If we can't allocate this one, - * chances are we won't be able to - * allocate future card structures. - */ - break; - } - error = aic7770_config(ahc, entry, eisaBase); - if (error != 0) { - ahc->bsh.ioport = 0; - ahc_free(ahc); - continue; - } - found++; - } + if (entry != NULL) + aic7770_linux_config(entry, NULL, eisaBase); + } +#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) { + eisa_driver_unregister(&aic7770_driver); + free(aic7770_driver.id_table, M_DEVBUF); } - return (found); -#else - return (0); #endif } +static int +aic7770_linux_config(struct aic7770_identity *entry, aic7770_dev_t dev, + u_int eisaBase) +{ + struct ahc_softc *ahc; + char buf[80]; + char *name; + int error; + + /* + * Allocate a softc for this card and + * set it up for attachment by our + * common detect routine. + */ + sprintf(buf, "ahc_eisa:%d", eisaBase >> 12); + name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); + if (name == NULL) + return (ENOMEM); + strcpy(name, buf); + ahc = ahc_alloc(&aic7xxx_driver_template, name); + if (ahc == NULL) { + free(name, M_DEVBUF); + return (ENOMEM); + } + ahc->dev_softc = dev; + error = aic7770_config(ahc, entry, eisaBase); + if (error != 0) { + ahc->bsh.ioport = 0; + ahc_free(ahc); + return (error); + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + dev->driver_data = (void *)ahc; + if (aic7xxx_detect_complete) + error = ahc_linux_register_host(ahc, &aic7xxx_driver_template); +#endif + return (error); +} + int aic7770_map_registers(struct ahc_softc *ahc, u_int port) { @@ -129,6 +212,8 @@ aic7770_map_registers(struct ahc_softc * * Lock out other contenders for our i/o space. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + if (check_region(port, AHC_EISA_IOSIZE) != 0) + return (ENOMEM); request_region(port, AHC_EISA_IOSIZE, "aic7xxx"); #else if (request_region(port, AHC_EISA_IOSIZE, "aic7xxx") == 0) @@ -155,3 +240,43 @@ aic7770_map_int(struct ahc_softc *ahc, u return (-error); } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +static int +aic7770_eisa_dev_probe(struct device *dev) +{ + struct eisa_device *edev; + + edev = to_eisa_device(dev); + return (aic7770_linux_config(aic7770_ident_table + edev->id.driver_data, + dev, edev->base_addr+AHC_EISA_SLOT_OFFSET)); +} + +static int +aic7770_eisa_dev_remove(struct device *dev) +{ + struct ahc_softc *ahc; + u_long l; + + /* + * We should be able to just perform + * the free directly, but check our + * list for extra sanity. + */ + ahc_list_lock(&l); + ahc = ahc_find_softc((struct ahc_softc *)dev->driver_data); + if (ahc != NULL) { + u_long s; + + TAILQ_REMOVE(&ahc_tailq, ahc, links); + ahc_list_unlock(&l); + ahc_lock(ahc, &s); + ahc_intr_enable(ahc, FALSE); + ahc_unlock(ahc, &s); + ahc_free(ahc); + } else + ahc_list_unlock(&l); + + return (0); +} +#endif diff -puN drivers/scsi/aic7xxx/aic79xx_core.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic79xx_core.c --- 25/drivers/scsi/aic7xxx/aic79xx_core.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic79xx_core.c Wed Dec 24 12:15:38 2003 @@ -37,9 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#194 $ - * - * $FreeBSD$ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#224 $ */ #ifdef __linux__ @@ -47,6 +45,8 @@ #include "aic79xx_inline.h" #include "aicasm/aicasm_insformat.h" #else +#include +__FBSDID("$FreeBSD$"); #include #include #include @@ -224,6 +224,14 @@ static u_int ahd_resolve_seqaddr(struct static void ahd_download_instr(struct ahd_softc *ahd, u_int instrptr, uint8_t *dconsts); static int ahd_probe_stack_size(struct ahd_softc *ahd); +static void ahd_other_scb_timeout(struct ahd_softc *ahd, + struct scb *scb, + struct scb *other_scb); +static int ahd_scb_active_in_fifo(struct ahd_softc *ahd, + struct scb *scb); +static void ahd_run_data_fifo(struct ahd_softc *ahd, + struct scb *scb); + #ifdef AHD_TARGET_MODE static void ahd_queue_lstate_event(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate, @@ -328,10 +336,7 @@ ahd_restart(struct ahd_softc *ahd) /* Always allow reselection */ ahd_outb(ahd, SCSISEQ1, ahd_inb(ahd, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP)); - /* Ensure that no DMA operations are in progress */ ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); - ahd_outb(ahd, SCBHCNT, 0); - ahd_outb(ahd, CCSCBCTL, CCSCBRESET); ahd_outb(ahd, SEQCTL0, FASTMODE|SEQRESET); ahd_unpause(ahd); } @@ -371,31 +376,119 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd u_int next_scbid; saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); + + /* + * Flush the good status FIFO for completed packetized commands. + */ + ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); saved_scbptr = ahd_get_scbptr(ahd); + while ((ahd_inb(ahd, LQISTAT2) & LQIGSAVAIL) != 0) { + u_int fifo_mode; + u_int i; + + scbid = ahd_inw(ahd, GSFIFO); + scb = ahd_lookup_scb(ahd, scbid); + if (scb == NULL) { + printf("%s: Warning - GSFIFO SCB %d invalid\n", + ahd_name(ahd), scbid); + continue; + } + /* + * Determine if this transaction is still active in + * any FIFO. If it is, we must flush that FIFO to + * the host before completing the command. + */ + fifo_mode = 0; +rescan_fifos: + for (i = 0; i < 2; i++) { + /* Toggle to the other mode. */ + fifo_mode ^= 1; + ahd_set_modes(ahd, fifo_mode, fifo_mode); + + if (ahd_scb_active_in_fifo(ahd, scb) == 0) + continue; + + ahd_run_data_fifo(ahd, scb); + + /* + * Running this FIFO may cause a CFG4DATA for + * this same transaction to assert in the other + * FIFO or a new snapshot SAVEPTRS interrupt + * in this FIFO. Even running a FIFO may not + * clear the transaction if we are still waiting + * for data to drain to the host. We must loop + * until the transaction is not active in either + * FIFO just to be sure. Reset our loop counter + * so we will visit both FIFOs again before + * declaring this transaction finished. We + * also delay a bit so that status has a chance + * to change before we look at this FIFO again. + */ + aic_delay(200); + goto rescan_fifos; + } + ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); + ahd_set_scbptr(ahd, scbid); + if ((ahd_inb_scbram(ahd, SCB_SGPTR) & SG_LIST_NULL) == 0 + && ((ahd_inb_scbram(ahd, SCB_SGPTR) & SG_FULL_RESID) != 0 + || (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR) + & SG_LIST_NULL) != 0)) { + u_int comp_head; + + /* + * The transfer completed with a residual. + * Place this SCB on the complete DMA list + * so that we update our in-core copy of the + * SCB before completing the command. + */ + ahd_outb(ahd, SCB_SCSI_STATUS, 0); + ahd_outb(ahd, SCB_SGPTR, + ahd_inb_scbram(ahd, SCB_SGPTR) + | SG_STATUS_VALID); + ahd_outw(ahd, SCB_TAG, SCB_GET_TAG(scb)); + comp_head = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD); + ahd_outw(ahd, SCB_NEXT_COMPLETE, comp_head); + ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, SCB_GET_TAG(scb)); + } else + ahd_complete_scb(ahd, scb); + } + ahd_set_scbptr(ahd, saved_scbptr); + + /* + * Setup for command channel portion of flush. + */ + ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); /* * Wait for any inprogress DMA to complete and clear DMA state * if this if for an SCB in the qinfifo. */ - while ((ccscbctl = ahd_inb(ahd, CCSCBCTL) & (CCARREN|CCSCBEN)) != 0) { + while (((ccscbctl = ahd_inb(ahd, CCSCBCTL)) & (CCARREN|CCSCBEN)) != 0) { if ((ccscbctl & (CCSCBDIR|CCARREN)) == (CCSCBDIR|CCARREN)) { if ((ccscbctl & ARRDONE) != 0) break; } else if ((ccscbctl & CCSCBDONE) != 0) break; - ahd_delay(200); + aic_delay(200); } - if ((ccscbctl & CCSCBDIR) != 0) + /* + * We leave the sequencer to cleanup in the case of DMA's to + * update the qoutfifo. In all other cases (DMA's to the + * chip or a push of an SCB from the COMPLETE_DMA_SCB list), + * we disable the DMA engine so that the sequencer will not + * attempt to handle the DMA completion. + */ + if ((ccscbctl & CCSCBDIR) != 0 || (ccscbctl & ARRDONE) != 0) ahd_outb(ahd, CCSCBCTL, ccscbctl & ~(CCARREN|CCSCBEN)); /* - * Complete any SCBs that just finished being - * DMA'ed into the qoutfifo. + * Complete any SCBs that just finished + * being DMA'ed into the qoutfifo. */ ahd_run_qoutfifo(ahd); + saved_scbptr = ahd_get_scbptr(ahd); /* * Manually update/complete any completed SCBs that are waiting to be * DMA'ed back up to the host. @@ -438,31 +531,272 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd scbid = next_scbid; } ahd_outw(ahd, COMPLETE_SCB_HEAD, SCB_LIST_NULL); - ahd_set_scbptr(ahd, saved_scbptr); - - /* - * Flush the good status FIFO for compelted packetized commands. - */ - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - while ((ahd_inb(ahd, LQISTAT2) & LQIGSAVAIL) != 0) { - scbid = (ahd_inb(ahd, GSFIFO+1) << 8) - | ahd_inb(ahd, GSFIFO); - scb = ahd_lookup_scb(ahd, scbid); - if (scb == NULL) { - printf("%s: Warning - GSFIFO SCB %d invalid\n", - ahd_name(ahd), scbid); - continue; - } - ahd_complete_scb(ahd, scb); - } /* * Restore state. */ + ahd_set_scbptr(ahd, saved_scbptr); ahd_restore_modes(ahd, saved_modes); ahd->flags |= AHD_UPDATE_PEND_CMDS; } +/* + * Determine if an SCB for a packetized transaction + * is active in a FIFO. + */ +static int +ahd_scb_active_in_fifo(struct ahd_softc *ahd, struct scb *scb) +{ + + /* + * The FIFO is only active for our transaction if + * the SCBPTR matches the SCB's ID and the firmware + * has installed a handler for the FIFO or we have + * a pending SAVEPTRS or CFG4DATA interrupt. + */ + if (ahd_get_scbptr(ahd) != SCB_GET_TAG(scb) + || ((ahd_inb(ahd, LONGJMP_ADDR+1) & INVALID_ADDR) != 0 + && (ahd_inb(ahd, SEQINTSRC) & (CFG4DATA|SAVEPTRS)) == 0)) + return (0); + + return (1); +} + +/* + * Run a data fifo to completion for a transaction we know + * has completed across the SCSI bus (good status has been + * received). We are already set to the correct FIFO mode + * on entry to this routine. + * + * This function attempts to operate exactly as the firmware + * would when running this FIFO. Care must be taken to update + * this routine any time the firmware's FIFO algorithm is + * changed. + */ +static void +ahd_run_data_fifo(struct ahd_softc *ahd, struct scb *scb) +{ + u_int seqintsrc; + + seqintsrc = ahd_inb(ahd, SEQINTSRC); + if ((seqintsrc & CFG4DATA) != 0) { + uint32_t datacnt; + uint32_t sgptr; + + /* + * Clear full residual flag. + */ + sgptr = ahd_inl_scbram(ahd, SCB_SGPTR) & ~SG_FULL_RESID; + ahd_outb(ahd, SCB_SGPTR, sgptr); + + /* + * Load datacnt and address. + */ + datacnt = ahd_inl_scbram(ahd, SCB_DATACNT); + if ((datacnt & AHD_DMA_LAST_SEG) != 0) { + sgptr |= LAST_SEG; + ahd_outb(ahd, SG_STATE, 0); + } else + ahd_outb(ahd, SG_STATE, LOADING_NEEDED); + ahd_outq(ahd, HADDR, ahd_inq_scbram(ahd, SCB_DATAPTR)); + ahd_outl(ahd, HCNT, datacnt & AHD_SG_LEN_MASK); + ahd_outb(ahd, SG_CACHE_PRE, sgptr); + ahd_outb(ahd, DFCNTRL, PRELOADEN|SCSIEN|HDMAEN); + + /* + * Initialize Residual Fields. + */ + ahd_outb(ahd, SCB_RESIDUAL_DATACNT+3, datacnt >> 24); + ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr & SG_PTR_MASK); + + /* + * Mark the SCB as having a FIFO in use. + */ + ahd_outb(ahd, SCB_FIFO_USE_COUNT, + ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) + 1); + + /* + * Install a "fake" handler for this FIFO. + */ + ahd_outw(ahd, LONGJMP_ADDR, 0); + + /* + * Notify the hardware that we have satisfied + * this sequencer interrupt. + */ + ahd_outb(ahd, CLRSEQINTSRC, CLRCFG4DATA); + } else if ((seqintsrc & SAVEPTRS) != 0) { + uint32_t sgptr; + uint32_t resid; + + if ((ahd_inb(ahd, LONGJMP_ADDR+1)&INVALID_ADDR) != 0) { + /* + * Snapshot Save Pointers. All that + * is necessary to clear the snapshot + * is a CLRCHN. + */ + goto clrchn; + } + + /* + * Disable S/G fetch so the DMA engine + * is available to future users. + */ + if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) + ahd_outb(ahd, CCSGCTL, 0); + ahd_outb(ahd, SG_STATE, 0); + + /* + * Flush the data FIFO. Strickly only + * necessary for Rev A parts. + */ + ahd_outb(ahd, DFCNTRL, ahd_inb(ahd, DFCNTRL) | FIFOFLUSH); + + /* + * Calculate residual. + */ + sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); + resid = ahd_inl(ahd, SHCNT); + resid |= ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+3) << 24; + ahd_outl(ahd, SCB_RESIDUAL_DATACNT, resid); + if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG) == 0) { + /* + * Must back up to the correct S/G element. + * Typically this just means resetting our + * low byte to the offset in the SG_CACHE, + * but if we wrapped, we have to correct + * the other bytes of the sgptr too. + */ + if ((ahd_inb(ahd, SG_CACHE_SHADOW) & 0x80) != 0 + && (sgptr & 0x80) == 0) + sgptr -= 0x100; + sgptr &= ~0xFF; + sgptr |= ahd_inb(ahd, SG_CACHE_SHADOW) + & SG_ADDR_MASK; + ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr); + ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 3, 0); + } else if ((resid & AHD_SG_LEN_MASK) == 0) { + ahd_outb(ahd, SCB_RESIDUAL_SGPTR, + sgptr | SG_LIST_NULL); + } + /* + * Save Pointers. + */ + ahd_outq(ahd, SCB_DATAPTR, ahd_inq(ahd, SHADDR)); + ahd_outl(ahd, SCB_DATACNT, resid); + ahd_outl(ahd, SCB_SGPTR, sgptr); + ahd_outb(ahd, CLRSEQINTSRC, CLRSAVEPTRS); + ahd_outb(ahd, SEQIMODE, + ahd_inb(ahd, SEQIMODE) | ENSAVEPTRS); + /* + * If the data is to the SCSI bus, we are + * done, otherwise wait for FIFOEMP. + */ + if ((ahd_inb(ahd, DFCNTRL) & DIRECTION) != 0) + goto clrchn; + } else if ((ahd_inb(ahd, SG_STATE) & LOADING_NEEDED) != 0) { + uint32_t sgptr; + uint64_t data_addr; + uint32_t data_len; + u_int dfcntrl; + + /* + * Disable S/G fetch so the DMA engine + * is available to future users. We won't + * be using the DMA engine to load segments. + */ + if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) { + ahd_outb(ahd, CCSGCTL, 0); + ahd_outb(ahd, SG_STATE, LOADING_NEEDED); + } + + /* + * Wait for the DMA engine to notice that the + * host transfer is enabled and that there is + * space in the S/G FIFO for new segments before + * loading more segments. + */ + if ((ahd_inb(ahd, DFSTATUS) & PRELOAD_AVAIL) != 0 + && (ahd_inb(ahd, DFCNTRL) & HDMAENACK) != 0) { + + /* + * Determine the offset of the next S/G + * element to load. + */ + sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); + sgptr &= SG_PTR_MASK; + if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { + struct ahd_dma64_seg *sg; + + sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); + data_addr = sg->addr; + data_len = sg->len; + sgptr += sizeof(*sg); + } else { + struct ahd_dma_seg *sg; + + sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); + data_addr = sg->len & AHD_SG_HIGH_ADDR_MASK; + data_addr <<= 8; + data_addr |= sg->addr; + data_len = sg->len; + sgptr += sizeof(*sg); + } + + /* + * Update residual information. + */ + ahd_outb(ahd, SCB_RESIDUAL_DATACNT+3, data_len >> 24); + ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr); + + /* + * Load the S/G. + */ + if (data_len & AHD_DMA_LAST_SEG) { + sgptr |= LAST_SEG; + ahd_outb(ahd, SG_STATE, 0); + } + ahd_outq(ahd, HADDR, data_addr); + ahd_outl(ahd, HCNT, data_len & AHD_SG_LEN_MASK); + ahd_outb(ahd, SG_CACHE_PRE, sgptr & 0xFF); + + /* + * Advertise the segment to the hardware. + */ + dfcntrl = ahd_inb(ahd, DFCNTRL)|PRELOADEN|HDMAEN; + if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) { + /* + * Use SCSIENWRDIS so that SCSIEN + * is never modified by this + * operation. + */ + dfcntrl |= SCSIENWRDIS; + } + ahd_outb(ahd, DFCNTRL, dfcntrl); + } + } else if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG_DONE) != 0) { + + /* + * Transfer completed to the end of SG list + * and has flushed to the host. + */ + ahd_outb(ahd, SCB_SGPTR, + ahd_inb_scbram(ahd, SCB_SGPTR) | SG_LIST_NULL); + goto clrchn; + } else if ((ahd_inb(ahd, DFSTATUS) & FIFOEMP) != 0) { +clrchn: + /* + * Clear any handler for this FIFO, decrement + * the FIFO use count for the SCB, and release + * the FIFO. + */ + ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR); + ahd_outb(ahd, SCB_FIFO_USE_COUNT, + ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) - 1); + ahd_outb(ahd, DFFSXFRCTL, CLRCHN); + } +} + void ahd_run_qoutfifo(struct ahd_softc *ahd) { @@ -476,7 +810,7 @@ ahd_run_qoutfifo(struct ahd_softc *ahd) while ((ahd->qoutfifo[ahd->qoutfifonext] & QOUTFIFO_ENTRY_VALID_LE) == ahd->qoutfifonext_valid_tag) { - scb_index = ahd_le16toh(ahd->qoutfifo[ahd->qoutfifonext] + scb_index = aic_le16toh(ahd->qoutfifo[ahd->qoutfifonext] & ~QOUTFIFO_ENTRY_VALID_LE); scb = ahd_lookup_scb(ahd, scb_index); if (scb == NULL) { @@ -556,26 +890,6 @@ ahd_handle_seqint(struct ahd_softc *ahd, ahd_name(ahd), seqintcode); #endif switch (seqintcode) { - case BAD_SCB_STATUS: - { - struct scb *scb; - u_int scbid; - int cmds_pending; - - scbid = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbid); - if (scb != NULL) { - ahd_complete_scb(ahd, scb); - } else { - printf("%s: WARNING no command for scb %d " - "(bad status)\n", ahd_name(ahd), scbid); - ahd_dump_card_state(ahd); - } - cmds_pending = ahd_inw(ahd, CMDS_PENDING); - if (cmds_pending > 0) - ahd_outw(ahd, CMDS_PENDING, cmds_pending - 1); - break; - } case ENTERING_NONPACK: { struct scb *scb; @@ -589,7 +903,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, /* * Somehow need to know if this * is from a selection or reselection. - * From that, we can termine target + * From that, we can determine target * ID so we at least have an I_T nexus. */ } else { @@ -740,11 +1054,11 @@ ahd_handle_seqint(struct ahd_softc *ahd, ahd_outb(ahd, SAVED_LUN, 0); ahd_outb(ahd, SEQ_FLAGS, 0); ahd_assert_atn(ahd); - scb->flags &= ~(SCB_PACKETIZED); + scb->flags &= ~SCB_PACKETIZED; scb->flags |= SCB_ABORT|SCB_CMDPHASE_ABORT; ahd_freeze_devq(ahd, scb); - ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); - ahd_freeze_scb(scb); + aic_set_transaction_status(scb, CAM_REQUEUE_REQ); + aic_freeze_scb(scb); /* * Allow the sequencer to continue with @@ -796,7 +1110,8 @@ ahd_handle_seqint(struct ahd_softc *ahd, * attempt to complete this bogus SCB. */ ahd_outb(ahd, SCB_CONTROL, - ahd_inb(ahd, SCB_CONTROL) & ~STATUS_RCVD); + ahd_inb_scbram(ahd, SCB_CONTROL) + & ~STATUS_RCVD); } break; } @@ -991,7 +1306,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, "NumSGs = %d.\n", ahd_inb(ahd, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't", - ahd_get_transfer_length(scb), scb->sg_count); + aic_get_transfer_length(scb), scb->sg_count); ahd_dump_sglist(scb); } #endif @@ -1001,8 +1316,8 @@ ahd_handle_seqint(struct ahd_softc *ahd, * target does a command complete. */ ahd_freeze_devq(ahd, scb); - ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR); - ahd_freeze_scb(scb); + aic_set_transaction_status(scb, CAM_DATA_RUN_ERR); + aic_freeze_scb(scb); break; } case MKMSG_FAILED: @@ -1029,7 +1344,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, ROLE_INITIATOR, /*status*/0, SEARCH_REMOVE); ahd_outb(ahd, SCB_CONTROL, - ahd_inb(ahd, SCB_CONTROL) & ~MK_MESSAGE); + ahd_inb_scbram(ahd, SCB_CONTROL) & ~MK_MESSAGE); break; } case TASKMGMT_FUNC_COMPLETE: @@ -1263,7 +1578,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd */ ahd_scb_devinfo(ahd, &devinfo, scb); ahd_force_renegotiation(ahd, &devinfo); - ahd_set_transaction_status(scb, CAM_SEL_TIMEOUT); + aic_set_transaction_status(scb, CAM_SEL_TIMEOUT); ahd_freeze_devq(ahd, scb); } ahd_outb(ahd, CLRINT, CLRSCSIINT); @@ -1710,8 +2025,8 @@ ahd_handle_pkt_busfree(struct ahd_softc } scb->crc_retry_count++; } else { - ahd_set_transaction_status(scb, CAM_UNCOR_PARITY); - ahd_freeze_scb(scb); + aic_set_transaction_status(scb, CAM_UNCOR_PARITY); + aic_freeze_scb(scb); ahd_freeze_devq(ahd, scb); } /* Return unpausing the sequencer. */ @@ -1853,7 +2168,7 @@ ahd_handle_nonpkt_busfree(struct ahd_sof && ahd_match_scb(ahd, scb, target, 'A', CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_INITIATOR)) - ahd_set_transaction_status(scb, CAM_REQ_CMP); + aic_set_transaction_status(scb, CAM_REQ_CMP); #endif ahd_handle_devreset(ahd, &devinfo, CAM_LUN_WILDCARD, CAM_BDR_SENT, "Bus Device Reset", @@ -1880,21 +2195,32 @@ ahd_handle_nonpkt_busfree(struct ahd_sof tinfo->goal.ppr_options = 0; ahd_qinfifo_requeue_tail(ahd, scb); printerror = 0; - } else if ((ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, FALSE) - || ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, FALSE)) + } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, FALSE) && ppr_busfree == 0) { /* - * Negotiation Rejected. Go-async and + * Negotiation Rejected. Go-narrow and * retry command. */ #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printf("Negotiation rejected busfree.\n"); + printf("WDTR negotiation rejected busfree.\n"); #endif ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, AHD_TRANS_CUR|AHD_TRANS_GOAL, /*paused*/TRUE); + ahd_qinfifo_requeue_tail(ahd, scb); + printerror = 0; + } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, FALSE) + && ppr_busfree == 0) { + /* + * Negotiation Rejected. Go-async and + * retry command. + */ +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) + printf("SDTR negotiation rejected busfree.\n"); +#endif ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, /*ppr_options*/0, @@ -1933,8 +2259,8 @@ ahd_handle_nonpkt_busfree(struct ahd_sof && ((ahd->msg_flags & MSG_FLAG_EXPECT_PPR_BUSFREE) != 0)) { ahd_freeze_devq(ahd, scb); - ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); - ahd_freeze_scb(scb); + aic_set_transaction_status(scb, CAM_REQUEUE_REQ); + aic_freeze_scb(scb); if ((ahd->msg_flags & MSG_FLAG_IU_REQ_CHANGED) != 0) { ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), SCB_GET_CHANNEL(ahd, scb), @@ -1978,8 +2304,7 @@ ahd_handle_nonpkt_busfree(struct ahd_sof "PRGMCNT == 0x%x\n", ahd_lookup_phase_entry(lastphase)->phasemsg, aborted, - ahd_inb(ahd, PRGMCNT) - | (ahd_inb(ahd, PRGMCNT+1) << 8)); + ahd_inw(ahd, PRGMCNT)); ahd_dump_card_state(ahd); } /* Always restart the sequencer. */ @@ -2023,7 +2348,7 @@ ahd_handle_proto_violation(struct ahd_so printf("No SCB found during protocol violation\n"); goto proto_violation_reset; } else { - ahd_set_transaction_status(scb, CAM_SEQUENCE_FAIL); + aic_set_transaction_status(scb, CAM_SEQUENCE_FAIL); if ((seq_flags & NO_CDB_SENT) != 0) { ahd_print_path(ahd, scb); printf("No or incomplete CDB sent to device.\n"); @@ -2142,8 +2467,7 @@ ahd_clear_critical_section(struct ahd_so u_int i; ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - seqaddr = ahd_inb(ahd, CURADDR) - | (ahd_inb(ahd, CURADDR+1) << 8); + seqaddr = ahd_inw(ahd, CURADDR); cs = ahd->critical_sections; for (i = 0; i < ahd->num_critical_sections; i++, cs++) { @@ -2187,8 +2511,14 @@ ahd_clear_critical_section(struct ahd_so ahd_outb(ahd, LQOMODE0, 0); ahd_outb(ahd, LQOMODE1, 0); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - simode1 = ahd_inb(ahd, SIMODE1); - ahd_outb(ahd, SIMODE1, ENBUSFREE); + simode1 = ahd_inb(ahd, SIMODE1); + /* + * We don't clear ENBUSFREE. Unfortunately + * we cannot re-enable busfree detection within + * the current connection, so we must leave it + * on while single stepping. + */ + ahd_outb(ahd, SIMODE1, simode1 & ENBUSFREE); ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) | STEP); stepping = TRUE; } @@ -2196,9 +2526,8 @@ ahd_clear_critical_section(struct ahd_so ahd_outb(ahd, CLRINT, CLRSCSIINT); ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); ahd_outb(ahd, HCNTRL, ahd->unpause); - do { - ahd_delay(200); - } while (!ahd_is_paused(ahd)); + while (!ahd_is_paused(ahd)) + aic_delay(200); ahd_update_modes(ahd); } if (stepping) { @@ -2274,10 +2603,10 @@ ahd_print_scb(struct scb *scb) for (i = 0; i < sizeof(hscb->shared_data.idata.cdb); i++) printf("%#02x", hscb->shared_data.idata.cdb[i]); printf(" dataptr:%#x%x datacnt:%#x sgptr:%#x tag:%#x\n", - (uint32_t)((ahd_le64toh(hscb->dataptr) >> 32) & 0xFFFFFFFF), - (uint32_t)(ahd_le64toh(hscb->dataptr) & 0xFFFFFFFF), - ahd_le32toh(hscb->datacnt), - ahd_le32toh(hscb->sgptr), + (uint32_t)((aic_le64toh(hscb->dataptr) >> 32) & 0xFFFFFFFF), + (uint32_t)(aic_le64toh(hscb->dataptr) & 0xFFFFFFFF), + aic_le32toh(hscb->datacnt), + aic_le32toh(hscb->sgptr), SCB_GET_TAG(scb)); ahd_dump_sglist(scb); } @@ -2296,8 +2625,8 @@ ahd_dump_sglist(struct scb *scb) uint64_t addr; uint32_t len; - addr = ahd_le64toh(sg_list[i].addr); - len = ahd_le32toh(sg_list[i].len); + addr = aic_le64toh(sg_list[i].addr); + len = aic_le32toh(sg_list[i].len); printf("sg[%d] - Addr 0x%x%x : Length %d%s\n", i, (uint32_t)((addr >> 32) & 0xFFFFFFFF), @@ -2313,11 +2642,11 @@ ahd_dump_sglist(struct scb *scb) for (i = 0; i < scb->sg_count; i++) { uint32_t len; - len = ahd_le32toh(sg_list[i].len); + len = aic_le32toh(sg_list[i].len); printf("sg[%d] - Addr 0x%x%x : Length %d%s\n", i, - (len >> 24) & SG_HIGH_ADDR_BITS, - ahd_le32toh(sg_list[i].addr), + (len & AHD_SG_HIGH_ADDR_MASK) >> 24, + aic_le32toh(sg_list[i].addr), len & AHD_SG_LEN_MASK, len & AHD_DMA_LAST_SEG ? " Last" : ""); } @@ -2859,14 +3188,25 @@ ahd_update_neg_table(struct ahd_softc *a iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_PRECOMP_MASK; if ((ahd->features & AHD_NEW_IOCELL_OPTS) != 0 - && (ppr_opts & MSG_EXT_PPR_DT_REQ) != 0) { + && (ppr_opts & MSG_EXT_PPR_DT_REQ) != 0 + && (ppr_opts & MSG_EXT_PPR_IU_REQ) == 0) { /* * Slow down our CRC interval to be - * compatible with devices that can't - * handle a CRC at full speed. + * compatible with non-packetized + * U160 devices that can't handle a + * CRC at full speed. */ con_opts |= ENSLOWCRC; } + + if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) { + /* + * On H2A4, revert to a slower slewrate + * on non-paced transfers. + */ + iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= + ~AHD_SLEWRATE_MASK; + } } ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PRECOMP_SLEW); @@ -2904,7 +3244,7 @@ ahd_update_pending_scbs(struct ahd_softc { struct scb *pending_scb; int pending_scb_count; - int i; + u_int scb_tag; int paused; u_int saved_scbptr; ahd_mode_state saved_modes; @@ -2962,17 +3302,14 @@ ahd_update_pending_scbs(struct ahd_softc ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); saved_scbptr = ahd_get_scbptr(ahd); /* Ensure that the hscbs down on the card match the new information */ - for (i = 0; i < ahd->scb_data.maxhscbs; i++) { + for (scb_tag = 0; scb_tag < ahd->scb_data.maxhscbs; scb_tag++) { struct hardware_scb *pending_hscb; u_int control; - u_int scb_tag; - ahd_set_scbptr(ahd, i); - scb_tag = i; pending_scb = ahd_lookup_scb(ahd, scb_tag); if (pending_scb == NULL) continue; - + ahd_set_scbptr(ahd, scb_tag); pending_hscb = pending_scb->hscb; control = ahd_inb_scbram(ahd, SCB_CONTROL); control &= ~MK_MESSAGE; @@ -3187,7 +3524,7 @@ ahd_setup_initiator_msgout(struct ahd_so devinfo->target_mask); panic("SCB = %d, SCB Control = %x:%x, MSG_OUT = %x " "SCB flags = %x", SCB_GET_TAG(scb), scb->hscb->control, - ahd_inb(ahd, SCB_CONTROL), ahd_inb(ahd, MSG_OUT), + ahd_inb_scbram(ahd, SCB_CONTROL), ahd_inb(ahd, MSG_OUT), scb->flags); } @@ -3232,6 +3569,7 @@ ahd_build_transfer_msg(struct ahd_softc * may change. */ period = tinfo->goal.period; + offset = tinfo->goal.offset; ppr_options = tinfo->goal.ppr_options; /* Target initiated PPR is not allowed in the SCSI spec */ if (devinfo->role == ROLE_TARGET) @@ -3239,7 +3577,7 @@ ahd_build_transfer_msg(struct ahd_softc ahd_devlimited_syncrate(ahd, tinfo, &period, &ppr_options, devinfo->role); dowide = tinfo->curr.width != tinfo->goal.width; - dosync = tinfo->curr.period != period; + dosync = tinfo->curr.offset != offset || tinfo->curr.period != period; /* * Only use PPR if we have options that need it, even if the device * claims to support it. There might be an expander in the way @@ -3249,7 +3587,7 @@ ahd_build_transfer_msg(struct ahd_softc if (!dowide && !dosync && !doppr) { dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; - dosync = tinfo->goal.period != 0; + dosync = tinfo->goal.offset != 0; } if (!dowide && !dosync && !doppr) { @@ -3725,8 +4063,13 @@ reswitch: if ((ahd->msg_flags & MSG_FLAG_PACKETIZED) != 0) { printf("%s: Returning to Idle Loop\n", ahd_name(ahd)); - ahd_outb(ahd, LASTPHASE, P_BUSFREE); ahd_clear_msg_state(ahd); + + /* + * Perform the equivalent of a clear_target_state. + */ + ahd_outb(ahd, LASTPHASE, P_BUSFREE); + ahd_outb(ahd, SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT); ahd_outb(ahd, SEQCTL0, FASTMODE|SEQRESET); } else { ahd_clear_msg_state(ahd); @@ -3983,22 +4326,30 @@ ahd_parse_msg(struct ahd_softc *ahd, str response = TRUE; sending_reply = TRUE; } + /* + * After a wide message, we are async, but + * some devices don't seem to honor this portion + * of the spec. Force a renegotiation of the + * sync component of our transfer agreement even + * if our goal is async. By updating our width + * after forcing the negotiation, we avoid + * renegotiating for width. + */ + ahd_update_neg_request(ahd, devinfo, tstate, + tinfo, AHD_NEG_ALWAYS); ahd_set_width(ahd, devinfo, bus_width, AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, /*paused*/TRUE); - /* After a wide message, we are async */ - ahd_set_syncrate(ahd, devinfo, /*period*/0, - /*offset*/0, /*ppr_options*/0, - AHD_TRANS_ACTIVE, /*paused*/TRUE); if (sending_reply == FALSE && reject == FALSE) { - if (tinfo->goal.offset) { - ahd->msgout_index = 0; - ahd->msgout_len = 0; - ahd_build_transfer_msg(ahd, devinfo); - ahd->msgout_index = 0; - response = TRUE; - } + /* + * We will always have an SDTR to send. + */ + ahd->msgout_index = 0; + ahd->msgout_len = 0; + ahd_build_transfer_msg(ahd, devinfo); + ahd->msgout_index = 0; + response = TRUE; } done = MSGLOOP_MSGCOMPLETE; break; @@ -4326,7 +4677,7 @@ ahd_handle_msg_reject(struct ahd_softc * ahd_outb(ahd, SCB_CONTROL, ahd_inb_scbram(ahd, SCB_CONTROL) & mask); scb->hscb->control &= mask; - ahd_set_transaction_tag(scb, /*enabled*/FALSE, + aic_set_transaction_tag(scb, /*enabled*/FALSE, /*type*/MSG_SIMPLE_TASK); ahd_outb(ahd, MSG_OUT, MSG_IDENTIFYFLAG); ahd_assert_atn(ahd); @@ -4384,7 +4735,7 @@ ahd_handle_ign_wide_residue(struct ahd_s * Perhaps add datadir to some spare bits in the hscb? */ if ((ahd_inb(ahd, SEQ_FLAGS) & DPHASE) == 0 - || ahd_get_transfer_dir(scb) != CAM_DIR_IN) { + || aic_get_transfer_dir(scb) != CAM_DIR_IN) { /* * Ignore the message if we haven't * seen an appropriate data phase yet. @@ -4401,7 +4752,8 @@ ahd_handle_ign_wide_residue(struct ahd_s sgptr = ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR); if ((sgptr & SG_LIST_NULL) != 0 - && (ahd_inb(ahd, SCB_TASK_ATTRIBUTE) & SCB_XFERLEN_ODD) != 0) { + && (ahd_inb_scbram(ahd, SCB_TASK_ATTRIBUTE) + & SCB_XFERLEN_ODD) != 0) { /* * If the residual occurred on the last * transfer and the transfer request was @@ -4438,18 +4790,18 @@ ahd_handle_ign_wide_residue(struct ahd_s * to load so we must go back one. */ sg--; - sglen = ahd_le32toh(sg->len) & AHD_SG_LEN_MASK; + sglen = aic_le32toh(sg->len) & AHD_SG_LEN_MASK; if (sg != scb->sg_list && sglen < (data_cnt & AHD_SG_LEN_MASK)) { sg--; - sglen = ahd_le32toh(sg->len); + sglen = aic_le32toh(sg->len); /* * Preserve High Address and SG_LIST * bits while setting the count to 1. */ data_cnt = 1|(sglen&(~AHD_SG_LEN_MASK)); - data_addr = ahd_le64toh(sg->addr) + data_addr = aic_le64toh(sg->addr) + (sglen & AHD_SG_LEN_MASK) - 1; @@ -4471,18 +4823,18 @@ ahd_handle_ign_wide_residue(struct ahd_s * to load so we must go back one. */ sg--; - sglen = ahd_le32toh(sg->len) & AHD_SG_LEN_MASK; + sglen = aic_le32toh(sg->len) & AHD_SG_LEN_MASK; if (sg != scb->sg_list && sglen < (data_cnt & AHD_SG_LEN_MASK)) { sg--; - sglen = ahd_le32toh(sg->len); + sglen = aic_le32toh(sg->len); /* * Preserve High Address and SG_LIST * bits while setting the count to 1. */ data_cnt = 1|(sglen&(~AHD_SG_LEN_MASK)); - data_addr = ahd_le32toh(sg->addr) + data_addr = aic_le32toh(sg->addr) + (sglen & AHD_SG_LEN_MASK) - 1; @@ -4502,7 +4854,8 @@ ahd_handle_ign_wide_residue(struct ahd_s * correct for subsequent data transfers. */ ahd_outb(ahd, SCB_TASK_ATTRIBUTE, - ahd_inb(ahd, SCB_TASK_ATTRIBUTE) ^ SCB_XFERLEN_ODD); + ahd_inb_scbram(ahd, SCB_TASK_ATTRIBUTE) + ^ SCB_XFERLEN_ODD); ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr); ahd_outl(ahd, SCB_RESIDUAL_DATACNT, data_cnt); @@ -4542,9 +4895,8 @@ ahd_reinitialize_dataptrs(struct ahd_sof */ ahd_outb(ahd, DFFSXFRCTL, CLRCHN); wait = 1000; - do { - ahd_delay(100); - } while (--wait && !(ahd_inb(ahd, MDFFSTAT) & FIFOFREE)); + while (--wait && !(ahd_inb(ahd, MDFFSTAT) & FIFOFREE)) + aic_delay(100); if (wait == 0) { ahd_print_path(ahd, scb); printf("ahd_reinitialize_dataptrs: Forcing FIFO free.\n"); @@ -4560,10 +4912,7 @@ ahd_reinitialize_dataptrs(struct ahd_sof * Determine initial values for data_addr and data_cnt * for resuming the data phase. */ - sgptr = (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 3) << 24) - | (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 2) << 16) - | (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 1) << 8) - | ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR); + sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); sgptr &= SG_PTR_MASK; resid = (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT + 2) << 16) @@ -4578,13 +4927,10 @@ ahd_reinitialize_dataptrs(struct ahd_sof /* The residual sg_ptr always points to the next sg */ sg--; - dataptr = ahd_le64toh(sg->addr) - + (ahd_le32toh(sg->len) & AHD_SG_LEN_MASK) + dataptr = aic_le64toh(sg->addr) + + (aic_le32toh(sg->len) & AHD_SG_LEN_MASK) - resid; - ahd_outb(ahd, HADDR + 7, dataptr >> 56); - ahd_outb(ahd, HADDR + 6, dataptr >> 48); - ahd_outb(ahd, HADDR + 5, dataptr >> 40); - ahd_outb(ahd, HADDR + 4, dataptr >> 32); + ahd_outl(ahd, HADDR + 4, dataptr >> 32); } else { struct ahd_dma_seg *sg; @@ -4593,16 +4939,13 @@ ahd_reinitialize_dataptrs(struct ahd_sof /* The residual sg_ptr always points to the next sg */ sg--; - dataptr = ahd_le32toh(sg->addr) - + (ahd_le32toh(sg->len) & AHD_SG_LEN_MASK) + dataptr = aic_le32toh(sg->addr) + + (aic_le32toh(sg->len) & AHD_SG_LEN_MASK) - resid; ahd_outb(ahd, HADDR + 4, - (ahd_le32toh(sg->len) & ~AHD_SG_LEN_MASK) >> 24); + (aic_le32toh(sg->len) & ~AHD_SG_LEN_MASK) >> 24); } - ahd_outb(ahd, HADDR + 3, dataptr >> 24); - ahd_outb(ahd, HADDR + 2, dataptr >> 16); - ahd_outb(ahd, HADDR + 1, dataptr >> 8); - ahd_outb(ahd, HADDR, dataptr); + ahd_outl(ahd, HADDR, dataptr); ahd_outb(ahd, HCNT + 2, resid >> 16); ahd_outb(ahd, HCNT + 1, resid >> 8); ahd_outb(ahd, HCNT, resid); @@ -4796,8 +5139,8 @@ ahd_alloc(void *platform_arg, char *name ahd->bugs = AHD_BUGNONE; ahd->flags = AHD_SPCHK_ENB_A|AHD_RESET_BUS_A|AHD_TERM_ENB_A | AHD_EXTENDED_TRANS_A|AHD_STPWLEVEL_A; - ahd_timer_init(&ahd->reset_timer); - ahd_timer_init(&ahd->stat_timer); + aic_timer_init(&ahd->reset_timer); + aic_timer_init(&ahd->stat_timer); ahd->int_coalescing_timer = AHD_INT_COALESCING_TIMER_DEFAULT; ahd->int_coalescing_maxcmds = AHD_INT_COALESCING_MAXCMDS_DEFAULT; ahd->int_coalescing_mincmds = AHD_INT_COALESCING_MINCMDS_DEFAULT; @@ -4833,24 +5176,24 @@ ahd_softc_insert(struct ahd_softc *ahd) { struct ahd_softc *list_ahd; -#if AHD_PCI_CONFIG > 0 +#if AIC_PCI_CONFIG > 0 /* * Second Function PCI devices need to inherit some * settings from function 0. */ if ((ahd->features & AHD_MULTI_FUNC) != 0) { TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { - ahd_dev_softc_t list_pci; - ahd_dev_softc_t pci; + aic_dev_softc_t list_pci; + aic_dev_softc_t pci; list_pci = list_ahd->dev_softc; pci = ahd->dev_softc; - if (ahd_get_pci_slot(list_pci) == ahd_get_pci_slot(pci) - && ahd_get_pci_bus(list_pci) == ahd_get_pci_bus(pci)) { + if (aic_get_pci_slot(list_pci) == aic_get_pci_slot(pci) + && aic_get_pci_bus(list_pci) == aic_get_pci_bus(pci)) { struct ahd_softc *master; struct ahd_softc *slave; - if (ahd_get_pci_function(list_pci) == 0) { + if (aic_get_pci_function(list_pci) == 0) { master = list_ahd; slave = ahd; } else { @@ -4915,27 +5258,27 @@ ahd_free(struct ahd_softc *ahd) { int i; + ahd_terminate_recovery_thread(ahd); switch (ahd->init_level) { default: case 5: ahd_shutdown(ahd); - TAILQ_REMOVE(&ahd_tailq, ahd, links); /* FALLTHROUGH */ case 4: - ahd_dmamap_unload(ahd, ahd->shared_data_dmat, - ahd->shared_data_dmamap); + aic_dmamap_unload(ahd, ahd->shared_data_dmat, + ahd->shared_data_map.dmamap); /* FALLTHROUGH */ case 3: - ahd_dmamem_free(ahd, ahd->shared_data_dmat, ahd->qoutfifo, - ahd->shared_data_dmamap); - ahd_dmamap_destroy(ahd, ahd->shared_data_dmat, - ahd->shared_data_dmamap); + aic_dmamem_free(ahd, ahd->shared_data_dmat, ahd->qoutfifo, + ahd->shared_data_map.dmamap); + aic_dmamap_destroy(ahd, ahd->shared_data_dmat, + ahd->shared_data_map.dmamap); /* FALLTHROUGH */ case 2: - ahd_dma_tag_destroy(ahd, ahd->shared_data_dmat); + aic_dma_tag_destroy(ahd, ahd->shared_data_dmat); case 1: #ifndef __linux__ - ahd_dma_tag_destroy(ahd, ahd->buffer_dmat); + aic_dma_tag_destroy(ahd, ahd->buffer_dmat); #endif break; case 0: @@ -4943,7 +5286,7 @@ ahd_free(struct ahd_softc *ahd) } #ifndef __linux__ - ahd_dma_tag_destroy(ahd, ahd->parent_dmat); + aic_dma_tag_destroy(ahd, ahd->parent_dmat); #endif ahd_platform_free(ahd); ahd_fini_scbdata(ahd); @@ -4996,19 +5339,24 @@ ahd_shutdown(void *arg) /* * Stop periodic timer callbacks. */ - ahd_timer_stop(&ahd->reset_timer); - ahd_timer_stop(&ahd->stat_timer); + aic_timer_stop(&ahd->reset_timer); + aic_timer_stop(&ahd->stat_timer); /* This will reset most registers to 0, but not all */ - ahd_reset(ahd); + ahd_reset(ahd, /*reinit*/FALSE); } /* * Reset the controller and record some information about it - * that is only available just after a reset. + * that is only available just after a reset. If "reinit" is + * non-zero, this reset occured after initial configuration + * and the caller requests that the chip be fully reinitialized + * to a runable state. Chip interrupts are *not* enabled after + * a reinitialization. The caller must enable interrupts via + * ahd_intr_enable(). */ int -ahd_reset(struct ahd_softc *ahd) +ahd_reset(struct ahd_softc *ahd, int reinit) { u_int sxfrctl1; int wait; @@ -5024,7 +5372,7 @@ ahd_reset(struct ahd_softc *ahd) ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); sxfrctl1 = ahd_inb(ahd, SXFRCTL1); - cmd = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); + cmd = aic_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); if ((ahd->bugs & AHD_PCIX_CHIPRST_BUG) != 0) { uint32_t mod_cmd; @@ -5038,7 +5386,7 @@ ahd_reset(struct ahd_softc *ahd) * PERR and SERR responses during the CHIPRST. */ mod_cmd = cmd & ~(PCIM_CMD_PERRESPEN|PCIM_CMD_SERRESPEN); - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, + aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND, mod_cmd, /*bytes*/2); } ahd_outb(ahd, HCNTRL, CHIPRST | ahd->pause); @@ -5051,7 +5399,7 @@ ahd_reset(struct ahd_softc *ahd) */ wait = 1000; do { - ahd_delay(1000); + aic_delay(1000); } while (--wait && !(ahd_inb(ahd, HCNTRL) & CHIPRSTACK)); if (wait == 0) { @@ -5065,9 +5413,9 @@ ahd_reset(struct ahd_softc *ahd) * Clear any latched PCI error status and restore * previous SERR and PERR response enables. */ - ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, + aic_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, 0xFF, /*bytes*/1); - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, + aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2); } @@ -5101,7 +5449,7 @@ ahd_reset(struct ahd_softc *ahd) * If a recovery action has forced a chip reset, * re-initialize the chip to our liking. */ - if (ahd->init_level > 0) + if (reinit != 0) ahd_chip_init(ahd); return (0); @@ -5194,7 +5542,7 @@ ahd_init_scbdata(struct ahd_softc *ahd) */ /* DMA tag for our hardware scb structures */ - if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, + if (aic_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, @@ -5208,7 +5556,7 @@ ahd_init_scbdata(struct ahd_softc *ahd) scb_data->init_level++; /* DMA tag for our S/G structures. */ - if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/8, + if (aic_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/8, /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, @@ -5227,7 +5575,7 @@ ahd_init_scbdata(struct ahd_softc *ahd) scb_data->init_level++; /* DMA tag for our sense buffers. We allocate in page sized chunks */ - if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, + if (aic_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, @@ -5315,13 +5663,13 @@ ahd_fini_scbdata(struct ahd_softc *ahd) while ((sns_map = SLIST_FIRST(&scb_data->sense_maps)) != NULL) { SLIST_REMOVE_HEAD(&scb_data->sense_maps, links); - ahd_dmamap_unload(ahd, scb_data->sense_dmat, + aic_dmamap_unload(ahd, scb_data->sense_dmat, sns_map->dmamap); - ahd_dmamem_free(ahd, scb_data->sense_dmat, + aic_dmamem_free(ahd, scb_data->sense_dmat, sns_map->vaddr, sns_map->dmamap); free(sns_map, M_DEVBUF); } - ahd_dma_tag_destroy(ahd, scb_data->sense_dmat); + aic_dma_tag_destroy(ahd, scb_data->sense_dmat); /* FALLTHROUGH */ } case 6: @@ -5330,13 +5678,13 @@ ahd_fini_scbdata(struct ahd_softc *ahd) while ((sg_map = SLIST_FIRST(&scb_data->sg_maps)) != NULL) { SLIST_REMOVE_HEAD(&scb_data->sg_maps, links); - ahd_dmamap_unload(ahd, scb_data->sg_dmat, + aic_dmamap_unload(ahd, scb_data->sg_dmat, sg_map->dmamap); - ahd_dmamem_free(ahd, scb_data->sg_dmat, + aic_dmamem_free(ahd, scb_data->sg_dmat, sg_map->vaddr, sg_map->dmamap); free(sg_map, M_DEVBUF); } - ahd_dma_tag_destroy(ahd, scb_data->sg_dmat); + aic_dma_tag_destroy(ahd, scb_data->sg_dmat); /* FALLTHROUGH */ } case 5: @@ -5345,13 +5693,13 @@ ahd_fini_scbdata(struct ahd_softc *ahd) while ((hscb_map = SLIST_FIRST(&scb_data->hscb_maps)) != NULL) { SLIST_REMOVE_HEAD(&scb_data->hscb_maps, links); - ahd_dmamap_unload(ahd, scb_data->hscb_dmat, + aic_dmamap_unload(ahd, scb_data->hscb_dmat, hscb_map->dmamap); - ahd_dmamem_free(ahd, scb_data->hscb_dmat, + aic_dmamem_free(ahd, scb_data->hscb_dmat, hscb_map->vaddr, hscb_map->dmamap); free(hscb_map, M_DEVBUF); } - ahd_dma_tag_destroy(ahd, scb_data->hscb_dmat); + aic_dma_tag_destroy(ahd, scb_data->hscb_dmat); /* FALLTHROUGH */ } case 4: @@ -5382,6 +5730,7 @@ ahd_setup_iocell_workaround(struct ahd_s printf("%s: Setting up iocell workaround\n", ahd_name(ahd)); #endif ahd_restore_modes(ahd, saved_modes); + ahd->flags &= ~AHD_HAD_FIRST_SEL; } static void @@ -5390,6 +5739,8 @@ ahd_iocell_first_selection(struct ahd_so ahd_mode_state saved_modes; u_int sblkctl; + if ((ahd->flags & AHD_HAD_FIRST_SEL) != 0) + return; saved_modes = ahd_save_modes(ahd); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); sblkctl = ahd_inb(ahd, SBLKCTL); @@ -5409,6 +5760,7 @@ ahd_iocell_first_selection(struct ahd_so ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) & ~(ENSELDO|ENSELDI)); ahd_outb(ahd, CLRINT, CLRSCSIINT); ahd_restore_modes(ahd, saved_modes); + ahd->flags |= AHD_HAD_FIRST_SEL; } /*************************** SCB Management ***********************************/ @@ -5552,7 +5904,7 @@ ahd_free_scb(struct ahd_softc *ahd, stru scb, links.le); } - ahd_platform_scb_free(ahd, scb); + aic_platform_scb_free(ahd, scb); } void @@ -5583,7 +5935,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) offset = (PAGE_SIZE / sizeof(*hscb)) - scb_data->scbs_left; hscb_map = SLIST_FIRST(&scb_data->hscb_maps); hscb = &((struct hardware_scb *)hscb_map->vaddr)[offset]; - hscb_busaddr = hscb_map->physaddr + (offset * sizeof(*hscb)); + hscb_busaddr = hscb_map->busaddr + (offset * sizeof(*hscb)); } else { hscb_map = malloc(sizeof(*hscb_map), M_DEVBUF, M_NOWAIT); @@ -5591,7 +5943,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) return; /* Allocate the next batch of hardware SCBs */ - if (ahd_dmamem_alloc(ahd, scb_data->hscb_dmat, + if (aic_dmamem_alloc(ahd, scb_data->hscb_dmat, (void **)&hscb_map->vaddr, BUS_DMA_NOWAIT, &hscb_map->dmamap) != 0) { free(hscb_map, M_DEVBUF); @@ -5600,12 +5952,12 @@ ahd_alloc_scbs(struct ahd_softc *ahd) SLIST_INSERT_HEAD(&scb_data->hscb_maps, hscb_map, links); - ahd_dmamap_load(ahd, scb_data->hscb_dmat, hscb_map->dmamap, + aic_dmamap_load(ahd, scb_data->hscb_dmat, hscb_map->dmamap, hscb_map->vaddr, PAGE_SIZE, ahd_dmamap_cb, - &hscb_map->physaddr, /*flags*/0); + &hscb_map->busaddr, /*flags*/0); hscb = (struct hardware_scb *)hscb_map->vaddr; - hscb_busaddr = hscb_map->physaddr; + hscb_busaddr = hscb_map->busaddr; scb_data->scbs_left = PAGE_SIZE / sizeof(*hscb); } @@ -5616,7 +5968,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) - scb_data->sgs_left) * ahd_sglist_size(ahd); sg_map = SLIST_FIRST(&scb_data->sg_maps); segs = sg_map->vaddr + offset; - sg_busaddr = sg_map->physaddr + offset; + sg_busaddr = sg_map->busaddr + offset; } else { sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); @@ -5624,7 +5976,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) return; /* Allocate the next batch of S/G lists */ - if (ahd_dmamem_alloc(ahd, scb_data->sg_dmat, + if (aic_dmamem_alloc(ahd, scb_data->sg_dmat, (void **)&sg_map->vaddr, BUS_DMA_NOWAIT, &sg_map->dmamap) != 0) { free(sg_map, M_DEVBUF); @@ -5633,12 +5985,12 @@ ahd_alloc_scbs(struct ahd_softc *ahd) SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links); - ahd_dmamap_load(ahd, scb_data->sg_dmat, sg_map->dmamap, + aic_dmamap_load(ahd, scb_data->sg_dmat, sg_map->dmamap, sg_map->vaddr, ahd_sglist_allocsize(ahd), - ahd_dmamap_cb, &sg_map->physaddr, /*flags*/0); + ahd_dmamap_cb, &sg_map->busaddr, /*flags*/0); segs = sg_map->vaddr; - sg_busaddr = sg_map->physaddr; + sg_busaddr = sg_map->busaddr; scb_data->sgs_left = ahd_sglist_allocsize(ahd) / ahd_sglist_size(ahd); #ifdef AHD_DEBUG @@ -5653,7 +6005,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) offset = PAGE_SIZE - (AHD_SENSE_BUFSIZE * scb_data->sense_left); sense_map = SLIST_FIRST(&scb_data->sense_maps); sense_data = sense_map->vaddr + offset; - sense_busaddr = sense_map->physaddr + offset; + sense_busaddr = sense_map->busaddr + offset; } else { sense_map = malloc(sizeof(*sense_map), M_DEVBUF, M_NOWAIT); @@ -5661,7 +6013,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) return; /* Allocate the next batch of sense buffers */ - if (ahd_dmamem_alloc(ahd, scb_data->sense_dmat, + if (aic_dmamem_alloc(ahd, scb_data->sense_dmat, (void **)&sense_map->vaddr, BUS_DMA_NOWAIT, &sense_map->dmamap) != 0) { free(sense_map, M_DEVBUF); @@ -5670,12 +6022,12 @@ ahd_alloc_scbs(struct ahd_softc *ahd) SLIST_INSERT_HEAD(&scb_data->sense_maps, sense_map, links); - ahd_dmamap_load(ahd, scb_data->sense_dmat, sense_map->dmamap, + aic_dmamap_load(ahd, scb_data->sense_dmat, sense_map->dmamap, sense_map->vaddr, PAGE_SIZE, ahd_dmamap_cb, - &sense_map->physaddr, /*flags*/0); + &sense_map->busaddr, /*flags*/0); sense_data = sense_map->vaddr; - sense_busaddr = sense_map->physaddr; + sense_busaddr = sense_map->busaddr; scb_data->sense_left = PAGE_SIZE / AHD_SENSE_BUFSIZE; #ifdef AHD_DEBUG if (ahd_debug & AHD_SHOW_MEMORY) @@ -5716,7 +6068,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) next_scb->sense_busaddr = sense_busaddr; memset(hscb, 0, sizeof(*hscb)); next_scb->hscb = hscb; - hscb->hscb_busaddr = ahd_htole32(hscb_busaddr); + hscb->hscb_busaddr = aic_htole32(hscb_busaddr); /* * The sequencer always starts with the second entry. @@ -5731,7 +6083,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) next_scb->ahd_softc = ahd; next_scb->flags = SCB_FLAG_NONE; #ifndef __linux__ - error = ahd_dmamap_create(ahd, ahd->buffer_dmat, /*flags*/0, + error = aic_dmamap_create(ahd, ahd->buffer_dmat, /*flags*/0, &next_scb->dmamap); if (error != 0) { free(next_scb, M_DEVBUF); @@ -5739,7 +6091,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) break; } #endif - next_scb->hscb->tag = ahd_htole16(scb_data->numscbs); + next_scb->hscb->tag = aic_htole16(scb_data->numscbs); col_tag = scb_data->numscbs ^ 0x100; next_scb->col_scb = ahd_find_scb_by_tag(ahd, col_tag); if (next_scb->col_scb != NULL) @@ -5799,7 +6151,6 @@ static const char *termstat_strings[] = int ahd_init(struct ahd_softc *ahd) { - uint8_t *base_vaddr; uint8_t *next_vaddr; bus_addr_t next_baddr; size_t driver_data_size; @@ -5842,7 +6193,7 @@ ahd_init(struct ahd_softc *ahd) #ifndef __linux__ /* DMA tag for mapping buffers into device visible space. */ - if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, + if (aic_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, /*lowaddr*/ahd->flags & AHD_39BIT_ADDRESSING ? (bus_addr_t)0x7FFFFFFFFFULL @@ -5873,7 +6224,7 @@ ahd_init(struct ahd_softc *ahd) driver_data_size += AHD_TMODE_CMDS * sizeof(struct target_cmd); if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) driver_data_size += PKT_OVERRUN_BUFSIZE; - if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, + if (aic_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, @@ -5888,21 +6239,24 @@ ahd_init(struct ahd_softc *ahd) ahd->init_level++; /* Allocation of driver data */ - if (ahd_dmamem_alloc(ahd, ahd->shared_data_dmat, - (void **)&base_vaddr, - BUS_DMA_NOWAIT, &ahd->shared_data_dmamap) != 0) { + if (aic_dmamem_alloc(ahd, ahd->shared_data_dmat, + (void **)&ahd->shared_data_map.vaddr, + BUS_DMA_NOWAIT, + &ahd->shared_data_map.dmamap) != 0) { return (ENOMEM); } ahd->init_level++; /* And permanently map it in */ - ahd_dmamap_load(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap, - base_vaddr, driver_data_size, ahd_dmamap_cb, - &ahd->shared_data_busaddr, /*flags*/0); - ahd->qoutfifo = (uint16_t *)base_vaddr; + aic_dmamap_load(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap, + ahd->shared_data_map.vaddr, driver_data_size, + ahd_dmamap_cb, &ahd->shared_data_map.busaddr, + /*flags*/0); + ahd->qoutfifo = (uint16_t *)ahd->shared_data_map.vaddr; next_vaddr = (uint8_t *)&ahd->qoutfifo[AHD_QOUT_SIZE]; - next_baddr = ahd->shared_data_busaddr + AHD_QOUT_SIZE*sizeof(uint16_t); + next_baddr = ahd->shared_data_map.busaddr + + AHD_QOUT_SIZE*sizeof(uint16_t); if ((ahd->features & AHD_TARGETMODE) != 0) { ahd->targetcmds = (struct target_cmd *)next_vaddr; next_vaddr += AHD_TMODE_CMDS * sizeof(struct target_cmd); @@ -5923,7 +6277,8 @@ ahd_init(struct ahd_softc *ahd) * specially from the DMA safe memory chunk used for the QOUTFIFO. */ ahd->next_queued_hscb = (struct hardware_scb *)next_vaddr; - ahd->next_queued_hscb->hscb_busaddr = ahd_htole32(next_baddr); + ahd->next_queued_hscb_map = &ahd->shared_data_map; + ahd->next_queued_hscb->hscb_busaddr = aic_htole32(next_baddr); ahd->init_level++; @@ -6014,7 +6369,7 @@ ahd_init(struct ahd_softc *ahd) } init_done: ahd_restart(ahd); - ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US, + aic_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US, ahd_stat_timer, ahd); return (0); } @@ -6075,7 +6430,7 @@ ahd_chip_init(struct ahd_softc *ahd) for (wait = 10000; (ahd_inb(ahd, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; wait--) - ahd_delay(100); + aic_delay(100); /* Clear any false bus resets due to the transceivers settling */ ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); @@ -6174,7 +6529,7 @@ ahd_chip_init(struct ahd_softc *ahd) ahd_outb(ahd, LUNLEN, sizeof(ahd->next_queued_hscb->pkt_long_lun) - 1); } else { - ahd_outb(ahd, LUNLEN, sizeof(ahd->next_queued_hscb->lun) - 1); + ahd_outb(ahd, LUNLEN, LUNLEN_SINGLE_LEVEL_LUN); } ahd_outb(ahd, CDBLIMIT, SCB_CDB_LEN_PTR - 1); ahd_outb(ahd, MAXCMD, 0xFF); @@ -6215,6 +6570,7 @@ ahd_chip_init(struct ahd_softc *ahd) ahd_outb(ahd, CLRSINT3, NTRAMPERR|OSRAMPERR); ahd_outb(ahd, CLRINT, CLRSCSIINT); +#if NEEDS_MORE_TESTING /* * Always enable abort on incoming L_Qs if this feature is * supported. We use this to catch invalid SCB references. @@ -6222,6 +6578,7 @@ ahd_chip_init(struct ahd_softc *ahd) if ((ahd->bugs & AHD_ABORT_LQI_BUG) == 0) ahd_outb(ahd, LQCTL1, ABORTPENDING); else +#endif ahd_outb(ahd, LQCTL1, 0); /* All of our queues are empty */ @@ -6271,15 +6628,9 @@ ahd_chip_init(struct ahd_softc *ahd) /* * Tell the sequencer where it can find our arrays in memory. */ - busaddr = ahd->shared_data_busaddr; - ahd_outb(ahd, SHARED_DATA_ADDR, busaddr & 0xFF); - ahd_outb(ahd, SHARED_DATA_ADDR + 1, (busaddr >> 8) & 0xFF); - ahd_outb(ahd, SHARED_DATA_ADDR + 2, (busaddr >> 16) & 0xFF); - ahd_outb(ahd, SHARED_DATA_ADDR + 3, (busaddr >> 24) & 0xFF); - ahd_outb(ahd, QOUTFIFO_NEXT_ADDR, busaddr & 0xFF); - ahd_outb(ahd, QOUTFIFO_NEXT_ADDR + 1, (busaddr >> 8) & 0xFF); - ahd_outb(ahd, QOUTFIFO_NEXT_ADDR + 2, (busaddr >> 16) & 0xFF); - ahd_outb(ahd, QOUTFIFO_NEXT_ADDR + 3, (busaddr >> 24) & 0xFF); + busaddr = ahd->shared_data_map.busaddr; + ahd_outl(ahd, SHARED_DATA_ADDR, busaddr); + ahd_outl(ahd, QOUTFIFO_NEXT_ADDR, busaddr); /* * Setup the allowed SCSI Sequences based on operational mode. @@ -6327,11 +6678,8 @@ ahd_chip_init(struct ahd_softc *ahd) /* * Tell the sequencer which SCB will be the next one it receives. */ - busaddr = ahd_le32toh(ahd->next_queued_hscb->hscb_busaddr); - ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 0, busaddr & 0xFF); - ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 1, (busaddr >> 8) & 0xFF); - ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 2, (busaddr >> 16) & 0xFF); - ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF); + busaddr = aic_le32toh(ahd->next_queued_hscb->hscb_busaddr); + ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr); /* * Default to coalescing disabled. @@ -6652,6 +7000,12 @@ ahd_pause_and_flushwork(struct ahd_softc struct scb *waiting_scb; ahd_unpause(ahd); + /* + * Give the sequencer some time to service + * any active selections. + */ + aic_delay(200); + ahd_intr(ahd); ahd_pause(ahd); ahd_clear_critical_section(ahd); @@ -6703,141 +7057,24 @@ ahd_pause_and_flushwork(struct ahd_softc int ahd_suspend(struct ahd_softc *ahd) { -#if 0 - uint8_t *ptr; - int i; ahd_pause_and_flushwork(ahd); - if (LIST_FIRST(&ahd->pending_scbs) != NULL) - return (EBUSY); - -#if AHD_TARGET_MODE - /* - * XXX What about ATIOs that have not yet been serviced? - * Perhaps we should just refuse to be suspended if we - * are acting in a target role. - */ - if (ahd->pending_device != NULL) + if (LIST_FIRST(&ahd->pending_scbs) != NULL) { + ahd_unpause(ahd); return (EBUSY); -#endif - - /* Save volatile registers */ - ahd->suspend_state.channel[0].scsiseq = ahd_inb(ahd, SCSISEQ0); - ahd->suspend_state.channel[0].sxfrctl0 = ahd_inb(ahd, SXFRCTL0); - ahd->suspend_state.channel[0].sxfrctl1 = ahd_inb(ahd, SXFRCTL1); - ahd->suspend_state.channel[0].simode0 = ahd_inb(ahd, SIMODE0); - ahd->suspend_state.channel[0].simode1 = ahd_inb(ahd, SIMODE1); - ahd->suspend_state.channel[0].seltimer = ahd_inb(ahd, SELTIMER); - ahd->suspend_state.channel[0].seqctl = ahd_inb(ahd, SEQCTL0); - ahd->suspend_state.dscommand0 = ahd_inb(ahd, DSCOMMAND0); - ahd->suspend_state.dspcistatus = ahd_inb(ahd, DSPCISTATUS); - - if ((ahd->features & AHD_DT) != 0) { - u_int sfunct; - - sfunct = ahd_inb(ahd, SFUNCT) & ~ALT_MODE; - ahd_outb(ahd, SFUNCT, sfunct | ALT_MODE); - ahd->suspend_state.optionmode = ahd_inb(ahd, OPTIONMODE); - ahd_outb(ahd, SFUNCT, sfunct); - ahd->suspend_state.crccontrol1 = ahd_inb(ahd, CRCCONTROL1); - } - - if ((ahd->features & AHD_MULTI_FUNC) != 0) - ahd->suspend_state.scbbaddr = ahd_inb(ahd, SCBBADDR); - - if ((ahd->features & AHD_ULTRA2) != 0) - ahd->suspend_state.dff_thrsh = ahd_inb(ahd, DFF_THRSH); - - ptr = ahd->suspend_state.scratch_ram; - for (i = 0; i < 64; i++) - *ptr++ = ahd_inb(ahd, SRAM_BASE + i); - - if ((ahd->features & AHD_MORE_SRAM) != 0) { - for (i = 0; i < 16; i++) - *ptr++ = ahd_inb(ahd, TARG_OFFSET + i); - } - - ptr = ahd->suspend_state.btt; - for (i = 0;i < AHD_NUM_TARGETS; i++) { - int j; - - for (j = 0;j < AHD_NUM_LUNS_NONPKT; j++) { - u_int tcl; - - tcl = BUILD_TCL_RAW(i, 'A', j); - *ptr = ahd_find_busy_tcl(ahd, tcl); - } } ahd_shutdown(ahd); -#endif return (0); } int ahd_resume(struct ahd_softc *ahd) { -#if 0 - uint8_t *ptr; - int i; - - ahd_reset(ahd); - - ahd_build_free_scb_list(ahd); - - /* Restore volatile registers */ - ahd_outb(ahd, SCSISEQ0, ahd->suspend_state.channel[0].scsiseq); - ahd_outb(ahd, SXFRCTL0, ahd->suspend_state.channel[0].sxfrctl0); - ahd_outb(ahd, SXFRCTL1, ahd->suspend_state.channel[0].sxfrctl1); - ahd_outb(ahd, SIMODE0, ahd->suspend_state.channel[0].simode0); - ahd_outb(ahd, SIMODE1, ahd->suspend_state.channel[0].simode1); - ahd_outb(ahd, SELTIMER, ahd->suspend_state.channel[0].seltimer); - ahd_outb(ahd, SEQCTL0, ahd->suspend_state.channel[0].seqctl); - if ((ahd->features & AHD_ULTRA2) != 0) - ahd_outb(ahd, SCSIID_ULTRA2, ahd->our_id); - else - ahd_outb(ahd, SCSIID, ahd->our_id); - - ahd_outb(ahd, DSCOMMAND0, ahd->suspend_state.dscommand0); - ahd_outb(ahd, DSPCISTATUS, ahd->suspend_state.dspcistatus); - - if ((ahd->features & AHD_DT) != 0) { - u_int sfunct; - - sfunct = ahd_inb(ahd, SFUNCT) & ~ALT_MODE; - ahd_outb(ahd, SFUNCT, sfunct | ALT_MODE); - ahd_outb(ahd, OPTIONMODE, ahd->suspend_state.optionmode); - ahd_outb(ahd, SFUNCT, sfunct); - ahd_outb(ahd, CRCCONTROL1, ahd->suspend_state.crccontrol1); - } - if ((ahd->features & AHD_MULTI_FUNC) != 0) - ahd_outb(ahd, SCBBADDR, ahd->suspend_state.scbbaddr); - - if ((ahd->features & AHD_ULTRA2) != 0) - ahd_outb(ahd, DFF_THRSH, ahd->suspend_state.dff_thrsh); - - ptr = ahd->suspend_state.scratch_ram; - for (i = 0; i < 64; i++) - ahd_outb(ahd, SRAM_BASE + i, *ptr++); - - if ((ahd->features & AHD_MORE_SRAM) != 0) { - for (i = 0; i < 16; i++) - ahd_outb(ahd, TARG_OFFSET + i, *ptr++); - } - - ptr = ahd->suspend_state.btt; - for (i = 0;i < AHD_NUM_TARGETS; i++) { - int j; - - for (j = 0;j < AHD_NUM_LUNS; j++) { - u_int tcl; - - tcl = BUILD_TCL(i << 4, j); - ahd_busy_tcl(ahd, tcl, *ptr); - } - } -#endif + ahd_reset(ahd, /*reinit*/TRUE); + ahd_intr_enable(ahd, TRUE); + ahd_restart(ahd); return (0); } @@ -6980,11 +7217,8 @@ ahd_qinfifo_requeue(struct ahd_softc *ah if (prev_scb == NULL) { uint32_t busaddr; - busaddr = ahd_le32toh(scb->hscb->hscb_busaddr); - ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 0, busaddr & 0xFF); - ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 1, (busaddr >> 8) & 0xFF); - ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 2, (busaddr >> 16) & 0xFF); - ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF); + busaddr = aic_le32toh(scb->hscb->hscb_busaddr); + ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr); } else { prev_scb->hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr; ahd_sync_scb(ahd, prev_scb, @@ -7090,11 +7324,8 @@ ahd_search_qinfifo(struct ahd_softc *ahd * for removal will be re-added to the queue as we go. */ ahd->qinfifonext = qinstart; - busaddr = ahd_le32toh(ahd->next_queued_hscb->hscb_busaddr); - ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 0, busaddr & 0xFF); - ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 1, (busaddr >> 8) & 0xFF); - ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 2, (busaddr >> 16) & 0xFF); - ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF); + busaddr = aic_le32toh(ahd->next_queued_hscb->hscb_busaddr); + ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr); while (qinpos != qintail) { scb = ahd_lookup_scb(ahd, ahd->qinfifo[qinpos]); @@ -7115,13 +7346,13 @@ ahd_search_qinfifo(struct ahd_softc *ahd cam_status ostat; cam_status cstat; - ostat = ahd_get_transaction_status(scb); + ostat = aic_get_transaction_status(scb); if (ostat == CAM_REQ_INPROG) - ahd_set_transaction_status(scb, + aic_set_transaction_status(scb, status); - cstat = ahd_get_transaction_status(scb); + cstat = aic_get_transaction_status(scb); if (cstat != CAM_REQ_CMP) - ahd_freeze_scb(scb); + aic_freeze_scb(scb); if ((scb->flags & SCB_ACTIVE) == 0) printf("Inactive SCB in qinfifo\n"); ahd_done(ahd, scb); @@ -7257,12 +7488,12 @@ ahd_search_scb_list(struct ahd_softc *ah cam_status ostat; cam_status cstat; - ostat = ahd_get_transaction_status(scb); + ostat = aic_get_transaction_status(scb); if (ostat == CAM_REQ_INPROG) - ahd_set_transaction_status(scb, status); - cstat = ahd_get_transaction_status(scb); + aic_set_transaction_status(scb, status); + cstat = aic_get_transaction_status(scb); if (cstat != CAM_REQ_CMP) - ahd_freeze_scb(scb); + aic_freeze_scb(scb); if ((scb->flags & SCB_ACTIVE) == 0) printf("Inactive SCB in Waiting List\n"); ahd_done(ahd, scb); @@ -7453,11 +7684,11 @@ ahd_abort_scbs(struct ahd_softc *ahd, in if (ahd_match_scb(ahd, scbp, target, channel, lun, tag, role)) { cam_status ostat; - ostat = ahd_get_transaction_status(scbp); + ostat = aic_get_transaction_status(scbp); if (ostat == CAM_REQ_INPROG) - ahd_set_transaction_status(scbp, status); - if (ahd_get_transaction_status(scbp) != CAM_REQ_CMP) - ahd_freeze_scb(scbp); + aic_set_transaction_status(scbp, status); + if (aic_get_transaction_status(scbp) != CAM_REQ_CMP) + aic_freeze_scb(scbp); if ((scbp->flags & SCB_ACTIVE) == 0) printf("Inactive SCB on pending list\n"); ahd_done(ahd, scbp); @@ -7479,9 +7710,12 @@ ahd_reset_current_bus(struct ahd_softc * ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) & ~ENSCSIRST); scsiseq = ahd_inb(ahd, SCSISEQ0) & ~(ENSELO|ENARBO|SCSIRSTO); ahd_outb(ahd, SCSISEQ0, scsiseq | SCSIRSTO); - ahd_delay(AHD_BUSRESET_DELAY); + ahd_flush_device_writes(ahd); + aic_delay(AHD_BUSRESET_DELAY); /* Turn off the bus reset */ ahd_outb(ahd, SCSISEQ0, scsiseq); + ahd_flush_device_writes(ahd); + aic_delay(AHD_BUSRESET_DELAY); if ((ahd->bugs & AHD_SCSIRST_BUG) != 0) { /* * 2A Razor #474 @@ -7489,8 +7723,7 @@ ahd_reset_current_bus(struct ahd_softc * * SCSI bus resets that we initiate, so * we must reset the chip. */ - ahd_delay(AHD_BUSRESET_DELAY); - ahd_reset(ahd); + ahd_reset(ahd, /*reinit*/TRUE); ahd_intr_enable(ahd, /*enable*/TRUE); AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); } @@ -7550,7 +7783,7 @@ ahd_reset_channel(struct ahd_softc *ahd, ahd_outb(ahd, DFCNTRL, ahd_inb(ahd, DFCNTRL) & ~(SCSIEN|HDMAEN)); while ((ahd_inb(ahd, DFCNTRL) & HDMAENACK) != 0) - ahd_delay(10); + aic_delay(10); /* * Set CURRFIFO to the now inactive channel. */ @@ -7563,7 +7796,7 @@ ahd_reset_channel(struct ahd_softc *ahd, */ ahd_clear_msg_state(ahd); ahd_outb(ahd, SIMODE1, - ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST|ENBUSFREE)); + ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST)); if (initiate_reset) ahd_reset_current_bus(ahd); @@ -7645,8 +7878,8 @@ ahd_reset_channel(struct ahd_softc *ahd, */ if ((ahd->flags & AHD_RESET_POLL_ACTIVE) == 0) { ahd->flags |= AHD_RESET_POLL_ACTIVE; - ahd_freeze_simq(ahd); - ahd_timer_reset(&ahd->reset_timer, 0, ahd_reset_poll, ahd); + aic_freeze_simq(ahd); + aic_timer_reset(&ahd->reset_timer, 0, ahd_reset_poll, ahd); } return (found); } @@ -7674,7 +7907,7 @@ ahd_reset_poll(void *arg) ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); if ((ahd_inb(ahd, SSTAT1) & SCSIRSTI) != 0) { - ahd_timer_reset(&ahd->reset_timer, AHD_RESET_POLL_US, + aic_timer_reset(&ahd->reset_timer, AHD_RESET_POLL_US, ahd_reset_poll, ahd); ahd_unpause(ahd); ahd_unlock(ahd, &s); @@ -7689,7 +7922,7 @@ ahd_reset_poll(void *arg) ahd_unpause(ahd); ahd->flags &= ~AHD_RESET_POLL_ACTIVE; ahd_unlock(ahd, &s); - ahd_release_simq(ahd); + aic_release_simq(ahd); ahd_list_unlock(&l); } @@ -7732,7 +7965,7 @@ ahd_stat_timer(void *arg) ahd->cmdcmplt_bucket = (ahd->cmdcmplt_bucket+1) & (AHD_STAT_BUCKETS-1); ahd->cmdcmplt_total -= ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]; ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket] = 0; - ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US, + aic_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US, ahd_stat_timer, ahd); ahd_unlock(ahd, &s); ahd_list_unlock(&l); @@ -7753,8 +7986,9 @@ ahd_handle_scb_status(struct ahd_softc * void ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) { - struct hardware_scb *hscb; - u_int qfreeze_cnt; + struct hardware_scb *hscb; + u_int qfreeze_cnt; + int paused; /* * The sequencer freezes its select-out queue @@ -7764,9 +7998,16 @@ ahd_handle_scsi_status(struct ahd_softc */ hscb = scb->hscb; + if (ahd_is_paused(ahd)) { + paused = 1; + } else { + paused = 0; + ahd_pause(ahd); + } + /* Freeze the queue until the client sees the error. */ ahd_freeze_devq(ahd, scb); - ahd_freeze_scb(scb); + aic_freeze_scb(scb); qfreeze_cnt = ahd_inw(ahd, QFREEZE_COUNT); if (qfreeze_cnt == 0) { printf("%s: Bad status with 0 qfreeze count!\n", ahd_name(ahd)); @@ -7778,6 +8019,9 @@ ahd_handle_scsi_status(struct ahd_softc ahd_outb(ahd, SEQ_FLAGS2, ahd_inb(ahd, SEQ_FLAGS2) & ~SELECTOUT_QFROZEN); + if (paused == 0) + ahd_unpause(ahd); + /* Don't want to clobber the original sense code */ if ((scb->flags & SCB_SENSE) != 0) { /* @@ -7785,12 +8029,12 @@ ahd_handle_scsi_status(struct ahd_softc * a normal command completion. */ scb->flags &= ~SCB_SENSE; - ahd_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); + aic_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); ahd_done(ahd, scb); return; } - ahd_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR); - ahd_set_scsi_status(scb, hscb->shared_data.istatus.scsi_status); + aic_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR); + aic_set_scsi_status(scb, hscb->shared_data.istatus.scsi_status); switch (hscb->shared_data.istatus.scsi_status) { case STATUS_PKT_SENSE: { @@ -7798,7 +8042,7 @@ ahd_handle_scsi_status(struct ahd_softc ahd_sync_sense(ahd, scb, BUS_DMASYNC_POSTREAD); siu = (struct scsi_status_iu_header *)scb->sense_data; - ahd_set_scsi_status(scb, siu->status); + aic_set_scsi_status(scb, siu->status); #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_SENSE) != 0) { ahd_print_path(ahd, scb); @@ -7839,7 +8083,7 @@ ahd_handle_scsi_status(struct ahd_softc } } if (siu->status == SCSI_STATUS_OK) - ahd_set_transaction_status(scb, + aic_set_transaction_status(scb, CAM_REQ_CMP_ERR); } if ((siu->flags & SIU_SNSVALID) != 0) { @@ -7869,7 +8113,7 @@ ahd_handle_scsi_status(struct ahd_softc } #endif - if (ahd_perform_autosense(scb) == 0) + if (aic_perform_autosense(scb) == 0) break; ahd_compile_devinfo(&devinfo, SCB_GET_OUR_ID(scb), @@ -7897,7 +8141,7 @@ ahd_handle_scsi_status(struct ahd_softc #endif scb->sg_count = 0; sg = ahd_sg_setup(ahd, scb, sg, ahd_get_sense_bufaddr(ahd, scb), - ahd_get_sense_bufsize(ahd, scb), + aic_get_sense_bufsize(ahd, scb), /*last*/TRUE); sc->opcode = REQUEST_SENSE; sc->byte2 = 0; @@ -7906,7 +8150,7 @@ ahd_handle_scsi_status(struct ahd_softc sc->byte2 = SCB_GET_LUN(scb) << 5; sc->unused[0] = 0; sc->unused[1] = 0; - sc->length = ahd_get_sense_bufsize(ahd, scb); + sc->length = aic_get_sense_bufsize(ahd, scb); sc->control = 0; /* @@ -7926,7 +8170,7 @@ ahd_handle_scsi_status(struct ahd_softc * errors will be reported before any data * phases occur. */ - if (ahd_get_residual(scb) == ahd_get_transfer_length(scb)) { + if (aic_get_residual(scb) == aic_get_transfer_length(scb)) { ahd_update_neg_request(ahd, &devinfo, tstate, targ_info, AHD_NEG_IF_NON_ASYNC); @@ -7945,7 +8189,7 @@ ahd_handle_scsi_status(struct ahd_softc * Ensure we have enough time to actually * retrieve the sense. */ - ahd_scb_timer_reset(scb, 5 * 1000000); + aic_scb_timer_reset(scb, 5 * 1000000); break; } case SCSI_STATUS_OK: @@ -7987,7 +8231,7 @@ ahd_calc_residual(struct ahd_softc *ahd, */ hscb = scb->hscb; - sgptr = ahd_le32toh(hscb->sgptr); + sgptr = aic_le32toh(hscb->sgptr); if ((sgptr & SG_STATUS_VALID) == 0) /* Case 1 */ return; @@ -8004,10 +8248,10 @@ ahd_calc_residual(struct ahd_softc *ahd, * regardless of the role for this SCB. */ spkt = &hscb->shared_data.istatus; - resid_sgptr = ahd_le32toh(spkt->residual_sgptr); + resid_sgptr = aic_le32toh(spkt->residual_sgptr); if ((sgptr & SG_FULL_RESID) != 0) { /* Case 3 */ - resid = ahd_get_transfer_length(scb); + resid = aic_get_transfer_length(scb); } else if ((resid_sgptr & SG_LIST_NULL) != 0) { /* Case 4 */ return; @@ -8016,8 +8260,8 @@ ahd_calc_residual(struct ahd_softc *ahd, printf("data overrun detected Tag == 0x%x.\n", SCB_GET_TAG(scb)); ahd_freeze_devq(ahd, scb); - ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR); - ahd_freeze_scb(scb); + aic_set_transaction_status(scb, CAM_DATA_RUN_ERR); + aic_freeze_scb(scb); return; } else if ((resid_sgptr & ~SG_PTR_MASK) != 0) { panic("Bogus resid sgptr value 0x%x\n", resid_sgptr); @@ -8029,7 +8273,7 @@ ahd_calc_residual(struct ahd_softc *ahd, * Remainder of the SG where the transfer * stopped. */ - resid = ahd_le32toh(spkt->residual_datacnt) & AHD_SG_LEN_MASK; + resid = aic_le32toh(spkt->residual_datacnt) & AHD_SG_LEN_MASK; sg = ahd_sg_bus_to_virt(ahd, scb, resid_sgptr & SG_PTR_MASK); /* The residual sg_ptr always points to the next sg */ @@ -8040,15 +8284,15 @@ ahd_calc_residual(struct ahd_softc *ahd, * SG segments that are after the SG where * the transfer stopped. */ - while ((ahd_le32toh(sg->len) & AHD_DMA_LAST_SEG) == 0) { + while ((aic_le32toh(sg->len) & AHD_DMA_LAST_SEG) == 0) { sg++; - resid += ahd_le32toh(sg->len) & AHD_SG_LEN_MASK; + resid += aic_le32toh(sg->len) & AHD_SG_LEN_MASK; } } if ((scb->flags & SCB_SENSE) == 0) - ahd_set_residual(scb, resid); + aic_set_residual(scb, resid); else - ahd_set_sense_residual(scb, resid); + aic_set_sense_residual(scb, resid); #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) { @@ -8160,8 +8404,7 @@ ahd_dumpseq(struct ahd_softc* ahd) max_prog = 2048; ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); - ahd_outb(ahd, PRGMCNT, 0); - ahd_outb(ahd, PRGMCNT+1, 0); + ahd_outw(ahd, PRGMCNT, 0); for (i = 0; i < max_prog; i++) { uint8_t ins_bytes[4]; @@ -8276,8 +8519,7 @@ ahd_loadseq(struct ahd_softc *ahd) downloaded = 0; skip_addr = 0; ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); - ahd_outb(ahd, PRGMCNT, 0); - ahd_outb(ahd, PRGMCNT+1, 0); + ahd_outw(ahd, PRGMCNT, 0); for (i = 0; i < sizeof(seqprog)/4; i++) { if (ahd_check_patch(ahd, &cur_patch, i, &skip_addr) == 0) { @@ -8406,7 +8648,7 @@ ahd_download_instr(struct ahd_softc *ahd /* * The firmware is always compiled into a little endian format. */ - instr.integer = ahd_le32toh(*(uint32_t*)&seqprog[instrptr * 4]); + instr.integer = aic_le32toh(*(uint32_t*)&seqprog[instrptr * 4]); fmt1_ins = &instr.format1; fmt3_ins = NULL; @@ -8454,7 +8696,7 @@ ahd_download_instr(struct ahd_softc *ahd instr.format1.parity = 1; /* The sequencer is a little endian cpu */ - instr.integer = ahd_htole32(instr.integer); + instr.integer = aic_htole32(instr.integer); ahd_outsb(ahd, SEQRAM, instr.bytes, 4); break; } @@ -8580,11 +8822,15 @@ ahd_dump_card_state(struct ahd_softc *ah printf(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n" "%s: Dumping Card State at program address 0x%x Mode 0x%x\n", ahd_name(ahd), - ahd_inb(ahd, CURADDR) | (ahd_inb(ahd, CURADDR+1) << 8), + ahd_inw(ahd, CURADDR), ahd_build_mode_state(ahd, ahd->saved_src_mode, ahd->saved_dst_mode)); if (paused) printf("Card was paused\n"); + + if (ahd_check_cmdcmpltqueues(ahd)) + printf("Completions are pending\n"); + /* * Mode independent registers. */ @@ -8634,10 +8880,12 @@ ahd_dump_card_state(struct ahd_softc *ah if (i++ > AHD_SCB_MAX) break; cur_col = printf("\n%3d FIFO_USE[0x%x] ", SCB_GET_TAG(scb), - ahd_inb(ahd, SCB_FIFO_USE_COUNT)); + ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT)); ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); - ahd_scb_control_print(ahd_inb(ahd, SCB_CONTROL), &cur_col, 60); - ahd_scb_scsiid_print(ahd_inb(ahd, SCB_SCSIID), &cur_col, 60); + ahd_scb_control_print(ahd_inb_scbram(ahd, SCB_CONTROL), + &cur_col, 60); + ahd_scb_scsiid_print(ahd_inb_scbram(ahd, SCB_SCSIID), + &cur_col, 60); } printf("\nTotal %d\n", i); @@ -8666,7 +8914,7 @@ ahd_dump_card_state(struct ahd_softc *ah while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { ahd_set_scbptr(ahd, scb_index); printf("%d ", scb_index); - scb_index = ahd_inw(ahd, SCB_NEXT_COMPLETE); + scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); } printf("\n"); @@ -8676,7 +8924,7 @@ ahd_dump_card_state(struct ahd_softc *ah while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { ahd_set_scbptr(ahd, scb_index); printf("%d ", scb_index); - scb_index = ahd_inw(ahd, SCB_NEXT_COMPLETE); + scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); } printf("\n"); @@ -8687,7 +8935,7 @@ ahd_dump_card_state(struct ahd_softc *ah while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { ahd_set_scbptr(ahd, scb_index); printf("%d ", scb_index); - scb_index = ahd_inw(ahd, SCB_NEXT_COMPLETE); + scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); } printf("\n"); ahd_set_scbptr(ahd, saved_scb_index); @@ -8766,15 +9014,16 @@ ahd_dump_card_state(struct ahd_softc *ah ahd_name(ahd), ahd_inw(ahd, REG0), ahd_inw(ahd, SINDEX), ahd_inw(ahd, DINDEX)); printf("%s: SCBPTR == 0x%x, SCB_NEXT == 0x%x, SCB_NEXT2 == 0x%x\n", - ahd_name(ahd), ahd_get_scbptr(ahd), ahd_inw(ahd, SCB_NEXT), - ahd_inw(ahd, SCB_NEXT2)); + ahd_name(ahd), ahd_get_scbptr(ahd), + ahd_inw_scbram(ahd, SCB_NEXT), + ahd_inw_scbram(ahd, SCB_NEXT2)); printf("CDB %x %x %x %x %x %x\n", - ahd_inb(ahd, SCB_CDB_STORE), - ahd_inb(ahd, SCB_CDB_STORE+1), - ahd_inb(ahd, SCB_CDB_STORE+2), - ahd_inb(ahd, SCB_CDB_STORE+3), - ahd_inb(ahd, SCB_CDB_STORE+4), - ahd_inb(ahd, SCB_CDB_STORE+5)); + ahd_inb_scbram(ahd, SCB_CDB_STORE), + ahd_inb_scbram(ahd, SCB_CDB_STORE+1), + ahd_inb_scbram(ahd, SCB_CDB_STORE+2), + ahd_inb_scbram(ahd, SCB_CDB_STORE+3), + ahd_inb_scbram(ahd, SCB_CDB_STORE+4), + ahd_inb_scbram(ahd, SCB_CDB_STORE+5)); printf("STACK:"); for (i = 0; i < ahd->stack_size; i++) { ahd->saved_stack[i] = @@ -8806,16 +9055,292 @@ ahd_dump_scbs(struct ahd_softc *ahd) ahd_set_scbptr(ahd, i); printf("%3d", i); printf("(CTRL 0x%x ID 0x%x N 0x%x N2 0x%x SG 0x%x, RSG 0x%x)\n", - ahd_inb(ahd, SCB_CONTROL), - ahd_inb(ahd, SCB_SCSIID), ahd_inw(ahd, SCB_NEXT), - ahd_inw(ahd, SCB_NEXT2), ahd_inl(ahd, SCB_SGPTR), - ahd_inl(ahd, SCB_RESIDUAL_SGPTR)); + ahd_inb_scbram(ahd, SCB_CONTROL), + ahd_inb_scbram(ahd, SCB_SCSIID), + ahd_inw_scbram(ahd, SCB_NEXT), + ahd_inw_scbram(ahd, SCB_NEXT2), + ahd_inl_scbram(ahd, SCB_SGPTR), + ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR)); } printf("\n"); ahd_set_scbptr(ahd, saved_scb_index); ahd_restore_modes(ahd, saved_modes); } + +/*************************** Timeout Handling *********************************/ +void +ahd_timeout(struct scb *scb) +{ + struct ahd_softc *ahd; + + ahd = scb->ahd_softc; + if ((scb->flags & SCB_ACTIVE) != 0) { + if ((scb->flags & SCB_TIMEDOUT) == 0) { + LIST_INSERT_HEAD(&ahd->timedout_scbs, scb, + timedout_links); + scb->flags |= SCB_TIMEDOUT; + } + ahd_wakeup_recovery_thread(ahd); + } +} + +/* + * ahd_recover_commands determines if any of the commands that have currently + * timedout are the root cause for this timeout. Innocent commands are given + * a new timeout while we wait for the command executing on the bus to timeout. + * This routine is invoked from a thread context so we are allowed to sleep. + * Our lock is not held on entry. + */ +void +ahd_recover_commands(struct ahd_softc *ahd) +{ + struct scb *scb; + struct scb *active_scb; + long s; + int found; + int was_paused; + u_int active_scbptr; + u_int last_phase; + + ahd_lock(ahd, &s); + + /* + * Pause the controller and manually flush any + * commands that have just completed but that our + * interrupt handler has yet to see. + */ + was_paused = ahd_is_paused(ahd); + ahd_pause_and_flushwork(ahd); + + if (LIST_EMPTY(&ahd->timedout_scbs) != 0) { + /* + * The timedout commands have already + * completed. This typically means + * that either the timeout value was on + * the hairy edge of what the device + * requires or - more likely - interrupts + * are not happening. + */ + printf("%s: Timedout SCBs already complete. " + "Interrupts may not be functioning.\n", ahd_name(ahd)); + ahd_unpause(ahd); + ahd_unlock(ahd, &s); + return; + } + + printf("%s: Recovery Initiated - Card was %spaused\n", ahd_name(ahd), + was_paused ? "" : "not "); + ahd_dump_card_state(ahd); + + /* + * Determine identity of SCB acting on the bus. + * This test only catches non-packetized transactions. + * Due to the fleeting nature of packetized operations, + * we can't easily determine that a packetized operation + * is on the bus. + */ + ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); + last_phase = ahd_inb(ahd, LASTPHASE); + active_scbptr = ahd_get_scbptr(ahd); + active_scb = NULL; + if (last_phase != P_BUSFREE + || (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) + active_scb = ahd_lookup_scb(ahd, active_scbptr); + + while ((scb = LIST_FIRST(&ahd->timedout_scbs)) != NULL) { + int target; + int lun; + char channel; + + target = SCB_GET_TARGET(ahd, scb); + channel = SCB_GET_CHANNEL(ahd, scb); + lun = SCB_GET_LUN(scb); + + ahd_print_path(ahd, scb); + printf("SCB 0x%x - timed out\n", scb->hscb->tag); + + if (scb->flags & (SCB_DEVICE_RESET|SCB_ABORT)) { + /* + * Been down this road before. + * Do a full bus reset. + */ + aic_set_transaction_status(scb, CAM_CMD_TIMEOUT); +bus_reset: + found = ahd_reset_channel(ahd, channel, + /*Initiate Reset*/TRUE); + printf("%s: Issued Channel %c Bus Reset. " + "%d SCBs aborted\n", ahd_name(ahd), channel, + found); + continue; + } + + /* + * Remove the command from the timedout list in + * preparation for requeing it. + */ + LIST_REMOVE(scb, timedout_links); + scb->flags &= ~SCB_TIMEDOUT; + + if (active_scb != NULL) { + + if (active_scb != scb) { + /* + * If the active SCB is not us, assume that + * the active SCB has a longer timeout than + * the timedout SCB, and wait for the active + * SCB to timeout. + */ + ahd_other_scb_timeout(ahd, scb, active_scb); + continue; + } + + /* + * We're active on the bus, so assert ATN + * and hope that the target responds. + */ + ahd_set_recoveryscb(ahd, active_scb); + active_scb->flags |= SCB_RECOVERY_SCB|SCB_DEVICE_RESET; + ahd_outb(ahd, MSG_OUT, HOST_MSG); + ahd_outb(ahd, SCSISIGO, last_phase|ATNO); + ahd_print_path(ahd, active_scb); + printf("BDR message in message buffer\n"); + aic_scb_timer_reset(scb, 2 * 1000000); + break; + } else if (last_phase != P_BUSFREE + && ahd_inb(ahd, SCSIPHASE) == 0) { + /* + * SCB is not identified, there + * is no pending REQ, and the sequencer + * has not seen a busfree. Looks like + * a stuck connection waiting to + * go busfree. Reset the bus. + */ + printf("%s: Connection stuck awaiting busfree or " + "Identify Msg.\n", ahd_name(ahd)); + goto bus_reset; + } else if (ahd_search_qinfifo(ahd, target, channel, lun, + scb->hscb->tag, ROLE_INITIATOR, + /*status*/0, SEARCH_COUNT) > 0) { + + /* + * We haven't even gone out on the bus + * yet, so the timeout must be due to + * some other command. Reset the timer + * and go on. + */ + ahd_other_scb_timeout(ahd, scb, scb); + } else { + /* + * This SCB is for a disconnected transaction + * and we haven't found a better candidate on + * the bus to explain this timeout. + */ + ahd_set_recoveryscb(ahd, scb); + + /* + * Actually re-queue this SCB in an attempt + * to select the device before it reconnects. + * In either case (selection or reselection), + * we will now issue a target reset to the + * timed-out device. + * + * Set the MK_MESSAGE control bit indicating + * that we desire to send a message. We + * also set the disconnected flag since + * in the paging case there is no guarantee + * that our SCB control byte matches the + * version on the card. We don't want the + * sequencer to abort the command thinking + * an unsolicited reselection occurred. + */ + scb->flags |= SCB_DEVICE_RESET; + scb->hscb->cdb_len = 0; + scb->hscb->task_attribute = 0; + scb->hscb->task_management = SIU_TASKMGMT_ABORT_TASK; + + ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); + if ((scb->flags & SCB_PACKETIZED) != 0) { + /* + * Mark the SCB has having an outstanding + * task management function. Should the command + * complete normally before the task management + * function can be sent, the host will be + * notified to abort our requeued SCB. + */ + ahd_outb(ahd, SCB_TASK_MANAGEMENT, + scb->hscb->task_management); + } else { + /* + * If non-packetized, set the MK_MESSAGE control + * bit indicating that we desire to send a + * message. We also set the disconnected flag + * since there is no guarantee that our SCB + * control byte matches the version on the + * card. We don't want the sequencer to abort + * the command thinking an unsolicited + * reselection occurred. + */ + scb->hscb->control |= MK_MESSAGE|DISCONNECTED; + + /* + * The sequencer will never re-reference the + * in-core SCB. To make sure we are notified + * during reslection, set the MK_MESSAGE flag in + * the card's copy of the SCB. + */ + ahd_outb(ahd, SCB_CONTROL, + ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE); + } + + /* + * Clear out any entries in the QINFIFO first + * so we are the next SCB for this target + * to run. + */ + ahd_search_qinfifo(ahd, target, channel, lun, + SCB_LIST_NULL, ROLE_INITIATOR, + CAM_REQUEUE_REQ, SEARCH_COMPLETE); + ahd_qinfifo_requeue_tail(ahd, scb); + ahd_set_scbptr(ahd, active_scbptr); + ahd_print_path(ahd, scb); + printf("Queuing a BDR SCB\n"); + aic_scb_timer_reset(scb, 2 * 1000000); + break; + } + } + + /* + * Any remaining SCBs were not the "culprit", so remove + * them from the timeout list. The timer for these commands + * will be reset once the recovery SCB completes. + */ + while ((scb = LIST_FIRST(&ahd->timedout_scbs)) != NULL) { + + LIST_REMOVE(scb, timedout_links); + scb->flags &= ~SCB_TIMEDOUT; + } + + ahd_unpause(ahd); + ahd_unlock(ahd, &s); +} + +static void +ahd_other_scb_timeout(struct ahd_softc *ahd, struct scb *scb, + struct scb *other_scb) +{ + u_int newtimeout; + + ahd_print_path(ahd, scb); + printf("Other SCB Timeout%s", + (scb->flags & SCB_OTHERTCL_TIMEOUT) != 0 + ? " again\n" : "\n"); + scb->flags |= SCB_OTHERTCL_TIMEOUT; + newtimeout = MAX(aic_get_timeout(other_scb), + aic_get_timeout(scb)); + aic_scb_timer_reset(scb, newtimeout); +} + /**************************** Flexport Logic **********************************/ /* * Read count 16bit words from 16bit word address start_addr from the @@ -8922,9 +9447,9 @@ ahd_wait_seeprom(struct ahd_softc *ahd) { int cnt; - cnt = 20; + cnt = 5000; while ((ahd_inb(ahd, SEESTAT) & (SEEARBACK|SEEBUSY)) != 0 && --cnt) - ahd_delay(5); + aic_delay(5); if (cnt == 0) return (ETIMEDOUT); @@ -9066,7 +9591,7 @@ ahd_wait_flexport(struct ahd_softc *ahd) AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); cnt = 1000000 * 2 / 5; while ((ahd_inb(ahd, BRDCTL) & FLXARBACK) == 0 && --cnt) - ahd_delay(5); + aic_delay(5); if (cnt == 0) return (ETIMEDOUT); @@ -9192,6 +9717,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, ahd->flags &= ~AHD_INITIATORROLE; ahd_pause(ahd); ahd_loadseq(ahd); + ahd_restart(ahd); ahd_unlock(ahd, &s); } cel = &ccb->cel; @@ -9267,13 +9793,9 @@ ahd_handle_en_lun(struct ahd_softc *ahd, if ((ahd->features & AHD_MULTI_TID) != 0) { u_int targid_mask; - targid_mask = ahd_inb(ahd, TARGID) - | (ahd_inb(ahd, TARGID + 1) << 8); - + targid_mask = ahd_inw(ahd, TARGID); targid_mask |= target_mask; - ahd_outb(ahd, TARGID, targid_mask); - ahd_outb(ahd, TARGID+1, (targid_mask >> 8)); - + ahd_outw(ahd, TARGID, targid_mask); ahd_update_scsiid(ahd, targid_mask); } else { u_int our_id; @@ -9387,14 +9909,9 @@ ahd_handle_en_lun(struct ahd_softc *ahd, if (ahd->features & AHD_MULTI_TID) { u_int targid_mask; - targid_mask = ahd_inb(ahd, TARGID) - | (ahd_inb(ahd, TARGID + 1) - << 8); - + targid_mask = ahd_inw(ahd, TARGID); targid_mask &= ~target_mask; - ahd_outb(ahd, TARGID, targid_mask); - ahd_outb(ahd, TARGID+1, - (targid_mask >> 8)); + ahd_outw(ahd, TARGID, targid_mask); ahd_update_scsiid(ahd, targid_mask); } } @@ -9425,6 +9942,11 @@ ahd_handle_en_lun(struct ahd_softc *ahd, ahd->flags |= AHD_INITIATORROLE; ahd_pause(ahd); ahd_loadseq(ahd); + ahd_restart(ahd); + /* + * Unpaused. The extra unpause + * that follows is harmless. + */ } } ahd_unpause(ahd); diff -puN drivers/scsi/aic7xxx/aic79xx.h~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic79xx.h --- 25/drivers/scsi/aic7xxx/aic79xx.h~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic79xx.h Wed Dec 24 12:15:38 2003 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#90 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#101 $ * * $FreeBSD$ */ @@ -74,9 +74,9 @@ struct scb_platform_data; #define ALL_TARGETS_MASK 0xFFFF #define INITIATOR_WILDCARD (~0) #define SCB_LIST_NULL 0xFF00 -#define SCB_LIST_NULL_LE (ahd_htole16(SCB_LIST_NULL)) +#define SCB_LIST_NULL_LE (aic_htole16(SCB_LIST_NULL)) #define QOUTFIFO_ENTRY_VALID 0x8000 -#define QOUTFIFO_ENTRY_VALID_LE (ahd_htole16(0x8000)) +#define QOUTFIFO_ENTRY_VALID_LE (aic_htole16(0x8000)) #define SCBID_IS_NULL(scbid) (((scbid) & 0xFF00 ) == SCB_LIST_NULL) #define SCSIID_TARGET(ahd, scsiid) \ @@ -118,7 +118,7 @@ struct scb_platform_data; ((lun) | ((target) << 8)) #define SCB_GET_TAG(scb) \ - ahd_le16toh(scb->hscb->tag) + aic_le16toh(scb->hscb->tag) #ifndef AHD_TARGET_MODE #undef AHD_TMODE_ENABLE @@ -229,8 +229,10 @@ typedef enum { AHD_RTI = 0x04000,/* Retained Training Support */ AHD_NEW_IOCELL_OPTS = 0x08000,/* More Signal knobs in the IOCELL */ AHD_NEW_DFCNTRL_OPTS = 0x10000,/* SCSIENWRDIS bit */ + AHD_FAST_CDB_DELIVERY = 0x20000,/* CDB acks released to Output Sync */ AHD_REMOVABLE = 0x00000,/* Hot-Swap supported - None so far*/ AHD_AIC7901_FE = AHD_FENONE, + AHD_AIC7901A_FE = AHD_FENONE, AHD_AIC7902_FE = AHD_MULTI_FUNC } ahd_feature; @@ -372,7 +374,9 @@ typedef enum { AHD_HP_BOARD = 0x100000, AHD_RESET_POLL_ACTIVE = 0x200000, AHD_UPDATE_PEND_CMDS = 0x400000, - AHD_RUNNING_QOUTFIFO = 0x800000 + AHD_RUNNING_QOUTFIFO = 0x800000, + AHD_HAD_FIRST_SEL = 0x1000000, + AHD_SHUTDOWN_RECOVERY = 0x2000000 /* Terminate recovery thread. */ } ahd_flag; /************************* Hardware SCB Definition ***************************/ @@ -494,21 +498,21 @@ struct hardware_scb { * transfer. */ #define SG_PTR_MASK 0xFFFFFFF8 -/*16*/ uint64_t dataptr; -/*24*/ uint32_t datacnt; /* Byte 3 is spare. */ -/*28*/ uint32_t sgptr; -/*32*/ uint32_t hscb_busaddr; -/*36*/ uint32_t next_hscb_busaddr; -/*40*/ uint8_t control; /* See SCB_CONTROL in aic79xx.reg for details */ -/*41*/ uint8_t scsiid; /* +/*16*/ uint16_t tag; /* Reused by Sequencer. */ +/*18*/ uint8_t control; /* See SCB_CONTROL in aic79xx.reg for details */ +/*19*/ uint8_t scsiid; /* * Selection out Id * Our Id (bits 0-3) Their ID (bits 4-7) */ -/*42*/ uint8_t lun; -/*43*/ uint8_t task_attribute; -/*44*/ uint8_t cdb_len; -/*45*/ uint8_t task_management; -/*46*/ uint16_t tag; /* Reused by Sequencer. */ +/*20*/ uint8_t lun; +/*21*/ uint8_t task_attribute; +/*22*/ uint8_t cdb_len; +/*23*/ uint8_t task_management; +/*24*/ uint64_t dataptr; +/*32*/ uint32_t datacnt; /* Byte 3 is spare. */ +/*36*/ uint32_t sgptr; +/*40*/ uint32_t hscb_busaddr; +/*44*/ uint32_t next_hscb_busaddr; /********** Long lun field only downloaded for full 8 byte lun support ********/ /*48*/ uint8_t pkt_long_lun[8]; /******* Fields below are not Downloaded (Sequencer may use for scratch) ******/ @@ -546,7 +550,7 @@ struct ahd_dma64_seg { struct map_node { bus_dmamap_t dmamap; - bus_addr_t physaddr; + bus_addr_t busaddr; uint8_t *vaddr; SLIST_ENTRY(map_node) links; }; @@ -588,12 +592,16 @@ typedef enum { SCB_PKT_SENSE = 0x02000, SCB_CMDPHASE_ABORT = 0x04000, SCB_ON_COL_LIST = 0x08000, - SCB_SILENT = 0x10000 /* + SCB_SILENT = 0x10000,/* * Be quiet about transmission type * errors. They are expected and we * don't want to upset the user. This * flag is typically used during DV. */ + SCB_TIMEDOUT = 0x20000/* + * SCB has timed out and is on the + * timedout list. + */ } scb_flag; struct scb { @@ -610,8 +618,9 @@ struct scb { } links2; #define pending_links links2.le #define collision_links links2.le + LIST_ENTRY(scb) timedout_links; struct scb *col_scb; - ahd_io_ctx_t io_ctx; + aic_io_ctx_t io_ctx; struct ahd_softc *ahd_softc; scb_flag flags; #ifndef __linux__ @@ -1059,6 +1068,7 @@ struct ahd_softc { struct scb_data scb_data; struct hardware_scb *next_queued_hscb; + struct map_node *next_queued_hscb_map; /* * SCBs that have been sent to the controller @@ -1066,6 +1076,11 @@ struct ahd_softc { LIST_HEAD(, scb) pending_scbs; /* + * SCBs whose timeout routine has been called. + */ + LIST_HEAD(, scb) timedout_scbs; + + /* * Current register window mode information. */ ahd_mode dst_mode; @@ -1086,7 +1101,7 @@ struct ahd_softc { /* * Platform specific device information. */ - ahd_dev_softc_t dev_softc; + aic_dev_softc_t dev_softc; /* * Bus specific device information. @@ -1116,8 +1131,8 @@ struct ahd_softc { /* * Timer handles for timer driven callbacks. */ - ahd_timer_t reset_timer; - ahd_timer_t stat_timer; + aic_timer_t reset_timer; + aic_timer_t stat_timer; /* * Statistics. @@ -1194,8 +1209,7 @@ struct ahd_softc { */ bus_dma_tag_t parent_dmat; bus_dma_tag_t shared_data_dmat; - bus_dmamap_t shared_data_dmamap; - bus_addr_t shared_data_busaddr; + struct map_node shared_data_map; /* Information saved through suspend/resume cycles */ struct ahd_suspend_state suspend_state; @@ -1296,9 +1310,9 @@ struct ahd_devinfo { }; /****************************** PCI Structures ********************************/ -#define AHD_PCI_IOADDR0 PCIR_MAPS /* I/O BAR*/ -#define AHD_PCI_MEMADDR (PCIR_MAPS + 4) /* Memory BAR */ -#define AHD_PCI_IOADDR1 (PCIR_MAPS + 12)/* Second I/O BAR */ +#define AHD_PCI_IOADDR0 PCIR_BAR(0) /* I/O BAR*/ +#define AHD_PCI_MEMADDR PCIR_BAR(1) /* Memory BAR */ +#define AHD_PCI_IOADDR1 PCIR_BAR(3) /* Second I/O BAR */ typedef int (ahd_device_setup_t)(struct ahd_softc *); @@ -1338,7 +1352,7 @@ ahd_unbusy_tcl(struct ahd_softc *ahd, u_ } /***************************** PCI Front End *********************************/ -struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t); +struct ahd_pci_identity *ahd_find_pci_device(aic_dev_softc_t); int ahd_pci_config(struct ahd_softc *, struct ahd_pci_identity *); int ahd_pci_test_register_access(struct ahd_softc *); @@ -1379,13 +1393,13 @@ struct scb *ahd_get_scb(struct ahd_soft void ahd_free_scb(struct ahd_softc *ahd, struct scb *scb); void ahd_alloc_scbs(struct ahd_softc *ahd); void ahd_free(struct ahd_softc *ahd); -int ahd_reset(struct ahd_softc *ahd); +int ahd_reset(struct ahd_softc *ahd, int reinit); void ahd_shutdown(void *arg); -int ahd_write_flexport(struct ahd_softc *ahd, - u_int addr, u_int value); -int ahd_read_flexport(struct ahd_softc *ahd, u_int addr, - uint8_t *value); -int ahd_wait_flexport(struct ahd_softc *ahd); +int ahd_write_flexport(struct ahd_softc *ahd, + u_int addr, u_int value); +int ahd_read_flexport(struct ahd_softc *ahd, u_int addr, + uint8_t *value); +int ahd_wait_flexport(struct ahd_softc *ahd); /*************************** Interrupt Services *******************************/ void ahd_pci_intr(struct ahd_softc *ahd); @@ -1430,6 +1444,8 @@ void ahd_handle_scsi_status(struct ahd struct scb *scb); void ahd_calc_residual(struct ahd_softc *ahd, struct scb *scb); +void ahd_timeout(struct scb *scb); +void ahd_recover_commands(struct ahd_softc *ahd); /*************************** Utility Functions ********************************/ struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase); diff -puN drivers/scsi/aic7xxx/aic79xx_inline.h~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic79xx_inline.h --- 25/drivers/scsi/aic7xxx/aic79xx_inline.h~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic79xx_inline.h Wed Dec 24 12:15:38 2003 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#50 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#55 $ * * $FreeBSD$ */ @@ -250,15 +250,15 @@ ahd_sg_setup(struct ahd_softc *ahd, stru struct ahd_dma64_seg *sg; sg = (struct ahd_dma64_seg *)sgptr; - sg->addr = ahd_htole64(addr); - sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0)); + sg->addr = aic_htole64(addr); + sg->len = aic_htole32(len | (last ? AHD_DMA_LAST_SEG : 0)); return (sg + 1); } else { struct ahd_dma_seg *sg; sg = (struct ahd_dma_seg *)sgptr; - sg->addr = ahd_htole32(addr & 0xFFFFFFFF); - sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000) + sg->addr = aic_htole32(addr & 0xFFFFFFFF); + sg->len = aic_htole32(len | ((addr >> 8) & 0x7F000000) | (last ? AHD_DMA_LAST_SEG : 0)); return (sg + 1); } @@ -273,7 +273,7 @@ ahd_setup_scb_common(struct ahd_softc *a /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */ scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE; } else { - if (ahd_get_transfer_length(scb) & 0x01) + if (aic_get_transfer_length(scb) & 0x01) scb->hscb->task_attribute = SCB_XFERLEN_ODD; else scb->hscb->task_attribute = 0; @@ -282,7 +282,7 @@ ahd_setup_scb_common(struct ahd_softc *a if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0) scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr = - ahd_htole32(scb->sense_busaddr); + aic_htole32(scb->sense_busaddr); } static __inline void @@ -308,8 +308,8 @@ ahd_setup_data_scb(struct ahd_softc *ahd if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) { uint64_t high_addr; - high_addr = ahd_le32toh(sg->len) & 0x7F000000; - scb->hscb->dataptr |= ahd_htole64(high_addr << 8); + high_addr = aic_le32toh(sg->len) & 0x7F000000; + scb->hscb->dataptr |= aic_htole64(high_addr << 8); } scb->hscb->datacnt = sg->len; } @@ -319,13 +319,13 @@ ahd_setup_data_scb(struct ahd_softc *ahd * sequencer will clear as soon as a data transfer * occurs. */ - scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID); + scb->hscb->sgptr = aic_htole32(scb->sg_list_busaddr|SG_FULL_RESID); } static __inline void ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb) { - scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL); + scb->hscb->sgptr = aic_htole32(SG_LIST_NULL); scb->hscb->dataptr = 0; scb->hscb->datacnt = 0; } @@ -383,7 +383,7 @@ ahd_sg_virt_to_bus(struct ahd_softc *ahd static __inline void ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op) { - ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat, + aic_dmamap_sync(ahd, ahd->scb_data.hscb_dmat, scb->hscb_map->dmamap, /*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr, /*len*/sizeof(*scb->hscb), op); @@ -395,7 +395,7 @@ ahd_sync_sglist(struct ahd_softc *ahd, s if (scb->sg_count == 0) return; - ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat, + aic_dmamap_sync(ahd, ahd->scb_data.sg_dmat, scb->sg_map->dmamap, /*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd), /*len*/ahd_sg_size(ahd) * scb->sg_count, op); @@ -404,7 +404,7 @@ ahd_sync_sglist(struct ahd_softc *ahd, s static __inline void ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op) { - ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat, + aic_dmamap_sync(ahd, ahd->scb_data.sense_dmat, scb->sense_map->dmamap, /*offset*/scb->sense_busaddr, /*len*/AHD_SENSE_BUFSIZE, op); @@ -455,6 +455,8 @@ static __inline u_int ahd_inb_scbram(str static __inline u_int ahd_inw_scbram(struct ahd_softc *ahd, u_int offset); static __inline uint32_t ahd_inl_scbram(struct ahd_softc *ahd, u_int offset); +static __inline uint64_t + ahd_inq_scbram(struct ahd_softc *ahd, u_int offset); static __inline void ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb); static __inline void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb); @@ -470,7 +472,7 @@ ahd_complete_scb(struct ahd_softc *ahd, { uint32_t sgptr; - sgptr = ahd_le32toh(scb->hscb->sgptr); + sgptr = aic_le32toh(scb->hscb->sgptr); if ((sgptr & SG_STATUS_VALID) != 0) ahd_handle_scb_status(ahd, scb); else @@ -486,7 +488,7 @@ ahd_update_residual(struct ahd_softc *ah { uint32_t sgptr; - sgptr = ahd_le32toh(scb->hscb->sgptr); + sgptr = aic_le32toh(scb->hscb->sgptr); if ((sgptr & SG_STATUS_VALID) != 0) ahd_calc_residual(ahd, scb); } @@ -520,12 +522,21 @@ do { \ static __inline uint16_t ahd_inw(struct ahd_softc *ahd, u_int port) { + /* + * Read high byte first as some registers increment + * or have other side effects when the low byte is + * read. + */ return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port)); } static __inline void ahd_outw(struct ahd_softc *ahd, u_int port, u_int value) { + /* + * Write low byte first to accomodate registers + * such as PRGMCNT where the order maters. + */ ahd_outb(ahd, port, value & 0xFF); ahd_outb(ahd, port+1, (value >> 8) & 0xFF); } @@ -697,10 +708,15 @@ ahd_inw_scbram(struct ahd_softc *ahd, u_ static __inline uint32_t ahd_inl_scbram(struct ahd_softc *ahd, u_int offset) { - return (ahd_inb_scbram(ahd, offset) - | (ahd_inb_scbram(ahd, offset+1) << 8) - | (ahd_inb_scbram(ahd, offset+2) << 16) - | (ahd_inb_scbram(ahd, offset+3) << 24)); + return (ahd_inw_scbram(ahd, offset) + | (ahd_inw_scbram(ahd, offset+2) << 16)); +} + +static __inline uint64_t +ahd_inq_scbram(struct ahd_softc *ahd, u_int offset) +{ + return (ahd_inl_scbram(ahd, offset) + | ((uint64_t)ahd_inl_scbram(ahd, offset+4)) << 32); } static __inline struct scb * @@ -720,7 +736,8 @@ ahd_lookup_scb(struct ahd_softc *ahd, u_ static __inline void ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb) { - struct hardware_scb *q_hscb; + struct hardware_scb *q_hscb; + struct map_node *q_hscb_map; uint32_t saved_hscb_busaddr; /* @@ -736,6 +753,7 @@ ahd_swap_with_next_hscb(struct ahd_softc * locate the correct SCB by SCB_TAG. */ q_hscb = ahd->next_queued_hscb; + q_hscb_map = ahd->next_queued_hscb_map; saved_hscb_busaddr = q_hscb->hscb_busaddr; memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); q_hscb->hscb_busaddr = saved_hscb_busaddr; @@ -743,7 +761,9 @@ ahd_swap_with_next_hscb(struct ahd_softc /* Now swap HSCB pointers. */ ahd->next_queued_hscb = scb->hscb; + ahd->next_queued_hscb_map = scb->hscb_map; scb->hscb = q_hscb; + scb->hscb_map = q_hscb_map; /* Now define the mapping from tag to SCB in the scbindex */ ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; @@ -783,13 +803,13 @@ ahd_queue_scb(struct ahd_softc *ahd, str if ((ahd_debug & AHD_SHOW_QUEUE) != 0) { uint64_t host_dataptr; - host_dataptr = ahd_le64toh(scb->hscb->dataptr); + host_dataptr = aic_le64toh(scb->hscb->dataptr); printf("%s: Queueing SCB 0x%x bus addr 0x%x - 0x%x%x/0x%x\n", ahd_name(ahd), - SCB_GET_TAG(scb), ahd_le32toh(scb->hscb->hscb_busaddr), + SCB_GET_TAG(scb), aic_le32toh(scb->hscb->hscb_busaddr), (u_int)((host_dataptr >> 32) & 0xFFFFFFFF), (u_int)(host_dataptr & 0xFFFFFFFF), - ahd_le32toh(scb->hscb->datacnt)); + aic_le32toh(scb->hscb->datacnt)); } #endif /* Tell the adapter about the newly queued SCB */ @@ -817,8 +837,8 @@ static __inline int ahd_intr(struct ahd_ static __inline void ahd_sync_qoutfifo(struct ahd_softc *ahd, int op) { - ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap, - /*offset*/0, /*len*/AHC_SCB_MAX * sizeof(uint16_t), op); + aic_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap, + /*offset*/0, /*len*/AHD_SCB_MAX * sizeof(uint16_t), op); } static __inline void @@ -826,8 +846,8 @@ ahd_sync_tqinfifo(struct ahd_softc *ahd, { #ifdef AHD_TARGET_MODE if ((ahd->flags & AHD_TARGETROLE) != 0) { - ahd_dmamap_sync(ahd, ahd->shared_data_dmat, - ahd->shared_data_dmamap, + aic_dmamap_sync(ahd, ahd->shared_data_dmat, + ahd->shared_data_map.dmamap, ahd_targetcmd_offset(ahd, 0), sizeof(struct target_cmd) * AHD_TMODE_CMDS, op); @@ -847,7 +867,7 @@ ahd_check_cmdcmpltqueues(struct ahd_soft u_int retval; retval = 0; - ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap, + aic_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap, /*offset*/ahd->qoutfifonext, /*len*/2, BUS_DMASYNC_POSTREAD); if ((ahd->qoutfifo[ahd->qoutfifonext] @@ -856,8 +876,8 @@ ahd_check_cmdcmpltqueues(struct ahd_soft #ifdef AHD_TARGET_MODE if ((ahd->flags & AHD_TARGETROLE) != 0 && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) { - ahd_dmamap_sync(ahd, ahd->shared_data_dmat, - ahd->shared_data_dmamap, + aic_dmamap_sync(ahd, ahd->shared_data_dmat, + ahd->shared_data_map.dmamap, ahd_targetcmd_offset(ahd, ahd->tqinfifofnext), /*len*/sizeof(struct target_cmd), BUS_DMASYNC_POSTREAD); diff -puN drivers/scsi/aic7xxx/aic79xx_osm.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic79xx_osm.c --- 25/drivers/scsi/aic7xxx/aic79xx_osm.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic79xx_osm.c Wed Dec 24 12:15:38 2003 @@ -1,7 +1,7 @@ /* * Adaptec AIC79xx device driver for Linux. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#169 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#193 $ * * -------------------------------------------------------------------------- * Copyright (c) 1994-2000 Justin T. Gibbs. @@ -62,6 +62,16 @@ #include /* For fetching system memory size */ +/************************* Magic SysReq Support *******************************/ +static struct aic_sysrq_key_op ahd_sysrq_op = +{ + aic_sysrq_handler, + "aic79xxstatedump", + "Dump aic79xx controller information to Console" +}; + +static int ahd_sysrq_key; + /* * Lock protecting manipulation of the ahd softc list. */ @@ -425,7 +435,7 @@ static char *aic79xx = NULL; static char dummy_buffer[60] = "Please don't trounce on me insmod!!\n"; MODULE_AUTHOR("Maintainer: Justin T. Gibbs "); -MODULE_DESCRIPTION("Adaptec Aic77XX/78XX SCSI Host Bus Adapter driver"); +MODULE_DESCRIPTION("Adaptec Aic790X U320 SCSI Host Bus Adapter driver"); #ifdef MODULE_LICENSE MODULE_LICENSE("Dual BSD/GPL"); #endif @@ -466,7 +476,7 @@ MODULE_PARM_DESC(aic79xx, #endif static void ahd_linux_handle_scsi_status(struct ahd_softc *, - struct ahd_linux_device *, + struct aic_linux_device *, struct scb *); static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, Scsi_Cmnd *cmd); @@ -478,21 +488,20 @@ static void ahd_linux_initialize_scsi_bu static void ahd_linux_size_nseg(void); static void ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd); static void ahd_linux_start_dv(struct ahd_softc *ahd); -static void ahd_linux_dv_timeout(struct scsi_cmnd *cmd); static int ahd_linux_dv_thread(void *data); static void ahd_linux_kill_dv_thread(struct ahd_softc *ahd); static void ahd_linux_dv_target(struct ahd_softc *ahd, u_int target); static void ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); + struct aic_linux_target *targ); static void ahd_linux_dv_fill_cmd(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo); static void ahd_linux_dv_inq(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ, + struct aic_linux_target *targ, u_int request_length); static void ahd_linux_dv_tur(struct ahd_softc *ahd, struct scsi_cmnd *cmd, @@ -500,19 +509,19 @@ static void ahd_linux_dv_tur(struct ahd_ static void ahd_linux_dv_rebd(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); + struct aic_linux_target *targ); static void ahd_linux_dv_web(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); + struct aic_linux_target *targ); static void ahd_linux_dv_reb(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); + struct aic_linux_target *targ); static void ahd_linux_dv_su(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); + struct aic_linux_target *targ); static __inline int ahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo); @@ -520,103 +529,57 @@ static int ahd_linux_fallback(struct ahd struct ahd_devinfo *devinfo); static __inline int ahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo); -static void ahd_linux_dv_complete(Scsi_Cmnd *cmd); -static void ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ); +static void ahd_linux_generate_dv_pattern(struct aic_linux_target *targ); static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo); static u_int ahd_linux_user_dv_setting(struct ahd_softc *ahd); static void ahd_linux_setup_user_rd_strm_settings(struct ahd_softc *ahd); -static void ahd_linux_device_queue_depth(struct ahd_softc *ahd, - struct ahd_linux_device *dev); -static struct ahd_linux_target* ahd_linux_alloc_target(struct ahd_softc*, +static void aic_linux_device_queue_depth(struct ahd_softc *ahd, + struct aic_linux_device *dev); +static struct aic_linux_target* ahd_linux_alloc_target(struct ahd_softc*, u_int, u_int); static void ahd_linux_free_target(struct ahd_softc*, - struct ahd_linux_target*); -static struct ahd_linux_device* ahd_linux_alloc_device(struct ahd_softc*, - struct ahd_linux_target*, + struct aic_linux_target*); +static struct aic_linux_device* ahd_linux_alloc_device(struct ahd_softc*, + struct aic_linux_target*, u_int); static void ahd_linux_free_device(struct ahd_softc*, - struct ahd_linux_device*); -static void ahd_linux_run_device_queue(struct ahd_softc*, - struct ahd_linux_device*); + struct aic_linux_device*); static void ahd_linux_setup_tag_info_global(char *p); static aic_option_callback_t ahd_linux_setup_tag_info; static aic_option_callback_t ahd_linux_setup_rd_strm_info; static aic_option_callback_t ahd_linux_setup_dv; static aic_option_callback_t ahd_linux_setup_iocell_info; static int ahd_linux_next_unit(void); -static void ahd_runq_tasklet(unsigned long data); static int aic79xx_setup(char *c); /****************************** Inlines ***************************************/ static __inline void ahd_schedule_completeq(struct ahd_softc *ahd); -static __inline void ahd_schedule_runq(struct ahd_softc *ahd); -static __inline void ahd_setup_runq_tasklet(struct ahd_softc *ahd); -static __inline void ahd_teardown_runq_tasklet(struct ahd_softc *ahd); -static __inline struct ahd_linux_device* +static __inline struct aic_linux_device* ahd_linux_get_device(struct ahd_softc *ahd, u_int channel, u_int target, u_int lun, int alloc); -static struct ahd_cmd *ahd_linux_run_complete_queue(struct ahd_softc *ahd); -static __inline void ahd_linux_check_device_queue(struct ahd_softc *ahd, - struct ahd_linux_device *dev); -static __inline struct ahd_linux_device * - ahd_linux_next_device_to_run(struct ahd_softc *ahd); -static __inline void ahd_linux_run_device_queues(struct ahd_softc *ahd); static __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*); - -static __inline int ahd_linux_map_seg(struct ahd_softc *ahd, struct scb *scb, - struct ahd_dma_seg *sg, - bus_addr_t addr, bus_size_t len); +static __inline struct ahd_dma_seg* + ahd_linux_sg_setup(struct ahd_softc *ahd, struct scb *scb, + struct ahd_dma_seg *sg, bus_addr_t addr, + bus_size_t len, int last_seg); static __inline void ahd_schedule_completeq(struct ahd_softc *ahd) { - if ((ahd->platform_data->flags & AHD_RUN_CMPLT_Q_TIMER) == 0) { - ahd->platform_data->flags |= AHD_RUN_CMPLT_Q_TIMER; + if ((ahd->platform_data->flags & AIC_RUN_CMPLT_Q_TIMER) == 0) { + ahd->platform_data->flags |= AIC_RUN_CMPLT_Q_TIMER; ahd->platform_data->completeq_timer.expires = jiffies; add_timer(&ahd->platform_data->completeq_timer); } } -/* - * Must be called with our lock held. - */ -static __inline void -ahd_schedule_runq(struct ahd_softc *ahd) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - tasklet_schedule(&ahd->platform_data->runq_tasklet); -#else - /* - * Tasklets are not available, so run inline. - */ - ahd_runq_tasklet((unsigned long)ahd); -#endif -} - -static __inline -void ahd_setup_runq_tasklet(struct ahd_softc *ahd) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - tasklet_init(&ahd->platform_data->runq_tasklet, ahd_runq_tasklet, - (unsigned long)ahd); -#endif -} - -static __inline void -ahd_teardown_runq_tasklet(struct ahd_softc *ahd) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - tasklet_kill(&ahd->platform_data->runq_tasklet); -#endif -} - -static __inline struct ahd_linux_device* +static __inline struct aic_linux_device* ahd_linux_get_device(struct ahd_softc *ahd, u_int channel, u_int target, u_int lun, int alloc) { - struct ahd_linux_target *targ; - struct ahd_linux_device *dev; + struct aic_linux_target *targ; + struct aic_linux_device *dev; u_int target_offset; target_offset = target; @@ -638,10 +601,10 @@ ahd_linux_get_device(struct ahd_softc *a } #define AHD_LINUX_MAX_RETURNED_ERRORS 4 -static struct ahd_cmd * +static struct aic_cmd * ahd_linux_run_complete_queue(struct ahd_softc *ahd) { - struct ahd_cmd *acmd; + struct aic_cmd *acmd; u_long done_flags; int with_errors; @@ -666,7 +629,7 @@ ahd_linux_run_complete_queue(struct ahd_ acmd, acmd_links.tqe); cmd = &acmd_scsi_cmd(acmd); cmd->host_scribble = NULL; - if (ahd_cmd_get_transaction_status(cmd) != DID_OK + if (aic_cmd_get_transaction_status(cmd) != DID_OK || (cmd->result & 0xFF) != SCSI_STATUS_OK) with_errors++; @@ -677,46 +640,6 @@ ahd_linux_run_complete_queue(struct ahd_ } static __inline void -ahd_linux_check_device_queue(struct ahd_softc *ahd, - struct ahd_linux_device *dev) -{ - if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) != 0 - && dev->active == 0) { - dev->flags &= ~AHD_DEV_FREEZE_TIL_EMPTY; - dev->qfrozen--; - } - - if (TAILQ_FIRST(&dev->busyq) == NULL - || dev->openings == 0 || dev->qfrozen != 0) - return; - - ahd_linux_run_device_queue(ahd, dev); -} - -static __inline struct ahd_linux_device * -ahd_linux_next_device_to_run(struct ahd_softc *ahd) -{ - - if ((ahd->flags & AHD_RESOURCE_SHORTAGE) != 0 - || (ahd->platform_data->qfrozen != 0 - && AHD_DV_SIMQ_FROZEN(ahd) == 0)) - return (NULL); - return (TAILQ_FIRST(&ahd->platform_data->device_runq)); -} - -static __inline void -ahd_linux_run_device_queues(struct ahd_softc *ahd) -{ - struct ahd_linux_device *dev; - - while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) { - TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links); - dev->flags &= ~AHD_DEV_ON_RUN_LIST; - ahd_linux_check_device_queue(ahd, dev); - } -} - -static __inline void ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb) { Scsi_Cmnd *cmd; @@ -729,34 +652,22 @@ ahd_linux_unmap_scb(struct ahd_softc *ah struct scatterlist *sg; sg = (struct scatterlist *)cmd->request_buffer; - pci_unmap_sg(ahd->dev_softc, sg, cmd->use_sg, direction); + aic_unmap_sg(ahd, sg, cmd->use_sg, direction); } else if (cmd->request_bufflen != 0) { - pci_unmap_single(ahd->dev_softc, + aic_unmap_single(ahd, scb->platform_data->buf_busaddr, cmd->request_bufflen, direction); } } -static __inline int -ahd_linux_map_seg(struct ahd_softc *ahd, struct scb *scb, - struct ahd_dma_seg *sg, bus_addr_t addr, bus_size_t len) +static __inline struct ahd_dma_seg* +ahd_linux_sg_setup(struct ahd_softc *ahd, struct scb *scb, + struct ahd_dma_seg *sg, bus_addr_t addr, + bus_size_t len, int last_seg) { - int consumed; - - if ((scb->sg_count + 1) > AHD_NSEG) - panic("Too few segs for dma mapping. " - "Increase AHD_NSEG\n"); - - consumed = 1; - sg->addr = ahd_htole32(addr & 0xFFFFFFFF); + sg = ahd_sg_setup(ahd, scb, sg, addr, len, last_seg); scb->platform_data->xfer_len += len; - - if (sizeof(bus_addr_t) > 4 - && (ahd->flags & AHD_39BIT_ADDRESSING) != 0) - len |= (addr >> 8) & AHD_SG_HIGH_ADDR_MASK; - - sg->len = ahd_htole32(len); - return (consumed); + return (sg); } /******************************** Macros **************************************/ @@ -797,7 +708,7 @@ static int ahd_linux_abort(Scsi_Cmnd * number of segments needed for the current transfer. Since the code that * sizes the SCSI malloc pool does not take into consideration fragmentation * of the pool, executing transactions numbering just a fraction of our - * concurrent transaction limit with SG list lengths aproaching AHC_NSEG will + * concurrent transaction limit with SG list lengths aproaching AHD_NSEG will * quickly depleat the SCSI malloc pool of usable space. Unfortunately, the * mid-layer does not properly handle this scsi malloc failures for the S/G * array and the result can be a lockup of the I/O subsystem. We try to size @@ -848,6 +759,165 @@ ahd_linux_size_nseg(void) #endif } +/************************** Error Recovery ************************************/ +static int ahd_linux_recovery_thread(void *arg); + +static int +ahd_linux_recovery_thread(void *arg) +{ + struct ahd_softc *ahd; + u_long s; + + ahd = (struct ahd_softc *)arg; + + /* + * Complete thread creation. + */ + lock_kernel(); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60) + /* + * Don't care about any signals. + */ + siginitsetinv(¤t->blocked, 0); + + daemonize(); + sprintf(current->comm, "ahd_recovery_%d", ahd->unit); +#else + daemonize("ahd_recovery_%d", ahd->unit); +#endif + unlock_kernel(); + + while (1) { + + /* + * Use down_interruptible() rather than down() to + * avoid inclusion in the load average. + */ + down_interruptible(&ahd->platform_data->recovery_sem); + + ahd_lock(ahd, &s); + if ((ahd->flags & AHD_SHUTDOWN_RECOVERY) != 0) { + ahd_unlock(ahd, &s); + break; + } + + /* + * Don't bother the recovery handler if the + * list has been cleared by a previous run + * of the handler. This can happen when + * several SCBs timeout before our handler + * can run causing our semaphore to be up'ed + * repeatedly. The extra calls need to be + * avoided so that the recovery handler doesn't + * confuse this case with timeouts occuring + * due to interrupts failing to function. + */ + if (LIST_EMPTY(&ahd->timedout_scbs) != 0) { + ahd_unlock(ahd, &s); + continue; + } + + ahd_unlock(ahd, &s); + ahd_recover_commands(ahd); + + /* + * Process any pent up completions. + */ + ahd_lock(ahd, &s); + aic_schedule_runq(ahd); + ahd_linux_run_complete_queue(ahd); + ahd_unlock(ahd, &s); + } + up(&ahd->platform_data->recovery_ending_sem); + return(0); +} + +int +ahd_spawn_recovery_thread(struct ahd_softc *ahd) +{ + ahd->platform_data->recovery_pid = + kernel_thread(ahd_linux_recovery_thread, ahd, 0); + + if (ahd->platform_data->recovery_pid < 0) + return (-ahd->platform_data->recovery_pid); + + return (0); +} + +void +ahd_terminate_recovery_thread(struct ahd_softc *ahd) +{ + u_long s; + + ahd_lock(ahd, &s); + if (ahd->platform_data->recovery_pid != 0) { + ahd->flags |= AHD_SHUTDOWN_RECOVERY; + ahd_unlock(ahd, &s); + up(&ahd->platform_data->recovery_sem); + + /* + * Use the recovery_ending_sem as an indicator that + * the dv thread is exiting. Note that the dv + * thread must still return after performing + * the up on our semaphore before it has + * completely exited this module. Unfortunately, + * there seems to be no easy way to wait for the + * exit of a thread for which you are not the + * parent (dv threads are parented by init). + * Cross your fingers... + */ + down(&ahd->platform_data->recovery_ending_sem); + + /* + * Mark the recovery thread as already dead. This + * avoids attempting to kill it a second time. + * This is necessary because we must kill the + * our threads before calling ahd_free() in the + * module shutdown case to avoid bogus locking + * in the SCSI mid-layer, but when ahd_free() is + * called without killing the DV thread in the + * instance detach case, so ahd_platform_free() + * calls us again to verify that the DV thread + * is dead. + */ + ahd->platform_data->recovery_pid = 0; + } else { + ahd_unlock(ahd, &s); + } +} + +void +ahd_set_recoveryscb(struct ahd_softc *ahd, struct scb *scb) +{ + if ((scb->flags & SCB_RECOVERY_SCB) == 0) { + struct scb *list_scb; + + scb->flags |= SCB_RECOVERY_SCB; + + /* + * Take all queued, but not sent SCBs out of the equation. + * Also ensure that no new commands are queued to us while we + * try to fix this problem. + */ + if ((scb->platform_data->flags & AIC_RELEASE_SIMQ) == 0) { + aic_freeze_simq(ahd); + scb->platform_data->flags |= AIC_RELEASE_SIMQ; + } + + /* + * Go through all of our pending SCBs and remove + * any scheduled timeouts for them. We will reschedule + * them after we've successfully fixed this problem. + */ + LIST_FOREACH(list_scb, &ahd->pending_scbs, pending_links) { + + scsi_delete_timer(list_scb->io_ctx); + list_scb->platform_data->flags &= ~AIC_TIMEOUT_ACTIVE; + } + } +} + +/********************** Host Template Entry Points ****************************/ /* * Try to detect an Adaptec 79XX controller. */ @@ -870,7 +940,7 @@ ahd_linux_detect(Scsi_Host_Template *tem * that some of our hacks^H^H^H^H^Hassumptions aren't * violated. */ - if (offsetof(struct ahd_cmd_internal, end) + if (offsetof(struct aic_cmd_internal, end) > offsetof(struct scsi_cmnd, host_scribble)) { printf("ahd_linux_detect: SCSI data structures changed.\n"); printf("ahd_linux_detect: Unable to attach\n"); @@ -938,7 +1008,6 @@ ahd_linux_release(struct Scsi_Host * hos struct ahd_softc *ahd; u_long l; - ahd_list_lock(&l); if (host != NULL) { /* @@ -946,17 +1015,20 @@ ahd_linux_release(struct Scsi_Host * hos * the free directly, but check our * list for extra sanity. */ + ahd_list_lock(&l); ahd = ahd_find_softc(*(struct ahd_softc **)host->hostdata); if (ahd != NULL) { u_long s; + TAILQ_REMOVE(&ahd_tailq, ahd, links); + ahd_list_unlock(&l); ahd_lock(ahd, &s); ahd_intr_enable(ahd, FALSE); ahd_unlock(ahd, &s); ahd_free(ahd); - } + } else + ahd_list_unlock(&l); } - ahd_list_unlock(&l); return (0); } #endif @@ -996,7 +1068,7 @@ static int ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) { struct ahd_softc *ahd; - struct ahd_linux_device *dev; + struct aic_linux_device *dev; u_long flags; ahd = *(struct ahd_softc **)cmd->device->host->hostdata; @@ -1015,9 +1087,9 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (* * perform DV. */ if (ahd->platform_data->qfrozen != 0 - && AHD_DV_CMD(cmd) == 0) { + && AIC_DV_CMD(cmd) == 0) { - ahd_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ); + aic_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ); ahd_linux_queue_cmd_complete(ahd, cmd); ahd_schedule_completeq(ahd); ahd_midlayer_entrypoint_unlock(ahd, &flags); @@ -1027,7 +1099,8 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (* cmd->device->id, cmd->device->lun, /*alloc*/TRUE); if (dev == NULL) { - ahd_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL); + + aic_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL); ahd_linux_queue_cmd_complete(ahd, cmd); ahd_schedule_completeq(ahd); ahd_midlayer_entrypoint_unlock(ahd, &flags); @@ -1035,14 +1108,30 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (* ahd_name(ahd)); return (0); } - if (cmd->cmd_len > MAX_CDB_LEN) - return (-EINVAL); + + if (cmd->cmd_len > MAX_CDB_LEN) { + + aic_cmd_set_transaction_status(cmd, CAM_REQ_INVALID); + ahd_linux_queue_cmd_complete(ahd, cmd); + ahd_schedule_completeq(ahd); + ahd_midlayer_entrypoint_unlock(ahd, &flags); + printf("%s: aic79xx_linux_queue -" + "CDB length of %d exceeds max!\n", + ahd_name(ahd), cmd->cmd_len); + return (0); + } + + /* + * We perform our own timeout handling. + */ + scsi_delete_timer(cmd); + cmd->result = CAM_REQ_INPROG << 16; - TAILQ_INSERT_TAIL(&dev->busyq, (struct ahd_cmd *)cmd, acmd_links.tqe); - if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) { + TAILQ_INSERT_TAIL(&dev->busyq, (struct aic_cmd *)cmd, acmd_links.tqe); + if ((dev->flags & AIC_DEV_ON_RUN_LIST) == 0) { TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links); - dev->flags |= AHD_DEV_ON_RUN_LIST; - ahd_linux_run_device_queues(ahd); + dev->flags |= AIC_DEV_ON_RUN_LIST; + aic_linux_run_device_queues(ahd); } ahd_midlayer_entrypoint_unlock(ahd, &flags); return (0); @@ -1064,7 +1153,7 @@ static int ahd_linux_slave_configure(Scsi_Device *device) { struct ahd_softc *ahd; - struct ahd_linux_device *dev; + struct aic_linux_device *dev; u_long flags; ahd = *((struct ahd_softc **)device->host->hostdata); @@ -1080,10 +1169,10 @@ ahd_linux_slave_configure(Scsi_Device *d device->id, device->lun, /*alloc*/TRUE); if (dev != NULL) { - dev->flags &= ~AHD_DEV_UNCONFIGURED; - dev->flags |= AHD_DEV_SLAVE_CONFIGURED; + dev->flags &= ~AIC_DEV_UNCONFIGURED; + dev->flags |= AIC_DEV_SLAVE_CONFIGURED; dev->scsi_device = device; - ahd_linux_device_queue_depth(ahd, dev); + aic_linux_device_queue_depth(ahd, dev); } ahd_midlayer_entrypoint_unlock(ahd, &flags); return (0); @@ -1093,7 +1182,7 @@ static void ahd_linux_slave_destroy(Scsi_Device *device) { struct ahd_softc *ahd; - struct ahd_linux_device *dev; + struct aic_linux_device *dev; u_long flags; ahd = *((struct ahd_softc **)device->host->hostdata); @@ -1112,11 +1201,10 @@ ahd_linux_slave_destroy(Scsi_Device *dev * the refcounting process. */ if (dev != NULL - && (dev->flags & AHD_DEV_SLAVE_CONFIGURED) != 0) { - dev->flags |= AHD_DEV_UNCONFIGURED; + && (dev->flags & AIC_DEV_SLAVE_CONFIGURED) != 0) { + dev->flags |= AIC_DEV_UNCONFIGURED; if (TAILQ_EMPTY(&dev->busyq) - && dev->active == 0 - && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0) + && dev->active == 0) ahd_linux_free_device(ahd, dev); } ahd_midlayer_entrypoint_unlock(ahd, &flags); @@ -1156,7 +1244,7 @@ ahd_linux_select_queue_depth(struct Scsi continue; if (device->host == host) { - struct ahd_linux_device *dev; + struct aic_linux_device *dev; /* * Since Linux has attached to the device, configure @@ -1167,13 +1255,13 @@ ahd_linux_select_queue_depth(struct Scsi device->id, device->lun, /*alloc*/TRUE); if (dev != NULL) { - dev->flags &= ~AHD_DEV_UNCONFIGURED; + dev->flags &= ~AIC_DEV_UNCONFIGURED; dev->scsi_device = device; - ahd_linux_device_queue_depth(ahd, dev); + aic_linux_device_queue_depth(ahd, dev); device->queue_depth = dev->openings + dev->active; - if ((dev->flags & (AHD_DEV_Q_BASIC - | AHD_DEV_Q_TAGGED)) == 0) { + if ((dev->flags & (AIC_DEV_Q_BASIC + | AIC_DEV_Q_TAGGED)) == 0) { /* * We allow the OS to queue 2 untagged * transactions to us at any time even @@ -1262,9 +1350,9 @@ static int ahd_linux_abort(Scsi_Cmnd *cmd) { struct ahd_softc *ahd; - struct ahd_cmd *acmd; - struct ahd_cmd *list_acmd; - struct ahd_linux_device *dev; + struct aic_cmd *acmd; + struct aic_cmd *list_acmd; + struct aic_linux_device *dev; struct scb *pending_scb; u_long s; u_int saved_scbptr; @@ -1282,7 +1370,7 @@ ahd_linux_abort(Scsi_Cmnd *cmd) paused = FALSE; wait = FALSE; ahd = *(struct ahd_softc **)cmd->device->host->hostdata; - acmd = (struct ahd_cmd *)cmd; + acmd = (struct aic_cmd *)cmd; printf("%s:%d:%d:%d: Attempting to abort cmd %p:", ahd_name(ahd), cmd->device->channel, cmd->device->id, @@ -1341,6 +1429,17 @@ ahd_linux_abort(Scsi_Cmnd *cmd) cmd->device->lun); TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe); cmd->result = DID_ABORT << 16; + /* + * The completion handler believes that + * commands without active timers running + * have lost the race of completing before + * their timer expires. Since commands in + * our busy queues do not have timers running, + * appease the mid-layer by adding a timer + * now. This timer will be immediately + * canceled by the midlayer. + */ + scsi_add_timer(cmd, 60*HZ, aic_linux_midlayer_timeout); ahd_linux_queue_cmd_complete(ahd, cmd); retval = SUCCESS; goto done; @@ -1516,7 +1615,7 @@ done: struct timer_list timer; int ret; - pending_scb->platform_data->flags |= AHD_SCB_UP_EH_SEM; + pending_scb->platform_data->flags |= AIC_SCB_UP_EH_SEM; spin_unlock_irq(&ahd->platform_data->spin_lock); init_timer(&timer); timer.data = (u_long)pending_scb; @@ -1533,7 +1632,7 @@ done: } spin_lock_irq(&ahd->platform_data->spin_lock); } - ahd_schedule_runq(ahd); + aic_schedule_runq(ahd); ahd_linux_run_complete_queue(ahd); ahd_midlayer_entrypoint_unlock(ahd, &s); return (retval); @@ -1554,7 +1653,7 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd) { struct ahd_softc *ahd; struct scsi_cmnd *recovery_cmd; - struct ahd_linux_device *dev; + struct aic_linux_device *dev; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; struct scb *scb; @@ -1592,9 +1691,11 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd) recovery_cmd->host_scribble = (char *)scb; scb->io_ctx = recovery_cmd; scb->platform_data->dev = dev; + scb->platform_data->flags = 0; scb->sg_count = 0; - ahd_set_residual(scb, 0); - ahd_set_sense_residual(scb, 0); + aic_set_residual(scb, 0); + aic_set_sense_residual(scb, 0); + scb->platform_data->xfer_len = 0; hscb = scb->hscb; hscb->control = 0; hscb->scsiid = BUILD_SCSIID(ahd, cmd); @@ -1613,7 +1714,7 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd) LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); ahd_queue_scb(ahd, scb); - scb->platform_data->flags |= AHD_SCB_UP_EH_SEM; + scb->platform_data->flags |= AIC_SCB_UP_EH_SEM; spin_unlock_irq(&ahd->platform_data->spin_lock); init_timer(&timer); timer.data = (u_long)scb; @@ -1629,7 +1730,7 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd) retval = FAILED; } spin_lock_irq(&ahd->platform_data->spin_lock); - ahd_schedule_runq(ahd); + aic_schedule_runq(ahd); ahd_linux_run_complete_queue(ahd); ahd_midlayer_entrypoint_unlock(ahd, &s); printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval); @@ -1665,189 +1766,8 @@ ahd_linux_bus_reset(Scsi_Cmnd *cmd) return (SUCCESS); } -Scsi_Host_Template aic79xx_driver_template = { - .module = THIS_MODULE, - .name = "aic79xx", - .proc_info = ahd_linux_proc_info, - .info = ahd_linux_info, - .queuecommand = ahd_linux_queue, - .eh_abort_handler = ahd_linux_abort, - .eh_device_reset_handler = ahd_linux_dev_reset, - .eh_bus_reset_handler = ahd_linux_bus_reset, -#if defined(__i386__) - .bios_param = ahd_linux_biosparam, -#endif - .can_queue = AHD_MAX_QUEUE, - .this_id = -1, - .cmd_per_lun = 2, - .use_clustering = ENABLE_CLUSTERING, - .slave_alloc = ahd_linux_slave_alloc, - .slave_configure = ahd_linux_slave_configure, - .slave_destroy = ahd_linux_slave_destroy, -}; - -/**************************** Tasklet Handler *********************************/ - -/* - * In 2.4.X and above, this routine is called from a tasklet, - * so we must re-acquire our lock prior to executing this code. - * In all prior kernels, ahd_schedule_runq() calls this routine - * directly and ahd_schedule_runq() is called with our lock held. - */ -static void -ahd_runq_tasklet(unsigned long data) -{ - struct ahd_softc* ahd; - struct ahd_linux_device *dev; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - u_long flags; -#endif - - ahd = (struct ahd_softc *)data; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - ahd_lock(ahd, &flags); -#endif - while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) { - - TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links); - dev->flags &= ~AHD_DEV_ON_RUN_LIST; - ahd_linux_check_device_queue(ahd, dev); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - /* Yeild to our interrupt handler */ - ahd_unlock(ahd, &flags); - ahd_lock(ahd, &flags); -#endif - } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - ahd_unlock(ahd, &flags); -#endif -} - -/******************************** Bus DMA *************************************/ -int -ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent, - bus_size_t alignment, bus_size_t boundary, - bus_addr_t lowaddr, bus_addr_t highaddr, - bus_dma_filter_t *filter, void *filterarg, - bus_size_t maxsize, int nsegments, - bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag) -{ - bus_dma_tag_t dmat; - - dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT); - if (dmat == NULL) - return (ENOMEM); - - /* - * Linux is very simplistic about DMA memory. For now don't - * maintain all specification information. Once Linux supplies - * better facilities for doing these operations, or the - * needs of this particular driver change, we might need to do - * more here. - */ - dmat->alignment = alignment; - dmat->boundary = boundary; - dmat->maxsize = maxsize; - *ret_tag = dmat; - return (0); -} - -void -ahd_dma_tag_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat) -{ - free(dmat, M_DEVBUF); -} - -int -ahd_dmamem_alloc(struct ahd_softc *ahd, bus_dma_tag_t dmat, void** vaddr, - int flags, bus_dmamap_t *mapp) -{ - bus_dmamap_t map; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT); - if (map == NULL) - return (ENOMEM); - /* - * Although we can dma data above 4GB, our - * "consistent" memory is below 4GB for - * space efficiency reasons (only need a 4byte - * address). For this reason, we have to reset - * our dma mask when doing allocations. - */ - if (ahd->dev_softc != NULL) - ahd_pci_set_dma_mask(ahd->dev_softc, 0xFFFFFFFF); - *vaddr = pci_alloc_consistent(ahd->dev_softc, - dmat->maxsize, &map->bus_addr); - if (ahd->dev_softc != NULL) - ahd_pci_set_dma_mask(ahd->dev_softc, - ahd->platform_data->hw_dma_mask); -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) */ - /* - * At least in 2.2.14, malloc is a slab allocator so all - * allocations are aligned. We assume for these kernel versions - * that all allocations will be bellow 4Gig, physically contiguous, - * and accessible via DMA by the controller. - */ - map = NULL; /* No additional information to store */ - *vaddr = malloc(dmat->maxsize, M_DEVBUF, M_NOWAIT); -#endif - if (*vaddr == NULL) - return (ENOMEM); - *mapp = map; - return(0); -} - -void -ahd_dmamem_free(struct ahd_softc *ahd, bus_dma_tag_t dmat, - void* vaddr, bus_dmamap_t map) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - pci_free_consistent(ahd->dev_softc, dmat->maxsize, - vaddr, map->bus_addr); -#else - free(vaddr, M_DEVBUF); -#endif -} - -int -ahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map, - void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb, - void *cb_arg, int flags) -{ - /* - * Assume for now that this will only be used during - * initialization and not for per-transaction buffer mapping. - */ - bus_dma_segment_t stack_sg; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - stack_sg.ds_addr = map->bus_addr; -#else -#define VIRT_TO_BUS(a) (uint32_t)virt_to_bus((void *)(a)) - stack_sg.ds_addr = VIRT_TO_BUS(buf); -#endif - stack_sg.ds_len = dmat->maxsize; - cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0); - return (0); -} - -void -ahd_dmamap_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map) -{ - /* - * The map may is NULL in our < 2.3.X implementation. - */ - if (map != NULL) - free(map, M_DEVBUF); -} - -int -ahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map) -{ - /* Nothing to do */ - return (0); -} +Scsi_Host_Template aic79xx_driver_template = + AIC_TEMPLATE_INITIALIZER("aic79xx", /*max_sectors*/8192); /********************* Platform Dependent Functions ***************************/ /* @@ -1883,19 +1803,19 @@ ahd_softc_comp(struct ahd_softc *lahd, s /* Still equal. Sort by bus/slot/func. */ if (aic79xx_reverse_scan != 0) - value = ahd_get_pci_bus(lahd->dev_softc) - - ahd_get_pci_bus(rahd->dev_softc); + value = aic_get_pci_bus(lahd->dev_softc) + - aic_get_pci_bus(rahd->dev_softc); else - value = ahd_get_pci_bus(rahd->dev_softc) - - ahd_get_pci_bus(lahd->dev_softc); + value = aic_get_pci_bus(rahd->dev_softc) + - aic_get_pci_bus(lahd->dev_softc); if (value != 0) return (value); if (aic79xx_reverse_scan != 0) - value = ahd_get_pci_slot(lahd->dev_softc) - - ahd_get_pci_slot(rahd->dev_softc); + value = aic_get_pci_slot(lahd->dev_softc) + - aic_get_pci_slot(rahd->dev_softc); else - value = ahd_get_pci_slot(rahd->dev_softc) - - ahd_get_pci_slot(lahd->dev_softc); + value = aic_get_pci_slot(rahd->dev_softc) + - aic_get_pci_slot(lahd->dev_softc); if (value != 0) return (value); @@ -2072,9 +1992,16 @@ ahd_linux_register_host(struct ahd_softc char *new_name; u_long s; u_long target; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + int error; +#endif template->name = ahd->description; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) host = scsi_host_alloc(template, sizeof(struct ahd_softc *)); +#else + host = scsi_register(template, sizeof(struct ahd_softc *)); +#endif if (host == NULL) return (ENOMEM); @@ -2083,8 +2010,12 @@ ahd_linux_register_host(struct ahd_softc #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_assign_lock(host, &ahd->platform_data->spin_lock); #elif AHD_SCSI_HAS_HOST_LOCK != 0 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,21) + host->host_lock = &ahd->platform_data->spin_lock; +#else host->lock = &ahd->platform_data->spin_lock; #endif +#endif ahd->platform_data->host = host; host->can_queue = AHD_MAX_QUEUE; host->cmd_per_lun = 2; @@ -2110,13 +2041,20 @@ ahd_linux_register_host(struct ahd_softc ahd_linux_setup_user_rd_strm_settings(ahd); ahd_linux_initialize_scsi_bus(ahd); ahd_unlock(ahd, &s); + ahd_sysrq_key = aic_install_sysrq(&ahd_sysrq_op); + ahd_spawn_recovery_thread(ahd); + if (ahd->platform_data->recovery_pid < 0) { + printf("%s: Failed to create recovery thread, error= %d\n", + ahd_name(ahd), ahd->platform_data->recovery_pid); + return (-ahd->platform_data->recovery_pid); + } ahd->platform_data->dv_pid = kernel_thread(ahd_linux_dv_thread, ahd, 0); - ahd_lock(ahd, &s); if (ahd->platform_data->dv_pid < 0) { printf("%s: Failed to create DV thread, error= %d\n", ahd_name(ahd), ahd->platform_data->dv_pid); return (-ahd->platform_data->dv_pid); } + ahd_lock(ahd, &s); /* * Initially allocate *all* of our linux target objects * so that the DV thread will scan them all in parallel @@ -2136,7 +2074,7 @@ ahd_linux_register_host(struct ahd_softc * It is expected that either an external application * or a modified kernel will be used to probe this * ID if it is appropriate. To accommodate these - * installations, ahc_linux_alloc_target() will allocate + * installations, ahd_linux_alloc_target() will allocate * for our ID if asked to do so. */ if (target == ahd->our_id) @@ -2149,7 +2087,9 @@ ahd_linux_register_host(struct ahd_softc ahd_unlock(ahd, &s); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */ + error = scsi_add_host(host, ahd->dev_softc); + if (error != 0) + return (-error); scsi_scan_host(host); #endif return (0); @@ -2225,17 +2165,6 @@ ahd_linux_initialize_scsi_bus(struct ahd ahd_update_neg_request(ahd, &devinfo, tstate, tinfo, AHD_NEG_ALWAYS); } - /* Give the bus some time to recover */ - if ((ahd->flags & AHD_RESET_BUS_A) != 0) { - ahd_freeze_simq(ahd); - init_timer(&ahd->platform_data->reset_timer); - ahd->platform_data->reset_timer.data = (u_long)ahd; - ahd->platform_data->reset_timer.expires = - jiffies + (AIC79XX_RESET_DELAY * HZ)/1000; - ahd->platform_data->reset_timer.function = - (ahd_linux_callback_t *)ahd_release_simq; - add_timer(&ahd->platform_data->reset_timer); - } } int @@ -2248,24 +2177,32 @@ ahd_platform_alloc(struct ahd_softc *ahd memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data)); TAILQ_INIT(&ahd->platform_data->completeq); TAILQ_INIT(&ahd->platform_data->device_runq); - ahd->platform_data->irq = AHD_LINUX_NOIRQ; + ahd->platform_data->irq = AIC_LINUX_NOIRQ; ahd->platform_data->hw_dma_mask = 0xFFFFFFFF; ahd_lockinit(ahd); ahd_done_lockinit(ahd); + init_timer(&ahd->platform_data->bus_settle_timer); + ahd->platform_data->bus_settle_timer.data = (u_long)ahd; + ahd->platform_data->bus_settle_timer.function = + (aic_linux_callback_t *)aic_bus_settle_complete; init_timer(&ahd->platform_data->completeq_timer); ahd->platform_data->completeq_timer.data = (u_long)ahd; ahd->platform_data->completeq_timer.function = - (ahd_linux_callback_t *)ahd_linux_thread_run_complete_queue; + (aic_linux_callback_t *)ahd_linux_thread_run_complete_queue; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) init_MUTEX_LOCKED(&ahd->platform_data->eh_sem); init_MUTEX_LOCKED(&ahd->platform_data->dv_sem); init_MUTEX_LOCKED(&ahd->platform_data->dv_cmd_sem); + init_MUTEX_LOCKED(&ahd->platform_data->recovery_sem); + init_MUTEX_LOCKED(&ahd->platform_data->recovery_ending_sem); #else ahd->platform_data->eh_sem = MUTEX_LOCKED; ahd->platform_data->dv_sem = MUTEX_LOCKED; ahd->platform_data->dv_cmd_sem = MUTEX_LOCKED; + ahd->platform_data->recovery_sem = MUTEX_LOCKED; + ahd->platform_data->recovery_ending_sem = MUTEX_LOCKED; #endif - ahd_setup_runq_tasklet(ahd); + aic_setup_tasklets(ahd); ahd->seltime = (aic79xx_seltime & 0x3) << 4; return (0); } @@ -2273,19 +2210,22 @@ ahd_platform_alloc(struct ahd_softc *ahd void ahd_platform_free(struct ahd_softc *ahd) { - struct ahd_linux_target *targ; - struct ahd_linux_device *dev; + struct aic_linux_target *targ; + struct aic_linux_device *dev; int i, j; + aic_remove_sysrq(ahd_sysrq_key, &ahd_sysrq_op); if (ahd->platform_data != NULL) { del_timer_sync(&ahd->platform_data->completeq_timer); ahd_linux_kill_dv_thread(ahd); - ahd_teardown_runq_tasklet(ahd); + aic_teardown_tasklets(ahd); if (ahd->platform_data->host != NULL) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_remove_host(ahd->platform_data->host); -#endif scsi_host_put(ahd->platform_data->host); +#else + scsi_unregister(ahd->platform_data->host); +#endif } /* destroy all of the device and target objects */ @@ -2299,6 +2239,7 @@ ahd_platform_free(struct ahd_softc *ahd) if (targ->devices[j] == NULL) continue; dev = targ->devices[j]; + del_timer_sync(&dev->timer); ahd_linux_free_device(ahd, dev); } /* @@ -2309,7 +2250,7 @@ ahd_platform_free(struct ahd_softc *ahd) } } - if (ahd->platform_data->irq != AHD_LINUX_NOIRQ) + if (ahd->platform_data->irq != AIC_LINUX_NOIRQ) free_irq(ahd->platform_data->irq, ahd); if (ahd->tags[0] == BUS_SPACE_PIO && ahd->bshs[0].ioport != 0) @@ -2377,7 +2318,7 @@ void ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, ahd_queue_alg alg) { - struct ahd_linux_device *dev; + struct aic_linux_device *dev; int was_queuing; int now_queuing; @@ -2386,27 +2327,27 @@ ahd_platform_set_tags(struct ahd_softc * devinfo->lun, /*alloc*/FALSE); if (dev == NULL) return; - was_queuing = dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED); + was_queuing = dev->flags & (AIC_DEV_Q_BASIC|AIC_DEV_Q_TAGGED); switch (alg) { default: case AHD_QUEUE_NONE: now_queuing = 0; break; case AHD_QUEUE_BASIC: - now_queuing = AHD_DEV_Q_BASIC; + now_queuing = AIC_DEV_Q_BASIC; break; case AHD_QUEUE_TAGGED: - now_queuing = AHD_DEV_Q_TAGGED; + now_queuing = AIC_DEV_Q_TAGGED; break; } - if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) == 0 + if ((dev->flags & AIC_DEV_FREEZE_TIL_EMPTY) == 0 && (was_queuing != now_queuing) && (dev->active != 0)) { - dev->flags |= AHD_DEV_FREEZE_TIL_EMPTY; + dev->flags |= AIC_DEV_FREEZE_TIL_EMPTY; dev->qfrozen++; } - dev->flags &= ~(AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED|AHD_DEV_PERIODIC_OTAG); + dev->flags &= ~(AIC_DEV_Q_BASIC|AIC_DEV_Q_TAGGED|AIC_DEV_PERIODIC_OTAG); if (now_queuing) { u_int usertags; @@ -2426,11 +2367,11 @@ ahd_platform_set_tags(struct ahd_softc * */ dev->openings = 1; } else if (alg == AHD_QUEUE_TAGGED) { - dev->flags |= AHD_DEV_Q_TAGGED; + dev->flags |= AIC_DEV_Q_TAGGED; if (aic79xx_periodic_otag != 0) - dev->flags |= AHD_DEV_PERIODIC_OTAG; + dev->flags |= AIC_DEV_PERIODIC_OTAG; } else - dev->flags |= AHD_DEV_Q_BASIC; + dev->flags |= AIC_DEV_Q_BASIC; } else { /* We can only have one opening. */ dev->maxtags = 0; @@ -2438,13 +2379,13 @@ ahd_platform_set_tags(struct ahd_softc * } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) if (dev->scsi_device != NULL) { - switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) { - case AHD_DEV_Q_BASIC: + switch ((dev->flags & (AIC_DEV_Q_BASIC|AIC_DEV_Q_TAGGED))) { + case AIC_DEV_Q_BASIC: scsi_adjust_queue_depth(dev->scsi_device, MSG_SIMPLE_TASK, dev->openings + dev->active); break; - case AHD_DEV_Q_TAGGED: + case AIC_DEV_Q_TAGGED: scsi_adjust_queue_depth(dev->scsi_device, MSG_ORDERED_TASK, dev->openings + dev->active); @@ -2497,9 +2438,9 @@ ahd_platform_abort_scbs(struct ahd_softc for (; targ < maxtarg; targ++) { for (; clun < maxlun; clun++) { - struct ahd_linux_device *dev; - struct ahd_busyq *busyq; - struct ahd_cmd *acmd; + struct aic_linux_device *dev; + struct aic_busyq *busyq; + struct aic_cmd *acmd; dev = ahd_linux_get_device(ahd, /*chan*/0, targ, clun, /*alloc*/FALSE); @@ -2515,6 +2456,18 @@ ahd_platform_abort_scbs(struct ahd_softc acmd_links.tqe); count++; cmd->result = status << 16; + /* + * The completion handler believes that + * commands without active timers running + * have lost the race of completing before + * their timer expires. Since commands in + * our busy queues do not have timers running, + * appease the mid-layer by adding a timer + * now. This timer will be immediately + * canceled by the midlayer. + */ + scsi_add_timer(cmd, 60*HZ, + aic_linux_midlayer_timeout); ahd_linux_queue_cmd_complete(ahd, cmd); } } @@ -2530,7 +2483,7 @@ ahd_linux_thread_run_complete_queue(stru ahd_lock(ahd, &flags); del_timer(&ahd->platform_data->completeq_timer); - ahd->platform_data->flags &= ~AHD_RUN_CMPLT_Q_TIMER; + ahd->platform_data->flags &= ~AIC_RUN_CMPLT_Q_TIMER; ahd_linux_run_complete_queue(ahd); ahd_unlock(ahd, &flags); } @@ -2543,14 +2496,23 @@ ahd_linux_start_dv(struct ahd_softc *ahd * Freeze the simq and signal ahd_linux_queue to not let any * more commands through */ - if ((ahd->platform_data->flags & AHD_DV_ACTIVE) == 0) { + if ((ahd->platform_data->flags & AIC_DV_ACTIVE) == 0) { #ifdef AHD_DEBUG if (ahd_debug & AHD_SHOW_DV) printf("%s: Starting DV\n", ahd_name(ahd)); #endif - ahd->platform_data->flags |= AHD_DV_ACTIVE; - ahd_freeze_simq(ahd); + ahd->platform_data->flags |= AIC_DV_ACTIVE; + + /* + * Prevent upper layer from sending any + * commands to us. + */ + aic_freeze_simq(ahd); + scsi_block_requests(ahd->platform_data->host); + ahd_platform_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS, + CAM_LUN_WILDCARD, SCB_LIST_NULL, + ROLE_INITIATOR, CAM_REQUEUE_REQ); /* Wake up the DV kthread */ up(&ahd->platform_data->dv_sem); @@ -2589,6 +2551,7 @@ ahd_linux_dv_thread(void *data) unlock_kernel(); while (1) { + /* * Use down_interruptible() rather than down() to * avoid inclusion in the load average. @@ -2597,7 +2560,7 @@ ahd_linux_dv_thread(void *data) /* Check to see if we've been signaled to exit */ ahd_lock(ahd, &s); - if ((ahd->platform_data->flags & AHD_DV_SHUTDOWN) != 0) { + if ((ahd->platform_data->flags & AIC_DV_SHUTDOWN) != 0) { ahd_unlock(ahd, &s); break; } @@ -2614,7 +2577,7 @@ ahd_linux_dv_thread(void *data) */ ahd_lock(ahd, &s); while (LIST_FIRST(&ahd->pending_scbs) != NULL) { - ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_EMPTY; + ahd->platform_data->flags |= AIC_DV_WAIT_SIMQ_EMPTY; ahd_unlock(ahd, &s); down_interruptible(&ahd->platform_data->dv_sem); ahd_lock(ahd, &s); @@ -2624,8 +2587,8 @@ ahd_linux_dv_thread(void *data) * Wait for the SIMQ to be released so that DV is the * only reason the queue is frozen. */ - while (AHD_DV_SIMQ_FROZEN(ahd) == 0) { - ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_RELEASE; + while (AIC_DV_SIMQ_FROZEN(ahd) == 0) { + ahd->platform_data->flags |= AIC_DV_WAIT_SIMQ_RELEASE; ahd_unlock(ahd, &s); down_interruptible(&ahd->platform_data->dv_sem); ahd_lock(ahd, &s); @@ -2636,14 +2599,17 @@ ahd_linux_dv_thread(void *data) ahd_linux_dv_target(ahd, target); ahd_lock(ahd, &s); - ahd->platform_data->flags &= ~AHD_DV_ACTIVE; - ahd_unlock(ahd, &s); + ahd->platform_data->flags &= ~AIC_DV_ACTIVE; /* * Release the SIMQ so that normal commands are * allowed to continue on the bus. */ - ahd_release_simq(ahd); + aic_release_simq_locked(ahd); + + ahd_unlock(ahd, &s); + + scsi_unblock_requests(ahd->platform_data->host); } up(&ahd->platform_data->eh_sem); return (0); @@ -2656,7 +2622,7 @@ ahd_linux_kill_dv_thread(struct ahd_soft ahd_lock(ahd, &s); if (ahd->platform_data->dv_pid != 0) { - ahd->platform_data->flags |= AHD_DV_SHUTDOWN; + ahd->platform_data->flags |= AIC_DV_SHUTDOWN; ahd_unlock(ahd, &s); up(&ahd->platform_data->dv_sem); @@ -2676,10 +2642,10 @@ ahd_linux_kill_dv_thread(struct ahd_soft /* * Mark the dv thread as already dead. This * avoids attempting to kill it a second time. - * This is necessary because we must kill the - * DV thread before calling ahd_free() in the + * This is necessary because we must kill our + * threads before calling ahd_free() in the * module shutdown case to avoid bogus locking - * in the SCSI mid-layer, but we ahd_free() is + * in the SCSI mid-layer, but when ahd_free() is * called without killing the DV thread in the * instance detach case, so ahd_platform_free() * calls us again to verify that the DV thread @@ -2699,10 +2665,10 @@ ahd_linux_kill_dv_thread(struct ahd_soft ahd_set_dv_state(ahd, targ, newstate, __LINE__) static __inline void -ahd_set_dv_state(struct ahd_softc *ahd, struct ahd_linux_target *targ, - ahd_dv_state newstate, u_int line) +ahd_set_dv_state(struct ahd_softc *ahd, struct aic_linux_target *targ, + aic_dv_state newstate, u_int line) { - ahd_dv_state oldstate; + aic_dv_state oldstate; oldstate = targ->dv_state; #ifdef AHD_DEBUG @@ -2722,7 +2688,7 @@ static void ahd_linux_dv_target(struct ahd_softc *ahd, u_int target_offset) { struct ahd_devinfo devinfo; - struct ahd_linux_target *targ; + struct aic_linux_target *targ; struct scsi_cmnd *cmd; struct scsi_device *scsi_dev; struct scsi_sense_data *sense; @@ -2736,7 +2702,7 @@ ahd_linux_dv_target(struct ahd_softc *ah echo_size = 0; ahd_lock(ahd, &s); targ = ahd->platform_data->targets[target_offset]; - if (targ == NULL || (targ->flags & AHD_DV_REQUIRED) == 0) { + if (targ == NULL || (targ->flags & AIC_DV_REQUIRED) == 0) { ahd_unlock(ahd, &s); return; } @@ -2759,14 +2725,14 @@ ahd_linux_dv_target(struct ahd_softc *ah scsi_dev->channel = devinfo.channel - 'A'; ahd->platform_data->dv_scsi_dev = scsi_dev; - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_INQ_SHORT_ASYNC); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_INQ_SHORT_ASYNC); - while (targ->dv_state != AHD_DV_STATE_EXIT) { + while (targ->dv_state != AIC_DV_STATE_EXIT) { timeout = AHD_LINUX_DV_TIMEOUT; switch (targ->dv_state) { - case AHD_DV_STATE_INQ_SHORT_ASYNC: - case AHD_DV_STATE_INQ_ASYNC: - case AHD_DV_STATE_INQ_ASYNC_VERIFY: + case AIC_DV_STATE_INQ_SHORT_ASYNC: + case AIC_DV_STATE_INQ_ASYNC: + case AIC_DV_STATE_INQ_ASYNC_VERIFY: /* * Set things to async narrow to reduce the * chance that the INQ will fail. @@ -2778,36 +2744,36 @@ ahd_linux_dv_target(struct ahd_softc *ah AHD_TRANS_GOAL, /*paused*/FALSE); ahd_unlock(ahd, &s); timeout = 10 * HZ; - targ->flags &= ~AHD_INQ_VALID; + targ->flags &= ~AIC_INQ_VALID; /* FALLTHROUGH */ - case AHD_DV_STATE_INQ_VERIFY: + case AIC_DV_STATE_INQ_VERIFY: { u_int inq_len; - if (targ->dv_state == AHD_DV_STATE_INQ_SHORT_ASYNC) + if (targ->dv_state == AIC_DV_STATE_INQ_SHORT_ASYNC) inq_len = AHD_LINUX_DV_INQ_SHORT_LEN; else inq_len = targ->inq_data->additional_length + 5; ahd_linux_dv_inq(ahd, cmd, &devinfo, targ, inq_len); break; } - case AHD_DV_STATE_TUR: - case AHD_DV_STATE_BUSY: + case AIC_DV_STATE_TUR: + case AIC_DV_STATE_BUSY: timeout = 5 * HZ; ahd_linux_dv_tur(ahd, cmd, &devinfo); break; - case AHD_DV_STATE_REBD: + case AIC_DV_STATE_REBD: ahd_linux_dv_rebd(ahd, cmd, &devinfo, targ); break; - case AHD_DV_STATE_WEB: + case AIC_DV_STATE_WEB: ahd_linux_dv_web(ahd, cmd, &devinfo, targ); break; - case AHD_DV_STATE_REB: + case AIC_DV_STATE_REB: ahd_linux_dv_reb(ahd, cmd, &devinfo, targ); break; - case AHD_DV_STATE_SU: + case AIC_DV_STATE_SU: ahd_linux_dv_su(ahd, cmd, &devinfo, targ); timeout = 50 * HZ; break; @@ -2819,8 +2785,6 @@ ahd_linux_dv_target(struct ahd_softc *ah } /* Queue the command and wait for it to complete */ - /* Abuse eh_timeout in the scsi_cmnd struct for our purposes */ - init_timer(&cmd->eh_timeout); #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) /* @@ -2830,7 +2794,9 @@ ahd_linux_dv_target(struct ahd_softc *ah */ timeout += HZ; #endif - scsi_add_timer(cmd, timeout, ahd_linux_dv_timeout); + init_timer(&cmd->eh_timeout); + cmd->timeout_per_command = timeout; + /* * In 2.5.X, it is assumed that all calls from the * "midlayer" (which we are emulating) will have the @@ -2849,13 +2815,14 @@ ahd_linux_dv_target(struct ahd_softc *ah spin_unlock_irqrestore(&io_request_lock, s); #endif down_interruptible(&ahd->platform_data->dv_cmd_sem); + /* * Wait for the SIMQ to be released so that DV is the * only reason the queue is frozen. */ ahd_lock(ahd, &s); - while (AHD_DV_SIMQ_FROZEN(ahd) == 0) { - ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_RELEASE; + while (AIC_DV_SIMQ_FROZEN(ahd) == 0) { + ahd->platform_data->flags |= AIC_DV_WAIT_SIMQ_RELEASE; ahd_unlock(ahd, &s); down_interruptible(&ahd->platform_data->dv_sem); ahd_lock(ahd, &s); @@ -2866,7 +2833,7 @@ ahd_linux_dv_target(struct ahd_softc *ah } out: - if ((targ->flags & AHD_INQ_VALID) != 0 + if ((targ->flags & AIC_INQ_VALID) != 0 && ahd_linux_get_device(ahd, devinfo.channel - 'A', devinfo.target, devinfo.lun, /*alloc*/FALSE) == NULL) { @@ -2877,7 +2844,7 @@ out: * parameters found in the inquiry string. */ ahd_linux_filter_inquiry(ahd, &devinfo); - if ((targ->flags & (AHD_BASIC_DV|AHD_ENHANCED_DV)) != 0) { + if ((targ->flags & (AIC_BASIC_DV|AIC_ENHANCED_DV)) != 0) { ahd_print_devinfo(ahd, &devinfo); printf("DV failed to configure device. " "Please file a bug report against " @@ -2902,7 +2869,7 @@ out: free(targ->dv_buffer1, M_DEVBUF); targ->dv_buffer1 = NULL; } - targ->flags &= ~AHD_DV_REQUIRED; + targ->flags &= ~AIC_DV_REQUIRED; if (targ->refcount == 0) ahd_linux_free_target(ahd, targ); ahd_unlock(ahd, &s); @@ -2911,13 +2878,13 @@ out: static void ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ) + struct aic_linux_target *targ) { u_int32_t status; status = aic_error_action(cmd, targ->inq_data, - ahd_cmd_get_transaction_status(cmd), - ahd_cmd_get_scsi_status(cmd)); + aic_cmd_get_transaction_status(cmd), + aic_cmd_get_scsi_status(cmd)); #ifdef AHD_DEBUG @@ -2930,8 +2897,8 @@ ahd_linux_dv_transition(struct ahd_softc #endif switch (targ->dv_state) { - case AHD_DV_STATE_INQ_SHORT_ASYNC: - case AHD_DV_STATE_INQ_ASYNC: + case AIC_DV_STATE_INQ_SHORT_ASYNC: + case AIC_DV_STATE_INQ_ASYNC: switch (status & SS_MASK) { case SS_NOP: { @@ -2940,21 +2907,21 @@ ahd_linux_dv_transition(struct ahd_softc } case SS_INQ_REFRESH: AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; case SS_TUR: case SS_RETRY: AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) targ->dv_state_retry--; if ((status & SS_ERRMASK) == EBUSY) - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_BUSY); if (targ->dv_state_retry < 10) break; /* FALLTHROUGH */ default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); #ifdef AHD_DEBUG if (ahd_debug & AHD_SHOW_DV) { ahd_print_devinfo(ahd, devinfo); @@ -2964,7 +2931,7 @@ ahd_linux_dv_transition(struct ahd_softc break; } break; - case AHD_DV_STATE_INQ_ASYNC_VERIFY: + case AIC_DV_STATE_INQ_ASYNC_VERIFY: switch (status & SS_MASK) { case SS_NOP: { @@ -2978,12 +2945,12 @@ ahd_linux_dv_transition(struct ahd_softc * Try from the top again. */ AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; } AHD_SET_DV_STATE(ahd, targ, targ->dv_state+1); - targ->flags |= AHD_INQ_VALID; + targ->flags |= AIC_INQ_VALID; if (ahd_linux_user_dv_setting(ahd) == 0) break; @@ -2996,33 +2963,33 @@ ahd_linux_dv_transition(struct ahd_softc default: case SID_SPI_CLOCK_ST: /* Assume only basic DV is supported. */ - targ->flags |= AHD_BASIC_DV; + targ->flags |= AIC_BASIC_DV; break; case SID_SPI_CLOCK_DT: case SID_SPI_CLOCK_DT_ST: - targ->flags |= AHD_ENHANCED_DV; + targ->flags |= AIC_ENHANCED_DV; break; } break; } case SS_INQ_REFRESH: AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; case SS_TUR: case SS_RETRY: AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) targ->dv_state_retry--; if ((status & SS_ERRMASK) == EBUSY) - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_BUSY); if (targ->dv_state_retry < 10) break; /* FALLTHROUGH */ default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); #ifdef AHD_DEBUG if (ahd_debug & AHD_SHOW_DV) { ahd_print_devinfo(ahd, devinfo); @@ -3032,14 +2999,14 @@ ahd_linux_dv_transition(struct ahd_softc break; } break; - case AHD_DV_STATE_INQ_VERIFY: + case AIC_DV_STATE_INQ_VERIFY: switch (status & SS_MASK) { case SS_NOP: { if (memcmp(targ->inq_data, targ->dv_buffer, AHD_LINUX_DV_INQ_LEN) == 0) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); break; } @@ -3061,7 +3028,7 @@ ahd_linux_dv_transition(struct ahd_softc #endif if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); break; } /* @@ -3074,18 +3041,18 @@ ahd_linux_dv_transition(struct ahd_softc } case SS_INQ_REFRESH: AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; case SS_TUR: case SS_RETRY: AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) { targ->dv_state_retry--; } else if ((status & SSQ_FALLBACK) != 0) { if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); + AIC_DV_STATE_EXIT); break; } /* @@ -3094,12 +3061,12 @@ ahd_linux_dv_transition(struct ahd_softc */ targ->dv_state_retry = 0; } else if ((status & SS_ERRMASK) == EBUSY) - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_BUSY); if (targ->dv_state_retry < 10) break; /* FALLTHROUGH */ default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); #ifdef AHD_DEBUG if (ahd_debug & AHD_SHOW_DV) { ahd_print_devinfo(ahd, devinfo); @@ -3110,33 +3077,33 @@ ahd_linux_dv_transition(struct ahd_softc } break; - case AHD_DV_STATE_TUR: + case AIC_DV_STATE_TUR: switch (status & SS_MASK) { case SS_NOP: - if ((targ->flags & AHD_BASIC_DV) != 0) { + if ((targ->flags & AIC_BASIC_DV) != 0) { ahd_linux_filter_inquiry(ahd, devinfo); AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_VERIFY); - } else if ((targ->flags & AHD_ENHANCED_DV) != 0) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_REBD); + AIC_DV_STATE_INQ_VERIFY); + } else if ((targ->flags & AIC_ENHANCED_DV) != 0) { + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_REBD); } else { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); } break; case SS_RETRY: case SS_TUR: if ((status & SS_ERRMASK) == EBUSY) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_BUSY); break; } AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) { targ->dv_state_retry--; } else if ((status & SSQ_FALLBACK) != 0) { if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); + AIC_DV_STATE_EXIT); break; } /* @@ -3152,7 +3119,7 @@ ahd_linux_dv_transition(struct ahd_softc printf("DV TUR reties exhausted\n"); } #endif - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); break; } if (status & SSQ_DELAY) @@ -3160,25 +3127,25 @@ ahd_linux_dv_transition(struct ahd_softc break; case SS_START: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_SU); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_SU); break; case SS_INQ_REFRESH: AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); break; } break; - case AHD_DV_STATE_REBD: + case AIC_DV_STATE_REBD: switch (status & SS_MASK) { case SS_NOP: { uint32_t echo_size; - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_WEB); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_WEB); echo_size = scsi_3btoul(&targ->dv_buffer[1]); echo_size &= 0x1FFF; #ifdef AHD_DEBUG @@ -3188,7 +3155,17 @@ ahd_linux_dv_transition(struct ahd_softc } #endif if (echo_size == 0) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + /* + * Fall back to basic DV. + */ + if (bootverbose) { + ahd_print_devinfo(ahd, devinfo); + printf("Echo Buffer unavailable. " + "Performing basic DV.\n"); + } + targ->flags &= ~AIC_ENHANCED_DV; + targ->flags |= AIC_BASIC_DV; + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_TUR); break; } @@ -3203,11 +3180,11 @@ ahd_linux_dv_transition(struct ahd_softc } case SS_INQ_REFRESH: AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; case SS_RETRY: AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) targ->dv_state_retry--; if (targ->dv_state_retry <= 10) @@ -3226,30 +3203,30 @@ ahd_linux_dv_transition(struct ahd_softc * and try level 1 DV. */ ahd_linux_filter_inquiry(ahd, devinfo); - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_INQ_VERIFY); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_INQ_VERIFY); targ->dv_echo_size = 0; break; } break; - case AHD_DV_STATE_WEB: + case AIC_DV_STATE_WEB: switch (status & SS_MASK) { case SS_NOP: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_REB); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_REB); break; case SS_INQ_REFRESH: AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; case SS_RETRY: AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) { targ->dv_state_retry--; } else if ((status & SSQ_FALLBACK) != 0) { if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); + AIC_DV_STATE_EXIT); break; } /* @@ -3268,22 +3245,22 @@ ahd_linux_dv_transition(struct ahd_softc } #endif default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); break; } break; - case AHD_DV_STATE_REB: + case AIC_DV_STATE_REB: switch (status & SS_MASK) { case SS_NOP: if (memcmp(targ->dv_buffer, targ->dv_buffer1, targ->dv_echo_size) != 0) { if (ahd_linux_dv_fallback(ahd, devinfo) != 0) AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); + AIC_DV_STATE_EXIT); else AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_WEB); + AIC_DV_STATE_WEB); break; } @@ -3295,24 +3272,24 @@ ahd_linux_dv_transition(struct ahd_softc free(targ->dv_buffer1, M_DEVBUF); targ->dv_buffer1 = NULL; } - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); break; case SS_INQ_REFRESH: AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; case SS_RETRY: AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) { targ->dv_state_retry--; } else if ((status & SSQ_FALLBACK) != 0) { if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); + AIC_DV_STATE_EXIT); break; } - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_WEB); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_WEB); } if (targ->dv_state_retry <= 10) { if ((status & (SSQ_DELAY_RANDOM|SSQ_DELAY))!= 0) @@ -3327,35 +3304,35 @@ ahd_linux_dv_transition(struct ahd_softc #endif /* FALLTHROUGH */ default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); break; } break; - case AHD_DV_STATE_SU: + case AIC_DV_STATE_SU: switch (status & SS_MASK) { case SS_NOP: case SS_INQ_REFRESH: AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); break; } break; - case AHD_DV_STATE_BUSY: + case AIC_DV_STATE_BUSY: switch (status & SS_MASK) { case SS_NOP: case SS_INQ_REFRESH: AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; case SS_TUR: case SS_RETRY: AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) { targ->dv_state_retry--; } else if (targ->dv_state_retry < 60) { @@ -3368,11 +3345,11 @@ ahd_linux_dv_transition(struct ahd_softc printf("DV BUSY reties exhausted\n"); } #endif - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); } break; default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); break; } break; @@ -3380,7 +3357,7 @@ ahd_linux_dv_transition(struct ahd_softc default: printf("%s: Invalid DV completion state %d\n", ahd_name(ahd), targ->dv_state); - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + AHD_SET_DV_STATE(ahd, targ, AIC_DV_STATE_EXIT); break; } } @@ -3400,7 +3377,7 @@ ahd_linux_dv_fill_cmd(struct ahd_softc * */ static void ahd_linux_dv_inq(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, struct ahd_linux_target *targ, + struct ahd_devinfo *devinfo, struct aic_linux_target *targ, u_int request_length) { @@ -3413,7 +3390,7 @@ ahd_linux_dv_inq(struct ahd_softc *ahd, if (targ->inq_data == NULL) targ->inq_data = malloc(AHD_LINUX_DV_INQ_LEN, M_DEVBUF, M_WAITOK); - if (targ->dv_state > AHD_DV_STATE_INQ_ASYNC) { + if (targ->dv_state > AIC_DV_STATE_INQ_ASYNC) { if (targ->dv_buffer != NULL) free(targ->dv_buffer, M_DEVBUF); targ->dv_buffer = malloc(AHD_LINUX_DV_INQ_LEN, @@ -3426,7 +3403,7 @@ ahd_linux_dv_inq(struct ahd_softc *ahd, cmd->cmnd[0] = INQUIRY; cmd->cmnd[4] = request_length; cmd->request_bufflen = request_length; - if (targ->dv_state > AHD_DV_STATE_INQ_ASYNC) + if (targ->dv_state > AIC_DV_STATE_INQ_ASYNC) cmd->request_buffer = targ->dv_buffer; else cmd->request_buffer = targ->inq_data; @@ -3455,7 +3432,7 @@ ahd_linux_dv_tur(struct ahd_softc *ahd, static void ahd_linux_dv_rebd(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, struct ahd_linux_target *targ) + struct ahd_devinfo *devinfo, struct aic_linux_target *targ) { #ifdef AHD_DEBUG @@ -3480,7 +3457,7 @@ ahd_linux_dv_rebd(struct ahd_softc *ahd, static void ahd_linux_dv_web(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, struct ahd_linux_target *targ) + struct ahd_devinfo *devinfo, struct aic_linux_target *targ) { #ifdef AHD_DEBUG @@ -3502,7 +3479,7 @@ ahd_linux_dv_web(struct ahd_softc *ahd, static void ahd_linux_dv_reb(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, struct ahd_linux_target *targ) + struct ahd_devinfo *devinfo, struct aic_linux_target *targ) { #ifdef AHD_DEBUG @@ -3525,7 +3502,7 @@ ahd_linux_dv_reb(struct ahd_softc *ahd, static void ahd_linux_dv_su(struct ahd_softc *ahd, struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ) + struct aic_linux_target *targ) { u_int le; @@ -3560,7 +3537,7 @@ ahd_linux_dv_fallback(struct ahd_softc * static int ahd_linux_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) { - struct ahd_linux_target *targ; + struct aic_linux_target *targ; struct ahd_initiator_tinfo *tinfo; struct ahd_transinfo *goal; struct ahd_tmode_tstate *tstate; @@ -3731,7 +3708,7 @@ ahd_linux_fallback(struct ahd_softc *ahd return (0); } -static void +void ahd_linux_dv_timeout(struct scsi_cmnd *cmd) { struct ahd_softc *ahd; @@ -3765,29 +3742,18 @@ ahd_linux_dv_timeout(struct scsi_cmnd *c * error code. */ if ((scb->flags & SCB_SENSE) != 0) - ahd_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); + aic_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); else - ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); + aic_set_transaction_status(scb, CAM_CMD_TIMEOUT); ahd_reset_channel(ahd, cmd->device->channel + 'A', /*initiate*/TRUE); - /* - * Add a minimal bus settle delay for devices that are slow to - * respond after bus resets. - */ - ahd_freeze_simq(ahd); - init_timer(&ahd->platform_data->reset_timer); - ahd->platform_data->reset_timer.data = (u_long)ahd; - ahd->platform_data->reset_timer.expires = jiffies + HZ / 2; - ahd->platform_data->reset_timer.function = - (ahd_linux_callback_t *)ahd_release_simq; - add_timer(&ahd->platform_data->reset_timer); - if (ahd_linux_next_device_to_run(ahd) != NULL) - ahd_schedule_runq(ahd); + if (aic_linux_next_device_to_run(ahd) != NULL) + aic_schedule_runq(ahd); ahd_linux_run_complete_queue(ahd); ahd_unlock(ahd, &flags); } -static void +void ahd_linux_dv_complete(struct scsi_cmnd *cmd) { struct ahd_softc *ahd; @@ -3809,7 +3775,7 @@ ahd_linux_dv_complete(struct scsi_cmnd * } static void -ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ) +ahd_linux_generate_dv_pattern(struct aic_linux_target *targ) { uint16_t b; u_int i; @@ -3975,8 +3941,8 @@ ahd_linux_setup_user_rd_strm_settings(st * Determines the queue depth for a given device. */ static void -ahd_linux_device_queue_depth(struct ahd_softc *ahd, - struct ahd_linux_device *dev) +aic_linux_device_queue_depth(struct ahd_softc *ahd, + struct aic_linux_device *dev) { struct ahd_devinfo devinfo; u_int tags; @@ -3999,10 +3965,10 @@ ahd_linux_device_queue_depth(struct ahd_ } } -static void -ahd_linux_run_device_queue(struct ahd_softc *ahd, struct ahd_linux_device *dev) +void +ahd_linux_run_device_queue(struct ahd_softc *ahd, struct aic_linux_device *dev) { - struct ahd_cmd *acmd; + struct aic_cmd *acmd; struct scsi_cmnd *cmd; struct scb *scb; struct hardware_scb *hscb; @@ -4011,7 +3977,7 @@ ahd_linux_run_device_queue(struct ahd_so u_int col_idx; uint16_t mask; - if ((dev->flags & AHD_DEV_ON_RUN_LIST) != 0) + if ((dev->flags & AIC_DEV_ON_RUN_LIST) != 0) panic("running device on run list"); while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL @@ -4022,11 +3988,11 @@ ahd_linux_run_device_queue(struct ahd_so * running is because the whole controller Q is frozen. */ if (ahd->platform_data->qfrozen != 0 - && AHD_DV_SIMQ_FROZEN(ahd) == 0) { + && AIC_DV_SIMQ_FROZEN(ahd) == 0) { TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links); - dev->flags |= AHD_DEV_ON_RUN_LIST; + dev->flags |= AIC_DEV_ON_RUN_LIST; return; } @@ -4037,7 +4003,7 @@ ahd_linux_run_device_queue(struct ahd_so */ tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, cmd->device->id, &tstate); - if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) == 0 + if ((dev->flags & (AIC_DEV_Q_TAGGED|AIC_DEV_Q_BASIC)) == 0 || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { col_idx = AHD_NEVER_COL_IDX; } else { @@ -4047,13 +4013,14 @@ ahd_linux_run_device_queue(struct ahd_so if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links); - dev->flags |= AHD_DEV_ON_RUN_LIST; + dev->flags |= AIC_DEV_ON_RUN_LIST; ahd->flags |= AHD_RESOURCE_SHORTAGE; return; } TAILQ_REMOVE(&dev->busyq, acmd, acmd_links.tqe); scb->io_ctx = cmd; scb->platform_data->dev = dev; + scb->platform_data->flags = 0; hscb = scb->hscb; cmd->host_scribble = (char *)scb; @@ -4069,7 +4036,7 @@ ahd_linux_run_device_queue(struct ahd_so if ((ahd->user_discenable & mask) != 0) hscb->control |= DISCENB; - if (AHD_DV_CMD(cmd) != 0) + if (AIC_DV_CMD(cmd) != 0) scb->flags |= SCB_SILENT; if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) @@ -4080,7 +4047,7 @@ ahd_linux_run_device_queue(struct ahd_so scb->hscb->control |= MK_MESSAGE; } - if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) { + if ((dev->flags & (AIC_DEV_Q_TAGGED|AIC_DEV_Q_BASIC)) != 0) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) int msg_bytes; uint8_t tag_msgs[2]; @@ -4092,8 +4059,8 @@ ahd_linux_run_device_queue(struct ahd_so dev->commands_since_idle_or_otag = 0; } else #endif - if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH - && (dev->flags & AHD_DEV_Q_TAGGED) != 0) { + if (dev->commands_since_idle_or_otag == AIC_OTAG_THRESH + && (dev->flags & AIC_DEV_Q_TAGGED) != 0) { hscb->control |= MSG_ORDERED_TASK; dev->commands_since_idle_or_otag = 0; } else { @@ -4105,8 +4072,9 @@ ahd_linux_run_device_queue(struct ahd_so memcpy(hscb->shared_data.idata.cdb, cmd->cmnd, hscb->cdb_len); scb->sg_count = 0; - ahd_set_residual(scb, 0); - ahd_set_sense_residual(scb, 0); + aic_set_residual(scb, 0); + aic_set_sense_residual(scb, 0); + scb->platform_data->xfer_len = 0; if (cmd->use_sg != 0) { void *sg; struct scatterlist *cur_seg; @@ -4115,18 +4083,15 @@ ahd_linux_run_device_queue(struct ahd_so cur_seg = (struct scatterlist *)cmd->request_buffer; dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); - nseg = pci_map_sg(ahd->dev_softc, cur_seg, - cmd->use_sg, dir); - scb->platform_data->xfer_len = 0; + nseg = aic_map_sg(ahd, cur_seg, cmd->use_sg, dir); for (sg = scb->sg_list; nseg > 0; nseg--, cur_seg++) { bus_addr_t addr; bus_size_t len; addr = sg_dma_address(cur_seg); len = sg_dma_len(cur_seg); - scb->platform_data->xfer_len += len; - sg = ahd_sg_setup(ahd, scb, sg, addr, len, - /*last*/nseg == 1); + sg = ahd_linux_sg_setup(ahd, scb, sg, addr, len, + /*last*/nseg == 1); } } else if (cmd->request_bufflen != 0) { void *sg; @@ -4135,13 +4100,13 @@ ahd_linux_run_device_queue(struct ahd_so sg = scb->sg_list; dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); - addr = pci_map_single(ahd->dev_softc, + addr = aic_map_single(ahd, cmd->request_buffer, cmd->request_bufflen, dir); - scb->platform_data->xfer_len = cmd->request_bufflen; scb->platform_data->buf_busaddr = addr; - sg = ahd_sg_setup(ahd, scb, sg, addr, - cmd->request_bufflen, /*last*/TRUE); + sg = ahd_linux_sg_setup(ahd, scb, sg, addr, + cmd->request_bufflen, + /*last*/TRUE); } LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); @@ -4157,9 +4122,10 @@ ahd_linux_run_device_queue(struct ahd_so dev->target->cmds_since_error = 0; } - if ((dev->flags & AHD_DEV_PERIODIC_OTAG) != 0) + if ((dev->flags & AIC_DEV_PERIODIC_OTAG) != 0) dev->commands_since_idle_or_otag++; scb->flags |= SCB_ACTIVE; + aic_scb_timer_start(scb); ahd_queue_scb(ahd, scb); } } @@ -4177,8 +4143,8 @@ ahd_linux_isr(int irq, void *dev_id, str ahd = (struct ahd_softc *) dev_id; ahd_lock(ahd, &flags); ours = ahd_intr(ahd); - if (ahd_linux_next_device_to_run(ahd) != NULL) - ahd_schedule_runq(ahd); + if (aic_linux_next_device_to_run(ahd) != NULL) + aic_schedule_runq(ahd); ahd_linux_run_complete_queue(ahd); ahd_unlock(ahd, &flags); return IRQ_RETVAL(ours); @@ -4192,10 +4158,10 @@ ahd_platform_flushwork(struct ahd_softc ; } -static struct ahd_linux_target* +static struct aic_linux_target* ahd_linux_alloc_target(struct ahd_softc *ahd, u_int channel, u_int target) { - struct ahd_linux_target *targ; + struct aic_linux_target *targ; targ = malloc(sizeof(*targ), M_DEVBUF, M_NOWAIT); if (targ == NULL) @@ -4203,14 +4169,14 @@ ahd_linux_alloc_target(struct ahd_softc memset(targ, 0, sizeof(*targ)); targ->channel = channel; targ->target = target; - targ->ahd = ahd; - targ->flags = AHD_DV_REQUIRED; + targ->softc = ahd; + targ->flags = AIC_DV_REQUIRED; ahd->platform_data->targets[target] = targ; return (targ); } static void -ahd_linux_free_target(struct ahd_softc *ahd, struct ahd_linux_target *targ) +ahd_linux_free_target(struct ahd_softc *ahd, struct aic_linux_target *targ) { struct ahd_devinfo devinfo; struct ahd_initiator_tinfo *tinfo; @@ -4246,11 +4212,11 @@ ahd_linux_free_target(struct ahd_softc * free(targ, M_DEVBUF); } -static struct ahd_linux_device* +static struct aic_linux_device* ahd_linux_alloc_device(struct ahd_softc *ahd, - struct ahd_linux_target *targ, u_int lun) + struct aic_linux_target *targ, u_int lun) { - struct ahd_linux_device *dev; + struct aic_linux_device *dev; dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT); if (dev == NULL) @@ -4258,7 +4224,7 @@ ahd_linux_alloc_device(struct ahd_softc memset(dev, 0, sizeof(*dev)); init_timer(&dev->timer); TAILQ_INIT(&dev->busyq); - dev->flags = AHD_DEV_UNCONFIGURED; + dev->flags = AIC_DEV_UNCONFIGURED; dev->lun = lun; dev->target = targ; @@ -4281,9 +4247,9 @@ ahd_linux_alloc_device(struct ahd_softc } static void -ahd_linux_free_device(struct ahd_softc *ahd, struct ahd_linux_device *dev) +ahd_linux_free_device(struct ahd_softc *ahd, struct aic_linux_device *dev) { - struct ahd_linux_target *targ; + struct aic_linux_target *targ; del_timer(&dev->timer); targ = dev->target; @@ -4291,7 +4257,7 @@ ahd_linux_free_device(struct ahd_softc * free(dev, M_DEVBUF); targ->refcount--; if (targ->refcount == 0 - && (targ->flags & AHD_DV_REQUIRED) == 0) + && (targ->flags & AIC_DV_REQUIRED) == 0) ahd_linux_free_target(ahd, targ); } @@ -4303,7 +4269,7 @@ ahd_send_async(struct ahd_softc *ahd, ch case AC_TRANSFER_NEG: { char buf[80]; - struct ahd_linux_target *targ; + struct aic_linux_target *targ; struct info_str info; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; @@ -4391,6 +4357,20 @@ ahd_send_async(struct ahd_softc *ahd, ch channel - 'A'); } #endif + /* + * Add a minimal bus settle delay for devices that are slow to + * respond after bus resets. + */ + if ((ahd->platform_data->flags & AIC_BUS_SETTLE_TIMER) == 0) { + aic_freeze_simq(ahd); + ahd->platform_data->flags |= AIC_BUS_SETTLE_TIMER; + ahd->platform_data->bus_settle_timer.expires = + jiffies + (AIC79XX_RESET_DELAY * HZ)/1000; + add_timer(&ahd->platform_data->bus_settle_timer); + } else { + mod_timer(&ahd->platform_data->bus_settle_timer, + jiffies + (AIC79XX_RESET_DELAY * HZ)/1000); + } break; default: panic("ahd_send_async: Unexpected async event"); @@ -4404,14 +4384,18 @@ void ahd_done(struct ahd_softc *ahd, struct scb *scb) { Scsi_Cmnd *cmd; - struct ahd_linux_device *dev; + struct aic_linux_device *dev; if ((scb->flags & SCB_ACTIVE) == 0) { printf("SCB %d done'd twice\n", SCB_GET_TAG(scb)); ahd_dump_card_state(ahd); panic("Stopping for safety"); } + LIST_REMOVE(scb, pending_links); + if ((scb->flags & SCB_TIMEDOUT) != 0) + LIST_REMOVE(scb, timedout_links); + cmd = scb->io_ctx; dev = scb->platform_data->dev; dev->active--; @@ -4429,11 +4413,11 @@ ahd_done(struct ahd_softc *ahd, struct s * the sense buffer looks "sane". */ cmd->sense_buffer[0] = 0; - if (ahd_get_transaction_status(scb) == CAM_REQ_INPROG) { + if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) { uint32_t amount_xferred; amount_xferred = - ahd_get_transfer_length(scb) - ahd_get_residual(scb); + aic_get_transfer_length(scb) - aic_get_residual(scb); if ((scb->flags & SCB_TRANSMISSION_ERROR) != 0) { #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) { @@ -4441,7 +4425,17 @@ ahd_done(struct ahd_softc *ahd, struct s printf("Set CAM_UNCOR_PARITY\n"); } #endif - ahd_set_transaction_status(scb, CAM_UNCOR_PARITY); + aic_set_transaction_status(scb, CAM_UNCOR_PARITY); +#ifdef AHD_REPORT_UNDERFLOWS + /* + * This code is disabled by default as some + * clients of the SCSI system do not properly + * initialize the underflow parameter. This + * results in spurious termination of commands + * that complete as expected (e.g. underflow is + * allowed as command can return variable amounts + * of data. + */ } else if (amount_xferred < scb->io_ctx->underflow) { u_int i; @@ -4453,30 +4447,31 @@ ahd_done(struct ahd_softc *ahd, struct s ahd_print_path(ahd, scb); printf("Saw underflow (%ld of %ld bytes). " "Treated as error\n", - ahd_get_residual(scb), - ahd_get_transfer_length(scb)); - ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR); + aic_get_residual(scb), + aic_get_transfer_length(scb)); + aic_set_transaction_status(scb, CAM_DATA_RUN_ERR); +#endif } else { - ahd_set_transaction_status(scb, CAM_REQ_CMP); + aic_set_transaction_status(scb, CAM_REQ_CMP); } - } else if (ahd_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) { + } else if (aic_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) { ahd_linux_handle_scsi_status(ahd, dev, scb); - } else if (ahd_get_transaction_status(scb) == CAM_SEL_TIMEOUT) { - dev->flags |= AHD_DEV_UNCONFIGURED; - if (AHD_DV_CMD(cmd) == FALSE) - dev->target->flags &= ~AHD_DV_REQUIRED; + } else if (aic_get_transaction_status(scb) == CAM_SEL_TIMEOUT) { + dev->flags |= AIC_DEV_UNCONFIGURED; + if (AIC_DV_CMD(cmd) == FALSE) + dev->target->flags &= ~AIC_DV_REQUIRED; } /* * Start DV for devices that require it assuming the first command * sent does not result in a selection timeout. */ - if (ahd_get_transaction_status(scb) != CAM_SEL_TIMEOUT - && (dev->target->flags & AHD_DV_REQUIRED) != 0) + if (aic_get_transaction_status(scb) != CAM_SEL_TIMEOUT + && (dev->target->flags & AIC_DV_REQUIRED) != 0) ahd_linux_start_dv(ahd); if (dev->openings == 1 - && ahd_get_transaction_status(scb) == CAM_REQ_CMP - && ahd_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL) + && aic_get_transaction_status(scb) == CAM_REQ_CMP + && aic_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL) dev->tag_success_count++; /* * Some devices deal with temporary internal resource @@ -4485,7 +4480,7 @@ ahd_done(struct ahd_softc *ahd, struct s * back to our previous queue depth. */ if ((dev->openings + dev->active) < dev->maxtags - && dev->tag_success_count > AHD_TAG_SUCCESS_INTERVAL) { + && dev->tag_success_count > AIC_TAG_SUCCESS_INTERVAL) { dev->tag_success_count = 0; dev->openings++; } @@ -4494,39 +4489,68 @@ ahd_done(struct ahd_softc *ahd, struct s dev->commands_since_idle_or_otag = 0; if (TAILQ_EMPTY(&dev->busyq)) { - if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0 - && dev->active == 0 - && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0) + if ((dev->flags & AIC_DEV_UNCONFIGURED) != 0 + && dev->active == 0) ahd_linux_free_device(ahd, dev); - } else if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) { + } else if ((dev->flags & AIC_DEV_ON_RUN_LIST) == 0) { TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links); - dev->flags |= AHD_DEV_ON_RUN_LIST; + dev->flags |= AIC_DEV_ON_RUN_LIST; } if ((scb->flags & SCB_RECOVERY_SCB) != 0) { printf("Recovery SCB completes\n"); - if (ahd_get_transaction_status(scb) == CAM_BDR_SENT - || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED) - ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); - if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { - scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; + if (aic_get_transaction_status(scb) == CAM_BDR_SENT + || aic_get_transaction_status(scb) == CAM_REQ_ABORTED) + aic_set_transaction_status(scb, CAM_CMD_TIMEOUT); + if ((scb->platform_data->flags & AIC_SCB_UP_EH_SEM) != 0) { + scb->platform_data->flags &= ~AIC_SCB_UP_EH_SEM; up(&ahd->platform_data->eh_sem); + } else { + struct scb *list_scb; + + /* + * We were able to complete the command successfully, + * so reinstate the timeouts for all other pending + * commands. + */ + LIST_FOREACH(list_scb, + &ahd->pending_scbs, pending_links) { + + aic_scb_timer_start(list_scb); + } } } + if ((scb->platform_data->flags & AIC_TIMEOUT_ACTIVE) == 0) { + /* + * The completion handler believes that + * commands without active timers running + * have lost the race of completing before + * their timer expires. Since commands in + * our busy queues do not have timers running, + * appease the mid-layer by adding a timer + * now. This timer will be immediately + * canceled by the midlayer. + */ + scsi_add_timer(cmd, 60*HZ, aic_linux_midlayer_timeout); + } + + if ((scb->platform_data->flags & AIC_RELEASE_SIMQ) != 0) + aic_release_simq_locked(ahd); + ahd_free_scb(ahd, scb); ahd_linux_queue_cmd_complete(ahd, cmd); - if ((ahd->platform_data->flags & AHD_DV_WAIT_SIMQ_EMPTY) != 0 + if ((ahd->platform_data->flags & AIC_DV_WAIT_SIMQ_EMPTY) != 0 && LIST_FIRST(&ahd->pending_scbs) == NULL) { - ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_EMPTY; + ahd->platform_data->flags &= ~AIC_DV_WAIT_SIMQ_EMPTY; up(&ahd->platform_data->dv_sem); } } static void ahd_linux_handle_scsi_status(struct ahd_softc *ahd, - struct ahd_linux_device *dev, struct scb *scb) + struct aic_linux_device *dev, struct scb *scb) { struct ahd_devinfo devinfo; @@ -4546,7 +4570,7 @@ ahd_linux_handle_scsi_status(struct ahd_ * we don't clobber the device with too many * commands. */ - switch (ahd_get_scsi_status(scb)) { + switch (aic_get_scsi_status(scb)) { default: break; case SCSI_STATUS_CHECK_COND: @@ -4560,13 +4584,15 @@ ahd_linux_handle_scsi_status(struct ahd_ */ cmd = scb->io_ctx; if ((scb->flags & (SCB_SENSE|SCB_PKT_SENSE)) != 0) { - struct scsi_status_iu_header *siu; - u_int sense_size; - u_int sense_offset; + struct scsi_status_iu_header *siu; + struct scsi_sense_data *sense; + u_int sense_size; + u_int sense_offset; + int error_code, sense_key, asc, ascq; if (scb->flags & SCB_SENSE) { sense_size = MIN(sizeof(struct scsi_sense_data) - - ahd_get_sense_residual(scb), + - aic_get_sense_residual(scb), sizeof(cmd->sense_buffer)); sense_offset = 0; } else { @@ -4581,10 +4607,10 @@ ahd_linux_handle_scsi_status(struct ahd_ sense_offset = SIU_SENSE_OFFSET(siu); } + sense = (struct scsi_sense_data *) + (ahd_get_sense_buf(ahd, scb) + sense_offset); memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); - memcpy(cmd->sense_buffer, - ahd_get_sense_buf(ahd, scb) - + sense_offset, sense_size); + memcpy(cmd->sense_buffer, sense, sense_size); cmd->result |= (DRIVER_SENSE << 24); #ifdef AHD_DEBUG @@ -4601,6 +4627,23 @@ ahd_linux_handle_scsi_status(struct ahd_ printf("\n"); } #endif + /* + * If this is not a DV command and the target + * provides some status that makes us believe + * that the target has changed (power on reset, + * etc.) kick off a DV scan to re-validate the + * device. + */ + if (AIC_DV_CMD(cmd) != 0) + break; + + scsi_extract_sense(sense, &error_code, + &sense_key, &asc, &ascq); + if (error_code == SSD_CURRENT_ERROR + && sense_key == SSD_KEY_UNIT_ATTENTION + && asc == 0x29 + && (ascq == 0 || ascq == 1)) + dev->target->flags |= AIC_DV_REQUIRED; } break; } @@ -4640,7 +4683,7 @@ ahd_linux_handle_scsi_status(struct ahd_ * this device. */ if (dev->last_queuefull_same_count - == AHD_LOCK_TAGS_COUNT) { + == AIC_LOCK_TAGS_COUNT) { dev->maxtags = dev->active; ahd_print_path(ahd, scb); printf("Locking max tag count at %d\n", @@ -4650,10 +4693,10 @@ ahd_linux_handle_scsi_status(struct ahd_ dev->tags_on_last_queuefull = dev->active; dev->last_queuefull_same_count = 0; } - ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); - ahd_set_scsi_status(scb, SCSI_STATUS_OK); + aic_set_transaction_status(scb, CAM_REQUEUE_REQ); + aic_set_scsi_status(scb, SCSI_STATUS_OK); ahd_platform_set_tags(ahd, &devinfo, - (dev->flags & AHD_DEV_Q_BASIC) + (dev->flags & AIC_DEV_Q_BASIC) ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); break; } @@ -4663,9 +4706,9 @@ ahd_linux_handle_scsi_status(struct ahd_ */ dev->openings = 1; ahd_platform_set_tags(ahd, &devinfo, - (dev->flags & AHD_DEV_Q_BASIC) + (dev->flags & AIC_DEV_Q_BASIC) ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); - ahd_set_scsi_status(scb, SCSI_STATUS_BUSY); + aic_set_scsi_status(scb, SCSI_STATUS_BUSY); /* FALLTHROUGH */ } case SCSI_STATUS_BUSY: @@ -4673,13 +4716,13 @@ ahd_linux_handle_scsi_status(struct ahd_ * Set a short timer to defer sending commands for * a bit since Linux will not delay in this case. */ - if ((dev->flags & AHD_DEV_TIMER_ACTIVE) != 0) { + if ((dev->flags & AIC_DEV_TIMER_ACTIVE) != 0) { printf("%s:%c:%d: Device Timer still active during " "busy processing\n", ahd_name(ahd), dev->target->channel, dev->target->target); break; } - dev->flags |= AHD_DEV_TIMER_ACTIVE; + dev->flags |= AIC_DEV_TIMER_ACTIVE; dev->qfrozen++; init_timer(&dev->timer); dev->timer.data = (u_long)dev; @@ -4705,9 +4748,9 @@ ahd_linux_queue_cmd_complete(struct ahd_ * not guarantee the order that aborted commands will be * returned to us. */ - struct ahd_completeq *completeq; - struct ahd_cmd *list_cmd; - struct ahd_cmd *acmd; + struct aic_completeq *completeq; + struct aic_cmd *list_cmd; + struct aic_cmd *acmd; /* * Map CAM error codes into Linux Error codes. We @@ -4715,13 +4758,13 @@ ahd_linux_queue_cmd_complete(struct ahd_ * full error information available when making * state change decisions. */ - if (AHD_DV_CMD(cmd) == FALSE) { + if (AIC_DV_CMD(cmd) == FALSE) { uint32_t status; u_int new_status; - status = ahd_cmd_get_transaction_status(cmd); + status = aic_cmd_get_transaction_status(cmd); if (status != CAM_REQ_CMP) { - struct ahd_linux_device *dev; + struct aic_linux_device *dev; struct ahd_devinfo devinfo; cam_status cam_status; uint32_t action; @@ -4741,8 +4784,8 @@ ahd_linux_queue_cmd_complete(struct ahd_ dev->target->channel == 0 ? 'A':'B', ROLE_INITIATOR); - scsi_status = ahd_cmd_get_scsi_status(cmd); - cam_status = ahd_cmd_get_transaction_status(cmd); + scsi_status = aic_cmd_get_scsi_status(cmd); + cam_status = aic_cmd_get_transaction_status(cmd); action = aic_error_action(cmd, dev->target->inq_data, cam_status, scsi_status); if ((action & SSQ_FALLBACK) != 0) { @@ -4785,7 +4828,17 @@ no_fallback: new_status = DID_PARITY; break; case CAM_CMD_TIMEOUT: - new_status = DID_TIME_OUT; + /* + * Returning DID_TIME_OUT will + * wake up the error recovery + * thread instead of doing the + * command retry we desire. Since + * we have already recovered the + * command, returning DID_ERROR + * will cause a retry up to the + * retry limit for this command. + */ + new_status = DID_ERROR; break; case CAM_UA_ABORT: case CAM_REQ_CMP_ERR: @@ -4815,7 +4868,7 @@ no_fallback: if (cmd->retries > 0) cmd->retries--; new_status = DID_OK; - ahd_cmd_set_scsi_status(cmd, SCSI_STATUS_CHECK_COND); + aic_cmd_set_scsi_status(cmd, SCSI_STATUS_CHECK_COND); cmd->result |= (DRIVER_SENSE << 24); memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); @@ -4829,12 +4882,12 @@ no_fallback: break; } - ahd_cmd_set_transaction_status(cmd, new_status); + aic_cmd_set_transaction_status(cmd, new_status); } completeq = &ahd->platform_data->completeq; list_cmd = TAILQ_FIRST(completeq); - acmd = (struct ahd_cmd *)cmd; + acmd = (struct aic_cmd *)cmd; while (list_cmd != NULL && acmd_scsi_cmd(list_cmd).serial_number < acmd_scsi_cmd(acmd).serial_number) @@ -4854,7 +4907,7 @@ ahd_linux_filter_inquiry(struct ahd_soft struct ahd_transinfo *goal; struct ahd_transinfo *curr; struct ahd_tmode_tstate *tstate; - struct ahd_linux_device *dev; + struct aic_linux_device *dev; u_int width; u_int period; u_int offset; @@ -4876,9 +4929,9 @@ ahd_linux_filter_inquiry(struct ahd_soft sid = (struct scsi_inquiry_data *)dev->target->inq_data; if (SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) { - dev->flags &= ~AHD_DEV_UNCONFIGURED; + dev->flags &= ~AIC_DEV_UNCONFIGURED; } else { - dev->flags |= AHD_DEV_UNCONFIGURED; + dev->flags |= AIC_DEV_UNCONFIGURED; return; } @@ -4944,48 +4997,6 @@ ahd_linux_filter_inquiry(struct ahd_soft AHD_TRANS_GOAL, /*paused*/FALSE); } -void -ahd_freeze_simq(struct ahd_softc *ahd) -{ - ahd->platform_data->qfrozen++; - if (ahd->platform_data->qfrozen == 1) { - scsi_block_requests(ahd->platform_data->host); - ahd_platform_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS, - CAM_LUN_WILDCARD, SCB_LIST_NULL, - ROLE_INITIATOR, CAM_REQUEUE_REQ); - } -} - -void -ahd_release_simq(struct ahd_softc *ahd) -{ - u_long s; - int unblock_reqs; - - unblock_reqs = 0; - ahd_lock(ahd, &s); - if (ahd->platform_data->qfrozen > 0) - ahd->platform_data->qfrozen--; - if (ahd->platform_data->qfrozen == 0) { - unblock_reqs = 1; - } - if (AHD_DV_SIMQ_FROZEN(ahd) - && ((ahd->platform_data->flags & AHD_DV_WAIT_SIMQ_RELEASE) != 0)) { - ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_RELEASE; - up(&ahd->platform_data->dv_sem); - } - ahd_schedule_runq(ahd); - ahd_unlock(ahd, &s); - /* - * There is still a race here. The mid-layer - * should keep its own freeze count and use - * a bottom half handler to run the queues - * so we can unblock with our own lock held. - */ - if (unblock_reqs) - scsi_unblock_requests(ahd->platform_data->host); -} - static void ahd_linux_sem_timeout(u_long arg) { @@ -4996,8 +5007,8 @@ ahd_linux_sem_timeout(u_long arg) scb = (struct scb *)arg; ahd = scb->ahd_softc; ahd_lock(ahd, &s); - if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { - scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; + if ((scb->platform_data->flags & AIC_SCB_UP_EH_SEM) != 0) { + scb->platform_data->flags &= ~AIC_SCB_UP_EH_SEM; up(&ahd->platform_data->eh_sem); } ahd_unlock(ahd, &s); @@ -5006,20 +5017,21 @@ ahd_linux_sem_timeout(u_long arg) static void ahd_linux_dev_timed_unfreeze(u_long arg) { - struct ahd_linux_device *dev; + struct aic_linux_device *dev; struct ahd_softc *ahd; u_long s; - dev = (struct ahd_linux_device *)arg; - ahd = dev->target->ahd; + dev = (struct aic_linux_device *)arg; + ahd = dev->target->softc; ahd_lock(ahd, &s); - dev->flags &= ~AHD_DEV_TIMER_ACTIVE; + dev->flags &= ~AIC_DEV_TIMER_ACTIVE; if (dev->qfrozen > 0) dev->qfrozen--; if (dev->qfrozen == 0 - && (dev->flags & AHD_DEV_ON_RUN_LIST) == 0) + && (dev->flags & AIC_DEV_ON_RUN_LIST) == 0) ahd_linux_run_device_queue(ahd, dev); - if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0 + if ((dev->flags & AIC_DEV_UNCONFIGURED) != 0 + && TAILQ_EMPTY(&dev->busyq) && dev->active == 0) ahd_linux_free_device(ahd, dev); ahd_unlock(ahd, &s); @@ -5028,17 +5040,26 @@ ahd_linux_dev_timed_unfreeze(u_long arg) void ahd_platform_dump_card_state(struct ahd_softc *ahd) { - struct ahd_linux_device *dev; + struct Scsi_Host *host; + struct aic_linux_device *dev; int target; int maxtarget; int lun; int i; + host = ahd->platform_data->host; + printf("%s: Host Status: Failed(%d) %s%s%s\n", + ahd_name(ahd), + host->host_failed, + host->eh_active ? "eh_active " : "", + host->host_blocked ? "host_blocked " : "", + host->host_self_blocked ? "host_self_blocked " : ""); + maxtarget = (ahd->features & AHD_WIDE) ? 15 : 7; for (target = 0; target <=maxtarget; target++) { for (lun = 0; lun < AHD_NUM_LUNS; lun++) { - struct ahd_cmd *acmd; + struct aic_cmd *acmd; dev = ahd_linux_get_device(ahd, 0, target, lun, /*alloc*/FALSE); @@ -5077,20 +5098,18 @@ static void __exit ahd_linux_exit(void) { struct ahd_softc *ahd; - u_long l; /* - * Shutdown DV threads before going into the SCSI mid-layer. + * Shutdown our threads before going into the SCSI mid-layer. * This avoids situations where the mid-layer locks the entire * kernel so that waiting for our DV threads to exit leads * to deadlock. */ - ahd_list_lock(&l); TAILQ_FOREACH(ahd, &ahd_tailq, links) { ahd_linux_kill_dv_thread(ahd); + ahd_terminate_recovery_thread(ahd); } - ahd_list_unlock(&l); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* * In 2.4 we have to unregister from the PCI core _after_ diff -puN drivers/scsi/aic7xxx/aic79xx_osm.h~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic79xx_osm.h --- 25/drivers/scsi/aic7xxx/aic79xx_osm.h~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic79xx_osm.h Wed Dec 24 12:15:38 2003 @@ -36,51 +36,22 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#133 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#153 $ * */ #ifndef _AIC79XX_LINUX_H_ #define _AIC79XX_LINUX_H_ -#include -#include -#include -#include -#include -#include #include -#include -#include -#include #ifndef KERNEL_VERSION #define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) -#include /* For tasklet support. */ #include -#include -#else -#include #endif -/* Core SCSI definitions */ -#define AIC_LIB_PREFIX ahd -#include "scsi.h" -#include "hosts.h" - -/* Name space conflict with BSD queue macros */ -#ifdef LIST_HEAD -#undef LIST_HEAD -#endif - -#include "cam.h" -#include "queue.h" -#include "scsi_message.h" -#include "scsi_iu.h" -#include "aiclib.h" - /*********************************** Debugging ********************************/ #ifdef CONFIG_AIC79XX_DEBUG_ENABLE #ifdef CONFIG_AIC79XX_DEBUG_MASK @@ -96,188 +67,27 @@ /* No debugging code. */ #endif -/********************************** Misc Macros *******************************/ -#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) -#define powerof2(x) ((((x)-1)&(x))==0) - -/************************* Forward Declarations *******************************/ -struct ahd_softc; -typedef struct pci_dev *ahd_dev_softc_t; -typedef Scsi_Cmnd *ahd_io_ctx_t; - -/******************************* Byte Order ***********************************/ -#define ahd_htobe16(x) cpu_to_be16(x) -#define ahd_htobe32(x) cpu_to_be32(x) -#define ahd_htobe64(x) cpu_to_be64(x) -#define ahd_htole16(x) cpu_to_le16(x) -#define ahd_htole32(x) cpu_to_le32(x) -#define ahd_htole64(x) cpu_to_le64(x) - -#define ahd_be16toh(x) be16_to_cpu(x) -#define ahd_be32toh(x) be32_to_cpu(x) -#define ahd_be64toh(x) be64_to_cpu(x) -#define ahd_le16toh(x) le16_to_cpu(x) -#define ahd_le32toh(x) le32_to_cpu(x) -#define ahd_le64toh(x) le64_to_cpu(x) - -#ifndef LITTLE_ENDIAN -#define LITTLE_ENDIAN 1234 -#endif - -#ifndef BIG_ENDIAN -#define BIG_ENDIAN 4321 -#endif - -#ifndef BYTE_ORDER -#if defined(__BIG_ENDIAN) -#define BYTE_ORDER BIG_ENDIAN -#endif -#if defined(__LITTLE_ENDIAN) -#define BYTE_ORDER LITTLE_ENDIAN -#endif -#endif /* BYTE_ORDER */ - -/************************* Configuration Data *********************************/ -extern uint32_t aic79xx_allow_memio; -extern int aic79xx_detect_complete; -extern Scsi_Host_Template aic79xx_driver_template; - -/***************************** Bus Space/DMA **********************************/ - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17) -typedef dma_addr_t bus_addr_t; -#else -typedef uint32_t bus_addr_t; -#endif -typedef uint32_t bus_size_t; - -typedef enum { - BUS_SPACE_MEMIO, - BUS_SPACE_PIO -} bus_space_tag_t; - -typedef union { - u_long ioport; - volatile uint8_t *maddr; -} bus_space_handle_t; - -typedef struct bus_dma_segment -{ - bus_addr_t ds_addr; - bus_size_t ds_len; -} bus_dma_segment_t; - -struct ahd_linux_dma_tag -{ - bus_size_t alignment; - bus_size_t boundary; - bus_size_t maxsize; -}; -typedef struct ahd_linux_dma_tag* bus_dma_tag_t; - -struct ahd_linux_dmamap -{ - bus_addr_t bus_addr; -}; -typedef struct ahd_linux_dmamap* bus_dmamap_t; - -typedef int bus_dma_filter_t(void*, bus_addr_t); -typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int); - -#define BUS_DMA_WAITOK 0x0 -#define BUS_DMA_NOWAIT 0x1 -#define BUS_DMA_ALLOCNOW 0x2 -#define BUS_DMA_LOAD_SEGS 0x4 /* - * Argument is an S/G list not - * a single buffer. - */ - -#define BUS_SPACE_MAXADDR 0xFFFFFFFF -#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF -#define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF - -int ahd_dma_tag_create(struct ahd_softc *, bus_dma_tag_t /*parent*/, - bus_size_t /*alignment*/, bus_size_t /*boundary*/, - bus_addr_t /*lowaddr*/, bus_addr_t /*highaddr*/, - bus_dma_filter_t*/*filter*/, void */*filterarg*/, - bus_size_t /*maxsize*/, int /*nsegments*/, - bus_size_t /*maxsegsz*/, int /*flags*/, - bus_dma_tag_t */*dma_tagp*/); - -void ahd_dma_tag_destroy(struct ahd_softc *, bus_dma_tag_t /*tag*/); - -int ahd_dmamem_alloc(struct ahd_softc *, bus_dma_tag_t /*dmat*/, - void** /*vaddr*/, int /*flags*/, - bus_dmamap_t* /*mapp*/); - -void ahd_dmamem_free(struct ahd_softc *, bus_dma_tag_t /*dmat*/, - void* /*vaddr*/, bus_dmamap_t /*map*/); - -void ahd_dmamap_destroy(struct ahd_softc *, bus_dma_tag_t /*tag*/, - bus_dmamap_t /*map*/); - -int ahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t /*dmat*/, - bus_dmamap_t /*map*/, void * /*buf*/, - bus_size_t /*buflen*/, bus_dmamap_callback_t *, - void */*callback_arg*/, int /*flags*/); - -int ahd_dmamap_unload(struct ahd_softc *, bus_dma_tag_t, bus_dmamap_t); - -/* - * Operations performed by ahd_dmamap_sync(). - */ -#define BUS_DMASYNC_PREREAD 0x01 /* pre-read synchronization */ -#define BUS_DMASYNC_POSTREAD 0x02 /* post-read synchronization */ -#define BUS_DMASYNC_PREWRITE 0x04 /* pre-write synchronization */ -#define BUS_DMASYNC_POSTWRITE 0x08 /* post-write synchronization */ - -/* - * XXX - * ahd_dmamap_sync is only used on buffers allocated with - * the pci_alloc_consistent() API. Although I'm not sure how - * this works on architectures with a write buffer, Linux does - * not have an API to sync "coherent" memory. Perhaps we need - * to do an mb()? - */ -#define ahd_dmamap_sync(ahd, dma_tag, dmamap, offset, len, op) - -/************************** Timer DataStructures ******************************/ -typedef struct timer_list ahd_timer_t; - /********************************** Includes **********************************/ +/* Core SCSI definitions */ +#define AIC_LIB_PREFIX ahd +#define AIC_CONST_PREFIX AHD + #ifdef CONFIG_AIC79XX_REG_PRETTY_PRINT #define AIC_DEBUG_REGISTERS 1 #else #define AIC_DEBUG_REGISTERS 0 #endif -#include "aic79xx.h" - -/***************************** Timer Facilities *******************************/ -#define ahd_timer_init init_timer -#define ahd_timer_stop del_timer_sync -typedef void ahd_linux_callback_t (u_long); -static __inline void ahd_timer_reset(ahd_timer_t *timer, u_int usec, - ahd_callback_t *func, void *arg); -static __inline void ahd_scb_timer_reset(struct scb *scb, u_int usec); - -static __inline void -ahd_timer_reset(ahd_timer_t *timer, u_int usec, ahd_callback_t *func, void *arg) -{ - struct ahd_softc *ahd; +#define AIC_CORE_INCLUDE "aic79xx.h" +#include "aiclib.h" - ahd = (struct ahd_softc *)arg; - del_timer(timer); - timer->data = (u_long)arg; - timer->expires = jiffies + (usec * HZ)/1000000; - timer->function = (ahd_linux_callback_t*)func; - add_timer(timer); -} +/************************* Configuration Data *********************************/ +extern uint32_t aic79xx_allow_memio; +extern int aic79xx_detect_complete; +extern Scsi_Host_Template aic79xx_driver_template; -static __inline void -ahd_scb_timer_reset(struct scb *scb, u_int usec) -{ - mod_timer(&scb->io_ctx->eh_timeout, jiffies + (usec * HZ)/1000000); -} +/***************************** Domain Validation ******************************/ +void ahd_linux_dv_complete(Scsi_Cmnd *cmd); +void ahd_linux_dv_timeout(struct scsi_cmnd *cmd); /***************************** SMP support ************************************/ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,17) @@ -292,193 +102,7 @@ ahd_scb_timer_reset(struct scb *scb, u_i #define AHD_SCSI_HAS_HOST_LOCK 0 #endif -#define AIC79XX_DRIVER_VERSION "1.3.9" - -/**************************** Front End Queues ********************************/ -/* - * Data structure used to cast the Linux struct scsi_cmnd to something - * that allows us to use the queue macros. The linux structure has - * plenty of space to hold the links fields as required by the queue - * macros, but the queue macors require them to have the correct type. - */ -struct ahd_cmd_internal { - /* Area owned by the Linux scsi layer. */ - uint8_t private[offsetof(struct scsi_cmnd, SCp.Status)]; - union { - STAILQ_ENTRY(ahd_cmd) ste; - LIST_ENTRY(ahd_cmd) le; - TAILQ_ENTRY(ahd_cmd) tqe; - } links; - uint32_t end; -}; - -struct ahd_cmd { - union { - struct ahd_cmd_internal icmd; - struct scsi_cmnd scsi_cmd; - } un; -}; - -#define acmd_icmd(cmd) ((cmd)->un.icmd) -#define acmd_scsi_cmd(cmd) ((cmd)->un.scsi_cmd) -#define acmd_links un.icmd.links - -/*************************** Device Data Structures ***************************/ -/* - * A per probed device structure used to deal with some error recovery - * scenarios that the Linux mid-layer code just doesn't know how to - * handle. The structure allocated for a device only becomes persistent - * after a successfully completed inquiry command to the target when - * that inquiry data indicates a lun is present. - */ -TAILQ_HEAD(ahd_busyq, ahd_cmd); -typedef enum { - AHD_DEV_UNCONFIGURED = 0x01, - AHD_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ - AHD_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ - AHD_DEV_ON_RUN_LIST = 0x08, /* Queued to be run later */ - AHD_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ - AHD_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ - AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ - AHD_DEV_SLAVE_CONFIGURED = 0x80 /* slave_configure() has been called */ -} ahd_linux_dev_flags; - -struct ahd_linux_target; -struct ahd_linux_device { - TAILQ_ENTRY(ahd_linux_device) links; - struct ahd_busyq busyq; - - /* - * The number of transactions currently - * queued to the device. - */ - int active; - - /* - * The currently allowed number of - * transactions that can be queued to - * the device. Must be signed for - * conversion from tagged to untagged - * mode where the device may have more - * than one outstanding active transaction. - */ - int openings; - - /* - * A positive count indicates that this - * device's queue is halted. - */ - u_int qfrozen; - - /* - * Cumulative command counter. - */ - u_long commands_issued; - - /* - * The number of tagged transactions when - * running at our current opening level - * that have been successfully received by - * this device since the last QUEUE FULL. - */ - u_int tag_success_count; -#define AHD_TAG_SUCCESS_INTERVAL 50 - - ahd_linux_dev_flags flags; - - /* - * Per device timer. - */ - struct timer_list timer; - - /* - * The high limit for the tags variable. - */ - u_int maxtags; - - /* - * The computed number of tags outstanding - * at the time of the last QUEUE FULL event. - */ - u_int tags_on_last_queuefull; - - /* - * How many times we have seen a queue full - * with the same number of tags. This is used - * to stop our adaptive queue depth algorithm - * on devices with a fixed number of tags. - */ - u_int last_queuefull_same_count; -#define AHD_LOCK_TAGS_COUNT 50 - - /* - * How many transactions have been queued - * without the device going idle. We use - * this statistic to determine when to issue - * an ordered tag to prevent transaction - * starvation. This statistic is only updated - * if the AHD_DEV_PERIODIC_OTAG flag is set - * on this device. - */ - u_int commands_since_idle_or_otag; -#define AHD_OTAG_THRESH 500 - - int lun; - Scsi_Device *scsi_device; - struct ahd_linux_target *target; -}; - -typedef enum { - AHD_DV_REQUIRED = 0x01, - AHD_INQ_VALID = 0x02, - AHD_BASIC_DV = 0x04, - AHD_ENHANCED_DV = 0x08 -} ahd_linux_targ_flags; - -/* DV States */ -typedef enum { - AHD_DV_STATE_EXIT = 0, - AHD_DV_STATE_INQ_SHORT_ASYNC, - AHD_DV_STATE_INQ_ASYNC, - AHD_DV_STATE_INQ_ASYNC_VERIFY, - AHD_DV_STATE_TUR, - AHD_DV_STATE_REBD, - AHD_DV_STATE_INQ_VERIFY, - AHD_DV_STATE_WEB, - AHD_DV_STATE_REB, - AHD_DV_STATE_SU, - AHD_DV_STATE_BUSY -} ahd_dv_state; - -struct ahd_linux_target { - struct ahd_linux_device *devices[AHD_NUM_LUNS]; - int channel; - int target; - int refcount; - struct ahd_transinfo last_tinfo; - struct ahd_softc *ahd; - ahd_linux_targ_flags flags; - struct scsi_inquiry_data *inq_data; - /* - * The next "fallback" period to use for narrow/wide transfers. - */ - uint8_t dv_next_narrow_period; - uint8_t dv_next_wide_period; - uint8_t dv_max_width; - uint8_t dv_max_ppr_options; - uint8_t dv_last_ppr_options; - u_int dv_echo_size; - ahd_dv_state dv_state; - u_int dv_state_retry; - uint8_t *dv_buffer; - uint8_t *dv_buffer1; - - /* - * Cumulative counter of errors. - */ - u_long errors_detected; - u_long cmds_since_error; -}; +#define AIC79XX_DRIVER_VERSION "2.0.5" /********************* Definitions Required by the Core ***********************/ /* @@ -500,100 +124,21 @@ extern u_int ahd_linux_nseg; #define AHD_NSEG 128 #endif -/* - * Per-SCB OSM storage. - */ -typedef enum { - AHD_SCB_UP_EH_SEM = 0x1 -} ahd_linux_scb_flags; - -struct scb_platform_data { - struct ahd_linux_device *dev; - bus_addr_t buf_busaddr; - uint32_t xfer_len; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) - uint32_t resid; /* Transfer residual */ -#endif - uint32_t sense_resid; /* Auto-Sense residual */ - ahd_linux_scb_flags flags; -}; - -/* - * Define a structure used for each host adapter. All members are - * aligned on a boundary >= the size of the member to honor the - * alignment restrictions of the various platforms supported by - * this driver. - */ -typedef enum { - AHD_DV_WAIT_SIMQ_EMPTY = 0x01, - AHD_DV_WAIT_SIMQ_RELEASE = 0x02, - AHD_DV_ACTIVE = 0x04, - AHD_DV_SHUTDOWN = 0x08, - AHD_RUN_CMPLT_Q_TIMER = 0x10 -} ahd_linux_softc_flags; - -TAILQ_HEAD(ahd_completeq, ahd_cmd); - -struct ahd_platform_data { - /* - * Fields accessed from interrupt context. - */ - struct ahd_linux_target *targets[AHD_NUM_TARGETS]; - TAILQ_HEAD(, ahd_linux_device) device_runq; - struct ahd_completeq completeq; - - spinlock_t spin_lock; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - struct tasklet_struct runq_tasklet; -#endif - u_int qfrozen; - pid_t dv_pid; - struct timer_list completeq_timer; - struct timer_list reset_timer; - struct timer_list stats_timer; - struct semaphore eh_sem; - struct semaphore dv_sem; - struct semaphore dv_cmd_sem; /* XXX This needs to be in - * the target struct - */ - struct scsi_device *dv_scsi_dev; - struct Scsi_Host *host; /* pointer to scsi host */ -#define AHD_LINUX_NOIRQ ((uint32_t)~0) - uint32_t irq; /* IRQ for this adapter */ - uint32_t bios_address; - uint32_t mem_busaddr; /* Mem Base Addr */ - bus_addr_t hw_dma_mask; - ahd_linux_softc_flags flags; -}; - -/************************** OS Utility Wrappers *******************************/ -#define printf printk -#define M_NOWAIT GFP_ATOMIC -#define M_WAITOK 0 -#define malloc(size, type, flags) kmalloc(size, flags) -#define free(ptr, type) kfree(ptr) - -static __inline void ahd_delay(long); -static __inline void -ahd_delay(long usec) -{ - /* - * udelay on Linux can have problems for - * multi-millisecond waits. Wait at most - * 1024us per call. - */ - while (usec > 0) { - udelay(usec % 1024); - usec -= 1024; - } -} - +/************************** Error Recovery ************************************/ +static __inline void ahd_wakeup_recovery_thread(struct ahd_softc *ahd); + +static __inline void +ahd_wakeup_recovery_thread(struct ahd_softc *ahd) +{ + up(&ahd->platform_data->recovery_sem); +} + +int ahd_spawn_recovery_thread(struct ahd_softc *ahd); +void ahd_terminate_recovery_thread(struct ahd_softc *ahd); +void ahd_set_recoveryscb(struct ahd_softc *ahd, + struct scb *scb); /***************************** Low Level I/O **********************************/ -#if defined(__powerpc__) || defined(__i386__) || defined(__ia64__) -#define MMAPIO -#endif - static __inline uint8_t ahd_inb(struct ahd_softc * ahd, long port); static __inline uint16_t ahd_inw_atomic(struct ahd_softc * ahd, long port); static __inline void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val); @@ -603,21 +148,18 @@ static __inline void ahd_outsb(struct ah uint8_t *, int count); static __inline void ahd_insb(struct ahd_softc * ahd, long port, uint8_t *, int count); +static __inline void ahd_flush_device_writes(struct ahd_softc *); static __inline uint8_t ahd_inb(struct ahd_softc * ahd, long port) { uint8_t x; -#ifdef MMAPIO if (ahd->tags[0] == BUS_SPACE_MEMIO) { x = readb(ahd->bshs[0].maddr + port); } else { x = inb(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF)); } -#else - x = inb(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF)); -#endif mb(); return (x); } @@ -626,16 +168,12 @@ static __inline uint16_t ahd_inw_atomic(struct ahd_softc * ahd, long port) { uint8_t x; -#ifdef MMAPIO if (ahd->tags[0] == BUS_SPACE_MEMIO) { x = readw(ahd->bshs[0].maddr + port); } else { x = inw(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF)); } -#else - x = inw(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF)); -#endif mb(); return (x); } @@ -643,30 +181,22 @@ ahd_inw_atomic(struct ahd_softc * ahd, l static __inline void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val) { -#ifdef MMAPIO if (ahd->tags[0] == BUS_SPACE_MEMIO) { writeb(val, ahd->bshs[0].maddr + port); } else { outb(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF)); } -#else - outb(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF)); -#endif mb(); } static __inline void ahd_outw_atomic(struct ahd_softc * ahd, long port, uint16_t val) { -#ifdef MMAPIO if (ahd->tags[0] == BUS_SPACE_MEMIO) { writew(val, ahd->bshs[0].maddr + port); } else { outw(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF)); } -#else - outw(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF)); -#endif mb(); } @@ -698,6 +228,13 @@ ahd_insb(struct ahd_softc * ahd, long po *array++ = ahd_inb(ahd, port); } +static __inline void +ahd_flush_device_writes(struct ahd_softc *ahd) +{ + /* XXX Is this sufficient for all architectures??? */ + ahd_inb(ahd, INTSTAT); +} + /**************************** Initialization **********************************/ int ahd_linux_register_host(struct ahd_softc *, Scsi_Host_Template *); @@ -826,384 +363,29 @@ ahd_list_unlock(unsigned long *flags) } /******************************* PCI Definitions ******************************/ -/* - * PCIM_xxx: mask to locate subfield in register - * PCIR_xxx: config register offset - * PCIC_xxx: device class - * PCIS_xxx: device subclass - * PCIP_xxx: device programming interface - * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices) - * PCID_xxx: device ID - */ -#define PCIR_DEVVENDOR 0x00 -#define PCIR_VENDOR 0x00 -#define PCIR_DEVICE 0x02 -#define PCIR_COMMAND 0x04 -#define PCIM_CMD_PORTEN 0x0001 -#define PCIM_CMD_MEMEN 0x0002 -#define PCIM_CMD_BUSMASTEREN 0x0004 -#define PCIM_CMD_MWRICEN 0x0010 -#define PCIM_CMD_PERRESPEN 0x0040 -#define PCIM_CMD_SERRESPEN 0x0100 -#define PCIR_STATUS 0x06 -#define PCIR_REVID 0x08 -#define PCIR_PROGIF 0x09 -#define PCIR_SUBCLASS 0x0a -#define PCIR_CLASS 0x0b -#define PCIR_CACHELNSZ 0x0c -#define PCIR_LATTIMER 0x0d -#define PCIR_HEADERTYPE 0x0e -#define PCIM_MFDEV 0x80 -#define PCIR_BIST 0x0f -#define PCIR_CAP_PTR 0x34 - -/* config registers for header type 0 devices */ -#define PCIR_MAPS 0x10 -#define PCIR_SUBVEND_0 0x2c -#define PCIR_SUBDEV_0 0x2e - -/****************************** PCI-X definitions *****************************/ -#define PCIXR_COMMAND 0x96 -#define PCIXR_DEVADDR 0x98 -#define PCIXM_DEVADDR_FNUM 0x0003 /* Function Number */ -#define PCIXM_DEVADDR_DNUM 0x00F8 /* Device Number */ -#define PCIXM_DEVADDR_BNUM 0xFF00 /* Bus Number */ -#define PCIXR_STATUS 0x9A -#define PCIXM_STATUS_64BIT 0x0001 /* Active 64bit connection to device. */ -#define PCIXM_STATUS_133CAP 0x0002 /* Device is 133MHz capable */ -#define PCIXM_STATUS_SCDISC 0x0004 /* Split Completion Discarded */ -#define PCIXM_STATUS_UNEXPSC 0x0008 /* Unexpected Split Completion */ -#define PCIXM_STATUS_CMPLEXDEV 0x0010 /* Device Complexity (set == bridge) */ -#define PCIXM_STATUS_MAXMRDBC 0x0060 /* Maximum Burst Read Count */ -#define PCIXM_STATUS_MAXSPLITS 0x0380 /* Maximum Split Transactions */ -#define PCIXM_STATUS_MAXCRDS 0x1C00 /* Maximum Cumulative Read Size */ -#define PCIXM_STATUS_RCVDSCEM 0x2000 /* Received a Split Comp w/Error msg */ - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) extern struct pci_driver aic79xx_pci_driver; #endif -typedef enum -{ - AHD_POWER_STATE_D0, - AHD_POWER_STATE_D1, - AHD_POWER_STATE_D2, - AHD_POWER_STATE_D3 -} ahd_power_state; - -void ahd_power_state_change(struct ahd_softc *ahd, - ahd_power_state new_state); - /******************************* PCI Routines *********************************/ int ahd_linux_pci_init(void); void ahd_linux_pci_exit(void); int ahd_pci_map_registers(struct ahd_softc *ahd); int ahd_pci_map_int(struct ahd_softc *ahd); -static __inline uint32_t ahd_pci_read_config(ahd_dev_softc_t pci, - int reg, int width); - -static __inline uint32_t -ahd_pci_read_config(ahd_dev_softc_t pci, int reg, int width) -{ - switch (width) { - case 1: - { - uint8_t retval; - - pci_read_config_byte(pci, reg, &retval); - return (retval); - } - case 2: - { - uint16_t retval; - pci_read_config_word(pci, reg, &retval); - return (retval); - } - case 4: - { - uint32_t retval; - pci_read_config_dword(pci, reg, &retval); - return (retval); - } - default: - panic("ahd_pci_read_config: Read size too big"); - /* NOTREACHED */ - return (0); - } -} - -static __inline void ahd_pci_write_config(ahd_dev_softc_t pci, - int reg, uint32_t value, - int width); - -static __inline void -ahd_pci_write_config(ahd_dev_softc_t pci, int reg, uint32_t value, int width) -{ - switch (width) { - case 1: - pci_write_config_byte(pci, reg, value); - break; - case 2: - pci_write_config_word(pci, reg, value); - break; - case 4: - pci_write_config_dword(pci, reg, value); - break; - default: - panic("ahd_pci_write_config: Write size too big"); - /* NOTREACHED */ - } -} - -static __inline int ahd_get_pci_function(ahd_dev_softc_t); -static __inline int -ahd_get_pci_function(ahd_dev_softc_t pci) -{ - return (PCI_FUNC(pci->devfn)); -} - -static __inline int ahd_get_pci_slot(ahd_dev_softc_t); -static __inline int -ahd_get_pci_slot(ahd_dev_softc_t pci) -{ - return (PCI_SLOT(pci->devfn)); -} - -static __inline int ahd_get_pci_bus(ahd_dev_softc_t); -static __inline int -ahd_get_pci_bus(ahd_dev_softc_t pci) -{ - return (pci->bus->number); -} - -static __inline void ahd_flush_device_writes(struct ahd_softc *); -static __inline void -ahd_flush_device_writes(struct ahd_softc *ahd) -{ - /* XXX Is this sufficient for all architectures??? */ - ahd_inb(ahd, INTSTAT); -} - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0) -#define pci_map_sg(pdev, sg_list, nseg, direction) (nseg) -#define pci_unmap_sg(pdev, sg_list, nseg, direction) -#define sg_dma_address(sg) (VIRT_TO_BUS((sg)->address)) -#define sg_dma_len(sg) ((sg)->length) -#define pci_map_single(pdev, buffer, bufflen, direction) \ - (VIRT_TO_BUS(buffer)) -#define pci_unmap_single(pdev, buffer, buflen, direction) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) -#define ahd_pci_set_dma_mask pci_set_dma_mask -#else -/* - * Always "return" 0 for success. - */ -#define ahd_pci_set_dma_mask(dev_softc, mask) \ - (((dev_softc)->dma_mask = mask) && 0) -#endif /**************************** Proc FS Support *********************************/ -int ahd_linux_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); - -/*************************** Domain Validation ********************************/ -#define AHD_DV_CMD(cmd) ((cmd)->scsi_done == ahd_linux_dv_complete) -#define AHD_DV_SIMQ_FROZEN(ahd) \ - ((((ahd)->platform_data->flags & AHD_DV_ACTIVE) != 0) \ - && (ahd)->platform_data->qfrozen == 1) - -/*********************** Transaction Access Wrappers **************************/ -static __inline void ahd_cmd_set_transaction_status(Scsi_Cmnd *, uint32_t); -static __inline void ahd_set_transaction_status(struct scb *, uint32_t); -static __inline void ahd_cmd_set_scsi_status(Scsi_Cmnd *, uint32_t); -static __inline void ahd_set_scsi_status(struct scb *, uint32_t); -static __inline uint32_t ahd_cmd_get_transaction_status(Scsi_Cmnd *cmd); -static __inline uint32_t ahd_get_transaction_status(struct scb *); -static __inline uint32_t ahd_cmd_get_scsi_status(Scsi_Cmnd *cmd); -static __inline uint32_t ahd_get_scsi_status(struct scb *); -static __inline void ahd_set_transaction_tag(struct scb *, int, u_int); -static __inline u_long ahd_get_transfer_length(struct scb *); -static __inline int ahd_get_transfer_dir(struct scb *); -static __inline void ahd_set_residual(struct scb *, u_long); -static __inline void ahd_set_sense_residual(struct scb *scb, u_long resid); -static __inline u_long ahd_get_residual(struct scb *); -static __inline u_long ahd_get_sense_residual(struct scb *); -static __inline int ahd_perform_autosense(struct scb *); -static __inline uint32_t ahd_get_sense_bufsize(struct ahd_softc *, - struct scb *); -static __inline void ahd_notify_xfer_settings_change(struct ahd_softc *, - struct ahd_devinfo *); -static __inline void ahd_platform_scb_free(struct ahd_softc *ahd, - struct scb *scb); -static __inline void ahd_freeze_scb(struct scb *scb); - -static __inline -void ahd_cmd_set_transaction_status(Scsi_Cmnd *cmd, uint32_t status) -{ - cmd->result &= ~(CAM_STATUS_MASK << 16); - cmd->result |= status << 16; -} - -static __inline -void ahd_set_transaction_status(struct scb *scb, uint32_t status) -{ - ahd_cmd_set_transaction_status(scb->io_ctx,status); -} - -static __inline -void ahd_cmd_set_scsi_status(Scsi_Cmnd *cmd, uint32_t status) -{ - cmd->result &= ~0xFFFF; - cmd->result |= status; -} - -static __inline -void ahd_set_scsi_status(struct scb *scb, uint32_t status) -{ - ahd_cmd_set_scsi_status(scb->io_ctx, status); -} - -static __inline -uint32_t ahd_cmd_get_transaction_status(Scsi_Cmnd *cmd) -{ - return ((cmd->result >> 16) & CAM_STATUS_MASK); -} - -static __inline -uint32_t ahd_get_transaction_status(struct scb *scb) -{ - return (ahd_cmd_get_transaction_status(scb->io_ctx)); -} - -static __inline -uint32_t ahd_cmd_get_scsi_status(Scsi_Cmnd *cmd) -{ - return (cmd->result & 0xFFFF); -} - -static __inline -uint32_t ahd_get_scsi_status(struct scb *scb) -{ - return (ahd_cmd_get_scsi_status(scb->io_ctx)); -} - -static __inline -void ahd_set_transaction_tag(struct scb *scb, int enabled, u_int type) -{ - /* - * Nothing to do for linux as the incoming transaction - * has no concept of tag/non tagged, etc. - */ -} - -static __inline -u_long ahd_get_transfer_length(struct scb *scb) -{ - return (scb->platform_data->xfer_len); -} - -static __inline -int ahd_get_transfer_dir(struct scb *scb) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,40) - return (scb->io_ctx->sc_data_direction); -#else - if (scb->io_ctx->bufflen == 0) - return (CAM_DIR_NONE); - - switch(scb->io_ctx->cmnd[0]) { - case 0x08: /* READ(6) */ - case 0x28: /* READ(10) */ - case 0xA8: /* READ(12) */ - return (CAM_DIR_IN); - case 0x0A: /* WRITE(6) */ - case 0x2A: /* WRITE(10) */ - case 0xAA: /* WRITE(12) */ - return (CAM_DIR_OUT); - default: - return (CAM_DIR_NONE); - } -#endif -} - -static __inline -void ahd_set_residual(struct scb *scb, u_long resid) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - scb->io_ctx->resid = resid; -#else - scb->platform_data->resid = resid; -#endif -} - -static __inline -void ahd_set_sense_residual(struct scb *scb, u_long resid) -{ - scb->platform_data->sense_resid = resid; -} - -static __inline -u_long ahd_get_residual(struct scb *scb) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - return (scb->io_ctx->resid); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +int ahd_linux_proc_info(char *, char **, off_t, int, int, int); #else - return (scb->platform_data->resid); +int ahd_linux_proc_info(struct Scsi_Host *, char *, char **, + off_t, int, int); #endif -} - -static __inline -u_long ahd_get_sense_residual(struct scb *scb) -{ - return (scb->platform_data->sense_resid); -} - -static __inline -int ahd_perform_autosense(struct scb *scb) -{ - /* - * We always perform autosense in Linux. - * On other platforms this is set on a - * per-transaction basis. - */ - return (1); -} - -static __inline uint32_t -ahd_get_sense_bufsize(struct ahd_softc *ahd, struct scb *scb) -{ - return (sizeof(struct scsi_sense_data)); -} - -static __inline void -ahd_notify_xfer_settings_change(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo) -{ - /* Nothing to do here for linux */ -} - -static __inline void -ahd_platform_scb_free(struct ahd_softc *ahd, struct scb *scb) -{ - ahd->flags &= ~AHD_RESOURCE_SHORTAGE; -} +/*********************** Transaction Access Wrappers **************************/ int ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg); void ahd_platform_free(struct ahd_softc *ahd); void ahd_platform_init(struct ahd_softc *ahd); void ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb); -void ahd_freeze_simq(struct ahd_softc *ahd); -void ahd_release_simq(struct ahd_softc *ahd); - -static __inline void -ahd_freeze_scb(struct scb *scb) -{ - if ((scb->io_ctx->result & (CAM_DEV_QFRZN << 16)) == 0) { - scb->io_ctx->result |= CAM_DEV_QFRZN << 16; - scb->platform_data->dev->qfrozen++; - } -} void ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, ahd_queue_alg); @@ -1221,9 +403,9 @@ void ahd_print_path(struct ahd_softc *, void ahd_platform_dump_card_state(struct ahd_softc *ahd); #ifdef CONFIG_PCI -#define AHD_PCI_CONFIG 1 +#define AIC_PCI_CONFIG 1 #else -#define AHD_PCI_CONFIG 0 +#define AIC_PCI_CONFIG 0 #endif #define bootverbose aic79xx_verbose extern uint32_t aic79xx_verbose; diff -puN drivers/scsi/aic7xxx/aic79xx_osm_pci.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic79xx_osm_pci.c --- 25/drivers/scsi/aic7xxx/aic79xx_osm_pci.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic79xx_osm_pci.c Wed Dec 24 12:15:38 2003 @@ -36,12 +36,18 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#23 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#29 $ */ #include "aic79xx_osm.h" #include "aic79xx_inline.h" +/* + * Include aiclib_pci.c as part of our + * "module dependencies are hard" work around. + */ +#include "aiclib_pci.c" + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) struct pci_device_id { @@ -52,11 +58,9 @@ static int ahd_linux_pci_dev_probe(struc const struct pci_device_id *ent); static int ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, u_long *base, u_long *base2); -#ifdef MMAPIO static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd, u_long *bus_addr, uint8_t **maddr); -#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) static void ahd_linux_pci_dev_remove(struct pci_dev *pdev); @@ -94,12 +98,14 @@ ahd_linux_pci_dev_remove(struct pci_dev if (ahd != NULL) { u_long s; + TAILQ_REMOVE(&ahd_tailq, ahd, links); + ahd_list_unlock(&l); ahd_lock(ahd, &s); ahd_intr_enable(ahd, FALSE); ahd_unlock(ahd, &s); ahd_free(ahd); - } - ahd_list_unlock(&l); + } else + ahd_list_unlock(&l); } #endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */ @@ -108,7 +114,7 @@ ahd_linux_pci_dev_probe(struct pci_dev * { char buf[80]; struct ahd_softc *ahd; - ahd_dev_softc_t pci; + aic_dev_softc_t dev; struct ahd_pci_identity *entry; char *name; int error; @@ -119,7 +125,7 @@ ahd_linux_pci_dev_probe(struct pci_dev * TAILQ_FOREACH(ahd, &ahd_tailq, links) { struct pci_dev *probed_pdev; - probed_pdev = ahd->dev_softc; + probed_pdev = aic_pci_dev(ahd); if (probed_pdev->bus->number == pdev->bus->number && probed_pdev->devfn == pdev->devfn) break; @@ -129,8 +135,8 @@ ahd_linux_pci_dev_probe(struct pci_dev * return (-ENODEV); } - pci = pdev; - entry = ahd_find_pci_device(pci); + dev = aic_pci_dev_to_dev(pdev); + entry = ahd_find_pci_device(dev); if (entry == NULL) return (-ENODEV); @@ -140,9 +146,9 @@ ahd_linux_pci_dev_probe(struct pci_dev * * common detect routine. */ sprintf(buf, "ahd_pci:%d:%d:%d", - ahd_get_pci_bus(pci), - ahd_get_pci_slot(pci), - ahd_get_pci_function(pci)); + aic_get_pci_bus(dev), + aic_get_pci_slot(dev), + aic_get_pci_function(dev)); name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); if (name == NULL) return (-ENOMEM); @@ -150,6 +156,7 @@ ahd_linux_pci_dev_probe(struct pci_dev * ahd = ahd_alloc(NULL, name); if (ahd == NULL) return (-ENOMEM); + ahd->dev_softc = dev; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (pci_enable_device(pdev)) { ahd_free(ahd); @@ -163,23 +170,22 @@ ahd_linux_pci_dev_probe(struct pci_dev * bus_addr_t mask_39bit; memsize = ahd_linux_get_memsize(); - mask_64bit = (bus_addr_t)(0xFFFFFFFFFFFFFFFFULL&(bus_addr_t)~0); - mask_39bit = (bus_addr_t)(0x7FFFFFFFFFULL&(bus_addr_t)~0); + mask_64bit = (bus_addr_t)0xFFFFFFFFFFFFFFFFULL; + mask_39bit = (bus_addr_t)0x7FFFFFFFFFULL; if (memsize >= 0x8000000000ULL - && ahd_pci_set_dma_mask(pdev, mask_64bit) == 0) { + && aic_set_dma_mask(ahd, mask_64bit) == 0) { ahd->flags |= AHD_64BIT_ADDRESSING; ahd->platform_data->hw_dma_mask = mask_64bit; } else if (memsize > 0x80000000 - && ahd_pci_set_dma_mask(pdev, mask_39bit) == 0) { + && aic_set_dma_mask(ahd, mask_39bit) == 0) { ahd->flags |= AHD_39BIT_ADDRESSING; ahd->platform_data->hw_dma_mask = mask_39bit; } } else { - ahd_pci_set_dma_mask(pdev, 0xFFFFFFFF); + aic_set_dma_mask(ahd, 0xFFFFFFFF); ahd->platform_data->hw_dma_mask = 0xFFFFFFFF; } #endif - ahd->dev_softc = pci; error = ahd_pci_config(ahd, entry); if (error != 0) { ahd_free(ahd); @@ -218,10 +224,8 @@ ahd_linux_pci_init(void) pdev = NULL; class = PCI_CLASS_STORAGE_SCSI << 8; while ((pdev = pci_find_class(class, pdev)) != NULL) { - ahd_dev_softc_t pci; int error; - pci = pdev; error = ahd_linux_pci_dev_probe(pdev, /*pci_devid*/NULL); if (error == 0) found++; @@ -240,17 +244,18 @@ static int ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, u_long *base, u_long *base2) { + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - *base = pci_resource_start(ahd->dev_softc, 0); + *base = pci_resource_start(aic_pci_dev(ahd), 0); /* * This is really the 3rd bar and should be at index 2, * but the Linux PCI code doesn't know how to "count" 64bit * bars. */ - *base2 = pci_resource_start(ahd->dev_softc, 3); + *base2 = pci_resource_start(aic_pci_dev(ahd), 3); #else - *base = ahd_pci_read_config(ahd->dev_softc, AHD_PCI_IOADDR0, 4); - *base2 = ahd_pci_read_config(ahd->dev_softc, AHD_PCI_IOADDR1, 4); + *base = aic_pci_read_config(ahd->dev_softc, AHD_PCI_IOADDR0, 4); + *base2 = aic_pci_read_config(ahd->dev_softc, AHD_PCI_IOADDR1, 4); *base &= PCI_BASE_ADDRESS_IO_MASK; *base2 &= PCI_BASE_ADDRESS_IO_MASK; #endif @@ -273,7 +278,6 @@ ahd_linux_pci_reserve_io_regions(struct return (0); } -#ifdef MMAPIO static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd, u_long *bus_addr, @@ -292,11 +296,11 @@ ahd_linux_pci_reserve_mem_region(struct error = 0; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - start = pci_resource_start(ahd->dev_softc, 1); + start = pci_resource_start(aic_pci_dev(ahd), 1); base_page = start & PAGE_MASK; base_offset = start - base_page; #else - start = ahd_pci_read_config(ahd->dev_softc, PCIR_MAPS+4, 4); + start = aic_pci_read_config(ahd->dev_softc, PCIR_MAPS+4, 4); base_offset = start & PCI_BASE_ADDRESS_MEM_MASK; base_page = base_offset & PAGE_MASK; base_offset -= base_page; @@ -321,7 +325,6 @@ ahd_linux_pci_reserve_mem_region(struct error = ENOMEM; return (error); } -#endif int ahd_pci_map_registers(struct ahd_softc *ahd) @@ -334,11 +337,10 @@ ahd_pci_map_registers(struct ahd_softc * /* * If its allowed, we prefer memory mapped access. */ - command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, 4); + command = aic_pci_read_config(ahd->dev_softc, PCIR_COMMAND, 4); command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN); base = 0; maddr = NULL; -#ifdef MMAPIO error = ahd_linux_pci_reserve_mem_region(ahd, &base, &maddr); if (error == 0) { ahd->platform_data->mem_busaddr = base; @@ -346,16 +348,16 @@ ahd_pci_map_registers(struct ahd_softc * ahd->bshs[0].maddr = maddr; ahd->tags[1] = BUS_SPACE_MEMIO; ahd->bshs[1].maddr = maddr + 0x100; - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, + aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command | PCIM_CMD_MEMEN, 4); if (ahd_pci_test_register_access(ahd) != 0) { printf("aic79xx: PCI Device %d:%d:%d " "failed memory mapped test. Using PIO.\n", - ahd_get_pci_bus(ahd->dev_softc), - ahd_get_pci_slot(ahd->dev_softc), - ahd_get_pci_function(ahd->dev_softc)); + aic_get_pci_bus(ahd->dev_softc), + aic_get_pci_slot(ahd->dev_softc), + aic_get_pci_function(ahd->dev_softc)); iounmap((void *)((u_long)maddr & PAGE_MASK)); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) release_mem_region(ahd->platform_data->mem_busaddr, @@ -368,12 +370,11 @@ ahd_pci_map_registers(struct ahd_softc * } else if (bootverbose) { printf("aic79xx: PCI%d:%d:%d MEM region 0x%lx " "unavailable. Cannot memory map device.\n", - ahd_get_pci_bus(ahd->dev_softc), - ahd_get_pci_slot(ahd->dev_softc), - ahd_get_pci_function(ahd->dev_softc), + aic_get_pci_bus(ahd->dev_softc), + aic_get_pci_slot(ahd->dev_softc), + aic_get_pci_function(ahd->dev_softc), base); } -#endif if (maddr == NULL) { u_long base2; @@ -388,13 +389,13 @@ ahd_pci_map_registers(struct ahd_softc * } else { printf("aic79xx: PCI%d:%d:%d IO regions 0x%lx and 0x%lx" "unavailable. Cannot map device.\n", - ahd_get_pci_bus(ahd->dev_softc), - ahd_get_pci_slot(ahd->dev_softc), - ahd_get_pci_function(ahd->dev_softc), + aic_get_pci_bus(ahd->dev_softc), + aic_get_pci_slot(ahd->dev_softc), + aic_get_pci_function(ahd->dev_softc), base, base2); } } - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, 4); + aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, 4); return (error); } @@ -403,49 +404,10 @@ ahd_pci_map_int(struct ahd_softc *ahd) { int error; - error = request_irq(ahd->dev_softc->irq, ahd_linux_isr, + error = request_irq(aic_pci_dev(ahd)->irq, ahd_linux_isr, SA_SHIRQ, "aic79xx", ahd); if (error == 0) - ahd->platform_data->irq = ahd->dev_softc->irq; + ahd->platform_data->irq = aic_pci_dev(ahd)->irq; return (-error); } - -void -ahd_power_state_change(struct ahd_softc *ahd, ahd_power_state new_state) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - pci_set_power_state(ahd->dev_softc, new_state); -#else - uint32_t cap; - u_int cap_offset; - - /* - * Traverse the capability list looking for - * the power management capability. - */ - cap = 0; - cap_offset = ahd_pci_read_config(ahd->dev_softc, - PCIR_CAP_PTR, /*bytes*/1); - while (cap_offset != 0) { - - cap = ahd_pci_read_config(ahd->dev_softc, - cap_offset, /*bytes*/4); - if ((cap & 0xFF) == 1 - && ((cap >> 16) & 0x3) > 0) { - uint32_t pm_control; - - pm_control = ahd_pci_read_config(ahd->dev_softc, - cap_offset + 4, - /*bytes*/4); - pm_control &= ~0x3; - pm_control |= new_state; - ahd_pci_write_config(ahd->dev_softc, - cap_offset + 4, - pm_control, /*bytes*/2); - break; - } - cap_offset = (cap >> 8) & 0xFF; - } -#endif -} diff -puN drivers/scsi/aic7xxx/aic79xx_pci.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic79xx_pci.c --- 25/drivers/scsi/aic7xxx/aic79xx_pci.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic79xx_pci.c Wed Dec 24 12:15:38 2003 @@ -38,15 +38,15 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#73 $ - * - * $FreeBSD$ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#84 $ */ #ifdef __linux__ #include "aic79xx_osm.h" #include "aic79xx_inline.h" #else +#include +__FBSDID("$FreeBSD$"); #include #include #endif @@ -75,13 +75,13 @@ ahd_compose_id(u_int device, u_int vendo #define ID_AHA_29320ALP 0x8017900500449005ull #define ID_AIC7901A 0x801E9005FFFF9005ull -#define ID_AHA_29320 0x8012900500429005ull -#define ID_AHA_29320B 0x8013900500439005ull #define ID_AHA_29320LP 0x8014900500449005ull #define ID_AIC7902 0x801F9005FFFF9005ull #define ID_AIC7902_B 0x801D9005FFFF9005ull #define ID_AHA_39320 0x8010900500409005ull +#define ID_AHA_29320 0x8012900500429005ull +#define ID_AHA_29320B 0x8013900500439005ull #define ID_AHA_39320_B 0x8015900500409005ull #define ID_AHA_39320A 0x8016900500409005ull #define ID_AHA_39320D 0x8011900500419005ull @@ -117,6 +117,7 @@ ahd_compose_id(u_int device, u_int vendo static ahd_device_setup_t ahd_aic7901_setup; static ahd_device_setup_t ahd_aic7901A_setup; static ahd_device_setup_t ahd_aic7902_setup; +static ahd_device_setup_t ahd_aic790X_setup; struct ahd_pci_identity ahd_pci_ident_table [] = { @@ -135,24 +136,24 @@ struct ahd_pci_identity ahd_pci_ident_ta }, /* aic7901A based controllers */ { - ID_AHA_29320, + ID_AHA_29320LP, ID_ALL_MASK, - "Adaptec 29320 Ultra320 SCSI adapter", + "Adaptec 29320LP Ultra320 SCSI adapter", ahd_aic7901A_setup }, + /* aic7902 based controllers */ { - ID_AHA_29320B, + ID_AHA_29320, ID_ALL_MASK, - "Adaptec 29320B Ultra320 SCSI adapter", - ahd_aic7901A_setup + "Adaptec 29320 Ultra320 SCSI adapter", + ahd_aic7902_setup }, { - ID_AHA_29320LP, + ID_AHA_29320B, ID_ALL_MASK, - "Adaptec 29320LP Ultra320 SCSI adapter", - ahd_aic7901A_setup + "Adaptec 29320B Ultra320 SCSI adapter", + ahd_aic7902_setup }, - /* aic7902 based controllers */ { ID_AHA_39320, ID_ALL_MASK, @@ -195,18 +196,6 @@ struct ahd_pci_identity ahd_pci_ident_ta "Adaptec (HP OEM) 39320D Ultra320 SCSI adapter", ahd_aic7902_setup }, - { - ID_AHA_29320, - ID_ALL_MASK, - "Adaptec 29320 Ultra320 SCSI adapter", - ahd_aic7902_setup - }, - { - ID_AHA_29320B, - ID_ALL_MASK, - "Adaptec 29320B Ultra320 SCSI adapter", - ahd_aic7902_setup - }, /* Generic chip probes for devices we don't know 'exactly' */ { ID_AIC7901 & ID_DEV_VENDOR_MASK, @@ -274,7 +263,7 @@ static void ahd_configure_termination(st static void ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat); struct ahd_pci_identity * -ahd_find_pci_device(ahd_dev_softc_t pci) +ahd_find_pci_device(aic_dev_softc_t pci) { uint64_t full_id; uint16_t device; @@ -284,10 +273,10 @@ ahd_find_pci_device(ahd_dev_softc_t pci) struct ahd_pci_identity *entry; u_int i; - vendor = ahd_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2); - device = ahd_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2); - subvendor = ahd_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2); - subdevice = ahd_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2); + vendor = aic_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2); + device = aic_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2); + subvendor = aic_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2); + subdevice = aic_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2); full_id = ahd_compose_id(device, vendor, subdevice, @@ -320,7 +309,7 @@ ahd_pci_config(struct ahd_softc *ahd, st /* * Record if this is an HP board. */ - subvendor = ahd_pci_read_config(ahd->dev_softc, + subvendor = aic_pci_read_config(ahd->dev_softc, PCIR_SUBVEND_0, /*bytes*/2); if (subvendor == SUBID_HP) ahd->flags |= AHD_HP_BOARD; @@ -329,7 +318,7 @@ ahd_pci_config(struct ahd_softc *ahd, st if (error != 0) return (error); - devconfig = ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4); + devconfig = aic_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4); if ((devconfig & PCIXINITPAT) == PCIXINIT_PCI33_66) { ahd->chip |= AHD_PCI; /* Disable PCIX workarounds when running in PCI mode. */ @@ -339,7 +328,7 @@ ahd_pci_config(struct ahd_softc *ahd, st } ahd->bus_description = pci_bus_modes[PCI_BUS_MODES_INDEX(devconfig)]; - ahd_power_state_change(ahd, AHD_POWER_STATE_D0); + aic_power_state_change(ahd, AIC_POWER_STATE_D0); error = ahd_pci_map_registers(ahd); if (error != 0) @@ -357,17 +346,17 @@ ahd_pci_config(struct ahd_softc *ahd, st if (bootverbose) printf("%s: Enabling 39Bit Addressing\n", ahd_name(ahd)); - devconfig = ahd_pci_read_config(ahd->dev_softc, + devconfig = aic_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4); devconfig |= DACEN; - ahd_pci_write_config(ahd->dev_softc, DEVCONFIG, + aic_pci_write_config(ahd->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); } /* Ensure busmastering is enabled */ - command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); + command = aic_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); command |= PCIM_CMD_BUSMASTEREN; - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/2); + aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/2); error = ahd_softc_init(ahd); if (error != 0) @@ -375,12 +364,12 @@ ahd_pci_config(struct ahd_softc *ahd, st ahd->bus_intr = ahd_pci_intr; - error = ahd_reset(ahd); + error = ahd_reset(ahd, /*reinit*/FALSE); if (error != 0) return (ENXIO); ahd->pci_cachesize = - ahd_pci_read_config(ahd->dev_softc, CSIZE_LATTIME, + aic_pci_read_config(ahd->dev_softc, CSIZE_LATTIME, /*bytes*/1) & CACHESIZE; ahd->pci_cachesize *= 4; @@ -418,9 +407,11 @@ ahd_pci_config(struct ahd_softc *ahd, st int ahd_pci_test_register_access(struct ahd_softc *ahd) { - uint32_t cmd; - int error; - uint8_t hcntrl; + uint32_t cmd; + u_int targpcistat; + u_int pci_status1; + int error; + uint8_t hcntrl; error = EIO; @@ -428,8 +419,8 @@ ahd_pci_test_register_access(struct ahd_ * Enable PCI error interrupt status, but suppress NMIs * generated by SERR raised due to target aborts. */ - cmd = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, + cmd = aic_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); + aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND, cmd & ~PCIM_CMD_SERRESPEN, /*bytes*/2); /* @@ -449,11 +440,25 @@ ahd_pci_test_register_access(struct ahd_ * or read prefetching could be initiated by the * CPU or host bridge. Our device does not support * either, so look for data corruption and/or flaged - * PCI errors. + * PCI errors. First pause without causing another + * chip reset. */ + hcntrl &= ~CHIPRST; ahd_outb(ahd, HCNTRL, hcntrl|PAUSE); while (ahd_is_paused(ahd) == 0) ; + + /* Clear any PCI errors that occurred before our driver attached. */ + ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); + targpcistat = ahd_inb(ahd, TARGPCISTAT); + ahd_outb(ahd, TARGPCISTAT, targpcistat); + pci_status1 = aic_pci_read_config(ahd->dev_softc, + PCIR_STATUS + 1, /*bytes*/1); + aic_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, + pci_status1, /*bytes*/1); + ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); + ahd_outb(ahd, CLRINT, CLRPCIINT); + ahd_outb(ahd, SEQCTL0, PERRORDIS); ahd_outl(ahd, SRAM_BASE, 0x5aa555aa); if (ahd_inl(ahd, SRAM_BASE) != 0x5aa555aa) @@ -472,23 +477,20 @@ ahd_pci_test_register_access(struct ahd_ fail: if ((ahd_inb(ahd, INTSTAT) & PCIINT) != 0) { - u_int targpcistat; - u_int pci_status1; ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); targpcistat = ahd_inb(ahd, TARGPCISTAT); /* Silently clear any latched errors. */ ahd_outb(ahd, TARGPCISTAT, targpcistat); - pci_status1 = ahd_pci_read_config(ahd->dev_softc, + pci_status1 = aic_pci_read_config(ahd->dev_softc, PCIR_STATUS + 1, /*bytes*/1); - ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, + aic_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, pci_status1, /*bytes*/1); ahd_outb(ahd, CLRINT, CLRPCIINT); } - ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS); - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2); + aic_pci_write_config(ahd->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2); return (error); } @@ -637,14 +639,14 @@ ahd_configure_termination(struct ahd_sof uint8_t termctl; uint32_t devconfig; - devconfig = ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4); + devconfig = aic_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4); devconfig &= ~STPWLEVEL; if ((ahd->flags & AHD_STPWLEVEL_A) != 0) devconfig |= STPWLEVEL; if (bootverbose) printf("%s: STPWLEVEL is %s\n", ahd_name(ahd), (devconfig & STPWLEVEL) ? "on" : "off"); - ahd_pci_write_config(ahd->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); + aic_pci_write_config(ahd->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); /* Make sure current sensing is off. */ if ((ahd->flags & AHD_CURRENT_SENSING) != 0) { @@ -689,6 +691,7 @@ ahd_configure_termination(struct ahd_sof * Now set the termination based on what we found. */ sxfrctl1 = ahd_inb(ahd, SXFRCTL1) & ~STPWEN; + ahd->flags &= ~AHD_TERM_ENB_A; if ((termctl & FLX_TERMCTL_ENPRILOW) != 0) { ahd->flags |= AHD_TERM_ENB_A; sxfrctl1 |= STPWEN; @@ -821,9 +824,9 @@ ahd_pci_intr(struct ahd_softc *ahd) } } } - pci_status1 = ahd_pci_read_config(ahd->dev_softc, + pci_status1 = aic_pci_read_config(ahd->dev_softc, PCIR_STATUS + 1, /*bytes*/1); - ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, + aic_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, pci_status1, /*bytes*/1); ahd_restore_modes(ahd, saved_modes); ahd_outb(ahd, CLRINT, CLRPCIINT); @@ -845,7 +848,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd * Check for splits in all modes. Modes 0 and 1 * additionally have SG engine splits to look at. */ - pcix_status = ahd_pci_read_config(ahd->dev_softc, PCIXR_STATUS, + pcix_status = aic_pci_read_config(ahd->dev_softc, PCIXR_STATUS, /*bytes*/2); printf("%s: PCI Split Interrupt - PCI-X status = 0x%x\n", ahd_name(ahd), pcix_status); @@ -894,7 +897,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd /* * Clear PCI-X status bits. */ - ahd_pci_write_config(ahd->dev_softc, PCIXR_STATUS, + aic_pci_write_config(ahd->dev_softc, PCIXR_STATUS, pcix_status, /*bytes*/2); ahd_outb(ahd, CLRINT, CLRSPLTINT); ahd_restore_modes(ahd, saved_modes); @@ -903,44 +906,44 @@ ahd_pci_split_intr(struct ahd_softc *ahd static int ahd_aic7901_setup(struct ahd_softc *ahd) { - int error; - error = ahd_aic7902_setup(ahd); - if (error != 0) - return (error); ahd->chip = AHD_AIC7901; - return (0); + ahd->features = AHD_AIC7901_FE; + return (ahd_aic790X_setup(ahd)); } static int ahd_aic7901A_setup(struct ahd_softc *ahd) { - int error; - error = ahd_aic7902_setup(ahd); - if (error != 0) - return (error); ahd->chip = AHD_AIC7901A; - return (0); + ahd->features = AHD_AIC7901A_FE; + return (ahd_aic790X_setup(ahd)); } static int ahd_aic7902_setup(struct ahd_softc *ahd) { - ahd_dev_softc_t pci; + ahd->chip = AHD_AIC7902; + ahd->features = AHD_AIC7902_FE; + return (ahd_aic790X_setup(ahd)); +} + +static int +ahd_aic790X_setup(struct ahd_softc *ahd) +{ + aic_dev_softc_t pci; u_int rev; pci = ahd->dev_softc; - rev = ahd_pci_read_config(pci, PCIR_REVID, /*bytes*/1); + rev = aic_pci_read_config(pci, PCIR_REVID, /*bytes*/1); if (rev < ID_AIC7902_PCI_REV_A4) { printf("%s: Unable to attach to unsupported chip revision %d\n", ahd_name(ahd), rev); - ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/2); + aic_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/2); return (ENXIO); } - ahd->channel = ahd_get_pci_function(pci) + 'A'; - ahd->chip = AHD_AIC7902; - ahd->features = AHD_AIC7902_FE; + ahd->channel = aic_get_pci_function(pci) + 'A'; if (rev < ID_AIC7902_PCI_REV_B0) { /* * Enable A series workarounds. @@ -968,9 +971,14 @@ ahd_aic7902_setup(struct ahd_softc *ahd) u_int devconfig1; ahd->features |= AHD_RTI|AHD_NEW_IOCELL_OPTS - | AHD_NEW_DFCNTRL_OPTS; - ahd->bugs |= AHD_LQOOVERRUN_BUG|AHD_ABORT_LQI_BUG - | AHD_INTCOLLISION_BUG|AHD_EARLY_REQ_BUG; + | AHD_NEW_DFCNTRL_OPTS|AHD_FAST_CDB_DELIVERY; + ahd->bugs |= AHD_LQOOVERRUN_BUG|AHD_EARLY_REQ_BUG; + + /* + * Some issues have been resolved in the 7901B. + */ + if ((ahd->features & AHD_MULTI_FUNC) != 0) + ahd->bugs |= AHD_INTCOLLISION_BUG|AHD_ABORT_LQI_BUG; /* * IO Cell paramter setup. @@ -985,10 +993,10 @@ ahd_aic7902_setup(struct ahd_softc *ahd) * XXX - Find out exactly what this does from the hardware * folks! */ - devconfig1 = ahd_pci_read_config(pci, DEVCONFIG1, /*bytes*/1); - ahd_pci_write_config(pci, DEVCONFIG1, + devconfig1 = aic_pci_read_config(pci, DEVCONFIG1, /*bytes*/1); + aic_pci_write_config(pci, DEVCONFIG1, devconfig1|PREQDIS, /*bytes*/1); - devconfig1 = ahd_pci_read_config(pci, DEVCONFIG1, /*bytes*/1); + devconfig1 = aic_pci_read_config(pci, DEVCONFIG1, /*bytes*/1); } return (0); diff -puN drivers/scsi/aic7xxx/aic79xx_proc.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic79xx_proc.c --- 25/drivers/scsi/aic7xxx/aic79xx_proc.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic79xx_proc.c Wed Dec 24 12:15:38 2003 @@ -37,7 +37,7 @@ * String handling code courtesy of Gerard Roudier's * sym driver. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_proc.c#17 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_proc.c#20 $ */ #include "aic79xx_osm.h" #include "aic79xx_inline.h" @@ -49,7 +49,7 @@ static void ahd_dump_target_state(struct u_int our_id, char channel, u_int target_id, u_int target_offset); static void ahd_dump_device_state(struct info_str *info, - struct ahd_linux_device *dev); + struct aic_linux_device *dev); static int ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length); @@ -166,7 +166,7 @@ ahd_dump_target_state(struct ahd_softc * u_int our_id, char channel, u_int target_id, u_int target_offset) { - struct ahd_linux_target *targ; + struct aic_linux_target *targ; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; int lun; @@ -187,7 +187,7 @@ ahd_dump_target_state(struct ahd_softc * copy_info(info, "\tTransmission Errors %ld\n", targ->errors_detected); for (lun = 0; lun < AHD_NUM_LUNS; lun++) { - struct ahd_linux_device *dev; + struct aic_linux_device *dev; dev = targ->devices[lun]; @@ -199,7 +199,7 @@ ahd_dump_target_state(struct ahd_softc * } static void -ahd_dump_device_state(struct info_str *info, struct ahd_linux_device *dev) +ahd_dump_device_state(struct info_str *info, struct aic_linux_device *dev) { copy_info(info, "\tChannel %c Target %d Lun %d Settings\n", dev->target->channel + 'A', dev->target->target, dev->lun); @@ -278,8 +278,13 @@ done: * Return information to handle /proc support for the driver. */ int -ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, - int length, int inout) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +ahd_linux_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int inout) +#else +ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, + off_t offset, int length, int inout) +#endif { struct ahd_softc *ahd; struct info_str info; @@ -291,10 +296,14 @@ ahd_linux_proc_info(struct Scsi_Host *sh retval = -EINVAL; ahd_list_lock(&l); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) TAILQ_FOREACH(ahd, &ahd_tailq, links) { - if (ahd->platform_data->host == shost) + if (ahd->platform_data->host->host_no == hostno) break; } +#else + ahd = ahd_find_softc(*(struct ahd_softc **)shost->hostdata); +#endif if (ahd == NULL) goto done; diff -puN drivers/scsi/aic7xxx/aic79xx.reg~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic79xx.reg --- 25/drivers/scsi/aic7xxx/aic79xx.reg~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic79xx.reg Wed Dec 24 12:15:38 2003 @@ -39,7 +39,7 @@ * * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#69 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -1377,7 +1377,10 @@ register LUNLEN { address 0x030 access_mode RW modes M_CFG + mask ILUNLEN 0x0F + mask TLUNLEN 0xF0 } +const LUNLEN_SINGLE_LEVEL_LUN 0xF /* * CDB Limit @@ -3797,32 +3800,8 @@ scb { size 4 alias SCB_NEXT_COMPLETE } - SCB_DATAPTR { - size 8 - } - SCB_DATACNT { - /* - * The last byte is really the high address bits for - * the data address. - */ - size 4 - field SG_LAST_SEG 0x80 /* In the fourth byte */ - field SG_HIGH_ADDR_BITS 0x7F /* In the fourth byte */ - } - SCB_SGPTR { - size 4 - field SG_STATUS_VALID 0x04 /* In the first byte */ - field SG_FULL_RESID 0x02 /* In the first byte */ - field SG_LIST_NULL 0x01 /* In the first byte */ - } - SCB_BUSADDR { - size 4 - } - SCB_NEXT { - alias SCB_NEXT_SCB_BUSADDR - size 2 - } - SCB_NEXT2 { + SCB_TAG { + alias SCB_FIFO_USE_COUNT size 2 } SCB_CONTROL { @@ -3859,8 +3838,32 @@ scb { SCB_TASK_MANAGEMENT { size 1 } - SCB_TAG { - alias SCB_FIFO_USE_COUNT + SCB_DATAPTR { + size 8 + } + SCB_DATACNT { + /* + * The last byte is really the high address bits for + * the data address. + */ + size 4 + field SG_LAST_SEG 0x80 /* In the fourth byte */ + field SG_HIGH_ADDR_BITS 0x7F /* In the fourth byte */ + } + SCB_SGPTR { + size 4 + field SG_STATUS_VALID 0x04 /* In the first byte */ + field SG_FULL_RESID 0x02 /* In the first byte */ + field SG_LIST_NULL 0x01 /* In the first byte */ + } + SCB_BUSADDR { + size 4 + } + SCB_NEXT { + alias SCB_NEXT_SCB_BUSADDR + size 2 + } + SCB_NEXT2 { size 2 } SCB_SPARE { diff -puN drivers/scsi/aic7xxx/aic79xx_reg.h_shipped~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic79xx_reg.h_shipped --- 25/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped Wed Dec 24 12:15:38 2003 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#69 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#107 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $ */ typedef int (ahd_reg_print_t)(u_int, u_int *, u_int); typedef struct ahd_reg_parse_entry { @@ -2239,94 +2239,94 @@ ahd_reg_print_t ahd_scb_sense_busaddr_pr #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_dataptr_print; +ahd_reg_print_t ahd_scb_tag_print; #else -#define ahd_scb_dataptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_DATAPTR", 0x190, regvalue, cur_col, wrap) +#define ahd_scb_tag_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_TAG", 0x190, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_datacnt_print; +ahd_reg_print_t ahd_scb_control_print; #else -#define ahd_scb_datacnt_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_DATACNT", 0x198, regvalue, cur_col, wrap) +#define ahd_scb_control_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_CONTROL", 0x192, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_sgptr_print; +ahd_reg_print_t ahd_scb_scsiid_print; #else -#define ahd_scb_sgptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_SGPTR", 0x19c, regvalue, cur_col, wrap) +#define ahd_scb_scsiid_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_SCSIID", 0x193, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_busaddr_print; +ahd_reg_print_t ahd_scb_lun_print; #else -#define ahd_scb_busaddr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_BUSADDR", 0x1a0, regvalue, cur_col, wrap) +#define ahd_scb_lun_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_LUN", 0x194, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_next_print; +ahd_reg_print_t ahd_scb_task_attribute_print; #else -#define ahd_scb_next_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_NEXT", 0x1a4, regvalue, cur_col, wrap) +#define ahd_scb_task_attribute_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_TASK_ATTRIBUTE", 0x195, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_next2_print; +ahd_reg_print_t ahd_scb_cdb_len_print; #else -#define ahd_scb_next2_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_NEXT2", 0x1a6, regvalue, cur_col, wrap) +#define ahd_scb_cdb_len_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_CDB_LEN", 0x196, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_control_print; +ahd_reg_print_t ahd_scb_task_management_print; #else -#define ahd_scb_control_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_CONTROL", 0x1a8, regvalue, cur_col, wrap) +#define ahd_scb_task_management_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_TASK_MANAGEMENT", 0x197, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_scsiid_print; +ahd_reg_print_t ahd_scb_dataptr_print; #else -#define ahd_scb_scsiid_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_SCSIID", 0x1a9, regvalue, cur_col, wrap) +#define ahd_scb_dataptr_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_DATAPTR", 0x198, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_lun_print; +ahd_reg_print_t ahd_scb_datacnt_print; #else -#define ahd_scb_lun_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_LUN", 0x1aa, regvalue, cur_col, wrap) +#define ahd_scb_datacnt_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_DATACNT", 0x1a0, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_task_attribute_print; +ahd_reg_print_t ahd_scb_sgptr_print; #else -#define ahd_scb_task_attribute_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_TASK_ATTRIBUTE", 0x1ab, regvalue, cur_col, wrap) +#define ahd_scb_sgptr_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_SGPTR", 0x1a4, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_cdb_len_print; +ahd_reg_print_t ahd_scb_busaddr_print; #else -#define ahd_scb_cdb_len_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_CDB_LEN", 0x1ac, regvalue, cur_col, wrap) +#define ahd_scb_busaddr_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_BUSADDR", 0x1a8, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_task_management_print; +ahd_reg_print_t ahd_scb_next_print; #else -#define ahd_scb_task_management_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_TASK_MANAGEMENT", 0x1ad, regvalue, cur_col, wrap) +#define ahd_scb_next_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_NEXT", 0x1ac, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_tag_print; +ahd_reg_print_t ahd_scb_next2_print; #else -#define ahd_scb_tag_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_TAG", 0x1ae, regvalue, cur_col, wrap) +#define ahd_scb_next2_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_NEXT2", 0x1ae, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS @@ -2557,6 +2557,8 @@ ahd_reg_print_t ahd_scb_disconnected_lis #define SHORTTHRESH 0x2f #define LUNLEN 0x30 +#define TLUNLEN 0xf0 +#define ILUNLEN 0x0f #define CDBLIMIT 0x31 @@ -3648,25 +3650,10 @@ ahd_reg_print_t ahd_scb_disconnected_lis #define SCB_SENSE_BUSADDR 0x18c #define SCB_NEXT_COMPLETE 0x18c -#define SCB_DATAPTR 0x190 - -#define SCB_DATACNT 0x198 -#define SG_LAST_SEG 0x80 -#define SG_HIGH_ADDR_BITS 0x7f - -#define SCB_SGPTR 0x19c -#define SG_STATUS_VALID 0x04 -#define SG_FULL_RESID 0x02 -#define SG_LIST_NULL 0x01 +#define SCB_TAG 0x190 +#define SCB_FIFO_USE_COUNT 0x190 -#define SCB_BUSADDR 0x1a0 - -#define SCB_NEXT 0x1a4 -#define SCB_NEXT_SCB_BUSADDR 0x1a4 - -#define SCB_NEXT2 0x1a6 - -#define SCB_CONTROL 0x1a8 +#define SCB_CONTROL 0x192 #define TARGET_SCB 0x80 #define DISCENB 0x40 #define TAG_ENB 0x20 @@ -3675,23 +3662,38 @@ ahd_reg_print_t ahd_scb_disconnected_lis #define DISCONNECTED 0x04 #define SCB_TAG_TYPE 0x03 -#define SCB_SCSIID 0x1a9 +#define SCB_SCSIID 0x193 #define TID 0xf0 #define OID 0x0f -#define SCB_LUN 0x1aa +#define SCB_LUN 0x194 #define LID 0xff -#define SCB_TASK_ATTRIBUTE 0x1ab +#define SCB_TASK_ATTRIBUTE 0x195 #define SCB_XFERLEN_ODD 0x01 -#define SCB_CDB_LEN 0x1ac +#define SCB_CDB_LEN 0x196 #define SCB_CDB_LEN_PTR 0x80 -#define SCB_TASK_MANAGEMENT 0x1ad +#define SCB_TASK_MANAGEMENT 0x197 + +#define SCB_DATAPTR 0x198 + +#define SCB_DATACNT 0x1a0 +#define SG_LAST_SEG 0x80 +#define SG_HIGH_ADDR_BITS 0x7f + +#define SCB_SGPTR 0x1a4 +#define SG_STATUS_VALID 0x04 +#define SG_FULL_RESID 0x02 +#define SG_LIST_NULL 0x01 + +#define SCB_BUSADDR 0x1a8 + +#define SCB_NEXT 0x1ac +#define SCB_NEXT_SCB_BUSADDR 0x1ac -#define SCB_TAG 0x1ae -#define SCB_FIFO_USE_COUNT 0x1ae +#define SCB_NEXT2 0x1ae #define SCB_SPARE 0x1b0 #define SCB_PKT_LUN 0x1b0 @@ -3720,6 +3722,7 @@ ahd_reg_print_t ahd_scb_disconnected_lis #define AHD_PRECOMP_CUTBACK_29 0x06 #define AHD_NUM_PER_DEV_ANNEXCOLS 0x04 #define B_CURRFIFO_0 0x02 +#define LUNLEN_SINGLE_LEVEL_LUN 0x0f #define NVRAM_SCB_OFFSET 0x2c #define AHD_TIMER_MAX_US 0x18ffe7 #define AHD_TIMER_MAX_TICKS 0xffff diff -puN drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped --- 25/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped Wed Dec 24 12:15:38 2003 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#93 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#68 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#107 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $ */ #include "aic79xx_osm.h" @@ -489,10 +489,15 @@ ahd_shortthresh_print(u_int regvalue, u_ 0x2f, regvalue, cur_col, wrap)); } +static ahd_reg_parse_entry_t LUNLEN_parse_table[] = { + { "ILUNLEN", 0x0f, 0x0f }, + { "TLUNLEN", 0xf0, 0xf0 } +}; + int ahd_lunlen_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "LUNLEN", + return (ahd_print_register(LUNLEN_parse_table, 2, "LUNLEN", 0x30, regvalue, cur_col, wrap)); } @@ -3486,58 +3491,12 @@ ahd_scb_sense_busaddr_print(u_int regval } int -ahd_scb_dataptr_print(u_int regvalue, u_int *cur_col, u_int wrap) +ahd_scb_tag_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "SCB_DATAPTR", + return (ahd_print_register(NULL, 0, "SCB_TAG", 0x190, regvalue, cur_col, wrap)); } -static ahd_reg_parse_entry_t SCB_DATACNT_parse_table[] = { - { "SG_HIGH_ADDR_BITS", 0x7f, 0x7f }, - { "SG_LAST_SEG", 0x80, 0x80 } -}; - -int -ahd_scb_datacnt_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SCB_DATACNT_parse_table, 2, "SCB_DATACNT", - 0x198, regvalue, cur_col, wrap)); -} - -static ahd_reg_parse_entry_t SCB_SGPTR_parse_table[] = { - { "SG_LIST_NULL", 0x01, 0x01 }, - { "SG_FULL_RESID", 0x02, 0x02 }, - { "SG_STATUS_VALID", 0x04, 0x04 } -}; - -int -ahd_scb_sgptr_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SCB_SGPTR_parse_table, 3, "SCB_SGPTR", - 0x19c, regvalue, cur_col, wrap)); -} - -int -ahd_scb_busaddr_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "SCB_BUSADDR", - 0x1a0, regvalue, cur_col, wrap)); -} - -int -ahd_scb_next_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "SCB_NEXT", - 0x1a4, regvalue, cur_col, wrap)); -} - -int -ahd_scb_next2_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "SCB_NEXT2", - 0x1a6, regvalue, cur_col, wrap)); -} - static ahd_reg_parse_entry_t SCB_CONTROL_parse_table[] = { { "SCB_TAG_TYPE", 0x03, 0x03 }, { "DISCONNECTED", 0x04, 0x04 }, @@ -3552,7 +3511,7 @@ int ahd_scb_control_print(u_int regvalue, u_int *cur_col, u_int wrap) { return (ahd_print_register(SCB_CONTROL_parse_table, 7, "SCB_CONTROL", - 0x1a8, regvalue, cur_col, wrap)); + 0x192, regvalue, cur_col, wrap)); } static ahd_reg_parse_entry_t SCB_SCSIID_parse_table[] = { @@ -3564,7 +3523,7 @@ int ahd_scb_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap) { return (ahd_print_register(SCB_SCSIID_parse_table, 2, "SCB_SCSIID", - 0x1a9, regvalue, cur_col, wrap)); + 0x193, regvalue, cur_col, wrap)); } static ahd_reg_parse_entry_t SCB_LUN_parse_table[] = { @@ -3575,14 +3534,18 @@ int ahd_scb_lun_print(u_int regvalue, u_int *cur_col, u_int wrap) { return (ahd_print_register(SCB_LUN_parse_table, 1, "SCB_LUN", - 0x1aa, regvalue, cur_col, wrap)); + 0x194, regvalue, cur_col, wrap)); } +static ahd_reg_parse_entry_t SCB_TASK_ATTRIBUTE_parse_table[] = { + { "SCB_XFERLEN_ODD", 0x01, 0x01 } +}; + int ahd_scb_task_attribute_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "SCB_TASK_ATTRIBUTE", - 0x1ab, regvalue, cur_col, wrap)); + return (ahd_print_register(SCB_TASK_ATTRIBUTE_parse_table, 1, "SCB_TASK_ATTRIBUTE", + 0x195, regvalue, cur_col, wrap)); } static ahd_reg_parse_entry_t SCB_CDB_LEN_parse_table[] = { @@ -3593,20 +3556,66 @@ int ahd_scb_cdb_len_print(u_int regvalue, u_int *cur_col, u_int wrap) { return (ahd_print_register(SCB_CDB_LEN_parse_table, 1, "SCB_CDB_LEN", - 0x1ac, regvalue, cur_col, wrap)); + 0x196, regvalue, cur_col, wrap)); } int ahd_scb_task_management_print(u_int regvalue, u_int *cur_col, u_int wrap) { return (ahd_print_register(NULL, 0, "SCB_TASK_MANAGEMENT", - 0x1ad, regvalue, cur_col, wrap)); + 0x197, regvalue, cur_col, wrap)); } int -ahd_scb_tag_print(u_int regvalue, u_int *cur_col, u_int wrap) +ahd_scb_dataptr_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "SCB_TAG", + return (ahd_print_register(NULL, 0, "SCB_DATAPTR", + 0x198, regvalue, cur_col, wrap)); +} + +static ahd_reg_parse_entry_t SCB_DATACNT_parse_table[] = { + { "SG_HIGH_ADDR_BITS", 0x7f, 0x7f }, + { "SG_LAST_SEG", 0x80, 0x80 } +}; + +int +ahd_scb_datacnt_print(u_int regvalue, u_int *cur_col, u_int wrap) +{ + return (ahd_print_register(SCB_DATACNT_parse_table, 2, "SCB_DATACNT", + 0x1a0, regvalue, cur_col, wrap)); +} + +static ahd_reg_parse_entry_t SCB_SGPTR_parse_table[] = { + { "SG_LIST_NULL", 0x01, 0x01 }, + { "SG_FULL_RESID", 0x02, 0x02 }, + { "SG_STATUS_VALID", 0x04, 0x04 } +}; + +int +ahd_scb_sgptr_print(u_int regvalue, u_int *cur_col, u_int wrap) +{ + return (ahd_print_register(SCB_SGPTR_parse_table, 3, "SCB_SGPTR", + 0x1a4, regvalue, cur_col, wrap)); +} + +int +ahd_scb_busaddr_print(u_int regvalue, u_int *cur_col, u_int wrap) +{ + return (ahd_print_register(NULL, 0, "SCB_BUSADDR", + 0x1a8, regvalue, cur_col, wrap)); +} + +int +ahd_scb_next_print(u_int regvalue, u_int *cur_col, u_int wrap) +{ + return (ahd_print_register(NULL, 0, "SCB_NEXT", + 0x1ac, regvalue, cur_col, wrap)); +} + +int +ahd_scb_next2_print(u_int regvalue, u_int *cur_col, u_int wrap) +{ + return (ahd_print_register(NULL, 0, "SCB_NEXT2", 0x1ae, regvalue, cur_col, wrap)); } diff -puN drivers/scsi/aic7xxx/aic79xx.seq~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic79xx.seq --- 25/drivers/scsi/aic7xxx/aic79xx.seq~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic79xx.seq Wed Dec 24 12:15:38 2003 @@ -40,7 +40,7 @@ * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#107 $" PATCH_ARG_LIST = "struct ahd_softc *ahd" PREFIX = "ahd_" @@ -90,6 +90,13 @@ idle_loop_check_nonpackreq: test SSTAT2, NONPACKREQ jz . + 2; call unexpected_nonpkt_phase_find_ctxt; if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) { + /* + * On Rev A. hardware, the busy LED is only + * turned on automaically during selections + * and re-selections. Make the LED status + * more useful by forcing it to be on so + * long as one of our data FIFOs is active. + */ and A, FIFO0FREE|FIFO1FREE, DFFSTAT; cmp A, FIFO0FREE|FIFO1FREE jne . + 3; and SBLKCTL, ~DIAGLEDEN|DIAGLEDON; @@ -101,9 +108,9 @@ idle_loop_check_nonpackreq: call idle_loop_cchan; jmp idle_loop; -BEGIN_CRITICAL; idle_loop_gsfifo: SET_MODE(M_SCSI, M_SCSI) +BEGIN_CRITICAL; idle_loop_gsfifo_in_scsi_mode: test LQISTAT2, LQIGSAVAIL jz return; /* @@ -152,25 +159,28 @@ END_CRITICAL; idle_loop_service_fifos: SET_MODE(M_DFF0, M_DFF0) +BEGIN_CRITICAL; test LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_next_fifo; call longjmp; +END_CRITICAL; idle_loop_next_fifo: SET_MODE(M_DFF1, M_DFF1) +BEGIN_CRITICAL; test LONGJMP_ADDR[1], INVALID_ADDR jz longjmp; +END_CRITICAL; return: ret; idle_loop_cchan: SET_MODE(M_CCHAN, M_CCHAN) test QOFF_CTLSTA, HS_MAILBOX_ACT jz hs_mailbox_empty; - mov LOCAL_HS_MAILBOX, HS_MAILBOX; or QOFF_CTLSTA, HS_MAILBOX_ACT; + mov LOCAL_HS_MAILBOX, HS_MAILBOX; hs_mailbox_empty: BEGIN_CRITICAL; test CCSCBCTL, CCARREN|CCSCBEN jz scbdma_idle; test CCSCBCTL, CCSCBDIR jnz fetch_new_scb_inprog; test CCSCBCTL, CCSCBDONE jz return; -END_CRITICAL; /* FALLTHROUGH */ scbdma_tohost_done: test CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone; @@ -180,26 +190,18 @@ scbdma_tohost_done: * bad SCSI status (currently only for underruns), we * queue the SCB for normal completion. Otherwise, we * wait until any select-out activity has halted, and - * then notify the host so that the transaction can be - * dealt with. + * then queue the completion. */ - test SCB_SCSI_STATUS, 0xff jnz scbdma_notify_host; - and CCSCBCTL, ~(CCARREN|CCSCBEN); - bmov COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2; - bmov SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2; - bmov COMPLETE_SCB_HEAD, SCBPTR, 2 ret; -scbdma_notify_host: + test SCB_SCSI_STATUS, 0xff jz scbdma_queue_completion; SET_MODE(M_SCSI, M_SCSI) test SCSISEQ0, ENSELO jnz return; test SSTAT0, (SELDO|SELINGO) jnz return; SET_MODE(M_CCHAN, M_CCHAN) - /* - * Remove SCB and notify host. - */ +scbdma_queue_completion: and CCSCBCTL, ~(CCARREN|CCSCBEN); bmov COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2; - SET_SEQINTCODE(BAD_SCB_STATUS) - ret; + bmov SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2; + bmov COMPLETE_SCB_HEAD, SCBPTR, 2 ret; fill_qoutfifo_dmadone: and CCSCBCTL, ~(CCARREN|CCSCBEN); call qoutfifo_updated; @@ -208,6 +210,7 @@ fill_qoutfifo_dmadone: test QOFF_CTLSTA, SDSCB_ROLLOVR jz return; bmov QOUTFIFO_NEXT_ADDR, SHARED_DATA_ADDR, 4; xor QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID_TOGGLE ret; +END_CRITICAL; qoutfifo_updated: /* @@ -276,7 +279,7 @@ fetch_new_scb_done: * knows the correct location to store the SCB. * Set it to zero before processing the SCB. */ - mov SCB_FIFO_USE_COUNT, ALLZEROS; + clr SCB_FIFO_USE_COUNT; /* Update the next SCB address to download. */ bmov NEXT_QUEUED_SCB_ADDR, SCB_NEXT_SCB_BUSADDR, 4; mvi SCB_NEXT[1], SCB_LIST_NULL; @@ -490,14 +493,30 @@ allocate_fifo1: SET_SRC_MODE M_SCSI; SET_DST_MODE M_SCSI; select_in: + if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) { + /* + * On Rev A. hardware, the busy LED is only + * turned on automaically during selections + * and re-selections. Make the LED status + * more useful by forcing it to be on from + * the point of selection until our idle + * loop determines that neither of our FIFOs + * are busy. This handles the non-packetized + * case nicely as we will not return to the + * idle loop until the busfree at the end of + * each transaction. + */ + or SBLKCTL, DIAGLEDEN|DIAGLEDON; + } if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { /* - * This exposes a window whereby a - * busfree just after a selection will - * be missed, but there is no other safe - * way to enable busfree detection if - * the busfreerev function is broken. + * Test to ensure that the bus has not + * already gone free prior to clearing + * any stale busfree status. This avoids + * a window whereby a busfree just after + * a selection could be missed. */ + test SCSISIGI, BSYI jz . + 2; mvi CLRSINT1,CLRBUSFREE; or SIMODE1, ENBUSFREE; } @@ -527,6 +546,21 @@ SET_SRC_MODE M_SCSI; SET_DST_MODE M_SCSI; select_out: BEGIN_CRITICAL; + if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) { + /* + * On Rev A. hardware, the busy LED is only + * turned on automaically during selections + * and re-selections. Make the LED status + * more useful by forcing it to be on from + * the point of re-selection until our idle + * loop determines that neither of our FIFOs + * are busy. This handles the non-packetized + * case nicely as we will not return to the + * idle loop until the busfree at the end of + * each transaction. + */ + or SBLKCTL, DIAGLEDEN|DIAGLEDON; + } /* Clear out all SCBs that have been successfully sent. */ if ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0) { /* @@ -582,9 +616,6 @@ found_last_sent_scb: bmov CURRSCB, SCBPTR, 2; curscb_ww_done: } else { - /* - * Untested - Verify with Rev B. - */ bmov SCBPTR, CURRSCB, 2; } @@ -651,12 +682,13 @@ select_out_non_packetized: and SCSISEQ0, ~ENSELO; if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { /* - * This exposes a window whereby a - * busfree just after a selection will - * be missed, but there is no other safe - * way to enable busfree detection if - * the busfreerev function is broken. + * Test to ensure that the bus has not + * already gone free prior to clearing + * any stale busfree status. This avoids + * a window whereby a busfree just after + * a selection could be missed. */ + test SCSISIGI, BSYI jz . + 2; mvi CLRSINT1,CLRBUSFREE; or SIMODE1, ENBUSFREE; } @@ -729,13 +761,38 @@ p_command_embedded: mvi DFCNTRL, SCSIEN; p_command_xfer: and SEQ_FLAGS, ~NO_CDB_SENT; - test DFCNTRL, SCSIEN jnz .; + if ((ahd->features & AHD_FAST_CDB_DELIVERY) != 0) { + /* + * To speed up CDB delivery in Rev B, all CDB acks + * are "released" to the output sync as soon as the + * command phase starts. There is only one problem + * with this approach. If the target changes phase + * before all data are sent, we have left over acks + * that can go out on the bus in a data phase. Due + * to other chip contraints, this only happens if + * the target goes to data-in, but if the acks go + * out before we can test SDONE, we'll think that + * the transfer has completed successfully. Work + * around this by taking advantage of the 400ns or + * 800ns dead time between command phase and the REQ + * of the new phase. If the transfer has completed + * successfully, SCSIEN should fall *long* before we + * see a phase change. We thus treat any phasemiss + * that occurs before SCSIEN falls as an incomplete + * transfer. + */ + test SSTAT1, PHASEMIS jnz p_command_xfer_failed; + test DFCNTRL, SCSIEN jnz . - 1; + } else { + test DFCNTRL, SCSIEN jnz .; + } /* * DMA Channel automatically disabled. * Don't allow a data phase if the command * was not fully transferred. */ test SSTAT2, SDONE jnz ITloop; +p_command_xfer_failed: or SEQ_FLAGS, NO_CDB_SENT; jmp ITloop; @@ -1061,8 +1118,10 @@ queue_scb_completion: test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */ test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb; complete: +BEGIN_CRITICAL; bmov SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2; bmov COMPLETE_SCB_HEAD, SCBPTR, 2 ret; +END_CRITICAL; bad_status: cmp SCB_SCSI_STATUS, STATUS_PKT_SENSE je upload_scb; call freeze_queue; @@ -1073,9 +1132,11 @@ upload_scb: * it on the host. */ bmov SCB_TAG, SCBPTR, 2; +BEGIN_CRITICAL; bmov SCB_NEXT_COMPLETE, COMPLETE_DMA_SCB_HEAD, 2; bmov COMPLETE_DMA_SCB_HEAD, SCBPTR, 2; or SCB_SGPTR, SG_STATUS_VALID ret; +END_CRITICAL; /* * Is it a disconnect message? Set a flag in the SCB to remind us @@ -1122,8 +1183,18 @@ SET_DST_MODE M_DFF1; await_busfree_clrchn: mvi DFFSXFRCTL, CLRCHN; await_busfree_not_m_dff: - call clear_target_state; + /* clear target specific flags */ + mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT; test SSTAT1,REQINIT|BUSFREE jz .; + /* + * We only set BUSFREE status once either a new + * phase has been detected or we are really + * BUSFREE. This allows the driver to know + * that we are active on the bus even though + * no identified transaction exists should a + * timeout occur while awaiting busfree. + */ + mvi LASTPHASE, P_BUSFREE; test SSTAT1, BUSFREE jnz idle_loop; SET_SEQINTCODE(MISSED_BUSFREE) @@ -1178,11 +1249,6 @@ msgin_rdptrs_get_fifo: call allocate_fifo; jmp mesgin_done; -clear_target_state: - mvi LASTPHASE, P_BUSFREE; - /* clear target specific flags */ - mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret; - phase_lock: if ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0) { /* @@ -1634,7 +1700,7 @@ export seq_isr: * savepointer in the current FIFO. We do this so that * a pending CTXTDONE or SAVEPTR is visible in the active * FIFO. This status is the only way we can detect if we - * have lost the race (e.g. host paused us) and our attepts + * have lost the race (e.g. host paused us) and our attempts * to disable the channel occurred after all REQs were * already seen and acked (REQINIT never comes true). */ @@ -1643,7 +1709,7 @@ export seq_isr: test DFCNTRL, DIRECTION jz interrupt_return; and DFCNTRL, ~SCSIEN; snapshot_wait_data_valid: - test SEQINTSRC, (CTXTDONE|SAVEPTRS) jnz snapshot_data_valid; + test SEQINTSRC, (CTXTDONE|SAVEPTRS) jnz interrupt_return; test SSTAT1, REQINIT jz snapshot_wait_data_valid; snapshot_data_valid: or DFCNTRL, SCSIEN; @@ -1810,7 +1876,6 @@ pkt_saveptrs_check_status: dec SCB_FIFO_USE_COUNT; test SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle; mvi DFFSXFRCTL, CLRCHN ret; -END_CRITICAL; /* * LAST_SEG_DONE status has been seen in the current FIFO. @@ -1819,7 +1884,6 @@ END_CRITICAL; * Check for overrun and see if we can complete this command. */ pkt_last_seg_done: -BEGIN_CRITICAL; /* * Mark transfer as completed. */ @@ -1959,12 +2023,14 @@ SET_DST_MODE M_SCSI; test SSTAT0, SELDO jnz return; mvi SCBPTR[1], SCB_LIST_NULL; unexpected_nonpkt_phase: - test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) jnz . + 3; + test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) + jnz unexpected_nonpkt_mode_cleared; SET_SRC_MODE M_DFF0; SET_DST_MODE M_DFF0; or LONGJMP_ADDR[1], INVALID_ADDR; dec SCB_FIFO_USE_COUNT; mvi DFFSXFRCTL, CLRCHN; +unexpected_nonpkt_mode_cleared: mvi CLRSINT2, CLRNONPACKREQ; test SCSIPHASE, ~(MSG_IN_PHASE|MSG_OUT_PHASE) jnz illegal_phase; SET_SEQINTCODE(ENTERING_NONPACK) diff -puN drivers/scsi/aic7xxx/aic79xx_seq.h_shipped~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic79xx_seq.h_shipped --- 25/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped Wed Dec 24 12:15:38 2003 @@ -2,25 +2,25 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#69 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#107 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $ */ static uint8_t seqprog[] = { 0xff, 0x02, 0x06, 0x78, - 0x00, 0xea, 0x50, 0x59, + 0x00, 0xea, 0x46, 0x59, 0x01, 0xea, 0x04, 0x30, 0xff, 0x04, 0x0c, 0x78, - 0x19, 0xea, 0x50, 0x59, + 0x19, 0xea, 0x46, 0x59, 0x19, 0xea, 0x04, 0x00, - 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x3a, 0x59, 0x33, 0xea, 0x00, 0x00, 0x60, 0x3a, 0x1a, 0x68, 0x04, 0x47, 0x1b, 0x68, 0xff, 0x21, 0x1b, 0x70, - 0x40, 0x4b, 0x92, 0x69, - 0x00, 0xe2, 0x54, 0x59, - 0x40, 0x4b, 0x92, 0x69, - 0x20, 0x4b, 0x82, 0x69, + 0x40, 0x4b, 0x8c, 0x69, + 0x00, 0xe2, 0x4a, 0x59, + 0x40, 0x4b, 0x8c, 0x69, + 0x20, 0x4b, 0x78, 0x69, 0xfc, 0x42, 0x24, 0x78, 0x10, 0x40, 0x24, 0x78, 0x00, 0xe2, 0xc4, 0x5d, @@ -35,70 +35,65 @@ static uint8_t seqprog[] = { 0x00, 0xe2, 0x56, 0x58, 0x00, 0xe2, 0x66, 0x58, 0x00, 0xe2, 0x06, 0x40, - 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x3a, 0x59, 0x33, 0xea, 0x00, 0x00, 0x01, 0x52, 0x64, 0x78, 0x02, 0x58, 0x50, 0x31, 0xff, 0xea, 0x10, 0x0b, - 0xff, 0xad, 0x4f, 0x78, + 0xff, 0x97, 0x4f, 0x78, 0x50, 0x4b, 0x4a, 0x68, 0xbf, 0x3a, 0x74, 0x08, - 0x14, 0xea, 0x50, 0x59, + 0x14, 0xea, 0x46, 0x59, 0x14, 0xea, 0x04, 0x00, - 0x08, 0xa8, 0x51, 0x03, - 0xff, 0xae, 0x3f, 0x68, - 0x00, 0xe2, 0x56, 0x5b, + 0x08, 0x92, 0x25, 0x03, + 0xff, 0x90, 0x3f, 0x68, + 0x00, 0xe2, 0x58, 0x5b, 0x00, 0xe2, 0x3e, 0x40, - 0x00, 0xea, 0x44, 0x59, + 0x00, 0xea, 0x3a, 0x59, 0x01, 0xea, 0x00, 0x30, 0x80, 0xf9, 0x5e, 0x68, - 0x00, 0xe2, 0x42, 0x59, - 0x11, 0xea, 0x44, 0x59, + 0x00, 0xe2, 0x38, 0x59, + 0x11, 0xea, 0x3a, 0x59, 0x11, 0xea, 0x00, 0x00, - 0x80, 0xf9, 0x42, 0x79, + 0x80, 0xf9, 0x38, 0x79, 0xff, 0xea, 0xd4, 0x0d, - 0x22, 0xea, 0x44, 0x59, + 0x22, 0xea, 0x3a, 0x59, 0x22, 0xea, 0x00, 0x00, 0x10, 0x16, 0x70, 0x78, - 0x01, 0x0b, 0xa2, 0x32, 0x10, 0x16, 0x2c, 0x00, - 0x18, 0xad, 0x00, 0x79, - 0x04, 0xad, 0xca, 0x68, + 0x01, 0x0b, 0xa2, 0x32, + 0x18, 0xad, 0xf6, 0x78, + 0x04, 0xad, 0xc0, 0x68, 0x80, 0xad, 0x64, 0x78, - 0x10, 0xad, 0x98, 0x78, - 0xff, 0x88, 0x83, 0x68, - 0xe7, 0xad, 0x5a, 0x09, - 0x02, 0x8c, 0x59, 0x32, - 0x02, 0x28, 0x19, 0x33, - 0x02, 0xa8, 0x50, 0x36, - 0x33, 0xea, 0x44, 0x59, + 0x10, 0xad, 0x8e, 0x78, + 0xff, 0x88, 0x87, 0x78, + 0x33, 0xea, 0x3a, 0x59, 0x33, 0xea, 0x00, 0x00, 0x40, 0x3a, 0x64, 0x68, 0x50, 0x4b, 0x64, 0x68, - 0x22, 0xea, 0x44, 0x59, + 0x22, 0xea, 0x3a, 0x59, 0x22, 0xea, 0x00, 0x00, 0xe7, 0xad, 0x5a, 0x09, 0x02, 0x8c, 0x59, 0x32, - 0x1a, 0xea, 0x50, 0x59, - 0x1a, 0xea, 0x04, 0x00, - 0xff, 0xea, 0xd4, 0x0d, + 0x02, 0x28, 0x19, 0x33, + 0x02, 0xa8, 0x50, 0x36, 0xe7, 0xad, 0x5a, 0x09, - 0x00, 0xe2, 0xa6, 0x58, + 0x00, 0xe2, 0x9c, 0x58, 0xff, 0xea, 0x56, 0x02, 0x04, 0x7c, 0x78, 0x32, 0x20, 0x16, 0x64, 0x78, 0x04, 0x38, 0x79, 0x32, 0x80, 0x37, 0x6f, 0x16, - 0xff, 0x2d, 0xb5, 0x60, - 0xff, 0x29, 0xb5, 0x60, - 0x40, 0x51, 0xc5, 0x78, - 0xff, 0x4f, 0xb5, 0x68, + 0xff, 0x2d, 0xab, 0x60, + 0xff, 0x29, 0xab, 0x60, + 0x40, 0x51, 0xbb, 0x78, + 0xff, 0x4f, 0xab, 0x68, 0xff, 0x4d, 0xc1, 0x19, 0x00, 0x4e, 0xd5, 0x19, - 0x00, 0xe2, 0xc4, 0x50, + 0x00, 0xe2, 0xba, 0x50, 0x01, 0x4c, 0xc1, 0x31, 0x00, 0x50, 0xd5, 0x19, - 0x00, 0xe2, 0xc4, 0x48, + 0x00, 0xe2, 0xba, 0x48, 0x80, 0x18, 0x64, 0x78, 0x02, 0x4a, 0x1d, 0x30, 0x10, 0xea, 0x18, 0x00, @@ -113,30 +108,30 @@ static uint8_t seqprog[] = { 0xff, 0xea, 0xc0, 0x09, 0x01, 0x4e, 0x9d, 0x1a, 0x00, 0x4f, 0x9f, 0x22, - 0x01, 0xaa, 0x6d, 0x33, - 0x01, 0xea, 0x5c, 0x33, - 0x04, 0xa4, 0x49, 0x32, - 0xff, 0xea, 0x4a, 0x03, - 0xff, 0xea, 0x4e, 0x03, + 0x01, 0x94, 0x6d, 0x33, + 0xff, 0xea, 0x20, 0x0b, + 0x04, 0xac, 0x49, 0x32, + 0xff, 0xea, 0x5a, 0x03, + 0xff, 0xea, 0x5e, 0x03, 0x01, 0x10, 0xd4, 0x31, - 0x10, 0xa8, 0xf5, 0x68, - 0x3d, 0xa9, 0xc5, 0x29, + 0x10, 0x92, 0xeb, 0x68, + 0x3d, 0x93, 0xc5, 0x29, 0xfe, 0xe2, 0xc4, 0x09, 0x01, 0xea, 0xc6, 0x01, 0x02, 0xe2, 0xc8, 0x31, 0x02, 0xec, 0x50, 0x31, 0x02, 0xa0, 0xda, 0x31, - 0xff, 0xa9, 0xf4, 0x70, - 0x02, 0xa0, 0x48, 0x37, - 0xff, 0x21, 0xfd, 0x70, + 0xff, 0xa9, 0xea, 0x70, + 0x02, 0xa0, 0x58, 0x37, + 0xff, 0x21, 0xf3, 0x70, 0x02, 0x22, 0x51, 0x31, - 0x02, 0xa0, 0x4c, 0x33, + 0x02, 0xa0, 0x5c, 0x33, 0x02, 0xa0, 0x44, 0x36, 0x02, 0xa0, 0x40, 0x32, 0x02, 0xa0, 0x44, 0x36, - 0x04, 0x47, 0x05, 0x69, - 0x40, 0x16, 0x30, 0x69, - 0xff, 0x2d, 0x35, 0x61, + 0x04, 0x47, 0xfb, 0x68, + 0x40, 0x16, 0x26, 0x69, + 0xff, 0x2d, 0x2b, 0x61, 0xff, 0x29, 0x65, 0x70, 0x01, 0x37, 0xc1, 0x31, 0x02, 0x28, 0x55, 0x32, @@ -149,20 +144,20 @@ static uint8_t seqprog[] = { 0x01, 0x50, 0xa1, 0x1a, 0xff, 0x4e, 0x9d, 0x1a, 0xff, 0x4f, 0x9f, 0x22, - 0xff, 0x8d, 0x29, 0x71, - 0x80, 0xac, 0x28, 0x71, - 0x20, 0x16, 0x28, 0x69, + 0xff, 0x8d, 0x1f, 0x71, + 0x80, 0xac, 0x1e, 0x71, + 0x20, 0x16, 0x1e, 0x69, 0x02, 0x8c, 0x51, 0x31, - 0x00, 0xe2, 0x12, 0x41, + 0x00, 0xe2, 0x08, 0x41, 0x01, 0xac, 0x08, 0x31, 0x09, 0xea, 0x5a, 0x01, 0x02, 0x8c, 0x51, 0x32, 0xff, 0xea, 0x1a, 0x07, 0x04, 0x24, 0xf9, 0x30, - 0x1d, 0xea, 0x3a, 0x41, + 0x1d, 0xea, 0x30, 0x41, 0x02, 0x2c, 0x51, 0x31, - 0x04, 0xa0, 0xf9, 0x30, - 0x19, 0xea, 0x3a, 0x41, + 0x04, 0xa8, 0xf9, 0x30, + 0x19, 0xea, 0x30, 0x41, 0x06, 0xea, 0x08, 0x81, 0x01, 0xe2, 0x5a, 0x35, 0x02, 0xf2, 0xf0, 0x35, @@ -179,26 +174,28 @@ static uint8_t seqprog[] = { 0x02, 0x20, 0xbd, 0x30, 0x02, 0x20, 0xb9, 0x30, 0x02, 0x20, 0x51, 0x31, - 0x4c, 0xa9, 0xd7, 0x28, - 0x10, 0xa8, 0x63, 0x79, + 0x4c, 0x93, 0xd7, 0x28, + 0x10, 0x92, 0x59, 0x79, 0x01, 0x6b, 0xc0, 0x30, 0x02, 0x64, 0xc8, 0x00, 0x40, 0x3a, 0x74, 0x04, 0x00, 0xe2, 0x56, 0x58, - 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x3a, 0x59, 0x33, 0xea, 0x00, 0x00, 0x30, 0x3f, 0xc0, 0x09, - 0x30, 0xe0, 0x64, 0x61, - 0x20, 0x3f, 0x7a, 0x69, - 0x10, 0x3f, 0x64, 0x79, + 0x30, 0xe0, 0x5a, 0x61, + 0x20, 0x3f, 0x70, 0x69, + 0x10, 0x3f, 0x5a, 0x79, 0x02, 0xea, 0x7e, 0x00, - 0x00, 0xea, 0x44, 0x59, + 0x00, 0xea, 0x3a, 0x59, 0x01, 0xea, 0x00, 0x30, 0x02, 0x48, 0x51, 0x35, 0x01, 0xea, 0x7e, 0x00, - 0x11, 0xea, 0x44, 0x59, + 0x11, 0xea, 0x3a, 0x59, 0x11, 0xea, 0x00, 0x00, 0x02, 0x48, 0x51, 0x35, + 0xc0, 0x4a, 0x94, 0x00, + 0x04, 0x41, 0x7e, 0x79, 0x08, 0xea, 0x98, 0x00, 0x08, 0x57, 0xae, 0x00, 0x08, 0x3c, 0x78, 0x00, @@ -206,11 +203,12 @@ static uint8_t seqprog[] = { 0x0f, 0x67, 0xc0, 0x09, 0x00, 0x34, 0x69, 0x02, 0x20, 0xea, 0x96, 0x00, - 0x00, 0xe2, 0xf8, 0x41, - 0x40, 0x3a, 0xae, 0x69, + 0x00, 0xe2, 0xf6, 0x41, + 0xc0, 0x4a, 0x94, 0x00, + 0x40, 0x3a, 0xaa, 0x69, 0x02, 0x55, 0x06, 0x68, - 0x02, 0x56, 0xae, 0x69, - 0xff, 0x5b, 0xae, 0x61, + 0x02, 0x56, 0xaa, 0x69, + 0xff, 0x5b, 0xaa, 0x61, 0x02, 0x20, 0x51, 0x31, 0x80, 0xea, 0xb2, 0x01, 0x44, 0xea, 0x00, 0x00, @@ -218,146 +216,149 @@ static uint8_t seqprog[] = { 0x33, 0xea, 0x00, 0x00, 0xff, 0xea, 0xb2, 0x09, 0xff, 0xe0, 0xc0, 0x19, - 0xff, 0xe0, 0xb0, 0x79, - 0x02, 0xa4, 0x51, 0x31, - 0x00, 0xe2, 0xa6, 0x41, + 0xff, 0xe0, 0xac, 0x79, + 0x02, 0xac, 0x51, 0x31, + 0x00, 0xe2, 0xa2, 0x41, 0x02, 0x5e, 0x50, 0x31, 0x02, 0xa8, 0xb8, 0x30, 0x02, 0x5c, 0x50, 0x31, - 0xff, 0xa5, 0xc1, 0x71, - 0x02, 0xa4, 0x41, 0x31, + 0xff, 0xad, 0xbd, 0x71, + 0x02, 0xac, 0x41, 0x31, 0x02, 0x22, 0x51, 0x31, - 0x02, 0xa0, 0x4c, 0x33, + 0x02, 0xa0, 0x5c, 0x33, 0x02, 0xa0, 0x44, 0x32, - 0x00, 0xe2, 0xca, 0x41, - 0x10, 0xa8, 0xcb, 0x69, - 0x3d, 0xa9, 0xc9, 0x29, + 0x00, 0xe2, 0xc6, 0x41, + 0x10, 0x92, 0xc7, 0x69, + 0x3d, 0x93, 0xc9, 0x29, 0x01, 0xe4, 0xc8, 0x01, 0x01, 0xea, 0xca, 0x01, 0xff, 0xea, 0xda, 0x01, 0x02, 0x20, 0x51, 0x31, - 0x02, 0xa6, 0x41, 0x32, - 0xff, 0x21, 0xd3, 0x61, + 0x02, 0xae, 0x41, 0x32, + 0xff, 0x21, 0xcf, 0x61, 0xff, 0xea, 0x46, 0x02, 0x02, 0x5c, 0x50, 0x31, 0x40, 0xea, 0x96, 0x00, 0x02, 0x56, 0xcc, 0x6d, 0x01, 0x55, 0xcc, 0x6d, - 0x10, 0xa8, 0xdf, 0x79, - 0x10, 0x40, 0xe8, 0x69, - 0x01, 0x56, 0xe8, 0x79, - 0xff, 0xad, 0x07, 0x78, - 0x13, 0xea, 0x50, 0x59, + 0x10, 0x92, 0xdb, 0x79, + 0x10, 0x40, 0xe4, 0x69, + 0x01, 0x56, 0xe4, 0x79, + 0xff, 0x97, 0x07, 0x78, + 0x13, 0xea, 0x46, 0x59, 0x13, 0xea, 0x04, 0x00, 0x00, 0xe2, 0x06, 0x40, 0xbf, 0x3a, 0x74, 0x08, + 0x04, 0x41, 0xea, 0x79, 0x08, 0xea, 0x98, 0x00, 0x08, 0x57, 0xae, 0x00, - 0x01, 0xa9, 0x69, 0x32, - 0x01, 0xaa, 0x6b, 0x32, + 0x01, 0x93, 0x69, 0x32, + 0x01, 0x94, 0x6b, 0x32, 0x40, 0xea, 0x66, 0x02, 0x08, 0x3c, 0x78, 0x00, 0x80, 0xea, 0x62, 0x02, 0x00, 0xe2, 0xb8, 0x5b, 0x01, 0x36, 0xc1, 0x31, 0x9f, 0xe0, 0x4c, 0x7c, - 0x80, 0xe0, 0x0c, 0x72, - 0xa0, 0xe0, 0x44, 0x72, - 0xc0, 0xe0, 0x3a, 0x72, - 0xe0, 0xe0, 0x74, 0x72, - 0x01, 0xea, 0x50, 0x59, + 0x80, 0xe0, 0x0a, 0x72, + 0xa0, 0xe0, 0x46, 0x72, + 0xc0, 0xe0, 0x3c, 0x72, + 0xe0, 0xe0, 0x76, 0x72, + 0x01, 0xea, 0x46, 0x59, 0x01, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf8, 0x41, - 0x80, 0x33, 0x13, 0x7a, - 0x03, 0xea, 0x50, 0x59, + 0x00, 0xe2, 0xf6, 0x41, + 0x80, 0x33, 0x11, 0x7a, + 0x03, 0xea, 0x46, 0x59, 0x03, 0xea, 0x04, 0x00, - 0xee, 0x00, 0x1a, 0x6a, + 0xee, 0x00, 0x18, 0x6a, 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x3a, 0x59, 0x33, 0xea, 0x00, 0x00, 0x02, 0xa8, 0x90, 0x32, - 0x00, 0xe2, 0x6a, 0x59, - 0xef, 0xac, 0xd5, 0x19, - 0x00, 0xe2, 0x2a, 0x52, + 0x00, 0xe2, 0x60, 0x59, + 0xef, 0x96, 0xd5, 0x19, + 0x00, 0xe2, 0x28, 0x52, 0x09, 0x80, 0xe1, 0x30, 0x02, 0xea, 0x36, 0x00, 0xa8, 0xea, 0x32, 0x00, - 0x00, 0xe2, 0x30, 0x42, - 0x01, 0xac, 0xd1, 0x30, + 0x00, 0xe2, 0x2e, 0x42, + 0x01, 0x96, 0xd1, 0x30, 0x10, 0x80, 0x89, 0x31, 0x20, 0xea, 0x32, 0x00, 0xbf, 0x33, 0x67, 0x0a, - 0x20, 0x19, 0x32, 0x6a, - 0x02, 0x4d, 0xf8, 0x69, + 0x10, 0x4c, 0x38, 0x6a, + 0x20, 0x19, 0x30, 0x6a, + 0x20, 0x19, 0x34, 0x6a, + 0x02, 0x4d, 0xf6, 0x69, 0x40, 0x33, 0x67, 0x02, - 0x00, 0xe2, 0xf8, 0x41, - 0x80, 0x33, 0xb5, 0x6a, + 0x00, 0xe2, 0xf6, 0x41, + 0x80, 0x33, 0xb7, 0x6a, 0x01, 0x44, 0x10, 0x33, - 0x08, 0xa8, 0x51, 0x03, - 0x00, 0xe2, 0xf8, 0x41, + 0x08, 0x92, 0x25, 0x03, + 0x00, 0xe2, 0xf6, 0x41, 0x10, 0xea, 0x80, 0x00, 0x01, 0x31, 0xc5, 0x31, - 0x80, 0xe2, 0x60, 0x62, - 0x10, 0xa8, 0x85, 0x6a, - 0xc0, 0xaa, 0xc5, 0x01, - 0x40, 0xa8, 0x51, 0x6a, + 0x80, 0xe2, 0x62, 0x62, + 0x10, 0x92, 0x87, 0x6a, + 0xc0, 0x94, 0xc5, 0x01, + 0x40, 0x92, 0x53, 0x6a, 0xbf, 0xe2, 0xc4, 0x09, - 0x20, 0xa8, 0x65, 0x7a, + 0x20, 0x92, 0x67, 0x7a, 0x01, 0xe2, 0x88, 0x30, 0x00, 0xe2, 0xb8, 0x5b, - 0xa0, 0x36, 0x6d, 0x62, - 0x23, 0xa8, 0x89, 0x08, + 0xa0, 0x36, 0x6f, 0x62, + 0x23, 0x92, 0x89, 0x08, 0x00, 0xe2, 0xb8, 0x5b, - 0xa0, 0x36, 0x6d, 0x62, - 0x00, 0xa8, 0x64, 0x42, - 0xff, 0xe2, 0x64, 0x62, - 0x00, 0xe2, 0x84, 0x42, + 0xa0, 0x36, 0x6f, 0x62, + 0x00, 0xa8, 0x66, 0x42, + 0xff, 0xe2, 0x66, 0x62, + 0x00, 0xe2, 0x86, 0x42, 0x40, 0xea, 0x98, 0x00, 0x01, 0xe2, 0x88, 0x30, 0x00, 0xe2, 0xb8, 0x5b, - 0xa0, 0x36, 0x43, 0x72, + 0xa0, 0x36, 0x45, 0x72, 0x40, 0xea, 0x98, 0x00, 0x01, 0x31, 0x89, 0x32, 0x08, 0xea, 0x62, 0x02, - 0x00, 0xe2, 0xf8, 0x41, + 0x00, 0xe2, 0xf6, 0x41, 0xe0, 0xea, 0xd4, 0x5b, - 0x80, 0xe0, 0xc0, 0x6a, - 0x04, 0xe0, 0x66, 0x73, - 0x02, 0xe0, 0x96, 0x73, - 0x00, 0xea, 0x1e, 0x73, - 0x03, 0xe0, 0xa6, 0x73, - 0x23, 0xe0, 0x96, 0x72, - 0x08, 0xe0, 0xbc, 0x72, + 0x80, 0xe0, 0xc2, 0x6a, + 0x04, 0xe0, 0x68, 0x73, + 0x02, 0xe0, 0x9a, 0x73, + 0x00, 0xea, 0x20, 0x73, + 0x03, 0xe0, 0xaa, 0x73, + 0x23, 0xe0, 0x98, 0x72, + 0x08, 0xe0, 0xbe, 0x72, 0x00, 0xe2, 0xb8, 0x5b, - 0x07, 0xea, 0x50, 0x59, + 0x07, 0xea, 0x46, 0x59, 0x07, 0xea, 0x04, 0x00, - 0x08, 0x42, 0xf9, 0x71, - 0x04, 0x42, 0x93, 0x62, + 0x08, 0x42, 0xf7, 0x71, + 0x04, 0x42, 0x95, 0x62, 0x01, 0x43, 0x89, 0x30, - 0x00, 0xe2, 0x84, 0x42, + 0x00, 0xe2, 0x86, 0x42, 0x01, 0x44, 0xd4, 0x31, - 0x00, 0xe2, 0x84, 0x42, + 0x00, 0xe2, 0x86, 0x42, 0x01, 0x00, 0x60, 0x32, - 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x3a, 0x59, 0x33, 0xea, 0x00, 0x00, 0x4c, 0x34, 0xc1, 0x28, 0x01, 0x64, 0xc0, 0x31, - 0x00, 0x30, 0x45, 0x59, + 0x00, 0x30, 0x3b, 0x59, 0x01, 0x30, 0x01, 0x30, - 0x01, 0xe0, 0xba, 0x7a, + 0x01, 0xe0, 0xbc, 0x7a, 0xa0, 0xea, 0xca, 0x5b, - 0x01, 0xa0, 0xba, 0x62, - 0x01, 0x84, 0xaf, 0x7a, - 0x01, 0xab, 0xbd, 0x6a, - 0x05, 0xea, 0x50, 0x59, + 0x01, 0xa0, 0xbc, 0x62, + 0x01, 0x84, 0xb1, 0x7a, + 0x01, 0x95, 0xbf, 0x6a, + 0x05, 0xea, 0x46, 0x59, 0x05, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xbc, 0x42, - 0x03, 0xea, 0x50, 0x59, + 0x00, 0xe2, 0xbe, 0x42, + 0x03, 0xea, 0x46, 0x59, 0x03, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xbc, 0x42, + 0x00, 0xe2, 0xbe, 0x42, 0x07, 0xea, 0xdc, 0x5b, 0x01, 0x44, 0xd4, 0x31, - 0x00, 0xe2, 0xf8, 0x41, + 0x00, 0xe2, 0xf6, 0x41, 0x3f, 0xe0, 0x6a, 0x0a, 0xc0, 0x34, 0xc1, 0x09, 0x00, 0x35, 0x51, 0x01, @@ -368,54 +369,54 @@ static uint8_t seqprog[] = { 0x01, 0xea, 0xc6, 0x01, 0x02, 0xe2, 0xc8, 0x31, 0x02, 0xec, 0x40, 0x31, - 0xff, 0xa1, 0xdc, 0x72, + 0xff, 0xa1, 0xde, 0x72, 0x02, 0xe8, 0xda, 0x31, 0x02, 0xa0, 0x50, 0x31, - 0x00, 0xe2, 0xfe, 0x42, + 0x00, 0xe2, 0x00, 0x43, 0x80, 0x33, 0x67, 0x02, 0x01, 0x44, 0xd4, 0x31, 0x00, 0xe2, 0xb8, 0x5b, 0x01, 0x33, 0x67, 0x02, - 0xe0, 0x36, 0x19, 0x63, + 0xe0, 0x36, 0x1b, 0x63, 0x02, 0x33, 0x67, 0x02, - 0x20, 0x46, 0x12, 0x63, + 0x20, 0x46, 0x14, 0x63, 0xff, 0xea, 0x52, 0x09, 0xa8, 0xea, 0xca, 0x5b, - 0x04, 0xa8, 0xf9, 0x7a, + 0x04, 0x92, 0xfb, 0x7a, 0x01, 0x34, 0xc1, 0x31, - 0x00, 0xa9, 0xf9, 0x62, + 0x00, 0x93, 0xfb, 0x62, 0x01, 0x35, 0xc1, 0x31, - 0x00, 0xaa, 0x03, 0x73, + 0x00, 0x94, 0x05, 0x73, 0x01, 0xa9, 0x52, 0x11, - 0xff, 0xa9, 0xee, 0x6a, - 0x00, 0xe2, 0x12, 0x43, + 0xff, 0xa9, 0xf0, 0x6a, + 0x00, 0xe2, 0x14, 0x43, 0x10, 0x33, 0x67, 0x02, - 0x04, 0xa8, 0x13, 0x7b, - 0xfb, 0xa8, 0x51, 0x0b, + 0x04, 0x92, 0x15, 0x7b, + 0xfb, 0x92, 0x25, 0x0b, 0xff, 0xea, 0x66, 0x0a, - 0x01, 0x9c, 0x0d, 0x6b, + 0x01, 0xa4, 0x0f, 0x6b, 0x02, 0xa8, 0x90, 0x32, - 0x00, 0xe2, 0x6a, 0x59, - 0x10, 0xa8, 0xbd, 0x7a, + 0x00, 0xe2, 0x60, 0x59, + 0x10, 0x92, 0xbf, 0x7a, 0xff, 0xea, 0xdc, 0x5b, - 0x00, 0xe2, 0xbc, 0x42, - 0x04, 0xea, 0x50, 0x59, + 0x00, 0xe2, 0xbe, 0x42, + 0x04, 0xea, 0x46, 0x59, 0x04, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xbc, 0x42, - 0x04, 0xea, 0x50, 0x59, + 0x00, 0xe2, 0xbe, 0x42, + 0x04, 0xea, 0x46, 0x59, 0x04, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf8, 0x41, - 0x08, 0xa8, 0xb5, 0x7a, - 0xc0, 0x33, 0x29, 0x7b, - 0x80, 0x33, 0xb5, 0x6a, - 0xff, 0x88, 0x29, 0x6b, - 0x40, 0x33, 0xb5, 0x6a, - 0x10, 0xa8, 0x2f, 0x7b, - 0x0a, 0xea, 0x50, 0x59, + 0x00, 0xe2, 0xf6, 0x41, + 0x08, 0x92, 0xb7, 0x7a, + 0xc0, 0x33, 0x2b, 0x7b, + 0x80, 0x33, 0xb7, 0x6a, + 0xff, 0x88, 0x2b, 0x6b, + 0x40, 0x33, 0xb7, 0x6a, + 0x10, 0x92, 0x31, 0x7b, + 0x0a, 0xea, 0x46, 0x59, 0x0a, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x4e, 0x5b, - 0x00, 0xe2, 0x82, 0x43, - 0x50, 0x4b, 0x36, 0x6b, + 0x00, 0xe2, 0x50, 0x5b, + 0x00, 0xe2, 0x84, 0x43, + 0x50, 0x4b, 0x38, 0x6b, 0xbf, 0x3a, 0x74, 0x08, 0x01, 0xe0, 0xf4, 0x31, 0xff, 0xea, 0xc0, 0x09, @@ -425,25 +426,25 @@ static uint8_t seqprog[] = { 0x01, 0xfa, 0xc0, 0x35, 0x02, 0xa8, 0x84, 0x32, 0x02, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x3a, 0x59, 0x33, 0xea, 0x00, 0x00, 0x02, 0x42, 0x51, 0x31, - 0xff, 0xae, 0x65, 0x68, - 0xff, 0x88, 0x5b, 0x6b, - 0x01, 0x9c, 0x57, 0x6b, - 0x02, 0x9c, 0x5f, 0x6b, - 0x01, 0x84, 0x5f, 0x7b, + 0xff, 0x90, 0x65, 0x68, + 0xff, 0x88, 0x5d, 0x6b, + 0x01, 0xa4, 0x59, 0x6b, + 0x02, 0xa4, 0x61, 0x6b, + 0x01, 0x84, 0x61, 0x7b, 0x02, 0x28, 0x19, 0x33, 0x02, 0xa8, 0x50, 0x36, - 0xff, 0x88, 0x5f, 0x73, - 0x00, 0xe2, 0x32, 0x5b, - 0x02, 0xa8, 0x5c, 0x33, + 0xff, 0x88, 0x61, 0x73, + 0x00, 0xe2, 0x34, 0x5b, + 0x02, 0xa8, 0x20, 0x33, 0x02, 0x2c, 0x19, 0x33, 0x02, 0xa8, 0x58, 0x32, - 0x04, 0x9c, 0x39, 0x07, - 0xc0, 0x33, 0xb5, 0x6a, - 0x04, 0xa8, 0x51, 0x03, - 0x20, 0xa8, 0x83, 0x6b, + 0x04, 0xa4, 0x49, 0x07, + 0xc0, 0x33, 0xb7, 0x6a, + 0x04, 0x92, 0x25, 0x03, + 0x20, 0x92, 0x85, 0x6b, 0x02, 0xa8, 0x40, 0x31, 0xc0, 0x34, 0xc1, 0x09, 0x00, 0x35, 0x51, 0x01, @@ -458,30 +459,29 @@ static uint8_t seqprog[] = { 0xf7, 0x57, 0xae, 0x08, 0x08, 0xea, 0x98, 0x00, 0x01, 0x44, 0xd4, 0x31, - 0xee, 0x00, 0x8c, 0x6b, + 0xee, 0x00, 0x8e, 0x6b, 0x02, 0xea, 0xb4, 0x00, - 0x00, 0xe2, 0xb4, 0x5b, - 0x09, 0x4c, 0x8e, 0x7b, + 0xc0, 0xea, 0x66, 0x02, + 0x09, 0x4c, 0x90, 0x7b, + 0x01, 0xea, 0x6c, 0x02, 0x08, 0x4c, 0x06, 0x68, - 0x0b, 0xea, 0x50, 0x59, + 0x0b, 0xea, 0x46, 0x59, 0x0b, 0xea, 0x04, 0x00, 0x01, 0x44, 0xd4, 0x31, - 0x20, 0x33, 0xf9, 0x79, - 0x00, 0xe2, 0x9e, 0x5b, - 0x00, 0xe2, 0xf8, 0x41, - 0x01, 0x84, 0xa3, 0x7b, - 0x01, 0x9c, 0x39, 0x07, - 0x08, 0x60, 0x20, 0x33, - 0x08, 0x80, 0x31, 0x37, + 0x20, 0x33, 0xf7, 0x79, + 0x00, 0xe2, 0xa2, 0x5b, + 0x00, 0xe2, 0xf6, 0x41, + 0x01, 0x84, 0xa7, 0x7b, + 0x01, 0xa4, 0x49, 0x07, + 0x08, 0x60, 0x30, 0x33, + 0x08, 0x80, 0x41, 0x37, 0xdf, 0x33, 0x67, 0x0a, - 0xee, 0x00, 0xb0, 0x6b, + 0xee, 0x00, 0xb4, 0x6b, 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x3a, 0x59, 0x33, 0xea, 0x00, 0x00, - 0x00, 0xe2, 0x6a, 0x59, - 0x00, 0xe2, 0xbc, 0x42, - 0x01, 0xea, 0x6c, 0x02, - 0xc0, 0xea, 0x66, 0x06, + 0x00, 0xe2, 0x60, 0x59, + 0x00, 0xe2, 0xbe, 0x42, 0xff, 0x42, 0xc4, 0x6b, 0x01, 0x41, 0xb8, 0x6b, 0x02, 0x41, 0xb8, 0x7b, @@ -495,7 +495,7 @@ static uint8_t seqprog[] = { 0xff, 0x42, 0xcc, 0x7b, 0x04, 0x4c, 0xcc, 0x6b, 0xe0, 0x41, 0x6c, 0x0a, - 0xe0, 0x36, 0xf9, 0x61, + 0xe0, 0x36, 0xf7, 0x61, 0xff, 0xea, 0xca, 0x09, 0x01, 0xe2, 0xc8, 0x31, 0x01, 0x46, 0xda, 0x35, @@ -542,42 +542,42 @@ static uint8_t seqprog[] = { 0x01, 0xac, 0xd4, 0x99, 0x00, 0xe2, 0x64, 0x50, 0xfe, 0xa6, 0x4c, 0x0d, - 0x0b, 0x90, 0xe1, 0x30, - 0xfd, 0x9c, 0x49, 0x09, - 0x80, 0x9b, 0x39, 0x7c, + 0x0b, 0x98, 0xe1, 0x30, + 0xfd, 0xa4, 0x49, 0x09, + 0x80, 0xa3, 0x39, 0x7c, 0x02, 0xa4, 0x48, 0x01, 0x01, 0xa4, 0x36, 0x30, 0xa8, 0xea, 0x32, 0x00, - 0xfd, 0x9c, 0x39, 0x0b, - 0x05, 0x9b, 0x07, 0x33, + 0xfd, 0xa4, 0x49, 0x0b, + 0x05, 0xa3, 0x07, 0x33, 0x80, 0x83, 0x45, 0x6c, 0x02, 0xea, 0x4c, 0x05, 0xff, 0xea, 0x4c, 0x0d, - 0x00, 0xe2, 0x3e, 0x59, + 0x00, 0xe2, 0x34, 0x59, 0x02, 0xa6, 0xe6, 0x6b, 0x80, 0xf9, 0xf2, 0x05, 0xc0, 0x33, 0x53, 0x7c, - 0x03, 0xea, 0x50, 0x59, + 0x03, 0xea, 0x46, 0x59, 0x03, 0xea, 0x04, 0x00, 0x20, 0x33, 0x77, 0x7c, 0x01, 0x84, 0x5d, 0x6c, - 0x06, 0xea, 0x50, 0x59, + 0x06, 0xea, 0x46, 0x59, 0x06, 0xea, 0x04, 0x00, 0x00, 0xe2, 0x7a, 0x44, 0x01, 0x00, 0x60, 0x32, 0xee, 0x00, 0x66, 0x6c, 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x44, 0x59, + 0x33, 0xea, 0x3a, 0x59, 0x33, 0xea, 0x00, 0x00, 0x80, 0x3d, 0x7a, 0x00, 0xfc, 0x42, 0x68, 0x7c, 0x7f, 0x3d, 0x7a, 0x08, - 0x00, 0x30, 0x45, 0x59, + 0x00, 0x30, 0x3b, 0x59, 0x01, 0x30, 0x01, 0x30, - 0x09, 0xea, 0x50, 0x59, + 0x09, 0xea, 0x46, 0x59, 0x09, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf8, 0x41, - 0x01, 0x9c, 0x5d, 0x6c, + 0x00, 0xe2, 0xf6, 0x41, + 0x01, 0xa4, 0x5d, 0x6c, 0x00, 0xe2, 0x30, 0x5c, 0x20, 0x33, 0x67, 0x02, 0x01, 0x00, 0x60, 0x32, @@ -586,7 +586,7 @@ static uint8_t seqprog[] = { 0x00, 0xe2, 0x56, 0x58, 0x00, 0xe2, 0x66, 0x58, 0x00, 0xe2, 0x3a, 0x58, - 0x00, 0x30, 0x45, 0x59, + 0x00, 0x30, 0x3b, 0x59, 0x01, 0x30, 0x01, 0x30, 0x20, 0x19, 0x82, 0x6c, 0x00, 0xe2, 0xb2, 0x5c, @@ -601,11 +601,11 @@ static uint8_t seqprog[] = { 0x03, 0x42, 0x4c, 0x6c, 0x00, 0xe2, 0xe0, 0x5b, 0x80, 0xf9, 0xf2, 0x01, - 0x04, 0x33, 0xf9, 0x79, - 0x00, 0xe2, 0xf8, 0x41, + 0x04, 0x33, 0xf7, 0x79, + 0x00, 0xe2, 0xf6, 0x41, 0x08, 0x5d, 0xba, 0x6c, 0x00, 0xe2, 0x56, 0x58, - 0x00, 0x30, 0x45, 0x59, + 0x00, 0x30, 0x3b, 0x59, 0x01, 0x30, 0x01, 0x30, 0x02, 0x1b, 0xaa, 0x7c, 0x08, 0x5d, 0xb8, 0x7c, @@ -619,7 +619,7 @@ static uint8_t seqprog[] = { 0xf8, 0x1b, 0x08, 0x0b, 0xff, 0xea, 0x06, 0x0b, 0x03, 0x68, 0x00, 0x37, - 0x00, 0xe2, 0xc4, 0x58, + 0x00, 0xe2, 0xba, 0x58, 0x10, 0xea, 0x18, 0x00, 0xf9, 0xd9, 0xb2, 0x0d, 0x01, 0xd9, 0xb2, 0x05, @@ -631,7 +631,7 @@ static uint8_t seqprog[] = { 0x11, 0x00, 0x00, 0x10, 0x04, 0x19, 0x08, 0x7d, 0xdf, 0x19, 0x32, 0x08, - 0x60, 0x5b, 0xe6, 0x6c, + 0x60, 0x5b, 0x08, 0x6d, 0x01, 0x4c, 0xe2, 0x7c, 0x20, 0x19, 0x32, 0x00, 0x01, 0xd9, 0xb2, 0x05, @@ -641,29 +641,29 @@ static uint8_t seqprog[] = { 0x08, 0x5b, 0x0a, 0x6d, 0x20, 0x5b, 0xfa, 0x6c, 0x02, 0x5b, 0x2a, 0x6d, - 0x0e, 0xea, 0x50, 0x59, + 0x0e, 0xea, 0x46, 0x59, 0x0e, 0xea, 0x04, 0x00, 0x80, 0xf9, 0xea, 0x6c, 0xdf, 0x5c, 0xb8, 0x08, 0x01, 0xd9, 0xb2, 0x05, - 0x01, 0x9c, 0xe5, 0x6d, + 0x01, 0xa4, 0xe5, 0x6d, 0x00, 0xe2, 0x30, 0x5c, 0x00, 0xe2, 0x34, 0x5d, - 0x01, 0xae, 0x5d, 0x1b, + 0x01, 0x90, 0x21, 0x1b, 0x01, 0xd9, 0xb2, 0x05, - 0x00, 0xe2, 0x32, 0x5b, - 0xf3, 0xac, 0xd5, 0x19, + 0x00, 0xe2, 0x34, 0x5b, + 0xf3, 0x96, 0xd5, 0x19, 0x00, 0xe2, 0x18, 0x55, - 0x80, 0xac, 0x19, 0x6d, - 0x0f, 0xea, 0x50, 0x59, + 0x80, 0x96, 0x19, 0x6d, + 0x0f, 0xea, 0x46, 0x59, 0x0f, 0xea, 0x04, 0x00, 0x00, 0xe2, 0x20, 0x45, 0x04, 0x8c, 0xe1, 0x30, 0x01, 0xea, 0xf2, 0x00, 0x02, 0xea, 0x36, 0x00, 0xa8, 0xea, 0x32, 0x00, - 0xff, 0xad, 0x27, 0x7d, - 0x14, 0xea, 0x50, 0x59, + 0xff, 0x97, 0x27, 0x7d, + 0x14, 0xea, 0x46, 0x59, 0x14, 0xea, 0x04, 0x00, 0x00, 0xe2, 0x96, 0x5d, 0x01, 0xd9, 0xb2, 0x05, @@ -673,14 +673,14 @@ static uint8_t seqprog[] = { 0x00, 0xe2, 0x8e, 0x5d, 0x01, 0xd9, 0xb2, 0x05, 0x02, 0xa6, 0x44, 0x7d, - 0x00, 0xe2, 0x3e, 0x59, + 0x00, 0xe2, 0x34, 0x59, 0x20, 0x5b, 0x52, 0x6d, 0xfc, 0x42, 0x3e, 0x7d, 0x10, 0x40, 0x40, 0x6d, 0x20, 0x4d, 0x42, 0x7d, 0x08, 0x5d, 0x52, 0x6d, 0x02, 0xa6, 0xe6, 0x6b, - 0x00, 0xe2, 0x3e, 0x59, + 0x00, 0xe2, 0x34, 0x59, 0x20, 0x5b, 0x52, 0x6d, 0x01, 0x1b, 0x72, 0x6d, 0xfc, 0x42, 0x4e, 0x7d, @@ -690,22 +690,22 @@ static uint8_t seqprog[] = { 0x02, 0x19, 0x32, 0x00, 0x01, 0x5b, 0x40, 0x31, 0x00, 0xe2, 0xb2, 0x5c, - 0x00, 0xe2, 0x9e, 0x5b, + 0x00, 0xe2, 0xa2, 0x5b, 0x20, 0xea, 0xb6, 0x00, 0x00, 0xe2, 0xe0, 0x5b, 0x20, 0x5c, 0xb8, 0x00, 0x04, 0x19, 0x68, 0x6d, 0x01, 0x1a, 0x68, 0x6d, - 0x00, 0xe2, 0x3e, 0x59, + 0x00, 0xe2, 0x34, 0x59, 0x01, 0x1a, 0x64, 0x78, 0x80, 0xf9, 0xf2, 0x01, 0x20, 0xa0, 0xcc, 0x7d, - 0xff, 0xae, 0x5d, 0x1b, - 0x08, 0xa8, 0x43, 0x6b, + 0xff, 0x90, 0x21, 0x1b, + 0x08, 0x92, 0x45, 0x6b, 0x02, 0xea, 0xb4, 0x04, - 0x01, 0x9c, 0x39, 0x03, + 0x01, 0xa4, 0x49, 0x03, 0x40, 0x5b, 0x82, 0x6d, - 0x00, 0xe2, 0x3e, 0x59, + 0x00, 0xe2, 0x34, 0x59, 0x40, 0x5b, 0x82, 0x6d, 0x04, 0x5d, 0xe6, 0x7d, 0x01, 0x1a, 0xe6, 0x7d, @@ -714,14 +714,14 @@ static uint8_t seqprog[] = { 0x04, 0x5d, 0xe6, 0x7d, 0x01, 0x1a, 0xe6, 0x7d, 0x80, 0xf9, 0xf2, 0x01, - 0xff, 0xae, 0x5d, 0x1b, - 0x08, 0xa8, 0x43, 0x6b, + 0xff, 0x90, 0x21, 0x1b, + 0x08, 0x92, 0x45, 0x6b, 0x02, 0xea, 0xb4, 0x04, - 0x00, 0xe2, 0x3e, 0x59, + 0x00, 0xe2, 0x34, 0x59, 0x01, 0x1b, 0x64, 0x78, 0x80, 0xf9, 0xf2, 0x01, 0x02, 0xea, 0xb4, 0x04, - 0x00, 0xe2, 0x3e, 0x59, + 0x00, 0xe2, 0x34, 0x59, 0x01, 0x1b, 0xaa, 0x6d, 0x40, 0x5b, 0xb8, 0x7d, 0x01, 0x1b, 0xaa, 0x6d, @@ -729,45 +729,45 @@ static uint8_t seqprog[] = { 0x01, 0x1a, 0x64, 0x78, 0x80, 0xf9, 0xf2, 0x01, 0xff, 0xea, 0x10, 0x03, - 0x08, 0xa8, 0x51, 0x03, - 0x00, 0xe2, 0x42, 0x43, + 0x08, 0x92, 0x25, 0x03, + 0x00, 0xe2, 0x44, 0x43, 0x01, 0x1a, 0xb4, 0x7d, 0x40, 0x5b, 0xb0, 0x7d, 0x01, 0x1a, 0x9e, 0x6d, 0xfc, 0x42, 0x64, 0x78, 0x01, 0x1a, 0xb8, 0x6d, - 0x10, 0xea, 0x50, 0x59, + 0x10, 0xea, 0x46, 0x59, 0x10, 0xea, 0x04, 0x00, 0xfc, 0x42, 0x64, 0x78, 0x10, 0x40, 0xbe, 0x6d, 0x20, 0x4d, 0x64, 0x78, 0x40, 0x5b, 0x9e, 0x6d, 0x01, 0x1a, 0x64, 0x78, - 0x01, 0xae, 0x5d, 0x1b, + 0x01, 0x90, 0x21, 0x1b, 0x30, 0x3f, 0xc0, 0x09, 0x30, 0xe0, 0x64, 0x60, 0x40, 0x4b, 0x64, 0x68, 0xff, 0xea, 0x52, 0x01, - 0xee, 0x00, 0xd2, 0x6d, + 0xee, 0x00, 0xd4, 0x6d, 0x80, 0xf9, 0xf2, 0x01, - 0xff, 0xae, 0x5d, 0x1b, + 0xff, 0x90, 0x21, 0x1b, 0x02, 0xea, 0xb4, 0x00, 0x20, 0xea, 0x9a, 0x00, 0xf3, 0x42, 0xde, 0x6d, - 0x12, 0xea, 0x50, 0x59, + 0x12, 0xea, 0x46, 0x59, 0x12, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf8, 0x41, - 0x0d, 0xea, 0x50, 0x59, + 0x00, 0xe2, 0xf6, 0x41, + 0x0d, 0xea, 0x46, 0x59, 0x0d, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf8, 0x41, - 0x01, 0xae, 0x5d, 0x1b, - 0x11, 0xea, 0x50, 0x59, + 0x00, 0xe2, 0xf6, 0x41, + 0x01, 0x90, 0x21, 0x1b, + 0x11, 0xea, 0x46, 0x59, 0x11, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x32, 0x5b, + 0x00, 0xe2, 0x34, 0x5b, 0x08, 0x5a, 0xb4, 0x00, 0x00, 0xe2, 0x0c, 0x5e, 0xa8, 0xea, 0x32, 0x00, - 0x00, 0xe2, 0x3e, 0x59, + 0x00, 0xe2, 0x34, 0x59, 0x80, 0x1a, 0xfa, 0x7d, 0x00, 0xe2, 0x0c, 0x5e, 0x80, 0x19, 0x32, 0x00, @@ -776,9 +776,9 @@ static uint8_t seqprog[] = { 0x20, 0x4d, 0x64, 0x78, 0x02, 0x84, 0x09, 0x03, 0x40, 0x5b, 0xcc, 0x7d, - 0xff, 0xae, 0x5d, 0x1b, + 0xff, 0x90, 0x21, 0x1b, 0x80, 0xf9, 0xf2, 0x01, - 0x08, 0xa8, 0x43, 0x6b, + 0x08, 0x92, 0x45, 0x6b, 0x02, 0xea, 0xb4, 0x04, 0x01, 0x38, 0xe1, 0x30, 0x05, 0x39, 0xe3, 0x98, @@ -794,12 +794,20 @@ static uint8_t seqprog[] = { }; typedef int ahd_patch_func_t (struct ahd_softc *ahd); +static ahd_patch_func_t ahd_patch23_func; + +static int +ahd_patch23_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0); +} + static ahd_patch_func_t ahd_patch22_func; static int ahd_patch22_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0); + return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0); } static ahd_patch_func_t ahd_patch21_func; @@ -807,7 +815,7 @@ static ahd_patch_func_t ahd_patch21_func static int ahd_patch21_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0); + return ((ahd->features & AHD_RTI) == 0); } static ahd_patch_func_t ahd_patch20_func; @@ -815,7 +823,7 @@ static ahd_patch_func_t ahd_patch20_func static int ahd_patch20_func(struct ahd_softc *ahd) { - return ((ahd->features & AHD_RTI) == 0); + return ((ahd->flags & AHD_INITIATORROLE) != 0); } static ahd_patch_func_t ahd_patch19_func; @@ -823,7 +831,7 @@ static ahd_patch_func_t ahd_patch19_func static int ahd_patch19_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_INITIATORROLE) != 0); + return ((ahd->flags & AHD_TARGETROLE) != 0); } static ahd_patch_func_t ahd_patch18_func; @@ -831,7 +839,7 @@ static ahd_patch_func_t ahd_patch18_func static int ahd_patch18_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_TARGETROLE) != 0); + return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0); } static ahd_patch_func_t ahd_patch17_func; @@ -839,7 +847,7 @@ static ahd_patch_func_t ahd_patch17_func static int ahd_patch17_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0); + return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0); } static ahd_patch_func_t ahd_patch16_func; @@ -847,7 +855,7 @@ static ahd_patch_func_t ahd_patch16_func static int ahd_patch16_func(struct ahd_softc *ahd) { - return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0); + return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0); } static ahd_patch_func_t ahd_patch15_func; @@ -855,7 +863,7 @@ static ahd_patch_func_t ahd_patch15_func static int ahd_patch15_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0); + return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0); } static ahd_patch_func_t ahd_patch14_func; @@ -863,7 +871,7 @@ static ahd_patch_func_t ahd_patch14_func static int ahd_patch14_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0); + return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0); } static ahd_patch_func_t ahd_patch13_func; @@ -871,7 +879,7 @@ static ahd_patch_func_t ahd_patch13_func static int ahd_patch13_func(struct ahd_softc *ahd) { - return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0); + return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0); } static ahd_patch_func_t ahd_patch12_func; @@ -879,7 +887,7 @@ static ahd_patch_func_t ahd_patch12_func static int ahd_patch12_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0); + return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0); } static ahd_patch_func_t ahd_patch11_func; @@ -887,7 +895,7 @@ static ahd_patch_func_t ahd_patch11_func static int ahd_patch11_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0); + return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0); } static ahd_patch_func_t ahd_patch10_func; @@ -895,7 +903,7 @@ static ahd_patch_func_t ahd_patch10_func static int ahd_patch10_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0); + return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0); } static ahd_patch_func_t ahd_patch9_func; @@ -903,7 +911,7 @@ static ahd_patch_func_t ahd_patch9_func; static int ahd_patch9_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0); + return ((ahd->features & AHD_FAST_CDB_DELIVERY) != 0); } static ahd_patch_func_t ahd_patch8_func; @@ -1003,73 +1011,75 @@ static struct patch { { ahd_patch0_func, 48, 1, 1 }, { ahd_patch2_func, 51, 1, 2 }, { ahd_patch0_func, 52, 1, 1 }, + { ahd_patch2_func, 61, 1, 2 }, + { ahd_patch0_func, 62, 1, 1 }, { ahd_patch2_func, 65, 1, 2 }, { ahd_patch0_func, 66, 1, 1 }, - { ahd_patch2_func, 69, 1, 2 }, - { ahd_patch0_func, 70, 1, 1 }, - { ahd_patch1_func, 73, 1, 2 }, - { ahd_patch0_func, 74, 1, 1 }, - { ahd_patch4_func, 107, 1, 1 }, - { ahd_patch2_func, 162, 6, 1 }, - { ahd_patch1_func, 168, 2, 1 }, - { ahd_patch5_func, 170, 1, 1 }, - { ahd_patch2_func, 179, 1, 2 }, - { ahd_patch0_func, 180, 1, 1 }, - { ahd_patch6_func, 181, 2, 2 }, - { ahd_patch0_func, 183, 6, 3 }, - { ahd_patch2_func, 186, 1, 2 }, - { ahd_patch0_func, 187, 1, 1 }, - { ahd_patch2_func, 190, 1, 2 }, - { ahd_patch0_func, 191, 1, 1 }, - { ahd_patch7_func, 193, 2, 1 }, - { ahd_patch5_func, 201, 16, 2 }, - { ahd_patch0_func, 217, 1, 1 }, - { ahd_patch8_func, 237, 2, 1 }, - { ahd_patch1_func, 241, 1, 2 }, - { ahd_patch0_func, 242, 1, 1 }, - { ahd_patch7_func, 245, 2, 1 }, - { ahd_patch1_func, 259, 1, 2 }, - { ahd_patch0_func, 260, 1, 1 }, - { ahd_patch1_func, 263, 1, 2 }, - { ahd_patch0_func, 264, 1, 1 }, - { ahd_patch2_func, 267, 1, 2 }, - { ahd_patch0_func, 268, 1, 1 }, - { ahd_patch1_func, 323, 1, 2 }, - { ahd_patch0_func, 324, 1, 1 }, - { ahd_patch2_func, 332, 1, 2 }, - { ahd_patch0_func, 333, 1, 1 }, - { ahd_patch2_func, 336, 1, 2 }, - { ahd_patch0_func, 337, 1, 1 }, - { ahd_patch1_func, 343, 1, 2 }, - { ahd_patch0_func, 344, 1, 1 }, - { ahd_patch1_func, 346, 1, 2 }, - { ahd_patch0_func, 347, 1, 1 }, - { ahd_patch9_func, 366, 1, 1 }, - { ahd_patch9_func, 369, 1, 1 }, - { ahd_patch9_func, 371, 1, 1 }, - { ahd_patch9_func, 383, 1, 1 }, - { ahd_patch1_func, 393, 1, 2 }, - { ahd_patch0_func, 394, 1, 1 }, - { ahd_patch1_func, 396, 1, 2 }, - { ahd_patch0_func, 397, 1, 1 }, - { ahd_patch1_func, 405, 1, 2 }, - { ahd_patch0_func, 406, 1, 1 }, - { ahd_patch2_func, 419, 1, 2 }, - { ahd_patch0_func, 420, 1, 1 }, - { ahd_patch10_func, 450, 1, 1 }, - { ahd_patch1_func, 457, 1, 2 }, - { ahd_patch0_func, 458, 1, 1 }, - { ahd_patch2_func, 470, 1, 2 }, - { ahd_patch0_func, 471, 1, 1 }, - { ahd_patch11_func, 476, 6, 2 }, + { ahd_patch4_func, 102, 1, 1 }, + { ahd_patch2_func, 157, 6, 1 }, + { ahd_patch1_func, 163, 2, 1 }, + { ahd_patch5_func, 165, 1, 1 }, + { ahd_patch2_func, 174, 1, 2 }, + { ahd_patch0_func, 175, 1, 1 }, + { ahd_patch6_func, 176, 2, 2 }, + { ahd_patch0_func, 178, 6, 3 }, + { ahd_patch2_func, 181, 1, 2 }, + { ahd_patch0_func, 182, 1, 1 }, + { ahd_patch2_func, 185, 1, 2 }, + { ahd_patch0_func, 186, 1, 1 }, + { ahd_patch3_func, 188, 1, 1 }, + { ahd_patch7_func, 189, 3, 1 }, + { ahd_patch3_func, 198, 1, 1 }, + { ahd_patch5_func, 199, 16, 2 }, + { ahd_patch0_func, 215, 1, 1 }, + { ahd_patch8_func, 235, 2, 1 }, + { ahd_patch1_func, 239, 1, 2 }, + { ahd_patch0_func, 240, 1, 1 }, + { ahd_patch7_func, 243, 3, 1 }, + { ahd_patch1_func, 258, 1, 2 }, + { ahd_patch0_func, 259, 1, 1 }, + { ahd_patch1_func, 262, 1, 2 }, + { ahd_patch0_func, 263, 1, 1 }, + { ahd_patch2_func, 266, 1, 2 }, + { ahd_patch0_func, 267, 1, 1 }, + { ahd_patch9_func, 280, 2, 2 }, + { ahd_patch0_func, 282, 1, 1 }, + { ahd_patch1_func, 324, 1, 2 }, + { ahd_patch0_func, 325, 1, 1 }, + { ahd_patch2_func, 333, 1, 2 }, + { ahd_patch0_func, 334, 1, 1 }, + { ahd_patch2_func, 337, 1, 2 }, + { ahd_patch0_func, 338, 1, 1 }, + { ahd_patch1_func, 344, 1, 2 }, + { ahd_patch0_func, 345, 1, 1 }, + { ahd_patch1_func, 347, 1, 2 }, + { ahd_patch0_func, 348, 1, 1 }, + { ahd_patch10_func, 367, 1, 1 }, + { ahd_patch10_func, 370, 1, 1 }, + { ahd_patch10_func, 372, 1, 1 }, + { ahd_patch10_func, 384, 1, 1 }, + { ahd_patch1_func, 394, 1, 2 }, + { ahd_patch0_func, 395, 1, 1 }, + { ahd_patch1_func, 397, 1, 2 }, + { ahd_patch0_func, 398, 1, 1 }, + { ahd_patch1_func, 406, 1, 2 }, + { ahd_patch0_func, 407, 1, 1 }, + { ahd_patch2_func, 420, 1, 2 }, + { ahd_patch0_func, 421, 1, 1 }, + { ahd_patch11_func, 451, 1, 1 }, + { ahd_patch1_func, 459, 1, 2 }, + { ahd_patch0_func, 460, 1, 1 }, + { ahd_patch2_func, 472, 1, 2 }, + { ahd_patch0_func, 473, 1, 1 }, + { ahd_patch12_func, 476, 6, 2 }, { ahd_patch0_func, 482, 1, 1 }, - { ahd_patch12_func, 505, 1, 1 }, - { ahd_patch13_func, 514, 1, 1 }, - { ahd_patch14_func, 515, 1, 2 }, + { ahd_patch13_func, 505, 1, 1 }, + { ahd_patch14_func, 514, 1, 1 }, + { ahd_patch15_func, 515, 1, 2 }, { ahd_patch0_func, 516, 1, 1 }, - { ahd_patch15_func, 519, 1, 1 }, - { ahd_patch14_func, 520, 1, 1 }, - { ahd_patch16_func, 531, 1, 2 }, + { ahd_patch16_func, 519, 1, 1 }, + { ahd_patch15_func, 520, 1, 1 }, + { ahd_patch17_func, 531, 1, 2 }, { ahd_patch0_func, 532, 1, 1 }, { ahd_patch1_func, 551, 1, 2 }, { ahd_patch0_func, 552, 1, 1 }, @@ -1083,25 +1093,25 @@ static struct patch { { ahd_patch0_func, 569, 1, 1 }, { ahd_patch2_func, 580, 1, 2 }, { ahd_patch0_func, 581, 1, 1 }, - { ahd_patch17_func, 585, 1, 1 }, - { ahd_patch18_func, 590, 1, 1 }, - { ahd_patch19_func, 591, 2, 1 }, - { ahd_patch18_func, 595, 1, 2 }, + { ahd_patch18_func, 585, 1, 1 }, + { ahd_patch19_func, 590, 1, 1 }, + { ahd_patch20_func, 591, 2, 1 }, + { ahd_patch19_func, 595, 1, 2 }, { ahd_patch0_func, 596, 1, 1 }, { ahd_patch2_func, 599, 1, 2 }, { ahd_patch0_func, 600, 1, 1 }, { ahd_patch2_func, 615, 1, 2 }, { ahd_patch0_func, 616, 1, 1 }, - { ahd_patch20_func, 617, 14, 1 }, + { ahd_patch21_func, 617, 14, 1 }, { ahd_patch1_func, 635, 1, 2 }, { ahd_patch0_func, 636, 1, 1 }, - { ahd_patch20_func, 637, 1, 1 }, + { ahd_patch21_func, 637, 1, 1 }, { ahd_patch1_func, 649, 1, 2 }, { ahd_patch0_func, 650, 1, 1 }, { ahd_patch1_func, 657, 1, 2 }, { ahd_patch0_func, 658, 1, 1 }, - { ahd_patch17_func, 681, 1, 1 }, - { ahd_patch17_func, 719, 1, 1 }, + { ahd_patch18_func, 681, 1, 1 }, + { ahd_patch18_func, 719, 1, 1 }, { ahd_patch1_func, 730, 1, 2 }, { ahd_patch0_func, 731, 1, 1 }, { ahd_patch1_func, 748, 1, 2 }, @@ -1110,11 +1120,11 @@ static struct patch { { ahd_patch0_func, 752, 1, 1 }, { ahd_patch1_func, 755, 1, 2 }, { ahd_patch0_func, 756, 1, 1 }, - { ahd_patch21_func, 758, 1, 2 }, + { ahd_patch22_func, 758, 1, 2 }, { ahd_patch0_func, 759, 2, 1 }, - { ahd_patch22_func, 762, 4, 2 }, + { ahd_patch23_func, 762, 4, 2 }, { ahd_patch0_func, 766, 1, 1 }, - { ahd_patch22_func, 774, 11, 1 } + { ahd_patch23_func, 774, 11, 1 } }; static struct cs { @@ -1123,15 +1133,18 @@ static struct cs { } critical_sections[] = { { 11, 12 }, { 13, 14 }, - { 29, 42 }, - { 56, 59 }, - { 101, 128 }, - { 129, 157 }, - { 159, 162 }, - { 170, 178 }, - { 201, 250 }, - { 681, 697 }, - { 697, 711 }, + { 31, 42 }, + { 45, 47 }, + { 49, 50 }, + { 56, 78 }, + { 96, 123 }, + { 124, 152 }, + { 154, 157 }, + { 165, 173 }, + { 198, 249 }, + { 428, 430 }, + { 433, 436 }, + { 681, 711 }, { 721, 725 } }; diff -puN drivers/scsi/aic7xxx/aic7xxx_93cx6.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7xxx_93cx6.c --- 25/drivers/scsi/aic7xxx/aic7xxx_93cx6.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7xxx_93cx6.c Wed Dec 24 12:15:38 2003 @@ -28,9 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#17 $ - * - * $FreeBSD$ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#19 $ */ /* @@ -64,7 +62,6 @@ * is preceded by an initial zero (leading 0, followed by 16-bits, MSB * first). The clock cycling from low to high initiates the next data * bit to be sent from the chip. - * */ #ifdef __linux__ @@ -72,6 +69,8 @@ #include "aic7xxx_inline.h" #include "aic7xxx_93cx6.h" #else +#include +__FBSDID("$FreeBSD$"); #include #include #include @@ -81,14 +80,22 @@ * Right now, we only have to read the SEEPROM. But we make it easier to * add other 93Cx6 functions. */ -static struct seeprom_cmd { +struct seeprom_cmd { uint8_t len; - uint8_t bits[9]; -} seeprom_read = {3, {1, 1, 0}}; + uint8_t bits[11]; +}; +/* Short opcodes for the c46 */ static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}}; static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}}; + +/* Long opcodes for the C56/C66 */ +static struct seeprom_cmd seeprom_long_ewen = {11, {1, 0, 0, 1, 1, 0, 0, 0, 0}}; +static struct seeprom_cmd seeprom_long_ewds = {11, {1, 0, 0, 0, 0, 0, 0, 0, 0}}; + +/* Common opcodes */ static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}}; +static struct seeprom_cmd seeprom_read = {3, {1, 1, 0}}; /* * Wait for the SEERDY to go high; about 800 ns. @@ -222,12 +229,25 @@ int ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, u_int start_addr, u_int count) { + struct seeprom_cmd *ewen, *ewds; uint16_t v; uint8_t temp; int i, k; /* Place the chip into write-enable mode */ - send_seeprom_cmd(sd, &seeprom_ewen); + if (sd->sd_chip == C46) { + ewen = &seeprom_ewen; + ewds = &seeprom_ewds; + } else if (sd->sd_chip == C56_66) { + ewen = &seeprom_long_ewen; + ewds = &seeprom_long_ewds; + } else { + printf("ahc_write_seeprom: unsupported seeprom type %d\n", + sd->sd_chip); + return (0); + } + + send_seeprom_cmd(sd, ewen); reset_seeprom(sd); /* Write all requested data out to the seeprom. */ @@ -277,7 +297,7 @@ ahc_write_seeprom(struct seeprom_descrip } /* Put the chip back into write-protect mode */ - send_seeprom_cmd(sd, &seeprom_ewds); + send_seeprom_cmd(sd, ewds); reset_seeprom(sd); return (1); diff -puN drivers/scsi/aic7xxx/aic7xxx_core.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7xxx_core.c --- 25/drivers/scsi/aic7xxx/aic7xxx_core.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7xxx_core.c Wed Dec 24 12:15:38 2003 @@ -37,9 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#131 $ - * - * $FreeBSD$ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#147 $ */ #ifdef __linux__ @@ -47,6 +45,8 @@ #include "aic7xxx_inline.h" #include "aicasm/aicasm_insformat.h" #else +#include +__FBSDID("$FreeBSD$"); #include #include #include @@ -320,7 +320,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc) */ modnext = ahc->qoutfifonext & ~0x3; *((uint32_t *)(&ahc->qoutfifo[modnext])) = 0xFFFFFFFFUL; - ahc_dmamap_sync(ahc, ahc->shared_data_dmat, + aic_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, /*offset*/modnext, /*len*/4, BUS_DMASYNC_PREREAD); @@ -458,14 +458,14 @@ ahc_handle_seqint(struct ahc_softc *ahc, * complete. */ scb->flags &= ~SCB_SENSE; - ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); + aic_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); break; } - ahc_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR); + aic_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR); /* Freeze the queue until the client sees the error. */ ahc_freeze_devq(ahc, scb); - ahc_freeze_scb(scb); - ahc_set_scsi_status(scb, hscb->shared_data.status.scsi_status); + aic_freeze_scb(scb); + aic_set_scsi_status(scb, hscb->shared_data.status.scsi_status); switch (hscb->shared_data.status.scsi_status) { case SCSI_STATUS_OK: printf("%s: Interrupted for staus of 0???\n", @@ -487,7 +487,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, } #endif - if (ahc_perform_autosense(scb) == 0) + if (aic_perform_autosense(scb) == 0) break; targ_info = ahc_fetch_transinfo(ahc, @@ -509,12 +509,12 @@ ahc_handle_seqint(struct ahc_softc *ahc, } #endif sg->addr = ahc_get_sense_bufaddr(ahc, scb); - sg->len = ahc_get_sense_bufsize(ahc, scb); + sg->len = aic_get_sense_bufsize(ahc, scb); sg->len |= AHC_DMA_LAST_SEG; /* Fixup byte order */ - sg->addr = ahc_htole32(sg->addr); - sg->len = ahc_htole32(sg->len); + sg->addr = aic_htole32(sg->addr); + sg->len = aic_htole32(sg->len); sc->opcode = REQUEST_SENSE; sc->byte2 = 0; @@ -543,8 +543,8 @@ ahc_handle_seqint(struct ahc_softc *ahc, * errors will be reported before any data * phases occur. */ - if (ahc_get_residual(scb) - == ahc_get_transfer_length(scb)) { + if (aic_get_residual(scb) + == aic_get_transfer_length(scb)) { ahc_update_neg_request(ahc, &devinfo, tstate, targ_info, AHC_NEG_IF_NON_ASYNC); @@ -558,7 +558,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, hscb->dataptr = sg->addr; hscb->datacnt = sg->len; hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; - hscb->sgptr = ahc_htole32(hscb->sgptr); + hscb->sgptr = aic_htole32(hscb->sgptr); scb->sg_count = 1; scb->flags |= SCB_SENSE; ahc_qinfifo_requeue_tail(ahc, scb); @@ -567,7 +567,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, * Ensure we have enough time to actually * retrieve the sense. */ - ahc_scb_timer_reset(scb, 5 * 1000000); + aic_scb_timer_reset(scb, 5 * 1000000); break; } default: @@ -768,7 +768,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, if ((ahc_inb(ahc, SCSISIGI) & (CDI|MSGI)) != 0) break; - ahc_delay(100); + aic_delay(100); } ahc_outb(ahc, SXFRCTL1, ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET); @@ -782,7 +782,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, scb_index = ahc_inb(ahc, SCB_TAG); scb = ahc_lookup_scb(ahc, scb_index); if (scb != NULL) - ahc_set_transaction_status(scb, + aic_set_transaction_status(scb, CAM_UNCOR_PARITY); ahc_reset_channel(ahc, devinfo.channel, /*init reset*/TRUE); @@ -820,16 +820,16 @@ ahc_handle_seqint(struct ahc_softc *ahc, ahc_print_path(ahc, scb); printf("%s seen Data Phase. Length = %ld. NumSGs = %d.\n", ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't", - ahc_get_transfer_length(scb), scb->sg_count); + aic_get_transfer_length(scb), scb->sg_count); if (scb->sg_count > 0) { for (i = 0; i < scb->sg_count; i++) { printf("sg[%d] - Addr 0x%x%x : Length %d\n", i, - (ahc_le32toh(scb->sg_list[i].len) >> 24 + (aic_le32toh(scb->sg_list[i].len) >> 24 & SG_HIGH_ADDR_BITS), - ahc_le32toh(scb->sg_list[i].addr), - ahc_le32toh(scb->sg_list[i].len) + aic_le32toh(scb->sg_list[i].addr), + aic_le32toh(scb->sg_list[i].len) & AHC_SG_LEN_MASK); } } @@ -839,12 +839,12 @@ ahc_handle_seqint(struct ahc_softc *ahc, */ ahc_freeze_devq(ahc, scb); if ((scb->flags & SCB_SENSE) == 0) { - ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); + aic_set_transaction_status(scb, CAM_DATA_RUN_ERR); } else { scb->flags &= ~SCB_SENSE; - ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); + aic_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); } - ahc_freeze_scb(scb); + aic_freeze_scb(scb); if ((ahc->features & AHC_ULTRA2) != 0) { /* @@ -1188,7 +1188,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc */ ahc_scb_devinfo(ahc, &devinfo, scb); ahc_force_renegotiation(ahc, &devinfo); - ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); + aic_set_transaction_status(scb, CAM_SEL_TIMEOUT); ahc_freeze_devq(ahc, scb); } ahc_outb(ahc, CLRINT, CLRSCSIINT); @@ -1270,7 +1270,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_INITIATOR)) { - ahc_set_transaction_status(scb, CAM_REQ_CMP); + aic_set_transaction_status(scb, CAM_REQ_CMP); } #endif ahc_compile_devinfo(&devinfo, @@ -1304,17 +1304,23 @@ ahc_handle_scsiint(struct ahc_softc *ahc ahc_qinfifo_requeue_tail(ahc, scb); printerror = 0; } else if (ahc_sent_msg(ahc, AHCMSG_EXT, - MSG_EXT_WDTR, FALSE) - || ahc_sent_msg(ahc, AHCMSG_EXT, - MSG_EXT_SDTR, FALSE)) { + MSG_EXT_WDTR, FALSE)) { /* - * Negotiation Rejected. Go-async and + * Negotiation Rejected. Go-narrow and * retry command. */ ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, AHC_TRANS_CUR|AHC_TRANS_GOAL, /*paused*/TRUE); + ahc_qinfifo_requeue_tail(ahc, scb); + printerror = 0; + } else if (ahc_sent_msg(ahc, AHCMSG_EXT, + MSG_EXT_SDTR, FALSE)) { + /* + * Negotiation Rejected. Go-async and + * retry command. + */ ahc_set_syncrate(ahc, &devinfo, /*syncrate*/NULL, /*period*/0, /*offset*/0, @@ -1463,7 +1469,7 @@ ahc_clear_critical_section(struct ahc_so * current connection, so we must * leave it on while single stepping. */ - ahc_outb(ahc, SIMODE1, ENBUSFREE); + ahc_outb(ahc, SIMODE1, simode1 & ENBUSFREE); else ahc_outb(ahc, SIMODE1, 0); ahc_outb(ahc, CLRINT, CLRSCSIINT); @@ -1476,7 +1482,7 @@ ahc_clear_critical_section(struct ahc_so } ahc_outb(ahc, HCNTRL, ahc->unpause); while (!ahc_is_paused(ahc)) - ahc_delay(200); + aic_delay(200); } if (stepping) { ahc_outb(ahc, SIMODE0, simode0); @@ -1524,18 +1530,18 @@ ahc_print_scb(struct scb *scb) for (i = 0; i < sizeof(hscb->shared_data.cdb); i++) printf("%#02x", hscb->shared_data.cdb[i]); printf(" dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n", - ahc_le32toh(hscb->dataptr), - ahc_le32toh(hscb->datacnt), - ahc_le32toh(hscb->sgptr), + aic_le32toh(hscb->dataptr), + aic_le32toh(hscb->datacnt), + aic_le32toh(hscb->sgptr), hscb->tag); if (scb->sg_count > 0) { for (i = 0; i < scb->sg_count; i++) { printf("sg[%d] - Addr 0x%x%x : Length %d\n", i, - (ahc_le32toh(scb->sg_list[i].len) >> 24 + (aic_le32toh(scb->sg_list[i].len) >> 24 & SG_HIGH_ADDR_BITS), - ahc_le32toh(scb->sg_list[i].addr), - ahc_le32toh(scb->sg_list[i].len)); + aic_le32toh(scb->sg_list[i].addr), + aic_le32toh(scb->sg_list[i].len)); } } } @@ -2373,6 +2379,7 @@ ahc_build_transfer_msg(struct ahc_softc * may change. */ period = tinfo->goal.period; + offset = tinfo->goal.offset; ppr_options = tinfo->goal.ppr_options; /* Target initiated PPR is not allowed in the SCSI spec */ if (devinfo->role == ROLE_TARGET) @@ -2380,7 +2387,7 @@ ahc_build_transfer_msg(struct ahc_softc rate = ahc_devlimited_syncrate(ahc, tinfo, &period, &ppr_options, devinfo->role); dowide = tinfo->curr.width != tinfo->goal.width; - dosync = tinfo->curr.period != period; + dosync = tinfo->curr.offset != offset || tinfo->curr.period != period; /* * Only use PPR if we have options that need it, even if the device * claims to support it. There might be an expander in the way @@ -2568,7 +2575,7 @@ ahc_handle_proto_violation(struct ahc_so printf("No SCB found during protocol violation\n"); goto proto_violation_reset; } else { - ahc_set_transaction_status(scb, CAM_SEQUENCE_FAIL); + aic_set_transaction_status(scb, CAM_SEQUENCE_FAIL); if ((seq_flags & NO_CDB_SENT) != 0) { ahc_print_path(ahc, scb); printf("No or incomplete CDB sent to device.\n"); @@ -3176,23 +3183,30 @@ ahc_parse_msg(struct ahc_softc *ahc, str response = TRUE; sending_reply = TRUE; } + /* + * After a wide message, we are async, but + * some devices don't seem to honor this portion + * of the spec. Force a renegotiation of the + * sync component of our transfer agreement even + * if our goal is async. By updating our width + * after forcing the negotiation, we avoid + * renegotiating for width. + */ + ahc_update_neg_request(ahc, devinfo, tstate, + tinfo, AHC_NEG_ALWAYS); ahc_set_width(ahc, devinfo, bus_width, AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, /*paused*/TRUE); - /* After a wide message, we are async */ - ahc_set_syncrate(ahc, devinfo, - /*syncrate*/NULL, /*period*/0, - /*offset*/0, /*ppr_options*/0, - AHC_TRANS_ACTIVE, /*paused*/TRUE); if (sending_reply == FALSE && reject == FALSE) { - if (tinfo->goal.offset) { - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_build_transfer_msg(ahc, devinfo); - ahc->msgout_index = 0; - response = TRUE; - } + /* + * We will always have an SDTR to send. + */ + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_build_transfer_msg(ahc, devinfo); + ahc->msgout_index = 0; + response = TRUE; } done = MSGLOOP_MSGCOMPLETE; break; @@ -3499,7 +3513,7 @@ ahc_handle_msg_reject(struct ahc_softc * ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & mask); scb->hscb->control &= mask; - ahc_set_transaction_tag(scb, /*enabled*/FALSE, + aic_set_transaction_tag(scb, /*enabled*/FALSE, /*type*/MSG_SIMPLE_TASK); ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG); ahc_assert_atn(ahc); @@ -3556,7 +3570,7 @@ ahc_handle_ign_wide_residue(struct ahc_s * Perhaps add datadir to some spare bits in the hscb? */ if ((ahc_inb(ahc, SEQ_FLAGS) & DPHASE) == 0 - || ahc_get_transfer_dir(scb) != CAM_DIR_IN) { + || aic_get_transfer_dir(scb) != CAM_DIR_IN) { /* * Ignore the message if we haven't * seen an appropriate data phase yet. @@ -3612,18 +3626,18 @@ ahc_handle_ign_wide_residue(struct ahc_s * to load so we must go back one. */ sg--; - sglen = ahc_le32toh(sg->len) & AHC_SG_LEN_MASK; + sglen = aic_le32toh(sg->len) & AHC_SG_LEN_MASK; if (sg != scb->sg_list && sglen < (data_cnt & AHC_SG_LEN_MASK)) { sg--; - sglen = ahc_le32toh(sg->len); + sglen = aic_le32toh(sg->len); /* * Preserve High Address and SG_LIST bits * while setting the count to 1. */ data_cnt = 1 | (sglen & (~AHC_SG_LEN_MASK)); - data_addr = ahc_le32toh(sg->addr) + data_addr = aic_le32toh(sg->addr) + (sglen & AHC_SG_LEN_MASK) - 1; /* @@ -3679,8 +3693,8 @@ ahc_reinitialize_dataptrs(struct ahc_sof | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 1) << 8) | ahc_inb(ahc, SCB_RESIDUAL_DATACNT); - dataptr = ahc_le32toh(sg->addr) - + (ahc_le32toh(sg->len) & AHC_SG_LEN_MASK) + dataptr = aic_le32toh(sg->addr) + + (aic_le32toh(sg->len) & AHC_SG_LEN_MASK) - resid; if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { u_int dscommand1; @@ -3688,7 +3702,7 @@ ahc_reinitialize_dataptrs(struct ahc_sof dscommand1 = ahc_inb(ahc, DSCOMMAND1); ahc_outb(ahc, DSCOMMAND1, dscommand1 | HADDLDSEL0); ahc_outb(ahc, HADDR, - (ahc_le32toh(sg->len) >> 24) & SG_HIGH_ADDR_BITS); + (aic_le32toh(sg->len) >> 24) & SG_HIGH_ADDR_BITS); ahc_outb(ahc, DSCOMMAND1, dscommand1); } ahc_outb(ahc, HADDR + 3, dataptr >> 24); @@ -3869,7 +3883,7 @@ ahc_softc_insert(struct ahc_softc *ahc) { struct ahc_softc *list_ahc; -#if AHC_PCI_CONFIG > 0 +#if AIC_PCI_CONFIG > 0 /* * Second Function PCI devices need to inherit some * settings from function 0. @@ -3877,17 +3891,17 @@ ahc_softc_insert(struct ahc_softc *ahc) if ((ahc->chip & AHC_BUS_MASK) == AHC_PCI && (ahc->features & AHC_MULTI_FUNC) != 0) { TAILQ_FOREACH(list_ahc, &ahc_tailq, links) { - ahc_dev_softc_t list_pci; - ahc_dev_softc_t pci; + aic_dev_softc_t list_pci; + aic_dev_softc_t pci; list_pci = list_ahc->dev_softc; pci = ahc->dev_softc; - if (ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci) - && ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci)) { + if (aic_get_pci_slot(list_pci) == aic_get_pci_slot(pci) + && aic_get_pci_bus(list_pci) == aic_get_pci_bus(pci)) { struct ahc_softc *master; struct ahc_softc *slave; - if (ahc_get_pci_function(list_pci) == 0) { + if (aic_get_pci_function(list_pci) == 0) { master = list_ahc; slave = ahc; } else { @@ -3955,27 +3969,27 @@ ahc_free(struct ahc_softc *ahc) { int i; + ahc_terminate_recovery_thread(ahc); switch (ahc->init_level) { default: case 5: ahc_shutdown(ahc); - TAILQ_REMOVE(&ahc_tailq, ahc, links); /* FALLTHROUGH */ case 4: - ahc_dmamap_unload(ahc, ahc->shared_data_dmat, + aic_dmamap_unload(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap); /* FALLTHROUGH */ case 3: - ahc_dmamem_free(ahc, ahc->shared_data_dmat, ahc->qoutfifo, + aic_dmamem_free(ahc, ahc->shared_data_dmat, ahc->qoutfifo, ahc->shared_data_dmamap); - ahc_dmamap_destroy(ahc, ahc->shared_data_dmat, + aic_dmamap_destroy(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap); /* FALLTHROUGH */ case 2: - ahc_dma_tag_destroy(ahc, ahc->shared_data_dmat); + aic_dma_tag_destroy(ahc, ahc->shared_data_dmat); case 1: #ifndef __linux__ - ahc_dma_tag_destroy(ahc, ahc->buffer_dmat); + aic_dma_tag_destroy(ahc, ahc->buffer_dmat); #endif break; case 0: @@ -3983,7 +3997,7 @@ ahc_free(struct ahc_softc *ahc) } #ifndef __linux__ - ahc_dma_tag_destroy(ahc, ahc->parent_dmat); + aic_dma_tag_destroy(ahc, ahc->parent_dmat); #endif ahc_platform_free(ahc); ahc_fini_scbdata(ahc); @@ -4033,7 +4047,7 @@ ahc_shutdown(void *arg) ahc = (struct ahc_softc *)arg; /* This will reset most registers to 0, but not all */ - ahc_reset(ahc); + ahc_reset(ahc, /*reinit*/FALSE); ahc_outb(ahc, SCSISEQ, 0); ahc_outb(ahc, SXFRCTL0, 0); ahc_outb(ahc, DSPCISTATUS, 0); @@ -4044,10 +4058,15 @@ ahc_shutdown(void *arg) /* * Reset the controller and record some information about it - * that is only available just after a reset. + * that is only available just after a reset. If "reinit" is + * non-zero, this reset occured after initial configuration + * and the caller requests that the chip be fully reinitialized + * to a runable state. Chip interrupts are *not* enabled after + * a reinitialization. The caller must enable interrupts via + * ahc_intr_enable(). */ int -ahc_reset(struct ahc_softc *ahc) +ahc_reset(struct ahc_softc *ahc, int reinit) { u_int sblkctl; u_int sxfrctl1_a, sxfrctl1_b; @@ -4060,14 +4079,6 @@ ahc_reset(struct ahc_softc *ahc) * to disturb the integrity of the bus. */ ahc_pause(ahc); - if ((ahc_inb(ahc, HCNTRL) & CHIPRST) != 0) { - /* - * The chip has not been initialized since - * PCI/EISA/VLB bus reset. Don't trust - * "left over BIOS data". - */ - ahc->flags |= AHC_NO_BIOS_INIT; - } sxfrctl1_b = 0; if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) { u_int sblkctl; @@ -4093,7 +4104,7 @@ ahc_reset(struct ahc_softc *ahc) */ wait = 1000; do { - ahc_delay(1000); + aic_delay(1000); } while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK)); if (wait == 0) { @@ -4143,7 +4154,7 @@ ahc_reset(struct ahc_softc *ahc) ahc_outb(ahc, SXFRCTL1, sxfrctl1_a); error = 0; - if (ahc->init_level > 0) + if (reinit != 0) /* * If a recovery action has forced a chip reset, * re-initialize the chip to our liking. @@ -4273,7 +4284,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) */ /* DMA tag for our hardware scb structures */ - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, + if (aic_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, @@ -4288,7 +4299,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) scb_data->init_level++; /* Allocation for our hscbs */ - if (ahc_dmamem_alloc(ahc, scb_data->hscb_dmat, + if (aic_dmamem_alloc(ahc, scb_data->hscb_dmat, (void **)&scb_data->hscbs, BUS_DMA_NOWAIT, &scb_data->hscb_dmamap) != 0) { goto error_exit; @@ -4297,7 +4308,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) scb_data->init_level++; /* And permanently map them */ - ahc_dmamap_load(ahc, scb_data->hscb_dmat, scb_data->hscb_dmamap, + aic_dmamap_load(ahc, scb_data->hscb_dmat, scb_data->hscb_dmamap, scb_data->hscbs, AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb), ahc_dmamap_cb, &scb_data->hscb_busaddr, /*flags*/0); @@ -4305,7 +4316,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) scb_data->init_level++; /* DMA tag for our sense buffers */ - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, + if (aic_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, @@ -4320,7 +4331,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) scb_data->init_level++; /* Allocate them */ - if (ahc_dmamem_alloc(ahc, scb_data->sense_dmat, + if (aic_dmamem_alloc(ahc, scb_data->sense_dmat, (void **)&scb_data->sense, BUS_DMA_NOWAIT, &scb_data->sense_dmamap) != 0) { goto error_exit; @@ -4329,7 +4340,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) scb_data->init_level++; /* And permanently map them */ - ahc_dmamap_load(ahc, scb_data->sense_dmat, scb_data->sense_dmamap, + aic_dmamap_load(ahc, scb_data->sense_dmat, scb_data->sense_dmamap, scb_data->sense, AHC_SCB_MAX_ALLOC * sizeof(struct scsi_sense_data), ahc_dmamap_cb, &scb_data->sense_busaddr, /*flags*/0); @@ -4337,7 +4348,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) scb_data->init_level++; /* DMA tag for our S/G structures. We allocate in page sized chunks */ - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/8, + if (aic_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/8, /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, @@ -4394,35 +4405,35 @@ ahc_fini_scbdata(struct ahc_softc *ahc) while ((sg_map = SLIST_FIRST(&scb_data->sg_maps))!= NULL) { SLIST_REMOVE_HEAD(&scb_data->sg_maps, links); - ahc_dmamap_unload(ahc, scb_data->sg_dmat, + aic_dmamap_unload(ahc, scb_data->sg_dmat, sg_map->sg_dmamap); - ahc_dmamem_free(ahc, scb_data->sg_dmat, + aic_dmamem_free(ahc, scb_data->sg_dmat, sg_map->sg_vaddr, sg_map->sg_dmamap); free(sg_map, M_DEVBUF); } - ahc_dma_tag_destroy(ahc, scb_data->sg_dmat); + aic_dma_tag_destroy(ahc, scb_data->sg_dmat); } case 6: - ahc_dmamap_unload(ahc, scb_data->sense_dmat, + aic_dmamap_unload(ahc, scb_data->sense_dmat, scb_data->sense_dmamap); case 5: - ahc_dmamem_free(ahc, scb_data->sense_dmat, scb_data->sense, + aic_dmamem_free(ahc, scb_data->sense_dmat, scb_data->sense, scb_data->sense_dmamap); - ahc_dmamap_destroy(ahc, scb_data->sense_dmat, + aic_dmamap_destroy(ahc, scb_data->sense_dmat, scb_data->sense_dmamap); case 4: - ahc_dma_tag_destroy(ahc, scb_data->sense_dmat); + aic_dma_tag_destroy(ahc, scb_data->sense_dmat); case 3: - ahc_dmamap_unload(ahc, scb_data->hscb_dmat, + aic_dmamap_unload(ahc, scb_data->hscb_dmat, scb_data->hscb_dmamap); case 2: - ahc_dmamem_free(ahc, scb_data->hscb_dmat, scb_data->hscbs, + aic_dmamem_free(ahc, scb_data->hscb_dmat, scb_data->hscbs, scb_data->hscb_dmamap); - ahc_dmamap_destroy(ahc, scb_data->hscb_dmat, + aic_dmamap_destroy(ahc, scb_data->hscb_dmat, scb_data->hscb_dmamap); case 1: - ahc_dma_tag_destroy(ahc, scb_data->hscb_dmat); + aic_dma_tag_destroy(ahc, scb_data->hscb_dmat); break; case 0: break; @@ -4455,7 +4466,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc) return; /* Allocate S/G space for the next batch of SCBS */ - if (ahc_dmamem_alloc(ahc, scb_data->sg_dmat, + if (aic_dmamem_alloc(ahc, scb_data->sg_dmat, (void **)&sg_map->sg_vaddr, BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { free(sg_map, M_DEVBUF); @@ -4464,7 +4475,7 @@ ahc_alloc_scbs(struct ahc_softc *ahc) SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links); - ahc_dmamap_load(ahc, scb_data->sg_dmat, sg_map->sg_dmamap, + aic_dmamap_load(ahc, scb_data->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, PAGE_SIZE, ahc_dmamap_cb, &sg_map->sg_physaddr, /*flags*/0); @@ -4491,9 +4502,9 @@ ahc_alloc_scbs(struct ahc_softc *ahc) */ next_scb->sg_list_phys = physaddr + sizeof(struct ahc_dma_seg); next_scb->ahc_softc = ahc; - next_scb->flags = SCB_FREE; + next_scb->flags = SCB_FLAG_NONE; #ifndef __linux__ - error = ahc_dmamap_create(ahc, ahc->buffer_dmat, /*flags*/0, + error = aic_dmamap_create(ahc, ahc->buffer_dmat, /*flags*/0, &next_scb->dmamap); if (error != 0) break; @@ -4725,14 +4736,12 @@ ahc_chip_init(struct ahc_softc *ahc) * never settle, so don't complain if we * fail here. */ - ahc_pause(ahc); for (wait = 5000; (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; wait--) - ahc_delay(100); - ahc_unpause(ahc); + aic_delay(100); } - + ahc_restart(ahc); return (0); } @@ -4743,6 +4752,7 @@ int ahc_init(struct ahc_softc *ahc) { int max_targ; + int error; u_int i; u_int scsi_conf; u_int ultraenb; @@ -4800,7 +4810,7 @@ ahc_init(struct ahc_softc *ahc) #ifndef __linux__ /* DMA tag for mapping buffers into device visible space. */ - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, + if (aic_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, /*lowaddr*/ahc->flags & AHC_39BIT_ADDRESSING ? (bus_addr_t)0x7FFFFFFFFFULL @@ -4831,7 +4841,7 @@ ahc_init(struct ahc_softc *ahc) if ((ahc->features & AHC_TARGETMODE) != 0) driver_data_size += AHC_TMODE_CMDS * sizeof(struct target_cmd) + /*DMA WideOdd Bug Buffer*/1; - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, + if (aic_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, @@ -4846,7 +4856,7 @@ ahc_init(struct ahc_softc *ahc) ahc->init_level++; /* Allocation of driver data */ - if (ahc_dmamem_alloc(ahc, ahc->shared_data_dmat, + if (aic_dmamem_alloc(ahc, ahc->shared_data_dmat, (void **)&ahc->qoutfifo, BUS_DMA_NOWAIT, &ahc->shared_data_dmamap) != 0) { return (ENOMEM); @@ -4855,7 +4865,7 @@ ahc_init(struct ahc_softc *ahc) ahc->init_level++; /* And permanently map it in */ - ahc_dmamap_load(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, + aic_dmamap_load(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, ahc->qoutfifo, driver_data_size, ahc_dmamap_cb, &ahc->shared_data_busaddr, /*flags*/0); @@ -4898,6 +4908,13 @@ ahc_init(struct ahc_softc *ahc) } } + /* + * Fire up a recovery thread for this controller. + */ + error = ahc_spawn_recovery_thread(ahc); + if (error != 0) + return (error); + if (ahc->scb_data->maxhscbs < AHC_SCB_MAX_ALLOC) { ahc->flags |= AHC_PAGESCBS; } else { @@ -5095,8 +5112,14 @@ ahc_pause_and_flushwork(struct ahc_softc ahc->flags |= AHC_ALL_INTERRUPTS; paused = FALSE; do { - if (paused) + if (paused) { ahc_unpause(ahc); + /* + * Give the sequencer some time to service + * any active selections. + */ + aic_delay(200); + } ahc_intr(ahc); ahc_pause(ahc); paused = TRUE; @@ -5145,7 +5168,9 @@ int ahc_resume(struct ahc_softc *ahc) { - ahc_reset(ahc); + ahc_reset(ahc, /*reinit*/TRUE); + ahc_intr_enable(ahc, TRUE); + ahc_restart(ahc); return (0); } @@ -5380,12 +5405,12 @@ ahc_search_qinfifo(struct ahc_softc *ahc cam_status ostat; cam_status cstat; - ostat = ahc_get_transaction_status(scb); + ostat = aic_get_transaction_status(scb); if (ostat == CAM_REQ_INPROG) - ahc_set_transaction_status(scb, status); - cstat = ahc_get_transaction_status(scb); + aic_set_transaction_status(scb, status); + cstat = aic_get_transaction_status(scb); if (cstat != CAM_REQ_CMP) - ahc_freeze_scb(scb); + aic_freeze_scb(scb); if ((scb->flags & SCB_ACTIVE) == 0) printf("Inactive SCB in qinfifo\n"); ahc_done(ahc, scb); @@ -5492,13 +5517,13 @@ ahc_search_qinfifo(struct ahc_softc *ahc cam_status ostat; cam_status cstat; - ostat = ahc_get_transaction_status(scb); + ostat = aic_get_transaction_status(scb); if (ostat == CAM_REQ_INPROG) - ahc_set_transaction_status(scb, + aic_set_transaction_status(scb, status); - cstat = ahc_get_transaction_status(scb); + cstat = aic_get_transaction_status(scb); if (cstat != CAM_REQ_CMP) - ahc_freeze_scb(scb); + aic_freeze_scb(scb); if ((scb->flags & SCB_ACTIVE) == 0) printf("Inactive SCB in Waiting List\n"); ahc_done(ahc, scb); @@ -5520,7 +5545,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc } ahc_outb(ahc, SCBPTR, curscbptr); - found += ahc_search_untagged_queues(ahc, /*ahc_io_ctx_t*/NULL, target, + found += ahc_search_untagged_queues(ahc, /*aic_io_ctx_t*/NULL, target, channel, lun, status, action); if (action == SEARCH_COMPLETE) @@ -5529,7 +5554,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc } int -ahc_search_untagged_queues(struct ahc_softc *ahc, ahc_io_ctx_t ctx, +ahc_search_untagged_queues(struct ahc_softc *ahc, aic_io_ctx_t ctx, int target, char channel, int lun, uint32_t status, ahc_search_action action) { @@ -5600,12 +5625,12 @@ ahc_search_untagged_queues(struct ahc_so cam_status ostat; cam_status cstat; - ostat = ahc_get_transaction_status(scb); + ostat = aic_get_transaction_status(scb); if (ostat == CAM_REQ_INPROG) - ahc_set_transaction_status(scb, status); - cstat = ahc_get_transaction_status(scb); + aic_set_transaction_status(scb, status); + cstat = aic_get_transaction_status(scb); if (cstat != CAM_REQ_CMP) - ahc_freeze_scb(scb); + aic_freeze_scb(scb); if ((scb->flags & SCB_ACTIVE) == 0) printf("Inactive SCB in untaggedQ\n"); ahc_done(ahc, scb); @@ -5904,11 +5929,11 @@ ahc_abort_scbs(struct ahc_softc *ahc, in if (ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)) { cam_status ostat; - ostat = ahc_get_transaction_status(scbp); + ostat = aic_get_transaction_status(scbp); if (ostat == CAM_REQ_INPROG) - ahc_set_transaction_status(scbp, status); - if (ahc_get_transaction_status(scbp) != CAM_REQ_CMP) - ahc_freeze_scb(scbp); + aic_set_transaction_status(scbp, status); + if (aic_get_transaction_status(scbp) != CAM_REQ_CMP) + aic_freeze_scb(scbp); if ((scbp->flags & SCB_ACTIVE) == 0) printf("Inactive SCB on pending list\n"); ahc_done(ahc, scbp); @@ -5930,7 +5955,7 @@ ahc_reset_current_bus(struct ahc_softc * scsiseq = ahc_inb(ahc, SCSISEQ); ahc_outb(ahc, SCSISEQ, scsiseq | SCSIRSTO); ahc_flush_device_writes(ahc); - ahc_delay(AHC_BUSRESET_DELAY); + aic_delay(AHC_BUSRESET_DELAY); /* Turn off the bus reset */ ahc_outb(ahc, SCSISEQ, scsiseq & ~SCSIRSTO); @@ -6137,7 +6162,7 @@ ahc_calc_residual(struct ahc_softc *ahc, */ hscb = scb->hscb; - sgptr = ahc_le32toh(hscb->sgptr); + sgptr = aic_le32toh(hscb->sgptr); if ((sgptr & SG_RESID_VALID) == 0) /* Case 1 */ return; @@ -6148,10 +6173,10 @@ ahc_calc_residual(struct ahc_softc *ahc, return; spkt = &hscb->shared_data.status; - resid_sgptr = ahc_le32toh(spkt->residual_sg_ptr); + resid_sgptr = aic_le32toh(spkt->residual_sg_ptr); if ((sgptr & SG_FULL_RESID) != 0) { /* Case 3 */ - resid = ahc_get_transfer_length(scb); + resid = aic_get_transfer_length(scb); } else if ((resid_sgptr & SG_LIST_NULL) != 0) { /* Case 4 */ return; @@ -6164,7 +6189,7 @@ ahc_calc_residual(struct ahc_softc *ahc, * Remainder of the SG where the transfer * stopped. */ - resid = ahc_le32toh(spkt->residual_datacnt) & AHC_SG_LEN_MASK; + resid = aic_le32toh(spkt->residual_datacnt) & AHC_SG_LEN_MASK; sg = ahc_sg_bus_to_virt(scb, resid_sgptr & SG_PTR_MASK); /* The residual sg_ptr always points to the next sg */ @@ -6175,15 +6200,15 @@ ahc_calc_residual(struct ahc_softc *ahc, * SG segments that are after the SG where * the transfer stopped. */ - while ((ahc_le32toh(sg->len) & AHC_DMA_LAST_SEG) == 0) { + while ((aic_le32toh(sg->len) & AHC_DMA_LAST_SEG) == 0) { sg++; - resid += ahc_le32toh(sg->len) & AHC_SG_LEN_MASK; + resid += aic_le32toh(sg->len) & AHC_SG_LEN_MASK; } } if ((scb->flags & SCB_SENSE) == 0) - ahc_set_residual(scb, resid); + aic_set_residual(scb, resid); else - ahc_set_sense_residual(scb, resid); + aic_set_sense_residual(scb, resid); #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_MISC) != 0) { @@ -6407,7 +6432,6 @@ ahc_loadseq(struct ahc_softc *ahc) memcpy(ahc->critical_sections, cs_table, cs_count); } ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE); - ahc_restart(ahc); if (bootverbose) { printf(" %d instructions downloaded\n", downloaded); @@ -6464,7 +6488,7 @@ ahc_download_instr(struct ahc_softc *ahc /* * The firmware is always compiled into a little endian format. */ - instr.integer = ahc_le32toh(*(uint32_t*)&seqprog[instrptr * 4]); + instr.integer = aic_le32toh(*(uint32_t*)&seqprog[instrptr * 4]); fmt1_ins = &instr.format1; fmt3_ins = NULL; @@ -6569,7 +6593,7 @@ ahc_download_instr(struct ahc_softc *ahc } } /* The sequencer is a little endian cpu */ - instr.integer = ahc_htole32(instr.integer); + instr.integer = aic_htole32(instr.integer); ahc_outsb(ahc, SEQRAM, instr.bytes, 4); break; default: @@ -6809,6 +6833,324 @@ ahc_dump_card_state(struct ahc_softc *ah ahc_unpause(ahc); } +/*************************** Timeout Handling *********************************/ +void +ahc_timeout(struct scb *scb) +{ + struct ahc_softc *ahc; + + ahc = scb->ahc_softc; + if ((scb->flags & SCB_ACTIVE) != 0) { + if ((scb->flags & SCB_TIMEDOUT) == 0) { + LIST_INSERT_HEAD(&ahc->timedout_scbs, scb, + timedout_links); + scb->flags |= SCB_TIMEDOUT; + } + ahc_wakeup_recovery_thread(ahc); + } +} + +/* + * ahc_recover_commands determines if any of the commands that have currently + * timedout are the root cause for this timeout. Innocent commands are given + * a new timeout while we wait for the command executing on the bus to timeout. + * This routine is invoked from a thread context so we are allowed to sleep. + * Our lock is not held on entry. + */ +void +ahc_recover_commands(struct ahc_softc *ahc) +{ + struct scb *scb; + long s; + int found; + int restart_needed; + u_int last_phase; + + ahc_lock(ahc, &s); + + /* + * Pause the controller and manually flush any + * commands that have just completed but that our + * interrupt handler has yet to see. + */ + ahc_pause_and_flushwork(ahc); + + if (LIST_EMPTY(&ahc->timedout_scbs) != 0) { + /* + * The timedout commands have already + * completed. This typically means + * that either the timeout value was on + * the hairy edge of what the device + * requires or - more likely - interrupts + * are not happening. + */ + printf("%s: Timedout SCBs already complete. " + "Interrupts may not be functioning.\n", ahc_name(ahc)); + ahc_unpause(ahc); + ahc_unlock(ahc, &s); + return; + } + + restart_needed = 0; + printf("%s: Recovery Initiated\n", ahc_name(ahc)); + ahc_dump_card_state(ahc); + + last_phase = ahc_inb(ahc, LASTPHASE); + while ((scb = LIST_FIRST(&ahc->timedout_scbs)) != NULL) { + u_int active_scb_index; + u_int saved_scbptr; + int target; + int lun; + int i; + char channel; + + target = SCB_GET_TARGET(ahc, scb); + channel = SCB_GET_CHANNEL(ahc, scb); + lun = SCB_GET_LUN(scb); + + ahc_print_path(ahc, scb); + printf("SCB 0x%x - timed out\n", scb->hscb->tag); + if (scb->sg_count > 0) { + for (i = 0; i < scb->sg_count; i++) { + printf("sg[%d] - Addr 0x%x : Length %d\n", + i, + scb->sg_list[i].addr, + scb->sg_list[i].len & AHC_SG_LEN_MASK); + } + } + if (scb->flags & (SCB_DEVICE_RESET|SCB_ABORT)) { + /* + * Been down this road before. + * Do a full bus reset. + */ + aic_set_transaction_status(scb, CAM_CMD_TIMEOUT); +bus_reset: + found = ahc_reset_channel(ahc, channel, + /*Initiate Reset*/TRUE); + printf("%s: Issued Channel %c Bus Reset. " + "%d SCBs aborted\n", ahc_name(ahc), channel, + found); + continue; + } + + /* + * Remove the command from the timedout list in + * preparation for requeing it. + */ + LIST_REMOVE(scb, timedout_links); + scb->flags &= ~SCB_TIMEDOUT; + + /* + * If we are a target, transition to bus free and report + * the timeout. + * + * The target/initiator that is holding up the bus may not + * be the same as the one that triggered this timeout + * (different commands have different timeout lengths). + * If the bus is idle and we are actiing as the initiator + * for this request, queue a BDR message to the timed out + * target. Otherwise, if the timed out transaction is + * active: + * Initiator transaction: + * Stuff the message buffer with a BDR message and assert + * ATN in the hopes that the target will let go of the bus + * and go to the mesgout phase. If this fails, we'll + * get another timeout 2 seconds later which will attempt + * a bus reset. + * + * Target transaction: + * Transition to BUS FREE and report the error. + * It's good to be the target! + */ + saved_scbptr = ahc_inb(ahc, SCBPTR); + active_scb_index = ahc_inb(ahc, SCB_TAG); + + if ((ahc_inb(ahc, SEQ_FLAGS) & NOT_IDENTIFIED) == 0 + && (active_scb_index < ahc->scb_data->numscbs)) { + struct scb *active_scb; + + /* + * If the active SCB is not us, assume that + * the active SCB has a longer timeout than + * the timedout SCB, and wait for the active + * SCB to timeout. + */ + active_scb = ahc_lookup_scb(ahc, active_scb_index); + if (active_scb != scb) { + u_int newtimeout; + + ahc_print_path(ahc, scb); + printf("Other SCB Timeout%s", + (scb->flags & SCB_OTHERTCL_TIMEOUT) != 0 + ? " again\n" : "\n"); + scb->flags |= SCB_OTHERTCL_TIMEOUT; + newtimeout = + MAX(aic_get_timeout(active_scb), + aic_get_timeout(scb)); + aic_scb_timer_reset(scb, newtimeout); + continue; + } + + /* It's us */ + if ((scb->flags & SCB_TARGET_SCB) != 0) { + + /* + * Send back any queued up transactions + * and properly record the error condition. + */ + ahc_abort_scbs(ahc, SCB_GET_TARGET(ahc, scb), + SCB_GET_CHANNEL(ahc, scb), + SCB_GET_LUN(scb), + scb->hscb->tag, + ROLE_TARGET, + CAM_CMD_TIMEOUT); + + /* Will clear us from the bus */ + restart_needed = 1; + break; + } + + ahc_set_recoveryscb(ahc, active_scb); + ahc_outb(ahc, MSG_OUT, HOST_MSG); + ahc_outb(ahc, SCSISIGO, last_phase|ATNO); + ahc_print_path(ahc, active_scb); + printf("BDR message in message buffer\n"); + active_scb->flags |= SCB_DEVICE_RESET; + aic_scb_timer_reset(scb, 2 * 1000000); + } else if (last_phase != P_BUSFREE + && (ahc_inb(ahc, SSTAT1) & REQINIT) == 0) { + /* + * SCB is not identified, there + * is no pending REQ, and the sequencer + * has not seen a busfree. Looks like + * a stuck connection waiting to + * go busfree. Reset the bus. + */ + printf("%s: Connection stuck awaiting busfree or " + "Identify Msg.\n", ahc_name(ahc)); + goto bus_reset; + } else { + int disconnected; + + if (last_phase != P_BUSFREE + && (ahc_inb(ahc, SSTAT0) & TARGET) != 0) { + /* Hung target selection. Goto busfree */ + printf("%s: Hung target selection\n", + ahc_name(ahc)); + restart_needed = 1; + break; + } + + /* XXX Shouldn't panic. Just punt instead? */ + if ((scb->flags & SCB_TARGET_SCB) != 0) + panic("Timed-out target SCB but bus idle"); + + if (ahc_search_qinfifo(ahc, target, channel, lun, + scb->hscb->tag, ROLE_INITIATOR, + /*status*/0, SEARCH_COUNT) > 0) { + disconnected = FALSE; + } else { + disconnected = TRUE; + } + + if (disconnected) { + + ahc_set_recoveryscb(ahc, scb); + /* + * Actually re-queue this SCB in an attempt + * to select the device before it reconnects. + * In either case (selection or reselection), + * we will now issue a target reset to the + * timed-out device. + * + * Set the MK_MESSAGE control bit indicating + * that we desire to send a message. We + * also set the disconnected flag since + * in the paging case there is no guarantee + * that our SCB control byte matches the + * version on the card. We don't want the + * sequencer to abort the command thinking + * an unsolicited reselection occurred. + */ + scb->hscb->control |= MK_MESSAGE|DISCONNECTED; + scb->flags |= SCB_DEVICE_RESET; + + /* + * Remove any cached copy of this SCB in the + * disconnected list in preparation for the + * queuing of our abort SCB. We use the + * same element in the SCB, SCB_NEXT, for + * both the qinfifo and the disconnected list. + */ + ahc_search_disc_list(ahc, target, channel, + lun, scb->hscb->tag, + /*stop_on_first*/TRUE, + /*remove*/TRUE, + /*save_state*/FALSE); + + /* + * In the non-paging case, the sequencer will + * never re-reference the in-core SCB. + * To make sure we are notified during + * reslection, set the MK_MESSAGE flag in + * the card's copy of the SCB. + */ + if ((ahc->flags & AHC_PAGESCBS) == 0) { + ahc_outb(ahc, SCBPTR, scb->hscb->tag); + ahc_outb(ahc, SCB_CONTROL, + ahc_inb(ahc, SCB_CONTROL) + | MK_MESSAGE); + } + + /* + * Clear out any entries in the QINFIFO first + * so we are the next SCB for this target + * to run. + */ + ahc_search_qinfifo(ahc, + SCB_GET_TARGET(ahc, scb), + channel, SCB_GET_LUN(scb), + SCB_LIST_NULL, + ROLE_INITIATOR, + CAM_REQUEUE_REQ, + SEARCH_COMPLETE); + ahc_print_path(ahc, scb); + printf("Queuing a BDR SCB\n"); + ahc_qinfifo_requeue_tail(ahc, scb); + ahc_outb(ahc, SCBPTR, saved_scbptr); + aic_scb_timer_reset(scb, 2 * 1000000); + } else { + /* Go "immediatly" to the bus reset */ + /* This shouldn't happen */ + ahc_set_recoveryscb(ahc, scb); + ahc_print_path(ahc, scb); + printf("SCB %d: Immediate reset. " + "Flags = 0x%x\n", scb->hscb->tag, + scb->flags); + goto bus_reset; + } + } + break; + } + + /* + * Any remaining SCBs were not the "culprit", so remove + * them from the timeout list. The timer for these commands + * will be reset once the recovery SCB completes. + */ + while ((scb = LIST_FIRST(&ahc->timedout_scbs)) != NULL) { + + LIST_REMOVE(scb, timedout_links); + scb->flags &= ~SCB_TIMEDOUT; + } + + if (restart_needed) + ahc_restart(ahc); + else + ahc_unpause(ahc); + ahc_unlock(ahc, &s); +} + /************************* Target Mode ****************************************/ #ifdef AHC_TARGET_MODE cam_status @@ -6968,11 +7310,12 @@ ahc_handle_en_lun(struct ahc_softc *ahc, */ ahc->flags = saved_flags; (void)ahc_loadseq(ahc); - ahc_unpause(ahc); + ahc_restart(ahc); ahc_unlock(ahc, &s); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; return; } + ahc_restart(ahc); ahc_unlock(ahc, &s); } cel = &ccb->cel; @@ -7207,12 +7550,16 @@ ahc_handle_en_lun(struct ahc_softc *ahc, printf("Configuring Initiator Mode\n"); ahc->flags &= ~AHC_TARGETROLE; ahc->flags |= AHC_INITIATORROLE; - ahc_pause(ahc); /* * Returning to a configuration that * fit previously will always succeed. */ (void)ahc_loadseq(ahc); + ahc_restart(ahc); + /* + * Unpaused. The extra unpause + * that follows is harmless. + */ } } ahc_unpause(ahc); @@ -7282,7 +7629,7 @@ ahc_run_tqinfifo(struct ahc_softc *ahc, break; cmd->cmd_valid = 0; - ahc_dmamap_sync(ahc, ahc->shared_data_dmat, + aic_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, ahc_targetcmd_offset(ahc, ahc->tqinfifonext), sizeof(struct target_cmd), @@ -7419,7 +7766,7 @@ ahc_handle_target_cmd(struct ahc_softc * initiator, target, lun, ahc->pending_device); #endif ahc->pending_device = lstate; - ahc_freeze_ccb((union ccb *)atio); + aic_freeze_ccb((union ccb *)atio); atio->ccb_h.flags |= CAM_DIS_DISCONNECT; } xpt_done((union ccb*)atio); diff -puN drivers/scsi/aic7xxx/aic7xxx.h~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7xxx.h --- 25/drivers/scsi/aic7xxx/aic7xxx.h~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7xxx.h Wed Dec 24 12:15:38 2003 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#77 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#85 $ * * $FreeBSD$ */ @@ -243,7 +243,7 @@ typedef enum { */ AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE|AHC_ULTRA, AHC_AIC7860_FE = AHC_AIC7850_FE, - AHC_AIC7870_FE = AHC_TARGETMODE, + AHC_AIC7870_FE = AHC_TARGETMODE|AHC_AUTOPAUSE, AHC_AIC7880_FE = AHC_AIC7870_FE|AHC_ULTRA, /* * Although we have space for both the initiator and @@ -366,7 +366,8 @@ typedef enum { AHC_SCB_CONFIG_USED = 0x4000000, /* No SEEPROM but SCB2 had info. */ AHC_NO_BIOS_INIT = 0x8000000, /* No BIOS left over settings. */ AHC_DISABLE_PCI_PERR = 0x10000000, - AHC_HAS_TERM_LOGIC = 0x20000000 + AHC_HAS_TERM_LOGIC = 0x20000000, + AHC_SHUTDOWN_RECOVERY = 0x40000000 /* Terminate recovery thread. */ } ahc_flag; /************************* Hardware SCB Definition ***************************/ @@ -411,6 +412,7 @@ struct target_data { uint8_t initiator_tag; /* Initiator's transaction tag */ }; +#define MAX_CDB_LEN 16 struct hardware_scb { /*0*/ union { /* @@ -530,7 +532,7 @@ struct sg_map_node { * The current state of this SCB. */ typedef enum { - SCB_FREE = 0x0000, + SCB_FLAG_NONE = 0x0000, SCB_OTHERTCL_TIMEOUT = 0x0002,/* * Another device was active * during the first timeout for @@ -560,12 +562,16 @@ typedef enum { * to report the error. */ SCB_TARGET_SCB = 0x2000, - SCB_SILENT = 0x4000 /* + SCB_SILENT = 0x4000,/* * Be quiet about transmission type * errors. They are expected and we * don't want to upset the user. This * flag is typically used during DV. */ + SCB_TIMEDOUT = 0x8000 /* + * SCB has timed out and is on the + * timedout list. + */ } scb_flag; struct scb { @@ -575,7 +581,8 @@ struct scb { TAILQ_ENTRY(scb) tqe; } links; LIST_ENTRY(scb) pending_links; - ahc_io_ctx_t io_ctx; + LIST_ENTRY(scb) timedout_links; + aic_io_ctx_t io_ctx; struct ahc_softc *ahc_softc; scb_flag flags; #ifndef __linux__ @@ -929,6 +936,11 @@ struct ahc_softc { LIST_HEAD(, scb) pending_scbs; /* + * SCBs whose timeout routine has been called. + */ + LIST_HEAD(, scb) timedout_scbs; + + /* * Counting lock for deferring the release of additional * untagged transactions from the untagged_queues. When * the lock is decremented to 0, all queues in the @@ -958,7 +970,7 @@ struct ahc_softc { /* * Platform specific device information. */ - ahc_dev_softc_t dev_softc; + aic_dev_softc_t dev_softc; /* * Bus specific device information. @@ -1135,6 +1147,9 @@ struct ahc_devinfo { }; /****************************** PCI Structures ********************************/ +#define AHC_PCI_IOADDR PCIR_BAR(0) /* I/O Address */ +#define AHC_PCI_MEMADDR PCIR_BAR(1) /* Mem I/O Address */ + typedef int (ahc_device_setup_t)(struct ahc_softc *); struct ahc_pci_identity { @@ -1143,17 +1158,17 @@ struct ahc_pci_identity { char *name; ahc_device_setup_t *setup; }; -extern struct ahc_pci_identity ahc_pci_ident_table []; +extern struct ahc_pci_identity ahc_pci_ident_table[]; extern const u_int ahc_num_pci_devs; /***************************** VL/EISA Declarations ***************************/ struct aic7770_identity { uint32_t full_id; uint32_t id_mask; - char *name; + const char *name; ahc_device_setup_t *setup; }; -extern struct aic7770_identity aic7770_ident_table []; +extern struct aic7770_identity aic7770_ident_table[]; extern const int ahc_num_aic7770_devs; #define AHC_EISA_SLOT_OFFSET 0xc00 @@ -1167,7 +1182,7 @@ void ahc_busy_tcl(struct ahc_softc *ah u_int tcl, u_int busyid); /***************************** PCI Front End *********************************/ -struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t); +struct ahc_pci_identity *ahc_find_pci_device(aic_dev_softc_t); int ahc_pci_config(struct ahc_softc *, struct ahc_pci_identity *); int ahc_pci_test_register_access(struct ahc_softc *); @@ -1205,7 +1220,7 @@ void ahc_set_unit(struct ahc_softc *, void ahc_set_name(struct ahc_softc *, char *); void ahc_alloc_scbs(struct ahc_softc *ahc); void ahc_free(struct ahc_softc *ahc); -int ahc_reset(struct ahc_softc *ahc); +int ahc_reset(struct ahc_softc *ahc, int reinit); void ahc_shutdown(void *arg); /*************************** Interrupt Services *******************************/ @@ -1231,7 +1246,7 @@ int ahc_search_qinfifo(struct ahc_soft role_t role, uint32_t status, ahc_search_action action); int ahc_search_untagged_queues(struct ahc_softc *ahc, - ahc_io_ctx_t ctx, + aic_io_ctx_t ctx, int target, char channel, int lun, uint32_t status, ahc_search_action action); @@ -1248,6 +1263,8 @@ int ahc_abort_scbs(struct ahc_softc *a void ahc_restart(struct ahc_softc *ahc); void ahc_calc_residual(struct ahc_softc *ahc, struct scb *scb); +void ahc_timeout(struct scb *scb); +void ahc_recover_commands(struct ahc_softc *ahc); /*************************** Utility Functions ********************************/ struct ahc_phase_table_entry* ahc_lookup_phase_entry(int phase); diff -puN drivers/scsi/aic7xxx/aic7xxx_inline.h~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7xxx_inline.h --- 25/drivers/scsi/aic7xxx/aic7xxx_inline.h~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7xxx_inline.h Wed Dec 24 12:15:38 2003 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#43 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#47 $ * * $FreeBSD$ */ @@ -196,7 +196,7 @@ ahc_hscb_busaddr(struct ahc_softc *ahc, static __inline void ahc_sync_scb(struct ahc_softc *ahc, struct scb *scb, int op) { - ahc_dmamap_sync(ahc, ahc->scb_data->hscb_dmat, + aic_dmamap_sync(ahc, ahc->scb_data->hscb_dmat, ahc->scb_data->hscb_dmamap, /*offset*/(scb->hscb - ahc->hscbs) * sizeof(*scb->hscb), /*len*/sizeof(*scb->hscb), op); @@ -208,7 +208,7 @@ ahc_sync_sglist(struct ahc_softc *ahc, s if (scb->sg_count == 0) return; - ahc_dmamap_sync(ahc, ahc->scb_data->sg_dmat, scb->sg_map->sg_dmamap, + aic_dmamap_sync(ahc, ahc->scb_data->sg_dmat, scb->sg_map->sg_dmamap, /*offset*/(scb->sg_list - scb->sg_map->sg_vaddr) * sizeof(struct ahc_dma_seg), /*len*/sizeof(struct ahc_dma_seg) * scb->sg_count, op); @@ -272,7 +272,7 @@ ahc_update_residual(struct ahc_softc *ah { uint32_t sgptr; - sgptr = ahc_le32toh(scb->hscb->sgptr); + sgptr = aic_le32toh(scb->hscb->sgptr); if ((sgptr & SG_RESID_VALID) != 0) ahc_calc_residual(ahc, scb); } @@ -383,13 +383,13 @@ ahc_free_scb(struct ahc_softc *ahc, stru hscb = scb->hscb; /* Clean up for the next user */ ahc->scb_data->scbindex[hscb->tag] = NULL; - scb->flags = SCB_FREE; + scb->flags = SCB_FLAG_NONE; hscb->control = 0; SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle); /* Notify the OSM that a resource is now available. */ - ahc_platform_scb_free(ahc, scb); + aic_platform_scb_free(ahc, scb); } static __inline struct scb * @@ -427,7 +427,7 @@ ahc_swap_with_next_hscb(struct ahc_softc memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); if ((scb->flags & SCB_CDB32_PTR) != 0) { q_hscb->shared_data.cdb_ptr = - ahc_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag) + aic_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag) + offsetof(struct hardware_scb, cdb32)); } q_hscb->tag = saved_tag; @@ -458,7 +458,7 @@ ahc_queue_scb(struct ahc_softc *ahc, str * Setup data "oddness". */ scb->hscb->lun &= LID; - if (ahc_get_transfer_length(scb) & 0x1) + if (aic_get_transfer_length(scb) & 0x1) scb->hscb->lun |= SCB_XFERLEN_ODD; /* @@ -512,7 +512,7 @@ static __inline int ahc_intr(struct ahc_ static __inline void ahc_sync_qoutfifo(struct ahc_softc *ahc, int op) { - ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, + aic_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, /*offset*/0, /*len*/256, op); } @@ -521,7 +521,7 @@ ahc_sync_tqinfifo(struct ahc_softc *ahc, { #ifdef AHC_TARGET_MODE if ((ahc->flags & AHC_TARGETROLE) != 0) { - ahc_dmamap_sync(ahc, ahc->shared_data_dmat, + aic_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, ahc_targetcmd_offset(ahc, 0), sizeof(struct target_cmd) * AHC_TMODE_CMDS, @@ -542,7 +542,7 @@ ahc_check_cmdcmpltqueues(struct ahc_soft u_int retval; retval = 0; - ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, + aic_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, /*offset*/ahc->qoutfifonext, /*len*/1, BUS_DMASYNC_POSTREAD); if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL) @@ -550,7 +550,7 @@ ahc_check_cmdcmpltqueues(struct ahc_soft #ifdef AHC_TARGET_MODE if ((ahc->flags & AHC_TARGETROLE) != 0 && (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) { - ahc_dmamap_sync(ahc, ahc->shared_data_dmat, + aic_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, ahc_targetcmd_offset(ahc, ahc->tqinfifofnext), /*len*/sizeof(struct target_cmd), @@ -593,7 +593,7 @@ ahc_intr(struct ahc_softc *ahc) } if ((intstat & INT_PEND) == 0) { -#if AHC_PCI_CONFIG > 0 +#if AIC_PCI_CONFIG > 0 if (ahc->unsolicited_ints > 500) { ahc->unsolicited_ints = 0; if ((ahc->chip & AHC_PCI) != 0 diff -puN drivers/scsi/aic7xxx/aic7xxx_osm.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7xxx_osm.c --- 25/drivers/scsi/aic7xxx/aic7xxx_osm.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7xxx_osm.c Wed Dec 24 12:15:38 2003 @@ -1,7 +1,7 @@ /* * Adaptec AIC7xxx device driver for Linux. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#232 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#256 $ * * Copyright (c) 1994 John Aycock * The University of Calgary Department of Computer Science. @@ -139,7 +139,16 @@ #endif #include /* For fetching system memory size */ -#include /* For block_size() */ + +/************************* Magic SysReq Support *******************************/ +static struct aic_sysrq_key_op ahc_sysrq_op = +{ + aic_sysrq_handler, + "aic7xxxstatedump", + "Dump aic7xxx controller information to Console" +}; + +static int ahc_sysrq_key; /* * Lock protecting manipulation of the ahc softc list. @@ -293,7 +302,7 @@ static adapter_tag_info_t aic7xxx_tag_in #define AIC7XXX_CONFIGED_DV -1 #endif -static uint8_t aic7xxx_dv_settings[] = +static int8_t aic7xxx_dv_settings[] = { AIC7XXX_CONFIGED_DV, AIC7XXX_CONFIGED_DV, @@ -391,9 +400,9 @@ static uint32_t aic7xxx_pci_parity = ~0; * would result in never finding any devices :) */ #ifndef CONFIG_AIC7XXX_PROBE_EISA_VL -static uint32_t aic7xxx_probe_eisa_vl; +uint32_t aic7xxx_probe_eisa_vl; #else -static uint32_t aic7xxx_probe_eisa_vl = ~0; +uint32_t aic7xxx_probe_eisa_vl = ~0; #endif /* @@ -482,35 +491,32 @@ MODULE_PARM_DESC(aic7xxx, #endif static void ahc_linux_handle_scsi_status(struct ahc_softc *, - struct ahc_linux_device *, + struct aic_linux_device *, struct scb *); static void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd); static void ahc_linux_filter_inquiry(struct ahc_softc*, struct ahc_devinfo*); static void ahc_linux_sem_timeout(u_long arg); -static void ahc_linux_freeze_simq(struct ahc_softc *ahc); -static void ahc_linux_release_simq(u_long arg); static void ahc_linux_dev_timed_unfreeze(u_long arg); static int ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); static void ahc_linux_size_nseg(void); static void ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc); static void ahc_linux_start_dv(struct ahc_softc *ahc); -static void ahc_linux_dv_timeout(struct scsi_cmnd *cmd); static int ahc_linux_dv_thread(void *data); static void ahc_linux_kill_dv_thread(struct ahc_softc *ahc); static void ahc_linux_dv_target(struct ahc_softc *ahc, u_int target); static void ahc_linux_dv_transition(struct ahc_softc *ahc, struct scsi_cmnd *cmd, struct ahc_devinfo *devinfo, - struct ahc_linux_target *targ); + struct aic_linux_target *targ); static void ahc_linux_dv_fill_cmd(struct ahc_softc *ahc, struct scsi_cmnd *cmd, struct ahc_devinfo *devinfo); static void ahc_linux_dv_inq(struct ahc_softc *ahc, struct scsi_cmnd *cmd, struct ahc_devinfo *devinfo, - struct ahc_linux_target *targ, + struct aic_linux_target *targ, u_int request_length); static void ahc_linux_dv_tur(struct ahc_softc *ahc, struct scsi_cmnd *cmd, @@ -518,58 +524,48 @@ static void ahc_linux_dv_tur(struct ahc_ static void ahc_linux_dv_rebd(struct ahc_softc *ahc, struct scsi_cmnd *cmd, struct ahc_devinfo *devinfo, - struct ahc_linux_target *targ); + struct aic_linux_target *targ); static void ahc_linux_dv_web(struct ahc_softc *ahc, struct scsi_cmnd *cmd, struct ahc_devinfo *devinfo, - struct ahc_linux_target *targ); + struct aic_linux_target *targ); static void ahc_linux_dv_reb(struct ahc_softc *ahc, struct scsi_cmnd *cmd, struct ahc_devinfo *devinfo, - struct ahc_linux_target *targ); + struct aic_linux_target *targ); static void ahc_linux_dv_su(struct ahc_softc *ahc, struct scsi_cmnd *cmd, struct ahc_devinfo *devinfo, - struct ahc_linux_target *targ); + struct aic_linux_target *targ); static int ahc_linux_fallback(struct ahc_softc *ahc, struct ahc_devinfo *devinfo); -static void ahc_linux_dv_complete(Scsi_Cmnd *cmd); -static void ahc_linux_generate_dv_pattern(struct ahc_linux_target *targ); +static void ahc_linux_generate_dv_pattern(struct aic_linux_target *targ); static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo); static u_int ahc_linux_user_dv_setting(struct ahc_softc *ahc); -static void ahc_linux_device_queue_depth(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static struct ahc_linux_target* ahc_linux_alloc_target(struct ahc_softc*, +static void aic_linux_device_queue_depth(struct ahc_softc *ahc, + struct aic_linux_device *dev); +static struct aic_linux_target* ahc_linux_alloc_target(struct ahc_softc*, u_int, u_int); static void ahc_linux_free_target(struct ahc_softc*, - struct ahc_linux_target*); -static struct ahc_linux_device* ahc_linux_alloc_device(struct ahc_softc*, - struct ahc_linux_target*, + struct aic_linux_target*); +static struct aic_linux_device* ahc_linux_alloc_device(struct ahc_softc*, + struct aic_linux_target*, u_int); static void ahc_linux_free_device(struct ahc_softc*, - struct ahc_linux_device*); -static void ahc_linux_run_device_queue(struct ahc_softc*, - struct ahc_linux_device*); + struct aic_linux_device*); static void ahc_linux_setup_tag_info_global(char *p); static aic_option_callback_t ahc_linux_setup_tag_info; static aic_option_callback_t ahc_linux_setup_dv; static int aic7xxx_setup(char *s); static int ahc_linux_next_unit(void); -static void ahc_runq_tasklet(unsigned long data); -static struct ahc_cmd *ahc_linux_run_complete_queue(struct ahc_softc *ahc); +static struct aic_cmd *ahc_linux_run_complete_queue(struct ahc_softc *ahc); /********************************* Inlines ************************************/ -static __inline void ahc_schedule_runq(struct ahc_softc *ahc); -static __inline struct ahc_linux_device* +static __inline struct aic_linux_device* ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, u_int lun, int alloc); static __inline void ahc_schedule_completeq(struct ahc_softc *ahc); -static __inline void ahc_linux_check_device_queue(struct ahc_softc *ahc, - struct ahc_linux_device *dev); -static __inline struct ahc_linux_device * - ahc_linux_next_device_to_run(struct ahc_softc *ahc); -static __inline void ahc_linux_run_device_queues(struct ahc_softc *ahc); static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, @@ -579,35 +575,19 @@ static __inline int ahc_linux_map_seg(st static __inline void ahc_schedule_completeq(struct ahc_softc *ahc) { - if ((ahc->platform_data->flags & AHC_RUN_CMPLT_Q_TIMER) == 0) { - ahc->platform_data->flags |= AHC_RUN_CMPLT_Q_TIMER; + if ((ahc->platform_data->flags & AIC_RUN_CMPLT_Q_TIMER) == 0) { + ahc->platform_data->flags |= AIC_RUN_CMPLT_Q_TIMER; ahc->platform_data->completeq_timer.expires = jiffies; add_timer(&ahc->platform_data->completeq_timer); } } -/* - * Must be called with our lock held. - */ -static __inline void -ahc_schedule_runq(struct ahc_softc *ahc) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - tasklet_schedule(&ahc->platform_data->runq_tasklet); -#else - /* - * Tasklets are not available, so run inline. - */ - ahc_runq_tasklet((unsigned long)ahc); -#endif -} - -static __inline struct ahc_linux_device* +static __inline struct aic_linux_device* ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target, u_int lun, int alloc) { - struct ahc_linux_target *targ; - struct ahc_linux_device *dev; + struct aic_linux_target *targ; + struct aic_linux_device *dev; u_int target_offset; target_offset = target; @@ -629,10 +609,10 @@ ahc_linux_get_device(struct ahc_softc *a } #define AHC_LINUX_MAX_RETURNED_ERRORS 4 -static struct ahc_cmd * +static struct aic_cmd * ahc_linux_run_complete_queue(struct ahc_softc *ahc) { - struct ahc_cmd *acmd; + struct aic_cmd *acmd; u_long done_flags; int with_errors; @@ -657,7 +637,7 @@ ahc_linux_run_complete_queue(struct ahc_ acmd, acmd_links.tqe); cmd = &acmd_scsi_cmd(acmd); cmd->host_scribble = NULL; - if (ahc_cmd_get_transaction_status(cmd) != DID_OK + if (aic_cmd_get_transaction_status(cmd) != DID_OK || (cmd->result & 0xFF) != SCSI_STATUS_OK) with_errors++; @@ -666,47 +646,6 @@ ahc_linux_run_complete_queue(struct ahc_ ahc_done_unlock(ahc, &done_flags); return (acmd); } - -static __inline void -ahc_linux_check_device_queue(struct ahc_softc *ahc, - struct ahc_linux_device *dev) -{ - if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) != 0 - && dev->active == 0) { - dev->flags &= ~AHC_DEV_FREEZE_TIL_EMPTY; - dev->qfrozen--; - } - - if (TAILQ_FIRST(&dev->busyq) == NULL - || dev->openings == 0 || dev->qfrozen != 0) - return; - - ahc_linux_run_device_queue(ahc, dev); -} - -static __inline struct ahc_linux_device * -ahc_linux_next_device_to_run(struct ahc_softc *ahc) -{ - - if ((ahc->flags & AHC_RESOURCE_SHORTAGE) != 0 - || (ahc->platform_data->qfrozen != 0 - && AHC_DV_SIMQ_FROZEN(ahc) == 0)) - return (NULL); - return (TAILQ_FIRST(&ahc->platform_data->device_runq)); -} - -static __inline void -ahc_linux_run_device_queues(struct ahc_softc *ahc) -{ - struct ahc_linux_device *dev; - - while ((dev = ahc_linux_next_device_to_run(ahc)) != NULL) { - TAILQ_REMOVE(&ahc->platform_data->device_runq, dev, links); - dev->flags &= ~AHC_DEV_ON_RUN_LIST; - ahc_linux_check_device_queue(ahc, dev); - } -} - static __inline void ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb) { @@ -718,10 +657,10 @@ ahc_linux_unmap_scb(struct ahc_softc *ah struct scatterlist *sg; sg = (struct scatterlist *)cmd->request_buffer; - pci_unmap_sg(ahc->dev_softc, sg, cmd->use_sg, + aic_unmap_sg(ahc, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction)); } else if (cmd->request_bufflen != 0) { - pci_unmap_single(ahc->dev_softc, + aic_unmap_single(ahc, scb->platform_data->buf_busaddr, cmd->request_bufflen, scsi_to_pci_dma_dir(cmd->sc_data_direction)); @@ -739,20 +678,19 @@ ahc_linux_map_seg(struct ahc_softc *ahc, "Increase AHC_NSEG\n"); consumed = 1; - sg->addr = ahc_htole32(addr & 0xFFFFFFFF); + sg->addr = aic_htole32(addr & 0xFFFFFFFF); scb->platform_data->xfer_len += len; if (sizeof(bus_addr_t) > 4 && (ahc->flags & AHC_39BIT_ADDRESSING) != 0) len |= (addr >> 8) & AHC_SG_HIGH_ADDR_MASK; - sg->len = ahc_htole32(len); + sg->len = aic_htole32(len); return (consumed); } /************************ Host template entry points *************************/ static int ahc_linux_detect(Scsi_Host_Template *); -static int ahc_linux_release(struct Scsi_Host *); static int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); static const char *ahc_linux_info(struct Scsi_Host *); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) @@ -765,6 +703,7 @@ static int ahc_linux_biosparam(struct sector_t, int[]); #endif #else +static int ahc_linux_release(struct Scsi_Host *); static void ahc_linux_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs); #if defined(__i386__) @@ -836,6 +775,164 @@ ahc_linux_size_nseg(void) #endif } +/************************** Error Recovery ************************************/ +static int ahc_linux_recovery_thread(void *arg); + +static int +ahc_linux_recovery_thread(void *arg) +{ + struct ahc_softc *ahc; + u_long s; + + ahc = (struct ahc_softc *)arg; + + /* + * Complete thread creation. + */ + lock_kernel(); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60) + /* + * Don't care about any signals. + */ + siginitsetinv(¤t->blocked, 0); + + daemonize(); + sprintf(current->comm, "ahc_recovery_%d", ahc->unit); +#else + daemonize("ahc_recovery_%d", ahc->unit); +#endif + unlock_kernel(); + + while (1) { + + /* + * Use down_interruptible() rather than down() to + * avoid inclusion in the load average. + */ + down_interruptible(&ahc->platform_data->recovery_sem); + + ahc_lock(ahc, &s); + if ((ahc->flags & AHC_SHUTDOWN_RECOVERY) != 0) { + ahc_unlock(ahc, &s); + break; + } + + /* + * Don't bother the recovery handler if the + * list has been cleared by a previous run + * of the handler. This can happen when + * several SCBs timeout before our handler + * can run causing our semaphore to be up'ed + * repeatedly. The extra calls need to be + * avoided so that the recovery handler doesn't + * confuse this case with timeouts occuring + * due to interrupts failing to function. + */ + if (LIST_EMPTY(&ahc->timedout_scbs) != 0) { + ahc_unlock(ahc, &s); + continue; + } + ahc_unlock(ahc, &s); + ahc_recover_commands(ahc); + + /* + * Process any pent up completions. + */ + ahc_lock(ahc, &s); + aic_schedule_runq(ahc); + ahc_linux_run_complete_queue(ahc); + ahc_unlock(ahc, &s); + } + up(&ahc->platform_data->recovery_ending_sem); + return(0); +} + +int +ahc_spawn_recovery_thread(struct ahc_softc *ahc) +{ + ahc->platform_data->recovery_pid = + kernel_thread(ahc_linux_recovery_thread, ahc, 0); + + if (ahc->platform_data->recovery_pid < 0) + return (-ahc->platform_data->recovery_pid); + + return (0); +} + +void +ahc_terminate_recovery_thread(struct ahc_softc *ahc) +{ + u_long s; + + ahc_lock(ahc, &s); + if (ahc->platform_data->recovery_pid != 0) { + ahc->flags |= AHC_SHUTDOWN_RECOVERY; + ahc_unlock(ahc, &s); + up(&ahc->platform_data->recovery_sem); + + /* + * Use the recovery_ending_sem as an indicator that + * the dv thread is exiting. Note that the dv + * thread must still return after performing + * the up on our semaphore before it has + * completely exited this module. Unfortunately, + * there seems to be no easy way to wait for the + * exit of a thread for which you are not the + * parent (dv threads are parented by init). + * Cross your fingers... + */ + down(&ahc->platform_data->recovery_ending_sem); + + /* + * Mark the recovery thread as already dead. This + * avoids attempting to kill it a second time. + * This is necessary because we must kill the + * our threads before calling ahc_free() in the + * module shutdown case to avoid bogus locking + * in the SCSI mid-layer, but when ahc_free() is + * called without killing the DV thread in the + * instance detach case, so ahc_platform_free() + * calls us again to verify that the DV thread + * is dead. + */ + ahc->platform_data->recovery_pid = 0; + } else { + ahc_unlock(ahc, &s); + } +} + +void +ahc_set_recoveryscb(struct ahc_softc *ahc, struct scb *scb) +{ + if ((scb->flags & SCB_RECOVERY_SCB) == 0) { + struct scb *list_scb; + + scb->flags |= SCB_RECOVERY_SCB; + + /* + * Take all queued, but not sent SCBs out of the equation. + * Also ensure that no new commands are queued to us while we + * try to fix this problem. + */ + if ((scb->platform_data->flags & AIC_RELEASE_SIMQ) == 0) { + aic_freeze_simq(ahc); + scb->platform_data->flags |= AIC_RELEASE_SIMQ; + } + + /* + * Go through all of our pending SCBs and remove + * any scheduled timeouts for them. We will reschedule + * them after we've successfully fixed this problem. + */ + LIST_FOREACH(list_scb, &ahc->pending_scbs, pending_links) { + + scsi_delete_timer(list_scb->io_ctx); + list_scb->platform_data->flags &= ~AIC_TIMEOUT_ACTIVE; + } + } +} + +/************************ Linux Entry Points **********************************/ /* * Try to detect an Adaptec 7XXX controller. */ @@ -858,7 +955,7 @@ ahc_linux_detect(Scsi_Host_Template *tem * that some of our hacks^H^H^H^H^Hassumptions aren't * violated. */ - if (offsetof(struct ahc_cmd_internal, end) + if (offsetof(struct aic_cmd_internal, end) > offsetof(struct scsi_cmnd, host_scribble)) { printf("ahc_linux_detect: SCSI data structures changed.\n"); printf("ahc_linux_detect: Unable to attach\n"); @@ -895,8 +992,9 @@ ahc_linux_detect(Scsi_Host_Template *tem ahc_linux_pci_init(); #endif - if (aic7xxx_probe_eisa_vl != 0) - aic7770_linux_probe(template); +#ifdef CONFIG_EISA + ahc_linux_eisa_init(); +#endif /* * Register with the SCSI layer all @@ -915,6 +1013,7 @@ ahc_linux_detect(Scsi_Host_Template *tem return (found); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* * Free the passed in Scsi_Host memory structures prior to unloading the * module. @@ -925,7 +1024,6 @@ ahc_linux_release(struct Scsi_Host * hos struct ahc_softc *ahc; u_long l; - ahc_list_lock(&l); if (host != NULL) { /* @@ -933,19 +1031,23 @@ ahc_linux_release(struct Scsi_Host * hos * the free directly, but check our * list for extra sanity. */ + ahc_list_lock(&l); ahc = ahc_find_softc(*(struct ahc_softc **)host->hostdata); if (ahc != NULL) { u_long s; + TAILQ_REMOVE(&ahc_tailq, ahc, links); + ahc_list_unlock(&l); ahc_lock(ahc, &s); ahc_intr_enable(ahc, FALSE); ahc_unlock(ahc, &s); ahc_free(ahc); - } + } else + ahc_list_unlock(&l); } - ahc_list_unlock(&l); return (0); } +#endif /* * Return a string describing the driver. @@ -982,7 +1084,7 @@ static int ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) { struct ahc_softc *ahc; - struct ahc_linux_device *dev; + struct aic_linux_device *dev; u_long flags; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; @@ -1001,9 +1103,9 @@ ahc_linux_queue(Scsi_Cmnd * cmd, void (* * perform DV. */ if (ahc->platform_data->qfrozen != 0 - && AHC_DV_CMD(cmd) == 0) { + && AIC_DV_CMD(cmd) == 0) { - ahc_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ); + aic_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ); ahc_linux_queue_cmd_complete(ahc, cmd); ahc_schedule_completeq(ahc); ahc_midlayer_entrypoint_unlock(ahc, &flags); @@ -1012,7 +1114,8 @@ ahc_linux_queue(Scsi_Cmnd * cmd, void (* dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id, cmd->device->lun, /*alloc*/TRUE); if (dev == NULL) { - ahc_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL); + + aic_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL); ahc_linux_queue_cmd_complete(ahc, cmd); ahc_schedule_completeq(ahc); ahc_midlayer_entrypoint_unlock(ahc, &flags); @@ -1020,12 +1123,30 @@ ahc_linux_queue(Scsi_Cmnd * cmd, void (* ahc_name(ahc)); return (0); } + + if (cmd->cmd_len > MAX_CDB_LEN) { + + aic_cmd_set_transaction_status(cmd, CAM_REQ_INVALID); + ahc_linux_queue_cmd_complete(ahc, cmd); + ahc_schedule_completeq(ahc); + ahc_midlayer_entrypoint_unlock(ahc, &flags); + printf("%s: aic7xxx_linux_queue -" + "CDB length of %d exceeds max!\n", + ahc_name(ahc), cmd->cmd_len); + return (0); + } + + /* + * We perform our own timeout handling. + */ + scsi_delete_timer(cmd); + cmd->result = CAM_REQ_INPROG << 16; - TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe); - if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { + TAILQ_INSERT_TAIL(&dev->busyq, (struct aic_cmd *)cmd, acmd_links.tqe); + if ((dev->flags & AIC_DEV_ON_RUN_LIST) == 0) { TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links); - dev->flags |= AHC_DEV_ON_RUN_LIST; - ahc_linux_run_device_queues(ahc); + dev->flags |= AIC_DEV_ON_RUN_LIST; + aic_linux_run_device_queues(ahc); } ahc_midlayer_entrypoint_unlock(ahc, &flags); return (0); @@ -1047,7 +1168,7 @@ static int ahc_linux_slave_configure(Scsi_Device *device) { struct ahc_softc *ahc; - struct ahc_linux_device *dev; + struct aic_linux_device *dev; u_long flags; ahc = *((struct ahc_softc **)device->host->hostdata); @@ -1063,9 +1184,9 @@ ahc_linux_slave_configure(Scsi_Device *d device->id, device->lun, /*alloc*/TRUE); if (dev != NULL) { - dev->flags &= ~AHC_DEV_UNCONFIGURED; + dev->flags &= ~AIC_DEV_UNCONFIGURED; dev->scsi_device = device; - ahc_linux_device_queue_depth(ahc, dev); + aic_linux_device_queue_depth(ahc, dev); } ahc_midlayer_entrypoint_unlock(ahc, &flags); return (0); @@ -1075,7 +1196,7 @@ static void ahc_linux_slave_destroy(Scsi_Device *device) { struct ahc_softc *ahc; - struct ahc_linux_device *dev; + struct aic_linux_device *dev; u_long flags; ahc = *((struct ahc_softc **)device->host->hostdata); @@ -1093,11 +1214,10 @@ ahc_linux_slave_destroy(Scsi_Device *dev * the refcounting process. */ if (dev != NULL - && (dev->flags & AHC_DEV_SLAVE_CONFIGURED) != 0) { - dev->flags |= AHC_DEV_UNCONFIGURED; + && (dev->flags & AIC_DEV_SLAVE_CONFIGURED) != 0) { + dev->flags |= AIC_DEV_UNCONFIGURED; if (TAILQ_EMPTY(&dev->busyq) - && dev->active == 0 - && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0) + && dev->active == 0) ahc_linux_free_device(ahc, dev); } ahc_midlayer_entrypoint_unlock(ahc, &flags); @@ -1136,7 +1256,7 @@ ahc_linux_select_queue_depth(struct Scsi continue; if (device->host == host) { - struct ahc_linux_device *dev; + struct aic_linux_device *dev; /* * Since Linux has attached to the device, configure @@ -1147,13 +1267,13 @@ ahc_linux_select_queue_depth(struct Scsi device->id, device->lun, /*alloc*/TRUE); if (dev != NULL) { - dev->flags &= ~AHC_DEV_UNCONFIGURED; + dev->flags &= ~AIC_DEV_UNCONFIGURED; dev->scsi_device = device; - ahc_linux_device_queue_depth(ahc, dev); + aic_linux_device_queue_depth(ahc, dev); device->queue_depth = dev->openings + dev->active; - if ((dev->flags & (AHC_DEV_Q_BASIC - | AHC_DEV_Q_TAGGED)) == 0) { + if ((dev->flags & (AIC_DEV_Q_BASIC + | AIC_DEV_Q_TAGGED)) == 0) { /* * We allow the OS to queue 2 untagged * transactions to us at any time even @@ -1291,63 +1411,8 @@ ahc_linux_bus_reset(Scsi_Cmnd *cmd) return SUCCESS; } -Scsi_Host_Template aic7xxx_driver_template = { - .module = THIS_MODULE, - .name = "aic7xxx", - .proc_info = ahc_linux_proc_info, - .info = ahc_linux_info, - .queuecommand = ahc_linux_queue, - .eh_abort_handler = ahc_linux_abort, - .eh_device_reset_handler = ahc_linux_dev_reset, - .eh_bus_reset_handler = ahc_linux_bus_reset, -#if defined(__i386__) - .bios_param = ahc_linux_biosparam, -#endif - .can_queue = AHC_MAX_QUEUE, - .this_id = -1, - .cmd_per_lun = 2, - .use_clustering = ENABLE_CLUSTERING, - .slave_alloc = ahc_linux_slave_alloc, - .slave_configure = ahc_linux_slave_configure, - .slave_destroy = ahc_linux_slave_destroy, -}; - -/**************************** Tasklet Handler *********************************/ - -/* - * In 2.4.X and above, this routine is called from a tasklet, - * so we must re-acquire our lock prior to executing this code. - * In all prior kernels, ahc_schedule_runq() calls this routine - * directly and ahc_schedule_runq() is called with our lock held. - */ -static void -ahc_runq_tasklet(unsigned long data) -{ - struct ahc_softc* ahc; - struct ahc_linux_device *dev; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - u_long flags; -#endif - - ahc = (struct ahc_softc *)data; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - ahc_lock(ahc, &flags); -#endif - while ((dev = ahc_linux_next_device_to_run(ahc)) != NULL) { - - TAILQ_REMOVE(&ahc->platform_data->device_runq, dev, links); - dev->flags &= ~AHC_DEV_ON_RUN_LIST; - ahc_linux_check_device_queue(ahc, dev); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - /* Yeild to our interrupt handler */ - ahc_unlock(ahc, &flags); - ahc_lock(ahc, &flags); -#endif - } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - ahc_unlock(ahc, &flags); -#endif -} +Scsi_Host_Template aic7xxx_driver_template = + AIC_TEMPLATE_INITIALIZER("aic7xxx", /* max_sectors*/8192); /******************************** Macros **************************************/ #define BUILD_SCSIID(ahc, cmd) \ @@ -1355,132 +1420,6 @@ ahc_runq_tasklet(unsigned long data) | (((cmd)->device->channel == 0) ? (ahc)->our_id : (ahc)->our_id_b) \ | (((cmd)->device->channel == 0) ? 0 : TWIN_CHNLB)) -/******************************** Bus DMA *************************************/ -int -ahc_dma_tag_create(struct ahc_softc *ahc, bus_dma_tag_t parent, - bus_size_t alignment, bus_size_t boundary, - bus_addr_t lowaddr, bus_addr_t highaddr, - bus_dma_filter_t *filter, void *filterarg, - bus_size_t maxsize, int nsegments, - bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag) -{ - bus_dma_tag_t dmat; - - dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT); - if (dmat == NULL) - return (ENOMEM); - - /* - * Linux is very simplistic about DMA memory. For now don't - * maintain all specification information. Once Linux supplies - * better facilities for doing these operations, or the - * needs of this particular driver change, we might need to do - * more here. - */ - dmat->alignment = alignment; - dmat->boundary = boundary; - dmat->maxsize = maxsize; - *ret_tag = dmat; - return (0); -} - -void -ahc_dma_tag_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat) -{ - free(dmat, M_DEVBUF); -} - -int -ahc_dmamem_alloc(struct ahc_softc *ahc, bus_dma_tag_t dmat, void** vaddr, - int flags, bus_dmamap_t *mapp) -{ - bus_dmamap_t map; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT); - if (map == NULL) - return (ENOMEM); - /* - * Although we can dma data above 4GB, our - * "consistent" memory is below 4GB for - * space efficiency reasons (only need a 4byte - * address). For this reason, we have to reset - * our dma mask when doing allocations. - */ - if (ahc->dev_softc != NULL) - ahc_pci_set_dma_mask(ahc->dev_softc, 0xFFFFFFFF); - *vaddr = pci_alloc_consistent(ahc->dev_softc, - dmat->maxsize, &map->bus_addr); - if (ahc->dev_softc != NULL) - ahc_pci_set_dma_mask(ahc->dev_softc, - ahc->platform_data->hw_dma_mask); -#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) */ - /* - * At least in 2.2.14, malloc is a slab allocator so all - * allocations are aligned. We assume for these kernel versions - * that all allocations will be bellow 4Gig, physically contiguous, - * and accessible via DMA by the controller. - */ - map = NULL; /* No additional information to store */ - *vaddr = malloc(dmat->maxsize, M_DEVBUF, M_NOWAIT); -#endif - if (*vaddr == NULL) - return (ENOMEM); - *mapp = map; - return(0); -} - -void -ahc_dmamem_free(struct ahc_softc *ahc, bus_dma_tag_t dmat, - void* vaddr, bus_dmamap_t map) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - pci_free_consistent(ahc->dev_softc, dmat->maxsize, - vaddr, map->bus_addr); -#else - free(vaddr, M_DEVBUF); -#endif -} - -int -ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map, - void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb, - void *cb_arg, int flags) -{ - /* - * Assume for now that this will only be used during - * initialization and not for per-transaction buffer mapping. - */ - bus_dma_segment_t stack_sg; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - stack_sg.ds_addr = map->bus_addr; -#else -#define VIRT_TO_BUS(a) (uint32_t)virt_to_bus((void *)(a)) - stack_sg.ds_addr = VIRT_TO_BUS(buf); -#endif - stack_sg.ds_len = dmat->maxsize; - cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0); - return (0); -} - -void -ahc_dmamap_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map) -{ - /* - * The map may is NULL in our < 2.3.X implementation. - */ - if (map != NULL) - free(map, M_DEVBUF); -} - -int -ahc_dmamap_unload(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map) -{ - /* Nothing to do */ - return (0); -} - /********************* Platform Dependent Functions ***************************/ /* * Compare "left hand" softc with "right hand" softc, returning: @@ -1525,24 +1464,25 @@ ahc_softc_comp(struct ahc_softc *lahc, s /* Still equal. Sort by BIOS address, ioport, or bus/slot/func. */ switch (rvalue) { +#ifdef CONFIG_PCI case AHC_PCI: { char primary_channel; if (aic7xxx_reverse_scan != 0) - value = ahc_get_pci_bus(lahc->dev_softc) - - ahc_get_pci_bus(rahc->dev_softc); + value = aic_get_pci_bus(lahc->dev_softc) + - aic_get_pci_bus(rahc->dev_softc); else - value = ahc_get_pci_bus(rahc->dev_softc) - - ahc_get_pci_bus(lahc->dev_softc); + value = aic_get_pci_bus(rahc->dev_softc) + - aic_get_pci_bus(lahc->dev_softc); if (value != 0) break; if (aic7xxx_reverse_scan != 0) - value = ahc_get_pci_slot(lahc->dev_softc) - - ahc_get_pci_slot(rahc->dev_softc); + value = aic_get_pci_slot(lahc->dev_softc) + - aic_get_pci_slot(rahc->dev_softc); else - value = ahc_get_pci_slot(rahc->dev_softc) - - ahc_get_pci_slot(lahc->dev_softc); + value = aic_get_pci_slot(rahc->dev_softc) + - aic_get_pci_slot(lahc->dev_softc); if (value != 0) break; /* @@ -1557,6 +1497,8 @@ ahc_softc_comp(struct ahc_softc *lahc, s value = 1; break; } +#endif +#ifdef CONFIG_EISA case AHC_EISA: if ((rahc->flags & AHC_BIOS_ENABLED) != 0) { value = rahc->platform_data->bios_address @@ -1566,6 +1508,7 @@ ahc_softc_comp(struct ahc_softc *lahc, s - lahc->bsh.ioport; } break; +#endif default: panic("ahc_softc_sort: invalid bus type"); } @@ -1699,9 +1642,16 @@ ahc_linux_register_host(struct ahc_softc char *new_name; u_long s; u_int targ_offset; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + int error; +#endif template->name = ahc->description; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) host = scsi_host_alloc(template, sizeof(struct ahc_softc *)); +#else + host = scsi_register(template, sizeof(struct ahc_softc *)); +#endif if (host == NULL) return (ENOMEM); @@ -1710,8 +1660,12 @@ ahc_linux_register_host(struct ahc_softc #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_assign_lock(host, &ahc->platform_data->spin_lock); #elif AHC_SCSI_HAS_HOST_LOCK != 0 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,21) + host->host_lock = &ahc->platform_data->spin_lock; +#else host->lock = &ahc->platform_data->spin_lock; #endif +#endif ahc->platform_data->host = host; host->can_queue = AHC_MAX_QUEUE; host->cmd_per_lun = 2; @@ -1736,13 +1690,20 @@ ahc_linux_register_host(struct ahc_softc #endif ahc_linux_initialize_scsi_bus(ahc); ahc_unlock(ahc, &s); + ahc_sysrq_key = aic_install_sysrq(&ahc_sysrq_op); + ahc_spawn_recovery_thread(ahc); + if (ahc->platform_data->recovery_pid < 0) { + printf("%s: Failed to create recovery thread, error= %d\n", + ahc_name(ahc), ahc->platform_data->recovery_pid); + return (-ahc->platform_data->recovery_pid); + } ahc->platform_data->dv_pid = kernel_thread(ahc_linux_dv_thread, ahc, 0); - ahc_lock(ahc, &s); if (ahc->platform_data->dv_pid < 0) { printf("%s: Failed to create DV thread, error= %d\n", ahc_name(ahc), ahc->platform_data->dv_pid); return (-ahc->platform_data->dv_pid); } + ahc_lock(ahc, &s); /* * Initially allocate *all* of our linux target objects * so that the DV thread will scan them all in parallel @@ -1787,7 +1748,9 @@ ahc_linux_register_host(struct ahc_softc ahc_unlock(ahc, &s); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); /* XXX handle failure */ + error = scsi_add_host(host, ahc->dev_softc); + if (error != 0) + return (-error); scsi_scan_host(host); #endif return (0); @@ -1885,17 +1848,6 @@ ahc_linux_initialize_scsi_bus(struct ahc ahc_update_neg_request(ahc, &devinfo, tstate, tinfo, AHC_NEG_ALWAYS); } - /* Give the bus some time to recover */ - if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) { - ahc_linux_freeze_simq(ahc); - init_timer(&ahc->platform_data->reset_timer); - ahc->platform_data->reset_timer.data = (u_long)ahc; - ahc->platform_data->reset_timer.expires = - jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000; - ahc->platform_data->reset_timer.function = - ahc_linux_release_simq; - add_timer(&ahc->platform_data->reset_timer); - } } int @@ -1909,27 +1861,32 @@ ahc_platform_alloc(struct ahc_softc *ahc memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data)); TAILQ_INIT(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->device_runq); - ahc->platform_data->irq = AHC_LINUX_NOIRQ; + ahc->platform_data->irq = AIC_LINUX_NOIRQ; ahc->platform_data->hw_dma_mask = 0xFFFFFFFF; ahc_lockinit(ahc); ahc_done_lockinit(ahc); + init_timer(&ahc->platform_data->bus_settle_timer); + ahc->platform_data->bus_settle_timer.data = (u_long)ahc; + ahc->platform_data->bus_settle_timer.function = + (aic_linux_callback_t *)aic_bus_settle_complete; init_timer(&ahc->platform_data->completeq_timer); ahc->platform_data->completeq_timer.data = (u_long)ahc; ahc->platform_data->completeq_timer.function = - (ahc_linux_callback_t *)ahc_linux_thread_run_complete_queue; + (aic_linux_callback_t *)ahc_linux_thread_run_complete_queue; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) init_MUTEX_LOCKED(&ahc->platform_data->eh_sem); init_MUTEX_LOCKED(&ahc->platform_data->dv_sem); init_MUTEX_LOCKED(&ahc->platform_data->dv_cmd_sem); + init_MUTEX_LOCKED(&ahc->platform_data->recovery_sem); + init_MUTEX_LOCKED(&ahc->platform_data->recovery_ending_sem); #else ahc->platform_data->eh_sem = MUTEX_LOCKED; ahc->platform_data->dv_sem = MUTEX_LOCKED; ahc->platform_data->dv_cmd_sem = MUTEX_LOCKED; + ahc->platform_data->recovery_sem = MUTEX_LOCKED; + ahc->platform_data->recovery_ending_sem = MUTEX_LOCKED; #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - tasklet_init(&ahc->platform_data->runq_tasklet, ahc_runq_tasklet, - (unsigned long)ahc); -#endif + aic_setup_tasklets(ahc); ahc->seltime = (aic7xxx_seltime & 0x3) << 4; ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4; if (aic7xxx_pci_parity == 0) @@ -1941,21 +1898,22 @@ ahc_platform_alloc(struct ahc_softc *ahc void ahc_platform_free(struct ahc_softc *ahc) { - struct ahc_linux_target *targ; - struct ahc_linux_device *dev; + struct aic_linux_target *targ; + struct aic_linux_device *dev; int i, j; + aic_remove_sysrq(ahc_sysrq_key, &ahc_sysrq_op); if (ahc->platform_data != NULL) { del_timer_sync(&ahc->platform_data->completeq_timer); ahc_linux_kill_dv_thread(ahc); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - tasklet_kill(&ahc->platform_data->runq_tasklet); -#endif + aic_teardown_tasklets(ahc); if (ahc->platform_data->host != NULL) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_remove_host(ahc->platform_data->host); -#endif scsi_host_put(ahc->platform_data->host); +#else + scsi_unregister(ahc->platform_data->host); +#endif } /* destroy all of the device and target objects */ @@ -1969,6 +1927,7 @@ ahc_platform_free(struct ahc_softc *ahc) if (targ->devices[j] == NULL) continue; dev = targ->devices[j]; + del_timer_sync(&dev->timer); ahc_linux_free_device(ahc, dev); } /* @@ -1979,7 +1938,7 @@ ahc_platform_free(struct ahc_softc *ahc) } } - if (ahc->platform_data->irq != AHC_LINUX_NOIRQ) + if (ahc->platform_data->irq != AIC_LINUX_NOIRQ) free_irq(ahc->platform_data->irq, ahc); if (ahc->tag == BUS_SPACE_PIO && ahc->bsh.ioport != 0) @@ -2024,7 +1983,7 @@ void ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, ahc_queue_alg alg) { - struct ahc_linux_device *dev; + struct aic_linux_device *dev; int was_queuing; int now_queuing; @@ -2033,27 +1992,27 @@ ahc_platform_set_tags(struct ahc_softc * devinfo->lun, /*alloc*/FALSE); if (dev == NULL) return; - was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); + was_queuing = dev->flags & (AIC_DEV_Q_BASIC|AIC_DEV_Q_TAGGED); switch (alg) { default: case AHC_QUEUE_NONE: now_queuing = 0; break; case AHC_QUEUE_BASIC: - now_queuing = AHC_DEV_Q_BASIC; + now_queuing = AIC_DEV_Q_BASIC; break; case AHC_QUEUE_TAGGED: - now_queuing = AHC_DEV_Q_TAGGED; + now_queuing = AIC_DEV_Q_TAGGED; break; } - if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0 + if ((dev->flags & AIC_DEV_FREEZE_TIL_EMPTY) == 0 && (was_queuing != now_queuing) && (dev->active != 0)) { - dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY; + dev->flags |= AIC_DEV_FREEZE_TIL_EMPTY; dev->qfrozen++; } - dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED|AHC_DEV_PERIODIC_OTAG); + dev->flags &= ~(AIC_DEV_Q_BASIC|AIC_DEV_Q_TAGGED|AIC_DEV_PERIODIC_OTAG); if (now_queuing) { u_int usertags; @@ -2073,11 +2032,11 @@ ahc_platform_set_tags(struct ahc_softc * */ dev->openings = 1; } else if (alg == AHC_QUEUE_TAGGED) { - dev->flags |= AHC_DEV_Q_TAGGED; + dev->flags |= AIC_DEV_Q_TAGGED; if (aic7xxx_periodic_otag != 0) - dev->flags |= AHC_DEV_PERIODIC_OTAG; + dev->flags |= AIC_DEV_PERIODIC_OTAG; } else - dev->flags |= AHC_DEV_Q_BASIC; + dev->flags |= AIC_DEV_Q_BASIC; } else { /* We can only have one opening. */ dev->maxtags = 0; @@ -2085,13 +2044,13 @@ ahc_platform_set_tags(struct ahc_softc * } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) if (dev->scsi_device != NULL) { - switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) { - case AHC_DEV_Q_BASIC: + switch ((dev->flags & (AIC_DEV_Q_BASIC|AIC_DEV_Q_TAGGED))) { + case AIC_DEV_Q_BASIC: scsi_adjust_queue_depth(dev->scsi_device, MSG_SIMPLE_TASK, dev->openings + dev->active); break; - case AHC_DEV_Q_TAGGED: + case AIC_DEV_Q_TAGGED: scsi_adjust_queue_depth(dev->scsi_device, MSG_ORDERED_TASK, dev->openings + dev->active); @@ -2155,9 +2114,9 @@ ahc_platform_abort_scbs(struct ahc_softc for (; targ < maxtarg; targ++) { for (; clun < maxlun; clun++) { - struct ahc_linux_device *dev; - struct ahc_busyq *busyq; - struct ahc_cmd *acmd; + struct aic_linux_device *dev; + struct aic_busyq *busyq; + struct aic_cmd *acmd; dev = ahc_linux_get_device(ahc, chan, targ, clun, @@ -2174,6 +2133,20 @@ ahc_platform_abort_scbs(struct ahc_softc acmd_links.tqe); count++; cmd->result = status << 16; + /* + * The completion handler believes that + * commands without active timers + * running have lost the race of + * completing before their timer + * expires. Since commands in our + * busy queues do not have timers + * running, appease the mid-layer by + * adding a timer now. This timer will + * be immediately canceled by the + * midlayer. + */ + scsi_add_timer(cmd, 60*HZ, + aic_linux_midlayer_timeout); ahc_linux_queue_cmd_complete(ahc, cmd); } } @@ -2190,7 +2163,7 @@ ahc_linux_thread_run_complete_queue(stru ahc_lock(ahc, &flags); del_timer(&ahc->platform_data->completeq_timer); - ahc->platform_data->flags &= ~AHC_RUN_CMPLT_Q_TIMER; + ahc->platform_data->flags &= ~AIC_RUN_CMPLT_Q_TIMER; ahc_linux_run_complete_queue(ahc); ahc_unlock(ahc, &flags); } @@ -2203,14 +2176,23 @@ ahc_linux_start_dv(struct ahc_softc *ahc * Freeze the simq and signal ahc_linux_queue to not let any * more commands through. */ - if ((ahc->platform_data->flags & AHC_DV_ACTIVE) == 0) { + if ((ahc->platform_data->flags & AIC_DV_ACTIVE) == 0) { #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_DV) printf("%s: Waking DV thread\n", ahc_name(ahc)); #endif - ahc->platform_data->flags |= AHC_DV_ACTIVE; - ahc_linux_freeze_simq(ahc); + ahc->platform_data->flags |= AIC_DV_ACTIVE; + + /* + * Prevent upper layer from sending any + * commands to us. + */ + aic_freeze_simq(ahc); + scsi_block_requests(ahc->platform_data->host); + ahc_platform_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS, + CAM_LUN_WILDCARD, SCB_LIST_NULL, + ROLE_INITIATOR, CAM_REQUEUE_REQ); /* Wake up the DV kthread */ up(&ahc->platform_data->dv_sem); @@ -2224,7 +2206,7 @@ ahc_linux_kill_dv_thread(struct ahc_soft ahc_lock(ahc, &s); if (ahc->platform_data->dv_pid != 0) { - ahc->platform_data->flags |= AHC_DV_SHUTDOWN; + ahc->platform_data->flags |= AIC_DV_SHUTDOWN; ahc_unlock(ahc, &s); up(&ahc->platform_data->dv_sem); @@ -2299,7 +2281,7 @@ ahc_linux_dv_thread(void *data) /* Check to see if we've been signaled to exit */ ahc_lock(ahc, &s); - if ((ahc->platform_data->flags & AHC_DV_SHUTDOWN) != 0) { + if ((ahc->platform_data->flags & AIC_DV_SHUTDOWN) != 0) { ahc_unlock(ahc, &s); break; } @@ -2316,7 +2298,7 @@ ahc_linux_dv_thread(void *data) */ ahc_lock(ahc, &s); while (LIST_FIRST(&ahc->pending_scbs) != NULL) { - ahc->platform_data->flags |= AHC_DV_WAIT_SIMQ_EMPTY; + ahc->platform_data->flags |= AIC_DV_WAIT_SIMQ_EMPTY; ahc_unlock(ahc, &s); down_interruptible(&ahc->platform_data->dv_sem); ahc_lock(ahc, &s); @@ -2326,8 +2308,8 @@ ahc_linux_dv_thread(void *data) * Wait for the SIMQ to be released so that DV is the * only reason the queue is frozen. */ - while (AHC_DV_SIMQ_FROZEN(ahc) == 0) { - ahc->platform_data->flags |= AHC_DV_WAIT_SIMQ_RELEASE; + while (AIC_DV_SIMQ_FROZEN(ahc) == 0) { + ahc->platform_data->flags |= AIC_DV_WAIT_SIMQ_RELEASE; ahc_unlock(ahc, &s); down_interruptible(&ahc->platform_data->dv_sem); ahc_lock(ahc, &s); @@ -2338,14 +2320,16 @@ ahc_linux_dv_thread(void *data) ahc_linux_dv_target(ahc, target); ahc_lock(ahc, &s); - ahc->platform_data->flags &= ~AHC_DV_ACTIVE; - ahc_unlock(ahc, &s); + ahc->platform_data->flags &= ~AIC_DV_ACTIVE; /* * Release the SIMQ so that normal commands are * allowed to continue on the bus. */ - ahc_linux_release_simq((u_long)ahc); + aic_release_simq_locked(ahc); + ahc_unlock(ahc, &s); + + scsi_unblock_requests(ahc->platform_data->host); } up(&ahc->platform_data->eh_sem); return (0); @@ -2359,10 +2343,10 @@ ahc_linux_dv_thread(void *data) ahc_set_dv_state(ahc, targ, newstate, __LINE__) static __inline void -ahc_set_dv_state(struct ahc_softc *ahc, struct ahc_linux_target *targ, - ahc_dv_state newstate, u_int line) +ahc_set_dv_state(struct ahc_softc *ahc, struct aic_linux_target *targ, + aic_dv_state newstate, u_int line) { - ahc_dv_state oldstate; + aic_dv_state oldstate; oldstate = targ->dv_state; #ifdef AHC_DEBUG @@ -2382,7 +2366,7 @@ static void ahc_linux_dv_target(struct ahc_softc *ahc, u_int target_offset) { struct ahc_devinfo devinfo; - struct ahc_linux_target *targ; + struct aic_linux_target *targ; struct scsi_cmnd *cmd; struct scsi_device *scsi_dev; struct scsi_sense_data *sense; @@ -2396,7 +2380,7 @@ ahc_linux_dv_target(struct ahc_softc *ah echo_size = 0; ahc_lock(ahc, &s); targ = ahc->platform_data->targets[target_offset]; - if (targ == NULL || (targ->flags & AHC_DV_REQUIRED) == 0) { + if (targ == NULL || (targ->flags & AIC_DV_REQUIRED) == 0) { ahc_unlock(ahc, &s); return; } @@ -2421,14 +2405,14 @@ ahc_linux_dv_target(struct ahc_softc *ah scsi_dev->channel = devinfo.channel - 'A'; ahc->platform_data->dv_scsi_dev = scsi_dev; - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_INQ_SHORT_ASYNC); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_INQ_SHORT_ASYNC); - while (targ->dv_state != AHC_DV_STATE_EXIT) { + while (targ->dv_state != AIC_DV_STATE_EXIT) { timeout = AHC_LINUX_DV_TIMEOUT; switch (targ->dv_state) { - case AHC_DV_STATE_INQ_SHORT_ASYNC: - case AHC_DV_STATE_INQ_ASYNC: - case AHC_DV_STATE_INQ_ASYNC_VERIFY: + case AIC_DV_STATE_INQ_SHORT_ASYNC: + case AIC_DV_STATE_INQ_ASYNC: + case AIC_DV_STATE_INQ_ASYNC_VERIFY: /* * Set things to async narrow to reduce the * chance that the INQ will fail. @@ -2440,36 +2424,36 @@ ahc_linux_dv_target(struct ahc_softc *ah AHC_TRANS_GOAL, /*paused*/FALSE); ahc_unlock(ahc, &s); timeout = 10 * HZ; - targ->flags &= ~AHC_INQ_VALID; + targ->flags &= ~AIC_INQ_VALID; /* FALLTHROUGH */ - case AHC_DV_STATE_INQ_VERIFY: + case AIC_DV_STATE_INQ_VERIFY: { u_int inq_len; - if (targ->dv_state == AHC_DV_STATE_INQ_SHORT_ASYNC) + if (targ->dv_state == AIC_DV_STATE_INQ_SHORT_ASYNC) inq_len = AHC_LINUX_DV_INQ_SHORT_LEN; else inq_len = targ->inq_data->additional_length + 5; ahc_linux_dv_inq(ahc, cmd, &devinfo, targ, inq_len); break; } - case AHC_DV_STATE_TUR: - case AHC_DV_STATE_BUSY: + case AIC_DV_STATE_TUR: + case AIC_DV_STATE_BUSY: timeout = 5 * HZ; ahc_linux_dv_tur(ahc, cmd, &devinfo); break; - case AHC_DV_STATE_REBD: + case AIC_DV_STATE_REBD: ahc_linux_dv_rebd(ahc, cmd, &devinfo, targ); break; - case AHC_DV_STATE_WEB: + case AIC_DV_STATE_WEB: ahc_linux_dv_web(ahc, cmd, &devinfo, targ); break; - case AHC_DV_STATE_REB: + case AIC_DV_STATE_REB: ahc_linux_dv_reb(ahc, cmd, &devinfo, targ); break; - case AHC_DV_STATE_SU: + case AIC_DV_STATE_SU: ahc_linux_dv_su(ahc, cmd, &devinfo, targ); timeout = 50 * HZ; break; @@ -2481,8 +2465,6 @@ ahc_linux_dv_target(struct ahc_softc *ah } /* Queue the command and wait for it to complete */ - /* Abuse eh_timeout in the scsi_cmnd struct for our purposes */ - init_timer(&cmd->eh_timeout); #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) /* @@ -2492,7 +2474,9 @@ ahc_linux_dv_target(struct ahc_softc *ah */ timeout += HZ; #endif - scsi_add_timer(cmd, timeout, ahc_linux_dv_timeout); + init_timer(&cmd->eh_timeout); + cmd->timeout_per_command = timeout; + /* * In 2.5.X, it is assumed that all calls from the * "midlayer" (which we are emulating) will have the @@ -2516,8 +2500,8 @@ ahc_linux_dv_target(struct ahc_softc *ah * only reason the queue is frozen. */ ahc_lock(ahc, &s); - while (AHC_DV_SIMQ_FROZEN(ahc) == 0) { - ahc->platform_data->flags |= AHC_DV_WAIT_SIMQ_RELEASE; + while (AIC_DV_SIMQ_FROZEN(ahc) == 0) { + ahc->platform_data->flags |= AIC_DV_WAIT_SIMQ_RELEASE; ahc_unlock(ahc, &s); down_interruptible(&ahc->platform_data->dv_sem); ahc_lock(ahc, &s); @@ -2528,7 +2512,7 @@ ahc_linux_dv_target(struct ahc_softc *ah } out: - if ((targ->flags & AHC_INQ_VALID) != 0 + if ((targ->flags & AIC_INQ_VALID) != 0 && ahc_linux_get_device(ahc, devinfo.channel - 'A', devinfo.target, devinfo.lun, /*alloc*/FALSE) == NULL) { @@ -2539,7 +2523,7 @@ out: * parameters found in the inquiry string. */ ahc_linux_filter_inquiry(ahc, &devinfo); - if ((targ->flags & (AHC_BASIC_DV|AHC_ENHANCED_DV)) != 0) { + if ((targ->flags & (AIC_BASIC_DV|AIC_ENHANCED_DV)) != 0) { ahc_print_devinfo(ahc, &devinfo); printf("DV failed to configure device. " "Please file a bug report against " @@ -2564,7 +2548,7 @@ out: free(targ->dv_buffer1, M_DEVBUF); targ->dv_buffer1 = NULL; } - targ->flags &= ~AHC_DV_REQUIRED; + targ->flags &= ~AIC_DV_REQUIRED; if (targ->refcount == 0) ahc_linux_free_target(ahc, targ); ahc_unlock(ahc, &s); @@ -2573,13 +2557,13 @@ out: static void ahc_linux_dv_transition(struct ahc_softc *ahc, struct scsi_cmnd *cmd, struct ahc_devinfo *devinfo, - struct ahc_linux_target *targ) + struct aic_linux_target *targ) { u_int32_t status; status = aic_error_action(cmd, targ->inq_data, - ahc_cmd_get_transaction_status(cmd), - ahc_cmd_get_scsi_status(cmd)); + aic_cmd_get_transaction_status(cmd), + aic_cmd_get_scsi_status(cmd)); #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_DV) { @@ -2591,8 +2575,8 @@ ahc_linux_dv_transition(struct ahc_softc #endif switch (targ->dv_state) { - case AHC_DV_STATE_INQ_SHORT_ASYNC: - case AHC_DV_STATE_INQ_ASYNC: + case AIC_DV_STATE_INQ_SHORT_ASYNC: + case AIC_DV_STATE_INQ_ASYNC: switch (status & SS_MASK) { case SS_NOP: { @@ -2601,21 +2585,21 @@ ahc_linux_dv_transition(struct ahc_softc } case SS_INQ_REFRESH: AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; case SS_TUR: case SS_RETRY: AHC_SET_DV_STATE(ahc, targ, targ->dv_state); - if (ahc_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) targ->dv_state_retry--; if ((status & SS_ERRMASK) == EBUSY) - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_BUSY); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_BUSY); if (targ->dv_state_retry < 10) break; /* FALLTHROUGH */ default: - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_DV) { ahc_print_devinfo(ahc, devinfo); @@ -2625,7 +2609,7 @@ ahc_linux_dv_transition(struct ahc_softc break; } break; - case AHC_DV_STATE_INQ_ASYNC_VERIFY: + case AIC_DV_STATE_INQ_ASYNC_VERIFY: switch (status & SS_MASK) { case SS_NOP: { @@ -2639,12 +2623,12 @@ ahc_linux_dv_transition(struct ahc_softc * Try from the top again. */ AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; } AHC_SET_DV_STATE(ahc, targ, targ->dv_state+1); - targ->flags |= AHC_INQ_VALID; + targ->flags |= AIC_INQ_VALID; if (ahc_linux_user_dv_setting(ahc) == 0) break; @@ -2657,33 +2641,33 @@ ahc_linux_dv_transition(struct ahc_softc default: case SID_SPI_CLOCK_ST: /* Assume only basic DV is supported. */ - targ->flags |= AHC_BASIC_DV; + targ->flags |= AIC_BASIC_DV; break; case SID_SPI_CLOCK_DT: case SID_SPI_CLOCK_DT_ST: - targ->flags |= AHC_ENHANCED_DV; + targ->flags |= AIC_ENHANCED_DV; break; } break; } case SS_INQ_REFRESH: AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; case SS_TUR: case SS_RETRY: AHC_SET_DV_STATE(ahc, targ, targ->dv_state); - if (ahc_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) targ->dv_state_retry--; if ((status & SS_ERRMASK) == EBUSY) - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_BUSY); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_BUSY); if (targ->dv_state_retry < 10) break; /* FALLTHROUGH */ default: - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_DV) { ahc_print_devinfo(ahc, devinfo); @@ -2693,14 +2677,14 @@ ahc_linux_dv_transition(struct ahc_softc break; } break; - case AHC_DV_STATE_INQ_VERIFY: + case AIC_DV_STATE_INQ_VERIFY: switch (status & SS_MASK) { case SS_NOP: { if (memcmp(targ->inq_data, targ->dv_buffer, AHC_LINUX_DV_INQ_LEN) == 0) { - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); break; } #ifdef AHC_DEBUG @@ -2721,7 +2705,7 @@ ahc_linux_dv_transition(struct ahc_softc #endif if (ahc_linux_fallback(ahc, devinfo) != 0) { - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); break; } /* @@ -2734,18 +2718,18 @@ ahc_linux_dv_transition(struct ahc_softc } case SS_INQ_REFRESH: AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; case SS_TUR: case SS_RETRY: AHC_SET_DV_STATE(ahc, targ, targ->dv_state); - if (ahc_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) { targ->dv_state_retry--; } else if ((status & SSQ_FALLBACK) != 0) { if (ahc_linux_fallback(ahc, devinfo) != 0) { AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_EXIT); + AIC_DV_STATE_EXIT); break; } /* @@ -2754,12 +2738,12 @@ ahc_linux_dv_transition(struct ahc_softc */ targ->dv_state_retry = 0; } else if ((status & SS_ERRMASK) == EBUSY) - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_BUSY); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_BUSY); if (targ->dv_state_retry < 10) break; /* FALLTHROUGH */ default: - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_DV) { ahc_print_devinfo(ahc, devinfo); @@ -2770,33 +2754,33 @@ ahc_linux_dv_transition(struct ahc_softc } break; - case AHC_DV_STATE_TUR: + case AIC_DV_STATE_TUR: switch (status & SS_MASK) { case SS_NOP: - if ((targ->flags & AHC_BASIC_DV) != 0) { + if ((targ->flags & AIC_BASIC_DV) != 0) { ahc_linux_filter_inquiry(ahc, devinfo); AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_INQ_VERIFY); - } else if ((targ->flags & AHC_ENHANCED_DV) != 0) { - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_REBD); + AIC_DV_STATE_INQ_VERIFY); + } else if ((targ->flags & AIC_ENHANCED_DV) != 0) { + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_REBD); } else { - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); } break; case SS_RETRY: case SS_TUR: if ((status & SS_ERRMASK) == EBUSY) { - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_BUSY); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_BUSY); break; } AHC_SET_DV_STATE(ahc, targ, targ->dv_state); - if (ahc_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) { targ->dv_state_retry--; } else if ((status & SSQ_FALLBACK) != 0) { if (ahc_linux_fallback(ahc, devinfo) != 0) { AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_EXIT); + AIC_DV_STATE_EXIT); break; } /* @@ -2812,7 +2796,7 @@ ahc_linux_dv_transition(struct ahc_softc printf("DV TUR reties exhausted\n"); } #endif - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); break; } if (status & SSQ_DELAY) @@ -2820,25 +2804,25 @@ ahc_linux_dv_transition(struct ahc_softc break; case SS_START: - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_SU); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_SU); break; case SS_INQ_REFRESH: AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; default: - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); break; } break; - case AHC_DV_STATE_REBD: + case AIC_DV_STATE_REBD: switch (status & SS_MASK) { case SS_NOP: { uint32_t echo_size; - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_WEB); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_WEB); echo_size = scsi_3btoul(&targ->dv_buffer[1]); echo_size &= 0x1FFF; #ifdef AHC_DEBUG @@ -2848,7 +2832,17 @@ ahc_linux_dv_transition(struct ahc_softc } #endif if (echo_size == 0) { - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + /* + * Fall back to basic DV. + */ + if (bootverbose) { + ahc_print_devinfo(ahc, devinfo); + printf("Echo Buffer unavailable. " + "Performing basic DV.\n"); + } + targ->flags &= ~AIC_ENHANCED_DV; + targ->flags |= AIC_BASIC_DV; + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_TUR); break; } @@ -2863,11 +2857,11 @@ ahc_linux_dv_transition(struct ahc_softc } case SS_INQ_REFRESH: AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; case SS_RETRY: AHC_SET_DV_STATE(ahc, targ, targ->dv_state); - if (ahc_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) targ->dv_state_retry--; if (targ->dv_state_retry <= 10) @@ -2886,30 +2880,30 @@ ahc_linux_dv_transition(struct ahc_softc * and try level 1 DV. */ ahc_linux_filter_inquiry(ahc, devinfo); - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_INQ_VERIFY); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_INQ_VERIFY); targ->dv_echo_size = 0; break; } break; - case AHC_DV_STATE_WEB: + case AIC_DV_STATE_WEB: switch (status & SS_MASK) { case SS_NOP: - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_REB); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_REB); break; case SS_INQ_REFRESH: AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; case SS_RETRY: AHC_SET_DV_STATE(ahc, targ, targ->dv_state); - if (ahc_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) { targ->dv_state_retry--; } else if ((status & SSQ_FALLBACK) != 0) { if (ahc_linux_fallback(ahc, devinfo) != 0) { AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_EXIT); + AIC_DV_STATE_EXIT); break; } /* @@ -2928,22 +2922,22 @@ ahc_linux_dv_transition(struct ahc_softc } #endif default: - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); break; } break; - case AHC_DV_STATE_REB: + case AIC_DV_STATE_REB: switch (status & SS_MASK) { case SS_NOP: if (memcmp(targ->dv_buffer, targ->dv_buffer1, targ->dv_echo_size) != 0) { if (ahc_linux_fallback(ahc, devinfo) != 0) AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_EXIT); + AIC_DV_STATE_EXIT); else AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_WEB); + AIC_DV_STATE_WEB); break; } @@ -2955,24 +2949,24 @@ ahc_linux_dv_transition(struct ahc_softc free(targ->dv_buffer1, M_DEVBUF); targ->dv_buffer1 = NULL; } - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); break; case SS_INQ_REFRESH: AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; case SS_RETRY: AHC_SET_DV_STATE(ahc, targ, targ->dv_state); - if (ahc_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) { targ->dv_state_retry--; } else if ((status & SSQ_FALLBACK) != 0) { if (ahc_linux_fallback(ahc, devinfo) != 0) { AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_EXIT); + AIC_DV_STATE_EXIT); break; } - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_WEB); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_WEB); } if (targ->dv_state_retry <= 10) { if ((status & (SSQ_DELAY_RANDOM|SSQ_DELAY))!= 0) @@ -2987,35 +2981,35 @@ ahc_linux_dv_transition(struct ahc_softc #endif /* FALLTHROUGH */ default: - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); break; } break; - case AHC_DV_STATE_SU: + case AIC_DV_STATE_SU: switch (status & SS_MASK) { case SS_NOP: case SS_INQ_REFRESH: AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; default: - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); break; } break; - case AHC_DV_STATE_BUSY: + case AIC_DV_STATE_BUSY: switch (status & SS_MASK) { case SS_NOP: case SS_INQ_REFRESH: AHC_SET_DV_STATE(ahc, targ, - AHC_DV_STATE_INQ_SHORT_ASYNC); + AIC_DV_STATE_INQ_SHORT_ASYNC); break; case SS_TUR: case SS_RETRY: AHC_SET_DV_STATE(ahc, targ, targ->dv_state); - if (ahc_cmd_get_transaction_status(cmd) + if (aic_cmd_get_transaction_status(cmd) == CAM_REQUEUE_REQ) { targ->dv_state_retry--; } else if (targ->dv_state_retry < 60) { @@ -3028,11 +3022,11 @@ ahc_linux_dv_transition(struct ahc_softc printf("DV BUSY reties exhausted\n"); } #endif - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); } break; default: - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); break; } break; @@ -3040,7 +3034,7 @@ ahc_linux_dv_transition(struct ahc_softc default: printf("%s: Invalid DV completion state %d\n", ahc_name(ahc), targ->dv_state); - AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT); + AHC_SET_DV_STATE(ahc, targ, AIC_DV_STATE_EXIT); break; } } @@ -3060,7 +3054,7 @@ ahc_linux_dv_fill_cmd(struct ahc_softc * */ static void ahc_linux_dv_inq(struct ahc_softc *ahc, struct scsi_cmnd *cmd, - struct ahc_devinfo *devinfo, struct ahc_linux_target *targ, + struct ahc_devinfo *devinfo, struct aic_linux_target *targ, u_int request_length) { @@ -3073,7 +3067,7 @@ ahc_linux_dv_inq(struct ahc_softc *ahc, if (targ->inq_data == NULL) targ->inq_data = malloc(AHC_LINUX_DV_INQ_LEN, M_DEVBUF, M_WAITOK); - if (targ->dv_state > AHC_DV_STATE_INQ_ASYNC) { + if (targ->dv_state > AIC_DV_STATE_INQ_ASYNC) { if (targ->dv_buffer != NULL) free(targ->dv_buffer, M_DEVBUF); targ->dv_buffer = malloc(AHC_LINUX_DV_INQ_LEN, @@ -3086,7 +3080,7 @@ ahc_linux_dv_inq(struct ahc_softc *ahc, cmd->cmnd[0] = INQUIRY; cmd->cmnd[4] = request_length; cmd->request_bufflen = request_length; - if (targ->dv_state > AHC_DV_STATE_INQ_ASYNC) + if (targ->dv_state > AIC_DV_STATE_INQ_ASYNC) cmd->request_buffer = targ->dv_buffer; else cmd->request_buffer = targ->inq_data; @@ -3115,7 +3109,7 @@ ahc_linux_dv_tur(struct ahc_softc *ahc, static void ahc_linux_dv_rebd(struct ahc_softc *ahc, struct scsi_cmnd *cmd, - struct ahc_devinfo *devinfo, struct ahc_linux_target *targ) + struct ahc_devinfo *devinfo, struct aic_linux_target *targ) { #ifdef AHC_DEBUG @@ -3140,7 +3134,7 @@ ahc_linux_dv_rebd(struct ahc_softc *ahc, static void ahc_linux_dv_web(struct ahc_softc *ahc, struct scsi_cmnd *cmd, - struct ahc_devinfo *devinfo, struct ahc_linux_target *targ) + struct ahc_devinfo *devinfo, struct aic_linux_target *targ) { #ifdef AHC_DEBUG @@ -3162,7 +3156,7 @@ ahc_linux_dv_web(struct ahc_softc *ahc, static void ahc_linux_dv_reb(struct ahc_softc *ahc, struct scsi_cmnd *cmd, - struct ahc_devinfo *devinfo, struct ahc_linux_target *targ) + struct ahc_devinfo *devinfo, struct aic_linux_target *targ) { #ifdef AHC_DEBUG @@ -3185,7 +3179,7 @@ ahc_linux_dv_reb(struct ahc_softc *ahc, static void ahc_linux_dv_su(struct ahc_softc *ahc, struct scsi_cmnd *cmd, struct ahc_devinfo *devinfo, - struct ahc_linux_target *targ) + struct aic_linux_target *targ) { u_int le; @@ -3207,7 +3201,7 @@ ahc_linux_dv_su(struct ahc_softc *ahc, s static int ahc_linux_fallback(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) { - struct ahc_linux_target *targ; + struct aic_linux_target *targ; struct ahc_initiator_tinfo *tinfo; struct ahc_transinfo *goal; struct ahc_tmode_tstate *tstate; @@ -3386,7 +3380,7 @@ ahc_linux_fallback(struct ahc_softc *ahc return (0); } -static void +void ahc_linux_dv_timeout(struct scsi_cmnd *cmd) { struct ahc_softc *ahc; @@ -3420,29 +3414,19 @@ ahc_linux_dv_timeout(struct scsi_cmnd *c * error code. */ if ((scb->flags & SCB_SENSE) != 0) - ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); + aic_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); else - ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT); + aic_set_transaction_status(scb, CAM_CMD_TIMEOUT); ahc_reset_channel(ahc, cmd->device->channel + 'A', /*initiate*/TRUE); - /* - * Add a minimal bus settle delay for devices that are slow to - * respond after bus resets. - */ - ahc_linux_freeze_simq(ahc); - init_timer(&ahc->platform_data->reset_timer); - ahc->platform_data->reset_timer.data = (u_long)ahc; - ahc->platform_data->reset_timer.expires = jiffies + HZ / 2; - ahc->platform_data->reset_timer.function = - (ahc_linux_callback_t *)ahc_linux_release_simq; - add_timer(&ahc->platform_data->reset_timer); - if (ahc_linux_next_device_to_run(ahc) != NULL) - ahc_schedule_runq(ahc); + if (aic_linux_next_device_to_run(ahc) != NULL) + aic_schedule_runq(ahc); + ahc_linux_run_complete_queue(ahc); ahc_unlock(ahc, &flags); } -static void +void ahc_linux_dv_complete(struct scsi_cmnd *cmd) { struct ahc_softc *ahc; @@ -3464,7 +3448,7 @@ ahc_linux_dv_complete(struct scsi_cmnd * } static void -ahc_linux_generate_dv_pattern(struct ahc_linux_target *targ) +ahc_linux_generate_dv_pattern(struct aic_linux_target *targ) { uint16_t b; u_int i; @@ -3596,8 +3580,8 @@ ahc_linux_user_dv_setting(struct ahc_sof * Determines the queue depth for a given device. */ static void -ahc_linux_device_queue_depth(struct ahc_softc *ahc, - struct ahc_linux_device *dev) +aic_linux_device_queue_depth(struct ahc_softc *ahc, + struct aic_linux_device *dev) { struct ahc_devinfo devinfo; u_int tags; @@ -3621,10 +3605,10 @@ ahc_linux_device_queue_depth(struct ahc_ } } -static void -ahc_linux_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev) +void +ahc_linux_run_device_queue(struct ahc_softc *ahc, struct aic_linux_device *dev) { - struct ahc_cmd *acmd; + struct aic_cmd *acmd; struct scsi_cmnd *cmd; struct scb *scb; struct hardware_scb *hscb; @@ -3632,7 +3616,7 @@ ahc_linux_run_device_queue(struct ahc_so struct ahc_tmode_tstate *tstate; uint16_t mask; - if ((dev->flags & AHC_DEV_ON_RUN_LIST) != 0) + if ((dev->flags & AIC_DEV_ON_RUN_LIST) != 0) panic("running device on run list"); while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL @@ -3643,10 +3627,10 @@ ahc_linux_run_device_queue(struct ahc_so * running is because the whole controller Q is frozen. */ if (ahc->platform_data->qfrozen != 0 - && AHC_DV_SIMQ_FROZEN(ahc) == 0) { + && AIC_DV_SIMQ_FROZEN(ahc) == 0) { TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links); - dev->flags |= AHC_DEV_ON_RUN_LIST; + dev->flags |= AIC_DEV_ON_RUN_LIST; return; } /* @@ -3655,7 +3639,7 @@ ahc_linux_run_device_queue(struct ahc_so if ((scb = ahc_get_scb(ahc)) == NULL) { TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links); - dev->flags |= AHC_DEV_ON_RUN_LIST; + dev->flags |= AIC_DEV_ON_RUN_LIST; ahc->flags |= AHC_RESOURCE_SHORTAGE; return; } @@ -3663,6 +3647,7 @@ ahc_linux_run_device_queue(struct ahc_so cmd = &acmd_scsi_cmd(acmd); scb->io_ctx = cmd; scb->platform_data->dev = dev; + scb->platform_data->flags = 0; hscb = scb->hscb; cmd->host_scribble = (char *)scb; @@ -3684,7 +3669,7 @@ ahc_linux_run_device_queue(struct ahc_so if ((ahc->user_discenable & mask) != 0) hscb->control |= DISCENB; - if (AHC_DV_CMD(cmd) != 0) + if (AIC_DV_CMD(cmd) != 0) scb->flags |= SCB_SILENT; if ((tstate->auto_negotiate & mask) != 0) { @@ -3692,7 +3677,7 @@ ahc_linux_run_device_queue(struct ahc_so scb->hscb->control |= MK_MESSAGE; } - if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) { + if ((dev->flags & (AIC_DEV_Q_TAGGED|AIC_DEV_Q_BASIC)) != 0) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) int msg_bytes; uint8_t tag_msgs[2]; @@ -3704,8 +3689,8 @@ ahc_linux_run_device_queue(struct ahc_so dev->commands_since_idle_or_otag = 0; } else #endif - if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH - && (dev->flags & AHC_DEV_Q_TAGGED) != 0) { + if (dev->commands_since_idle_or_otag == AIC_OTAG_THRESH + && (dev->flags & AIC_DEV_Q_TAGGED) != 0) { hscb->control |= MSG_ORDERED_TASK; dev->commands_since_idle_or_otag = 0; } else { @@ -3722,8 +3707,8 @@ ahc_linux_run_device_queue(struct ahc_so } scb->platform_data->xfer_len = 0; - ahc_set_residual(scb, 0); - ahc_set_sense_residual(scb, 0); + aic_set_residual(scb, 0); + aic_set_sense_residual(scb, 0); scb->sg_count = 0; if (cmd->use_sg != 0) { struct ahc_dma_seg *sg; @@ -3732,7 +3717,7 @@ ahc_linux_run_device_queue(struct ahc_so int nseg; cur_seg = (struct scatterlist *)cmd->request_buffer; - nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg, + nseg = aic_map_sg(ahc, cur_seg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction)); end_seg = cur_seg + nseg; /* Copy the segments into the SG list. */ @@ -3755,13 +3740,13 @@ ahc_linux_run_device_queue(struct ahc_so cur_seg++; } sg--; - sg->len |= ahc_htole32(AHC_DMA_LAST_SEG); + sg->len |= aic_htole32(AHC_DMA_LAST_SEG); /* * Reset the sg list pointer. */ scb->hscb->sgptr = - ahc_htole32(scb->sg_list_phys | SG_FULL_RESID); + aic_htole32(scb->sg_list_phys | SG_FULL_RESID); /* * Copy the first SG into the "current" @@ -3774,7 +3759,7 @@ ahc_linux_run_device_queue(struct ahc_so bus_addr_t addr; sg = scb->sg_list; - addr = pci_map_single(ahc->dev_softc, + addr = aic_map_single(ahc, cmd->request_buffer, cmd->request_bufflen, scsi_to_pci_dma_dir(cmd->sc_data_direction)); @@ -3782,13 +3767,13 @@ ahc_linux_run_device_queue(struct ahc_so scb->sg_count = ahc_linux_map_seg(ahc, scb, sg, addr, cmd->request_bufflen); - sg->len |= ahc_htole32(AHC_DMA_LAST_SEG); + sg->len |= aic_htole32(AHC_DMA_LAST_SEG); /* * Reset the sg list pointer. */ scb->hscb->sgptr = - ahc_htole32(scb->sg_list_phys | SG_FULL_RESID); + aic_htole32(scb->sg_list_phys | SG_FULL_RESID); /* * Copy the first SG into the "current" @@ -3797,7 +3782,7 @@ ahc_linux_run_device_queue(struct ahc_so scb->hscb->dataptr = sg->addr; scb->hscb->datacnt = sg->len; } else { - scb->hscb->sgptr = ahc_htole32(SG_LIST_NULL); + scb->hscb->sgptr = aic_htole32(SG_LIST_NULL); scb->hscb->dataptr = 0; scb->hscb->datacnt = 0; scb->sg_count = 0; @@ -3808,7 +3793,7 @@ ahc_linux_run_device_queue(struct ahc_so dev->openings--; dev->active++; dev->commands_issued++; - if ((dev->flags & AHC_DEV_PERIODIC_OTAG) != 0) + if ((dev->flags & AIC_DEV_PERIODIC_OTAG) != 0) dev->commands_since_idle_or_otag++; /* @@ -3830,6 +3815,7 @@ ahc_linux_run_device_queue(struct ahc_so continue; } scb->flags |= SCB_ACTIVE; + aic_scb_timer_start(scb); ahc_queue_scb(ahc, scb); } } @@ -3847,8 +3833,8 @@ ahc_linux_isr(int irq, void *dev_id, str ahc = (struct ahc_softc *) dev_id; ahc_lock(ahc, &flags); ours = ahc_intr(ahc); - if (ahc_linux_next_device_to_run(ahc) != NULL) - ahc_schedule_runq(ahc); + if (aic_linux_next_device_to_run(ahc) != NULL) + aic_schedule_runq(ahc); ahc_linux_run_complete_queue(ahc); ahc_unlock(ahc, &flags); return IRQ_RETVAL(ours); @@ -3862,10 +3848,10 @@ ahc_platform_flushwork(struct ahc_softc ; } -static struct ahc_linux_target* +static struct aic_linux_target* ahc_linux_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target) { - struct ahc_linux_target *targ; + struct aic_linux_target *targ; u_int target_offset; target_offset = target; @@ -3878,14 +3864,14 @@ ahc_linux_alloc_target(struct ahc_softc memset(targ, 0, sizeof(*targ)); targ->channel = channel; targ->target = target; - targ->ahc = ahc; - targ->flags = AHC_DV_REQUIRED; + targ->softc = ahc; + targ->flags = AIC_DV_REQUIRED; ahc->platform_data->targets[target_offset] = targ; return (targ); } static void -ahc_linux_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ) +ahc_linux_free_target(struct ahc_softc *ahc, struct aic_linux_target *targ) { struct ahc_devinfo devinfo; struct ahc_initiator_tinfo *tinfo; @@ -3925,11 +3911,11 @@ ahc_linux_free_target(struct ahc_softc * free(targ, M_DEVBUF); } -static struct ahc_linux_device* +static struct aic_linux_device* ahc_linux_alloc_device(struct ahc_softc *ahc, - struct ahc_linux_target *targ, u_int lun) + struct aic_linux_target *targ, u_int lun) { - struct ahc_linux_device *dev; + struct aic_linux_device *dev; dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT); if (dev == NULL) @@ -3937,7 +3923,7 @@ ahc_linux_alloc_device(struct ahc_softc memset(dev, 0, sizeof(*dev)); init_timer(&dev->timer); TAILQ_INIT(&dev->busyq); - dev->flags = AHC_DEV_UNCONFIGURED; + dev->flags = AIC_DEV_UNCONFIGURED; dev->lun = lun; dev->target = targ; @@ -3960,17 +3946,17 @@ ahc_linux_alloc_device(struct ahc_softc } static void -ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev) +ahc_linux_free_device(struct ahc_softc *ahc, struct aic_linux_device *dev) { - struct ahc_linux_target *targ; + struct aic_linux_target *targ; - del_timer_sync(&dev->timer); + del_timer(&dev->timer); targ = dev->target; targ->devices[dev->lun] = NULL; free(dev, M_DEVBUF); targ->refcount--; if (targ->refcount == 0 - && (targ->flags & AHC_DV_REQUIRED) == 0) + && (targ->flags & AIC_DV_REQUIRED) == 0) ahc_linux_free_target(ahc, targ); } @@ -3982,7 +3968,7 @@ ahc_send_async(struct ahc_softc *ahc, ch case AC_TRANSFER_NEG: { char buf[80]; - struct ahc_linux_target *targ; + struct aic_linux_target *targ; struct info_str info; struct ahc_initiator_tinfo *tinfo; struct ahc_tmode_tstate *tstate; @@ -4076,6 +4062,20 @@ ahc_send_async(struct ahc_softc *ahc, ch channel - 'A'); } #endif + /* + * Add a minimal bus settle delay for devices that are slow to + * respond after bus resets. + */ + if ((ahc->platform_data->flags & AIC_BUS_SETTLE_TIMER) == 0) { + aic_freeze_simq(ahc); + ahc->platform_data->flags |= AIC_BUS_SETTLE_TIMER; + ahc->platform_data->bus_settle_timer.expires = + jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000; + add_timer(&ahc->platform_data->bus_settle_timer); + } else { + mod_timer(&ahc->platform_data->bus_settle_timer, + jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000); + } break; default: panic("ahc_send_async: Unexpected async event"); @@ -4089,9 +4089,11 @@ void ahc_done(struct ahc_softc *ahc, struct scb *scb) { Scsi_Cmnd *cmd; - struct ahc_linux_device *dev; + struct aic_linux_device *dev; LIST_REMOVE(scb, pending_links); + if ((scb->flags & SCB_TIMEDOUT) != 0) + LIST_REMOVE(scb, timedout_links); if ((scb->flags & SCB_UNTAGGEDQ) != 0) { struct scb_tailq *untagged_q; int target_offset; @@ -4124,11 +4126,11 @@ ahc_done(struct ahc_softc *ahc, struct s * the sense buffer looks "sane". */ cmd->sense_buffer[0] = 0; - if (ahc_get_transaction_status(scb) == CAM_REQ_INPROG) { + if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) { uint32_t amount_xferred; amount_xferred = - ahc_get_transfer_length(scb) - ahc_get_residual(scb); + aic_get_transfer_length(scb) - aic_get_residual(scb); if ((scb->flags & SCB_TRANSMISSION_ERROR) != 0) { #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_MISC) != 0) { @@ -4136,7 +4138,17 @@ ahc_done(struct ahc_softc *ahc, struct s printf("Set CAM_UNCOR_PARITY\n"); } #endif - ahc_set_transaction_status(scb, CAM_UNCOR_PARITY); + aic_set_transaction_status(scb, CAM_UNCOR_PARITY); +#ifdef AHC_REPORT_UNDERFLOWS + /* + * This code is disabled by default as some + * clients of the SCSI system do not properly + * initialize the underflow parameter. This + * results in spurious termination of commands + * that complete as expected (e.g. underflow is + * allowed as command can return variable amounts + * of data. + */ } else if (amount_xferred < scb->io_ctx->underflow) { u_int i; @@ -4148,30 +4160,31 @@ ahc_done(struct ahc_softc *ahc, struct s ahc_print_path(ahc, scb); printf("Saw underflow (%ld of %ld bytes). " "Treated as error\n", - ahc_get_residual(scb), - ahc_get_transfer_length(scb)); - ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); + aic_get_residual(scb), + aic_get_transfer_length(scb)); + aic_set_transaction_status(scb, CAM_DATA_RUN_ERR); +#endif } else { - ahc_set_transaction_status(scb, CAM_REQ_CMP); + aic_set_transaction_status(scb, CAM_REQ_CMP); } - } else if (ahc_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) { + } else if (aic_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) { ahc_linux_handle_scsi_status(ahc, dev, scb); - } else if (ahc_get_transaction_status(scb) == CAM_SEL_TIMEOUT) { - dev->flags |= AHC_DEV_UNCONFIGURED; - if (AHC_DV_CMD(cmd) == FALSE) - dev->target->flags &= ~AHC_DV_REQUIRED; + } else if (aic_get_transaction_status(scb) == CAM_SEL_TIMEOUT) { + dev->flags |= AIC_DEV_UNCONFIGURED; + if (AIC_DV_CMD(cmd) == FALSE) + dev->target->flags &= ~AIC_DV_REQUIRED; } /* * Start DV for devices that require it assuming the first command * sent does not result in a selection timeout. */ - if (ahc_get_transaction_status(scb) != CAM_SEL_TIMEOUT - && (dev->target->flags & AHC_DV_REQUIRED) != 0) + if (aic_get_transaction_status(scb) != CAM_SEL_TIMEOUT + && (dev->target->flags & AIC_DV_REQUIRED) != 0) ahc_linux_start_dv(ahc); if (dev->openings == 1 - && ahc_get_transaction_status(scb) == CAM_REQ_CMP - && ahc_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL) + && aic_get_transaction_status(scb) == CAM_REQ_CMP + && aic_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL) dev->tag_success_count++; /* * Some devices deal with temporary internal resource @@ -4180,7 +4193,7 @@ ahc_done(struct ahc_softc *ahc, struct s * back to our previous queue depth. */ if ((dev->openings + dev->active) < dev->maxtags - && dev->tag_success_count > AHC_TAG_SUCCESS_INTERVAL) { + && dev->tag_success_count > AIC_TAG_SUCCESS_INTERVAL) { dev->tag_success_count = 0; dev->openings++; } @@ -4189,32 +4202,61 @@ ahc_done(struct ahc_softc *ahc, struct s dev->commands_since_idle_or_otag = 0; if (TAILQ_EMPTY(&dev->busyq)) { - if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0 - && dev->active == 0 - && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0) + if ((dev->flags & AIC_DEV_UNCONFIGURED) != 0 + && dev->active == 0) ahc_linux_free_device(ahc, dev); - } else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) { + } else if ((dev->flags & AIC_DEV_ON_RUN_LIST) == 0) { TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links); - dev->flags |= AHC_DEV_ON_RUN_LIST; + dev->flags |= AIC_DEV_ON_RUN_LIST; } if ((scb->flags & SCB_RECOVERY_SCB) != 0) { printf("Recovery SCB completes\n"); - if (ahc_get_transaction_status(scb) == CAM_BDR_SENT - || ahc_get_transaction_status(scb) == CAM_REQ_ABORTED) - ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT); - if ((ahc->platform_data->flags & AHC_UP_EH_SEMAPHORE) != 0) { - ahc->platform_data->flags &= ~AHC_UP_EH_SEMAPHORE; + if (aic_get_transaction_status(scb) == CAM_BDR_SENT + || aic_get_transaction_status(scb) == CAM_REQ_ABORTED) + aic_set_transaction_status(scb, CAM_CMD_TIMEOUT); + if ((scb->platform_data->flags & AIC_SCB_UP_EH_SEM) != 0) { + scb->platform_data->flags &= ~AIC_SCB_UP_EH_SEM; up(&ahc->platform_data->eh_sem); + } else { + struct scb *list_scb; + + /* + * We were able to complete the command successfully, + * so reinstate the timeouts for all other pending + * commands. + */ + LIST_FOREACH(list_scb, + &ahc->pending_scbs, pending_links) { + + aic_scb_timer_start(list_scb); + } } } + if ((scb->platform_data->flags & AIC_TIMEOUT_ACTIVE) == 0) { + /* + * The completion handler believes that + * commands without active timers running + * have lost the race of completing before + * their timer expires. Since commands in + * our busy queues do not have timers running, + * appease the mid-layer by adding a timer + * now. This timer will be immediately + * canceled by the midlayer. + */ + scsi_add_timer(cmd, 60*HZ, aic_linux_midlayer_timeout); + } + + if ((scb->platform_data->flags & AIC_RELEASE_SIMQ) != 0) + aic_release_simq_locked(ahc); + ahc_free_scb(ahc, scb); ahc_linux_queue_cmd_complete(ahc, cmd); - if ((ahc->platform_data->flags & AHC_DV_WAIT_SIMQ_EMPTY) != 0 + if ((ahc->platform_data->flags & AIC_DV_WAIT_SIMQ_EMPTY) != 0 && LIST_FIRST(&ahc->pending_scbs) == NULL) { - ahc->platform_data->flags &= ~AHC_DV_WAIT_SIMQ_EMPTY; + ahc->platform_data->flags &= ~AIC_DV_WAIT_SIMQ_EMPTY; up(&ahc->platform_data->dv_sem); } @@ -4222,7 +4264,7 @@ ahc_done(struct ahc_softc *ahc, struct s static void ahc_linux_handle_scsi_status(struct ahc_softc *ahc, - struct ahc_linux_device *dev, struct scb *scb) + struct aic_linux_device *dev, struct scb *scb) { struct ahc_devinfo devinfo; @@ -4242,7 +4284,7 @@ ahc_linux_handle_scsi_status(struct ahc_ * we don't clobber the device with too many * commands. */ - switch (ahc_get_scsi_status(scb)) { + switch (aic_get_scsi_status(scb)) { default: break; case SCSI_STATUS_CHECK_COND: @@ -4256,13 +4298,15 @@ ahc_linux_handle_scsi_status(struct ahc_ */ cmd = scb->io_ctx; if (scb->flags & SCB_SENSE) { - u_int sense_size; + struct scsi_sense_data *sense; + u_int sense_size; + int error_code, sense_key, asc, ascq; + sense = ahc_get_sense_buf(ahc, scb); sense_size = MIN(sizeof(struct scsi_sense_data) - - ahc_get_sense_residual(scb), + - aic_get_sense_residual(scb), sizeof(cmd->sense_buffer)); - memcpy(cmd->sense_buffer, - ahc_get_sense_buf(ahc, scb), sense_size); + memcpy(cmd->sense_buffer, sense, sense_size); if (sense_size < sizeof(cmd->sense_buffer)) memset(&cmd->sense_buffer[sense_size], 0, sizeof(cmd->sense_buffer) - sense_size); @@ -4281,6 +4325,23 @@ ahc_linux_handle_scsi_status(struct ahc_ printf("\n"); } #endif + /* + * If this is not a DV command and the target + * provides some status that makes us believe + * that the target has changed (power on reset, + * etc.) kick off a DV scan to re-validate the + * device. + */ + if (AIC_DV_CMD(cmd) != 0) + break; + + scsi_extract_sense(sense, &error_code, + &sense_key, &asc, &ascq); + if (error_code == SSD_CURRENT_ERROR + && sense_key == SSD_KEY_UNIT_ATTENTION + && asc == 0x29 + && (ascq == 0 || ascq == 1)) + dev->target->flags |= AIC_DV_REQUIRED; } break; } @@ -4317,7 +4378,7 @@ ahc_linux_handle_scsi_status(struct ahc_ * this device. */ if (dev->last_queuefull_same_count - == AHC_LOCK_TAGS_COUNT) { + == AIC_LOCK_TAGS_COUNT) { dev->maxtags = dev->active; ahc_print_path(ahc, scb); printf("Locking max tag count at %d\n", @@ -4327,10 +4388,10 @@ ahc_linux_handle_scsi_status(struct ahc_ dev->tags_on_last_queuefull = dev->active; dev->last_queuefull_same_count = 0; } - ahc_set_transaction_status(scb, CAM_REQUEUE_REQ); - ahc_set_scsi_status(scb, SCSI_STATUS_OK); + aic_set_transaction_status(scb, CAM_REQUEUE_REQ); + aic_set_scsi_status(scb, SCSI_STATUS_OK); ahc_platform_set_tags(ahc, &devinfo, - (dev->flags & AHC_DEV_Q_BASIC) + (dev->flags & AIC_DEV_Q_BASIC) ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED); break; } @@ -4339,9 +4400,9 @@ ahc_linux_handle_scsi_status(struct ahc_ * as if the target returned BUSY SCSI status. */ dev->openings = 1; - ahc_set_scsi_status(scb, SCSI_STATUS_BUSY); + aic_set_scsi_status(scb, SCSI_STATUS_BUSY); ahc_platform_set_tags(ahc, &devinfo, - (dev->flags & AHC_DEV_Q_BASIC) + (dev->flags & AIC_DEV_Q_BASIC) ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED); /* FALLTHROUGH */ } @@ -4351,13 +4412,13 @@ ahc_linux_handle_scsi_status(struct ahc_ * Set a short timer to defer sending commands for * a bit since Linux will not delay in this case. */ - if ((dev->flags & AHC_DEV_TIMER_ACTIVE) != 0) { + if ((dev->flags & AIC_DEV_TIMER_ACTIVE) != 0) { printf("%s:%c:%d: Device Timer still active during " "busy processing\n", ahc_name(ahc), dev->target->channel, dev->target->target); break; } - dev->flags |= AHC_DEV_TIMER_ACTIVE; + dev->flags |= AIC_DEV_TIMER_ACTIVE; dev->qfrozen++; init_timer(&dev->timer); dev->timer.data = (u_long)dev; @@ -4384,9 +4445,9 @@ ahc_linux_queue_cmd_complete(struct ahc_ * not guarantee the order that aborted commands will be * returned to us. */ - struct ahc_completeq *completeq; - struct ahc_cmd *list_cmd; - struct ahc_cmd *acmd; + struct aic_completeq *completeq; + struct aic_cmd *list_cmd; + struct aic_cmd *acmd; /* * Map CAM error codes into Linux Error codes. We @@ -4394,10 +4455,10 @@ ahc_linux_queue_cmd_complete(struct ahc_ * full error information available when making * state change decisions. */ - if (AHC_DV_CMD(cmd) == FALSE) { + if (AIC_DV_CMD(cmd) == FALSE) { u_int new_status; - switch (ahc_cmd_get_transaction_status(cmd)) { + switch (aic_cmd_get_transaction_status(cmd)) { case CAM_REQ_INPROG: case CAM_REQ_CMP: case CAM_SCSI_STATUS_ERROR: @@ -4424,7 +4485,17 @@ ahc_linux_queue_cmd_complete(struct ahc_ new_status = DID_PARITY; break; case CAM_CMD_TIMEOUT: - new_status = DID_TIME_OUT; + /* + * Returning DID_TIME_OUT will + * wake up the error recovery + * thread instead of doing the + * command retry we desire. Since + * we have already recovered the + * command, returning DID_ERROR + * will cause a retry up to the + * retry limit for this command. + */ + new_status = DID_ERROR; break; case CAM_UA_ABORT: case CAM_REQ_CMP_ERR: @@ -4454,7 +4525,7 @@ ahc_linux_queue_cmd_complete(struct ahc_ if (cmd->retries > 0) cmd->retries--; new_status = DID_OK; - ahc_cmd_set_scsi_status(cmd, SCSI_STATUS_CHECK_COND); + aic_cmd_set_scsi_status(cmd, SCSI_STATUS_CHECK_COND); cmd->result |= (DRIVER_SENSE << 24); memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); @@ -4468,12 +4539,12 @@ ahc_linux_queue_cmd_complete(struct ahc_ break; } - ahc_cmd_set_transaction_status(cmd, new_status); + aic_cmd_set_transaction_status(cmd, new_status); } completeq = &ahc->platform_data->completeq; list_cmd = TAILQ_FIRST(completeq); - acmd = (struct ahc_cmd *)cmd; + acmd = (struct aic_cmd *)cmd; while (list_cmd != NULL && acmd_scsi_cmd(list_cmd).serial_number < acmd_scsi_cmd(acmd).serial_number) @@ -4494,7 +4565,7 @@ ahc_linux_filter_inquiry(struct ahc_soft struct ahc_transinfo *curr; struct ahc_tmode_tstate *tstate; struct ahc_syncrate *syncrate; - struct ahc_linux_device *dev; + struct aic_linux_device *dev; u_int maxsync; u_int width; u_int period; @@ -4517,9 +4588,9 @@ ahc_linux_filter_inquiry(struct ahc_soft sid = (struct scsi_inquiry_data *)dev->target->inq_data; if (SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) { - dev->flags &= ~AHC_DEV_UNCONFIGURED; + dev->flags &= ~AIC_DEV_UNCONFIGURED; } else { - dev->flags |= AHC_DEV_UNCONFIGURED; + dev->flags |= AIC_DEV_UNCONFIGURED; return; } @@ -4596,82 +4667,38 @@ ahc_linux_filter_inquiry(struct ahc_soft static void ahc_linux_sem_timeout(u_long arg) { + struct scb *scb; struct ahc_softc *ahc; u_long s; - ahc = (struct ahc_softc *)arg; - + scb = (struct scb *)arg; + ahc = scb->ahc_softc; ahc_lock(ahc, &s); - if ((ahc->platform_data->flags & AHC_UP_EH_SEMAPHORE) != 0) { - ahc->platform_data->flags &= ~AHC_UP_EH_SEMAPHORE; + if ((scb->platform_data->flags & AIC_SCB_UP_EH_SEM) != 0) { + scb->platform_data->flags &= ~AIC_SCB_UP_EH_SEM; up(&ahc->platform_data->eh_sem); } ahc_unlock(ahc, &s); } static void -ahc_linux_freeze_simq(struct ahc_softc *ahc) -{ - ahc->platform_data->qfrozen++; - if (ahc->platform_data->qfrozen == 1) { - scsi_block_requests(ahc->platform_data->host); - - /* XXX What about Twin channels? */ - ahc_platform_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS, - CAM_LUN_WILDCARD, SCB_LIST_NULL, - ROLE_INITIATOR, CAM_REQUEUE_REQ); - } -} - -static void -ahc_linux_release_simq(u_long arg) -{ - struct ahc_softc *ahc; - u_long s; - int unblock_reqs; - - ahc = (struct ahc_softc *)arg; - - unblock_reqs = 0; - ahc_lock(ahc, &s); - if (ahc->platform_data->qfrozen > 0) - ahc->platform_data->qfrozen--; - if (ahc->platform_data->qfrozen == 0) - unblock_reqs = 1; - if (AHC_DV_SIMQ_FROZEN(ahc) - && ((ahc->platform_data->flags & AHC_DV_WAIT_SIMQ_RELEASE) != 0)) { - ahc->platform_data->flags &= ~AHC_DV_WAIT_SIMQ_RELEASE; - up(&ahc->platform_data->dv_sem); - } - ahc_schedule_runq(ahc); - ahc_unlock(ahc, &s); - /* - * There is still a race here. The mid-layer - * should keep its own freeze count and use - * a bottom half handler to run the queues - * so we can unblock with our own lock held. - */ - if (unblock_reqs) - scsi_unblock_requests(ahc->platform_data->host); -} - -static void ahc_linux_dev_timed_unfreeze(u_long arg) { - struct ahc_linux_device *dev; + struct aic_linux_device *dev; struct ahc_softc *ahc; u_long s; - dev = (struct ahc_linux_device *)arg; - ahc = dev->target->ahc; + dev = (struct aic_linux_device *)arg; + ahc = dev->target->softc; ahc_lock(ahc, &s); - dev->flags &= ~AHC_DEV_TIMER_ACTIVE; + dev->flags &= ~AIC_DEV_TIMER_ACTIVE; if (dev->qfrozen > 0) dev->qfrozen--; if (dev->qfrozen == 0 - && (dev->flags & AHC_DEV_ON_RUN_LIST) == 0) + && (dev->flags & AIC_DEV_ON_RUN_LIST) == 0) ahc_linux_run_device_queue(ahc, dev); - if (TAILQ_EMPTY(&dev->busyq) + if ((dev->flags & AIC_DEV_UNCONFIGURED) != 0 + && TAILQ_EMPTY(&dev->busyq) && dev->active == 0) ahc_linux_free_device(ahc, dev); ahc_unlock(ahc, &s); @@ -4681,9 +4708,9 @@ static int ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) { struct ahc_softc *ahc; - struct ahc_cmd *acmd; - struct ahc_cmd *list_acmd; - struct ahc_linux_device *dev; + struct aic_cmd *acmd; + struct aic_cmd *list_acmd; + struct aic_linux_device *dev; struct scb *pending_scb; u_long s; u_int saved_scbptr; @@ -4701,7 +4728,7 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd * paused = FALSE; wait = FALSE; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; - acmd = (struct ahc_cmd *)cmd; + acmd = (struct aic_cmd *)cmd; printf("%s:%d:%d:%d: Attempting to queue a%s message\n", ahc_name(ahc), cmd->device->channel, @@ -4763,13 +4790,24 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd * if (flag == SCB_ABORT) { TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe); cmd->result = DID_ABORT << 16; + /* + * The completion handler believes that + * commands without active timers running + * have lost the race of completing before + * their timer expires. Since commands in our + * busy queues do not have timers running, + * appease the mid-layer by adding a timer + * now. This timer will be immediately + * canceled by the midlayer. + */ + scsi_add_timer(cmd, 60*HZ, aic_linux_midlayer_timeout); ahc_linux_queue_cmd_complete(ahc, cmd); retval = SUCCESS; goto done; } } - if ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED)) == 0 + if ((dev->flags & (AIC_DEV_Q_BASIC|AIC_DEV_Q_TAGGED)) == 0 && ahc_search_untagged_queues(ahc, cmd, cmd->device->id, cmd->device->channel + 'A', cmd->device->lun, @@ -4985,10 +5023,10 @@ done: struct timer_list timer; int ret; - ahc->platform_data->flags |= AHC_UP_EH_SEMAPHORE; + pending_scb->platform_data->flags |= AIC_SCB_UP_EH_SEM; spin_unlock_irq(&ahc->platform_data->spin_lock); init_timer(&timer); - timer.data = (u_long)ahc; + timer.data = (u_long)pending_scb; timer.expires = jiffies + (5 * HZ); timer.function = ahc_linux_sem_timeout; add_timer(&timer); @@ -5002,7 +5040,7 @@ done: } spin_lock_irq(&ahc->platform_data->spin_lock); } - ahc_schedule_runq(ahc); + aic_schedule_runq(ahc); ahc_linux_run_complete_queue(ahc); ahc_midlayer_entrypoint_unlock(ahc, &s); return (retval); @@ -5011,7 +5049,8 @@ done: void ahc_platform_dump_card_state(struct ahc_softc *ahc) { - struct ahc_linux_device *dev; + struct Scsi_Host *host; + struct aic_linux_device *dev; int channel; int maxchannel; int target; @@ -5019,6 +5058,14 @@ ahc_platform_dump_card_state(struct ahc_ int lun; int i; + host = ahc->platform_data->host; + printf("%s: Host Status: Failed(%d) %s%s%s\n", + ahc_name(ahc), + host->host_failed, + host->eh_active ? "eh_active " : "", + host->host_blocked ? "host_blocked " : "", + host->host_self_blocked ? "host_self_blocked " : ""); + maxchannel = (ahc->features & AHC_TWIN) ? 1 : 0; maxtarget = (ahc->features & AHC_WIDE) ? 15 : 7; for (channel = 0; channel <= maxchannel; channel++) { @@ -5026,7 +5073,7 @@ ahc_platform_dump_card_state(struct ahc_ for (target = 0; target <=maxtarget; target++) { for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct ahc_cmd *acmd; + struct aic_cmd *acmd; dev = ahc_linux_get_device(ahc, channel, target, lun, /*alloc*/FALSE); @@ -5068,41 +5115,33 @@ static void __exit ahc_linux_exit(void) { struct ahc_softc *ahc; - u_long l; /* - * Shutdown DV threads before going into the SCSI mid-layer. + * Shutdown our threads before going into the SCSI mid-layer. * This avoids situations where the mid-layer locks the entire * kernel so that waiting for our DV threads to exit leads * to deadlock. */ - ahc_list_lock(&l); TAILQ_FOREACH(ahc, &ahc_tailq, links) { ahc_linux_kill_dv_thread(ahc); + ahc_terminate_recovery_thread(ahc); } - ahc_list_unlock(&l); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - - ahc_linux_pci_exit(); - - /* - * Get rid of the non-pci devices. - * - * XXX(hch): switch over eisa support to new LDM-based API - */ - TAILQ_FOREACH(ahc, &ahc_tailq, links) - ahc_linux_release(ahc->platform_data->host); -#else - scsi_unregister_module(MODULE_SCSI_HA, &aic7xxx_driver_template); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* * In 2.4 we have to unregister from the PCI core _after_ * unregistering from the scsi midlayer to avoid dangling * references. */ + 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 -puN drivers/scsi/aic7xxx/aic7xxx_osm.h~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7xxx_osm.h --- 25/drivers/scsi/aic7xxx/aic7xxx_osm.h~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7xxx_osm.h Wed Dec 24 12:15:38 2003 @@ -53,50 +53,22 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#147 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#166 $ * */ #ifndef _AIC7XXX_LINUX_H_ #define _AIC7XXX_LINUX_H_ -#include -#include -#include -#include -#include -#include #include -#include -#include -#include #ifndef KERNEL_VERSION #define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) -#include /* For tasklet support. */ #include -#include -#else -#include #endif -/* Core SCSI definitions */ -#define AIC_LIB_PREFIX ahc -#include "scsi.h" -#include "hosts.h" - -/* Name space conflict with BSD queue macros */ -#ifdef LIST_HEAD -#undef LIST_HEAD -#endif - -#include "cam.h" -#include "queue.h" -#include "scsi_message.h" -#include "aiclib.h" - /*********************************** Debugging ********************************/ #ifdef CONFIG_AIC7XXX_DEBUG_ENABLE #ifdef CONFIG_AIC7XXX_DEBUG_MASK @@ -111,42 +83,18 @@ /* No debugging code. */ #endif -/************************* Forward Declarations *******************************/ -struct ahc_softc; -typedef struct pci_dev *ahc_dev_softc_t; -typedef Scsi_Cmnd *ahc_io_ctx_t; - -/******************************* Byte Order ***********************************/ -#define ahc_htobe16(x) cpu_to_be16(x) -#define ahc_htobe32(x) cpu_to_be32(x) -#define ahc_htobe64(x) cpu_to_be64(x) -#define ahc_htole16(x) cpu_to_le16(x) -#define ahc_htole32(x) cpu_to_le32(x) -#define ahc_htole64(x) cpu_to_le64(x) - -#define ahc_be16toh(x) be16_to_cpu(x) -#define ahc_be32toh(x) be32_to_cpu(x) -#define ahc_be64toh(x) be64_to_cpu(x) -#define ahc_le16toh(x) le16_to_cpu(x) -#define ahc_le32toh(x) le32_to_cpu(x) -#define ahc_le64toh(x) le64_to_cpu(x) - -#ifndef LITTLE_ENDIAN -#define LITTLE_ENDIAN 1234 -#endif - -#ifndef BIG_ENDIAN -#define BIG_ENDIAN 4321 -#endif +/********************************** Includes **********************************/ +/* Core SCSI definitions */ +#define AIC_LIB_PREFIX ahc +#define AIC_CONST_PREFIX AHC -#ifndef BYTE_ORDER -#if defined(__BIG_ENDIAN) -#define BYTE_ORDER BIG_ENDIAN -#endif -#if defined(__LITTLE_ENDIAN) -#define BYTE_ORDER LITTLE_ENDIAN +#ifdef CONFIG_AIC7XXX_REG_PRETTY_PRINT +#define AIC_DEBUG_REGISTERS 1 +#else +#define AIC_DEBUG_REGISTERS 0 #endif -#endif /* BYTE_ORDER */ +#define AIC_CORE_INCLUDE "aic7xxx.h" +#include "aiclib.h" /************************* Configuration Data *********************************/ extern u_int aic7xxx_no_probe; @@ -154,142 +102,9 @@ extern u_int aic7xxx_allow_memio; extern int aic7xxx_detect_complete; extern Scsi_Host_Template aic7xxx_driver_template; -/***************************** Bus Space/DMA **********************************/ - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17) -typedef dma_addr_t bus_addr_t; -#else -typedef uint32_t bus_addr_t; -#endif -typedef uint32_t bus_size_t; - -typedef enum { - BUS_SPACE_MEMIO, - BUS_SPACE_PIO -} bus_space_tag_t; - -typedef union { - u_long ioport; - volatile uint8_t *maddr; -} bus_space_handle_t; - -typedef struct bus_dma_segment -{ - bus_addr_t ds_addr; - bus_size_t ds_len; -} bus_dma_segment_t; - -struct ahc_linux_dma_tag -{ - bus_size_t alignment; - bus_size_t boundary; - bus_size_t maxsize; -}; -typedef struct ahc_linux_dma_tag* bus_dma_tag_t; - -struct ahc_linux_dmamap -{ - bus_addr_t bus_addr; -}; -typedef struct ahc_linux_dmamap* bus_dmamap_t; - -typedef int bus_dma_filter_t(void*, bus_addr_t); -typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int); - -#define BUS_DMA_WAITOK 0x0 -#define BUS_DMA_NOWAIT 0x1 -#define BUS_DMA_ALLOCNOW 0x2 -#define BUS_DMA_LOAD_SEGS 0x4 /* - * Argument is an S/G list not - * a single buffer. - */ - -#define BUS_SPACE_MAXADDR 0xFFFFFFFF -#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF -#define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF - -int ahc_dma_tag_create(struct ahc_softc *, bus_dma_tag_t /*parent*/, - bus_size_t /*alignment*/, bus_size_t /*boundary*/, - bus_addr_t /*lowaddr*/, bus_addr_t /*highaddr*/, - bus_dma_filter_t*/*filter*/, void */*filterarg*/, - bus_size_t /*maxsize*/, int /*nsegments*/, - bus_size_t /*maxsegsz*/, int /*flags*/, - bus_dma_tag_t */*dma_tagp*/); - -void ahc_dma_tag_destroy(struct ahc_softc *, bus_dma_tag_t /*tag*/); - -int ahc_dmamem_alloc(struct ahc_softc *, bus_dma_tag_t /*dmat*/, - void** /*vaddr*/, int /*flags*/, - bus_dmamap_t* /*mapp*/); - -void ahc_dmamem_free(struct ahc_softc *, bus_dma_tag_t /*dmat*/, - void* /*vaddr*/, bus_dmamap_t /*map*/); - -void ahc_dmamap_destroy(struct ahc_softc *, bus_dma_tag_t /*tag*/, - bus_dmamap_t /*map*/); - -int ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t /*dmat*/, - bus_dmamap_t /*map*/, void * /*buf*/, - bus_size_t /*buflen*/, bus_dmamap_callback_t *, - void */*callback_arg*/, int /*flags*/); - -int ahc_dmamap_unload(struct ahc_softc *, bus_dma_tag_t, bus_dmamap_t); - -/* - * Operations performed by ahc_dmamap_sync(). - */ -#define BUS_DMASYNC_PREREAD 0x01 /* pre-read synchronization */ -#define BUS_DMASYNC_POSTREAD 0x02 /* post-read synchronization */ -#define BUS_DMASYNC_PREWRITE 0x04 /* pre-write synchronization */ -#define BUS_DMASYNC_POSTWRITE 0x08 /* post-write synchronization */ - -/* - * XXX - * ahc_dmamap_sync is only used on buffers allocated with - * the pci_alloc_consistent() API. Although I'm not sure how - * this works on architectures with a write buffer, Linux does - * not have an API to sync "coherent" memory. Perhaps we need - * to do an mb()? - */ -#define ahc_dmamap_sync(ahc, dma_tag, dmamap, offset, len, op) - -/************************** Timer DataStructures ******************************/ -typedef struct timer_list ahc_timer_t; - -/********************************** Includes **********************************/ -#ifdef CONFIG_AIC7XXX_REG_PRETTY_PRINT -#define AIC_DEBUG_REGISTERS 1 -#else -#define AIC_DEBUG_REGISTERS 0 -#endif -#include "aic7xxx.h" - -/***************************** Timer Facilities *******************************/ -#define ahc_timer_init init_timer -#define ahc_timer_stop del_timer_sync -typedef void ahc_linux_callback_t (u_long); -static __inline void ahc_timer_reset(ahc_timer_t *timer, int usec, - ahc_callback_t *func, void *arg); -static __inline void ahc_scb_timer_reset(struct scb *scb, u_int usec); - -static __inline void -ahc_timer_reset(ahc_timer_t *timer, int usec, ahc_callback_t *func, void *arg) -{ - struct ahc_softc *ahc; - - ahc = (struct ahc_softc *)arg; - del_timer(timer); - timer->data = (u_long)arg; - timer->expires = jiffies + (usec * HZ)/1000000; - timer->function = (ahc_linux_callback_t*)func; - add_timer(timer); -} - -static __inline void -ahc_scb_timer_reset(struct scb *scb, u_int usec) -{ - mod_timer(&scb->io_ctx->eh_timeout, jiffies + (usec * HZ)/1000000); -} +/***************************** Domain Validation ******************************/ +void ahc_linux_dv_complete(Scsi_Cmnd *cmd); +void ahc_linux_dv_timeout(struct scsi_cmnd *cmd); /***************************** SMP support ************************************/ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,17) @@ -304,187 +119,7 @@ ahc_scb_timer_reset(struct scb *scb, u_i #define AHC_SCSI_HAS_HOST_LOCK 0 #endif -#define AIC7XXX_DRIVER_VERSION "6.2.35" - -/**************************** Front End Queues ********************************/ -/* - * Data structure used to cast the Linux struct scsi_cmnd to something - * that allows us to use the queue macros. The linux structure has - * plenty of space to hold the links fields as required by the queue - * macros, but the queue macors require them to have the correct type. - */ -struct ahc_cmd_internal { - /* Area owned by the Linux scsi layer. */ - uint8_t private[offsetof(struct scsi_cmnd, SCp.Status)]; - union { - STAILQ_ENTRY(ahc_cmd) ste; - LIST_ENTRY(ahc_cmd) le; - TAILQ_ENTRY(ahc_cmd) tqe; - } links; - uint32_t end; -}; - -struct ahc_cmd { - union { - struct ahc_cmd_internal icmd; - struct scsi_cmnd scsi_cmd; - } un; -}; - -#define acmd_icmd(cmd) ((cmd)->un.icmd) -#define acmd_scsi_cmd(cmd) ((cmd)->un.scsi_cmd) -#define acmd_links un.icmd.links - -/*************************** Device Data Structures ***************************/ -/* - * A per probed device structure used to deal with some error recovery - * scenarios that the Linux mid-layer code just doesn't know how to - * handle. The structure allocated for a device only becomes persistent - * after a successfully completed inquiry command to the target when - * that inquiry data indicates a lun is present. - */ -TAILQ_HEAD(ahc_busyq, ahc_cmd); -typedef enum { - AHC_DEV_UNCONFIGURED = 0x01, - AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ - AHC_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ - AHC_DEV_ON_RUN_LIST = 0x08, /* Queued to be run later */ - AHC_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ - AHC_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ - AHC_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ - AHC_DEV_SLAVE_CONFIGURED = 0x80 /* slave_configure() has been called */ -} ahc_linux_dev_flags; - -struct ahc_linux_target; -struct ahc_linux_device { - TAILQ_ENTRY(ahc_linux_device) links; - struct ahc_busyq busyq; - - /* - * The number of transactions currently - * queued to the device. - */ - int active; - - /* - * The currently allowed number of - * transactions that can be queued to - * the device. Must be signed for - * conversion from tagged to untagged - * mode where the device may have more - * than one outstanding active transaction. - */ - int openings; - - /* - * A positive count indicates that this - * device's queue is halted. - */ - u_int qfrozen; - - /* - * Cumulative command counter. - */ - u_long commands_issued; - - /* - * The number of tagged transactions when - * running at our current opening level - * that have been successfully received by - * this device since the last QUEUE FULL. - */ - u_int tag_success_count; -#define AHC_TAG_SUCCESS_INTERVAL 50 - - ahc_linux_dev_flags flags; - - /* - * Per device timer. - */ - struct timer_list timer; - - /* - * The high limit for the tags variable. - */ - u_int maxtags; - - /* - * The computed number of tags outstanding - * at the time of the last QUEUE FULL event. - */ - u_int tags_on_last_queuefull; - - /* - * How many times we have seen a queue full - * with the same number of tags. This is used - * to stop our adaptive queue depth algorithm - * on devices with a fixed number of tags. - */ - u_int last_queuefull_same_count; -#define AHC_LOCK_TAGS_COUNT 50 - - /* - * How many transactions have been queued - * without the device going idle. We use - * this statistic to determine when to issue - * an ordered tag to prevent transaction - * starvation. This statistic is only updated - * if the AHC_DEV_PERIODIC_OTAG flag is set - * on this device. - */ - u_int commands_since_idle_or_otag; -#define AHC_OTAG_THRESH 500 - - int lun; - Scsi_Device *scsi_device; - struct ahc_linux_target *target; -}; - -typedef enum { - AHC_DV_REQUIRED = 0x01, - AHC_INQ_VALID = 0x02, - AHC_BASIC_DV = 0x04, - AHC_ENHANCED_DV = 0x08 -} ahc_linux_targ_flags; - -/* DV States */ -typedef enum { - AHC_DV_STATE_EXIT = 0, - AHC_DV_STATE_INQ_SHORT_ASYNC, - AHC_DV_STATE_INQ_ASYNC, - AHC_DV_STATE_INQ_ASYNC_VERIFY, - AHC_DV_STATE_TUR, - AHC_DV_STATE_REBD, - AHC_DV_STATE_INQ_VERIFY, - AHC_DV_STATE_WEB, - AHC_DV_STATE_REB, - AHC_DV_STATE_SU, - AHC_DV_STATE_BUSY -} ahc_dv_state; - -struct ahc_linux_target { - struct ahc_linux_device *devices[AHC_NUM_LUNS]; - int channel; - int target; - int refcount; - struct ahc_transinfo last_tinfo; - struct ahc_softc *ahc; - ahc_linux_targ_flags flags; - struct scsi_inquiry_data *inq_data; - /* - * The next "fallback" period to use for narrow/wide transfers. - */ - uint8_t dv_next_narrow_period; - uint8_t dv_next_wide_period; - uint8_t dv_max_width; - uint8_t dv_max_ppr_options; - uint8_t dv_last_ppr_options; - u_int dv_echo_size; - ahc_dv_state dv_state; - u_int dv_state_retry; - char *dv_buffer; - char *dv_buffer1; -}; +#define AIC7XXX_DRIVER_VERSION "6.3.4" /********************* Definitions Required by the Core ***********************/ /* @@ -506,120 +141,39 @@ extern u_int ahc_linux_nseg; #define AHC_NSEG 128 #endif -/* - * Per-SCB OSM storage. - */ -typedef enum { - AHC_UP_EH_SEMAPHORE = 0x1 -} ahc_linux_scb_flags; - -struct scb_platform_data { - struct ahc_linux_device *dev; - bus_addr_t buf_busaddr; - uint32_t xfer_len; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) - uint32_t resid; /* Transfer residual */ -#endif - uint32_t sense_resid; /* Auto-Sense residual */ - ahc_linux_scb_flags flags; -}; - -/* - * Define a structure used for each host adapter. All members are - * aligned on a boundary >= the size of the member to honor the - * alignment restrictions of the various platforms supported by - * this driver. - */ -typedef enum { - AHC_DV_WAIT_SIMQ_EMPTY = 0x01, - AHC_DV_WAIT_SIMQ_RELEASE = 0x02, - AHC_DV_ACTIVE = 0x04, - AHC_DV_SHUTDOWN = 0x08, - AHC_RUN_CMPLT_Q_TIMER = 0x10 -} ahc_linux_softc_flags; - -TAILQ_HEAD(ahc_completeq, ahc_cmd); - -struct ahc_platform_data { - /* - * Fields accessed from interrupt context. - */ - struct ahc_linux_target *targets[AHC_NUM_TARGETS]; - TAILQ_HEAD(, ahc_linux_device) device_runq; - struct ahc_completeq completeq; - - spinlock_t spin_lock; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - struct tasklet_struct runq_tasklet; -#endif - u_int qfrozen; - pid_t dv_pid; - struct timer_list completeq_timer; - struct timer_list reset_timer; - struct semaphore eh_sem; - struct semaphore dv_sem; - struct semaphore dv_cmd_sem; /* XXX This needs to be in - * the target struct - */ - struct scsi_device *dv_scsi_dev; - struct Scsi_Host *host; /* pointer to scsi host */ -#define AHC_LINUX_NOIRQ ((uint32_t)~0) - uint32_t irq; /* IRQ for this adapter */ - uint32_t bios_address; - uint32_t mem_busaddr; /* Mem Base Addr */ - bus_addr_t hw_dma_mask; - ahc_linux_softc_flags flags; -}; - -/************************** OS Utility Wrappers *******************************/ -#define printf printk -#define M_NOWAIT GFP_ATOMIC -#define M_WAITOK 0 -#define malloc(size, type, flags) kmalloc(size, flags) -#define free(ptr, type) kfree(ptr) - -static __inline void ahc_delay(long); -static __inline void -ahc_delay(long usec) -{ - /* - * udelay on Linux can have problems for - * multi-millisecond waits. Wait at most - * 1024us per call. - */ - while (usec > 0) { - udelay(usec % 1024); - usec -= 1024; - } -} - +/************************** Error Recovery ************************************/ +static __inline void ahc_wakeup_recovery_thread(struct ahc_softc *ahc); + +static __inline void +ahc_wakeup_recovery_thread(struct ahc_softc *ahc) +{ + up(&ahc->platform_data->recovery_sem); +} + +int ahc_spawn_recovery_thread(struct ahc_softc *ahc); +void ahc_terminate_recovery_thread(struct ahc_softc *ahc); +void ahc_set_recoveryscb(struct ahc_softc *ahc, + struct scb *scb); /***************************** Low Level I/O **********************************/ -#if defined(__powerpc__) || defined(__i386__) || defined(__ia64__) -#define MMAPIO -#endif - static __inline uint8_t ahc_inb(struct ahc_softc * ahc, long port); static __inline void ahc_outb(struct ahc_softc * ahc, long port, uint8_t val); static __inline void ahc_outsb(struct ahc_softc * ahc, long port, uint8_t *, int count); static __inline void ahc_insb(struct ahc_softc * ahc, long port, uint8_t *, int count); +static __inline void ahc_flush_device_writes(struct ahc_softc *); static __inline uint8_t ahc_inb(struct ahc_softc * ahc, long port) { uint8_t x; -#ifdef MMAPIO if (ahc->tag == BUS_SPACE_MEMIO) { x = readb(ahc->bsh.maddr + port); } else { x = inb(ahc->bsh.ioport + port); } -#else - x = inb(ahc->bsh.ioport + port); -#endif mb(); return (x); } @@ -627,15 +181,11 @@ ahc_inb(struct ahc_softc * ahc, long por static __inline void ahc_outb(struct ahc_softc * ahc, long port, uint8_t val) { -#ifdef MMAPIO if (ahc->tag == BUS_SPACE_MEMIO) { writeb(val, ahc->bsh.maddr + port); } else { outb(val, ahc->bsh.ioport + port); } -#else - outb(val, ahc->bsh.ioport + port); -#endif mb(); } @@ -667,6 +217,13 @@ ahc_insb(struct ahc_softc * ahc, long po *array++ = ahc_inb(ahc, port); } +static __inline void +ahc_flush_device_writes(struct ahc_softc *ahc) +{ + /* XXX Is this sufficient for all architectures??? */ + ahc_inb(ahc, INTSTAT); +} + /**************************** Initialization **********************************/ int ahc_linux_register_host(struct ahc_softc *, Scsi_Host_Template *); @@ -795,174 +352,41 @@ ahc_list_unlock(unsigned long *flags) } /******************************* PCI Definitions ******************************/ -/* - * PCIM_xxx: mask to locate subfield in register - * PCIR_xxx: config register offset - * PCIC_xxx: device class - * PCIS_xxx: device subclass - * PCIP_xxx: device programming interface - * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices) - * PCID_xxx: device ID - */ -#define PCIR_DEVVENDOR 0x00 -#define PCIR_VENDOR 0x00 -#define PCIR_DEVICE 0x02 -#define PCIR_COMMAND 0x04 -#define PCIM_CMD_PORTEN 0x0001 -#define PCIM_CMD_MEMEN 0x0002 -#define PCIM_CMD_BUSMASTEREN 0x0004 -#define PCIM_CMD_MWRICEN 0x0010 -#define PCIM_CMD_PERRESPEN 0x0040 -#define PCIM_CMD_SERRESPEN 0x0100 -#define PCIR_STATUS 0x06 -#define PCIR_REVID 0x08 -#define PCIR_PROGIF 0x09 -#define PCIR_SUBCLASS 0x0a -#define PCIR_CLASS 0x0b -#define PCIR_CACHELNSZ 0x0c -#define PCIR_LATTIMER 0x0d -#define PCIR_HEADERTYPE 0x0e -#define PCIM_MFDEV 0x80 -#define PCIR_BIST 0x0f -#define PCIR_CAP_PTR 0x34 - -/* config registers for header type 0 devices */ -#define PCIR_MAPS 0x10 -#define PCIR_SUBVEND_0 0x2c -#define PCIR_SUBDEV_0 0x2e - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) extern struct pci_driver aic7xxx_pci_driver; #endif -typedef enum -{ - AHC_POWER_STATE_D0, - AHC_POWER_STATE_D1, - AHC_POWER_STATE_D2, - AHC_POWER_STATE_D3 -} ahc_power_state; - -void ahc_power_state_change(struct ahc_softc *ahc, - ahc_power_state new_state); /**************************** VL/EISA Routines ********************************/ -int aic7770_linux_probe(Scsi_Host_Template *); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) \ + && (defined(__i386__) || defined(__alpha__)) \ + && (!defined(CONFIG_EISA))) +#define CONFIG_EISA +#endif + +#ifdef CONFIG_EISA +extern uint32_t aic7xxx_probe_eisa_vl; +void 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); +#endif /******************************* PCI Routines *********************************/ +#ifdef CONFIG_PCI int ahc_linux_pci_init(void); void ahc_linux_pci_exit(void); int ahc_pci_map_registers(struct ahc_softc *ahc); int ahc_pci_map_int(struct ahc_softc *ahc); +#endif -static __inline uint32_t ahc_pci_read_config(ahc_dev_softc_t pci, - int reg, int width); - -static __inline uint32_t -ahc_pci_read_config(ahc_dev_softc_t pci, int reg, int width) -{ - switch (width) { - case 1: - { - uint8_t retval; - - pci_read_config_byte(pci, reg, &retval); - return (retval); - } - case 2: - { - uint16_t retval; - pci_read_config_word(pci, reg, &retval); - return (retval); - } - case 4: - { - uint32_t retval; - pci_read_config_dword(pci, reg, &retval); - return (retval); - } - default: - panic("ahc_pci_read_config: Read size too big"); - /* NOTREACHED */ - return (0); - } -} - -static __inline void ahc_pci_write_config(ahc_dev_softc_t pci, - int reg, uint32_t value, - int width); - -static __inline void -ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width) -{ - switch (width) { - case 1: - pci_write_config_byte(pci, reg, value); - break; - case 2: - pci_write_config_word(pci, reg, value); - break; - case 4: - pci_write_config_dword(pci, reg, value); - break; - default: - panic("ahc_pci_write_config: Write size too big"); - /* NOTREACHED */ - } -} - -static __inline int ahc_get_pci_function(ahc_dev_softc_t); -static __inline int -ahc_get_pci_function(ahc_dev_softc_t pci) -{ - return (PCI_FUNC(pci->devfn)); -} - -static __inline int ahc_get_pci_slot(ahc_dev_softc_t); -static __inline int -ahc_get_pci_slot(ahc_dev_softc_t pci) -{ - return (PCI_SLOT(pci->devfn)); -} - -static __inline int ahc_get_pci_bus(ahc_dev_softc_t); -static __inline int -ahc_get_pci_bus(ahc_dev_softc_t pci) -{ - return (pci->bus->number); -} - -static __inline void ahc_flush_device_writes(struct ahc_softc *); -static __inline void -ahc_flush_device_writes(struct ahc_softc *ahc) -{ - /* XXX Is this sufficient for all architectures??? */ - ahc_inb(ahc, INTSTAT); -} - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,3,0) -#define pci_map_sg(pdev, sg_list, nseg, direction) (nseg) -#define pci_unmap_sg(pdev, sg_list, nseg, direction) -#define sg_dma_address(sg) (VIRT_TO_BUS((sg)->address)) -#define sg_dma_len(sg) ((sg)->length) -#define pci_map_single(pdev, buffer, bufflen, direction) \ - (VIRT_TO_BUS(buffer)) -#define pci_unmap_single(pdev, buffer, buflen, direction) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) -#define ahc_pci_set_dma_mask pci_set_dma_mask +/**************************** Proc FS Support *********************************/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +int ahc_linux_proc_info(char *, char **, off_t, int, int, int); #else -/* - * Always "return" 0 for success. - */ -#define ahc_pci_set_dma_mask(dev_softc, mask) \ - (((dev_softc)->dma_mask = mask) && 0) +int ahc_linux_proc_info(struct Scsi_Host *, char *, char **, + off_t, int, int); #endif -/**************************** Proc FS Support *********************************/ -int ahc_linux_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); /*************************** Domain Validation ********************************/ #define AHC_DV_CMD(cmd) ((cmd)->scsi_done == ahc_linux_dv_complete) @@ -971,194 +395,9 @@ int ahc_linux_proc_info(struct Scsi_Host && (ahc)->platform_data->qfrozen == 1) /*********************** Transaction Access Wrappers *************************/ -static __inline void ahc_cmd_set_transaction_status(Scsi_Cmnd *, uint32_t); -static __inline void ahc_set_transaction_status(struct scb *, uint32_t); -static __inline void ahc_cmd_set_scsi_status(Scsi_Cmnd *, uint32_t); -static __inline void ahc_set_scsi_status(struct scb *, uint32_t); -static __inline uint32_t ahc_cmd_get_transaction_status(Scsi_Cmnd *cmd); -static __inline uint32_t ahc_get_transaction_status(struct scb *); -static __inline uint32_t ahc_cmd_get_scsi_status(Scsi_Cmnd *cmd); -static __inline uint32_t ahc_get_scsi_status(struct scb *); -static __inline void ahc_set_transaction_tag(struct scb *, int, u_int); -static __inline u_long ahc_get_transfer_length(struct scb *); -static __inline int ahc_get_transfer_dir(struct scb *); -static __inline void ahc_set_residual(struct scb *, u_long); -static __inline void ahc_set_sense_residual(struct scb *scb, u_long resid); -static __inline u_long ahc_get_residual(struct scb *); -static __inline u_long ahc_get_sense_residual(struct scb *); -static __inline int ahc_perform_autosense(struct scb *); -static __inline uint32_t ahc_get_sense_bufsize(struct ahc_softc *, - struct scb *); -static __inline void ahc_notify_xfer_settings_change(struct ahc_softc *, - struct ahc_devinfo *); -static __inline void ahc_platform_scb_free(struct ahc_softc *ahc, - struct scb *scb); -static __inline void ahc_freeze_scb(struct scb *scb); - -static __inline -void ahc_cmd_set_transaction_status(Scsi_Cmnd *cmd, uint32_t status) -{ - cmd->result &= ~(CAM_STATUS_MASK << 16); - cmd->result |= status << 16; -} - -static __inline -void ahc_set_transaction_status(struct scb *scb, uint32_t status) -{ - ahc_cmd_set_transaction_status(scb->io_ctx,status); -} - -static __inline -void ahc_cmd_set_scsi_status(Scsi_Cmnd *cmd, uint32_t status) -{ - cmd->result &= ~0xFFFF; - cmd->result |= status; -} - -static __inline -void ahc_set_scsi_status(struct scb *scb, uint32_t status) -{ - ahc_cmd_set_scsi_status(scb->io_ctx, status); -} - -static __inline -uint32_t ahc_cmd_get_transaction_status(Scsi_Cmnd *cmd) -{ - return ((cmd->result >> 16) & CAM_STATUS_MASK); -} - -static __inline -uint32_t ahc_get_transaction_status(struct scb *scb) -{ - return (ahc_cmd_get_transaction_status(scb->io_ctx)); -} - -static __inline -uint32_t ahc_cmd_get_scsi_status(Scsi_Cmnd *cmd) -{ - return (cmd->result & 0xFFFF); -} - -static __inline -uint32_t ahc_get_scsi_status(struct scb *scb) -{ - return (ahc_cmd_get_scsi_status(scb->io_ctx)); -} - -static __inline -void ahc_set_transaction_tag(struct scb *scb, int enabled, u_int type) -{ - /* - * Nothing to do for linux as the incoming transaction - * has no concept of tag/non tagged, etc. - */ -} - -static __inline -u_long ahc_get_transfer_length(struct scb *scb) -{ - return (scb->platform_data->xfer_len); -} - -static __inline -int ahc_get_transfer_dir(struct scb *scb) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,40) - return (scb->io_ctx->sc_data_direction); -#else - if (scb->io_ctx->bufflen == 0) - return (CAM_DIR_NONE); - - switch(scb->io_ctx->cmnd[0]) { - case 0x08: /* READ(6) */ - case 0x28: /* READ(10) */ - case 0xA8: /* READ(12) */ - return (CAM_DIR_IN); - case 0x0A: /* WRITE(6) */ - case 0x2A: /* WRITE(10) */ - case 0xAA: /* WRITE(12) */ - return (CAM_DIR_OUT); - default: - return (CAM_DIR_NONE); - } -#endif -} - -static __inline -void ahc_set_residual(struct scb *scb, u_long resid) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - scb->io_ctx->resid = resid; -#else - scb->platform_data->resid = resid; -#endif -} - -static __inline -void ahc_set_sense_residual(struct scb *scb, u_long resid) -{ - scb->platform_data->sense_resid = resid; -} - -static __inline -u_long ahc_get_residual(struct scb *scb) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - return (scb->io_ctx->resid); -#else - return (scb->platform_data->resid); -#endif -} - -static __inline -u_long ahc_get_sense_residual(struct scb *scb) -{ - return (scb->platform_data->sense_resid); -} - -static __inline -int ahc_perform_autosense(struct scb *scb) -{ - /* - * We always perform autosense in Linux. - * On other platforms this is set on a - * per-transaction basis. - */ - return (1); -} - -static __inline uint32_t -ahc_get_sense_bufsize(struct ahc_softc *ahc, struct scb *scb) -{ - return (sizeof(struct scsi_sense_data)); -} - -static __inline void -ahc_notify_xfer_settings_change(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo) -{ - /* Nothing to do here for linux */ -} - -static __inline void -ahc_platform_scb_free(struct ahc_softc *ahc, struct scb *scb) -{ - ahc->flags &= ~AHC_RESOURCE_SHORTAGE; -} - int ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg); void ahc_platform_free(struct ahc_softc *ahc); void ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb); - -static __inline void -ahc_freeze_scb(struct scb *scb) -{ - if ((scb->io_ctx->result & (CAM_DEV_QFRZN << 16)) == 0) { - scb->io_ctx->result |= CAM_DEV_QFRZN << 16; - scb->platform_data->dev->qfrozen++; - } -} - void ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, ahc_queue_alg); int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, @@ -1175,9 +414,9 @@ void ahc_print_path(struct ahc_softc *, void ahc_platform_dump_card_state(struct ahc_softc *ahc); #ifdef CONFIG_PCI -#define AHC_PCI_CONFIG 1 +#define AIC_PCI_CONFIG 1 #else -#define AHC_PCI_CONFIG 0 +#define AIC_PCI_CONFIG 0 #endif #define bootverbose aic7xxx_verbose extern u_int aic7xxx_verbose; diff -puN drivers/scsi/aic7xxx/aic7xxx_osm_pci.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7xxx_osm_pci.c --- 25/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c Wed Dec 24 12:15:38 2003 @@ -36,11 +36,17 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#45 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#52 $ */ #include "aic7xxx_osm.h" +/* + * Include aiclib_pci.c as part of our + * "module dependencies are hard" work around. + */ +#include "aiclib_pci.c" + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) struct pci_device_id { @@ -51,11 +57,9 @@ static int ahc_linux_pci_dev_probe(struc const struct pci_device_id *ent); static int ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, u_long *base); -#ifdef MMAPIO static int ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc, u_long *bus_addr, uint8_t **maddr); -#endif /* MMAPIO */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) static void ahc_linux_pci_dev_remove(struct pci_dev *pdev); @@ -97,12 +101,14 @@ ahc_linux_pci_dev_remove(struct pci_dev if (ahc != NULL) { u_long s; + TAILQ_REMOVE(&ahc_tailq, ahc, links); + ahc_list_unlock(&l); ahc_lock(ahc, &s); ahc_intr_enable(ahc, FALSE); ahc_unlock(ahc, &s); ahc_free(ahc); - } - ahc_list_unlock(&l); + } else + ahc_list_unlock(&l); } #endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */ @@ -112,7 +118,7 @@ ahc_linux_pci_dev_probe(struct pci_dev * char buf[80]; bus_addr_t mask_39bit; struct ahc_softc *ahc; - ahc_dev_softc_t pci; + aic_dev_softc_t dev; struct ahc_pci_identity *entry; char *name; int error; @@ -123,7 +129,7 @@ ahc_linux_pci_dev_probe(struct pci_dev * TAILQ_FOREACH(ahc, &ahc_tailq, links) { struct pci_dev *probed_pdev; - probed_pdev = ahc->dev_softc; + probed_pdev = aic_dev_to_pci_dev(ahc->dev_softc); if (probed_pdev->bus->number == pdev->bus->number && probed_pdev->devfn == pdev->devfn) break; @@ -133,8 +139,8 @@ ahc_linux_pci_dev_probe(struct pci_dev * return (-ENODEV); } - pci = pdev; - entry = ahc_find_pci_device(pci); + dev = aic_pci_dev_to_dev(pdev); + entry = ahc_find_pci_device(dev); if (entry == NULL) return (-ENODEV); @@ -144,9 +150,9 @@ ahc_linux_pci_dev_probe(struct pci_dev * * common detect routine. */ sprintf(buf, "ahc_pci:%d:%d:%d", - ahc_get_pci_bus(pci), - ahc_get_pci_slot(pci), - ahc_get_pci_function(pci)); + aic_get_pci_bus(dev), + aic_get_pci_slot(dev), + aic_get_pci_function(dev)); name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); if (name == NULL) return (-ENOMEM); @@ -154,6 +160,8 @@ ahc_linux_pci_dev_probe(struct pci_dev * ahc = ahc_alloc(NULL, name); if (ahc == NULL) return (-ENOMEM); + ahc->dev_softc = dev; + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (pci_enable_device(pdev)) { ahc_free(ahc); @@ -161,18 +169,17 @@ ahc_linux_pci_dev_probe(struct pci_dev * } pci_set_master(pdev); - mask_39bit = (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0); + mask_39bit = (bus_addr_t)0x7FFFFFFFFFULL; if (sizeof(bus_addr_t) > 4 && ahc_linux_get_memsize() > 0x80000000 - && ahc_pci_set_dma_mask(pdev, mask_39bit) == 0) { + && aic_set_dma_mask(ahc, mask_39bit) == 0) { ahc->flags |= AHC_39BIT_ADDRESSING; ahc->platform_data->hw_dma_mask = mask_39bit; } else { - ahc_pci_set_dma_mask(pdev, 0xFFFFFFFF); + aic_set_dma_mask(ahc, 0xFFFFFFFF); ahc->platform_data->hw_dma_mask = 0xFFFFFFFF; } #endif - ahc->dev_softc = pci; error = ahc_pci_config(ahc, entry); if (error != 0) { ahc_free(ahc); @@ -211,10 +218,8 @@ ahc_linux_pci_init(void) pdev = NULL; class = PCI_CLASS_STORAGE_SCSI << 8; while ((pdev = pci_find_class(class, pdev)) != NULL) { - ahc_dev_softc_t pci; int error; - pci = pdev; error = ahc_linux_pci_dev_probe(pdev, /*pci_devid*/NULL); if (error == 0) found++; @@ -236,9 +241,9 @@ ahc_linux_pci_reserve_io_region(struct a return (ENOMEM); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - *base = pci_resource_start(ahc->dev_softc, 0); + *base = pci_resource_start(aic_pci_dev(ahc), 0); #else - *base = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS, 4); + *base = aic_pci_read_config(ahc->dev_softc, PCIR_MAPS, 4); *base &= PCI_BASE_ADDRESS_IO_MASK; #endif if (*base == 0) @@ -254,7 +259,6 @@ ahc_linux_pci_reserve_io_region(struct a return (0); } -#ifdef MMAPIO static int ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc, u_long *bus_addr, @@ -267,11 +271,11 @@ ahc_linux_pci_reserve_mem_region(struct error = 0; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) - start = pci_resource_start(ahc->dev_softc, 1); + start = pci_resource_start(aic_pci_dev(ahc), 1); base_page = start & PAGE_MASK; base_offset = start - base_page; #else - start = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS+4, 4); + start = aic_pci_read_config(ahc->dev_softc, PCIR_MAPS+4, 4); base_offset = start & PCI_BASE_ADDRESS_MEM_MASK; base_page = base_offset & PAGE_MASK; base_offset -= base_page; @@ -296,7 +300,6 @@ ahc_linux_pci_reserve_mem_region(struct error = ENOMEM; return (error); } -#endif /* MMAPIO */ int ahc_pci_map_registers(struct ahc_softc *ahc) @@ -309,17 +312,16 @@ ahc_pci_map_registers(struct ahc_softc * /* * If its allowed, we prefer memory mapped access. */ - command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4); + command = aic_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4); command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN); base = 0; maddr = NULL; -#ifdef MMAPIO error = ahc_linux_pci_reserve_mem_region(ahc, &base, &maddr); if (error == 0) { ahc->platform_data->mem_busaddr = base; ahc->tag = BUS_SPACE_MEMIO; ahc->bsh.maddr = maddr; - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, + aic_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command | PCIM_CMD_MEMEN, 4); /* @@ -330,9 +332,9 @@ ahc_pci_map_registers(struct ahc_softc * printf("aic7xxx: PCI Device %d:%d:%d " "failed memory mapped test. Using PIO.\n", - ahc_get_pci_bus(ahc->dev_softc), - ahc_get_pci_slot(ahc->dev_softc), - ahc_get_pci_function(ahc->dev_softc)); + aic_get_pci_bus(ahc->dev_softc), + aic_get_pci_slot(ahc->dev_softc), + aic_get_pci_function(ahc->dev_softc)); iounmap((void *)((u_long)maddr & PAGE_MASK)); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) release_mem_region(ahc->platform_data->mem_busaddr, @@ -345,12 +347,11 @@ ahc_pci_map_registers(struct ahc_softc * } else { printf("aic7xxx: PCI%d:%d:%d MEM region 0x%lx " "unavailable. Cannot memory map device.\n", - ahc_get_pci_bus(ahc->dev_softc), - ahc_get_pci_slot(ahc->dev_softc), - ahc_get_pci_function(ahc->dev_softc), + aic_get_pci_bus(ahc->dev_softc), + aic_get_pci_slot(ahc->dev_softc), + aic_get_pci_function(ahc->dev_softc), base); } -#endif /* MMAPIO */ /* * We always prefer memory mapped access. @@ -358,20 +359,20 @@ ahc_pci_map_registers(struct ahc_softc * if (maddr == NULL) { error = ahc_linux_pci_reserve_io_region(ahc, &base); - if (error == 0) { + if (error == 0 && ahc_pci_test_register_access(ahc) == 0) { ahc->tag = BUS_SPACE_PIO; ahc->bsh.ioport = base; command |= PCIM_CMD_PORTEN; } else { printf("aic7xxx: PCI%d:%d:%d IO region 0x%lx[0..255] " "unavailable. Cannot map device.\n", - ahc_get_pci_bus(ahc->dev_softc), - ahc_get_pci_slot(ahc->dev_softc), - ahc_get_pci_function(ahc->dev_softc), + aic_get_pci_bus(ahc->dev_softc), + aic_get_pci_slot(ahc->dev_softc), + aic_get_pci_function(ahc->dev_softc), base); } } - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4); + aic_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4); return (error); } @@ -380,49 +381,10 @@ ahc_pci_map_int(struct ahc_softc *ahc) { int error; - error = request_irq(ahc->dev_softc->irq, ahc_linux_isr, + error = request_irq(aic_pci_dev(ahc)->irq, ahc_linux_isr, SA_SHIRQ, "aic7xxx", ahc); if (error == 0) - ahc->platform_data->irq = ahc->dev_softc->irq; + ahc->platform_data->irq = aic_pci_dev(ahc)->irq; return (-error); } - -void -ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - pci_set_power_state(ahc->dev_softc, new_state); -#else - uint32_t cap; - u_int cap_offset; - - /* - * Traverse the capability list looking for - * the power management capability. - */ - cap = 0; - cap_offset = ahc_pci_read_config(ahc->dev_softc, - PCIR_CAP_PTR, /*bytes*/1); - while (cap_offset != 0) { - - cap = ahc_pci_read_config(ahc->dev_softc, - cap_offset, /*bytes*/4); - if ((cap & 0xFF) == 1 - && ((cap >> 16) & 0x3) > 0) { - uint32_t pm_control; - - pm_control = ahc_pci_read_config(ahc->dev_softc, - cap_offset + 4, - /*bytes*/4); - pm_control &= ~0x3; - pm_control |= new_state; - ahc_pci_write_config(ahc->dev_softc, - cap_offset + 4, - pm_control, /*bytes*/2); - break; - } - cap_offset = (cap >> 8) & 0xFF; - } -#endif -} diff -puN drivers/scsi/aic7xxx/aic7xxx_pci.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7xxx_pci.c --- 25/drivers/scsi/aic7xxx/aic7xxx_pci.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7xxx_pci.c Wed Dec 24 12:15:38 2003 @@ -39,9 +39,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#66 $ - * - * $FreeBSD$ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#78 $ */ #ifdef __linux__ @@ -49,14 +47,13 @@ #include "aic7xxx_inline.h" #include "aic7xxx_93cx6.h" #else +#include +__FBSDID("$FreeBSD$"); #include #include #include #endif -#define AHC_PCI_IOADDR PCIR_MAPS /* I/O Address */ -#define AHC_PCI_MEMADDR (PCIR_MAPS + 4) /* Mem I/O Address */ - static __inline uint64_t ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor) { @@ -76,7 +73,7 @@ ahc_compose_id(u_int device, u_int vendo #define ID_9005_SISL_MASK 0x000FFFFF00000000ull #define ID_9005_SISL_ID 0x0005900500000000ull #define ID_AIC7850 0x5078900400000000ull -#define ID_AHA_2902_04_10_15_20_30C 0x5078900478509004ull +#define ID_AHA_2902_04_10_15_20C_30C 0x5078900478509004ull #define ID_AIC7855 0x5578900400000000ull #define ID_AIC7859 0x3860900400000000ull #define ID_AHA_2930CU 0x3860900438699004ull @@ -133,6 +130,7 @@ ahc_compose_id(u_int device, u_int vendo #define ID_AHA_29160C 0x0080900562209005ull #define ID_AHA_29160B 0x00809005E2209005ull #define ID_AHA_19160B 0x0081900562A19005ull +#define ID_AHA_2915_30LP 0x0082900502109005ull #define ID_AIC7896 0x005F9005FFFF9005ull #define ID_AIC7896_ARO 0x00539005FFFF9005ull @@ -245,9 +243,9 @@ struct ahc_pci_identity ahc_pci_ident_ta { /* aic7850 based controllers */ { - ID_AHA_2902_04_10_15_20_30C, + ID_AHA_2902_04_10_15_20C_30C, ID_ALL_MASK, - "Adaptec 2902/04/10/15/20/30C SCSI adapter", + "Adaptec 2902/04/10/15/20C/30C SCSI adapter", ahc_aic785X_setup }, /* aic7860 based controllers */ @@ -470,6 +468,12 @@ struct ahc_pci_identity ahc_pci_ident_ta "Adaptec aic7892 Ultra160 SCSI adapter (ARO)", ahc_aic7892_setup }, + { + ID_AHA_2915_30LP, + ID_ALL_MASK, + "Adaptec 2915/30LP Ultra160 SCSI adapter", + ahc_aic7892_setup + }, /* aic7895 based controllers */ { ID_AHA_2940U_DUAL, @@ -738,7 +742,7 @@ ahc_9005_subdevinfo_valid(uint16_t devic } struct ahc_pci_identity * -ahc_find_pci_device(ahc_dev_softc_t pci) +ahc_find_pci_device(aic_dev_softc_t pci) { uint64_t full_id; uint16_t device; @@ -748,10 +752,10 @@ ahc_find_pci_device(ahc_dev_softc_t pci) struct ahc_pci_identity *entry; u_int i; - vendor = ahc_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2); - device = ahc_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2); - subvendor = ahc_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2); - subdevice = ahc_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2); + vendor = aic_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2); + device = aic_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2); + subvendor = aic_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2); + subdevice = aic_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2); full_id = ahc_compose_id(device, vendor, subdevice, subvendor); /* @@ -761,7 +765,7 @@ ahc_find_pci_device(ahc_dev_softc_t pci) * to sanity check it prior to accepting the subdevice * ID as valid. */ - if (ahc_get_pci_function(pci) > 0 + if (aic_get_pci_function(pci) > 0 && ahc_9005_subdevinfo_valid(vendor, device, subvendor, subdevice) && SUBID_9005_MFUNCENB(subdevice) == 0) return (NULL); @@ -798,7 +802,7 @@ ahc_pci_config(struct ahc_softc *ahc, st ahc->chip |= AHC_PCI; ahc->description = entry->name; - ahc_power_state_change(ahc, AHC_POWER_STATE_D0); + aic_power_state_change(ahc, AIC_POWER_STATE_D0); error = ahc_pci_map_registers(ahc); if (error != 0) @@ -812,7 +816,7 @@ ahc_pci_config(struct ahc_softc *ahc, st */ ahc_intr_enable(ahc, FALSE); - devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); + devconfig = aic_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); /* * If we need to support high memory, enable dual @@ -831,13 +835,13 @@ ahc_pci_config(struct ahc_softc *ahc, st /* Ensure that pci error generation, a test feature, is disabled. */ devconfig |= PCIERRGENDIS; - ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); + aic_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); /* Ensure busmastering is enabled */ - command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2); + command = aic_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2); command |= PCIM_CMD_BUSMASTEREN; - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/2); + aic_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/2); /* On all PCI adapters, we allow SCB paging */ ahc->flags |= AHC_PAGESCBS; @@ -877,7 +881,7 @@ ahc_pci_config(struct ahc_softc *ahc, st scsiseq = 0; } - error = ahc_reset(ahc); + error = ahc_reset(ahc, /*reinit*/FALSE); if (error != 0) return (ENXIO); @@ -920,14 +924,14 @@ ahc_pci_config(struct ahc_softc *ahc, st ahc_outb(ahc, DSCOMMAND0, dscommand0); ahc->pci_cachesize = - ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, + aic_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1) & CACHESIZE; ahc->pci_cachesize *= 4; if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0 && ahc->pci_cachesize == 4) { - ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, + aic_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, 0, /*bytes*/1); ahc->pci_cachesize = 0; } @@ -939,7 +943,7 @@ ahc_pci_config(struct ahc_softc *ahc, st if ((ahc->features & AHC_ULTRA) != 0) { uint32_t devconfig; - devconfig = ahc_pci_read_config(ahc->dev_softc, + devconfig = aic_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); if ((devconfig & REXTVALID) == 0) ahc->features &= ~AHC_ULTRA; @@ -1005,11 +1009,11 @@ ahc_pci_config(struct ahc_softc *ahc, st * that occur during runtime and resume events. */ ahc->bus_softc.pci_softc.devconfig = - ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); + aic_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); ahc->bus_softc.pci_softc.command = - ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1); + aic_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1); ahc->bus_softc.pci_softc.csize_lattime = - ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1); + aic_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1); ahc->bus_softc.pci_softc.dscommand0 = ahc_inb(ahc, DSCOMMAND0); ahc->bus_softc.pci_softc.dspcistatus = ahc_inb(ahc, DSPCISTATUS); if ((ahc->features & AHC_DT) != 0) { @@ -1063,7 +1067,7 @@ ahc_ext_scbram_present(struct ahc_softc uint32_t devconfig; chip = ahc->chip & AHC_CHIPID_MASK; - devconfig = ahc_pci_read_config(ahc->dev_softc, + devconfig = aic_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); single_user = (devconfig & MPORTMODE) != 0; @@ -1101,13 +1105,13 @@ ahc_scbram_config(struct ahc_softc *ahc, * Set the SCB Base addr (highest address bit) * depending on which channel we are. */ - ahc_outb(ahc, SCBBADDR, ahc_get_pci_function(ahc->dev_softc)); + ahc_outb(ahc, SCBBADDR, aic_get_pci_function(ahc->dev_softc)); } ahc->flags &= ~AHC_LSCBS_ENABLED; if (large) ahc->flags |= AHC_LSCBS_ENABLED; - devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); + devconfig = aic_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); if ((ahc->features & AHC_ULTRA2) != 0) { u_int dscommand0; @@ -1140,7 +1144,7 @@ ahc_scbram_config(struct ahc_softc *ahc, else devconfig &= ~EXTSCBPEN; - ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); + aic_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); } /* @@ -1263,8 +1267,8 @@ ahc_pci_test_register_access(struct ahc_ * Enable PCI error interrupt status, but suppress NMIs * generated by SERR raised due to target aborts. */ - cmd = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2); - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, + cmd = aic_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2); + aic_pci_write_config(ahc->dev_softc, PCIR_COMMAND, cmd & ~PCIM_CMD_SERRESPEN, /*bytes*/2); /* @@ -1276,26 +1280,46 @@ ahc_pci_test_register_access(struct ahc_ * use for this test. */ hcntrl = ahc_inb(ahc, HCNTRL); + if (hcntrl == 0xFF) goto fail; + if ((hcntrl & CHIPRST) != 0) { + /* + * The chip has not been initialized since + * PCI/EISA/VLB bus reset. Don't trust + * "left over BIOS data". + */ + ahc->flags |= AHC_NO_BIOS_INIT; + } + /* * Next create a situation where write combining * or read prefetching could be initiated by the * CPU or host bridge. Our device does not support * either, so look for data corruption and/or flagged - * PCI errors. + * PCI errors. First pause without causing another + * chip reset. */ + hcntrl &= ~CHIPRST; ahc_outb(ahc, HCNTRL, hcntrl|PAUSE); while (ahc_is_paused(ahc) == 0) ; + + /* Clear any PCI errors that occurred before our driver attached. */ + status1 = aic_pci_read_config(ahc->dev_softc, + PCIR_STATUS + 1, /*bytes*/1); + aic_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, + status1, /*bytes*/1); + ahc_outb(ahc, CLRINT, CLRPARERR); + ahc_outb(ahc, SEQCTL, PERRORDIS); ahc_outb(ahc, SCBPTR, 0); ahc_outl(ahc, SCB_BASE, 0x5aa555aa); if (ahc_inl(ahc, SCB_BASE) != 0x5aa555aa) goto fail; - status1 = ahc_pci_read_config(ahc->dev_softc, + status1 = aic_pci_read_config(ahc->dev_softc, PCIR_STATUS + 1, /*bytes*/1); if ((status1 & STA) != 0) goto fail; @@ -1304,13 +1328,13 @@ ahc_pci_test_register_access(struct ahc_ fail: /* Silently clear any latched errors. */ - status1 = ahc_pci_read_config(ahc->dev_softc, + status1 = aic_pci_read_config(ahc->dev_softc, PCIR_STATUS + 1, /*bytes*/1); - ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, + aic_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, status1, /*bytes*/1); ahc_outb(ahc, CLRINT, CLRPARERR); ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS); - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2); + aic_pci_write_config(ahc->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2); return (error); } @@ -1380,6 +1404,10 @@ check_extport(struct ahc_softc *ahc, u_i sd.sd_chip = C56_66; } ahc_release_seeprom(&sd); + + /* Remember the SEEPROM type for later */ + if (sd.sd_chip == C56_66) + ahc->flags |= AHC_LARGE_SEEPROM; } if (!have_seeprom) { @@ -1565,12 +1593,12 @@ ahc_parse_pci_eeprom(struct ahc_softc *a uint32_t devconfig; /* Honor the STPWLEVEL settings */ - devconfig = ahc_pci_read_config(ahc->dev_softc, + devconfig = aic_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); devconfig &= ~STPWLEVEL; if ((sc->bios_control & CFSTPWLEVEL) != 0) devconfig |= STPWLEVEL; - ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, + aic_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); } /* Set SCSICONF info */ @@ -1883,10 +1911,10 @@ aic785X_cable_detect(struct ahc_softc *a ahc_outb(ahc, SPIOCAP, spiocap); ahc_outb(ahc, BRDCTL, BRDRW|BRDCS); ahc_flush_device_writes(ahc); - ahc_delay(500); + aic_delay(500); ahc_outb(ahc, BRDCTL, 0); ahc_flush_device_writes(ahc); - ahc_delay(500); + aic_delay(500); brdctl = ahc_inb(ahc, BRDCTL); *internal50_present = (brdctl & BRDDAT5) ? 0 : 1; *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1; @@ -1912,7 +1940,7 @@ ahc_acquire_seeprom(struct ahc_softc *ah SEEPROM_OUTB(sd, sd->sd_MS); wait = 1000; /* 1 second timeout in msec */ while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) { - ahc_delay(1000); /* delay 1 msec */ + aic_delay(1000); /* delay 1 msec */ } if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) { SEEPROM_OUTB(sd, 0); @@ -1992,7 +2020,7 @@ ahc_pci_intr(struct ahc_softc *ahc) if ((error & PCIERRSTAT) == 0) return; - status1 = ahc_pci_read_config(ahc->dev_softc, + status1 = aic_pci_read_config(ahc->dev_softc, PCIR_STATUS + 1, /*bytes*/1); printf("%s: PCI error Interrupt at seqaddr = 0x%x\n", @@ -2022,7 +2050,7 @@ ahc_pci_intr(struct ahc_softc *ahc) } /* Clear latched errors. */ - ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, + aic_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, status1, /*bytes*/1); if ((status1 & (DPE|SSE|RMA|RTA|STA|DPR)) == 0) { @@ -2083,7 +2111,7 @@ static int ahc_pci_resume(struct ahc_softc *ahc) { - ahc_power_state_change(ahc, AHC_POWER_STATE_D0); + aic_power_state_change(ahc, AIC_POWER_STATE_D0); /* * We assume that the OS has restored our register @@ -2091,11 +2119,11 @@ ahc_pci_resume(struct ahc_softc *ahc) * that the OS doesn't know about and rely on our chip * reset handler to handle the rest. */ - ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4, + aic_pci_write_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4, ahc->bus_softc.pci_softc.devconfig); - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1, + aic_pci_write_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1, ahc->bus_softc.pci_softc.command); - ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1, + aic_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1, ahc->bus_softc.pci_softc.csize_lattime); if ((ahc->flags & AHC_HAS_TERM_LOGIC) != 0) { struct seeprom_descriptor sd; @@ -2118,7 +2146,7 @@ ahc_pci_resume(struct ahc_softc *ahc) static int ahc_aic785X_setup(struct ahc_softc *ahc) { - ahc_dev_softc_t pci; + aic_dev_softc_t pci; uint8_t rev; pci = ahc->dev_softc; @@ -2126,7 +2154,7 @@ ahc_aic785X_setup(struct ahc_softc *ahc) ahc->chip = AHC_AIC7850; ahc->features = AHC_AIC7850_FE; ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; - rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); + rev = aic_pci_read_config(pci, PCIR_REVID, /*bytes*/1); if (rev >= 1) ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; ahc->instruction_ram_size = 512; @@ -2136,7 +2164,7 @@ ahc_aic785X_setup(struct ahc_softc *ahc) static int ahc_aic7860_setup(struct ahc_softc *ahc) { - ahc_dev_softc_t pci; + aic_dev_softc_t pci; uint8_t rev; pci = ahc->dev_softc; @@ -2144,7 +2172,7 @@ ahc_aic7860_setup(struct ahc_softc *ahc) ahc->chip = AHC_AIC7860; ahc->features = AHC_AIC7860_FE; ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; - rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); + rev = aic_pci_read_config(pci, PCIR_REVID, /*bytes*/1); if (rev >= 1) ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; ahc->instruction_ram_size = 512; @@ -2211,7 +2239,7 @@ ahc_aha494X_setup(struct ahc_softc *ahc) static int ahc_aic7880_setup(struct ahc_softc *ahc) { - ahc_dev_softc_t pci; + aic_dev_softc_t pci; uint8_t rev; pci = ahc->dev_softc; @@ -2219,7 +2247,7 @@ ahc_aic7880_setup(struct ahc_softc *ahc) ahc->chip = AHC_AIC7880; ahc->features = AHC_AIC7880_FE; ahc->bugs |= AHC_TMODE_WIDEODD_BUG; - rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); + rev = aic_pci_read_config(pci, PCIR_REVID, /*bytes*/1); if (rev >= 1) { ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; } else { @@ -2262,7 +2290,7 @@ ahc_aha398XU_setup(struct ahc_softc *ahc static int ahc_aic7890_setup(struct ahc_softc *ahc) { - ahc_dev_softc_t pci; + aic_dev_softc_t pci; uint8_t rev; pci = ahc->dev_softc; @@ -2270,7 +2298,7 @@ ahc_aic7890_setup(struct ahc_softc *ahc) ahc->chip = AHC_AIC7890; ahc->features = AHC_AIC7890_FE; ahc->flags |= AHC_NEWEEPROM_FMT; - rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); + rev = aic_pci_read_config(pci, PCIR_REVID, /*bytes*/1); if (rev == 0) ahc->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG; ahc->instruction_ram_size = 768; @@ -2293,15 +2321,15 @@ ahc_aic7892_setup(struct ahc_softc *ahc) static int ahc_aic7895_setup(struct ahc_softc *ahc) { - ahc_dev_softc_t pci; + aic_dev_softc_t pci; uint8_t rev; pci = ahc->dev_softc; - ahc->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A'; + ahc->channel = aic_get_pci_function(pci) == 1 ? 'B' : 'A'; /* * The 'C' revision of the aic7895 has a few additional features. */ - rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); + rev = aic_pci_read_config(pci, PCIR_REVID, /*bytes*/1); if (rev >= 4) { ahc->chip = AHC_AIC7895C; ahc->features = AHC_AIC7895C_FE; @@ -2317,9 +2345,9 @@ ahc_aic7895_setup(struct ahc_softc *ahc) * we have. Disabling MWI reduces performance, so * turn it on again. */ - command = ahc_pci_read_config(pci, PCIR_COMMAND, /*bytes*/1); + command = aic_pci_read_config(pci, PCIR_COMMAND, /*bytes*/1); command |= PCIM_CMD_MWRICEN; - ahc_pci_write_config(pci, PCIR_COMMAND, command, /*bytes*/1); + aic_pci_write_config(pci, PCIR_COMMAND, command, /*bytes*/1); ahc->bugs |= AHC_PCI_MWI_BUG; } /* @@ -2336,10 +2364,10 @@ ahc_aic7895_setup(struct ahc_softc *ahc) * Cachesize must also be zero due to stray DAC * problem when sitting behind some bridges. */ - ahc_pci_write_config(pci, CSIZE_LATTIME, 0, /*bytes*/1); - devconfig = ahc_pci_read_config(pci, DEVCONFIG, /*bytes*/1); + aic_pci_write_config(pci, CSIZE_LATTIME, 0, /*bytes*/1); + devconfig = aic_pci_read_config(pci, DEVCONFIG, /*bytes*/1); devconfig |= MRDCEN; - ahc_pci_write_config(pci, DEVCONFIG, devconfig, /*bytes*/1); + aic_pci_write_config(pci, DEVCONFIG, devconfig, /*bytes*/1); #endif ahc->flags |= AHC_NEWEEPROM_FMT; ahc->instruction_ram_size = 512; @@ -2349,10 +2377,10 @@ ahc_aic7895_setup(struct ahc_softc *ahc) static int ahc_aic7896_setup(struct ahc_softc *ahc) { - ahc_dev_softc_t pci; + aic_dev_softc_t pci; pci = ahc->dev_softc; - ahc->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A'; + ahc->channel = aic_get_pci_function(pci) == 1 ? 'B' : 'A'; ahc->chip = AHC_AIC7896; ahc->features = AHC_AIC7896_FE; ahc->flags |= AHC_NEWEEPROM_FMT; @@ -2364,10 +2392,10 @@ ahc_aic7896_setup(struct ahc_softc *ahc) static int ahc_aic7899_setup(struct ahc_softc *ahc) { - ahc_dev_softc_t pci; + aic_dev_softc_t pci; pci = ahc->dev_softc; - ahc->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A'; + ahc->channel = aic_get_pci_function(pci) == 1 ? 'B' : 'A'; ahc->chip = AHC_AIC7899; ahc->features = AHC_AIC7899_FE; ahc->flags |= AHC_NEWEEPROM_FMT; @@ -2398,10 +2426,10 @@ ahc_raid_setup(struct ahc_softc *ahc) static int ahc_aha394XX_setup(struct ahc_softc *ahc) { - ahc_dev_softc_t pci; + aic_dev_softc_t pci; pci = ahc->dev_softc; - switch (ahc_get_pci_slot(pci)) { + switch (aic_get_pci_slot(pci)) { case AHC_394X_SLOT_CHANNEL_A: ahc->channel = 'A'; break; @@ -2411,7 +2439,7 @@ ahc_aha394XX_setup(struct ahc_softc *ahc default: printf("adapter at unexpected slot %d\n" "unable to map to a channel\n", - ahc_get_pci_slot(pci)); + aic_get_pci_slot(pci)); ahc->channel = 'A'; } return (0); @@ -2420,10 +2448,10 @@ ahc_aha394XX_setup(struct ahc_softc *ahc static int ahc_aha398XX_setup(struct ahc_softc *ahc) { - ahc_dev_softc_t pci; + aic_dev_softc_t pci; pci = ahc->dev_softc; - switch (ahc_get_pci_slot(pci)) { + switch (aic_get_pci_slot(pci)) { case AHC_398X_SLOT_CHANNEL_A: ahc->channel = 'A'; break; @@ -2436,7 +2464,7 @@ ahc_aha398XX_setup(struct ahc_softc *ahc default: printf("adapter at unexpected slot %d\n" "unable to map to a channel\n", - ahc_get_pci_slot(pci)); + aic_get_pci_slot(pci)); ahc->channel = 'A'; break; } @@ -2447,10 +2475,10 @@ ahc_aha398XX_setup(struct ahc_softc *ahc static int ahc_aha494XX_setup(struct ahc_softc *ahc) { - ahc_dev_softc_t pci; + aic_dev_softc_t pci; pci = ahc->dev_softc; - switch (ahc_get_pci_slot(pci)) { + switch (aic_get_pci_slot(pci)) { case AHC_494X_SLOT_CHANNEL_A: ahc->channel = 'A'; break; @@ -2466,7 +2494,7 @@ ahc_aha494XX_setup(struct ahc_softc *ahc default: printf("adapter at unexpected slot %d\n" "unable to map to a channel\n", - ahc_get_pci_slot(pci)); + aic_get_pci_slot(pci)); ahc->channel = 'A'; } ahc->flags |= AHC_LARGE_SEEPROM; diff -puN drivers/scsi/aic7xxx/aic7xxx_proc.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7xxx_proc.c --- 25/drivers/scsi/aic7xxx/aic7xxx_proc.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7xxx_proc.c Wed Dec 24 12:15:38 2003 @@ -37,7 +37,7 @@ * String handling code courtesy of Gerard Roudier's * sym driver. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#27 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#32 $ */ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" @@ -50,7 +50,7 @@ static void ahc_dump_target_state(struct u_int our_id, char channel, u_int target_id, u_int target_offset); static void ahc_dump_device_state(struct info_str *info, - struct ahc_linux_device *dev); + struct aic_linux_device *dev); static int ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length); @@ -141,7 +141,7 @@ ahc_dump_target_state(struct ahc_softc * u_int our_id, char channel, u_int target_id, u_int target_offset) { - struct ahc_linux_target *targ; + struct aic_linux_target *targ; struct ahc_initiator_tinfo *tinfo; struct ahc_tmode_tstate *tstate; int lun; @@ -163,7 +163,7 @@ ahc_dump_target_state(struct ahc_softc * ahc_format_transinfo(info, &tinfo->curr); for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct ahc_linux_device *dev; + struct aic_linux_device *dev; dev = targ->devices[lun]; @@ -175,7 +175,7 @@ ahc_dump_target_state(struct ahc_softc * } static void -ahc_dump_device_state(struct info_str *info, struct ahc_linux_device *dev) +ahc_dump_device_state(struct info_str *info, struct aic_linux_device *dev) { copy_info(info, "\tChannel %c Target %d Lun %d Settings\n", dev->target->channel + 'A', dev->target->target, dev->lun); @@ -204,7 +204,8 @@ ahc_proc_write_seeprom(struct ahc_softc ahc_pause(ahc); if (length != sizeof(struct seeprom_config)) { - printf("ahc_proc_write_seeprom: incorrect buffer size\n"); + printf("ahc_proc_write_seeprom: incorrect buffer size %d\n", + length); goto done; } @@ -215,7 +216,7 @@ ahc_proc_write_seeprom(struct ahc_softc } sd.sd_ahc = ahc; -#if AHC_PCI_CONFIG > 0 +#if AIC_PCI_CONFIG > 0 if ((ahc->chip & AHC_PCI) != 0) { sd.sd_control_offset = SEECTL; sd.sd_status_offset = SEECTL; @@ -271,7 +272,7 @@ ahc_proc_write_seeprom(struct ahc_softc sizeof(struct seeprom_config)/2); ahc_read_seeprom(&sd, (uint16_t *)ahc->seep_config, start_addr, sizeof(struct seeprom_config)/2); -#if AHC_PCI_CONFIG > 0 +#if AIC_PCI_CONFIG > 0 if ((ahc->chip & AHC_VL) == 0) ahc_release_seeprom(&sd); #endif @@ -289,8 +290,13 @@ done: * Return information to handle /proc support for the driver. */ int -ahc_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, - int length, int inout) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +ahc_linux_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int inout) +#else +ahc_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, + off_t offset, int length, int inout) +#endif { struct ahc_softc *ahc; struct info_str info; @@ -302,10 +308,14 @@ ahc_linux_proc_info(struct Scsi_Host *sh retval = -EINVAL; ahc_list_lock(&s); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) TAILQ_FOREACH(ahc, &ahc_tailq, links) { - if (ahc->platform_data->host == shost) + if (ahc->platform_data->host->host_no == hostno) break; } +#else + ahc = ahc_find_softc(*(struct ahc_softc **)shost->hostdata); +#endif if (ahc == NULL) goto done; diff -puN drivers/scsi/aic7xxx/aic7xxx.reg~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7xxx.reg --- 25/drivers/scsi/aic7xxx/aic7xxx.reg~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7xxx.reg Wed Dec 24 12:15:38 2003 @@ -39,7 +39,7 @@ * * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -1306,7 +1306,6 @@ scratch_ram { */ MWI_RESIDUAL { size 1 - alias TARG_IMMEDIATE_SCB } /* * SCBID of the next SCB to be started by the controller. @@ -1461,6 +1460,7 @@ scratch_ram { */ LAST_MSG { size 1 + alias TARG_IMMEDIATE_SCB } /* diff -puN drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped --- 25/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped Wed Dec 24 12:15:38 2003 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $ */ typedef int (ahc_reg_print_t)(u_int, u_int *, u_int); typedef struct ahc_reg_parse_entry { @@ -1298,7 +1298,6 @@ ahc_reg_print_t ahc_sg_cache_pre_print; #define CMDSIZE_TABLE_TAIL 0x34 #define MWI_RESIDUAL 0x38 -#define TARG_IMMEDIATE_SCB 0x38 #define NEXT_QUEUED_SCB 0x39 @@ -1380,6 +1379,7 @@ ahc_reg_print_t ahc_sg_cache_pre_print; #define RETURN_2 0x52 #define LAST_MSG 0x53 +#define TARG_IMMEDIATE_SCB 0x53 #define SCSISEQ_TEMPLATE 0x54 #define ENSELO 0x40 diff -puN drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped --- 25/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped Wed Dec 24 12:15:38 2003 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $ */ #include "aic7xxx_osm.h" @@ -747,13 +747,6 @@ ahc_scsiseq_template_print(u_int regvalu 0x54, regvalue, cur_col, wrap)); } -int -ahc_data_count_odd_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(NULL, 0, "DATA_COUNT_ODD", - 0x55, regvalue, cur_col, wrap)); -} - static ahc_reg_parse_entry_t HA_274_BIOSGLOBAL_parse_table[] = { { "HA_274_EXTENDED_TRANS",0x01, 0x01 } }; @@ -1416,13 +1409,14 @@ ahc_scb_scsiid_print(u_int regvalue, u_i } static ahc_reg_parse_entry_t SCB_LUN_parse_table[] = { - { "LID", 0xff, 0xff } + { "SCB_XFERLEN_ODD", 0x80, 0x80 }, + { "LID", 0x3f, 0x3f } }; int ahc_scb_lun_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahc_print_register(SCB_LUN_parse_table, 1, "SCB_LUN", + return (ahc_print_register(SCB_LUN_parse_table, 2, "SCB_LUN", 0xba, regvalue, cur_col, wrap)); } @@ -1662,28 +1656,26 @@ ahc_dff_thrsh_print(u_int regvalue, u_in static ahc_reg_parse_entry_t SG_CACHE_SHADOW_parse_table[] = { { "LAST_SEG_DONE", 0x01, 0x01 }, { "LAST_SEG", 0x02, 0x02 }, - { "ODD_SEG", 0x04, 0x04 }, { "SG_ADDR_MASK", 0xf8, 0xf8 } }; int ahc_sg_cache_shadow_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahc_print_register(SG_CACHE_SHADOW_parse_table, 4, "SG_CACHE_SHADOW", + return (ahc_print_register(SG_CACHE_SHADOW_parse_table, 3, "SG_CACHE_SHADOW", 0xfc, regvalue, cur_col, wrap)); } static ahc_reg_parse_entry_t SG_CACHE_PRE_parse_table[] = { { "LAST_SEG_DONE", 0x01, 0x01 }, { "LAST_SEG", 0x02, 0x02 }, - { "ODD_SEG", 0x04, 0x04 }, { "SG_ADDR_MASK", 0xf8, 0xf8 } }; int ahc_sg_cache_pre_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahc_print_register(SG_CACHE_PRE_parse_table, 4, "SG_CACHE_PRE", + return (ahc_print_register(SG_CACHE_PRE_parse_table, 3, "SG_CACHE_PRE", 0xfc, regvalue, cur_col, wrap)); } diff -puN drivers/scsi/aic7xxx/aic7xxx.seq~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7xxx.seq --- 25/drivers/scsi/aic7xxx/aic7xxx.seq~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7xxx.seq Wed Dec 24 12:15:38 2003 @@ -40,7 +40,7 @@ * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $" PATCH_ARG_LIST = "struct ahc_softc *ahc" PREFIX = "ahc_" @@ -679,6 +679,7 @@ await_busfree: clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ } and SXFRCTL0, ~SPIOEN; + mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT; test SSTAT1,REQINIT|BUSFREE jz .; test SSTAT1, BUSFREE jnz poll_for_work; mvi MISSED_BUSFREE call set_seqint; @@ -1097,7 +1098,7 @@ ultra2_dmahalt: test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; if ((ahc->flags & AHC_TARGETROLE) != 0) { test SSTAT0, TARGET jz dma_last_sg; - if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) { + if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0) { test DMAPARAMS, DIRECTION jz dma_mid_sg; } } diff -puN drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped --- 25/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped Wed Dec 24 12:15:38 2003 @@ -2,13 +2,13 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $ */ static uint8_t seqprog[] = { 0xb2, 0x00, 0x00, 0x08, 0xf7, 0x11, 0x22, 0x08, - 0x00, 0x65, 0xec, 0x59, + 0x00, 0x65, 0xee, 0x59, 0xf7, 0x01, 0x02, 0x08, 0xff, 0x6a, 0x24, 0x08, 0x40, 0x00, 0x40, 0x68, @@ -21,15 +21,15 @@ static uint8_t seqprog[] = { 0x01, 0x4d, 0xc8, 0x30, 0x00, 0x4c, 0x12, 0x70, 0x01, 0x39, 0xa2, 0x30, - 0x00, 0x6a, 0xc0, 0x5e, + 0x00, 0x6a, 0xc2, 0x5e, 0x01, 0x51, 0x20, 0x31, 0x01, 0x57, 0xae, 0x00, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0x12, 0x5e, + 0x00, 0x51, 0x14, 0x5e, 0x01, 0x51, 0xc8, 0x30, 0x00, 0x39, 0xc8, 0x60, 0x00, 0xbb, 0x30, 0x70, - 0xc1, 0x6a, 0xd8, 0x5e, + 0xc1, 0x6a, 0xda, 0x5e, 0x01, 0xbf, 0x72, 0x30, 0x01, 0x40, 0x7e, 0x31, 0x01, 0x90, 0x80, 0x30, @@ -49,10 +49,10 @@ static uint8_t seqprog[] = { 0x08, 0x6a, 0x78, 0x00, 0x01, 0x50, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xfc, 0x5d, + 0x48, 0x6a, 0xfe, 0x5d, 0x01, 0x6a, 0xdc, 0x01, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xfc, 0x5d, + 0x48, 0x6a, 0xfe, 0x5d, 0x01, 0x6a, 0x26, 0x01, 0xf0, 0x19, 0x7a, 0x08, 0x0f, 0x18, 0xc8, 0x08, @@ -93,7 +93,7 @@ static uint8_t seqprog[] = { 0x00, 0x65, 0x20, 0x41, 0x02, 0x57, 0xae, 0x00, 0x00, 0x65, 0x9e, 0x40, - 0x61, 0x6a, 0xd8, 0x5e, + 0x61, 0x6a, 0xda, 0x5e, 0x08, 0x51, 0x20, 0x71, 0x02, 0x0b, 0xb2, 0x78, 0x00, 0x65, 0xae, 0x40, @@ -106,7 +106,7 @@ static uint8_t seqprog[] = { 0x80, 0x3d, 0x7a, 0x00, 0x20, 0x6a, 0x16, 0x00, 0x00, 0x65, 0xcc, 0x41, - 0x00, 0x65, 0xb2, 0x5e, + 0x00, 0x65, 0xb4, 0x5e, 0x00, 0x65, 0x12, 0x40, 0x20, 0x11, 0xd2, 0x68, 0x20, 0x6a, 0x18, 0x00, @@ -140,27 +140,27 @@ static uint8_t seqprog[] = { 0x80, 0x0b, 0xc4, 0x79, 0x12, 0x01, 0x02, 0x00, 0x01, 0xab, 0xac, 0x30, - 0xe4, 0x6a, 0x6e, 0x5d, + 0xe4, 0x6a, 0x70, 0x5d, 0x40, 0x6a, 0x16, 0x00, - 0x80, 0x3e, 0x84, 0x5d, + 0x80, 0x3e, 0x86, 0x5d, 0x20, 0xb8, 0x18, 0x79, - 0x20, 0x6a, 0x84, 0x5d, - 0x00, 0xab, 0x84, 0x5d, + 0x20, 0x6a, 0x86, 0x5d, + 0x00, 0xab, 0x86, 0x5d, 0x01, 0xa9, 0x78, 0x30, 0x10, 0xb8, 0x20, 0x79, - 0xe4, 0x6a, 0x6e, 0x5d, + 0xe4, 0x6a, 0x70, 0x5d, 0x00, 0x65, 0xae, 0x40, 0x10, 0x03, 0x3c, 0x69, 0x08, 0x3c, 0x5a, 0x69, 0x04, 0x3c, 0x92, 0x69, 0x02, 0x3c, 0x98, 0x69, 0x01, 0x3c, 0x44, 0x79, - 0xff, 0x6a, 0x70, 0x00, + 0xff, 0x6a, 0xa6, 0x00, 0x00, 0x65, 0xa4, 0x59, - 0x00, 0x6a, 0xc0, 0x5e, - 0xff, 0x38, 0x30, 0x71, + 0x00, 0x6a, 0xc2, 0x5e, + 0xff, 0x53, 0x30, 0x71, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x38, 0x12, 0x5e, + 0x00, 0x53, 0x14, 0x5e, 0x00, 0x65, 0xea, 0x58, 0x12, 0x01, 0x02, 0x00, 0x00, 0x65, 0x18, 0x41, @@ -168,10 +168,10 @@ static uint8_t seqprog[] = { 0x00, 0x65, 0xf2, 0x58, 0xfd, 0x57, 0xae, 0x08, 0x00, 0x65, 0xae, 0x40, - 0xe4, 0x6a, 0x6e, 0x5d, + 0xe4, 0x6a, 0x70, 0x5d, 0x20, 0x3c, 0x4a, 0x79, - 0x02, 0x6a, 0x84, 0x5d, - 0x04, 0x6a, 0x84, 0x5d, + 0x02, 0x6a, 0x86, 0x5d, + 0x04, 0x6a, 0x86, 0x5d, 0x01, 0x03, 0x4c, 0x69, 0xf7, 0x11, 0x22, 0x08, 0xff, 0x6a, 0x24, 0x08, @@ -182,13 +182,13 @@ static uint8_t seqprog[] = { 0x80, 0x86, 0xc8, 0x08, 0x01, 0x4f, 0xc8, 0x30, 0x00, 0x50, 0x6c, 0x61, - 0xc4, 0x6a, 0x6e, 0x5d, + 0xc4, 0x6a, 0x70, 0x5d, 0x40, 0x3c, 0x68, 0x79, - 0x28, 0x6a, 0x84, 0x5d, + 0x28, 0x6a, 0x86, 0x5d, 0x00, 0x65, 0x4c, 0x41, - 0x08, 0x6a, 0x84, 0x5d, + 0x08, 0x6a, 0x86, 0x5d, 0x00, 0x65, 0x4c, 0x41, - 0x84, 0x6a, 0x6e, 0x5d, + 0x84, 0x6a, 0x70, 0x5d, 0x00, 0x65, 0xf2, 0x58, 0x01, 0x66, 0xc8, 0x30, 0x01, 0x64, 0xd8, 0x31, @@ -208,16 +208,16 @@ static uint8_t seqprog[] = { 0xf7, 0x3c, 0x78, 0x08, 0x00, 0x65, 0x20, 0x41, 0x40, 0xaa, 0x7e, 0x10, - 0x04, 0xaa, 0x6e, 0x5d, - 0x00, 0x65, 0x56, 0x42, - 0xc4, 0x6a, 0x6e, 0x5d, + 0x04, 0xaa, 0x70, 0x5d, + 0x00, 0x65, 0x58, 0x42, + 0xc4, 0x6a, 0x70, 0x5d, 0xc0, 0x6a, 0x7e, 0x00, - 0x00, 0xa8, 0x84, 0x5d, + 0x00, 0xa8, 0x86, 0x5d, 0xe4, 0x6a, 0x06, 0x00, - 0x00, 0x6a, 0x84, 0x5d, + 0x00, 0x6a, 0x86, 0x5d, 0x00, 0x65, 0x4c, 0x41, 0x10, 0x3c, 0xa8, 0x69, - 0x00, 0xbb, 0x8a, 0x44, + 0x00, 0xbb, 0x8c, 0x44, 0x18, 0x6a, 0xda, 0x01, 0x01, 0x69, 0xd8, 0x31, 0x1c, 0x6a, 0xd0, 0x01, @@ -227,31 +227,32 @@ static uint8_t seqprog[] = { 0x01, 0x93, 0x26, 0x01, 0x03, 0x6a, 0x2a, 0x01, 0x01, 0x69, 0x32, 0x31, - 0x1c, 0x6a, 0xe0, 0x5d, + 0x1c, 0x6a, 0xe2, 0x5d, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xa8, 0x5e, + 0x00, 0x65, 0xaa, 0x5e, 0x01, 0x50, 0xa0, 0x18, 0x02, 0x6a, 0x22, 0x05, 0x1a, 0x01, 0x02, 0x00, 0x80, 0x6a, 0x74, 0x00, 0x40, 0x6a, 0x78, 0x00, 0x40, 0x6a, 0x16, 0x00, - 0x00, 0x65, 0xd8, 0x5d, + 0x00, 0x65, 0xda, 0x5d, 0x01, 0x3f, 0xc8, 0x30, - 0xbf, 0x64, 0x56, 0x7a, - 0x80, 0x64, 0x9e, 0x73, - 0xa0, 0x64, 0x00, 0x74, - 0xc0, 0x64, 0xf4, 0x73, - 0xe0, 0x64, 0x30, 0x74, - 0x01, 0x6a, 0xd8, 0x5e, + 0xbf, 0x64, 0x58, 0x7a, + 0x80, 0x64, 0xa0, 0x73, + 0xa0, 0x64, 0x02, 0x74, + 0xc0, 0x64, 0xf6, 0x73, + 0xe0, 0x64, 0x32, 0x74, + 0x01, 0x6a, 0xda, 0x5e, 0x00, 0x65, 0xcc, 0x41, 0xf7, 0x11, 0x22, 0x08, 0x01, 0x06, 0xd4, 0x30, 0xff, 0x6a, 0x24, 0x08, 0xf7, 0x01, 0x02, 0x08, - 0x09, 0x0c, 0xe6, 0x79, + 0xc0, 0x6a, 0x78, 0x00, + 0x09, 0x0c, 0xe8, 0x79, 0x08, 0x0c, 0x04, 0x68, - 0xb1, 0x6a, 0xd8, 0x5e, + 0xb1, 0x6a, 0xda, 0x5e, 0xff, 0x6a, 0x26, 0x09, 0x12, 0x01, 0x02, 0x00, 0x02, 0x6a, 0x08, 0x30, @@ -264,29 +265,29 @@ static uint8_t seqprog[] = { 0x00, 0xa5, 0x4a, 0x21, 0x00, 0xa6, 0x4c, 0x21, 0x00, 0xa7, 0x4e, 0x25, - 0x08, 0xeb, 0xdc, 0x7e, - 0x80, 0xeb, 0x06, 0x7a, + 0x08, 0xeb, 0xde, 0x7e, + 0x80, 0xeb, 0x08, 0x7a, 0xff, 0x6a, 0xd6, 0x09, - 0x08, 0xeb, 0x0a, 0x6a, + 0x08, 0xeb, 0x0c, 0x6a, 0xff, 0x6a, 0xd4, 0x0c, - 0x80, 0xa3, 0xdc, 0x6e, - 0x88, 0xeb, 0x20, 0x72, - 0x08, 0xeb, 0xdc, 0x6e, - 0x04, 0xea, 0x24, 0xe2, - 0x08, 0xee, 0xdc, 0x6e, + 0x80, 0xa3, 0xde, 0x6e, + 0x88, 0xeb, 0x22, 0x72, + 0x08, 0xeb, 0xde, 0x6e, + 0x04, 0xea, 0x26, 0xe2, + 0x08, 0xee, 0xde, 0x6e, 0x04, 0x6a, 0xd0, 0x81, 0x05, 0xa4, 0xc0, 0x89, 0x03, 0xa5, 0xc2, 0x31, 0x09, 0x6a, 0xd6, 0x05, - 0x00, 0x65, 0x08, 0x5a, + 0x00, 0x65, 0x0a, 0x5a, 0x06, 0xa4, 0xd4, 0x89, - 0x80, 0x94, 0xdc, 0x7e, + 0x80, 0x94, 0xde, 0x7e, 0x07, 0xe9, 0x10, 0x31, 0x01, 0xe9, 0x46, 0x31, - 0x00, 0xa3, 0xba, 0x5e, - 0x00, 0x65, 0xfa, 0x59, + 0x00, 0xa3, 0xbc, 0x5e, + 0x00, 0x65, 0xfc, 0x59, 0x01, 0xa4, 0xca, 0x30, - 0x80, 0xa3, 0x34, 0x7a, + 0x80, 0xa3, 0x36, 0x7a, 0x02, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, 0x80, 0x93, 0x26, 0x01, @@ -294,162 +295,162 @@ static uint8_t seqprog[] = { 0x01, 0x8c, 0xc8, 0x30, 0x00, 0x88, 0xc8, 0x18, 0x02, 0x64, 0xc8, 0x88, - 0xff, 0x64, 0xdc, 0x7e, - 0xff, 0x8d, 0x4a, 0x6a, - 0xff, 0x8e, 0x4a, 0x6a, + 0xff, 0x64, 0xde, 0x7e, + 0xff, 0x8d, 0x4c, 0x6a, + 0xff, 0x8e, 0x4c, 0x6a, 0x03, 0x8c, 0xd4, 0x98, - 0x00, 0x65, 0xdc, 0x56, + 0x00, 0x65, 0xde, 0x56, 0x01, 0x64, 0x70, 0x30, 0xff, 0x64, 0xc8, 0x10, 0x01, 0x64, 0xc8, 0x18, 0x00, 0x8c, 0x18, 0x19, 0xff, 0x8d, 0x1a, 0x21, 0xff, 0x8e, 0x1c, 0x25, - 0xc0, 0x3c, 0x5a, 0x7a, - 0x21, 0x6a, 0xd8, 0x5e, + 0xc0, 0x3c, 0x5c, 0x7a, + 0x21, 0x6a, 0xda, 0x5e, 0xa8, 0x6a, 0x76, 0x00, 0x79, 0x6a, 0x76, 0x00, - 0x40, 0x3f, 0x62, 0x6a, + 0x40, 0x3f, 0x64, 0x6a, 0x04, 0x3b, 0x76, 0x00, 0x04, 0x6a, 0xd4, 0x81, - 0x20, 0x3c, 0x6a, 0x7a, - 0x51, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x82, 0x42, + 0x20, 0x3c, 0x6c, 0x7a, + 0x51, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x84, 0x42, 0x20, 0x3c, 0x78, 0x00, - 0x00, 0xb3, 0xba, 0x5e, + 0x00, 0xb3, 0xbc, 0x5e, 0x07, 0xac, 0x10, 0x31, 0x05, 0xb3, 0x46, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0xee, 0x5d, + 0xac, 0x6a, 0xf0, 0x5d, 0xa3, 0x6a, 0xcc, 0x00, - 0xb3, 0x6a, 0xf2, 0x5d, - 0x00, 0x65, 0x3a, 0x5a, + 0xb3, 0x6a, 0xf4, 0x5d, + 0x00, 0x65, 0x3c, 0x5a, 0xfd, 0xa4, 0x48, 0x09, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xe6, 0x5d, - 0x01, 0xa4, 0x94, 0x7a, + 0x00, 0x65, 0xe8, 0x5d, + 0x01, 0xa4, 0x96, 0x7a, 0x04, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, 0x80, 0x02, 0x04, 0x00, - 0x10, 0x0c, 0x8a, 0x7a, - 0x03, 0x9e, 0x8c, 0x6a, + 0x10, 0x0c, 0x8c, 0x7a, + 0x03, 0x9e, 0x8e, 0x6a, 0x7f, 0x02, 0x04, 0x08, - 0x91, 0x6a, 0xd8, 0x5e, + 0x91, 0x6a, 0xda, 0x5e, 0x00, 0x65, 0xcc, 0x41, 0x01, 0xa4, 0xca, 0x30, - 0x80, 0xa3, 0x9a, 0x7a, + 0x80, 0xa3, 0x9c, 0x7a, 0x02, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x0e, 0x5a, - 0x01, 0xfc, 0xa8, 0x6a, - 0x80, 0x0b, 0x9e, 0x6a, - 0x10, 0x0c, 0x9e, 0x7a, - 0x20, 0x93, 0x9e, 0x6a, + 0x00, 0x65, 0x10, 0x5a, + 0x01, 0xfc, 0xaa, 0x6a, + 0x80, 0x0b, 0xa0, 0x6a, + 0x10, 0x0c, 0xa0, 0x7a, + 0x20, 0x93, 0xa0, 0x6a, 0x02, 0x93, 0x26, 0x01, - 0x02, 0xfc, 0xb2, 0x7a, - 0x40, 0x0d, 0xc6, 0x6a, + 0x02, 0xfc, 0xb4, 0x7a, + 0x40, 0x0d, 0xc8, 0x6a, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0xc6, 0x42, - 0x40, 0x0d, 0xb8, 0x6a, - 0x00, 0x65, 0x0e, 0x5a, - 0x00, 0x65, 0xaa, 0x42, - 0x80, 0xfc, 0xc2, 0x7a, - 0x80, 0xa4, 0xc2, 0x6a, + 0x00, 0x65, 0xc8, 0x42, + 0x40, 0x0d, 0xba, 0x6a, + 0x00, 0x65, 0x10, 0x5a, + 0x00, 0x65, 0xac, 0x42, + 0x80, 0xfc, 0xc4, 0x7a, + 0x80, 0xa4, 0xc4, 0x6a, 0xff, 0xa5, 0x4a, 0x19, 0xff, 0xa6, 0x4c, 0x21, 0xff, 0xa7, 0x4e, 0x21, 0xf8, 0xfc, 0x48, 0x09, 0x7f, 0xa3, 0x46, 0x09, - 0x04, 0x3b, 0xe2, 0x6a, + 0x04, 0x3b, 0xe4, 0x6a, 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0xa4, 0xe0, 0x7a, - 0x01, 0xfc, 0xd6, 0x7a, - 0x01, 0x94, 0xe2, 0x6a, - 0x01, 0x94, 0xe2, 0x6a, - 0x01, 0x94, 0xe2, 0x6a, - 0x00, 0x65, 0x82, 0x42, - 0x01, 0x94, 0xe0, 0x7a, - 0x10, 0x94, 0xe2, 0x6a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0xa4, 0xe2, 0x7a, + 0x01, 0xfc, 0xd8, 0x7a, + 0x01, 0x94, 0xe4, 0x6a, + 0x01, 0x94, 0xe4, 0x6a, + 0x01, 0x94, 0xe4, 0x6a, + 0x00, 0x65, 0x84, 0x42, + 0x01, 0x94, 0xe2, 0x7a, + 0x10, 0x94, 0xe4, 0x6a, 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xe6, 0x6a, + 0x28, 0x93, 0xe8, 0x6a, 0x01, 0x85, 0x0a, 0x01, - 0x02, 0xfc, 0xee, 0x6a, + 0x02, 0xfc, 0xf0, 0x6a, 0x01, 0x14, 0x46, 0x31, 0xff, 0x6a, 0x10, 0x09, 0xfe, 0x85, 0x0a, 0x09, - 0xff, 0x38, 0xfc, 0x6a, - 0x80, 0xa3, 0xfc, 0x7a, - 0x80, 0x0b, 0xfa, 0x7a, - 0x04, 0x3b, 0xfc, 0x7a, + 0xff, 0x38, 0xfe, 0x6a, + 0x80, 0xa3, 0xfe, 0x7a, + 0x80, 0x0b, 0xfc, 0x7a, + 0x04, 0x3b, 0xfe, 0x7a, 0xbf, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x0e, 0x5a, - 0x01, 0x0b, 0x0a, 0x6b, - 0x10, 0x0c, 0xfe, 0x7a, - 0x04, 0x93, 0x08, 0x6b, - 0x01, 0x94, 0x06, 0x7b, - 0x10, 0x94, 0x08, 0x6b, + 0x00, 0x65, 0x10, 0x5a, + 0x01, 0x0b, 0x0c, 0x6b, + 0x10, 0x0c, 0x00, 0x7b, + 0x04, 0x93, 0x0a, 0x6b, + 0x01, 0x94, 0x08, 0x7b, + 0x10, 0x94, 0x0a, 0x6b, 0xc7, 0x93, 0x26, 0x09, 0x01, 0x99, 0xd4, 0x30, - 0x38, 0x93, 0x0c, 0x6b, - 0xff, 0x08, 0x5a, 0x6b, - 0xff, 0x09, 0x5a, 0x6b, - 0xff, 0x0a, 0x5a, 0x6b, - 0xff, 0x38, 0x28, 0x7b, + 0x38, 0x93, 0x0e, 0x6b, + 0xff, 0x08, 0x5c, 0x6b, + 0xff, 0x09, 0x5c, 0x6b, + 0xff, 0x0a, 0x5c, 0x6b, + 0xff, 0x38, 0x2a, 0x7b, 0x04, 0x14, 0x10, 0x31, 0x01, 0x38, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xf4, 0x5d, - 0x00, 0x38, 0xe0, 0x5d, + 0x14, 0x6a, 0xf6, 0x5d, + 0x00, 0x38, 0xe2, 0x5d, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x54, 0x43, - 0x80, 0xa3, 0x2e, 0x7b, + 0x00, 0x65, 0x56, 0x43, + 0x80, 0xa3, 0x30, 0x7b, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0x5a, 0x43, - 0x08, 0xeb, 0x34, 0x7b, - 0x00, 0x65, 0x0e, 0x5a, - 0x08, 0xeb, 0x30, 0x6b, + 0x00, 0x65, 0x5c, 0x43, + 0x08, 0xeb, 0x36, 0x7b, + 0x00, 0x65, 0x10, 0x5a, + 0x08, 0xeb, 0x32, 0x6b, 0x07, 0xe9, 0x10, 0x31, 0x01, 0xe9, 0xca, 0x30, 0x01, 0x65, 0x46, 0x31, - 0x00, 0x6a, 0xba, 0x5e, + 0x00, 0x6a, 0xbc, 0x5e, 0x88, 0x6a, 0xcc, 0x00, - 0xa4, 0x6a, 0xf4, 0x5d, - 0x08, 0x6a, 0xe0, 0x5d, + 0xa4, 0x6a, 0xf6, 0x5d, + 0x08, 0x6a, 0xe2, 0x5d, 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xa8, 0x5e, + 0x00, 0x65, 0xaa, 0x5e, 0x88, 0x6a, 0xcc, 0x00, - 0x00, 0x65, 0x8a, 0x5e, + 0x00, 0x65, 0x8c, 0x5e, 0x01, 0x99, 0x46, 0x31, - 0x00, 0xa3, 0xba, 0x5e, + 0x00, 0xa3, 0xbc, 0x5e, 0x01, 0x88, 0x10, 0x31, - 0x00, 0x65, 0x3a, 0x5a, - 0x00, 0x65, 0xfa, 0x59, + 0x00, 0x65, 0x3c, 0x5a, + 0x00, 0x65, 0xfc, 0x59, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xe6, 0x5d, - 0x80, 0x0b, 0x82, 0x6a, - 0x80, 0x0b, 0x62, 0x6b, - 0x01, 0x0c, 0x5c, 0x7b, - 0x10, 0x0c, 0x82, 0x7a, - 0x03, 0x9e, 0x82, 0x6a, - 0x00, 0x65, 0x04, 0x5a, - 0x00, 0x6a, 0xba, 0x5e, - 0x01, 0xa4, 0x82, 0x6b, - 0xff, 0x38, 0x78, 0x7b, + 0x00, 0x65, 0xe8, 0x5d, + 0x80, 0x0b, 0x84, 0x6a, + 0x80, 0x0b, 0x64, 0x6b, + 0x01, 0x0c, 0x5e, 0x7b, + 0x10, 0x0c, 0x84, 0x7a, + 0x03, 0x9e, 0x84, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x00, 0x6a, 0xbc, 0x5e, + 0x01, 0xa4, 0x84, 0x6b, + 0xff, 0x38, 0x7a, 0x7b, 0x01, 0x38, 0xc8, 0x30, 0x00, 0x08, 0x40, 0x19, 0xff, 0x6a, 0xc8, 0x08, 0x00, 0x09, 0x42, 0x21, 0x00, 0x0a, 0x44, 0x21, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x7a, 0x43, + 0x00, 0x65, 0x7c, 0x43, 0x03, 0x08, 0x40, 0x31, 0x03, 0x08, 0x40, 0x31, 0x01, 0x08, 0x40, 0x31, @@ -461,16 +462,16 @@ static uint8_t seqprog[] = { 0x04, 0x3c, 0xcc, 0x79, 0xfb, 0x3c, 0x78, 0x08, 0x04, 0x93, 0x20, 0x79, - 0x01, 0x0c, 0x8e, 0x6b, + 0x01, 0x0c, 0x90, 0x6b, 0x80, 0xba, 0x20, 0x79, 0x80, 0x04, 0x20, 0x79, - 0xe4, 0x6a, 0x6e, 0x5d, - 0x23, 0x6a, 0x84, 0x5d, - 0x01, 0x6a, 0x84, 0x5d, + 0xe4, 0x6a, 0x70, 0x5d, + 0x23, 0x6a, 0x86, 0x5d, + 0x01, 0x6a, 0x86, 0x5d, 0x00, 0x65, 0x20, 0x41, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0x3c, 0xa2, 0x7b, - 0x21, 0x6a, 0xd8, 0x5e, + 0x80, 0x3c, 0xa4, 0x7b, + 0x21, 0x6a, 0xda, 0x5e, 0x01, 0xbc, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x02, 0x6a, 0xf8, 0x01, @@ -480,16 +481,16 @@ static uint8_t seqprog[] = { 0xff, 0x6a, 0x12, 0x08, 0xff, 0x6a, 0x14, 0x08, 0xf3, 0xbc, 0xd4, 0x18, - 0xa0, 0x6a, 0xc8, 0x53, + 0xa0, 0x6a, 0xca, 0x53, 0x04, 0xa0, 0x10, 0x31, 0xac, 0x6a, 0x26, 0x01, 0x04, 0xa0, 0x10, 0x31, 0x03, 0x08, 0x18, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xa0, 0x6a, 0xf4, 0x5d, - 0x00, 0xbc, 0xe0, 0x5d, + 0xa0, 0x6a, 0xf6, 0x5d, + 0x00, 0xbc, 0xe2, 0x5d, 0x3d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0xe0, 0x43, + 0x00, 0x65, 0xe2, 0x43, 0xff, 0x6a, 0x10, 0x09, 0xa4, 0x6a, 0x26, 0x01, 0x0c, 0xa0, 0x32, 0x31, @@ -499,128 +500,128 @@ static uint8_t seqprog[] = { 0x36, 0x6a, 0x26, 0x01, 0x02, 0x93, 0x26, 0x01, 0x35, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0x9c, 0x5e, - 0x00, 0x65, 0x9c, 0x5e, + 0x00, 0x65, 0x9e, 0x5e, + 0x00, 0x65, 0x9e, 0x5e, 0x02, 0x93, 0x26, 0x01, 0xbf, 0x3c, 0x78, 0x08, - 0x04, 0x0b, 0xe6, 0x6b, - 0x10, 0x0c, 0xe2, 0x7b, - 0x01, 0x03, 0xe6, 0x6b, - 0x20, 0x93, 0xe8, 0x6b, - 0x04, 0x0b, 0xee, 0x6b, + 0x04, 0x0b, 0xe8, 0x6b, + 0x10, 0x0c, 0xe4, 0x7b, + 0x01, 0x03, 0xe8, 0x6b, + 0x20, 0x93, 0xea, 0x6b, + 0x04, 0x0b, 0xf0, 0x6b, 0x40, 0x3c, 0x78, 0x00, 0xc7, 0x93, 0x26, 0x09, - 0x38, 0x93, 0xf0, 0x6b, + 0x38, 0x93, 0xf2, 0x6b, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0x3c, 0x56, 0x6c, + 0x80, 0x3c, 0x58, 0x6c, 0x01, 0x06, 0x50, 0x31, 0x80, 0xb8, 0x70, 0x01, 0x00, 0x65, 0xcc, 0x41, 0x10, 0x3f, 0x06, 0x00, 0x10, 0x6a, 0x06, 0x00, 0x01, 0x3a, 0xca, 0x30, - 0x80, 0x65, 0x1c, 0x64, - 0x10, 0xb8, 0x40, 0x6c, + 0x80, 0x65, 0x1e, 0x64, + 0x10, 0xb8, 0x42, 0x6c, 0xc0, 0x3e, 0xca, 0x00, - 0x40, 0xb8, 0x0c, 0x6c, + 0x40, 0xb8, 0x0e, 0x6c, 0xbf, 0x65, 0xca, 0x08, - 0x20, 0xb8, 0x20, 0x7c, + 0x20, 0xb8, 0x22, 0x7c, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xd8, 0x5d, - 0xa0, 0x3f, 0x28, 0x64, + 0x00, 0x65, 0xda, 0x5d, + 0xa0, 0x3f, 0x2a, 0x64, 0x23, 0xb8, 0x0c, 0x08, - 0x00, 0x65, 0xd8, 0x5d, - 0xa0, 0x3f, 0x28, 0x64, - 0x00, 0xbb, 0x20, 0x44, - 0xff, 0x65, 0x20, 0x64, - 0x00, 0x65, 0x40, 0x44, + 0x00, 0x65, 0xda, 0x5d, + 0xa0, 0x3f, 0x2a, 0x64, + 0x00, 0xbb, 0x22, 0x44, + 0xff, 0x65, 0x22, 0x64, + 0x00, 0x65, 0x42, 0x44, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xd8, 0x5d, - 0xa0, 0x3f, 0xfc, 0x73, + 0x00, 0x65, 0xda, 0x5d, + 0xa0, 0x3f, 0xfe, 0x73, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x3a, 0xa6, 0x30, 0x08, 0x6a, 0x74, 0x00, 0x00, 0x65, 0xcc, 0x41, - 0x64, 0x6a, 0x68, 0x5d, - 0x80, 0x64, 0xd8, 0x6c, - 0x04, 0x64, 0x9a, 0x74, - 0x02, 0x64, 0xaa, 0x74, - 0x00, 0x6a, 0x60, 0x74, - 0x03, 0x64, 0xc8, 0x74, - 0x23, 0x64, 0x48, 0x74, - 0x08, 0x64, 0x5c, 0x74, - 0x61, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0xd8, 0x5d, + 0x64, 0x6a, 0x6a, 0x5d, + 0x80, 0x64, 0xda, 0x6c, + 0x04, 0x64, 0x9c, 0x74, + 0x02, 0x64, 0xac, 0x74, + 0x00, 0x6a, 0x62, 0x74, + 0x03, 0x64, 0xca, 0x74, + 0x23, 0x64, 0x4a, 0x74, + 0x08, 0x64, 0x5e, 0x74, + 0x61, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0xda, 0x5d, 0x08, 0x51, 0xce, 0x71, - 0x00, 0x65, 0x40, 0x44, - 0x80, 0x04, 0x5a, 0x7c, - 0x51, 0x6a, 0x5e, 0x5d, - 0x01, 0x51, 0x5a, 0x64, - 0x01, 0xa4, 0x52, 0x7c, - 0x80, 0xba, 0x5c, 0x6c, - 0x41, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x5c, 0x44, - 0x21, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x5c, 0x44, - 0x07, 0x6a, 0x54, 0x5d, + 0x00, 0x65, 0x42, 0x44, + 0x80, 0x04, 0x5c, 0x7c, + 0x51, 0x6a, 0x60, 0x5d, + 0x01, 0x51, 0x5c, 0x64, + 0x01, 0xa4, 0x54, 0x7c, + 0x80, 0xba, 0x5e, 0x6c, + 0x41, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x5e, 0x44, + 0x21, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x5e, 0x44, + 0x07, 0x6a, 0x56, 0x5d, 0x01, 0x06, 0xd4, 0x30, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0xb8, 0x56, 0x7c, - 0xc0, 0x3c, 0x6a, 0x7c, - 0x80, 0x3c, 0x56, 0x6c, - 0xff, 0xa8, 0x6a, 0x6c, - 0x40, 0x3c, 0x56, 0x6c, - 0x10, 0xb8, 0x6e, 0x7c, - 0xa1, 0x6a, 0xd8, 0x5e, - 0x01, 0xb4, 0x74, 0x6c, - 0x02, 0xb4, 0x76, 0x6c, - 0x01, 0xa4, 0x76, 0x7c, - 0xff, 0xa8, 0x86, 0x7c, + 0x80, 0xb8, 0x58, 0x7c, + 0xc0, 0x3c, 0x6c, 0x7c, + 0x80, 0x3c, 0x58, 0x6c, + 0xff, 0xa8, 0x6c, 0x6c, + 0x40, 0x3c, 0x58, 0x6c, + 0x10, 0xb8, 0x70, 0x7c, + 0xa1, 0x6a, 0xda, 0x5e, + 0x01, 0xb4, 0x76, 0x6c, + 0x02, 0xb4, 0x78, 0x6c, + 0x01, 0xa4, 0x78, 0x7c, + 0xff, 0xa8, 0x88, 0x7c, 0x04, 0xb4, 0x68, 0x01, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0x12, 0x5e, - 0xff, 0xa8, 0x86, 0x7c, - 0x71, 0x6a, 0xd8, 0x5e, - 0x40, 0x51, 0x86, 0x64, - 0x00, 0x65, 0xb2, 0x5e, + 0x00, 0xbb, 0x14, 0x5e, + 0xff, 0xa8, 0x88, 0x7c, + 0x71, 0x6a, 0xda, 0x5e, + 0x40, 0x51, 0x88, 0x64, + 0x00, 0x65, 0xb4, 0x5e, 0x00, 0x65, 0xde, 0x41, - 0x00, 0xbb, 0x8a, 0x5c, + 0x00, 0xbb, 0x8c, 0x5c, 0x00, 0x65, 0xde, 0x41, - 0x00, 0x65, 0xb2, 0x5e, + 0x00, 0x65, 0xb4, 0x5e, 0x01, 0x65, 0xa2, 0x30, 0x01, 0xf8, 0xc8, 0x30, 0x01, 0x4e, 0xc8, 0x30, - 0x00, 0x6a, 0xb6, 0xdd, - 0x00, 0x51, 0xc8, 0x5d, + 0x00, 0x6a, 0xb8, 0xdd, + 0x00, 0x51, 0xca, 0x5d, 0x01, 0x4e, 0x9c, 0x18, 0x02, 0x6a, 0x22, 0x05, - 0xc0, 0x3c, 0x56, 0x6c, + 0xc0, 0x3c, 0x58, 0x6c, 0x04, 0xb8, 0x70, 0x01, - 0x00, 0x65, 0xd4, 0x5e, + 0x00, 0x65, 0xd6, 0x5e, 0x20, 0xb8, 0xde, 0x69, 0x01, 0xbb, 0xa2, 0x30, 0x3f, 0xba, 0x7c, 0x08, - 0x00, 0xb9, 0xce, 0x5c, + 0x00, 0xb9, 0xd0, 0x5c, 0x00, 0x65, 0xde, 0x41, 0x01, 0x06, 0xd4, 0x30, 0x20, 0x3c, 0xcc, 0x79, - 0x20, 0x3c, 0x5c, 0x7c, - 0x01, 0xa4, 0xb8, 0x7c, + 0x20, 0x3c, 0x5e, 0x7c, + 0x01, 0xa4, 0xba, 0x7c, 0x01, 0xb4, 0x68, 0x01, 0x00, 0x65, 0xcc, 0x41, - 0x00, 0x65, 0x5c, 0x44, + 0x00, 0x65, 0x5e, 0x44, 0x04, 0x14, 0x58, 0x31, 0x01, 0x06, 0xd4, 0x30, 0x08, 0xa0, 0x60, 0x31, 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xf4, 0x5d, + 0x14, 0x6a, 0xf6, 0x5d, 0x01, 0x06, 0xd4, 0x30, - 0xa0, 0x6a, 0xec, 0x5d, + 0xa0, 0x6a, 0xee, 0x5d, 0x00, 0x65, 0xcc, 0x41, 0xdf, 0x3c, 0x78, 0x08, 0x12, 0x01, 0x02, 0x00, - 0x00, 0x65, 0x5c, 0x44, + 0x00, 0x65, 0x5e, 0x44, 0x4c, 0x65, 0xcc, 0x28, 0x01, 0x3e, 0x20, 0x31, 0xd0, 0x66, 0xcc, 0x18, @@ -631,102 +632,102 @@ static uint8_t seqprog[] = { 0xd0, 0x65, 0xca, 0x18, 0x01, 0x3e, 0x20, 0x31, 0x30, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xe6, 0x4c, + 0x00, 0x65, 0xe8, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xee, 0x54, + 0x00, 0x65, 0xf0, 0x54, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xca, 0x18, 0xe0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xf8, 0x4c, + 0x00, 0x65, 0xfa, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0xd0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0x00, 0x55, + 0x00, 0x65, 0x02, 0x55, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x01, 0x6c, 0xa2, 0x30, - 0xff, 0x51, 0x12, 0x75, - 0x00, 0x51, 0x8e, 0x5d, + 0xff, 0x51, 0x14, 0x75, + 0x00, 0x51, 0x90, 0x5d, 0x01, 0x51, 0x20, 0x31, - 0x00, 0x65, 0x34, 0x45, + 0x00, 0x65, 0x36, 0x45, 0x3f, 0xba, 0xc8, 0x08, - 0x00, 0x3e, 0x34, 0x75, - 0x00, 0x65, 0xb0, 0x5e, + 0x00, 0x3e, 0x36, 0x75, + 0x00, 0x65, 0xb2, 0x5e, 0x80, 0x3c, 0x78, 0x00, 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xd8, 0x5d, + 0x00, 0x65, 0xda, 0x5d, 0x01, 0x3c, 0x78, 0x00, - 0xe0, 0x3f, 0x50, 0x65, + 0xe0, 0x3f, 0x52, 0x65, 0x02, 0x3c, 0x78, 0x00, - 0x20, 0x12, 0x50, 0x65, - 0x51, 0x6a, 0x5e, 0x5d, - 0x00, 0x51, 0x8e, 0x5d, - 0x51, 0x6a, 0x5e, 0x5d, + 0x20, 0x12, 0x52, 0x65, + 0x51, 0x6a, 0x60, 0x5d, + 0x00, 0x51, 0x90, 0x5d, + 0x51, 0x6a, 0x60, 0x5d, 0x01, 0x51, 0x20, 0x31, 0x04, 0x3c, 0x78, 0x00, 0x01, 0xb9, 0xc8, 0x30, - 0x00, 0x3d, 0x4e, 0x65, + 0x00, 0x3d, 0x50, 0x65, 0x08, 0x3c, 0x78, 0x00, 0x3f, 0xba, 0xc8, 0x08, - 0x00, 0x3e, 0x4e, 0x65, + 0x00, 0x3e, 0x50, 0x65, 0x10, 0x3c, 0x78, 0x00, - 0x04, 0xb8, 0x4e, 0x7d, + 0x04, 0xb8, 0x50, 0x7d, 0xfb, 0xb8, 0x70, 0x09, - 0x20, 0xb8, 0x44, 0x6d, + 0x20, 0xb8, 0x46, 0x6d, 0x01, 0x90, 0xc8, 0x30, 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3d, 0xce, 0x5c, + 0x00, 0x3d, 0xd0, 0x5c, 0x01, 0x64, 0x20, 0x31, 0xff, 0x6a, 0x78, 0x08, 0x00, 0x65, 0xea, 0x58, - 0x10, 0xb8, 0x5c, 0x7c, - 0xff, 0x6a, 0x54, 0x5d, - 0x00, 0x65, 0x5c, 0x44, - 0x00, 0x65, 0xb0, 0x5e, - 0x31, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x5c, 0x44, + 0x10, 0xb8, 0x5e, 0x7c, + 0xff, 0x6a, 0x56, 0x5d, + 0x00, 0x65, 0x5e, 0x44, + 0x00, 0x65, 0xb2, 0x5e, + 0x31, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x5e, 0x44, 0x10, 0x3f, 0x06, 0x00, 0x10, 0x6a, 0x06, 0x00, 0x01, 0x65, 0x74, 0x34, - 0x81, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x60, 0x45, + 0x81, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x62, 0x45, 0x01, 0x06, 0xd4, 0x30, - 0x01, 0x0c, 0x60, 0x7d, - 0x04, 0x0c, 0x5a, 0x6d, + 0x01, 0x0c, 0x62, 0x7d, + 0x04, 0x0c, 0x5c, 0x6d, 0xe0, 0x03, 0x7e, 0x08, 0xe0, 0x3f, 0xcc, 0x61, 0x01, 0x65, 0xcc, 0x30, 0x01, 0x12, 0xda, 0x34, 0x01, 0x06, 0xd4, 0x34, - 0x01, 0x03, 0x6e, 0x6d, + 0x01, 0x03, 0x70, 0x6d, 0x40, 0x03, 0xcc, 0x08, 0x01, 0x65, 0x06, 0x30, 0x40, 0x65, 0xc8, 0x08, - 0x00, 0x66, 0x7c, 0x75, - 0x40, 0x65, 0x7c, 0x7d, - 0x00, 0x65, 0x7c, 0x5d, + 0x00, 0x66, 0x7e, 0x75, + 0x40, 0x65, 0x7e, 0x7d, + 0x00, 0x65, 0x7e, 0x5d, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x0c, 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x86, 0x7d, + 0x02, 0x0b, 0x88, 0x7d, 0x01, 0x65, 0x0c, 0x30, - 0x02, 0x0b, 0x8a, 0x7d, + 0x02, 0x0b, 0x8c, 0x7d, 0xf7, 0x01, 0x02, 0x0c, 0x01, 0x65, 0xc8, 0x30, - 0xff, 0x41, 0xae, 0x75, + 0xff, 0x41, 0xb0, 0x75, 0x01, 0x41, 0x20, 0x31, 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0x9e, 0x45, - 0xff, 0xbf, 0xae, 0x75, + 0x00, 0x65, 0xa0, 0x45, + 0xff, 0xbf, 0xb0, 0x75, 0x01, 0x90, 0xa4, 0x30, 0x01, 0xbf, 0x20, 0x31, - 0x00, 0xbb, 0x98, 0x65, - 0xff, 0x52, 0xac, 0x75, + 0x00, 0xbb, 0x9a, 0x65, + 0xff, 0x52, 0xae, 0x75, 0x01, 0xbf, 0xcc, 0x30, 0x01, 0x90, 0xca, 0x30, 0x01, 0x52, 0x20, 0x31, @@ -734,28 +735,28 @@ static uint8_t seqprog[] = { 0x01, 0x65, 0x20, 0x35, 0x01, 0xbf, 0x82, 0x34, 0x01, 0x64, 0xa2, 0x30, - 0x00, 0x6a, 0xc0, 0x5e, + 0x00, 0x6a, 0xc2, 0x5e, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0x12, 0x46, + 0x00, 0x51, 0x14, 0x46, 0x01, 0x65, 0xa4, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x06, 0x5e, + 0x48, 0x6a, 0x08, 0x5e, 0x01, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x05, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x06, 0x5e, - 0x01, 0x6a, 0xe0, 0x5d, + 0x48, 0x6a, 0x08, 0x5e, + 0x01, 0x6a, 0xe2, 0x5d, 0x01, 0x6a, 0x26, 0x05, 0x01, 0x65, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xcc, 0x7d, + 0x80, 0xee, 0xce, 0x7d, 0xff, 0x6a, 0xdc, 0x0d, 0x01, 0x65, 0x32, 0x31, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xa8, 0x46, - 0x81, 0x6a, 0xd8, 0x5e, - 0x01, 0x0c, 0xd8, 0x7d, - 0x04, 0x0c, 0xd6, 0x6d, + 0x00, 0x65, 0xaa, 0x46, + 0x81, 0x6a, 0xda, 0x5e, + 0x01, 0x0c, 0xda, 0x7d, + 0x04, 0x0c, 0xd8, 0x6d, 0xe0, 0x03, 0x06, 0x08, 0xe0, 0x03, 0x7e, 0x0c, 0x01, 0x65, 0x18, 0x31, @@ -774,7 +775,7 @@ static uint8_t seqprog[] = { 0x01, 0x6c, 0xda, 0x34, 0x3d, 0x64, 0xa4, 0x28, 0x55, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0x06, 0x46, + 0x00, 0x65, 0x08, 0x46, 0x2e, 0x64, 0xa4, 0x28, 0x66, 0x64, 0xc8, 0x28, 0x00, 0x6c, 0xda, 0x18, @@ -785,63 +786,63 @@ static uint8_t seqprog[] = { 0x00, 0x6c, 0xda, 0x24, 0x01, 0x65, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0x02, 0x5e, + 0x44, 0x6a, 0x04, 0x5e, 0x01, 0x90, 0xe2, 0x31, - 0x04, 0x3b, 0x26, 0x7e, + 0x04, 0x3b, 0x28, 0x7e, 0x30, 0x6a, 0xd0, 0x01, 0x20, 0x6a, 0xd0, 0x01, 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0x22, 0x66, - 0x00, 0x65, 0x3e, 0x46, + 0xdc, 0xee, 0x24, 0x66, + 0x00, 0x65, 0x40, 0x46, 0x20, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x01, 0x20, 0xa0, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x2e, 0x7e, + 0x80, 0xee, 0x30, 0x7e, 0x11, 0x6a, 0xdc, 0x01, - 0x50, 0xee, 0x32, 0x66, + 0x50, 0xee, 0x34, 0x66, 0x20, 0x6a, 0xd0, 0x01, 0x09, 0x6a, 0xdc, 0x01, - 0x88, 0xee, 0x38, 0x66, + 0x88, 0xee, 0x3a, 0x66, 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0x3c, 0x66, + 0xd8, 0xee, 0x3e, 0x66, 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0x40, 0x6e, + 0x18, 0xee, 0x42, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, 0x88, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0x02, 0x5e, - 0x20, 0x6a, 0xe0, 0x5d, + 0x44, 0x6a, 0x04, 0x5e, + 0x20, 0x6a, 0xe2, 0x5d, 0x01, 0x3b, 0x26, 0x31, - 0x04, 0x3b, 0x5a, 0x6e, + 0x04, 0x3b, 0x5c, 0x6e, 0xa0, 0x6a, 0xca, 0x00, 0x20, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x98, 0x5e, - 0x00, 0x65, 0x52, 0x66, + 0x00, 0x65, 0x9a, 0x5e, + 0x00, 0x65, 0x54, 0x66, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xa8, 0x46, + 0x00, 0x65, 0xaa, 0x46, 0xa0, 0x6a, 0xcc, 0x00, 0xff, 0x6a, 0xc8, 0x08, - 0x20, 0x94, 0x5e, 0x6e, - 0x10, 0x94, 0x60, 0x6e, - 0x08, 0x94, 0x7a, 0x6e, - 0x08, 0x94, 0x7a, 0x6e, - 0x08, 0x94, 0x7a, 0x6e, + 0x20, 0x94, 0x60, 0x6e, + 0x10, 0x94, 0x62, 0x6e, + 0x08, 0x94, 0x7c, 0x6e, + 0x08, 0x94, 0x7c, 0x6e, + 0x08, 0x94, 0x7c, 0x6e, 0xff, 0x8c, 0xc8, 0x10, 0xc1, 0x64, 0xc8, 0x18, 0xf8, 0x64, 0xc8, 0x08, 0x01, 0x99, 0xda, 0x30, - 0x00, 0x66, 0x6e, 0x66, - 0xc0, 0x66, 0xaa, 0x76, + 0x00, 0x66, 0x70, 0x66, + 0xc0, 0x66, 0xac, 0x76, 0x60, 0x66, 0xc8, 0x18, 0x3d, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0x5e, 0x46, + 0x00, 0x65, 0x60, 0x46, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x7c, 0x6e, + 0x08, 0x93, 0x7e, 0x6e, 0x00, 0x62, 0xc4, 0x18, - 0x00, 0x65, 0xa8, 0x5e, - 0x00, 0x65, 0x88, 0x5e, - 0x00, 0x65, 0x88, 0x5e, - 0x00, 0x65, 0x88, 0x5e, + 0x00, 0x65, 0xaa, 0x5e, + 0x00, 0x65, 0x8a, 0x5e, + 0x00, 0x65, 0x8a, 0x5e, + 0x00, 0x65, 0x8a, 0x5e, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, @@ -858,11 +859,11 @@ static uint8_t seqprog[] = { 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x35, - 0x08, 0x94, 0xa8, 0x7e, + 0x08, 0x94, 0xaa, 0x7e, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0xac, 0x6e, + 0x08, 0x93, 0xae, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, - 0x04, 0xb8, 0xd4, 0x6e, + 0x04, 0xb8, 0xd6, 0x6e, 0x01, 0x42, 0x7e, 0x31, 0xff, 0x6a, 0x76, 0x01, 0x01, 0x90, 0x84, 0x34, @@ -870,14 +871,14 @@ static uint8_t seqprog[] = { 0x01, 0x85, 0x0a, 0x01, 0x7f, 0x65, 0x10, 0x09, 0xfe, 0x85, 0x0a, 0x0d, - 0xff, 0x42, 0xd0, 0x66, - 0xff, 0x41, 0xc8, 0x66, - 0xd1, 0x6a, 0xd8, 0x5e, + 0xff, 0x42, 0xd2, 0x66, + 0xff, 0x41, 0xca, 0x66, + 0xd1, 0x6a, 0xda, 0x5e, 0xff, 0x6a, 0xca, 0x04, 0x01, 0x41, 0x20, 0x31, 0x01, 0xbf, 0x82, 0x30, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0x12, 0x46, + 0x00, 0xbb, 0x14, 0x46, 0x01, 0x42, 0x20, 0x31, 0x01, 0xbf, 0x84, 0x34, 0x01, 0x41, 0x7e, 0x31, @@ -941,7 +942,7 @@ static ahc_patch_func_t ahc_patch17_func static int ahc_patch17_func(struct ahc_softc *ahc) { - return ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0); + return ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0); } static ahc_patch_func_t ahc_patch16_func; @@ -1142,152 +1143,152 @@ static struct patch { { ahc_patch0_func, 196, 1, 1 }, { ahc_patch9_func, 212, 6, 2 }, { ahc_patch0_func, 218, 6, 1 }, - { ahc_patch8_func, 226, 20, 2 }, + { ahc_patch8_func, 226, 21, 2 }, { ahc_patch1_func, 241, 1, 1 }, - { ahc_patch1_func, 248, 1, 2 }, - { ahc_patch0_func, 249, 2, 2 }, - { ahc_patch11_func, 250, 1, 1 }, - { ahc_patch9_func, 258, 27, 3 }, - { ahc_patch1_func, 274, 10, 2 }, - { ahc_patch13_func, 277, 1, 1 }, - { ahc_patch14_func, 285, 14, 1 }, - { ahc_patch1_func, 301, 1, 2 }, - { ahc_patch0_func, 302, 1, 1 }, - { ahc_patch9_func, 305, 1, 1 }, - { ahc_patch13_func, 310, 1, 1 }, - { ahc_patch9_func, 311, 2, 2 }, - { ahc_patch0_func, 313, 4, 1 }, - { ahc_patch14_func, 317, 1, 1 }, - { ahc_patch15_func, 319, 2, 3 }, - { ahc_patch9_func, 319, 1, 2 }, - { ahc_patch0_func, 320, 1, 1 }, - { ahc_patch6_func, 325, 1, 2 }, - { ahc_patch0_func, 326, 1, 1 }, - { ahc_patch1_func, 330, 47, 11 }, - { ahc_patch6_func, 337, 2, 4 }, - { ahc_patch7_func, 337, 1, 1 }, - { ahc_patch8_func, 338, 1, 1 }, - { ahc_patch0_func, 339, 1, 1 }, - { ahc_patch16_func, 340, 1, 1 }, - { ahc_patch6_func, 356, 6, 3 }, - { ahc_patch16_func, 356, 5, 1 }, - { ahc_patch0_func, 362, 7, 1 }, - { ahc_patch13_func, 372, 5, 1 }, - { ahc_patch0_func, 377, 52, 17 }, - { ahc_patch14_func, 377, 1, 1 }, - { ahc_patch7_func, 379, 2, 2 }, - { ahc_patch17_func, 380, 1, 1 }, - { ahc_patch9_func, 383, 1, 1 }, - { ahc_patch18_func, 390, 1, 1 }, - { ahc_patch14_func, 395, 9, 3 }, - { ahc_patch9_func, 396, 3, 2 }, - { ahc_patch0_func, 399, 3, 1 }, - { ahc_patch9_func, 407, 6, 2 }, - { ahc_patch0_func, 413, 9, 2 }, - { ahc_patch13_func, 413, 1, 1 }, - { ahc_patch13_func, 422, 2, 1 }, - { ahc_patch14_func, 424, 1, 1 }, - { ahc_patch9_func, 426, 1, 2 }, - { ahc_patch0_func, 427, 1, 1 }, - { ahc_patch7_func, 428, 1, 1 }, + { ahc_patch1_func, 249, 1, 2 }, + { ahc_patch0_func, 250, 2, 2 }, + { ahc_patch11_func, 251, 1, 1 }, + { ahc_patch9_func, 259, 27, 3 }, + { ahc_patch1_func, 275, 10, 2 }, + { ahc_patch13_func, 278, 1, 1 }, + { ahc_patch14_func, 286, 14, 1 }, + { ahc_patch1_func, 302, 1, 2 }, + { ahc_patch0_func, 303, 1, 1 }, + { ahc_patch9_func, 306, 1, 1 }, + { ahc_patch13_func, 311, 1, 1 }, + { ahc_patch9_func, 312, 2, 2 }, + { ahc_patch0_func, 314, 4, 1 }, + { ahc_patch14_func, 318, 1, 1 }, + { ahc_patch15_func, 320, 2, 3 }, + { ahc_patch9_func, 320, 1, 2 }, + { ahc_patch0_func, 321, 1, 1 }, + { ahc_patch6_func, 326, 1, 2 }, + { ahc_patch0_func, 327, 1, 1 }, + { ahc_patch1_func, 331, 47, 11 }, + { ahc_patch6_func, 338, 2, 4 }, + { ahc_patch7_func, 338, 1, 1 }, + { ahc_patch8_func, 339, 1, 1 }, + { ahc_patch0_func, 340, 1, 1 }, + { ahc_patch16_func, 341, 1, 1 }, + { ahc_patch6_func, 357, 6, 3 }, + { ahc_patch16_func, 357, 5, 1 }, + { ahc_patch0_func, 363, 7, 1 }, + { ahc_patch13_func, 373, 5, 1 }, + { ahc_patch0_func, 378, 52, 17 }, + { ahc_patch14_func, 378, 1, 1 }, + { ahc_patch7_func, 380, 2, 2 }, + { ahc_patch17_func, 381, 1, 1 }, + { ahc_patch9_func, 384, 1, 1 }, + { ahc_patch18_func, 391, 1, 1 }, + { ahc_patch14_func, 396, 9, 3 }, + { ahc_patch9_func, 397, 3, 2 }, + { ahc_patch0_func, 400, 3, 1 }, + { ahc_patch9_func, 408, 6, 2 }, + { ahc_patch0_func, 414, 9, 2 }, + { ahc_patch13_func, 414, 1, 1 }, + { ahc_patch13_func, 423, 2, 1 }, + { ahc_patch14_func, 425, 1, 1 }, + { ahc_patch9_func, 427, 1, 2 }, + { ahc_patch0_func, 428, 1, 1 }, { ahc_patch7_func, 429, 1, 1 }, - { ahc_patch8_func, 430, 3, 3 }, - { ahc_patch6_func, 431, 1, 2 }, - { ahc_patch0_func, 432, 1, 1 }, - { ahc_patch9_func, 433, 1, 1 }, - { ahc_patch15_func, 434, 1, 2 }, - { ahc_patch13_func, 434, 1, 1 }, - { ahc_patch14_func, 436, 9, 4 }, - { ahc_patch9_func, 436, 1, 1 }, - { ahc_patch9_func, 443, 2, 1 }, - { ahc_patch0_func, 445, 4, 3 }, - { ahc_patch9_func, 445, 1, 2 }, - { ahc_patch0_func, 446, 3, 1 }, - { ahc_patch1_func, 450, 2, 1 }, - { ahc_patch7_func, 452, 10, 2 }, - { ahc_patch0_func, 462, 1, 1 }, - { ahc_patch8_func, 463, 118, 22 }, - { ahc_patch1_func, 465, 3, 2 }, - { ahc_patch0_func, 468, 5, 3 }, - { ahc_patch9_func, 468, 2, 2 }, - { ahc_patch0_func, 470, 3, 1 }, - { ahc_patch1_func, 475, 2, 2 }, - { ahc_patch0_func, 477, 6, 3 }, - { ahc_patch9_func, 477, 2, 2 }, - { ahc_patch0_func, 479, 3, 1 }, - { ahc_patch1_func, 485, 2, 2 }, - { ahc_patch0_func, 487, 9, 7 }, - { ahc_patch9_func, 487, 5, 6 }, - { ahc_patch19_func, 487, 1, 2 }, - { ahc_patch0_func, 488, 1, 1 }, - { ahc_patch19_func, 490, 1, 2 }, - { ahc_patch0_func, 491, 1, 1 }, - { ahc_patch0_func, 492, 4, 1 }, - { ahc_patch6_func, 497, 3, 2 }, - { ahc_patch0_func, 500, 1, 1 }, - { ahc_patch6_func, 510, 1, 2 }, - { ahc_patch0_func, 511, 1, 1 }, - { ahc_patch20_func, 548, 7, 1 }, - { ahc_patch3_func, 583, 1, 2 }, - { ahc_patch0_func, 584, 1, 1 }, - { ahc_patch21_func, 587, 1, 1 }, - { ahc_patch8_func, 589, 106, 33 }, - { ahc_patch4_func, 591, 1, 1 }, - { ahc_patch1_func, 597, 2, 2 }, - { ahc_patch0_func, 599, 1, 1 }, - { ahc_patch1_func, 602, 1, 2 }, - { ahc_patch0_func, 603, 1, 1 }, - { ahc_patch9_func, 604, 3, 3 }, - { ahc_patch15_func, 605, 1, 1 }, - { ahc_patch0_func, 607, 4, 1 }, - { ahc_patch19_func, 616, 2, 2 }, - { ahc_patch0_func, 618, 1, 1 }, - { ahc_patch19_func, 622, 10, 3 }, - { ahc_patch5_func, 624, 8, 1 }, - { ahc_patch0_func, 632, 9, 2 }, - { ahc_patch5_func, 633, 8, 1 }, - { ahc_patch4_func, 643, 1, 2 }, - { ahc_patch0_func, 644, 1, 1 }, - { ahc_patch19_func, 645, 1, 2 }, - { ahc_patch0_func, 646, 3, 2 }, - { ahc_patch4_func, 648, 1, 1 }, - { ahc_patch5_func, 649, 1, 1 }, - { ahc_patch5_func, 652, 1, 1 }, - { ahc_patch5_func, 654, 1, 1 }, - { ahc_patch4_func, 656, 2, 2 }, - { ahc_patch0_func, 658, 2, 1 }, - { ahc_patch5_func, 660, 1, 1 }, - { ahc_patch5_func, 663, 1, 1 }, - { ahc_patch5_func, 666, 1, 1 }, - { ahc_patch19_func, 670, 1, 1 }, - { ahc_patch19_func, 673, 1, 1 }, - { ahc_patch4_func, 679, 1, 1 }, - { ahc_patch6_func, 682, 1, 2 }, - { ahc_patch0_func, 683, 1, 1 }, - { ahc_patch7_func, 695, 16, 1 }, - { ahc_patch4_func, 711, 20, 1 }, - { ahc_patch9_func, 732, 4, 2 }, - { ahc_patch0_func, 736, 4, 1 }, - { ahc_patch9_func, 740, 4, 2 }, - { ahc_patch0_func, 744, 3, 1 }, - { ahc_patch6_func, 750, 1, 1 }, - { ahc_patch22_func, 752, 14, 1 }, - { ahc_patch7_func, 766, 3, 1 }, - { ahc_patch9_func, 778, 24, 8 }, - { ahc_patch19_func, 782, 1, 2 }, - { ahc_patch0_func, 783, 1, 1 }, - { ahc_patch15_func, 788, 4, 2 }, - { ahc_patch0_func, 792, 7, 3 }, - { ahc_patch23_func, 792, 5, 2 }, - { ahc_patch0_func, 797, 2, 1 }, - { ahc_patch0_func, 802, 42, 3 }, - { ahc_patch18_func, 814, 18, 2 }, - { ahc_patch0_func, 832, 1, 1 }, - { ahc_patch4_func, 856, 1, 1 }, - { ahc_patch4_func, 857, 3, 2 }, - { ahc_patch0_func, 860, 1, 1 }, - { ahc_patch13_func, 861, 3, 1 }, - { ahc_patch4_func, 864, 12, 1 } + { ahc_patch7_func, 430, 1, 1 }, + { ahc_patch8_func, 431, 3, 3 }, + { ahc_patch6_func, 432, 1, 2 }, + { ahc_patch0_func, 433, 1, 1 }, + { ahc_patch9_func, 434, 1, 1 }, + { ahc_patch15_func, 435, 1, 2 }, + { ahc_patch13_func, 435, 1, 1 }, + { ahc_patch14_func, 437, 9, 4 }, + { ahc_patch9_func, 437, 1, 1 }, + { ahc_patch9_func, 444, 2, 1 }, + { ahc_patch0_func, 446, 4, 3 }, + { ahc_patch9_func, 446, 1, 2 }, + { ahc_patch0_func, 447, 3, 1 }, + { ahc_patch1_func, 451, 2, 1 }, + { ahc_patch7_func, 453, 10, 2 }, + { ahc_patch0_func, 463, 1, 1 }, + { ahc_patch8_func, 464, 118, 22 }, + { ahc_patch1_func, 466, 3, 2 }, + { ahc_patch0_func, 469, 5, 3 }, + { ahc_patch9_func, 469, 2, 2 }, + { ahc_patch0_func, 471, 3, 1 }, + { ahc_patch1_func, 476, 2, 2 }, + { ahc_patch0_func, 478, 6, 3 }, + { ahc_patch9_func, 478, 2, 2 }, + { ahc_patch0_func, 480, 3, 1 }, + { ahc_patch1_func, 486, 2, 2 }, + { ahc_patch0_func, 488, 9, 7 }, + { ahc_patch9_func, 488, 5, 6 }, + { ahc_patch19_func, 488, 1, 2 }, + { ahc_patch0_func, 489, 1, 1 }, + { ahc_patch19_func, 491, 1, 2 }, + { ahc_patch0_func, 492, 1, 1 }, + { ahc_patch0_func, 493, 4, 1 }, + { ahc_patch6_func, 498, 3, 2 }, + { ahc_patch0_func, 501, 1, 1 }, + { ahc_patch6_func, 511, 1, 2 }, + { ahc_patch0_func, 512, 1, 1 }, + { ahc_patch20_func, 549, 7, 1 }, + { ahc_patch3_func, 584, 1, 2 }, + { ahc_patch0_func, 585, 1, 1 }, + { ahc_patch21_func, 588, 1, 1 }, + { ahc_patch8_func, 590, 106, 33 }, + { ahc_patch4_func, 592, 1, 1 }, + { ahc_patch1_func, 598, 2, 2 }, + { ahc_patch0_func, 600, 1, 1 }, + { ahc_patch1_func, 603, 1, 2 }, + { ahc_patch0_func, 604, 1, 1 }, + { ahc_patch9_func, 605, 3, 3 }, + { ahc_patch15_func, 606, 1, 1 }, + { ahc_patch0_func, 608, 4, 1 }, + { ahc_patch19_func, 617, 2, 2 }, + { ahc_patch0_func, 619, 1, 1 }, + { ahc_patch19_func, 623, 10, 3 }, + { ahc_patch5_func, 625, 8, 1 }, + { ahc_patch0_func, 633, 9, 2 }, + { ahc_patch5_func, 634, 8, 1 }, + { ahc_patch4_func, 644, 1, 2 }, + { ahc_patch0_func, 645, 1, 1 }, + { ahc_patch19_func, 646, 1, 2 }, + { ahc_patch0_func, 647, 3, 2 }, + { ahc_patch4_func, 649, 1, 1 }, + { ahc_patch5_func, 650, 1, 1 }, + { ahc_patch5_func, 653, 1, 1 }, + { ahc_patch5_func, 655, 1, 1 }, + { ahc_patch4_func, 657, 2, 2 }, + { ahc_patch0_func, 659, 2, 1 }, + { ahc_patch5_func, 661, 1, 1 }, + { ahc_patch5_func, 664, 1, 1 }, + { ahc_patch5_func, 667, 1, 1 }, + { ahc_patch19_func, 671, 1, 1 }, + { ahc_patch19_func, 674, 1, 1 }, + { ahc_patch4_func, 680, 1, 1 }, + { ahc_patch6_func, 683, 1, 2 }, + { ahc_patch0_func, 684, 1, 1 }, + { ahc_patch7_func, 696, 16, 1 }, + { ahc_patch4_func, 712, 20, 1 }, + { ahc_patch9_func, 733, 4, 2 }, + { ahc_patch0_func, 737, 4, 1 }, + { ahc_patch9_func, 741, 4, 2 }, + { ahc_patch0_func, 745, 3, 1 }, + { ahc_patch6_func, 751, 1, 1 }, + { ahc_patch22_func, 753, 14, 1 }, + { ahc_patch7_func, 767, 3, 1 }, + { ahc_patch9_func, 779, 24, 8 }, + { ahc_patch19_func, 783, 1, 2 }, + { ahc_patch0_func, 784, 1, 1 }, + { ahc_patch15_func, 789, 4, 2 }, + { ahc_patch0_func, 793, 7, 3 }, + { ahc_patch23_func, 793, 5, 2 }, + { ahc_patch0_func, 798, 2, 1 }, + { ahc_patch0_func, 803, 42, 3 }, + { ahc_patch18_func, 815, 18, 2 }, + { ahc_patch0_func, 833, 1, 1 }, + { ahc_patch4_func, 857, 1, 1 }, + { ahc_patch4_func, 858, 3, 2 }, + { ahc_patch0_func, 861, 1, 1 }, + { ahc_patch13_func, 862, 3, 1 }, + { ahc_patch4_func, 865, 12, 1 } }; static struct cs { @@ -1296,11 +1297,11 @@ static struct cs { } critical_sections[] = { { 11, 18 }, { 21, 30 }, - { 711, 727 }, - { 857, 860 }, - { 864, 870 }, - { 872, 874 }, - { 874, 876 } + { 712, 728 }, + { 858, 861 }, + { 865, 871 }, + { 873, 875 }, + { 875, 877 } }; static const int num_critical_sections = sizeof(critical_sections) diff -puN drivers/scsi/aic7xxx/aicasm/aicasm.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aicasm/aicasm.c --- 25/drivers/scsi/aic7xxx/aicasm/aicasm.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aicasm/aicasm.c Wed Dec 24 12:15:38 2003 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.c#22 $ + * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.c#23 $ * * $FreeBSD$ */ @@ -609,10 +609,10 @@ output_listing(char *ifilename) while (line < cur_instr->srcline) { fgets(buf, sizeof(buf), ifile); - fprintf(listfile, "\t\t%s", buf); + fprintf(listfile, " \t%s", buf); line++; } - fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr, + fprintf(listfile, "%04x %02x%02x%02x%02x", instrptr, #if BYTE_ORDER == LITTLE_ENDIAN cur_instr->format.bytes[0], cur_instr->format.bytes[1], @@ -624,14 +624,23 @@ output_listing(char *ifilename) cur_instr->format.bytes[1], cur_instr->format.bytes[0]); #endif - fgets(buf, sizeof(buf), ifile); - fprintf(listfile, "\t%s", buf); - line++; + /* + * Macro expansions can cause several instructions + * to be output for a single source line. Only + * advance the line once in these cases. + */ + if (line == cur_instr->srcline) { + fgets(buf, sizeof(buf), ifile); + fprintf(listfile, "\t%s", buf); + line++; + } else { + fprintf(listfile, "\n"); + } instrptr++; } /* Dump the remainder of the file */ while(fgets(buf, sizeof(buf), ifile) != NULL) - fprintf(listfile, "\t\t%s", buf); + fprintf(listfile, " %s", buf); fclose(ifile); } diff -puN drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l --- 25/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l Wed Dec 24 12:15:38 2003 @@ -38,7 +38,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_macro_scan.l#7 $ + * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_macro_scan.l#8 $ * * $FreeBSD$ */ @@ -78,6 +78,7 @@ MCARG [^(), \t]+ \n { ++yylineno; } +\r ; {SPACE} ; \( { parren_count++; diff -puN drivers/scsi/aic7xxx/aicasm/aicasm_scan.l~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aicasm/aicasm_scan.l --- 25/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l Wed Dec 24 12:15:38 2003 @@ -38,7 +38,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_scan.l#18 $ + * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_scan.l#19 $ * * $FreeBSD$ */ @@ -87,6 +87,7 @@ MBODY ((\\[^\n])*[^\n\\]*)+ %% \n { ++yylineno; } +\r ; "/*" { BEGIN COMMENT; /* Enter comment eating state */ } "/*" { fprintf(stderr, "Warning! Comment within comment."); } \n { ++yylineno; } @@ -114,6 +115,7 @@ if[ \t]*\( { } } \n { ++yylineno; } +\r ; [^()\n]+ { char *yptr; @@ -359,6 +361,7 @@ else { return T_ELSE; } /* Eat escaped newlines. */ ++yylineno; } +\r ; \n { /* Macros end on the first unescaped newline. */ BEGIN INITIAL; @@ -369,10 +372,17 @@ else { return T_ELSE; } } {MBODY} { char *yptr; + char c; yptr = yytext; - while (*yptr) - *string_buf_ptr++ = *yptr++; + while (c = *yptr++) { + /* + * Strip carriage returns. + */ + if (c == '\r') + continue; + *string_buf_ptr++ = c; + } } {WORD}\( { char *yptr; diff -puN drivers/scsi/aic7xxx/aicasm/Makefile~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aicasm/Makefile --- 25/drivers/scsi/aic7xxx/aicasm/Makefile~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aicasm/Makefile Wed Dec 24 12:15:38 2003 @@ -49,11 +49,19 @@ aicdb.h: clean: rm -f $(clean-files) +# Create a dependency chain in generated files +# to avoid concurrent invocations of the single +# rule that builds them all. +aicasm_gram.c: aicasm_gram.h aicasm_gram.c aicasm_gram.h: aicasm_gram.y $(YACC) $(YFLAGS) -b $(<:.y=) $< mv $(<:.y=).tab.c $(<:.y=.c) mv $(<:.y=).tab.h $(<:.y=.h) +# Create a dependency chain in generated files +# to avoid concurrent invocations of the single +# rule that builds them all. +aicasm_macro_gram.c: aicasm_macro_gram.h aicasm_macro_gram.c aicasm_macro_gram.h: aicasm_macro_gram.y $(YACC) $(YFLAGS) -b $(<:.y=) -p mm $< mv $(<:.y=).tab.c $(<:.y=.c) diff -puN drivers/scsi/aic7xxx/aiclib.c~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aiclib.c --- 25/drivers/scsi/aic7xxx/aiclib.c~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aiclib.c Wed Dec 24 12:15:38 2003 @@ -30,16 +30,6 @@ * $Id$ */ -#include -#include -#include - -/* Core SCSI definitions */ -#include "scsi.h" -#include "hosts.h" -#include "aiclib.h" -#include "cam.h" - #ifndef FALSE #define FALSE 0 #endif /* FALSE */ @@ -1410,3 +1400,336 @@ aic_parse_brace_option(char *opt_name, c } return (opt_arg); } + +/************************* Magic SysReq Support *******************************/ +void +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +aic_sysrq_handler(int key, struct pt_regs *unused, struct kbd_struct *unused1, + struct tty_struct *unused2) +#else +aic_sysrq_handler(int key, struct pt_regs *unused, struct tty_struct *unused2) +#endif +{ +#ifdef CONFIG_MAGIC_SYSRQ + struct aic_softc *aic; + u_long l; + + aic_list_lock(&l); + + TAILQ_FOREACH(aic, &aic_tailq, links) { + u_long s; + + aic_lock(aic, &s); + aic_dump_card_state(aic); + aic_unlock(aic, &s); + } + aic_list_unlock(&l); +#endif +} + +int +aic_install_sysrq(struct aic_sysrq_key_op *key_op) +{ +#ifdef CONFIG_MAGIC_SYSRQ + char *str; + int len; + int i; + + str = key_op->help_msg; + len = strlen(str); + for (i = 0; i < len; i++) { + int key; + + key = str[i]; + if (register_sysrq_key(key, key_op) == 0) { + + if (key >= 'a' && key <= 'z') + str[i] = key + ('A' - 'a'); + return (key); + } + } +#endif + return (0); +} + +void +aic_remove_sysrq(int key, struct aic_sysrq_key_op *key_op) +{ +#ifdef CONFIG_MAGIC_SYSRQ + unregister_sysrq_key(key, key_op); +#endif +} + +/******************************** Bus DMA *************************************/ +int +aic_dma_tag_create(struct aic_softc *aic, bus_dma_tag_t parent, + bus_size_t alignment, bus_size_t boundary, + bus_addr_t lowaddr, bus_addr_t highaddr, + bus_dma_filter_t *filter, void *filterarg, + bus_size_t maxsize, int nsegments, + bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag) +{ + bus_dma_tag_t dmat; + + dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT); + if (dmat == NULL) + return (ENOMEM); + + /* + * Linux is very simplistic about DMA memory. For now don't + * maintain all specification information. Once Linux supplies + * better facilities for doing these operations, or the + * needs of this particular driver change, we might need to do + * more here. + */ + dmat->alignment = alignment; + dmat->boundary = boundary; + dmat->maxsize = maxsize; + *ret_tag = dmat; + return (0); +} + +void +aic_dma_tag_destroy(struct aic_softc *aic, bus_dma_tag_t dmat) +{ + free(dmat, M_DEVBUF); +} + +int +aic_dmamem_alloc(struct aic_softc *aic, bus_dma_tag_t dmat, void** vaddr, + int flags, bus_dmamap_t *mapp) +{ + bus_dmamap_t map; + + map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT); + if (map == NULL) + return (ENOMEM); + /* + * Although we can dma data above 4GB, our + * coherent memory is below 4GB for + * space efficiency reasons (only need a 4byte + * address). For this reason, we have to reset + * our dma mask when doing allocations. + */ + aic_set_dma_mask(aic, 0xFFFFFFFF); + *vaddr = aic_alloc_coherent(aic, dmat->maxsize, &map->bus_addr); + aic_set_dma_mask(aic, aic->platform_data->hw_dma_mask); + if (*vaddr == NULL) + return (ENOMEM); + *mapp = map; + return(0); +} + +void +aic_dmamem_free(struct aic_softc *aic, bus_dma_tag_t dmat, + void* vaddr, bus_dmamap_t map) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + aic_free_coherent(aic, dmat->maxsize, vaddr, map->bus_addr); +#else + free(vaddr, M_DEVBUF); +#endif +} + +int +aic_dmamap_load(struct aic_softc *aic, bus_dma_tag_t dmat, bus_dmamap_t map, + void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb, + void *cb_arg, int flags) +{ + /* + * Assume for now that this will only be used during + * initialization and not for per-transaction buffer mapping. + */ + bus_dma_segment_t stack_sg; + + stack_sg.ds_addr = map->bus_addr; + stack_sg.ds_len = dmat->maxsize; + cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0); + return (0); +} + +void +aic_dmamap_destroy(struct aic_softc *aic, bus_dma_tag_t dmat, bus_dmamap_t map) +{ + free(map, M_DEVBUF); +} + +int +aic_dmamap_unload(struct aic_softc *aic, bus_dma_tag_t dmat, bus_dmamap_t map) +{ + /* Nothing to do */ + return (0); +} + +/***************************** Queue Handling ********************************/ +/* + * In 2.4.X and above, this routine is called from a tasklet, + * so we must re-acquire our lock prior to executing this code. + * In all prior kernels, aic_schedule_runq() calls this routine + * directly and aic_schedule_runq() is called with our lock held. + */ +void +aic_runq_tasklet(unsigned long data) +{ + struct aic_softc* aic; + struct aic_linux_device *dev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + u_long flags; +#endif + + aic = (struct aic_softc *)data; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + aic_lock(aic, &flags); +#endif + while ((dev = aic_linux_next_device_to_run(aic)) != NULL) { + + TAILQ_REMOVE(&aic->platform_data->device_runq, dev, links); + dev->flags &= ~AIC_DEV_ON_RUN_LIST; + aic_linux_check_device_queue(aic, dev); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + /* Yeild to our interrupt handler */ + aic_unlock(aic, &flags); + aic_lock(aic, &flags); +#endif + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + aic_unlock(aic, &flags); +#endif +} + +void +aic_unblock_tasklet(unsigned long data) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + struct aic_softc* aic; + + aic = (struct aic_softc *)data; + scsi_unblock_requests(aic->platform_data->host); +#else +#error "Fix 2.2.X Kernel Support" +#endif +} + +void +aic_bus_settle_complete(u_long data) +{ + struct aic_softc *aic; + u_long s; + + aic = (struct aic_softc *)data; + /* + * Guard against our bottom half scheduling another + * bus settle delay just as our timer runs. If this + * occurs, do nothing. The newly scheduled timer will + * take care of things. + */ + aic_lock(aic, &s); + if (timer_pending(&aic->platform_data->bus_settle_timer) == 0) { + aic->platform_data->flags &= ~AIC_BUS_SETTLE_TIMER; + aic_release_simq_locked(aic); + } + aic_unlock(aic, &s); +} + +void +aic_freeze_simq(struct aic_softc *aic) +{ + aic->platform_data->qfrozen++; + if (aic->platform_data->qfrozen == 1) + scsi_block_requests(aic->platform_data->host); +} + +void +aic_release_simq(struct aic_softc *aic) +{ + u_long s; + + aic_lock(aic, &s); + aic_release_simq_locked(aic); + aic_unlock(aic, &s); +} + +void +aic_release_simq_locked(struct aic_softc *aic) +{ + + if (aic->platform_data->qfrozen > 0) + aic->platform_data->qfrozen--; + if (AIC_DV_SIMQ_FROZEN(aic) + && ((aic->platform_data->flags & AIC_DV_WAIT_SIMQ_RELEASE) != 0)) { + aic->platform_data->flags &= ~AIC_DV_WAIT_SIMQ_RELEASE; + up(&aic->platform_data->dv_sem); + } + if (aic->platform_data->qfrozen == 0) { + aic_schedule_unblock(aic); + aic_schedule_runq(aic); + } +} + +/***************************** Timer Facilities *******************************/ +void +aic_platform_timeout(struct scsi_cmnd *cmd) +{ + + if (AIC_DV_CMD(cmd) != 0) { + + aic_linux_dv_timeout(cmd); + } else { + struct scb *scb; + struct aic_softc *aic; + u_long s; + + scb = (struct scb *)cmd->host_scribble; + aic = scb->aic_softc; + aic_lock(aic, &s); + + if (scb == NULL + || scb->flags == SCB_FLAG_NONE) { + int done_late; + + /* + * Handle timeout/completion races. + * If the command is still sitting on + * our completion queue, just re-instate + * the timeout. If we've already completed + * the command, the function pointer in our + * timer will be cleared and we will need to + * additionally complete it again to the mid-layer. + * + * Since done_late is cleared by adding a + * timer, we must save off its value first. + */ + done_late = cmd->eh_timeout.function == NULL; + scsi_add_timer(cmd, 60*HZ, aic_linux_midlayer_timeout); + if (done_late) + cmd->scsi_done(cmd); + } else if ((scb->platform_data->flags & AIC_TIMEOUT_ACTIVE)) { + + /* + * Handle the case of timeouts that expire just + * as we delete timers during recovery by skipping + * SCBs that don't have timers active. + */ + scb->platform_data->flags &= ~AIC_TIMEOUT_ACTIVE; + + /* + * We must clear out the function pointer so that + * scsi_add_timer does not believe that a del_timer + * is required before setting up a new timer for + * this command. + */ + scb->io_ctx->eh_timeout.function = NULL; + aic_timeout(scb); + } + aic_unlock(aic, &s); + } +} + +void +aic_linux_midlayer_timeout(struct scsi_cmnd *cmd) +{ + struct aic_softc *aic; + + aic = *(struct aic_softc **)cmd->device->host->hostdata; + printf("%s: midlayer_timeout\n", aic_name(aic)); +} diff -puN drivers/scsi/aic7xxx/aiclib.h~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/aiclib.h --- 25/drivers/scsi/aic7xxx/aiclib.h~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/aiclib.h Wed Dec 24 12:15:38 2003 @@ -1,4 +1,5 @@ /* + * SCSI definitions... * Largely written by Julian Elischer (julian@tfs.com) * for TRW Financial Systems. * @@ -57,6 +58,42 @@ #ifndef _AICLIB_H #define _AICLIB_H +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#include +#else +#include +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) +#include /* For tasklet support. */ +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#include +#endif +#include + +#include "scsi.h" +#include "hosts.h" + +/* Name space conflict with BSD queue macros */ +#ifdef LIST_HEAD +#undef LIST_HEAD +#endif +#include "cam.h" +#include "queue.h" +#include "scsi_message.h" +#include "scsi_iu.h" + /* * Linux Interrupt Support. */ @@ -66,9 +103,731 @@ typedef void irqreturn_t; #endif /* - * SCSI command format + * Linux Timer Support. + */ +#define AIC_USECS_PER_JIFFY (1000000/HZ) + +/**************************** Module Library Hack *****************************/ +/* + * What we'd like to do is have a single "scsi library" module that both the + * aic7xxx and aic79xx drivers could load and depend on. A cursory examination + * of implementing module dependencies in Linux (handling the install and + * initrd cases) does not look promissing. For now, we just duplicate this + * code in both drivers using a simple symbol renaming scheme that hides this + * hack from the drivers. + */ +#define AIC_LIB_ENTRY_CONCAT(x, prefix) prefix ## x +#define AIC_LIB_ENTRY_EXPAND(x, prefix) AIC_LIB_ENTRY_CONCAT(x, prefix) +#define AIC_LIB_ENTRY(x) AIC_LIB_ENTRY_EXPAND(x, AIC_LIB_PREFIX) + +#define AIC_CONST_ENTRY(x) AIC_LIB_ENTRY_EXPAND(x,AIC_CONST_PREFIX) + +#define aic_sense_desc AIC_LIB_ENTRY(_sense_desc) +#define aic_sense_error_action AIC_LIB_ENTRY(_sense_error_action) +#define aic_error_action AIC_LIB_ENTRY(_error_action) +#define aic_op_desc AIC_LIB_ENTRY(_op_desc) +#define aic_cdb_string AIC_LIB_ENTRY(_cdb_string) +#define aic_print_inquiry AIC_LIB_ENTRY(_print_inquiry) +#define aic_calc_syncsrate AIC_LIB_ENTRY(_calc_syncrate) +#define aic_calc_syncparam AIC_LIB_ENTRY(_calc_syncparam) +#define aic_calc_speed AIC_LIB_ENTRY(_calc_speed) +#define aic_inquiry_match AIC_LIB_ENTRY(_inquiry_match) +#define aic_static_inquiry_match AIC_LIB_ENTRY(_static_inquiry_match) +#define aic_parse_brace_option AIC_LIB_ENTRY(_parse_brace_option) +#define aic_power_state_change AIC_LIB_ENTRY(_power_state_change) +#define aic_sysrq_handler AIC_LIB_ENTRY(_sysrq_handler) +#define aic_install_sysrq AIC_LIB_ENTRY(_install_sysrq) +#define aic_remove_sysrq AIC_LIB_ENTRY(_remove_sysrq) +#define aic_list_lock AIC_LIB_ENTRY(_list_lock) +#define aic_list_unlock AIC_LIB_ENTRY(_list_unlock) +#define aic_lock AIC_LIB_ENTRY(_lock) +#define aic_unlock AIC_LIB_ENTRY(_unlock) +#define aic_dump_card_state AIC_LIB_ENTRY(_dump_card_state) +#define aic_linux_dv_complete AIC_LIB_ENTRY(_linux_dv_complete) +#define aic_linux_run_device_queue AIC_LIB_ENTRY(_linux_run_device_queue) +#define aic_linux_dv_timeout AIC_LIB_ENTRY(_linux_dv_timeout) +#define aic_linux_midlayer_timeout AIC_LIB_ENTRY(_linux_midlayer_timeout) +#define aic_freeze_simq AIC_LIB_ENTRY(_freeze_simq) +#define aic_bus_settle_complete AIC_LIB_ENTRY(_bus_settle_complete) +#define aic_release_simq AIC_LIB_ENTRY(_release_simq) +#define aic_release_simq AIC_LIB_ENTRY(_release_simq) +#define aic_release_simq_locked AIC_LIB_ENTRY(_release_simq_locked) +#define aic_dma_tag_create AIC_LIB_ENTRY(_dma_tag_create) +#define aic_dma_tag_destroy AIC_LIB_ENTRY(_dma_tag_destroy) +#define aic_dmamem_alloc AIC_LIB_ENTRY(_dmamem_alloc) +#define aic_dmamem_free AIC_LIB_ENTRY(_dmamem_free) +#define aic_dmamap_create AIC_LIB_ENTRY(_dmamap_create) +#define aic_dmamap_destroy AIC_LIB_ENTRY(_dmamap_destroy) +#define aic_dmamap_load AIC_LIB_ENTRY(_dmamap_load) +#define aic_dmamap_unload AIC_LIB_ENTRY(_dmamap_unload) +#define aic_dmamap_destroy AIC_LIB_ENTRY(_dmamap_destroy) +#define aic_timeout AIC_LIB_ENTRY(_timeout) +#define aic_runq_tasklet AIC_LIB_ENTRY(_runq_tasklet) +#define aic_unblock_tasklet AIC_LIB_ENTRY(_unblock_tasklet) +#define aic_platform_timeout AIC_LIB_ENTRY(_platform_timeout) +#define aic_name AIC_LIB_ENTRY(_name) + +#define aic_tailq AIC_LIB_ENTRY(_tailq) +#define aic_softc AIC_LIB_ENTRY(_softc) +#define aic_transinfo AIC_LIB_ENTRY(_transinfo) +#define aic_platform_data AIC_LIB_ENTRY(_platform_data) +#define aic_devinfo AIC_LIB_ENTRY(_devinfo) +#define aic_callback_t AIC_LIB_ENTRY(_callback_t) + +#define AIC_NUM_LUNS AIC_CONST_ENTRY(_NUM_LUNS) +#define AIC_NUM_TARGETS AIC_CONST_ENTRY(_NUM_TARGETS) +#define AIC_RESOURCE_SHORTAGE AIC_CONST_ENTRY(_RESOURCE_SHORTAGE) + +/*************************** Forward Declarations *****************************/ +struct aic_softc; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +typedef struct device *aic_dev_softc_t; +#else +typedef struct pci_dev *aic_dev_softc_t; +#endif +typedef Scsi_Cmnd *aic_io_ctx_t; + +/*************************** Timer DataStructures *****************************/ +typedef struct timer_list aic_timer_t; + +/***************************** Bus Space/DMA **********************************/ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17) +typedef dma_addr_t bus_addr_t; +#else +typedef uint32_t bus_addr_t; +#endif +typedef uint32_t bus_size_t; + +typedef enum { + BUS_SPACE_MEMIO, + BUS_SPACE_PIO +} bus_space_tag_t; + +typedef union { + u_long ioport; + volatile uint8_t *maddr; +} bus_space_handle_t; + +typedef struct bus_dma_segment +{ + bus_addr_t ds_addr; + bus_size_t ds_len; +} bus_dma_segment_t; + +struct aic_linux_dma_tag +{ + bus_size_t alignment; + bus_size_t boundary; + bus_size_t maxsize; +}; +typedef struct aic_linux_dma_tag* bus_dma_tag_t; + +struct aic_linux_dmamap +{ + bus_addr_t bus_addr; +}; +typedef struct aic_linux_dmamap* bus_dmamap_t; + +typedef int bus_dma_filter_t(void*, bus_addr_t); +typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int); + +#define BUS_DMA_WAITOK 0x0 +#define BUS_DMA_NOWAIT 0x1 +#define BUS_DMA_ALLOCNOW 0x2 +#define BUS_DMA_LOAD_SEGS 0x4 /* + * Argument is an S/G list not + * a single buffer. + */ + +#define BUS_SPACE_MAXADDR 0xFFFFFFFF +#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF +#define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF + +int aic_dma_tag_create(struct aic_softc *, bus_dma_tag_t /*parent*/, + bus_size_t /*alignment*/, bus_size_t /*boundary*/, + bus_addr_t /*lowaddr*/, bus_addr_t /*highaddr*/, + bus_dma_filter_t*/*filter*/, void */*filterarg*/, + bus_size_t /*maxsize*/, int /*nsegments*/, + bus_size_t /*maxsegsz*/, int /*flags*/, + bus_dma_tag_t */*dma_tagp*/); + +void aic_dma_tag_destroy(struct aic_softc *, bus_dma_tag_t /*tag*/); + +int aic_dmamem_alloc(struct aic_softc *, bus_dma_tag_t /*dmat*/, + void** /*vaddr*/, int /*flags*/, + bus_dmamap_t* /*mapp*/); + +void aic_dmamem_free(struct aic_softc *, bus_dma_tag_t /*dmat*/, + void* /*vaddr*/, bus_dmamap_t /*map*/); + +void aic_dmamap_destroy(struct aic_softc *, bus_dma_tag_t /*tag*/, + bus_dmamap_t /*map*/); + +int aic_dmamap_load(struct aic_softc *aic, bus_dma_tag_t /*dmat*/, + bus_dmamap_t /*map*/, void * /*buf*/, + bus_size_t /*buflen*/, bus_dmamap_callback_t *, + void */*callback_arg*/, int /*flags*/); + +int aic_dmamap_unload(struct aic_softc *, bus_dma_tag_t, bus_dmamap_t); + +/* + * Operations performed by aic_dmamap_sync(). */ +#define BUS_DMASYNC_PREREAD 0x01 /* pre-read synchronization */ +#define BUS_DMASYNC_POSTREAD 0x02 /* post-read synchronization */ +#define BUS_DMASYNC_PREWRITE 0x04 /* pre-write synchronization */ +#define BUS_DMASYNC_POSTWRITE 0x08 /* post-write synchronization */ + +/* + * XXX + * aic_dmamap_sync is only used on buffers allocated with + * the pci_alloc_consistent() API. Although I'm not sure how + * this works on architectures with a write buffer, Linux does + * not have an API to sync "coherent" memory. Perhaps we need + * to do an mb()? + */ +#define aic_dmamap_sync(aic, dma_tag, dmamap, offset, len, op) + +/*************************** Linux DMA Wrappers *******************************/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#define aic_alloc_coherent(aic, size, bus_addr_ptr) \ + dma_alloc_coherent(aic->dev_softc, size, bus_addr_ptr, /*flag*/0) + +#define aic_free_coherent(aic, size, vaddr, bus_addr) \ + dma_free_coherent(aic->dev_softc, size, vaddr, bus_addr) + +#define aic_map_single(aic, buf, size, direction) \ + dma_map_single(aic->dev_softc, buf, size, direction) + +#define aic_unmap_single(aic, busaddr, size, direction) \ + dma_unmap_single(aic->dev_softc, busaddr, size, direction) + +#define aic_map_sg(aic, sg_list, num_sg, direction) \ + dma_map_sg(aic->dev_softc, sg_list, num_sg, direction) + +#define aic_unmap_sg(aic, sg_list, num_sg, direction) \ + dma_unmap_sg(aic->dev_softc, sg_list, num_sg, direction) + +#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) + +#define aic_alloc_coherent(aic, size, bus_addr_ptr) \ + pci_alloc_consistent(aic->dev_softc, size, bus_addr_ptr) + +#define aic_free_coherent(aic, size, vaddr, bus_addr) \ + pci_free_consistent(aic->dev_softc, size, vaddr, bus_addr) + +#define aic_map_single(aic, buf, size, direction) \ + pci_map_single(aic->dev_softc, buf, size, direction) + +#define aic_unmap_single(aic, busaddr, size, direction) \ + pci_unmap_single(aic->dev_softc, busaddr, size, direction) + +#define aic_map_sg(aic, sg_list, num_sg, direction) \ + pci_map_sg(aic->dev_softc, sg_list, num_sg, direction) + +#define aic_unmap_sg(aic, sg_list, num_sg, direction) \ + pci_unmap_sg(aic->dev_softc, sg_list, num_sg, direction) + +#else + +static __inline void *aic_alloc_coherent(struct aic_softc *aic, + bus_size_t size, bus_addr_t *baddrp); + +/* + * At least in 2.2.14, malloc is a slab allocator so all + * allocations are aligned. We assume for these kernel versions + * that all allocations will be bellow 4Gig, physically contiguous, + * and accessible via DMA by the controller. + */ +static __inline void * +aic_alloc_coherent(struct aic_softc *aic, bus_size_t size, bus_addr_t *baddrp) +{ + void *vaddr; + + vaddr_ = malloc(size, M_DEVBUF, M_NOWAIT); + if (vaddr != NULL) + *baddrp = virt_to_bus(vaddr); + return (vaddr); +} + +#define aic_free_coherent(aic, size, vaddr, bus_addr) \ + free(vaddr, M_DEVBUF) + +#define aic_map_sg(pdev, sg_list, nseg, direction) (nseg) +#define aic_unmap_sg(pdev, sg_list, nseg, direction) +#define aic_map_single(pdev, buffer, bufflen, direction) \ + (VIRT_TO_BUS(buffer)) +#define aic_unmap_single(pdev, buffer, buflen, direction) +#define sg_dma_address(sg) (VIRT_TO_BUS((sg)->address)) +#define sg_dma_len(sg) ((sg)->length) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + +#define aic_set_dma_mask(aic, mask) dma_set_mask(aic->dev_softc, mask) + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3) + +/* + * Device softc is NULL for EISA devices. + */ +#define aic_set_dma_mask(aic, mask) \ + ((aic)->dev_softc == NULL ? 0 : pci_set_dma_mask(aic->dev_softc, mask)) + +#else +/* + * Device softc is NULL for EISA devices. + * Always "return" 0 for success. + */ +#define aic_set_dma_mask(aic, mask) \ + (((aic)->dev_softc == NULL) \ + ? 0 \ + : (((aic)->dev_softc->dma_mask = mask) && 0)) +#endif + +/************************* Host Template Macros *******************************/ +#if defined CONFIG_HIGHIO +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) +/* Assume RedHat Distribution with its different HIGHIO conventions. */ +#define AIC_TEMPLATE_DMA_SETTINGS() \ + .can_dma_32 = 1, \ + .single_sg_okay = 1, +#else +#define AIC_TEMPLATE_DMA_SETTINGS() \ + .highmem_io = 1, +#endif +#else +#define AIC_TEMPLATE_DMA_SETTINGS() +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) +#define AIC_TEMPLATE_MAX_SECTORS(sectors) \ + .max_sectors = (sectors), +#else +#define AIC_TEMPLATE_MAX_SECTORS(sectors) +#endif + +#if defined(__i386__) +#define AIC_TEMPLATE_BIOSPARAM() \ + .bios_param = AIC_LIB_ENTRY(_linux_biosparam), +#else +#define AIC_TEMPLATE_BIOSPARAM() +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#define AIC_TEMPLATE_VERSIONED_ENTRIES() \ + .slave_alloc = AIC_LIB_ENTRY(_linux_slave_alloc), \ + .slave_configure = AIC_LIB_ENTRY(_linux_slave_configure), \ + .slave_destroy = AIC_LIB_ENTRY(_linux_slave_destroy) +#else +#define AIC_TEMPLATE_VERSIONED_ENTRIES() \ + .detect = AIC_LIB_ENTRY(_linux_detect), \ + .release = AIC_LIB_ENTRY(_linux_release), \ + .select_queue_depths = AIC_LIB_ENTRY(_linux_select_queue_depth), \ + .use_new_eh_code = 1 +#endif + +#define AIC_TEMPLATE_INITIALIZER(NAME, MAX_SECTORS) \ +{ \ + .module = THIS_MODULE, \ + .name = NAME, \ + .proc_info = AIC_LIB_ENTRY(_linux_proc_info), \ + .info = AIC_LIB_ENTRY(_linux_info), \ + .queuecommand = AIC_LIB_ENTRY(_linux_queue), \ + .eh_abort_handler = AIC_LIB_ENTRY(_linux_abort), \ + .eh_device_reset_handler = AIC_LIB_ENTRY(_linux_dev_reset), \ + .eh_bus_reset_handler = AIC_LIB_ENTRY(_linux_bus_reset), \ + .can_queue = AIC_CONST_ENTRY(_MAX_QUEUE), \ + .this_id = -1, \ + .cmd_per_lun = 2, \ + .use_clustering = ENABLE_CLUSTERING, \ + AIC_TEMPLATE_MAX_SECTORS(MAX_SECTORS) \ + AIC_TEMPLATE_DMA_SETTINGS() \ + AIC_TEMPLATE_BIOSPARAM() \ + AIC_TEMPLATE_VERSIONED_ENTRIES() \ +} + +/************************** OS Utility Wrappers *******************************/ +#define printf printk +#define M_NOWAIT GFP_ATOMIC +#define M_WAITOK 0 +#define malloc(size, type, flags) kmalloc(size, flags) +#define free(ptr, type) kfree(ptr) + +static __inline void aic_delay(long); +static __inline void +aic_delay(long usec) +{ + /* + * udelay on Linux can have problems for + * multi-millisecond waits. Wait at most + * 1024us per call. + */ + while (usec > 0) { + udelay(usec % 1024); + usec -= 1024; + } +} + +/********************************** Misc Macros *******************************/ +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) +#define powerof2(x) ((((x)-1)&(x))==0) + +/******************************* Byte Order ***********************************/ +#define aic_htobe16(x) cpu_to_be16(x) +#define aic_htobe32(x) cpu_to_be32(x) +#define aic_htobe64(x) cpu_to_be64(x) +#define aic_htole16(x) cpu_to_le16(x) +#define aic_htole32(x) cpu_to_le32(x) +#define aic_htole64(x) cpu_to_le64(x) + +#define aic_be16toh(x) be16_to_cpu(x) +#define aic_be32toh(x) be32_to_cpu(x) +#define aic_be64toh(x) be64_to_cpu(x) +#define aic_le16toh(x) le16_to_cpu(x) +#define aic_le32toh(x) le32_to_cpu(x) +#define aic_le64toh(x) le64_to_cpu(x) + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif + +#ifndef BYTE_ORDER +#if defined(__BIG_ENDIAN) +#define BYTE_ORDER BIG_ENDIAN +#endif +#if defined(__LITTLE_ENDIAN) +#define BYTE_ORDER LITTLE_ENDIAN +#endif +#endif /* BYTE_ORDER */ + +/********************************* Core Includes ******************************/ +#include AIC_CORE_INCLUDE + +/**************************** Front End Queues ********************************/ +/* + * Data structure used to cast the Linux struct scsi_cmnd to something + * that allows us to use the queue macros. The linux structure has + * plenty of space to hold the links fields as required by the queue + * macros, but the queue macors require them to have the correct type. + */ +struct aic_cmd_internal { + /* Area owned by the Linux scsi layer. */ + uint8_t private[offsetof(struct scsi_cmnd, SCp.Status)]; + union { + STAILQ_ENTRY(aic_cmd) ste; + LIST_ENTRY(aic_cmd) le; + TAILQ_ENTRY(aic_cmd) tqe; + } links; + uint32_t end; +}; + +struct aic_cmd { + union { + struct aic_cmd_internal icmd; + struct scsi_cmnd scsi_cmd; + } un; +}; + +#define acmd_icmd(cmd) ((cmd)->un.icmd) +#define acmd_scsi_cmd(cmd) ((cmd)->un.scsi_cmd) +#define acmd_links un.icmd.links + +/*************************** Device Data Structures ***************************/ +/* + * A per probed device structure used to deal with some error recovery + * scenarios that the Linux mid-layer code just doesn't know how to + * handle. The structure allocated for a device only becomes persistent + * after a successfully completed inquiry command to the target when + * that inquiry data indicates a lun is present. + */ +TAILQ_HEAD(aic_busyq, aic_cmd); +typedef enum { + AIC_DEV_UNCONFIGURED = 0x01, + AIC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ + AIC_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ + AIC_DEV_ON_RUN_LIST = 0x08, /* Queued to be run later */ + AIC_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ + AIC_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ + AIC_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ + AIC_DEV_SLAVE_CONFIGURED = 0x80 /* slave_configure() has been called */ +} aic_linux_dev_flags; + +struct aic_linux_target; +struct aic_linux_device { + TAILQ_ENTRY(aic_linux_device) links; + struct aic_busyq busyq; + + /* + * The number of transactions currently + * queued to the device. + */ + int active; + + /* + * The currently allowed number of + * transactions that can be queued to + * the device. Must be signed for + * conversion from tagged to untagged + * mode where the device may have more + * than one outstanding active transaction. + */ + int openings; + + /* + * A positive count indicates that this + * device's queue is halted. + */ + u_int qfrozen; + + /* + * Cumulative command counter. + */ + u_long commands_issued; + + /* + * The number of tagged transactions when + * running at our current opening level + * that have been successfully received by + * this device since the last QUEUE FULL. + */ + u_int tag_success_count; +#define AIC_TAG_SUCCESS_INTERVAL 50 + + aic_linux_dev_flags flags; + + /* + * Per device timer. + */ + struct timer_list timer; + + /* + * The high limit for the tags variable. + */ + u_int maxtags; + + /* + * The computed number of tags outstanding + * at the time of the last QUEUE FULL event. + */ + u_int tags_on_last_queuefull; + + /* + * How many times we have seen a queue full + * with the same number of tags. This is used + * to stop our adaptive queue depth algorithm + * on devices with a fixed number of tags. + */ + u_int last_queuefull_same_count; +#define AIC_LOCK_TAGS_COUNT 50 + + /* + * How many transactions have been queued + * without the device going idle. We use + * this statistic to determine when to issue + * an ordered tag to prevent transaction + * starvation. This statistic is only updated + * if the AIC_DEV_PERIODIC_OTAG flag is set + * on this device. + */ + u_int commands_since_idle_or_otag; +#define AIC_OTAG_THRESH 500 + + int lun; + Scsi_Device *scsi_device; + struct aic_linux_target *target; +}; + +typedef enum { + AIC_DV_REQUIRED = 0x01, + AIC_INQ_VALID = 0x02, + AIC_BASIC_DV = 0x04, + AIC_ENHANCED_DV = 0x08 +} aic_linux_targ_flags; + +/* DV States */ +typedef enum { + AIC_DV_STATE_EXIT = 0, + AIC_DV_STATE_INQ_SHORT_ASYNC, + AIC_DV_STATE_INQ_ASYNC, + AIC_DV_STATE_INQ_ASYNC_VERIFY, + AIC_DV_STATE_TUR, + AIC_DV_STATE_REBD, + AIC_DV_STATE_INQ_VERIFY, + AIC_DV_STATE_WEB, + AIC_DV_STATE_REB, + AIC_DV_STATE_SU, + AIC_DV_STATE_BUSY +} aic_dv_state; + +struct aic_linux_target { + struct aic_linux_device *devices[AIC_NUM_LUNS]; + int channel; + int target; + int refcount; + struct aic_transinfo last_tinfo; + struct aic_softc *softc; + aic_linux_targ_flags flags; + struct scsi_inquiry_data *inq_data; + /* + * The next "fallback" period to use for narrow/wide transfers. + */ + uint8_t dv_next_narrow_period; + uint8_t dv_next_wide_period; + uint8_t dv_max_width; + uint8_t dv_max_ppr_options; + uint8_t dv_last_ppr_options; + u_int dv_echo_size; + aic_dv_state dv_state; + u_int dv_state_retry; + uint8_t *dv_buffer; + uint8_t *dv_buffer1; + + /* + * Cumulative counter of errors. + */ + u_long errors_detected; + u_long cmds_since_error; +}; + +/*************** OSM Dependent Components of Core Datastructures **************/ +/* + * Per-SCB OSM storage. + */ +typedef enum { + AIC_SCB_UP_EH_SEM = 0x1, + AIC_TIMEOUT_ACTIVE = 0x2, + AIC_RELEASE_SIMQ = 0x4 +} aic_linux_scb_flags; + +struct scb_platform_data { + struct aic_linux_device *dev; + bus_addr_t buf_busaddr; + uint32_t xfer_len; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) + uint32_t resid; /* Transfer residual */ +#endif + uint32_t sense_resid; /* Auto-Sense residual */ + aic_linux_scb_flags flags; +}; + +/* + * Define a structure used for each host adapter. All members are + * aligned on a boundary >= the size of the member to honor the + * alignment restrictions of the various platforms supported by + * this driver. + */ +typedef enum { + AIC_DV_WAIT_SIMQ_EMPTY = 0x01, + AIC_DV_WAIT_SIMQ_RELEASE = 0x02, + AIC_DV_ACTIVE = 0x04, + AIC_DV_SHUTDOWN = 0x08, + AIC_RUN_CMPLT_Q_TIMER = 0x10, + AIC_BUS_SETTLE_TIMER = 0x20 +} aic_linux_softc_flags; + +TAILQ_HEAD(aic_completeq, aic_cmd); + +struct aic_platform_data { + /* + * Fields accessed from interrupt context. + */ + struct aic_linux_target *targets[AIC_NUM_TARGETS]; + TAILQ_HEAD(, aic_linux_device) device_runq; + struct aic_completeq completeq; + + spinlock_t spin_lock; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + struct tasklet_struct runq_tasklet; + struct tasklet_struct unblock_tasklet; +#endif + u_int qfrozen; + pid_t dv_pid; + pid_t recovery_pid; + struct timer_list completeq_timer; + struct timer_list bus_settle_timer; + struct timer_list stats_timer; + struct semaphore eh_sem; + struct semaphore dv_sem; + struct semaphore dv_cmd_sem; + struct semaphore recovery_sem; + struct semaphore recovery_ending_sem; + struct scsi_device *dv_scsi_dev; + struct Scsi_Host *host; /* pointer to scsi host */ +#define AIC_LINUX_NOIRQ ((uint32_t)~0) + uint32_t irq; /* IRQ for this adapter */ + uint32_t bios_address; + uint32_t mem_busaddr; /* Mem Base Addr */ + bus_addr_t hw_dma_mask; + aic_linux_softc_flags flags; +}; + +/***************************** Timer Facilities *******************************/ +typedef void aic_linux_callback_t (u_long); +void aic_platform_timeout(struct scsi_cmnd *); +void aic_linux_midlayer_timeout(struct scsi_cmnd *); + +#define aic_timer_init init_timer +#define aic_timer_stop del_timer_sync +static __inline void aic_timer_reset(aic_timer_t *timer, uint32_t usec, + aic_callback_t *func, void *arg); +static __inline uint32_t aic_get_timeout(struct scb *); +static __inline void aic_scb_timer_start(struct scb *scb); +static __inline void aic_scb_timer_reset(struct scb *scb, uint32_t usec); +static __inline void +aic_timer_reset(aic_timer_t *timer, uint32_t usec, + aic_callback_t *func, void *arg) +{ + struct aic_softc *aic; + + aic = (struct aic_softc *)arg; + del_timer(timer); + timer->data = (u_long)arg; + timer->expires = jiffies + (usec / AIC_USECS_PER_JIFFY); + timer->function = (aic_linux_callback_t*)func; + add_timer(timer); +} + +static __inline uint32_t +aic_get_timeout(struct scb *scb) +{ + + /* + * Convert from jiffies to usec. + */ + return (scb->io_ctx->timeout_per_command * AIC_USECS_PER_JIFFY); +} + +static __inline void +aic_scb_timer_start(struct scb *scb) +{ + scb->platform_data->flags |= AIC_TIMEOUT_ACTIVE; + scsi_add_timer(scb->io_ctx, scb->io_ctx->timeout_per_command, + aic_platform_timeout); +} + +static __inline void +aic_scb_timer_reset(struct scb *scb, uint32_t usec) +{ + /* + * Restore timer data that is clobbered by scsi_delete_timer(). + */ + scb->io_ctx->eh_timeout.data = (unsigned long)scb->io_ctx; + scb->io_ctx->eh_timeout.function = + (void (*)(unsigned long))aic_platform_timeout; + scb->platform_data->flags |= AIC_TIMEOUT_ACTIVE; + mod_timer(&scb->io_ctx->eh_timeout, + jiffies + (usec / AIC_USECS_PER_JIFFY)); +} + +/************************* SCSI command formats *******************************/ /* * Define dome bits that are in ALL (or a lot of) scsi commands */ @@ -865,6 +1624,368 @@ typedef enum { extern const char *scsi_sense_key_text[]; +/*************************** Domain Validation ********************************/ +#define AIC_DV_CMD(cmd) ((cmd)->scsi_done == aic_linux_dv_complete) +#define AIC_DV_SIMQ_FROZEN(aic) \ + ((((aic)->platform_data->flags & AIC_DV_ACTIVE) != 0) \ + && (aic)->platform_data->qfrozen == 1) + +/*********************** Transaction Access Wrappers **************************/ +static __inline void aic_cmd_set_transaction_status(Scsi_Cmnd *, uint32_t); +static __inline void aic_set_transaction_status(struct scb *, uint32_t); +static __inline void aic_cmd_set_scsi_status(Scsi_Cmnd *, uint32_t); +static __inline void aic_set_scsi_status(struct scb *, uint32_t); +static __inline uint32_t aic_cmd_get_transaction_status(Scsi_Cmnd *cmd); +static __inline uint32_t aic_get_transaction_status(struct scb *); +static __inline uint32_t aic_cmd_get_scsi_status(Scsi_Cmnd *cmd); +static __inline uint32_t aic_get_scsi_status(struct scb *); +static __inline void aic_set_transaction_tag(struct scb *, int, u_int); +static __inline u_long aic_get_transfer_length(struct scb *); +static __inline int aic_get_transfer_dir(struct scb *); +static __inline void aic_set_residual(struct scb *, u_long); +static __inline void aic_set_sense_residual(struct scb *scb, u_long resid); +static __inline u_long aic_get_residual(struct scb *); +static __inline u_long aic_get_sense_residual(struct scb *); +static __inline int aic_perform_autosense(struct scb *); +static __inline uint32_t aic_get_sense_bufsize(struct aic_softc *, + struct scb *); +static __inline void aic_notify_xfer_settings_change(struct aic_softc *, + struct aic_devinfo *); +static __inline void aic_platform_scb_free(struct aic_softc *aic, + struct scb *scb); +static __inline void aic_freeze_scb(struct scb *scb); + +static __inline +void aic_cmd_set_transaction_status(Scsi_Cmnd *cmd, uint32_t status) +{ + cmd->result &= ~(CAM_STATUS_MASK << 16); + cmd->result |= status << 16; +} + +static __inline +void aic_set_transaction_status(struct scb *scb, uint32_t status) +{ + aic_cmd_set_transaction_status(scb->io_ctx,status); +} + +static __inline +void aic_cmd_set_scsi_status(Scsi_Cmnd *cmd, uint32_t status) +{ + cmd->result &= ~0xFFFF; + cmd->result |= status; +} + +static __inline +void aic_set_scsi_status(struct scb *scb, uint32_t status) +{ + aic_cmd_set_scsi_status(scb->io_ctx, status); +} + +static __inline +uint32_t aic_cmd_get_transaction_status(Scsi_Cmnd *cmd) +{ + return ((cmd->result >> 16) & CAM_STATUS_MASK); +} + +static __inline +uint32_t aic_get_transaction_status(struct scb *scb) +{ + return (aic_cmd_get_transaction_status(scb->io_ctx)); +} + +static __inline +uint32_t aic_cmd_get_scsi_status(Scsi_Cmnd *cmd) +{ + return (cmd->result & 0xFFFF); +} + +static __inline +uint32_t aic_get_scsi_status(struct scb *scb) +{ + return (aic_cmd_get_scsi_status(scb->io_ctx)); +} + +static __inline +void aic_set_transaction_tag(struct scb *scb, int enabled, u_int type) +{ + /* + * Nothing to do for linux as the incoming transaction + * has no concept of tag/non tagged, etc. + */ +} + +static __inline +u_long aic_get_transfer_length(struct scb *scb) +{ + return (scb->platform_data->xfer_len); +} + +static __inline +int aic_get_transfer_dir(struct scb *scb) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,40) + return (scb->io_ctx->sc_data_direction); +#else + if (scb->io_ctx->bufflen == 0) + return (CAM_DIR_NONE); + + switch(scb->io_ctx->cmnd[0]) { + case 0x08: /* READ(6) */ + case 0x28: /* READ(10) */ + case 0xA8: /* READ(12) */ + return (CAM_DIR_IN); + case 0x0A: /* WRITE(6) */ + case 0x2A: /* WRITE(10) */ + case 0xAA: /* WRITE(12) */ + return (CAM_DIR_OUT); + default: + return (CAM_DIR_NONE); + } +#endif +} + +static __inline +void aic_set_residual(struct scb *scb, u_long resid) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + scb->io_ctx->resid = resid; +#else + scb->platform_data->resid = resid; +#endif +} + +static __inline +void aic_set_sense_residual(struct scb *scb, u_long resid) +{ + scb->platform_data->sense_resid = resid; +} + +static __inline +u_long aic_get_residual(struct scb *scb) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + return (scb->io_ctx->resid); +#else + return (scb->platform_data->resid); +#endif +} + +static __inline +u_long aic_get_sense_residual(struct scb *scb) +{ + return (scb->platform_data->sense_resid); +} + +static __inline +int aic_perform_autosense(struct scb *scb) +{ + /* + * We always perform autosense in Linux. + * On other platforms this is set on a + * per-transaction basis. + */ + return (1); +} + +static __inline uint32_t +aic_get_sense_bufsize(struct aic_softc *aic, struct scb *scb) +{ + return (sizeof(struct scsi_sense_data)); +} + +static __inline void +aic_notify_xfer_settings_change(struct aic_softc *aic, + struct aic_devinfo *devinfo) +{ + /* Nothing to do here for linux */ +} + +static __inline void +aic_platform_scb_free(struct aic_softc *aic, struct scb *scb) +{ + aic->flags &= ~AIC_RESOURCE_SHORTAGE; +} + +static __inline void +aic_freeze_scb(struct scb *scb) +{ + if ((scb->io_ctx->result & (CAM_DEV_QFRZN << 16)) == 0) { + scb->io_ctx->result |= CAM_DEV_QFRZN << 16; + scb->platform_data->dev->qfrozen++; + } +} + +/******************************* PCI Definitions ******************************/ +/* + * PCIM_xxx: mask to locate subfield in register + * PCIR_xxx: config register offset + * PCIC_xxx: device class + * PCIS_xxx: device subclass + * PCIP_xxx: device programming interface + * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices) + * PCID_xxx: device ID + */ +#define PCIR_DEVVENDOR 0x00 +#define PCIR_VENDOR 0x00 +#define PCIR_DEVICE 0x02 +#define PCIR_COMMAND 0x04 +#define PCIM_CMD_PORTEN 0x0001 +#define PCIM_CMD_MEMEN 0x0002 +#define PCIM_CMD_BUSMASTEREN 0x0004 +#define PCIM_CMD_MWRICEN 0x0010 +#define PCIM_CMD_PERRESPEN 0x0040 +#define PCIM_CMD_SERRESPEN 0x0100 +#define PCIR_STATUS 0x06 +#define PCIR_REVID 0x08 +#define PCIR_PROGIF 0x09 +#define PCIR_SUBCLASS 0x0a +#define PCIR_CLASS 0x0b +#define PCIR_CACHELNSZ 0x0c +#define PCIR_LATTIMER 0x0d +#define PCIR_HEADERTYPE 0x0e +#define PCIM_MFDEV 0x80 +#define PCIR_BIST 0x0f +#define PCIR_CAP_PTR 0x34 + +/* config registers for header type 0 devices */ +#define PCIR_MAPS 0x10 +#define PCIR_BARS PCIR_MAPS +#define PCIR_BAR(x) (PCIR_BARS + (x) * 4) +#define PCIR_SUBVEND_0 0x2c +#define PCIR_SUBDEV_0 0x2e + +typedef enum +{ + AIC_POWER_STATE_D0, + AIC_POWER_STATE_D1, + AIC_POWER_STATE_D2, + AIC_POWER_STATE_D3 +} aic_power_state; + +/****************************** PCI-X definitions *****************************/ +#define PCIXR_COMMAND 0x96 +#define PCIXR_DEVADDR 0x98 +#define PCIXM_DEVADDR_FNUM 0x0003 /* Function Number */ +#define PCIXM_DEVADDR_DNUM 0x00F8 /* Device Number */ +#define PCIXM_DEVADDR_BNUM 0xFF00 /* Bus Number */ +#define PCIXR_STATUS 0x9A +#define PCIXM_STATUS_64BIT 0x0001 /* Active 64bit connection to device. */ +#define PCIXM_STATUS_133CAP 0x0002 /* Device is 133MHz capable */ +#define PCIXM_STATUS_SCDISC 0x0004 /* Split Completion Discarded */ +#define PCIXM_STATUS_UNEXPSC 0x0008 /* Unexpected Split Completion */ +#define PCIXM_STATUS_CMPLEXDEV 0x0010 /* Device Complexity (set == bridge) */ +#define PCIXM_STATUS_MAXMRDBC 0x0060 /* Maximum Burst Read Count */ +#define PCIXM_STATUS_MAXSPLITS 0x0380 /* Maximum Split Transactions */ +#define PCIXM_STATUS_MAXCRDS 0x1C00 /* Maximum Cumulative Read Size */ +#define PCIXM_STATUS_RCVDSCEM 0x2000 /* Received a Split Comp w/Error msg */ + +/**************************** KObject Wrappers ********************************/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#define aic_dev_to_pci_dev(dev) to_pci_dev(dev) +#define aic_dev_to_eisa_dev(dev) to_eisa_dev(dev) +#define aic_pci_dev_to_dev(pci) (&pci->dev) +#define aic_eisa_dev_to_dev(eisa) (&eisa->dev) +#else +#define aic_dev_to_pci_dev(dev) (dev) +#define aic_dev_to_eisa_dev(dev) (NULL) +#define aic_pci_dev_to_dev(pci) (pci) +#define aic_eisa_dev_to_dev(eisa) (NULL) +#endif + +#define aic_pci_dev(aic) aic_dev_to_pci_dev((aic)->dev_softc) +#define aic_eisa_dev(aic) aic_dev_to_eisa_dev((aic)->dev_softc) +/***************************** PCI Routines ***********************************/ +static __inline uint32_t aic_pci_read_config(aic_dev_softc_t dev, + int reg, int width); +static __inline void aic_pci_write_config(aic_dev_softc_t dev, + int reg, uint32_t value, + int width); +static __inline int aic_get_pci_function(aic_dev_softc_t); +static __inline int aic_get_pci_slot(aic_dev_softc_t); +static __inline int aic_get_pci_bus(aic_dev_softc_t); + +static __inline uint32_t +aic_pci_read_config(aic_dev_softc_t dev, int reg, int width) +{ + struct pci_dev *pci; + + pci = aic_dev_to_pci_dev(dev); + switch (width) { + case 1: + { + uint8_t retval; + + pci_read_config_byte(pci, reg, &retval); + return (retval); + } + case 2: + { + uint16_t retval; + pci_read_config_word(pci, reg, &retval); + return (retval); + } + case 4: + { + uint32_t retval; + pci_read_config_dword(pci, reg, &retval); + return (retval); + } + default: + panic("aic_pci_read_config: Read size too big"); + /* NOTREACHED */ + return (0); + } +} + +static __inline void +aic_pci_write_config(aic_dev_softc_t dev, int reg, uint32_t value, int width) +{ + struct pci_dev *pci; + + pci = aic_dev_to_pci_dev(dev); + switch (width) { + case 1: + pci_write_config_byte(pci, reg, value); + break; + case 2: + pci_write_config_word(pci, reg, value); + break; + case 4: + pci_write_config_dword(pci, reg, value); + break; + default: + panic("aic_pci_write_config: Write size too big"); + /* NOTREACHED */ + } +} + +static __inline int +aic_get_pci_function(aic_dev_softc_t dev) +{ + struct pci_dev *pci; + + pci = aic_dev_to_pci_dev(dev); + return (PCI_FUNC(pci->devfn)); +} + +static __inline int +aic_get_pci_slot(aic_dev_softc_t dev) +{ + struct pci_dev *pci; + + pci = aic_dev_to_pci_dev(dev); + return (PCI_SLOT(pci->devfn)); +} + +static __inline int +aic_get_pci_bus(aic_dev_softc_t dev) +{ + struct pci_dev *pci; + + pci = aic_dev_to_pci_dev(dev); + return (pci->bus->number); +} + /************************* Large Disk Handling ********************************/ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) static __inline int aic_sector_div(u_long capacity, int heads, int sectors); @@ -886,34 +2007,31 @@ aic_sector_div(sector_t capacity, int he } #endif -/**************************** Module Library Hack *****************************/ -/* - * What we'd like to do is have a single "scsi library" module that both the - * aic7xxx and aic79xx drivers could load and depend on. A cursory examination - * of implementing module dependencies in Linux (handling the install and - * initrd cases) does not look promissing. For now, we just duplicate this - * code in both drivers using a simple symbol renaming scheme that hides this - * hack from the drivers. - */ -#define AIC_LIB_ENTRY_CONCAT(x, prefix) prefix ## x -#define AIC_LIB_ENTRY_EXPAND(x, prefix) AIC_LIB_ENTRY_CONCAT(x, prefix) -#define AIC_LIB_ENTRY(x) AIC_LIB_ENTRY_EXPAND(x, AIC_LIB_PREFIX) +/************************* Magic SysReq Support *******************************/ +#include -#define aic_sense_desc AIC_LIB_ENTRY(_sense_desc) -#define aic_sense_error_action AIC_LIB_ENTRY(_sense_error_action) -#define aic_error_action AIC_LIB_ENTRY(_error_action) -#define aic_op_desc AIC_LIB_ENTRY(_op_desc) -#define aic_cdb_string AIC_LIB_ENTRY(_cdb_string) -#define aic_print_inquiry AIC_LIB_ENTRY(_print_inquiry) -#define aic_calc_syncsrate AIC_LIB_ENTRY(_calc_syncrate) -#define aic_calc_syncparam AIC_LIB_ENTRY(_calc_syncparam) -#define aic_calc_speed AIC_LIB_ENTRY(_calc_speed) -#define aic_inquiry_match AIC_LIB_ENTRY(_inquiry_match) -#define aic_static_inquiry_match AIC_LIB_ENTRY(_static_inquiry_match) -#define aic_parse_brace_option AIC_LIB_ENTRY(_parse_brace_option) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +typedef void aic_sysrq_handler_t (int, struct pt_regs *, struct kbd_struct *, + struct tty_struct *); +#else +typedef void aic_sysrq_handler_t (int, struct pt_regs *, struct tty_struct *); +#endif -/******************************************************************************/ +#ifdef CONFIG_MAGIC_SYSRQ +#define aic_sysrq_key_op sysrq_key_op +#else +struct aic_sysrq_key_op { + aic_sysrq_handler_t *handler; + char *help_msg; + char *action_msg; +}; +#endif +aic_sysrq_handler_t aic_sysrq_handler; +int aic_install_sysrq(struct aic_sysrq_key_op *); +void aic_remove_sysrq(int key, + struct aic_sysrq_key_op *key_op); +/************************ SCSI Library Functions *****************************/ void aic_sense_desc(int /*sense_key*/, int /*asc*/, int /*ascq*/, struct scsi_inquiry_data*, const char** /*sense_key_desc*/, @@ -1043,4 +2161,115 @@ scsi_4btoul(uint8_t *bytes) return (rv); } +/******************************* PCI Funcitons ********************************/ +void aic_power_state_change(struct aic_softc *aic, aic_power_state new_state); + +/******************************* Queue Handling *******************************/ +void aic_runq_tasklet(unsigned long data); +void aic_unblock_tasklet(unsigned long data); +void aic_linux_run_device_queue(struct aic_softc*, + struct aic_linux_device*); +void aic_bus_settle_complete(u_long data); +void aic_freeze_simq(struct aic_softc *aic); +void aic_release_simq(struct aic_softc *aic); +void aic_release_simq_locked(struct aic_softc *aic); +static __inline void aic_schedule_runq(struct aic_softc *aic); +static __inline void aic_schedule_unblock(struct aic_softc *aic); +static __inline struct aic_linux_device * + aic_linux_next_device_to_run(struct aic_softc *aic); +static __inline void aic_linux_check_device_queue(struct aic_softc *aic, + struct aic_linux_device *dev); +static __inline void aic_linux_run_device_queues(struct aic_softc *aic); + +/* + * Must be called with our lock held. + */ +static __inline void +aic_schedule_runq(struct aic_softc *aic) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + tasklet_schedule(&aic->platform_data->runq_tasklet); +#else + /* + * Tasklets are not available, so run inline. + */ + aic_runq_tasklet((unsigned long)aic); +#endif +} + +static __inline void +aic_schedule_unblock(struct aic_softc *aic) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + tasklet_schedule(&aic->platform_data->unblock_tasklet); +#else +#error "Fix 2.2.X Kernel Support" +#endif +} + +static __inline struct aic_linux_device * +aic_linux_next_device_to_run(struct aic_softc *aic) +{ + + if ((aic->flags & AIC_RESOURCE_SHORTAGE) != 0 + || (aic->platform_data->qfrozen != 0 + && AIC_DV_SIMQ_FROZEN(aic) == 0)) + return (NULL); + return (TAILQ_FIRST(&aic->platform_data->device_runq)); +} + +static __inline void +aic_linux_check_device_queue(struct aic_softc *aic, + struct aic_linux_device *dev) +{ + if ((dev->flags & AIC_DEV_FREEZE_TIL_EMPTY) != 0 + && dev->active == 0) { + dev->flags &= ~AIC_DEV_FREEZE_TIL_EMPTY; + dev->qfrozen--; + } + + if (TAILQ_FIRST(&dev->busyq) == NULL + || dev->openings == 0 || dev->qfrozen != 0) + return; + + aic_linux_run_device_queue(aic, dev); +} + +static __inline void +aic_linux_run_device_queues(struct aic_softc *aic) +{ + struct aic_linux_device *dev; + + while ((dev = aic_linux_next_device_to_run(aic)) != NULL) { + TAILQ_REMOVE(&aic->platform_data->device_runq, dev, links); + dev->flags &= ~AIC_DEV_ON_RUN_LIST; + aic_linux_check_device_queue(aic, dev); + } +} + +/****************************** Tasklet Support *******************************/ +static __inline void aic_setup_tasklets(struct aic_softc *aic); +static __inline void aic_teardown_tasklets(struct aic_softc *aic); + +static __inline void +aic_setup_tasklets(struct aic_softc *aic) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + tasklet_init(&aic->platform_data->runq_tasklet, aic_runq_tasklet, + (unsigned long)aic); + tasklet_init(&aic->platform_data->unblock_tasklet, aic_unblock_tasklet, + (unsigned long)aic); +#endif +} + +static __inline void +aic_teardown_tasklets(struct aic_softc *aic) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + tasklet_kill(&aic->platform_data->runq_tasklet); + tasklet_kill(&aic->platform_data->unblock_tasklet); +#endif +} + + #endif /*_AICLIB_H */ diff -puN /dev/null drivers/scsi/aic7xxx/aiclib_pci.c --- /dev/null Thu Apr 11 07:25:15 2002 +++ 25-akpm/drivers/scsi/aic7xxx/aiclib_pci.c Wed Dec 24 12:15:38 2003 @@ -0,0 +1,79 @@ +/* + * Implementation of Utility functions for PCI controller types. + * + * Copyright (c) 2000-2003 Adaptec Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#25 $ + */ + +void +aic_power_state_change(struct aic_softc *aic, aic_power_state new_state) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) + pci_set_power_state(aic_dev_to_pci_dev(aic->dev_softc), new_state); +#else + uint32_t cap; + u_int cap_offset; + + /* + * Traverse the capability list looking for + * the power management capability. + */ + cap = 0; + cap_offset = aic_pci_read_config(aic->dev_softc, + PCIR_CAP_PTR, /*bytes*/1); + while (cap_offset != 0) { + + cap = aic_pci_read_config(aic->dev_softc, + cap_offset, /*bytes*/4); + if ((cap & 0xFF) == 1 + && ((cap >> 16) & 0x3) > 0) { + uint32_t pm_control; + + pm_control = aic_pci_read_config(aic->dev_softc, + cap_offset + 4, + /*bytes*/4); + pm_control &= ~0x3; + pm_control |= new_state; + aic_pci_write_config(aic->dev_softc, + cap_offset + 4, + pm_control, /*bytes*/2); + break; + } + cap_offset = (cap >> 8) & 0xFF; + } +#endif +} diff -puN drivers/scsi/aic7xxx/Kconfig.aic7xxx~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/Kconfig.aic7xxx --- 25/drivers/scsi/aic7xxx/Kconfig.aic7xxx~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/Kconfig.aic7xxx Wed Dec 24 12:15:38 2003 @@ -1,18 +1,16 @@ # # AIC7XXX and AIC79XX 2.5.X Kernel configuration File. -# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic7xxx#6 $ +# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic7xxx#8 $ # config SCSI_AIC7XXX tristate "Adaptec AIC7xxx Fast -> U160 support (New Driver)" + depends on PCI || EISA ---help--- This driver supports all of Adaptec's Fast through Ultra 160 PCI based SCSI controllers as well as the aic7770 based EISA and VLB SCSI controllers (the 274x and 284x series). For AAA and ARO based configurations, only SCSI functionality is provided. - To compile this driver as a module, choose M here: the - module will be called aic7xxx. - config AIC7XXX_CMDS_PER_DEVICE int "Maximum number of TCQ commands per device" depends on SCSI_AIC7XXX @@ -50,7 +48,7 @@ config AIC7XXX_RESET_DELAY_MS config AIC7XXX_PROBE_EISA_VL bool "Probe for EISA and VL AIC7XXX Adapters" - depends on SCSI_AIC7XXX + depends on SCSI_AIC7XXX && EISA help Probe for EISA and VLB Aic7xxx controllers. In many newer systems, the invasive probes necessary to detect these controllers can cause diff -puN drivers/scsi/aic7xxx/Makefile~aic7xxx-aic79xx-update drivers/scsi/aic7xxx/Makefile --- 25/drivers/scsi/aic7xxx/Makefile~aic7xxx-aic79xx-update Wed Dec 24 12:15:38 2003 +++ 25-akpm/drivers/scsi/aic7xxx/Makefile Wed Dec 24 12:15:38 2003 @@ -1,7 +1,7 @@ # # Makefile for the Linux aic7xxx SCSI driver. # -# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Makefile#6 $ +# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Makefile#8 $ # # Let kbuild descend into aicasm when cleaning @@ -12,15 +12,15 @@ obj-$(CONFIG_SCSI_AIC79XX) += aic79xx.o # Core Fast -> U160 files aic7xxx-y += aic7xxx_core.o \ - aic7xxx_93cx6.o \ - aic7770.o + aic7xxx_93cx6.o +aic7xxx-$(CONFIG_EISA) += aic7770.o aic7xxx-$(CONFIG_PCI) += aic7xxx_pci.o aic7xxx-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) += aic7xxx_reg_print.o # Platform Specific Fast -> U160 Files aic7xxx-y += aic7xxx_osm.o \ - aic7xxx_proc.o \ - aic7770_osm.o + aic7xxx_proc.o +aic7xxx-$(CONFIG_EISA) += aic7770_osm.o aic7xxx-$(CONFIG_PCI) += aic7xxx_osm_pci.o # Core U320 files @@ -58,6 +58,13 @@ aicasm-7xxx-opts-$(CONFIG_AIC7XXX_REG_PR -p $(obj)/aic7xxx_reg_print.c -i aic7xxx_osm.h ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y) +# Create a dependency chain in generated files +# to avoid concurrent invocations of the single +# rule that builds them all. +aic7xxx_seq.h: aic7xxx_reg.h +ifeq ($(CONFIG_AIC7XXX_REG_PRETTY_PRINT),y) +aic7xxx_reg.h: aic7xxx_reg_print.c +endif $(aic7xxx-gen-y): $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic7xxx_reg.h \ $(aicasm-7xxx-opts-y) -o $(obj)/aic7xxx_seq.h \ @@ -72,6 +79,13 @@ aicasm-79xx-opts-$(CONFIG_AIC79XX_REG_PR -p $(obj)/aic79xx_reg_print.c -i aic79xx_osm.h ifeq ($(CONFIG_AIC79XX_BUILD_FIRMWARE),y) +# Create a dependency chain in generated files +# to avoid concurrent invocations of the single +# rule that builds them all. +aic79xx_seq.h: aic79xx_reg.h +ifeq ($(CONFIG_AIC79XX_REG_PRETTY_PRINT),y) +aic79xx_reg.h: aic79xx_reg_print.c +endif $(aic79xx-gen-y): $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic79xx_reg.h \ $(aicasm-79xx-opts-y) -o $(obj)/aic79xx_seq.h \ _