struct	ahc_tmode_tstate *tstate;
struct	tmode_tstate *tstate; u_int	old_period; u_int	old_offset; int	active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE;  if (syncrate == NULL) { period = 0; offset = 0; }  tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); old_period = tinfo->current.period; old_offset = tinfo->current.offset;  if ((type & AHC_TRANS_CUR) != 0 && (old_period != period || old_offset != offset)) { u_int	scsirate;  scsirate = tinfo->scsirate; if ((ahc->features & AHC_ULTRA2) != 0) {    scsirate &= ~(SXFR_ULTRA2|SINGLE_EDGE|ENABLE_CRC); if (syncrate != NULL) scsirate |= syncrate->sxfr_u2|SINGLE_EDGE;  if (active) ahc_outb(ahc, SCSIOFFSET, offset); } else {  scsirate &= ~(SXFR|SOFS);  tstate->ultraenb &= ~devinfo->target_mask; if (syncrate != NULL) { if (syncrate->sxfr & ULTRA_SXFR) { tstate->ultraenb |= devinfo->target_mask; } scsirate |= syncrate->sxfr & SXFR; scsirate |= offset & SOFS; } if (active) { u_int sxfrctl0;  sxfrctl0 = ahc_inb(ahc, SXFRCTL0); sxfrctl0 &= ~FAST20; if (tstate->ultraenb & devinfo->target_mask) sxfrctl0 |= FAST20; ahc_outb(ahc, SXFRCTL0, sxfrctl0); } } if (active) ahc_outb(ahc, SCSIRATE, scsirate);  tinfo->scsirate = scsirate; tinfo->current.period = period; tinfo->current.offset = offset;   ahc_update_pending_syncrates(ahc); }   if (done) { if (offset != 0) { printf("%s: target %d synchronous at %sMHz, " "offset = 0x%x\n", ahc_name(ahc), devinfo->target, syncrate->rate, offset); } else { printf("%s: target %d using " "asynchronous transfers\n", ahc_name(ahc), devinfo->target); } }  if ((type & AHC_TRANS_GOAL) != 0) { tinfo->goal.period = period; tinfo->goal.offset = offset; }  if ((type & AHC_TRANS_USER) != 0) { tinfo->user.period = period; tinfo->user.offset = offset; }  ahc_update_target_msg_request(ahc, devinfo, tinfo, FALSE, paused); }  STATIC void ahc_set_width(ahc, devinfo, width, type, paused, done) struct ahc_softc *ahc; struct ahc_devinfo *devinfo; u_int width; u_int type; int paused; int done; { struct ahc_initiator_tinfo *tinfo; struct tmode_tstate *tstate; u_int  oldwidth; int    active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE;  tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); oldwidth = tinfo->current.width;  if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) { u_int	scsirate;  scsirate =  tinfo->scsirate; scsirate &= ~WIDEXFER; if (width == MSG_EXT_WDTR_BUS_16_BIT) scsirate |= WIDEXFER;  tinfo->scsirate = scsirate;  if (active) ahc_outb(ahc, SCSIRATE, scsirate);  tinfo->current.width = width; }  if (done) { printf("%s: target %d using %dbit transfers\n", ahc_name(ahc), devinfo->target, 8 * (0x01 << width)); }  if ((type & AHC_TRANS_GOAL) != 0) tinfo->goal.width = width; if ((type & AHC_TRANS_USER) != 0) tinfo->user.width = width;  ahc_update_target_msg_request(ahc, devinfo, tinfo, FALSE, paused); }  STATIC void ahc_set_tags(ahc, devinfo, enable) struct ahc_softc *ahc; struct ahc_devinfo *devinfo; int enable; { struct ahc_initiator_tinfo *tinfo; struct tmode_tstate *tstate;  tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); if (enable) tstate->tagenable |= devinfo->target_mask; else { tstate->tagenable &= ~devinfo->target_mask; tstate->tagdisable |= devinfo->target_mask; } }   int ahc_attach(ahc) struct ahc_softc *ahc; {  LIST_INIT(&ahc->sc_xxxq);  #ifdef AHC_BROKEN_CACHE if (cpu_class == CPUCLASS_386)	 ahc_broken_cache = 0; #endif  ahc->sc_link.adapter_target = ahc->our_id; if (ahc->features & AHC_WIDE) ahc->sc_link.adapter_buswidth = 16; ahc->sc_link.adapter_softc = ahc; ahc->sc_link.adapter = &ahc_switch; ahc->sc_link.openings = 2; ahc->sc_link.device = &ahc_dev; ahc->sc_link.flags = SCSIDEBUG_LEVEL;  if (ahc->features & AHC_TWIN) {  ahc->sc_link_b = ahc->sc_link; ahc->sc_link_b.adapter_target = ahc->our_id_b; if (ahc->features & AHC_WIDE) ahc->sc_link.adapter_buswidth = 16; }   if ((ahc->flags & AHC_CHANNEL_B_PRIMARY) == 0) {  ahc->sc_link_b.scsibus = 0xff;  config_found((void *)ahc, &ahc->sc_link, scsiprint); if (ahc->features & AHC_TWIN) config_found((void *)ahc, &ahc->sc_link_b, scsiprint); } else {    config_found((void *)ahc, &ahc->sc_link_b, scsiprint); config_found((void *)ahc, &ahc->sc_link, scsiprint); } return 1; }  STATIC void ahc_fetch_devinfo(ahc, devinfo) struct ahc_softc *ahc; struct ahc_devinfo *devinfo; { u_int	saved_tcl; role_t	role; int	our_id;  if (ahc_inb(ahc, SSTAT0) & TARGET) role = ROLE_TARGET; else role = ROLE_INITIATOR;  if (role == ROLE_TARGET && (ahc->features & AHC_MULTI_TID) != 0 && (ahc_inb(ahc, SEQ_FLAGS) & CMDPHASE_PENDING) != 0) {  our_id = ahc_inb(ahc, TARGIDIN) & OID; } else if ((ahc->features & AHC_ULTRA2) != 0) our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID; else our_id = ahc_inb(ahc, SCSIID) & OID;  saved_tcl = ahc_inb(ahc, SAVED_TCL); ahc_compile_devinfo(devinfo, our_id, TCL_TARGET(saved_tcl), TCL_LUN(saved_tcl), TCL_CHANNEL(ahc, saved_tcl), role); }  STATIC void ahc_compile_devinfo(devinfo, our_id, target, lun, channel, role) struct ahc_devinfo *devinfo; u_int our_id; u_int target; u_int lun; char channel; role_t role; { devinfo->our_scsiid = our_id; devinfo->target = target; devinfo->lun = lun; devinfo->target_offset = target; devinfo->channel = channel; devinfo->role = role; if (channel == 'B') devinfo->target_offset += 8; devinfo->target_mask = (0x01 << devinfo->target_offset); }   int ahc_intr(void *arg) { struct	ahc_softc *ahc; u_int	intstat;  ahc = (struct ahc_softc *)arg;  intstat = ahc_inb(ahc, INTSTAT);   if ((intstat & INT_PEND) == 0) { if (ahc->pci_intr_func && ahc->pci_intr_func(ahc)) { #ifdef AHC_DEBUG printf("%s: bus intr: CCHADDR %x HADDR %x SEQADDR %x\n", ahc_name(ahc), ahc_inb(ahc, CCHADDR) | (ahc_inb(ahc, CCHADDR+1) << 8) | (ahc_inb(ahc, CCHADDR+2) << 16) | (ahc_inb(ahc, CCHADDR+3) << 24), ahc_inb(ahc, HADDR) | (ahc_inb(ahc, HADDR+1) << 8) | (ahc_inb(ahc, HADDR+2) << 16) | (ahc_inb(ahc, HADDR+3) << 24), ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); #endif return 1; } return 0; }  if (intstat & CMDCMPLT) { ahc_outb(ahc, CLRINT, CLRCMDINT); ahc_run_qoutfifo(ahc); } if (intstat & BRKADRINT) {  int i, error, num_errors;  error = ahc_inb(ahc, ERROR); 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));   ahc_abort_scbs(ahc, ALL_TARGETS, ALL_CHANNELS, ALL_LUNS, SCB_LIST_NULL, ROLE_UNKNOWN, XS_DRIVER_STUFFUP); } if (intstat & SEQINT) ahc_handle_seqint(ahc, intstat);  if (intstat & SCSIINT) ahc_handle_scsiint(ahc, intstat); return(1); }  STATIC struct tmode_tstate * ahc_alloc_tstate(ahc, scsi_id, channel) struct ahc_softc *ahc; u_int scsi_id; char channel; { struct tmode_tstate *master_tstate; struct tmode_tstate *tstate; int i, s;  master_tstate = ahc->enabled_targets[ahc->our_id]; if (channel == 'B') { scsi_id += 8; master_tstate = ahc->enabled_targets[ahc->our_id_b + 8]; } if (ahc->enabled_targets[scsi_id] != NULL && ahc->enabled_targets[scsi_id] != master_tstate) panic("%s: ahc_alloc_tstate - Target already allocated", ahc_name(ahc)); tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT); if (tstate == NULL) return (NULL);   if (master_tstate != NULL) { bcopy(master_tstate, tstate, sizeof(*tstate)); tstate->ultraenb = 0; for (i = 0; i < 16; i++) { bzero(&tstate->transinfo[i].current, sizeof(tstate->transinfo[i].current)); bzero(&tstate->transinfo[i].goal, sizeof(tstate->transinfo[i].goal)); } } else bzero(tstate, sizeof(*tstate)); s = splbio(); ahc->enabled_targets[scsi_id] = tstate; splx(s); return (tstate); }  STATIC void ahc_handle_seqint(ahc, intstat) struct ahc_softc *ahc; u_int intstat; { struct scb *scb; struct ahc_devinfo devinfo;  ahc_fetch_devinfo(ahc, &devinfo);   ahc_outb(ahc, CLRINT, CLRSEQINT); switch (intstat & SEQINT_MASK) { case NO_MATCH: {  ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));  printf("%s:%c:%d: no active SCB for reconnecting " "target - issuing BUS DEVICE RESET\n", ahc_name(ahc), devinfo.channel, devinfo.target); printf("SAVED_TCL == 0x%x, ARG_1 == 0x%x, SEQ_FLAGS == 0x%x\n", ahc_inb(ahc, SAVED_TCL), ahc_inb(ahc, ARG_1), ahc_inb(ahc, SEQ_FLAGS)); ahc->msgout_buf[0] = MSG_BUS_DEV_RESET; ahc->msgout_len = 1; 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); break; } case UPDATE_TMSG_REQ: ahc_outb(ahc, TARGET_MSG_REQUEST, ahc->targ_msg_req & 0xFF); ahc_outb(ahc, TARGET_MSG_REQUEST + 1, (ahc->targ_msg_req >> 8) & 0xFF); ahc_outb(ahc, HS_MAILBOX, 0); break; case SEND_REJECT: { u_int rejbyte = ahc_inb(ahc, ACCUM); printf("%s:%c:%d: Warning - unknown message received from " "target (0x%x).  Rejecting\n", ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte); break; } case NO_IDENT: {  int found;  printf("%s:%c:%d: Target did not send an IDENTIFY message. " "LASTPHASE = 0x%x, SAVED_TCL == 0x%x\n", ahc_name(ahc), devinfo.channel, devinfo.target, ahc_inb(ahc, LASTPHASE), ahc_inb(ahc, SAVED_TCL)); found = ahc_reset_channel(ahc, devinfo.channel, TRUE); printf("%s: Issued Channel %c Bus Reset. " "%d SCBs aborted\n", ahc_name(ahc), devinfo.channel, found); return; } case BAD_PHASE: { u_int lastphase;  lastphase = ahc_inb(ahc, LASTPHASE); if (lastphase == P_BUSFREE) { printf("%s:%c:%d: Missed busfree.  Curphase = 0x%x\n", ahc_name(ahc), devinfo.channel, devinfo.target, ahc_inb(ahc, SCSISIGI)); restart_sequencer(ahc); return; } else { printf("%s:%c:%d: unknown scsi bus phase %x.  " "Attempting to continue\n", ahc_name(ahc), devinfo.channel, devinfo.target, ahc_inb(ahc, SCSISIGI)); } break; } case BAD_STATUS: { u_int  scb_index; struct hardware_scb *hscb; struct scsi_xfer *xs;  scb_index = ahc_inb(ahc, SCB_TAG); scb = &ahc->scb_data->scbarray[scb_index];   ahc_outb(ahc, RETURN_1, 0); if (!(scb_index < ahc->scb_data->numscbs && (scb->flags & SCB_ACTIVE) != 0)) { printf("%s:%c:%d: ahc_intr - referenced scb " "not valid during seqint 0x%x scb(%d)\n", ahc_name(ahc), devinfo.channel, devinfo.target, intstat, scb_index); goto unpause; }  hscb = scb->hscb; xs = scb->xs;   if ((scb->flags & SCB_SENSE) != 0) {  scb->flags &= ~SCB_SENSE; ahcsetccbstatus(xs, XS_DRIVER_STUFFUP); break; }  ahc_freeze_devq(ahc, xs->sc_link); ahc_freeze_ccb(scb); xs->status = hscb->status; switch (hscb->status) { case SCSI_OK: printf("%s: Interrupted for staus of 0???\n", ahc_name(ahc)); break; case SCSI_CHECK: #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWSENSE) { sc_print_addr(scb->xs->sc_link); printf("SCB %d: requests Check Status\n", scb->hscb->tag); } #endif  if (xs->error == XS_NOERROR && !(scb->flags & SCB_SENSE)) { struct ahc_dma_seg *sg; struct scsi_sense *sc; struct ahc_initiator_tinfo *tinfo; struct tmode_tstate *tstate;  sg = scb->sg_list; sc = (struct scsi_sense *)(&hscb->cmdstore);  if (hscb->residual_SG_count != 0) ahc_calc_residual(scb); else xs->resid = 0;  #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWSENSE) { sc_print_addr(scb->xs->sc_link); printf("Sending Sense\n"); } #endif sg->addr = ahc->scb_data->sense_busaddr + (hscb->tag*sizeof(struct scsi_sense_data));  sg->len = sizeof(struct scsi_sense_data);  sc->opcode = REQUEST_SENSE; sc->byte2 =  SCB_LUN(scb) << 5; sc->unused[0] = 0; sc->unused[1] = 0; sc->length = sg->len; sc->control = 0;   hscb->control = 0;   ahc_calc_residual(scb); #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWSENSE) { sc_print_addr(xs->sc_link); printf("Sense: datalen %d resid %d" "chan %d id %d targ %d\n", xs->datalen, xs->resid, devinfo.channel, devinfo.our_scsiid, devinfo.target); } #endif if (xs->datalen > 0 && xs->resid == xs->datalen) { tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, devinfo.our_scsiid, devinfo.target, &tstate); ahc_update_target_msg_request(ahc, &devinfo, tinfo, TRUE, TRUE); } hscb->status = 0; hscb->SG_count = 1; hscb->SG_pointer = scb->sg_list_phys; hscb->data = sg->addr; hscb->datalen = sg->len; hscb->cmdpointer = hscb->cmdstore_busaddr; hscb->cmdlen = sizeof(*sc); scb->sg_count = hscb->SG_count; ahc_swap_hscb(hscb); ahc_swap_sg(scb->sg_list); scb->flags |= SCB_SENSE;  ahc_busy_tcl(ahc, scb); ahc_outb(ahc, RETURN_1, SEND_SENSE);   if (!(scb->xs->flags & SCSI_POLL)) timeout_add(&scb->xs->stimeout, 5 * hz); } break; case SCSI_BUSY:  ahc_freeze_devq(ahc, xs->sc_link); ahc_freeze_ccb(scb); break; } break; } case TRACE_POINT: { printf("SSTAT2 = 0x%x DFCNTRL = 0x%x\n", ahc_inb(ahc, SSTAT2), ahc_inb(ahc, DFCNTRL)); printf("SSTAT3 = 0x%x DSTATUS = 0x%x\n", ahc_inb(ahc, SSTAT3), ahc_inb(ahc, DFSTATUS)); printf("SSTAT0 = 0x%x, SCB_DATACNT = 0x%x\n", ahc_inb(ahc, SSTAT0), ahc_inb(ahc, SCB_DATACNT)); break; } case HOST_MSG_LOOP: {  if (ahc->msg_type == MSG_TYPE_NONE) { u_int bus_phase;  bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; if (bus_phase != P_MESGIN && bus_phase != P_MESGOUT) { printf("ahc_intr: HOST_MSG_LOOP bad " "phase 0x%x\n", bus_phase);  ahc_clear_intstat(ahc); restart_sequencer(ahc); }  if (devinfo.role == ROLE_INITIATOR) { struct scb *scb; u_int scb_index;  scb_index = ahc_inb(ahc, SCB_TAG); scb = &ahc->scb_data->scbarray[scb_index];  if (bus_phase == P_MESGOUT) ahc_setup_initiator_msgout(ahc, &devinfo, scb); else { ahc->msg_type = MSG_TYPE_INITIATOR_MSGIN; ahc->msgin_index = 0; } } else { if (bus_phase == P_MESGOUT) { ahc->msg_type = MSG_TYPE_TARGET_MSGOUT; ahc->msgin_index = 0; } else  ahc_setup_target_msgin(ahc, &devinfo); } }   ahc_handle_message_phase(ahc, NULL); break; } case PERR_DETECTED: {  if ((intstat & SCSIINT) == 0 && (ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0) { u_int curphase;   curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; ahc_outb(ahc, LASTPHASE, curphase); ahc_outb(ahc, SCSISIGO, curphase); ahc_inb(ahc, SCSIDATL); } break; } case DATA_OVERRUN: {  u_int scbindex = ahc_inb(ahc, SCB_TAG); u_int lastphase = ahc_inb(ahc, LASTPHASE); int i;  scb = &ahc->scb_data->scbarray[scbindex]; for (i = 0; i < num_phases; i++) { if (lastphase == phase_table[i].phase) break; } sc_print_addr(scb->xs->sc_link); printf("data overrun detected %s." "  Tag == 0x%x.\n", phase_table[i].phasemsg, scb->hscb->tag); sc_print_addr(scb->xs->sc_link); printf("%s seen Data Phase.  Length = %d.  NumSGs = %d.\n", ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't", scb->xs->datalen, scb->sg_count); if (scb->sg_count > 0) { for (i = 0; i < scb->sg_count; i++) { printf("sg[%d] - Addr 0x%x : Length %d\n", i, (unsigned int)le32toh(scb->sg_list[i].addr), (unsigned int)le32toh(scb->sg_list[i].len)); } }  ahc_freeze_devq(ahc, scb->xs->sc_link); ahcsetccbstatus(scb->xs, XS_DRIVER_STUFFUP); ahc_freeze_ccb(scb); break; } case TRACEPOINT: { printf("TRACEPOINT: RETURN_2 = %d\n", ahc_inb(ahc, RETURN_2)); #if 0 printf("SSTAT1 == 0x%x\n", ahc_inb(ahc, SSTAT1)); printf("SSTAT0 == 0x%x\n", ahc_inb(ahc, SSTAT0)); printf(", SCSISIGI == 0x%x\n", ahc_inb(ahc, SCSISIGI)); printf("TRACEPOINT: CCHCNT = %d, SG_COUNT = %d\n", ahc_inb(ahc, CCHCNT), ahc_inb(ahc, SG_COUNT)); printf("TRACEPOINT: SCB_TAG = %d\n", ahc_inb(ahc, SCB_TAG)); printf("TRACEPOINT1: CCHADDR = %d, CCHCNT = %d, SCBPTR = %d\n", ahc_inb(ahc, CCHADDR) | (ahc_inb(ahc, CCHADDR+1) << 8) | (ahc_inb(ahc, CCHADDR+2) << 16) | (ahc_inb(ahc, CCHADDR+3) << 24), ahc_inb(ahc, CCHCNT) | (ahc_inb(ahc, CCHCNT+1) << 8) | (ahc_inb(ahc, CCHCNT+2) << 16), ahc_inb(ahc, SCBPTR)); printf("TRACEPOINT: WAITING_SCBH = %d\n", ahc_inb(ahc, WAITING_SCBH)); printf("TRACEPOINT: SCB_TAG = %d\n", ahc_inb(ahc, SCB_TAG)); #endif break; } #if NOT_YET  case MESG_BUFFER_BUSY: break; case MSGIN_PHASEMIS: break; #endif default: printf("ahc_intr: seqint, " "intstat == 0x%x, scsisigi = 0x%x\n", intstat, ahc_inb(ahc, SCSISIGI)); break; }  unpause:  unpause_sequencer(ahc); }  STATIC void ahc_handle_scsiint(ahc, intstat) struct ahc_softc *ahc; u_int intstat; { u_int	scb_index; u_int	status; struct	scb *scb; char	cur_channel; char	intr_channel;  if ((ahc->features & AHC_TWIN) != 0 && ((ahc_inb(ahc, SBLKCTL) & SELBUSB) != 0)) cur_channel = 'B'; else cur_channel = 'A'; intr_channel = cur_channel;  status = ahc_inb(ahc, SSTAT1); if (status == 0) { if ((ahc->features & AHC_TWIN) != 0) {  ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB); status = ahc_inb(ahc, SSTAT1); ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB); intr_channel = (cur_channel == 'A') ? 'B' : 'A'; } if (status == 0) { printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc)); return; } }  scb_index = ahc_inb(ahc, SCB_TAG); if (scb_index < ahc->scb_data->numscbs) { scb = &ahc->scb_data->scbarray[scb_index]; if ((scb->flags & SCB_ACTIVE) == 0 || (ahc_inb(ahc, SEQ_FLAGS) & IDENTIFY_SEEN) == 0) scb = NULL; } else scb = NULL;  if ((status & SCSIRSTI) != 0) { printf("%s: Someone reset channel %c\n", ahc_name(ahc), intr_channel); ahc_reset_channel(ahc, intr_channel, FALSE); } else if ((status & SCSIPERR) != 0) {  u_int mesg_out; u_int curphase; u_int errorphase; u_int lastphase; int   i;  lastphase = ahc_inb(ahc, LASTPHASE); curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; ahc_outb(ahc, CLRSINT1, CLRSCSIPERR);  if ((ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0 || curphase == P_DATAIN) errorphase = curphase; else errorphase = lastphase;  for (i = 0; i < num_phases; i++) { if (errorphase == phase_table[i].phase) break; } mesg_out = phase_table[i].mesg_out; if (scb != NULL) sc_print_addr(scb->xs->sc_link); else printf("%s:%c:%d: ", ahc_name(ahc), intr_channel, TCL_TARGET(ahc_inb(ahc, SAVED_TCL)));  printf("parity error detected %s. " "SEQADDR(0x%x) SCSIRATE(0x%x)\n", phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8), ahc_inb(ahc, SCSIRATE));   if (mesg_out != MSG_NOOP) { if (ahc->msg_type != MSG_TYPE_NONE) ahc->send_msg_perror = TRUE; else ahc_outb(ahc, MSG_OUT, mesg_out); } ahc_outb(ahc, CLRINT, CLRSCSIINT); unpause_sequencer(ahc); } else if ((status & BUSFREE) != 0 && (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) {  u_int lastphase = ahc_inb(ahc, LASTPHASE); u_int saved_tcl = ahc_inb(ahc, SAVED_TCL); u_int target = TCL_TARGET(saved_tcl); u_int initiator_role_id = TCL_SCSI_ID(ahc, saved_tcl); char channel = TCL_CHANNEL(ahc, saved_tcl); int printerror = 1;  ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); if (lastphase == P_MESGOUT) { u_int message; u_int tag;  message = ahc->msgout_buf[ahc->msgout_index - 1]; tag = SCB_LIST_NULL; switch (message) { case MSG_ABORT_TAG: tag = scb->hscb->tag;  case MSG_ABORT: sc_print_addr(scb->xs->sc_link); printf("SCB %d - Abort %s Completed.\n", scb->hscb->tag, tag == SCB_LIST_NULL ? "" : "Tag"); ahc_abort_scbs(ahc, target, channel, TCL_LUN(saved_tcl), tag, ROLE_INITIATOR, XS_DRIVER_STUFFUP); printerror = 0; break; case MSG_BUS_DEV_RESET: { struct ahc_devinfo devinfo;  if (scb != NULL && (scb->xs->flags & SCSI_RESET) && ahc_match_scb(scb, target, channel, TCL_LUN(saved_tcl), SCB_LIST_NULL, ROLE_INITIATOR)) { ahcsetccbstatus(scb->xs, XS_NOERROR); } ahc_compile_devinfo(&devinfo, initiator_role_id, target, TCL_LUN(saved_tcl), channel, ROLE_INITIATOR); ahc_handle_devreset(ahc, &devinfo, XS_RESET, "Bus Device Reset", 0); printerror = 0; break; } default: break; } } if (printerror != 0) { int i;  if (scb != NULL) { u_int tag;  if ((scb->hscb->control & TAG_ENB) != 0) tag = scb->hscb->tag; else tag = SCB_LIST_NULL; ahc_abort_scbs(ahc, target, channel, SCB_LUN(scb), tag, ROLE_INITIATOR, XS_DRIVER_STUFFUP); sc_print_addr(scb->xs->sc_link); } else {  printf("%s: ", ahc_name(ahc)); } for (i = 0; i < num_phases; i++) { if (lastphase == phase_table[i].phase) break; } printf("Unexpected busfree %s\n" "SEQADDR == 0x%x\n", phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); } ahc_clear_msg_state(ahc); ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); ahc_outb(ahc, CLRSINT1, CLRBUSFREE|CLRSCSIPERR); ahc_outb(ahc, CLRINT, CLRSCSIINT); restart_sequencer(ahc); } else if ((status & SELTO) != 0) { u_int scbptr;  scbptr = ahc_inb(ahc, WAITING_SCBH); ahc_outb(ahc, SCBPTR, scbptr); scb_index = ahc_inb(ahc, SCB_TAG);  if (scb_index < ahc->scb_data->numscbs) { scb = &ahc->scb_data->scbarray[scb_index]; if ((scb->flags & SCB_ACTIVE) == 0) scb = NULL; } else scb = NULL;  if (scb == NULL) { printf("%s: ahc_intr - referenced scb not " "valid during SELTO scb(%d, %d)\n", ahc_name(ahc), scbptr, scb_index); } else { u_int tag;  tag = SCB_LIST_NULL; if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) tag = scb->hscb->tag;  ahc_abort_scbs(ahc, SCB_TARGET(scb), SCB_CHANNEL(scb), SCB_LUN(scb), tag, ROLE_INITIATOR, XS_SELTIMEOUT); }  ahc_outb(ahc, SCSISEQ, 0);   ahc_clear_msg_state(ahc);   ahc_outb(ahc, CLRSINT0, CLRSELINGO);   ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); ahc_outb(ahc, CLRINT, CLRSCSIINT); restart_sequencer(ahc); } else { sc_print_addr(scb->xs->sc_link); printf("Unknown SCSIINT. Status = 0x%x\n", status); ahc_outb(ahc, CLRSINT1, status); ahc_outb(ahc, CLRINT, CLRSCSIINT); unpause_sequencer(ahc); } }  STATIC void ahc_build_transfer_msg(ahc, devinfo) struct ahc_softc *ahc; struct ahc_devinfo *devinfo; {  struct	ahc_initiator_tinfo *tinfo; struct	tmode_tstate *tstate; int	dowide; int	dosync;  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;  if (!dowide && !dosync) { dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; dosync = tinfo->goal.period != 0; }  if (dowide) { ahc_construct_wdtr(ahc, tinfo->goal.width); } else if (dosync) { struct	ahc_syncrate *rate; u_int	period; u_int	offset;  period = tinfo->goal.period; rate = ahc_devlimited_syncrate(ahc, &period); offset = tinfo->goal.offset; ahc_validate_offset(ahc, rate, &offset, tinfo->current.width); ahc_construct_sdtr(ahc, period, offset); } else { panic("ahc_intr: AWAITING_MSG for negotiation, " "but no negotiation needed\n"); } }  STATIC void ahc_setup_initiator_msgout(ahc, devinfo, scb) struct ahc_softc *ahc; struct ahc_devinfo *devinfo; struct scb *scb; {  ahc->msgout_index = 0; ahc->msgout_len = 0;  if ((scb->flags & SCB_DEVICE_RESET) == 0 && ahc_inb(ahc, MSG_OUT) == MSG_IDENTIFYFLAG) { u_int identify_msg;  identify_msg = MSG_IDENTIFYFLAG | SCB_LUN(scb); if ((scb->hscb->control & DISCENB) != 0) identify_msg |= MSG_IDENTIFY_DISCFLAG; ahc->msgout_buf[ahc->msgout_index++] = identify_msg; ahc->msgout_len++;  if ((scb->hscb->control & TAG_ENB) != 0) {  ahc->msgout_buf[ahc->msgout_index++] = MSG_SIMPLE_Q_TAG; ahc->msgout_buf[ahc->msgout_index++] = scb->hscb->tag; ahc->msgout_len += 2; } }  if (scb->flags & SCB_DEVICE_RESET) { ahc->msgout_buf[ahc->msgout_index++] = MSG_BUS_DEV_RESET; ahc->msgout_len++;  sc_print_addr(scb->xs->sc_link); printf("Bus Device Reset Message Sent\n"); } else if (scb->flags & SCB_ABORT) { if ((scb->hscb->control & TAG_ENB) != 0) ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT_TAG; else ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT; ahc->msgout_len++; sc_print_addr(scb->xs->sc_link); printf("Abort Message Sent\n"); } else if ((ahc->targ_msg_req & devinfo->target_mask) != 0) { ahc_build_transfer_msg(ahc, devinfo); } else { printf("ahc_intr: AWAITING_MSG for an SCB that " "does not have a waiting message"); panic("SCB = %d, SCB Control = %x, MSG_OUT = %x " "SCB flags = %x", scb->hscb->tag, scb->hscb->control, ahc_inb(ahc, MSG_OUT), scb->flags); }   ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MK_MESSAGE); ahc->msgout_index = 0; ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; }  STATIC void ahc_setup_target_msgin(ahc, devinfo) struct ahc_softc *ahc; struct ahc_devinfo *devinfo; {  ahc->msgout_index = 0; ahc->msgout_len = 0;  if ((ahc->targ_msg_req & devinfo->target_mask) != 0) ahc_build_transfer_msg(ahc, devinfo); else panic("ahc_intr: AWAITING target message with no message");  ahc->msgout_index = 0; ahc->msg_type = MSG_TYPE_TARGET_MSGIN; }  STATIC int ahc_handle_msg_reject(ahc, devinfo) struct ahc_softc *ahc; struct ahc_devinfo *devinfo; {  struct scb *scb; u_int scb_index; u_int last_msg; int   response = 0;  scb_index = ahc_inb(ahc, SCB_TAG); scb = &ahc->scb_data->scbarray[scb_index];   last_msg = ahc_inb(ahc, LAST_MSG);  if (ahc_sent_msg(ahc, MSG_EXT_WDTR, FALSE)) { struct ahc_initiator_tinfo *tinfo; struct tmode_tstate *tstate;   if (bootverbose) printf("%s:%c:%d: refuses WIDE negotiation.  Using " "8bit transfers\n", ahc_name(ahc), devinfo->channel, devinfo->target); ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT, AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, TRUE, TRUE);  tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, devinfo->target, &tstate); if (tinfo->goal.period) { u_int period;   period = tinfo->goal.period; ahc_devlimited_syncrate(ahc, &period); ahc->msgout_index = 0; ahc->msgout_len = 0; ahc_construct_sdtr(ahc, period, tinfo->goal.offset); ahc->msgout_index = 0; response = 1; } } else if (ahc_sent_msg(ahc, MSG_EXT_SDTR, FALSE)) {  ahc_set_syncrate(ahc, devinfo, NULL, 0, 0, AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, TRUE, TRUE); if (bootverbose) printf("%s:%c:%d: refuses synchronous negotiation. " "Using asynchronous transfers\n", ahc_name(ahc), devinfo->channel, devinfo->target); } else if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) { if (bootverbose) printf("%s:%c:%d: refuses tagged commands.  Performing " "non-tagged I/O\n", ahc_name(ahc), devinfo->channel, devinfo->target);  ahc_set_tags(ahc, devinfo, FALSE);   ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MSG_SIMPLE_Q_TAG); scb->hscb->control &= ~MSG_SIMPLE_Q_TAG; ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG); ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO);   ahc_search_qinfifo(ahc, SCB_TARGET(scb), SCB_CHANNEL(scb), SCB_LUN(scb), SCB_LIST_NULL, ROLE_INITIATOR, SCB_REQUEUE, SEARCH_COMPLETE); } else {  printf("%s:%c:%d: Message reject for %x -- ignored\n", ahc_name(ahc), devinfo->channel, devinfo->target, last_msg); } return (response); }  STATIC void ahc_clear_msg_state(ahc) struct ahc_softc *ahc; { ahc->msgout_len = 0; ahc->msgin_index = 0; ahc->msg_type = MSG_TYPE_NONE; ahc_outb(ahc, MSG_OUT, MSG_NOOP); }  STATIC void ahc_handle_message_phase(ahc, sc_link) struct ahc_softc *ahc; struct scsi_link *sc_link; { struct	ahc_devinfo devinfo; u_int	bus_phase; int	end_session;  ahc_fetch_devinfo(ahc, &devinfo); end_session = FALSE; bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;  reswitch: switch (ahc->msg_type) { case MSG_TYPE_INITIATOR_MSGOUT: { int lastbyte; int phasemis; int msgdone;  if (ahc->msgout_len == 0) panic("REQINIT interrupt with no active message");  phasemis = bus_phase != P_MESGOUT; if (phasemis) { if (bus_phase == P_MESGIN) {  ahc_outb(ahc, CLRSINT1, CLRATNO); ahc->send_msg_perror = FALSE; ahc->msg_type = MSG_TYPE_INITIATOR_MSGIN; ahc->msgin_index = 0; goto reswitch; } end_session = TRUE; break; }  if (ahc->send_msg_perror) { ahc_outb(ahc, CLRSINT1, CLRATNO); ahc_outb(ahc, CLRSINT1, CLRREQINIT); ahc_outb(ahc, SCSIDATL, MSG_PARITY_ERROR); break; }  msgdone	= ahc->msgout_index == ahc->msgout_len; if (msgdone) {  ahc->msgout_index = 0; ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); }  lastbyte = ahc->msgout_index == (ahc->msgout_len - 1); if (lastbyte) {  ahc_outb(ahc, CLRSINT1, CLRATNO); }   ahc_outb(ahc, CLRSINT1, CLRREQINIT); ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]); break; } case MSG_TYPE_INITIATOR_MSGIN: { int phasemis; int message_done;  phasemis = bus_phase != P_MESGIN;  if (phasemis) { ahc->msgin_index = 0; if (bus_phase == P_MESGOUT && (ahc->send_msg_perror == TRUE || (ahc->msgout_len != 0 && ahc->msgout_index == 0))) { ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; goto reswitch; } end_session = TRUE; break; }   ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIBUSL);  message_done = ahc_parse_msg(ahc, sc_link, &devinfo);  if (message_done) {  ahc->msgin_index = 0;   if (ahc->msgout_len != 0) ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO); } else ahc->msgin_index++;   ahc_outb(ahc, CLRSINT1, CLRREQINIT); ahc_inb(ahc, SCSIDATL); break; } case MSG_TYPE_TARGET_MSGIN: { int msgdone; int msgout_request;  if (ahc->msgout_len == 0) panic("Target MSGIN with no active message");   if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0 && ahc->msgout_index > 0) msgout_request = TRUE; else msgout_request = FALSE;  if (msgout_request) {   ahc->msg_type = MSG_TYPE_TARGET_MSGOUT; ahc_outb(ahc, SCSISIGO, P_MESGOUT | BSYO); ahc->msgin_index = 0;  ahc_inb(ahc, SCSIDATL); ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) | SPIOEN); break; }  msgdone = ahc->msgout_index == ahc->msgout_len; if (msgdone) { ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); end_session = TRUE; break; }   ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) | SPIOEN); ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]); break; } case MSG_TYPE_TARGET_MSGOUT: { int lastbyte; int msgdone;   lastbyte = (ahc_inb(ahc, SCSISIGI) & ATNI) == 0;   ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIDATL); msgdone = ahc_parse_msg(ahc, sc_link, &devinfo); if (msgdone == MSGLOOP_TERMINATED) {  return; }  ahc->msgin_index++;   if (msgdone == MSGLOOP_MSGCOMPLETE) { ahc->msgin_index = 0;   if (ahc->msgout_len != 0) { ahc_outb(ahc, SCSISIGO, P_MESGIN | BSYO); ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) | SPIOEN); ahc->msg_type = MSG_TYPE_TARGET_MSGIN; ahc->msgin_index = 0; break; } }  if (lastbyte) end_session = TRUE; else {  ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) | SPIOEN); }  break; } default: panic("Unknown REQINIT message type"); }  if (end_session) { ahc_clear_msg_state(ahc); ahc_outb(ahc, RETURN_1, EXIT_MSG_LOOP); } else ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP); }   STATIC int ahc_sent_msg(ahc, msgtype, full) struct ahc_softc *ahc; u_int msgtype; int full; { int found; int index;  found = FALSE; index = 0;  while (index < ahc->msgout_len) { if (ahc->msgout_buf[index] == MSG_EXTENDED) {   if (ahc->msgout_buf[index+2] == msgtype) { u_int end_index;  end_index = index + 1 + ahc->msgout_buf[index + 1]; if (full) { if (ahc->msgout_index > end_index) found = TRUE; } else if (ahc->msgout_index > index) found = TRUE; } break; } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_Q_TAG && ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) {   index += 2; } else {  index++; } } return (found); }  STATIC int ahc_parse_msg(ahc, sc_link, devinfo) struct ahc_softc *ahc; struct scsi_link *sc_link; struct ahc_devinfo *devinfo; { struct	ahc_initiator_tinfo *tinfo; struct	tmode_tstate *tstate;
ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo){	struct	ahc_initiator_tinfo *tinfo;	struct	ahc_tmode_tstate *tstate;	int	reject;	int	done;	int	response;	u_int	targ_scsirate;	done = MSGLOOP_IN_PROG;	response = FALSE;	reject = FALSE;	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,				    devinfo->target, &tstate);	targ_scsirate = tinfo->scsirate;	/*	 * Parse as much of the message as is availible,	 * rejecting it if we don't support it.  When	 * the entire message is availible and has been	 * handled, return MSGLOOP_MSGCOMPLETE, indicating	 * that we have parsed an entire message.	 *	 * In the case of extended messages, we accept the length	 * byte outright and perform more checking once we know the	 * extended message type.	 */	switch (ahc->msgin_buf[0]) {	case MSG_MESSAGE_REJECT:		response = ahc_handle_msg_reject(ahc, devinfo);		/* FALLTHROUGH */	case MSG_NOOP:		done = MSGLOOP_MSGCOMPLETE;		break;	case MSG_EXTENDED:	{		/* Wait for enough of the message to begin validation */		if (ahc->msgin_index < 2)			break;		switch (ahc->msgin_buf[2]) {		case MSG_EXT_SDTR:		{			struct	 ahc_syncrate *syncrate;			u_int	 period;			u_int	 ppr_options;			u_int	 offset;			u_int	 saved_offset;						if (ahc->msgin_buf[1] != MSG_EXT_SDTR_LEN) {				reject = TRUE;				break;			}			/*			 * Wait until we have both args before validating			 * and acting on this message.			 *			 * Add one to MSG_EXT_SDTR_LEN to account for			 * the extended message preamble.			 */			if (ahc->msgin_index < (MSG_EXT_SDTR_LEN + 1))				break;			period = ahc->msgin_buf[3];			ppr_options = 0;			saved_offset = offset = ahc->msgin_buf[4];			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"				       "Filtered to period %x, offset %x\n",				       ahc_name(ahc), devinfo->channel,				       devinfo->target, devinfo->lun,				       ahc->msgin_buf[3], saved_offset,				       period, offset);			}			ahc_set_syncrate(ahc, devinfo, 					 syncrate, period,					 offset, ppr_options,					 AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,					 /*paused*/TRUE);			/*			 * See if we initiated Sync Negotiation			 * and didn't have to fall down to async			 * transfers.			 */			if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, TRUE)) {				/* We started it */				if (saved_offset != offset) {					/* Went too low - force async */					reject = TRUE;				}			} else {				/*				 * Send our own SDTR in reply				 */				if (bootverbose				 && devinfo->role == ROLE_INITIATOR) {					printf("(%s:%c:%d:%d): Target "					       "Initiated SDTR\n",					       ahc_name(ahc), devinfo->channel,					       devinfo->target, devinfo->lun);				}				ahc->msgout_index = 0;				ahc->msgout_len = 0;				ahc_construct_sdtr(ahc, devinfo,						   period, offset);				ahc->msgout_index = 0;				response = TRUE;			}			done = MSGLOOP_MSGCOMPLETE;			break;		}		case MSG_EXT_WDTR:		{			u_int bus_width;			u_int saved_width;			u_int sending_reply;			sending_reply = FALSE;			if (ahc->msgin_buf[1] != MSG_EXT_WDTR_LEN) {				reject = TRUE;				break;			}			/*			 * Wait until we have our arg before validating			 * and acting on this message.			 *			 * Add one to MSG_EXT_WDTR_LEN to account for			 * the extended message preamble.			 */			if (ahc->msgin_index < (MSG_EXT_WDTR_LEN + 1))				break;			bus_width = ahc->msgin_buf[3];			saved_width = 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",				       ahc_name(ahc), devinfo->channel,				       devinfo->target, devinfo->lun,				       saved_width, bus_width);			}			if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, TRUE)) {				/*				 * Don't send a WDTR back to the				 * target, since we asked first.				 * If the width went higher than our				 * request, reject it.				 */				if (saved_width > bus_width) {					reject = TRUE;					printf("(%s:%c:%d:%d): requested %dBit "					       "transfers.  Rejecting...\n",					       ahc_name(ahc), devinfo->channel,					       devinfo->target, devinfo->lun,					       8 * (0x01 << bus_width));					bus_width = 0;				}			} else {				/*				 * Send our own WDTR in reply				 */				if (bootverbose				 && devinfo->role == ROLE_INITIATOR) {					printf("(%s:%c:%d:%d): Target "					       "Initiated WDTR\n",					       ahc_name(ahc), devinfo->channel,					       devinfo->target, devinfo->lun);				}				ahc->msgout_index = 0;				ahc->msgout_len = 0;				ahc_construct_wdtr(ahc, devinfo, bus_width);				ahc->msgout_index = 0;				response = TRUE;				sending_reply = TRUE;			}			ahc_set_width(ahc, devinfo, bus_width,				      AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,				      /*paused*/TRUE);			/* After a wide message, we are async */			ahc_set_syncrate(ahc, devinfo,					 /*syncrate*/NULL, /*period*/0,					 /*offset*/0, /*ppr_options*/0,					 AHC_TRANS_ACTIVE, /*paused*/TRUE);			if (sending_reply == FALSE && reject == FALSE) {				if (tinfo->goal.period) {					ahc->msgout_index = 0;					ahc->msgout_len = 0;					ahc_build_transfer_msg(ahc, devinfo);					ahc->msgout_index = 0;					response = TRUE;				}			}			done = MSGLOOP_MSGCOMPLETE;			break;		}		case MSG_EXT_PPR:		{			struct	ahc_syncrate *syncrate;			u_int	period;			u_int	offset;			u_int	bus_width;			u_int	ppr_options;			u_int	saved_width;			u_int	saved_offset;			u_int	saved_ppr_options;			if (ahc->msgin_buf[1] != MSG_EXT_PPR_LEN) {				reject = TRUE;				break;			}			/*			 * Wait until we have all args before validating			 * and acting on this message.			 *			 * Add one to MSG_EXT_PPR_LEN to account for			 * the extended message preamble.			 */			if (ahc->msgin_index < (MSG_EXT_PPR_LEN + 1))				break;			period = ahc->msgin_buf[3];			offset = ahc->msgin_buf[5];			bus_width = ahc->msgin_buf[6];			saved_width = bus_width;			ppr_options = ahc->msgin_buf[7];			/*			 * According to the spec, a DT only			 * period factor with no DT option			 * set implies async.			 */			if ((ppr_options & MSG_EXT_PPR_DT_REQ) == 0			 && period == 9)				offset = 0;			saved_ppr_options = ppr_options;			saved_offset = offset;			/*			 * Mask out any options we don't support			 * on any controller.  Transfer options are			 * only available if we are negotiating wide.			 */			ppr_options &= MSG_EXT_PPR_DT_REQ;			if (bus_width == 0)				ppr_options = 0;			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, AHCMSG_EXT, MSG_EXT_PPR, TRUE)) {				/*				 * If we are unable to do any of the				 * requested options (we went too low),				 * then we'll have to reject the message.				 */				if (saved_width > bus_width				 || saved_offset != offset				 || saved_ppr_options != ppr_options) {					reject = TRUE;					period = 0;					offset = 0;					bus_width = 0;					ppr_options = 0;					syncrate = NULL;				}			} else {				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) {				printf("(%s:%c:%d:%d): Received PPR width %x, "				       "period %x, offset %x,options %x\n"				       "\tFiltered to width %x, period %x, "				       "offset %x, options %x\n",				       ahc_name(ahc), devinfo->channel,				       devinfo->target, devinfo->lun,				       saved_width, ahc->msgin_buf[3],				       saved_offset, saved_ppr_options,				       bus_width, period, offset, ppr_options);			}			ahc_set_width(ahc, devinfo, bus_width,				      AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,				      /*paused*/TRUE);			ahc_set_syncrate(ahc, devinfo,					 syncrate, period,					 offset, ppr_options,					 AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,					 /*paused*/TRUE);			done = MSGLOOP_MSGCOMPLETE;			break;		}		default:			/* Unknown extended message.  Reject it. */			reject = TRUE;			break;		}		break;	}	case MSG_BUS_DEV_RESET:		ahc_handle_devreset(ahc, devinfo,				    CAM_BDR_SENT,				    "Bus Device Reset Received",				    /*verbose_level*/0);		ahc_restart(ahc);		done = MSGLOOP_TERMINATED;		break;	case MSG_ABORT_TAG:	case MSG_ABORT:	case MSG_CLEAR_QUEUE:#ifdef AHC_TARGET_MODE		/* Target mode messages */		if (devinfo->role != ROLE_TARGET) {			reject = TRUE;			break;		}		ahc_abort_scbs(ahc, devinfo->target, devinfo->channel,			       devinfo->lun,			       ahc->msgin_buf[0] == MSG_ABORT_TAG						  ? SCB_LIST_NULL						  : ahc_inb(ahc, INITIATOR_TAG),			       ROLE_TARGET, CAM_REQ_ABORTED);		tstate = ahc->enabled_targets[devinfo->our_scsiid];		if (tstate != NULL) {			struct ahc_tmode_lstate* lstate;			lstate = tstate->enabled_luns[devinfo->lun];			if (lstate != NULL) {				ahc_queue_lstate_event(ahc, lstate,						       devinfo->our_scsiid,						       ahc->msgin_buf[0],						       /*arg*/0);				ahc_send_lstate_events(ahc, lstate);			}		}		done = MSGLOOP_MSGCOMPLETE;		break;#endif	case MSG_TERM_IO_PROC:	default:		reject = TRUE;		break;	}	if (reject) {		/*		 * Setup to reject the message.		 */		ahc->msgout_index = 0;		ahc->msgout_len = 1;		ahc->msgout_buf[0] = MSG_MESSAGE_REJECT;		done = MSGLOOP_MSGCOMPLETE;		response = TRUE;	}	if (done != MSGLOOP_IN_PROG && !response)		/* Clear the outgoing message buffer */		ahc->msgout_len = 0;	return (done);}