ahc_rem_scb_from_disc_list(struct ahc_softc *ahc, u_int prev, u_int scbptr)
STATIC u_int	ahc_rem_scb_from_disc_list __P((struct ahc_softc *ahc, u_int prev, u_int scbptr)); STATIC void	ahc_add_curscb_to_free_list __P((struct ahc_softc *ahc)); STATIC void	ahc_clear_intstat __P((struct ahc_softc *ahc)); STATIC void	ahc_reset_current_bus __P((struct ahc_softc *ahc)); STATIC struct ahc_syncrate * ahc_devlimited_syncrate __P((struct ahc_softc *ahc, u_int *period)); STATIC struct ahc_syncrate * ahc_find_syncrate __P((struct ahc_softc *ahc, u_int *period, u_int maxsync)); STATIC u_int ahc_find_period __P((struct ahc_softc *ahc, u_int scsirate, u_int maxsync)); STATIC void	ahc_validate_offset __P((struct ahc_softc *ahc, struct ahc_syncrate *syncrate, u_int *offset, int wide)); STATIC void	ahc_update_target_msg_request __P((struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct ahc_initiator_tinfo *tinfo, int force, int paused)); STATIC void	ahc_set_syncrate __P((struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct ahc_syncrate *syncrate, u_int period, u_int offset, u_int type, int paused, int done)); STATIC void	ahc_set_width __P((struct ahc_softc *ahc, struct ahc_devinfo *devinfo, u_int width, u_int type, int paused, int done)); STATIC void	ahc_set_tags __P((struct ahc_softc *ahc, struct ahc_devinfo *devinfo,int enable)); STATIC int      ahc_istagged_device __P((struct ahc_softc *ahc, struct scsi_xfer *xs, int nocmdcheck)); STATIC void     ahc_check_tags __P((struct ahc_softc *ahc, struct scsi_xfer *xs)); STATIC void	ahc_construct_sdtr __P((struct ahc_softc *ahc, u_int period, u_int offset)); STATIC void	ahc_construct_wdtr __P((struct ahc_softc *ahc, u_int bus_width));  STATIC void	ahc_calc_residual __P((struct scb *scb));  STATIC void	ahc_update_pending_syncrates __P((struct ahc_softc *ahc));  STATIC void	ahc_set_recoveryscb __P((struct ahc_softc *ahc, struct scb *scb)); STATIC void ahc_timeout __P((void *));  static __inline int  sequencer_paused __P((struct ahc_softc *ahc)); static __inline void pause_sequencer __P((struct ahc_softc *ahc)); static __inline void unpause_sequencer __P((struct ahc_softc *ahc)); STATIC void restart_sequencer __P((struct ahc_softc *ahc)); static __inline u_int ahc_index_busy_tcl __P((struct ahc_softc *ahc, u_int tcl, int unbusy));  static __inline void	ahc_busy_tcl __P((struct ahc_softc *ahc, struct scb *scb)); static __inline int	ahc_isbusy_tcl __P((struct ahc_softc *ahc, struct scb *scb)); static __inline void ahc_freeze_ccb __P((struct scb* scb)); static __inline void ahcsetccbstatus __P((struct scsi_xfer *xs, int status)); STATIC void ahc_run_qoutfifo __P((struct ahc_softc *ahc));  static __inline struct ahc_initiator_tinfo * ahc_fetch_transinfo __P((struct ahc_softc *ahc, char channel, u_int our_id, u_int target, struct tmode_tstate **tstate)); STATIC void ahcfreescb __P((struct ahc_softc *ahc, struct scb *scb)); static __inline struct scb *ahcgetscb __P((struct ahc_softc *ahc)); int    ahc_createdmamem __P((struct ahc_softc *ahc, int size, bus_dmamap_t *mapp, caddr_t *vaddr, bus_addr_t *baddr, bus_dma_segment_t *segs, int *nseg, const char *what)); STATIC void ahc_freedmamem __P((bus_dma_tag_t tag, int size, bus_dmamap_t map, caddr_t vaddr, bus_dma_segment_t *seg, int nseg)); STATIC void ahcminphys __P((struct buf *bp));  STATIC INLINE	struct scsi_xfer *ahc_first_xs __P((struct ahc_softc *)); STATIC INLINE	void   ahc_list_insert_before __P((struct ahc_softc *ahc, struct scsi_xfer *xs, struct scsi_xfer *next_xs)); STATIC INLINE	void   ahc_list_insert_head __P((struct ahc_softc *ahc, struct scsi_xfer *xs)); STATIC INLINE	void   ahc_list_insert_tail __P((struct ahc_softc *ahc, struct scsi_xfer *xs)); STATIC INLINE	void   ahc_list_remove __P((struct ahc_softc *ahc, struct scsi_xfer *xs)); STATIC INLINE	struct scsi_xfer *ahc_list_next __P((struct ahc_softc *ahc, struct scsi_xfer *xs)); STATIC int32_t ahc_scsi_cmd __P((struct scsi_xfer *xs)); static __inline void ahc_swap_hscb __P((struct hardware_scb *)); static __inline void ahc_swap_sg __P((struct ahc_dma_seg *));  struct cfdriver ahc_cd = { NULL, "ahc", DV_DULL };  static struct scsi_adapter ahc_switch = { ahc_scsi_cmd, ahcminphys, 0, 0, };   static struct scsi_device ahc_dev = { NULL,  NULL,  NULL,  NULL,  };  static __inline void ahc_swap_hscb(struct hardware_scb *hscb) { hscb->SG_pointer = htole32(hscb->SG_pointer); hscb->data = htole32(hscb->data); hscb->datalen = htole32(hscb->datalen);  }  static __inline void ahc_swap_sg(struct ahc_dma_seg *sg) { sg->addr = htole32(sg->addr); sg->len = htole32(sg->len); }  STATIC void ahcminphys(bp) struct buf *bp; {  if (bp->b_bcount > ((AHC_NSEG - 1) * PAGE_SIZE)) { bp->b_bcount = ((AHC_NSEG - 1) * PAGE_SIZE); } minphys(bp); }   static __inline u_int32_t ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index) { return (ahc->scb_data->hscb_busaddr + (sizeof(struct hardware_scb) * index)); }  #define AHC_BUSRESET_DELAY	25	  static __inline int sequencer_paused(ahc) struct ahc_softc *ahc; { return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0); }  static __inline void pause_sequencer(ahc) struct ahc_softc *ahc; { ahc_outb(ahc, HCNTRL, ahc->pause);   while (sequencer_paused(ahc) == 0) ; }  static __inline void unpause_sequencer(ahc) struct ahc_softc *ahc; { if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0) ahc_outb(ahc, HCNTRL, ahc->unpause); }   STATIC void restart_sequencer(ahc) struct ahc_softc *ahc; { u_int i;  pause_sequencer(ahc);   ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL); for (i = 0; i < ahc->scb_data->maxhscbs; i++) {  ahc_outb(ahc, SCBPTR, i); if (ahc_inb(ahc, SCB_TAG) == SCB_LIST_NULL) ahc_add_curscb_to_free_list(ahc); } ahc_outb(ahc, SEQCTL, FASTMODE|SEQRESET); unpause_sequencer(ahc); }  static __inline u_int ahc_index_busy_tcl(ahc, tcl, unbusy) struct ahc_softc *ahc; u_int tcl; int unbusy; { u_int scbid;  scbid = ahc->untagged_scbs[tcl]; if (unbusy) { ahc->untagged_scbs[tcl] = SCB_LIST_NULL; bus_dmamap_sync(ahc->sc_dmat, ahc->shared_data_dmamap, UNTAGGEDSCB_OFFSET * 256, 256, BUS_DMASYNC_PREWRITE); }  return (scbid); }  static __inline void ahc_busy_tcl(ahc, scb) struct ahc_softc *ahc; struct scb *scb; { ahc->untagged_scbs[scb->hscb->tcl] = scb->hscb->tag; bus_dmamap_sync(ahc->sc_dmat, ahc->shared_data_dmamap, UNTAGGEDSCB_OFFSET * 256, 256, BUS_DMASYNC_PREWRITE); }  static __inline int ahc_isbusy_tcl(ahc, scb) struct ahc_softc *ahc; struct scb *scb; { return ahc->untagged_scbs[scb->hscb->tcl] != SCB_LIST_NULL; }  static __inline void ahc_freeze_ccb(scb) struct scb *scb; { struct scsi_xfer *xs = scb->xs; struct ahc_softc *ahc = (struct ahc_softc *)xs->sc_link->adapter_softc; int target;  target = xs->sc_link->target; if (!(scb->flags & SCB_FREEZE_QUEUE)) { ahc->devqueue_blocked[target]++; scb->flags |= SCB_FREEZE_QUEUE; } }  static __inline void ahcsetccbstatus(xs, status) struct scsi_xfer *xs; int status; { xs->error = status; }  static __inline struct ahc_initiator_tinfo * ahc_fetch_transinfo(ahc, channel, our_id, remote_id, tstate) struct ahc_softc *ahc; char channel; u_int our_id; u_int remote_id; struct tmode_tstate **tstate; {  if (channel == 'B') our_id += 8; *tstate = ahc->enabled_targets[our_id]; return (&(*tstate)->transinfo[remote_id]); }  STATIC void ahc_run_qoutfifo(ahc) struct ahc_softc *ahc; { struct scb *scb; u_int  scb_index;  bus_dmamap_sync(ahc->sc_dmat, ahc->shared_data_dmamap, 0, 256, BUS_DMASYNC_POSTREAD);  while (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL) { scb_index = ahc->qoutfifo[ahc->qoutfifonext]; ahc->qoutfifo[ahc->qoutfifonext++] = SCB_LIST_NULL;  scb = &ahc->scb_data->scbarray[scb_index]; if (scb_index >= ahc->scb_data->numscbs || (scb->flags & SCB_ACTIVE) == 0) { printf("%s: WARNING no command for scb %d " "(cmdcmplt)\nQOUTPOS = %d\n", ahc_name(ahc), scb_index, ahc->qoutfifonext - 1); continue; }   if (scb->hscb->residual_SG_count != 0) ahc_calc_residual(scb); else scb->xs->resid = 0; ahc_done(ahc, scb); } }    STATIC void ahcfreescb(ahc, scb) struct ahc_softc *ahc; struct scb *scb; { struct hardware_scb *hscb; int opri;  hscb = scb->hscb;  #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWSCBS) printf("%s: free SCB tag %x\n", ahc_name(ahc), hscb->tag); #endif  opri = splbio();  if ((ahc->flags & AHC_RESOURCE_SHORTAGE) != 0 || (scb->flags & SCB_RECOVERY_SCB) != 0) { ahc->flags &= ~AHC_RESOURCE_SHORTAGE; ahc->queue_blocked = 0; }   scb->flags = SCB_FREE; hscb->control = 0; hscb->status = 0; timeout_del(&scb->xs->stimeout);  SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links);  splx(opri); }   static __inline struct scb * ahcgetscb(ahc) struct ahc_softc *ahc; { struct scb *scbp; int opri;  opri = splbio(); if ((scbp = SLIST_FIRST(&ahc->scb_data->free_scbs))) { SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links); } else { ahcallocscbs(ahc); scbp = SLIST_FIRST(&ahc->scb_data->free_scbs); if (scbp != NULL) SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links); }  splx(opri);  return (scbp); }  int ahc_createdmamem(ahc, size, mapp, vaddr, baddr, seg, nseg, what) struct ahc_softc *ahc; int size; bus_dmamap_t *mapp; caddr_t *vaddr; bus_addr_t *baddr; bus_dma_segment_t *seg; int *nseg; const char *what; { int error, level = 0; int dma_flags = BUS_DMA_NOWAIT; bus_dma_tag_t tag = ahc->sc_dmat; const char *myname = ahc_name(ahc); if ((ahc->chip & AHC_VL) !=0) dma_flags |= ISABUS_DMA_32BIT;  if ((error = bus_dmamem_alloc(tag, size, NBPG, 0, seg, 1, nseg, BUS_DMA_NOWAIT)) != 0) { printf("%s: failed to allocate DMA mem for %s, error = %d\n", myname, what, error); goto out; } level++;  if ((error = bus_dmamem_map(tag, seg, *nseg, size, vaddr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) { printf("%s: failed to map DMA mem for %s, error = %d\n", myname, what, error); goto out; } level++;  if ((error = bus_dmamap_create(tag, size, 1, size, 0, dma_flags, mapp)) != 0) { printf("%s: failed to create DMA map for %s, error = %d\n", myname, what, error); goto out; } level++;  if ((error = bus_dmamap_load(tag, *mapp, *vaddr, size, NULL, BUS_DMA_NOWAIT)) != 0) { printf("%s: failed to load DMA map for %s, error = %d\n", myname, what, error); goto out; }  *baddr = (*mapp)->dm_segs[0].ds_addr; return 0; out: switch (level) { case 3: bus_dmamap_destroy(tag, *mapp);  case 2: bus_dmamem_unmap(tag, *vaddr, size);  case 1: bus_dmamem_free(tag, seg, *nseg); break; default: break; }  return error; }  STATIC void ahc_freedmamem(tag, size, map, vaddr, seg, nseg) bus_dma_tag_t tag; int size; bus_dmamap_t map; caddr_t vaddr; bus_dma_segment_t *seg; int nseg; {  bus_dmamap_unload(tag, map); bus_dmamap_destroy(tag, map); bus_dmamem_unmap(tag, vaddr, size); bus_dmamem_free(tag, seg, nseg); }  #ifdef  AHC_DEBUG STATIC void ahc_print_scb(scb) struct scb *scb; { struct hardware_scb *hscb = scb->hscb;  printf("scb:%p tag %x control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n", scb, hscb->tag, hscb->control, hscb->tcl, hscb->cmdlen, (unsigned long)le32toh(hscb->cmdpointer)); printf("        datlen:%u data:0x%lx segs:0x%x segp:0x%lx\n", le32toh(hscb->datalen), (unsigned long)(le32toh(hscb->data)), hscb->SG_count, (unsigned long)(le32toh(hscb->SG_pointer))); printf("	sg_addr:%lx sg_len:%lu\n", (unsigned long)(le32toh(scb->sg_list[0].addr)), (unsigned long)(le32toh(scb->sg_list[0].len))); printf("	cdb:%x %x %x %x %x %x %x %x %x %x %x %x\n", hscb->cmdstore[0], hscb->cmdstore[1], hscb->cmdstore[2], hscb->cmdstore[3], hscb->cmdstore[4], hscb->cmdstore[5], hscb->cmdstore[6], hscb->cmdstore[7], hscb->cmdstore[8], hscb->cmdstore[9], hscb->cmdstore[10], hscb->cmdstore[11]); } #endif  static struct { u_int8_t errno; char *errmesg; } hard_error[] = { { ILLHADDR,	"Illegal Host Access" }, { ILLSADDR,	"Illegal Sequencer Address referrenced" }, { ILLOPCODE,	"Illegal Opcode in sequencer program" }, { SQPARERR,	"Sequencer Parity Error" }, { DPARERR,	"Data-path Parity Error" }, { MPARERR,	"Scratch or SCB Memory Parity Error" }, { PCIERRSTAT,	"PCI Error detected" }, { CIOPARERR,	"CIOBUS Parity Error" }, }; static const int num_errors = sizeof(hard_error)/sizeof(hard_error[0]);  static struct { u_int8_t phase; u_int8_t mesg_out;  char *phasemsg; } phase_table[] = { { P_DATAOUT,	MSG_NOOP,		"in Data-out phase"	}, { P_DATAIN,	MSG_INITIATOR_DET_ERR,	"in Data-in phase"	}, { P_COMMAND,	MSG_NOOP,		"in Command phase"	}, { P_MESGOUT,	MSG_NOOP,		"in Message-out phase"	}, { P_STATUS,	MSG_INITIATOR_DET_ERR,	"in Status phase"	}, { P_MESGIN,	MSG_PARITY_ERROR,	"in Message-in phase"	}, { P_BUSFREE,	MSG_NOOP,		"while idle"		}, { 0,		MSG_NOOP,		"in unknown phase"	} }; static const int num_phases = (sizeof(phase_table)/sizeof(phase_table[0])) - 1;   #define AHC_SYNCRATE_DT		0 #define AHC_SYNCRATE_ULTRA2	1 #define AHC_SYNCRATE_ULTRA	3 #define AHC_SYNCRATE_FAST	6 static struct ahc_syncrate ahc_syncrates[] = {  { 0x42,      0x000,      9,      "80.0" }, { 0x03,      0x000,     10,      "40.0" }, { 0x04,      0x000,     11,      "33.0" }, { 0x05,      0x100,     12,      "20.0" }, { 0x06,      0x110,     15,      "16.0" }, { 0x07,      0x120,     18,      "13.4" }, { 0x08,      0x000,     25,      "10.0" }, { 0x19,      0x010,     31,      "8.0"  }, { 0x1a,      0x020,     37,      "6.67" }, { 0x1b,      0x030,     43,      "5.7"  }, { 0x1c,      0x040,     50,      "5.0"  }, { 0x00,      0x050,     56,      "4.4"  }, { 0x00,      0x060,     62,      "4.0"  }, { 0x00,      0x070,     68,      "3.6"  }, { 0x00,      0x000,      0,      NULL   } };   void ahc_construct(ahc, iot, ioh, chip, flags, features, channel) struct  ahc_softc *ahc; bus_space_tag_t iot; bus_space_handle_t ioh; ahc_chip chip; ahc_flag flags; ahc_feature features; u_char channel; {  LIST_INIT(&ahc->pending_scbs); ahc->sc_iot = iot; ahc->sc_ioh = ioh; ahc->chip = chip; ahc->flags = flags; ahc->features = features; ahc->channel = channel; ahc->scb_data = NULL; ahc->pci_intr_func = NULL;  ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN;  if ((ahc->chip & AHC_PCI) != 0) ahc->unpause &= ~IRQMS; ahc->pause = ahc->unpause | PAUSE; }  void ahc_free(ahc) struct ahc_softc *ahc; { ahcfiniscbdata(ahc); if (ahc->init_level != 0) ahc_freedmamem(ahc->sc_dmat, ahc->shared_data_size, ahc->shared_data_dmamap, ahc->qoutfifo, &ahc->shared_data_seg, ahc->shared_data_nseg);  if (ahc->scb_data != NULL) free(ahc->scb_data, M_DEVBUF); if (ahc->pci_data != NULL) free(ahc->pci_data, M_DEVBUF); return; }  STATIC int ahcinitscbdata(ahc) struct ahc_softc *ahc; { struct scb_data *scb_data; int i;  scb_data = ahc->scb_data; SLIST_INIT(&scb_data->free_scbs); SLIST_INIT(&scb_data->sg_maps);   scb_data->scbarray = (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX, M_DEVBUF, M_NOWAIT); if (scb_data->scbarray == NULL) return (ENOMEM); bzero(scb_data->scbarray, sizeof(struct scb) * AHC_SCB_MAX);    scb_data->maxhscbs = ahc_probe_scbs(ahc);  ahc_outb(ahc, FREE_SCBH, 0); for (i = 0; i < ahc->scb_data->maxhscbs; i++) { ahc_outb(ahc, SCBPTR, i);   ahc_outb(ahc, SCB_CONTROL, 0);   ahc_outb(ahc, SCB_NEXT, i+1);   ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); }   ahc_outb(ahc, SCBPTR, i-1); ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL);   ahc_outb(ahc, SCBPTR, 0); ahc_outb(ahc, SCB_CONTROL, 0);  scb_data->maxhscbs = i;  if (ahc->scb_data->maxhscbs == 0) panic("%s: No SCB space found", ahc_name(ahc));    if (ahc_createdmamem(ahc, AHC_SCB_MAX * sizeof(struct hardware_scb), &scb_data->hscb_dmamap, (caddr_t *)&scb_data->hscbs, &scb_data->hscb_busaddr, &scb_data->hscb_seg, &scb_data->hscb_nseg, "hardware SCB structures") < 0) goto error_exit;  scb_data->init_level++;  if (ahc_createdmamem(ahc, AHC_SCB_MAX * sizeof(struct scsi_sense_data), &scb_data->sense_dmamap, (caddr_t *)&scb_data->sense, &scb_data->sense_busaddr, &scb_data->sense_seg, &scb_data->sense_nseg, "sense buffers") < 0) goto error_exit;  scb_data->init_level++;   bzero(scb_data->hscbs, AHC_SCB_MAX * sizeof(struct hardware_scb)); ahcallocscbs(ahc);  if (scb_data->numscbs == 0) { printf("%s: ahc_init_scb_data - " "Unable to allocate initial scbs\n", ahc_name(ahc)); goto error_exit; }  scb_data->init_level++;   return 0;  error_exit:  return ENOMEM; }  STATIC void ahcfiniscbdata(ahc) struct ahc_softc *ahc; { struct scb_data *scb_data;  scb_data = ahc->scb_data;  switch (scb_data->init_level) { default: case 3: { struct sg_map_node *sg_map;  while ((sg_map = SLIST_FIRST(&scb_data->sg_maps))!= NULL) { SLIST_REMOVE_HEAD(&scb_data->sg_maps, links); ahc_freedmamem(ahc->sc_dmat, PAGE_SIZE, sg_map->sg_dmamap, (caddr_t)sg_map->sg_vaddr, &sg_map->sg_dmasegs, sg_map->sg_nseg); free(sg_map, M_DEVBUF); } }  case 2: ahc_freedmamem(ahc->sc_dmat, AHC_SCB_MAX * sizeof(struct scsi_sense_data), scb_data->sense_dmamap, (caddr_t)scb_data->sense, &scb_data->sense_seg, scb_data->sense_nseg);  case 1: ahc_freedmamem(ahc->sc_dmat, AHC_SCB_MAX * sizeof(struct hardware_scb), scb_data->hscb_dmamap, (caddr_t)scb_data->hscbs, &scb_data->hscb_seg, scb_data->hscb_nseg);  } if (scb_data->scbarray != NULL) free(scb_data->scbarray, M_DEVBUF); }  void ahc_xxx_reset(devname, iot, ioh) char *devname; bus_space_tag_t iot; bus_space_handle_t ioh; { u_char hcntrl; int wait;  #ifdef AHC_DUMP_SEQ ahc_dumpseq(ahc); #endif  hcntrl = (bus_space_read_1(iot, ioh, HCNTRL) & IRQMS) | INTEN;  bus_space_write_1(iot, ioh, HCNTRL, CHIPRST | PAUSE);  wait = 1000; while (--wait && !(bus_space_read_1(iot, ioh, HCNTRL) & CHIPRSTACK)) DELAY(1000); if (wait == 0) { printf("%s: WARNING - Failed chip reset!  " "Trying to initialize anyway.\n", devname); } bus_space_write_1(iot, ioh, HCNTRL, hcntrl | PAUSE); }  int ahc_reset(ahc) struct ahc_softc *ahc; { u_int	sblkctl; int	wait;  #ifdef AHC_DUMP_SEQ if (ahc->init_level == 0) ahc_dumpseq(ahc); #endif ahc_outb(ahc, HCNTRL, CHIPRST | ahc->pause);  wait = 1000; do { DELAY(1000); } while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK));  if (wait == 0) { printf("%s: WARNING - Failed chip reset!  " "Trying to initialize anyway.\n", ahc_name(ahc)); } ahc_outb(ahc, HCNTRL, ahc->pause);   sblkctl = ahc_inb(ahc, SBLKCTL) & (SELBUSB|SELWIDE);  if ((ahc->chip & AHC_PCI) != 0) sblkctl &= ~SELBUSB; switch (sblkctl) { case 0:  break; case 2:  ahc->features |= AHC_WIDE; break; case 8:  ahc->features |= AHC_TWIN; break; default: printf(" Unsupported adapter type.  Ignoring\n"); return(-1); } return (0); }   STATIC struct ahc_syncrate * ahc_devlimited_syncrate(ahc, period) struct ahc_softc *ahc; u_int *period; { u_int	maxsync;  if ((ahc->features & AHC_ULTRA2) != 0) { if ((ahc_inb(ahc, SBLKCTL) & ENAB40) != 0 && (ahc_inb(ahc, SSTAT2) & EXP_ACTIVE) == 0) { maxsync = AHC_SYNCRATE_ULTRA2; } else { maxsync = AHC_SYNCRATE_ULTRA; } } else if ((ahc->features & AHC_ULTRA) != 0) { maxsync = AHC_SYNCRATE_ULTRA; } else { maxsync = AHC_SYNCRATE_FAST; } return (ahc_find_syncrate(ahc, period, maxsync)); }   STATIC struct ahc_syncrate * ahc_find_syncrate(ahc, period, maxsync) struct ahc_softc *ahc; u_int *period; u_int maxsync; { struct ahc_syncrate *syncrate;  syncrate = &ahc_syncrates[maxsync]; while ((syncrate->rate != NULL) && ((ahc->features & AHC_ULTRA2) == 0 || (syncrate->sxfr_u2 != 0))) {  if (*period <= syncrate->period) {  if (syncrate == &ahc_syncrates[maxsync]) *period = syncrate->period; break; } syncrate++; }  if ((*period == 0) || (syncrate->rate == NULL) || ((ahc->features & AHC_ULTRA2) != 0 && (syncrate->sxfr_u2 == 0))) {  *period = 0; syncrate = NULL; } return (syncrate); }  STATIC u_int ahc_find_period(ahc, scsirate, maxsync) struct ahc_softc *ahc; u_int scsirate; u_int maxsync; { struct ahc_syncrate *syncrate;  if ((ahc->features & AHC_ULTRA2) != 0) scsirate &= SXFR_ULTRA2; else scsirate &= SXFR;  syncrate = &ahc_syncrates[maxsync]; while (syncrate->rate != NULL) {  if ((ahc->features & AHC_ULTRA2) != 0) { if (syncrate->sxfr_u2 == 0) break; else if (scsirate == (syncrate->sxfr_u2 & SXFR_ULTRA2)) return (syncrate->period); } else if (scsirate == (syncrate->sxfr & SXFR)) { return (syncrate->period); } syncrate++; } return (0);  }  STATIC void ahc_validate_offset(ahc, syncrate, offset, wide) struct ahc_softc *ahc; struct ahc_syncrate *syncrate; u_int *offset; int wide; { u_int maxoffset;   if (syncrate == NULL) { maxoffset = 0; } else if ((ahc->features & AHC_ULTRA2) != 0) { maxoffset = MAX_OFFSET_ULTRA2; } else { if (wide) maxoffset = MAX_OFFSET_16BIT; else maxoffset = MAX_OFFSET_8BIT; } *offset = MIN(*offset, maxoffset); }  STATIC void ahc_update_target_msg_request(ahc, devinfo, tinfo, force, paused) struct ahc_softc *ahc; struct ahc_devinfo *devinfo; struct ahc_initiator_tinfo *tinfo; int force; int paused; { u_int targ_msg_req_orig;  targ_msg_req_orig = ahc->targ_msg_req; if (tinfo->current.period != tinfo->goal.period || tinfo->current.width != tinfo->goal.width || tinfo->current.offset != tinfo->goal.offset || (force && (tinfo->goal.period != 0 || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT))) ahc->targ_msg_req |= devinfo->target_mask; else ahc->targ_msg_req &= ~devinfo->target_mask;  if (ahc->targ_msg_req != targ_msg_req_orig) {  if ((ahc->features & AHC_HS_MAILBOX) != 0) { if (paused) { ahc_outb(ahc, TARGET_MSG_REQUEST, ahc->targ_msg_req & 0xFF); ahc_outb(ahc, TARGET_MSG_REQUEST + 1, (ahc->targ_msg_req >> 8) & 0xFF); } else { ahc_outb(ahc, HS_MAILBOX, 0x01 << HOST_MAILBOX_SHIFT); } } else { if (!paused) pause_sequencer(ahc);  ahc_outb(ahc, TARGET_MSG_REQUEST, ahc->targ_msg_req & 0xFF); ahc_outb(ahc, TARGET_MSG_REQUEST + 1, (ahc->targ_msg_req >> 8) & 0xFF);  if (!paused) unpause_sequencer(ahc); } } }  STATIC void ahc_set_syncrate(ahc, devinfo, syncrate, period, offset, type, paused, done) struct ahc_softc *ahc; struct ahc_devinfo *devinfo; struct ahc_syncrate *syncrate; u_int period; u_int offset; u_int type; int paused; int done; { struct	ahc_initiator_tinfo *tinfo; 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; 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;   switch (ahc->msgin_buf[0]) { case MSG_MESSAGE_REJECT: response = ahc_handle_msg_reject(ahc, devinfo);  case MSG_NOOP: done = MSGLOOP_MSGCOMPLETE; break; case MSG_IGN_WIDE_RESIDUE: {  if (ahc->msgin_index >= 1) { if (ahc->msgin_buf[1] != 1 || tinfo->current.width == MSG_EXT_WDTR_BUS_8_BIT) { reject = TRUE; done = MSGLOOP_MSGCOMPLETE; } else ahc_handle_ign_wide_residue(ahc, devinfo); } break; } case MSG_EXTENDED: {  if (ahc->msgin_index < 2) break; switch (ahc->msgin_buf[2]) { case MSG_EXT_SDTR: { struct	 ahc_syncrate *syncrate; u_int	 period; u_int	 offset; u_int	 saved_offset;  if (ahc->msgin_buf[1] != MSG_EXT_SDTR_LEN) { reject = TRUE; break; }   if (ahc->msgin_index < (MSG_EXT_SDTR_LEN + 1)) break;  period = ahc->msgin_buf[3]; saved_offset = offset = ahc->msgin_buf[4]; syncrate = ahc_devlimited_syncrate(ahc, &period); ahc_validate_offset(ahc, syncrate, &offset, targ_scsirate & WIDEXFER); ahc_set_syncrate(ahc, devinfo, syncrate, period, offset, AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, TRUE, TRUE);   if (ahc_sent_msg(ahc, MSG_EXT_SDTR, TRUE)) {  if (saved_offset != offset) {  reject = TRUE; } } else {  if (bootverbose) printf("Sending SDTR!\n"); ahc->msgout_index = 0; ahc->msgout_len = 0; ahc_construct_sdtr(ahc, period, offset); ahc->msgout_index = 0; response = TRUE; } done = MSGLOOP_MSGCOMPLETE; break; } case MSG_EXT_WDTR: { u_int	bus_width; u_int	sending_reply;  sending_reply = FALSE; if (ahc->msgin_buf[1] != MSG_EXT_WDTR_LEN) { reject = TRUE; break; }   if (ahc->msgin_index < (MSG_EXT_WDTR_LEN + 1)) break;  bus_width = ahc->msgin_buf[3]; if (ahc_sent_msg(ahc, MSG_EXT_WDTR, TRUE)) {  switch (bus_width){ default:  reject = TRUE; printf("%s: target %d requested %dBit " "transfers.  Rejecting...\n", ahc_name(ahc), devinfo->target, 8 * (0x01 << bus_width));  case MSG_EXT_WDTR_BUS_8_BIT: bus_width = MSG_EXT_WDTR_BUS_8_BIT; break; case MSG_EXT_WDTR_BUS_16_BIT: break; } } else {  if (bootverbose) printf("Sending WDTR!\n"); switch (bus_width) { default: if (ahc->features & AHC_WIDE) {  bus_width = MSG_EXT_WDTR_BUS_16_BIT; break; }  case MSG_EXT_WDTR_BUS_8_BIT: bus_width = MSG_EXT_WDTR_BUS_8_BIT; break; } ahc->msgout_index = 0; ahc->msgout_len = 0; ahc_construct_wdtr(ahc, bus_width); ahc->msgout_index = 0; response = TRUE; sending_reply = TRUE; } ahc_set_width(ahc, devinfo, bus_width, AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, TRUE, TRUE);   ahc_set_syncrate(ahc, devinfo, NULL, 0, 0, AHC_TRANS_ACTIVE, TRUE, FALSE); if (sending_reply == FALSE && reject == FALSE) {  if (tinfo->goal.period) { 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->msgout_index = 0; ahc->msgout_len = 0; ahc_construct_sdtr(ahc, period, offset); ahc->msgout_index = 0; response = TRUE; } } done = MSGLOOP_MSGCOMPLETE; break; } default:  reject = TRUE; break; } break; } case MSG_BUS_DEV_RESET: ahc_handle_devreset(ahc, devinfo, XS_RESET, "Bus Device Reset Received", 0); restart_sequencer(ahc); done = MSGLOOP_TERMINATED; break; case MSG_ABORT_TAG: case MSG_ABORT: case MSG_CLEAR_QUEUE:  if (devinfo->role != ROLE_TARGET) { reject = TRUE; break; } #if AHC_TARGET_MODE 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, XS_DRIVER_STUFFUP);  tstate = ahc->enabled_targets[devinfo->our_scsiid]; if (tstate != NULL) { struct 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], 0); ahc_send_lstate_events(ahc, lstate); } } done = MSGLOOP_MSGCOMPLETE; #else panic("ahc: got target mode message"); #endif break; case MSG_TERM_IO_PROC: default: reject = TRUE; break; }  if (reject) {  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)  ahc->msgout_len = 0;  return (done); }  STATIC void ahc_handle_ign_wide_residue(ahc, devinfo) struct ahc_softc *ahc; struct ahc_devinfo *devinfo; { u_int scb_index; struct scb *scb;  scb_index = ahc_inb(ahc, SCB_TAG); scb = &ahc->scb_data->scbarray[scb_index]; if ((ahc_inb(ahc, SEQ_FLAGS) & DPHASE) == 0 || !(scb->xs->flags & SCSI_DATA_IN)) {  } else {  u_int resid_sgcnt;  resid_sgcnt = ahc_inb(ahc, SCB_RESID_SGCNT); if (resid_sgcnt == 0 && ahc_inb(ahc, DATA_COUNT_ODD) == 1) {  } else { u_int data_cnt; u_int data_addr; u_int sg_index;  data_cnt = (ahc_inb(ahc, SCB_RESID_DCNT + 2) << 16) | (ahc_inb(ahc, SCB_RESID_DCNT + 1) << 8) | (ahc_inb(ahc, SCB_RESID_DCNT));  data_addr = (ahc_inb(ahc, SHADDR + 3) << 24) | (ahc_inb(ahc, SHADDR + 2) << 16) | (ahc_inb(ahc, SHADDR + 1) << 8) | (ahc_inb(ahc, SHADDR));  data_cnt += 1; data_addr -= 1;  sg_index = scb->sg_count - resid_sgcnt;  if (sg_index != 0 && (le32toh(scb->sg_list[sg_index].len) < data_cnt)) { u_int32_t sg_addr;  sg_index--; data_cnt = 1; data_addr = le32toh(scb->sg_list[sg_index].addr) + le32toh(scb->sg_list[sg_index].len) - 1;   sg_addr = scb->sg_list_phys + (sg_index* sizeof(*scb->sg_list)); ahc_outb(ahc, SG_NEXT + 3, sg_addr >> 24); ahc_outb(ahc, SG_NEXT + 2, sg_addr >> 16); ahc_outb(ahc, SG_NEXT + 1, sg_addr >> 8); ahc_outb(ahc, SG_NEXT, sg_addr); }  ahc_outb(ahc, SCB_RESID_DCNT + 2, data_cnt >> 16); ahc_outb(ahc, SCB_RESID_DCNT + 1, data_cnt >> 8); ahc_outb(ahc, SCB_RESID_DCNT, data_cnt);  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); } } }  STATIC void ahc_handle_devreset(ahc, devinfo, status, message, verbose_level) struct ahc_softc *ahc; struct ahc_devinfo *devinfo; int status; char *message; int verbose_level; { int found;  found = ahc_abort_scbs(ahc, devinfo->target, devinfo->channel, ALL_LUNS, SCB_LIST_NULL, devinfo->role, status);   ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT, AHC_TRANS_CUR, TRUE, FALSE); ahc_set_syncrate(ahc, devinfo, NULL, 0, 0, AHC_TRANS_CUR, TRUE, FALSE);  if (message != NULL && (verbose_level <= bootverbose)) printf("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc), message, devinfo->channel, devinfo->target, found); }   STATIC void ahc_done(ahc, scb) struct ahc_softc *ahc; struct scb *scb; { struct scsi_xfer *xs = scb->xs; struct scsi_link *sc_link = xs->sc_link; int requeue = 0; int target;  SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_done\n"));  LIST_REMOVE(scb, pend_links);  timeout_del(&scb->xs->stimeout);  #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWCMDS) { sc_print_addr(sc_link); printf("ahc_done opcode %d tag %x\n", xs->cmdstore.opcode, scb->hscb->tag); } #endif  target = sc_link->target;  if (xs->datalen) { int op;  if ((xs->flags & SCSI_DATA_IN) != 0) op = BUS_DMASYNC_POSTREAD; else op = BUS_DMASYNC_POSTWRITE; bus_dmamap_sync(ahc->sc_dmat, scb->dmamap, 0, scb->dmamap->dm_mapsize, op); bus_dmamap_unload(ahc->sc_dmat, scb->dmamap); }   if (!(scb->hscb->control & TAG_ENB)) ahc_index_busy_tcl(ahc, scb->hscb->tcl, TRUE);   if ((scb->flags & SCB_RECOVERY_SCB) != 0) {  struct	scb *scbp;   scbp = ahc->pending_scbs.lh_first; while (scbp != NULL) { struct scsi_xfer *txs = scbp->xs;  if (!(txs->flags & SCSI_POLL)) timeout_add(&scbp->xs->stimeout, (scbp->xs->timeout * hz)/1000); scbp = LIST_NEXT(scbp, pend_links); }   ahc_search_qinfifo(ahc, SCB_TARGET(scb), SCB_CHANNEL(scb), SCB_LUN(scb), scb->hscb->tag, ROLE_INITIATOR, 0, SEARCH_REMOVE); if (xs->error != XS_NOERROR) ahcsetccbstatus(xs, XS_TIMEOUT); sc_print_addr(xs->sc_link); printf("no longer in timeout, status = %x\n", xs->status); }  if (xs->error != XS_NOERROR) {  } else if ((scb->flags & SCB_SENSE) != 0) {  bzero(&xs->sense, sizeof(struct scsi_sense)); bcopy(&ahc->scb_data->sense[scb->hscb->tag], &xs->sense, le32toh(scb->sg_list->len)); xs->error = XS_SENSE; } if (scb->flags & SCB_FREEZE_QUEUE) { ahc->devqueue_blocked[target]--; scb->flags &= ~SCB_FREEZE_QUEUE; }  requeue = scb->flags & SCB_REQUEUE; ahcfreescb(ahc, scb);  if (requeue) {  int s;  s = splbio();  ahc_list_insert_head(ahc, xs); splx(s); } else { xs->flags |= ITSDONE; ahc_check_tags(ahc, xs); scsi_done(xs); }   if ((xs = ahc->sc_xxxq.lh_first) != NULL) (void) ahc_scsi_cmd(xs); }   int ahc_probe_scbs(ahc) struct ahc_softc *ahc; { int i;  for (i = 0; i < AHC_SCB_MAX; i++) { ahc_outb(ahc, SCBPTR, i); ahc_outb(ahc, SCB_CONTROL, i); if (ahc_inb(ahc, SCB_CONTROL) != i) break; ahc_outb(ahc, SCBPTR, 0); if (ahc_inb(ahc, SCB_CONTROL) != 0) break; }  return (i); }   int ahc_init(ahc) struct ahc_softc *ahc; { int	  max_targ = 15; int	  i; int	  term; u_int	  scsi_conf; u_int	  scsiseq_template; u_int	  ultraenb; u_int	  discenable; u_int	  tagenable; size_t	  driver_data_size; u_int32_t physaddr; struct scb_data *scb_data = NULL;  #ifdef AHC_PRINT_SRAM printf("Scratch Ram:"); for (i = 0x20; i < 0x5f; i++) { if (((i % 8) == 0) && (i != 0)) { printf ("\n              "); } printf (" 0x%x", ahc_inb(ahc, i)); } if ((ahc->features & AHC_MORE_SRAM) != 0) { for (i = 0x70; i < 0x7f; i++) { if (((i % 8) == 0) && (i != 0)) { printf ("\n              "); } printf (" 0x%x", ahc_inb(ahc, i)); } } printf ("\n"); #endif  if (ahc->scb_data == NULL) { scb_data = malloc(sizeof (struct scb_data), M_DEVBUF, M_NOWAIT); if (scb_data == NULL) { printf("%s: cannot malloc scb_data!\n", ahc_name(ahc)); return (ENOMEM); } bzero(scb_data, sizeof(struct scb_data)); ahc->scb_data = scb_data; }  if ((ahc->flags & AHC_USEDEFAULTS) != 0) ahc->our_id = ahc->our_id_b = 7;   ahc->flags |= AHC_INITIATORMODE;   driver_data_size = 3 * 256 * sizeof(u_int8_t);  if (ahc_createdmamem(ahc, driver_data_size, &ahc->shared_data_dmamap, (caddr_t *)&ahc->qoutfifo, &ahc->shared_data_busaddr, &ahc->shared_data_seg, &ahc->shared_data_nseg, "shared data") < 0) return (ENOMEM);  ahc->init_level++;   if (ahc->scb_data->maxhscbs == 0) if (ahcinitscbdata(ahc) != 0) return (ENOMEM);  ahc->qinfifo = &ahc->qoutfifo[256]; ahc->untagged_scbs = &ahc->qinfifo[256];  for (i = 0; i < 256; i++) ahc->untagged_scbs[i] = SCB_LIST_NULL;   for (i = 0; i < 256; i++) ahc->qoutfifo[i] = SCB_LIST_NULL;  bus_dmamap_sync(ahc->sc_dmat, ahc->shared_data_dmamap, 0, driver_data_size, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);   if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) { printf("%s: unable to allocate tmode_tstate.  " "Failing attach\n", ahc_name(ahc)); return (-1); }  if ((ahc->features & AHC_TWIN) != 0) { if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) { printf("%s: unable to allocate tmode_tstate.  " "Failing attach\n", ahc_name(ahc)); return (-1); } printf("Twin Channel, A SCSI Id=%d, B SCSI Id=%d, primary %c, ", ahc->our_id, ahc->our_id_b, ahc->flags & AHC_CHANNEL_B_PRIMARY? 'B': 'A'); } else { if ((ahc->features & AHC_WIDE) != 0) { printf("Wide "); } else { printf("Single "); } printf("Channel %c, SCSI Id=%d, ", ahc->channel, ahc->our_id); }  ahc_outb(ahc, SEQ_FLAGS, 0);  if (ahc->scb_data->maxhscbs < AHC_SCB_MAX) { ahc->flags |= AHC_PAGESCBS; printf("%d/%d SCBs\n", ahc->scb_data->maxhscbs, AHC_SCB_MAX); } else { ahc->flags &= ~AHC_PAGESCBS; printf("%d SCBs\n", ahc->scb_data->maxhscbs); }  #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWMISC) { printf("%s: hardware scb %d bytes; kernel scb %d bytes; " "ahc_dma %d bytes\n", ahc_name(ahc), sizeof(struct hardware_scb), sizeof(struct scb), sizeof(struct ahc_dma_seg)); } #endif    if (ahc->features & AHC_TWIN) {   term = (ahc->flags & AHC_TERM_ENB_B) != 0 ? STPWEN : 0; if ((ahc->features & AHC_ULTRA2) != 0) ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id_b); else ahc_outb(ahc, SCSIID, ahc->our_id_b); scsi_conf = ahc_inb(ahc, SCSICONF + 1); ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) |term|ENSTIMER|ACTNEGEN); ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);  if ((scsi_conf & RESET_SCSI) != 0 && (ahc->flags & AHC_INITIATORMODE) != 0) ahc->flags |= AHC_RESET_BUS_B;   ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); } term = (ahc->flags & AHC_TERM_ENB_A) != 0 ? STPWEN : 0; if ((ahc->features & AHC_ULTRA2) != 0) ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id); else ahc_outb(ahc, SCSIID, ahc->our_id); scsi_conf = ahc_inb(ahc, SCSICONF); ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) |term |ENSTIMER|ACTNEGEN); ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);  if ((scsi_conf & RESET_SCSI) != 0 && (ahc->flags & AHC_INITIATORMODE) != 0) ahc->flags |= AHC_RESET_BUS_A;   ultraenb = 0; tagenable = ALL_TARGETS_MASK;   if (ahc->flags & AHC_USEDEFAULTS) { printf("%s: Host Adapter Bios disabled.  Using default SCSI " "device parameters\n", ahc_name(ahc)); ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B| AHC_TERM_ENB_A|AHC_TERM_ENB_B; discenable = ALL_TARGETS_MASK; if ((ahc->features & AHC_ULTRA) != 0) ultraenb = ALL_TARGETS_MASK; } else { discenable = ~((ahc_inb(ahc, DISC_DSB + 1) << 8) | ahc_inb(ahc, DISC_DSB)); if ((ahc->features & (AHC_ULTRA|AHC_ULTRA2)) != 0) ultraenb = (ahc_inb(ahc, ULTRA_ENB + 1) << 8) | ahc_inb(ahc, ULTRA_ENB); }  if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0) max_targ = 7;  for (i = 0; i <= max_targ; i++) { struct ahc_initiator_tinfo *tinfo; struct tmode_tstate *tstate; u_int our_id; u_int target_id; char channel;  channel = 'A'; our_id = ahc->our_id; target_id = i; if (i > 7 && (ahc->features & AHC_TWIN) != 0) { channel = 'B'; our_id = ahc->our_id_b; target_id = i % 8; } tinfo = ahc_fetch_transinfo(ahc, channel, our_id, target_id, &tstate);  bzero(tinfo, sizeof(*tinfo)); if (ahc->flags & AHC_USEDEFAULTS) { if ((ahc->features & AHC_WIDE) != 0) tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT;   tinfo->user.period = ahc_syncrates->period; tinfo->user.offset = ~0; } else { u_int scsirate; u_int16_t mask;   scsirate = ahc_inb(ahc, TARG_SCSIRATE + i); mask = (0x01 << i); if ((ahc->features & AHC_ULTRA2) != 0) { u_int offset; u_int maxsync;  if ((scsirate & SOFS) == 0x0F) {  scsirate = (scsirate & SXFR) >> 4 | (ultraenb & mask) ? 0x08 : 0x0 | (scsirate & WIDEXFER); offset = MAX_OFFSET_ULTRA2; } else offset = ahc_inb(ahc, TARG_OFFSET + i); maxsync = AHC_SYNCRATE_ULTRA2; if ((ahc->features & AHC_DT) != 0) maxsync = AHC_SYNCRATE_DT; tinfo->user.period = ahc_find_period(ahc, scsirate, maxsync); if (offset == 0) tinfo->user.period = 0; else tinfo->user.offset = ~0; } else if ((scsirate & SOFS) != 0) { tinfo->user.period = ahc_find_period(ahc, scsirate, (ultraenb & mask) ? AHC_SYNCRATE_ULTRA : AHC_SYNCRATE_FAST); if (tinfo->user.period != 0) tinfo->user.offset = ~0; } if ((scsirate & WIDEXFER) != 0 && (ahc->features & AHC_WIDE) != 0) tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; } tinfo->goal = tinfo->user;  tstate->ultraenb = ultraenb; tstate->discenable = discenable; tstate->tagenable = 0;  tstate->tagdisable = 0; } ahc->user_discenable = discenable; ahc->user_tagenable = tagenable;   physaddr = ahc->scb_data->hscb_busaddr; ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF); ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF); ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF); ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF);  physaddr = ahc->shared_data_busaddr; ahc_outb(ahc, SCBID_ADDR, physaddr & 0xFF); ahc_outb(ahc, SCBID_ADDR + 1, (physaddr >> 8) & 0xFF); ahc_outb(ahc, SCBID_ADDR + 2, (physaddr >> 16) & 0xFF); ahc_outb(ahc, SCBID_ADDR + 3, (physaddr >> 24) & 0xFF);   physaddr += 3 * 256 * sizeof(u_int8_t); ahc_outb(ahc, TMODE_CMDADDR, physaddr & 0xFF); ahc_outb(ahc, TMODE_CMDADDR + 1, (physaddr >> 8) & 0xFF); ahc_outb(ahc, TMODE_CMDADDR + 2, (physaddr >> 16) & 0xFF); ahc_outb(ahc, TMODE_CMDADDR + 3, (physaddr >> 24) & 0xFF);   ahc_outb(ahc, CMDSIZE_TABLE, 5); ahc_outb(ahc, CMDSIZE_TABLE + 1, 9); ahc_outb(ahc, CMDSIZE_TABLE + 2, 9); ahc_outb(ahc, CMDSIZE_TABLE + 3, 0); ahc_outb(ahc, CMDSIZE_TABLE + 4, 15); ahc_outb(ahc, CMDSIZE_TABLE + 5, 11); ahc_outb(ahc, CMDSIZE_TABLE + 6, 0); ahc_outb(ahc, CMDSIZE_TABLE + 7, 0);   ahc_outb(ahc, KERNEL_QINPOS, 0); ahc_outb(ahc, QINPOS, 0); ahc_outb(ahc, QOUTPOS, 0);  #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWMISC) printf("DISCENABLE == 0x%x\nULTRAENB == 0x%x\n", discenable, ultraenb); #endif   ahc_outb(ahc, TARGET_MSG_REQUEST, 0); ahc_outb(ahc, TARGET_MSG_REQUEST + 1, 0);   if ((ahc->features & AHC_QUEUE_REGS) != 0) { ahc_outb(ahc, QOFF_CTLSTA, SCB_QSIZE_256); ahc_outb(ahc, SDSCB_QOFF, 0); ahc_outb(ahc, SNSCB_QOFF, 0); ahc_outb(ahc, HNSCB_QOFF, 0); }    ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL);   ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL);   ahc_outb(ahc, MSG_OUT, MSG_NOOP);   scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP; if ((ahc->flags & AHC_INITIATORMODE) != 0) scsiseq_template |= ENRSELI; ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template);   if (bootverbose) printf("%s: Downloading Sequencer Program...", ahc_name(ahc));  ahc_loadseq(ahc);   shutdownhook_establish(ahc_shutdown, ahc); return (0); }   STATIC INLINE void ahc_list_insert_before(ahc, xs, next_xs) struct ahc_softc *ahc; struct scsi_xfer *xs; struct scsi_xfer *next_xs; { LIST_INSERT_BEFORE(xs, next_xs, free_list);  }  STATIC INLINE void ahc_list_insert_head(ahc, xs) struct ahc_softc *ahc; struct scsi_xfer *xs; { if (ahc->sc_xxxq.lh_first == NULL) ahc->sc_xxxqlast = xs; LIST_INSERT_HEAD(&ahc->sc_xxxq, xs, free_list); return; }  STATIC INLINE void ahc_list_insert_tail(ahc, xs) struct ahc_softc *ahc; struct scsi_xfer *xs; { if (ahc->sc_xxxq.lh_first == NULL){ ahc->sc_xxxqlast = xs; LIST_INSERT_HEAD(&ahc->sc_xxxq, xs, free_list); return; } LIST_INSERT_AFTER(ahc->sc_xxxqlast, xs, free_list); ahc->sc_xxxqlast = xs; }  STATIC INLINE void ahc_list_remove(ahc, xs) struct ahc_softc *ahc; struct scsi_xfer *xs; { struct scsi_xfer *lxs; if (xs == ahc->sc_xxxqlast) { lxs = ahc->sc_xxxq.lh_first; while (lxs != NULL) { if (LIST_NEXT(lxs, free_list) == ahc->sc_xxxqlast) { ahc->sc_xxxqlast = lxs; break; } lxs = LIST_NEXT(xs, free_list); } }  LIST_REMOVE(xs, free_list); if (ahc->sc_xxxq.lh_first == NULL) ahc->sc_xxxqlast = NULL; }  STATIC INLINE struct scsi_xfer * ahc_list_next(ahc, xs) struct ahc_softc *ahc; struct scsi_xfer *xs; { return(LIST_NEXT(xs, free_list)); }   STATIC INLINE struct scsi_xfer * ahc_first_xs(struct ahc_softc *ahc) { int target; struct scsi_xfer *xs = ahc->sc_xxxq.lh_first;  if (ahc->queue_blocked) return NULL;  while (xs != NULL) { target = xs->sc_link->target; if (ahc->devqueue_blocked[target] == 0 && ahc_index_busy_tcl(ahc, XS_TCL(ahc, xs), FALSE) == SCB_LIST_NULL) break; xs = LIST_NEXT(xs, free_list); }  return xs; }  STATIC int32_t ahc_scsi_cmd(xs) struct scsi_xfer *xs; { struct scsi_xfer *first_xs, *next_xs = NULL; struct ahc_softc *ahc; struct scb *scb; struct hardware_scb *hscb; struct ahc_initiator_tinfo *tinfo; struct tmode_tstate *tstate; u_int target_id; u_int our_id; char channel; int s, tcl; u_int16_t mask; int dontqueue = 0, fromqueue = 0;  SC_DEBUG(xs->sc_link, SDEV_DB3, ("ahc_scsi_cmd\n")); ahc = (struct ahc_softc *)xs->sc_link->adapter_softc;   s = splbio();  if (xs == ahc->sc_xxxq.lh_first) {   if (ahc->queue_blocked) { splx(s); return (TRY_AGAIN_LATER); }  xs = ahc_first_xs(ahc); if (xs == NULL) { splx(s); return (TRY_AGAIN_LATER); }  next_xs = ahc_list_next(ahc, xs); ahc_list_remove(ahc, xs); fromqueue = 1; goto get_scb; }   dontqueue = xs->flags & SCSI_POLL;   tcl = XS_TCL(ahc, xs);  if (ahc->queue_blocked || ahc->devqueue_blocked[xs->sc_link->target] || (!ahc_istagged_device(ahc, xs, 0) && ahc_index_busy_tcl(ahc, tcl, FALSE) != SCB_LIST_NULL)) { if (dontqueue) { splx(s); xs->error = XS_DRIVER_STUFFUP; return TRY_AGAIN_LATER; } ahc_list_insert_tail(ahc, xs); splx(s); return SUCCESSFULLY_QUEUED; }  first_xs = ahc_first_xs(ahc);   dontqueue = xs->flags & SCSI_POLL;   if (first_xs != NULL) {  if (dontqueue) { splx(s); xs->error = XS_DRIVER_STUFFUP; return (TRY_AGAIN_LATER); }   ahc_list_insert_tail(ahc, xs); xs = first_xs; next_xs = ahc_list_next(ahc, xs); ahc_list_remove(ahc, xs); fromqueue = 1;  }  get_scb:  target_id = xs->sc_link->target; our_id = SIM_SCSI_ID(ahc, xs->sc_link);   if ((scb = ahcgetscb(ahc)) == NULL) {  if (dontqueue) { splx(s); xs->error = XS_DRIVER_STUFFUP; return (TRY_AGAIN_LATER); }   if (fromqueue && next_xs != NULL) ahc_list_insert_before(ahc, xs, next_xs); else ahc_list_insert_tail(ahc, xs);  splx(s); return (SUCCESSFULLY_QUEUED); }  tcl = XS_TCL(ahc, xs);  #ifdef DIAGNOSTIC if (!ahc_istagged_device(ahc, xs, 0) && ahc_index_busy_tcl(ahc, tcl, FALSE) != SCB_LIST_NULL) panic("ahc: queuing for busy target"); #endif  scb->xs = xs; hscb = scb->hscb; hscb->tcl = tcl; timeout_set(&xs->stimeout, ahc_timeout, scb);  if (ahc_istagged_device(ahc, xs, 0)) scb->hscb->control |= MSG_SIMPLE_Q_TAG; else ahc_busy_tcl(ahc, scb);  splx(s);  channel = SIM_CHANNEL(ahc, xs->sc_link); if (ahc->inited_channels[channel - 'A'] == 0) { if ((channel == 'A' && (ahc->flags & AHC_RESET_BUS_A)) || (channel == 'B' && (ahc->flags & AHC_RESET_BUS_B))) { s = splbio(); ahc_reset_channel(ahc, channel, TRUE); splx(s); } ahc->inited_channels[channel - 'A'] = 1; }    mask = SCB_TARGET_MASK(scb); tinfo = ahc_fetch_transinfo(ahc, SIM_CHANNEL(ahc, xs->sc_link), our_id, target_id, &tstate); if (ahc->inited_targets[target_id] == 0) { struct ahc_devinfo devinfo;  s = splbio(); ahc_compile_devinfo(&devinfo, our_id, target_id, xs->sc_link->lun, SIM_CHANNEL(ahc, xs->sc_link), ROLE_INITIATOR); ahc_update_target_msg_request(ahc, &devinfo, tinfo, TRUE, FALSE); ahc->inited_targets[target_id] = 1; splx(s); }  hscb->scsirate = tinfo->scsirate; hscb->scsioffset = tinfo->current.offset; if ((tstate->ultraenb & mask) != 0) hscb->control |= ULTRAENB;  if ((tstate->discenable & mask) != 0) hscb->control |= DISCENB;  if (xs->flags & SCSI_RESET) { hscb->cmdpointer = NULL; scb->flags |= SCB_DEVICE_RESET; hscb->control |= MK_MESSAGE; return ahc_execute_scb(scb, NULL, 0); }  return ahc_setup_data(ahc, xs, scb); }  STATIC int ahc_execute_scb(arg, dm_segs, nsegments) void *arg; bus_dma_segment_t *dm_segs; int nsegments; { struct	 scb *scb; struct scsi_xfer *xs; struct	 ahc_softc *ahc; int	 s;  scb = (struct scb *)arg; xs = scb->xs; ahc = (struct ahc_softc *)xs->sc_link->adapter_softc;   if (nsegments != 0) { struct ahc_dma_seg *sg; bus_dma_segment_t *end_seg; int op;  end_seg = dm_segs + nsegments;   scb->hscb->data = dm_segs->ds_addr; scb->hscb->datalen = dm_segs->ds_len;   sg = scb->sg_list; while (dm_segs < end_seg) { sg->addr = dm_segs->ds_addr; sg->len = dm_segs->ds_len; ahc_swap_sg(sg); sg++; dm_segs++; }   scb->hscb->SG_pointer = scb->sg_list_phys; if ((scb->xs->flags & SCSI_DATA_IN) != 0) op = BUS_DMASYNC_PREREAD; else op = BUS_DMASYNC_PREWRITE; bus_dmamap_sync(ahc->sc_dmat, scb->dmamap, 0, scb->dmamap->dm_mapsize, op); } else { scb->hscb->SG_pointer = 0; scb->hscb->data = 0; scb->hscb->datalen = 0; }  scb->sg_count = scb->hscb->SG_count = nsegments;  s = splbio();   if (xs->flags & ITSDONE) { if (!ahc_istagged_device(ahc, xs, 0)) ahc_index_busy_tcl(ahc, scb->hscb->tcl, TRUE); if (nsegments != 0) bus_dmamap_unload(ahc->sc_dmat, scb->dmamap); ahcfreescb(ahc, scb); splx(s); return (COMPLETE); }  #ifdef DIAGNOSTIC if (scb->sg_count > 255) panic("ahc bad sg_count"); #endif  ahc_swap_hscb(scb->hscb);  LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pend_links);  scb->flags |= SCB_ACTIVE;  if (!(xs->flags & SCSI_POLL)) timeout_add(&xs->stimeout, (xs->timeout * hz) / 1000);  if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) { #if 0 printf("Continueing Immediate Command %d:%d\n", xs->sc_link->target, xs->sc_link->lun); #endif pause_sequencer(ahc); if ((ahc->flags & AHC_PAGESCBS) == 0) ahc_outb(ahc, SCBPTR, scb->hscb->tag); ahc_outb(ahc, SCB_TAG, scb->hscb->tag); ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP); unpause_sequencer(ahc); } else {  ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;  bus_dmamap_sync(ahc->sc_dmat, ahc->shared_data_dmamap, QINFIFO_OFFSET * 256, 256, BUS_DMASYNC_PREWRITE);  if ((ahc->features & AHC_QUEUE_REGS) != 0) { ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); } else { pause_sequencer(ahc); ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); unpause_sequencer(ahc); } }  #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOWCMDS) { sc_print_addr(xs->sc_link); printf("opcode %d tag %x len %d flags %x control %x fpos %u" " rate %x\n", xs->cmdstore.opcode, scb->hscb->tag, scb->hscb->datalen, scb->flags, scb->hscb->control, ahc->qinfifonext, scb->hscb->scsirate); } #endif  if (!(xs->flags & SCSI_POLL)) { splx(s); return (SUCCESSFULLY_QUEUED); }  SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_poll\n")); do { if (ahc_poll(ahc, xs->timeout)) { if (!(xs->flags & SCSI_SILENT)) printf("cmd fail\n"); ahc_timeout(scb); break; } } while (!(xs->flags & ITSDONE)); splx(s); return (COMPLETE); }  STATIC int ahc_poll(ahc, wait) struct   ahc_softc *ahc; int   wait;	 { while (--wait) { DELAY(1000); if (ahc_inb(ahc, INTSTAT) & INT_PEND) break; }  if (wait == 0) { printf("%s: board is not responding\n", ahc_name(ahc)); return (EIO); }  ahc_intr((void *)ahc); return (0); }  STATIC int ahc_setup_data(ahc, xs, scb) struct ahc_softc *ahc; struct scsi_xfer *xs; struct scb *scb; { struct hardware_scb *hscb;  hscb = scb->hscb; xs->resid = xs->status = 0;  hscb->cmdlen = xs->cmdlen; bcopy(xs->cmd, hscb->cmdstore, xs->cmdlen); hscb->cmdpointer = hscb->cmdstore_busaddr;   if (xs->datalen) { int error;  error = bus_dmamap_load(ahc->sc_dmat, scb->dmamap, xs->data, xs->datalen, NULL, (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK); if (error) { if (!ahc_istagged_device(ahc, xs, 0)) ahc_index_busy_tcl(ahc, hscb->tcl, TRUE); return (TRY_AGAIN_LATER);	 } error = ahc_execute_scb(scb, scb->dmamap->dm_segs, scb->dmamap->dm_nsegs); return error; } else { return ahc_execute_scb(scb, NULL, 0); } }  STATIC void ahc_freeze_devq(ahc, sc_link) struct ahc_softc *ahc; struct scsi_link *sc_link; { int	target; char	channel; int	lun;  target = sc_link->target; lun = sc_link->lun; channel = SIM_CHANNEL(ahc, sc_link);  ahc_search_qinfifo(ahc, target, channel, lun, SCB_LIST_NULL, ROLE_UNKNOWN, SCB_REQUEUE, SEARCH_COMPLETE); }  STATIC void ahcallocscbs(ahc) struct ahc_softc *ahc; { struct scb_data *scb_data; struct scb *next_scb; struct sg_map_node *sg_map; bus_addr_t physaddr; struct ahc_dma_seg *segs; int newcount; int i; int dma_flags = 0;  scb_data = ahc->scb_data; if (scb_data->numscbs >= AHC_SCB_MAX)  return;  next_scb = &scb_data->scbarray[scb_data->numscbs];  sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);  if (sg_map == NULL) return; bzero(sg_map, sizeof(struct sg_map_node));  if (ahc_createdmamem(ahc, PAGE_SIZE, &sg_map->sg_dmamap, (caddr_t *)&sg_map->sg_vaddr, &sg_map->sg_physaddr, &sg_map->sg_dmasegs, &sg_map->sg_nseg, "SG space") < 0) { free(sg_map, M_DEVBUF); return; }  SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links);  segs = sg_map->sg_vaddr; physaddr = sg_map->sg_physaddr;  newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg)));  for (i = 0; scb_data->numscbs < AHC_SCB_MAX && i < newcount; i++) { int error;  next_scb->sg_list = segs;  next_scb->sg_list_phys = physaddr + sizeof(struct ahc_dma_seg); next_scb->flags = SCB_FREE;   dma_flags = ((ahc->chip & AHC_VL) !=0) ? BUS_DMA_NOWAIT|ISABUS_DMA_32BIT : BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW;  error = bus_dmamap_create(ahc->sc_dmat, AHC_MAXTRANSFER_SIZE, AHC_NSEG, MAXBSIZE, 0, dma_flags, &next_scb->dmamap); if (error !=0) break;  next_scb->hscb = &scb_data->hscbs[scb_data->numscbs]; next_scb->hscb->tag = ahc->scb_data->numscbs; next_scb->hscb->cmdstore_busaddr = ahc_hscb_busaddr(ahc, next_scb->hscb->tag) + offsetof(struct hardware_scb, cmdstore); next_scb->hscb->cmdstore_busaddr = htole32(next_scb->hscb->cmdstore_busaddr); SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, next_scb, links); segs += AHC_NSEG; physaddr += (AHC_NSEG * sizeof(struct ahc_dma_seg)); next_scb++; ahc->scb_data->numscbs++; } }  #ifdef AHC_DUMP_SEQ STATIC void ahc_dumpseq(ahc) struct ahc_softc* ahc; { int i; int max_prog;  if ((ahc->chip & AHC_BUS_MASK) < AHC_PCI) max_prog = 448; else if ((ahc->features & AHC_ULTRA2) != 0) max_prog = 768; else max_prog = 512;  ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); ahc_outb(ahc, SEQADDR0, 0); ahc_outb(ahc, SEQADDR1, 0); for (i = 0; i < max_prog; i++) { u_int8_t ins_bytes[4];  ahc_insb(ahc, SEQRAM, ins_bytes, 4); printf("0x%08x\n", ins_bytes[0] << 24 | ins_bytes[1] << 16 | ins_bytes[2] << 8 | ins_bytes[3]); } } #endif  STATIC void ahc_loadseq(ahc) struct ahc_softc* ahc; { struct patch *cur_patch; int i; int downloaded; int skip_addr; u_int8_t download_consts[4];   #if 0  download_consts[TMODE_NUMCMDS] = ahc->num_targetcmds; #endif  cur_patch = patches; downloaded = 0; skip_addr = 0; ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); ahc_outb(ahc, SEQADDR0, 0); ahc_outb(ahc, SEQADDR1, 0);  for (i = 0; i < sizeof(seqprog)/4; i++) { if (ahc_check_patch(ahc, &cur_patch, i, &skip_addr) == 0) {  continue; } ahc_download_instr(ahc, i, download_consts); downloaded++; } ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE); restart_sequencer(ahc);  if (bootverbose) printf(" %d instructions downloaded\n", downloaded); }  STATIC int ahc_check_patch(ahc, start_patch, start_instr,skip_addr) struct ahc_softc *ahc; struct patch **start_patch; int start_instr; int *skip_addr; { struct	patch *cur_patch; struct	patch *last_patch; int	num_patches;  num_patches = sizeof(patches)/sizeof(struct patch); last_patch = &patches[num_patches]; cur_patch = *start_patch;  while (cur_patch < last_patch && start_instr == cur_patch->begin) {  if (cur_patch->patch_func(ahc) == 0) {   *skip_addr = start_instr + cur_patch->skip_instr; cur_patch += cur_patch->skip_patch; } else {  cur_patch++; } }  *start_patch = cur_patch; if (start_instr < *skip_addr)  return (0);  return (1); }  STATIC void ahc_download_instr(ahc, instrptr, dconsts) struct ahc_softc *ahc; int instrptr; u_int8_t *dconsts; { union	ins_formats instr; struct	ins_format1 *fmt1_ins; struct	ins_format3 *fmt3_ins; u_int	opcode;   instr = *(union ins_formats*)&seqprog[instrptr * 4];  instr.integer = le32toh(instr.integer);  fmt1_ins = &instr.format1; fmt3_ins = NULL;   opcode = instr.format1.opcode; switch (opcode) { case AIC_OP_JMP: case AIC_OP_JC: case AIC_OP_JNC: case AIC_OP_CALL: case AIC_OP_JNE: case AIC_OP_JNZ: case AIC_OP_JE: case AIC_OP_JZ: { struct patch *cur_patch; int address_offset; u_int address; int skip_addr; int i;  fmt3_ins = &instr.format3; address_offset = 0; address = fmt3_ins->address; cur_patch = patches; skip_addr = 0;  for (i = 0; i < address;) {  ahc_check_patch(ahc, &cur_patch, i, &skip_addr);  if (skip_addr > i) { int end_addr;  end_addr = MIN(address, skip_addr); address_offset += end_addr - i; i = skip_addr; } else { i++; } } address -= address_offset; fmt3_ins->address = address;  } case AIC_OP_OR: case AIC_OP_AND: case AIC_OP_XOR: case AIC_OP_ADD: case AIC_OP_ADC: case AIC_OP_BMOV: if (fmt1_ins->parity != 0) { fmt1_ins->immediate = dconsts[fmt1_ins->immediate]; } fmt1_ins->parity = 0;  case AIC_OP_ROL: if ((ahc->features & AHC_ULTRA2) != 0) { int i, count;   for (i = 0, count = 0; i < 31; i++) { u_int32_t mask;  mask = 0x01 << i; if ((instr.integer & mask) != 0) count++; } if ((count & 0x01) == 0) instr.format1.parity = 1; } else {  if (fmt3_ins != NULL) { instr.integer = fmt3_ins->immediate | (fmt3_ins->source << 8) | (fmt3_ins->address << 16) |	(fmt3_ins->opcode << 25); } else { instr.integer = fmt1_ins->immediate | (fmt1_ins->source << 8) | (fmt1_ins->destination << 16) |	(fmt1_ins->ret << 24) |	(fmt1_ins->opcode << 25); } } instr.integer = htole32(instr.integer); ahc_outsb(ahc, SEQRAM, instr.bytes, 4); break; default: panic("Unknown opcode encountered in seq program"); break; } }  STATIC void ahc_set_recoveryscb(ahc, scb) struct ahc_softc *ahc; struct scb *scb; {  if ((scb->flags & SCB_RECOVERY_SCB) == 0) { struct scb *scbp;  scb->flags |= SCB_RECOVERY_SCB;   ahc->queue_blocked = 1;   scbp = ahc->pending_scbs.lh_first; while (scbp != NULL) { timeout_del(&scbp->xs->stimeout); scbp = scbp->pend_links.le_next; } } }  STATIC void ahc_timeout(void *arg) { struct	scb *scb; struct	ahc_softc *ahc; int	s, found; u_int	last_phase; int	target; int	lun; int	i; char	channel;  scb = (struct scb *)arg; ahc = (struct ahc_softc *)scb->xs->sc_link->adapter_softc;  s = splbio();   do { ahc_intr(ahc); pause_sequencer(ahc); } while (ahc_inb(ahc, INTSTAT) & INT_PEND);  if ((scb->flags & SCB_ACTIVE) == 0) {  printf("Timedout SCB handled by another timeout\n"); unpause_sequencer(ahc); splx(s); return; }  target = SCB_TARGET(scb); channel = SCB_CHANNEL(scb); lun = SCB_LUN(scb);  sc_print_addr(scb->xs->sc_link); printf("SCB 0x%x - timed out ", scb->hscb->tag);  last_phase = ahc_inb(ahc, LASTPHASE);  for (i = 0; i < num_phases; i++) { if (last_phase == phase_table[i].phase) break; } printf("%s", phase_table[i].phasemsg);  printf(", SEQADDR == 0x%x\n", ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); #if 0 printf("SSTAT1 == 0x%x\n", ahc_inb(ahc, SSTAT1)); printf("SSTAT3 == 0x%x\n", ahc_inb(ahc, SSTAT3)); printf("SCSIPHASE == 0x%x\n", ahc_inb(ahc, SCSIPHASE)); printf("SCSIRATE == 0x%x\n", ahc_inb(ahc, SCSIRATE)); printf("SCSIOFFSET == 0x%x\n", ahc_inb(ahc, SCSIOFFSET)); printf("SEQ_FLAGS == 0x%x\n", ahc_inb(ahc, SEQ_FLAGS)); printf("SCB_DATAPTR == 0x%x\n", ahc_inb(ahc, SCB_DATAPTR) | ahc_inb(ahc, SCB_DATAPTR + 1) << 8 | ahc_inb(ahc, SCB_DATAPTR + 2) << 16 | ahc_inb(ahc, SCB_DATAPTR + 3) << 24); printf("SCB_DATACNT == 0x%x\n", ahc_inb(ahc, SCB_DATACNT) | ahc_inb(ahc, SCB_DATACNT + 1) << 8 | ahc_inb(ahc, SCB_DATACNT + 2) << 16); printf("SCB_SGCOUNT == 0x%x\n", ahc_inb(ahc, SCB_SGCOUNT)); printf("CCSCBCTL == 0x%x\n", ahc_inb(ahc, CCSCBCTL)); printf("CCSCBCNT == 0x%x\n", ahc_inb(ahc, CCSCBCNT)); printf("DFCNTRL == 0x%x\n", ahc_inb(ahc, DFCNTRL)); printf("DFSTATUS == 0x%x\n", ahc_inb(ahc, DFSTATUS)); printf("CCHCNT == 0x%x\n", ahc_inb(ahc, CCHCNT)); if (scb->sg_count > 0) { for (i = 0; i < scb->sg_count; i++) { printf("sg[%d] - Addr 0x%x : Length %d\n", i, le32toh(scb->sg_list[i].addr), le32toh(scb->sg_list[i].len)); } } #endif if (scb->flags & (SCB_DEVICE_RESET|SCB_ABORT)) {  bus_reset: ahcsetccbstatus(scb->xs, XS_TIMEOUT); found = ahc_reset_channel(ahc, channel, TRUE); printf("%s: Issued Channel %c Bus Reset. " "%d SCBs aborted\n", ahc_name(ahc), channel, found); } else {  u_int active_scb_index;  active_scb_index = ahc_inb(ahc, SCB_TAG);  if (last_phase != P_BUSFREE && (active_scb_index < ahc->scb_data->numscbs)) { struct scb *active_scb;   active_scb = &ahc->scb_data->scbarray[active_scb_index]; if (active_scb->hscb->tcl != scb->hscb->tcl) { u_int	newtimeout;  sc_print_addr(scb->xs->sc_link); printf("Other SCB Timeout%s", (scb->flags & SCB_OTHERTCL_TIMEOUT) != 0 ? " again\n" : "\n"); scb->flags |= SCB_OTHERTCL_TIMEOUT; newtimeout = MAX(active_scb->xs->timeout, scb->xs->timeout); timeout_add(&scb->xs->stimeout, (newtimeout * hz) / 1000); splx(s); return; }   if ((scb->hscb->control & TARGET_SCB) != 0) {   ahc_freeze_devq(ahc, scb->xs->sc_link); ahcsetccbstatus(scb->xs, XS_TIMEOUT); ahc_freeze_ccb(scb); ahc_done(ahc, scb);   restart_sequencer(ahc); splx(s); return; }  ahc_set_recoveryscb(ahc, active_scb); ahc_outb(ahc, MSG_OUT, MSG_BUS_DEV_RESET); ahc_outb(ahc, SCSISIGO, last_phase|ATNO); sc_print_addr(active_scb->xs->sc_link); printf("BDR message in message buffer\n"); active_scb->flags |=  SCB_DEVICE_RESET; timeout_add(&active_scb->xs->stimeout, 2 * hz); unpause_sequencer(ahc); } else { int	 disconnected;   if ((scb->hscb->control & TARGET_SCB) != 0) panic("Timed-out target SCB but bus idle");  if (last_phase != P_BUSFREE && (ahc_inb(ahc, SSTAT0) & TARGET) != 0) {   printf("%s: Hung target selection\n", ahc_name(ahc)); restart_sequencer(ahc); splx(s); return; }  if (ahc_search_qinfifo(ahc, target, channel, lun, scb->hscb->tag, ROLE_INITIATOR, 0, SEARCH_COUNT) > 0) { disconnected = FALSE; } else { disconnected = TRUE; }  if (disconnected) { u_int active_scb;  ahc_set_recoveryscb(ahc, scb);  scb->hscb->control |= MK_MESSAGE; scb->flags |= SCB_QUEUED_MSG |  SCB_DEVICE_RESET;   active_scb = ahc_inb(ahc, SCBPTR); if (ahc_search_disc_list(ahc, target, channel, lun, scb->hscb->tag, TRUE, FALSE, FALSE)) { u_int scb_control;  scb_control = ahc_inb(ahc, SCB_CONTROL); scb_control |= MK_MESSAGE; ahc_outb(ahc, SCB_CONTROL, scb_control); } ahc_outb(ahc, SCBPTR, active_scb); ahc_index_busy_tcl(ahc, scb->hscb->tcl, TRUE);   ahc_search_qinfifo(ahc, SCB_TARGET(scb), channel, SCB_LUN(scb), SCB_LIST_NULL, ROLE_INITIATOR, SCB_REQUEUE, SEARCH_COMPLETE); sc_print_addr(scb->xs->sc_link); printf("Queuing a BDR SCB\n"); ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;  bus_dmamap_sync(ahc->sc_dmat, ahc->shared_data_dmamap, QINFIFO_OFFSET * 256, 256, BUS_DMASYNC_PREWRITE);  if ((ahc->features & AHC_QUEUE_REGS) != 0) { ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); } else { ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); } timeout_add(&scb->xs->stimeout, 2 * hz); unpause_sequencer(ahc); } else {   ahc_set_recoveryscb(ahc, scb); sc_print_addr(scb->xs->sc_link); printf("SCB %d: Immediate reset.  " "Flags = 0x%x\n", scb->hscb->tag, scb->flags); goto bus_reset; } } } splx(s); }  STATIC int ahc_search_qinfifo(ahc, target, channel, lun, tag, role, status, action) struct ahc_softc *ahc; int target; char channel; int lun; u_int tag; role_t role; u_int32_t status; ahc_search_action action; { struct	 scb *scbp; u_int8_t qinpos; u_int8_t qintail; int	 found;  qinpos = ahc_inb(ahc, QINPOS); qintail = ahc->qinfifonext; found = 0;   ahc->qinfifonext = qinpos; bus_dmamap_sync(ahc->sc_dmat, ahc->shared_data_dmamap, QINFIFO_OFFSET * 256, 256, BUS_DMASYNC_POSTREAD);  while (qinpos != qintail) { scbp = &ahc->scb_data->scbarray[ahc->qinfifo[qinpos]]; if (ahc_match_scb(scbp, target, channel, lun, tag, role)) {  switch (action) { case SEARCH_COMPLETE: if (!(scbp->xs->flags & ITSDONE)) { scbp->flags |= status; scbp->xs->error = XS_NOERROR; } ahc_freeze_ccb(scbp); ahc_done(ahc, scbp); break; case SEARCH_COUNT: ahc->qinfifo[ahc->qinfifonext++] = scbp->hscb->tag; break; case SEARCH_REMOVE: break; } found++; } else { ahc->qinfifo[ahc->qinfifonext++] = scbp->hscb->tag; } qinpos++; } bus_dmamap_sync(ahc->sc_dmat, ahc->shared_data_dmamap, QINFIFO_OFFSET * 256, 256, BUS_DMASYNC_PREWRITE);  if ((ahc->features & AHC_QUEUE_REGS) != 0) { ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); } else { ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); }  return (found); }   STATIC int ahc_abort_scbs(ahc, target, channel, lun, tag, role, status) struct ahc_softc *ahc; int target; char channel; int lun; u_int tag; role_t role; u_int32_t status; { struct	scb *scbp; u_int	active_scb; int	i; int	found;   active_scb = ahc_inb(ahc, SCBPTR);  found = ahc_search_qinfifo(ahc, target, channel, lun, SCB_LIST_NULL, role, SCB_REQUEUE, SEARCH_COMPLETE);   { u_int8_t next, prev;  next = ahc_inb(ahc, WAITING_SCBH); prev = SCB_LIST_NULL;  while (next != SCB_LIST_NULL) { u_int8_t scb_index;  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); } scbp = &ahc->scb_data->scbarray[scb_index]; if (ahc_match_scb(scbp, target, channel, lun, SCB_LIST_NULL, role)) {  next = ahc_abort_wscb(ahc, next, prev); } else {  prev = next; next = ahc_inb(ahc, SCB_NEXT); } } }  ahc_search_disc_list(ahc, target, channel, lun, tag, FALSE, TRUE, FALSE);   for(i = 0; i < ahc->scb_data->maxhscbs; i++) { u_int scbid;  ahc_outb(ahc, SCBPTR, i); scbid = ahc_inb(ahc, SCB_TAG); scbp = &ahc->scb_data->scbarray[scbid]; if (scbid < ahc->scb_data->numscbs && ahc_match_scb(scbp, target, channel, lun, tag, role)) ahc_add_curscb_to_free_list(ahc); }   { struct scb *scb;  scb = ahc->pending_scbs.lh_first; while (scb != NULL) { scbp = scb; scb = scb->pend_links.le_next; if (ahc_match_scb(scbp, target, channel, lun, tag, role)) { if (!(scbp->xs->flags & ITSDONE)) ahcsetccbstatus(scbp->xs, status); ahc_freeze_ccb(scbp); ahc_done(ahc, scbp); found++; } } } ahc_outb(ahc, SCBPTR, active_scb); return found; }  STATIC int ahc_search_disc_list(ahc, target, channel, lun, tag, stop_on_first, remove, save_state) struct ahc_softc *ahc; int target; char channel; int lun; u_int tag; int stop_on_first; int remove; int save_state; { struct	scb *scbp; u_int	next; u_int	prev; u_int	count; u_int	active_scb;  count = 0; next = ahc_inb(ahc, DISCONNECTED_SCBH); prev = SCB_LIST_NULL;  if (save_state) {  active_scb = ahc_inb(ahc, SCBPTR); } else  active_scb = SCB_LIST_NULL;  while (next != SCB_LIST_NULL) { u_int scb_index;  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); } scbp = &ahc->scb_data->scbarray[scb_index]; if (ahc_match_scb(scbp, target, channel, lun, tag, ROLE_INITIATOR)) { count++; if (remove) { next = ahc_rem_scb_from_disc_list(ahc, prev, next); } else { prev = next; next = ahc_inb(ahc, SCB_NEXT); } if (stop_on_first) break; } else { prev = next; next = ahc_inb(ahc, SCB_NEXT); } } if (save_state) ahc_outb(ahc, SCBPTR, active_scb); return (count); }  STATIC u_int ahc_rem_scb_from_disc_list(ahc, prev, scbptr) struct ahc_softc *ahc; u_int prev; u_int scbptr;
ahc_rem_scb_from_disc_list(struct ahc_softc *ahc, u_int prev, u_int scbptr){	u_int next;	ahc_outb(ahc, SCBPTR, scbptr);	next = ahc_inb(ahc, SCB_NEXT);	ahc_outb(ahc, SCB_CONTROL, 0);	ahc_add_curscb_to_free_list(ahc);	if (prev != SCB_LIST_NULL) {		ahc_outb(ahc, SCBPTR, prev);		ahc_outb(ahc, SCB_NEXT, next);	} else		ahc_outb(ahc, DISCONNECTED_SCBH, next);	return (next);}