⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scsi.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
static intwait_for_select(hd)	volatile register struct scsidevice *hd;{	u_char ints;	while ((ints = hd->scsi_ints) == 0)		DELAY(1);	hd->scsi_ints = ints;	return (!(hd->scsi_ssts & SSTS_INITIATOR));}static intixfer_start(hd, len, phase, wait)	volatile register struct scsidevice *hd;	int len;	u_char phase;	register int wait;{	hd->scsi_tch = len >> 16;	hd->scsi_tcm = len >> 8;	hd->scsi_tcl = len;	hd->scsi_pctl = phase;	hd->scsi_tmod = 0; /*XXX*/	hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR;	/* wait for xfer to start or svc_req interrupt */	while ((hd->scsi_ssts & SSTS_BUSY) == 0) {		if (hd->scsi_ints || --wait < 0) {#ifdef DEBUG			if (scsi_debug)				printf("ixfer_start fail: i%x, w%d\n",				       hd->scsi_ints, wait);#endif			HIST(ixstart_wait, wait)			return (0);		}		DELAY(1);	}	HIST(ixstart_wait, wait)	return (1);}static intixfer_out(hd, len, buf)	volatile register struct scsidevice *hd;	int len;	register u_char *buf;{	register int wait = scsi_data_wait;	for (; len > 0; --len) {		while (hd->scsi_ssts & SSTS_DREG_FULL) {			if (hd->scsi_ints || --wait < 0) {#ifdef DEBUG				if (scsi_debug)					printf("ixfer_out fail: l%d i%x w%d\n",					       len, hd->scsi_ints, wait);#endif				HIST(ixout_wait, wait)				return (len);			}			DELAY(1);		}		hd->scsi_dreg = *buf++;	}	HIST(ixout_wait, wait)	return (0);}static voidixfer_in(hd, len, buf)	volatile register struct scsidevice *hd;	int len;	register u_char *buf;{	register int wait = scsi_data_wait;	for (; len > 0; --len) {		while (hd->scsi_ssts & SSTS_DREG_EMPTY) {			if (hd->scsi_ints || --wait < 0) {				while (! (hd->scsi_ssts & SSTS_DREG_EMPTY)) {					*buf++ = hd->scsi_dreg;					--len;				}#ifdef DEBUG				if (scsi_debug)					printf("ixfer_in fail: l%d i%x w%d\n",					       len, hd->scsi_ints, wait);#endif				HIST(ixin_wait, wait)				return;			}			DELAY(1);		}		*buf++ = hd->scsi_dreg;	}	HIST(ixin_wait, wait)}static intmxfer_in(hd, len, buf, phase)	volatile register struct scsidevice *hd;	register int len;	register u_char *buf;	register u_char phase;{	register int wait = scsi_cmd_wait;	register int i;	hd->scsi_tmod = 0;	for (i = 0; i < len; ++i) {		/*		 * manual sez: reset ATN before ACK is sent.		 */		if (hd->scsi_psns & PSNS_ATN)			hd->scsi_scmd = SCMD_RST_ATN;		/*		 * wait for the request line (which says the target		 * wants to give us data).  If the phase changes while		 * we're waiting, we're done.		 */		while ((hd->scsi_psns & PSNS_REQ) == 0) {			if (--wait < 0) {				HIST(mxin_wait, wait)				return (-1);			}			if ((hd->scsi_psns & PHASE) != phase ||			    (hd->scsi_ssts & SSTS_INITIATOR) == 0)				goto out;			DELAY(1);		}		/*		 * set ack (which says we're ready for the data, wait for		 * req to go away (target says data is available), grab the		 * data, then reset ack (say we've got the data).		 */		hd->scsi_pctl = phase;		hd->scsi_scmd = SCMD_SET_ACK;		while (hd->scsi_psns & PSNS_REQ) {			if (--wait < 0) {				HIST(mxin_wait, wait)				return (-2);			}			DELAY(1);		}		*buf++ = hd->scsi_temp;		hd->scsi_scmd = SCMD_RST_ACK;	}out:	HIST(mxin_wait, wait)	/*	 * Wait for manual transfer to finish.	 * Avoids occasional "unexpected phase" errors in finishxfer	 * formerly addressed by per-slave delays.	 */	wait = scsi_cmd_wait;	while ((hd->scsi_ssts & SSTS_ACTIVE) == SSTS_INITIATOR) {		if (--wait < 0)			break;		DELAY(1);	}	HIST(mxin2_wait, wait)	return (i);}/* * SCSI 'immediate' command:  issue a command to some SCSI device * and get back an 'immediate' response (i.e., do programmed xfer * to get the response data).  'cbuf' is a buffer containing a scsi * command of length clen bytes.  'buf' is a buffer of length 'len' * bytes for data.  The transfer direction is determined by the device * (i.e., by the scsi bus data xfer phase).  If 'len' is zero, the * command must supply no data.  'xferphase' is the bus phase the * caller expects to happen after the command is issued.  It should * be one of DATA_IN_PHASE, DATA_OUT_PHASE or STATUS_PHASE. */static intscsiicmd(hs, target, cbuf, clen, buf, len, xferphase)	struct scsi_softc *hs;	int target;	u_char *cbuf;	int clen;	u_char *buf;	int len;	u_char xferphase;{	volatile register struct scsidevice *hd =				(struct scsidevice *)hs->sc_hc->hp_addr;	u_char phase, ints;	register int wait;	/* select the SCSI bus (it's an error if bus isn't free) */	if (issue_select(hd, target, hs->sc_scsi_addr))		return (-1);	if (wait_for_select(hd))		return (-1);	/*	 * Wait for a phase change (or error) then let the device	 * sequence us through the various SCSI phases.	 */	hs->sc_stat[0] = 0xff;	hs->sc_msg[0] = 0xff;	phase = CMD_PHASE;	while (1) {		wait = scsi_cmd_wait;		switch (phase) {		case CMD_PHASE:			if (ixfer_start(hd, clen, phase, wait))				if (ixfer_out(hd, clen, cbuf))					goto abort;			phase = xferphase;			break;		case DATA_IN_PHASE:			if (len <= 0)				goto abort;			wait = scsi_data_wait;			if (ixfer_start(hd, len, phase, wait) ||			    !(hd->scsi_ssts & SSTS_DREG_EMPTY))				ixfer_in(hd, len, buf);			phase = STATUS_PHASE;			break;		case DATA_OUT_PHASE:			if (len <= 0)				goto abort;			wait = scsi_data_wait;			if (ixfer_start(hd, len, phase, wait)) {				if (ixfer_out(hd, len, buf))					goto abort;			}			phase = STATUS_PHASE;			break;		case STATUS_PHASE:			wait = scsi_data_wait;			if (ixfer_start(hd, sizeof(hs->sc_stat), phase, wait) ||			    !(hd->scsi_ssts & SSTS_DREG_EMPTY))				ixfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat);			phase = MESG_IN_PHASE;			break;		case MESG_IN_PHASE:			if (ixfer_start(hd, sizeof(hs->sc_msg), phase, wait) ||			    !(hd->scsi_ssts & SSTS_DREG_EMPTY)) {				ixfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg);				hd->scsi_scmd = SCMD_RST_ACK;			}			phase = BUS_FREE_PHASE;			break;		case BUS_FREE_PHASE:			goto out;		default:			printf("scsi%d: unexpected phase %d in icmd from %d\n",				hs->sc_hc->hp_unit, phase, target);			goto abort;		}		/* wait for last command to complete */		while ((ints = hd->scsi_ints) == 0) {			if (--wait < 0) {				HIST(cxin_wait, wait)				goto abort;			}			DELAY(1);		}		HIST(cxin_wait, wait)		hd->scsi_ints = ints;		if (ints & INTS_SRV_REQ)			phase = hd->scsi_psns & PHASE;		else if (ints & INTS_DISCON)			goto out;		else if ((ints & INTS_CMD_DONE) == 0) {			scsierror(hs, hd, ints);			goto abort;		}	}abort:	scsiabort(hs, hd, "icmd");out:	return (hs->sc_stat[0]);}/* * Finish SCSI xfer command:  After the completion interrupt from * a read/write operation, sequence through the final phases in * programmed i/o.  This routine is a lot like scsiicmd except we * skip (and don't allow) the select, cmd out and data in/out phases. */static voidfinishxfer(hs, hd, target)	struct scsi_softc *hs;	volatile register struct scsidevice *hd;	int target;{	u_char phase, ints;	/*	 * We specified padding xfer so we ended with either a phase	 * change interrupt (normal case) or an error interrupt (handled	 * elsewhere).  Reset the board dma logic then try to get the	 * completion status & command done msg.  The reset confuses	 * the SPC REQ/ACK logic so we have to do any status/msg input	 * operations via 'manual xfer'.	 */	if (hd->scsi_ssts & SSTS_BUSY) {		int wait = scsi_cmd_wait;		/* wait for dma operation to finish */		while (hd->scsi_ssts & SSTS_BUSY) {			if (--wait < 0) {#ifdef DEBUG				if (scsi_debug)					printf("finishxfer fail: ssts %x\n",					       hd->scsi_ssts);#endif				HIST(fxfr_wait, wait)				goto abort;			}		}		HIST(fxfr_wait, wait)	}	hd->scsi_scmd |= SCMD_PROG_XFR;	hd->scsi_sctl |= SCTL_CTRLRST;	DELAY(1);	hd->scsi_sctl &=~ SCTL_CTRLRST;	hd->scsi_hconf = 0;	/*	 * The following delay is definitely needed when trying to	 * write on a write protected disk (in the optical jukebox anyways),	 * but we shall see if other unexplained machine freezeups	 * also stop occuring...  A value of 5 seems to work but	 * 10 seems safer considering the potential consequences.	 */	DELAY(10);	hs->sc_stat[0] = 0xff;	hs->sc_msg[0] = 0xff;	hd->scsi_csr = 0;	hd->scsi_ints = ints = hd->scsi_ints;	while (1) {		phase = hd->scsi_psns & PHASE;		switch (phase) {		case STATUS_PHASE:			if (mxfer_in(hd, sizeof(hs->sc_stat), hs->sc_stat,				     phase) <= 0)				goto abort;			break;		case MESG_IN_PHASE:			if (mxfer_in(hd, sizeof(hs->sc_msg), hs->sc_msg,				     phase) < 0)				goto abort;			break;		case BUS_FREE_PHASE:			return;		default:			printf("scsi%d: unexpected phase %d in finishxfer from %d\n",				hs->sc_hc->hp_unit, phase, target);			goto abort;		}		if (ints = hd->scsi_ints) {			hd->scsi_ints = ints;			if (ints & INTS_DISCON)				return;			else if (ints & ~(INTS_SRV_REQ|INTS_CMD_DONE)) {				scsierror(hs, hd, ints);				break;			}		}		if ((hd->scsi_ssts & SSTS_INITIATOR) == 0)			return;	}abort:	scsiabort(hs, hd, "finishxfer");	hs->sc_stat[0] = 0xfe;}intscsi_test_unit_rdy(ctlr, slave, unit)	int ctlr, slave, unit;{	register struct scsi_softc *hs = &scsi_softc[ctlr];	static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };	cdb.lun = unit;	return (scsiicmd(hs, slave, &cdb, sizeof(cdb), (u_char *)0, 0,			 STATUS_PHASE));}intscsi_request_sense(ctlr, slave, unit, buf, len)	int ctlr, slave, unit;	u_char *buf;	unsigned len;{	register struct scsi_softc *hs = &scsi_softc[ctlr];	static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };	cdb.lun = unit;	cdb.len = len;	return (scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE));}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -