diff --git a/sys/dev/aic7xxx/ahc_eisa.c b/sys/dev/aic7xxx/ahc_eisa.c index 79db102db0f8..f7552d4fb66f 100644 --- a/sys/dev/aic7xxx/ahc_eisa.c +++ b/sys/dev/aic7xxx/ahc_eisa.c @@ -211,3 +211,5 @@ static driver_t ahc_eisa_driver = { static devclass_t ahc_devclass; DRIVER_MODULE(ahc, eisa, ahc_eisa_driver, ahc_devclass, 0, 0); +MODULE_DEPEND(ahc_eisa, ahc, 1, 1, 1); +MODULE_VERSION(ahc_eisa, 1); diff --git a/sys/dev/aic7xxx/ahc_pci.c b/sys/dev/aic7xxx/ahc_pci.c index 3519dce156ba..9968570c36b5 100644 --- a/sys/dev/aic7xxx/ahc_pci.c +++ b/sys/dev/aic7xxx/ahc_pci.c @@ -59,6 +59,8 @@ static devclass_t ahc_devclass; DRIVER_MODULE(ahc, pci, ahc_pci_driver, ahc_devclass, 0, 0); DRIVER_MODULE(ahc, cardbus, ahc_pci_driver, ahc_devclass, 0, 0); +MODULE_DEPEND(ahc_pci, ahc, 1, 1, 1); +MODULE_VERSION(ahc_pci, 1); static int ahc_pci_probe(device_t dev) diff --git a/sys/dev/aic7xxx/aic7770.c b/sys/dev/aic7xxx/aic7770.c index ac23d19cba09..d71788227b18 100644 --- a/sys/dev/aic7xxx/aic7770.c +++ b/sys/dev/aic7xxx/aic7770.c @@ -29,22 +29,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7770.c#9 $ + * $Id: //depot/src/aic7xxx/aic7770.c#11 $ * * $FreeBSD$ */ -#ifdef __linux__ -#include "aic7xxx_linux.h" -#include "aic7xxx_inline.h" -#include "aic7xxx_93cx6.h" -#endif - -#ifdef __FreeBSD__ #include #include #include -#endif #define ID_AIC7770 0x04907770 #define ID_AHA_274x 0x04907771 @@ -139,10 +131,6 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry) if ((intdef & EDGE_TRIG) != 0) ahc->flags |= AHC_EDGE_INTERRUPT; - error = aic7770_map_int(ahc, irq); - if (error != 0) - return (error); - switch (probe_config.chip & (AHC_EISA|AHC_VL)) { case AHC_EISA: { @@ -212,6 +200,10 @@ aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry) */ ahc_softc_insert(ahc); + error = aic7770_map_int(ahc, irq); + if (error != 0) + return (error); + /* * Enable the board's BUS drivers */ diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c index 0e4fa18831ad..829f609195c9 100644 --- a/sys/dev/aic7xxx/aic7xxx.c +++ b/sys/dev/aic7xxx/aic7xxx.c @@ -28,22 +28,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.c#35 $ + * $Id: //depot/src/aic7xxx/aic7xxx.c#39 $ * * $FreeBSD$ */ -#ifdef __linux__ -#include "aic7xxx_linux.h" -#include "aic7xxx_inline.h" -#include "aicasm/aicasm_insformat.h" -#endif - -#ifdef __FreeBSD__ #include #include #include -#endif /****************************** Softc Data ************************************/ struct ahc_softc_tailq ahc_tailq = TAILQ_HEAD_INITIALIZER(ahc_tailq); @@ -156,6 +148,7 @@ static void ahc_fetch_devinfo(struct ahc_softc *ahc, static void ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct scb *scb); +static void ahc_assert_atn(struct ahc_softc *ahc); static void ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct scb *scb); @@ -190,9 +183,11 @@ static void ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, cam_status status, char *message, int verbose_level); +#if AHC_TARGET_MODE static void ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct scb *scb); +#endif static bus_dmamap_callback_t ahc_dmamap_cb; static void ahc_build_free_scb_list(struct ahc_softc *ahc); @@ -211,7 +206,6 @@ static int ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, role_t role, uint32_t status); static void ahc_reset_current_bus(struct ahc_softc *ahc); -static void ahc_calc_residual(struct scb *scb); #ifdef AHC_DUMP_SEQ static void ahc_dumpseq(struct ahc_softc *ahc); #endif @@ -296,7 +290,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc) /* * Clear 32bits of QOUTFIFO at a time - * so that we don't clobber an incomming + * so that we don't clobber an incoming * byte DMA to the array on architectures * that only support 32bit load and store * operations. @@ -319,10 +313,7 @@ ahc_run_qoutfifo(struct ahc_softc *ahc) * Save off the residual * if there is one. */ - if (ahc_check_residual(scb) != 0) - ahc_calc_residual(scb); - else - ahc_set_residual(scb, 0); + ahc_update_residual(scb); ahc_done(ahc, scb); } } @@ -477,16 +468,13 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) devinfo.our_scsiid, devinfo.target, &tstate); - tinfo = &targ_info->current; + tinfo = &targ_info->curr; sg = scb->sg_list; sc = (struct scsi_sense *)(&hscb->shared_data.cdb); /* * Save off the residual if there is one. */ - if (ahc_check_residual(scb)) - ahc_calc_residual(scb); - else - ahc_set_residual(scb, 0); + ahc_update_residual(scb); #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWSENSE) { ahc_print_path(ahc, scb); @@ -600,7 +588,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) ahc->msgout_index = 0; ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; ahc_outb(ahc, MSG_OUT, HOST_MSG); - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, LASTPHASE) | ATNO); + ahc_assert_atn(ahc); break; } case SEND_REJECT: @@ -741,17 +729,20 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) */ if ((intstat & SCSIINT) == 0 && (ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0) { - u_int curphase; - /* - * The hardware will only let you ack bytes - * if the expected phase in SCSISIGO matches - * the current phase. Make sure this is - * currently the case. - */ - curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - ahc_outb(ahc, LASTPHASE, curphase); - ahc_outb(ahc, SCSISIGO, curphase); + if ((ahc->features & AHC_DT) == 0) { + u_int curphase; + + /* + * The hardware will only let you ack bytes + * if the expected phase in SCSISIGO matches + * the current phase. Make sure this is + * currently the case. + */ + curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; + ahc_outb(ahc, LASTPHASE, curphase); + ahc_outb(ahc, SCSISIGO, curphase); + } ahc_inb(ahc, SCSIDATL); } break; @@ -1042,6 +1033,44 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) } ahc_outb(ahc, CLRINT, CLRSCSIINT); ahc_unpause(ahc); + } else if ((status & SELTO) != 0) { + u_int scbptr; + + /* Stop the selection */ + ahc_outb(ahc, SCSISEQ, 0); + + /* No more pending messages */ + ahc_clear_msg_state(ahc); + + /* Clear interrupt state */ + ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); + ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); + + /* + * Although the driver does not care about the + * 'Selection in Progress' status bit, the busy + * LED does. SELINGO is only cleared by a sucessfull + * selection, so we must manually clear it to insure + * the LED turns off just incase no future successful + * selections occur (e.g. no devices on the bus). + */ + ahc_outb(ahc, CLRSINT0, CLRSELINGO); + + scbptr = ahc_inb(ahc, WAITING_SCBH); + ahc_outb(ahc, SCBPTR, scbptr); + scb_index = ahc_inb(ahc, SCB_TAG); + + scb = ahc_lookup_scb(ahc, scb_index); + if (scb == NULL) { + printf("%s: ahc_intr - referenced scb not " + "valid during SELTO scb(%d, %d)\n", + ahc_name(ahc), scbptr, scb_index); + } else { + ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); + ahc_freeze_devq(ahc, scb); + } + ahc_outb(ahc, CLRINT, CLRSCSIINT); + ahc_restart(ahc); } else if ((status & BUSFREE) != 0 && (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) { u_int lastphase; @@ -1147,7 +1176,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) devinfo.our_scsiid, devinfo.target, &tstate); - tinfo->current.transport_version = 2; + tinfo->curr.transport_version = 2; tinfo->goal.transport_version = 2; tinfo->goal.ppr_options = 0; ahc_qinfifo_requeue_tail(ahc, scb); @@ -1209,43 +1238,6 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) ahc_clear_msg_state(ahc); ahc_outb(ahc, CLRINT, CLRSCSIINT); ahc_restart(ahc); - } else if ((status & SELTO) != 0) { - u_int scbptr; - - /* Stop the selection */ - ahc_outb(ahc, SCSISEQ, 0); - - /* No more pending messages */ - ahc_clear_msg_state(ahc); - - /* Clear interrupt state */ - ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); - - /* - * Although the driver does not care about the - * 'Selection in Progress' status bit, the busy - * LED does. SELINGO is only cleared by a sucessful - * selection, so we must manually clear it to insure - * the LED turns off just incase no future successful - * selections occur (e.g. no devices on the bus). - */ - ahc_outb(ahc, CLRSINT0, CLRSELINGO); - - scbptr = ahc_inb(ahc, WAITING_SCBH); - ahc_outb(ahc, SCBPTR, scbptr); - scb_index = ahc_inb(ahc, SCB_TAG); - - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) { - printf("%s: ahc_intr - referenced scb not " - "valid during SELTO scb(%d, %d)\n", - ahc_name(ahc), scbptr, scb_index); - } else { - ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); - ahc_freeze_devq(ahc, scb); - } - ahc_outb(ahc, CLRINT, CLRSCSIINT); - ahc_restart(ahc); } else { printf("%s: Missing case in ahc_handle_scsiint. status = %x\n", ahc_name(ahc), status); @@ -1418,8 +1410,8 @@ ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel) memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns)); tstate->ultraenb = 0; for (i = 0; i < 16; i++) { - memset(&tstate->transinfo[i].current, 0, - sizeof(tstate->transinfo[i].current)); + memset(&tstate->transinfo[i].curr, 0, + sizeof(tstate->transinfo[i].curr)); memset(&tstate->transinfo[i].goal, 0, sizeof(tstate->transinfo[i].goal)); } @@ -1479,8 +1471,7 @@ ahc_devlimited_syncrate(struct ahc_softc *ahc, /* Can't do DT on an SE bus */ *ppr_options &= ~MSG_EXT_PPR_DT_REQ; } - } else if ((ahc->features & AHC_ULTRA) != 0 - && (ahc->flags & AHC_ULTRA_DISABLED) == 0) { + } else if ((ahc->features & AHC_ULTRA) != 0) { maxsync = AHC_SYNCRATE_ULTRA; } else { maxsync = AHC_SYNCRATE_FAST; @@ -1522,6 +1513,11 @@ ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, if ((ahc->features & AHC_DT) == 0) *ppr_options &= ~MSG_EXT_PPR_DT_REQ; + + /* Skip all DT only entries if DT is not available */ + if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 + && maxsync < AHC_SYNCRATE_ULTRA2) + maxsync = AHC_SYNCRATE_ULTRA2; for (syncrate = &ahc_syncrates[maxsync]; syncrate->rate != NULL; @@ -1535,11 +1531,6 @@ ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, && (syncrate->sxfr_u2 == 0)) break; - /* Skip any DT entries if DT is not available */ - if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 - && (syncrate->sxfr_u2 & DT_SXFR) != 0) - continue; - if (*period <= syncrate->period) { /* * When responding to a target that requests @@ -1681,10 +1672,10 @@ ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, u_int auto_negotiate_orig; auto_negotiate_orig = tstate->auto_negotiate; - if (tinfo->current.period != tinfo->goal.period - || tinfo->current.width != tinfo->goal.width - || tinfo->current.offset != tinfo->goal.offset - || tinfo->current.ppr_options != tinfo->goal.ppr_options + 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 || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT @@ -1697,7 +1688,7 @@ ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, } /* - * Update the user/goal/current tables of synchronous negotiation + * Update the user/goal/curr tables of synchronous negotiation * parameters as well as, in the case of a current or active update, * any data structures on the host controller. In the case of an * active update, the specified target is currently talking to us on @@ -1740,9 +1731,9 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, tinfo->goal.ppr_options = ppr_options; } - old_period = tinfo->current.period; - old_offset = tinfo->current.offset; - old_ppr = tinfo->current.ppr_options; + old_period = tinfo->curr.period; + old_offset = tinfo->curr.offset; + old_ppr = tinfo->curr.ppr_options; if ((type & AHC_TRANS_CUR) != 0 && (old_period != period @@ -1795,12 +1786,12 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, } tinfo->scsirate = scsirate; - tinfo->current.period = period; - tinfo->current.offset = offset; - tinfo->current.ppr_options = ppr_options; + tinfo->curr.period = period; + tinfo->curr.offset = offset; + tinfo->curr.ppr_options = ppr_options; ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); if (bootverbose) { if (offset != 0) { printf("%s: target %d synchronous at %sMHz%s, " @@ -1824,7 +1815,7 @@ ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, } /* - * Update the user/goal/current tables of wide negotiation + * Update the user/goal/curr tables of wide negotiation * parameters as well as, in the case of a current or active update, * any data structures on the host controller. In the case of an * active update, the specified target is currently talking to us on @@ -1852,7 +1843,7 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, if ((type & AHC_TRANS_GOAL) != 0) tinfo->goal.width = width; - oldwidth = tinfo->current.width; + oldwidth = tinfo->curr.width; if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) { u_int scsirate; @@ -1867,10 +1858,10 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, if (active) ahc_outb(ahc, SCSIRATE, scsirate); - tinfo->current.width = width; + tinfo->curr.width = width; ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); if (bootverbose) { printf("%s: target %d using %dbit transfers\n", ahc_name(ahc), devinfo->target, @@ -1888,27 +1879,12 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, * Update the current state of tagged queuing for a given target. */ void -ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, int enable) +ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, + ahc_queue_alg alg) { - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - uint16_t orig_tagenable; - - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - - orig_tagenable = tstate->tagenable; - if (enable) - tstate->tagenable |= devinfo->target_mask; - else - tstate->tagenable &= ~devinfo->target_mask; - - if (orig_tagenable != tstate->tagenable) { - ahc_platform_set_tags(ahc, devinfo, enable); - ahc_send_async(ahc, devinfo->channel, devinfo->target, - devinfo->lun, AC_TRANSFER_NEG); - } - + ahc_platform_set_tags(ahc, devinfo, alg); + ahc_send_async(ahc, devinfo->channel, devinfo->target, + devinfo->lun, AC_TRANSFER_NEG, &alg); } /* @@ -1945,7 +1921,7 @@ ahc_update_pending_scbs(struct ahc_softc *ahc) if ((tstate->ultraenb & devinfo.target_mask) != 0) pending_hscb->control |= ULTRAENB; pending_hscb->scsirate = tinfo->scsirate; - pending_hscb->scsioffset = tinfo->current.offset; + pending_hscb->scsioffset = tinfo->curr.offset; if ((tstate->auto_negotiate & devinfo.target_mask) == 0 && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) { pending_scb->flags &= ~SCB_AUTO_NEGOTIATE; @@ -2073,6 +2049,17 @@ ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, /************************ Message Phase Processing ****************************/ +static void +ahc_assert_atn(struct ahc_softc *ahc) +{ + u_int scsisigo; + + scsisigo = ATNO; + if ((ahc->features & AHC_DT) == 0) + scsisigo |= ahc_inb(ahc, SCSISIGI); + ahc_outb(ahc, SCSISIGO, scsisigo); +} + /* * When an initiator transaction with the MK_MESSAGE flag either reconnects * or enters the initial message out phase, we are interrupted. Fill our @@ -2186,9 +2173,19 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); - dowide = tinfo->current.width != tinfo->goal.width; - dosync = tinfo->current.period != tinfo->goal.period; - doppr = tinfo->current.ppr_options != tinfo->goal.ppr_options; + /* + * Filter our period based on the current connection. + * If we can't perform DT transfers on this segment (not in LVD + * mode for instance), then our decision to issue a PPR message + * may change. + */ + period = tinfo->goal.period; + ppr_options = tinfo->goal.ppr_options; + rate = ahc_devlimited_syncrate(ahc, tinfo, &period, + &ppr_options, devinfo->role); + dowide = tinfo->curr.width != tinfo->goal.width; + dosync = tinfo->curr.period != period; + doppr = tinfo->curr.ppr_options != ppr_options; if (!dowide && !dosync && !doppr) { dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; @@ -2201,7 +2198,7 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) "but no negotiation needed\n"); } - use_ppr = (tinfo->current.transport_version >= 3) || doppr; + use_ppr = (tinfo->curr.transport_version >= 3) || doppr; /* Target initiated PPR is not allowed in the SCSI spec */ if (devinfo->role == ROLE_TARGET) use_ppr = 0; @@ -2216,16 +2213,10 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) */ if (use_ppr || (dosync && !dowide)) { - period = tinfo->goal.period; - ppr_options = tinfo->goal.ppr_options; - if (use_ppr == 0) - ppr_options = 0; - rate = ahc_devlimited_syncrate(ahc, tinfo, &period, - &ppr_options, devinfo->role); offset = tinfo->goal.offset; ahc_validate_offset(ahc, tinfo, rate, &offset, use_ppr ? tinfo->goal.width - : tinfo->current.width, + : tinfo->curr.width, devinfo->role); if (use_ppr) { ahc_construct_ppr(ahc, devinfo, period, offset, @@ -2383,7 +2374,7 @@ ahc_handle_message_phase(struct ahc_softc *ahc) * 0, and try again. */ ahc->msgout_index = 0; - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); + ahc_assert_atn(ahc); } lastbyte = ahc->msgout_index == (ahc->msgout_len - 1); @@ -2438,8 +2429,7 @@ ahc_handle_message_phase(struct ahc_softc *ahc) * message out phase. */ if (ahc->msgout_len != 0) - ahc_outb(ahc, SCSISIGO, - ahc_inb(ahc, SCSISIGO) | ATNO); + ahc_assert_atn(ahc); } else ahc->msgin_index++; @@ -2604,7 +2594,7 @@ ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, u_int msgval, int full) found = TRUE; } index = end_index; - } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_Q_TAG + } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_TASK && ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) { /* Skip tag type and tag id or residue param*/ @@ -2625,7 +2615,7 @@ ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, u_int msgval, int full) } /* - * Wait for a complete incomming message, parse it, and respond accordingly. + * Wait for a complete incoming message, parse it, and respond accordingly. */ static int ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) @@ -3062,7 +3052,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) devinfo->target, devinfo->lun); } tinfo->goal.ppr_options = 0; - tinfo->current.transport_version = 2; + tinfo->curr.transport_version = 2; tinfo->goal.transport_version = 2; ahc->msgout_index = 0; ahc->msgout_len = 0; @@ -3104,24 +3094,39 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) "Using asynchronous transfers\n", ahc_name(ahc), devinfo->channel, devinfo->target, devinfo->lun); - } else if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) { + } else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) { + int tag_type; + int mask; - printf("(%s:%c:%d:%d): refuses tagged commands. Performing " - "non-tagged I/O\n", ahc_name(ahc), - devinfo->channel, devinfo->target, devinfo->lun); - ahc_set_tags(ahc, devinfo, FALSE); + tag_type = (scb->hscb->control & MSG_SIMPLE_TASK); + + if (tag_type == MSG_SIMPLE_TASK) { + printf("(%s:%c:%d:%d): refuses tagged commands. " + "Performing non-tagged I/O\n", ahc_name(ahc), + devinfo->channel, devinfo->target, devinfo->lun); + ahc_set_tags(ahc, devinfo, AHC_QUEUE_NONE); + mask = ~0x23; + } else { + printf("(%s:%c:%d:%d): refuses %s tagged commands. " + "Performing simple queue tagged I/O only\n", + ahc_name(ahc), devinfo->channel, devinfo->target, + devinfo->lun, tag_type == MSG_ORDERED_TASK + ? "ordered" : "head of queue"); + ahc_set_tags(ahc, devinfo, AHC_QUEUE_BASIC); + mask = ~0x03; + } /* * Resend the identify for this CCB as the target * may believe that the selection is invalid otherwise. */ ahc_outb(ahc, SCB_CONTROL, - ahc_inb(ahc, SCB_CONTROL) & ~MSG_SIMPLE_Q_TAG); - scb->hscb->control &= ~MSG_SIMPLE_Q_TAG; + ahc_inb(ahc, SCB_CONTROL) & mask); + scb->hscb->control &= mask; ahc_set_transaction_tag(scb, /*enabled*/FALSE, - /*type*/MSG_SIMPLE_Q_TAG); + /*type*/MSG_SIMPLE_TASK); ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG); - ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); + ahc_assert_atn(ahc); /* * This transaction is now at the head of @@ -3323,7 +3328,7 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, AHC_TRANS_CUR, /*paused*/TRUE); ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_SENT_BDR); + CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); if (message != NULL && (verbose_level <= bootverbose)) @@ -4032,15 +4037,24 @@ ahc_controller_info(struct ahc_softc *ahc, char *buf) ahc->our_id, ahc->our_id_b, (ahc->flags & AHC_PRIMARY_CHANNEL) + 'A'); else { + const char *speed; const char *type; + speed = ""; + if ((ahc->features & AHC_ULTRA) != 0) { + speed = "Ultra "; + } else if ((ahc->features & AHC_DT) != 0) { + speed = "Ultra160 "; + } else if ((ahc->features & AHC_ULTRA2) != 0) { + speed = "Ultra2 "; + } if ((ahc->features & AHC_WIDE) != 0) { type = "Wide"; } else { type = "Single"; } - len = sprintf(buf, "%s Channel %c, SCSI Id=%d, ", - type, ahc->channel, ahc->our_id); + len = sprintf(buf, "%s%s Channel %c, SCSI Id=%d, ", + speed, type, ahc->channel, ahc->our_id); } buf += len; @@ -4292,8 +4306,6 @@ ahc_init(struct ahc_softc *ahc) ultraenb = (ahc_inb(ahc, ULTRA_ENB + 1) << 8) | ahc_inb(ahc, ULTRA_ENB); } - if ((ahc->flags & AHC_ULTRA_DISABLED) != 0) - ultraenb = 0; if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0) max_targ = 7; @@ -4393,12 +4405,10 @@ ahc_init(struct ahc_softc *ahc) tinfo->user.transport_version = 2; tinfo->goal.protocol_version = 2; tinfo->goal.transport_version = 2; - tinfo->current.protocol_version = 2; - tinfo->current.transport_version = 2; + tinfo->curr.protocol_version = 2; + tinfo->curr.transport_version = 2; } tstate->ultraenb = ultraenb; - tstate->discenable = discenable; - tstate->tagenable = 0; /* Wait until the XPT says its okay */ } ahc->user_discenable = discenable; ahc->user_tagenable = tagenable; @@ -5430,7 +5440,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, * Go through the pending CCB list and look for * commands for this target that are still active. * These are other tagged commands that were - * disconnected when the reset occured. + * disconnected when the reset occurred. */ scbp_next = LIST_FIRST(&ahc->pending_scbs); while (scbp_next != NULL) { @@ -5581,7 +5591,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) #endif /* Notify the XPT that a bus reset occurred */ ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, AC_BUS_RESET); + CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); /* * Revert to async/narrow transfers until we renegotiate. @@ -5617,7 +5627,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) /* * Calculate the residual for a just completed SCB. */ -static void +void ahc_calc_residual(struct scb *scb) { struct hardware_scb *hscb; @@ -6632,7 +6642,7 @@ ahc_run_tqinfifo(struct ahc_softc *ahc, int paused) cmd->cmd_valid = 0; /* - * Lazily update our position in the target mode incomming + * Lazily update our position in the target mode incoming * command queue as seen by the sequencer. */ if ((ahc->tqinfifonext & (HOST_TQINPOS - 1)) == 1) { diff --git a/sys/dev/aic7xxx/aic7xxx.h b/sys/dev/aic7xxx/aic7xxx.h index eada9ad5778a..4eded92809ab 100644 --- a/sys/dev/aic7xxx/aic7xxx.h +++ b/sys/dev/aic7xxx/aic7xxx.h @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.h#24 $ + * $Id: //depot/src/aic7xxx/aic7xxx.h#27 $ * * $FreeBSD$ */ @@ -209,9 +209,15 @@ typedef enum { AHC_MULTIROLE = 0x40000, /* Space for two roles at a time */ AHC_REMOVABLE = 0x80000, /* Hot-Swap supported */ AHC_AIC7770_FE = AHC_FENONE, - AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE, - AHC_AIC7855_FE = AHC_AIC7850_FE, - AHC_AIC7860_FE = AHC_AIC7850_FE|AHC_ULTRA, + /* + * The real 7850 does not support Ultra modes, but there are + * several cards that use the generic 7850 PCI ID even though + * they are using an Ultra capable chip (7859/7860). We start + * out with the AHC_ULTRA feature set and then check the DEVSTATUS + * register to determine if the capability is really present. + */ + AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE|AHC_ULTRA, + AHC_AIC7860_FE = AHC_AIC7850_FE, AHC_AIC7870_FE = AHC_TARGETMODE, AHC_AIC7880_FE = AHC_AIC7870_FE|AHC_ULTRA, /* @@ -328,12 +334,6 @@ typedef enum { */ AHC_BIOS_ENABLED = 0x80000, AHC_ALL_INTERRUPTS = 0x100000, - AHC_ULTRA_DISABLED = 0x200000, /* - * The precision resistor for - * ultra transmission speeds is - * missing, so we must limit - * ourselves to fast SCSI. - */ AHC_PAGESCBS = 0x400000, /* Enable SCB paging */ AHC_EDGE_INTERRUPT = 0x800000 /* Device uses edge triggered ints */ } ahc_flag; @@ -660,7 +660,7 @@ struct ahc_transinfo { * Per-initiator current, goal and user transfer negotiation information. */ struct ahc_initiator_tinfo { uint8_t scsirate; /* Computed value for SCSIRATE reg */ - struct ahc_transinfo current; + struct ahc_transinfo curr; struct ahc_transinfo goal; struct ahc_transinfo user; }; @@ -749,12 +749,19 @@ struct seeprom_config { #define CFSUPREM 0x0001 /* support all removeable drives */ #define CFSUPREMB 0x0002 /* support removeable boot drives */ #define CFBIOSEN 0x0004 /* BIOS enabled */ -/* UNUSED 0x0008 */ +#define CFBIOS_BUSSCAN 0x0008 /* Have the BIOS Scan the Bus */ #define CFSM2DRV 0x0010 /* support more than two drives */ -#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ #define CFSTPWLEVEL 0x0010 /* Termination level control */ +#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ +#define CFCTRL_A 0x0020 /* BIOS displays Ctrl-A message */ +#define CFTERM_MENU 0x0040 /* BIOS displays termination menu */ #define CFEXTEND 0x0080 /* extended translation enabled */ #define CFSCAMEN 0x0100 /* SCAM enable */ +#define CFMSG_LEVEL 0x0600 /* BIOS Message Level */ +#define CFMSG_VERBOSE 0x0000 +#define CFMSG_SILENT 0x0200 +#define CFMSG_DIAG 0x0400 +#define CFBOOTCD 0x0800 /* Support Bootable CD-ROM */ /* UNUSED 0xff00 */ /* @@ -769,7 +776,7 @@ struct seeprom_config { #define CFWSTERM 0x0008 /* SCSI high byte termination */ #define CFSPARITY 0x0010 /* SCSI parity */ #define CF284XSTERM 0x0020 /* SCSI low byte term (284x cards) */ -#define CFMULTILUN 0x0020 /* SCSI low byte term (284x cards) */ +#define CFMULTILUN 0x0020 #define CFRESETB 0x0040 /* reset SCSI bus at boot */ #define CFCLUSTERENB 0x0080 /* Cluster Enable */ #define CFBOOTCHAN 0x0300 /* probe this channel first */ @@ -1135,6 +1142,7 @@ void ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb); int ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset); void ahc_restart(struct ahc_softc *ahc); +void ahc_calc_residual(struct scb *scb); /*************************** Utility Functions ********************************/ struct ahc_phase_table_entry* ahc_lookup_phase_entry(int phase); @@ -1170,8 +1178,15 @@ void ahc_set_syncrate(struct ahc_softc *ahc, u_int period, u_int offset, u_int ppr_options, u_int type, int paused); +typedef enum { + AHC_QUEUE_NONE, + AHC_QUEUE_BASIC, + AHC_QUEUE_TAGGED +} ahc_queue_alg; + void ahc_set_tags(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, int enable); + struct ahc_devinfo *devinfo, + ahc_queue_alg alg); /**************************** Target Mode *************************************/ #ifdef AHC_TARGET_MODE diff --git a/sys/dev/aic7xxx/aic7xxx.reg b/sys/dev/aic7xxx/aic7xxx.reg index c1f342f5bdcd..91c6b8af1700 100644 --- a/sys/dev/aic7xxx/aic7xxx.reg +++ b/sys/dev/aic7xxx/aic7xxx.reg @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.reg#15 $ + * $Id: //depot/src/aic7xxx/aic7xxx.reg#17 $ * * $FreeBSD$ */ @@ -970,6 +970,7 @@ register SCSIPHASE { bit MSG_OUT_PHASE 0x04 bit DATA_IN_PHASE 0x02 bit DATA_OUT_PHASE 0x01 + mask DATA_PHASE_MASK 0x03 } /* diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq index bd4342a29b06..c50a99c75e25 100644 --- a/sys/dev/aic7xxx/aic7xxx.seq +++ b/sys/dev/aic7xxx/aic7xxx.seq @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx.seq#24 $ + * $Id: //depot/src/aic7xxx/aic7xxx.seq#27 $ * * $FreeBSD$ */ @@ -153,7 +153,9 @@ selection: * the kernel driver if it happens. */ mvi CLRSINT1,CLRBUSFREE; - or SIMODE1, ENBUSFREE; + if ((ahc->features & AHC_DT) == 0) { + or SIMODE1, ENBUSFREE; + } /* * Guard against a bus free after (re)selection @@ -706,17 +708,17 @@ disable_ccsgen_fetch_done: test CCSGCTL, CCSGEN jnz .; ret; idle_loop: + /* + * Do we need any more segments for this transfer? + */ + test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; + /* Did we just finish fetching segs? */ cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete; /* Are we actively fetching segments? */ test CCSGCTL, CCSGEN jnz return; - /* - * Do we need any more segments? - */ - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; - /* * Do we have any prefetch left??? */ @@ -885,7 +887,11 @@ data_phase_loop: and DMAPARAMS, DIRECTION; mov DFCNTRL, DMAPARAMS; or SXFRCTL1,BITBUCKET; - test SSTAT1,PHASEMIS jz .; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT1,PHASEMIS jz .; + } else { + test SCSIPHASE, DATA_PHASE_MASK jnz .; + } and SXFRCTL1, ~BITBUCKET; mvi DATA_OVERRUN call set_seqint; jmp ITloop; @@ -906,54 +912,48 @@ ultra2_dma_loop: * completes or the target changes phase. */ test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish; - if ((ahc->flags & AHC_TARGETROLE) != 0) { - /* - * As a target, we control the phases, - * so ignore PHASEMIS. - */ - test SSTAT0, TARGET jnz ultra2_dma_loop; - } - if ((ahc->flags & AHC_INITIATORROLE) != 0) { - test SSTAT1,PHASEMIS jz ultra2_dma_loop; + if ((ahc->features & AHC_DT) == 0) { + if ((ahc->flags & AHC_TARGETROLE) != 0) { + /* + * As a target, we control the phases, + * so ignore PHASEMIS. + */ + test SSTAT0, TARGET jnz ultra2_dma_loop; + } + if ((ahc->flags & AHC_INITIATORROLE) != 0) { + test SSTAT1,PHASEMIS jz ultra2_dma_loop; + } + } else { + test DFCNTRL, SCSIEN jnz ultra2_dma_loop; } ultra2_dmafinish: - test DFCNTRL, DIRECTION jnz ultra2_dmafifoempty; - if ((ahc->features & AHC_DT) == 0) { - and DFCNTRL, ~SCSIEN; - test DFCNTRL, SCSIEN jnz .; - } -ultra2_dmafifoflush: + /* + * The transfer has terminated either due to a phase + * change, and/or the completion of the last segment. + * We have two goals here. Do as much other work + * as possible while the data fifo drains on a read + * and respond as quickly as possible to the standard + * messages (save data pointers/disconnect and command + * complete) that usually follow a data phase. + */ if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { /* - * On Rev A of the aic7890, the autoflush - * features doesn't function correctly. - * Perform an explicit manual flush. During - * a manual flush, the FIFOEMP bit becomes - * true every time the PCI FIFO empties - * regardless of the state of the SCSI FIFO. - * It can take up to 4 clock cycles for the - * SCSI FIFO to get data into the PCI FIFO - * and for FIFOEMP to de-assert. Here we - * guard against this condition by making - * sure the FIFOEMP bit stays on for 5 full - * clock cycles. + * On chips with broken auto-flush, start + * the flushing process now. We'll poke + * the chip from time to time to keep the + * flush process going as we complete the + * data phase. */ or DFCNTRL, FIFOFLUSH; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; } - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; -ultra2_dmafifoempty: - /* Don't clobber an inprogress host data transfer */ - test DFSTATUS, MREQPEND jnz ultra2_dmafifoempty; -ultra2_dmahalt: - and DFCNTRL, ~(SCSIEN|HDMAEN); - test DFCNTRL, SCSIEN|HDMAEN jnz .; - /* + * We assume that, even though data may still be + * transferring to the host, that the SCSI side of + * the DMA engine is now in a static state. This + * allows us to update our notion of where we are + * in this transfer. + * * If, by chance, we stopped before being able * to fetch additional segments for this transfer, * yet the last S/G was completely exhausted, @@ -964,14 +964,14 @@ ultra2_dmahalt: * If we happened to stop on the last segment, then * our residual information is still correct from * the idle loop and there is no need to perform - * any fixups. Just jump to data_phase_finish. + * any fixups. */ ultra2_ensure_sg: test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; /* Record if we've consumed all S/G entries */ - test SG_CACHE_SHADOW, LAST_SEG_DONE jz data_phase_finish; + test SSTAT2, SHVALID jnz residuals_correct; or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; - jmp data_phase_finish; + jmp residuals_correct; ultra2_shvalid: test SSTAT2, SHVALID jnz sgptr_fixup; @@ -1001,6 +1001,62 @@ sgptr_fixup_done: test SG_CACHE_SHADOW, ODD_SEG jz . + 2; or DATA_COUNT_ODD, 0x1; clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ +residuals_correct: + /* + * Go ahead and shut down the DMA engine now. + * In the future, we'll want to handle end of + * transfer messages prior to doing this, but this + * requires similar restructuring for pre-ULTRA2 + * controllers. + */ + test DMAPARAMS, DIRECTION jnz ultra2_fifoempty; +ultra2_fifoflush: + if ((ahc->features & AHC_DT) == 0) { + if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { + /* + * On Rev A of the aic7890, the autoflush + * feature doesn't function correctly. + * Perform an explicit manual flush. During + * a manual flush, the FIFOEMP bit becomes + * true every time the PCI FIFO empties + * regardless of the state of the SCSI FIFO. + * It can take up to 4 clock cycles for the + * SCSI FIFO to get data into the PCI FIFO + * and for FIFOEMP to de-assert. Here we + * guard against this condition by making + * sure the FIFOEMP bit stays on for 5 full + * clock cycles. + */ + or DFCNTRL, FIFOFLUSH; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + } + test DFSTATUS, FIFOEMP jz ultra2_fifoflush; + } else { + /* + * We enable the auto-ack feature on DT capable + * controllers. This means that the controller may + * have already transferred some overrun bytes into + * the data FIFO and acked them on the bus. The only + * way to detect this situation is to wait for + * LAST_SEG_DONE to come true on a completed transfer + * and then test to see if the data FIFO is non-empty. + */ + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 4; + test SG_CACHE_SHADOW, LAST_SEG_DONE jz .; + test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; + /* Overrun */ + jmp data_phase_loop; + test DFSTATUS, FIFOEMP jz .; + } +ultra2_fifoempty: + /* Don't clobber an inprogress host data transfer */ + test DFSTATUS, MREQPEND jnz ultra2_fifoempty; +ultra2_dmahalt: + and DFCNTRL, ~(SCSIEN|HDMAEN); + test DFCNTRL, SCSIEN|HDMAEN jnz .; } else { /* If we are the last SG block, tell the hardware. */ if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 @@ -1159,7 +1215,11 @@ data_phase_finish: } if ((ahc->flags & AHC_INITIATORROLE) != 0) { test SSTAT1, REQINIT jz .; - test SSTAT1,PHASEMIS jz data_phase_loop; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT1,PHASEMIS jz data_phase_loop; + } else { + test SCSIPHASE, DATA_PHASE_MASK jnz data_phase_loop; + } } data_phase_done: @@ -1263,7 +1323,7 @@ p_command_from_host: jmp p_command_loop; p_command_embedded: /* - * The data fifo seems to require 4 byte alligned + * The data fifo seems to require 4 byte aligned * transfers from the sequencer. Force this to * be the case by clearing HADDR[0] even though * we aren't going to touch host memeory. @@ -1299,13 +1359,17 @@ p_command_embedded: or DFCNTRL, FIFOFLUSH; } p_command_loop: - test SSTAT0, SDONE jnz . + 2; - test SSTAT1, PHASEMIS jz p_command_loop; - /* - * Wait for our ACK to go-away on it's own - * instead of being killed by SCSIEN getting cleared. - */ - test SCSISIGI, ACKI jnz .; + if ((ahc->features & AHC_DT) == 0) { + test SSTAT0, SDONE jnz . + 2; + test SSTAT1, PHASEMIS jz p_command_loop; + /* + * Wait for our ACK to go-away on it's own + * instead of being killed by SCSIEN getting cleared. + */ + test SCSISIGI, ACKI jnz .; + } else { + test DFCNTRL, SCSIEN jnz p_command_loop; + } and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -1349,7 +1413,12 @@ p_status: * reason. */ p_mesgout_retry: - or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ + /* Turn on ATN for the retry */ + if ((ahc->features & AHC_DT) == 0) { + or SCSISIGO, ATNO, LASTPHASE; + } else { + mvi SCSISIGO, ATNO; + } p_mesgout: mov SINDEX, MSG_OUT; cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; @@ -1546,10 +1615,17 @@ mesgin_disconnect: * only if we've actually been into a data phase to change them. This * protects against bogus data in scratch ram and the residual counts * since they are only initialized when we go into data_in or data_out. + * Ack the message as soon as possible. For chips without S/G pipelining, + * we can only ack the message after SHADDR has been saved. On these + * chips, SHADDR increments with every bus transaction, even PIO. */ mesgin_sdptrs: - test SEQ_FLAGS, DPHASE jz mesgin_done; - + if ((ahc->features & AHC_ULTRA2) != 0) { + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ + test SEQ_FLAGS, DPHASE jz ITloop; + } else { + test SEQ_FLAGS, DPHASE jz mesgin_done; + } /* * The SCB_SGPTR becomes the next one we'll download, * and the SCB_DATAPTR becomes the current SHADDR. @@ -1558,13 +1634,17 @@ mesgin_sdptrs: */ if ((ahc->features & AHC_CMD_CHAN) != 0) { bmov SCB_DATAPTR, SHADDR, 4; + if ((ahc->features & AHC_ULTRA2) == 0) { + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ + } bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8; } else { mvi DINDEX, SCB_DATAPTR; mvi SHADDR call bcopy_4; + mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ mvi SCB_RESIDUAL_DATACNT call bcopy_8; } - jmp mesgin_done; + jmp ITloop; /* * Restore pointers message? Data pointers are recopied from the @@ -1742,7 +1822,11 @@ not_found: jmp mesgin_done; mk_mesg: - or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ + if ((ahc->features & AHC_DT) == 0) { + or SCSISIGO, ATNO, LASTPHASE; + } else { + mvi SCSISIGO, ATNO; + } mov MSG_OUT,SINDEX ret; /* @@ -1789,7 +1873,7 @@ if ((ahc->flags & AHC_TARGETROLE) != 0) { * from out to in, wait an additional data release delay before continuing. */ change_phase: - /* Wait for preceding I/O session to complete. */ + /* Wait for preceeding I/O session to complete. */ test SCSISIGI, ACKI jnz .; /* Change the phase */ @@ -1915,7 +1999,9 @@ phase_lock: test SSTAT1, REQINIT jz phase_lock; test SSTAT1, SCSIPERR jnz phase_lock_perr; phase_lock_latch_phase: - and SCSISIGO, PHASE_MASK, SCSISIGI; + if ((ahc->features & AHC_DT) == 0) { + and SCSISIGO, PHASE_MASK, SCSISIGI; + } and LASTPHASE, PHASE_MASK, SCSISIGI ret; if ((ahc->features & AHC_CMD_CHAN) == 0) { diff --git a/sys/dev/aic7xxx/aic7xxx_93cx6.c b/sys/dev/aic7xxx/aic7xxx_93cx6.c index 684c60859cab..e3eaedd68838 100644 --- a/sys/dev/aic7xxx/aic7xxx_93cx6.c +++ b/sys/dev/aic7xxx/aic7xxx_93cx6.c @@ -67,17 +67,9 @@ * */ -#ifdef __linux__ -#include "aic7xxx_linux.h" -#include "aic7xxx_inline.h" -#include "aic7xxx_93cx6.h" -#endif - -#ifdef __FreeBSD__ #include #include #include -#endif /* * Right now, we only have to read the SEEPROM. But we make it easier to diff --git a/sys/dev/aic7xxx/aic7xxx_freebsd.c b/sys/dev/aic7xxx/aic7xxx_freebsd.c index f61c8da46053..e06a1d66d023 100644 --- a/sys/dev/aic7xxx/aic7xxx_freebsd.c +++ b/sys/dev/aic7xxx/aic7xxx_freebsd.c @@ -49,6 +49,7 @@ static int ahc_debug = AHC_DEBUG; #if UNUSED static void ahc_dump_targcmd(struct target_cmd *cmd); #endif +static int ahc_modevent(module_t mod, int type, void *data); static void ahc_action(struct cam_sim *sim, union ccb *ccb); static void ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel, @@ -572,9 +573,9 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) update_type |= AHC_TRANS_GOAL; discenable = &tstate->discenable; tagenable = &tstate->tagenable; - tinfo->current.protocol_version = + tinfo->curr.protocol_version = cts->protocol_version; - tinfo->current.transport_version = + tinfo->curr.transport_version = cts->transport_version; tinfo->goal.protocol_version = cts->protocol_version; @@ -777,7 +778,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) && tinfo->user.transport_version >= 3) { tinfo->goal.transport_version = tinfo->user.transport_version; - tinfo->current.transport_version = + tinfo->curr.transport_version = tinfo->user.transport_version; } @@ -932,7 +933,7 @@ ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel, devinfo.target, &tstate); if (cts->type == CTS_TYPE_CURRENT_SETTINGS) - tinfo = &targ_info->current; + tinfo = &targ_info->curr; else tinfo = &targ_info->user; @@ -990,7 +991,7 @@ ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel, devinfo.target, &tstate); if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) - tinfo = &targ_info->current; + tinfo = &targ_info->curr; else tinfo = &targ_info->user; @@ -1206,7 +1207,7 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, mask = SCB_GET_TARGET_MASK(ahc, scb); scb->hscb->scsirate = tinfo->scsirate; - scb->hscb->scsioffset = tinfo->current.offset; + scb->hscb->scsioffset = tinfo->curr.offset; if ((tstate->ultraenb & mask) != 0) scb->hscb->control |= ULTRAENB; @@ -1767,7 +1768,7 @@ ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) void ahc_send_async(struct ahc_softc *ahc, char channel, u_int target, - u_int lun, ac_code code) + u_int lun, ac_code code, void *opt_arg) { struct ccb_trans_settings cts; struct cam_path *path; @@ -1782,8 +1783,12 @@ ahc_send_async(struct ahc_softc *ahc, char channel, u_int target, switch (code) { case AC_TRANSFER_NEG: + { #ifdef AHC_NEW_TRAN_SETTINGS + struct ccb_trans_settings_scsi *scsi; + cts.type = CTS_TYPE_CURRENT_SETTINGS; + scsi = &cts.proto_specific.scsi; #else cts.flags = CCB_TRANS_CURRENT_SETTINGS; #endif @@ -1794,7 +1799,25 @@ ahc_send_async(struct ahc_softc *ahc, char channel, u_int target, : ahc->our_id_b, channel, &cts); arg = &cts; +#ifdef AHC_NEW_TRAN_SETTINGS + scsi->valid &= ~CTS_SCSI_VALID_TQ; + scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; +#else + cts.valid &= ~CCB_TRANS_TQ_VALID; + cts.flags &= ~CCB_TRANS_TAG_ENB; +#endif + if (opt_arg == NULL) + break; + if (*((ahc_queue_alg *)opt_arg) == AHC_QUEUE_TAGGED) +#ifdef AHC_NEW_TRAN_SETTINGS + scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB; + scsi->valid |= CTS_SCSI_VALID_TQ; +#else + cts.flags |= CCB_TRANS_TAG_ENB; + cts.valid |= CCB_TRANS_TQ_VALID; +#endif break; + } case AC_SENT_BDR: case AC_BUS_RESET: break; @@ -1906,3 +1929,20 @@ ahc_dump_targcmd(struct target_cmd *cmd) } } #endif + +static int +ahc_modevent(module_t mod, int type, void *data) +{ + /* XXX Deal with busy status on unload. */ + return 0; +} + +static moduledata_t ahc_mod = { + "ahc", + ahc_modevent, + NULL +}; + +DECLARE_MODULE(ahc, ahc_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); +MODULE_DEPEND(ahc, cam, 1, 1, 1); +MODULE_VERSION(ahc, 1); diff --git a/sys/dev/aic7xxx/aic7xxx_freebsd.h b/sys/dev/aic7xxx/aic7xxx_freebsd.h index 9e5c8f172976..b2bf917bde0a 100644 --- a/sys/dev/aic7xxx/aic7xxx_freebsd.h +++ b/sys/dev/aic7xxx/aic7xxx_freebsd.h @@ -41,7 +41,9 @@ #define AHC_NEW_TRAN_SETTINGS #endif /* CAM_NEW_TRAN_CODE */ #include /* for config options */ -#include /* for NPCI */ +#ifndef NPCI +#include +#endif #include #include @@ -96,6 +98,9 @@ (SCB_GET_CHANNEL(ahc, scb) == 'A' ? (ahc)->platform_data->sim \ : (ahc)->platform_data->sim_b) +#ifndef offsetof +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) +#endif /************************* Forward Declarations *******************************/ typedef device_t ahc_dev_softc_t; typedef union ccb *ahc_io_ctx_t; @@ -144,10 +149,10 @@ typedef union ccb *ahc_io_ctx_t; * transfer is as fragmented as possible and unaligned, this turns out to * be the number of paged sized transfers in MAXPHYS plus an extra element * to handle any unaligned residual. The sequencer fetches SG elements - * in 128 byte chucks, so make the number per-transaction a nice multiple - * of 16 (8 byte S/G elements). + * in cacheline sized chucks, so make the number per-transaction an even + * multiple of 16 which should align us on even the largest of cacheline + * boundaries. */ -/* XXX Worth the space??? */ #define AHC_NSEG (roundup(btoc(MAXPHYS) + 1, 16)) /* This driver supports target mode */ @@ -505,5 +510,5 @@ ahc_platform_flushwork(struct ahc_softc *ahc) timeout_t ahc_timeout; void ahc_done(struct ahc_softc *ahc, struct scb *scb); void ahc_send_async(struct ahc_softc *, char /*channel*/, - u_int /*target*/, u_int /*lun*/, ac_code); + u_int /*target*/, u_int /*lun*/, ac_code, void *arg); #endif /* _AIC7XXX_FREEBSD_H_ */ diff --git a/sys/dev/aic7xxx/aic7xxx_inline.h b/sys/dev/aic7xxx/aic7xxx_inline.h index 446b10488db6..ddf1bb5a5beb 100644 --- a/sys/dev/aic7xxx/aic7xxx_inline.h +++ b/sys/dev/aic7xxx/aic7xxx_inline.h @@ -28,7 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#19 $ + * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#21 $ * * $FreeBSD$ */ @@ -188,7 +188,7 @@ ahc_name(struct ahc_softc *ahc) /*********************** Miscelaneous Support Functions ***********************/ -static __inline int ahc_check_residual(struct scb *scb); +static __inline void ahc_update_residual(struct scb *scb); static __inline struct ahc_initiator_tinfo * ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, @@ -211,15 +211,16 @@ static __inline uint32_t * Determine whether the sequencer reported a residual * for this SCB/transaction. */ -static __inline int -ahc_check_residual(struct scb *scb) +static __inline void +ahc_update_residual(struct scb *scb) { - struct status_pkt *sp; + uint32_t sgptr; - sp = &scb->hscb->shared_data.status; - if ((scb->hscb->sgptr & SG_RESID_VALID) != 0) - return (1); - return (0); + sgptr = ahc_le32toh(scb->hscb->sgptr); + if ((sgptr & SG_RESID_VALID) != 0) + ahc_calc_residual(scb); + else + ahc_set_residual(scb, 0); } /* diff --git a/sys/dev/aic7xxx/aic7xxx_osm.c b/sys/dev/aic7xxx/aic7xxx_osm.c index f61c8da46053..e06a1d66d023 100644 --- a/sys/dev/aic7xxx/aic7xxx_osm.c +++ b/sys/dev/aic7xxx/aic7xxx_osm.c @@ -49,6 +49,7 @@ static int ahc_debug = AHC_DEBUG; #if UNUSED static void ahc_dump_targcmd(struct target_cmd *cmd); #endif +static int ahc_modevent(module_t mod, int type, void *data); static void ahc_action(struct cam_sim *sim, union ccb *ccb); static void ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel, @@ -572,9 +573,9 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) update_type |= AHC_TRANS_GOAL; discenable = &tstate->discenable; tagenable = &tstate->tagenable; - tinfo->current.protocol_version = + tinfo->curr.protocol_version = cts->protocol_version; - tinfo->current.transport_version = + tinfo->curr.transport_version = cts->transport_version; tinfo->goal.protocol_version = cts->protocol_version; @@ -777,7 +778,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) && tinfo->user.transport_version >= 3) { tinfo->goal.transport_version = tinfo->user.transport_version; - tinfo->current.transport_version = + tinfo->curr.transport_version = tinfo->user.transport_version; } @@ -932,7 +933,7 @@ ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel, devinfo.target, &tstate); if (cts->type == CTS_TYPE_CURRENT_SETTINGS) - tinfo = &targ_info->current; + tinfo = &targ_info->curr; else tinfo = &targ_info->user; @@ -990,7 +991,7 @@ ahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel, devinfo.target, &tstate); if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) - tinfo = &targ_info->current; + tinfo = &targ_info->curr; else tinfo = &targ_info->user; @@ -1206,7 +1207,7 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, mask = SCB_GET_TARGET_MASK(ahc, scb); scb->hscb->scsirate = tinfo->scsirate; - scb->hscb->scsioffset = tinfo->current.offset; + scb->hscb->scsioffset = tinfo->curr.offset; if ((tstate->ultraenb & mask) != 0) scb->hscb->control |= ULTRAENB; @@ -1767,7 +1768,7 @@ ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) void ahc_send_async(struct ahc_softc *ahc, char channel, u_int target, - u_int lun, ac_code code) + u_int lun, ac_code code, void *opt_arg) { struct ccb_trans_settings cts; struct cam_path *path; @@ -1782,8 +1783,12 @@ ahc_send_async(struct ahc_softc *ahc, char channel, u_int target, switch (code) { case AC_TRANSFER_NEG: + { #ifdef AHC_NEW_TRAN_SETTINGS + struct ccb_trans_settings_scsi *scsi; + cts.type = CTS_TYPE_CURRENT_SETTINGS; + scsi = &cts.proto_specific.scsi; #else cts.flags = CCB_TRANS_CURRENT_SETTINGS; #endif @@ -1794,7 +1799,25 @@ ahc_send_async(struct ahc_softc *ahc, char channel, u_int target, : ahc->our_id_b, channel, &cts); arg = &cts; +#ifdef AHC_NEW_TRAN_SETTINGS + scsi->valid &= ~CTS_SCSI_VALID_TQ; + scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; +#else + cts.valid &= ~CCB_TRANS_TQ_VALID; + cts.flags &= ~CCB_TRANS_TAG_ENB; +#endif + if (opt_arg == NULL) + break; + if (*((ahc_queue_alg *)opt_arg) == AHC_QUEUE_TAGGED) +#ifdef AHC_NEW_TRAN_SETTINGS + scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB; + scsi->valid |= CTS_SCSI_VALID_TQ; +#else + cts.flags |= CCB_TRANS_TAG_ENB; + cts.valid |= CCB_TRANS_TQ_VALID; +#endif break; + } case AC_SENT_BDR: case AC_BUS_RESET: break; @@ -1906,3 +1929,20 @@ ahc_dump_targcmd(struct target_cmd *cmd) } } #endif + +static int +ahc_modevent(module_t mod, int type, void *data) +{ + /* XXX Deal with busy status on unload. */ + return 0; +} + +static moduledata_t ahc_mod = { + "ahc", + ahc_modevent, + NULL +}; + +DECLARE_MODULE(ahc, ahc_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); +MODULE_DEPEND(ahc, cam, 1, 1, 1); +MODULE_VERSION(ahc, 1); diff --git a/sys/dev/aic7xxx/aic7xxx_osm.h b/sys/dev/aic7xxx/aic7xxx_osm.h index 9e5c8f172976..b2bf917bde0a 100644 --- a/sys/dev/aic7xxx/aic7xxx_osm.h +++ b/sys/dev/aic7xxx/aic7xxx_osm.h @@ -41,7 +41,9 @@ #define AHC_NEW_TRAN_SETTINGS #endif /* CAM_NEW_TRAN_CODE */ #include /* for config options */ -#include /* for NPCI */ +#ifndef NPCI +#include +#endif #include #include @@ -96,6 +98,9 @@ (SCB_GET_CHANNEL(ahc, scb) == 'A' ? (ahc)->platform_data->sim \ : (ahc)->platform_data->sim_b) +#ifndef offsetof +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) +#endif /************************* Forward Declarations *******************************/ typedef device_t ahc_dev_softc_t; typedef union ccb *ahc_io_ctx_t; @@ -144,10 +149,10 @@ typedef union ccb *ahc_io_ctx_t; * transfer is as fragmented as possible and unaligned, this turns out to * be the number of paged sized transfers in MAXPHYS plus an extra element * to handle any unaligned residual. The sequencer fetches SG elements - * in 128 byte chucks, so make the number per-transaction a nice multiple - * of 16 (8 byte S/G elements). + * in cacheline sized chucks, so make the number per-transaction an even + * multiple of 16 which should align us on even the largest of cacheline + * boundaries. */ -/* XXX Worth the space??? */ #define AHC_NSEG (roundup(btoc(MAXPHYS) + 1, 16)) /* This driver supports target mode */ @@ -505,5 +510,5 @@ ahc_platform_flushwork(struct ahc_softc *ahc) timeout_t ahc_timeout; void ahc_done(struct ahc_softc *ahc, struct scb *scb); void ahc_send_async(struct ahc_softc *, char /*channel*/, - u_int /*target*/, u_int /*lun*/, ac_code); + u_int /*target*/, u_int /*lun*/, ac_code, void *arg); #endif /* _AIC7XXX_FREEBSD_H_ */ diff --git a/sys/dev/aic7xxx/aic7xxx_pci.c b/sys/dev/aic7xxx/aic7xxx_pci.c index 5102c5b922cb..0a7b4f3f1fa3 100644 --- a/sys/dev/aic7xxx/aic7xxx_pci.c +++ b/sys/dev/aic7xxx/aic7xxx_pci.c @@ -30,22 +30,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#21 $ + * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#24 $ * * $FreeBSD$ */ -#ifdef __linux__ -#include "aic7xxx_linux.h" -#include "aic7xxx_inline.h" -#include "aic7xxx_93cx6.h" -#endif - -#ifdef __FreeBSD__ #include #include #include -#endif #define AHC_PCI_IOADDR PCIR_MAPS /* I/O Address */ #define AHC_PCI_MEMADDR (PCIR_MAPS + 4) /* Mem I/O Address */ @@ -271,7 +263,7 @@ struct ahc_pci_identity ahc_pci_ident_table [] = { ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK, ID_DEV_VENDOR_MASK, - "Adaptec 2930C SCSI adapter (VAR)", + "Adaptec 2930C Ultra SCSI adapter (VAR)", ahc_aic7860_setup }, /* aic7870 based controllers */ @@ -460,7 +452,7 @@ struct ahc_pci_identity ahc_pci_ident_table [] = { ID_AIC7892_ARO, ID_ALL_MASK, - "Adaptec aic7892 Ultra2 SCSI adapter (ARO)", + "Adaptec aic7892 Ultra160 SCSI adapter (ARO)", ahc_aic7892_setup }, /* aic7895 based controllers */ @@ -554,13 +546,13 @@ struct ahc_pci_identity ahc_pci_ident_table [] = { ID_AIC7859 & ID_DEV_VENDOR_MASK, ID_DEV_VENDOR_MASK, - "Adaptec aic7859 Ultra SCSI adapter", + "Adaptec aic7859 SCSI adapter", ahc_aic7860_setup }, { ID_AIC7860 & ID_DEV_VENDOR_MASK, ID_DEV_VENDOR_MASK, - "Adaptec aic7860 SCSI adapter", + "Adaptec aic7860 Ultra SCSI adapter", ahc_aic7860_setup }, { @@ -786,7 +778,8 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry) /* Perform ALT-Mode Setup */ sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); - ahc_outb(ahc, OPTIONMODE, OPTIONMODE_DEFAULTS); + ahc_outb(ahc, OPTIONMODE, + OPTIONMODE_DEFAULTS|AUTOACKEN|BUSFREEREV|EXPPHASEDIS); ahc_outb(ahc, SFUNCT, sfunct); /* Normal mode setup */ @@ -794,10 +787,6 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry) |TARGCRCENDEN); } - error = ahc_pci_map_int(ahc); - if (error != 0) - return (error); - dscommand0 = ahc_inb(ahc, DSCOMMAND0); dscommand0 |= MPARCKEN|CACHETHEN; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -826,6 +815,19 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry) /*bytes*/1) & CACHESIZE; ahc->pci_cachesize *= 4; + /* + * We cannot perform ULTRA speeds without the presense + * of the external precision resistor. + */ + if ((ahc->features & AHC_ULTRA) != 0) { + uint32_t devconfig; + + devconfig = ahc_pci_read_config(ahc->dev_softc, + DEVCONFIG, /*bytes*/4); + if ((devconfig & REXTVALID) == 0) + ahc->features &= ~AHC_ULTRA; + } + /* See if we have a SEEPROM and perform auto-term */ check_extport(ahc, &sxfrctl1); @@ -880,20 +882,6 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry) if ((sxfrctl1 & STPWEN) != 0) ahc->flags |= AHC_TERM_ENB_A; - /* - * We cannot perform ULTRA speeds without - * the presense of the external precision - * resistor. - */ - if ((ahc->features & AHC_ULTRA) != 0) { - uint32_t devconfig; - - devconfig = ahc_pci_read_config(ahc->dev_softc, - DEVCONFIG, /*bytes*/4); - if ((devconfig & REXTVALID) == 0) - ahc->flags |= AHC_ULTRA_DISABLED; - } - /* Core initialization */ error = ahc_init(ahc); if (error != 0) @@ -907,6 +895,10 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry) /* * Allow interrupts now that we are completely setup. */ + error = ahc_pci_map_int(ahc); + if (error != 0) + return (error); + ahc_intr_enable(ahc, TRUE); return (0);