ahc_clear_msg_state(struct ahc_softc *ahc)
STATIC void	ahc_clear_msg_state __P((struct ahc_softc *ahc)); STATIC void	ahc_handle_message_phase __P((struct ahc_softc *ahc, struct scsi_link *sc_link)); STATIC int	ahc_sent_msg __P((struct ahc_softc *ahc, u_int msgtype, int full));  typedef enum { MSGLOOP_IN_PROG, MSGLOOP_MSGCOMPLETE, MSGLOOP_TERMINATED } msg_loop_stat;  STATIC int	ahc_parse_msg __P((struct ahc_softc *ahc, struct scsi_link *sc_link, struct ahc_devinfo *devinfo)); STATIC void	ahc_handle_ign_wide_residue __P((struct ahc_softc *ahc, struct ahc_devinfo *devinfo)); STATIC void	ahc_handle_devreset __P((struct ahc_softc *ahc, struct ahc_devinfo *devinfo, int status, char *message, int verbose_level)); #ifdef AHC_DUMP_SEQ STATIC void	ahc_dumpseq __P((struct ahc_softc *ahc)); #endif STATIC void	ahc_loadseq __P((struct ahc_softc *ahc)); STATIC int	ahc_check_patch __P((struct ahc_softc *ahc, struct patch **start_patch, int start_instr, int *skip_addr)); STATIC void	ahc_download_instr __P((struct ahc_softc *ahc, int instrptr, u_int8_t *dconsts)); STATIC int	ahc_match_scb __P((struct scb *scb, int target, char channel, int lun, u_int tag, role_t role)); #ifdef AHC_DEBUG STATIC void	ahc_print_scb __P((struct scb *scb)); #endif STATIC int	ahc_search_qinfifo __P((struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, role_t role, u_int32_t status, ahc_search_action action)); STATIC int	ahc_reset_channel __P((struct ahc_softc *ahc, char channel, int initiate_reset)); STATIC int	ahc_abort_scbs __P((struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, role_t role, u_int32_t status)); STATIC int	ahc_search_disc_list __P((struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, int stop_on_first, int remove, int save_state)); 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_clear_msg_state(struct ahc_softc *ahc){	ahc->msgout_len = 0;	ahc->msgin_index = 0;	ahc->msg_type = MSG_TYPE_NONE;	if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0) {		/*		 * The target didn't care to respond to our		 * message request, so clear ATN.		 */		ahc_outb(ahc, CLRSINT1, CLRATNO);	}	ahc_outb(ahc, MSG_OUT, MSG_NOOP);}