diff options
| author | Scott Long <scottl@FreeBSD.org> | 2002-12-01 08:13:37 +0000 |
|---|---|---|
| committer | Scott Long <scottl@FreeBSD.org> | 2002-12-01 08:13:37 +0000 |
| commit | 0c5aa4c57b9874b8ae016bb722deaaf4b6278068 (patch) | |
| tree | 8f5f273b1ccc8f34c05265b9f4327079f55c99a0 /sys | |
| parent | 454bf1693ad2014f7c1a7251d40ad6fb7400ddc1 (diff) | |
Notes
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/dev/aic7xxx/aic79xx.c | 701 | ||||
| -rw-r--r-- | sys/dev/aic7xxx/aic79xx.h | 204 | ||||
| -rw-r--r-- | sys/dev/aic7xxx/aic79xx.reg | 130 | ||||
| -rw-r--r-- | sys/dev/aic7xxx/aic79xx.seq | 286 |
4 files changed, 949 insertions, 372 deletions
diff --git a/sys/dev/aic7xxx/aic79xx.c b/sys/dev/aic7xxx/aic79xx.c index 7762fa2e479c..19a98c0db27b 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#113 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#139 $ * * $FreeBSD$ */ @@ -135,8 +135,6 @@ static void ahd_update_neg_table(struct ahd_softc *ahd, static void ahd_update_pending_scbs(struct ahd_softc *ahd); static void ahd_fetch_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo); -static void ahd_print_devinfo(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); static void ahd_scb_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, struct scb *scb); @@ -224,6 +222,7 @@ static u_int ahd_resolve_seqaddr(struct ahd_softc *ahd, u_int address); static void ahd_download_instr(struct ahd_softc *ahd, u_int instrptr, uint8_t *dconsts); +static int ahd_probe_stack_size(struct ahd_softc *ahd); #ifdef AHD_TARGET_MODE static void ahd_queue_lstate_event(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate, @@ -429,6 +428,18 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) */ seqintcode = ahd_inb(ahd, SEQINTCODE); ahd_outb(ahd, CLRINT, CLRSEQINT); + if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { + /* + * Unpause the sequencer and let it clear + * SEQINT by writing NO_SEQINT to it. This + * will cause the sequencer to be paused again, + * which is the expected state of this routine. + */ + ahd_unpause(ahd); + while (!ahd_is_paused(ahd)) + ; + ahd_outb(ahd, CLRINT, CLRSEQINT); + } ahd_update_modes(ahd); #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) @@ -464,16 +475,22 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) * CRC error with P0 asserted on last * packet. */ - printf("Assuming LQIPHASE_NLQ with P0 assertion\n"); +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) + printf("%s: Assuming LQIPHASE_NLQ with " + "P0 assertion\n", ahd_name(ahd)); +#endif } - printf("Entering NONPACK\n"); +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) + printf("%s: Entering NONPACK\n", ahd_name(ahd)); +#endif break; } case INVALID_SEQINT: printf("%s: Invalid Sequencer interrupt occurred.\n", ahd_name(ahd)); ahd_dump_card_state(ahd); - printf("invalid seqint"); ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); break; case STATUS_OVERRUN: @@ -601,16 +618,51 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) { ahd_outb(ahd, CLRLQOINT1, 0); } - printf("Continuing non-pack processing...\n"); +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { + ahd_print_path(ahd, scb); + printf("Unexpected command phase from " + "packetized target\n"); + } +#endif break; } } break; } case CFG4OVERRUN: - printf("%s: CFG4OVERRUN mode = %x\n", ahd_name(ahd), - ahd_inb(ahd, MODE_PTR)); + { + struct scb *scb; + u_int scb_index; + +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { + printf("%s: CFG4OVERRUN mode = %x\n", ahd_name(ahd), + ahd_inb(ahd, MODE_PTR)); + } +#endif + scb_index = ahd_get_scbptr(ahd); + scb = ahd_lookup_scb(ahd, scb_index); + if (scb == NULL) { + /* + * Attempt to transfer to an SCB that is + * not outstanding. + */ + ahd_assert_atn(ahd); + ahd_outb(ahd, MSG_OUT, HOST_MSG); + ahd->msgout_buf[0] = MSG_ABORT_TASK; + ahd->msgout_len = 1; + ahd->msgout_index = 0; + ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; + /* + * Clear status received flag to prevent any + * attempt to complete this bogus SCB. + */ + ahd_outb(ahd, SCB_CONTROL, + ahd_inb(ahd, SCB_CONTROL) & ~STATUS_RCVD); + } break; + } case DUMP_CARD_STATE: { ahd_dump_card_state(ahd); @@ -618,10 +670,14 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) } case PDATA_REINIT: { - printf("%s: PDATA_REINIT - DFCNTRL = 0x%x " - "SG_CACHE_SHADOW = 0x%x\n", - ahd_name(ahd), ahd_inb(ahd, DFCNTRL), - ahd_inb(ahd, SG_CACHE_SHADOW)); +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { + printf("%s: PDATA_REINIT - DFCNTRL = 0x%x " + "SG_CACHE_SHADOW = 0x%x\n", + ahd_name(ahd), ahd_inb(ahd, DFCNTRL), + ahd_inb(ahd, SG_CACHE_SHADOW)); + } +#endif ahd_reinitialize_dataptrs(ahd); break; } @@ -650,8 +706,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) if (bus_phase != P_MESGIN && bus_phase != P_MESGOUT) { printf("ahd_intr: HOST_MSG_LOOP bad " - "phase 0x%x\n", - bus_phase); + "phase 0x%x\n", bus_phase); /* * Probably transitioned to bus free before * we got here. Just punt the message. @@ -780,20 +835,29 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) * no way of knowing how large the overrun was. */ struct scb *scb; - u_int scbindex = ahd_get_scbptr(ahd); - u_int lastphase = ahd_inb(ahd, LASTPHASE); + u_int scbindex; +#ifdef AHD_DEBUG + u_int lastphase; +#endif + scbindex = ahd_get_scbptr(ahd); scb = ahd_lookup_scb(ahd, scbindex); - ahd_print_path(ahd, scb); - printf("data overrun detected %s." - " Tag == 0x%x.\n", - ahd_lookup_phase_entry(lastphase)->phasemsg, - SCB_GET_TAG(scb)); - ahd_print_path(ahd, scb); - printf("%s seen Data Phase. Length = %ld. NumSGs = %d.\n", - ahd_inb(ahd, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't", - ahd_get_transfer_length(scb), scb->sg_count); - ahd_dump_sglist(scb); +#ifdef AHD_DEBUG + lastphase = ahd_inb(ahd, LASTPHASE); + if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { + ahd_print_path(ahd, scb); + printf("data overrun detected %s. Tag == 0x%x.\n", + ahd_lookup_phase_entry(lastphase)->phasemsg, + SCB_GET_TAG(scb)); + ahd_print_path(ahd, scb); + printf("%s seen Data Phase. Length = %ld. " + "NumSGs = %d.\n", + ahd_inb(ahd, SEQ_FLAGS) & DPHASE + ? "Have" : "Haven't", + ahd_get_transfer_length(scb), scb->sg_count); + ahd_dump_sglist(scb); + } +#endif /* * Set this and it will take effect when the @@ -831,6 +895,18 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) ahd_inb(ahd, SCB_CONTROL) & ~MK_MESSAGE); break; } + case TRACEPOINT0: + case TRACEPOINT1: + case TRACEPOINT2: + case TRACEPOINT3: + printf("%s: Tracepoint %d\n", ahd_name(ahd), + seqintcode - TRACEPOINT0); + break; + case NO_SEQINT: + break; + case SAW_HWERR: + ahd_handle_hwerrint(ahd); + break; default: printf("%s: Unexpected SEQINTCODE %d\n", ahd_name(ahd), seqintcode); @@ -854,6 +930,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) u_int lqistat1; u_int lqostat0; u_int scbid; + u_int busfreetime; ahd_update_modes(ahd); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); @@ -863,6 +940,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) status = ahd_inb(ahd, SSTAT1) & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR); lqistat1 = ahd_inb(ahd, LQISTAT1); lqostat0 = ahd_inb(ahd, LQOSTAT0); + busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME; if ((status0 & (SELDI|SELDO)) != 0) { u_int simode0; @@ -910,7 +988,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) ahd_outb(ahd, CLRLQOINT1, 0); } } else if ((status & SELTO) != 0) { - u_int scbid; + u_int scbid; /* Stop the selection */ ahd_outb(ahd, SCSISEQ0, 0); @@ -938,8 +1016,8 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) "valid during SELTO scb(0x%x)\n", ahd_name(ahd), scbid); ahd_dump_card_state(ahd); - panic("For diagnostics"); } else { + struct ahd_devinfo devinfo; #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_SELTO) != 0) { ahd_print_path(ahd, scb); @@ -947,6 +1025,17 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) scbid); } #endif + /* + * Force a renegotiation with this target just in + * case the cable was pulled and will later be + * re-attached. The target may forget its negotiation + * settings with us should it attempt to reselect + * during the interruption. The target will not issue + * a unit attention in this case, so we must always + * renegotiate. + */ + ahd_scb_devinfo(ahd, &devinfo, scb); + ahd_force_renegotiation(ahd, &devinfo); ahd_set_transaction_status(scb, CAM_SEL_TIMEOUT); ahd_freeze_devq(ahd, scb); } @@ -963,7 +1052,6 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) } else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) { ahd_handle_lqiphase_error(ahd, lqistat1); } else if ((status & BUSFREE) != 0) { - u_int busfreetime; u_int lqostat1; int restart; int clear_fifo; @@ -983,7 +1071,6 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) * the busfree. */ mode = AHD_MODE_SCSI; - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME; lqostat1 = ahd_inb(ahd, LQOSTAT1); switch (busfreetime) { @@ -1075,6 +1162,8 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) static void ahd_handle_transmission_error(struct ahd_softc *ahd) { + struct scb *scb; + u_int scbid; u_int lqistat1; u_int lqistat2; u_int msg_out; @@ -1083,6 +1172,7 @@ ahd_handle_transmission_error(struct ahd_softc *ahd) u_int perrdiag; u_int cur_col; + scb = NULL; ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); lqistat1 = ahd_inb(ahd, LQISTAT1) & ~(LQIPHASE_LQ|LQIPHASE_NLQ); lqistat2 = ahd_inb(ahd, LQISTAT2); @@ -1094,8 +1184,12 @@ ahd_handle_transmission_error(struct ahd_softc *ahd) lqistate = ahd_inb(ahd, LQISTATE); if ((lqistate >= 0x1E && lqistate <= 0x24) || (lqistate == 0x29)) { - printf("%s: NLQCRC found via LQISTATE\n", - ahd_name(ahd)); +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { + printf("%s: NLQCRC found via LQISTATE\n", + ahd_name(ahd)); + } +#endif lqistat1 |= LQICRCI_NLQ; } ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); @@ -1146,9 +1240,6 @@ ahd_handle_transmission_error(struct ahd_softc *ahd) ahd_outb(ahd, LQCTL2, LQIRETRY); printf("LQIRetry for LQICRCI_LQ to release ACK\n"); } else if ((lqistat1 & LQICRCI_NLQ) != 0) { - u_int scbid; - struct scb *scb; - /* * We detected a CRC error in a NON-LQ packet. * The hardware has varying behavior in this situation @@ -1188,7 +1279,7 @@ ahd_handle_transmission_error(struct ahd_softc *ahd) * MSGOUT in or after a packet where P0 is not * asserted, the hardware will assert LQIPHASE_NLQ. * We should respond to the LQIPHASE_NLQ with an - * LQICONTINUE. Should the target stay in a non-pkt + * LQIRETRY. Should the target stay in a non-pkt * phase after we send our message, the hardware * will assert LQIPHASE_LQ. Recovery is then just as * listed above for the read streaming with P0 asserted. @@ -1204,12 +1295,13 @@ ahd_handle_transmission_error(struct ahd_softc *ahd) ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); return; } - scb->flags |= SCB_TRANSMISSION_ERROR; } else if ((lqistat1 & LQIBADLQI) != 0) { printf("Need to handle BADLQI!\n"); ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); return; } else if ((perrdiag & (PARITYERR|PREVPHASE)) == PARITYERR) { + scbid = ahd_get_scbptr(ahd); + scb = ahd_lookup_scb(ahd, scbid); if ((curphase & ~P_DATAIN_DT) != 0) { /* Ack the byte. So we can continue. */ printf("Acking %s to clear perror\n", @@ -1229,6 +1321,8 @@ ahd_handle_transmission_error(struct ahd_softc *ahd) * mesg_out to something other than MSG_NOP. */ ahd->send_msg_perror = msg_out; + if (scb != NULL && msg_out == MSG_INITIATOR_DET_ERR) + scb->flags |= SCB_TRANSMISSION_ERROR; ahd_outb(ahd, MSG_OUT, HOST_MSG); ahd_outb(ahd, CLRINT, CLRSCSIINT); ahd_unpause(ahd); @@ -1258,7 +1352,7 @@ ahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1) printf("LQIRETRY for LQIPHASE_LQ\n"); ahd_outb(ahd, LQCTL2, LQIRETRY); } else if ((lqistat1 & LQIPHASE_NLQ) != 0) { - printf("LQICONTINUE for LQIPHASE_NLQ\n"); + printf("LQIRETRY for LQIPHASE_NLQ\n"); ahd_outb(ahd, LQCTL2, LQIRETRY); } else panic("ahd_handle_lqiphase_error: No phase errors\n"); @@ -1316,9 +1410,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"); - ahd_print_path(ahd, scb); - printf("Probable outgoing LQ CRC error. Retrying command\n"); - /* * Return the LQO manager to its idle loop. It will * not do this automatically if the busfree occurs @@ -1357,6 +1448,33 @@ ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) ahd_outw(ahd, SCB_NEXT2, next); } ahd_set_scbptr(ahd, saved_scbptr); + if (scb->crc_retry_count < AHD_MAX_LQ_CRC_ERRORS) { + ahd_print_path(ahd, scb); + printf("Probable outgoing LQ CRC error. " + "Retrying command\n"); + scb->crc_retry_count++; + } else { + ahd_set_transaction_status(scb, CAM_UNCOR_PARITY); + ahd_freeze_scb(scb); + ahd_freeze_devq(ahd, scb); + } + /* Return unpausing the sequencer. */ + return (0); + } else if ((ahd_inb(ahd, PERRDIAG) & PARITYERR) != 0) { + /* + * Ignore what are really parity errors that + * occur on the last REQ of a free running + * clock prior to going busfree. Some drives + * do not properly active negate just before + * going busfree resulting in a parity glitch. + */ + ahd_outb(ahd, CLRSINT1, CLRSCSIPERR|CLRBUSFREE); +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_MASKED_ERRORS) != 0) + printf("%s: Parity on last REQ detected " + "during busfree phase.\n", + ahd_name(ahd)); +#endif /* Return unpausing the sequencer. */ return (0); } @@ -1395,6 +1513,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) u_int target; u_int initiator_role_id; u_int scbid; + u_int ppr_busfree; int printerror; /* @@ -1417,6 +1536,7 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) != 0) scb = NULL; + ppr_busfree = (ahd->msg_flags & MSG_FLAG_EXPECT_PPR_BUSFREE) != 0; if (lastphase == P_MESGOUT) { u_int tag; @@ -1482,7 +1602,8 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) "Bus Device Reset", /*verbose_level*/0); printerror = 0; - } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, FALSE)) { + } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, FALSE) + && ppr_busfree == 0) { struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; @@ -1490,6 +1611,10 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) * PPR Rejected. Try non-ppr negotiation * and retry command. */ +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) + printf("PPR negotiation rejected busfree.\n"); +#endif tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, devinfo.our_scsiid, devinfo.target, &tstate); @@ -1498,12 +1623,17 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) tinfo->goal.ppr_options = 0; ahd_qinfifo_requeue_tail(ahd, scb); printerror = 0; - } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, FALSE) - || ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, FALSE)) { + } else if ((ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, FALSE) + || ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, FALSE)) + && ppr_busfree == 0) { /* * Negotiation Rejected. Go-async and * retry command. */ +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) + printf("Negotiation rejected busfree.\n"); +#endif ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, AHD_TRANS_CUR|AHD_TRANS_GOAL, @@ -1524,6 +1654,15 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) printf("Expected IDE Busfree\n"); #endif printerror = 0; + } else if ((ahd->msg_flags & MSG_FLAG_EXPECT_QASREJ_BUSFREE) + && ahd_sent_msg(ahd, AHDMSG_1B, + MSG_MESSAGE_REJECT, TRUE)) { + +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) + printf("Expected QAS Reject Busfree\n"); +#endif + printerror = 0; } } @@ -1651,7 +1790,8 @@ ahd_handle_proto_violation(struct ahd_softc *ahd) ahd_dump_card_state(ahd); } } - if ((lastphase & ~P_DATAIN_DT) == 0) { + if ((lastphase & ~P_DATAIN_DT) == 0 + || lastphase == P_COMMAND) { proto_violation_reset: /* * Target either went directly to data @@ -1697,16 +1837,19 @@ ahd_force_renegotiation(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) struct ahd_initiator_tinfo *targ_info; struct ahd_tmode_tstate *tstate; - printf("Forcing renegotiation (%d:%c:%d)\n", - devinfo->our_scsiid, devinfo->channel, - devinfo->target); +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { + ahd_print_devinfo(ahd, devinfo); + printf("Forcing renegotiation\n"); + } +#endif targ_info = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); ahd_update_neg_request(ahd, devinfo, tstate, - targ_info, /*force*/TRUE); + targ_info, AHD_NEG_IF_NON_ASYNC); } #define AHD_MAX_STEPS 2000 @@ -1716,12 +1859,28 @@ ahd_clear_critical_section(struct ahd_softc *ahd) ahd_mode_state saved_modes; int stepping; int steps; + int first_instr; + u_int simode0; + u_int simode1; + u_int simode3; + u_int lqimode0; + u_int lqimode1; + u_int lqomode0; + u_int lqomode1; if (ahd->num_critical_sections == 0) return; stepping = FALSE; steps = 0; + first_instr = 0; + simode0 = 0; + simode1 = 0; + simode3 = 0; + lqimode0 = 0; + lqimode1 = 0; + lqomode0 = 0; + lqomode1 = 0; saved_modes = ahd_save_modes(ahd); for (;;) { struct cs *cs; @@ -1743,19 +1902,44 @@ ahd_clear_critical_section(struct ahd_softc *ahd) break; if (steps > AHD_MAX_STEPS) { - printf("%s: Infinite loop in critical section\n", - ahd_name(ahd)); + printf("%s: Infinite loop in critical section\n" + "%s: First Instruction 0x%x now 0x%x\n", + ahd_name(ahd), ahd_name(ahd), first_instr, + seqaddr); ahd_dump_card_state(ahd); panic("critical section loop"); } steps++; +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_MISC) != 0) + printf("%s: Single stepping at 0x%x\n", ahd_name(ahd), + seqaddr); +#endif if (stepping == FALSE) { + first_instr = seqaddr; + ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); + simode0 = ahd_inb(ahd, SIMODE0); + simode3 = ahd_inb(ahd, SIMODE3); + lqimode0 = ahd_inb(ahd, LQIMODE0); + lqimode1 = ahd_inb(ahd, LQIMODE1); + lqomode0 = ahd_inb(ahd, LQOMODE0); + lqomode1 = ahd_inb(ahd, LQOMODE1); + ahd_outb(ahd, SIMODE0, 0); + ahd_outb(ahd, SIMODE3, 0); + ahd_outb(ahd, LQIMODE0, 0); + ahd_outb(ahd, LQIMODE1, 0); + ahd_outb(ahd, LQOMODE0, 0); + ahd_outb(ahd, LQOMODE1, 0); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); + simode1 = ahd_inb(ahd, SIMODE1); + ahd_outb(ahd, SIMODE1, ENBUSFREE); ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) | STEP); stepping = TRUE; } + ahd_outb(ahd, CLRSINT1, CLRBUSFREE); + ahd_outb(ahd, CLRINT, CLRSCSIINT); ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); ahd_outb(ahd, HCNTRL, ahd->unpause); do { @@ -1764,8 +1948,16 @@ ahd_clear_critical_section(struct ahd_softc *ahd) ahd_update_modes(ahd); } if (stepping) { + ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); + ahd_outb(ahd, SIMODE0, simode0); + ahd_outb(ahd, SIMODE3, simode3); + ahd_outb(ahd, LQIMODE0, lqimode0); + ahd_outb(ahd, LQIMODE1, lqimode1); + ahd_outb(ahd, LQOMODE0, lqomode0); + ahd_outb(ahd, LQOMODE1, lqomode1); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) & ~STEP); + ahd_outb(ahd, SIMODE1, simode1); } ahd_restore_modes(ahd, saved_modes); } @@ -1795,7 +1987,8 @@ ahd_clear_intstat(struct ahd_softc *ahd) ahd_outb(ahd, CLRSINT3, CLRNTRAMPERR|CLROSRAMPERR); ahd_outb(ahd, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI |CLRBUSFREE|CLRSCSIPERR|CLRREQINIT); - ahd_outb(ahd, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO|CLRIOERR); + ahd_outb(ahd, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO + |CLRIOERR|CLROVERRUN); ahd_outb(ahd, CLRINT, CLRSCSIINT); } @@ -1975,6 +2168,8 @@ ahd_devlimited_syncrate(struct ahd_softc *ahd, else transinfo = &tinfo->goal; *ppr_options &= (transinfo->ppr_options|MSG_EXT_PPR_PCOMP_EN); + if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT) + maxsync = MAX(maxsync, AHD_SYNCRATE_ULTRA2); if (transinfo->period == 0) { *period = 0; *ppr_options = 0; @@ -2014,6 +2209,9 @@ ahd_find_syncrate(struct ahd_softc *ahd, u_int *period, *period = 0; /* Honor PPR option conformance rules. */ + if (*period > AHD_SYNCRATE_PACED) + *ppr_options &= ~MSG_EXT_PPR_RTI; + if ((*ppr_options & MSG_EXT_PPR_IU_REQ) == 0) *ppr_options &= (MSG_EXT_PPR_DT_REQ|MSG_EXT_PPR_QAS_REQ); @@ -2036,10 +2234,13 @@ ahd_validate_offset(struct ahd_softc *ahd, /* Limit offset to what we can do */ if (period == 0) maxoffset = 0; - else if (period <= AHD_SYNCRATE_PACED) - maxoffset = MAX_OFFSET_PACED; - else - maxoffset = MAX_OFFSET; + else if (period <= AHD_SYNCRATE_PACED) { + if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) + maxoffset = MAX_OFFSET_PACED_BUG; + else + maxoffset = MAX_OFFSET_PACED; + } else + maxoffset = MAX_OFFSET_NON_PACED; *offset = MIN(*offset, maxoffset); if (tinfo != NULL) { if (role == ROLE_TARGET) @@ -2086,17 +2287,29 @@ ahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo, int ahd_update_neg_request(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, struct ahd_tmode_tstate *tstate, - struct ahd_initiator_tinfo *tinfo, int force) + struct ahd_initiator_tinfo *tinfo, ahd_neg_type neg_type) { u_int auto_negotiate_orig; auto_negotiate_orig = tstate->auto_negotiate; + if (neg_type == AHD_NEG_ALWAYS) { + /* + * Force our "current" settings to be + * unknown so that unless a bus reset + * occurs the need to renegotiate is + * recorded persistently. + */ + tinfo->curr.period = AHD_PERIOD_UNKNOWN; + tinfo->curr.width = AHD_WIDTH_UNKNOWN; + tinfo->curr.offset = AHD_OFFSET_UNKNOWN; + tinfo->curr.ppr_options = AHD_OFFSET_UNKNOWN; + } if (tinfo->curr.period != tinfo->goal.period || tinfo->curr.width != tinfo->goal.width || tinfo->curr.offset != tinfo->goal.offset || tinfo->curr.ppr_options != tinfo->goal.ppr_options - || (force - && (tinfo->goal.period != 0 + || (neg_type == AHD_NEG_IF_NON_ASYNC + && (tinfo->goal.offset != 0 || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT || tinfo->goal.ppr_options != 0))) tstate->auto_negotiate |= devinfo->target_mask; @@ -2200,8 +2413,10 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, if ((old_ppr & MSG_EXT_PPR_IU_REQ) != (ppr_options & MSG_EXT_PPR_IU_REQ)) { #ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) + if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { + ahd_print_devinfo(ahd, devinfo); printf("Expecting IU Change busfree\n"); + } #endif ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE | MSG_FLAG_IU_REQ_CHANGED; @@ -2217,7 +2432,7 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, } update_needed += ahd_update_neg_request(ahd, devinfo, tstate, - tinfo, /*force*/FALSE); + tinfo, AHD_NEG_TO_GOAL); if (update_needed && active) ahd_update_pending_scbs(ahd); @@ -2276,7 +2491,7 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, } update_needed += ahd_update_neg_request(ahd, devinfo, tstate, - tinfo, /*force*/FALSE); + tinfo, AHD_NEG_TO_GOAL); if (update_needed && active) ahd_update_pending_scbs(ahd); @@ -2303,7 +2518,7 @@ ahd_update_neg_table(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, u_int ppr_opts; u_int con_opts; u_int offset; - u_int precomp; + uint8_t iocell_opts[sizeof(ahd->iocell_opts)]; saved_modes = ahd_save_modes(ahd); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); @@ -2311,42 +2526,66 @@ ahd_update_neg_table(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, ahd_outb(ahd, NEGOADDR, devinfo->target); period = tinfo->period; offset = tinfo->offset; - precomp = 0; + memcpy(iocell_opts, ahd->iocell_opts, sizeof(ahd->iocell_opts)); + ppr_opts = tinfo->ppr_options & (MSG_EXT_PPR_QAS_REQ|MSG_EXT_PPR_DT_REQ + |MSG_EXT_PPR_IU_REQ|MSG_EXT_PPR_RTI); + con_opts = 0; if (period == 0) period = AHD_SYNCRATE_ASYNC; if (period == AHD_SYNCRATE_160) { - period = AHD_SYNCRATE_REVA_160; - precomp = 0; - if ((ahd->flags & AHD_CPQ_BOARD) == 0) - precomp |= AHD_PRECOMP_FASTSLEW; - if ((tinfo->ppr_options & MSG_EXT_PPR_PCOMP_EN) != 0) - precomp |= AHD_PRECOMP_CUTBACK_29; + + if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) { + /* + * When the SPI4 spec was finalized, PACE transfers + * was not made a configurable option in the PPR + * message. Instead it is assumed to be enabled for + * any syncrate faster than 80MHz. Nevertheless, + * Harpoon2A4 allows this to be configurable. + * + * Harpoon2A4 also assumes at most 2 data bytes per + * negotiated REQ/ACK offset. Paced transfers take + * 4, so we must adjust our offset. + */ + ppr_opts |= PPROPT_PACE; + offset *= 2; + + /* + * Harpoon2A assumed that there would be a + * fallback rate between 160MHz and 80Mhz, + * so 7 is used as the period factor rather + * than 8 for 160MHz. + */ + period = AHD_SYNCRATE_REVA_160; + } + if ((tinfo->ppr_options & MSG_EXT_PPR_PCOMP_EN) == 0) + iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= + ~AHD_PRECOMP_MASK; + } else { + /* + * Precomp should be disabled for non-paced transfers. + */ + iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_PRECOMP_MASK; + + if ((ahd->features & AHD_NEW_IOCELL_OPTS) != 0 + && (ppr_opts & MSG_EXT_PPR_DT_REQ) != 0) { + /* + * Slow down our CRC interval to be + * compatible with devices that can't + * handle a CRC at full speed. + */ + con_opts |= ENSLOWCRC; + } } - ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PRECOMP); - ahd_outb(ahd, ANNEXDAT, precomp); + + ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PRECOMP_SLEW); + ahd_outb(ahd, ANNEXDAT, iocell_opts[AHD_PRECOMP_SLEW_INDEX]); + ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_AMPLITUDE); + ahd_outb(ahd, ANNEXDAT, iocell_opts[AHD_AMPLITUDE_INDEX]); ahd_outb(ahd, NEGPERIOD, period); - ppr_opts = tinfo->ppr_options - & (MSG_EXT_PPR_QAS_REQ|MSG_EXT_PPR_DT_REQ|MSG_EXT_PPR_IU_REQ); - /* - * When the SPI4 spec was finalized, PACE transfers - * was not made a configurable option in the PPR message. - * Instead it is assumed to be enabled for any - * syncrate faster than 80MHz. Nevertheless, Harpoon - * allows this to be configurable. - * - * Harpoon also assumes at most 2 data bytes per negotiated - * REQ/ACK offset. Paced transfers take 4, so we must - * adjust our offset. - */ - if (period <= AHD_SYNCRATE_PACED) { - ppr_opts |= PPROPT_PACE; - offset *= 2; - } ahd_outb(ahd, NEGPPROPTS, ppr_opts); ahd_outb(ahd, NEGOFFSET, offset); - con_opts = 0; if (tinfo->width == MSG_EXT_WDTR_BUS_16_BIT) con_opts |= WIDEXFER; @@ -2490,10 +2729,10 @@ ahd_fetch_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) ahd_restore_modes(ahd, saved_modes); } -static void +void ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) { - printf("%s:%c:%d:%d:", ahd_name(ahd), 'A', + printf("%s:%c:%d:%d: ", ahd_name(ahd), 'A', devinfo->target, devinfo->lun); } @@ -2573,7 +2812,10 @@ ahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, ahd->msgout_buf[ahd->msgout_index++] = ahd->send_msg_perror; ahd->msgout_len++; ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - printf("Setting up for Parity Error delivery\n"); +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) + printf("Setting up for Parity Error delivery\n"); +#endif return; } else if (scb == NULL) { printf("%s: WARNING. No pending message for " @@ -2683,7 +2925,6 @@ ahd_build_transfer_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) int dowide; int dosync; int doppr; - int use_ppr; u_int period; u_int ppr_options; u_int offset; @@ -2705,23 +2946,36 @@ ahd_build_transfer_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) &ppr_options, devinfo->role); dowide = tinfo->curr.width != tinfo->goal.width; dosync = tinfo->curr.period != period; - doppr = tinfo->curr.ppr_options != ppr_options; + /* + * Only use PPR if we have options that need it, even if the device + * claims to support it. There might be an expander in the way + * that doesn't. + */ + doppr = ppr_options != 0; if (!dowide && !dosync && !doppr) { dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; dosync = tinfo->goal.period != 0; - doppr = tinfo->goal.ppr_options != 0; } if (!dowide && !dosync && !doppr) { - panic("ahd_intr: AWAITING_MSG for negotiation, " - "but no negotiation needed\n"); - } + /* + * Force async with a WDTR message if we have a wide bus, + * or just issue an SDTR with a 0 offset. + */ + if ((ahd->features & AHD_WIDE) != 0) + dowide = 1; + else + dosync = 1; - use_ppr = (tinfo->curr.transport_version >= 3) || doppr; + if (bootverbose) { + ahd_print_devinfo(ahd, devinfo); + printf("Ensuring async\n"); + } + } /* Target initiated PPR is not allowed in the SCSI spec */ if (devinfo->role == ROLE_TARGET) - use_ppr = 0; + doppr = 0; /* * Both the PPR message and SDTR message require the @@ -2731,14 +2985,14 @@ ahd_build_transfer_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) * Regardless, guarantee that if we are using WDTR and SDTR * messages that WDTR comes first. */ - if (use_ppr || (dosync && !dowide)) { + if (doppr || (dosync && !dowide)) { offset = tinfo->goal.offset; ahd_validate_offset(ahd, tinfo, period, &offset, - use_ppr ? tinfo->goal.width - : tinfo->curr.width, + doppr ? tinfo->goal.width + : tinfo->curr.width, devinfo->role); - if (use_ppr) { + if (doppr) { ahd_construct_ppr(ahd, devinfo, period, offset, tinfo->goal.width, ppr_options); } else { @@ -2757,6 +3011,8 @@ static void ahd_construct_sdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, u_int period, u_int offset) { + if (offset == 0) + period = AHD_ASYNC_XFER_PERIOD; ahd->msgout_buf[ahd->msgout_index++] = MSG_EXTENDED; ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_SDTR_LEN; ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_SDTR; @@ -2806,6 +3062,8 @@ ahd_construct_ppr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, */ if (period <= AHD_SYNCRATE_PACED) ppr_options |= MSG_EXT_PPR_PCOMP_EN; + if (offset == 0) + period = AHD_ASYNC_XFER_PERIOD; ahd->msgout_buf[ahd->msgout_index++] = MSG_EXTENDED; ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_PPR_LEN; ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_PPR; @@ -3605,8 +3863,12 @@ ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) } #endif case MSG_QAS_REQUEST: - printf("%s: QAS request. SCSISIGI == 0x%x\n", - ahd_name(ahd), ahd_inb(ahd, SCSISIGI)); +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) + printf("%s: QAS request. SCSISIGI == 0x%x\n", + ahd_name(ahd), ahd_inb(ahd, SCSISIGI)); +#endif + ahd->msg_flags |= MSG_FLAG_EXPECT_QASREJ_BUSFREE; /* FALLTHROUGH */ case MSG_TERM_IO_PROC: default: @@ -3660,19 +3922,38 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) last_msg = ahd_inb(ahd, LAST_MSG); if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, /*full*/FALSE)) { - /* - * Target does not support the PPR message. - * Attempt to negotiate SPI-2 style. - */ - if (bootverbose) { - printf("(%s:%c:%d:%d): PPR Rejected. " - "Trying WDTR/SDTR\n", - ahd_name(ahd), devinfo->channel, - devinfo->target, devinfo->lun); + if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, /*full*/TRUE) + && tinfo->goal.period <= AHD_SYNCRATE_PACED) { + /* + * Target may not like our SPI-4 PPR Options. + * Attempt to negotiate 80MHz which will turn + * off these options. + */ + if (bootverbose) { + printf("(%s:%c:%d:%d): PPR Rejected. " + "Trying simple U160 PPR\n", + ahd_name(ahd), devinfo->channel, + devinfo->target, devinfo->lun); + } + tinfo->goal.period = AHD_SYNCRATE_DT; + tinfo->goal.ppr_options &= MSG_EXT_PPR_IU_REQ + | MSG_EXT_PPR_QAS_REQ + | MSG_EXT_PPR_DT_REQ; + } else { + /* + * Target does not support the PPR message. + * Attempt to negotiate SPI-2 style. + */ + if (bootverbose) { + printf("(%s:%c:%d:%d): PPR Rejected. " + "Trying WDTR/SDTR\n", + ahd_name(ahd), devinfo->channel, + devinfo->target, devinfo->lun); + } + tinfo->goal.ppr_options = 0; + tinfo->curr.transport_version = 2; + tinfo->goal.transport_version = 2; } - tinfo->goal.ppr_options = 0; - tinfo->curr.transport_version = 2; - tinfo->goal.transport_version = 2; ahd->msgout_index = 0; ahd->msgout_len = 0; ahd_build_transfer_msg(ahd, devinfo); @@ -3963,7 +4244,8 @@ ahd_reinitialize_dataptrs(struct ahd_softc *ahd) saved_modes = ahd_save_modes(ahd); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); ahd_outb(ahd, DFFSTAT, - ahd_inb(ahd, DFFSTAT) | (saved_modes == 0x11 ? CURRFIFO : 0)); + ahd_inb(ahd, DFFSTAT) + | (saved_modes == 0x11 ? CURRFIFO_1 : CURRFIFO_0)); /* * Determine initial values for data_addr and data_cnt @@ -4373,6 +4655,8 @@ ahd_free(struct ahd_softc *ahd) free(ahd->name, M_DEVBUF); if (ahd->seep_config != NULL) free(ahd->seep_config, M_DEVBUF); + if (ahd->saved_stack != NULL) + free(ahd->saved_stack, M_DEVBUF); #ifndef __FreeBSD__ free(ahd, M_DEVBUF); #endif @@ -5187,6 +5471,12 @@ ahd_init(struct ahd_softc *ahd) AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); + ahd->stack_size = ahd_probe_stack_size(ahd); + ahd->saved_stack = malloc(ahd->stack_size * sizeof(uint16_t), + M_DEVBUF, M_NOWAIT); + if (ahd->saved_stack == NULL) + return (ENOMEM); + /* * Verify that the compiler hasn't over-agressively * padded important structures. @@ -5301,6 +5591,13 @@ ahd_init(struct ahd_softc *ahd) if ((ahd->flags & AHD_INITIATORROLE) == 0) ahd->flags &= ~AHD_RESET_BUS_A; + /* + * Before committing these settings to the chip, give + * the OSM one last chance to modify our configuration. + */ + ahd_platform_init(ahd); + + /* Bring up the chip. */ ahd_chip_init(ahd); AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); @@ -5455,6 +5752,7 @@ ahd_chip_init(struct ahd_softc *ahd) } else { ahd_outb(ahd, OPTIONMODE, AUTOACKEN|BUSFREEREV|AUTO_MSGOUT_DE); } + ahd_outb(ahd, SCSCHKN, CURRFIFODEF|WIDERESEN); if ((ahd->chip & AHD_BUS_MASK) == AHD_PCIX) /* * Do not issue a target abort when a split completion @@ -5463,18 +5761,21 @@ ahd_chip_init(struct ahd_softc *ahd) */ ahd_outb(ahd, PCIXCTL, ahd_inb(ahd, PCIXCTL) | SPLTSTADIS); + if ((ahd->bugs & AHD_LQOOVERRUN_BUG) != 0) + ahd_outb(ahd, LQOSCSCTL, LQONOCHKOVER); + /* * Tweak IOCELL settings. */ - if ((ahd->flags & AHD_CPQ_BOARD) != 0) { + if ((ahd->flags & AHD_HP_BOARD) != 0) { for (i = 0; i < NUMDSPS; i++) { ahd_outb(ahd, DSPSELECT, i); - ahd_outb(ahd, WRTBIASCTL, WRTBIASCTL_CPQ_DEFAULT); + ahd_outb(ahd, WRTBIASCTL, WRTBIASCTL_HP_DEFAULT); } #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MISC) != 0) printf("%s: WRTBIASCTL now 0x%x\n", ahd_name(ahd), - WRTBIASCTL_CPQ_DEFAULT); + WRTBIASCTL_HP_DEFAULT); #endif } ahd_setup_iocell_workaround(ahd); @@ -5534,17 +5835,32 @@ ahd_chip_init(struct ahd_softc *ahd) ahd_outb(ahd, MULTARGID + 1, 0); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - /* - * Clear the spare bytes in the neg table to avoid - * spurious parity errors. - */ + /* Initialize the negotiation table. */ + if ((ahd->features & AHD_NEW_IOCELL_OPTS) == 0) { + /* + * Clear the spare bytes in the neg table to avoid + * spurious parity errors. + */ + for (target = 0; target < AHD_NUM_TARGETS; target++) { + ahd_outb(ahd, NEGOADDR, target); + ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PER_DEV0); + for (i = 0; i < AHD_NUM_PER_DEV_ANNEXCOLS; i++) + ahd_outb(ahd, ANNEXDAT, 0); + } + } for (target = 0; target < AHD_NUM_TARGETS; target++) { + struct ahd_devinfo devinfo; + struct ahd_initiator_tinfo *tinfo; + struct ahd_tmode_tstate *tstate; - ahd_outb(ahd, NEGOADDR, target); - ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PRECOMP); - for (i = 0; i < AHD_NUM_ANNEXCOLS; i++) - ahd_outb(ahd, ANNEXDAT, 0); + tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, + target, &tstate); + ahd_compile_devinfo(&devinfo, ahd->our_id, + target, CAM_LUN_WILDCARD, + 'A', ROLE_INITIATOR); + ahd_update_neg_table(ahd, &devinfo, &tinfo->curr); } + ahd_outb(ahd, CLRSINT3, NTRAMPERR|OSRAMPERR); ahd_outb(ahd, CLRINT, CLRSCSIINT); @@ -5633,15 +5949,6 @@ ahd_chip_init(struct ahd_softc *ahd) } /* - * Always enable abort on incoming L_Qs if this feature is - * supported. We use this to catch invalid SCB references. - */ - if ((ahd->bugs & AHD_ABORT_LQI_BUG) == 0) - ahd_outb(ahd, LQCTL1, ABORTPENDING); - else - ahd_outb(ahd, LQCTL1, 0); - - /* * Initialize the group code to command length table. * Vendor Unique codes are set to 0 so we only capture * the first byte of the cdb. These can be overridden @@ -5731,6 +6038,8 @@ ahd_default_config(struct ahd_softc *ahd) | MSG_EXT_PPR_IU_REQ | MSG_EXT_PPR_QAS_REQ | MSG_EXT_PPR_DT_REQ; + if ((ahd->features & AHD_RTI) != 0) + tinfo->user.ppr_options |= MSG_EXT_PPR_RTI; tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; @@ -5751,13 +6060,6 @@ ahd_default_config(struct ahd_softc *ahd) ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, /*ppr_options*/0, AHD_TRANS_CUR|AHD_TRANS_GOAL, /*paused*/TRUE); - /* - * The neg table must be initialized even if the - * new settings above are the same as those from - * when our xfer info data structures were allocated - * and initialized. - */ - ahd_update_neg_table(ahd, &devinfo, &tinfo->curr); } return (0); } @@ -5832,11 +6134,14 @@ ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc) user_tinfo->period = AHD_SYNCRATE_DT; #endif - if ((sc->device_flags[targ] & CFPACKETIZED) != 0) + 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 ((ahd->features & AHD_RTI) != 0) + user_tinfo->ppr_options |= MSG_EXT_PPR_RTI; + } if ((sc->device_flags[targ] & CFQAS) != 0) user_tinfo->ppr_options |= MSG_EXT_PPR_QAS_REQ; @@ -5868,13 +6173,6 @@ ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc) ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, /*ppr_options*/0, AHD_TRANS_CUR|AHD_TRANS_GOAL, /*paused*/TRUE); - /* - * The neg table must be initialized even if the - * new settings above are the same as those from - * when our xfer info data structures were allocated - * and initialized. - */ - ahd_update_neg_table(ahd, &devinfo, &tinfo->curr); } ahd->flags &= ~AHD_SPCHK_ENB_A; @@ -6204,8 +6502,11 @@ ahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb) void ahd_qinfifo_requeue_tail(struct ahd_softc *ahd, struct scb *scb) { - struct scb *prev_scb; + struct scb *prev_scb; + ahd_mode_state saved_modes; + saved_modes = ahd_save_modes(ahd); + ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); prev_scb = NULL; if (ahd_qinfifo_count(ahd) != 0) { u_int prev_tag; @@ -6217,6 +6518,7 @@ ahd_qinfifo_requeue_tail(struct ahd_softc *ahd, struct scb *scb) } ahd_qinfifo_requeue(ahd, prev_scb, scb); ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); + ahd_restore_modes(ahd, saved_modes); } static void @@ -6762,8 +7064,11 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) * actively connected). */ next_fifo = fifo = ahd_inb(ahd, DFFSTAT) & CURRFIFO; + if (next_fifo > CURRFIFO_1) + /* If disconneced, arbitrarily start with FIFO1. */ + next_fifo = fifo = 0; do { - next_fifo = next_fifo ^ CURRFIFO; + next_fifo ^= CURRFIFO_1; ahd_set_modes(ahd, next_fifo, next_fifo); ahd_outb(ahd, DFCNTRL, ahd_inb(ahd, DFCNTRL) & ~(SCSIEN|HDMAEN)); @@ -6775,7 +7080,6 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); ahd_outb(ahd, DFFSTAT, next_fifo); } while (next_fifo != fifo); - /* * Reset the bus if we are initiating this reset */ @@ -6977,7 +7281,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) siu = (struct scsi_status_iu_header *)scb->sense_data; ahd_set_scsi_status(scb, siu->status); #ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_SENSE) != 0) + if ((ahd_debug & AHD_SHOW_SENSE) != 0) { ahd_print_path(ahd, scb); printf("SCB 0x%x Received PKT Status of 0x%x\n", SCB_GET_TAG(scb), siu->status); @@ -6985,6 +7289,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) "pktfail = 0x%x\n", siu->flags, scsi_4btoul(siu->sense_length), scsi_4btoul(siu->pkt_failures_length)); + } #endif if ((siu->flags & SIU_RSPVALID) != 0) { ahd_print_path(ahd, scb); @@ -7105,7 +7410,7 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) if (ahd_get_residual(scb) == ahd_get_transfer_length(scb)) { ahd_update_neg_request(ahd, &devinfo, tstate, targ_info, - /*force*/TRUE); + AHD_NEG_IF_NON_ASYNC); } if (tstate->auto_negotiate & devinfo.target_mask) { hscb->control |= MK_MESSAGE; @@ -7117,16 +7422,11 @@ ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) ahd_setup_data_scb(ahd, scb); scb->flags |= SCB_SENSE; ahd_queue_scb(ahd, scb); -#ifdef __FreeBSD__ /* * Ensure we have enough time to actually * retrieve the sense. */ - untimeout(ahd_timeout, (caddr_t)scb, - scb->io_ctx->ccb_h.timeout_ch); - scb->io_ctx->ccb_h.timeout_ch = - timeout(ahd_timeout, (caddr_t)scb, 5 * hz); -#endif + ahd_scb_timer_reset(scb, 5 * 1000000); break; } case SCSI_STATUS_OK: @@ -7643,6 +7943,41 @@ ahd_download_instr(struct ahd_softc *ahd, u_int instrptr, uint8_t *dconsts) } } +static int +ahd_probe_stack_size(struct ahd_softc *ahd) +{ + int last_probe; + + last_probe = 0; + while (1) { + int i; + + /* + * We avoid using 0 as a pattern to avoid + * confusion if the stack implementation + * "back-fills" with zeros when "poping' + * entries. + */ + for (i = 1; i <= last_probe+1; i++) { + ahd_outb(ahd, STACK, i & 0xFF); + ahd_outb(ahd, STACK, (i >> 8) & 0xFF); + } + + /* Verify */ + for (i = last_probe+1; i > 0; i--) { + u_int stack_entry; + + stack_entry = ahd_inb(ahd, STACK) + |(ahd_inb(ahd, STACK) << 8); + if (stack_entry != i) + goto sized; + } + last_probe++; + } +sized: + return (last_probe); +} + void ahd_dump_all_cards_state() { @@ -7661,7 +7996,7 @@ ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries, int printed; u_int printed_mask; - if (*cur_column >= wrap_point) { + if (cur_column != NULL && *cur_column >= wrap_point) { printf("\n"); *cur_column = 0; } @@ -7696,7 +8031,8 @@ ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries, printed += printf(") "); else printed += printf(" "); - *cur_column += printed; + if (cur_column != NULL) + *cur_column += printed; return (printed); } @@ -7709,8 +8045,8 @@ ahd_dump_card_state(struct ahd_softc *ahd) int paused; u_int scb_index; u_int saved_scb_index; - u_int i; u_int cur_col; + int i; if (ahd_is_paused(ahd)) { paused = 1; @@ -7732,15 +8068,19 @@ ahd_dump_card_state(struct ahd_softc *ahd) * Mode independent registers. */ cur_col = 0; - ahd_scsiseq0_print(ahd_inb(ahd, SCSISEQ0), &cur_col, 50); - ahd_scsiseq1_print(ahd_inb(ahd, SCSISEQ1), &cur_col, 50); - ahd_seqintctl_print(ahd_inb(ahd, SEQINTCTL), &cur_col, 50); + ahd_saved_mode_print(ahd_inb(ahd, SAVED_MODE), &cur_col, 50); + ahd_dffstat_print(ahd_inb(ahd, DFFSTAT), &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_scsiseq0_print(ahd_inb(ahd, SCSISEQ0), &cur_col, 50); + ahd_scsiseq1_print(ahd_inb(ahd, SCSISEQ1), &cur_col, 50); + ahd_seqctl0_print(ahd_inb(ahd, SEQCTL0), &cur_col, 50); + ahd_seqintctl_print(ahd_inb(ahd, SEQINTCTL), &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); + ahd_ccscbctl_print(ahd_inb(ahd, CCSCBCTL), &cur_col, 50); ahd_sstat0_print(ahd_inb(ahd, SSTAT0), &cur_col, 50); ahd_sstat1_print(ahd_inb(ahd, SSTAT1), &cur_col, 50); ahd_sstat2_print(ahd_inb(ahd, SSTAT2), &cur_col, 50); @@ -7866,7 +8206,7 @@ ahd_dump_card_state(struct ahd_softc *ahd) printf("\n"); cur_col = 0; } - cur_col += printf("HADDR = 0x%x%x, HCNT = 0x%x", + cur_col += printf("HADDR = 0x%x%x, HCNT = 0x%x ", ahd_inl(ahd, HADDR+4), ahd_inl(ahd, HADDR), (ahd_inb(ahd, HCNT) @@ -7892,6 +8232,8 @@ ahd_dump_card_state(struct ahd_softc *ahd) printf("%s: OS_SPACE_CNT = 0x%x MAXCMDCNT = 0x%x\n", ahd_name(ahd), ahd_inb(ahd, OS_SPACE_CNT), ahd_inb(ahd, MAXCMDCNT)); + ahd_simode0_print(ahd_inb(ahd, SIMODE0), &cur_col, 50); + printf("\n"); ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); printf("%s: REG0 == 0x%x, SINDEX = 0x%x, DINDEX = 0x%x\n", ahd_name(ahd), ahd_inw(ahd, REG0), ahd_inw(ahd, SINDEX), @@ -7907,8 +8249,15 @@ ahd_dump_card_state(struct ahd_softc *ahd) ahd_inb(ahd, SCB_CDB_STORE+4), ahd_inb(ahd, SCB_CDB_STORE+5)); printf("STACK:"); - for(i = 0; i < SEQ_STACK_SIZE; i++) - printf(" 0x%x", ahd_inb(ahd, STACK)|(ahd_inb(ahd, STACK) << 8)); + for (i = 0; i < ahd->stack_size; i++) { + ahd->saved_stack[i] = + ahd_inb(ahd, STACK)|(ahd_inb(ahd, STACK) << 8); + printf(" 0x%x", ahd->saved_stack[i]); + } + for (i = ahd->stack_size-1; i >= 0; i--) { + ahd_outb(ahd, STACK, ahd->saved_stack[i] & 0xFF); + ahd_outb(ahd, STACK, (ahd->saved_stack[i] >> 8) & 0xFF); + } printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n"); ahd_platform_dump_card_state(ahd); ahd_restore_modes(ahd, saved_modes); diff --git a/sys/dev/aic7xxx/aic79xx.h b/sys/dev/aic7xxx/aic79xx.h index 293e01caffcb..2f9a47e49e5c 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#61 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#73 $ * * $FreeBSD$ */ @@ -213,14 +213,17 @@ typedef enum { * Features available in each chip type. */ typedef enum { - AHD_FENONE = 0x00000, - AHD_WIDE = 0x00001, /* Wide Channel */ - AHD_MULTI_FUNC = 0x00100, /* Multi-Function Twin Channel Device */ - AHD_TARGETMODE = 0x01000, /* Has tested target mode support */ - AHD_MULTIROLE = 0x02000, /* Space for two roles at a time */ - AHD_REMOVABLE = 0x00000, /* Hot-Swap supported - None so far*/ - AHD_AIC7901_FE = AHD_FENONE, - AHD_AIC7902_FE = AHD_MULTI_FUNC + AHD_FENONE = 0x00000, + AHD_WIDE = 0x00001,/* Wide Channel */ + AHD_MULTI_FUNC = 0x00100,/* Multi-Function/Channel Device */ + AHD_TARGETMODE = 0x01000,/* Has tested target mode support */ + AHD_MULTIROLE = 0x02000,/* Space for two roles at a time */ + AHD_RTI = 0x04000,/* Retained Training Support */ + AHD_NEW_IOCELL_OPTS = 0x08000,/* More Signal knobs in the IOCELL */ + AHD_NEW_DFCNTRL_OPTS = 0x10000,/* SCSIENWRDIS bit */ + AHD_REMOVABLE = 0x00000,/* Hot-Swap supported - None so far*/ + AHD_AIC7901_FE = AHD_FENONE, + AHD_AIC7902_FE = AHD_MULTI_FUNC } ahd_feature; /* @@ -228,26 +231,77 @@ typedef enum { */ typedef enum { AHD_BUGNONE = 0x0000, + /* + * Rev A hardware fails to update LAST/CURR/NEXTSCB + * correctly in certain packetized selection cases. + */ AHD_SENT_SCB_UPDATE_BUG = 0x0001, + /* The wrong SCB is accessed to check the abort pending bit. */ AHD_ABORT_LQI_BUG = 0x0002, + /* Packetized bitbucket crosses packet boundaries. */ AHD_PKT_BITBUCKET_BUG = 0x0004, + /* The selection timer runs twice as long as its setting. */ AHD_LONG_SETIMO_BUG = 0x0008, + /* The Non-LQ CRC error status is delayed until phase change. */ AHD_NLQICRC_DELAYED_BUG = 0x0010, + /* The chip must be reset for all outgoing bus resets. */ AHD_SCSIRST_BUG = 0x0020, + /* Some PCIX fields must be saved and restored across chip reset. */ AHD_PCIX_CHIPRST_BUG = 0x0040, + /* MMAPIO is not functional in PCI-X mode. */ AHD_PCIX_MMAPIO_BUG = 0x0080, /* Bug workarounds that can be disabled on non-PCIX busses. */ AHD_PCIX_BUG_MASK = AHD_PCIX_CHIPRST_BUG | AHD_PCIX_MMAPIO_BUG, + /* + * LQOSTOP0 status set even for forced selections with ATN + * to perform non-packetized message delivery. + */ AHD_LQO_ATNO_BUG = 0x0100, + /* FIFO auto-flush does not always trigger. */ AHD_AUTOFLUSH_BUG = 0x0200, + /* The CLRLQO registers are not self-clearing. */ AHD_CLRLQO_AUTOCLR_BUG = 0x0400, + /* The PACKETIZED status bit refers to the previous connection. */ AHD_PKTIZED_STATUS_BUG = 0x0800, + /* "Short Luns" are not placed into outgoing LQ packets correctly. */ 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 + /* + * Only the FIFO allocated to the non-packetized connection may + * be in use during a non-packetzied connection. + */ + AHD_NONPACKFIFO_BUG = 0x2000, + /* + * Writing to a DFF SCBPTR register may fail if concurent with + * a hardware write to the other DFF SCBPTR register. This is + * not currently a concern in our sequencer since all chips with + * this bug have the AHD_NONPACKFIFO_BUG and all writes of concern + * occur in non-packetized connections. + */ + AHD_MDFF_WSCBPTR_BUG = 0x4000, + /* SGHADDR updates are slow. */ + AHD_REG_SLOW_SETTLE_BUG = 0x8000, + /* + * Changing the MODE_PTR coincident with an interrupt that + * switches to a different mode will cause the interrupt to + * be in the mode written outside of interrupt context. + */ + AHD_SET_MODE_BUG = 0x10000, + /* Non-packetized busfree revision does not work. */ + AHD_BUSFREEREV_BUG = 0x20000, + /* + * Paced transfers are indicated with a non-standard PPR + * option bit in the neg table, 160MHz is indicated by + * sync factor 0x7, and the offset if off by a factor of 2. + */ + AHD_PACED_NEGTABLE_BUG = 0x40000, + /* LQOOVERRUN false positives. */ + AHD_LQOOVERRUN_BUG = 0x80000, + /* + * Controller write to INTSTAT will lose to a host + * write to CLRINT. + */ + AHD_INTCOLLISION_BUG = 0x100000 } ahd_bug; /* @@ -293,7 +347,7 @@ typedef enum { AHD_64BIT_ADDRESSING = 0x20000,/* Use 64 bit addressing scheme. */ AHD_CURRENT_SENSING = 0x40000, AHD_SCB_CONFIG_USED = 0x80000,/* No SEEPROM but SCB had info. */ - AHD_CPQ_BOARD = 0x100000, + AHD_HP_BOARD = 0x100000, AHD_RESET_POLL_ACTIVE = 0x200000 } ahd_flag; @@ -500,13 +554,13 @@ typedef enum { SCB_AUTO_NEGOTIATE = 0x00040,/* Negotiate to achieve goal. */ SCB_NEGOTIATE = 0x00080,/* Negotiation forced for command. */ SCB_ABORT = 0x00100, - SCB_ACTIVE = 0x00400, - SCB_TARGET_IMMEDIATE = 0x00800, - SCB_PACKETIZED = 0x01000, - SCB_EXPECT_PPR_BUSFREE = 0x02000, - SCB_PKT_SENSE = 0x04000, - SCB_CMDPHASE_ABORT = 0x08000, - SCB_ON_COL_LIST = 0x10000 + SCB_ACTIVE = 0x00200, + SCB_TARGET_IMMEDIATE = 0x00400, + SCB_PACKETIZED = 0x00800, + SCB_EXPECT_PPR_BUSFREE = 0x01000, + SCB_PKT_SENSE = 0x02000, + SCB_CMDPHASE_ABORT = 0x04000, + SCB_ON_COL_LIST = 0x08000 } scb_flag; struct scb { @@ -539,6 +593,8 @@ struct scb { bus_addr_t sg_list_busaddr; bus_addr_t sense_busaddr; u_int sg_count;/* How full ahd_dma_seg is */ +#define AHD_MAX_LQ_CRC_ERRORS 5 + u_int crc_retry_count; }; TAILQ_HEAD(scb_tailq, scb); @@ -654,6 +710,11 @@ struct ahd_tmode_lstate; #define AHD_PERIOD_ASYNC 0xFF #define AHD_PERIOD_10MHz 0x19 +#define AHD_WIDTH_UNKNOWN 0xFF +#define AHD_PERIOD_UNKNOWN 0xFF +#define AHD_OFFSET_UNKNOWN 0x0 +#define AHD_PPR_OPTS_UNKNOWN 0xFF + /* * Transfer Negotiation Information. */ @@ -708,6 +769,9 @@ struct ahd_tmode_tstate { #define AHD_SYNCRATE_MIN 0x60 #define AHD_SYNCRATE_ASYNC 0xFF +/* Safe and valid period for async negotiations. */ +#define AHD_ASYNC_XFER_PERIOD 0x44 + /* * In RevA, the synctable uses a 120MHz rate for the period * factor 8 and 160MHz for the period factor 7. The 120MHz @@ -852,7 +916,8 @@ typedef enum { MSG_FLAG_EXPECT_PPR_BUSFREE = 0x01, MSG_FLAG_IU_REQ_CHANGED = 0x02, MSG_FLAG_EXPECT_IDE_BUSFREE = 0x04, - MSG_FLAG_PACKETIZED = 0x08 + MSG_FLAG_EXPECT_QASREJ_BUSFREE = 0x08, + MSG_FLAG_PACKETIZED = 0x10 } ahd_msg_flags; typedef enum { @@ -1023,11 +1088,6 @@ struct ahd_softc { uint8_t our_id; /* - * PCI error detection. - */ - int unsolicited_ints; - - /* * Target incoming command FIFO. */ struct target_cmd *targetcmds; @@ -1066,6 +1126,12 @@ struct ahd_softc { /* PCI cacheline size. */ u_int pci_cachesize; + /* IO Cell Parameters */ + uint8_t iocell_opts[AHD_NUM_PER_DEV_ANNEXCOLS]; + + u_int stack_size; + uint16_t *saved_stack; + /* Per-Unit descriptive information */ const char *description; const char *bus_description; @@ -1082,6 +1148,34 @@ struct ahd_softc { TAILQ_HEAD(ahd_softc_tailq, ahd_softc); extern struct ahd_softc_tailq ahd_tailq; +/*************************** IO Cell Configuration ****************************/ +#define AHD_PRECOMP_SLEW_INDEX \ + (AHD_ANNEXCOL_PRECOMP_SLEW - AHD_ANNEXCOL_PER_DEV0) + +#define AHD_AMPLITUDE_INDEX \ + (AHD_ANNEXCOL_AMPLITUDE - AHD_ANNEXCOL_PER_DEV0) + +#define AHD_SET_SLEWRATE(ahd, new_slew) \ +do { \ + (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_SLEWRATE_MASK; \ + (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] |= \ + (((new_slew) << AHD_SLEWRATE_SHIFT) & AHD_SLEWRATE_MASK); \ +} while (0) + +#define AHD_SET_PRECOMP(ahd, new_pcomp) \ +do { \ + (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_PRECOMP_MASK; \ + (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] |= \ + (((new_pcomp) << AHD_PRECOMP_SHIFT) & AHD_PRECOMP_MASK); \ +} while (0) + +#define AHD_SET_AMPLITUDE(ahd, new_amp) \ +do { \ + (ahd)->iocell_opts[AHD_AMPLITUDE_INDEX] &= ~AHD_AMPLITUDE_MASK; \ + (ahd)->iocell_opts[AHD_AMPLITUDE_INDEX] |= \ + (((new_amp) << AHD_AMPLITUDE_SHIFT) & AHD_AMPLITUDE_MASK); \ +} while (0) + /************************ Active Device Information ***************************/ typedef enum { ROLE_UNKNOWN, @@ -1144,14 +1238,10 @@ ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl) } /***************************** PCI Front End *********************************/ -struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t); -int ahd_pci_config(struct ahd_softc *, - struct ahd_pci_identity *); - -/*************************** EISA/VL Front End ********************************/ -struct aic7770_identity *aic7770_find_device(uint32_t); -int aic7770_config(struct ahd_softc *ahd, - struct aic7770_identity *); +struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t); +int ahd_pci_config(struct ahd_softc *, + struct ahd_pci_identity *); +int ahd_pci_test_register_access(struct ahd_softc *); /************************** SCB and SCB queue management **********************/ int ahd_probe_scbs(struct ahd_softc *); @@ -1249,11 +1339,20 @@ void ahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo, u_int *bus_width, role_t role); +/* + * Negotiation types. These are used to qualify if we should renegotiate + * even if our goal and current transport parameters are identical. + */ +typedef enum { + AHD_NEG_TO_GOAL, /* Renegotiate only if goal and curr differ. */ + AHD_NEG_IF_NON_ASYNC, /* Renegotiate so long as goal is non-async. */ + AHD_NEG_ALWAYS /* Renegotiat even if goal is async. */ +} ahd_neg_type; int ahd_update_neg_request(struct ahd_softc*, struct ahd_devinfo*, struct ahd_tmode_tstate*, struct ahd_initiator_tinfo*, - int /*force*/); + ahd_neg_type); void ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, u_int width, u_int type, int paused); @@ -1290,22 +1389,27 @@ cam_status ahd_find_tmode_devs(struct ahd_softc *ahd, /******************************* Debug ***************************************/ #ifdef AHD_DEBUG extern uint32_t ahd_debug; -#define AHD_SHOW_MISC 0x0001 -#define AHD_SHOW_SENSE 0x0002 -#define AHD_DUMP_SEEPROM 0x0004 -#define AHD_SHOW_TERMCTL 0x0008 -#define AHD_SHOW_MEMORY 0x0010 -#define AHD_SHOW_MESSAGES 0x0020 -#define AHD_SHOW_MODEPTR 0x0040 -#define AHD_SHOW_SELTO 0x0080 -#define AHD_SHOW_FIFOS 0x0100 -#define AHD_SHOW_QFULL 0x0200 -#define AHD_SHOW_QUEUE 0x0400 -#define AHD_SHOW_TQIN 0x0800 -#define AHD_SHOW_SG 0x1000 -#define AHD_DEBUG_SEQUENCER 0x2000 +#define AHD_SHOW_MISC 0x00001 +#define AHD_SHOW_SENSE 0x00002 +#define AHD_SHOW_RECOVERY 0x00004 +#define AHD_DUMP_SEEPROM 0x00008 +#define AHD_SHOW_TERMCTL 0x00010 +#define AHD_SHOW_MEMORY 0x00020 +#define AHD_SHOW_MESSAGES 0x00040 +#define AHD_SHOW_MODEPTR 0x00080 +#define AHD_SHOW_SELTO 0x00100 +#define AHD_SHOW_FIFOS 0x00200 +#define AHD_SHOW_QFULL 0x00400 +#define AHD_SHOW_DV 0x00800 +#define AHD_SHOW_MASKED_ERRORS 0x01000 +#define AHD_SHOW_QUEUE 0x02000 +#define AHD_SHOW_TQIN 0x04000 +#define AHD_SHOW_SG 0x08000 +#define AHD_DEBUG_SEQUENCER 0x10000 #endif void ahd_print_scb(struct scb *scb); +void ahd_print_devinfo(struct ahd_softc *ahd, + struct ahd_devinfo *devinfo); void ahd_dump_sglist(struct scb *scb); void ahd_dump_all_cards_state(void); void ahd_dump_card_state(struct ahd_softc *ahd); diff --git a/sys/dev/aic7xxx/aic79xx.reg b/sys/dev/aic7xxx/aic79xx.reg index 81f19067b0f1..7611b9aa0d0b 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#45 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#55 $" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -72,6 +72,19 @@ VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#45 $" xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); \ } +#define RESTORE_MODE(mode) \ + if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { \ + mov mode call set_mode_work_around; \ + } else { \ + mov MODE_PTR, mode; \ + } + +#define SET_SEQINTCODE(code) \ + if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { \ + mvi code call set_seqint_work_around; \ + } else { \ + mvi SEQINTCODE, code; \ + } /* * Mode Pointer @@ -114,7 +127,8 @@ register SEQINTCODE { address 0x002 access_mode RW field { - BAD_PHASE 1, /* unknown scsi bus phase */ + NO_SEQINT, /* No seqint pending. */ + BAD_PHASE, /* unknown scsi bus phase */ SEND_REJECT, /* sending a message reject */ PROTO_VIOLATION, /* Protocol Violation */ NO_MATCH, /* no cmd match for reconnect */ @@ -158,7 +172,12 @@ register SEQINTCODE { CFG4ISTAT_INTR, STATUS_OVERRUN, CFG4OVERRUN, - ENTERING_NONPACK + ENTERING_NONPACK, + TRACEPOINT0, + TRACEPOINT1, + TRACEPOINT2, + TRACEPOINT3, + SAW_HWERR } } @@ -366,6 +385,7 @@ register DFCNTRL { access_mode RW modes M_DFF0, M_DFF1 field PRELOADEN 0x80 + field SCSIENWRDIS 0x40 /* Rev B only. */ field SCSIEN 0x20 field SCSIENACK 0x20 field HDMAEN 0x08 @@ -463,6 +483,17 @@ register HODMAADR { } /* + * PCI PLL Delay. + */ +register PLLDELAY { + address 0x070 + access_mode RW + size 1 + modes M_CFG + field SPLIT_DROP_REQ 0x80 +} + +/* * Data Channel Host Count */ register HCNT { @@ -1561,9 +1592,24 @@ register DFFSTAT { modes M_SCSI field FIFO1FREE 0x20 field FIFO0FREE 0x10 - field CURRFIFO 0x01 + /* + * On the B, this enum only works + * in the read direction. For writes, + * you must use the B version of the + * CURRFIFO_0 definition which is defined + * as a constant outside of this register + * definition to avoid confusing the + * register pretty printing code. + */ + enum CURRFIFO 0x03 { + CURRFIFO_0, + CURRFIFO_1, + CURRFIFO_NONE 0x3 + } } +const B_CURRFIFO_0 0x2 + /* * SCSI Bus Target IDs * Bitmask of observed targets on the bus. @@ -2208,6 +2254,7 @@ register DFFSXFRCTL { address 0x05A access_mode RW modes M_DFF0, M_DFF1 + field DFFBITBUCKET 0x08 field CLRSHCNT 0x04 field CLRCHN 0x02 field RSTCHN 0x01 @@ -2222,7 +2269,17 @@ register NEXTSCB { size 2 modes M_SCSI } - + +/* Rev B only. */ +register LQOSCSCTL { + address 0x05A + access_mode RW + size 1 + modes M_CFG + field LQOH2A_VERSION 0x80 + field LQONOCHKOVER 0x01 +} + /* * SEQ Interrupts */ @@ -2427,7 +2484,10 @@ register NEGCONOPTS { address 0x064 access_mode RW modes M_SCSI - field ENAIP 0x08 + field ENSNAPSHOT 0x40 + field RTI_WRTDIS 0x20 + field RTI_OVRDTRN 0x10 + field ENSLOWCRC 0x08 field ENAUTOATNI 0x04 field ENAUTOATNO 0x02 field WIDEXFER 0x01 @@ -2447,7 +2507,7 @@ register SCSCHKN { access_mode RW modes M_CFG field STSELSKIDDIS 0x40 - field CURFIFODEF 0x20 + field CURRFIFODEF 0x20 field WIDERESEN 0x10 field SDONEMSKDIS 0x08 field DFFACTCLR 0x04 @@ -2455,13 +2515,28 @@ register SCSCHKN { field LSTSGCLRDIS 0x01 } -const AHD_ANNEXCOL_PRECOMP 4 +const AHD_ANNEXCOL_PER_DEV0 4 +const AHD_NUM_PER_DEV_ANNEXCOLS 4 +const AHD_ANNEXCOL_PRECOMP_SLEW 4 const AHD_PRECOMP_MASK 0x07 +const AHD_PRECOMP_SHIFT 0 const AHD_PRECOMP_CUTBACK_17 0x04 const AHD_PRECOMP_CUTBACK_29 0x06 const AHD_PRECOMP_CUTBACK_37 0x07 -const AHD_PRECOMP_FASTSLEW 0x40 -const AHD_NUM_ANNEXCOLS 4 +const AHD_SLEWRATE_MASK 0x78 +const AHD_SLEWRATE_SHIFT 3 +/* + * Rev A has only a single bit of slew adjustment. + * Rev B has 4 bits. + */ +const AHD_SLEWRATE_DEF_REVA 0x01 +const AHD_SLEWRATE_DEF_REVB 0x08 + +/* Rev A does not have any amplitude setting. */ +const AHD_ANNEXCOL_AMPLITUDE 6 +const AHD_AMPLITUDE_MASK 0x7 +const AHD_AMPLITUDE_SHIFT 0 +const AHD_AMPLITUDE_DEF 0x7 /* * Negotiation Table Annex Data Port. @@ -2689,7 +2764,8 @@ register CCSGCTL { modes M_DFF0, M_DFF1 field CCSGDONE 0x80 field SG_CACHE_AVAIL 0x10 - field CCSGEN 0x08 + field CCSGENACK 0x08 + mask CCSGEN 0x0C field SG_FETCH_REQ 0x02 field CCSGRESET 0x01 } @@ -2983,7 +3059,10 @@ register WRTBIASCTL { field XMITMANVAL 0x3F } -const WRTBIASCTL_CPQ_DEFAULT 0x97 +/* + * Currently the WRTBIASCTL is the same as the default. + */ +const WRTBIASCTL_HP_DEFAULT 0x0 /* * Receiver Bias Control @@ -3447,7 +3526,7 @@ scratch_ram { size 2 } /* - * Mode to restore on idle_loop exit. + * Mode to restore on legacy idle loop exit. */ SAVED_MODE { size 1 @@ -3518,6 +3597,13 @@ scratch_ram { } } /* + * Value to "or" into the SCBPTR[1] value to + * indicate that an entry in the QINFIFO is valid. + */ + QOUTFIFO_ENTRY_VALID_TAG { + size 1 + } + /* * Base address of our shared data with the kernel driver in host * memory. This includes the qoutfifo and target mode * incoming command queue. @@ -3533,13 +3619,6 @@ scratch_ram { size 4 } /* - * Value to "or" into the SCBPTR[1] value to - * indicate that an entry in the QINFIFO is valid. - */ - QOUTFIFO_ENTRY_VALID_TAG { - size 1 - } - /* * Kernel and sequencer offsets into the queue of * incoming target mode command descriptors. The * queue is full when the KERNEL_TQINPOS == TQINPOS. @@ -3722,7 +3801,6 @@ scb { } /*********************************** Constants ********************************/ -const SEQ_STACK_SIZE 8 const MK_MESSAGE_BIT_OFFSET 4 const TID_SHIFT 4 const TARGET_CMD_CMPLT 0xfe @@ -3746,7 +3824,15 @@ const BUS_32_BIT 0x02 /* Offset maximums */ const MAX_OFFSET 0xfe -const MAX_OFFSET_PACED 0x7f +const MAX_OFFSET_PACED 0xfe +const MAX_OFFSET_PACED_BUG 0x7f +/* + * Some 160 devices incorrectly accept 0xfe as a + * sync offset, but will overrun this value. Limit + * to 0x7f for speed lower than U320 which will + * avoid the persistent sync offset overruns. + */ +const MAX_OFFSET_NON_PACED 0x7f const HOST_MSG 0xff /* diff --git a/sys/dev/aic7xxx/aic79xx.seq b/sys/dev/aic7xxx/aic79xx.seq index e21fb601662f..6774896a1419 100644 --- a/sys/dev/aic7xxx/aic79xx.seq +++ b/sys/dev/aic7xxx/aic79xx.seq @@ -40,14 +40,31 @@ * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#60 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#72 $" PATCH_ARG_LIST = "struct ahd_softc *ahd" PREFIX = "ahd_" #include "aic79xx.reg" #include "scsi_message.h" +restart: +if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { + test SEQINTCODE, 0xFF jz idle_loop; + SET_SEQINTCODE(NO_SEQINT) +} + idle_loop: + + if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { + /* + * Convert ERROR status into a sequencer + * interrupt to handle the case of an + * interrupt collision on the hardware + * setting of HWERR. + */ + test ERROR, 0xFF jz . + 2; + SET_SEQINTCODE(SAW_HWERR) + } SET_MODE(M_SCSI, M_SCSI) test SCSISEQ0, ENSELO|ENARBO jnz idle_loop_checkbus; test SEQ_FLAGS2, SELECTOUT_QFROZEN jnz idle_loop_checkbus; @@ -69,11 +86,18 @@ END_CRITICAL; test SCSISIGO, ATNO jz idle_loop_check_nonpackreq; call unexpected_nonpkt_phase_find_ctxt; idle_loop_check_nonpackreq: - test SSTAT2, NONPACKREQ jz idle_loop_scsi; + test SSTAT2, NONPACKREQ jz . + 2; call unexpected_nonpkt_phase_find_ctxt; -idle_loop_scsi: + call idle_loop_gsfifo_in_scsi_mode; + call idle_loop_service_fifos; + call idle_loop_cchan; + jmp idle_loop; + BEGIN_CRITICAL; - test LQISTAT2, LQIGSAVAIL jz idle_loop_service_fifos; +idle_loop_gsfifo: + SET_MODE(M_SCSI, M_SCSI) +idle_loop_gsfifo_in_scsi_mode: + test LQISTAT2, LQIGSAVAIL jz return; /* * We have received good status for this transaction. There may * still be data in our FIFOs draining to the host. Setup @@ -113,31 +137,29 @@ good_status_IU_done: */ call complete; END_CRITICAL; - jmp idle_loop_scsi; + jmp idle_loop_gsfifo_in_scsi_mode; BEGIN_CRITICAL; good_status_check_fifos: clc; bmov ARG_1, SCBPTR, 2; SET_MODE(M_DFF0, M_DFF0) call check_fifo; - jc idle_loop_service_fifos; + jc return; SET_MODE(M_DFF1, M_DFF1) call check_fifo; - jc idle_loop_service_fifos; + jc return; SET_MODE(M_SCSI, M_SCSI) - call queue_scb_completion; + jmp queue_scb_completion; END_CRITICAL; + idle_loop_service_fifos: 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) - test LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_last_fifo_done; - call longjmp; -idle_loop_last_fifo_done: - call idle_loop_cchan; - jmp idle_loop; + test LONGJMP_ADDR[1], INVALID_ADDR jz longjmp; + ret; idle_loop_cchan: SET_MODE(M_CCHAN, M_CCHAN) @@ -175,6 +197,8 @@ fetch_new_scb_done: bmov NEXT_QUEUED_SCB_ADDR, SCB_NEXT_SCB_BUSADDR, 4; mvi SCB_NEXT[1], SCB_LIST_NULL; mvi SCB_NEXT2[1], SCB_LIST_NULL; + /* Increment our position in the QINFIFO. */ + mov NONE, SNSCB_QOFF; /* * SCBs that want to send messages are always * queued independently. This ensures that they @@ -189,22 +213,15 @@ fetch_new_scb_done: bmov SCBPTR, SINDIR, 2; bmov DINDIR, REG0, 2; cmp SCBPTR[1], SCB_LIST_NULL je first_new_target_scb; - bmov SCB_NEXT, REG0, 2; -fetch_new_scb_fini: - /* Increment our position in the QINFIFO. */ - mov NONE, SNSCB_QOFF ret; + bmov SCB_NEXT, REG0, 2 ret; first_new_target_scb: cmp WAITING_TID_HEAD[1], SCB_LIST_NULL je first_new_scb; bmov SCBPTR, WAITING_TID_TAIL, 2; bmov SCB_NEXT2, REG0, 2; - bmov WAITING_TID_TAIL, REG0, 2; - /* Increment our position in the QINFIFO. */ - mov NONE, SNSCB_QOFF ret; + bmov WAITING_TID_TAIL, REG0, 2 ret; first_new_scb: bmov WAITING_TID_HEAD, REG0, 2; - bmov WAITING_TID_TAIL, REG0, 2; - /* Increment our position in the QINFIFO. */ - mov NONE, SNSCB_QOFF ret; + bmov WAITING_TID_TAIL, REG0, 2 ret; END_CRITICAL; scbdma_idle: @@ -228,19 +245,16 @@ fill_qoutfifo: bmov COMPLETE_SCB_DMAINPROG_HEAD, COMPLETE_SCB_HEAD, 2; mvi CCSCBCTL, CCSCBRESET; bmov SCBHADDR, QOUTFIFO_NEXT_ADDR, 4; - mov CCSCBRAM, COMPLETE_SCB_HEAD; - or CCSCBRAM, A, COMPLETE_SCB_HEAD[1]; bmov SCBPTR, COMPLETE_SCB_HEAD, 2; - jmp fill_qoutfifo_first_entry; fill_qoutfifo_loop: - mov CCSCBRAM, SCB_NEXT_COMPLETE; - or CCSCBRAM, A, SCB_NEXT_COMPLETE[1]; - bmov SCBPTR, SCB_NEXT_COMPLETE, 2; -fill_qoutfifo_first_entry: + mov CCSCBRAM, SCBPTR; + or CCSCBRAM, A, SCBPTR[1]; mov NONE, SDSCB_QOFF; cmp SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je fill_qoutfifo_done; cmp CCSCBADDR, CCSCBADDR_MAX je fill_qoutfifo_done; - test QOFF_CTLSTA, SDSCB_ROLLOVR jz fill_qoutfifo_loop; + test QOFF_CTLSTA, SDSCB_ROLLOVR jnz fill_qoutfifo_done; + bmov SCBPTR, SCB_NEXT_COMPLETE, 2; + jmp fill_qoutfifo_loop; fill_qoutfifo_done: mov SCBHCNT, CCSCBADDR; mvi CCSCBCTL, CCSCBEN|CCSCBRESET; @@ -290,7 +304,7 @@ longjmp: bmov STACK, LONGJMP_ADDR, 2 ret; END_CRITICAL; -/************************ Packetized LongJmp Routines *************************/ +/*************************** Chip Bug Work Arounds ****************************/ /* * Must disable interrupts when setting the mode pointer * register as an interrupt occurring mid update will @@ -309,6 +323,14 @@ toggle_dff_mode_work_around: clr SEQINTCTL ret; } + +if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { +set_seqint_work_around: + mov SEQINTCODE, SINDEX; + mvi SEQINTCODE, NO_SEQINT ret; +} + +/************************ Packetized LongJmp Routines *************************/ SET_SRC_MODE M_SCSI; SET_DST_MODE M_SCSI; start_selection: @@ -358,26 +380,30 @@ END_CRITICAL; /* * Allocate a FIFO for a non-packetized transaction. - * For some reason unkown to me, both FIFOs must be free before we - * can allocate a FIFO for a non-packetized transaction. This - * may be fixed in Rev B. + * In RevA hardware, both FIFOs must be free before we + * can allocate a FIFO for a non-packetized transaction. */ allocate_fifo_loop: /* * Do whatever work is required to free a FIFO. */ - SET_MODE(M_DFF0, M_DFF0) - test LONGJMP_ADDR[1], INVALID_ADDR jnz . + 2; - call longjmp; - SET_MODE(M_DFF1, M_DFF1) - test LONGJMP_ADDR[1], INVALID_ADDR jnz . + 2; - call longjmp; + call idle_loop_service_fifos; SET_MODE(M_SCSI, M_SCSI) allocate_fifo: - and A, FIFO0FREE|FIFO1FREE, DFFSTAT; - cmp A, FIFO0FREE|FIFO1FREE jne allocate_fifo_loop; -take_fifo: - or DFFSTAT, CURRFIFO; + if ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0) { + and A, FIFO0FREE|FIFO1FREE, DFFSTAT; + cmp A, FIFO0FREE|FIFO1FREE jne allocate_fifo_loop; + } else { + test DFFSTAT, FIFO1FREE jnz allocate_fifo1; + test DFFSTAT, FIFO0FREE jz allocate_fifo_loop; + mvi DFFSTAT, B_CURRFIFO_0; + SET_MODE(M_DFF0, M_DFF0) + bmov SCBPTR, ALLOCFIFO_SCBPTR, 2 ret; + } +SET_SRC_MODE M_SCSI; +SET_DST_MODE M_SCSI; +allocate_fifo1: + mvi DFFSTAT, CURRFIFO_1; SET_MODE(M_DFF1, M_DFF1) bmov SCBPTR, ALLOCFIFO_SCBPTR, 2 ret; @@ -485,6 +511,7 @@ curscb_ww_done: */ bmov SCBPTR, CURRSCB, 2; } + /* * Requeue any SCBs not sent, to the tail of the waiting Q. */ @@ -518,9 +545,7 @@ select_out_inc_tid_q: mvi WAITING_TID_TAIL[1], SCB_LIST_NULL; bmov SCBPTR, CURRSCB, 2; END_CRITICAL; - mvi CLRSINT0, CLRSELDO; - test LQOSTAT2, LQOPHACHGOUTPKT jnz unexpected_nonpkt_phase; test LQOSTAT1, LQOPHACHGINPKT jnz unexpected_nonpkt_phase; @@ -583,15 +608,16 @@ ITloop: cmp A,P_STATUS je p_status; cmp A,P_MESGIN je p_mesgin; - mvi SEQINTCODE, BAD_PHASE; + SET_SEQINTCODE(BAD_PHASE) jmp ITloop; /* Try reading the bus again. */ /* * Command phase. Set up the DMA registers and let 'er rip. */ p_command: -SET_SRC_MODE M_DFF1; -SET_DST_MODE M_DFF1; + test SEQ_FLAGS, NOT_IDENTIFIED jz p_command_okay; + SET_SEQINTCODE(PROTO_VIOLATION) +p_command_okay: test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) jnz p_command_allocate_fifo; /* @@ -599,32 +625,34 @@ SET_DST_MODE M_DFF1; * re-allocate a FIFO so transfer state is * reset. */ +SET_SRC_MODE M_DFF1; +SET_DST_MODE M_DFF1; mvi DFFSXFRCTL, RSTCHN|CLRSHCNT; + SET_MODE(M_SCSI, M_SCSI) p_command_allocate_fifo: bmov ALLOCFIFO_SCBPTR, SCBPTR, 2; call allocate_fifo; +SET_SRC_MODE M_DFF1; +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; mvi SG_CACHE_PRE, LAST_SEG; mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN); - jmp p_command_loop; + jmp p_command_xfer; p_command_embedded: bmov SHCNT[0], SCB_CDB_LEN, 1; - bmov SHCNT[1], ALLZEROS, 2; bmov DFDAT, SCB_CDB_STORE, 16; mvi DFCNTRL, SCSIEN; -p_command_loop: - test DFCNTRL, SCSIEN jnz p_command_loop; +p_command_xfer: + and SEQ_FLAGS, ~NO_CDB_SENT; + test DFCNTRL, SCSIEN jnz .; /* * DMA Channel automatically disabled. * Don't allow a data phase if the command - * was not fully transferred. Make sure that - * we clear the IDENTIFY SEEN flag if a retry - * falls short too. + * was not fully transferred. */ - and SEQ_FLAGS, ~NO_CDB_SENT; test SSTAT2, SDONE jnz ITloop; or SEQ_FLAGS, NO_CDB_SENT; jmp ITloop; @@ -637,9 +665,7 @@ p_command_loop: SET_SRC_MODE M_SCSI; SET_DST_MODE M_SCSI; p_status: - test SEQ_FLAGS,NOT_IDENTIFIED jz p_status_okay; - mvi SEQINTCODE, PROTO_VIOLATION; - jmp mesgin_done; + test SEQ_FLAGS,NOT_IDENTIFIED jnz mesgin_proto_violation; p_status_okay: mov SCB_SCSI_STATUS, SCSIDAT; or SCB_CONTROL, STATUS_RCVD; @@ -744,7 +770,7 @@ p_mesgin: */ host_message_loop: call phase_lock; /* Benign the first time through. */ - mvi SEQINTCODE, HOST_MSG_LOOP; + SET_SEQINTCODE(HOST_MSG_LOOP) cmp RETURN_1, EXIT_MSG_LOOP je ITloop; cmp RETURN_1, CONT_MSG_LOOP_WRITE jne . + 3; mov SCSIDAT, RETURN_2; @@ -761,9 +787,12 @@ mesgin_ign_wide_residue: cmp REG0, 0x01 jne mesgin_reject; test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; test DATA_COUNT_ODD, 0x1 jz mesgin_done; - mvi SEQINTCODE, IGN_WIDE_RES; + SET_SEQINTCODE(IGN_WIDE_RES) jmp mesgin_done; +mesgin_proto_violation: + SET_SEQINTCODE(PROTO_VIOLATION) + jmp mesgin_done; mesgin_reject: mvi MSG_MESSAGE_REJECT call mk_mesg; mesgin_done: @@ -851,11 +880,11 @@ setup_SCB_disconnected: jmp mesgin_done; not_found: - mvi SEQINTCODE, NO_MATCH; + SET_SEQINTCODE(NO_MATCH) jmp mesgin_done; not_found_ITloop: - mvi SEQINTCODE, NO_MATCH; + SET_SEQINTCODE(NO_MATCH) jmp ITloop; /* @@ -871,9 +900,6 @@ not_found_ITloop: * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting * RETURN_1 to SEND_SENSE. */ -mesgin_complete_proto_violation: - mvi SEQINTCODE, PROTO_VIOLATION; - jmp mesgin_done; mesgin_complete: /* @@ -891,34 +917,28 @@ mesgin_complete: * If we are identified and have successfully sent the CDB, * any status will do. Optimize this fast path. */ - test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jnz . + 2; - test SCB_CONTROL, STATUS_RCVD jnz complete_accepted; + test SCB_CONTROL, STATUS_RCVD jz mesgin_proto_violation; + test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz complete_accepted; /* * If the target never sent an identify message but instead went * to mesgin to give an invalid message, let the host abort us. */ - test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_complete_proto_violation; - - /* - * If the target never gave us status information, have - * the host abort the command. - */ - test SCB_CONTROL, STATUS_RCVD jz mesgin_complete_proto_violation; + test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation; /* * If we recevied good status but never successfully sent the * cdb, abort the command. */ test SCB_SCSI_STATUS,0xff jnz complete_accepted; - test SEQ_FLAGS, NO_CDB_SENT jnz mesgin_complete_proto_violation; + test SEQ_FLAGS, NO_CDB_SENT jnz mesgin_proto_violation; complete_accepted: /* * See if we attempted to deliver a message but the target ingnored us. */ test SCB_CONTROL, MK_MESSAGE jz . + 2; - mvi SEQINTCODE, MKMSG_FAILED; + SET_SEQINTCODE(MKMSG_FAILED) call queue_scb_completion; jmp await_busfree; @@ -937,6 +957,14 @@ 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 @@ -971,10 +999,8 @@ mesgin_disconnect: * XXX - Wait for more testing. test SCSISIGI, ATNI jnz mesgin_done; */ - test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz disconnect_allowed; - mvi SEQINTCODE, PROTO_VIOLATION; - jmp mesgin_done; -disconnect_allowed: + test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT + jnz mesgin_proto_violation; or SCB_CONTROL,DISCONNECTED; test SCB_CONTROL, TAG_ENB jnz await_busfree; queue_disc_scb: @@ -1005,7 +1031,7 @@ await_busfree_not_m_dff: call clear_target_state; test SSTAT1,REQINIT|BUSFREE jz .; test SSTAT1, BUSFREE jnz idle_loop; - mvi SEQINTCODE, MISSED_BUSFREE; + SET_SEQINTCODE(MISSED_BUSFREE) /* @@ -1047,12 +1073,13 @@ save_pointers_full: * SCB anytime we enter a data phase for the first time, so all * we need to do is clear the DPHASE flag and let the data phase * code do the rest. We also reset/reallocate the FIFO to make - * sure we have a clean start for the next data phase. + * sure we have a clean start for the next data or command phase. */ mesgin_rdptrs: and SEQ_FLAGS, ~DPHASE; test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) jnz msgin_rdptrs_get_fifo; mvi DFFSXFRCTL, RSTCHN|CLRSHCNT; + SET_MODE(M_SCSI, M_SCSI) msgin_rdptrs_get_fifo: call allocate_fifo; jmp mesgin_done; @@ -1064,6 +1091,7 @@ clear_target_state: phase_lock: test SCSIPHASE, 0xFF jz .; + test SSTAT1, SCSIPERR jnz phase_lock; phase_lock_latch_phase: and LASTPHASE, PHASE_MASK, SCSISIGI ret; @@ -1090,6 +1118,7 @@ inb_next_wait: * before continuing. */ test SCSIPHASE, 0xFF jz .; + test SSTAT1, SCSIPERR jnz inb_next_wait; inb_next_check_phase: and LASTPHASE, PHASE_MASK, SCSISIGI; cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; @@ -1112,20 +1141,6 @@ disable_ccsgen: disable_ccsgen_fetch_done: clr SG_STATE ret; -data_group_idle_loop: - mov SAVED_MODE, MODE_PTR; - test SG_STATE, LOADING_NEEDED jz . + 2; - call service_fifo; - TOGGLE_DFF_MODE - test SG_STATE, LOADING_NEEDED jz . + 2; - call service_fifo; - call idle_loop_cchan; - 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: /* * Do we have any prefetch left??? @@ -1138,11 +1153,10 @@ service_fifo: test CCSGCTL, SG_CACHE_AVAIL jz return; /* Did we just finish fetching segs? */ - cmp CCSGCTL, CCSGEN|SG_CACHE_AVAIL|CCSGDONE - je idle_sgfetch_complete; + test CCSGCTL, CCSGDONE jnz idle_sgfetch_complete; /* Are we actively fetching segments? */ - test CCSGCTL, CCSGEN jnz return; + test CCSGCTL, CCSGENACK jnz return; /* * We fetch a "cacheline aligned" and sized amount of data @@ -1151,17 +1165,15 @@ service_fifo: * set the prefetch amount to a reasonable level if the * cacheline size is unknown. */ - and SGHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; + bmov SGHADDR, SCB_RESIDUAL_SGPTR, 4; 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; + and SGHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; mvi CCSGCTL, CCSGEN|SG_CACHE_AVAIL|CCSGRESET; or SG_STATE, FETCH_INPROG ret; idle_sgfetch_complete: @@ -1215,7 +1227,15 @@ sg_advance: * de-asserts and we don't want to accidentally * re-enable it. */ - or DFCNTRL, PRELOADEN|HDMAEN; + if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) { + /* + * Use SCSIENWRDIS so that SCSIEN is never + * modified by this operation. + */ + or DFCNTRL, PRELOADEN|SCSIENWRDIS|HDMAEN; + } else { + or DFCNTRL, PRELOADEN|HDMAEN; + } /* * Do we have another segment in the cache? */ @@ -1248,9 +1268,15 @@ load_first_seg: mvi SG_STATE, LOADING_NEEDED ret; clr SG_STATE ret; +p_data_handle_xfer: + call setjmp_setscb; + test SG_STATE, LOADING_NEEDED jnz service_fifo; +p_data_clear_handler: + or LONGJMP_ADDR[1], INVALID_ADDR ret; + p_data: test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz p_data_allowed; - mvi SEQINTCODE, PROTO_VIOLATION; + SET_SEQINTCODE(PROTO_VIOLATION) p_data_allowed: test SEQ_FLAGS, DPHASE jz data_phase_initialize; @@ -1263,14 +1289,15 @@ p_data_allowed: * unless we already know that we should be bitbucketing. */ test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jnz p_data_bitbucket; - mvi SEQINTCODE, PDATA_REINIT; - jmp data_group_dma_loop; + SET_SEQINTCODE(PDATA_REINIT) + jmp data_phase_inbounds; p_data_bitbucket: /* * Turn on `Bit Bucket' mode, wait until the target takes * us to another phase, and then notify the host. */ + mov SAVED_MODE, MODE_PTR; test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) jnz bitbucket_not_m_dff; /* @@ -1285,8 +1312,10 @@ bitbucket_not_m_dff: /* Wait for non-data phase. */ test SCSIPHASE, ~DATA_PHASE_MASK jz .; and SXFRCTL1, ~BITBUCKET; - SET_MODE(M_DFF1, M_DFF1) - mvi SEQINTCODE, DATA_OVERRUN; + RESTORE_MODE(SAVED_MODE) +SET_SRC_MODE M_DFF1; +SET_DST_MODE M_DFF1; + SET_SEQINTCODE(DATA_OVERRUN) jmp ITloop; data_phase_initialize: @@ -1295,13 +1324,19 @@ data_phase_initialize: data_phase_inbounds: /* We have seen a data phase at least once. */ or SEQ_FLAGS, DPHASE; + mov SAVED_MODE, MODE_PTR; + test SG_STATE, LOADING_NEEDED jz data_group_dma_loop; + call p_data_handle_xfer; data_group_dma_loop: /* * The transfer is complete if either the last segment * completes or the target changes phase. Both conditions * will clear SCSIEN. */ - call data_group_idle_loop; + call idle_loop_service_fifos; + call idle_loop_cchan; + call idle_loop_gsfifo; + RESTORE_MODE(SAVED_MODE) test DFCNTRL, SCSIEN jnz data_group_dma_loop; data_group_dmafinish: @@ -1357,6 +1392,7 @@ data_phase_finish: data_phase_done: /* Kill off any pending prefetch */ call disable_ccsgen; + or LONGJMP_ADDR[1], INVALID_ADDR; if ((ahd->flags & AHD_TARGETROLE) != 0) { test SEQ_FLAGS, DPHASE_PENDING jz ITloop; @@ -1414,7 +1450,8 @@ residual_before_last_seg: * hardware will only interrupt us once SHVALID or * LAST_SEG_DONE. */ - call data_group_idle_loop; + call idle_loop_service_fifos; + RESTORE_MODE(SAVED_MODE) jmp calc_residual; sgptr_fixup: @@ -1448,7 +1485,7 @@ export seq_isr: test SEQINTSRC, CFG4DATA jnz cfg4data_intr; test SEQINTSRC, CFG4ISTAT jnz cfg4istat_intr; test SEQINTSRC, CFG4ICMD jnz cfg4icmd_intr; - mvi SEQINTCODE, INVALID_SEQINT; + SET_SEQINTCODE(INVALID_SEQINT) /* * There are two types of save pointers interrupts: @@ -1486,7 +1523,7 @@ cfg4istat_intr: /* * Host sets up address/count and enables transfer. */ - mvi SEQINTCODE, CFG4ISTAT_INTR; + SET_SEQINTCODE(CFG4ISTAT_INTR) jmp cfg4istat_setup_handler; cfg4istat_have_sense_addr: bmov HADDR, SCB_SENSE_BUSADDR, 4; @@ -1635,7 +1672,7 @@ END_CRITICAL; check_status_overrun: test SHCNT[2], 0xFF jz status_IU_done; - mvi SEQINTCODE, STATUS_OVERRUN; + SET_SEQINTCODE(STATUS_OVERRUN) jmp status_IU_done; pkt_handle_status: call setjmp_setscb; @@ -1694,11 +1731,11 @@ SET_DST_MODE M_DFF0; mvi DFFSXFRCTL, CLRCHN; mvi CLRSINT2, CLRNONPACKREQ; test SCSIPHASE, ~(MSG_IN_PHASE|MSG_OUT_PHASE) jnz illegal_phase; - mvi SEQINTCODE, ENTERING_NONPACK; + SET_SEQINTCODE(ENTERING_NONPACK) jmp ITloop; illegal_phase: - mvi SEQINTCODE, ILLEGAL_PHASE; + SET_SEQINTCODE(ILLEGAL_PHASE) jmp ITloop; /* @@ -1708,11 +1745,10 @@ illegal_phase: * BITBUCKET. */ pkt_handle_overrun: - mvi SEQINTCODE, CFG4OVERRUN; + SET_SEQINTCODE(CFG4OVERRUN) call freeze_queue; if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0) { - SET_MODE(M_SCSI, M_SCSI) - or SXFRCTL1,BITBUCKET; + or DFFSXFRCTL, DFFBITBUCKET; SET_SRC_MODE M_DFF1; SET_DST_MODE M_DFF1; } else { @@ -1721,12 +1757,14 @@ SET_DST_MODE M_DFF1; } call setjmp; if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) { - test DFSTATUS, PKT_PRELOAD_AVAIL jz overrun_load_done; + test DFSTATUS, PRELOAD_AVAIL jz overrun_load_done; call load_overrun_buf; or DFCNTRL, PRELOADEN; overrun_load_done: + test SEQINTSRC, CTXTDONE jnz pkt_overrun_end; + } else { + test DFFSXFRCTL, DFFBITBUCKET jz pkt_overrun_end; } - test SEQINTSRC, CTXTDONE jnz pkt_overrun_end; test SSTAT2, NONPACKREQ jz return; pkt_overrun_end: or SCB_RESIDUAL_SGPTR, SG_OVERRUN_RESID; |
