bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF);
bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_ISTAT, ISTAT_INTF); } if ((istat &(ISTAT_DIP | ISTAT_SIP | ISTAT_ABRT)) == (ISTAT_DIP | ISTAT_ABRT)) {  bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_ISTAT, 0);
siop_intr(v)	void *v;{	struct siop_softc *sc = v;	struct siop_target *siop_target;	struct siop_cmd *siop_cmd;	struct siop_lun *siop_lun;	struct scsi_xfer *xs;	int istat, sist = 0, sstat1 = 0, dstat = 0;	u_int32_t irqcode = 0;	int need_reset = 0;	int offset, target, lun, tag;	bus_addr_t dsa;	struct siop_cbd *cbdp;	int freetarget = 0;	int restart = 0;	istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT);	if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)		return 0;	INCSTAT(siop_stat_intr);	if (istat & ISTAT_INTF) {		printf("INTRF\n");		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF);	}	/* use DSA to find the current siop_cmd */	dsa = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA);	for (cbdp = TAILQ_FIRST(&sc->cmds); cbdp != NULL;	    cbdp = TAILQ_NEXT(cbdp, next)) {		if (dsa >= cbdp->xferdma->dm_segs[0].ds_addr &&	    	    dsa < cbdp->xferdma->dm_segs[0].ds_addr + PAGE_SIZE) {			dsa -= cbdp->xferdma->dm_segs[0].ds_addr;			siop_cmd = &cbdp->cmds[dsa / sizeof(struct siop_xfer)];			siop_table_sync(siop_cmd,			    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);			break;		}	} 	if (cbdp == NULL) {		siop_cmd = NULL;	}	if (siop_cmd) {		xs = siop_cmd->xs;		siop_target = siop_cmd->siop_target;		target = siop_cmd->xs->sc_link->target;		lun = siop_cmd->xs->sc_link->lun;		tag = siop_cmd->tag;		siop_lun = siop_target->siop_lun[lun];#ifdef DIAGNOSTIC		if (siop_cmd->status != CMDST_ACTIVE &&		    siop_cmd->status != CMDST_SENSE_ACTIVE) {			printf("siop_cmd (lun %d) not active (%d)\n",				lun, siop_cmd->status);			xs = NULL;			siop_target = NULL;			target = -1;			lun = -1;			tag = -1;			siop_lun = NULL;			siop_cmd = NULL;		} else if (siop_lun->siop_tag[tag].active != siop_cmd) {			printf("siop_cmd (lun %d tag %d) not in siop_lun "			    "active (%p != %p)\n", lun, tag, siop_cmd,			    siop_lun->siop_tag[tag].active);		}#endif	} else {		xs = NULL;		siop_target = NULL;		target = -1;		lun = -1;		tag = -1;		siop_lun = NULL;	}	if (istat & ISTAT_DIP) {		dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT);		if (dstat & DSTAT_SSI) {			printf("single step dsp 0x%08x dsa 0x08%x\n",			    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -			    sc->sc_scriptaddr),			    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));			if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 &&			    (istat & ISTAT_SIP) == 0) {				bus_space_write_1(sc->sc_rt, sc->sc_rh,				    SIOP_DCNTL, bus_space_read_1(sc->sc_rt,				    sc->sc_rh, SIOP_DCNTL) | DCNTL_STD);			}			return 1;		}		if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) {			printf("DMA IRQ:");			if (dstat & DSTAT_IID)				printf("Illegal instruction");			if (dstat & DSTAT_ABRT)				printf(" abort");			if (dstat & DSTAT_BF)				printf(" bus fault");			if (dstat & DSTAT_MDPE)				printf(" parity");			if (dstat & DSTAT_DFE)				printf(" dma fifo empty");			printf(", DSP=0x%x DSA=0x%x: ",			    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -				sc->sc_scriptaddr),			    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));			if (siop_cmd)				printf("last msg_in=0x%x status=0x%x\n",				    siop_cmd->siop_tables.msg_in[0],				    letoh32(siop_cmd->siop_tables.status));			else 				printf("%s: current DSA invalid\n",				    sc->sc_dev.dv_xname);			need_reset = 1;		}	}	if (istat & ISTAT_SIP) {		if (istat & ISTAT_DIP)			delay(10);		/*		 * Can't read sist0 & sist1 independantly, or we have to		 * insert delay		 */		sist = bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_SIST0);		sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1);#ifdef SIOP_DEBUG_INTR		printf("scsi interrupt, sist=0x%x sstat1=0x%x "		    "DSA=0x%x DSP=0x%lx\n", sist,		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),		    (u_long)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -		    sc->sc_scriptaddr));#endif		if (sist & SIST0_RST) {			siop_handle_reset(sc);			siop_start(sc);			/* no table to flush here */			return 1;		}		if (sist & SIST0_SGE) {			if (siop_cmd)				sc_print_addr(xs->sc_link);			else				printf("%s:", sc->sc_dev.dv_xname);			printf("scsi gross error\n");			goto reset;		}		if ((sist & SIST0_MA) && need_reset == 0) {			if (siop_cmd) { 				int scratcha0;				dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,				    SIOP_DSTAT);				/*				 * first restore DSA, in case we were in a S/G				 * operation.				 */				bus_space_write_4(sc->sc_rt, sc->sc_rh,				    SIOP_DSA, siop_cmd->dsa);				scratcha0 = bus_space_read_1(sc->sc_rt,				    sc->sc_rh, SIOP_SCRATCHA);				switch (sstat1 & SSTAT1_PHASE_MASK) {				case SSTAT1_PHASE_STATUS:				/*				 * Previous phase may have aborted for any reason				 * (for example, the target has less data to				 * transfer than requested). Just go to status				 * and the command should terminate.				 */					INCSTAT(siop_stat_intr_shortxfer);					if ((dstat & DSTAT_DFE) == 0)						siop_clearfifo(sc);					/* no table to flush here */					CALL_SCRIPT(Ent_status);					return 1;				case SSTAT1_PHASE_MSGIN:					/*					 * Target may be ready to disconnect.					 * Save data pointers just in case.					 */					INCSTAT(siop_stat_intr_xferdisc);					if (scratcha0 & A_flag_data)						siop_sdp(siop_cmd);					else if ((dstat & DSTAT_DFE) == 0)						siop_clearfifo(sc);					bus_space_write_1(sc->sc_rt, sc->sc_rh,					    SIOP_SCRATCHA,					    scratcha0 & ~A_flag_data);					siop_table_sync(siop_cmd,					    BUS_DMASYNC_PREREAD |					    BUS_DMASYNC_PREWRITE);					CALL_SCRIPT(Ent_msgin);					return 1;				}				printf("%s: unexpected phase mismatch %d\n",				    sc->sc_dev.dv_xname,				    sstat1 & SSTAT1_PHASE_MASK);			} else {				printf("%s: phase mismatch without command\n",				    sc->sc_dev.dv_xname);			}			need_reset = 1;		}		if (sist & SIST0_PAR) {			/* parity error, reset */			if (siop_cmd)				sc_print_addr(xs->sc_link);			else				printf("%s:", sc->sc_dev.dv_xname);			printf("parity error\n");			goto reset;		}		if ((sist & (SIST1_STO << 8)) && need_reset == 0) {			/* selection time out, assume there's no device here */			if (siop_cmd) {				siop_cmd->status = CMDST_DONE;				xs->error = XS_SELTIMEOUT;				freetarget = 1;				goto end;			} else {				printf("%s: selection timeout without "				    "command\n", sc->sc_dev.dv_xname);				need_reset = 1;			}		}		if (sist & SIST0_UDC) {			/*			 * unexpected disconnect. Usually the target signals			 * a fatal condition this way. Attempt to get sense.			 */			 if (siop_cmd) {				siop_cmd->siop_tables.status =				    htole32(SCSI_CHECK);				goto end;			}			printf("%s: unexpected disconnect without "			    "command\n", sc->sc_dev.dv_xname);			goto reset;		}		if (sist & (SIST1_SBMC << 8)) {			/* SCSI bus mode change */			if (siop_modechange(sc) == 0 || need_reset == 1)				goto reset;			if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) {				/*				 * We have a script interrupt. It will				 * restart the script.				 */				goto scintr;			}			/*			 * Else we have to restart the script ourself, at the			 * interrupted instruction.			 */			bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,			    bus_space_read_4(sc->sc_rt, sc->sc_rh,			    SIOP_DSP) - 8);			return 1;		}		/* Else it's an unhandled exception (for now). */		printf("%s: unhandled scsi interrupt, sist=0x%x sstat1=0x%x "		    "DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname, sist,		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),		    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -		    sc->sc_scriptaddr));		if (siop_cmd) {			siop_cmd->status = CMDST_DONE;			xs->error = XS_SELTIMEOUT;			goto end;		}		need_reset = 1;	}	if (need_reset) {reset:		/* fatal error, reset the bus */		siop_resetbus(sc);		/* no table to flush here */		return 1;	}scintr:	if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */		irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh,		    SIOP_DSPS);#ifdef SIOP_DEBUG_INTR		printf("script interrupt 0x%x\n", irqcode);#endif		/*		 * no command, or an inactive command is only valid for a		 * reselect interrupt		 */		if ((irqcode & 0x80) == 0) {			if (siop_cmd == NULL) {				printf("%s: script interrupt (0x%x) with "				    "invalid DSA !!!\n", sc->sc_dev.dv_xname,				    irqcode);				goto reset;			}			if (siop_cmd->status != CMDST_ACTIVE &&			    siop_cmd->status != CMDST_SENSE_ACTIVE) {				printf("%s: command with invalid status "				    "(IRQ code 0x%x current status %d) !\n",				    sc->sc_dev.dv_xname,				    irqcode, siop_cmd->status);				xs = NULL;			}		}		switch(irqcode) {		case A_int_err:			printf("error, DSP=0x%x\n",			    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh,			    SIOP_DSP) - sc->sc_scriptaddr));			if (xs) {				xs->error = XS_SELTIMEOUT;				goto end;			} else {				goto reset;			}		case A_int_reseltarg:			printf("%s: reselect with invalid target\n",				    sc->sc_dev.dv_xname);			goto reset;		case A_int_resellun: 			INCSTAT(siop_stat_intr_lunresel);			target = bus_space_read_1(sc->sc_rt, sc->sc_rh,			    SIOP_SCRATCHA) & 0xf;			lun = bus_space_read_1(sc->sc_rt, sc->sc_rh,			    SIOP_SCRATCHA + 1);			tag = bus_space_read_1(sc->sc_rt, sc->sc_rh,			    SIOP_SCRATCHA + 2);			siop_target = sc->targets[target];			if (siop_target == NULL) {				printf("%s: reselect with invalid "				    "target %d\n", sc->sc_dev.dv_xname, target);				goto reset;			}			siop_lun = siop_target->siop_lun[lun];			if (siop_lun == NULL) {				printf("%s: target %d reselect with invalid "				    "lun %d\n", sc->sc_dev.dv_xname,				    target, lun);				goto reset;			}			if (siop_lun->siop_tag[tag].active == NULL) {				printf("%s: target %d lun %d tag %d reselect "				    "without command\n", sc->sc_dev.dv_xname,				    target, lun, tag);				goto reset;			}			siop_cmd = siop_lun->siop_tag[tag].active;			bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,			    siop_cmd->dsa + sizeof(struct siop_xfer_common) +			    Ent_ldsa_reload_dsa);			siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);			return 1;		case A_int_reseltag:			printf("%s: reselect with invalid tag\n",				    sc->sc_dev.dv_xname);			goto reset;		case A_int_msgin:		{			int msgin = bus_space_read_1(sc->sc_rt, sc->sc_rh,			    SIOP_SFBR);			if (msgin == MSG_MESSAGE_REJECT) {				int msg, extmsg;				if (siop_cmd->siop_tables.msg_out[0] & 0x80) {					/*					 * Message was part of an identify +					 * something else. Identify shouldn't					 * have been rejected.					 */					msg = siop_cmd->siop_tables.msg_out[1];					extmsg =					    siop_cmd->siop_tables.msg_out[3];				} else {					msg = siop_cmd->siop_tables.msg_out[0];					extmsg =					    siop_cmd->siop_tables.msg_out[2];				}				if (msg == MSG_MESSAGE_REJECT) {					/* MSG_REJECT for a MSG_REJECT! */					if (xs)						sc_print_addr(xs->sc_link);					else						printf("%s: ",						   sc->sc_dev.dv_xname);					printf("our reject message was "					    "rejected\n");					goto reset;				}				if (msg == MSG_EXTENDED &&				    extmsg == MSG_EXT_WDTR) {					if ((siop_target->flags & TARF_SYNC)					    == 0) {						siop_target->status = TARST_OK;						siop_print_info(sc, target);						/* no table to flush here */						CALL_SCRIPT(Ent_msgin_ack);						return 1;					}					siop_target->status = TARST_SYNC_NEG;					siop_sdtr_msg(siop_cmd, 0,					    sc->min_st_sync, sc->maxoff);					siop_table_sync(siop_cmd,					    BUS_DMASYNC_PREREAD |					    BUS_DMASYNC_PREWRITE);					CALL_SCRIPT(Ent_send_msgout);					return 1;				} else if (msg == MSG_EXTENDED &&				    extmsg == MSG_EXT_SDTR) {					siop_target->status = TARST_OK;					siop_print_info(sc, target);					/* no table to flush here */					CALL_SCRIPT(Ent_msgin_ack);					return 1;				} else if (msg == MSG_SIMPLE_Q_TAG || 				    msg == MSG_HEAD_OF_Q_TAG ||				    msg == MSG_ORDERED_Q_TAG) {					if (siop_handle_qtag_reject(					    siop_cmd) == -1)						goto reset;					CALL_SCRIPT(Ent_msgin_ack);					return 1;				}				if (xs)					sc_print_addr(xs->sc_link);				else					printf("%s: ", sc->sc_dev.dv_xname);				if (msg == MSG_EXTENDED) {					printf("scsi message reject, extended "					    "message sent was 0x%x\n", extmsg);				} else {					printf("scsi message reject, message "					    "sent was 0x%x\n", msg);				}				/* no table to flush here */				CALL_SCRIPT(Ent_msgin_ack);				return 1;			}			if (xs)				sc_print_addr(xs->sc_link);			else				printf("%s: ", sc->sc_dev.dv_xname);			printf("unhandled message 0x%x\n",			    siop_cmd->siop_tables.msg_in[0]);			siop_cmd->siop_tables.msg_out[0] = MSG_MESSAGE_REJECT;			siop_cmd->siop_tables.t_msgout.count= htole32(1);			siop_table_sync(siop_cmd,			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);			CALL_SCRIPT(Ent_send_msgout);			return 1;		}		case A_int_extmsgin:#ifdef SIOP_DEBUG_INTR			printf("extended message: msg 0x%x len %d\n",			    siop_cmd->siop_tables.msg_in[2], 			    siop_cmd->siop_tables.msg_in[1]);#endif			if (siop_cmd->siop_tables.msg_in[1] > 6)				printf("%s: extended message too big (%d)\n",				    sc->sc_dev.dv_xname,				    siop_cmd->siop_tables.msg_in[1]);			siop_cmd->siop_tables.t_extmsgdata.count =			    htole32(siop_cmd->siop_tables.msg_in[1] - 1);			siop_table_sync(siop_cmd,			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);			CALL_SCRIPT(Ent_get_extmsgdata);			return 1;		case A_int_extmsgdata:		{#ifdef SIOP_DEBUG_INTR			{			int i;			printf("extended message: 0x%x, data:",			    siop_cmd->siop_tables.msg_in[2]);			for (i = 3; i < 2 + siop_cmd->siop_tables.msg_in[1];			    i++)				printf(" 0x%x",				    siop_cmd->siop_tables.msg_in[i]);			printf("\n");			}#endif			int neg_action = SIOP_NEG_NOP;			const char *neg_name = "";			switch (siop_cmd->siop_tables.msg_in[2]) {			case MSG_EXT_WDTR:				neg_action = siop_wdtr_neg(siop_cmd);				neg_name = "wdtr";				break;			case MSG_EXT_SDTR:				neg_action = siop_sdtr_neg(siop_cmd);				neg_name = "sdtr";				break;			case MSG_EXT_PPR:				neg_action = siop_ppr_neg(siop_cmd);				neg_name = "ppr";				break;			default:				neg_action = SIOP_NEG_MSGREJ;				break;			}			switch (neg_action) {			case SIOP_NEG_NOP:				break;			case SIOP_NEG_MSGOUT:				siop_update_scntl3(sc, siop_cmd->siop_target);				siop_table_sync(siop_cmd,				    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);				CALL_SCRIPT(Ent_send_msgout);				break;			case SIOP_NEG_ACK:				siop_update_scntl3(sc, siop_cmd->siop_target);				siop_table_sync(siop_cmd,				    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);				CALL_SCRIPT(Ent_msgin_ack);				break;			case SIOP_NEG_MSGREJ:				siop_cmd->siop_tables.msg_out[0] = MSG_MESSAGE_REJECT;				siop_cmd->siop_tables.t_msgout.count = htole32(1);				siop_table_sync(siop_cmd,				    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);				CALL_SCRIPT(Ent_send_msgout);				break;			default:				panic("invalid return value from siop_%s_neg(): 0x%x", neg_name, neg_action);			}						return (1);		}		case A_int_disc:			INCSTAT(siop_stat_intr_sdp);			offset = bus_space_read_1(sc->sc_rt, sc->sc_rh,			    SIOP_SCRATCHA + 1);#ifdef SIOP_DEBUG_DR			printf("disconnect offset %d\n", offset);#endif			if (offset > SIOP_NSG) {				printf("%s: bad offset for disconnect (%d)\n",				    sc->sc_dev.dv_xname, offset);				goto reset;			}			/* 			 * offset == SIOP_NSG may be a valid condition if			 * we get a sdp when the xfer is done.			 * Don't call memmove in this case.			 */			if (offset < SIOP_NSG) {				bcopy(&siop_cmd->siop_tables.data[offset],				    &siop_cmd->siop_tables.data[0],				    (SIOP_NSG - offset) * sizeof(struct scr_table));				siop_table_sync(siop_cmd,				    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);			}			CALL_SCRIPT(Ent_script_sched);			/* check if we can put some command in scheduler */			siop_start(sc);			return 1;		case A_int_resfail:			printf("reselect failed\n");			CALL_SCRIPT(Ent_script_sched);			return  1;		case A_int_done:			if (xs == NULL) {				printf("%s: done without command, DSA=0x%lx\n",				    sc->sc_dev.dv_xname, (u_long)siop_cmd->dsa);				siop_cmd->status = CMDST_FREE;				siop_start(sc);				CALL_SCRIPT(Ent_script_sched);				return 1;			}#ifdef SIOP_DEBUG_INTR			printf("done, DSA=0x%lx target id 0x%x last msg "			    "in=0x%x status=0x%x\n", (u_long)siop_cmd->dsa,			    letoh32(siop_cmd->siop_tables.id),			    siop_cmd->siop_tables.msg_in[0],			    letoh32(siop_cmd->siop_tables.status));#endif			INCSTAT(siop_stat_intr_done);			if (siop_cmd->status == CMDST_SENSE_ACTIVE)				siop_cmd->status = CMDST_SENSE_DONE;			else				siop_cmd->status = CMDST_DONE;			goto end;		default:			printf("unknown irqcode %x\n", irqcode);			if (xs) {				xs->error = XS_SELTIMEOUT;				goto end;			}			goto reset;		}		return 1;	}	/* We can get here if ISTAT_DIP and DSTAT_DFE are the only bits set. */	/* But that *SHOULDN'T* happen. It does on powerpc (at least).	     */	printf("%s: siop_intr() - we should not be here!\n"	    "   istat = 0x%x, dstat = 0x%x, sist = 0x%x, sstat1 = 0x%x\n"	    "   need_reset = %x, irqcode = %x, siop_cmd %s\n",	    sc->sc_dev.dv_xname,	    istat, dstat, sist, sstat1, need_reset, irqcode,	    (siop_cmd == NULL) ? "== NULL" : "!= NULL");	goto reset; /* Where we should have gone in the first place! */end:	/*	 * Restart the script now if command completed properly.	 * Otherwise wait for siop_scsicmd_end(), it may need to put	 * a cmd at the front of the queue.	 */	if (letoh32(siop_cmd->siop_tables.status) == SCSI_OK &&	    TAILQ_FIRST(&sc->urgent_list) != NULL)		CALL_SCRIPT(Ent_script_sched);	else		restart = 1;	siop_scsicmd_end(siop_cmd);	siop_lun->siop_tag[tag].active = NULL;	if (siop_cmd->status == CMDST_FREE) {		TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);		siop_lun->lun_flags &= ~SIOP_LUNF_FULL;		if (freetarget && siop_target->status == TARST_PROBING)			siop_del_dev(sc, target, lun);	}	siop_start(sc);	if (restart)		CALL_SCRIPT(Ent_script_sched);	return 1;}