int	have_qregs;
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);
ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,		   int lun, u_int tag, role_t role, uint32_t status,		   ahc_search_action action){	struct	scb *scb;	struct	scb *prev_scb;	uint8_t qinstart;	uint8_t qinpos;	uint8_t qintail;	uint8_t next, prev;	uint8_t curscbptr;	int	found;	int	maxtarget;	int	i;	int	have_qregs;	qintail = ahc->qinfifonext;	have_qregs = (ahc->features & AHC_QUEUE_REGS) != 0;	if (have_qregs) {		qinstart = ahc_inb(ahc, SNSCB_QOFF);		ahc_outb(ahc, SNSCB_QOFF, qinstart);	} else		qinstart = ahc_inb(ahc, QINPOS);	qinpos = qinstart;	next = ahc_inb(ahc, NEXT_QUEUED_SCB);	found = 0;	prev_scb = NULL;		if (action == SEARCH_COMPLETE) {		/*		 * Don't attempt to run any queued untagged transactions		 * until we are done with the abort process.		 */		ahc_freeze_untagged_queues(ahc);	}	/*	 * Start with an empty queue.  Entries that are not chosen	 * for removal will be re-added to the queue as we go.	 */	ahc->qinfifonext = qinpos;	ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag);	while (qinpos != qintail) {		scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinpos]);		if (scb == NULL) {			printf("qinpos = %d, SCB index = %d\n",				qinpos, ahc->qinfifo[qinpos]);			panic("Loop 1\n");		}		if (ahc_match_scb(ahc, scb, target, channel, lun, tag, role)) {			/*			 * We found an scb that needs to be acted on.			 */			found++;			switch (action) {			case SEARCH_COMPLETE:			{				cam_status ostat;				cam_status cstat;				ostat = ahc_get_transaction_status(scb);				if (ostat == CAM_REQ_INPROG)					ahc_set_transaction_status(scb,								   status);				cstat = ahc_get_transaction_status(scb);				if (cstat != CAM_REQ_CMP)					ahc_freeze_scb(scb);				if ((scb->flags & SCB_ACTIVE) == 0)					printf("Inactive SCB in qinfifo\n");				ahc_done(ahc, scb);				/* FALLTHROUGH */			}			case SEARCH_REMOVE:				break;			case SEARCH_COUNT:				ahc_qinfifo_requeue(ahc, prev_scb, scb);				prev_scb = scb;				break;			}		} else {			ahc_qinfifo_requeue(ahc, prev_scb, scb);			prev_scb = scb;		}		qinpos++;	}	if ((ahc->features & AHC_QUEUE_REGS) != 0) {		ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);	} else {		ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);	}	if (action != SEARCH_COUNT	 && (found != 0)	 && (qinstart != ahc->qinfifonext)) {		/*		 * The sequencer may be in the process of dmaing		 * down the SCB at the beginning of the queue.		 * This could be problematic if either the first,		 * or the second SCB is removed from the queue		 * (the first SCB includes a pointer to the "next"		 * SCB to dma). If we have removed any entries, swap		 * the first element in the queue with the next HSCB		 * so the sequencer will notice that NEXT_QUEUED_SCB		 * has changed during its dma attempt and will retry		 * the DMA.		 */		scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinstart]);		if (scb == NULL) {			printf("found = %d, qinstart = %d, qinfifionext = %d\n",				found, qinstart, ahc->qinfifonext);			panic("First/Second Qinfifo fixup\n");		}		/*		 * ahc_swap_with_next_hscb forces our next pointer to		 * point to the reserved SCB for future commands.  Save		 * and restore our original next pointer to maintain		 * queue integrity.		 */		next = scb->hscb->next;		ahc->scb_data->scbindex[scb->hscb->tag] = NULL;		ahc_swap_with_next_hscb(ahc, scb);		scb->hscb->next = next;		ahc->qinfifo[qinstart] = scb->hscb->tag;		/* Tell the card about the new head of the qinfifo. */		ahc_outb(ahc, NEXT_QUEUED_SCB, scb->hscb->tag);		/* Fixup the tail "next" pointer. */		qintail = ahc->qinfifonext - 1;		scb = ahc_lookup_scb(ahc, ahc->qinfifo[qintail]);		scb->hscb->next = ahc->next_queued_scb->hscb->tag;	}	/*	 * Search waiting for selection list.	 */	curscbptr = ahc_inb(ahc, SCBPTR);	next = ahc_inb(ahc, WAITING_SCBH);  /* Start at head of list. */	prev = SCB_LIST_NULL;	while (next != SCB_LIST_NULL) {		uint8_t scb_index;		ahc_outb(ahc, SCBPTR, next);		scb_index = ahc_inb(ahc, SCB_TAG);		if (scb_index >= ahc->scb_data->numscbs) {			printf("Waiting List inconsistency. "			       "SCB index == %d, yet numscbs == %d.",			       scb_index, ahc->scb_data->numscbs);			ahc_dump_card_state(ahc);			panic("for safety");		}		scb = ahc_lookup_scb(ahc, scb_index);		if (scb == NULL) {			printf("scb_index = %d, next = %d\n",				scb_index, next);			panic("Waiting List traversal\n");		}		if (ahc_match_scb(ahc, scb, target, channel,				  lun, SCB_LIST_NULL, role)) {			/*			 * We found an scb that needs to be acted on.			 */			found++;			switch (action) {			case SEARCH_COMPLETE:			{				cam_status ostat;				cam_status cstat;				ostat = ahc_get_transaction_status(scb);				if (ostat == CAM_REQ_INPROG)					ahc_set_transaction_status(scb,								   status);				cstat = ahc_get_transaction_status(scb);				if (cstat != CAM_REQ_CMP)					ahc_freeze_scb(scb);				if ((scb->flags & SCB_ACTIVE) == 0)					printf("Inactive SCB in Waiting List\n");				ahc_done(ahc, scb);				/* FALLTHROUGH */			}			case SEARCH_REMOVE:				next = ahc_rem_wscb(ahc, next, prev);				break;			case SEARCH_COUNT:				prev = next;				next = ahc_inb(ahc, SCB_NEXT);				break;			}		} else {						prev = next;			next = ahc_inb(ahc, SCB_NEXT);		}	}	ahc_outb(ahc, SCBPTR, curscbptr);	/*	 * And lastly, the untagged holding queues.	 */	i = 0;	if ((ahc->flags & AHC_SCB_BTT) == 0) {		maxtarget = 16;		if (target != CAM_TARGET_WILDCARD) {			i = target;			if (channel == 'B')				i += 8;			maxtarget = i + 1;		}	} else {		maxtarget = 0;	}	for (; i < maxtarget; i++) {		struct scb_tailq *untagged_q;		struct scb *next_scb;		untagged_q = &(ahc->untagged_queues[i]);		next_scb = TAILQ_FIRST(untagged_q);		while (next_scb != NULL) {			scb = next_scb;			next_scb = TAILQ_NEXT(scb, links.tqe);			/*			 * The head of the list may be the currently			 * active untagged command for a device.			 * We're only searching for commands that			 * have not been started.  A transaction			 * marked active but still in the qinfifo			 * is removed by the qinfifo scanning code			 * above.			 */			if ((scb->flags & SCB_ACTIVE) != 0)				continue;			if (ahc_match_scb(ahc, scb, target, channel,					  lun, SCB_LIST_NULL, role)) {				/*				 * We found an scb that needs to be acted on.				 */				found++;				switch (action) {				case SEARCH_COMPLETE:				{					cam_status ostat;					cam_status cstat;					ostat = ahc_get_transaction_status(scb);					if (ostat == CAM_REQ_INPROG)						ahc_set_transaction_status(scb,								   status);					cstat = ahc_get_transaction_status(scb);					if (cstat != CAM_REQ_CMP)						ahc_freeze_scb(scb);					if ((scb->flags & SCB_ACTIVE) == 0)						printf("Inactive SCB in untaggedQ\n");					ahc_done(ahc, scb);					break;				}				case SEARCH_REMOVE:					TAILQ_REMOVE(untagged_q, scb,						     links.tqe);					break;				case SEARCH_COUNT:					break;				}			}		}	}	if (action == SEARCH_COMPLETE)		ahc_release_untagged_queues(ahc);	return (found);}