diff options
-rw-r--r-- | sys/dev/aic7xxx/aic79xx.c | 238 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic79xx.h | 16 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic79xx.reg | 44 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic79xx.seq | 222 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic79xx_inline.h | 52 | ||||
-rw-r--r-- | sys/dev/aic7xxx/aic79xx_pci.c | 6 |
6 files changed, 335 insertions, 243 deletions
diff --git a/sys/dev/aic7xxx/aic79xx.c b/sys/dev/aic7xxx/aic79xx.c index ebe094d..e24bfcd 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#102 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#113 $ * * $FreeBSD$ */ @@ -488,7 +488,6 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) struct scb *scb; u_int scbid; - ahd_update_modes(ahd); scbid = ahd_get_scbptr(ahd); scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { @@ -933,12 +932,6 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) ahd_outb(ahd, CLRSINT0, CLRSELINGO); scbid = ahd_inw(ahd, WAITING_TID_HEAD); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_SELTO) != 0) { - ahd_print_path(ahd, scb); - printf("Saw Selection Timeout for SCB 0x%x\n", scbid); - } -#endif scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) { printf("%s: ahd_intr - referenced scb not " @@ -947,6 +940,13 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) ahd_dump_card_state(ahd); panic("For diagnostics"); } else { +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_SELTO) != 0) { + ahd_print_path(ahd, scb); + printf("Saw Selection Timeout for SCB 0x%x\n", + scbid); + } +#endif ahd_set_transaction_status(scb, CAM_SEL_TIMEOUT); ahd_freeze_devq(ahd, scb); } @@ -1033,22 +1033,31 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) if (packetized && ahd_inb(ahd, LASTPHASE) == P_BUSFREE) { restart = ahd_handle_pkt_busfree(ahd, busfreetime); } else { + packetized = 0; restart = ahd_handle_nonpkt_busfree(ahd); } /* * Clear the busfree interrupt status. The setting of - * the interrupt is a pulse, so we do not need to muck - * with the ENBUSFREE logic. This also ensures that if - * the bus has moved on to another connection, busfree - * protection is still in force. + * the interrupt is a pulse, so in a perfect world, we + * would not need to muck with the ENBUSFREE logic. This + * would ensure that if the bus moves on to another + * connection, busfree protection is still in force. If + * BUSFREEREV is broken, however, we must manually clear + * the ENBUSFREE if the busfree occurred during a non-pack + * connection so that we don't get false positives during + * future, packetized, connections. */ - ahd_outb(ahd, CLRSINT1, CLRBUSFREE|CLRSCSIPERR); + ahd_outb(ahd, CLRSINT1, CLRBUSFREE); + if (packetized == 0 + && (ahd->bugs & AHD_BUSFREEREV_BUG) != 0) + ahd_outb(ahd, SIMODE1, + ahd_inb(ahd, SIMODE1) & ~ENBUSFREE); if (clear_fifo) ahd_clear_fifo(ahd, mode); ahd_clear_msg_state(ahd); - ahd_clear_intstat(ahd); + ahd_outb(ahd, CLRINT, CLRSCSIINT); if (restart) { ahd_restart(ahd); } else { @@ -1066,12 +1075,13 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) static void ahd_handle_transmission_error(struct ahd_softc *ahd) { - u_int lqistat1; - u_int lqistat2; - u_int msg_out; - u_int curphase; - u_int lastphase; - u_int perrdiag; + u_int lqistat1; + u_int lqistat2; + u_int msg_out; + u_int curphase; + u_int lastphase; + u_int perrdiag; + u_int cur_col; ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); lqistat1 = ahd_inb(ahd, LQISTAT1) & ~(LQIPHASE_LQ|LQIPHASE_NLQ); @@ -1098,9 +1108,12 @@ ahd_handle_transmission_error(struct ahd_softc *ahd) msg_out = MSG_INITIATOR_DET_ERR; ahd_outb(ahd, CLRSINT1, CLRSCSIPERR); printf("%s: Transmission error detected\n", ahd_name(ahd)); - printf("%s: lqistat1 == 0x%x, LASTPHASE == 0x0%x, " - "curphase = 0x%x, perrdiag == 0x%x\n", - ahd_name(ahd), lqistat1, lastphase, curphase, perrdiag); + cur_col = 0; + ahd_lqistat1_print(lqistat1, &cur_col, 50); + ahd_lastphase_print(lastphase, &cur_col, 50); + ahd_scsisigi_print(curphase, &cur_col, 50); + ahd_perrdiag_print(perrdiag, &cur_col, 50); + printf("\n"); ahd_dump_card_state(ahd); if ((lqistat1 & (LQIOVERI_LQ|LQIOVERI_NLQ)) != 0) { printf("%s: Gross protocol error during incoming " @@ -1261,7 +1274,7 @@ ahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1) /* * Packetized unexpected or expected busfree. - * Entered in MODE_SCSI. + * Entered in mode based on busfreetime. */ static int ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) @@ -1274,6 +1287,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) if ((lqostat1 & LQOBUSFREE) != 0) { struct scb *scb; u_int scbid; + u_int saved_scbptr; u_int waiting_h; u_int waiting_t; u_int next; @@ -1282,8 +1296,23 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) printf("%s: Warning, BUSFREE time is 0x%x. " "Expected BUSFREE_LQO.\n", ahd_name(ahd), busfreetime); - - scbid = ahd_get_scbptr(ahd); + /* + * The LQO manager detected an unexpected busfree + * either: + * + * 1) During an outgoing LQ. + * 2) After an outgoing LQ but before the first + * REQ of the command packet. + * 3) During an outgoing command packet. + * + * In all cases, CURRSCB is pointing to the + * SCB that encountered the failure. Clean + * up the queue, clear SELDO and LQOBUSFREE, + * and allow the sequencer to restart the select + * out at its lesure. + */ + ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); + scbid = ahd_inw(ahd, CURRSCB); scb = ahd_lookup_scb(ahd, scbid); if (scb == NULL) panic("SCB not valid during LQOBUSFREE"); @@ -1302,27 +1331,17 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) * Clear the status. */ ahd_outb(ahd, CLRLQOINT1, CLRLQOBUSFREE); - if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) { + if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) ahd_outb(ahd, CLRLQOINT1, 0); - } - /* - * The LQO manager detected an unexpected busfree - * either: - * - * 1) During an outgoing LQ. - * 2) After an outgoing LQ but before the first - * REQ of the command packet. - * 3) During an outgoing command packet. - * - * In all cases, CURRSCB is pointing to the - * SCB that encountered the failure. Clean - * up the queue, clear SELDO and LQOBUSFREE, - * and allow the sequencer to restart the select - * out at its lesure. - */ ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); ahd_outb(ahd, CLRSINT0, CLRSELDO); + + /* + * Update the waiting for selection queue so + * we restart on the correct SCB. + */ waiting_h = ahd_inw(ahd, WAITING_TID_HEAD); + saved_scbptr = ahd_get_scbptr(ahd); if (waiting_h != scbid) { ahd_outw(ahd, WAITING_TID_HEAD, scbid); @@ -1337,7 +1356,7 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) ahd_set_scbptr(ahd, scbid); ahd_outw(ahd, SCB_NEXT2, next); } - + ahd_set_scbptr(ahd, saved_scbptr); /* Return unpausing the sequencer. */ return (0); } @@ -1769,6 +1788,10 @@ ahd_clear_intstat(struct ahd_softc *ahd) |CLRLQOATNPKT|CLRLQOTCRC); ahd_outb(ahd, CLRLQOINT1, CLRLQOINITSCBPERR|CLRLQOSTOPI2|CLRLQOBADQAS |CLRLQOBUSFREE|CLRLQOPHACHGINPKT); + if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) { + ahd_outb(ahd, CLRLQOINT0, 0); + ahd_outb(ahd, CLRLQOINT1, 0); + } ahd_outb(ahd, CLRSINT3, CLRNTRAMPERR|CLROSRAMPERR); ahd_outb(ahd, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI |CLRBUSFREE|CLRSCSIPERR|CLRREQINIT); @@ -1817,26 +1840,32 @@ ahd_dump_sglist(struct scb *scb) sg_list = (struct ahd_dma64_seg*)scb->sg_list; for (i = 0; i < scb->sg_count; i++) { uint64_t addr; + uint32_t len; addr = ahd_le64toh(sg_list[i].addr); - printf("sg[%d] - Addr 0x%x%x : Length %d\n", + len = ahd_le32toh(sg_list[i].len); + printf("sg[%d] - Addr 0x%x%x : Length %d%s\n", i, (uint32_t)((addr >> 32) & 0xFFFFFFFF), (uint32_t)(addr & 0xFFFFFFFF), - ahd_le32toh(sg_list[i].len)); + sg_list[i].len & AHD_SG_LEN_MASK, + (sg_list[i].len & AHD_DMA_LAST_SEG) + ? " Last" : ""); } } else { struct ahd_dma_seg *sg_list; sg_list = (struct ahd_dma_seg*)scb->sg_list; for (i = 0; i < scb->sg_count; i++) { - printf("sg[%d] - Addr 0x%x%x : Length %d\n", + uint32_t len; + + len = ahd_le32toh(sg_list[i].len); + printf("sg[%d] - Addr 0x%x%x : Length %d%s\n", i, - (ahd_le32toh(sg_list[i].len) >> 24 - & SG_HIGH_ADDR_BITS), + (len >> 24) & SG_HIGH_ADDR_BITS, ahd_le32toh(sg_list[i].addr), - ahd_le32toh(sg_list[i].len) - & AHD_SG_LEN_MASK); + len & AHD_SG_LEN_MASK, + len & AHD_DMA_LAST_SEG ? " Last" : ""); } } } @@ -2396,9 +2425,9 @@ ahd_update_pending_scbs(struct ahd_softc *ahd) * has already been setup. The negotiation changes may * effect whether we select-out with ATN. */ - ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); saved_modes = ahd_save_modes(ahd); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); + ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); saved_scbptr = ahd_get_scbptr(ahd); /* Ensure that the hscbs down on the card match the new information */ for (i = 0; i < ahd->scb_data.maxhscbs; i++) { @@ -2418,7 +2447,7 @@ ahd_update_pending_scbs(struct ahd_softc *ahd) control |= pending_hscb->control & MK_MESSAGE; ahd_outb(ahd, SCB_CONTROL, control); } - ahd_set_scbptr(ahd,saved_scbptr); + ahd_set_scbptr(ahd, saved_scbptr); ahd_restore_modes(ahd, saved_modes); if (paused == 0) @@ -4725,6 +4754,10 @@ ahd_setup_iocell_workaround(struct ahd_softc *ahd) ahd_outb(ahd, DSPDATACTL, ahd_inb(ahd, DSPDATACTL) | BYPASSENAB | RCVROFFSTDIS | XMITOFFSTDIS); ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) | (ENSELDO|ENSELDI)); +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_MISC) != 0) + printf("%s: Setting up iocell workaround\n", ahd_name(ahd)); +#endif ahd_restore_modes(ahd, saved_modes); } @@ -4738,9 +4771,17 @@ ahd_iocell_first_selection(struct ahd_softc *ahd) ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); sblkctl = ahd_inb(ahd, SBLKCTL); ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_MISC) != 0) + printf("%s: iocell first selection\n", ahd_name(ahd)); +#endif if ((sblkctl & ENAB40) != 0) { ahd_outb(ahd, DSPDATACTL, ahd_inb(ahd, DSPDATACTL) & ~BYPASSENAB); +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_MISC) != 0) + printf("%s: BYPASS now disabled\n", ahd_name(ahd)); +#endif } ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) & ~(ENSELDO|ENSELDI)); ahd_outb(ahd, CLRINT, CLRSCSIINT); @@ -5409,7 +5450,11 @@ ahd_chip_init(struct ahd_softc *ahd) ahd_outb(ahd, DFF_THRSH, RD_DFTHRSH_75|WR_DFTHRSH_75); ahd_outb(ahd, SIMODE0, ENIOERR|ENOVERRUN); ahd_outb(ahd, SIMODE3, ENNTRAMPERR|ENOSRAMPERR); - ahd_outb(ahd, OPTIONMODE, AUTOACKEN|BUSFREEREV|AUTO_MSGOUT_DE); + if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { + ahd_outb(ahd, OPTIONMODE, AUTOACKEN|AUTO_MSGOUT_DE); + } else { + ahd_outb(ahd, OPTIONMODE, AUTOACKEN|BUSFREEREV|AUTO_MSGOUT_DE); + } if ((ahd->chip & AHD_BUS_MASK) == AHD_PCIX) /* * Do not issue a target abort when a split completion @@ -5426,6 +5471,11 @@ ahd_chip_init(struct ahd_softc *ahd) ahd_outb(ahd, DSPSELECT, i); ahd_outb(ahd, WRTBIASCTL, WRTBIASCTL_CPQ_DEFAULT); } +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_MISC) != 0) + printf("%s: WRTBIASCTL now 0x%x\n", ahd_name(ahd), + WRTBIASCTL_CPQ_DEFAULT); +#endif } ahd_setup_iocell_workaround(ahd); @@ -5460,8 +5510,7 @@ ahd_chip_init(struct ahd_softc *ahd) ahd_outb(ahd, LUNPTR, offsetof(struct hardware_scb, lun)); } ahd_outb(ahd, CMDLENPTR, offsetof(struct hardware_scb, cdb_len)); - ahd_outb(ahd, ATTRPTR, - offsetof(struct hardware_scb, task_attribute_nonpkt_tag)); + ahd_outb(ahd, ATTRPTR, offsetof(struct hardware_scb, task_attribute)); ahd_outb(ahd, FLAGPTR, offsetof(struct hardware_scb, task_management)); ahd_outb(ahd, CMDPTR, offsetof(struct hardware_scb, shared_data.idata.cdb)); @@ -5678,6 +5727,7 @@ ahd_default_config(struct ahd_softc *ahd) tinfo->user.offset= ~0; tinfo->user.ppr_options = MSG_EXT_PPR_RD_STRM | MSG_EXT_PPR_WR_FLOW + | MSG_EXT_PPR_HOLD_MCS | MSG_EXT_PPR_IU_REQ | MSG_EXT_PPR_QAS_REQ | MSG_EXT_PPR_DT_REQ; @@ -5785,6 +5835,7 @@ ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc) if ((sc->device_flags[targ] & CFPACKETIZED) != 0) user_tinfo->ppr_options |= MSG_EXT_PPR_RD_STRM | MSG_EXT_PPR_WR_FLOW + | MSG_EXT_PPR_HOLD_MCS | MSG_EXT_PPR_IU_REQ; if ((sc->device_flags[targ] & CFQAS) != 0) @@ -6051,12 +6102,11 @@ ahd_resume(struct ahd_softc *ahd) static __inline u_int ahd_index_busy_tcl(struct ahd_softc *ahd, u_int *saved_scbid, u_int tcl) { - - *saved_scbid = ahd_get_scbptr(ahd); - /* * Index to the SCB that contains the busy entry. */ + AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); + *saved_scbid = ahd_get_scbptr(ahd); ahd_set_scbptr(ahd, TCL_LUN(tcl) | ((TCL_TARGET_OFFSET(tcl) & 0xC) << 4)); @@ -6547,19 +6597,21 @@ int ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel, int lun, u_int tag, role_t role, uint32_t status) { - struct scb *scbp; - struct scb *scbp_next; - u_int active_scb; - u_int i, j; - u_int maxtarget; - u_int minlun; - u_int maxlun; - - int found; + struct scb *scbp; + struct scb *scbp_next; + u_int active_scb; + u_int i, j; + u_int maxtarget; + u_int minlun; + u_int maxlun; + int found; + ahd_mode_state saved_modes; - /* restore this when we're done */ + /* restore these when we're done */ active_scb = ahd_get_scbptr(ahd); + 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); @@ -6628,6 +6680,7 @@ ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel, } } ahd_set_scbptr(ahd, active_scb); + ahd_restore_modes(ahd, saved_modes); ahd_platform_abort_scbs(ahd, target, channel, lun, tag, role, status); return found; } @@ -6712,10 +6765,8 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) do { next_fifo = next_fifo ^ CURRFIFO; ahd_set_modes(ahd, next_fifo, next_fifo); - ahd_outb(ahd, DFCNTRL, ahd_inb(ahd, DFCNTRL) & ~SCSIEN); - while ((ahd_inb(ahd, DFCNTRL) & SCSIENACK) != 0) - ahd_delay(10); - ahd_outb(ahd, DFCNTRL, ahd_inb(ahd, DFCNTRL) & ~HDMAEN); + ahd_outb(ahd, DFCNTRL, + ahd_inb(ahd, DFCNTRL) & ~(SCSIEN|HDMAEN)); while ((ahd_inb(ahd, DFCNTRL) & HDMAENACK) != 0) ahd_delay(10); /* @@ -6729,7 +6780,8 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) * Reset the bus if we are initiating this reset */ ahd_clear_msg_state(ahd); - ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST)); + ahd_outb(ahd, SIMODE1, + ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST|ENBUSFREE)); if (initiate_reset) ahd_reset_current_bus(ahd); ahd_clear_intstat(ahd); @@ -6800,7 +6852,7 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) /* Notify the XPT that a bus reset occurred */ ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); - + ahd_restart(ahd); /* * Freeze the SIMQ until our poller can determine that * the bus reset has really gone away. We set the initial @@ -6812,7 +6864,6 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) ahd_freeze_simq(ahd); ahd_timer_reset(&ahd->reset_timer, 0, ahd_reset_poll, ahd); } - ahd_restart(ahd); return (found); } @@ -6835,6 +6886,8 @@ ahd_reset_poll(void *arg) } ahd_lock(ahd, &s); ahd_pause(ahd); + ahd_update_modes(ahd); + ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); if ((ahd_inb(ahd, SSTAT1) & SCSIRSTI) != 0) { ahd_timer_reset(&ahd->reset_timer, AHD_RESET_POLL_US, @@ -7655,6 +7708,7 @@ ahd_dump_card_state(struct ahd_softc *ahd) u_int dffstat; int paused; u_int scb_index; + u_int saved_scb_index; u_int i; u_int cur_col; @@ -7683,6 +7737,7 @@ ahd_dump_card_state(struct ahd_softc *ahd) ahd_seqintctl_print(ahd_inb(ahd, SEQINTCTL), &cur_col, 50); ahd_scsisigi_print(ahd_inb(ahd, SCSISIGI), &cur_col, 50); ahd_scsiphase_print(ahd_inb(ahd, SCSIPHASE), &cur_col, 50); + ahd_scsibus_print(ahd_inb(ahd, SCSIBUS), &cur_col, 50); ahd_lastphase_print(ahd_inb(ahd, LASTPHASE), &cur_col, 50); ahd_seq_flags_print(ahd_inb(ahd, SEQ_FLAGS), &cur_col, 50); ahd_seq_flags2_print(ahd_inb(ahd, SEQ_FLAGS2), &cur_col, 50); @@ -7691,6 +7746,14 @@ ahd_dump_card_state(struct ahd_softc *ahd) ahd_sstat2_print(ahd_inb(ahd, SSTAT2), &cur_col, 50); ahd_sstat3_print(ahd_inb(ahd, SSTAT3), &cur_col, 50); ahd_perrdiag_print(ahd_inb(ahd, PERRDIAG), &cur_col, 50); + ahd_simode1_print(ahd_inb(ahd, SIMODE1), &cur_col, 50); + ahd_lqistat0_print(ahd_inb(ahd, LQISTAT0), &cur_col, 50); + ahd_lqistat1_print(ahd_inb(ahd, LQISTAT1), &cur_col, 50); + ahd_lqistat2_print(ahd_inb(ahd, LQISTAT2), &cur_col, 50); + ahd_lqostat0_print(ahd_inb(ahd, LQOSTAT0), &cur_col, 50); + ahd_lqostat1_print(ahd_inb(ahd, LQOSTAT1), &cur_col, 50); + ahd_lqostat2_print(ahd_inb(ahd, LQOSTAT2), &cur_col, 50); + printf("\n"); printf("\nSCB Count = %d LASTSCB 0x%x CURRSCB 0x%x NEXTSCB 0x%x\n", ahd->scb_data.numscbs, ahd_inw(ahd, LASTSCB), ahd_inw(ahd, CURRSCB), ahd_inw(ahd, NEXTSCB)); @@ -7699,17 +7762,17 @@ ahd_dump_card_state(struct ahd_softc *ahd) ahd_search_qinfifo(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS, CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN, /*status*/0, SEARCH_PRINT); + saved_scb_index = ahd_get_scbptr(ahd); printf("Pending list:"); i = 0; LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) { if (i++ > AHD_SCB_MAX) break; - if (scb != LIST_FIRST(&ahd->pending_scbs)) - printf(", "); - cur_col = printf("\n%3d", SCB_GET_TAG(scb)); + cur_col = printf("\n%3d ", SCB_GET_TAG(scb)); ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); - ahd_scb_control_print(ahd_inb(ahd, SCB_CONTROL), &cur_col, 50); - ahd_scb_scsiid_print(ahd_inb(ahd, SCB_SCSIID), &cur_col, 50); + ahd_scb_control_print(ahd_inb(ahd, SCB_CONTROL), &cur_col, 60); + ahd_scb_scsiid_print(ahd_inb(ahd, SCB_SCSIID), &cur_col, 60); + ahd_scb_tag_print(ahd_inb(ahd, SCB_TAG), &cur_col, 60); } printf("\n"); @@ -7762,11 +7825,7 @@ ahd_dump_card_state(struct ahd_softc *ahd) scb_index = ahd_inw(ahd, SCB_NEXT_COMPLETE); } printf("\n"); - cur_col = 0; - ahd_simode1_print(ahd_inb(ahd, SIMODE1), &cur_col, 50); - ahd_lqistat0_print(ahd_inb(ahd, LQISTAT0), &cur_col, 50); - ahd_lqistat1_print(ahd_inb(ahd, LQISTAT1), &cur_col, 50); - ahd_lqistat2_print(ahd_inb(ahd, LQISTAT2), &cur_col, 50); + ahd_set_scbptr(ahd, saved_scb_index); dffstat = ahd_inb(ahd, DFFSTAT); for (i = 0; i < 2; i++) { #ifdef AHD_DEBUG @@ -7775,7 +7834,7 @@ ahd_dump_card_state(struct ahd_softc *ahd) u_int fifo_scbptr; ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i); - fifo_scbptr = ahd_inb(ahd, SCBPTR); + fifo_scbptr = ahd_get_scbptr(ahd); printf("\n%s: FIFO%d %s, LONGJMP == 0x%x, " "SCB 0x%x, LJSCB 0x%x\n", ahd_name(ahd), i, @@ -7822,7 +7881,7 @@ ahd_dump_card_state(struct ahd_softc *ahd) } #endif } - printf("LQIN: "); + printf("\nLQIN: "); for (i = 0; i < 20; i++) printf("0x%x ", ahd_inb(ahd, LQIN + i)); printf("\n"); @@ -7861,10 +7920,12 @@ void ahd_dump_scbs(struct ahd_softc *ahd) { ahd_mode_state saved_modes; + u_int saved_scb_index; int i; saved_modes = ahd_save_modes(ahd); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); + saved_scb_index = ahd_get_scbptr(ahd); for (i = 0; i < AHD_SCB_MAX; i++) { ahd_set_scbptr(ahd, i); printf("%3d", i); @@ -7875,6 +7936,7 @@ ahd_dump_scbs(struct ahd_softc *ahd) ahd_inl(ahd, SCB_RESIDUAL_SGPTR)); } printf("\n"); + ahd_set_scbptr(ahd, saved_scb_index); ahd_restore_modes(ahd, saved_modes); } diff --git a/sys/dev/aic7xxx/aic79xx.h b/sys/dev/aic7xxx/aic79xx.h index fee45dd..293e01c 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#56 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#61 $ * * $FreeBSD$ */ @@ -243,7 +243,11 @@ typedef enum { AHD_AUTOFLUSH_BUG = 0x0200, AHD_CLRLQO_AUTOCLR_BUG = 0x0400, AHD_PKTIZED_STATUS_BUG = 0x0800, - AHD_PKT_LUN_BUG = 0x1000 + AHD_PKT_LUN_BUG = 0x1000, + AHD_MDFF_WSCBPTR_BUG = 0x2000, + AHD_REG_SLOW_SETTLE_BUG = 0x4000, + AHD_SET_MODE_BUG = 0x8000, + AHD_BUSFREEREV_BUG = 0x10000 } ahd_bug; /* @@ -409,9 +413,9 @@ struct hardware_scb { * transfer. */ #define SG_PTR_MASK 0xFFFFFFF8 -/*16*/ uint8_t cdb_len; -/*17*/ uint8_t task_management; -/*18*/ uint16_t tag; +/*16*/ uint16_t tag; +/*18*/ uint8_t cdb_len; +/*19*/ uint8_t task_management; /*20*/ uint32_t next_hscb_busaddr; /*24*/ uint64_t dataptr; /*32*/ uint32_t datacnt; /* Byte 3 is spare. */ @@ -422,7 +426,7 @@ struct hardware_scb { * Our Id (bits 0-3) Their ID (bits 4-7) */ /*42*/ uint8_t lun; -/*43*/ uint8_t task_attribute_nonpkt_tag; +/*43*/ uint8_t task_attribute; /*44*/ uint32_t hscb_busaddr; /******* Long lun field only downloaded for full 8 byte lun support *******/ /*48*/ uint8_t pkt_long_lun[8]; diff --git a/sys/dev/aic7xxx/aic79xx.reg b/sys/dev/aic7xxx/aic79xx.reg index 4e80566..81f1906 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#39 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#45 $" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -56,10 +56,22 @@ VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#39 $" #define M_DST_SHIFT 4 #define MK_MODE(src, dst) ((src) | ((dst) << M_DST_SHIFT)) -#define SET_MODE(src, dst) \ - SET_SRC_MODE src; \ - SET_DST_MODE dst; \ - mvi MK_MODE(src, dst) call set_mode_work_around +#define SET_MODE(src, dst) \ + SET_SRC_MODE src; \ + SET_DST_MODE dst; \ + if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { \ + mvi MK_MODE(src, dst) call set_mode_work_around; \ + } else { \ + mvi MODE_PTR, MK_MODE(src, dst); \ + } + +#define TOGGLE_DFF_MODE \ + if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { \ + call toggle_dff_mode_work_around; \ + } else { \ + xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); \ + } + /* * Mode Pointer @@ -1807,7 +1819,7 @@ register SSTAT1 { * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1. */ register CLRSINT1 { - address 0x04c + address 0x04C access_mode WO modes M_DFF0, M_DFF1, M_SCSI field CLRSELTIMEO 0x80 @@ -3347,7 +3359,7 @@ scratch_ram { REG1 { size 2 } - REG2 { + REG_ISR { size 2 } SG_STATE { @@ -3464,8 +3476,8 @@ scratch_ram { SEQ_FLAGS { size 1 field NOT_IDENTIFIED 0x80 - field TARGET_CMD_IS_TAGGED 0x40 field NO_CDB_SENT 0x40 + field TARGET_CMD_IS_TAGGED 0x40 field DPHASE 0x20 /* Target flags */ field TARG_CMD_PENDING 0x10 @@ -3493,6 +3505,7 @@ scratch_ram { field CDI 0x80 field IOI 0x40 field MSGI 0x20 + field P_BUSFREE 0x01 enum PHASE_MASK CDO|IOO|MSGO { P_DATAOUT 0x0, P_DATAIN IOO, @@ -3501,8 +3514,7 @@ scratch_ram { P_COMMAND CDO, P_MESGOUT CDO|MSGO, P_STATUS CDO|IOO, - P_MESGIN CDO|IOO|MSGO, - P_BUSFREE 0x01 + P_MESGIN CDO|IOO|MSGO } } /* @@ -3586,10 +3598,14 @@ scratch_ram { SEQ_FLAGS2 { size 1 - field SCB_DMA 0x01 field TARGET_MSG_PENDING 0x02 field SELECTOUT_QFROZEN 0x04 } + + ALLOCFIFO_SCBPTR { + size 2 + } + /* * Target-mode CDB type to CDB length table used * in non-packetized operation. @@ -3636,6 +3652,9 @@ scb { size 4 alias SCB_NEXT_COMPLETE } + SCB_TAG { + size 2 + } SCB_CDB_LEN { size 1 field SCB_CDB_LEN_PTR 0x80 /* CDB in host memory */ @@ -3643,9 +3662,6 @@ scb { SCB_TASK_MANAGEMENT { size 1 } - SCB_TAG { - size 2 - } SCB_NEXT { alias SCB_NEXT_SCB_BUSADDR size 2 diff --git a/sys/dev/aic7xxx/aic79xx.seq b/sys/dev/aic7xxx/aic79xx.seq index be733e202..e21fb60 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#51 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#60 $" PATCH_ARG_LIST = "struct ahd_softc *ahd" PREFIX = "ahd_" @@ -48,7 +48,7 @@ PREFIX = "ahd_" #include "scsi_message.h" idle_loop: - SET_MODE(M_SCSI, M_SCSI); + SET_MODE(M_SCSI, M_SCSI) test SCSISEQ0, ENSELO|ENARBO jnz idle_loop_checkbus; test SEQ_FLAGS2, SELECTOUT_QFROZEN jnz idle_loop_checkbus; cmp WAITING_TID_HEAD[1], SCB_LIST_NULL je idle_loop_checkbus; @@ -94,14 +94,9 @@ good_status_IU_done: * 2) Configured and draining to the host, no pending CLRCHN. * 3) Pending cfg4data, fifo not empty. * - * For case 1, we assume that our DMA post of the completed command - * will occur after the FIFO finishes draining due to the higher - * priority of data FIFO transfers relative to command channel - * transfers. - * - * Case 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. + * 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 3 implies either a pending or yet to occur save data * pointers for this same context in the other FIFO. So, if @@ -123,21 +118,21 @@ BEGIN_CRITICAL; good_status_check_fifos: clc; bmov ARG_1, SCBPTR, 2; - SET_MODE(M_DFF0, M_DFF0); + SET_MODE(M_DFF0, M_DFF0) call check_fifo; jc idle_loop_service_fifos; - SET_MODE(M_DFF1, M_DFF1); + SET_MODE(M_DFF1, M_DFF1) call check_fifo; jc idle_loop_service_fifos; - SET_MODE(M_SCSI, M_SCSI); + SET_MODE(M_SCSI, M_SCSI) call queue_scb_completion; END_CRITICAL; idle_loop_service_fifos: - SET_MODE(M_DFF0, M_DFF0); + SET_MODE(M_DFF0, M_DFF0) test LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_next_fifo; call longjmp; idle_loop_next_fifo: - SET_MODE(M_DFF1, M_DFF1); + SET_MODE(M_DFF1, M_DFF1) test LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_last_fifo_done; call longjmp; idle_loop_last_fifo_done: @@ -145,10 +140,12 @@ idle_loop_last_fifo_done: jmp idle_loop; idle_loop_cchan: - SET_MODE(M_CCHAN, M_CCHAN); + SET_MODE(M_CCHAN, M_CCHAN) +BEGIN_CRITICAL; test CCSCBCTL, CCARREN|CCSCBEN jz scbdma_idle; test CCSCBCTL, CCSCBDIR jnz fetch_new_scb_inprog; test CCSCBCTL, CCSCBDONE jz return; +END_CRITICAL; /* FALLTHROUGH */ scbdma_tohost_done: test CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone; @@ -168,6 +165,7 @@ fill_qoutfifo_dmadone: bmov QOUTFIFO_NEXT_ADDR, SHARED_DATA_ADDR, 4; xor QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID_TOGGLE ret; +BEGIN_CRITICAL; fetch_new_scb_inprog: test CCSCBCTL, ARRDONE jz return; fetch_new_scb_done: @@ -207,6 +205,7 @@ first_new_scb: bmov WAITING_TID_TAIL, REG0, 2; /* Increment our position in the QINFIFO. */ mov NONE, SNSCB_QOFF ret; +END_CRITICAL; scbdma_idle: /* @@ -278,8 +277,7 @@ SET_SRC_MODE M_CCHAN; SET_DST_MODE M_CCHAN; dma_scb: mvi SCBHCNT, SCB_TRANSFER_SIZE; - mov CCSCBCTL, SINDEX; - or SEQ_FLAGS2, SCB_DMA ret; + mov CCSCBCTL, SINDEX ret; BEGIN_CRITICAL; setjmp_setscb: @@ -299,11 +297,18 @@ END_CRITICAL; * fail to store the new mode value for restoration on * an iret. */ +if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { set_mode_work_around: mvi SEQINTCTL, INTVEC1DSL; mov MODE_PTR, SINDEX; clr SEQINTCTL ret; +toggle_dff_mode_work_around: + mvi SEQINTCTL, INTVEC1DSL; + xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); + clr SEQINTCTL ret; +} + SET_SRC_MODE M_SCSI; SET_DST_MODE M_SCSI; start_selection: @@ -361,21 +366,20 @@ allocate_fifo_loop: /* * Do whatever work is required to free a FIFO. */ - SET_MODE(M_DFF0, M_DFF0); + SET_MODE(M_DFF0, M_DFF0) test LONGJMP_ADDR[1], INVALID_ADDR jnz . + 2; call longjmp; - SET_MODE(M_DFF1, M_DFF1); + SET_MODE(M_DFF1, M_DFF1) test LONGJMP_ADDR[1], INVALID_ADDR jnz . + 2; call longjmp; - SET_MODE(M_SCSI, M_SCSI); + SET_MODE(M_SCSI, M_SCSI) allocate_fifo: and A, FIFO0FREE|FIFO1FREE, DFFSTAT; cmp A, FIFO0FREE|FIFO1FREE jne allocate_fifo_loop; take_fifo: - bmov ARG_1, SCBPTR, 2; or DFFSTAT, CURRFIFO; - SET_MODE(M_DFF1, M_DFF1); - bmov SCBPTR, ARG_1, 2 ret; + SET_MODE(M_DFF1, M_DFF1) + bmov SCBPTR, ALLOCFIFO_SCBPTR, 2 ret; /* * We have been reselected as an initiator @@ -384,6 +388,17 @@ take_fifo: SET_SRC_MODE M_SCSI; SET_DST_MODE M_SCSI; select_in: + if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { + /* + * This exposes a window whereby a + * busfree just after a selection will + * be missed, but there is not other safe + * way to enable busfree detection if + * the busfreerev function is broken. + */ + mvi CLRSINT1,CLRBUSFREE; + or SIMODE1, ENBUSFREE; + } or SXFRCTL0, SPIOEN; and SAVED_SCSIID, SELID_MASK, SELID; and A, OID, IOWNID; @@ -493,7 +508,6 @@ select_out_list_done: */ test SCB_CONTROL, MK_MESSAGE jnz select_out_inc_tid_q; shr DINDEX, 3, SCB_SCSIID; -/* XXX When we switch to SCB_SELOID, put +1 in addition below. */ or DINDEX, 1; /* Want only the second byte */ mvi DINDEX[1], ((WAITING_SCB_TAILS) >> 8); mvi DINDIR, SCB_LIST_NULL; @@ -529,6 +543,17 @@ select_out_no_message: select_out_non_packetized: /* Non packetized request. */ and SCSISEQ0, ~ENSELO; + if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { + /* + * This exposes a window whereby a + * busfree just after a selection will + * be missed, but there is not other safe + * way to enable busfree detection if + * the busfreerev function is broken. + */ + mvi CLRSINT1,CLRBUSFREE; + or SIMODE1, ENBUSFREE; + } mov SAVED_SCSIID, SCB_SCSIID; mov SAVED_LUN, SCB_LUN; or SXFRCTL0, SPIOEN; @@ -576,6 +601,7 @@ SET_DST_MODE M_DFF1; */ mvi DFFSXFRCTL, RSTCHN|CLRSHCNT; p_command_allocate_fifo: + bmov ALLOCFIFO_SCBPTR, SCBPTR, 2; call allocate_fifo; add NONE, -17, SCB_CDB_LEN; jnc p_command_embedded; @@ -744,13 +770,10 @@ mesgin_done: mov NONE,SCSIDAT; /*dummy read from latch to ACK*/ jmp ITloop; -#define INDEX_DISC_LIST_SCB(scsiid, lun) \ +#define INDEX_DISC_LIST(scsiid, lun) \ and A, 0xC0, scsiid; \ or SCBPTR, A, lun; \ - clr SCBPTR[1] - -#define INDEX_DISC_LIST(scsiid, lun) \ - INDEX_DISC_LIST_SCB(scsiid, lun); \ + clr SCBPTR[1]; \ and SINDEX, 0x30, scsiid; \ shr SINDEX, 3; /* Multiply by 2 */ \ add SINDEX, (SCB_DISCONNECTED_LISTS & 0xFF); \ @@ -819,7 +842,8 @@ setup_SCB: setup_SCB_disconnected: and SCB_CONTROL,~DISCONNECTED; clr SEQ_FLAGS; /* make note of IDENTIFY */ - test SCB_SGPTR, SG_LIST_NULL jnz . + 2; + test SCB_SGPTR, SG_LIST_NULL jnz . + 3; + bmov ALLOCFIFO_SCBPTR, SCBPTR, 2; call allocate_fifo; /* See if the host wants to send a message upon reconnection */ test SCB_CONTROL, MK_MESSAGE jz mesgin_done; @@ -910,7 +934,7 @@ freeze_queue: mov A, ACCUM_SAVE ret; queue_arg1_scb_completion: - SET_MODE(M_SCSI, M_SCSI); + SET_MODE(M_SCSI, M_SCSI) bmov SCBPTR, ARG_1, 2; queue_scb_completion: test SCB_SCSI_STATUS,0xff jnz bad_status; @@ -962,8 +986,15 @@ queue_disc_scb: /* FALLTHROUGH */ await_busfree: and SIMODE1, ~ENBUSFREE; + if ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0) { + /* + * In the BUSFREEREV_BUG case, the + * busfree status was cleared at the + * beginning of the connection. + */ + mvi CLRSINT1,CLRBUSFREE; + } mov NONE, SCSIDAT; /* Ack the last byte */ - call clear_target_state; test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) jnz await_busfree_not_m_dff; SET_SRC_MODE M_DFF1; @@ -971,6 +1002,7 @@ SET_DST_MODE M_DFF1; await_busfree_clrchn: mvi DFFSXFRCTL, CLRCHN; await_busfree_not_m_dff: + call clear_target_state; test SSTAT1,REQINIT|BUSFREE jz .; test SSTAT1, BUSFREE jnz idle_loop; mvi SEQINTCODE, MISSED_BUSFREE; @@ -1080,20 +1112,19 @@ disable_ccsgen: disable_ccsgen_fetch_done: clr SG_STATE ret; -toggle_dff_mode: - mvi SEQINTCTL, INTVEC1DSL; - xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); - clr SEQINTCTL ret; - data_group_idle_loop: mov SAVED_MODE, MODE_PTR; test SG_STATE, LOADING_NEEDED jz . + 2; call service_fifo; - call toggle_dff_mode; + TOGGLE_DFF_MODE test SG_STATE, LOADING_NEEDED jz . + 2; call service_fifo; call idle_loop_cchan; - mov SAVED_MODE jmp set_mode_work_around; + if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { + mov SAVED_MODE jmp set_mode_work_around; + } else { + mov MODE_PTR, SAVED_MODE ret; + } service_fifo: /* @@ -1120,8 +1151,16 @@ service_fifo: * set the prefetch amount to a reasonable level if the * cacheline size is unknown. */ - mvi SGHCNT, SG_PREFETCH_CNT; and SGHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; + mvi SGHCNT, SG_PREFETCH_CNT; + if ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0) { + /* + * Need two instruction between "touches" of SGHADDR. + * Note the setting of SGHCNT counts as one of + * these two instructions. + */ + nop; + } bmov SGHADDR[1], SCB_RESIDUAL_SGPTR[1], 3; mvi CCSGCTL, CCSGEN|SG_CACHE_AVAIL|CCSGRESET; or SG_STATE, FETCH_INPROG ret; @@ -1190,12 +1229,12 @@ sg_advance: load_first_seg: bmov HADDR, SCB_DATAPTR, 11; and DATA_COUNT_ODD, 0x1, SCB_DATACNT[0]; - and REG0, ~SG_FULL_RESID, SCB_SGPTR[0]; + and REG_ISR, ~SG_FULL_RESID, SCB_SGPTR[0]; test SCB_DATACNT[3], SG_LAST_SEG jz . + 2; - or REG0, LAST_SEG; + or REG_ISR, LAST_SEG; test DATA_COUNT_ODD, 0x1 jz . + 2; - or REG0, ODD_SEG; - mov SG_CACHE_PRE, REG0; + or REG_ISR, ODD_SEG; + mov SG_CACHE_PRE, REG_ISR; mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN); /* * Since we've are entering a data phase, we will @@ -1225,6 +1264,7 @@ p_data_allowed: */ test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jnz p_data_bitbucket; mvi SEQINTCODE, PDATA_REINIT; + jmp data_group_dma_loop; p_data_bitbucket: /* @@ -1239,12 +1279,13 @@ p_data_bitbucket: * doesn't discard data already in the FIFO. */ mvi DFFSXFRCTL, RSTCHN|CLRSHCNT; - SET_MODE(M_SCSI, M_SCSI); + SET_MODE(M_SCSI, M_SCSI) bitbucket_not_m_dff: or SXFRCTL1,BITBUCKET; - test SCSIPHASE, DATA_PHASE_MASK jnz .; + /* Wait for non-data phase. */ + test SCSIPHASE, ~DATA_PHASE_MASK jz .; and SXFRCTL1, ~BITBUCKET; - SET_MODE(M_DFF1, M_DFF1); + SET_MODE(M_DFF1, M_DFF1) mvi SEQINTCODE, DATA_OVERRUN; jmp ITloop; @@ -1327,7 +1368,7 @@ data_phase_done: test DFCNTRL, DIRECTION jz target_ITloop; test SSTAT1, REQINIT jnz .; test DATA_COUNT_ODD, 0x1 jz target_ITloop; - SET_MODE(M_SCSI, M_SCSI); + SET_MODE(M_SCSI, M_SCSI) test NEGCONOPTS, WIDEXFER jz target_ITloop; */ /* @@ -1463,7 +1504,7 @@ cfg4istat_setup_handler: /* * See if the target has gone on in this context creating an * overrun condition. For the write case, the hardware cannot - * ack bytes until data is provided. So, if the target begins + * ack bytes until data are provided. So, if the target begins * another packet without changing contexts, implying we are * not sitting on a packet boundary, we are in an overrun * situation. For the read case, the hardware will continue to @@ -1503,8 +1544,46 @@ pkt_last_seg: test SCSIPHASE, ~DATA_PHASE_MASK jz . + 2; test SCSISIGO, ATNO jnz . + 2; test SSTAT2, NONPACKREQ jz return; - test MDFFSTAT, SHVALID jnz pkt_saveptrs; - jmp return; + test MDFFSTAT, SHVALID jz return; + /* FALLTHROUGH */ + +/* + * Either a SAVEPTRS interrupt condition is pending for this FIFO + * or we have a pending nonpackreq for this FIFO. We differentiate + * between the two by capturing the state of the SAVEPTRS interrupt + * prior to clearing this status and executing the common code for + * these two cases. + */ +pkt_saveptrs: +BEGIN_CRITICAL; + if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { + or DFCNTRL, FIFOFLUSH; + } + mov REG0, SEQINTSRC; + call calc_residual; + call save_pointers; + mvi CLRSEQINTSRC, CLRSAVEPTRS; + call disable_ccsgen; + or SEQIMODE, ENSAVEPTRS; + test DFCNTRL, DIRECTION jnz pkt_saveptrs_check_status; + test DFSTATUS, FIFOEMP jnz pkt_saveptrs_check_status; + /* + * Keep a handler around for this FIFO until it drains + * to the host to guarantee that we don't complete the + * command to the host before the data arrives. + */ +pkt_saveptrs_wait_fifoemp: + call setjmp; + test DFSTATUS, FIFOEMP jz return; +pkt_saveptrs_check_status: + or LONGJMP_ADDR[1], INVALID_ADDR; + test REG0, SAVEPTRS jz unexpected_nonpkt_phase; + test SCB_CONTROL, STATUS_RCVD jz pkt_saveptrs_clrchn; + jmp last_pkt_complete; +pkt_saveptrs_clrchn: + mvi DFFSXFRCTL, CLRCHN ret; +END_CRITICAL; + last_pkt_done: BEGIN_CRITICAL; if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { @@ -1514,10 +1593,11 @@ BEGIN_CRITICAL; check_overrun; or SCB_SGPTR, SG_LIST_NULL; /* - * I think it is safe to skip the FIFO check. - * in this case as LAST_SEG_DONE implies - * the other FIFO, if ever active for this transfer, - * has completed. + * It is safe to skip the other FIFO check since + * we defer CLRCHN on SAVEPTRS until all data in + * the FIFO are seen by the host and a CFG4DATA + * in this FIFO for the same context is held off + * by hardware. */ last_pkt_queue_scb: or LONGJMP_ADDR[1], INVALID_ADDR; @@ -1530,7 +1610,7 @@ last_pkt_complete: mvi DFFSXFRCTL, CLRCHN; check_other_fifo: clc; - call toggle_dff_mode; + TOGGLE_DFF_MODE call check_fifo; jnc queue_arg1_scb_completion; return: @@ -1553,32 +1633,6 @@ BEGIN_CRITICAL; mvi DFFSXFRCTL, CLRCHN ret; END_CRITICAL; -/* - * Either a SAVEPTRS interrupt condition is pending for this FIFO - * or we have a pending nonpackreq for this FIFO. We differentiate - * between the two by capturing the state of the SAVEPTRS interrupt - * prior to clearing and handling the common code of these two cases. - */ -pkt_saveptrs: -BEGIN_CRITICAL; - if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { - or DFCNTRL, FIFOFLUSH; - } - mov REG0, SEQINTSRC; - mvi CLRSEQINTSRC, CLRSAVEPTRS; - call calc_residual; - call save_pointers; - call disable_ccsgen; - or SEQIMODE, ENSAVEPTRS; - or LONGJMP_ADDR[1], INVALID_ADDR; -pkt_saveptrs_check_status: - test REG0, SAVEPTRS jz unexpected_nonpkt_phase; - test SCB_CONTROL, STATUS_RCVD jz pkt_saveptrs_clrchn; - jmp last_pkt_complete; -pkt_saveptrs_clrchn: - mvi DFFSXFRCTL, CLRCHN ret; -END_CRITICAL; - check_status_overrun: test SHCNT[2], 0xFF jz status_IU_done; mvi SEQINTCODE, STATUS_OVERRUN; @@ -1657,7 +1711,7 @@ pkt_handle_overrun: mvi SEQINTCODE, CFG4OVERRUN; call freeze_queue; if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0) { - SET_MODE(M_SCSI, M_SCSI); + SET_MODE(M_SCSI, M_SCSI) or SXFRCTL1,BITBUCKET; SET_SRC_MODE M_DFF1; SET_DST_MODE M_DFF1; diff --git a/sys/dev/aic7xxx/aic79xx_inline.h b/sys/dev/aic7xxx/aic79xx_inline.h index 46c85a5..1992c49 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#34 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#36 $ * * $FreeBSD$ */ @@ -226,48 +226,6 @@ ahd_unpause(struct ahd_softc *ahd) ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN); } -/*********************** Untagged Transaction Routines ************************/ -static __inline void ahd_freeze_untagged_queues(struct ahd_softc *ahd); -static __inline void ahd_release_untagged_queues(struct ahd_softc *ahd); - -/* - * Block our completion routine from starting the next untagged - * transaction for this target or target lun. - */ -static __inline void -ahd_freeze_untagged_queues(struct ahd_softc *ahd) -{ - /* - * Assume we have enough space in the card's SCB - * to obviate the need for a per target untagged - * transaction limit. - */ -#if 0 - ahd->untagged_queue_lock++; -#endif -} - -/* - * Allow the next untagged transaction for this target or target lun - * to be executed. We use a counting semaphore to allow the lock - * to be acquired recursively. Once the count drops to zero, the - * transaction queues will be run. - */ -static __inline void -ahd_release_untagged_queues(struct ahd_softc *ahd) -{ - /* - * Assume we have enough space in the card's SCB - * to obviate the need for a per target untagged - * transaction limit. - */ -#if 0 - ahd->untagged_queue_lock--; - if (ahd->untagged_queue_lock == 0) - ahd_run_untagged_queues(ahd); -#endif -} - /*********************** Scatter Gather List Handling *************************/ static __inline void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, void *sgptr, bus_addr_t addr, @@ -296,7 +254,7 @@ ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, struct ahd_dma_seg *sg; sg = (struct ahd_dma_seg *)sgptr; - sg->addr = ahd_htole64(addr); + sg->addr = ahd_htole32(addr & 0xFFFFFFFF); sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000) | (last ? AHD_DMA_LAST_SEG : 0)); return (sg + 1); @@ -309,15 +267,12 @@ ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb) /* XXX Handle target mode SCBs. */ if ((scb->flags & SCB_PACKETIZED) != 0) { /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */ - scb->hscb->task_attribute_nonpkt_tag = - scb->hscb->control & SCB_TAG_TYPE; + scb->hscb->task_attribute= scb->hscb->control & SCB_TAG_TYPE; scb->hscb->task_management = 0; /* * For Rev A short lun workaround. */ scb->hscb->pkt_long_lun[6] = scb->hscb->lun; - } else { - scb->hscb->task_attribute_nonpkt_tag = SCB_GET_TAG(scb); } if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR @@ -783,7 +738,6 @@ ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb) scb->hscb = q_hscb; /* Now define the mapping from tag to SCB in the scbindex */ -/* XXX This should be constant now. Can we avoid the mapping? */ ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; } diff --git a/sys/dev/aic7xxx/aic79xx_pci.c b/sys/dev/aic7xxx/aic79xx_pci.c index fe7e12b..c165ce2 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#41 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#44 $ * * $FreeBSD$ */ @@ -791,7 +791,9 @@ ahd_aic7902_setup(struct ahd_softc *ahd) | 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_PKT_LUN_BUG|AHD_MDFF_WSCBPTR_BUG + | AHD_REG_SLOW_SETTLE_BUG|AHD_SET_MODE_BUG + | AHD_BUSFREEREV_BUG; } ahd->channel = ahd_get_pci_function(pci) + 'A'; |