diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c index 18f003aa9af..89224a061f6 100644 --- a/sys/dev/aic7xxx/aic7xxx.c +++ b/sys/dev/aic7xxx/aic7xxx.c @@ -136,8 +136,10 @@ static void ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force); static struct ahc_syncrate* ahc_devlimited_syncrate(struct ahc_softc *ahc, + struct ahc_initiator_tinfo *, u_int *period, - u_int *ppr_options); + u_int *ppr_options, + role_t role); static void ahc_update_target_msg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct ahc_initiator_tinfo *tinfo, @@ -181,13 +183,12 @@ static void ahc_handle_devreset(struct ahc_softc *ahc, static bus_dmamap_callback_t ahc_dmamap_cb; static int ahc_init_scbdata(struct ahc_softc *ahc); static void ahc_fini_scbdata(struct ahc_softc *ahc); - static void ahc_busy_tcl(struct ahc_softc *ahc, u_int tcl, u_int busyid); -static int ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, - int target, char channel, int lun, - u_int tag, role_t role); - +static void ahc_qinfifo_requeue(struct ahc_softc *ahc, + struct scb *prev_scb, + struct scb *scb); +static int ahc_qinfifo_count(struct ahc_softc *ahc); static u_int ahc_rem_scb_from_disc_list(struct ahc_softc *ahc, u_int prev, u_int scbptr); static void ahc_add_curscb_to_free_list(struct ahc_softc *ahc); @@ -225,10 +226,13 @@ static int ahc_handle_target_cmd(struct ahc_softc *ahc, void restart_sequencer(struct ahc_softc *ahc) { + uint16_t stack[4]; + pause_sequencer(ahc); ahc_outb(ahc, SCSISIGO, 0); /* De-assert BSY */ ahc_outb(ahc, MSG_OUT, MSG_NOOP); /* No message to send */ ahc_outb(ahc, SXFRCTL1, ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET); + /* * Ensure that the sequencer's idea of TQINPOS * matches our own. The sequencer increments TQINPOS @@ -247,7 +251,24 @@ restart_sequencer(struct ahc_softc *ahc) ahc_outb(ahc, CCSCBCTL, 0); } ahc_outb(ahc, MWI_RESIDUAL, 0); - ahc_outb(ahc, SEQCTL, FASTMODE|SEQRESET); + /* + * Avoid stack pointer lockup on aic7895 chips where SEQADDR0 + * cannot be changed without first writing to SEQADDR1. This + * seems to only happen if an interrupt or pause occurs mid + * update of the stack pointer (i.e. during a ret). + */ + stack[0] = ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8); + stack[1] = ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8); + stack[2] = ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8); + stack[3] = ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8); + if (stack[0] == stack[1] + && stack[1] == stack[2] + && stack[2] == stack[3] + && stack[0] != 0) + ahc_outb(ahc, SEQADDR1, 0); + ahc_outb(ahc, SEQCTL, FASTMODE); + ahc_outb(ahc, SEQADDR0, 0); + ahc_outb(ahc, SEQADDR1, 0); unpause_sequencer(ahc); } @@ -335,10 +356,12 @@ ahc_handle_brkadrint(struct ahc_softc *ahc) num_errors = sizeof(hard_error)/sizeof(hard_error[0]); for (i = 0; error != 1 && i < num_errors; i++) error >>= 1; - panic("%s: brkadrint, %s at seqaddr = 0x%x\n", - ahc_name(ahc), hard_error[i].errmesg, - ahc_inb(ahc, SEQADDR0) | - (ahc_inb(ahc, SEQADDR1) << 8)); + printf("%s: brkadrint, %s at seqaddr = 0x%x\n", + ahc_name(ahc), hard_error[i].errmesg, + ahc_inb(ahc, SEQADDR0) | + (ahc_inb(ahc, SEQADDR1) << 8)); + + ahc_dump_card_state(ahc); /* Tell everyone that this HBA is no longer availible */ ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS, @@ -390,6 +413,8 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) "not valid during seqint 0x%x scb(%d)\n", ahc_name(ahc), devinfo.channel, devinfo.target, intstat, scb_index); + ahc_dump_card_state(ahc); + panic("for safety"); goto unpause; } @@ -500,8 +525,8 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; scb->sg_count = 1; scb->flags |= SCB_SENSE; + ahc_qinfifo_requeue_tail(ahc, scb); ahc_outb(ahc, RETURN_1, SEND_SENSE); - #ifdef __FreeBSD__ /* * Ensure we have enough time to actually @@ -529,14 +554,22 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) "target - issuing BUS DEVICE RESET\n", ahc_name(ahc), devinfo.channel, devinfo.target); printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " - "ARG_1 == 0x%x ARG_2 = 0x%x, SEQ_FLAGS == 0x%x\n", + "ARG_1 == 0x%x ACCUM = 0x%x\n", ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN), - ahc_inb(ahc, ARG_1), ahc_inb(ahc, ARG_2), - ahc_inb(ahc, SEQ_FLAGS)); - printf("SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " - "SCB_TAG == 0x%x\n", - ahc_inb(ahc, SCB_SCSIID), ahc_inb(ahc, SCB_LUN), - ahc_inb(ahc, SCB_TAG)); + ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM)); + printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " + "SINDEX == 0x%x\n", + ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR), + ahc_index_busy_tcl(ahc, + BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID), + ahc_inb(ahc, SAVED_LUN)), + /*unbusy*/FALSE), ahc_inb(ahc, SINDEX)); + printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " + "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n", + ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID), + ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG), + ahc_inb(ahc, SCB_CONTROL)); + ahc_dump_card_state(ahc); ahc->msgout_buf[0] = MSG_BUS_DEV_RESET; ahc->msgout_len = 1; ahc->msgout_index = 0; @@ -656,7 +689,6 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) } #if AHC_TARGET_MODE else - /* XXX Ever executed??? */ ahc_setup_target_msgin(ahc, &devinfo); #endif } @@ -740,12 +772,72 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) ahc_freeze_scb(scb); break; } - case TRACEPOINT: + case BOGUS_TAG: { + printf("%s: Somehow queued a tag value of 0xFF\n", + ahc_name(ahc)); + ahc_dump_card_state(ahc); + panic("For safety\n"); break; } - case TRACEPOINT2: + case ABORT_QINSCB: { + printf("%s: Abort QINSCB\n", ahc_name(ahc)); + DELAY(10000000); + break; + } + case NO_FREE_SCB: + { + printf("%s: No free or disconnected SCBs\n", ahc_name(ahc)); + ahc_dump_card_state(ahc); + panic("for safety"); + break; + } + case SCB_MISMATCH: + { + u_int scbptr; + + scbptr = ahc_inb(ahc, SCBPTR); + printf("Bogus TAG after DMA. SCBPTR %d, tag %d, our tag %d\n", + scbptr, ahc_inb(ahc, ARG_1), + ahc->scb_data->hscbs[scbptr].tag); + ahc_dump_card_state(ahc); + panic("for saftey"); + break; + } + case SCBPTR_MISMATCH: + { + u_int scbptr; + + scbptr = ahc_inb(ahc, SCBPTR); + printf("SCBPTR wrong. SCBPTR %d, tag %d, our tag %d\n", + scbptr, ahc_inb(ahc, ARG_1), + ahc->scb_data->hscbs[scbptr].tag); + ahc_dump_card_state(ahc); + panic("for safety"); + break; + } + case OUT_OF_RANGE: + { + printf("%s: BTT calculation out of range\n", ahc_name(ahc)); + printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " + "ARG_1 == 0x%x ACCUM = 0x%x\n", + ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN), + ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM)); + printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " + "SINDEX == 0x%x\n, A == 0x%x\n", + ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR), + ahc_index_busy_tcl(ahc, + BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID), + ahc_inb(ahc, SAVED_LUN)), + /*unbusy*/FALSE), ahc_inb(ahc, SINDEX), + ahc_inb(ahc, ACCUM)); + printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " + "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n", + ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID), + ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG), + ahc_inb(ahc, SCB_CONTROL)); + panic("for safety"); break; } default: @@ -1225,7 +1317,7 @@ ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force) struct tmode_tstate *tstate; /* Don't clean up the entry for our initiator role */ - if ((ahc->flags & AHC_INITIATORMODE) != 0 + if ((ahc->flags & AHC_INITIATORROLE) != 0 && ((channel == 'B' && scsi_id == ahc->our_id_b) || (channel == 'A' && scsi_id == ahc->our_id)) && force == FALSE) @@ -1242,11 +1334,14 @@ ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force) /* * Called when we have an active connection to a target on the bus, * this function finds the nearest syncrate to the input period limited - * by the capabilities of the bus connectivity of the target. + * by the capabilities of the bus connectivity of and sync settings for + * the target. */ struct ahc_syncrate * -ahc_devlimited_syncrate(struct ahc_softc *ahc, u_int *period, - u_int *ppr_options) { +ahc_devlimited_syncrate(struct ahc_softc *ahc, + struct ahc_initiator_tinfo *tinfo, + u_int *period, u_int *ppr_options, role_t role) { + struct ahc_transinfo *transinfo; u_int maxsync; if ((ahc->features & AHC_ULTRA2) != 0) { @@ -1263,6 +1358,27 @@ ahc_devlimited_syncrate(struct ahc_softc *ahc, u_int *period, } else { maxsync = AHC_SYNCRATE_FAST; } + /* + * Never allow a value higher than our current goal + * period otherwise we may allow a target initiated + * negotiation to go above the limit as set by the + * user. In the case of an initiator initiated + * sync negotiation, we limit based on the user + * setting. This allows the system to still accept + * incoming negotiations even if target initiated + * negotiation is not performed. + */ + if (role == ROLE_TARGET) + transinfo = &tinfo->user; + else + transinfo = &tinfo->goal; + *ppr_options &= transinfo->ppr_options; + if (transinfo->period == 0) { + *period = 0; + *ppr_options = 0; + return (NULL); + } + *period = MAX(*period, transinfo->period); return (ahc_find_syncrate(ahc, period, ppr_options, maxsync)); } @@ -1369,8 +1485,10 @@ ahc_find_period(struct ahc_softc *ahc, u_int scsirate, u_int maxsync) * current adapter type and syncrate are capable of. */ void -ahc_validate_offset(struct ahc_softc *ahc, struct ahc_syncrate *syncrate, - u_int *offset, int wide) +ahc_validate_offset(struct ahc_softc *ahc, + struct ahc_initiator_tinfo *tinfo, + struct ahc_syncrate *syncrate, + u_int *offset, int wide, role_t role) { u_int maxoffset; @@ -1386,6 +1504,12 @@ ahc_validate_offset(struct ahc_softc *ahc, struct ahc_syncrate *syncrate, maxoffset = MAX_OFFSET_8BIT; } *offset = MIN(*offset, maxoffset); + if (tinfo != NULL) { + if (role == ROLE_TARGET) + *offset = MIN(*offset, tinfo->user.offset); + else + *offset = MIN(*offset, tinfo->goal.offset); + } } /* @@ -1393,7 +1517,8 @@ ahc_validate_offset(struct ahc_softc *ahc, struct ahc_syncrate *syncrate, * current adapter type is capable of. */ void -ahc_validate_width(struct ahc_softc *ahc, u_int *bus_width) +ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo, + u_int *bus_width, role_t role) { switch (*bus_width) { default: @@ -1404,9 +1529,15 @@ ahc_validate_width(struct ahc_softc *ahc, u_int *bus_width) } /* FALLTHROUGH */ case MSG_EXT_WDTR_BUS_8_BIT: - bus_width = MSG_EXT_WDTR_BUS_8_BIT; + *bus_width = MSG_EXT_WDTR_BUS_8_BIT; break; } + if (tinfo != NULL) { + if (role == ROLE_TARGET) + *bus_width = MIN(tinfo->user.width, *bus_width); + else + *bus_width = MIN(tinfo->goal.width, *bus_width); + } } /* @@ -1427,9 +1558,11 @@ ahc_update_target_msg_request(struct ahc_softc *ahc, 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 || (force && (tinfo->goal.period != 0 - || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT))) + || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT + || tinfo->goal.ppr_options != 0))) ahc->targ_msg_req |= devinfo->target_mask; else ahc->targ_msg_req &= ~devinfo->target_mask; @@ -1891,6 +2024,10 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) } use_ppr = (tinfo->current.transport_version >= 3) || doppr; + /* Target initiated PPR is not allowed in the SCSI spec */ + if (devinfo->role == ROLE_TARGET) + use_ppr = 0; + /* * Both the PPR message and SDTR message require the * goal syncrate to be limited to what the target device @@ -1905,10 +2042,13 @@ ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) ppr_options = tinfo->goal.ppr_options; if (use_ppr == 0) ppr_options = 0; - rate = ahc_devlimited_syncrate(ahc, &period, &ppr_options); + rate = ahc_devlimited_syncrate(ahc, tinfo, &period, + &ppr_options, devinfo->role); offset = tinfo->goal.offset; - ahc_validate_offset(ahc, rate, &offset, - tinfo->current.width); + ahc_validate_offset(ahc, tinfo, rate, &offset, + use_ppr ? tinfo->goal.width + : tinfo->current.width, + devinfo->role); if (use_ppr) { ahc_construct_ppr(ahc, devinfo, period, offset, tinfo->goal.width, ppr_options); @@ -2363,10 +2503,12 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) period = ahc->msgin_buf[3]; ppr_options = 0; saved_offset = offset = ahc->msgin_buf[4]; - syncrate = ahc_devlimited_syncrate(ahc, &period, - &ppr_options); - ahc_validate_offset(ahc, syncrate, &offset, - targ_scsirate & WIDEXFER); + syncrate = ahc_devlimited_syncrate(ahc, tinfo, &period, + &ppr_options, + devinfo->role); + ahc_validate_offset(ahc, tinfo, syncrate, &offset, + targ_scsirate & WIDEXFER, + devinfo->role); if (bootverbose) { printf("(%s:%c:%d:%d): Received " "SDTR period %x, offset %x\n\t" @@ -2437,7 +2579,8 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) bus_width = ahc->msgin_buf[3]; saved_width = bus_width; - ahc_validate_width(ahc, &bus_width); + ahc_validate_width(ahc, tinfo, &bus_width, + devinfo->role); if (bootverbose) { printf("(%s:%c:%d:%d): Received WDTR " "%x filtered to %x\n", @@ -2551,10 +2694,14 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) if (bus_width == 0) ppr_options = 0; - ahc_validate_width(ahc, &bus_width); - syncrate = ahc_devlimited_syncrate(ahc, &period, - &ppr_options); - ahc_validate_offset(ahc, syncrate, &offset, bus_width); + ahc_validate_width(ahc, tinfo, &bus_width, + devinfo->role); + syncrate = ahc_devlimited_syncrate(ahc, tinfo, &period, + &ppr_options, + devinfo->role); + ahc_validate_offset(ahc, tinfo, syncrate, + &offset, bus_width, + devinfo->role); if (ahc_sent_msg(ahc, MSG_EXT_PPR, /*full*/TRUE)) { /* @@ -2573,7 +2720,21 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) syncrate = NULL; } } else { - printf("Target Initated PPR detected!\n"); + if (devinfo->role != ROLE_TARGET) + printf("(%s:%c:%d:%d): Target " + "Initiated PPR\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun); + else + printf("(%s:%c:%d:%d): Initiator " + "Initiated PPR\n", + ahc_name(ahc), devinfo->channel, + devinfo->target, devinfo->lun); + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_construct_ppr(ahc, devinfo, period, offset, + bus_width, ppr_options); + ahc->msgout_index = 0; response = TRUE; } if (bootverbose) { @@ -2595,6 +2756,7 @@ ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) offset, ppr_options, AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, /*paused*/TRUE); + done = MSGLOOP_MSGCOMPLETE; break; } default: @@ -2777,6 +2939,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) untagged_q = &(ahc->untagged_queues[devinfo->target]); TAILQ_INSERT_HEAD(untagged_q, scb, links.tqe); + scb->flags |= SCB_UNTAGGEDQ; } ahc_busy_tcl(ahc, BUILD_TCL(scb->hscb->scsiid, devinfo->lun), scb->hscb->tag); @@ -2909,10 +3072,10 @@ ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) | CLRCHN); } else { - ahc_outb(ahc, SHADDR + 3, data_addr >> 24); - ahc_outb(ahc, SHADDR + 2, data_addr >> 16); - ahc_outb(ahc, SHADDR + 1, data_addr >> 8); - ahc_outb(ahc, SHADDR, data_addr); + ahc_outb(ahc, HADDR + 3, data_addr >> 24); + ahc_outb(ahc, HADDR + 2, data_addr >> 16); + ahc_outb(ahc, HADDR + 1, data_addr >> 8); + ahc_outb(ahc, HADDR, data_addr); } } } @@ -3328,8 +3491,12 @@ ahc_init_scbdata(struct ahc_softc *ahc) /* Determine the number of hardware SCBs and initialize them */ scb_data->maxhscbs = ahc_probe_scbs(ahc); - /* SCB 0 heads the free list */ - ahc_outb(ahc, FREE_SCBH, 0); + if ((ahc->flags & AHC_PAGESCBS) != 0) { + /* SCB 0 heads the free list */ + ahc_outb(ahc, FREE_SCBH, 0); + } else { + ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL); + } for (i = 0; i < ahc->scb_data->maxhscbs; i++) { ahc_outb(ahc, SCBPTR, i); @@ -3337,7 +3504,10 @@ ahc_init_scbdata(struct ahc_softc *ahc) ahc_outb(ahc, SCB_CONTROL, 0); /* Set the next pointer */ - ahc_outb(ahc, SCB_NEXT, i+1); + if ((ahc->flags & AHC_PAGESCBS) != 0) + ahc_outb(ahc, SCB_NEXT, i+1); + else + ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); /* Make the tag number invalid */ ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); @@ -3585,9 +3755,6 @@ ahc_alloc_scbs(struct ahc_softc *ahc) #endif next_scb->hscb = &scb_data->hscbs[scb_data->numscbs]; next_scb->hscb->tag = ahc->scb_data->numscbs; - next_scb->cdb32_busaddr = - ahc_hscb_busaddr(ahc, next_scb->hscb->tag) - + offsetof(struct hardware_scb, cdb32); SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, next_scb, links.sle); segs += AHC_NSEG; @@ -3622,7 +3789,7 @@ ahc_controller_info(struct ahc_softc *ahc, char *buf) } buf += len; - if (ahc->flags & AHC_PAGESCBS) + if ((ahc->flags & AHC_PAGESCBS) != 0) sprintf(buf, "%d/%d SCBs", ahc->scb_data->maxhscbs, AHC_SCB_MAX); else @@ -3646,6 +3813,10 @@ ahc_init(struct ahc_softc *ahc) size_t driver_data_size; uint32_t physaddr; +#ifdef AHC_DEBUG_SEQUENCER + ahc->flags |= AHC_SEQUENCER_DEBUG; +#endif + #ifdef AHC_PRINT_SRAM printf("Scratch Ram:"); for (i = 0x20; i < 0x5f; i++) { @@ -3675,20 +3846,13 @@ ahc_init(struct ahc_softc *ahc) /* * Default to allowing initiator operations. */ - ahc->flags |= AHC_INITIATORMODE; + ahc->flags |= AHC_INITIATORROLE; - if ((ahc->flags & AHC_TARGETMODE) != 0) { - /* - * Although we have space for both the initiator and - * target roles on ULTRA2 chips, we currently disable - * the initiator role to allow multi-scsi-id target mode - * configurations. We can only respond on the same SCSI - * ID as our initiator role if we allow initiator operation. - * At some point, we should add a configuration knob to - * allow both roles to be loaded. - */ - ahc->flags &= ~AHC_INITIATORMODE; - } + /* + * Only allow target mode features if this unit has them enabled. + */ + if ((AHC_TMODE_ENABLE & (0x1 << ahc->unit)) == 0) + ahc->features &= ~AHC_TARGETMODE; #ifndef __linux__ /* DMA tag for mapping buffers into device visible space. */ @@ -3716,7 +3880,7 @@ ahc_init(struct ahc_softc *ahc) * byte to deal with a dma bug in some chip versions. */ driver_data_size = 2 * 256 * sizeof(uint8_t); - if ((ahc->flags & AHC_TARGETMODE) != 0) + if ((ahc->features & AHC_TARGETMODE) != 0) driver_data_size += AHC_TMODE_CMDS * sizeof(struct target_cmd) + /*DMA WideOdd Bug Buffer*/1; if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, @@ -3746,7 +3910,7 @@ ahc_init(struct ahc_softc *ahc) ahc->qoutfifo, driver_data_size, ahc_dmamap_cb, &ahc->shared_data_busaddr, /*flags*/0); - if ((ahc->flags & AHC_TARGETMODE) != 0) { + if ((ahc->features & AHC_TARGETMODE) != 0) { ahc->targetcmds = (struct target_cmd *)ahc->qoutfifo; ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256]; ahc->dma_bug_buf = ahc->shared_data_busaddr @@ -3823,7 +3987,7 @@ ahc_init(struct ahc_softc *ahc) ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); if ((scsi_conf & RESET_SCSI) != 0 - && (ahc->flags & AHC_INITIATORMODE) != 0) + && (ahc->flags & AHC_INITIATORROLE) != 0) ahc->flags |= AHC_RESET_BUS_B; /* Select Channel A */ @@ -3842,7 +4006,7 @@ ahc_init(struct ahc_softc *ahc) ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); if ((scsi_conf & RESET_SCSI) != 0 - && (ahc->flags & AHC_INITIATORMODE) != 0) + && (ahc->flags & AHC_INITIATORROLE) != 0) ahc->flags |= AHC_RESET_BUS_A; /* @@ -3938,6 +4102,12 @@ ahc_init(struct ahc_softc *ahc) tinfo->user.ppr_options = MSG_EXT_PPR_DT_REQ; } else if ((scsirate & SOFS) != 0) { + if ((scsirate & SXFR) == 0x40 + && (ultraenb & mask) != 0) { + /* Treat 10MHz as a non-ultra speed */ + scsirate &= ~SXFR; + ultraenb &= ~mask; + } tinfo->user.period = ahc_find_period(ahc, scsirate, (ultraenb & mask) @@ -4061,7 +4231,7 @@ ahc_init(struct ahc_softc *ahc) * we've had a lun enabled. */ scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP; - if ((ahc->flags & AHC_INITIATORMODE) != 0) + if ((ahc->flags & AHC_INITIATORROLE) != 0) scsiseq_template |= ENRSELI; ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template); @@ -4201,6 +4371,26 @@ ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb) } void +ahc_qinfifo_requeue_tail(struct ahc_softc *ahc, struct scb *scb) +{ + struct scb *prev_scb; + + prev_scb = NULL; + if (ahc_qinfifo_count(ahc) != 0) { + u_int prev_tag; + + prev_tag = ahc->qinfifo[ahc->qinfifonext - 1]; + prev_scb = ahc_lookup_scb(ahc, prev_tag); + } + ahc_qinfifo_requeue(ahc, prev_scb, scb); + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); + } else { + ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); + } +} + +static void ahc_qinfifo_requeue(struct ahc_softc *ahc, struct scb *prev_scb, struct scb *scb) { @@ -4212,7 +4402,7 @@ ahc_qinfifo_requeue(struct ahc_softc *ahc, struct scb *prev_scb, scb->hscb->next = ahc->next_queued_scb->hscb->tag; } -int +static int ahc_qinfifo_count(struct ahc_softc *ahc) { u_int8_t qinpos; @@ -4360,9 +4550,11 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, ahc_outb(ahc, SCBPTR, next); scb_index = ahc_inb(ahc, SCB_TAG); if (scb_index >= ahc->scb_data->numscbs) { - panic("Waiting List inconsistency. " - "SCB index == %d, yet numscbs == %d.", - scb_index, ahc->scb_data->numscbs); + printf("Waiting List inconsistency. " + "SCB index == %d, yet numscbs == %d.", + scb_index, ahc->scb_data->numscbs); + ahc_dump_card_state(ahc); + panic("for safety"); } scb = ahc_lookup_scb(ahc, scb_index); if (ahc_match_scb(ahc, scb, target, channel, @@ -4376,7 +4568,6 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, { cam_status ostat; - next = ahc_rem_wscb(ahc, next, prev); ostat = ahc_get_transaction_status(scb); if (ostat == CAM_REQ_INPROG) ahc_set_transaction_status(scb, @@ -4385,15 +4576,15 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, if ((scb->flags & SCB_ACTIVE) == 0) printf("Inactive SCB in Waiting List\n"); ahc_done(ahc, scb); - break; + /* FALLTHROUGH */ } + case SEARCH_REMOVE: + next = ahc_rem_wscb(ahc, next, prev); + break; case SEARCH_COUNT: prev = next; next = ahc_inb(ahc, SCB_NEXT); break; - case SEARCH_REMOVE: - next = ahc_rem_wscb(ahc, next, prev); - break; } } else { @@ -4509,9 +4700,11 @@ ahc_search_disc_list(struct ahc_softc *ahc, int target, char channel, ahc_outb(ahc, SCBPTR, next); scb_index = ahc_inb(ahc, SCB_TAG); if (scb_index >= ahc->scb_data->numscbs) { - panic("Disconnected List inconsistency. " - "SCB index == %d, yet numscbs == %d.", - scb_index, ahc->scb_data->numscbs); + printf("Disconnected List inconsistency. " + "SCB index == %d, yet numscbs == %d.", + scb_index, ahc->scb_data->numscbs); + ahc_dump_card_state(ahc); + panic("for safety"); } if (next == prev) { @@ -4581,8 +4774,10 @@ ahc_add_curscb_to_free_list(struct ahc_softc *ahc) */ ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); - ahc_outb(ahc, SCB_NEXT, ahc_inb(ahc, FREE_SCBH)); - ahc_outb(ahc, FREE_SCBH, ahc_inb(ahc, SCBPTR)); + if ((ahc->flags & AHC_PAGESCBS) != 0) { + ahc_outb(ahc, SCB_NEXT, ahc_inb(ahc, FREE_SCBH)); + ahc_outb(ahc, FREE_SCBH, ahc_inb(ahc, SCBPTR)); + } } /* @@ -4715,7 +4910,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, * Go through the hardware SCB array looking for commands that * were active but not on any list. */ - for(i = 0; i < ahc->scb_data->maxhscbs; i++) { + for (i = 0; i < ahc->scb_data->maxhscbs; i++) { u_int scbid; ahc_outb(ahc, SCBPTR, i); @@ -4802,7 +4997,7 @@ ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) */ ahc_run_qoutfifo(ahc); #if AHC_TARGET_MODE - if ((ahc->flags & AHC_TARGETMODE) != 0) { + if ((ahc->flags & AHC_TARGETROLE) != 0) { ahc_run_tqinfifo(ahc, /*paused*/TRUE); } #endif @@ -5318,6 +5513,21 @@ ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts) fmt1_ins->immediate = dconsts[fmt1_ins->immediate]; } fmt1_ins->parity = 0; + if ((ahc->features & AHC_CMD_CHAN) == 0 + && opcode == AIC_OP_BMOV) { + /* + * Block move was added at the same time + * as the command channel. Verify that + * this is only a move of a single element + * and convert the BMOV to a MOV + * (AND with an immediate of FF). + */ + if (fmt1_ins->immediate != 1) + panic("%s: BMOV not supported\n", + ahc_name(ahc)); + fmt1_ins->opcode = AIC_OP_AND; + fmt1_ins->immediate = 0xff; + } /* FALLTHROUGH */ case AIC_OP_ROL: if ((ahc->features & AHC_ULTRA2) != 0) { @@ -5385,7 +5595,11 @@ ahc_dump_card_state(struct ahc_softc *ahc) printf("SCB count = %d\n", ahc->scb_data->numscbs); /* QINFIFO */ printf("QINFIFO entries: "); - qinpos = ahc_inb(ahc, QINPOS); + if ((ahc->features & AHC_QUEUE_REGS) != 0) { + qinpos = ahc_inb(ahc, SNSCB_QOFF); + ahc_outb(ahc, SNSCB_QOFF, qinpos); + } else + qinpos = ahc_inb(ahc, QINPOS); qintail = ahc->qinfifonext; while (qinpos != qintail) { printf("%d ", ahc->qinfifo[qinpos]); @@ -5452,7 +5666,7 @@ ahc_dump_card_state(struct ahc_softc *ahc) maxtarget = (ahc->features & (AHC_WIDE|AHC_TWIN)) ? 15 : 7; for (target = 0; target <= maxtarget; target++) { - untagged_q = &ahc->untagged_queues[0]; + untagged_q = &ahc->untagged_queues[target]; if (TAILQ_FIRST(untagged_q) == NULL) continue; printf("Untagged Q(%d): ", target); @@ -5476,17 +5690,10 @@ ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, struct tmode_tstate **tstate, struct tmode_lstate **lstate, int notfound_failure) { - u_int our_id; - /* - * If we are not configured for target mode, someone - * is really confused to be sending this to us. - */ - if ((ahc->flags & AHC_TARGETMODE) == 0) + if ((ahc->features & AHC_TARGETMODE) == 0) return (CAM_REQ_INVALID); - /* Range check target and lun */ - /* * Handle the 'black hole' device that sucks up * requests to unattached luns on enabled targets. @@ -5498,11 +5705,6 @@ ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, } else { u_int max_id; - if (cam_sim_bus(sim) == 0) - our_id = ahc->our_id; - else - our_id = ahc->our_id_b; - max_id = (ahc->features & AHC_WIDE) ? 15 : 7; if (ccb->ccb_h.target_id > max_id) return (CAM_TID_INVALID); @@ -5510,31 +5712,6 @@ ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, if (ccb->ccb_h.target_lun > 7) return (CAM_LUN_INVALID); - if (ccb->ccb_h.target_id != our_id) { - if ((ahc->features & AHC_MULTI_TID) != 0) { - /* - * Only allow additional targets if - * the initiator role is disabled. - * The hardware cannot handle a re-select-in - * on the initiator id during a re-select-out - * on a different target id. - */ - if ((ahc->flags & AHC_INITIATORMODE) != 0) - return (CAM_TID_INVALID); - } else { - /* - * Only allow our target id to change - * if the initiator role is not configured - * and there are no enabled luns which - * are attached to the currently registered - * scsi id. - */ - if ((ahc->flags & AHC_INITIATORMODE) != 0 - || ahc->enabled_luns > 0) - return (CAM_TID_INVALID); - } - } - *tstate = ahc->enabled_targets[ccb->ccb_h.target_id]; *lstate = NULL; if (*tstate != NULL) @@ -5562,13 +5739,73 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) char channel; status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, &lstate, - /* notfound_failure*/FALSE); + /*notfound_failure*/FALSE); if (status != CAM_REQ_CMP) { ccb->ccb_h.status = status; return; } - + + if ((ahc->features & AHC_MULTIROLE) != 0) { + u_int our_id; + + if (cam_sim_bus(sim) == 0) + our_id = ahc->our_id; + else + our_id = ahc->our_id_b; + + if (ccb->ccb_h.target_id != our_id) { + if ((ahc->features & AHC_MULTI_TID) != 0 + && (ahc->flags & AHC_INITIATORROLE) != 0) { + /* + * Only allow additional targets if + * the initiator role is disabled. + * The hardware cannot handle a re-select-in + * on the initiator id during a re-select-out + * on a different target id. + */ + status = CAM_TID_INVALID; + } else if ((ahc->flags & AHC_INITIATORROLE) != 0 + || ahc->enabled_luns > 0) { + /* + * Only allow our target id to change + * if the initiator role is not configured + * and there are no enabled luns which + * are attached to the currently registered + * scsi id. + */ + status = CAM_TID_INVALID; + } + } + } + + if (status != CAM_REQ_CMP) { + ccb->ccb_h.status = status; + return; + } + + /* + * We now have an id that is valid. + * If we aren't in target mode, switch modes. + */ + if ((ahc->flags & AHC_TARGETROLE) == 0 + && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { + u_long s; + + printf("Configuring Target Mode\n"); + ahc_lock(ahc, &s); + if (LIST_FIRST(&ahc->pending_scbs) != NULL) { + ccb->ccb_h.status = CAM_BUSY; + ahc_unlock(ahc, &s); + return; + } + ahc->flags |= AHC_TARGETROLE; + if ((ahc->features & AHC_MULTIROLE) == 0) + ahc->flags &= ~AHC_INITIATORROLE; + pause_sequencer(ahc); + ahc_loadseq(ahc); + ahc_unlock(ahc, &s); + } cel = &ccb->cel; target = ccb->ccb_h.target_id; lun = ccb->ccb_h.target_lun; @@ -5796,6 +6033,14 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) scsiseq = ahc_inb(ahc, SCSISEQ); scsiseq &= ~ENSELI; ahc_outb(ahc, SCSISEQ, scsiseq); + + if ((ahc->features & AHC_MULTIROLE) == 0) { + printf("Configuring Initiator Mode\n"); + ahc->flags &= ~AHC_TARGETROLE; + ahc->flags |= AHC_INITIATORROLE; + pause_sequencer(ahc); + ahc_loadseq(ahc); + } } unpause_sequencer(ahc); ahc_unlock(ahc, &s); diff --git a/sys/dev/aic7xxx/aic7xxx.h b/sys/dev/aic7xxx/aic7xxx.h index d5cc59da6f0..a3813737879 100644 --- a/sys/dev/aic7xxx/aic7xxx.h +++ b/sys/dev/aic7xxx/aic7xxx.h @@ -184,15 +184,27 @@ typedef enum { AHC_LARGE_SCBS = 0x04000, /* 64byte SCBs */ AHC_AUTORATE = 0x08000, /* Automatic update of SCSIRATE/OFFSET*/ AHC_AUTOPAUSE = 0x10000, /* Automatic pause on register access */ + AHC_TARGETMODE = 0x20000, /* Has tested target mode support */ + AHC_MULTIROLE = 0x40000, /* Space for two roles at a time */ AHC_AIC7770_FE = AHC_FENONE, - AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE, + AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE, AHC_AIC7855_FE = AHC_AIC7850_FE, AHC_AIC7860_FE = AHC_AIC7850_FE|AHC_ULTRA, - AHC_AIC7870_FE = AHC_FENONE, - AHC_AIC7880_FE = AHC_ULTRA, - AHC_AIC7890_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2|AHC_QUEUE_REGS - |AHC_SG_PRELOAD|AHC_MULTI_TID|AHC_HS_MAILBOX - |AHC_NEW_TERMCTL|AHC_LARGE_SCBS, + AHC_AIC7870_FE = AHC_TARGETMODE, + AHC_AIC7880_FE = AHC_AIC7870_FE|AHC_ULTRA, + /* + * Although we have space for both the initiator and + * target roles on ULTRA2 chips, we currently disable + * the initiator role to allow multi-scsi-id target mode + * configurations. We can only respond on the same SCSI + * ID as our initiator role if we allow initiator operation. + * At some point, we should add a configuration knob to + * allow both roles to be loaded. + */ + AHC_AIC7890_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2 + |AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_MULTI_TID + |AHC_HS_MAILBOX |AHC_NEW_TERMCTL|AHC_LARGE_SCBS + |AHC_TARGETMODE, AHC_AIC7892_FE = AHC_AIC7890_FE|AHC_DT|AHC_AUTORATE|AHC_AUTOPAUSE, AHC_AIC7895_FE = AHC_AIC7880_FE|AHC_MORE_SRAM|AHC_AUTOPAUSE |AHC_CMD_CHAN|AHC_MULTI_FUNC|AHC_LARGE_SCBS, @@ -265,6 +277,7 @@ typedef enum { * SRAM, we use the default target * settings. */ + AHC_SEQUENCER_DEBUG = 0x008, AHC_SHARED_SRAM = 0x010, AHC_LARGE_SEEPROM = 0x020,/* Uses C56_66 not C46 */ AHC_RESET_BUS_A = 0x040, @@ -273,11 +286,11 @@ typedef enum { AHC_EXTENDED_TRANS_B = 0x200, AHC_TERM_ENB_A = 0x400, AHC_TERM_ENB_B = 0x800, - AHC_INITIATORMODE = 0x1000,/* + AHC_INITIATORROLE = 0x1000,/* * Allow initiator operations on * this controller. */ - AHC_TARGETMODE = 0x2000,/* + AHC_TARGETROLE = 0x2000,/* * Allow target operations on this * controller. */ @@ -472,6 +485,7 @@ typedef enum { */ SCB_DEVICE_RESET = 0x0004, SCB_SENSE = 0x0008, + SCB_CDB32_PTR = 0x0010, SCB_RECOVERY_SCB = 0x0040, SCB_NEGOTIATE = 0x0080, SCB_ABORT = 0x1000, @@ -496,7 +510,6 @@ struct scb { struct scb_platform_data *platform_data; struct ahc_dma_seg *sg_list; bus_addr_t sg_list_phys; - bus_addr_t cdb32_busaddr; u_int sg_count;/* How full ahc_dma_seg is */ }; @@ -1012,10 +1025,11 @@ int ahc_probe_scbs(struct ahc_softc *); void ahc_run_untagged_queues(struct ahc_softc *ahc); void ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue); -void ahc_qinfifo_requeue(struct ahc_softc *ahc, - struct scb *prev_scb, - struct scb *scb); -int ahc_qinfifo_count(struct ahc_softc *ahc); +void ahc_qinfifo_requeue_tail(struct ahc_softc *ahc, + struct scb *scb); +int ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, + int target, char channel, int lun, + u_int tag, role_t role); /****************************** Initialization ********************************/ void ahc_init_probe_config(struct ahc_probe_config *); @@ -1074,10 +1088,14 @@ struct ahc_syncrate* ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, u_int ahc_find_period(struct ahc_softc *ahc, u_int scsirate, u_int maxsync); void ahc_validate_offset(struct ahc_softc *ahc, + struct ahc_initiator_tinfo *tinfo, struct ahc_syncrate *syncrate, - u_int *offset, int wide); + u_int *offset, int wide, + role_t role); void ahc_validate_width(struct ahc_softc *ahc, - u_int *bus_width); + struct ahc_initiator_tinfo *tinfo, + u_int *bus_width, + role_t role); void ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, u_int width, u_int type, int paused); @@ -1103,6 +1121,9 @@ cam_status ahc_find_tmode_devs(struct ahc_softc *ahc, int notfound_failure); void ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo); +#ifndef AHC_TMODE_ENABLE +#define AHC_TMODE_ENABLE 0 +#endif #endif /******************************* Debug ***************************************/ void ahc_print_scb(struct scb *scb); diff --git a/sys/dev/aic7xxx/aic7xxx.reg b/sys/dev/aic7xxx/aic7xxx.reg index d83ad223927..ed272844f74 100644 --- a/sys/dev/aic7xxx/aic7xxx.reg +++ b/sys/dev/aic7xxx/aic7xxx.reg @@ -382,12 +382,12 @@ register SIMODE1 { */ register SCSIBUSL { address 0x012 - access_mode RO + access_mode RW } register SCSIBUSH { address 0x013 - access_mode RO + access_mode RW } /* @@ -702,6 +702,7 @@ register BUSSPD { mask STBOFF 0x38 mask STBON 0x07 mask DFTHRSH_100 0xc0 + mask DFTHRSH_75 0x80 } /* aic7850/55/60/70/80/95 only */ @@ -779,10 +780,8 @@ register INTSTAT { mask NO_IDENT 0x20|SEQINT /* no IDENTIFY after reconnect*/ mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */ mask IGN_WIDE_RES 0x40|SEQINT /* Complex IGN Wide Res Msg */ - mask BAD_STATUS 0x70|SEQINT /* Bad status from target */ - mask RESIDUAL 0x80|SEQINT /* Residual byte count != 0 */ - mask TRACEPOINT2 0x90|SEQINT - mask HOST_MSG_LOOP 0xa0|SEQINT /* + mask RESIDUAL 0x50|SEQINT /* Residual byte count != 0 */ + mask HOST_MSG_LOOP 0x60|SEQINT /* * The bus is ready for the * host to perform another * message transaction. This @@ -791,17 +790,41 @@ register INTSTAT { * that require a kernel based * message state engine. */ - mask PERR_DETECTED 0xb0|SEQINT /* + mask BAD_STATUS 0x70|SEQINT /* Bad status from target */ + mask PERR_DETECTED 0x80|SEQINT /* * Either the phase_lock * or inb_next routine has * noticed a parity error. */ - mask TRACEPOINT 0xd0|SEQINT - mask DATA_OVERRUN 0xf0|SEQINT /* + mask DATA_OVERRUN 0x90|SEQINT /* * Target attempted to write * beyond the bounds of its * command. */ + mask BOGUS_TAG 0xa0|SEQINT /* + * Sequencer given an SCB with + * a Tag value of 0xFF. + */ + mask SCBPTR_MISMATCH 0xb0|SEQINT /* + * In the SCB paging case, our + * SCBPTR is not the same as + * we originally set prior to + * download of a new scb. + */ + mask SCB_MISMATCH 0xc0|SEQINT /* + * Downloaded SCB's tag does + * not match the entry we + * intended to download. + */ + mask ABORT_QINSCB 0xd0|SEQINT /* + * An SCB was aborted + * during download. + * Informational. + */ + mask NO_FREE_SCB 0xe0|SEQINT /* + * get_free_or_disc_scb failed. + */ + mask OUT_OF_RANGE 0xf0|SEQINT mask SEQINT_MASK 0xf0|SEQINT /* SEQINT Status Codes */ mask INT_PEND (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT) @@ -1214,7 +1237,29 @@ scratch_ram { size 8 } BUSY_TARGETS { - size 16 + size 8 + } + /* + * Bit vector of targets that have ULTRA enabled as set by + * the BIOS. The Sequencer relies on a per-SCB field to + * control whether to enable Ultra transfers or not. During + * initialization, we read this field and reuse it for 2 + * entries in the busy target table. + */ + ULTRA_ENB { + size 2 + } + /* + * Bit vector of targets that have disconnection disabled as set by + * the BIOS. The Sequencer relies in a per-SCB field to control the + * disconnect priveldge. During initialization, we read this field + * and reuse it for 2 entries in the busy target table. + */ + DISC_DSB { + size 2 + } + BUSY_TARGETS_TAIL { + size 4 } /* * Partial transfer past cacheline end to be @@ -1222,11 +1267,6 @@ scratch_ram { */ MWI_RESIDUAL { size 1 - /* - * Bit vector of targets that have ULTRA enabled as set by * the BIOS. The Sequencer relies on a per-SCB field to - * control whether to enable Ultra transfers or not. - */ - alias ULTRA_ENB } /* * SCBID of the next SCB to be started by the controller. @@ -1234,14 +1274,6 @@ scratch_ram { NEXT_QUEUED_SCB { size 1 } - /* - * Bit vector of targets that have disconnection disabled as set by - * the BIOS. The Sequencer relies in a per-SCB field to control the - * disconnect priveldge. - */ - DISC_DSB { - size 2 - } /* * Single byte buffer used to designate the type or message * to send to a target. @@ -1266,7 +1298,6 @@ scratch_ram { SEQ_FLAGS { size 1 bit IDENTIFY_SEEN 0x80 - bit SCBPTR_VALID 0x40 bit TARGET_CMD_IS_TAGGED 0x40 bit DPHASE 0x20 /* Target flags */ diff --git a/sys/dev/aic7xxx/aic7xxx.seq b/sys/dev/aic7xxx/aic7xxx.seq index 33af1a52123..f300676fe99 100644 --- a/sys/dev/aic7xxx/aic7xxx.seq +++ b/sys/dev/aic7xxx/aic7xxx.seq @@ -57,9 +57,7 @@ poll_for_work: call clear_target_state; and SXFRCTL0, ~SPIOEN; - if ((ahc->features & AHC_QUEUE_REGS) == 0) { - mov A, QINPOS; - } + clr SCSIBUSL; poll_for_work_loop: test SSTAT0, SELDO|SELDI jnz selection; test SCSISEQ, ENSELO jnz poll_for_work_loop; @@ -82,6 +80,7 @@ BEGIN_CRITICAL test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; mov NONE, SNSCB_QOFF; } else { + mov A, QINPOS; cmp KERNEL_QINPOS, A je poll_for_work_loop; inc QINPOS; } @@ -114,6 +113,14 @@ dma_queued_scb: mov A, ARG_1; BEGIN_CRITICAL cmp NEXT_QUEUED_SCB, A jne abort_qinscb; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + if ((ahc->flags & AHC_PAGESCBS) == 0) { + cmp SCBPTR, A je . + 2; + mvi INTSTAT, SCBPTR_MISMATCH; + } + cmp SCB_TAG, A je . + 2; + mvi INTSTAT, SCB_MISMATCH; + } mov NEXT_QUEUED_SCB, SCB_NEXT; mov SCB_NEXT,WAITING_SCBH; mov WAITING_SCBH, SCBPTR; @@ -127,7 +134,7 @@ start_waiting: jmp poll_for_work_loop; abort_qinscb: - mvi INTSTAT, TRACEPOINT; + mvi INTSTAT, ABORT_QINSCB; call add_scb_to_free_list; jmp poll_for_work_loop; @@ -146,7 +153,7 @@ initialize_scsiid: } else { mov SCSIID, SCB_SCSIID; } - if ((ahc->flags & AHC_TARGETMODE) != 0) { + if ((ahc->flags & AHC_TARGETROLE) != 0) { mov SINDEX, SCSISEQ_TEMPLATE; test SCB_CONTROL, TARGET_SCB jz . + 2; or SINDEX, TEMODE; @@ -162,7 +169,7 @@ initialize_scsiid: * a valid SCB for the target we wish to talk to. */ initialize_channel: - or SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX; + or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; set_transfer_settings: if ((ahc->features & AHC_ULTRA) != 0) { test SCB_CONTROL, ULTRAENB jz . + 2; @@ -188,8 +195,8 @@ selection: test SSTAT0,SELDO jnz select_out; mvi CLRSINT0, CLRSELDI; select_in: - if ((ahc->flags & AHC_TARGETMODE) != 0) { - if ((ahc->flags & AHC_INITIATORMODE) != 0) { + if ((ahc->flags & AHC_TARGETROLE) != 0) { + if ((ahc->flags & AHC_INITIATORROLE) != 0) { test SSTAT0, TARGET jz initiator_reselect; } @@ -332,7 +339,7 @@ ident_messages_done: } cmp TQINPOS, A jne tqinfifo_has_space; mvi P_STATUS|BSYO call change_phase; - test SEQ_FLAGS, TARGET_CMD_IS_TAGGED jnz . + 3; + test SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 3; mvi STATUS_QUEUE_FULL call target_outb; jmp target_busfree_wait; mvi STATUS_BUSY call target_outb; @@ -366,7 +373,7 @@ target_inb: mov DINDEX, SCSIDATL ret; } -if ((ahc->flags & AHC_INITIATORMODE) != 0) { +if ((ahc->flags & AHC_INITIATORROLE) != 0) { /* * Reselection has been initiated by a target. Make a note that we've been * reselected, but haven't seen an IDENTIFY message from the target yet. @@ -399,11 +406,15 @@ select_out: and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; mvi CLRSINT0, CLRSELDO; mov SCBPTR, WAITING_SCBH; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + cmp SCB_TAG, SCB_LIST_NULL jne . + 2; + mvi INTSTAT, BOGUS_TAG; + } mov WAITING_SCBH,SCB_NEXT; mov SAVED_SCSIID, SCB_SCSIID; mov SAVED_LUN, SCB_LUN; - mvi SPIOEN call initialize_channel; - if ((ahc->flags & AHC_TARGETMODE) != 0) { + call initialize_channel; + if ((ahc->flags & AHC_TARGETROLE) != 0) { test SSTAT0, TARGET jz initiator_select; /* @@ -476,6 +487,7 @@ target_busfree_wait: test SCSISIGI, ACKI jnz .; target_busfree: and SIMODE1, ~ENBUSFREE; + clr SCSIBUSL; clr SCSISIGO; mvi LASTPHASE, P_BUSFREE; call complete_target_cmd; @@ -501,7 +513,7 @@ target_cmdphase: * the first byte. */ shr A, CMD_GROUP_CODE_SHIFT; - add SINDEX, TARG_SCSIRATE, A; + add SINDEX, CMDSIZE_TABLE, A; mov A, SINDIR; test A, 0xFF jz command_phase_done; @@ -569,7 +581,7 @@ complete_target_cmd: mvi INTSTAT,CMDCMPLT ret; } -if ((ahc->flags & AHC_INITIATORMODE) != 0) { +if ((ahc->flags & AHC_INITIATORROLE) != 0) { initiator_select: /* * As soon as we get a successful selection, the target @@ -602,6 +614,7 @@ ITloop: await_busfree: and SIMODE1, ~ENBUSFREE; mov NONE, SCSIDATL; /* Ack the last byte */ + clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ and SXFRCTL0, ~SPIOEN; test SSTAT1,REQINIT|BUSFREE jz .; test SSTAT1, BUSFREE jnz poll_for_work; @@ -615,7 +628,7 @@ clear_target_state: * clear DFCNTRL too. */ clr DFCNTRL; - mvi SXFRCTL0, CLRSTCNT|CLRCHN; + or SXFRCTL0, CLRSTCNT|CLRCHN; /* * We don't know the target we will connect to, @@ -817,23 +830,17 @@ data_phase_loop: test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds; /* - * Turn on 'Bit Bucket' mode, set the transfer count to - * 16meg and let the target run until it changes phase. - * When the transfer completes, notify the host that we - * had an overrun. + * Turn on `Bit Bucket' mode, wait until the target takes + * us to another phase, and then notify the host. */ + and DMAPARAMS, DIRECTION; + mov DFCNTRL, DMAPARAMS; or SXFRCTL1,BITBUCKET; - and DMAPARAMS, ~(HDMAEN|SDMAEN); - if ((ahc->features & AHC_ULTRA2) != 0) { - bmov HCNT, ALLONES, 3; - or SXFRCTL0, CLRCHN|CLRSTCNT;/* Ensure FIFO empty */ - } else if ((ahc->features & AHC_CMD_CHAN) != 0) { - bmov STCNT, ALLONES, 3; - } else { - mvi STCNT[0], 0xFF; - mvi STCNT[1], 0xFF; - mvi STCNT[2], 0xFF; - } + test SSTAT1,PHASEMIS jz .; + and SXFRCTL1, ~BITBUCKET; + mvi INTSTAT,DATA_OVERRUN; + jmp ITloop; + data_phase_inbounds: if ((ahc->features & AHC_ULTRA2) != 0) { mov SINDEX, SCB_RESIDUAL_SGPTR[0]; @@ -889,8 +896,6 @@ ultra2_dmahalt: and DFCNTRL, ~(SCSIEN|HDMAEN); test DFCNTRL, HDMAEN jnz .; - test SXFRCTL1,BITBUCKET jnz data_phase_finish; - /* * If, by chance, we stopped before being able * to fetch additional segments for this transfer, @@ -946,7 +951,7 @@ sgptr_fixup_done: test MWI_RESIDUAL, 0xFF jnz dma_mid_sg; } test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; - if ((ahc->flags & AHC_TARGETMODE) != 0) { + if ((ahc->flags & AHC_TARGETROLE) != 0) { test SSTAT0, TARGET jz dma_last_sg; if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) { test DMAPARAMS, DIRECTION jz dma_mid_sg; @@ -1080,7 +1085,7 @@ sg_load_done: test HCNT[0], 0x1 jz . + 2; xor DATA_COUNT_ODD, 0x1; - if ((ahc->flags & AHC_TARGETMODE) != 0) { + if ((ahc->flags & AHC_TARGETROLE) != 0) { test SSTAT0, TARGET jnz data_phase_loop; } } @@ -1092,10 +1097,10 @@ data_phase_finish: * all other adapters, we'll loop after each S/G element * is loaded as well as if there is an overrun. */ - if ((ahc->flags & AHC_TARGETMODE) != 0) { + if ((ahc->flags & AHC_TARGETROLE) != 0) { test SSTAT0, TARGET jnz data_phase_done; } - if ((ahc->flags & AHC_INITIATORMODE) != 0) { + if ((ahc->flags & AHC_INITIATORROLE) != 0) { test SSTAT1, REQINIT jz .; test SSTAT1,PHASEMIS jz data_phase_loop; @@ -1104,15 +1109,6 @@ data_phase_finish: clr CCSGCTL; test CCSGCTL, CCSGEN jnz .; } - - /* - * Turn off BITBUCKET mode and notify the host - * in the event of an overrun. - */ - test SXFRCTL1,BITBUCKET jz data_phase_done; - and SXFRCTL1, ~BITBUCKET; - mvi INTSTAT,DATA_OVERRUN; - jmp ITloop; } data_phase_done: @@ -1163,7 +1159,7 @@ bmov_resid: or SXFRCTL0, CLRSTCNT|CLRCHN; } - if ((ahc->flags & AHC_TARGETMODE) != 0) { + if ((ahc->flags & AHC_TARGETROLE) != 0) { test SEQ_FLAGS, DPHASE_PENDING jz ITloop; and SEQ_FLAGS, ~DPHASE_PENDING; /* @@ -1177,7 +1173,7 @@ bmov_resid: jmp ITloop; } -if ((ahc->flags & AHC_INITIATORMODE) != 0) { +if ((ahc->flags & AHC_INITIATORROLE) != 0) { /* * Command phase. Set up the DMA registers and let 'er rip. */ @@ -1208,8 +1204,8 @@ p_command_from_host: bmov HCNT, STCNT, 3; } else { mvi DINDEX, HADDR; - mvi SCB_CDB_PTR call bcopy_5; - call clear_hcnt; + mvi SCB_CDB_PTR call bcopy_4; + mov SCB_CDB_LEN call set_hcnt; } mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET); } @@ -1261,6 +1257,10 @@ p_command_loop: test SCSISIGI, ACKI jnz .; and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; + if ((ahc->features & AHC_ULTRA2) != 0) { + /* Drop any residual from the S/G Preload queue */ + or SXFRCTL0, CLRSTCNT; + } jmp ITloop; /* @@ -1413,14 +1413,9 @@ mesgin_complete: * process this information. In the case of a non zero status byte, we * additionally interrupt the kernel driver synchronously, allowing it to * decide if sense should be retrieved. If the kernel driver wishes to request - * sense, it will fill the kernel SCB with a request sense command and set - * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload - * the SCB, and process it as the next command by adding it to the waiting list. - * If the kernel driver does not wish to request sense, it need only clear - * RETURN_1, and the command is allowed to complete normally. We don't bother - * to post to the QOUTFIFO in the error cases since it would require extra - * work in the kernel driver to ensure that the entry was removed before the - * command complete code tried processing it. + * sense, it will fill the kernel SCB with a request sense command, requeue + * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting + * RETURN_1 to SEND_SENSE. */ /* @@ -1437,23 +1432,10 @@ upload_scb: mov SCB_TAG call dma_scb; test SCB_SCSI_STATUS, 0xff jz complete; /* Just a residual? */ mvi INTSTAT, BAD_STATUS; /* let driver know */ - /* - * Prepare to DMA this SCB in case we are told to retrieve sense. - * Fills a delay slot after the INTSTAT as well. - */ - mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; + nop; cmp RETURN_1, SEND_SENSE jne complete; - mov SCB_TAG call dma_scb; -add_to_waiting_list: - mov SCB_NEXT,WAITING_SCBH; - mov WAITING_SCBH, SCBPTR; - /* - * Prepare our selection hardware before the busfree so we have a - * high probability of winning arbitration. - */ - call start_selection; + call add_scb_to_free_list; jmp await_busfree; - complete: mov SCB_TAG call complete_post; jmp await_busfree; @@ -1475,7 +1457,7 @@ complete_post: } mvi INTSTAT,CMDCMPLT ret; -if ((ahc->flags & AHC_INITIATORMODE) != 0) { +if ((ahc->flags & AHC_INITIATORROLE) != 0) { /* * Is it a disconnect message? Set a flag in the SCB to remind us * and await the bus going free. If this is an untagged transaction @@ -1490,8 +1472,7 @@ mesgin_disconnect: test SCB_CONTROL, TAG_ENB jnz await_busfree; mov ARG_1, SCB_TAG; mov SAVED_LUN, SCB_LUN; - mov SCB_SCSIID call index_busy_target; - mov DINDIR, ARG_1; + mov SCB_SCSIID call set_busy_target; jmp await_busfree; /* @@ -1538,15 +1519,15 @@ mesgin_rdptrs: * Index into our Busy Target table. SINDEX and DINDEX are modified * upon return. SCBPTR may be modified by this action. */ -index_busy_target: - shr SINDEX, 4; +set_busy_target: + shr DINDEX, 4, SINDEX; if ((ahc->features & AHC_SCB_BTT) != 0) { mov SCBPTR, SAVED_LUN; - add SINDEX, SCB_64_BTT; + add DINDEX, SCB_64_BTT; } else { - add SINDEX, BUSY_TARGETS; + add DINDEX, BUSY_TARGETS; } - mov DINDEX, SINDEX ret; + mov DINDIR, ARG_1 ret; /* * Identify message? For a reconnecting target, this tells us the lun @@ -1562,13 +1543,28 @@ mesgin_identify: * for this target or the transaction is for a different lun, then * this must be an untagged transaction. */ - mov SAVED_SCSIID call index_busy_target; - mov A, SINDIR; - cmp A, SCB_LIST_NULL je snoop_tag; - if ((ahc->flags & AHC_PAGESCBS) != 0) { - mov A call findSCB; +fetch_busy_target: + shr A, 4, SAVED_SCSIID; + if ((ahc->features & AHC_SCB_BTT) != 0) { + add SINDEX, SCB_64_BTT, A; + mov SCBPTR, SAVED_LUN; } else { - mov SCBPTR, A; + add SINDEX, BUSY_TARGETS, A; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + add A, -BUSY_TARGETS, SINDEX; + jc . + 2; + mvi INTSTAT, OUT_OF_RANGE; + add A, -(BUSY_TARGETS + 16), SINDEX; + jnc . + 2; + mvi INTSTAT, OUT_OF_RANGE; + } + } + mov ARG_1, SINDIR; + cmp ARG_1, SCB_LIST_NULL je snoop_tag; + if ((ahc->flags & AHC_PAGESCBS) != 0) { + mov RETURN_1 call findSCB; + } else { + mov SCBPTR, RETURN_1; } if ((ahc->features & AHC_SCB_BTT) != 0) { jmp setup_SCB_id_lun_okay; @@ -1576,6 +1572,9 @@ mesgin_identify: mov A, SCB_LUN; cmp SAVED_LUN, A je setup_SCB_id_lun_okay; } + if ((ahc->flags & AHC_PAGESCBS) != 0) { + call add_scb_to_disc_list; + } /* * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. @@ -1587,16 +1586,22 @@ mesgin_identify: */ snoop_tag: mov NONE,SCSIDATL; /* ACK Identify MSG */ -snoop_tag_loop: call phase_lock; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x1; + } cmp LASTPHASE, P_MESGIN jne not_found; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x2; + } cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; get_tag: if ((ahc->flags & AHC_PAGESCBS) != 0) { mvi ARG_1 call inb_next; /* tag value */ mov ARG_1 call findSCB; } else { - mvi SCBPTR call inb_next; /* tag value */ + mvi ARG_1 call inb_next; /* tag value */ + mov SCBPTR, ARG_1; } /* @@ -1605,20 +1610,26 @@ get_tag: */ setup_SCB: mov A, SAVED_SCSIID; - cmp SCB_SCSIID, A jne not_found; - mov A, SAVED_LUN; - cmp SCB_LUN, A jne not_found; -setup_SCB_id_lun_okay: - test SCB_CONTROL,DISCONNECTED jz not_found; - if ((ahc->flags & AHC_PAGESCBS) != 0) { - mov SCBPTR call rem_scb_from_disc_list; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x4; } + cmp SCB_SCSIID, A jne not_found_cleanup_scb; + mov A, SAVED_LUN; + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x8; + } + cmp SCB_LUN, A jne not_found_cleanup_scb; +setup_SCB_id_lun_okay: + if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { + or SEQ_FLAGS, 0x10; + } + test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; and SCB_CONTROL,~DISCONNECTED; - or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ + mvi SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ test SCB_CONTROL, TAG_ENB jnz setup_SCB_tagged; mov A, SCBPTR; - mov SAVED_SCSIID call index_busy_target; - mvi DINDIR, SCB_LIST_NULL; + mvi ARG_1, SCB_LIST_NULL; + mov SAVED_SCSIID call set_busy_target; mov SCBPTR, A; setup_SCB_tagged: call set_transfer_settings; @@ -1627,6 +1638,10 @@ setup_SCB_tagged: mvi HOST_MSG call mk_mesg; jmp mesgin_done; +not_found_cleanup_scb: + if ((ahc->flags & AHC_PAGESCBS) != 0) { + call add_scb_to_free_list; + } not_found: mvi INTSTAT, NO_MATCH; jmp mesgin_done; @@ -1673,7 +1688,7 @@ inb_last: mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ } -if ((ahc->flags & AHC_TARGETMODE) != 0) { +if ((ahc->flags & AHC_TARGETROLE) != 0) { /* * Change to a new phase. If we are changing the state of the I/O signal, * from out to in, wait an additional data release delay before continuing. @@ -1732,47 +1747,35 @@ assert: */ if ((ahc->flags & AHC_PAGESCBS) != 0) { findSCB: - mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */ mov A, SINDEX; /* Tag passed in SINDEX */ - mvi RETURN_2, SCB_LIST_NULL; /* Head of list */ + cmp DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound; + mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */ + mvi ARG_2, SCB_LIST_NULL; /* Head of list */ jmp findSCB_loop; findSCB_next: - mov RETURN_2, SCBPTR; cmp SCB_NEXT, SCB_LIST_NULL je findSCB_notFound; + mov ARG_2, SCBPTR; mov SCBPTR,SCB_NEXT; findSCB_loop: cmp SCB_TAG, A jne findSCB_next; - mov SINDEX, SCBPTR ret; -findSCB_notFound: - /* - * We didn't find it. Page in the SCB and make it look - * like it was at the head of the appropriate scb list. - */ - mov ARG_1, A; /* Save tag */ - mov ALLZEROS call get_free_or_disc_scb; - mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - mov ARG_1 call dma_scb; - mvi RETURN_2, SCB_LIST_NULL; /* Head of list */ - /* Jump instead of call as we want to return anyway */ - test SCB_CONTROL, DISCONNECTED jnz add_scb_to_disc_list; - jmp add_scb_to_free_list; -} - -/* - * This routine expects SINDEX to contain the index of the SCB to be - * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the - * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL - * if it is at the head. - */ rem_scb_from_disc_list: -/* Remove this SCB from the disconnection list */ cmp ARG_2, SCB_LIST_NULL je rHead; mov DINDEX, SCB_NEXT; + mov SINDEX, SCBPTR; mov SCBPTR, ARG_2; mov SCB_NEXT, DINDEX; mov SCBPTR, SINDEX ret; rHead: mov DISCONNECTED_SCBH,SCB_NEXT ret; +findSCB_notFound: + /* + * We didn't find it. Page in the SCB. + */ + mov ARG_1, A; /* Save tag */ + mov ALLZEROS call get_free_or_disc_scb; + mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; + mov ARG_1 jmp dma_scb; +} /* * Prepare the hardware to post a byte to host memory given an @@ -1845,7 +1848,7 @@ bcopy_3: mov DINDIR, SINDIR ret; } -if ((ahc->flags & AHC_TARGETMODE) != 0) { +if ((ahc->flags & AHC_TARGETROLE) != 0) { /* * Setup addr assuming that A is an index into * an array of 32byte objects, SINDEX contains @@ -2049,12 +2052,13 @@ get_free_or_disc_scb: cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; return_error: + mvi INTSTAT, NO_FREE_SCB; mvi SINDEX, SCB_LIST_NULL ret; dequeue_disc_scb: mov SCBPTR, DISCONNECTED_SCBH; dma_up_scb: mvi DMAPARAMS, FIFORESET; - mov SCB_TAG call dma_scb; + mov SCB_TAG call dma_scb; unlink_disc_scb: mov DISCONNECTED_SCBH, SCB_NEXT ret; dequeue_free_scb: @@ -2067,8 +2071,10 @@ add_scb_to_disc_list: * candidates for paging out an SCB if one is needed for a new command. * Modifying the disconnected list is a critical(pause dissabled) section. */ +BEGIN_CRITICAL mov SCB_NEXT, DISCONNECTED_SCBH; mov DISCONNECTED_SCBH, SCBPTR ret; +END_CRITICAL } return: ret; diff --git a/sys/dev/aic7xxx/aic7xxx_freebsd.c b/sys/dev/aic7xxx/aic7xxx_freebsd.c index 31ae3a518b3..6a247c02681 100644 --- a/sys/dev/aic7xxx/aic7xxx_freebsd.c +++ b/sys/dev/aic7xxx/aic7xxx_freebsd.c @@ -424,6 +424,13 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) struct scb *scb; struct hardware_scb *hscb; + if ((ahc->flags & AHC_INITIATORROLE) == 0 + && (ccb->ccb_h.func_code == XPT_SCSI_IO + || ccb->ccb_h.func_code == XPT_RESET_DEV)) { + ccb->ccb_h.status = CAM_PROVIDE_FAIL; + xpt_done(ccb); + } + /* * get an scb to use. */ @@ -583,7 +590,8 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) } if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { - ahc_validate_width(ahc, &spi->bus_width); + ahc_validate_width(ahc, /*tinfo limit*/NULL, + &spi->bus_width, ROLE_UNKNOWN); ahc_set_width(ahc, &devinfo, spi->bus_width, update_type, /*paused*/FALSE); } @@ -624,8 +632,9 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) syncrate = ahc_find_syncrate(ahc, &spi->sync_period, &spi->ppr_options, maxsync); - ahc_validate_offset(ahc, syncrate, &spi->sync_offset, - spi->bus_width); + ahc_validate_offset(ahc, /*tinfo limit*/NULL, + syncrate, &spi->sync_offset, + spi->bus_width, ROLE_UNKNOWN); /* We use a period of 0 to represent async */ if (spi->sync_offset == 0) { @@ -692,7 +701,8 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) } if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) { - ahc_validate_width(ahc, &cts->bus_width); + ahc_validate_width(ahc, /*tinfo limit*/NULL, + &cts->bus_width, ROLE_UNKNOWN); ahc_set_width(ahc, &devinfo, cts->bus_width, update_type, /*paused*/FALSE); } @@ -731,8 +741,10 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) syncrate = ahc_find_syncrate(ahc, &cts->sync_period, &ppr_options, maxsync); - ahc_validate_offset(ahc, syncrate, &cts->sync_offset, - MSG_EXT_WDTR_BUS_8_BIT); + ahc_validate_offset(ahc, /*tinfo limit*/NULL, + syncrate, &cts->sync_offset, + MSG_EXT_WDTR_BUS_8_BIT, + ROLE_UNKNOWN); /* We use a period of 0 to represent async */ if (cts->sync_offset == 0) { @@ -827,15 +839,14 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; if ((ahc->features & AHC_WIDE) != 0) cpi->hba_inquiry |= PI_WIDE_16; - if ((ahc->flags & AHC_TARGETMODE) != 0) { + if ((ahc->features & AHC_TARGETMODE) != 0) { cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; } else { cpi->target_sprt = 0; } - cpi->hba_misc = (ahc->flags & AHC_INITIATORMODE) - ? 0 : PIM_NOINITIATOR; + cpi->hba_misc = 0; cpi->hba_eng_cnt = 0; cpi->max_target = (ahc->features & AHC_WIDE) ? 15 : 7; cpi->max_lun = 64; @@ -871,7 +882,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) break; } default: - ccb->ccb_h.status = CAM_REQ_INVALID; + ccb->ccb_h.status = CAM_PROVIDE_FAIL; xpt_done(ccb); break; } @@ -1169,7 +1180,8 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, tinfo = ahc_fetch_transinfo(ahc, SCSIID_CHANNEL(ahc, scb->hscb->scsiid), SCSIID_OUR_ID(scb->hscb->scsiid), - ccb->ccb_h.target_id, &tstate); + SCSIID_TARGET(ahc, scb->hscb->scsiid), + &tstate); mask = SCB_GET_TARGET_MASK(ahc, scb); scb->hscb->scsirate = tinfo->scsirate; @@ -1269,7 +1281,7 @@ ahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim, memcpy(hscb->cdb32, csio->cdb_io.cdb_ptr, hscb->cdb_len); - hscb->shared_data.cdb_ptr = scb->cdb32_busaddr; + scb->flags |= SCB_CDB32_PTR; } else { memcpy(hscb->shared_data.cdb, csio->cdb_io.cdb_ptr, @@ -1279,7 +1291,7 @@ ahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim, if (hscb->cdb_len > 12) { memcpy(hscb->cdb32, csio->cdb_io.cdb_bytes, hscb->cdb_len); - hscb->shared_data.cdb_ptr = scb->cdb32_busaddr; + scb->flags |= SCB_CDB32_PTR; } else { memcpy(hscb->shared_data.cdb, csio->cdb_io.cdb_bytes, @@ -1405,7 +1417,7 @@ ahc_timeout(void *arg) * affect this timeout. */ do { - ahc_intr(ahc); + ahc_freebsd_intr(ahc); pause_sequencer(ahc); } while (ahc_inb(ahc, INTSTAT) & INT_PEND); @@ -1425,6 +1437,7 @@ ahc_timeout(void *arg) channel = SCB_GET_CHANNEL(ahc, scb); lun = SCB_GET_LUN(scb); + ahc_print_path(ahc, scb); printf("SCB 0x%x - timed out ", scb->hscb->tag); /* * Take a snapshot of the bus state and print out @@ -1441,6 +1454,15 @@ ahc_timeout(void *arg) printf(", SEQADDR == 0x%x\n", ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); + printf("STACK == 0x%x, 0x%x, 0x%x, 0x%x\n", + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8)); + + printf("SXFRCTL0 == 0x%x\n", ahc_inb(ahc, SXFRCTL0)); + + ahc_dump_card_state(ahc); if (scb->sg_count > 0) { for (i = 0; i < scb->sg_count; i++) { printf("sg[%d] - Addr 0x%x : Length %d\n", @@ -1483,7 +1505,9 @@ bus_reset: * It's good to be the target! */ u_int active_scb_index; + u_int saved_scbptr; + saved_scbptr = ahc_inb(ahc, SCBPTR); active_scb_index = ahc_inb(ahc, SCB_TAG); if (last_phase != P_BUSFREE @@ -1491,14 +1515,13 @@ bus_reset: struct scb *active_scb; /* - * If the active SCB is not from our device, - * assume that another device is hogging the bus - * and wait for it's timeout to expire before - * taking additional action. + * If the active SCB is not us, assume that + * the active SCB has a longer timeout than + * the timedout SCB, and wait for the active + * SCB to timeout. */ active_scb = ahc_lookup_scb(ahc, active_scb_index); - if (active_scb->hscb->scsiid != scb->hscb->scsiid - || active_scb->hscb->lun != scb->hscb->lun) { + if (active_scb != scb) { struct ccb_hdr *ccbh; u_int newtimeout; @@ -1542,7 +1565,7 @@ bus_reset: ahc_outb(ahc, SCSISIGO, last_phase|ATNO); ahc_print_path(ahc, active_scb); printf("BDR message in message buffer\n"); - active_scb->flags |= SCB_DEVICE_RESET; + active_scb->flags |= SCB_DEVICE_RESET; active_scb->io_ctx->ccb_h.timeout_ch = timeout(ahc_timeout, (caddr_t)active_scb, 2 * hz); unpause_sequencer(ahc); @@ -1573,7 +1596,6 @@ bus_reset: } if (disconnected) { - struct scb *prev_scb; ahc_set_recoveryscb(ahc, scb); /* @@ -1636,17 +1658,8 @@ bus_reset: SEARCH_COMPLETE); ahc_print_path(ahc, scb); printf("Queuing a BDR SCB\n"); - prev_scb = NULL; - if (ahc_qinfifo_count(ahc) != 0) { - u_int prev_tag; - - prev_tag = - ahc->qinfifo[ahc->qinfifonext - 1]; - prev_scb = ahc_lookup_scb(ahc, - prev_tag); - } - ahc_qinfifo_requeue(ahc, prev_scb, scb); - ahc_outb(ahc, SCBPTR, active_scb_index); + ahc_qinfifo_requeue_tail(ahc, scb); + ahc_outb(ahc, SCBPTR, saved_scbptr); scb->io_ctx->ccb_h.timeout_ch = timeout(ahc_timeout, (caddr_t)scb, 2 * hz); unpause_sequencer(ahc); @@ -1729,6 +1742,7 @@ ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) xpt_done(abort_ccb); ccb->ccb_h.status = CAM_REQ_CMP; } else { + xpt_print_path(abort_ccb->ccb_h.path); printf("Not found\n"); ccb->ccb_h.status = CAM_PATH_INVALID; } diff --git a/sys/dev/aic7xxx/aic7xxx_inline.h b/sys/dev/aic7xxx/aic7xxx_inline.h index 77f32c10c9b..1a6b63837af 100644 --- a/sys/dev/aic7xxx/aic7xxx_inline.h +++ b/sys/dev/aic7xxx/aic7xxx_inline.h @@ -309,6 +309,11 @@ ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb) q_hscb = ahc->next_queued_scb->hscb; saved_tag = q_hscb->tag; memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); + if ((scb->flags & SCB_CDB32_PTR) != 0) { + q_hscb->shared_data.cdb_ptr = + ahc_hscb_busaddr(ahc, q_hscb->tag) + + offsetof(struct hardware_scb, cdb32); + } q_hscb->tag = saved_tag; q_hscb->next = scb->hscb->tag; @@ -319,6 +324,11 @@ ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb) /* Now define the mapping from tag to SCB in the scbindex */ ahc->scb_data->scbindex[scb->hscb->tag] = scb; + if (scb->hscb->tag == SCB_LIST_NULL + || scb->hscb->next == SCB_LIST_NULL) + panic("Attempt to queue invalid SCB tag %x:%x\n", + scb->hscb->tag, scb->hscb->next); + /* * Keep a history of SCBs we've downloaded in the qinfifo. */ @@ -382,7 +392,7 @@ ahc_intr(struct ahc_softc *ahc) ahc_flush_device_writes(ahc); ahc_run_qoutfifo(ahc); #ifdef AHC_TARGET_MODE - if ((ahc->flags & AHC_TARGETMODE) != 0) + if ((ahc->flags & AHC_TARGETROLE) != 0) ahc_run_tqinfifo(ahc, /*paused*/FALSE); #endif } diff --git a/sys/dev/aic7xxx/aic7xxx_osm.c b/sys/dev/aic7xxx/aic7xxx_osm.c index 31ae3a518b3..6a247c02681 100644 --- a/sys/dev/aic7xxx/aic7xxx_osm.c +++ b/sys/dev/aic7xxx/aic7xxx_osm.c @@ -424,6 +424,13 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) struct scb *scb; struct hardware_scb *hscb; + if ((ahc->flags & AHC_INITIATORROLE) == 0 + && (ccb->ccb_h.func_code == XPT_SCSI_IO + || ccb->ccb_h.func_code == XPT_RESET_DEV)) { + ccb->ccb_h.status = CAM_PROVIDE_FAIL; + xpt_done(ccb); + } + /* * get an scb to use. */ @@ -583,7 +590,8 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) } if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) { - ahc_validate_width(ahc, &spi->bus_width); + ahc_validate_width(ahc, /*tinfo limit*/NULL, + &spi->bus_width, ROLE_UNKNOWN); ahc_set_width(ahc, &devinfo, spi->bus_width, update_type, /*paused*/FALSE); } @@ -624,8 +632,9 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) syncrate = ahc_find_syncrate(ahc, &spi->sync_period, &spi->ppr_options, maxsync); - ahc_validate_offset(ahc, syncrate, &spi->sync_offset, - spi->bus_width); + ahc_validate_offset(ahc, /*tinfo limit*/NULL, + syncrate, &spi->sync_offset, + spi->bus_width, ROLE_UNKNOWN); /* We use a period of 0 to represent async */ if (spi->sync_offset == 0) { @@ -692,7 +701,8 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) } if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) { - ahc_validate_width(ahc, &cts->bus_width); + ahc_validate_width(ahc, /*tinfo limit*/NULL, + &cts->bus_width, ROLE_UNKNOWN); ahc_set_width(ahc, &devinfo, cts->bus_width, update_type, /*paused*/FALSE); } @@ -731,8 +741,10 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) syncrate = ahc_find_syncrate(ahc, &cts->sync_period, &ppr_options, maxsync); - ahc_validate_offset(ahc, syncrate, &cts->sync_offset, - MSG_EXT_WDTR_BUS_8_BIT); + ahc_validate_offset(ahc, /*tinfo limit*/NULL, + syncrate, &cts->sync_offset, + MSG_EXT_WDTR_BUS_8_BIT, + ROLE_UNKNOWN); /* We use a period of 0 to represent async */ if (cts->sync_offset == 0) { @@ -827,15 +839,14 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE; if ((ahc->features & AHC_WIDE) != 0) cpi->hba_inquiry |= PI_WIDE_16; - if ((ahc->flags & AHC_TARGETMODE) != 0) { + if ((ahc->features & AHC_TARGETMODE) != 0) { cpi->target_sprt = PIT_PROCESSOR | PIT_DISCONNECT | PIT_TERM_IO; } else { cpi->target_sprt = 0; } - cpi->hba_misc = (ahc->flags & AHC_INITIATORMODE) - ? 0 : PIM_NOINITIATOR; + cpi->hba_misc = 0; cpi->hba_eng_cnt = 0; cpi->max_target = (ahc->features & AHC_WIDE) ? 15 : 7; cpi->max_lun = 64; @@ -871,7 +882,7 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) break; } default: - ccb->ccb_h.status = CAM_REQ_INVALID; + ccb->ccb_h.status = CAM_PROVIDE_FAIL; xpt_done(ccb); break; } @@ -1169,7 +1180,8 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, tinfo = ahc_fetch_transinfo(ahc, SCSIID_CHANNEL(ahc, scb->hscb->scsiid), SCSIID_OUR_ID(scb->hscb->scsiid), - ccb->ccb_h.target_id, &tstate); + SCSIID_TARGET(ahc, scb->hscb->scsiid), + &tstate); mask = SCB_GET_TARGET_MASK(ahc, scb); scb->hscb->scsirate = tinfo->scsirate; @@ -1269,7 +1281,7 @@ ahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim, memcpy(hscb->cdb32, csio->cdb_io.cdb_ptr, hscb->cdb_len); - hscb->shared_data.cdb_ptr = scb->cdb32_busaddr; + scb->flags |= SCB_CDB32_PTR; } else { memcpy(hscb->shared_data.cdb, csio->cdb_io.cdb_ptr, @@ -1279,7 +1291,7 @@ ahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim, if (hscb->cdb_len > 12) { memcpy(hscb->cdb32, csio->cdb_io.cdb_bytes, hscb->cdb_len); - hscb->shared_data.cdb_ptr = scb->cdb32_busaddr; + scb->flags |= SCB_CDB32_PTR; } else { memcpy(hscb->shared_data.cdb, csio->cdb_io.cdb_bytes, @@ -1405,7 +1417,7 @@ ahc_timeout(void *arg) * affect this timeout. */ do { - ahc_intr(ahc); + ahc_freebsd_intr(ahc); pause_sequencer(ahc); } while (ahc_inb(ahc, INTSTAT) & INT_PEND); @@ -1425,6 +1437,7 @@ ahc_timeout(void *arg) channel = SCB_GET_CHANNEL(ahc, scb); lun = SCB_GET_LUN(scb); + ahc_print_path(ahc, scb); printf("SCB 0x%x - timed out ", scb->hscb->tag); /* * Take a snapshot of the bus state and print out @@ -1441,6 +1454,15 @@ ahc_timeout(void *arg) printf(", SEQADDR == 0x%x\n", ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); + printf("STACK == 0x%x, 0x%x, 0x%x, 0x%x\n", + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8), + ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8)); + + printf("SXFRCTL0 == 0x%x\n", ahc_inb(ahc, SXFRCTL0)); + + ahc_dump_card_state(ahc); if (scb->sg_count > 0) { for (i = 0; i < scb->sg_count; i++) { printf("sg[%d] - Addr 0x%x : Length %d\n", @@ -1483,7 +1505,9 @@ bus_reset: * It's good to be the target! */ u_int active_scb_index; + u_int saved_scbptr; + saved_scbptr = ahc_inb(ahc, SCBPTR); active_scb_index = ahc_inb(ahc, SCB_TAG); if (last_phase != P_BUSFREE @@ -1491,14 +1515,13 @@ bus_reset: struct scb *active_scb; /* - * If the active SCB is not from our device, - * assume that another device is hogging the bus - * and wait for it's timeout to expire before - * taking additional action. + * If the active SCB is not us, assume that + * the active SCB has a longer timeout than + * the timedout SCB, and wait for the active + * SCB to timeout. */ active_scb = ahc_lookup_scb(ahc, active_scb_index); - if (active_scb->hscb->scsiid != scb->hscb->scsiid - || active_scb->hscb->lun != scb->hscb->lun) { + if (active_scb != scb) { struct ccb_hdr *ccbh; u_int newtimeout; @@ -1542,7 +1565,7 @@ bus_reset: ahc_outb(ahc, SCSISIGO, last_phase|ATNO); ahc_print_path(ahc, active_scb); printf("BDR message in message buffer\n"); - active_scb->flags |= SCB_DEVICE_RESET; + active_scb->flags |= SCB_DEVICE_RESET; active_scb->io_ctx->ccb_h.timeout_ch = timeout(ahc_timeout, (caddr_t)active_scb, 2 * hz); unpause_sequencer(ahc); @@ -1573,7 +1596,6 @@ bus_reset: } if (disconnected) { - struct scb *prev_scb; ahc_set_recoveryscb(ahc, scb); /* @@ -1636,17 +1658,8 @@ bus_reset: SEARCH_COMPLETE); ahc_print_path(ahc, scb); printf("Queuing a BDR SCB\n"); - prev_scb = NULL; - if (ahc_qinfifo_count(ahc) != 0) { - u_int prev_tag; - - prev_tag = - ahc->qinfifo[ahc->qinfifonext - 1]; - prev_scb = ahc_lookup_scb(ahc, - prev_tag); - } - ahc_qinfifo_requeue(ahc, prev_scb, scb); - ahc_outb(ahc, SCBPTR, active_scb_index); + ahc_qinfifo_requeue_tail(ahc, scb); + ahc_outb(ahc, SCBPTR, saved_scbptr); scb->io_ctx->ccb_h.timeout_ch = timeout(ahc_timeout, (caddr_t)scb, 2 * hz); unpause_sequencer(ahc); @@ -1729,6 +1742,7 @@ ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) xpt_done(abort_ccb); ccb->ccb_h.status = CAM_REQ_CMP; } else { + xpt_print_path(abort_ccb->ccb_h.path); printf("Not found\n"); ccb->ccb_h.status = CAM_PATH_INVALID; } diff --git a/sys/dev/aic7xxx/aic7xxx_pci.c b/sys/dev/aic7xxx/aic7xxx_pci.c index 4179a291520..761f57cf1a0 100644 --- a/sys/dev/aic7xxx/aic7xxx_pci.c +++ b/sys/dev/aic7xxx/aic7xxx_pci.c @@ -698,13 +698,8 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry) sblkctl = ahc_inb(ahc, SBLKCTL); ahc_outb(ahc, SBLKCTL, (sblkctl & ~(DIAGLEDEN|DIAGLEDON))); - /* - * I don't know where this is set in the SEEPROM or by the - * BIOS, so we default to 100% on Ultra or slower controllers - * and 75% on ULTRA2 controllers. - */ if ((ahc->features & AHC_ULTRA2) != 0) { - ahc_outb(ahc, DFF_THRSH, RD_DFTHRSH_75|WR_DFTHRSH_75); + ahc_outb(ahc, DFF_THRSH, RD_DFTHRSH_MAX|WR_DFTHRSH_MAX); } else { ahc_outb(ahc, DSPCISTATUS, DFTHRSH_100); } @@ -767,17 +762,19 @@ ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry) static int ahc_ext_scbram_present(struct ahc_softc *ahc) { + u_int chip; int ramps; int single_user; uint32_t devconfig; + chip = ahc->chip & AHC_CHIPID_MASK; devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); single_user = (devconfig & MPORTMODE) != 0; if ((ahc->features & AHC_ULTRA2) != 0) ramps = (ahc_inb(ahc, DSCOMMAND0) & RAMPS) != 0; - else if ((ahc->chip & AHC_CHIPID_MASK) >= AHC_AIC7870) + else if (chip >= AHC_AIC7870) ramps = (devconfig & RAMPSM) != 0; else ramps = 0;