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

📄 sd.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
			break;		}done:		bn += btodb(count);		resid -= count;		addr += count;#ifdef DEBUG		if (sddebug & SDB_PARTIAL)			printf(" done: bn %x resid %x addr %x\n",			       bn, resid, addr);#endif	}	free(cbuf, M_DEVBUF);	free((caddr_t)tbp, M_DEVBUF);	biodone(bp);}/* * Start a transfer on sc as described by bp * (i.e., call hba or target start). * If in format mode, we may not need dma. */#define sdstart(sc, bp) { \	SD_TRACE(T_START, sc, bp); \	if ((sc)->sc_format_pid && legal_cmds[(sc)->sc_cmd.cdb_bytes[0]] > 0) \		(*(sc)->sc_unit.u_start)((sc)->sc_unit.u_updev, \		    &(sc)->sc_unit.u_forw, (struct buf *)NULL, \		    sdigo, &(sc)->sc_dk.dk_dev); \	else \		(*(sc)->sc_unit.u_start)((sc)->sc_unit.u_updev, \		    &(sc)->sc_unit.u_forw, bp, sdgo, &(sc)->sc_dk.dk_dev); \}voidsdstrategy(bp)	register struct buf *bp;{	register struct sd_softc *sc = sdcd.cd_devs[sdunit(bp->b_dev)];	register int s;	if (sc->sc_format_pid) {		/* XXXXXXXXX SHOULD NOT COMPARE curproc IN HERE!?! */		/*		 * In format mode, only allow the owner to mess		 * with the drive.  Skip all the partition checks.		 */		if (sc->sc_format_pid != curproc->p_pid) {			bp->b_error = EPERM;			bp->b_flags |= B_ERROR;			biodone(bp);			return;		}		bp->b_cylin = 0;	} else {		register daddr_t bn = bp->b_blkno;		register int sz = howmany(bp->b_bcount, DEV_BSIZE);		register struct partition *p;		/*		 * Make sure transfer is within partition.		 * If it starts at the end, return EOF; if		 * it extends past the end, truncate it.		 */		p = &sc->sc_dk.dk_label.d_partitions[sdpart(bp->b_dev)];		if ((unsigned)bn >= p->p_size) {			if ((unsigned)bn > p->p_size) {				bp->b_error = EINVAL;				bp->b_flags |= B_ERROR;			} else				bp->b_resid = bp->b_bcount;			biodone(bp);			return;		}		if (bn + sz > p->p_size) {			sz = p->p_size - bn;			bp->b_bcount = dbtob(sz);		}		/*		 * Non-aligned or partial-block transfers handled specially.		 * SHOULD THIS BE AT A HIGHER LEVEL?		 */		s = sc->sc_blksize - 1;		if ((dbtob(bn) & s) || (bp->b_bcount & s)) {			sdlblkstrat(bp, sc->sc_blksize);			return;		}		bp->b_cylin = (bn + p->p_offset) >> sc->sc_bshift;	}	/*	 * Transfer valid, or format mode.  Queue the request	 * on the drive, and maybe try to start it.	 */	s = splbio();	disksort(&sc->sc_tab, bp);	if (sc->sc_tab.b_active == 0) {		sc->sc_tab.b_active = 1;		sdstart(sc, bp);	}	splx(s);}intsderror(sc, stat)	register struct sd_softc *sc;	register int stat;{	register struct scsi_sense *sn;	int retry = 0;	sc->sc_sense.status = stat;	if ((stat & STS_MASK) == STS_CHECKCOND) {		sn = (struct scsi_sense *)sc->sc_sense.sense;		stat = scsi_request_sense(sc->sc_unit.u_hba,		    sc->sc_unit.u_targ, sc->sc_unit.u_unit,		    (caddr_t)sn, sizeof sc->sc_sense.sense);		sc->sc_sense.status = stat;	/* ??? */		if ((stat & STS_MASK) != STS_GOOD) {			printf("%s: sense failed, status %x\n",			    sc->sc_dk.dk_dev.dv_xname, stat);			return (0);		}		printf("%s: scsi sense class %d, code %d",		    sc->sc_dk.dk_dev.dv_xname,		    SENSE_ECLASS(sn), SENSE_ECODE(sn));		if (SENSE_ISXSENSE(sn) && XSENSE_ISSTD(sn)) {			int key;			/*			 * Standard extended sense: can examine sense key			 * and (if valid) info.			 */			key = XSENSE_KEY(sn);			printf(", key %d", key);			if (XSENSE_IVALID(sn))				printf(", blk %d", XSENSE_INFO(sn));			/* no sense or recovered error, try again */			if (key == 0 || key == 1)				retry = 1;		}		printf("\n");	}	return (retry);}/* * sdigo is called from the hba driver when it has got the scsi bus * for us, and we were doing a format op that did not need dma. */voidsdigo(sc0, cdb)	struct device *sc0;	struct scsi_cdb *cdb;{	register struct sd_softc *sc = (struct sd_softc *)sc0;	register struct buf *bp = sc->sc_tab.b_actf;	register int stat;	stat = (*sc->sc_unit.u_hbd->hd_icmd)(sc->sc_unit.u_hba,	    sc->sc_unit.u_targ, &sc->sc_cmd, bp->b_un.b_addr, bp->b_bcount,	    bp->b_flags & B_READ);	sc->sc_sense.status = stat;	if (stat & 0xfe) {		/* XXX */		(void) sderror(sc, stat);		bp->b_flags |= B_ERROR;		bp->b_error = EIO;	}	/*	 * Done with SCSI bus, before we `ought' to be.  Release it.	 */	(*sc->sc_unit.u_rel)(sc->sc_unit.u_updev);	bp->b_resid = 0;	sc->sc_tab.b_errcnt = 0;	sc->sc_tab.b_actf = bp->b_actf;	biodone(bp);	if ((bp = sc->sc_tab.b_actf) == NULL)		sc->sc_tab.b_active = 0;	else		sdstart(sc, bp);}/* * sdgo is called from the hba driver or target code when it has * allocated the scsi bus and DMA resources and target datapath for us. */voidsdgo(sc0, cdb)	struct device *sc0;	register struct scsi_cdb *cdb;{	register struct sd_softc *sc = (struct sd_softc *)sc0;	register struct buf *bp = sc->sc_tab.b_actf;	register int n;	register unsigned int u;	SD_TRACE(T_MKCDB, sc, bp);	if (sc->sc_format_pid) {		*cdb = sc->sc_cmd;		n = 0;	} else {		CDB10(cdb)->cdb_cmd = bp->b_flags & B_READ ? CMD_READ10 :		    CMD_WRITE10;		CDB10(cdb)->cdb_lun_rel = sc->sc_unit.u_unit << 5;		u = bp->b_cylin;		CDB10(cdb)->cdb_lbah = u >> 24;		CDB10(cdb)->cdb_lbahm = u >> 16;		CDB10(cdb)->cdb_lbalm = u >> 8;		CDB10(cdb)->cdb_lbal = u;		CDB10(cdb)->cdb_xxx = 0;		n = sc->sc_blksize - 1;		u = (bp->b_bcount + n) >> (DEV_BSHIFT + sc->sc_bshift);		CDB10(cdb)->cdb_lenh = u >> 8;		CDB10(cdb)->cdb_lenl = u;		CDB10(cdb)->cdb_ctrl = 0;		n = (bp->b_bcount & n) != 0;#ifdef DEBUG		if (n)			printf("%s: partial block xfer -- %x bytes\n",			    sc->sc_dk.dk_dev.dv_xname, bp->b_bcount);#endif		sc->sc_transfers++;	}	if ((*sc->sc_unit.u_go)(sc->sc_unit.u_updev, sc->sc_unit.u_targ,	    sdintr, (void *)sc, bp, n) == 0) {#ifdef notyet		sc->sc_dk.dk_busy = 1;		sc->sc_dk.dk_seek++;	/* XXX */		sc->sc_dk.dk_xfer++;		sc->sc_dk.dk_wds += bp->b_bcount >> 6;#endif		return;	}	/*	 * Some sort of nasty unrecoverable error: clobber the	 * transfer.  Call the bus release function first, though.	 */	(*sc->sc_unit.u_rel)(sc->sc_unit.u_updev);#ifdef DEBUG	if (sddebug & SDB_ERROR)		printf("%s: sdgo: %s adr %d blk %d len %d ecnt %d\n",		    sc->sc_dk.dk_dev.dv_xname,		    bp->b_flags & B_READ? "read" : "write",		    bp->b_un.b_addr, bp->b_cylin, bp->b_bcount,		    sc->sc_tab.b_errcnt);#endif	bp->b_flags |= B_ERROR;	bp->b_error = EIO;	bp->b_resid = 0;	sc->sc_tab.b_errcnt = 0;	sc->sc_tab.b_actf = bp->b_actf;	biodone(bp);	if ((bp = sc->sc_tab.b_actf) == NULL)		sc->sc_tab.b_active = 0;	else		sdstart(sc, bp);}/* * A transfer finished (or, someday, disconnected). * We are already off the target/hba queues. * Restart this one for error recovery, or start the next, as appropriate. */voidsdintr(sc0, stat, resid)	struct device *sc0;	int stat, resid;{	register struct sd_softc *sc = (struct sd_softc *)sc0;	register struct buf *bp = sc->sc_tab.b_actf;	int retry;	if (bp == NULL)		panic("sdintr");	SD_TRACE(T_INTR, sc, bp);#ifdef notyet	sc->sc_dk.dk_busy = 0;#endif	if ((stat & STS_MASK) != STS_GOOD) {#ifdef DEBUG		if (sddebug & SDB_ERROR)			printf("%s: sdintr scsi status 0x%x resid %d\n",			    sc->sc_dk.dk_dev.dv_xname, stat, resid);#endif		retry = sderror(sc, stat);		if (retry && ++sc->sc_tab.b_errcnt <= SDRETRY) {			printf("%s: retry %d\n",			    sc->sc_dk.dk_dev.dv_xname, sc->sc_tab.b_errcnt);			goto restart;		}		bp->b_flags |= B_ERROR;		bp->b_error = EIO;	}	bp->b_resid = resid;	sc->sc_tab.b_errcnt = 0;	sc->sc_tab.b_actf = bp->b_actf;	biodone(bp);	if ((bp = sc->sc_tab.b_actf) == NULL)		sc->sc_tab.b_active = 0;	else {restart:		sdstart(sc, bp);	}}intsdioctl(dev_t dev, int cmd, register caddr_t data, int flag, struct proc *p){	register struct sd_softc *sc = sdcd.cd_devs[sdunit(dev)];#ifdef COMPAT_SUNOS	int error;	error = sun_dkioctl(&sc->sc_dk, cmd, data, sdpart(dev));	if (error >= 0)		return (error);#endif	switch (cmd) {	case SDIOCSFORMAT:		/* take this device into or out of "format" mode */		if (suser(p->p_ucred, &p->p_acflag))			return (EPERM);		if (*(int *)data) {			if (sc->sc_format_pid)				return (EPERM);			sc->sc_format_pid = p->p_pid;		} else			sc->sc_format_pid = 0;		break;	case SDIOCGFORMAT:		/* find out who has the device in format mode */		*(int *)data = sc->sc_format_pid;		break;	case SDIOCSCSICOMMAND:#define cdb ((struct scsi_cdb *)data)		/*		 * Save what user gave us as SCSI cdb to use with next		 * read or write to the char device.  Be sure to replace		 * the lun field with the actual unit number.		 */		if (sc->sc_format_pid != p->p_pid)			return (EPERM);		if (legal_cmds[cdb->cdb_bytes[0]] == 0)			return (EINVAL);		sc->sc_cmd = *cdb;		sc->sc_cmd.cdb_bytes[1] =		    (sc->sc_cmd.cdb_bytes[1] & ~(7 << 5)) |		    (sc->sc_unit.u_unit << 5);#undef	cdb		break;	case SDIOCSENSE:		/*		 * return the SCSI sense data saved after the last		 * operation that completed with "check condition" status.		 */		sc->sc_sense = *(struct scsi_fmt_sense *)data;		break;	case DIOCGDINFO:		*(struct disklabel *)data = sc->sc_dk.dk_label;		break;	case DIOCGPART:		((struct partinfo *)data)->disklab = &sc->sc_dk.dk_label;		((struct partinfo *)data)->part =		    &sc->sc_dk.dk_label.d_partitions[sdpart(dev)];		break;	default:		return (ENOTTY);	}	return (0);}intsdsize(dev_t dev){	register int unit = sdunit(dev);	register struct sd_softc *sc;	if (unit >= sdcd.cd_ndevs || (sc = sdcd.cd_devs[unit]) == NULL ||	    (sc->sc_flags & SDF_ALIVE) == 0)		return (-1);	return (sc->sc_dk.dk_label.d_partitions[sdpart(dev)].p_size);}/* * Write `len' bytes from address `addr' to drive and partition in `dev', * at block blkoff from the beginning of the partition.  The address is * either kernel virtual or physical (some machines may never use one or * the other, but we need it in the protocol to stay machine-independent). */intsddump(dev_t dev, daddr_t blkoff, caddr_t addr, int len){	register struct sd_softc *sc;	register struct partition *p;	register daddr_t bn, n, nblks;	register struct hba_softc *hba;	register int stat, unit;	struct scsi_cdb cdb;	/* drive ok? */	unit = sdunit(dev);	if (unit >= sdcd.cd_ndevs || (sc = sdcd.cd_devs[unit]) == NULL ||	    (sc->sc_flags & SDF_ALIVE) == 0)		return (ENXIO);	/* blocks in range? */	p = &sc->sc_dk.dk_label.d_partitions[sdpart(dev)];	n = (len + sc->sc_blksize - 1) >> DEV_BSHIFT;	if (blkoff < 0 || blkoff >= p->p_size || blkoff + n > p->p_size)		return (EINVAL);	bn = blkoff + p->p_offset;	bn >>= sc->sc_bshift;	/* scsi bus idle? */	hba = sc->sc_unit.u_hba;	if (hba->hba_head) {		(*hba->hba_driver->hd_reset)(hba, 0);		printf("[reset %s] ", sc->sc_dk.dk_dev.dv_xname);	}	CDB10(&cdb)->cdb_cmd = CMD_WRITE10;	CDB10(&cdb)->cdb_lun_rel = sc->sc_unit.u_unit << 5;	CDB10(&cdb)->cdb_xxx = 0;	CDB10(&cdb)->cdb_ctrl = 0;#define	DUMP_MAX	(32 * 1024)	/* no more than 32k per write */	for (;;) {		if ((n = len) > DUMP_MAX)			n = DUMP_MAX;		CDB10(&cdb)->cdb_lbah = bn >> 24;		CDB10(&cdb)->cdb_lbahm = bn >> 16;		CDB10(&cdb)->cdb_lbalm = bn >> 8;		CDB10(&cdb)->cdb_lbal = bn;		nblks = n >> (DEV_BSHIFT + sc->sc_bshift);		CDB10(&cdb)->cdb_lenh = nblks >> 8;		CDB10(&cdb)->cdb_lenl = nblks;		stat = hba->hba_driver->hd_dump(hba, sc->sc_unit.u_targ,		    &cdb, addr, n);		if ((stat & STS_MASK) != STS_GOOD) {			printf("%s: scsi write error 0x%x\ndump ",			    sc->sc_dk.dk_dev.dv_xname, stat);			return (EIO);		}		if ((len -= n) == 0)			return (0);		addr += n;		bn += nblks;	}}

⌨️ 快捷键说明

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