diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx index 70b49a9ba691242dff56e675a14ca87d5f7000d3..5bf5b8afc53852a7acde6253eb03049588825a6a 100644 --- a/drivers/scsi/aic7xxx/Kconfig.aic79xx +++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx @@ -1,6 +1,6 @@ # # AIC79XX 2.5.X Kernel configuration File. -# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic79xx#3 $ +# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic79xx#4 $ # config SCSI_AIC79XX tristate "Adaptec AIC79xx U320 support" @@ -59,6 +59,7 @@ config AIC79XX_BUILD_FIRMWARE config AIC79XX_ENABLE_RD_STRM bool "Enable Read Streaming for All Targets" depends on SCSI_AIC79XX + default n help Read Streaming is a U320 protocol option that should enhance performance. Early U320 drive firmware actually performs slower diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx index d30e280d50ceabe2ab93c5076844760877cdc1de..450b0fd1ecfd997c1cccad5f75cbbbd42a7abf60 100644 --- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx +++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx @@ -1,6 +1,6 @@ # # AIC7XXX and AIC79XX 2.5.X Kernel configuration File. -# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic7xxx#5 $ +# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic7xxx#6 $ # config SCSI_AIC7XXX tristate "Adaptec AIC7xxx Fast -> U160 support (New Driver)" diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c index 5229eb2cdafa14ebf5b8a92f666150d955737387..c0df52812a20be9fd0b95808b2e1c198ceaca13c 100644 --- a/drivers/scsi/aic7xxx/aic7770.c +++ b/drivers/scsi/aic7xxx/aic7770.c @@ -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/aic7770.c#27 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#29 $ * * $FreeBSD$ */ @@ -59,6 +59,9 @@ #define ID_OLV_274x 0x04907782 /* Olivetti OEM */ #define ID_OLV_274xD 0x04907783 /* Olivetti OEM (Differential) */ +static int aic7770_chip_init(struct ahc_softc *ahc); +static int aic7770_suspend(struct ahc_softc *ahc); +static int aic7770_resume(struct ahc_softc *ahc); static int aha2840_load_seeprom(struct ahc_softc *ahc); static ahc_device_setup_t ahc_aic7770_VL_setup; static ahc_device_setup_t ahc_aic7770_EISA_setup;; @@ -144,6 +147,12 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io) ahc->description = entry->name; error = ahc_softc_init(ahc); + if (error != 0) + return (error); + + ahc->bus_chip_init = aic7770_chip_init; + ahc->bus_suspend = aic7770_suspend; + ahc->bus_resume = aic7770_resume; error = ahc_reset(ahc); if (error != 0) @@ -226,6 +235,9 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io) ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH); ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF); + ahc->bus_softc.aic7770_softc.busspd = hostconf & DFTHRSH; + ahc->bus_softc.aic7770_softc.bustime = (hostconf << 2) & BOFF; + /* * Generic aic7xxx initialization. */ @@ -253,6 +265,28 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io) return (0); } +static int +aic7770_chip_init(struct ahc_softc *ahc) +{ + ahc_outb(ahc, BUSSPD, ahc->bus_softc.aic7770_softc.busspd); + ahc_outb(ahc, BUSTIME, ahc->bus_softc.aic7770_softc.bustime); + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS); + ahc_outb(ahc, BCTL, ENABLE); + return (ahc_chip_init(ahc)); +} + +static int +aic7770_suspend(struct ahc_softc *ahc) +{ + return (ahc_suspend(ahc)); +} + +static int +aic7770_resume(struct ahc_softc *ahc) +{ + return (ahc_resume(ahc)); +} + /* * Read the 284x SEEPROM. */ @@ -371,5 +405,6 @@ ahc_aic7770_setup(struct ahc_softc *ahc) ahc->features = AHC_AIC7770_FE; ahc->bugs |= AHC_TMODE_WIDEODD_BUG; ahc->flags |= AHC_PAGESCBS; + ahc->instruction_ram_size = 448; return (0); } diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c index 0646072850b9ac4412e79caf0241637e65a24dff..a374f84f22388e6865169826f5051b0c734e0a0a 100644 --- a/drivers/scsi/aic7xxx/aic7770_osm.c +++ b/drivers/scsi/aic7xxx/aic7770_osm.c @@ -36,7 +36,7 @@ * 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#12 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7770_osm.c#13 $ */ #include "aic7xxx_osm.h" @@ -66,7 +66,7 @@ aic7770_linux_probe(Scsi_Host_Template *template) continue; request_region(eisaBase, AHC_EISA_IOSIZE, "aic7xxx"); #else - if (request_region(eisaBase, AHC_EISA_IOSIZE, "aic7xxx") != 0) + if (request_region(eisaBase, AHC_EISA_IOSIZE, "aic7xxx") == 0) continue; #endif diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h index 8197906e03e5c69f0653e328714d7ef9ad631db1..2a906c7d1c6aea0e674410b9ca7b62f22e72c364 100644 --- a/drivers/scsi/aic7xxx/aic79xx.h +++ b/drivers/scsi/aic7xxx/aic79xx.h @@ -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#78 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#88 $ * * $FreeBSD$ */ @@ -258,27 +258,30 @@ typedef enum { AHD_PCIX_CHIPRST_BUG = 0x0040, /* MMAPIO is not functional in PCI-X mode. */ AHD_PCIX_MMAPIO_BUG = 0x0080, + /* Reads to SCBRAM fail to reset the discard timer. */ + AHD_PCIX_SCBRAM_RD_BUG = 0x0100, /* Bug workarounds that can be disabled on non-PCIX busses. */ AHD_PCIX_BUG_MASK = AHD_PCIX_CHIPRST_BUG - | AHD_PCIX_MMAPIO_BUG, + | AHD_PCIX_MMAPIO_BUG + | AHD_PCIX_SCBRAM_RD_BUG, /* * LQOSTOP0 status set even for forced selections with ATN * to perform non-packetized message delivery. */ - AHD_LQO_ATNO_BUG = 0x0100, + AHD_LQO_ATNO_BUG = 0x0200, /* FIFO auto-flush does not always trigger. */ - AHD_AUTOFLUSH_BUG = 0x0200, + AHD_AUTOFLUSH_BUG = 0x0400, /* The CLRLQO registers are not self-clearing. */ - AHD_CLRLQO_AUTOCLR_BUG = 0x0400, + AHD_CLRLQO_AUTOCLR_BUG = 0x0800, /* The PACKETIZED status bit refers to the previous connection. */ - AHD_PKTIZED_STATUS_BUG = 0x0800, + AHD_PKTIZED_STATUS_BUG = 0x1000, /* "Short Luns" are not placed into outgoing LQ packets correctly. */ - AHD_PKT_LUN_BUG = 0x1000, + AHD_PKT_LUN_BUG = 0x2000, /* * Only the FIFO allocated to the non-packetized connection may * be in use during a non-packetzied connection. */ - AHD_NONPACKFIFO_BUG = 0x2000, + AHD_NONPACKFIFO_BUG = 0x4000, /* * Writing to a DFF SCBPTR register may fail if concurent with * a hardware write to the other DFF SCBPTR register. This is @@ -286,30 +289,44 @@ typedef enum { * this bug have the AHD_NONPACKFIFO_BUG and all writes of concern * occur in non-packetized connections. */ - AHD_MDFF_WSCBPTR_BUG = 0x4000, + AHD_MDFF_WSCBPTR_BUG = 0x8000, /* SGHADDR updates are slow. */ - AHD_REG_SLOW_SETTLE_BUG = 0x8000, + AHD_REG_SLOW_SETTLE_BUG = 0x10000, /* * Changing the MODE_PTR coincident with an interrupt that * switches to a different mode will cause the interrupt to * be in the mode written outside of interrupt context. */ - AHD_SET_MODE_BUG = 0x10000, + AHD_SET_MODE_BUG = 0x20000, /* Non-packetized busfree revision does not work. */ - AHD_BUSFREEREV_BUG = 0x20000, + AHD_BUSFREEREV_BUG = 0x40000, /* * Paced transfers are indicated with a non-standard PPR * option bit in the neg table, 160MHz is indicated by * sync factor 0x7, and the offset if off by a factor of 2. */ - AHD_PACED_NEGTABLE_BUG = 0x40000, + AHD_PACED_NEGTABLE_BUG = 0x80000, /* LQOOVERRUN false positives. */ - AHD_LQOOVERRUN_BUG = 0x80000, + AHD_LQOOVERRUN_BUG = 0x100000, /* * Controller write to INTSTAT will lose to a host * write to CLRINT. */ - AHD_INTCOLLISION_BUG = 0x100000 + AHD_INTCOLLISION_BUG = 0x200000, + /* + * The GEM318 violates the SCSI spec by not waiting + * the mandated bus settle delay between phase changes + * in some situations. Some aic79xx chip revs. are more + * strict in this regard and will treat REQ assertions + * that fall within the bus settle delay window as + * glitches. This flag tells the firmware to tolerate + * early REQ assertions. + */ + AHD_EARLY_REQ_BUG = 0x400000, + /* + * The LED does not stay on long enough in packetized modes. + */ + AHD_FAINT_LED_BUG = 0x800000 } ahd_bug; /* @@ -319,10 +336,7 @@ typedef enum { */ typedef enum { AHD_FNONE = 0x00000, - AHD_PRIMARY_CHANNEL = 0x00003,/* - * The channel that should - * be probed first. - */ + AHD_BOOT_CHANNEL = 0x00001,/* We were set as the boot channel. */ AHD_USEDEFAULTS = 0x00004,/* * For cards without an seeprom * or a BIOS to initialize the chip's @@ -411,7 +425,10 @@ typedef uint32_t sense_addr_t; #define MAX_CDB_LEN 16 #define MAX_CDB_LEN_WITH_SENSE_ADDR (MAX_CDB_LEN - sizeof(sense_addr_t)) union initiator_data { - uint64_t cdbptr; + struct { + uint64_t cdbptr; + uint8_t cdblen; + } cdb_from_host; uint8_t cdb[MAX_CDB_LEN]; struct { uint8_t cdb[MAX_CDB_LEN_WITH_SENSE_ADDR]; @@ -727,7 +744,7 @@ struct ahd_tmode_lstate; #define AHD_WIDTH_UNKNOWN 0xFF #define AHD_PERIOD_UNKNOWN 0xFF -#define AHD_OFFSET_UNKNOWN 0x0 +#define AHD_OFFSET_UNKNOWN 0xFF #define AHD_PPR_OPTS_UNKNOWN 0xFF /* @@ -884,6 +901,40 @@ struct seeprom_config { uint16_t checksum; /* word 31 */ }; +/* + * Vital Product Data used during POST and by the BIOS. + */ +struct vpd_config { + uint8_t bios_flags; +#define VPDMASTERBIOS 0x0001 +#define VPDBOOTHOST 0x0002 + uint8_t reserved_1[21]; + uint8_t resource_type; + uint8_t resource_len[2]; + uint8_t resource_data[8]; + uint8_t vpd_tag; + uint16_t vpd_len; + uint8_t vpd_keyword[2]; + uint8_t length; + uint8_t revision; + uint8_t device_flags; + uint8_t termnation_menus[2]; + uint8_t fifo_threshold; + uint8_t end_tag; + uint8_t vpd_checksum; + uint16_t default_target_flags; + uint16_t default_bios_flags; + uint16_t default_ctrl_flags; + uint8_t default_irq; + uint8_t pci_lattime; + uint8_t max_target; + uint8_t boot_lun; + uint16_t signature; + uint8_t reserved_2; + uint8_t checksum; + uint8_t reserved_3[4]; +}; + /****************************** Flexport Logic ********************************/ #define FLXADDR_TERMCTL 0x0 #define FLX_TERMCTL_ENSECHIGH 0x8 @@ -916,11 +967,12 @@ struct seeprom_config { #define FLX_CSTAT_INVALID 0x3 int ahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf, - u_int start_addr, u_int count); + u_int start_addr, u_int count, int bstream); int ahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf, u_int start_addr, u_int count); int ahd_wait_seeprom(struct ahd_softc *ahd); +int ahd_verify_vpd_cksum(struct vpd_config *vpd); int ahd_verify_cksum(struct seeprom_config *sc); int ahd_acquire_seeprom(struct ahd_softc *ahd); void ahd_release_seeprom(struct ahd_softc *ahd); @@ -1305,6 +1357,8 @@ int ahd_softc_init(struct ahd_softc *); void ahd_controller_info(struct ahd_softc *ahd, char *buf); int ahd_init(struct ahd_softc *ahd); int ahd_default_config(struct ahd_softc *ahd); +int ahd_parse_vpddata(struct ahd_softc *ahd, + struct vpd_config *vpd); int ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc); void ahd_intr_enable(struct ahd_softc *ahd, int enable); diff --git a/drivers/scsi/aic7xxx/aic79xx.reg b/drivers/scsi/aic7xxx/aic79xx.reg index 2d22db151c8d824da5fb944c44370b2daab02101..4b921d2c5fb16934bed7ec556337bdfbaa684054 100644 --- a/drivers/scsi/aic7xxx/aic79xx.reg +++ b/drivers/scsi/aic7xxx/aic79xx.reg @@ -39,7 +39,7 @@ * * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#60 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#65 $" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -2071,14 +2071,14 @@ register LQIMODE1 { address 0x051 access_mode RW modes M_CFG - field ENLQIPHASE_LQ 0x80 - field ENLQIPHASE_NLQ 0x40 + field ENLQIPHASE_LQ 0x80 /* LQIPHASE1 */ + field ENLQIPHASE_NLQ 0x40 /* LQIPHASE2 */ field ENLIQABORT 0x20 - field ENLQICRCI_LQ 0x10 - field ENLQICRCI_NLQ 0x08 + field ENLQICRCI_LQ 0x10 /* LQICRCI1 */ + field ENLQICRCI_NLQ 0x08 /* LQICRCI2 */ field ENLQIBADLQI 0x04 - field ENLQIOVERI_LQ 0x02 - field ENLQIOVERI_NLQ 0x01 + field ENLQIOVERI_LQ 0x02 /* LQIOVERI1 */ + field ENLQIOVERI_NLQ 0x01 /* LQIOVERI2 */ } /* @@ -2545,10 +2545,10 @@ const AHD_PRECOMP_CUTBACK_37 0x07 const AHD_SLEWRATE_MASK 0x78 const AHD_SLEWRATE_SHIFT 3 /* - * Rev A has only a single bit of slew adjustment. - * Rev B has 4 bits. + * Rev A has only a single bit (high bit of field) of slew adjustment. + * Rev B has 4 bits. The current default happens to be the same for both. */ -const AHD_SLEWRATE_DEF_REVA 0x01 +const AHD_SLEWRATE_DEF_REVA 0x08 const AHD_SLEWRATE_DEF_REVB 0x08 /* Rev A does not have any amplitude setting. */ @@ -3769,16 +3769,17 @@ scb { SCB_RESIDUAL_DATACNT { size 4 alias SCB_CDB_STORE + alias SCB_HOST_CDB_PTR } SCB_RESIDUAL_SGPTR { size 4 - alias SCB_CDB_PTR field SG_ADDR_MASK 0xf8 /* In the last byte */ field SG_OVERRUN_RESID 0x02 /* In the first byte */ field SG_LIST_NULL 0x01 /* In the first byte */ } SCB_SCSI_STATUS { size 1 + alias SCB_HOST_CDB_LEN } SCB_TARGET_PHASES { size 1 diff --git a/drivers/scsi/aic7xxx/aic79xx.seq b/drivers/scsi/aic7xxx/aic79xx.seq index 31cc29d9d4ddb7f58cfa83628bcf4bdb9aacfe52..e25c7c5f49d107fa55ecceaa9d4714e861b96b51 100644 --- a/drivers/scsi/aic7xxx/aic79xx.seq +++ b/drivers/scsi/aic7xxx/aic79xx.seq @@ -40,7 +40,7 @@ * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#78 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#89 $" PATCH_ARG_LIST = "struct ahd_softc *ahd" PREFIX = "ahd_" @@ -89,6 +89,13 @@ END_CRITICAL; idle_loop_check_nonpackreq: test SSTAT2, NONPACKREQ jz . + 2; call unexpected_nonpkt_phase_find_ctxt; + if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) { + and A, FIFO0FREE|FIFO1FREE, DFFSTAT; + cmp A, FIFO0FREE|FIFO1FREE jne . + 3; + and SBLKCTL, ~DIAGLEDEN|DIAGLEDON; + jmp . + 2; + or SBLKCTL, DIAGLEDEN|DIAGLEDON; + } call idle_loop_gsfifo_in_scsi_mode; call idle_loop_service_fifos; call idle_loop_cchan; @@ -122,22 +129,24 @@ gsfifo_complete_normally: /* * Since this status did not consume a FIFO, we have to * be a bit more dilligent in how we check for FIFOs pertaining - * to this transaction. There are three states that a FIFO still + * to this transaction. There are two states that a FIFO still * transferring data may be in. * - * 1) Configured and draining to the host, with a pending CLRCHN. - * 2) Configured and draining to the host, no pending CLRCHN. - * 3) Pending cfg4data, fifo not empty. + * 1) Configured and draining to the host, with a FIFO handler. + * 2) Pending cfg4data, fifo not empty. * - * Cases 1 and 2 can be detected by noticing that a longjmp is - * active for the FIFO and LONGJMP_SCB matches our SCB. In this - * case, we allow the routine servicing the FIFO to complete the SCB. + * Case 1 can be detected by noticing that a longjmp is active for + * the FIFO and LONGJMP_SCB matches our SCB. In this case, we allow + * the routine servicing the FIFO to complete the SCB. * - * Case 3 implies either a pending or yet to occur save data + * Case 2 implies either a pending or yet to occur save data * pointers for this same context in the other FIFO. So, if - * we detect case 2, we will properly defer the post of the SCB + * we detect case 1, we will properly defer the post of the SCB * and achieve the desired result. The pending cfg4data will * notice that status has been received and complete the SCB. + * + * If the data-transfer has been completed, or no data transfer + * was needed for this SCB, it is safe to complete the command. */ test SCB_SGPTR, SG_LIST_NULL jz good_status_check_fifos; /* @@ -519,7 +528,7 @@ BEGIN_CRITICAL; /* * For packetized, the LQO manager clears ENSELO on * the assertion of SELDO. If we are non-packetized, - * LASTSCB and CURRSCB are acuate. + * LASTSCB and CURRSCB are accurate. */ test SCSISEQ0, ENSELO jnz use_lastscb; @@ -706,7 +715,7 @@ SET_DST_MODE M_DFF1; add NONE, -17, SCB_CDB_LEN; jnc p_command_embedded; p_command_from_host: - bmov HADDR[0], SCB_CDB_PTR, 11; + bmov HADDR[0], SCB_HOST_CDB_PTR, 9; mvi SG_CACHE_PRE, LAST_SEG; mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN); jmp p_command_xfer; @@ -1030,14 +1039,6 @@ queue_arg1_scb_completion: SET_MODE(M_SCSI, M_SCSI) bmov SCBPTR, ARG_1, 2; queue_scb_completion: - if ((ahd->bugs & AHD_ABORT_LQI_BUG) == 0) { - /* - * Set MK_MESSAGE to trigger an abort should this SCB - * be referenced by a target even though it is not currently - * active. - */ - or SCB_CONTROL, MK_MESSAGE; - } test SCB_SCSI_STATUS,0xff jnz bad_status; /* * Check for residuals @@ -1163,7 +1164,28 @@ clear_target_state: mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret; phase_lock: - test SCSIPHASE, 0xFF jz .; + if ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0) { + /* + * Don't ignore persistent REQ assertions just because + * they were asserted within the bus settle delay window. + * This allows us to tolerate devices like the GEM318 + * that violate the SCSI spec. We are careful not to + * count REQ while we are waiting for it to fall during + * an async phase due to our asserted ACK. Each + * sequencer instruction takes ~25ns, so the REQ must + * last at least 100ns in order to be counted as a true + * REQ. + */ + test SCSIPHASE, 0xFF jnz phase_locked; + test SCSISIGI, ACKI jnz phase_lock; + test SCSISIGI, REQI jz phase_lock; + test SCSIPHASE, 0xFF jnz phase_locked; + test SCSISIGI, ACKI jnz phase_lock; + test SCSISIGI, REQI jz phase_lock; +phase_locked: + } else { + test SCSIPHASE, 0xFF jz .; + } test SSTAT1, SCSIPERR jnz phase_lock; phase_lock_latch_phase: and LASTPHASE, PHASE_MASK, SCSISIGI ret; @@ -1247,7 +1269,7 @@ service_fifo: nop; } and SGHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; - mvi CCSGCTL, CCSGEN|SG_CACHE_AVAIL|CCSGRESET; + mvi CCSGCTL, CCSGEN|CCSGRESET; or SG_STATE, FETCH_INPROG ret; idle_sgfetch_complete: /* @@ -1261,6 +1283,15 @@ idle_sgfetch_complete: idle_sg_avail: /* Does the hardware have space for another SG entry? */ test DFSTATUS, PRELOAD_AVAIL jz return; + /* + * On the A, preloading a segment before HDMAENACK + * comes true can clobber the shaddow address of the + * first segment in the S/G FIFO. Wait until it is + * safe to proceed. + */ + if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0) { + test DFCNTRL, HDMAENACK jz return; + } if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { bmov HADDR, CCSGRAM, 8; } else { @@ -1290,22 +1321,12 @@ sg_advance: or SINDEX, LAST_SEG; clr SG_STATE; mov SG_CACHE_PRE, SINDEX; - /* - * Load the segment. Or in HDMAEN here too - * just in case HDMAENACK has not come true - * by the time this segment is loaded. If - * HDMAENACK is not true, this or will disable - * HDMAEN mid-transfer. We do not want to simply - * mvi our original settings as SCSIEN automatically - * de-asserts and we don't want to accidentally - * re-enable it. - */ if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) { /* * Use SCSIENWRDIS so that SCSIEN is never * modified by this operation. */ - or DFCNTRL, PRELOADEN|SCSIENWRDIS|HDMAEN; + or DFCNTRL, PRELOADEN|HDMAEN|SCSIENWRDIS; } else { or DFCNTRL, PRELOADEN|HDMAEN; } @@ -1510,12 +1531,6 @@ data_phase_done: * the idle loop and there is no need to perform * any fixups. */ -calc_residual: - test SG_CACHE_SHADOW, LAST_SEG jz residual_before_last_seg; - /* Record if we've consumed all S/G entries */ - test MDFFSTAT, SHVALID jz . + 2; - bmov SCB_RESIDUAL_DATACNT, SHCNT, 3 ret; - or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL ret; residual_before_last_seg: test MDFFSTAT, SHVALID jnz sgptr_fixup; /* @@ -1525,7 +1540,13 @@ residual_before_last_seg: */ call idle_loop_service_fifos; RESTORE_MODE(SAVED_MODE) - jmp calc_residual; + /* FALLTHROUGH */ +calc_residual: + test SG_CACHE_SHADOW, LAST_SEG jz residual_before_last_seg; + /* Record if we've consumed all S/G entries */ + test MDFFSTAT, SHVALID jz . + 2; + bmov SCB_RESIDUAL_DATACNT, SHCNT, 3 ret; + or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL ret; sgptr_fixup: /* @@ -1570,7 +1591,51 @@ export timer_isr: } export seq_isr: - nop; /* Jumps in the first ISR instruction fail on Rev A. */ + if ((ahd->features & AHD_RTI) == 0) { + /* + * On RevA Silicon, if the target returns us to data-out + * after we have already trained for data-out, it is + * possible for us to transition the free running clock to + * data-valid before the required 100ns P1 setup time (8 P1 + * assertions in fast-160 mode). This will only happen if + * this L-Q is a continuation of a data transfer for which + * we have already prefetched data into our FIFO (LQ/Data + * followed by LQ/Data for the same write transaction). + * This can cause some target implementations to miss the + * first few data transfers on the bus. We detect this + * situation by noticing that this is the first data transfer + * after an LQ (LQIWORKONLQ true), that the data transfer is + * a continuation of a transfer already setup in our FIFO + * (SAVEPTRS interrupt), and that the transaction is a write + * (DIRECTION set in DFCNTRL). The delay is performed by + * disabling SCSIEN until we see the first REQ from the + * target. + * + * First instruction in an ISR cannot be a branch on + * Rev A. Snapshot LQISTAT2 so the status is not missed + * and deffer the test by one instruction. + */ + mov REG_ISR, LQISTAT2; + test REG_ISR, LQIWORKONLQ jz data_valid; + test SEQINTSRC, SAVEPTRS jz data_valid; + test LONGJMP_ADDR[1], INVALID_ADDR jz saveptr_active_fifo; + /* + * Switch to the active FIFO. + */ + xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); + test DFCNTRL, DIRECTION jz snapshot_other_fifo; + and DFCNTRL, ~SCSIEN; + test SSTAT1, REQINIT jz .; + or DFCNTRL, SCSIEN; + /* FALLTHROUGH */ +snapshot_other_fifo: + xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); + /* FALLTHROUGH */ +snapshot_saveptr: + mvi DFFSXFRCTL, CLRCHN; + or SEQINTCTL, IRET ret; +data_valid: + } test SEQINTSRC, CFG4DATA jnz cfg4data_intr; test SEQINTSRC, CFG4ISTAT jnz cfg4istat_intr; test SEQINTSRC, SAVEPTRS jnz saveptr_intr; @@ -1583,21 +1648,23 @@ export seq_isr: * active and contains a snapshot of the current poniter information. * This happens between packets in a stream for a single L_Q. Since we * are not performing a pointer save, we can safely clear the channel - * so it can be used for other transactions. + * so it can be used for other transactions. On RTI capable controllers, + * where snapshots can, and are, disabled, the code to handle this type + * of snapshot is not active. * * The second case is a save pointers on an active FIFO which occurs - * if the target changes to a new L_Q or busfrees/QAS' and the transfer + * if the target changes to a new L_Q or busfrees/QASes and the transfer * has a residual. This should occur coincident with a ctxtdone. We * disable the interrupt and allow our active routine to handle the * save. */ saveptr_intr: - test DFCNTRL, HDMAENACK jz snapshot_saveptr; + if ((ahd->features & AHD_RTI) == 0) { + test LONGJMP_ADDR[1], INVALID_ADDR jnz snapshot_saveptr; + } +saveptr_active_fifo: and SEQIMODE, ~ENSAVEPTRS; or SEQINTCTL, IRET ret; -snapshot_saveptr: - mvi DFFSXFRCTL, CLRCHN; - or SEQINTCTL, IRET ret; cfg4data_intr: test SCB_SGPTR[0], SG_LIST_NULL jnz pkt_handle_overrun; @@ -1633,6 +1700,18 @@ cfg4istat_no_taskmgmt_func: call pkt_handle_status; or SEQINTCTL, IRET ret; +cfg4icmd_intr: + /* + * In the case of DMAing a CDB from the host, the normal + * CDB buffer is formatted with an 8 byte address followed + * by a 1 byte count. + */ + bmov HADDR[0], SCB_HOST_CDB_PTR, 9; + mvi SG_CACHE_PRE, LAST_SEG; + mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN); + call pkt_handle_cdb; + or SEQINTCTL, IRET ret; + /* * See if the target has gone on in this context creating an * overrun condition. For the write case, the hardware cannot @@ -1672,7 +1751,7 @@ pkt_service_fifo: pkt_last_seg: call setjmp; test SEQINTSRC, SAVEPTRS jnz pkt_saveptrs; - test SG_CACHE_SHADOW, LAST_SEG_DONE jnz last_pkt_done; + test SG_CACHE_SHADOW, LAST_SEG_DONE jnz last_pkt_xfer_done; test SCSIPHASE, ~DATA_PHASE_MASK jz . + 2; test SCSISIGO, ATNO jnz . + 2; test SSTAT2, NONPACKREQ jz return; @@ -1716,7 +1795,7 @@ pkt_saveptrs_clrchn: mvi DFFSXFRCTL, CLRCHN ret; END_CRITICAL; -last_pkt_done: +last_pkt_xfer_done: BEGIN_CRITICAL; if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { or DFCNTRL, FIFOFLUSH; @@ -1765,13 +1844,15 @@ BEGIN_CRITICAL; mvi DFFSXFRCTL, CLRCHN ret; END_CRITICAL; -check_status_overrun: - test SHCNT[2], 0xFF jz status_IU_done; - SET_SEQINTCODE(STATUS_OVERRUN) - jmp status_IU_done; +/* + * Watch over the status transfer. Our host sense buffer is + * large enough to take the maximum allowed status packet. + * None-the-less, we must still catch and report overruns to + * the host. + */ pkt_handle_status: call setjmp_setscb; - test MDFFSTAT, LASTSDONE jnz check_status_overrun; + test SG_CACHE_SHADOW, LAST_SEG_DONE jz check_status_overrun; test SEQINTSRC, CTXTDONE jz return; status_IU_done: BEGIN_CRITICAL; @@ -1783,6 +1864,21 @@ BEGIN_CRITICAL; or SCB_CONTROL, STATUS_RCVD; jmp last_pkt_complete; END_CRITICAL; +check_status_overrun: + /* + * We've filled the entire sense buffer. + * Wait for either context done or a negative + * shaddow count. If the context completes without + * causing the shaddow count to go negative, then + * this was a successful transfer up to the status + * limit. Otherwise we report the error. + */ + test SHCNT[2], 0xFF jnz report_status_overrun; + test SEQINTSRC, CTXTDONE jz return; + test SHCNT[2], 0xFF jz status_IU_done; +report_status_overrun: + SET_SEQINTCODE(STATUS_OVERRUN) + jmp status_IU_done; SET_SRC_MODE M_DFF0; SET_DST_MODE M_DFF0; @@ -1796,6 +1892,16 @@ check_fifo: stc ret; END_CRITICAL; +/* + * Must wait until CDB xfer is over before issuing the + * clear channel. + */ +pkt_handle_cdb: + call setjmp_setscb; + test SG_CACHE_SHADOW, LAST_SEG_DONE jz return; + or LONGJMP_ADDR[1], INVALID_ADDR; + mvi DFFSXFRCTL, CLRCHN ret; + /* * Nonpackreq is a polled status. It can come true in three situations: * we have received an L_Q, we have sent one or more L_Qs, or there is no @@ -1865,6 +1971,7 @@ pkt_overrun_end: or SCB_RESIDUAL_SGPTR, SG_OVERRUN_RESID; test SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase; test SCB_CONTROL, STATUS_RCVD jnz last_pkt_queue_scb; + or LONGJMP_ADDR[1], INVALID_ADDR; mvi DFFSXFRCTL, CLRCHN ret; if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) { @@ -1885,5 +1992,3 @@ load_overrun_buf: mvi HCNT[1], ((PKT_OVERRUN_BUFSIZE >> 8) & 0xFF); clr HCNT[2] ret; } - -cfg4icmd_intr: diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index eb877417ab725bea301e4d182deb5ffdbd878b94..e9080a5cda038936d1c5da0f7d5f0d39601cb65d 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -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.c#156 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#178 $ * * $FreeBSD$ */ @@ -406,7 +406,7 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd) u_int i; ahd_set_scbptr(ahd, scbid); - next_scbid = ahd_inw(ahd, SCB_NEXT_COMPLETE); + next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { printf("%s: Warning - DMA-up and complete " @@ -415,7 +415,7 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd) } hscb_ptr = (uint8_t *)scb->hscb; for (i = 0; i < sizeof(struct hardware_scb); i++) - *hscb_ptr++ = ahd_inb(ahd, SCB_BASE + i); + *hscb_ptr++ = ahd_inb_scbram(ahd, SCB_BASE + i); ahd_complete_scb(ahd, scb); scbid = next_scbid; @@ -426,7 +426,7 @@ ahd_flush_qoutfifo(struct ahd_softc *ahd) while (!SCBID_IS_NULL(scbid)) { ahd_set_scbptr(ahd, scbid); - next_scbid = ahd_inw(ahd, SCB_NEXT_COMPLETE); + next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { printf("%s: Warning - Complete SCB %d invalid\n", @@ -1249,6 +1249,14 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) ahd_outb(ahd, CLRSINT3, status3); } else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) { ahd_handle_lqiphase_error(ahd, lqistat1); + } else if ((lqistat1 & LQICRCI_NLQ) != 0) { + /* + * This status can be delayed during some + * streaming operations. The SCSIPHASE + * handler has already dealt with this case + * so just clear the error. + */ + ahd_outb(ahd, CLRLQIINT1, CLRLQICRCI_NLQ); } else if ((status & BUSFREE) != 0) { u_int lqostat1; int restart; @@ -1284,9 +1292,9 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) scbid = ahd_get_scbptr(ahd); scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { - printf("%s: Invalid SCB in DFF%d " + printf("%s: Invalid SCB %d in DFF%d " "during unexpected busfree\n", - ahd_name(ahd), mode); + ahd_name(ahd), scbid, mode); packetized = 0; } else packetized = (scb->flags & SCB_PACKETIZED) != 0; @@ -1626,14 +1634,6 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) panic("SCB not valid during LQOBUSFREE"); - /* - * Return the LQO manager to its idle loop. It will - * not do this automatically if the busfree occurs - * after the first REQ of either the LQ or command - * packet or between the LQ and command packet. - */ - ahd_outb(ahd, LQCTL2, ahd_inb(ahd, LQCTL2) | LQOTOIDLE); - /* * Clear the status. */ @@ -1641,8 +1641,17 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) ahd_outb(ahd, CLRLQOINT1, 0); ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); + ahd_flush_device_writes(ahd); ahd_outb(ahd, CLRSINT0, CLRSELDO); + /* + * Return the LQO manager to its idle loop. It will + * not do this automatically if the busfree occurs + * after the first REQ of either the LQ or command + * packet or between the LQ and command packet. + */ + ahd_outb(ahd, LQCTL2, ahd_inb(ahd, LQCTL2) | LQOTOIDLE); + /* * Update the waiting for selection queue so * we restart on the correct SCB. @@ -1653,12 +1662,12 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) ahd_outw(ahd, WAITING_TID_HEAD, scbid); waiting_t = ahd_inw(ahd, WAITING_TID_TAIL); - next = SCB_LIST_NULL; if (waiting_t == waiting_h) { ahd_outw(ahd, WAITING_TID_TAIL, scbid); + next = SCB_LIST_NULL; } else { ahd_set_scbptr(ahd, waiting_h); - next = ahd_inw(ahd, SCB_NEXT2); + next = ahd_inw_scbram(ahd, SCB_NEXT2); } ahd_set_scbptr(ahd, scbid); ahd_outw(ahd, SCB_NEXT2, next); @@ -1704,6 +1713,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) scb = ahd_lookup_scb(ahd, scbid); ahd_print_path(ahd, scb); printf("Unexpected PKT busfree condition\n"); + ahd_dump_card_state(ahd); ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 'A', SCB_GET_LUN(scb), SCB_GET_TAG(scb), ROLE_INITIATOR, CAM_UNEXP_BUSFREE); @@ -1988,7 +1998,8 @@ ahd_handle_proto_violation(struct ahd_softc *ahd) if ((seq_flags & NO_CDB_SENT) != 0) { ahd_print_path(ahd, scb); printf("No or incomplete CDB sent to device.\n"); - } else if ((ahd_inb(ahd, SCB_CONTROL) & STATUS_RCVD) == 0) { + } else if ((ahd_inb_scbram(ahd, SCB_CONTROL) + & STATUS_RCVD) == 0) { /* * The target never bothered to provide status to * us prior to completing the command. Since we don't @@ -2605,8 +2616,12 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, ahd_name(ahd), devinfo->target, period, offset); options = 0; + if ((ppr_options & MSG_EXT_PPR_RD_STRM) != 0) { + printf("(RDSTRM"); + options++; + } if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) { - printf("(DT"); + printf("%s", options ? "|DT" : "(DT"); options++; } if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { @@ -4817,9 +4832,6 @@ ahd_softc_insert(struct ahd_softc *ahd) slave->flags &= ~AHD_BIOS_ENABLED; slave->flags |= master->flags & AHD_BIOS_ENABLED; - slave->flags &= ~AHD_PRIMARY_CHANNEL; - slave->flags |= - master->flags & AHD_PRIMARY_CHANNEL; break; } } @@ -4831,7 +4843,7 @@ ahd_softc_insert(struct ahd_softc *ahd) */ list_ahd = TAILQ_FIRST(&ahd_tailq); while (list_ahd != NULL - && ahd_softc_comp(list_ahd, ahd) <= 0) + && ahd_softc_comp(ahd, list_ahd) <= 0) list_ahd = TAILQ_NEXT(list_ahd, links); if (list_ahd != NULL) TAILQ_INSERT_BEFORE(list_ahd, ahd, links); @@ -4980,6 +4992,8 @@ ahd_reset(struct ahd_softc *ahd) * to disturb the integrity of the bus. */ ahd_pause(ahd); + ahd_update_modes(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); @@ -5028,13 +5042,16 @@ ahd_reset(struct ahd_softc *ahd) ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2); } - /* After a reset, we know the state of the mode register. */ - ahd_known_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - /* Determine chip configuration */ - ahd->features &= ~AHD_WIDE; - if ((ahd_inb(ahd, SBLKCTL) & SELWIDE) != 0) - ahd->features |= AHD_WIDE; + /* + * Mode should be SCSI after a chip reset, but lets + * set it just to be safe. We touch the MODE_PTR + * register directly so as to bypass the lazy update + * code in ahd_set_modes(). + */ + ahd_known_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); + ahd_outb(ahd, MODE_PTR, + ahd_build_mode_state(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI)); /* * Restore SXFRCTL1. @@ -5047,9 +5064,14 @@ ahd_reset(struct ahd_softc *ahd) ahd_outb(ahd, SXFRCTL1, sxfrctl1|STPWEN); ahd_outb(ahd, SXFRCTL1, sxfrctl1); + /* Determine chip configuration */ + ahd->features &= ~AHD_WIDE; + if ((ahd_inb(ahd, SBLKCTL) & SELWIDE) != 0) + ahd->features |= AHD_WIDE; + /* * If a recovery action has forced a chip reset, - * re-initialize the chip to our likeing. + * re-initialize the chip to our liking. */ if (ahd->init_level > 0) ahd_chip_init(ahd); @@ -5158,7 +5180,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*/1, + if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/8, /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, @@ -5793,7 +5815,9 @@ ahd_init(struct ahd_softc *ahd) /* DMA tag for mapping buffers into device visible space. */ if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR, + /*lowaddr*/ahd->flags & AHD_39BIT_ADDRESSING + ? (bus_addr_t)0x7FFFFFFFFFULL + : BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, /*maxsize*/(AHD_NSEG - 1) * PAGE_SIZE, @@ -6050,7 +6074,7 @@ ahd_chip_init(struct ahd_softc *ahd) } else { ahd_outb(ahd, OPTIONMODE, AUTOACKEN|BUSFREEREV|AUTO_MSGOUT_DE); } - ahd_outb(ahd, SCSCHKN, CURRFIFODEF|WIDERESEN); + ahd_outb(ahd, SCSCHKN, CURRFIFODEF|WIDERESEN|SHVALIDSTDIS); if ((ahd->chip & AHD_BUS_MASK) == AHD_PCIX) /* * Do not issue a target abort when a split completion @@ -6341,7 +6365,7 @@ ahd_default_config(struct ahd_softc *ahd) #else tinfo->user.period = AHD_SYNCRATE_160; #endif - tinfo->user.offset= ~0; + tinfo->user.offset = MAX_OFFSET; tinfo->user.ppr_options = MSG_EXT_PPR_RD_STRM | MSG_EXT_PPR_WR_FLOW | MSG_EXT_PPR_HOLD_MCS @@ -6508,6 +6532,22 @@ ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc) return (0); } +/* + * Parse device configuration information. + */ +int +ahd_parse_vpddata(struct ahd_softc *ahd, struct vpd_config *vpd) +{ + int error; + + error = ahd_verify_vpd_cksum(vpd); + if (error == 0) + return (EINVAL); + if ((vpd->bios_flags & VPDBOOTHOST) != 0) + ahd->flags |= AHD_BOOT_CHANNEL; + return (0); +} + void ahd_intr_enable(struct ahd_softc *ahd, int enable) { @@ -6565,13 +6605,13 @@ ahd_enable_coalessing(struct ahd_softc *ahd, int enable) void ahd_pause_and_flushwork(struct ahd_softc *ahd) { - u_int intstat; - u_int maxloops; - int paused; + ahd_mode_state saved_modes; + u_int intstat; + u_int maxloops; + int paused; maxloops = 1000; ahd->flags |= AHD_ALL_INTERRUPTS; - intstat = 0; paused = FALSE; do { struct scb *waiting_scb; @@ -6582,6 +6622,8 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd) ahd_pause(ahd); paused = TRUE; ahd_clear_critical_section(ahd); + saved_modes = ahd_save_modes(ahd); + ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); if ((ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0) ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); @@ -6598,10 +6640,10 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd) ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) | ENSELO); - if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) - break; + intstat = ahd_inb(ahd, INTSTAT); } while (--maxloops - && (((intstat = ahd_inb(ahd, INTSTAT)) & INT_PEND) != 0 + && (intstat != 0xFF || (ahd->features & AHD_REMOVABLE) == 0) + && ((intstat & INT_PEND) != 0 || (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)))); if (maxloops == 0) { printf("Infinite interrupt loop, INTSTAT = %x", @@ -6612,6 +6654,7 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd) ahd_platform_flushwork(ahd); ahd->flags &= ~AHD_ALL_INTERRUPTS; + ahd_restore_modes(ahd, saved_modes); } int @@ -6785,7 +6828,6 @@ ahd_index_busy_tcl(struct ahd_softc *ahd, u_int *saved_scbid, u_int tcl) /* * Return the untagged transaction id for a given target/channel lun. - * Optionally, clear the entry. */ u_int ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl) @@ -7295,7 +7337,6 @@ ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel, { struct scb *scbp; struct scb *scbp_next; - u_int active_scb; u_int i, j; u_int maxtarget; u_int minlun; @@ -7303,11 +7344,10 @@ ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel, int found; ahd_mode_state saved_modes; - /* restore these when we're done */ - active_scb = ahd_get_scbptr(ahd); + /* restore this when we're done */ saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); + found = ahd_search_qinfifo(ahd, target, channel, lun, SCB_LIST_NULL, role, CAM_REQUEUE_REQ, SEARCH_COMPLETE); @@ -7381,7 +7421,6 @@ ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel, found++; } } - ahd_set_scbptr(ahd, active_scb); ahd_restore_modes(ahd, saved_modes); ahd_platform_abort_scbs(ahd, target, channel, lun, tag, role, status); ahd->flags |= AHD_UPDATE_PEND_CMDS; @@ -7670,7 +7709,6 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) { struct hardware_scb *hscb; u_int qfreeze_cnt; - ahd_mode_state saved_modes; /* * The sequencer freezes its select-out queue @@ -7682,7 +7720,6 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) /* Freeze the queue until the client sees the error. */ ahd_pause(ahd); - saved_modes = ahd_save_modes(ahd); ahd_clear_critical_section(ahd); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); ahd_freeze_devq(ahd, scb); @@ -8148,7 +8185,7 @@ ahd_loadseq(struct ahd_softc *ahd) /* Start by aligning to the nearest cacheline. */ sg_prefetch_align = ahd->pci_cachesize; if (sg_prefetch_align == 0) - sg_prefetch_cnt = 8; + sg_prefetch_align = 8; /* Round down to the nearest power of 2. */ while (powerof2(sg_prefetch_align) == 0) sg_prefetch_align--; @@ -8744,11 +8781,12 @@ ahd_dump_scbs(struct ahd_softc *ahd) /* * Read count 16bit words from 16bit word address start_addr from the * SEEPROM attached to the controller, into buf, using the controller's - * SEEPROM reading state machine. + * SEEPROM reading state machine. Optionally treat the data as a byte + * stream in terms of byte order. */ int ahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf, - u_int start_addr, u_int count) + u_int start_addr, u_int count, int bytestream) { u_int cur_addr; u_int end_addr; @@ -8762,13 +8800,26 @@ ahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf, AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); end_addr = start_addr + count; for (cur_addr = start_addr; cur_addr < end_addr; cur_addr++) { + ahd_outb(ahd, SEEADR, cur_addr); ahd_outb(ahd, SEECTL, SEEOP_READ | SEESTART); error = ahd_wait_seeprom(ahd); if (error) break; - *buf++ = ahd_inw(ahd, SEEDAT); + if (bytestream != 0) { + uint8_t *bytestream_ptr; + + bytestream_ptr = (uint8_t *)buf; + *bytestream_ptr++ = ahd_inb(ahd, SEEDAT); + *bytestream_ptr = ahd_inb(ahd, SEEDAT+1); + } else { + /* + * ahd_inw() already handles machine byte order. + */ + *buf = ahd_inw(ahd, SEEDAT); + } + buf++; } return (error); } @@ -8841,6 +8892,38 @@ ahd_wait_seeprom(struct ahd_softc *ahd) return (0); } +/* + * Validate the two checksums in the per_channel + * vital product data struct. + */ +int +ahd_verify_vpd_cksum(struct vpd_config *vpd) +{ + int i; + int maxaddr; + uint32_t checksum; + uint8_t *vpdarray; + + vpdarray = (uint8_t *)vpd; + maxaddr = offsetof(struct vpd_config, vpd_checksum); + checksum = 0; + for (i = offsetof(struct vpd_config, resource_type); i < maxaddr; i++) + checksum = checksum + vpdarray[i]; + if (checksum == 0 + || (-checksum & 0xFF) != vpd->vpd_checksum) + return (0); + + checksum = 0; + maxaddr = offsetof(struct vpd_config, checksum); + for (i = offsetof(struct vpd_config, default_target_flags); + i < maxaddr; i++) + checksum = checksum + vpdarray[i]; + if (checksum == 0 + || (-checksum & 0xFF) != vpd->checksum) + return (0); + return (1); +} + int ahd_verify_cksum(struct seeprom_config *sc) { diff --git a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h index bdca5c17b33fec27f41bf0e56b32715264e0b8d2..78462adc6457c7513c48ab790a65d12bc4216a02 100644 --- a/drivers/scsi/aic7xxx/aic79xx_inline.h +++ b/drivers/scsi/aic7xxx/aic79xx_inline.h @@ -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#41 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#44 $ * * $FreeBSD$ */ @@ -678,7 +678,8 @@ ahd_inb_scbram(struct ahd_softc *ahd, u_int offset) * Razor #528 */ value = ahd_inb(ahd, offset); - ahd_inb(ahd, MODE_PTR); + if ((ahd->flags & AHD_PCIX_SCBRAM_RD_BUG) != 0) + ahd_inb(ahd, MODE_PTR); return (value); } diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index b67dd10f98d2a84fdf56d82d7163c4602a123048..47992fc7b0e0b235b2ed379847a863b34e353211 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1,7 +1,7 @@ /* * Adaptec AIC79xx device driver for Linux. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#115 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#141 $ * * -------------------------------------------------------------------------- * Copyright (c) 1994-2000 Justin T. Gibbs. @@ -460,12 +460,12 @@ MODULE_PARM_DESC(aic79xx, " Set tag depth on Controller 2/Target 2 to 10 tags\n" " Shorten the selection timeout to 128ms\n" "\n" -" options aic79xx='\"verbose.tag_info:{{}.{}.{..10}}.seltime:1\"'\n" +" options aic79xx 'aic79xx=verbose.tag_info:{{}.{}.{..10}}.seltime:1'\n" "\n" " Sample /etc/modules.conf line:\n" " Change Read Streaming for Controller's 2 and 3\n" "\n" -" options aic79xx='\"rd_strm:{..0xFFF0.0xC0F0}\"'"); +" options aic79xx 'aic79xx=rd_strm:{..0xFFF0.0xC0F0}'"); #endif static void ahd_linux_handle_scsi_status(struct ahd_softc *, @@ -482,6 +482,7 @@ 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, @@ -526,6 +527,7 @@ static void ahd_linux_generate_dv_pattern(struct ahd_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*, @@ -539,11 +541,11 @@ 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*); -static void ahd_linux_setup_tag_info(char *p, char *end, char *s); static void ahd_linux_setup_tag_info_global(char *p); -static void ahd_linux_setup_rd_strm_info(char *p, char *end, char *s); -static void ahd_linux_setup_dv(char *p, char *end, char *s); -static void ahd_linux_setup_iocell_info(char *p, char *end, char *s, int index); +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 ahd_linux_halt(struct notifier_block *nb, u_long event, void *buf); @@ -599,6 +601,9 @@ ahd_schedule_completeq(struct ahd_softc *ahd, struct ahd_cmd *acmd) } } +/* + * Must be called with our lock held. + */ static __inline void ahd_schedule_runq(struct ahd_softc *ahd) { @@ -662,8 +667,8 @@ ahd_linux_run_complete_queue(struct ahd_softc *ahd, struct ahd_cmd *acmd) u_long done_flags; int with_errors; - ahd_done_lock(ahd, &done_flags); with_errors = 0; + ahd_done_lock(ahd, &done_flags); while (acmd != NULL) { Scsi_Cmnd *cmd; @@ -994,9 +999,13 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) cmd->device->id, cmd->device->lun, /*alloc*/TRUE); if (dev == NULL) { + ahd_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL); + ahd_linux_queue_cmd_complete(ahd, cmd); + ahd_schedule_completeq(ahd, NULL); ahd_midlayer_entrypoint_unlock(ahd, &flags); - printf("aic79xx_linux_queue: Unable to allocate device!\n"); - return (-ENOMEM); + printf("%s: aic79xx_linux_queue - Unable to allocate device!\n", + ahd_name(ahd)); + return (0); } if (cmd->cmd_len > MAX_CDB_LEN) return (-EINVAL); @@ -1098,7 +1107,7 @@ ahd_linux_select_queue_depth(struct Scsi_Host * host, int scbnum; ahd = *((struct ahd_softc **)host->hostdata); - ahd_midlayer_entrypoint_lock(ahd, &flags); + ahd_lock(ahd, &flags); scbnum = 0; for (device = scsi_devs; device != NULL; device = device->next) { @@ -1133,7 +1142,7 @@ ahd_linux_select_queue_depth(struct Scsi_Host * host, } } } - ahd_midlayer_entrypoint_unlock(ahd, &flags); + ahd_unlock(ahd, &flags); } #endif @@ -1215,6 +1224,7 @@ ahd_linux_abort(Scsi_Cmnd *cmd) u_int saved_scbptr; u_int active_scbptr; u_int last_phase; + u_int cdb_byte; int retval; int paused; int wait; @@ -1227,9 +1237,12 @@ ahd_linux_abort(Scsi_Cmnd *cmd) ahd = *(struct ahd_softc **)cmd->device->host->hostdata; acmd = (struct ahd_cmd *)cmd; - printf("%s:%d:%d:%d: Attempting to abort cmd %p\n", + printf("%s:%d:%d:%d: Attempting to abort cmd %p:", ahd_name(ahd), cmd->device->channel, cmd->device->id, cmd->device->lun, cmd); + for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) + printf(" 0x%x", cmd->cmnd[cdb_byte]); + printf("\n"); /* * In all versions of Linux, we have to work around @@ -1245,9 +1258,6 @@ ahd_linux_abort(Scsi_Cmnd *cmd) * by acquiring either the io_request_lock or our own * lock, this *should* be safe. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_unlock_irq(&io_request_lock); -#endif ahd_midlayer_entrypoint_lock(ahd, &s); /* @@ -1456,14 +1466,10 @@ ahd_linux_abort(Scsi_Cmnd *cmd) struct timer_list timer; int ret; - ahd->platform_data->flags |= AHD_UP_EH_SEMAPHORE; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_unlock(ahd, &s); -#else - spin_unlock_irq(ahd->platform_data->host->host_lock); -#endif + pending_scb->platform_data->flags |= AHD_SCB_UP_EH_SEM; + spin_unlock_irq(&ahd->platform_data->spin_lock); init_timer(&timer); - timer.data = (u_long)ahd; + timer.data = (u_long)pending_scb; timer.expires = jiffies + (5 * HZ); timer.function = ahd_linux_sem_timeout; add_timer(&timer); @@ -1475,27 +1481,17 @@ ahd_linux_abort(Scsi_Cmnd *cmd) printf("Timer Expired\n"); retval = FAILED; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_lock(ahd, &s); -#else - spin_lock_irq(ahd->platform_data->host->host_lock); -#endif + spin_lock_irq(&ahd->platform_data->spin_lock); } acmd = TAILQ_FIRST(&ahd->platform_data->completeq); TAILQ_INIT(&ahd->platform_data->completeq); - ahd_midlayer_entrypoint_unlock(ahd, &s); + ahd_schedule_runq(ahd); if (acmd != NULL) { acmd = ahd_linux_run_complete_queue(ahd, acmd); - if (acmd != NULL) { - ahd_midlayer_entrypoint_lock(ahd, &s); + if (acmd != NULL) ahd_schedule_completeq(ahd, acmd); - ahd_midlayer_entrypoint_unlock(ahd, &s); - } } - ahd_schedule_runq(ahd); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_lock_irq(&io_request_lock); -#endif + ahd_midlayer_entrypoint_unlock(ahd, &s); return (retval); } @@ -1524,9 +1520,6 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd) struct timer_list timer; int retval; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_unlock_irq(&io_request_lock); -#endif ahd = *(struct ahd_softc **)cmd->device->host->hostdata; recovery_cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK); memset(recovery_cmd, 0, sizeof(struct scsi_cmnd)); @@ -1577,14 +1570,10 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd) LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); ahd_queue_scb(ahd, scb); - ahd->platform_data->flags |= AHD_UP_EH_SEMAPHORE; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_unlock(ahd, &s); -#else - spin_unlock_irq(ahd->platform_data->host->host_lock); -#endif + scb->platform_data->flags |= AHD_SCB_UP_EH_SEM; + spin_unlock_irq(&ahd->platform_data->spin_lock); init_timer(&timer); - timer.data = (u_long)ahd; + timer.data = (u_long)scb; timer.expires = jiffies + (5 * HZ); timer.function = ahd_linux_sem_timeout; add_timer(&timer); @@ -1596,26 +1585,16 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd) printf("Timer Expired\n"); retval = FAILED; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_lock(ahd, &s); -#else - spin_lock_irq(ahd->platform_data->host->host_lock); -#endif + spin_lock_irq(&ahd->platform_data->spin_lock); acmd = TAILQ_FIRST(&ahd->platform_data->completeq); TAILQ_INIT(&ahd->platform_data->completeq); - ahd_midlayer_entrypoint_unlock(ahd, &s); + ahd_schedule_runq(ahd); if (acmd != NULL) { acmd = ahd_linux_run_complete_queue(ahd, acmd); - if (acmd != NULL) { - ahd_midlayer_entrypoint_lock(ahd, &s); + if (acmd != NULL) ahd_schedule_completeq(ahd, acmd); - ahd_midlayer_entrypoint_unlock(ahd, &s); - } } - ahd_schedule_runq(ahd); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_lock_irq(&io_request_lock); -#endif + ahd_midlayer_entrypoint_unlock(ahd, &s); printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval); return (retval); } @@ -1631,9 +1610,6 @@ ahd_linux_bus_reset(Scsi_Cmnd *cmd) u_long s; int found; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_unlock_irq(&io_request_lock); -#endif ahd = *(struct ahd_softc **)cmd->device->host->hostdata; #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) @@ -1645,23 +1621,18 @@ ahd_linux_bus_reset(Scsi_Cmnd *cmd) /*initiate reset*/TRUE); acmd = TAILQ_FIRST(&ahd->platform_data->completeq); TAILQ_INIT(&ahd->platform_data->completeq); - ahd_midlayer_entrypoint_unlock(ahd, &s); - if (bootverbose) - printf("%s: SCSI bus reset delivered. " - "%d SCBs aborted.\n", ahd_name(ahd), found); if (acmd != NULL) { acmd = ahd_linux_run_complete_queue(ahd, acmd); - if (acmd != NULL) { - ahd_midlayer_entrypoint_lock(ahd, &s); + if (acmd != NULL) ahd_schedule_completeq(ahd, acmd); - ahd_midlayer_entrypoint_unlock(ahd, &s); - } } + ahd_midlayer_entrypoint_unlock(ahd, &s); + + if (bootverbose) + printf("%s: SCSI bus reset delivered. " + "%d SCBs aborted.\n", ahd_name(ahd), found); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_lock_irq(&io_request_lock); -#endif return (SUCCESS); } @@ -1691,7 +1662,7 @@ Scsi_Host_Template aic79xx_driver_template = { .max_sectors = 8192, #endif #if defined CONFIG_HIGHIO || LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) /* Assume RedHat Distribution with its different HIGHIO conventions. */ .can_dma_32 = 1, .single_sg_okay = 1, @@ -1713,15 +1684,25 @@ Scsi_Host_Template aic79xx_driver_template = { /**************************** 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); @@ -1731,7 +1712,9 @@ ahd_runq_tasklet(unsigned long data) ahd_unlock(ahd, &flags); ahd_lock(ahd, &flags); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) ahd_unlock(ahd, &flags); +#endif } /************************ Shutdown/halt/reboot hook ***************************/ @@ -1890,361 +1873,109 @@ ahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map) } /********************* Platform Dependent Functions ***************************/ +/* + * Compare "left hand" softc with "right hand" softc, returning: + * < 0 - lahd has a lower priority than rahd + * 0 - Softcs are equal + * > 0 - lahd has a higher priority than rahd + */ int ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd) { int value; - char primary_channel; /* * Under Linux, cards are ordered as follows: - * 1) PCI devices with BIOS enabled sorted by bus/slot/func. - * 2) All remaining PCI devices sorted by bus/slot/func. + * 1) PCI devices that are marked as the boot controller. + * 2) PCI devices with BIOS enabled sorted by bus/slot/func. + * 3) All remaining PCI devices sorted by bus/slot/func. */ +#if 0 + value = (lahd->flags & AHD_BOOT_CHANNEL) + - (rahd->flags & AHD_BOOT_CHANNEL); + if (value != 0) + /* Controllers set for boot have a *higher* priority */ + return (value); +#endif + value = (lahd->flags & AHD_BIOS_ENABLED) - (rahd->flags & AHD_BIOS_ENABLED); if (value != 0) /* Controllers with BIOS enabled have a *higher* priority */ - return (-value); + return (value); /* Still equal. Sort by bus/slot/func. */ if (aic79xx_reverse_scan != 0) - value = ahd_get_pci_bus(rahd->dev_softc) - - ahd_get_pci_bus(lahd->dev_softc); - else value = ahd_get_pci_bus(lahd->dev_softc) - ahd_get_pci_bus(rahd->dev_softc); + else + value = ahd_get_pci_bus(rahd->dev_softc) + - ahd_get_pci_bus(lahd->dev_softc); if (value != 0) return (value); if (aic79xx_reverse_scan != 0) - value = ahd_get_pci_slot(rahd->dev_softc) - - ahd_get_pci_slot(lahd->dev_softc); - else value = ahd_get_pci_slot(lahd->dev_softc) - ahd_get_pci_slot(rahd->dev_softc); + else + value = ahd_get_pci_slot(rahd->dev_softc) + - ahd_get_pci_slot(lahd->dev_softc); if (value != 0) return (value); - /* - * On multi-function devices, the user can choose - * to have function 1 probed before function 0. - * Give whichever channel is the primary channel - * the lowest priority. - */ - primary_channel = (lahd->flags & AHD_PRIMARY_CHANNEL) + 'A'; - value = 1; - if (lahd->channel == primary_channel) - value = -1; + value = rahd->channel - lahd->channel; return (value); } static void -ahd_linux_setup_tag_info(char *p, char *end, char *s) +ahd_linux_setup_tag_info(void *arg, int instance, int targ, int32_t value) { - char *base; - char *tok; - char *tok_end; - char *tok_end2; - int i; - int instance; - int targ; - int done; - char tok_list[] = {'.', ',', '{', '}', '\0'}; - - if (*p != ':') - return; - instance = -1; - targ = -1; - done = FALSE; - base = p; - /* Forward us just past the ':' */ - tok = base + 1; - tok_end = strchr(tok, '\0'); - if (tok_end < end) - *tok_end = ','; - while (!done) { - switch (*tok) { - case '{': - if (instance == -1) - instance = 0; - else if (targ == -1) - targ = 0; - tok++; - break; - case '}': - if (targ != -1) - targ = -1; - else if (instance != -1) - instance = -1; - tok++; - break; - case ',': - case '.': - if (instance == -1) - done = TRUE; - else if (targ >= 0) - targ++; - else if (instance >= 0) - instance++; - if ((targ >= AHD_NUM_TARGETS) || - (instance >= NUM_ELEMENTS(aic79xx_tag_info))) - done = TRUE; - tok++; - if (!done) { - base = tok; - } - break; - case '\0': - done = TRUE; - break; - default: - done = TRUE; - tok_end = strchr(tok, '\0'); - for (i = 0; tok_list[i]; i++) { - tok_end2 = strchr(tok, tok_list[i]); - if ((tok_end2) && (tok_end2 < tok_end)) { - tok_end = tok_end2; - done = FALSE; - } - } - if ((instance >= 0) && (targ >= 0) - && (instance < NUM_ELEMENTS(aic79xx_tag_info)) - && (targ < AHD_NUM_TARGETS)) { - aic79xx_tag_info[instance].tag_commands[targ] = - simple_strtoul(tok, NULL, 0) & 0xff; - } - tok = tok_end; - break; - } + if ((instance >= 0) && (targ >= 0) + && (instance < NUM_ELEMENTS(aic79xx_tag_info)) + && (targ < AHD_NUM_TARGETS)) { + aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF; + if (bootverbose) + printf("tag_info[%d:%d] = %d\n", instance, targ, value); } - while ((p != base) && (p != NULL)) - p = strsep(&s, ",."); } static void -ahd_linux_setup_rd_strm_info(char *p, char *end, char *s) +ahd_linux_setup_rd_strm_info(void *arg, int instance, int targ, int32_t value) { - char *base; - char *tok; - char *tok_end; - char *tok_end2; - int i; - int instance; - int done; - char tok_list[] = {'.', ',', '{', '}', '\0'}; - - if (*p != ':') - return; - - instance = -1; - done = FALSE; - base = p; - /* Forward us just past the ':' */ - tok = base + 1; - tok_end = strchr(tok, '\0'); - if (tok_end < end) - *tok_end = ','; - while (!done) { - switch (*tok) { - case '{': - if (instance == -1) - instance = 0; - tok++; - break; - case '}': - if (instance != -1) - instance = -1; - tok++; - break; - case ',': - case '.': - if (instance == -1) - done = TRUE; - else if (instance >= 0) - instance++; - if (instance >= NUM_ELEMENTS(aic79xx_rd_strm_info)) - done = TRUE; - tok++; - if (!done) { - base = tok; - } - break; - case '\0': - done = TRUE; - break; - default: - done = TRUE; - tok_end = strchr(tok, '\0'); - for (i = 0; tok_list[i]; i++) { - tok_end2 = strchr(tok, tok_list[i]); - if ((tok_end2) && (tok_end2 < tok_end)) { - tok_end = tok_end2; - done = FALSE; - } - } - if ((instance >= 0) - && (instance < NUM_ELEMENTS(aic79xx_rd_strm_info))) { - aic79xx_rd_strm_info[instance] = - simple_strtoul(tok, NULL, 0) & 0xffff; - } - tok = tok_end; - break; - } + if ((instance >= 0) + && (instance < NUM_ELEMENTS(aic79xx_rd_strm_info))) { + aic79xx_rd_strm_info[instance] = value * 0xFFFF; + if (bootverbose) + printf("rd_strm[%d] = 0x%x\n", instance, value); } - while ((p != base) && (p != NULL)) - p = strsep(&s, ",."); } static void -ahd_linux_setup_dv(char *p, char *end, char *s) +ahd_linux_setup_dv(void *arg, int instance, int targ, int32_t value) { - char *base; - char *tok; - char *tok_end; - char *tok_end2; - int i; - int instance; - int done; - char tok_list[] = {'.', ',', '{', '}', '\0'}; - - if (*p != ':') - return; - - instance = -1; - done = FALSE; - base = p; - /* Forward us just past the ':' */ - tok = base + 1; - tok_end = strchr(tok, '\0'); - if (tok_end < end) - *tok_end = ','; - while (!done) { - switch (*tok) { - case '{': - if (instance == -1) - instance = 0; - tok++; - break; - case '}': - if (instance != -1) - instance = -1; - tok++; - break; - case ',': - case '.': - if (instance == -1) - done = TRUE; - else if (instance >= 0) - instance++; - if (instance >= NUM_ELEMENTS(aic79xx_dv_settings)) - done = TRUE; - tok++; - if (!done) { - base = tok; - } - break; - case '\0': - done = TRUE; - break; - default: - done = TRUE; - tok_end = strchr(tok, '\0'); - for (i = 0; tok_list[i]; i++) { - tok_end2 = strchr(tok, tok_list[i]); - if ((tok_end2) && (tok_end2 < tok_end)) { - tok_end = tok_end2; - done = FALSE; - } - } - if ((instance >= 0) - && (instance < NUM_ELEMENTS(aic79xx_dv_settings))) { - aic79xx_dv_settings[instance] = - simple_strtol(tok, NULL, 0); - } - tok = tok_end; - break; - } + if ((instance >= 0) + && (instance < NUM_ELEMENTS(aic79xx_dv_settings))) { + aic79xx_dv_settings[instance] = value; + if (bootverbose) + printf("dv[%d] = %d\n", instance, value); } - while ((p != base) && (p != NULL)) - p = strsep(&s, ",."); } static void -ahd_linux_setup_iocell_info(char *p, char *end, char *s, int index) +ahd_linux_setup_iocell_info(void *arg, int instance, int targ, int32_t value) { - char *base; - char *tok; - char *tok_end; - char *tok_end2; - uint8_t *iocell_info; - int i; - int instance; - int done; - char tok_list[] = {'.', ',', '{', '}', '\0'}; - - if (*p != ':') - return; + u_int index; - instance = -1; - done = FALSE; - base = p; - /* Forward us just past the ':' */ - tok = base + 1; - tok_end = strchr(tok, '\0'); - if (tok_end < end) - *tok_end = ','; - while (!done) { - switch (*tok) { - case '{': - if (instance == -1) - instance = 0; - tok++; - break; - case '}': - if (instance != -1) - instance = -1; - tok++; - break; - case ',': - case '.': - if (instance == -1) - done = TRUE; - else if (instance >= 0) - instance++; - if (instance >= NUM_ELEMENTS(aic79xx_iocell_info)) - done = TRUE; - tok++; - if (!done) { - base = tok; - } - break; - case '\0': - done = TRUE; - break; - default: - done = TRUE; - tok_end = strchr(tok, '\0'); - for (i = 0; tok_list[i]; i++) { - tok_end2 = strchr(tok, tok_list[i]); - if ((tok_end2) && (tok_end2 < tok_end)) { - tok_end = tok_end2; - done = FALSE; - } - } - if ((instance >= 0) - && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) { - iocell_info = - (uint8_t*)&aic79xx_iocell_info[instance]; - iocell_info[index] = - simple_strtoul(tok, NULL, 0) & 0xffff; - } - tok = tok_end; - break; - } + index = (u_int)arg; + if ((instance >= 0) + && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) { + uint8_t *iocell_info; + + iocell_info = (uint8_t*)&aic79xx_iocell_info[instance]; + iocell_info[index] = value & 0xFFFF; + if (bootverbose) + printf("iocell[%d:%d] = %d\n", instance, index, value); } - while ((p != base) && (p != NULL)) - p = strsep(&s, ",."); } static void @@ -2300,41 +2031,54 @@ aic79xx_setup(char *s) end = strchr(s, '\0'); + /* + * XXX ia64 gcc isn't smart enough to know that NUM_ELEMENTS + * will never be 0 in this case. + */ + n = 0; + while ((p = strsep(&s, ",.")) != NULL) { if (*p == '\0') continue; for (i = 0; i < NUM_ELEMENTS(options); i++) { - n = strlen(options[i].name); - if (strncmp(options[i].name, p, n) != 0) - continue; + n = strlen(options[i].name); + if (strncmp(options[i].name, p, n) == 0) + break; + } + if (i == NUM_ELEMENTS(options)) + continue; - if (!strncmp(p, "global_tag_depth", n)) { - ahd_linux_setup_tag_info_global(p + n); - } else if (!strncmp(p, "tag_info", n)) { - ahd_linux_setup_tag_info(p + n, end, s); - } else if (strncmp(p, "rd_strm", n) == 0) { - ahd_linux_setup_rd_strm_info(p + n, end, s); - } else if (strncmp(p, "dv", n) == 0) { - ahd_linux_setup_dv(p + n, end, s); - } else if (strncmp(p, "slewrate", n) == 0) { - ahd_linux_setup_iocell_info(p + n, end, s, - AIC79XX_SLEWRATE_INDEX); - } else if (strncmp(p, "precomp", n) == 0) { - ahd_linux_setup_iocell_info(p + n, end, s, - AIC79XX_PRECOMP_INDEX); - } else if (strncmp(p, "amplitude", n) == 0) { - ahd_linux_setup_iocell_info(p + n, end, s, - AIC79XX_AMPLITUDE_INDEX); - } else if (p[n] == ':') { - *(options[i].flag) = - simple_strtoul(p + n + 1, NULL, 0); - } else if (!strncmp(p, "verbose", n)) { - *(options[i].flag) = 1; - } else { - *(options[i].flag) = ~(*(options[i].flag)); - } - break; + if (strncmp(p, "global_tag_depth", n) == 0) { + ahd_linux_setup_tag_info_global(p + n); + } else if (strncmp(p, "tag_info", n) == 0) { + s = aic_parse_brace_option("tag_info", p + n, end, + 2, ahd_linux_setup_tag_info, NULL); + } else if (strncmp(p, "rd_strm", n) == 0) { + printf("Calling brace parse for %s\n", p); + s = aic_parse_brace_option("rd_strm", p + n, end, + 1, ahd_linux_setup_rd_strm_info, NULL); + } else if (strncmp(p, "dv", n) == 0) { + s = aic_parse_brace_option("dv", p + n, end, 1, + ahd_linux_setup_dv, NULL); + } else if (strncmp(p, "slewrate", n) == 0) { + s = aic_parse_brace_option("slewrate", + p + n, end, 1, ahd_linux_setup_iocell_info, + (void *)AIC79XX_SLEWRATE_INDEX); + } else if (strncmp(p, "precomp", n) == 0) { + s = aic_parse_brace_option("precomp", + p + n, end, 1, ahd_linux_setup_iocell_info, + (void *)AIC79XX_PRECOMP_INDEX); + } else if (strncmp(p, "amplitude", n) == 0) { + s = aic_parse_brace_option("amplitude", + p + n, end, 1, ahd_linux_setup_iocell_info, + (void *)AIC79XX_AMPLITUDE_INDEX); + } else if (p[n] == ':') { + *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); + } else if (!strncmp(p, "verbose", n)) { + *(options[i].flag) = 1; + } else { + *(options[i].flag) = ~(*(options[i].flag)); } } return 1; @@ -2364,6 +2108,8 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) ahd_lock(ahd, &s); #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 + host->lock = &ahd->platform_data->spin_lock; #endif ahd->platform_data->host = host; host->can_queue = AHD_MAX_QUEUE; @@ -2383,9 +2129,10 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) } host->unique_id = ahd->unit; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) && \ - LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) + LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) scsi_set_pci_device(host, ahd->dev_softc); #endif + ahd_linux_setup_user_rd_strm_settings(ahd); ahd_linux_initialize_scsi_bus(ahd); ahd_unlock(ahd, &s); ahd->platform_data->dv_pid = kernel_thread(ahd_linux_dv_thread, ahd, 0); @@ -2405,13 +2152,28 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) * negotiation will occur for the first command, and DV * will comence should that first command be successful. */ - for (target = 0; target < host->max_id; target++) + for (target = 0; target < host->max_id; target++) { + + /* + * Skip our own ID. Some Compaq/HP storage devices + * have enclosure management devices that respond to + * single bit selection (i.e. selecting ourselves). + * 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 + * for our ID if asked to do so. + */ + if (target == ahd->our_id) + continue; + ahd_linux_alloc_target(ahd, 0, target); + } ahd_intr_enable(ahd, TRUE); ahd_linux_start_dv(ahd); ahd_unlock(ahd, &s); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_add_host(host, &ahd->dev_softc->dev); #endif return (0); @@ -2539,29 +2301,13 @@ ahd_platform_free(struct ahd_softc *ahd) { struct ahd_linux_target *targ; struct ahd_linux_device *dev; - u_long s; int i, j; if (ahd->platform_data != NULL) { - /* Kill the DV kthread */ - if (ahd->platform_data->dv_pid != 0) { - ahd_lock(ahd, &s); - ahd->platform_data->flags |= AHD_DV_SHUTDOWN; - ahd_unlock(ahd, &s); - up(&ahd->platform_data->dv_sem); - do { -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - printf("%s: Waiting for DV thread to " - "exit\n", ahd_name(ahd)); - } -#endif - } while (waitpid(ahd->platform_data->dv_pid, NULL, - __WCLONE) == -ERESTARTSYS); - } + ahd_linux_kill_dv_thread(ahd); ahd_teardown_runq_tasklet(ahd); if (ahd->platform_data->host != NULL) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_remove_host(ahd->platform_data->host); #endif scsi_unregister(ahd->platform_data->host); @@ -2604,10 +2350,12 @@ ahd_platform_free(struct ahd_softc *ahd) #endif } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) && \ - LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) + LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* * In 2.4 we detach from the scsi midlayer before the PCI - * layer invokes our remove callback. + * layer invokes our remove callback. No per-instance + * detach is provided, so we must reach inside the PCI + * subsystem's internals and detach our driver manually. */ if (ahd->dev_softc != NULL) ahd->dev_softc->driver = NULL; @@ -2659,7 +2407,18 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, if (dev == NULL) return; was_queuing = dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED); - now_queuing = alg != AHD_QUEUE_NONE; + switch (alg) { + default: + case AHD_QUEUE_NONE: + now_queuing = 0; + break; + case AHD_QUEUE_BASIC: + now_queuing = AHD_DEV_Q_BASIC; + break; + case AHD_QUEUE_TAGGED: + now_queuing = AHD_DEV_Q_TAGGED; + break; + } if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) == 0 && (was_queuing != now_queuing) && (dev->active != 0)) { @@ -2795,24 +2554,12 @@ ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd) ahd->platform_data->flags &= ~AHD_RUN_CMPLT_Q_TIMER; acmd = TAILQ_FIRST(&ahd->platform_data->completeq); TAILQ_INIT(&ahd->platform_data->completeq); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_unlock(ahd, &flags); -#endif if (acmd != NULL) { acmd = ahd_linux_run_complete_queue(ahd, acmd); - if (acmd != NULL) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_lock(ahd, &flags); -#endif + if (acmd != NULL) ahd_schedule_completeq(ahd, acmd); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_unlock(ahd, &flags); -#endif - } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ahd_unlock(ahd, &flags); -#endif } static void @@ -2851,16 +2598,21 @@ ahd_linux_dv_thread(void *data) printf("In DV Thread\n"); #endif + /* + * Complete thread creation. + */ + lock_kernel(); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60) /* * Don't care about any signals. */ siginitsetinv(¤t->blocked, 0); - /* - * Complete thread creation. - */ - lock_kernel(); + daemonize(); + sprintf(current->comm, "ahd_dv_%d", ahd->unit); +#else daemonize("ahd_dv_%d", ahd->unit); +#endif unlock_kernel(); while (1) { @@ -2874,7 +2626,7 @@ ahd_linux_dv_thread(void *data) ahd_lock(ahd, &s); if ((ahd->platform_data->flags & AHD_DV_SHUTDOWN) != 0) { ahd_unlock(ahd, &s); - return (0); + break; } ahd_unlock(ahd, &s); @@ -2920,10 +2672,52 @@ ahd_linux_dv_thread(void *data) */ ahd_release_simq(ahd); } - + up(&ahd->platform_data->eh_sem); return (0); } +static void +ahd_linux_kill_dv_thread(struct ahd_softc *ahd) +{ + u_long s; + + ahd_lock(ahd, &s); + if (ahd->platform_data->dv_pid != 0) { + ahd->platform_data->flags |= AHD_DV_SHUTDOWN; + ahd_unlock(ahd, &s); + up(&ahd->platform_data->dv_sem); + + /* + * Use the eh_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->eh_sem); + + /* + * 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 + * module shutdown case to avoid bogus locking + * in the SCSI mid-layer, but we 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->dv_pid = 0; + } else { + ahd_unlock(ahd, &s); + } +} + #define AHD_LINUX_DV_INQ_SHORT_LEN 36 #define AHD_LINUX_DV_INQ_LEN 256 #define AHD_LINUX_DV_TIMEOUT (HZ / 4) @@ -3026,6 +2820,7 @@ ahd_linux_dv_target(struct ahd_softc *ahd, u_int target_offset) } case AHD_DV_STATE_TUR: case AHD_DV_STATE_BUSY: + timeout = 5 * HZ; ahd_linux_dv_tur(ahd, cmd, &devinfo); break; case AHD_DV_STATE_REBD: @@ -3066,14 +2861,19 @@ ahd_linux_dv_target(struct ahd_softc *ahd, u_int target_offset) /* * In 2.5.X, it is assumed that all calls from the * "midlayer" (which we are emulating) will have the - * ahd host lock held. + * ahd host lock held. For other kernels, the + * io_request_lock must be held. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#if AHD_SCSI_HAS_HOST_LOCK != 0 ahd_lock(ahd, &s); +#else + spin_lock_irqsave(&io_request_lock, s); #endif ahd_linux_queue(cmd, ahd_linux_dv_complete); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#if AHD_SCSI_HAS_HOST_LOCK != 0 ahd_unlock(ahd, &s); +#else + spin_unlock_irqrestore(&io_request_lock, s); #endif down_interruptible(&ahd->platform_data->dv_cmd_sem); /* @@ -3961,7 +3761,6 @@ ahd_linux_dv_timeout(struct scsi_cmnd *cmd) { struct ahd_softc *ahd; struct ahd_cmd *acmd; - struct ahd_linux_device *next_dev; struct scb *scb; u_long flags; @@ -4008,36 +3807,17 @@ ahd_linux_dv_timeout(struct scsi_cmnd *cmd) ahd->platform_data->reset_timer.function = (ahd_linux_callback_t *)ahd_release_simq; add_timer(&ahd->platform_data->reset_timer); - /* - * In 2.5.X, the "done lock" is the ahd_lock. - * Instead of dropping and re-acquiring the same - * lock in the 2.5.X case, just hold our ahd_lock - * the whole time. ahd_done_lock() has been - * made a no-op for 2.5.X too. - */ acmd = TAILQ_FIRST(&ahd->platform_data->completeq); TAILQ_INIT(&ahd->platform_data->completeq); - next_dev = ahd_linux_next_device_to_run(ahd); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_unlock(ahd, &flags); -#endif - if (next_dev) + if (ahd_linux_next_device_to_run(ahd) != NULL) ahd_schedule_runq(ahd); if (acmd != NULL) { acmd = ahd_linux_run_complete_queue(ahd, acmd); if (acmd != NULL) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_lock(ahd, &flags); -#endif ahd_schedule_completeq(ahd, acmd); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_unlock(ahd, &flags); -#endif } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ahd_unlock(ahd, &flags); -#endif } static void @@ -4126,17 +3906,17 @@ ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) tags = 0; if ((ahd->user_discenable & devinfo->target_mask) != 0) { - if (warned_user == 0 - && ahd->unit >= NUM_ELEMENTS(aic79xx_tag_info)) { - - printf("aic79xx: WARNING, insufficient " - "tag_info instances for installed " - "controllers. Using defaults\n"); - printf("aic79xx: Please update the " - "aic79xx_tag_info array in the " - "aic79xx.c source file.\n"); + if (ahd->unit >= NUM_ELEMENTS(aic79xx_tag_info)) { + + if (warned_user == 0) { + printf(KERN_WARNING +"aic79xx: WARNING: Insufficient tag_info instances\n" +"aic79xx: for installed controllers. Using defaults\n" +"aic79xx: Please update the aic79xx_tag_info array in\n" +"aic79xx: the aic79xx_osm.c source file.\n"); + warned_user++; + } tags = AHD_MAX_QUEUE; - warned_user++; } else { adapter_tag_info_t *tag_info; @@ -4155,17 +3935,17 @@ ahd_linux_user_dv_setting(struct ahd_softc *ahd) static int warned_user; int dv; - if (warned_user == 0 - && ahd->unit >= NUM_ELEMENTS(aic79xx_dv_settings)) { + if (ahd->unit >= NUM_ELEMENTS(aic79xx_dv_settings)) { - printf("aic79xx: WARNING, insufficient " - "dv settings instances for installed " - "controllers. Using defaults\n"); - printf("aic79xx: Please update the " - "aic79xx_dv_settings array in the " - "aic79xx.c source file.\n"); + if (warned_user == 0) { + printf(KERN_WARNING +"aic79xx: WARNING: Insufficient dv settings instances\n" +"aic79xx: for installed controllers. Using defaults\n" +"aic79xx: Please update the aic79xx_dv_settings array in" +"aic79xx: the aic79xx_osm.c source file.\n"); + warned_user++; + } dv = -1; - warned_user++; } else { dv = aic79xx_dv_settings[ahd->unit]; @@ -4182,6 +3962,48 @@ ahd_linux_user_dv_setting(struct ahd_softc *ahd) return (dv); } +static void +ahd_linux_setup_user_rd_strm_settings(struct ahd_softc *ahd) +{ + static int warned_user; + u_int rd_strm_mask; + u_int target_id; + + /* + * If we have specific read streaming info for this controller, + * apply it. Otherwise use the defaults. + */ + if (ahd->unit >= NUM_ELEMENTS(aic79xx_rd_strm_info)) { + + if (warned_user == 0) { + + printf(KERN_WARNING +"aic79xx: WARNING: Insufficient rd_strm instances\n" +"aic79xx: for installed controllers. Using defaults\n" +"aic79xx: Please update the aic79xx_rd_strm_info array\n" +"aic79xx: in the aic79xx_osm.c source file.\n"); + warned_user++; + } + rd_strm_mask = AIC79XX_CONFIGED_RD_STRM; + } else { + + rd_strm_mask = aic79xx_rd_strm_info[ahd->unit]; + } + for (target_id = 0; target_id < 16; target_id++) { + struct ahd_devinfo devinfo; + struct ahd_initiator_tinfo *tinfo; + struct ahd_tmode_tstate *tstate; + + tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, + target_id, &tstate); + ahd_compile_devinfo(&devinfo, ahd->our_id, target_id, + CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR); + tinfo->user.ppr_options &= ~MSG_EXT_PPR_RD_STRM; + if ((rd_strm_mask & devinfo.target_mask) != 0) + tinfo->user.ppr_options |= MSG_EXT_PPR_RD_STRM; + } +} + /* * Determines the queue depth for a given device. */ @@ -4385,41 +4207,21 @@ ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs) struct ahd_softc *ahd; struct ahd_cmd *acmd; u_long flags; - struct ahd_linux_device *next_dev; ahd = (struct ahd_softc *) dev_id; ahd_lock(ahd, &flags); ahd_intr(ahd); acmd = TAILQ_FIRST(&ahd->platform_data->completeq); TAILQ_INIT(&ahd->platform_data->completeq); - next_dev = ahd_linux_next_device_to_run(ahd); - /* - * In 2.5.X, the "done lock" is the ahd_lock. - * Instead of dropping and re-acquiring the same - * lock in the 2.5.X case, just hold our ahd_lock - * the whole time. ahd_done_lock() has been - * made a no-op for 2.5.X too. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_unlock(ahd, &flags); -#endif - if (next_dev) + if (ahd_linux_next_device_to_run(ahd) != NULL) ahd_schedule_runq(ahd); if (acmd != NULL) { acmd = ahd_linux_run_complete_queue(ahd, acmd); if (acmd != NULL) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_lock(ahd, &flags); -#endif ahd_schedule_completeq(ahd, acmd); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_unlock(ahd, &flags); -#endif } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ahd_unlock(ahd, &flags); -#endif } void @@ -4437,17 +4239,6 @@ static struct ahd_linux_target* ahd_linux_alloc_target(struct ahd_softc *ahd, u_int channel, u_int target) { struct ahd_linux_target *targ; - u_int target_offset; - - target_offset = target; - /* - * Never allow allocation of a target object for - * our own SCSIID. - */ - if (target == ahd->our_id) { - ahd->platform_data->targets[target_offset] = NULL; - return (NULL); - } targ = malloc(sizeof(*targ), M_DEVBUF, M_NOWAIT); if (targ == NULL) @@ -4457,7 +4248,7 @@ ahd_linux_alloc_target(struct ahd_softc *ahd, u_int channel, u_int target) targ->target = target; targ->ahd = ahd; targ->flags = AHD_DV_REQUIRED; - ahd->platform_data->targets[target_offset] = targ; + ahd->platform_data->targets[target] = targ; return (targ); } @@ -4699,6 +4490,14 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) #endif ahd_set_transaction_status(scb, CAM_UNCOR_PARITY); } else if (amount_xferred < scb->io_ctx->underflow) { + u_int i; + + ahd_print_path(ahd, scb); + printf("CDB:"); + for (i = 0; i < scb->io_ctx->cmd_len; i++) + printf(" 0x%x", scb->io_ctx->cmnd[i]); + printf("\n"); + ahd_print_path(ahd, scb); printf("Saw underflow (%ld of %ld bytes). " "Treated as error\n", ahd_get_residual(scb), @@ -4755,8 +4554,8 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) 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 ((ahd->platform_data->flags & AHD_UP_EH_SEMAPHORE) != 0) { - ahd->platform_data->flags &= ~AHD_UP_EH_SEMAPHORE; + if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { + scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; up(&ahd->platform_data->eh_sem); } } @@ -4869,7 +4668,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, */ dev->openings = 0; #ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_QFULL) { + if ((ahd_debug & AHD_SHOW_QFULL) != 0) { ahd_print_path(ahd, scb); printf("Dropping tag count to %d\n", dev->active); @@ -4899,7 +4698,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, } ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); ahd_set_scsi_status(scb, SCSI_STATUS_OK); - ahd_set_tags(ahd, &devinfo, + ahd_platform_set_tags(ahd, &devinfo, (dev->flags & AHD_DEV_Q_BASIC) ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); break; @@ -4909,7 +4708,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, * as if the target returned BUSY SCSI status. */ dev->openings = 1; - ahd_set_tags(ahd, &devinfo, + ahd_platform_set_tags(ahd, &devinfo, (dev->flags & AHD_DEV_Q_BASIC) ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); ahd_set_scsi_status(scb, SCSI_STATUS_BUSY); @@ -5108,7 +4907,6 @@ ahd_linux_filter_inquiry(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) u_int ppr_options; u_int trans_version; u_int prot_version; - static int warned_user; /* * Determine if this lun actually exists. If so, @@ -5147,26 +4945,6 @@ ahd_linux_filter_inquiry(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) trans_version = user->transport_version; prot_version = MIN(user->protocol_version, SID_ANSI_REV(sid)); - /* - * If we have read streaming info for this controller, - * apply it to this target. - */ - if (warned_user == 0 - && ahd->unit >= NUM_ELEMENTS(aic79xx_rd_strm_info)) { - - printf("aic79xx: WARNING, insufficient rd_strm instances " - "for installed controllers. Using defaults\n"); - printf("aic79xx: Please update the aic79xx_rd_strm_info " - "array in the aic79xx_osm.c source file.\n"); - warned_user++; - } else { - uint16_t rd_strm_mask; - - rd_strm_mask = aic79xx_rd_strm_info[ahd->unit]; - if ((rd_strm_mask & devinfo->target_mask) == 0) - ppr_options &= ~MSG_EXT_PPR_RD_STRM; - } - /* * Only attempt SPI3/4 once we've verified that * the device claims to support SPI3/4 features. @@ -5242,6 +5020,7 @@ ahd_release_simq(struct ahd_softc *ahd) 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 @@ -5251,20 +5030,20 @@ ahd_release_simq(struct ahd_softc *ahd) */ if (unblock_reqs) scsi_unblock_requests(ahd->platform_data->host); - - ahd_schedule_runq(ahd); } static void ahd_linux_sem_timeout(u_long arg) { + struct scb *scb; struct ahd_softc *ahd; u_long s; - ahd = (struct ahd_softc *)arg; + scb = (struct scb *)arg; + ahd = scb->ahd_softc; ahd_lock(ahd, &s); - if ((ahd->platform_data->flags & AHD_UP_EH_SEMAPHORE) != 0) { - ahd->platform_data->flags &= ~AHD_UP_EH_SEMAPHORE; + if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { + scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; up(&ahd->platform_data->eh_sem); } ahd_unlock(ahd, &s); @@ -5320,13 +5099,14 @@ ahd_platform_dump_card_state(struct ahd_softc *ahd) } } -static int __init ahd_linux_init(void) +static int __init +ahd_linux_init(void) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) return (ahd_linux_detect(&aic79xx_driver_template) ? 0 : -ENODEV); #else scsi_register_module(MODULE_SCSI_HA, &aic79xx_driver_template); - if (!driver_template.present) { + if (aic79xx_driver_template.present == 0) { scsi_unregister_module(MODULE_SCSI_HA, &aic79xx_driver_template); return (-ENODEV); @@ -5336,12 +5116,35 @@ static int __init ahd_linux_init(void) #endif } -static void __exit ahd_linux_exit(void) +static void __exit +ahd_linux_exit(void) { + struct ahd_softc *ahd; + u_long l; + + /* + * Shutdown DV 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_list_unlock(&l); #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, &aic79xx_driver_template); #endif ahd_linux_pci_exit(); + + unregister_reboot_notifier(&ahd_linux_notifier); } module_init(ahd_linux_init); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index e1267e9bb2973bfe49357bd5c559a74f59af56ec..e2a0eeab5f5c741932fa44025438a805ea955d2e 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -36,7 +36,7 @@ * 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#108 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#121 $ * */ #ifndef _AIC79XX_LINUX_H_ @@ -92,6 +92,7 @@ * Compile in debugging code, but do not enable any printfs. */ #define AHD_DEBUG 1 +#define AHD_DEBUG_OPTS 0 #endif /* No debugging code. */ #endif @@ -286,7 +287,13 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec) #include <linux/smp.h> #endif -#define AIC79XX_DRIVER_VERSION "1.3.0" +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) || defined(SCSI_HAS_HOST_LOCK)) +#define AHD_SCSI_HAS_HOST_LOCK 1 +#else +#define AHD_SCSI_HAS_HOST_LOCK 0 +#endif + +#define AIC79XX_DRIVER_VERSION "1.3.5" /**************************** Front End Queues ********************************/ /* @@ -487,7 +494,7 @@ struct ahd_linux_target { * Per-SCB OSM storage. */ typedef enum { - AHD_UP_EH_SEMAPHORE = 0x1 + AHD_SCB_UP_EH_SEM = 0x1 } ahd_linux_scb_flags; struct scb_platform_data { @@ -733,7 +740,6 @@ ahd_lockinit(struct ahd_softc *ahd) static __inline void ahd_lock(struct ahd_softc *ahd, unsigned long *flags) { - *flags = 0; spin_lock_irqsave(&ahd->platform_data->spin_lock, *flags); } @@ -747,23 +753,24 @@ static __inline void ahd_midlayer_entrypoint_lock(struct ahd_softc *ahd, unsigned long *flags) { /* - * In 2.5.X, the midlayer takes our lock just before - * calling us, so avoid locking again. + * In 2.5.X and some 2.4.X versions, the midlayer takes our + * lock just before calling us, so we avoid locking again. + * For other kernel versions, the io_request_lock is taken + * just before our entry point is called. In this case, we + * trade the io_request_lock for our per-softc lock. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_lock(ahd, flags); +#if AHD_SCSI_HAS_HOST_LOCK == 0 + spin_unlock(&io_request_lock); + spin_lock(&ahd->platform_data->spin_lock); #endif } static __inline void ahd_midlayer_entrypoint_unlock(struct ahd_softc *ahd, unsigned long *flags) { - /* - * In 2.5.X, the midlayer takes our lock just before - * calling us and unlocks when we return, so let it do the unlock. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahd_unlock(ahd, flags); +#if AHD_SCSI_HAS_HOST_LOCK == 0 + spin_unlock(&ahd->platform_data->spin_lock); + spin_lock(&io_request_lock); #endif } @@ -780,17 +787,16 @@ ahd_done_lockinit(struct ahd_softc *ahd) static __inline void ahd_done_lock(struct ahd_softc *ahd, unsigned long *flags) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - *flags = 0; - spin_lock_irqsave(&io_request_lock, *flags); +#if AHD_SCSI_HAS_HOST_LOCK == 0 + spin_lock(&io_request_lock); #endif } static __inline void ahd_done_unlock(struct ahd_softc *ahd, unsigned long *flags) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_unlock_irqrestore(&io_request_lock, *flags); +#if AHD_SCSI_HAS_HOST_LOCK == 0 + spin_unlock(&io_request_lock); #endif } @@ -803,7 +809,6 @@ ahd_list_lockinit() static __inline void ahd_list_lock(unsigned long *flags) { - *flags = 0; spin_lock_irqsave(&ahd_list_spinlock, *flags); } @@ -822,7 +827,6 @@ ahd_lockinit(struct ahd_softc *ahd) static __inline void ahd_lock(struct ahd_softc *ahd, unsigned long *flags) { - *flags = 0; save_flags(*flags); cli(); } @@ -860,7 +864,6 @@ ahd_list_lockinit() static __inline void ahd_list_lock(unsigned long *flags) { - *flags = 0; save_flags(*flags); cli(); } @@ -947,7 +950,7 @@ void ahd_power_state_change(struct ahd_softc *ahd, */ #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92) #if defined(__sparc_v9__) || defined(__powerpc__) -#error "PPC and Sparc platforms are only support under 2.1.92 and above" +#error "PPC and Sparc platforms are only supported under 2.1.92 and above" #endif #include <linux/bios32.h> #endif diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index eb09fd3b13a571eceea38b616605245203018ed5..8ec854777727d5ca521ae4da28daa535aa137f15 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -36,7 +36,7 @@ * 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#20 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#21 $ */ #include "aic79xx_osm.h" diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index f3cfa41557dc4ccb387e16c1cc062fdc95402678..0fd6e0afa61e479313e4102743884cdb000897db 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -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/aic79xx_pci.c#61 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#70 $ * * $FreeBSD$ */ @@ -80,6 +80,7 @@ ahd_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor) #define ID_AIC7902_B 0x801D9005FFFF9005ull #define ID_AIC7902_B_IROC 0x809D9005FFFF9005ull #define ID_AHA_39320 0x8010900500409005ull +#define ID_AHA_39320A 0x8016900500409005ull #define ID_AHA_39320D 0x8011900500419005ull #define ID_AHA_39320D_B 0x801C900500419005ull #define ID_AHA_39320D_HP 0x8011900500AC0E11ull @@ -137,6 +138,12 @@ struct ahd_pci_identity ahd_pci_ident_table [] = "Adaptec 39320 Ultra320 SCSI adapter", ahd_aic7902_setup }, + { + ID_AHA_39320A, + ID_ALL_MASK, + "Adaptec 39320A Ultra320 SCSI adapter", + ahd_aic7902_setup + }, { ID_AHA_39320D, ID_ALL_MASK, @@ -378,12 +385,10 @@ ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry) int ahd_pci_test_register_access(struct ahd_softc *ahd) { - ahd_mode_state saved_modes; uint32_t cmd; int error; uint8_t hcntrl; - saved_modes = ahd_save_modes(ahd); error = EIO; /* @@ -449,7 +454,6 @@ ahd_pci_test_register_access(struct ahd_softc *ahd) ahd_outb(ahd, CLRINT, CLRPCIINT); } - ahd_restore_modes(ahd, saved_modes); ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS); ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2); return (error); @@ -462,6 +466,7 @@ ahd_pci_test_register_access(struct ahd_softc *ahd) static int ahd_check_extport(struct ahd_softc *ahd) { + struct vpd_config vpd; struct seeprom_config *sc; u_int adapter_control; int have_seeprom; @@ -472,6 +477,27 @@ ahd_check_extport(struct ahd_softc *ahd) if (have_seeprom) { u_int start_addr; + /* + * Fetch VPD for this function and parse it. + */ + if (bootverbose) + printf("%s: Reading VPD from SEEPROM...", + ahd_name(ahd)); + + /* Address is always in units of 16bit words */ + start_addr = ((2 * sizeof(*sc)) + + (sizeof(vpd) * (ahd->channel - 'A'))) / 2; + + error = ahd_read_seeprom(ahd, (uint16_t *)&vpd, + start_addr, sizeof(vpd)/2, + /*bytestream*/TRUE); + if (error == 0) + error = ahd_parse_vpddata(ahd, &vpd); + if (bootverbose) + printf("%s: VPD parsing %s\n", + ahd_name(ahd), + error == 0 ? "successful" : "failed"); + if (bootverbose) printf("%s: Reading SEEPROM...", ahd_name(ahd)); @@ -479,7 +505,8 @@ ahd_check_extport(struct ahd_softc *ahd) start_addr = (sizeof(*sc) / 2) * (ahd->channel - 'A'); error = ahd_read_seeprom(ahd, (uint16_t *)sc, - start_addr, sizeof(*sc)/2); + start_addr, sizeof(*sc)/2, + /*bytestream*/FALSE); if (error != 0) { printf("Unable to read SEEPROM\n"); @@ -698,7 +725,7 @@ static const char *split_status_strings[] = "%s: Split completion data bucket in %s\n", "%s: Split completion address error in %s\n", "%s: Split completion byte count error in %s\n", - "%s: Signaled Target-abort to early terminate a split in %s\n", + "%s: Signaled Target-abort to early terminate a split in %s\n" }; static const char *pci_status_strings[] = @@ -799,7 +826,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat) /* Clear latched errors. So our interrupt deasserts. */ ahd_outb(ahd, DCHSPLTSTAT0, split_status[i]); ahd_outb(ahd, DCHSPLTSTAT1, split_status1[i]); - if (i != 0) + if (i > 1) continue; sg_split_status[i] = ahd_inb(ahd, SGSPLTSTAT0); sg_split_status1[i] = ahd_inb(ahd, SGSPLTSTAT1); @@ -821,7 +848,7 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat) split_status_source[i]); } - if (i != 0) + if (i > 1) continue; if ((sg_split_status[i] & (0x1 << bit)) != 0) { @@ -879,11 +906,12 @@ ahd_aic7902_setup(struct ahd_softc *ahd) | AHD_NLQICRC_DELAYED_BUG|AHD_SCSIRST_BUG | AHD_LQO_ATNO_BUG|AHD_AUTOFLUSH_BUG | AHD_CLRLQO_AUTOCLR_BUG|AHD_PCIX_MMAPIO_BUG - | AHD_PCIX_CHIPRST_BUG|AHD_PKTIZED_STATUS_BUG - | AHD_PKT_LUN_BUG|AHD_MDFF_WSCBPTR_BUG - | AHD_REG_SLOW_SETTLE_BUG|AHD_SET_MODE_BUG - | AHD_BUSFREEREV_BUG|AHD_NONPACKFIFO_BUG - | AHD_PACED_NEGTABLE_BUG; + | AHD_PCIX_CHIPRST_BUG|AHD_PCIX_SCBRAM_RD_BUG + | AHD_PKTIZED_STATUS_BUG|AHD_PKT_LUN_BUG + | AHD_MDFF_WSCBPTR_BUG|AHD_REG_SLOW_SETTLE_BUG + | AHD_SET_MODE_BUG|AHD_BUSFREEREV_BUG + | AHD_NONPACKFIFO_BUG|AHD_PACED_NEGTABLE_BUG + | AHD_FAINT_LED_BUG; /* * IO Cell paramter setup. @@ -898,7 +926,7 @@ ahd_aic7902_setup(struct ahd_softc *ahd) 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_INTCOLLISION_BUG|AHD_EARLY_REQ_BUG; /* * IO Cell paramter setup. diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index 85d6ba27b1470bb7e1c041a94a0b95f6728007d8..0c391b793a3829102ca358c28b31fb6166d9f3b6 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -37,7 +37,7 @@ * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr> * sym driver. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_proc.c#11 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_proc.c#14 $ */ #include "aic79xx_osm.h" #include "aic79xx_inline.h" @@ -124,8 +124,12 @@ ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo) printed_options = 0; copy_info(info, " (%d.%03dMHz", freq / 1000, freq % 1000); + if ((tinfo->ppr_options & MSG_EXT_PPR_RD_STRM) != 0) { + copy_info(info, " RDSTRM"); + printed_options++; + } if ((tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0) { - copy_info(info, " DT"); + copy_info(info, "%s", printed_options ? "|DT" : " DT"); printed_options++; } if ((tinfo->ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { @@ -258,7 +262,8 @@ ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length) ahd_write_seeprom(ahd, (u_int16_t *)buffer, start_addr, sizeof(struct seeprom_config)/2); ahd_read_seeprom(ahd, (uint16_t *)ahd->seep_config, - start_addr, sizeof(struct seeprom_config)/2); + start_addr, sizeof(struct seeprom_config)/2, + /*ByteStream*/FALSE); ahd_release_seeprom(ahd); written = length; } @@ -311,6 +316,7 @@ ahd_linux_proc_info(char *buffer, char **start, off_t offset, copy_info(&info, "Adaptec AIC79xx driver version: %s\n", AIC79XX_DRIVER_VERSION); + copy_info(&info, "%s\n", ahd->description); ahd_controller_info(ahd, ahd_info); copy_info(&info, "%s\n\n", ahd_info); diff --git a/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped index 49b45105a4621ec5067c4d880f76eace8091470f..dfac5aa3eb9070a3b01c1ea31a7ef5bb8686bbee 100644 --- a/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped +++ b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#78 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#60 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#89 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#65 $ */ typedef int (ahd_reg_print_t)(u_int, u_int *, u_int); typedef struct ahd_reg_parse_entry { @@ -3638,13 +3638,14 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print; #define SCB_RESIDUAL_DATACNT 0x180 #define SCB_CDB_STORE 0x180 +#define SCB_HOST_CDB_PTR 0x180 #define SCB_RESIDUAL_SGPTR 0x184 -#define SCB_CDB_PTR 0x184 #define SG_ADDR_MASK 0xf8 #define SG_OVERRUN_RESID 0x02 #define SCB_SCSI_STATUS 0x188 +#define SCB_HOST_CDB_LEN 0x188 #define SCB_TARGET_PHASES 0x189 @@ -3719,7 +3720,7 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print; #define AHD_AMPLITUDE_SHIFT 0x00 #define AHD_AMPLITUDE_MASK 0x07 #define AHD_ANNEXCOL_AMPLITUDE 0x06 -#define AHD_SLEWRATE_DEF_REVA 0x01 +#define AHD_SLEWRATE_DEF_REVA 0x08 #define AHD_SLEWRATE_SHIFT 0x03 #define AHD_SLEWRATE_MASK 0x78 #define AHD_PRECOMP_CUTBACK_29 0x06 @@ -3774,5 +3775,5 @@ ahd_reg_print_t ahd_scb_disconnected_lists_print; /* Exported Labels */ -#define LABEL_seq_isr 0x263 -#define LABEL_timer_isr 0x25f +#define LABEL_seq_isr 0x26d +#define LABEL_timer_isr 0x269 diff --git a/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped index e9c944a93bc60f5a92faf2abe3681f263bc4b6d9..79321cb0960cdf998ba61614e9b162b44d6255c0 100644 --- a/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped +++ b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#78 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#60 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#89 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#65 $ */ #include "aic79xx_osm.h" diff --git a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped index 56c21cecb17a5483f9e0c1373eb4004a1e03d2c0..b65c8f7fdc44d24c9444c40b6b38b0ce01d205c1 100644 --- a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped +++ b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped @@ -2,97 +2,102 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#78 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#60 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#89 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#65 $ */ static uint8_t seqprog[] = { 0xff, 0x02, 0x06, 0x78, - 0x00, 0xea, 0x46, 0x59, + 0x00, 0xea, 0x50, 0x59, 0x01, 0xea, 0x04, 0x30, 0xff, 0x04, 0x0c, 0x78, - 0x19, 0xea, 0x46, 0x59, + 0x19, 0xea, 0x50, 0x59, 0x19, 0xea, 0x04, 0x00, - 0x33, 0xea, 0x3a, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x60, 0x3a, 0x1a, 0x68, 0x04, 0x47, 0x1b, 0x68, 0xff, 0x21, 0x1b, 0x70, - 0x40, 0x4b, 0x88, 0x69, - 0x00, 0xe2, 0x4a, 0x59, - 0x40, 0x4b, 0x88, 0x69, - 0x20, 0x4b, 0x78, 0x69, + 0x40, 0x4b, 0x92, 0x69, + 0x00, 0xe2, 0x54, 0x59, + 0x40, 0x4b, 0x92, 0x69, + 0x20, 0x4b, 0x82, 0x69, 0xfc, 0x42, 0x24, 0x78, 0x10, 0x40, 0x24, 0x78, - 0x00, 0xe2, 0xa4, 0x5d, + 0x00, 0xe2, 0xe0, 0x5d, 0x20, 0x4d, 0x28, 0x78, - 0x00, 0xe2, 0xa4, 0x5d, - 0x00, 0xe2, 0x34, 0x58, - 0x00, 0xe2, 0x66, 0x58, - 0x00, 0xe2, 0x76, 0x58, + 0x00, 0xe2, 0xe0, 0x5d, + 0x30, 0x3f, 0xc0, 0x09, + 0x30, 0xe0, 0x30, 0x60, + 0x7f, 0x4a, 0x94, 0x08, + 0x00, 0xe2, 0x32, 0x40, + 0xc0, 0x4a, 0x94, 0x00, + 0x00, 0xe2, 0x3e, 0x58, + 0x00, 0xe2, 0x70, 0x58, + 0x00, 0xe2, 0x80, 0x58, 0x00, 0xe2, 0x06, 0x40, - 0x33, 0xea, 0x3a, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, - 0x01, 0x52, 0x66, 0x7d, + 0x01, 0x52, 0x96, 0x7d, 0x02, 0x58, 0x50, 0x31, 0xff, 0xea, 0x10, 0x0b, - 0xff, 0x93, 0x45, 0x78, - 0x50, 0x4b, 0x40, 0x68, + 0xff, 0x93, 0x4f, 0x78, + 0x50, 0x4b, 0x4a, 0x68, 0xbf, 0x3a, 0x74, 0x08, - 0x14, 0xea, 0x46, 0x59, + 0x14, 0xea, 0x50, 0x59, 0x14, 0xea, 0x04, 0x00, 0x08, 0xa8, 0x51, 0x03, - 0x01, 0xa4, 0x4d, 0x78, - 0x00, 0xe2, 0x44, 0x5b, - 0x00, 0xe2, 0x34, 0x40, + 0x01, 0xa4, 0x57, 0x78, + 0x00, 0xe2, 0x4c, 0x5b, + 0x00, 0xe2, 0x3e, 0x40, 0xff, 0xea, 0xd4, 0x19, 0x02, 0xa8, 0x84, 0x32, - 0x00, 0xea, 0x3a, 0x59, + 0x00, 0xea, 0x44, 0x59, 0x01, 0xea, 0x00, 0x30, - 0x00, 0xe2, 0x98, 0x5d, - 0x00, 0xe2, 0x66, 0x4d, - 0x11, 0xea, 0x3a, 0x59, + 0x00, 0xe2, 0xcc, 0x5d, + 0x00, 0xe2, 0x96, 0x4d, + 0x11, 0xea, 0x44, 0x59, 0x11, 0xea, 0x00, 0x00, - 0x00, 0xe2, 0x98, 0x5d, - 0x00, 0xe2, 0x66, 0x4d, - 0x33, 0xea, 0x3a, 0x59, + 0x00, 0xe2, 0xcc, 0x5d, + 0x00, 0xe2, 0x96, 0x4d, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, - 0x00, 0xe2, 0x3a, 0x43, - 0x00, 0xea, 0x3a, 0x59, + 0x00, 0xe2, 0x44, 0x43, + 0x00, 0xea, 0x44, 0x59, 0x01, 0xea, 0x00, 0x30, - 0x80, 0xf9, 0x6e, 0x68, - 0x00, 0xe2, 0x38, 0x59, - 0x11, 0xea, 0x3a, 0x59, + 0x80, 0xf9, 0x78, 0x68, + 0x00, 0xe2, 0x42, 0x59, + 0x11, 0xea, 0x44, 0x59, 0x11, 0xea, 0x00, 0x00, - 0x80, 0xf9, 0x38, 0x79, + 0x80, 0xf9, 0x42, 0x79, 0xff, 0xea, 0xd4, 0x0d, - 0x22, 0xea, 0x3a, 0x59, + 0x22, 0xea, 0x44, 0x59, 0x22, 0xea, 0x00, 0x00, - 0x10, 0x16, 0x80, 0x78, + 0x10, 0x16, 0x8a, 0x78, 0x01, 0x0b, 0xa2, 0x32, 0x10, 0x16, 0x2c, 0x00, - 0x18, 0xad, 0xee, 0x78, - 0x04, 0xad, 0xbc, 0x68, - 0x80, 0xad, 0x66, 0x7d, - 0x10, 0xad, 0x8a, 0x78, + 0x18, 0xad, 0xf8, 0x78, + 0x04, 0xad, 0xc6, 0x68, + 0x80, 0xad, 0x96, 0x7d, + 0x10, 0xad, 0x94, 0x78, 0xe7, 0xad, 0x5a, 0x0d, 0xe7, 0xad, 0x5a, 0x09, - 0x00, 0xe2, 0x98, 0x58, + 0x00, 0xe2, 0xa2, 0x58, 0xff, 0xea, 0x56, 0x02, 0x04, 0x7c, 0x78, 0x32, - 0x20, 0x16, 0x66, 0x7d, + 0x20, 0x16, 0x96, 0x7d, 0x04, 0x38, 0x79, 0x32, 0x80, 0x37, 0x6f, 0x16, - 0xff, 0x2d, 0xa7, 0x60, - 0xff, 0x29, 0xa7, 0x60, - 0x40, 0x51, 0xb7, 0x78, - 0xff, 0x4f, 0xa7, 0x68, + 0xff, 0x2d, 0xb1, 0x60, + 0xff, 0x29, 0xb1, 0x60, + 0x40, 0x51, 0xc1, 0x78, + 0xff, 0x4f, 0xb1, 0x68, 0xff, 0x4d, 0xc1, 0x19, 0x00, 0x4e, 0xd5, 0x19, - 0x00, 0xe2, 0xb6, 0x50, + 0x00, 0xe2, 0xc0, 0x50, 0x01, 0x4c, 0xc1, 0x31, 0x00, 0x50, 0xd5, 0x19, - 0x00, 0xe2, 0xb6, 0x48, - 0x80, 0x18, 0x66, 0x7d, + 0x00, 0xe2, 0xc0, 0x48, + 0x80, 0x18, 0x96, 0x7d, 0x02, 0x4a, 0x1d, 0x30, 0x10, 0xea, 0x18, 0x00, 0x60, 0x18, 0x30, 0x00, @@ -100,7 +105,7 @@ static uint8_t seqprog[] = { 0x02, 0xea, 0x02, 0x00, 0xff, 0xea, 0xa0, 0x0a, 0x80, 0x18, 0x30, 0x04, - 0x40, 0xad, 0x66, 0x7d, + 0x40, 0xad, 0x96, 0x7d, 0xe7, 0xad, 0x5a, 0x09, 0x02, 0xa8, 0x40, 0x31, 0xff, 0xea, 0xc0, 0x09, @@ -110,25 +115,25 @@ static uint8_t seqprog[] = { 0xff, 0xea, 0x2a, 0x03, 0xff, 0xea, 0x2e, 0x03, 0x01, 0x10, 0xd4, 0x31, - 0x10, 0xa8, 0xe3, 0x68, + 0x10, 0xa8, 0xed, 0x68, 0x3d, 0xa9, 0xc5, 0x29, 0xfe, 0xe2, 0xc4, 0x09, 0x01, 0xea, 0xc6, 0x01, 0x02, 0xe2, 0xc8, 0x31, 0x02, 0xec, 0x50, 0x31, 0x02, 0xa0, 0xda, 0x31, - 0xff, 0xa9, 0xe2, 0x70, + 0xff, 0xa9, 0xec, 0x70, 0x02, 0xa0, 0x28, 0x37, - 0xff, 0x21, 0xeb, 0x70, + 0xff, 0x21, 0xf5, 0x70, 0x02, 0x22, 0x51, 0x31, 0x02, 0xa0, 0x2c, 0x33, 0x02, 0xa0, 0x44, 0x36, 0x02, 0xa0, 0x40, 0x32, 0x02, 0xa0, 0x44, 0x36, - 0x04, 0x47, 0xf3, 0x68, - 0x40, 0x16, 0x1e, 0x69, - 0xff, 0x2d, 0x23, 0x61, - 0xff, 0x29, 0x67, 0x75, + 0x04, 0x47, 0xfd, 0x68, + 0x40, 0x16, 0x28, 0x69, + 0xff, 0x2d, 0x2d, 0x61, + 0xff, 0x29, 0x97, 0x75, 0x01, 0x37, 0xc1, 0x31, 0x02, 0x28, 0x55, 0x32, 0x01, 0xea, 0x5a, 0x01, @@ -140,20 +145,20 @@ static uint8_t seqprog[] = { 0x01, 0x50, 0xa1, 0x1a, 0xff, 0x4e, 0x9d, 0x1a, 0xff, 0x4f, 0x9f, 0x22, - 0xff, 0x8d, 0x17, 0x71, - 0x80, 0xac, 0x16, 0x71, - 0x20, 0x16, 0x16, 0x69, + 0xff, 0x8d, 0x21, 0x71, + 0x80, 0xac, 0x20, 0x71, + 0x20, 0x16, 0x20, 0x69, 0x02, 0x8c, 0x51, 0x31, - 0x00, 0xe2, 0x00, 0x41, + 0x00, 0xe2, 0x0a, 0x41, 0x01, 0xac, 0x08, 0x31, 0x09, 0xea, 0x5a, 0x01, 0x02, 0x8c, 0x51, 0x32, 0xff, 0xea, 0x1a, 0x07, 0x04, 0x24, 0xf9, 0x30, - 0x1d, 0xea, 0x2e, 0x41, + 0x1d, 0xea, 0x38, 0x41, 0x02, 0x2c, 0x51, 0x31, 0x04, 0xac, 0xf9, 0x30, - 0x19, 0xea, 0x2e, 0x59, + 0x19, 0xea, 0x38, 0x59, 0x02, 0x8c, 0x59, 0x32, 0x02, 0x28, 0x19, 0x33, 0x02, 0xa8, 0x50, 0x36, @@ -175,23 +180,23 @@ static uint8_t seqprog[] = { 0x02, 0x20, 0xb9, 0x30, 0x02, 0x20, 0x51, 0x31, 0x4c, 0xa9, 0xd7, 0x28, - 0x10, 0xa8, 0x59, 0x79, + 0x10, 0xa8, 0x63, 0x79, 0x01, 0x6b, 0xc0, 0x30, 0x02, 0x64, 0xc8, 0x00, 0x40, 0x3a, 0x74, 0x04, - 0x00, 0xe2, 0x66, 0x58, - 0x33, 0xea, 0x3a, 0x59, + 0x00, 0xe2, 0x70, 0x58, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x30, 0x3f, 0xc0, 0x09, - 0x30, 0xe0, 0x5a, 0x61, - 0x20, 0x3f, 0x70, 0x69, - 0x10, 0x3f, 0x5a, 0x79, + 0x30, 0xe0, 0x64, 0x61, + 0x20, 0x3f, 0x7a, 0x69, + 0x10, 0x3f, 0x64, 0x79, 0x02, 0xea, 0x7e, 0x00, - 0x00, 0xea, 0x3a, 0x59, + 0x00, 0xea, 0x44, 0x59, 0x01, 0xea, 0x00, 0x30, 0x02, 0x48, 0x51, 0x35, 0x01, 0xea, 0x7e, 0x00, - 0x11, 0xea, 0x3a, 0x59, + 0x11, 0xea, 0x44, 0x59, 0x11, 0xea, 0x00, 0x00, 0x02, 0x48, 0x51, 0x35, 0x08, 0xea, 0x98, 0x00, @@ -201,11 +206,11 @@ static uint8_t seqprog[] = { 0x0f, 0x67, 0xc0, 0x09, 0x00, 0x34, 0x69, 0x02, 0x20, 0xea, 0x96, 0x00, - 0x00, 0xe2, 0xee, 0x41, - 0x40, 0x3a, 0xa4, 0x69, + 0x00, 0xe2, 0xf8, 0x41, + 0x40, 0x3a, 0xae, 0x69, 0x02, 0x55, 0x06, 0x68, - 0x02, 0x56, 0xa4, 0x69, - 0xff, 0x5b, 0xa4, 0x61, + 0x02, 0x56, 0xae, 0x69, + 0xff, 0x5b, 0xae, 0x61, 0x02, 0x20, 0x51, 0x31, 0x80, 0xea, 0xb2, 0x01, 0x44, 0xea, 0x00, 0x00, @@ -213,36 +218,36 @@ static uint8_t seqprog[] = { 0x33, 0xea, 0x00, 0x00, 0xff, 0xea, 0xb2, 0x09, 0xff, 0xe0, 0xc0, 0x19, - 0xff, 0xe0, 0xa6, 0x79, + 0xff, 0xe0, 0xb0, 0x79, 0x02, 0x94, 0x51, 0x31, - 0x00, 0xe2, 0x9c, 0x41, + 0x00, 0xe2, 0xa6, 0x41, 0x02, 0x5e, 0x50, 0x31, 0x02, 0xa8, 0xb8, 0x30, 0x02, 0x5c, 0x50, 0x31, - 0xff, 0x95, 0xb7, 0x71, + 0xff, 0x95, 0xc1, 0x71, 0x02, 0x94, 0x41, 0x31, 0x02, 0x22, 0x51, 0x31, 0x02, 0xa0, 0x2c, 0x33, 0x02, 0xa0, 0x44, 0x32, - 0x00, 0xe2, 0xc0, 0x41, - 0x10, 0xa8, 0xc1, 0x69, + 0x00, 0xe2, 0xca, 0x41, + 0x10, 0xa8, 0xcb, 0x69, 0x3d, 0xa9, 0xc9, 0x29, 0x01, 0xe4, 0xc8, 0x01, 0x01, 0xea, 0xca, 0x01, 0xff, 0xea, 0xda, 0x01, 0x02, 0x20, 0x51, 0x31, 0x02, 0x96, 0x41, 0x32, - 0xff, 0x21, 0xc9, 0x61, + 0xff, 0x21, 0xd3, 0x61, 0xff, 0xea, 0x46, 0x02, 0x02, 0x5c, 0x50, 0x31, 0x40, 0xea, 0x96, 0x00, - 0x02, 0x56, 0xac, 0x6d, - 0x01, 0x55, 0xac, 0x6d, - 0x10, 0xa8, 0xd5, 0x79, - 0x10, 0x40, 0xde, 0x69, - 0x01, 0x56, 0xde, 0x79, + 0x02, 0x56, 0xe8, 0x6d, + 0x01, 0x55, 0xe8, 0x6d, + 0x10, 0xa8, 0xdf, 0x79, + 0x10, 0x40, 0xe8, 0x69, + 0x01, 0x56, 0xe8, 0x79, 0xff, 0x93, 0x07, 0x78, - 0x13, 0xea, 0x46, 0x59, + 0x13, 0xea, 0x50, 0x59, 0x13, 0xea, 0x04, 0x00, 0x00, 0xe2, 0x06, 0x40, 0xbf, 0x3a, 0x74, 0x08, @@ -253,104 +258,104 @@ static uint8_t seqprog[] = { 0x40, 0xea, 0x66, 0x02, 0x08, 0x3c, 0x78, 0x00, 0x80, 0xea, 0x62, 0x02, - 0x00, 0xe2, 0xa4, 0x5b, + 0x00, 0xe2, 0xac, 0x5b, 0x01, 0x36, 0xc1, 0x31, - 0x9f, 0xe0, 0x38, 0x7c, - 0x80, 0xe0, 0x02, 0x72, - 0xa0, 0xe0, 0x3a, 0x72, - 0xc0, 0xe0, 0x30, 0x72, - 0xe0, 0xe0, 0x6a, 0x72, - 0x01, 0xea, 0x46, 0x59, + 0x9f, 0xe0, 0x4e, 0x7c, + 0x80, 0xe0, 0x0c, 0x72, + 0xa0, 0xe0, 0x44, 0x72, + 0xc0, 0xe0, 0x3a, 0x72, + 0xe0, 0xe0, 0x74, 0x72, + 0x01, 0xea, 0x50, 0x59, 0x01, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xee, 0x41, - 0x80, 0x33, 0x09, 0x7a, - 0x03, 0xea, 0x46, 0x59, + 0x00, 0xe2, 0xf8, 0x41, + 0x80, 0x33, 0x13, 0x7a, + 0x03, 0xea, 0x50, 0x59, 0x03, 0xea, 0x04, 0x00, - 0xee, 0x00, 0x10, 0x6a, + 0xee, 0x00, 0x1a, 0x6a, 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x3a, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x02, 0xa8, 0x90, 0x32, - 0x00, 0xe2, 0x60, 0x59, + 0x00, 0xe2, 0x6a, 0x59, 0xef, 0x92, 0xd5, 0x19, - 0x00, 0xe2, 0x20, 0x52, - 0x0b, 0x84, 0xe1, 0x30, + 0x00, 0xe2, 0x2a, 0x52, + 0x09, 0x80, 0xe1, 0x30, 0x02, 0xea, 0x36, 0x00, 0xa8, 0xea, 0x32, 0x00, - 0x00, 0xe2, 0x26, 0x42, + 0x00, 0xe2, 0x30, 0x42, 0x01, 0x92, 0xd1, 0x30, 0x10, 0x80, 0x89, 0x31, 0x20, 0xea, 0x32, 0x00, 0xbf, 0x33, 0x67, 0x0a, - 0x20, 0x19, 0x28, 0x6a, - 0x02, 0x4d, 0xee, 0x69, + 0x20, 0x19, 0x32, 0x6a, + 0x02, 0x4d, 0xf8, 0x69, 0x40, 0x33, 0x67, 0x02, - 0x00, 0xe2, 0xee, 0x41, - 0x80, 0x33, 0xa7, 0x6a, + 0x00, 0xe2, 0xf8, 0x41, + 0x80, 0x33, 0xb1, 0x6a, 0x01, 0x44, 0x10, 0x33, 0x08, 0xa8, 0x51, 0x03, - 0x00, 0xe2, 0xee, 0x41, + 0x00, 0xe2, 0xf8, 0x41, 0x10, 0xea, 0x80, 0x00, 0x01, 0x31, 0xc5, 0x31, - 0x80, 0xe2, 0x56, 0x62, - 0x10, 0xa8, 0x7b, 0x6a, + 0x80, 0xe2, 0x60, 0x62, + 0x10, 0xa8, 0x85, 0x6a, 0xc0, 0xaa, 0xc5, 0x01, - 0x40, 0xa8, 0x47, 0x6a, + 0x40, 0xa8, 0x51, 0x6a, 0xbf, 0xe2, 0xc4, 0x09, - 0x20, 0xa8, 0x5b, 0x7a, + 0x20, 0xa8, 0x65, 0x7a, 0x01, 0xe2, 0x88, 0x30, - 0x00, 0xe2, 0xa4, 0x5b, - 0xa0, 0x36, 0x63, 0x62, + 0x00, 0xe2, 0xac, 0x5b, + 0xa0, 0x36, 0x6d, 0x62, 0x23, 0xa8, 0x89, 0x08, - 0x00, 0xe2, 0xa4, 0x5b, - 0xa0, 0x36, 0x63, 0x62, - 0x00, 0xa8, 0x5a, 0x42, - 0xff, 0xe2, 0x5a, 0x62, - 0x00, 0xe2, 0x7a, 0x42, + 0x00, 0xe2, 0xac, 0x5b, + 0xa0, 0x36, 0x6d, 0x62, + 0x00, 0xa8, 0x64, 0x42, + 0xff, 0xe2, 0x64, 0x62, + 0x00, 0xe2, 0x84, 0x42, 0x40, 0xea, 0x98, 0x00, 0x01, 0xe2, 0x88, 0x30, - 0x00, 0xe2, 0xa4, 0x5b, - 0xa0, 0x36, 0x39, 0x72, + 0x00, 0xe2, 0xac, 0x5b, + 0xa0, 0x36, 0x43, 0x72, 0x40, 0xea, 0x98, 0x00, 0x01, 0x31, 0x89, 0x32, 0x08, 0xea, 0x62, 0x02, - 0x00, 0xe2, 0xee, 0x41, - 0xe0, 0xea, 0xb4, 0x5b, - 0x80, 0xe0, 0xb2, 0x6a, - 0x04, 0xe0, 0x52, 0x73, - 0x02, 0xe0, 0x82, 0x73, - 0x00, 0xea, 0x10, 0x73, - 0x03, 0xe0, 0x92, 0x73, - 0x23, 0xe0, 0x8c, 0x72, - 0x08, 0xe0, 0xae, 0x72, - 0x00, 0xe2, 0xa4, 0x5b, - 0x07, 0xea, 0x46, 0x59, + 0x00, 0xe2, 0xf8, 0x41, + 0xe0, 0xea, 0xc8, 0x5b, + 0x80, 0xe0, 0xbc, 0x6a, + 0x04, 0xe0, 0x5a, 0x73, + 0x02, 0xe0, 0x8a, 0x73, + 0x00, 0xea, 0x1a, 0x73, + 0x03, 0xe0, 0x9a, 0x73, + 0x23, 0xe0, 0x96, 0x72, + 0x08, 0xe0, 0xb8, 0x72, + 0x00, 0xe2, 0xac, 0x5b, + 0x07, 0xea, 0x50, 0x59, 0x07, 0xea, 0x04, 0x00, - 0x08, 0x42, 0xef, 0x71, - 0x04, 0x42, 0x89, 0x62, + 0x08, 0x42, 0xf9, 0x71, + 0x04, 0x42, 0x93, 0x62, 0x01, 0x43, 0x89, 0x30, - 0x00, 0xe2, 0x7a, 0x42, + 0x00, 0xe2, 0x84, 0x42, 0x01, 0x44, 0xd4, 0x31, - 0x00, 0xe2, 0x7a, 0x42, + 0x00, 0xe2, 0x84, 0x42, 0x01, 0x00, 0x60, 0x32, - 0x33, 0xea, 0x3a, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x4c, 0x34, 0xc1, 0x28, 0x01, 0x64, 0xc0, 0x31, - 0x00, 0x30, 0x3b, 0x59, + 0x00, 0x30, 0x45, 0x59, 0x01, 0x30, 0x01, 0x30, - 0x01, 0xe0, 0xac, 0x7a, - 0xa0, 0xea, 0xaa, 0x5b, - 0x01, 0xa0, 0xac, 0x62, - 0x01, 0x84, 0xa5, 0x7a, - 0x01, 0xa7, 0xae, 0x7a, - 0x00, 0xe2, 0xae, 0x42, - 0x03, 0xea, 0x46, 0x59, + 0x01, 0xe0, 0xb6, 0x7a, + 0xa0, 0xea, 0xbe, 0x5b, + 0x01, 0xa0, 0xb6, 0x62, + 0x01, 0x84, 0xaf, 0x7a, + 0x01, 0xa7, 0xb8, 0x7a, + 0x00, 0xe2, 0xb8, 0x42, + 0x03, 0xea, 0x50, 0x59, 0x03, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xae, 0x42, - 0x07, 0xea, 0xbc, 0x5b, + 0x00, 0xe2, 0xb8, 0x42, + 0x07, 0xea, 0xd0, 0x5b, 0x01, 0x44, 0xd4, 0x31, - 0x00, 0xe2, 0xee, 0x41, + 0x00, 0xe2, 0xf8, 0x41, 0x3f, 0xe0, 0x6a, 0x0a, 0xc0, 0x34, 0xc1, 0x09, 0x00, 0x35, 0x51, 0x01, @@ -361,54 +366,54 @@ static uint8_t seqprog[] = { 0x01, 0xea, 0xc6, 0x01, 0x02, 0xe2, 0xc8, 0x31, 0x02, 0xec, 0x40, 0x31, - 0xff, 0xa1, 0xce, 0x72, + 0xff, 0xa1, 0xd8, 0x72, 0x02, 0xe8, 0xda, 0x31, 0x02, 0xa0, 0x50, 0x31, - 0x00, 0xe2, 0xf0, 0x42, + 0x00, 0xe2, 0xfa, 0x42, 0x80, 0x33, 0x67, 0x02, 0x01, 0x44, 0xd4, 0x31, - 0x00, 0xe2, 0xa4, 0x5b, + 0x00, 0xe2, 0xac, 0x5b, 0x01, 0x33, 0x67, 0x02, - 0xe0, 0x36, 0x0b, 0x63, + 0xe0, 0x36, 0x15, 0x63, 0x02, 0x33, 0x67, 0x02, - 0x20, 0x46, 0x04, 0x63, + 0x20, 0x46, 0x0e, 0x63, 0xff, 0xea, 0x52, 0x09, - 0xa8, 0xea, 0xaa, 0x5b, - 0x04, 0xa8, 0xeb, 0x7a, + 0xa8, 0xea, 0xbe, 0x5b, + 0x04, 0xa8, 0xf5, 0x7a, 0x01, 0x34, 0xc1, 0x31, - 0x00, 0xa9, 0xeb, 0x62, + 0x00, 0xa9, 0xf5, 0x62, 0x01, 0x35, 0xc1, 0x31, - 0x00, 0xaa, 0xf5, 0x72, + 0x00, 0xaa, 0xff, 0x72, 0x01, 0xa9, 0x52, 0x11, - 0xff, 0xa9, 0xe0, 0x6a, - 0x00, 0xe2, 0x04, 0x43, + 0xff, 0xa9, 0xea, 0x6a, + 0x00, 0xe2, 0x0e, 0x43, 0x10, 0x33, 0x67, 0x02, - 0x04, 0xa8, 0x05, 0x7b, + 0x04, 0xa8, 0x0f, 0x7b, 0xfb, 0xa8, 0x51, 0x0b, 0xff, 0xea, 0x66, 0x0a, - 0x01, 0xa4, 0xff, 0x6a, + 0x01, 0xa4, 0x09, 0x6b, 0x02, 0xa8, 0x90, 0x32, - 0x00, 0xe2, 0x60, 0x59, - 0x10, 0xa8, 0xaf, 0x7a, - 0xff, 0xea, 0xbc, 0x5b, - 0x00, 0xe2, 0xae, 0x42, - 0x04, 0xea, 0x46, 0x59, + 0x00, 0xe2, 0x6a, 0x59, + 0x10, 0xa8, 0xb9, 0x7a, + 0xff, 0xea, 0xd0, 0x5b, + 0x00, 0xe2, 0xb8, 0x42, + 0x04, 0xea, 0x50, 0x59, 0x04, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xae, 0x42, - 0x04, 0xea, 0x46, 0x59, + 0x00, 0xe2, 0xb8, 0x42, + 0x04, 0xea, 0x50, 0x59, 0x04, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xee, 0x41, - 0x08, 0xa8, 0xa7, 0x7a, - 0xc0, 0x33, 0x1b, 0x7b, - 0x80, 0x33, 0xa7, 0x6a, - 0xff, 0x88, 0x1b, 0x6b, - 0x40, 0x33, 0xa7, 0x6a, - 0x10, 0xa8, 0x21, 0x7b, - 0x0a, 0xea, 0x46, 0x59, + 0x00, 0xe2, 0xf8, 0x41, + 0x08, 0xa8, 0xb1, 0x7a, + 0xc0, 0x33, 0x25, 0x7b, + 0x80, 0x33, 0xb1, 0x6a, + 0xff, 0x88, 0x25, 0x6b, + 0x40, 0x33, 0xb1, 0x6a, + 0x10, 0xa8, 0x2b, 0x7b, + 0x0a, 0xea, 0x50, 0x59, 0x0a, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x3a, 0x5b, - 0x00, 0xe2, 0x6e, 0x43, - 0x50, 0x4b, 0x28, 0x6b, + 0x00, 0xe2, 0x44, 0x5b, + 0x00, 0xe2, 0x76, 0x43, + 0x50, 0x4b, 0x32, 0x6b, 0xbf, 0x3a, 0x74, 0x08, 0x01, 0xe0, 0xf8, 0x31, 0xff, 0xea, 0xc0, 0x09, @@ -416,24 +421,23 @@ static uint8_t seqprog[] = { 0x00, 0x2f, 0x5f, 0x22, 0x04, 0x47, 0x8f, 0x02, 0x01, 0xfc, 0xc0, 0x35, - 0x33, 0xea, 0x3a, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x02, 0x42, 0x51, 0x31, - 0x10, 0xa8, 0x51, 0x03, - 0xff, 0x88, 0x49, 0x6b, - 0x01, 0xa4, 0x45, 0x6b, - 0x02, 0xa4, 0x4d, 0x6b, - 0x01, 0x84, 0x4d, 0x7b, + 0xff, 0x88, 0x51, 0x6b, + 0x01, 0xa4, 0x4d, 0x6b, + 0x02, 0xa4, 0x55, 0x6b, + 0x01, 0x84, 0x55, 0x7b, 0x02, 0x28, 0x19, 0x33, 0x02, 0xa8, 0x50, 0x36, - 0xff, 0x88, 0x4d, 0x73, - 0x00, 0xe2, 0x24, 0x5b, + 0xff, 0x88, 0x55, 0x73, + 0x00, 0xe2, 0x2e, 0x5b, 0x02, 0x2c, 0x19, 0x33, 0x02, 0xa8, 0x58, 0x32, 0x04, 0xa4, 0x49, 0x07, - 0xc0, 0x33, 0xa7, 0x6a, + 0xc0, 0x33, 0xb1, 0x6a, 0x04, 0xa8, 0x51, 0x03, - 0x20, 0xa8, 0x6f, 0x6b, + 0x20, 0xa8, 0x77, 0x6b, 0x02, 0xa8, 0x40, 0x31, 0xc0, 0x34, 0xc1, 0x09, 0x00, 0x35, 0x51, 0x01, @@ -448,66 +452,73 @@ static uint8_t seqprog[] = { 0xf7, 0x57, 0xae, 0x08, 0x08, 0xea, 0x98, 0x00, 0x01, 0x44, 0xd4, 0x31, - 0xee, 0x00, 0x78, 0x6b, + 0xee, 0x00, 0x80, 0x6b, 0x02, 0xea, 0xb4, 0x00, - 0x00, 0xe2, 0xa0, 0x5b, - 0x09, 0x4c, 0x7a, 0x7b, + 0x00, 0xe2, 0xa8, 0x5b, + 0x09, 0x4c, 0x82, 0x7b, 0x08, 0x4c, 0x06, 0x68, - 0x0b, 0xea, 0x46, 0x59, + 0x0b, 0xea, 0x50, 0x59, 0x0b, 0xea, 0x04, 0x00, 0x01, 0x44, 0xd4, 0x31, - 0x20, 0x33, 0xef, 0x79, - 0x00, 0xe2, 0x8a, 0x5b, - 0x00, 0xe2, 0xee, 0x41, - 0x01, 0x84, 0x8f, 0x7b, + 0x20, 0x33, 0xf9, 0x79, + 0x00, 0xe2, 0x92, 0x5b, + 0x00, 0xe2, 0xf8, 0x41, + 0x01, 0x84, 0x97, 0x7b, 0x01, 0xa4, 0x49, 0x07, 0x08, 0x60, 0x30, 0x33, 0x08, 0x80, 0x41, 0x37, 0xdf, 0x33, 0x67, 0x0a, - 0xee, 0x00, 0x9c, 0x6b, + 0xee, 0x00, 0xa4, 0x6b, 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x3a, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, - 0x00, 0xe2, 0x60, 0x59, - 0x00, 0xe2, 0xae, 0x42, + 0x00, 0xe2, 0x6a, 0x59, + 0x00, 0xe2, 0xb8, 0x42, 0x01, 0xea, 0x6c, 0x02, 0xc0, 0xea, 0x66, 0x06, - 0xff, 0x42, 0xa4, 0x7b, - 0x04, 0x4c, 0xa4, 0x6b, + 0xff, 0x42, 0xb8, 0x6b, + 0x01, 0x41, 0xac, 0x6b, + 0x02, 0x41, 0xac, 0x7b, + 0xff, 0x42, 0xb8, 0x6b, + 0x01, 0x41, 0xac, 0x6b, + 0x02, 0x41, 0xac, 0x7b, + 0xff, 0x42, 0xb8, 0x7b, + 0x04, 0x4c, 0xac, 0x6b, 0xe0, 0x41, 0x6c, 0x0e, 0x01, 0x44, 0xd4, 0x31, - 0xff, 0x42, 0xac, 0x7b, - 0x04, 0x4c, 0xac, 0x6b, + 0xff, 0x42, 0xc0, 0x7b, + 0x04, 0x4c, 0xc0, 0x6b, 0xe0, 0x41, 0x6c, 0x0a, - 0xe0, 0x36, 0xef, 0x61, + 0xe0, 0x36, 0xf9, 0x61, 0xff, 0xea, 0xca, 0x09, 0x01, 0xe2, 0xc8, 0x31, 0x01, 0x46, 0xda, 0x35, 0x01, 0x44, 0xd4, 0x35, 0x10, 0xea, 0x80, 0x00, 0x01, 0xe2, 0x62, 0x36, - 0x04, 0xa6, 0xc4, 0x7b, + 0x04, 0xa6, 0xd8, 0x7b, 0xff, 0xea, 0x5a, 0x09, 0xff, 0xea, 0x4c, 0x0d, - 0x01, 0xa6, 0xe2, 0x6b, - 0x10, 0xad, 0x66, 0x7d, - 0x80, 0xad, 0xda, 0x6b, - 0x08, 0xad, 0x66, 0x6d, + 0x01, 0xa6, 0xf6, 0x6b, + 0x10, 0xad, 0x96, 0x7d, + 0x80, 0xad, 0xee, 0x6b, + 0x08, 0xad, 0x96, 0x6d, 0x04, 0x84, 0xf9, 0x30, 0x00, 0xea, 0x08, 0x81, 0xff, 0xea, 0xd4, 0x09, 0x02, 0x84, 0xf9, 0x88, - 0x1d, 0xea, 0x5a, 0x01, + 0x0d, 0xea, 0x5a, 0x01, 0x04, 0xa6, 0x4c, 0x05, - 0x04, 0xa6, 0x66, 0x7d, + 0x04, 0xa6, 0x96, 0x7d, 0xff, 0xea, 0x5a, 0x09, 0x03, 0x84, 0x59, 0x89, 0x03, 0xea, 0x4c, 0x01, - 0x80, 0x1a, 0x66, 0x7d, + 0x80, 0x1a, 0x96, 0x7d, + 0x08, 0x19, 0x96, 0x7d, 0x08, 0xb0, 0xe0, 0x30, 0x04, 0xb0, 0xe0, 0x30, 0x03, 0xb0, 0xf0, 0x30, - 0x01, 0x78, 0xee, 0x7b, + 0x01, 0x78, 0x04, 0x7c, 0x01, 0xa7, 0x4e, 0x11, 0x01, 0xb0, 0x06, 0x33, 0x7f, 0x83, 0xe9, 0x08, @@ -518,247 +529,267 @@ static uint8_t seqprog[] = { 0x00, 0x86, 0x0d, 0x23, 0x00, 0x87, 0x0f, 0x23, 0x01, 0x84, 0xc5, 0x31, - 0x01, 0xa7, 0x04, 0x7c, + 0x01, 0xa7, 0x1a, 0x7c, 0x04, 0xe2, 0xc4, 0x01, - 0x80, 0x83, 0x0b, 0x7c, + 0x80, 0x83, 0x21, 0x7c, 0x02, 0xe2, 0xc4, 0x01, 0xff, 0xea, 0x4c, 0x09, 0x01, 0xe2, 0x36, 0x30, 0xc8, 0x19, 0x32, 0x00, 0x88, 0x19, 0x32, 0x00, 0x01, 0xac, 0xd4, 0x99, - 0x00, 0xe2, 0x66, 0x55, + 0x00, 0xe2, 0x96, 0x55, 0xfe, 0xa6, 0x4c, 0x0d, 0x0b, 0x98, 0xe1, 0x30, 0x01, 0xa0, 0x4f, 0x09, 0xfd, 0xa4, 0x49, 0x09, - 0x80, 0xa3, 0x21, 0x7c, + 0x80, 0xa3, 0x37, 0x7c, 0x02, 0xa4, 0x48, 0x01, - 0x01, 0xa7, 0x24, 0x7c, + 0x01, 0xa7, 0x3a, 0x7c, 0x04, 0xa4, 0x48, 0x01, 0x01, 0xa4, 0x36, 0x30, 0xa8, 0xea, 0x32, 0x00, 0xfd, 0xa4, 0x49, 0x0b, 0x05, 0xa3, 0x07, 0x33, - 0x80, 0x83, 0x31, 0x6c, + 0x80, 0x83, 0x47, 0x6c, 0x02, 0xea, 0x4c, 0x05, 0xff, 0xea, 0x4c, 0x0d, - 0x00, 0xe2, 0x32, 0x59, - 0x02, 0xa6, 0xc6, 0x6b, + 0x00, 0xe2, 0x3c, 0x59, + 0x02, 0xa6, 0xda, 0x6b, 0x80, 0xf9, 0xf2, 0x05, - 0xc0, 0x33, 0x3f, 0x7c, - 0x03, 0xea, 0x46, 0x59, + 0xc0, 0x33, 0x55, 0x7c, + 0x03, 0xea, 0x50, 0x59, 0x03, 0xea, 0x04, 0x00, - 0x20, 0x33, 0x63, 0x7c, - 0x01, 0x84, 0x49, 0x6c, - 0x06, 0xea, 0x46, 0x59, + 0x20, 0x33, 0x79, 0x7c, + 0x01, 0x84, 0x5f, 0x6c, + 0x06, 0xea, 0x50, 0x59, 0x06, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x66, 0x44, + 0x00, 0xe2, 0x7c, 0x44, 0x01, 0x00, 0x60, 0x32, - 0xee, 0x00, 0x52, 0x6c, + 0xee, 0x00, 0x68, 0x6c, 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x3a, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x80, 0x3d, 0x7a, 0x00, - 0xfc, 0x42, 0x54, 0x7c, + 0xfc, 0x42, 0x6a, 0x7c, 0x7f, 0x3d, 0x7a, 0x08, - 0x00, 0x30, 0x3b, 0x59, + 0x00, 0x30, 0x45, 0x59, 0x01, 0x30, 0x01, 0x30, - 0x09, 0xea, 0x46, 0x59, + 0x09, 0xea, 0x50, 0x59, 0x09, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xee, 0x41, - 0x01, 0xa4, 0x49, 0x6c, - 0x00, 0xe2, 0x16, 0x5c, + 0x00, 0xe2, 0xf8, 0x41, + 0x01, 0xa4, 0x5f, 0x6c, + 0x00, 0xe2, 0x2c, 0x5c, 0x20, 0x33, 0x67, 0x02, 0x01, 0x00, 0x60, 0x32, - 0x02, 0xa6, 0x6e, 0x7c, - 0x00, 0xe2, 0x32, 0x5c, - 0x00, 0xe2, 0x66, 0x58, - 0x00, 0xe2, 0x76, 0x58, - 0x00, 0xe2, 0x30, 0x58, - 0x00, 0x30, 0x3b, 0x59, + 0x02, 0xa6, 0x84, 0x7c, + 0x00, 0xe2, 0x48, 0x5c, + 0x00, 0xe2, 0x70, 0x58, + 0x00, 0xe2, 0x80, 0x58, + 0x00, 0xe2, 0x3a, 0x58, + 0x00, 0x30, 0x45, 0x59, 0x01, 0x30, 0x01, 0x30, - 0x20, 0x19, 0x6e, 0x6c, - 0x00, 0xe2, 0x96, 0x5c, - 0x04, 0x19, 0x88, 0x6c, + 0x20, 0x19, 0x84, 0x6c, + 0x00, 0xe2, 0xb4, 0x5c, + 0x04, 0x19, 0x9e, 0x6c, 0x02, 0x19, 0x32, 0x00, - 0x01, 0x84, 0x89, 0x7c, - 0x01, 0x1b, 0x82, 0x7c, - 0x01, 0x1a, 0x88, 0x6c, - 0x00, 0xe2, 0x38, 0x44, - 0x80, 0x4b, 0x8e, 0x6c, - 0x01, 0x4c, 0x8a, 0x7c, - 0x03, 0x42, 0x38, 0x6c, - 0x00, 0xe2, 0xc0, 0x5b, + 0x01, 0x84, 0x9f, 0x7c, + 0x01, 0x1b, 0x98, 0x7c, + 0x01, 0x1a, 0x9e, 0x6c, + 0x00, 0xe2, 0x4e, 0x44, + 0x80, 0x4b, 0xa4, 0x6c, + 0x01, 0x4c, 0xa0, 0x7c, + 0x03, 0x42, 0x4e, 0x6c, + 0x00, 0xe2, 0xd4, 0x5b, 0x80, 0xf9, 0xf2, 0x01, - 0x04, 0x33, 0xef, 0x79, - 0x00, 0xe2, 0xee, 0x41, - 0x02, 0x1b, 0x9e, 0x7c, - 0x08, 0x5d, 0x9c, 0x7c, + 0x04, 0x33, 0xf9, 0x79, + 0x00, 0xe2, 0xf8, 0x41, + 0x08, 0x5d, 0xbc, 0x6c, + 0x00, 0xe2, 0x70, 0x58, + 0x00, 0x30, 0x45, 0x59, + 0x01, 0x30, 0x01, 0x30, + 0x02, 0x1b, 0xac, 0x7c, + 0x08, 0x5d, 0xba, 0x7c, 0x03, 0x68, 0x00, 0x37, 0x01, 0x84, 0x09, 0x07, - 0x08, 0x5d, 0xa8, 0x6c, - 0x00, 0xe2, 0x66, 0x58, - 0x00, 0x30, 0x3b, 0x59, - 0x01, 0x30, 0x01, 0x30, - 0x00, 0xe2, 0x96, 0x44, - 0x80, 0x1b, 0xb2, 0x7c, - 0x80, 0x84, 0xb3, 0x6c, + 0x80, 0x1b, 0xc6, 0x7c, + 0x80, 0x84, 0xc7, 0x6c, 0xff, 0x85, 0x0b, 0x1b, 0xff, 0x86, 0x0d, 0x23, 0xff, 0x87, 0x0f, 0x23, 0xf8, 0x1b, 0x08, 0x0b, 0xff, 0xea, 0x4e, 0x09, - 0x04, 0x1b, 0xba, 0x7c, + 0x04, 0x1b, 0xce, 0x7c, 0x01, 0xa7, 0x4e, 0x01, 0xff, 0xea, 0x06, 0x0b, 0x03, 0x68, 0x00, 0x37, - 0x00, 0xe2, 0xb6, 0x58, + 0x00, 0xe2, 0xc0, 0x58, 0x10, 0xea, 0x18, 0x00, 0xf9, 0xd9, 0xb2, 0x0d, 0x01, 0xd9, 0xb2, 0x05, - 0xff, 0xea, 0xd4, 0x09, - 0x10, 0x5b, 0xde, 0x6c, - 0x08, 0x5b, 0xe6, 0x6c, - 0x20, 0x5b, 0xd4, 0x6c, - 0x02, 0x5b, 0xfa, 0x6d, - 0x0e, 0xea, 0x46, 0x59, + 0x01, 0x52, 0x48, 0x31, + 0x20, 0xa4, 0xf2, 0x7c, + 0x20, 0x5b, 0xf2, 0x7c, + 0x80, 0xf9, 0x00, 0x7d, + 0x11, 0x00, 0x00, 0x10, + 0x04, 0x19, 0xec, 0x7c, + 0xdf, 0x19, 0x32, 0x08, + 0x01, 0x4c, 0xe8, 0x7c, + 0x20, 0x19, 0x32, 0x00, + 0x11, 0x00, 0x00, 0x10, + 0x02, 0xea, 0xb4, 0x00, + 0x01, 0xd9, 0xb2, 0x05, + 0x10, 0x5b, 0x04, 0x6d, + 0x08, 0x5b, 0x0c, 0x6d, + 0x20, 0x5b, 0xfe, 0x6c, + 0x02, 0x5b, 0x2c, 0x6d, + 0x0e, 0xea, 0x50, 0x59, 0x0e, 0xea, 0x04, 0x00, - 0x08, 0x19, 0xda, 0x7c, + 0x80, 0xf9, 0xee, 0x6c, 0xdf, 0x5c, 0xb8, 0x08, 0x01, 0xd9, 0xb2, 0x05, - 0x02, 0xea, 0xb4, 0x00, - 0x01, 0xd9, 0xb2, 0x05, - 0x01, 0xa4, 0xc3, 0x6d, - 0x00, 0xe2, 0x16, 0x5c, - 0x00, 0xe2, 0x06, 0x5d, + 0x01, 0xa4, 0xff, 0x6d, + 0x00, 0xe2, 0x2c, 0x5c, + 0x00, 0xe2, 0x36, 0x5d, 0x01, 0xd9, 0xb2, 0x05, - 0x00, 0xe2, 0x24, 0x5b, + 0x00, 0xe2, 0x2e, 0x5b, 0xf3, 0x92, 0xd5, 0x19, - 0x00, 0xe2, 0xf4, 0x54, - 0x80, 0x92, 0xf5, 0x6c, - 0x0f, 0xea, 0x46, 0x59, + 0x00, 0xe2, 0x1a, 0x55, + 0x80, 0x92, 0x1b, 0x6d, + 0x0f, 0xea, 0x50, 0x59, 0x0f, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xfc, 0x44, + 0x00, 0xe2, 0x22, 0x45, 0x04, 0x8c, 0xe1, 0x30, 0x01, 0xea, 0xf2, 0x00, 0x02, 0xea, 0x36, 0x00, 0xa8, 0xea, 0x32, 0x00, - 0xff, 0x93, 0x03, 0x7d, - 0x14, 0xea, 0x46, 0x59, + 0xff, 0x93, 0x29, 0x7d, + 0x14, 0xea, 0x50, 0x59, 0x14, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x88, 0x5d, + 0x00, 0xe2, 0xb0, 0x5d, + 0x01, 0xd9, 0xb2, 0x05, + 0x09, 0x80, 0xe1, 0x30, + 0x02, 0xea, 0x36, 0x00, + 0xa8, 0xea, 0x32, 0x00, + 0x00, 0xe2, 0xd8, 0x5d, 0x01, 0xd9, 0xb2, 0x05, 0x02, 0xa8, 0xf4, 0x31, - 0x02, 0xa6, 0x18, 0x7d, - 0x00, 0xe2, 0x34, 0x59, - 0x20, 0x5b, 0x26, 0x6d, - 0xfc, 0x42, 0x12, 0x7d, - 0x10, 0x40, 0x14, 0x6d, - 0x20, 0x4d, 0x16, 0x7d, - 0x08, 0x5d, 0x26, 0x6d, - 0x02, 0xa6, 0xc6, 0x6b, - 0x00, 0xe2, 0x34, 0x59, - 0x20, 0x5b, 0x26, 0x6d, - 0x01, 0x1b, 0x46, 0x6d, - 0xfc, 0x42, 0x22, 0x7d, - 0x10, 0x40, 0x24, 0x6d, - 0x20, 0x4d, 0x66, 0x7d, - 0x08, 0x5d, 0x66, 0x7d, + 0x02, 0xa6, 0x48, 0x7d, + 0x00, 0xe2, 0x3e, 0x59, + 0x20, 0x5b, 0x56, 0x6d, + 0xfc, 0x42, 0x42, 0x7d, + 0x10, 0x40, 0x44, 0x6d, + 0x20, 0x4d, 0x46, 0x7d, + 0x08, 0x5d, 0x56, 0x6d, + 0x02, 0xa6, 0xda, 0x6b, + 0x00, 0xe2, 0x3e, 0x59, + 0x20, 0x5b, 0x56, 0x6d, + 0x01, 0x1b, 0x76, 0x6d, + 0xfc, 0x42, 0x52, 0x7d, + 0x10, 0x40, 0x54, 0x6d, + 0x20, 0x4d, 0x96, 0x7d, + 0x08, 0x5d, 0x96, 0x7d, 0x02, 0x19, 0x32, 0x00, 0x01, 0x5b, 0x40, 0x31, - 0x00, 0xe2, 0x96, 0x5c, - 0x00, 0xe2, 0x8a, 0x5b, + 0x00, 0xe2, 0xb4, 0x5c, + 0x00, 0xe2, 0x92, 0x5b, 0x20, 0xea, 0xb6, 0x00, - 0x00, 0xe2, 0xc0, 0x5b, + 0x00, 0xe2, 0xd4, 0x5b, 0x20, 0x5c, 0xb8, 0x00, - 0x04, 0x19, 0x3c, 0x6d, - 0x01, 0x1a, 0x3c, 0x6d, - 0x00, 0xe2, 0x34, 0x59, - 0x01, 0x1a, 0x66, 0x7d, + 0x04, 0x19, 0x6c, 0x6d, + 0x01, 0x1a, 0x6c, 0x6d, + 0x00, 0xe2, 0x3e, 0x59, + 0x01, 0x1a, 0x96, 0x7d, 0x80, 0xf9, 0xf2, 0x01, - 0x20, 0xa0, 0xac, 0x7d, - 0x08, 0xa8, 0x45, 0x7d, - 0x00, 0xe2, 0x58, 0x45, + 0x20, 0xa0, 0xe8, 0x7d, + 0x08, 0xa8, 0x75, 0x7d, + 0x00, 0xe2, 0x88, 0x45, 0x02, 0xea, 0xb4, 0x04, 0x02, 0x19, 0x32, 0x00, - 0x08, 0xa8, 0x69, 0x7d, - 0x04, 0x5d, 0xc2, 0x7d, - 0x01, 0x1a, 0xc2, 0x7d, + 0x08, 0xa8, 0x99, 0x7d, + 0x04, 0x5d, 0xfe, 0x7d, + 0x01, 0x1a, 0xfe, 0x7d, 0x01, 0xa4, 0x49, 0x03, 0x80, 0xf9, 0xf2, 0x01, 0x02, 0xa8, 0x84, 0x32, 0x02, 0xea, 0xb4, 0x00, - 0x00, 0xe2, 0x34, 0x43, + 0x00, 0xe2, 0x3e, 0x43, 0x02, 0xa8, 0x84, 0x32, 0x02, 0xea, 0xb4, 0x00, 0xff, 0xea, 0xd4, 0x19, - 0x00, 0xe2, 0x40, 0x59, + 0x00, 0xe2, 0x4a, 0x59, 0x11, 0x00, 0x00, 0x10, - 0x00, 0xe2, 0x98, 0x5d, - 0x00, 0xe2, 0x34, 0x53, + 0x00, 0xe2, 0xcc, 0x5d, + 0x00, 0xe2, 0x3e, 0x53, 0xff, 0xea, 0xd4, 0x0d, - 0x00, 0xe2, 0x34, 0x59, - 0x40, 0x5b, 0x74, 0x6d, - 0x04, 0x5d, 0xc2, 0x7d, - 0x01, 0x1a, 0xc2, 0x7d, - 0x20, 0x4d, 0x66, 0x7d, - 0x40, 0x5b, 0xac, 0x7d, - 0x04, 0x5d, 0xc2, 0x7d, - 0x01, 0x1a, 0xc2, 0x7d, + 0x00, 0xe2, 0x3e, 0x59, + 0x40, 0x5b, 0xa4, 0x6d, + 0x04, 0x5d, 0xfe, 0x7d, + 0x01, 0x1a, 0xfe, 0x7d, + 0x20, 0x4d, 0x96, 0x7d, + 0x40, 0x5b, 0xe8, 0x7d, + 0x04, 0x5d, 0xfe, 0x7d, + 0x01, 0x1a, 0xfe, 0x7d, 0x80, 0xf9, 0xf2, 0x01, 0x01, 0xa4, 0x49, 0x03, - 0x08, 0xa8, 0x59, 0x6d, + 0x08, 0xa8, 0x89, 0x6d, 0x02, 0xea, 0xb4, 0x04, - 0xff, 0x6a, 0x8e, 0x7d, - 0x10, 0xea, 0x46, 0x59, - 0x10, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x8e, 0x45, - 0x00, 0xe2, 0x32, 0x59, - 0x10, 0x5d, 0x80, 0x6d, - 0x40, 0x5b, 0x66, 0x7d, + 0x00, 0xe2, 0x3c, 0x59, + 0x01, 0x1b, 0xc0, 0x7d, + 0x40, 0x5b, 0x96, 0x7d, 0x02, 0x19, 0x32, 0x00, 0x80, 0xf9, 0xf2, 0x01, 0xff, 0xea, 0x10, 0x03, 0x08, 0xa8, 0x51, 0x03, - 0x00, 0xe2, 0x58, 0x45, - 0x80, 0xf9, 0x66, 0x6d, + 0x00, 0xe2, 0x88, 0x45, + 0xff, 0x6a, 0xc6, 0x6d, + 0x40, 0x5b, 0x96, 0x7d, + 0xff, 0x6a, 0xb6, 0x7d, + 0x10, 0xea, 0x50, 0x59, + 0x10, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0xb6, 0x45, + 0x80, 0xf9, 0x96, 0x6d, 0x01, 0x43, 0xc1, 0x31, - 0x00, 0xfb, 0x66, 0x65, + 0x00, 0xfb, 0x96, 0x65, 0x01, 0x42, 0xc1, 0x31, - 0x00, 0xfa, 0x66, 0x65, + 0x00, 0xfa, 0x96, 0x65, 0x01, 0xe8, 0xd4, 0x1d, + 0x00, 0xe2, 0x3c, 0x59, + 0x01, 0x1b, 0x96, 0x7d, + 0x80, 0xf9, 0xf2, 0x01, + 0x02, 0xea, 0xb4, 0x04, 0x30, 0x3f, 0xc0, 0x09, - 0x30, 0xe0, 0x66, 0x65, - 0x40, 0x4b, 0x66, 0x6d, + 0x30, 0xe0, 0x96, 0x65, + 0x40, 0x4b, 0x96, 0x6d, 0xff, 0xea, 0x52, 0x01, - 0xee, 0x00, 0xb2, 0x6d, + 0xee, 0x00, 0xee, 0x6d, 0x80, 0xf9, 0xf2, 0x01, 0x02, 0xea, 0xb4, 0x00, 0x20, 0xea, 0x9a, 0x00, - 0xf3, 0x42, 0xbc, 0x6d, - 0x12, 0xea, 0x46, 0x59, + 0xf3, 0x42, 0xf8, 0x6d, + 0x12, 0xea, 0x50, 0x59, 0x12, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xee, 0x41, - 0x0d, 0xea, 0x46, 0x59, + 0x00, 0xe2, 0xf8, 0x41, + 0x0d, 0xea, 0x50, 0x59, 0x0d, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xee, 0x41, - 0x11, 0xea, 0x46, 0x59, + 0x00, 0xe2, 0xf8, 0x41, + 0x11, 0xea, 0x50, 0x59, 0x11, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x24, 0x5b, + 0x00, 0xe2, 0x2e, 0x5b, 0x08, 0x5a, 0xb4, 0x00, - 0x00, 0xe2, 0xe4, 0x5d, + 0x00, 0xe2, 0x22, 0x5e, 0xa8, 0xea, 0x32, 0x00, - 0x00, 0xe2, 0x34, 0x59, - 0x80, 0x1a, 0xd6, 0x7d, - 0x00, 0xe2, 0xe4, 0x5d, + 0x00, 0xe2, 0x3e, 0x59, + 0x80, 0x1a, 0x12, 0x7e, + 0x00, 0xe2, 0x22, 0x5e, 0x80, 0x19, 0x32, 0x00, - 0x40, 0x5b, 0xdc, 0x6d, - 0x08, 0x5a, 0xdc, 0x7d, - 0x20, 0x4d, 0x66, 0x7d, + 0x40, 0x5b, 0x18, 0x6e, + 0x08, 0x5a, 0x18, 0x7e, + 0x20, 0x4d, 0x96, 0x7d, 0x02, 0x84, 0x09, 0x03, - 0x40, 0x5b, 0xac, 0x7d, - 0x08, 0xa8, 0x51, 0x6d, + 0x40, 0x5b, 0xe8, 0x7d, + 0x08, 0xa8, 0x81, 0x6d, + 0x80, 0xf9, 0xf2, 0x01, 0x02, 0xea, 0xb4, 0x04, 0x01, 0x38, 0xe1, 0x30, 0x05, 0x39, 0xe3, 0x98, @@ -774,12 +805,36 @@ static uint8_t seqprog[] = { }; typedef int ahd_patch_func_t (struct ahd_softc *ahd); +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); +} + +static ahd_patch_func_t ahd_patch20_func; + +static int +ahd_patch20_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0); +} + +static ahd_patch_func_t ahd_patch19_func; + +static int +ahd_patch19_func(struct ahd_softc *ahd) +{ + return ((ahd->features & AHD_RTI) == 0); +} + static ahd_patch_func_t ahd_patch18_func; static int ahd_patch18_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0); + return ((ahd->flags & AHD_INITIATORROLE) != 0); } static ahd_patch_func_t ahd_patch17_func; @@ -787,7 +842,7 @@ static ahd_patch_func_t ahd_patch17_func; static int ahd_patch17_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0); + return ((ahd->flags & AHD_TARGETROLE) != 0); } static ahd_patch_func_t ahd_patch16_func; @@ -795,7 +850,7 @@ static ahd_patch_func_t ahd_patch16_func; static int ahd_patch16_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_INITIATORROLE) != 0); + return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0); } static ahd_patch_func_t ahd_patch15_func; @@ -803,7 +858,7 @@ static ahd_patch_func_t ahd_patch15_func; static int ahd_patch15_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_TARGETROLE) != 0); + return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0); } static ahd_patch_func_t ahd_patch14_func; @@ -811,7 +866,7 @@ static ahd_patch_func_t ahd_patch14_func; static int ahd_patch14_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0); + return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0); } static ahd_patch_func_t ahd_patch13_func; @@ -819,7 +874,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->flags & AHD_64BIT_ADDRESSING) != 0); } static ahd_patch_func_t ahd_patch12_func; @@ -827,7 +882,7 @@ static ahd_patch_func_t ahd_patch12_func; static int ahd_patch12_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0); + return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0); } static ahd_patch_func_t ahd_patch11_func; @@ -835,7 +890,7 @@ static ahd_patch_func_t ahd_patch11_func; static int ahd_patch11_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0); + return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0); } static ahd_patch_func_t ahd_patch10_func; @@ -843,7 +898,7 @@ static ahd_patch_func_t ahd_patch10_func; static int ahd_patch10_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_patch9_func; @@ -859,7 +914,7 @@ static ahd_patch_func_t ahd_patch8_func; static int ahd_patch8_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_ABORT_LQI_BUG) == 0); + return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0); } static ahd_patch_func_t ahd_patch7_func; @@ -867,7 +922,7 @@ static ahd_patch_func_t ahd_patch7_func; static int ahd_patch7_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0); + return ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0); } static ahd_patch_func_t ahd_patch6_func; @@ -875,7 +930,7 @@ static ahd_patch_func_t ahd_patch6_func; static int ahd_patch6_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0); + return ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0); } static ahd_patch_func_t ahd_patch5_func; @@ -883,7 +938,7 @@ static ahd_patch_func_t ahd_patch5_func; static int ahd_patch5_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0); + return ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0); } static ahd_patch_func_t ahd_patch4_func; @@ -891,7 +946,7 @@ static ahd_patch_func_t ahd_patch4_func; static int ahd_patch4_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0); + return ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0); } static ahd_patch_func_t ahd_patch3_func; @@ -899,7 +954,7 @@ static ahd_patch_func_t ahd_patch3_func; static int ahd_patch3_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0); + return ((ahd->bugs & AHD_FAINT_LED_BUG) != 0); } static ahd_patch_func_t ahd_patch2_func; @@ -940,124 +995,129 @@ static struct patch { { ahd_patch0_func, 5, 1, 1 }, { ahd_patch2_func, 6, 1, 2 }, { ahd_patch0_func, 7, 1, 1 }, - { ahd_patch2_func, 24, 1, 2 }, - { ahd_patch0_func, 25, 1, 1 }, - { ahd_patch1_func, 32, 1, 2 }, - { ahd_patch0_func, 33, 1, 1 }, - { ahd_patch2_func, 40, 1, 2 }, - { ahd_patch0_func, 41, 1, 1 }, - { ahd_patch2_func, 44, 1, 2 }, - { ahd_patch0_func, 45, 1, 1 }, - { ahd_patch2_func, 48, 1, 2 }, - { ahd_patch0_func, 49, 1, 1 }, - { ahd_patch2_func, 51, 1, 2 }, - { ahd_patch0_func, 52, 1, 1 }, - { ahd_patch2_func, 55, 1, 2 }, - { ahd_patch0_func, 56, 1, 1 }, - { ahd_patch2_func, 59, 1, 2 }, - { ahd_patch0_func, 60, 1, 1 }, - { ahd_patch2_func, 157, 6, 1 }, - { ahd_patch1_func, 163, 2, 1 }, - { ahd_patch3_func, 165, 1, 1 }, - { ahd_patch2_func, 174, 1, 2 }, - { ahd_patch0_func, 175, 1, 1 }, - { ahd_patch4_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_patch5_func, 188, 2, 1 }, - { ahd_patch3_func, 196, 16, 2 }, - { ahd_patch0_func, 212, 1, 1 }, - { ahd_patch6_func, 232, 2, 1 }, - { ahd_patch1_func, 236, 1, 2 }, - { ahd_patch0_func, 237, 1, 1 }, - { ahd_patch5_func, 240, 2, 1 }, - { ahd_patch1_func, 254, 1, 2 }, - { ahd_patch0_func, 255, 1, 1 }, - { ahd_patch1_func, 258, 1, 2 }, - { ahd_patch0_func, 259, 1, 1 }, - { ahd_patch2_func, 262, 1, 2 }, - { ahd_patch0_func, 263, 1, 1 }, - { ahd_patch1_func, 318, 1, 2 }, - { ahd_patch0_func, 319, 1, 1 }, - { ahd_patch2_func, 327, 1, 2 }, - { ahd_patch0_func, 328, 1, 1 }, - { ahd_patch2_func, 331, 1, 2 }, - { ahd_patch0_func, 332, 1, 1 }, - { ahd_patch1_func, 339, 1, 2 }, - { ahd_patch0_func, 340, 1, 1 }, - { ahd_patch7_func, 359, 1, 1 }, - { ahd_patch7_func, 362, 1, 1 }, - { ahd_patch7_func, 364, 1, 1 }, - { ahd_patch7_func, 376, 1, 1 }, - { ahd_patch1_func, 386, 1, 2 }, - { ahd_patch0_func, 387, 1, 1 }, - { ahd_patch1_func, 389, 1, 2 }, - { ahd_patch0_func, 390, 1, 1 }, - { ahd_patch1_func, 398, 1, 2 }, - { ahd_patch0_func, 399, 1, 1 }, - { ahd_patch2_func, 410, 1, 2 }, - { ahd_patch0_func, 411, 1, 1 }, - { ahd_patch8_func, 413, 1, 1 }, - { ahd_patch9_func, 440, 1, 1 }, - { ahd_patch1_func, 447, 1, 2 }, - { ahd_patch0_func, 448, 1, 1 }, - { ahd_patch2_func, 460, 1, 2 }, - { ahd_patch0_func, 461, 1, 1 }, - { ahd_patch10_func, 489, 1, 1 }, - { ahd_patch11_func, 498, 1, 2 }, - { ahd_patch0_func, 499, 1, 1 }, - { ahd_patch12_func, 504, 1, 1 }, - { ahd_patch11_func, 505, 1, 1 }, - { ahd_patch13_func, 518, 1, 2 }, - { ahd_patch0_func, 519, 1, 1 }, - { ahd_patch1_func, 541, 1, 2 }, - { ahd_patch0_func, 542, 1, 1 }, - { ahd_patch1_func, 545, 1, 2 }, - { ahd_patch0_func, 546, 1, 1 }, - { ahd_patch2_func, 551, 1, 2 }, - { ahd_patch0_func, 552, 1, 1 }, - { ahd_patch2_func, 556, 1, 2 }, + { ahd_patch3_func, 20, 5, 1 }, + { ahd_patch2_func, 29, 1, 2 }, + { ahd_patch0_func, 30, 1, 1 }, + { ahd_patch1_func, 37, 1, 2 }, + { ahd_patch0_func, 38, 1, 1 }, + { ahd_patch2_func, 45, 1, 2 }, + { ahd_patch0_func, 46, 1, 1 }, + { ahd_patch2_func, 49, 1, 2 }, + { ahd_patch0_func, 50, 1, 1 }, + { ahd_patch2_func, 53, 1, 2 }, + { ahd_patch0_func, 54, 1, 1 }, + { ahd_patch2_func, 56, 1, 2 }, + { ahd_patch0_func, 57, 1, 1 }, + { ahd_patch2_func, 60, 1, 2 }, + { ahd_patch0_func, 61, 1, 1 }, + { ahd_patch2_func, 64, 1, 2 }, + { ahd_patch0_func, 65, 1, 1 }, + { ahd_patch2_func, 162, 6, 1 }, + { ahd_patch1_func, 168, 2, 1 }, + { ahd_patch4_func, 170, 1, 1 }, + { ahd_patch2_func, 179, 1, 2 }, + { ahd_patch0_func, 180, 1, 1 }, + { ahd_patch5_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_patch6_func, 193, 2, 1 }, + { ahd_patch4_func, 201, 16, 2 }, + { ahd_patch0_func, 217, 1, 1 }, + { ahd_patch7_func, 237, 2, 1 }, + { ahd_patch1_func, 241, 1, 2 }, + { ahd_patch0_func, 242, 1, 1 }, + { ahd_patch6_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, 344, 1, 2 }, + { ahd_patch0_func, 345, 1, 1 }, + { ahd_patch8_func, 364, 1, 1 }, + { ahd_patch8_func, 367, 1, 1 }, + { ahd_patch8_func, 369, 1, 1 }, + { ahd_patch8_func, 381, 1, 1 }, + { ahd_patch1_func, 391, 1, 2 }, + { ahd_patch0_func, 392, 1, 1 }, + { ahd_patch1_func, 394, 1, 2 }, + { ahd_patch0_func, 395, 1, 1 }, + { ahd_patch1_func, 403, 1, 2 }, + { ahd_patch0_func, 404, 1, 1 }, + { ahd_patch2_func, 415, 1, 2 }, + { ahd_patch0_func, 416, 1, 1 }, + { ahd_patch9_func, 444, 1, 1 }, + { ahd_patch1_func, 451, 1, 2 }, + { ahd_patch0_func, 452, 1, 1 }, + { ahd_patch2_func, 464, 1, 2 }, + { ahd_patch0_func, 465, 1, 1 }, + { ahd_patch10_func, 470, 6, 2 }, + { ahd_patch0_func, 476, 1, 1 }, + { ahd_patch11_func, 499, 1, 1 }, + { ahd_patch12_func, 508, 1, 1 }, + { ahd_patch13_func, 509, 1, 2 }, + { ahd_patch0_func, 510, 1, 1 }, + { ahd_patch14_func, 515, 1, 1 }, + { ahd_patch13_func, 516, 1, 1 }, + { ahd_patch15_func, 529, 1, 2 }, + { ahd_patch0_func, 530, 1, 1 }, + { ahd_patch1_func, 552, 1, 2 }, + { ahd_patch0_func, 553, 1, 1 }, + { ahd_patch1_func, 556, 1, 2 }, { ahd_patch0_func, 557, 1, 1 }, - { ahd_patch1_func, 558, 1, 2 }, - { ahd_patch0_func, 559, 1, 1 }, - { ahd_patch2_func, 570, 1, 2 }, - { ahd_patch0_func, 571, 1, 1 }, - { ahd_patch14_func, 575, 1, 1 }, - { ahd_patch15_func, 580, 1, 1 }, - { ahd_patch16_func, 581, 2, 1 }, - { ahd_patch15_func, 585, 1, 2 }, - { ahd_patch0_func, 586, 1, 1 }, - { ahd_patch2_func, 593, 1, 2 }, - { ahd_patch0_func, 594, 1, 1 }, - { ahd_patch2_func, 609, 1, 2 }, - { ahd_patch0_func, 610, 1, 1 }, - { ahd_patch1_func, 616, 1, 2 }, - { ahd_patch0_func, 617, 1, 1 }, - { ahd_patch1_func, 631, 1, 2 }, - { ahd_patch0_func, 632, 1, 1 }, - { ahd_patch1_func, 639, 1, 2 }, - { ahd_patch0_func, 640, 1, 1 }, - { ahd_patch14_func, 659, 1, 1 }, - { ahd_patch14_func, 675, 1, 1 }, - { ahd_patch2_func, 687, 1, 2 }, - { ahd_patch0_func, 688, 1, 1 }, - { ahd_patch1_func, 705, 1, 2 }, - { ahd_patch0_func, 706, 1, 1 }, - { ahd_patch14_func, 711, 1, 1 }, - { ahd_patch1_func, 731, 1, 2 }, - { ahd_patch0_func, 732, 1, 1 }, - { ahd_patch1_func, 734, 1, 2 }, - { ahd_patch0_func, 735, 1, 1 }, - { ahd_patch1_func, 737, 1, 2 }, - { ahd_patch0_func, 738, 1, 1 }, - { ahd_patch17_func, 740, 1, 2 }, - { ahd_patch0_func, 741, 2, 1 }, - { ahd_patch18_func, 744, 4, 2 }, - { ahd_patch0_func, 748, 1, 1 }, - { ahd_patch18_func, 754, 11, 1 } + { ahd_patch2_func, 562, 1, 2 }, + { ahd_patch0_func, 563, 1, 1 }, + { ahd_patch2_func, 567, 1, 2 }, + { ahd_patch0_func, 568, 1, 1 }, + { ahd_patch1_func, 569, 1, 2 }, + { ahd_patch0_func, 570, 1, 1 }, + { ahd_patch2_func, 581, 1, 2 }, + { ahd_patch0_func, 582, 1, 1 }, + { ahd_patch16_func, 586, 1, 1 }, + { ahd_patch17_func, 591, 1, 1 }, + { ahd_patch18_func, 592, 2, 1 }, + { ahd_patch17_func, 596, 1, 2 }, + { ahd_patch0_func, 597, 1, 1 }, + { ahd_patch2_func, 600, 1, 2 }, + { ahd_patch0_func, 601, 1, 1 }, + { ahd_patch2_func, 619, 1, 2 }, + { ahd_patch0_func, 620, 1, 1 }, + { ahd_patch19_func, 621, 12, 1 }, + { ahd_patch1_func, 637, 1, 2 }, + { ahd_patch0_func, 638, 1, 1 }, + { ahd_patch19_func, 639, 1, 1 }, + { ahd_patch1_func, 650, 1, 2 }, + { ahd_patch0_func, 651, 1, 1 }, + { ahd_patch1_func, 658, 1, 2 }, + { ahd_patch0_func, 659, 1, 1 }, + { ahd_patch16_func, 683, 1, 1 }, + { ahd_patch16_func, 699, 1, 1 }, + { ahd_patch2_func, 711, 1, 2 }, + { ahd_patch0_func, 712, 1, 1 }, + { ahd_patch16_func, 731, 1, 1 }, + { ahd_patch1_func, 739, 1, 2 }, + { ahd_patch0_func, 740, 1, 1 }, + { ahd_patch1_func, 761, 1, 2 }, + { ahd_patch0_func, 762, 1, 1 }, + { ahd_patch1_func, 764, 1, 2 }, + { ahd_patch0_func, 765, 1, 1 }, + { ahd_patch1_func, 767, 1, 2 }, + { ahd_patch0_func, 768, 1, 1 }, + { ahd_patch20_func, 770, 1, 2 }, + { ahd_patch0_func, 771, 2, 1 }, + { ahd_patch21_func, 774, 4, 2 }, + { ahd_patch0_func, 778, 1, 1 }, + { ahd_patch21_func, 785, 11, 1 } }; static struct cs { @@ -1066,19 +1126,19 @@ static struct cs { } critical_sections[] = { { 11, 12 }, { 13, 14 }, - { 24, 37 }, - { 38, 51 }, - { 64, 67 }, - { 94, 119 }, - { 120, 151 }, - { 153, 157 }, - { 165, 173 }, - { 196, 245 }, - { 659, 675 }, - { 675, 693 }, - { 698, 704 }, - { 711, 716 }, - { 716, 722 } + { 29, 42 }, + { 43, 56 }, + { 69, 72 }, + { 99, 124 }, + { 125, 156 }, + { 158, 162 }, + { 170, 178 }, + { 201, 250 }, + { 683, 699 }, + { 699, 717 }, + { 722, 728 }, + { 731, 736 }, + { 742, 748 } }; static const int num_critical_sections = sizeof(critical_sections) diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h index b797b01998a2994b8de8cdb2bb58721e1250a0c2..c5fe1dcfa3f2ee8382721d79344ead98d47a00b7 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.h +++ b/drivers/scsi/aic7xxx/aic7xxx.h @@ -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#70 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#74 $ * * $FreeBSD$ */ @@ -365,7 +365,8 @@ typedef enum { AHC_LSCBS_ENABLED = 0x2000000, /* 64Byte SCBs enabled */ 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_DISABLE_PCI_PERR = 0x10000000, + AHC_HAS_TERM_LOGIC = 0x20000000 } ahc_flag; /************************* Hardware SCB Definition ***************************/ @@ -691,7 +692,7 @@ struct ahc_tmode_lstate; #define AHC_WIDTH_UNKNOWN 0xFF #define AHC_PERIOD_UNKNOWN 0xFF -#define AHC_OFFSET_UNKNOWN 0x0 +#define AHC_OFFSET_UNKNOWN 0xFF #define AHC_PPR_OPTS_UNKNOWN 0xFF /* @@ -877,31 +878,39 @@ typedef enum { /*********************** Software Configuration Structure *********************/ TAILQ_HEAD(scb_tailq, scb); -struct ahc_suspend_channel_state { - uint8_t scsiseq; - uint8_t sxfrctl0; - uint8_t sxfrctl1; - uint8_t simode0; - uint8_t simode1; - uint8_t seltimer; - uint8_t seqctl; +struct ahc_aic7770_softc { + /* + * Saved register state used for chip_init(). + */ + uint8_t busspd; + uint8_t bustime; +}; + +struct ahc_pci_softc { + /* + * Saved register state used for chip_init(). + */ + uint32_t devconfig; + uint16_t targcrccnt; + uint8_t command; + uint8_t csize_lattime; + uint8_t optionmode; + uint8_t crccontrol1; + uint8_t dscommand0; + uint8_t dspcistatus; + uint8_t scbbaddr; + uint8_t dff_thrsh; }; -struct ahc_suspend_state { - struct ahc_suspend_channel_state channel[2]; - uint8_t optionmode; - uint8_t dscommand0; - uint8_t dspcistatus; - /* hsmailbox */ - uint8_t crccontrol1; - uint8_t scbbaddr; - /* Host and sequencer SCB counts */ - uint8_t dff_thrsh; - uint8_t *scratch_ram; - uint8_t *btt; +union ahc_bus_softc { + struct ahc_aic7770_softc aic7770_softc; + struct ahc_pci_softc pci_softc; }; typedef void (*ahc_bus_intr_t)(struct ahc_softc *); +typedef int (*ahc_bus_chip_init_t)(struct ahc_softc *); +typedef int (*ahc_bus_suspend_t)(struct ahc_softc *); +typedef int (*ahc_bus_resume_t)(struct ahc_softc *); typedef void ahc_callback_t (void *); struct ahc_softc { @@ -936,6 +945,11 @@ struct ahc_softc { */ struct scb_tailq untagged_queues[AHC_NUM_TARGETS]; + /* + * Bus attachment specific data. + */ + union ahc_bus_softc bus_softc; + /* * Platform specific data. */ @@ -951,6 +965,22 @@ struct ahc_softc { */ ahc_bus_intr_t bus_intr; + /* + * Bus specific initialization required + * after a chip reset. + */ + ahc_bus_chip_init_t bus_chip_init; + + /* + * Bus specific suspend routine. + */ + ahc_bus_suspend_t bus_suspend; + + /* + * Bus specific resume routine. + */ + ahc_bus_resume_t bus_resume; + /* * Target mode related state kept on a per enabled lun basis. * Targets that are not enabled will have null entries. @@ -1043,9 +1073,6 @@ struct ahc_softc { */ bus_addr_t dma_bug_buf; - /* Information saved through suspend/resume cycles */ - struct ahc_suspend_state suspend_state; - /* Number of enabled target mode device on this card */ u_int enabled_luns; @@ -1055,7 +1082,8 @@ struct ahc_softc { /* PCI cacheline size. */ u_int pci_cachesize; - u_int stack_size; + /* Maximum number of sequencer instructions supported. */ + u_int instruction_ram_size; /* Per-Unit descriptive information */ const char *description; @@ -1152,6 +1180,7 @@ int ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, struct ahc_softc *ahc_alloc(void *platform_arg, char *name); int ahc_softc_init(struct ahc_softc *); void ahc_controller_info(struct ahc_softc *ahc, char *buf); +int ahc_chip_init(struct ahc_softc *ahc); int ahc_init(struct ahc_softc *ahc); void ahc_intr_enable(struct ahc_softc *ahc, int enable); void ahc_pause_and_flushwork(struct ahc_softc *ahc); @@ -1167,7 +1196,6 @@ int ahc_reset(struct ahc_softc *ahc); void ahc_shutdown(void *arg); /*************************** Interrupt Services *******************************/ -void ahc_pci_intr(struct ahc_softc *ahc); void ahc_clear_intstat(struct ahc_softc *ahc); void ahc_run_qoutfifo(struct ahc_softc *ahc); #ifdef AHC_TARGET_MODE diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg index 7dc8f6d9ab69e1f8abd65588001887d2dba9dfdc..49bc1f2b37cc0c049eda6c6fb141c8bad0d1ea7c 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.reg +++ b/drivers/scsi/aic7xxx/aic7xxx.reg @@ -39,7 +39,7 @@ * * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#37 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -1580,7 +1580,7 @@ const BUS_32_BIT 0x02 const MAX_OFFSET_8BIT 0x0f const MAX_OFFSET_16BIT 0x08 const MAX_OFFSET_ULTRA2 0x7f -const MAX_OFFSET 0xff +const MAX_OFFSET 0x7f const HOST_MSG 0xff /* Target mode command processing constants */ diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index 0eedbbae0200e7f5c6b9c4217c224dafae667ce8..507fda5a9662ef6a1debcf06b944d92748735061 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -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.c#112 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#124 $ * * $FreeBSD$ */ @@ -144,7 +144,8 @@ static struct ahc_syncrate ahc_syncrates[] = #include "aic7xxx_seq.h" /**************************** Function Declarations ***************************/ -static void ahc_force_renegotiation(struct ahc_softc *ahc); +static void ahc_force_renegotiation(struct ahc_softc *ahc, + struct ahc_devinfo *devinfo); static struct ahc_tmode_tstate* ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel); @@ -224,7 +225,7 @@ static void ahc_reset_current_bus(struct ahc_softc *ahc); #ifdef AHC_DUMP_SEQ static void ahc_dumpseq(struct ahc_softc *ahc); #endif -static void ahc_loadseq(struct ahc_softc *ahc); +static int ahc_loadseq(struct ahc_softc *ahc); static int ahc_check_patch(struct ahc_softc *ahc, struct patch **start_patch, u_int start_instr, u_int *skip_addr); @@ -1032,14 +1033,15 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) * we should look at the last phase the sequencer recorded, * or the current phase presented on the bus. */ - u_int mesg_out; - u_int curphase; - u_int errorphase; - u_int lastphase; - u_int scsirate; - u_int i; - u_int sstat2; - int silent; + struct ahc_devinfo devinfo; + u_int mesg_out; + u_int curphase; + u_int errorphase; + u_int lastphase; + u_int scsirate; + u_int i; + u_int sstat2; + int silent; lastphase = ahc_inb(ahc, LASTPHASE); curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; @@ -1128,7 +1130,9 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) * case we are out of sync for some external reason * unknown (or unreported) by the target. */ - ahc_force_renegotiation(ahc); + ahc_fetch_devinfo(ahc, &devinfo); + ahc_force_renegotiation(ahc, &devinfo); + ahc_outb(ahc, CLRINT, CLRSCSIINT); ahc_unpause(ahc); } else if ((status & SELTO) != 0) { @@ -1165,6 +1169,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) ahc_name(ahc), scbptr, scb_index); ahc_dump_card_state(ahc); } else { + struct ahc_devinfo devinfo; #ifdef AHC_DEBUG if ((ahc_debug & AHC_SHOW_SELTO) != 0) { ahc_print_path(ahc, scb); @@ -1181,7 +1186,8 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) * a unit attention in this case, so we must always * renegotiate. */ - ahc_force_renegotiation(ahc); + ahc_scb_devinfo(ahc, &devinfo, scb); + ahc_force_renegotiation(ahc, &devinfo); ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); ahc_freeze_devq(ahc, scb); } @@ -1189,13 +1195,14 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) ahc_restart(ahc); } else if ((status & BUSFREE) != 0 && (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) { - u_int lastphase; - u_int saved_scsiid; - u_int saved_lun; - u_int target; - u_int initiator_role_id; - char channel; - int printerror; + struct ahc_devinfo devinfo; + u_int lastphase; + u_int saved_scsiid; + u_int saved_lun; + u_int target; + u_int initiator_role_id; + char channel; + int printerror; /* * Clear our selection hardware as soon as possible. @@ -1227,13 +1234,13 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) target = SCSIID_TARGET(ahc, saved_scsiid); initiator_role_id = SCSIID_OUR_ID(saved_scsiid); channel = SCSIID_CHANNEL(ahc, saved_scsiid); + ahc_compile_devinfo(&devinfo, initiator_role_id, + target, saved_lun, channel, ROLE_INITIATOR); printerror = 1; if (lastphase == P_MESGOUT) { - struct ahc_devinfo devinfo; u_int tag; - ahc_fetch_devinfo(ahc, &devinfo); tag = SCB_LIST_NULL; if (ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT_TAG, TRUE) || ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT, TRUE)) { @@ -1344,13 +1351,15 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) if (lastphase == ahc_phase_table[i].phase) break; } - /* - * Renegotiate with this device at the - * next oportunity just in case this busfree - * is due to a negotiation mismatch with the - * device. - */ - ahc_force_renegotiation(ahc); + if (lastphase != P_BUSFREE) { + /* + * Renegotiate with this device at the + * next oportunity just in case this busfree + * is due to a negotiation mismatch with the + * device. + */ + ahc_force_renegotiation(ahc, &devinfo); + } printf("Unexpected busfree %s\n" "SEQADDR == 0x%x\n", ahc_phase_table[i].phasemsg, @@ -1371,19 +1380,17 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) * a command to the current device. */ static void -ahc_force_renegotiation(struct ahc_softc *ahc) +ahc_force_renegotiation(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) { - struct ahc_devinfo devinfo; struct ahc_initiator_tinfo *targ_info; struct ahc_tmode_tstate *tstate; - ahc_fetch_devinfo(ahc, &devinfo); targ_info = ahc_fetch_transinfo(ahc, - devinfo.channel, - devinfo.our_scsiid, - devinfo.target, + devinfo->channel, + devinfo->our_scsiid, + devinfo->target, &tstate); - ahc_update_neg_request(ahc, &devinfo, tstate, + ahc_update_neg_request(ahc, devinfo, tstate, targ_info, AHC_NEG_IF_NON_ASYNC); } @@ -3898,7 +3905,7 @@ ahc_softc_insert(struct ahc_softc *ahc) */ list_ahc = TAILQ_FIRST(&ahc_tailq); while (list_ahc != NULL - && ahc_softc_comp(list_ahc, ahc) <= 0) + && ahc_softc_comp(ahc, list_ahc) <= 0) list_ahc = TAILQ_NEXT(list_ahc, links); if (list_ahc != NULL) TAILQ_INSERT_BEFORE(list_ahc, ahc, links); @@ -4038,6 +4045,7 @@ ahc_reset(struct ahc_softc *ahc) { u_int sblkctl; u_int sxfrctl1_a, sxfrctl1_b; + int error; int wait; /* @@ -4128,12 +4136,19 @@ ahc_reset(struct ahc_softc *ahc) } ahc_outb(ahc, SXFRCTL1, sxfrctl1_a); + error = 0; + if (ahc->init_level > 0) + /* + * If a recovery action has forced a chip reset, + * re-initialize the chip to our liking. + */ + error = ahc->bus_chip_init(ahc); #ifdef AHC_DUMP_SEQ - if (ahc->init_level == 0) + else ahc_dumpseq(ahc); #endif - return (0); + return (error); } /* @@ -4203,6 +4218,14 @@ ahc_build_free_scb_list(struct ahc_softc *ahc) ahc_outb(ahc, SCB_LUN, 0xFF); } + if ((ahc->flags & AHC_PAGESCBS) != 0) { + /* SCB 0 heads the free list. */ + ahc_outb(ahc, FREE_SCBH, 0); + } else { + /* No free list. */ + ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL); + } + /* Make sure that the last SCB terminates the free list */ ahc_outb(ahc, SCBPTR, i-1); ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); @@ -4228,20 +4251,11 @@ ahc_init_scbdata(struct ahc_softc *ahc) /* Determine the number of hardware SCBs and initialize them */ scb_data->maxhscbs = ahc_probe_scbs(ahc); - if ((ahc->flags & AHC_PAGESCBS) != 0) { - /* SCB 0 heads the free list */ - ahc_outb(ahc, FREE_SCBH, 0); - } else { - ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL); - } - if (ahc->scb_data->maxhscbs == 0) { printf("%s: No SCB space found\n", ahc_name(ahc)); return (ENXIO); } - ahc_build_free_scb_list(ahc); - /* * Create our DMA tags. These tags define the kinds of device * accessible memory allocations and memory mappings we will @@ -4343,10 +4357,9 @@ ahc_init_scbdata(struct ahc_softc *ahc) } /* - * Tell the sequencer which SCB will be the next one it receives. + * Reserve the next queued SCB. */ ahc->next_queued_scb = ahc_get_scb(ahc); - ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag); /* * Note that we were successfull @@ -4531,6 +4544,192 @@ ahc_controller_info(struct ahc_softc *ahc, char *buf) sprintf(buf, "%d SCBs", ahc->scb_data->maxhscbs); } +int +ahc_chip_init(struct ahc_softc *ahc) +{ + int term; + int error; + u_int i; + u_int scsi_conf; + u_int scsiseq_template; + uint32_t physaddr; + + ahc_outb(ahc, SEQ_FLAGS, 0); + ahc_outb(ahc, SEQ_FLAGS2, 0); + + /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/ + if (ahc->features & AHC_TWIN) { + + /* + * Setup Channel B first. + */ + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB); + term = (ahc->flags & AHC_TERM_ENB_B) != 0 ? STPWEN : 0; + ahc_outb(ahc, SCSIID, ahc->our_id_b); + scsi_conf = ahc_inb(ahc, SCSICONF + 1); + ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) + |term|ahc->seltime_b|ENSTIMER|ACTNEGEN); + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR); + ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); + ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); + + /* Select Channel A */ + ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); + } + term = (ahc->flags & AHC_TERM_ENB_A) != 0 ? STPWEN : 0; + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id); + else + ahc_outb(ahc, SCSIID, ahc->our_id); + scsi_conf = ahc_inb(ahc, SCSICONF); + ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) + |term|ahc->seltime + |ENSTIMER|ACTNEGEN); + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR); + ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); + ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); + + /* There are no untagged SCBs active yet. */ + for (i = 0; i < 16; i++) { + ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, 0)); + if ((ahc->flags & AHC_SCB_BTT) != 0) { + int lun; + + /* + * The SCB based BTT allows an entry per + * target and lun pair. + */ + for (lun = 1; lun < AHC_NUM_LUNS; lun++) + ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, lun)); + } + } + + /* All of our queues are empty */ + for (i = 0; i < 256; i++) + ahc->qoutfifo[i] = SCB_LIST_NULL; + ahc_sync_qoutfifo(ahc, BUS_DMASYNC_PREREAD); + + for (i = 0; i < 256; i++) + ahc->qinfifo[i] = SCB_LIST_NULL; + + if ((ahc->features & AHC_MULTI_TID) != 0) { + ahc_outb(ahc, TARGID, 0); + ahc_outb(ahc, TARGID + 1, 0); + } + + /* + * Tell the sequencer where it can find our arrays in memory. + */ + physaddr = ahc->scb_data->hscb_busaddr; + ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF); + ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF); + ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF); + ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF); + + physaddr = ahc->shared_data_busaddr; + ahc_outb(ahc, SHARED_DATA_ADDR, physaddr & 0xFF); + ahc_outb(ahc, SHARED_DATA_ADDR + 1, (physaddr >> 8) & 0xFF); + ahc_outb(ahc, SHARED_DATA_ADDR + 2, (physaddr >> 16) & 0xFF); + ahc_outb(ahc, SHARED_DATA_ADDR + 3, (physaddr >> 24) & 0xFF); + + /* + * Initialize the group code to command length table. + * This overrides the values in TARG_SCSIRATE, so only + * setup the table after we have processed that information. + */ + ahc_outb(ahc, CMDSIZE_TABLE, 5); + ahc_outb(ahc, CMDSIZE_TABLE + 1, 9); + ahc_outb(ahc, CMDSIZE_TABLE + 2, 9); + ahc_outb(ahc, CMDSIZE_TABLE + 3, 0); + ahc_outb(ahc, CMDSIZE_TABLE + 4, 15); + ahc_outb(ahc, CMDSIZE_TABLE + 5, 11); + ahc_outb(ahc, CMDSIZE_TABLE + 6, 0); + ahc_outb(ahc, CMDSIZE_TABLE + 7, 0); + + if ((ahc->features & AHC_HS_MAILBOX) != 0) + ahc_outb(ahc, HS_MAILBOX, 0); + + /* Tell the sequencer of our initial queue positions */ + if ((ahc->features & AHC_TARGETMODE) != 0) { + ahc->tqinfifonext = 1; + ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1); + ahc_outb(ahc, TQINPOS, ahc->tqinfifonext); + } + ahc->qinfifonext = 0; + ahc->qoutfifonext = 0; + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + ahc_outb(ahc, QOFF_CTLSTA, SCB_QSIZE_256); + ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); + ahc_outb(ahc, SNSCB_QOFF, ahc->qinfifonext); + ahc_outb(ahc, SDSCB_QOFF, 0); + } else { + ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); + ahc_outb(ahc, QINPOS, ahc->qinfifonext); + ahc_outb(ahc, QOUTPOS, ahc->qoutfifonext); + } + + /* We don't have any waiting selections */ + ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL); + + /* Our disconnection list is empty too */ + ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL); + + /* Message out buffer starts empty */ + ahc_outb(ahc, MSG_OUT, MSG_NOOP); + + /* + * Setup the allowed SCSI Sequences based on operational mode. + * If we are a target, we'll enalbe select in operations once + * we've had a lun enabled. + */ + scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP; + if ((ahc->flags & AHC_INITIATORROLE) != 0) + scsiseq_template |= ENRSELI; + ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template); + + /* Initialize our list of free SCBs. */ + ahc_build_free_scb_list(ahc); + + /* + * Tell the sequencer which SCB will be the next one it receives. + */ + ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag); + + /* + * Load the Sequencer program and Enable the adapter + * in "fast" mode. + */ + if (bootverbose) + printf("%s: Downloading Sequencer Program...", + ahc_name(ahc)); + + error = ahc_loadseq(ahc); + if (error != 0) + return (error); + + if ((ahc->features & AHC_ULTRA2) != 0) { + int wait; + + /* + * Wait for up to 500ms for our transceivers + * to settle. If the adapter does not have + * a cable attached, the transceivers may + * 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); + } + + return (0); +} + /* * Start the board, ready for normal operation */ @@ -4538,15 +4737,12 @@ int ahc_init(struct ahc_softc *ahc) { int max_targ; - int i; - int term; + u_int i; u_int scsi_conf; - u_int scsiseq_template; u_int ultraenb; u_int discenable; u_int tagenable; size_t driver_data_size; - uint32_t physaddr; #ifdef AHC_DEBUG if ((ahc_debug & AHC_DEBUG_SEQUENCER) != 0) @@ -4600,7 +4796,9 @@ ahc_init(struct ahc_softc *ahc) /* DMA tag for mapping buffers into device visible space. */ if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR, + /*lowaddr*/ahc->flags & AHC_39BIT_ADDRESSING + ? (bus_addr_t)0x7FFFFFFFFFULL + : BUS_SPACE_MAXADDR_32BIT, /*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL, /*maxsize*/(AHC_NSEG - 1) * PAGE_SIZE, @@ -4664,9 +4862,6 @@ ahc_init(struct ahc_softc *ahc) for (i = 0; i < AHC_TMODE_CMDS; i++) ahc->targetcmds[i].cmd_valid = 0; ahc_sync_tqinfifo(ahc, BUS_DMASYNC_PREREAD); - ahc->tqinfifonext = 1; - ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1); - ahc_outb(ahc, TQINPOS, ahc->tqinfifonext); ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256]; } ahc->qinfifo = &ahc->qoutfifo[256]; @@ -4697,9 +4892,6 @@ ahc_init(struct ahc_softc *ahc) } } - ahc_outb(ahc, SEQ_FLAGS, 0); - ahc_outb(ahc, SEQ_FLAGS2, 0); - if (ahc->scb_data->maxhscbs < AHC_SCB_MAX_ALLOC) { ahc->flags |= AHC_PAGESCBS; } else { @@ -4708,62 +4900,31 @@ ahc_init(struct ahc_softc *ahc) #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_MISC) { - printf("%s: hardware scb %Zu bytes; kernel scb %Zu bytes; " - "ahc_dma %Zu bytes\n", + printf("%s: hardware scb %u bytes; kernel scb %u bytes; " + "ahc_dma %u bytes\n", ahc_name(ahc), - sizeof(struct hardware_scb), - sizeof(struct scb), - sizeof(struct ahc_dma_seg)); + (u_int)sizeof(struct hardware_scb), + (u_int)sizeof(struct scb), + (u_int)sizeof(struct ahc_dma_seg)); } #endif /* AHC_DEBUG */ - /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/ + /* + * Look at the information that board initialization or + * the board bios has left us. + */ if (ahc->features & AHC_TWIN) { - - /* - * The device is gated to channel B after a chip reset, - * so set those values first - */ - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB); - term = (ahc->flags & AHC_TERM_ENB_B) != 0 ? STPWEN : 0; - ahc_outb(ahc, SCSIID, ahc->our_id_b); scsi_conf = ahc_inb(ahc, SCSICONF + 1); - ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) - |term|ahc->seltime_b|ENSTIMER|ACTNEGEN); - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR); - ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); - ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); - if ((scsi_conf & RESET_SCSI) != 0 && (ahc->flags & AHC_INITIATORROLE) != 0) ahc->flags |= AHC_RESET_BUS_B; - - /* Select Channel A */ - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); } - term = (ahc->flags & AHC_TERM_ENB_A) != 0 ? STPWEN : 0; - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id); - else - ahc_outb(ahc, SCSIID, ahc->our_id); - scsi_conf = ahc_inb(ahc, SCSICONF); - ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) - |term|ahc->seltime - |ENSTIMER|ACTNEGEN); - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR); - ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); - ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); + scsi_conf = ahc_inb(ahc, SCSICONF); if ((scsi_conf & RESET_SCSI) != 0 && (ahc->flags & AHC_INITIATORROLE) != 0) ahc->flags |= AHC_RESET_BUS_A; - /* - * Look at the information that board initialization or - * the board bios has left us. - */ ultraenb = 0; tagenable = ALL_TARGETS_MASK; @@ -4815,7 +4976,7 @@ ahc_init(struct ahc_softc *ahc) * connection type we have with the target. */ tinfo->user.period = ahc_syncrates->period; - tinfo->user.offset = ~0; + tinfo->user.offset = MAX_OFFSET; } else { u_int scsirate; uint16_t mask; @@ -4850,7 +5011,7 @@ ahc_init(struct ahc_softc *ahc) if (offset == 0) tinfo->user.period = 0; else - tinfo->user.offset = ~0; + tinfo->user.offset = MAX_OFFSET; if ((scsirate & SXFR_ULTRA2) <= 8/*10MHz*/ && (ahc->features & AHC_DT) != 0) tinfo->user.ppr_options = @@ -4868,7 +5029,7 @@ ahc_init(struct ahc_softc *ahc) ? AHC_SYNCRATE_ULTRA : AHC_SYNCRATE_FAST); if (tinfo->user.period != 0) - tinfo->user.offset = ~0; + tinfo->user.offset = MAX_OFFSET; } if (tinfo->user.period == 0) tinfo->user.offset = 0; @@ -4890,127 +5051,7 @@ ahc_init(struct ahc_softc *ahc) ahc->user_discenable = discenable; ahc->user_tagenable = tagenable; - /* There are no untagged SCBs active yet. */ - for (i = 0; i < 16; i++) { - ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, 0)); - if ((ahc->flags & AHC_SCB_BTT) != 0) { - int lun; - - /* - * The SCB based BTT allows an entry per - * target and lun pair. - */ - for (lun = 1; lun < AHC_NUM_LUNS; lun++) - ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, lun)); - } - } - - /* All of our queues are empty */ - for (i = 0; i < 256; i++) - ahc->qoutfifo[i] = SCB_LIST_NULL; - ahc_sync_qoutfifo(ahc, BUS_DMASYNC_PREREAD); - - for (i = 0; i < 256; i++) - ahc->qinfifo[i] = SCB_LIST_NULL; - - if ((ahc->features & AHC_MULTI_TID) != 0) { - ahc_outb(ahc, TARGID, 0); - ahc_outb(ahc, TARGID + 1, 0); - } - - /* - * Tell the sequencer where it can find our arrays in memory. - */ - physaddr = ahc->scb_data->hscb_busaddr; - ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF); - ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF); - ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF); - ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF); - - physaddr = ahc->shared_data_busaddr; - ahc_outb(ahc, SHARED_DATA_ADDR, physaddr & 0xFF); - ahc_outb(ahc, SHARED_DATA_ADDR + 1, (physaddr >> 8) & 0xFF); - ahc_outb(ahc, SHARED_DATA_ADDR + 2, (physaddr >> 16) & 0xFF); - ahc_outb(ahc, SHARED_DATA_ADDR + 3, (physaddr >> 24) & 0xFF); - - /* - * Initialize the group code to command length table. - * This overrides the values in TARG_SCSIRATE, so only - * setup the table after we have processed that information. - */ - ahc_outb(ahc, CMDSIZE_TABLE, 5); - ahc_outb(ahc, CMDSIZE_TABLE + 1, 9); - ahc_outb(ahc, CMDSIZE_TABLE + 2, 9); - ahc_outb(ahc, CMDSIZE_TABLE + 3, 0); - ahc_outb(ahc, CMDSIZE_TABLE + 4, 15); - ahc_outb(ahc, CMDSIZE_TABLE + 5, 11); - ahc_outb(ahc, CMDSIZE_TABLE + 6, 0); - ahc_outb(ahc, CMDSIZE_TABLE + 7, 0); - - /* Tell the sequencer of our initial queue positions */ - ahc_outb(ahc, KERNEL_QINPOS, 0); - ahc_outb(ahc, QINPOS, 0); - ahc_outb(ahc, QOUTPOS, 0); - - /* - * Use the built in queue management registers - * if they are available. - */ - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - ahc_outb(ahc, QOFF_CTLSTA, SCB_QSIZE_256); - ahc_outb(ahc, SDSCB_QOFF, 0); - ahc_outb(ahc, SNSCB_QOFF, 0); - ahc_outb(ahc, HNSCB_QOFF, 0); - } - - - /* We don't have any waiting selections */ - ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL); - - /* Our disconnection list is empty too */ - ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL); - - /* Message out buffer starts empty */ - ahc_outb(ahc, MSG_OUT, MSG_NOOP); - - /* - * Setup the allowed SCSI Sequences based on operational mode. - * If we are a target, we'll enalbe select in operations once - * we've had a lun enabled. - */ - scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP; - if ((ahc->flags & AHC_INITIATORROLE) != 0) - scsiseq_template |= ENRSELI; - ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template); - - /* - * Load the Sequencer program and Enable the adapter - * in "fast" mode. - */ - if (bootverbose) - printf("%s: Downloading Sequencer Program...", - ahc_name(ahc)); - - ahc_loadseq(ahc); - - if ((ahc->features & AHC_ULTRA2) != 0) { - int wait; - - /* - * Wait for up to 500ms for our transceivers - * to settle. If the adapter does not have - * a cable attached, the transceivers may - * 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); - } - return (0); + return (ahc->bus_chip_init(ahc)); } void @@ -5046,7 +5087,6 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc) maxloops = 1000; ahc->flags |= AHC_ALL_INTERRUPTS; - intstat = 0; paused = FALSE; do { if (paused) @@ -5056,10 +5096,10 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc) paused = TRUE; ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & ~ENSELO); ahc_clear_critical_section(ahc); - if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) - break; + intstat = ahc_inb(ahc, INTSTAT); } while (--maxloops - && (((intstat = ahc_inb(ahc, INTSTAT)) & INT_PEND) != 0 + && (intstat != 0xFF || (ahc->features & AHC_REMOVABLE) == 0) + && ((intstat & INT_PEND) != 0 || (ahc_inb(ahc, SSTAT0) & (SELDO|SELINGO)))); if (maxloops == 0) { printf("Infinite interrupt loop, INTSTAT = %x", @@ -5072,13 +5112,13 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc) int ahc_suspend(struct ahc_softc *ahc) { - uint8_t *ptr; - int i; ahc_pause_and_flushwork(ahc); - if (LIST_FIRST(&ahc->pending_scbs) != NULL) + if (LIST_FIRST(&ahc->pending_scbs) != NULL) { + ahc_unpause(ahc); return (EBUSY); + } #if AHC_TARGET_MODE /* @@ -5086,73 +5126,11 @@ ahc_suspend(struct ahc_softc *ahc) * Perhaps we should just refuse to be suspended if we * are acting in a target role. */ - if (ahc->pending_device != NULL) + if (ahc->pending_device != NULL) { + ahc_unpause(ahc); return (EBUSY); -#endif - - /* Save volatile registers */ - if ((ahc->features & AHC_TWIN) != 0) { - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB); - ahc->suspend_state.channel[1].scsiseq = ahc_inb(ahc, SCSISEQ); - ahc->suspend_state.channel[1].sxfrctl0 = ahc_inb(ahc, SXFRCTL0); - ahc->suspend_state.channel[1].sxfrctl1 = ahc_inb(ahc, SXFRCTL1); - ahc->suspend_state.channel[1].simode0 = ahc_inb(ahc, SIMODE0); - ahc->suspend_state.channel[1].simode1 = ahc_inb(ahc, SIMODE1); - ahc->suspend_state.channel[1].seltimer = ahc_inb(ahc, SELTIMER); - ahc->suspend_state.channel[1].seqctl = ahc_inb(ahc, SEQCTL); - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); - } - ahc->suspend_state.channel[0].scsiseq = ahc_inb(ahc, SCSISEQ); - ahc->suspend_state.channel[0].sxfrctl0 = ahc_inb(ahc, SXFRCTL0); - ahc->suspend_state.channel[0].sxfrctl1 = ahc_inb(ahc, SXFRCTL1); - ahc->suspend_state.channel[0].simode0 = ahc_inb(ahc, SIMODE0); - ahc->suspend_state.channel[0].simode1 = ahc_inb(ahc, SIMODE1); - ahc->suspend_state.channel[0].seltimer = ahc_inb(ahc, SELTIMER); - ahc->suspend_state.channel[0].seqctl = ahc_inb(ahc, SEQCTL); - - if ((ahc->chip & AHC_PCI) != 0) { - ahc->suspend_state.dscommand0 = ahc_inb(ahc, DSCOMMAND0); - ahc->suspend_state.dspcistatus = ahc_inb(ahc, DSPCISTATUS); - } - - if ((ahc->features & AHC_DT) != 0) { - u_int sfunct; - - sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; - ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); - ahc->suspend_state.optionmode = ahc_inb(ahc, OPTIONMODE); - ahc_outb(ahc, SFUNCT, sfunct); - ahc->suspend_state.crccontrol1 = ahc_inb(ahc, CRCCONTROL1); - } - - if ((ahc->features & AHC_MULTI_FUNC) != 0) - ahc->suspend_state.scbbaddr = ahc_inb(ahc, SCBBADDR); - - if ((ahc->features & AHC_ULTRA2) != 0) - ahc->suspend_state.dff_thrsh = ahc_inb(ahc, DFF_THRSH); - - ptr = ahc->suspend_state.scratch_ram; - for (i = 0; i < 64; i++) - *ptr++ = ahc_inb(ahc, SRAM_BASE + i); - - if ((ahc->features & AHC_MORE_SRAM) != 0) { - for (i = 0; i < 16; i++) - *ptr++ = ahc_inb(ahc, TARG_OFFSET + i); - } - - ptr = ahc->suspend_state.btt; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - for (i = 0;i < AHC_NUM_TARGETS; i++) { - int j; - - for (j = 0;j < AHC_NUM_LUNS; j++) { - u_int tcl; - - tcl = BUILD_TCL(i << 4, j); - *ptr = ahc_index_busy_tcl(ahc, tcl); - } - } } +#endif ahc_shutdown(ahc); return (0); } @@ -5160,81 +5138,8 @@ ahc_suspend(struct ahc_softc *ahc) int ahc_resume(struct ahc_softc *ahc) { - uint8_t *ptr; - int i; ahc_reset(ahc); - - ahc_build_free_scb_list(ahc); - - /* Restore volatile registers */ - if ((ahc->features & AHC_TWIN) != 0) { - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB); - ahc_outb(ahc, SCSIID, ahc->our_id); - ahc_outb(ahc, SCSISEQ, ahc->suspend_state.channel[1].scsiseq); - ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.channel[1].sxfrctl0); - ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.channel[1].sxfrctl1); - ahc_outb(ahc, SIMODE0, ahc->suspend_state.channel[1].simode0); - ahc_outb(ahc, SIMODE1, ahc->suspend_state.channel[1].simode1); - ahc_outb(ahc, SELTIMER, ahc->suspend_state.channel[1].seltimer); - ahc_outb(ahc, SEQCTL, ahc->suspend_state.channel[1].seqctl); - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); - } - ahc_outb(ahc, SCSISEQ, ahc->suspend_state.channel[0].scsiseq); - ahc_outb(ahc, SXFRCTL0, ahc->suspend_state.channel[0].sxfrctl0); - ahc_outb(ahc, SXFRCTL1, ahc->suspend_state.channel[0].sxfrctl1); - ahc_outb(ahc, SIMODE0, ahc->suspend_state.channel[0].simode0); - ahc_outb(ahc, SIMODE1, ahc->suspend_state.channel[0].simode1); - ahc_outb(ahc, SELTIMER, ahc->suspend_state.channel[0].seltimer); - ahc_outb(ahc, SEQCTL, ahc->suspend_state.channel[0].seqctl); - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id); - else - ahc_outb(ahc, SCSIID, ahc->our_id); - - if ((ahc->chip & AHC_PCI) != 0) { - ahc_outb(ahc, DSCOMMAND0, ahc->suspend_state.dscommand0); - ahc_outb(ahc, DSPCISTATUS, ahc->suspend_state.dspcistatus); - } - - if ((ahc->features & AHC_DT) != 0) { - u_int sfunct; - - sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; - ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); - ahc_outb(ahc, OPTIONMODE, ahc->suspend_state.optionmode); - ahc_outb(ahc, SFUNCT, sfunct); - ahc_outb(ahc, CRCCONTROL1, ahc->suspend_state.crccontrol1); - } - - if ((ahc->features & AHC_MULTI_FUNC) != 0) - ahc_outb(ahc, SCBBADDR, ahc->suspend_state.scbbaddr); - - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, DFF_THRSH, ahc->suspend_state.dff_thrsh); - - ptr = ahc->suspend_state.scratch_ram; - for (i = 0; i < 64; i++) - ahc_outb(ahc, SRAM_BASE + i, *ptr++); - - if ((ahc->features & AHC_MORE_SRAM) != 0) { - for (i = 0; i < 16; i++) - ahc_outb(ahc, TARG_OFFSET + i, *ptr++); - } - - ptr = ahc->suspend_state.btt; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - for (i = 0;i < AHC_NUM_TARGETS; i++) { - int j; - - for (j = 0;j < AHC_NUM_LUNS; j++) { - u_int tcl; - - tcl = BUILD_TCL(i << 4, j); - ahc_busy_tcl(ahc, tcl, *ptr); - } - } - } return (0); } @@ -6379,19 +6284,11 @@ void ahc_dumpseq(struct ahc_softc* ahc) { int i; - int max_prog; - - if ((ahc->chip & AHC_BUS_MASK) < AHC_PCI) - max_prog = 448; - else if ((ahc->features & AHC_ULTRA2) != 0) - max_prog = 768; - else - max_prog = 512; ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); ahc_outb(ahc, SEQADDR0, 0); ahc_outb(ahc, SEQADDR1, 0); - for (i = 0; i < max_prog; i++) { + for (i = 0; i < ahc->instruction_ram_size; i++) { uint8_t ins_bytes[4]; ahc_insb(ahc, SEQRAM, ins_bytes, 4); @@ -6403,7 +6300,7 @@ ahc_dumpseq(struct ahc_softc* ahc) } #endif -static void +static int ahc_loadseq(struct ahc_softc *ahc) { struct cs cs_table[num_critical_sections]; @@ -6413,9 +6310,9 @@ ahc_loadseq(struct ahc_softc *ahc) u_int cs_count; u_int cur_cs; u_int i; - int downloaded; u_int skip_addr; u_int sg_prefetch_cnt; + int downloaded; uint8_t download_consts[7]; /* @@ -6456,6 +6353,19 @@ ahc_loadseq(struct ahc_softc *ahc) */ continue; } + + if (downloaded == ahc->instruction_ram_size) { + /* + * We're about to exceed the instruction + * storage capacity for this chip. Fail + * the load. + */ + printf("\n%s: Program too large for instruction memory " + "size of %d!\n", ahc_name(ahc), + ahc->instruction_ram_size); + return (ENOMEM); + } + /* * Move through the CS table until we find a CS * that might apply to this instruction. @@ -6498,6 +6408,7 @@ ahc_loadseq(struct ahc_softc *ahc) printf("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n", ahc_name(ahc), ahc->features, ahc->bugs, ahc->flags); } + return (0); } static int @@ -6942,11 +6853,12 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) struct ahc_tmode_lstate *lstate; struct ccb_en_lun *cel; cam_status status; + u_long s; u_int target; u_int lun; u_int target_mask; u_int our_id; - u_long s; + int error; char channel; status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, &lstate, @@ -7023,7 +6935,8 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) */ if ((ahc->flags & AHC_TARGETROLE) == 0 && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { - u_long s; + u_long s; + ahc_flag saved_flags; printf("Configuring Target Mode\n"); ahc_lock(ahc, &s); @@ -7032,11 +6945,28 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) ahc_unlock(ahc, &s); return; } + saved_flags = ahc->flags; ahc->flags |= AHC_TARGETROLE; if ((ahc->features & AHC_MULTIROLE) == 0) ahc->flags &= ~AHC_INITIATORROLE; ahc_pause(ahc); - ahc_loadseq(ahc); + error = ahc_loadseq(ahc); + if (error != 0) { + /* + * Restore original configuration and notify + * the caller that we cannot support target mode. + * Since the adapter started out in this + * configuration, the firmware load will succeed, + * so there is no point in checking ahc_loadseq's + * return value. + */ + ahc->flags = saved_flags; + (void)ahc_loadseq(ahc); + ahc_unpause(ahc); + ahc_unlock(ahc, &s); + ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; + return; + } ahc_unlock(ahc, &s); } cel = &ccb->cel; @@ -7272,7 +7202,11 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) ahc->flags &= ~AHC_TARGETROLE; ahc->flags |= AHC_INITIATORROLE; ahc_pause(ahc); - ahc_loadseq(ahc); + /* + * Returning to a configuration that + * fit previously will always succeed. + */ + (void)ahc_loadseq(ahc); } } ahc_unpause(ahc); diff --git a/drivers/scsi/aic7xxx/aic7xxx_inline.h b/drivers/scsi/aic7xxx/aic7xxx_inline.h index c38b0cb97d360f369c2af121ade53e3355e30e68..f0fe05c23349744894e5f020861744026a9c3983 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_inline.h +++ b/drivers/scsi/aic7xxx/aic7xxx_inline.h @@ -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#39 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#40 $ * * $FreeBSD$ */ diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 2e32a59cbf700d6dfe34e917c241a1d5ffb57f9f..4c5389c237e8bf6d5d40aa8b448d40f8b54156e7 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -1,7 +1,7 @@ /* * Adaptec AIC7xxx device driver for Linux. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#179 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#206 $ * * Copyright (c) 1994 John Aycock * The University of Calgary Department of Computer Science. @@ -488,12 +488,11 @@ MODULE_PARM_DESC(aic7xxx, " (0/256ms,1/128ms,2/64ms,3/32ms)\n" "\n" " Sample /etc/modules.conf line:\n" -" Enable verbose logging\n" -" Disable EISA/VLB probing\n" +" Toggle EISA/VLB probing\n" " Set tag depth on Controller 1/Target 2 to 10 tags\n" " Shorten the selection timeout to 128ms\n" "\n" -" options aic7xxx='\"verbose.no_probe.tag_info:{{}.{..10}}.seltime:1\"'\n" +" options aic7xxx 'aic7xxx=no_probe.tag_info:{{}.{..10}}.seltime:1'\n" ); #endif @@ -513,6 +512,7 @@ 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, @@ -565,9 +565,9 @@ 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*); -static void ahc_linux_setup_tag_info(char *p, char *end, char *s); static void ahc_linux_setup_tag_info_global(char *p); -static void ahc_linux_setup_dv(char *p, char *end, char *s); +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); @@ -620,6 +620,9 @@ ahc_schedule_completeq(struct ahc_softc *ahc, struct ahc_cmd *acmd) } } +/* + * Must be called with our lock held. + */ static __inline void ahc_schedule_runq(struct ahc_softc *ahc) { @@ -666,8 +669,8 @@ ahc_linux_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd) u_long done_flags; int with_errors; - ahc_done_lock(ahc, &done_flags); with_errors = 0; + ahc_done_lock(ahc, &done_flags); while (acmd != NULL) { Scsi_Cmnd *cmd; @@ -995,9 +998,13 @@ ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) 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); + ahc_linux_queue_cmd_complete(ahc, cmd); + ahc_schedule_completeq(ahc, NULL); ahc_midlayer_entrypoint_unlock(ahc, &flags); - printf("aic7xxx_linux_queue: Unable to allocate device!\n"); - return (-ENOMEM); + printf("%s: aic7xxx_linux_queue - Unable to allocate device!\n", + ahc_name(ahc)); + return (0); } cmd->result = CAM_REQ_INPROG << 16; TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe); @@ -1094,7 +1101,7 @@ ahc_linux_select_queue_depth(struct Scsi_Host * host, u_long flags; ahc = *((struct ahc_softc **)host->hostdata); - ahc_midlayer_entrypoint_lock(ahc, &flags); + ahc_lock(ahc, &flags); for (device = scsi_devs; device != NULL; device = device->next) { if (device->host == host) { struct ahc_linux_device *dev; @@ -1127,7 +1134,7 @@ ahc_linux_select_queue_depth(struct Scsi_Host * host, } } } - ahc_midlayer_entrypoint_unlock(ahc, &flags); + ahc_unlock(ahc, &flags); } #endif @@ -1238,30 +1245,23 @@ ahc_linux_bus_reset(Scsi_Cmnd *cmd) int found; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_unlock_irq(&io_request_lock); -#endif ahc_midlayer_entrypoint_lock(ahc, &s); found = ahc_reset_channel(ahc, cmd->device->channel + 'A', /*initiate reset*/TRUE); acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); - ahc_midlayer_entrypoint_unlock(ahc, &s); - if (bootverbose) - printf("%s: SCSI bus reset delivered. " - "%d SCBs aborted.\n", ahc_name(ahc), found); if (acmd != NULL) { acmd = ahc_linux_run_complete_queue(ahc, acmd); - if (acmd != NULL) { - ahc_midlayer_entrypoint_lock(ahc, &s); + if (acmd != NULL) ahc_schedule_completeq(ahc, acmd); - ahc_midlayer_entrypoint_unlock(ahc, &s); - } } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_lock_irq(&io_request_lock); -#endif + ahc_midlayer_entrypoint_unlock(ahc, &s); + + if (bootverbose) + printf("%s: SCSI bus reset delivered. " + "%d SCBs aborted.\n", ahc_name(ahc), found); + return SUCCESS; } @@ -1291,7 +1291,7 @@ Scsi_Host_Template aic7xxx_driver_template = { .max_sectors = 8192, #endif #if defined CONFIG_HIGHIO || LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) /* Assume RedHat Distribution with its different HIGHIO conventions. */ .can_dma_32 = 1, .single_sg_okay = 1, @@ -1313,15 +1313,25 @@ Scsi_Host_Template aic7xxx_driver_template = { /**************************** 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); @@ -1331,7 +1341,9 @@ ahc_runq_tasklet(unsigned long data) ahc_unlock(ahc, &flags); ahc_lock(ahc, &flags); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) ahc_unlock(ahc, &flags); +#endif } /************************ Shutdown/halt/reboot hook ***************************/ @@ -1495,6 +1507,12 @@ ahc_dmamap_unload(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map) } /********************* Platform Dependent Functions ***************************/ +/* + * Compare "left hand" softc with "right hand" softc, returning: + * < 0 - lahc has a lower priority than rahc + * 0 - Softcs are equal + * > 0 - lahc has a higher priority than rahc + */ int ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc) { @@ -1513,7 +1531,7 @@ ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc) - (rahc->flags & AHC_BIOS_ENABLED); if (value != 0) /* Controllers with BIOS enabled have a *higher* priority */ - return (-value); + return (value); /* * Same BIOS setting, now sort based on bus type. @@ -1526,7 +1544,7 @@ ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc) lvalue = (lahc->chip & AHC_BUS_MASK); if (lvalue == AHC_VL) lvalue = AHC_EISA; - value = lvalue - rvalue; + value = rvalue - lvalue; if (value != 0) return (value); @@ -1537,40 +1555,40 @@ ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc) char primary_channel; if (aic7xxx_reverse_scan != 0) - value = ahc_get_pci_bus(rahc->dev_softc) - - ahc_get_pci_bus(lahc->dev_softc); - else value = ahc_get_pci_bus(lahc->dev_softc) - ahc_get_pci_bus(rahc->dev_softc); + else + value = ahc_get_pci_bus(rahc->dev_softc) + - ahc_get_pci_bus(lahc->dev_softc); if (value != 0) break; if (aic7xxx_reverse_scan != 0) - value = ahc_get_pci_slot(rahc->dev_softc) - - ahc_get_pci_slot(lahc->dev_softc); - else value = ahc_get_pci_slot(lahc->dev_softc) - ahc_get_pci_slot(rahc->dev_softc); + else + value = ahc_get_pci_slot(rahc->dev_softc) + - ahc_get_pci_slot(lahc->dev_softc); if (value != 0) break; /* * On multi-function devices, the user can choose * to have function 1 probed before function 0. * Give whichever channel is the primary channel - * the lowest priority. + * the highest priority. */ primary_channel = (lahc->flags & AHC_PRIMARY_CHANNEL) + 'A'; - value = 1; + value = -1; if (lahc->channel == primary_channel) - value = -1; + value = 1; break; } case AHC_EISA: if ((rahc->flags & AHC_BIOS_ENABLED) != 0) { - value = lahc->platform_data->bios_address - - rahc->platform_data->bios_address; + value = rahc->platform_data->bios_address + - lahc->platform_data->bios_address; } else { - value = lahc->bsh.ioport - - rahc->bsh.ioport; + value = rahc->bsh.ioport + - lahc->bsh.ioport; } break; default: @@ -1579,90 +1597,6 @@ ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc) return (value); } -static void -ahc_linux_setup_tag_info(char *p, char *end, char *s) -{ - char *base; - char *tok; - char *tok_end; - char *tok_end2; - int i; - int instance; - int targ; - int done; - char tok_list[] = {'.', ',', '{', '}', '\0'}; - - if (*p != ':') - return; - - instance = -1; - targ = -1; - done = FALSE; - base = p; - /* Forward us just past the ':' */ - tok = base + 1; - tok_end = strchr(tok, '\0'); - if (tok_end < end) - *tok_end = ','; - while (!done) { - switch (*tok) { - case '{': - if (instance == -1) - instance = 0; - else if (targ == -1) - targ = 0; - tok++; - break; - case '}': - if (targ != -1) - targ = -1; - else if (instance != -1) - instance = -1; - tok++; - break; - case ',': - case '.': - if (instance == -1) - done = TRUE; - else if (targ >= 0) - targ++; - else if (instance >= 0) - instance++; - if ((targ >= AHC_NUM_TARGETS) || - (instance >= NUM_ELEMENTS(aic7xxx_tag_info))) - done = TRUE; - tok++; - if (!done) { - base = tok; - } - break; - case '\0': - done = TRUE; - break; - default: - done = TRUE; - tok_end = strchr(tok, '\0'); - for (i = 0; tok_list[i]; i++) { - tok_end2 = strchr(tok, tok_list[i]); - if ((tok_end2) && (tok_end2 < tok_end)) { - tok_end = tok_end2; - done = FALSE; - } - } - if ((instance >= 0) && (targ >= 0) - && (instance < NUM_ELEMENTS(aic7xxx_tag_info)) - && (targ < AHC_NUM_TARGETS)) { - aic7xxx_tag_info[instance].tag_commands[targ] = - simple_strtoul(tok, NULL, 0) & 0xff; - } - tok = tok_end; - break; - } - } - while ((p != base) && (p != NULL)) - p = strsep(&s, ",."); -} - static void ahc_linux_setup_tag_info_global(char *p) { @@ -1679,77 +1613,28 @@ ahc_linux_setup_tag_info_global(char *p) } static void -ahc_linux_setup_dv(char *p, char *end, char *s) +ahc_linux_setup_tag_info(void *arg, int instance, int targ, int32_t value) { - char *base; - char *tok; - char *tok_end; - char *tok_end2; - int i; - int instance; - int done; - char tok_list[] = {'.', ',', '{', '}', '\0'}; - - if (*p != ':') - return; - instance = -1; - done = FALSE; - base = p; - /* Forward us just past the ':' */ - tok = base + 1; - tok_end = strchr(tok, '\0'); - if (tok_end < end) - *tok_end = ','; - while (!done) { - switch (*tok) { - case '{': - if (instance == -1) - instance = 0; - tok++; - break; - case '}': - if (instance != -1) - instance = -1; - tok++; - break; - case ',': - case '.': - if (instance == -1) - done = TRUE; - else if (instance >= 0) - instance++; - if (instance >= NUM_ELEMENTS(aic7xxx_dv_settings)) - done = TRUE; - tok++; - if (!done) { - base = tok; - } - break; - case '\0': - done = TRUE; - break; - default: - done = TRUE; - tok_end = strchr(tok, '\0'); - for (i = 0; tok_list[i]; i++) { - tok_end2 = strchr(tok, tok_list[i]); - if ((tok_end2) && (tok_end2 < tok_end)) { - tok_end = tok_end2; - done = FALSE; - } - } - if ((instance >= 0) - && (instance < NUM_ELEMENTS(aic7xxx_dv_settings))) { - aic7xxx_dv_settings[instance] = - simple_strtol(tok, NULL, 0); - } - tok = tok_end; - break; - } + if ((instance >= 0) && (targ >= 0) + && (instance < NUM_ELEMENTS(aic7xxx_tag_info)) + && (targ < AHC_NUM_TARGETS)) { + aic7xxx_tag_info[instance].tag_commands[targ] = value & 0xff; + if (bootverbose) + printf("tag_info[%d:%d] = %d\n", instance, targ, value); + } +} + +static void +ahc_linux_setup_dv(void *arg, int instance, int targ, int32_t value) +{ + + if ((instance >= 0) + && (instance < NUM_ELEMENTS(aic7xxx_dv_settings))) { + aic7xxx_dv_settings[instance] = value; + if (bootverbose) + printf("dv[%d] = %d\n", instance, value); } - while ((p != base) && (p != NULL)) - p = strsep(&s, ",."); } /* @@ -1787,30 +1672,38 @@ aic7xxx_setup(char *s) end = strchr(s, '\0'); + /* + * XXX ia64 gcc isn't smart enough to know that NUM_ELEMENTS + * will never be 0 in this case. + */ + n = 0; + while ((p = strsep(&s, ",.")) != NULL) { if (*p == '\0') continue; for (i = 0; i < NUM_ELEMENTS(options); i++) { - n = strlen(options[i].name); - if (strncmp(options[i].name, p, n) != 0) - continue; + n = strlen(options[i].name); + if (strncmp(options[i].name, p, n) == 0) + break; + } + if (i == NUM_ELEMENTS(options)) + continue; - if (!strncmp(p, "global_tag_depth", n)) { - ahc_linux_setup_tag_info_global(p + n); - } else if (!strncmp(p, "tag_info", n)) { - ahc_linux_setup_tag_info(p + n, end, s); - } else if (strncmp(p, "dv", n) == 0) { - ahc_linux_setup_dv(p + n, end, s); - } else if (p[n] == ':') { - *(options[i].flag) = - simple_strtoul(p + n + 1, NULL, 0); - } else if (!strncmp(p, "verbose", n)) { - *(options[i].flag) = 1; - } else { - *(options[i].flag) = ~(*(options[i].flag)); - } - break; + if (strncmp(p, "global_tag_depth", n) == 0) { + ahc_linux_setup_tag_info_global(p + n); + } else if (strncmp(p, "tag_info", n) == 0) { + s = aic_parse_brace_option("tag_info", p + n, end, + 2, ahc_linux_setup_tag_info, NULL); + } else if (strncmp(p, "dv", n) == 0) { + s = aic_parse_brace_option("dv", p + n, end, 1, + ahc_linux_setup_dv, NULL); + } else if (p[n] == ':') { + *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); + } else if (strncmp(p, "verbose", n) == 0) { + *(options[i].flag) = 1; + } else { + *(options[i].flag) = ~(*(options[i].flag)); } } return 1; @@ -1840,6 +1733,8 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) ahc_lock(ahc, &s); #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 + host->lock = &ahc->platform_data->spin_lock; #endif ahc->platform_data->host = host; host->can_queue = AHC_MAX_QUEUE; @@ -1860,7 +1755,7 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) } host->unique_id = ahc->unit; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4) && \ - LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) + LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) scsi_set_pci_device(host, ahc->dev_softc); #endif ahc_linux_initialize_scsi_bus(ahc); @@ -1882,20 +1777,35 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template) * negotiation will occur for the first command, and DV * will comence should that first command be successful. */ - for (target = 0; target < host->max_id*host->max_channel+1; target++) { + for (target = 0; + target < host->max_id * (host->max_channel + 1); target++) { u_int channel; channel = 0; if (target > 7 && (ahc->features & AHC_TWIN) != 0) channel = 1; + /* + * Skip our own ID. Some Compaq/HP storage devices + * have enclosure management devices that respond to + * single bit selection (i.e. selecting ourselves). + * 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 + * for our ID if asked to do so. + */ + if ((channel == 0 && target == ahc->our_id) + || (channel == 1 && target == ahc->our_id_b)) + continue; + ahc_linux_alloc_target(ahc, channel, target); } ahc_intr_enable(ahc, TRUE); ahc_linux_start_dv(ahc); ahc_unlock(ahc, &s); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); #endif return (0); @@ -2053,31 +1963,15 @@ ahc_platform_free(struct ahc_softc *ahc) { struct ahc_linux_target *targ; struct ahc_linux_device *dev; - u_long s; int i, j; if (ahc->platform_data != NULL) { - /* Kill the DV kthread */ - if (ahc->platform_data->dv_pid > 0) { - ahc_lock(ahc, &s); - ahc->platform_data->flags |= AHC_DV_SHUTDOWN; - ahc_unlock(ahc, &s); - up(&ahc->platform_data->dv_sem); - do { -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOW_DV) { - printf("%s: Waiting for DV thread to " - "exit\n", ahc_name(ahc)); - } -#endif - } while (waitpid(ahc->platform_data->dv_pid, NULL, - __WCLONE) == -ERESTARTSYS); - } + ahc_linux_kill_dv_thread(ahc); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) tasklet_kill(&ahc->platform_data->runq_tasklet); #endif if (ahc->platform_data->host != NULL) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_remove_host(ahc->platform_data->host); #endif scsi_unregister(ahc->platform_data->host); @@ -2116,15 +2010,16 @@ ahc_platform_free(struct ahc_softc *ahc) 0x1000); #endif } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) && \ + LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* * In 2.4 we detach from the scsi midlayer before the PCI - * layer invokes our remove callback. + * layer invokes our remove callback. No per-instance + * detach is provided, so we must reach inside the PCI + * subsystem's internals and detach our driver manually. */ if (ahc->dev_softc != NULL) ahc->dev_softc->driver = NULL; -#endif #endif free(ahc->platform_data, M_DEVBUF); } @@ -2153,7 +2048,18 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, if (dev == NULL) return; was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); - now_queuing = alg != AHC_QUEUE_NONE; + switch (alg) { + default: + case AHC_QUEUE_NONE: + now_queuing = 0; + break; + case AHC_QUEUE_BASIC: + now_queuing = AHC_DEV_Q_BASIC; + break; + case AHC_QUEUE_TAGGED: + now_queuing = AHC_DEV_Q_TAGGED; + break; + } if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0 && (was_queuing != now_queuing) && (dev->active != 0)) { @@ -2302,24 +2208,12 @@ ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc) ahc->platform_data->flags &= ~AHC_RUN_CMPLT_Q_TIMER; acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahc_unlock(ahc, &flags); -#endif if (acmd != NULL) { acmd = ahc_linux_run_complete_queue(ahc, acmd); - if (acmd != NULL) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahc_lock(ahc, &flags); -#endif + if (acmd != NULL) ahc_schedule_completeq(ahc, acmd); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahc_unlock(ahc, &flags); -#endif - } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ahc_unlock(ahc, &flags); -#endif } static void @@ -2328,7 +2222,7 @@ ahc_linux_start_dv(struct ahc_softc *ahc) /* * Freeze the simq and signal ahc_linux_queue to not let any - * more commands through + * more commands through. */ if ((ahc->platform_data->flags & AHC_DV_ACTIVE) == 0) { #ifdef AHC_DEBUG @@ -2344,6 +2238,48 @@ ahc_linux_start_dv(struct ahc_softc *ahc) } } +static void +ahc_linux_kill_dv_thread(struct ahc_softc *ahc) +{ + u_long s; + + ahc_lock(ahc, &s); + if (ahc->platform_data->dv_pid != 0) { + ahc->platform_data->flags |= AHC_DV_SHUTDOWN; + ahc_unlock(ahc, &s); + up(&ahc->platform_data->dv_sem); + + /* + * Use the eh_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->eh_sem); + + /* + * 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 ahc_free() in the + * module shutdown case to avoid bogus locking + * in the SCSI mid-layer, but we 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->dv_pid = 0; + } else { + ahc_unlock(ahc, &s); + } +} + static int ahc_linux_dv_thread(void *data) { @@ -2362,7 +2298,17 @@ ahc_linux_dv_thread(void *data) * Complete thread creation. */ lock_kernel(); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) + /* + * Don't care about any signals. + */ + siginitsetinv(¤t->blocked, 0); + + daemonize(); + sprintf(current->comm, "ahc_dv_%d", ahc->unit); +#else daemonize("ahc_dv_%d", ahc->unit); +#endif unlock_kernel(); while (1) { @@ -2376,7 +2322,7 @@ ahc_linux_dv_thread(void *data) ahc_lock(ahc, &s); if ((ahc->platform_data->flags & AHC_DV_SHUTDOWN) != 0) { ahc_unlock(ahc, &s); - return (0); + break; } ahc_unlock(ahc, &s); @@ -2422,7 +2368,7 @@ ahc_linux_dv_thread(void *data) */ ahc_linux_release_simq((u_long)ahc); } - + up(&ahc->platform_data->eh_sem); return (0); } @@ -2528,6 +2474,7 @@ ahc_linux_dv_target(struct ahc_softc *ahc, u_int target_offset) } case AHC_DV_STATE_TUR: case AHC_DV_STATE_BUSY: + timeout = 5 * HZ; ahc_linux_dv_tur(ahc, cmd, &devinfo); break; case AHC_DV_STATE_REBD: @@ -2568,14 +2515,19 @@ ahc_linux_dv_target(struct ahc_softc *ahc, u_int target_offset) /* * In 2.5.X, it is assumed that all calls from the * "midlayer" (which we are emulating) will have the - * ahc host lock held. + * ahc host lock held. For other kernels, the + * io_request_lock must be held. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#if AHC_SCSI_HAS_HOST_LOCK != 0 ahc_lock(ahc, &s); +#else + spin_lock_irqsave(&io_request_lock, s); #endif ahc_linux_queue(cmd, ahc_linux_dv_complete); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#if AHC_SCSI_HAS_HOST_LOCK != 0 ahc_unlock(ahc, &s); +#else + spin_unlock_irqrestore(&io_request_lock, s); #endif down_interruptible(&ahc->platform_data->dv_cmd_sem); /* @@ -3457,7 +3409,6 @@ ahc_linux_dv_timeout(struct scsi_cmnd *cmd) { struct ahc_softc *ahc; struct ahc_cmd *acmd; - struct ahc_linux_device *next_dev; struct scb *scb; u_long flags; @@ -3504,36 +3455,16 @@ ahc_linux_dv_timeout(struct scsi_cmnd *cmd) ahc->platform_data->reset_timer.function = (ahc_linux_callback_t *)ahc_linux_release_simq; add_timer(&ahc->platform_data->reset_timer); - /* - * In 2.5.X, the "done lock" is the ahc_lock. - * Instead of dropping and re-acquiring the same - * lock in the 2.5.X case, just hold our ahc_lock - * the whole time. ahc_done_lock() has been - * made a no-op for 2.5.X too. - */ acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); - next_dev = ahc_linux_next_device_to_run(ahc); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahc_unlock(ahc, &flags); -#endif - if (next_dev) + if (ahc_linux_next_device_to_run(ahc) != NULL) ahc_schedule_runq(ahc); if (acmd != NULL) { acmd = ahc_linux_run_complete_queue(ahc, acmd); - if (acmd != NULL) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahc_lock(ahc, &flags); -#endif + if (acmd != NULL) ahc_schedule_completeq(ahc, acmd); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahc_unlock(ahc, &flags); -#endif - } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ahc_unlock(ahc, &flags); -#endif } static void @@ -3621,17 +3552,17 @@ ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) tags = 0; if ((ahc->user_discenable & devinfo->target_mask) != 0) { - if (warned_user == 0 - && ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) { - - printf("aic7xxx: WARNING, insufficient " - "tag_info instances for installed " - "controllers. Using defaults\n"); - printf("aic7xxx: Please update the " - "aic7xxx_tag_info array in the " - "aic7xxx.c source file.\n"); + if (ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) { + if (warned_user == 0) { + + printf(KERN_WARNING +"aic7xxx: WARNING: Insufficient tag_info instances\n" +"aic7xxx: for installed controllers. Using defaults\n" +"aic7xxx: Please update the aic7xxx_tag_info array in\n" +"aic7xxx: the aic7xxx_osm..c source file.\n"); + warned_user++; + } tags = AHC_MAX_QUEUE; - warned_user++; } else { adapter_tag_info_t *tag_info; @@ -3650,17 +3581,17 @@ ahc_linux_user_dv_setting(struct ahc_softc *ahc) static int warned_user; int dv; - if (warned_user == 0 - && ahc->unit >= NUM_ELEMENTS(aic7xxx_dv_settings)) { + if (ahc->unit >= NUM_ELEMENTS(aic7xxx_dv_settings)) { + if (warned_user == 0) { - printf("aic7xxx: WARNING, insufficient " - "dv settings instances for installed " - "controllers. Using defaults\n"); - printf("aic7xxx: Please update the " - "aic7xxx_dv_settings array in the " - "aic7xxx.c source file.\n"); + printf(KERN_WARNING +"aic7xxx: WARNING: Insufficient dv settings instances\n" +"aic7xxx: for installed controllers. Using defaults\n" +"aic7xxx: Please update the aic7xxx_dv_settings array\n" +"aic7xxx: in the aic7xxx_osm.c source file.\n"); + warned_user++; + } dv = -1; - warned_user++; } else { dv = aic7xxx_dv_settings[ahc->unit]; @@ -3938,41 +3869,20 @@ ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs) struct ahc_softc *ahc; struct ahc_cmd *acmd; u_long flags; - struct ahc_linux_device *next_dev; ahc = (struct ahc_softc *) dev_id; ahc_lock(ahc, &flags); ahc_intr(ahc); acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); - next_dev = ahc_linux_next_device_to_run(ahc); - /* - * In 2.5.X, the "done lock" is the ahc_lock. - * Instead of dropping and re-acquiring the same - * lock in the 2.5.X case, just hold our ahc_lock - * the whole time. ahc_done_lock() has been - * made a no-op for 2.5.X too. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahc_unlock(ahc, &flags); -#endif - if (next_dev) + if (ahc_linux_next_device_to_run(ahc) != NULL) ahc_schedule_runq(ahc); if (acmd != NULL) { acmd = ahc_linux_run_complete_queue(ahc, acmd); - if (acmd != NULL) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahc_lock(ahc, &flags); -#endif + if (acmd != NULL) ahc_schedule_completeq(ahc, acmd); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahc_unlock(ahc, &flags); -#endif - } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ahc_unlock(ahc, &flags); -#endif } void @@ -3995,15 +3905,6 @@ ahc_linux_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target) target_offset = target; if (channel != 0) target_offset += 8; - /* - * Never allow allocation of a target object for - * our own SCSIID. - */ - if ((channel == 0 && target == ahc->our_id) - || (channel == 1 && target == ahc->our_id_b)) { - ahc->platform_data->targets[target_offset] = NULL; - return (NULL); - } targ = malloc(sizeof(*targ), M_DEVBUG, M_NOWAIT); if (targ == NULL) @@ -4274,6 +4175,14 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) #endif ahc_set_transaction_status(scb, CAM_UNCOR_PARITY); } else if (amount_xferred < scb->io_ctx->underflow) { + u_int i; + + ahc_print_path(ahc, scb); + printf("CDB:"); + for (i = 0; i < scb->io_ctx->cmd_len; i++) + printf(" 0x%x", scb->io_ctx->cmnd[i]); + printf("\n"); + ahc_print_path(ahc, scb); printf("Saw underflow (%ld of %ld bytes). " "Treated as error\n", ahc_get_residual(scb), @@ -4456,7 +4365,7 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc, } ahc_set_transaction_status(scb, CAM_REQUEUE_REQ); ahc_set_scsi_status(scb, SCSI_STATUS_OK); - ahc_set_tags(ahc, &devinfo, + ahc_platform_set_tags(ahc, &devinfo, (dev->flags & AHC_DEV_Q_BASIC) ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED); break; @@ -4467,7 +4376,7 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc, */ dev->openings = 1; ahc_set_scsi_status(scb, SCSI_STATUS_BUSY); - ahc_set_tags(ahc, &devinfo, + ahc_platform_set_tags(ahc, &devinfo, (dev->flags & AHC_DEV_Q_BASIC) ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED); /* FALLTHROUGH */ @@ -4770,6 +4679,7 @@ ahc_linux_release_simq(u_long arg) 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 @@ -4779,8 +4689,6 @@ ahc_linux_release_simq(u_long arg) */ if (unblock_reqs) scsi_unblock_requests(ahc->platform_data->host); - - ahc_schedule_runq(ahc); } static void @@ -4815,6 +4723,7 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) u_int active_scb_index; u_int last_phase; u_int saved_scsiid; + u_int cdb_byte; int retval; int paused; int wait; @@ -4831,6 +4740,11 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) cmd->device->id, cmd->device->lun, flag == SCB_ABORT ? "n ABORT" : " TARGET RESET"); + printf("CDB:"); + for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) + printf(" 0x%x", cmd->cmnd[cdb_byte]); + printf("\n"); + /* * In all versions of Linux, we have to work around * a major flaw in how the mid-layer is locked down @@ -4845,9 +4759,6 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) * by acquiring either the io_request_lock or our own * lock, this *should* be safe. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_unlock_irq(&io_request_lock); -#endif ahc_midlayer_entrypoint_lock(ahc, &s); /* @@ -5104,11 +5015,7 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) int ret; ahc->platform_data->flags |= AHC_UP_EH_SEMAPHORE; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahc_unlock(ahc, &s); -#else - spin_unlock_irq(ahc->platform_data->host->host_lock); -#endif + spin_unlock_irq(&ahc->platform_data->spin_lock); init_timer(&timer); timer.data = (u_long)ahc; timer.expires = jiffies + (5 * HZ); @@ -5122,27 +5029,17 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag) printf("Timer Expired\n"); retval = FAILED; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - ahc_lock(ahc, &s); -#else - spin_lock_irq(ahc->platform_data->host->host_lock); -#endif + spin_lock_irq(&ahc->platform_data->spin_lock); } acmd = TAILQ_FIRST(&ahc->platform_data->completeq); TAILQ_INIT(&ahc->platform_data->completeq); - ahc_midlayer_entrypoint_unlock(ahc, &s); + ahc_schedule_runq(ahc); if (acmd != NULL) { acmd = ahc_linux_run_complete_queue(ahc, acmd); - if (acmd != NULL) { - ahc_midlayer_entrypoint_lock(ahc, &s); + if (acmd != NULL) ahc_schedule_completeq(ahc, acmd); - ahc_midlayer_entrypoint_unlock(ahc, &s); - } } - ahc_schedule_runq(ahc); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_lock_irq(&io_request_lock); -#endif + ahc_midlayer_entrypoint_unlock(ahc, &s); return (retval); } @@ -5185,13 +5082,14 @@ ahc_platform_dump_card_state(struct ahc_softc *ahc) } } -static int __init ahc_linux_init(void) +static int __init +ahc_linux_init(void) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) return (ahc_linux_detect(&aic7xxx_driver_template) ? 0 : -ENODEV); #else scsi_register_module(MODULE_SCSI_HA, &aic7xxx_driver_template); - if (!driver_template.present) { + if (aic7xxx_driver_template.present == 0) { scsi_unregister_module(MODULE_SCSI_HA, &aic7xxx_driver_template); return (-ENODEV); @@ -5201,10 +5099,25 @@ static int __init ahc_linux_init(void) #endif } -static void __exit ahc_linux_exit(void) +static void __exit +ahc_linux_exit(void) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) - struct ahc_softc *ahc; + struct ahc_softc *ahc; + u_long l; + + /* + * Shutdown DV 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_list_unlock(&l); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ahc_linux_pci_exit(); @@ -5220,9 +5133,8 @@ static void __exit ahc_linux_exit(void) /* * In 2.4 we have to unregister from the PCI core _after_ - * unregistering from the scsi midlayer to avoid danling references. - * - * The 2.4 scsi midlayer is so f***ed.. + * unregistering from the scsi midlayer to avoid dangling + * references. */ ahc_linux_pci_exit(); #endif diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index da982de0053380300c3ede4c157f5c670a6fd252..17ed9a587a04f352a2e625e588c1d115b806e8b1 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -53,7 +53,7 @@ * 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#123 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#131 $ * */ #ifndef _AIC7XXX_LINUX_H_ @@ -299,7 +299,13 @@ ahc_scb_timer_reset(struct scb *scb, u_int usec) #include <linux/smp.h> #endif -#define AIC7XXX_DRIVER_VERSION "6.2.28" +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) || defined(SCSI_HAS_HOST_LOCK)) +#define AHC_SCSI_HAS_HOST_LOCK 1 +#else +#define AHC_SCSI_HAS_HOST_LOCK 0 +#endif + +#define AIC7XXX_DRIVER_VERSION "6.2.31" /**************************** Front End Queues ********************************/ /* @@ -703,7 +709,6 @@ ahc_lockinit(struct ahc_softc *ahc) static __inline void ahc_lock(struct ahc_softc *ahc, unsigned long *flags) { - *flags = 0; spin_lock_irqsave(&ahc->platform_data->spin_lock, *flags); } @@ -717,10 +722,13 @@ static __inline void ahc_midlayer_entrypoint_lock(struct ahc_softc *ahc, unsigned long *flags) { /* - * In 2.5.X, the midlayer takes our lock just before - * calling us, so avoid locking again. + * In 2.5.X and some 2.4.X versions, the midlayer takes our + * lock just before calling us, so we avoid locking again. + * For other kernel versions, the io_request_lock is taken + * just before our entry point is called. In this case, we + * trade the io_request_lock for our per-softc lock. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#if AHC_SCSI_HAS_HOST_LOCK == 0 ahc_lock(ahc, flags); #endif } @@ -728,11 +736,7 @@ ahc_midlayer_entrypoint_lock(struct ahc_softc *ahc, unsigned long *flags) static __inline void ahc_midlayer_entrypoint_unlock(struct ahc_softc *ahc, unsigned long *flags) { - /* - * In 2.5.X, the midlayer takes our lock just before - * calling us and unlocks when we return, so let it do the unlock. - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#if AHC_SCSI_HAS_HOST_LOCK == 0 ahc_unlock(ahc, flags); #endif } @@ -750,8 +754,7 @@ ahc_done_lockinit(struct ahc_softc *ahc) static __inline void ahc_done_lock(struct ahc_softc *ahc, unsigned long *flags) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - *flags = 0; +#if AHC_SCSI_HAS_HOST_LOCK == 0 spin_lock_irqsave(&io_request_lock, *flags); #endif } @@ -759,7 +762,7 @@ ahc_done_lock(struct ahc_softc *ahc, unsigned long *flags) static __inline void ahc_done_unlock(struct ahc_softc *ahc, unsigned long *flags) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#if AHC_SCSI_HAS_HOST_LOCK == 0 spin_unlock_irqrestore(&io_request_lock, *flags); #endif } @@ -773,7 +776,6 @@ ahc_list_lockinit() static __inline void ahc_list_lock(unsigned long *flags) { - *flags = 0; spin_lock_irqsave(&ahc_list_spinlock, *flags); } @@ -793,7 +795,6 @@ ahc_lockinit(struct ahc_softc *ahc) static __inline void ahc_lock(struct ahc_softc *ahc, unsigned long *flags) { - *flags = 0; save_flags(*flags); cli(); } @@ -832,7 +833,6 @@ ahc_list_lockinit() static __inline void ahc_list_lock(unsigned long *flags) { - *flags = 0; save_flags(*flags); cli(); } @@ -907,7 +907,7 @@ int aic7770_map_int(struct ahc_softc *ahc, u_int irq); */ #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,1,92) #if defined(__sparc_v9__) || defined(__powerpc__) -#error "PPC and Sparc platforms are only support under 2.1.92 and above" +#error "PPC and Sparc platforms are only supported under 2.1.92 and above" #endif #include <linux/bios32.h> #endif diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index b6dcea5c9d5d505fd579f9b66a2d0012ee514c14..1bc16d403d6217af254c7aa14de7041c780561d7 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -36,7 +36,7 @@ * 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#43 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#44 $ */ #include "aic7xxx_osm.h" diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index ed1e641dbbab78aa840d6c304fe503d8283013e9..f20d0b9bbddcbcc01e9c1ef1fcd7e8f81f4cb186 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -39,7 +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#57 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#62 $ * * $FreeBSD$ */ @@ -696,8 +696,12 @@ static void aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present, static void aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present, int *externalcable_present, int *eeprom_present); -static void write_brdctl(struct ahc_softc *ahc, uint8_t value); +static void write_brdctl(struct ahc_softc *ahc, uint8_t value); static uint8_t read_brdctl(struct ahc_softc *ahc); +static void ahc_pci_intr(struct ahc_softc *ahc); +static int ahc_pci_chip_init(struct ahc_softc *ahc); +static int ahc_pci_suspend(struct ahc_softc *ahc); +static int ahc_pci_resume(struct ahc_softc *ahc); static int ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor, @@ -748,10 +752,7 @@ ahc_find_pci_device(ahc_dev_softc_t pci) 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); - full_id = ahc_compose_id(device, - vendor, - subdevice, - subvendor); + full_id = ahc_compose_id(device, vendor, subdevice, subvendor); /* * If the second function is not hooked up, ignore it. @@ -854,6 +855,9 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry) return (error); ahc->bus_intr = ahc_pci_intr; + ahc->bus_chip_init = ahc_pci_chip_init; + ahc->bus_suspend = ahc_pci_suspend; + ahc->bus_resume = ahc_pci_resume; /* Remeber how the card was setup in case there is no SEEPROM */ if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) { @@ -993,6 +997,35 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry) if ((sxfrctl1 & STPWEN) != 0) ahc->flags |= AHC_TERM_ENB_A; + /* + * Save chip register configuration data for chip resets + * that occur during runtime and resume events. + */ + ahc->bus_softc.pci_softc.devconfig = + ahc_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); + ahc->bus_softc.pci_softc.csize_lattime = + ahc_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) { + u_int sfunct; + + sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; + ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); + ahc->bus_softc.pci_softc.optionmode = ahc_inb(ahc, OPTIONMODE); + ahc->bus_softc.pci_softc.targcrccnt = ahc_inw(ahc, TARGCRCCNT); + ahc_outb(ahc, SFUNCT, sfunct); + ahc->bus_softc.pci_softc.crccontrol1 = + ahc_inb(ahc, CRCCONTROL1); + } + if ((ahc->features & AHC_MULTI_FUNC) != 0) + ahc->bus_softc.pci_softc.scbbaddr = ahc_inb(ahc, SCBBADDR); + + if ((ahc->features & AHC_ULTRA2) != 0) + ahc->bus_softc.pci_softc.dff_thrsh = ahc_inb(ahc, DFF_THRSH); + /* Core initialization */ error = ahc_init(ahc); if (error != 0) @@ -1412,6 +1445,7 @@ check_extport(struct ahc_softc *ahc, u_int *sxfrctl1) } if (have_autoterm) { + ahc->flags |= AHC_HAS_TERM_LOGIC; ahc_acquire_seeprom(ahc, &sd); configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1); ahc_release_seeprom(&sd); @@ -1845,11 +1879,14 @@ aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present, spiocap |= EXT_BRDCTL; ahc_outb(ahc, SPIOCAP, spiocap); ahc_outb(ahc, BRDCTL, BRDRW|BRDCS); + ahc_flush_device_writes(ahc); + ahc_delay(500); ahc_outb(ahc, BRDCTL, 0); + ahc_flush_device_writes(ahc); + ahc_delay(500); brdctl = ahc_inb(ahc, BRDCTL); *internal50_present = (brdctl & BRDDAT5) ? 0 : 1; *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1; - *eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0; } @@ -1943,7 +1980,7 @@ read_brdctl(ahc) return (value); } -void +static void ahc_pci_intr(struct ahc_softc *ahc) { u_int error; @@ -1995,6 +2032,73 @@ ahc_pci_intr(struct ahc_softc *ahc) ahc_unpause(ahc); } +static int +ahc_pci_chip_init(struct ahc_softc *ahc) +{ + ahc_outb(ahc, DSCOMMAND0, ahc->bus_softc.pci_softc.dscommand0); + ahc_outb(ahc, DSPCISTATUS, ahc->bus_softc.pci_softc.dspcistatus); + if ((ahc->features & AHC_DT) != 0) { + u_int sfunct; + + sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; + ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); + ahc_outb(ahc, OPTIONMODE, ahc->bus_softc.pci_softc.optionmode); + ahc_outw(ahc, TARGCRCCNT, ahc->bus_softc.pci_softc.targcrccnt); + ahc_outb(ahc, SFUNCT, sfunct); + ahc_outb(ahc, CRCCONTROL1, + ahc->bus_softc.pci_softc.crccontrol1); + } + if ((ahc->features & AHC_MULTI_FUNC) != 0) + ahc_outb(ahc, SCBBADDR, ahc->bus_softc.pci_softc.scbbaddr); + + if ((ahc->features & AHC_ULTRA2) != 0) + ahc_outb(ahc, DFF_THRSH, ahc->bus_softc.pci_softc.dff_thrsh); + + return (ahc_chip_init(ahc)); +} + +static int +ahc_pci_suspend(struct ahc_softc *ahc) +{ + return (ahc_suspend(ahc)); +} + +static int +ahc_pci_resume(struct ahc_softc *ahc) +{ + + ahc_power_state_change(ahc, AHC_POWER_STATE_D0); + + /* + * We assume that the OS has restored our register + * mappings, etc. Just update the config space registers + * 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, + ahc->bus_softc.pci_softc.devconfig); + ahc_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, + ahc->bus_softc.pci_softc.csize_lattime); + if ((ahc->flags & AHC_HAS_TERM_LOGIC) != 0) { + struct seeprom_descriptor sd; + u_int sxfrctl1; + + sd.sd_ahc = ahc; + sd.sd_control_offset = SEECTL; + sd.sd_status_offset = SEECTL; + sd.sd_dataout_offset = SEECTL; + + ahc_acquire_seeprom(ahc, &sd); + configure_termination(ahc, &sd, + ahc->seep_config->adapter_control, + &sxfrctl1); + ahc_release_seeprom(&sd); + } + return (ahc_resume(ahc)); +} + static int ahc_aic785X_setup(struct ahc_softc *ahc) { @@ -2009,6 +2113,7 @@ ahc_aic785X_setup(struct ahc_softc *ahc) rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); if (rev >= 1) ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; + ahc->instruction_ram_size = 512; return (0); } @@ -2026,6 +2131,7 @@ ahc_aic7860_setup(struct ahc_softc *ahc) rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); if (rev >= 1) ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; + ahc->instruction_ram_size = 512; return (0); } @@ -2049,6 +2155,7 @@ ahc_aic7870_setup(struct ahc_softc *ahc) ahc->chip = AHC_AIC7870; ahc->features = AHC_AIC7870_FE; ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; + ahc->instruction_ram_size = 512; return (0); } @@ -2102,6 +2209,7 @@ ahc_aic7880_setup(struct ahc_softc *ahc) } else { ahc->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; } + ahc->instruction_ram_size = 512; return (0); } @@ -2149,6 +2257,7 @@ ahc_aic7890_setup(struct ahc_softc *ahc) rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); if (rev == 0) ahc->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG; + ahc->instruction_ram_size = 768; return (0); } @@ -2161,6 +2270,7 @@ ahc_aic7892_setup(struct ahc_softc *ahc) ahc->features = AHC_AIC7892_FE; ahc->flags |= AHC_NEWEEPROM_FMT; ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG; + ahc->instruction_ram_size = 1024; return (0); } @@ -2216,6 +2326,7 @@ ahc_aic7895_setup(struct ahc_softc *ahc) ahc_pci_write_config(pci, DEVCONFIG, devconfig, /*bytes*/1); #endif ahc->flags |= AHC_NEWEEPROM_FMT; + ahc->instruction_ram_size = 512; return (0); } @@ -2230,6 +2341,7 @@ ahc_aic7896_setup(struct ahc_softc *ahc) ahc->features = AHC_AIC7896_FE; ahc->flags |= AHC_NEWEEPROM_FMT; ahc->bugs |= AHC_CACHETHEN_DIS_BUG; + ahc->instruction_ram_size = 768; return (0); } @@ -2244,6 +2356,7 @@ ahc_aic7899_setup(struct ahc_softc *ahc) ahc->features = AHC_AIC7899_FE; ahc->flags |= AHC_NEWEEPROM_FMT; ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG; + ahc->instruction_ram_size = 1024; return (0); } diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c index 8a510e7daec181e861f7ca99d9a0717cb6845841..4d39533e9124aa8987b290d1d70efa3f2c539b5e 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_proc.c +++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c @@ -37,7 +37,7 @@ * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr> * sym driver. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#23 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#24 $ */ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" @@ -325,6 +325,7 @@ ahc_linux_proc_info(char *buffer, char **start, off_t offset, copy_info(&info, "Adaptec AIC7xxx driver version: %s\n", AIC7XXX_DRIVER_VERSION); + copy_info(&info, "%s\n", ahc->description); ahc_controller_info(ahc, ahc_info); copy_info(&info, "%s\n\n", ahc_info); diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped index 769c2d602f9f313a94ccd4b81d663062ac3b4833..cda0b8e5961331e86e66b66009a712e3f5ee5d81 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped +++ b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped @@ -3,7 +3,7 @@ * from the following source files: * * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#37 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $ */ typedef int (ahc_reg_print_t)(u_int, u_int *, u_int); typedef struct ahc_reg_parse_entry { @@ -1776,7 +1776,7 @@ ahc_reg_print_t ahc_sg_cache_pre_print; #define SEQ_MAILBOX_SHIFT 0x00 #define TARGET_DATA_IN 0x01 #define HOST_MSG 0xff -#define MAX_OFFSET 0xff +#define MAX_OFFSET 0x7f #define BUS_16_BIT 0x01 #define SCB_UPLOAD_SIZE 0x20 #define STACK_SIZE 0x04 diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped index 63b961c739fb1d1afcd45fb7b0417c7c605dad6e..b0687b13a656fcee9353b35072ba7a8ee05863b9 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped +++ b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped @@ -3,7 +3,7 @@ * from the following source files: * * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#37 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $ */ #include "aic7xxx_osm.h" diff --git a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped index def9fc7ef9be03c8605873da26c3fef44d3d4ddd..0f376fb1cf188d1cbeacebcff2f6c1583831caaf 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped +++ b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped @@ -3,7 +3,7 @@ * from the following source files: * * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#37 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $ */ static uint8_t seqprog[] = { 0xb2, 0x00, 0x00, 0x08, diff --git a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile index 7599658d73257b81183df5b9e7d2e2d8f56cb3ce..fa2fbbcc92e633a55df05d157f98454b29975949 100644 --- a/drivers/scsi/aic7xxx/aicasm/Makefile +++ b/drivers/scsi/aic7xxx/aicasm/Makefile @@ -11,7 +11,7 @@ GENSRCS= $(YSRCS:.y=.c) $(LSRCS:.l=.c) SRCS= ${CSRCS} ${GENSRCS} LIBS= -ldb -CLEANFILES= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output) +clean-files:= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output) $(PROG) # Override default kernel CFLAGS. This is a userland app. AICASM_CFLAGS:= -I/usr/include -I. YFLAGS= -d @@ -46,7 +46,6 @@ aicdb.h: echo "*** Install db development libraries"; \ fi -clean-files := $(CLEANFILES) $(PROG) clean: rm -f $(clean-files) diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c index aa2676edc10ead08a6afa46625b261aa34955a99..fa13a1fdce6dbc5df5b38104a381137593501cbd 100644 --- a/drivers/scsi/aic7xxx/aiclib.c +++ b/drivers/scsi/aic7xxx/aiclib.c @@ -1333,3 +1333,81 @@ aic_error_action(struct scsi_cmnd *cmd, struct scsi_inquiry_data *inq_data, return (err_action); } +char * +aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, + aic_option_callback_t *callback, void *callback_arg) +{ + char *tok_end; + char *tok_end2; + int i; + int instance; + int targ; + int done; + char tok_list[] = {'.', ',', '{', '}', '\0'}; + + /* All options use a ':' name/arg separator */ + if (*opt_arg != ':') + return (opt_arg); + opt_arg++; + instance = -1; + targ = -1; + done = FALSE; + /* + * Restore separator that may be in + * the middle of our option argument. + */ + tok_end = strchr(opt_arg, '\0'); + if (tok_end < end) + *tok_end = ','; + while (!done) { + switch (*opt_arg) { + case '{': + if (instance == -1) { + instance = 0; + } else { + if (depth > 1) { + if (targ == -1) + targ = 0; + } else { + printf("Malformed Option %s\n", + opt_name); + done = TRUE; + } + } + opt_arg++; + break; + case '}': + if (targ != -1) + targ = -1; + else if (instance != -1) + instance = -1; + opt_arg++; + break; + case ',': + case '.': + if (instance == -1) + done = TRUE; + else if (targ >= 0) + targ++; + else if (instance >= 0) + instance++; + opt_arg++; + break; + case '\0': + done = TRUE; + break; + default: + tok_end = end; + for (i = 0; tok_list[i]; i++) { + tok_end2 = strchr(opt_arg, tok_list[i]); + if ((tok_end2) && (tok_end2 < tok_end)) + tok_end = tok_end2; + } + callback(callback_arg, instance, targ, + simple_strtol(opt_arg, NULL, 0)); + opt_arg = tok_end; + break; + } + } + return (opt_arg); +} diff --git a/drivers/scsi/aic7xxx/aiclib.h b/drivers/scsi/aic7xxx/aiclib.h index 1b9da8346c5d92a76b3fb32c4fc2035d9cef4404..6fa722e1096fd49bc97e277ac47820acd39c8120 100644 --- a/drivers/scsi/aic7xxx/aiclib.h +++ b/drivers/scsi/aic7xxx/aiclib.h @@ -870,6 +870,7 @@ aic_sector_div(sector_t capacity, int heads, int sectors) #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) /******************************************************************************/ @@ -905,6 +906,10 @@ int aic_inquiry_match(caddr_t /*inqbuffer*/, int aic_static_inquiry_match(caddr_t /*inqbuffer*/, caddr_t /*table_entry*/); +typedef void aic_option_callback_t(void *, int, int, int32_t); +char * aic_parse_brace_option(char *opt_name, char *opt_arg, + char *end, int depth, + aic_option_callback_t *, void *); static __inline void scsi_extract_sense(struct scsi_sense_data *sense, int *error_code, int *sense_key,