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

📄 scsi.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
intscsi_immed_command(ctlr, slave, unit, cdb, buf, len, rd)	int ctlr, slave, unit, rd;	struct scsi_fmt_cdb *cdb;	u_char *buf;	u_int len;{	register struct scsi_softc *hs = &scsi_softc[ctlr];	cdb->cdb[1] |= unit << 5;	return (scsiicmd(hs, slave, cdb->cdb, cdb->len, buf, len,			 rd != 0? DATA_IN_PHASE : DATA_OUT_PHASE));}/* * The following routines are test-and-transfer i/o versions of read/write * for things like reading disk labels and writing core dumps.  The * routine scsigo should be used for normal data transfers, NOT these * routines. */intscsi_tt_read(ctlr, slave, unit, buf, len, blk, bshift)	int ctlr, slave, unit;	u_char *buf;	u_int len;	daddr_t blk;	int bshift;{	register struct scsi_softc *hs = &scsi_softc[ctlr];	struct scsi_cdb10 cdb;	int stat;	int old_wait = scsi_data_wait;	scsi_data_wait = 300000;	bzero(&cdb, sizeof(cdb));	cdb.cmd = CMD_READ_EXT;	cdb.lun = unit;	blk >>= bshift;	cdb.lbah = blk >> 24;	cdb.lbahm = blk >> 16;	cdb.lbalm = blk >> 8;	cdb.lbal = blk;	cdb.lenh = len >> (8 + DEV_BSHIFT + bshift);	cdb.lenl = len >> (DEV_BSHIFT + bshift);	stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_IN_PHASE);	scsi_data_wait = old_wait;	return (stat);}intscsi_tt_write(ctlr, slave, unit, buf, len, blk, bshift)	int ctlr, slave, unit;	u_char *buf;	u_int len;	daddr_t blk;	int bshift;{	register struct scsi_softc *hs = &scsi_softc[ctlr];	struct scsi_cdb10 cdb;	int stat;	int old_wait = scsi_data_wait;	scsi_data_wait = 300000;	bzero(&cdb, sizeof(cdb));	cdb.cmd = CMD_WRITE_EXT;	cdb.lun = unit;	blk >>= bshift;	cdb.lbah = blk >> 24;	cdb.lbahm = blk >> 16;	cdb.lbalm = blk >> 8;	cdb.lbal = blk;	cdb.lenh = len >> (8 + DEV_BSHIFT + bshift);	cdb.lenl = len >> (DEV_BSHIFT + bshift);	stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, DATA_OUT_PHASE);	scsi_data_wait = old_wait;	return (stat);}intscsireq(dq)	register struct devqueue *dq;{	register struct devqueue *hq;	hq = &scsi_softc[dq->dq_ctlr].sc_sq;	insque(dq, hq->dq_back);	if (dq->dq_back == hq)		return(1);	return(0);}intscsiustart(unit)	int unit;{	register struct scsi_softc *hs = &scsi_softc[unit];	hs->sc_dq.dq_ctlr = DMA0 | DMA1;	hs->sc_flags |= SCSI_HAVEDMA;	if (dmareq(&hs->sc_dq))		return(1);	return(0);}voidscsistart(unit)	int unit;{	register struct devqueue *dq;		dq = scsi_softc[unit].sc_sq.dq_forw;	(dq->dq_driver->d_go)(dq->dq_unit);}intscsigo(ctlr, slave, unit, bp, cdb, pad)	int ctlr, slave, unit;	struct buf *bp;	struct scsi_fmt_cdb *cdb;	int pad;{	register struct scsi_softc *hs = &scsi_softc[ctlr];	volatile register struct scsidevice *hd =				(struct scsidevice *)hs->sc_hc->hp_addr;	int i, dmaflags;	u_char phase, ints, cmd;	cdb->cdb[1] |= unit << 5;	/* select the SCSI bus (it's an error if bus isn't free) */	if (issue_select(hd, slave, hs->sc_scsi_addr) || wait_for_select(hd)) {		if (hs->sc_flags & SCSI_HAVEDMA) {			hs->sc_flags &=~ SCSI_HAVEDMA;			dmafree(&hs->sc_dq);		}		return (1);	}	/*	 * Wait for a phase change (or error) then let the device	 * sequence us through command phase (we may have to take	 * a msg in/out before doing the command).  If the disk has	 * to do a seek, it may be a long time until we get a change	 * to data phase so, in the absense of an explicit phase	 * change, we assume data phase will be coming up and tell	 * the SPC to start a transfer whenever it does.  We'll get	 * a service required interrupt later if this assumption is	 * wrong.  Otherwise we'll get a service required int when	 * the transfer changes to status phase.	 */	phase = CMD_PHASE;	while (1) {		register int wait = scsi_cmd_wait;		switch (phase) {		case CMD_PHASE:			if (ixfer_start(hd, cdb->len, phase, wait))				if (ixfer_out(hd, cdb->len, cdb->cdb))					goto abort;			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 DATA_IN_PHASE:		case DATA_OUT_PHASE:			goto out;		default:			printf("scsi%d: unexpected phase %d in go from %d\n",				hs->sc_hc->hp_unit, phase, slave);			goto abort;		}		while ((ints = hd->scsi_ints) == 0) {			if (--wait < 0) {				HIST(sgo_wait, wait)				goto abort;			}			DELAY(1);		}		HIST(sgo_wait, wait)		hd->scsi_ints = ints;		if (ints & INTS_SRV_REQ)			phase = hd->scsi_psns & PHASE;		else if (ints & INTS_CMD_DONE)			goto out;		else {			scsierror(hs, hd, ints);			goto abort;		}	}out:	/*	 * Reset the card dma logic, setup the dma channel then	 * get the dio part of the card set for a dma xfer.	 */	hd->scsi_hconf = 0;	cmd = CSR_IE;	dmaflags = DMAGO_NOINT;	if (scsi_pridma)		dmaflags |= DMAGO_PRI;	if (bp->b_flags & B_READ)		dmaflags |= DMAGO_READ;	if ((hs->sc_flags & SCSI_DMA32) &&	    ((int)bp->b_un.b_addr & 3) == 0 && (bp->b_bcount & 3) == 0) {		cmd |= CSR_DMA32;		dmaflags |= DMAGO_LWORD;	} else		dmaflags |= DMAGO_WORD;	dmago(hs->sc_dq.dq_ctlr, bp->b_un.b_addr, bp->b_bcount, dmaflags);	if (bp->b_flags & B_READ) {		cmd |= CSR_DMAIN;		phase = DATA_IN_PHASE;	} else		phase = DATA_OUT_PHASE;	/*	 * DMA enable bits must be set after size and direction bits.	 */	hd->scsi_csr = cmd;	hd->scsi_csr |= (CSR_DE0 << hs->sc_dq.dq_ctlr);	/*	 * Setup the SPC for the transfer.  We don't want to take	 * first a command complete then a service required interrupt	 * at the end of the transfer so we try to disable the cmd	 * complete by setting the transfer counter to more bytes	 * than we expect.  (XXX - This strategy may have to be	 * modified to deal with devices that return variable length	 * blocks, e.g., some tape drives.)	 */	cmd = SCMD_XFR;	i = (unsigned)bp->b_bcount;	if (pad) {		cmd |= SCMD_PAD;		/*		 * XXX - If we don't do this, the last 2 or 4 bytes		 * (depending on word/lword DMA) of a read get trashed.		 * It looks like it is necessary for the DMA to complete		 * before the SPC goes into "pad mode"???  Note: if we		 * also do this on a write, the request never completes.		 */		if (bp->b_flags & B_READ)			i += 2;#ifdef DEBUG		hs->sc_flags |= SCSI_PAD;		if (i & 1)			printf("scsi%d: odd byte count: %d bytes @ %d\n",				ctlr, i, bp->b_cylin);#endif	} else		i += 4;	hd->scsi_tch = i >> 16;	hd->scsi_tcm = i >> 8;	hd->scsi_tcl = i;	hd->scsi_pctl = phase;	hd->scsi_tmod = 0;	hd->scsi_scmd = cmd;	hs->sc_flags |= SCSI_IO;	return (0);abort:	scsiabort(hs, hd, "go");	hs->sc_flags &=~ SCSI_HAVEDMA;	dmafree(&hs->sc_dq);	return (1);}voidscsidone(unit)	register int unit;{	volatile register struct scsidevice *hd =			(struct scsidevice *)scsi_softc[unit].sc_hc->hp_addr;#ifdef DEBUG	if (scsi_debug)		printf("scsi%d: done called!\n", unit);#endif	/* dma operation is done -- turn off card dma */	hd->scsi_csr &=~ (CSR_DE1|CSR_DE0);}intscsiintr(unit)	register int unit;{	register struct scsi_softc *hs = &scsi_softc[unit];	volatile register struct scsidevice *hd =				(struct scsidevice *)hs->sc_hc->hp_addr;	register u_char ints;	register struct devqueue *dq;	if ((hd->scsi_csr & (CSR_IE|CSR_IR)) != (CSR_IE|CSR_IR))		return (0);	ints = hd->scsi_ints;	if ((ints & INTS_SRV_REQ) && (hs->sc_flags & SCSI_IO)) {		/*		 * this should be the normal i/o completion case.		 * get the status & cmd complete msg then let the		 * device driver look at what happened.		 */#ifdef DEBUG		int len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) |			  hd->scsi_tcl;		if (!(hs->sc_flags & SCSI_PAD))			len -= 4;		hs->sc_flags &=~ SCSI_PAD;#endif		dq = hs->sc_sq.dq_forw;		finishxfer(hs, hd, dq->dq_slave);		hs->sc_flags &=~ (SCSI_IO|SCSI_HAVEDMA);		dmafree(&hs->sc_dq);		(dq->dq_driver->d_intr)(dq->dq_unit, hs->sc_stat[0]);	} else {		/* Something unexpected happened -- deal with it. */		hd->scsi_ints = ints;		hd->scsi_csr = 0;		scsierror(hs, hd, ints);		scsiabort(hs, hd, "intr");		if (hs->sc_flags & SCSI_IO) {			hs->sc_flags &=~ (SCSI_IO|SCSI_HAVEDMA);			dmafree(&hs->sc_dq);			dq = hs->sc_sq.dq_forw;			(dq->dq_driver->d_intr)(dq->dq_unit, -1);		}	}	return(1);}voidscsifree(dq)	register struct devqueue *dq;{	register struct devqueue *hq;	hq = &scsi_softc[dq->dq_ctlr].sc_sq;	remque(dq);	if ((dq = hq->dq_forw) != hq)		(dq->dq_driver->d_start)(dq->dq_unit);}/* * (XXX) The following routine is needed for the SCSI tape driver * to read odd-size records. */#include "st.h"#if NST > 0intscsi_tt_oddio(ctlr, slave, unit, buf, len, b_flags, freedma)	int ctlr, slave, unit, b_flags, freedma;	u_char *buf;	u_int len;{	register struct scsi_softc *hs = &scsi_softc[ctlr];	struct scsi_cdb6 cdb;	u_char iphase;	int stat;#ifdef DEBUG	if (freedma && (hs->sc_flags & SCSI_HAVEDMA) == 0 ||	    !freedma && (hs->sc_flags & SCSI_HAVEDMA))		printf("oddio: freedma (%d) inconsistency (flags=%x)\n",		       freedma, hs->sc_flags);#endif	/*	 * First free any DMA channel that was allocated.	 * We can't use DMA to do this transfer.	 */	if (freedma) {		hs->sc_flags &=~ SCSI_HAVEDMA;		dmafree(hs->sc_dq);	}	/*	 * Initialize command block	 */	bzero(&cdb, sizeof(cdb));	cdb.lun = unit;	cdb.lbam = (len >> 16) & 0xff;	cdb.lbal = (len >> 8) & 0xff;	cdb.len = len & 0xff;	if (buf == 0) {		cdb.cmd = CMD_SPACE;		cdb.lun |= 0x00;		len = 0;		iphase = MESG_IN_PHASE;	} else if (b_flags & B_READ) {		cdb.cmd = CMD_READ;		iphase = DATA_IN_PHASE;	} else {		cdb.cmd = CMD_WRITE;		iphase = DATA_OUT_PHASE;	}	/*	 * Perform command (with very long delays)	 */	scsi_delay(30000000);	stat = scsiicmd(hs, slave, &cdb, sizeof(cdb), buf, len, iphase);	scsi_delay(0);	return (stat);}#endif#endif

⌨️ 快捷键说明

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