spkt = &hscb->shared_data.status; resid_sgptr = ahc_le32toh(spkt->residual_sg_ptr); if ((sgptr & SG_FULL_RESID) != 0) {  resid = ahc_get_transfer_length(scb); } else if ((resid_sgptr & SG_LIST_NULL) != 0) {
} 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)
ahc_calc_residual(struct scb *scb){	struct hardware_scb *hscb;	struct status_pkt *spkt;	uint32_t sgptr;	uint32_t resid_sgptr;	uint32_t resid;	/*	 * 5 cases.	 * 1) No residual.	 *    SG_RESID_VALID clear in sgptr.	 * 2) Transferless command	 * 3) Never performed any transfers.	 *    sgptr has SG_FULL_RESID set.	 * 4) No residual but target did not	 *    save data pointers after the	 *    last transfer, so sgptr was	 *    never updated.	 * 5) We have a partial residual.	 *    Use residual_sgptr to determine	 *    where we are.	 */	hscb = scb->hscb;	sgptr = ahc_le32toh(hscb->sgptr);	if ((sgptr & SG_RESID_VALID) == 0)		/* Case 1 */		return;	sgptr &= ~SG_RESID_VALID;	if ((sgptr & SG_LIST_NULL) != 0)		/* Case 2 */		return;	spkt = &hscb->shared_data.status;	resid_sgptr = ahc_le32toh(spkt->residual_sg_ptr);	if ((sgptr & SG_FULL_RESID) != 0) {		/* Case 3 */		resid = ahc_get_transfer_length(scb);	} else if ((resid_sgptr & SG_LIST_NULL) != 0) {		/* Case 4 */		return;	} else if ((resid_sgptr & ~SG_PTR_MASK) != 0) {		panic("Bogus resid sgptr value 0x%x\n", resid_sgptr);	} else {		struct ahc_dma_seg *sg;		/*		 * Remainder of the SG where the transfer		 * stopped.  		 */		resid = ahc_le32toh(spkt->residual_datacnt) & AHC_SG_LEN_MASK;		sg = ahc_sg_bus_to_virt(scb, resid_sgptr & SG_PTR_MASK);		/* The residual sg_ptr always points to the next sg */		sg--;		/*		 * Add up the contents of all residual		 * SG segments that are after the SG where		 * the transfer stopped.		 */		while ((ahc_le32toh(sg->len) & AHC_DMA_LAST_SEG) == 0) {			sg++;			resid += ahc_le32toh(sg->len) & AHC_SG_LEN_MASK;		}	}	if ((scb->flags & SCB_SENSE) == 0)		ahc_set_residual(scb, resid);	else		ahc_set_sense_residual(scb, resid);#ifdef AHC_DEBUG	if (ahc_debug & AHC_SHOWMISC) {		ahc_print_path(scb->ahc_softc, scb);		printf("Handled Residual of %d bytes\n", resid);	}#endif}