summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/aic7xxx/aic79xx.c238
-rw-r--r--sys/dev/aic7xxx/aic79xx.h16
-rw-r--r--sys/dev/aic7xxx/aic79xx.reg44
-rw-r--r--sys/dev/aic7xxx/aic79xx.seq222
-rw-r--r--sys/dev/aic7xxx/aic79xx_inline.h52
-rw-r--r--sys/dev/aic7xxx/aic79xx_pci.c6
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';
OpenPOWER on IntegriCloud