diff --git a/sys/dev/aic7xxx/aic79xx.c b/sys/dev/aic7xxx/aic79xx.c index b3807a5fd5ca..ae0f62e5dd28 100644 --- a/sys/dev/aic7xxx/aic79xx.c +++ b/sys/dev/aic7xxx/aic79xx.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#165 $ * * $FreeBSD$ */ @@ -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; @@ -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,9 +1662,9 @@ 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); @@ -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); @@ -4980,6 +4990,7 @@ ahd_reset(struct ahd_softc *ahd) * to disturb the integrity of the bus. */ ahd_pause(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 +5039,13 @@ 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. + */ + ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); + ahd_known_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); /* * Restore SXFRCTL1. @@ -5047,9 +5058,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 +5174,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, @@ -6050,7 +6066,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 +6357,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 @@ -6565,13 +6581,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 +6598,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 +6616,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 +6630,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 @@ -8148,7 +8167,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--; diff --git a/sys/dev/aic7xxx/aic79xx.h b/sys/dev/aic7xxx/aic79xx.h index 64a97dc8f998..f1607f8f18cd 100644 --- a/sys/dev/aic7xxx/aic79xx.h +++ b/sys/dev/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#84 $ * * $FreeBSD$ */ @@ -309,7 +309,17 @@ typedef enum { * Controller write to INTSTAT will lose to a host * write to CLRINT. */ - AHD_INTCOLLISION_BUG = 0x100000 + AHD_INTCOLLISION_BUG = 0x100000, + /* + * 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 = 0x200000 } ahd_bug; /* @@ -404,14 +414,17 @@ struct target_status { * Initiator mode SCB shared data area. * If the embedded CDB is 12 bytes or less, we embed * the sense buffer address in the SCB. This allows - * us to retrieve sense information without interupting + * us to retrieve sense information without interrupting * the host in packetized mode. */ 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 +740,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 /* diff --git a/sys/dev/aic7xxx/aic79xx.reg b/sys/dev/aic7xxx/aic79xx.reg index 0138ca271031..65c527d7002b 100644 --- a/sys/dev/aic7xxx/aic79xx.reg +++ b/sys/dev/aic7xxx/aic79xx.reg @@ -39,7 +39,7 @@ * * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#60 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#64 $" /* * 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 */ } /* @@ -3725,7 +3725,7 @@ scratch_ram { /* * The minimum number of commands still outstanding required - * to continue coalessing (2's compliment of value). + * to continue coalessing (2's complement of value). */ INT_COALESSING_MINCMDS { size 1 @@ -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/sys/dev/aic7xxx/aic79xx.seq b/sys/dev/aic7xxx/aic79xx.seq index 31cc29d9d4dd..3a772aad883a 100644 --- a/sys/dev/aic7xxx/aic79xx.seq +++ b/sys/dev/aic7xxx/aic79xx.seq @@ -40,7 +40,7 @@ * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#78 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#88 $" PATCH_ARG_LIST = "struct ahd_softc *ahd" PREFIX = "ahd_" @@ -122,22 +122,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 +521,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 +708,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 +1032,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 +1157,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 +1262,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 +1276,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 +1314,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 +1524,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 +1533,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 +1584,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 +1641,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 +1693,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 +1744,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 +1788,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 +1837,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 +1857,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 +1885,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 +1964,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 +1985,3 @@ load_overrun_buf: mvi HCNT[1], ((PKT_OVERRUN_BUFSIZE >> 8) & 0xFF); clr HCNT[2] ret; } - -cfg4icmd_intr: diff --git a/sys/dev/aic7xxx/aic79xx_inline.h b/sys/dev/aic7xxx/aic79xx_inline.h index e41701472bfc..d5963ce92f36 100644 --- a/sys/dev/aic7xxx/aic79xx_inline.h +++ b/sys/dev/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#43 $ * * $FreeBSD$ */ @@ -769,7 +769,7 @@ ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb) ahd_setup_scb_common(ahd, scb); /* - * Make sure our data is consistant from the + * Make sure our data is consistent from the * perspective of the adapter. */ ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); diff --git a/sys/dev/aic7xxx/aic79xx_osm.c b/sys/dev/aic7xxx/aic79xx_osm.c index 7e4a8d9f0686..365375eda8e4 100644 --- a/sys/dev/aic7xxx/aic79xx_osm.c +++ b/sys/dev/aic7xxx/aic79xx_osm.c @@ -29,7 +29,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/aic79xx_osm.c#25 $ + * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/aic79xx_osm.c#26 $ * * $FreeBSD$ */ @@ -1188,6 +1188,11 @@ ahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim, && (ccb_h->flags & CAM_CDB_PHYS) == 0) { u_long s; + /* + * Should CAM start to support CDB sizes + * greater than 16 bytes, we could use + * the sense buffer to store the CDB. + */ ahd_set_transaction_status(scb, CAM_REQ_INVALID); ahd_lock(ahd, &s); @@ -1197,8 +1202,11 @@ ahd_setup_data(struct ahd_softc *ahd, struct cam_sim *sim, return; } if ((ccb_h->flags & CAM_CDB_PHYS) != 0) { - hscb->shared_data.idata.cdbptr = + hscb->shared_data.idata.cdb_from_host.cdbptr = ahd_htole64((uintptr_t)csio->cdb_io.cdb_ptr); + hscb->shared_data.idata.cdb_from_host.cdblen = + csio->cdb_len; + hscb->cdb_len |= SCB_CDB_LEN_PTR; } else { memcpy(hscb->shared_data.idata.cdb, csio->cdb_io.cdb_ptr, diff --git a/sys/dev/aic7xxx/aic79xx_pci.c b/sys/dev/aic7xxx/aic79xx_pci.c index 79b1a172d6be..4869afbece0c 100644 --- a/sys/dev/aic7xxx/aic79xx_pci.c +++ b/sys/dev/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#66 $ * * $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, @@ -691,14 +698,14 @@ static const char *pci_status_source[] = static const char *split_status_strings[] = { - "%s: Received split response in %s.\n" + "%s: Received split response in %s.\n", "%s: Received split completion error message in %s\n", "%s: Receive overrun in %s\n", "%s: Count not complete in %s\n", "%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[] = @@ -740,7 +747,7 @@ ahd_pci_intr(struct ahd_softc *ahd) if (i == 5) continue; pci_status[i] = ahd_inb(ahd, reg); - /* Clear latched errors. So our interupt deasserts. */ + /* Clear latched errors. So our interrupt deasserts. */ ahd_outb(ahd, reg, pci_status[i]); } @@ -796,14 +803,14 @@ ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat) split_status[i] = ahd_inb(ahd, DCHSPLTSTAT0); split_status1[i] = ahd_inb(ahd, DCHSPLTSTAT1); - /* Clear latched errors. So our interupt deasserts. */ + /* Clear latched errors. So our interrupt deasserts. */ ahd_outb(ahd, DCHSPLTSTAT0, split_status[i]); ahd_outb(ahd, DCHSPLTSTAT1, split_status1[i]); if (i != 0) continue; sg_split_status[i] = ahd_inb(ahd, SGSPLTSTAT0); sg_split_status1[i] = ahd_inb(ahd, SGSPLTSTAT1); - /* Clear latched errors. So our interupt deasserts. */ + /* Clear latched errors. So our interrupt deasserts. */ ahd_outb(ahd, SGSPLTSTAT0, sg_split_status[i]); ahd_outb(ahd, SGSPLTSTAT1, sg_split_status1[i]); } @@ -898,7 +905,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.