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

📄 vd.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
		bp->b_error = ENXIO;		goto bad;	}	vi = vddinfo[unit];	lp = &dklabel[unit];	if (vi == 0 || vi->ui_alive == 0) {		bp->b_error = ENXIO;		goto bad;	}	dk = &dksoftc[unit];	if (dk->dk_state < OPEN) {		if (dk->dk_state == CLOSED) {			bp->b_error = EIO;			goto bad;		}		goto q;	}	if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) {		bp->b_error = EROFS;		goto bad;	}	part = vdpart(bp->b_dev);	if ((dk->dk_openpart & (1 << part)) == 0) {		bp->b_error = ENODEV;		goto bad;	}	sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;	maxsz = lp->d_partitions[part].p_size;#ifndef SECSIZE	sn = bp->b_blkno << dk->dk_bshift;#else SECSIZE	sn = bp->b_blkno;#endif SECSIZE	if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR &&#if LABELSECTOR != 0	    sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR &&#endif	    (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) {		bp->b_error = EROFS;		goto bad;	}	if (sn < 0 || sn + sz > maxsz) {		if (sn == maxsz) {			bp->b_resid = bp->b_bcount;			goto done;		}		sz = maxsz - sn;		if (sz <= 0) {			bp->b_error = EINVAL;			goto bad;		}		bp->b_bcount = sz * lp->d_secsize;	}	bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;#ifdef SECSIZEif (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0)panic("vdstrat blksize");#endif SECSIZEq:	s = spl7();	dp = &dkutab[vi->ui_unit];	disksort(dp, bp);	if (!dp->b_active) {		(void) vdustart(vi);		if (!vi->ui_mi->um_tab.b_active)			vdstart(vi->ui_mi);	}	splx(s);	return;bad:		bp->b_flags |= B_ERROR;done:	biodone(bp);	return;}vdustart(vi)	register struct vba_device *vi;{	register struct buf *bp, *dp;	register struct vba_ctlr *vm;	register int unit = vi->ui_unit;	register struct dksoftc *dk;	register struct vdsoftc *vd;	struct disklabel *lp;	dp = &dkutab[unit];	/*	 * If queue empty, nothing to do.	 */	if ((bp = dp->b_actf) == NULL)		return;	/*	 * If drive is off-cylinder and controller supports seeks,	 * place drive on seek queue for controller.	 * Otherwise, place on transfer queue.	 */	vd = &vdsoftc[vi->ui_ctlr];	dk = &dksoftc[unit];	vm = vi->ui_mi;	if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) {		lp = &dklabel[unit];		bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors;		if (vm->um_tab.b_seekf == NULL)			vm->um_tab.b_seekf = dp;		else			vm->um_tab.b_seekl->b_forw = dp;		vm->um_tab.b_seekl = dp;	} else {		if (vm->um_tab.b_actf == NULL)			vm->um_tab.b_actf = dp;		else			vm->um_tab.b_actl->b_forw = dp;		vm->um_tab.b_actl = dp;	}	dp->b_forw = NULL;	dp->b_active++;}/* * Start next transfer on a controller. * There are two queues of drives, the first on-cylinder * and the second off-cylinder from their next transfers. * Perform the first transfer for the first drive on the on-cylinder * queue, if any, otherwise the first transfer for the first drive * on the second queue.  Initiate seeks on remaining drives on the * off-cylinder queue, then move them all to the on-cylinder queue. */vdstart(vm)	register struct vba_ctlr *vm;{	register struct buf *bp;	register struct vba_device *vi;	register struct vdsoftc *vd;	register struct dksoftc *dk;	register struct disklabel *lp;	register struct dcb **dcbp;	struct buf *dp;	int sn, tn;loop:	/*	 * Pull a request off the controller queue.	 */	if ((dp = vm->um_tab.b_actf) == NULL &&	    (dp = vm->um_tab.b_seekf) == NULL)		return;	if ((bp = dp->b_actf) == NULL) {		if (dp == vm->um_tab.b_actf)			vm->um_tab.b_actf = dp->b_forw;		else			vm->um_tab.b_seekf = dp->b_forw;		goto loop;	}	/*	 * Mark controller busy, and determine	 * destination of this request.	 */	vm->um_tab.b_active++;	vi = vddinfo[vdunit(bp->b_dev)];	dk = &dksoftc[vi->ui_unit];#ifndef SECSIZE	sn = bp->b_blkno << dk->dk_bshift;#else SECSIZE	sn = bp->b_blkno;#endif SECSIZE	lp = &dklabel[vi->ui_unit];	sn %= lp->d_secpercyl;	tn = sn / lp->d_nsectors;	sn %= lp->d_nsectors;	/*	 * Construct dcb for read/write command.	 */	vd = &vdsoftc[vm->um_ctlr];	vd->vd_dcb.intflg = DCBINT_DONE;	vd->vd_dcb.devselect = dk->dk_dcb.devselect;	vd->vd_dcb.operrsta = 0;	vd->vd_dcb.nxtdcb = (struct dcb *)0;	/* end of chain */	vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin;	vd->vd_dcb.trail.rwtrail.disk.track = tn;	vd->vd_dcb.trail.rwtrail.disk.sector = sn;	dk->dk_curcyl = bp->b_cylin;	bp->b_track = 0;		/* init overloaded field */	vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);	if (bp->b_flags & B_FORMAT)		vd->vd_dcb.opcode = dk->dk_op;	else if (vd->vd_flags & VD_SCATGATH &&	    ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0)		vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW;	else		vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD;	switch (vd->vd_dcb.opcode) {	case VDOP_FSECT:		vd->vd_dcb.trailcnt = sizeof (struct trfmt) / sizeof (long);		vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount /		    lp->d_secsize;		vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr;		vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags;		goto setupaddr;	case VDOP_RDRAW:	case VDOP_RD:	case VDOP_RHDE:	case VDOP_WD:		vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;setupaddr:		vd->vd_dcb.trail.rwtrail.memadr =			vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize);		break;	case VDOP_RAS:	case VDOP_GAW:		vd->vd_dcb.trailcnt += vd_sgsetup(bp, &vd->vd_rbuf,		    &vd->vd_dcb.trail.sgtrail);		break;	}	if (vi->ui_dk >= 0) {		dk_busy |= 1<<vi->ui_dk;		dk_xfer[vi->ui_dk]++;		dk_wds[vi->ui_dk] += bp->b_bcount>>6;	}	/*	 * Look for any seeks to be performed on other drives on this	 * controller.  If overlapped seeks exist, insert seek commands	 * on the controller's command queue before the transfer.	 */	dcbp = &vd->vd_mdcb.mdcb_head;	if (dp == vm->um_tab.b_seekf)		dp = dp->b_forw;	else		dp = vm->um_tab.b_seekf;	for (; dp != NULL; dp = dp->b_forw) {		if ((bp = dp->b_actf) == NULL)			continue;		vi = vddinfo[vdunit(bp->b_dev)];		dk = &dksoftc[vi->ui_unit];		dk->dk_curcyl = bp->b_cylin;		if (vi->ui_dk >= 0)			dk_seek[vi->ui_dk]++;		dk->dk_dcb.operrsta = 0;		dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin;		dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track;		*dcbp = (struct dcb *)dk->dk_dcbphys;		dcbp = &dk->dk_dcb.nxtdcb;	}	*dcbp = (struct dcb *)vd->vd_dcbphys;	if (vm->um_tab.b_actf)		vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf;	else		vm->um_tab.b_actf = vm->um_tab.b_seekf;	if (vm->um_tab.b_seekf)		vm->um_tab.b_actl = vm->um_tab.b_seekl;	vm->um_tab.b_seekf = 0;	/*	 * Initiate operation.	 */	vd->vd_mdcb.mdcb_status = 0;	VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);}/* * Wait for controller to finish current operation * so that direct controller accesses can be done. */vdlock(ctlr){	register struct vba_ctlr *vm = vdminfo[ctlr];	register struct vdsoftc *vd = &vdsoftc[ctlr];	int s;	s = spl7();	while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) {		vd->vd_flags |= VD_WAIT;		sleep((caddr_t)vd, PRIBIO);	}	vd->vd_flags |= VD_LOCKED;	splx(s);}/* * Continue normal operations after pausing for  * munging the controller directly. */vdunlock(ctlr){	register struct vba_ctlr *vm = vdminfo[ctlr];	register struct vdsoftc *vd = &vdsoftc[ctlr];	vd->vd_flags &= ~VD_LOCKED;	if (vd->vd_flags & VD_WAIT) {		vd->vd_flags &= ~VD_WAIT;		wakeup((caddr_t)vd);	} else if (vm->um_tab.b_actf || vm->um_tab.b_seekf)		vdstart(vm);}#define	DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)/* * Handle a disk interrupt. */vdintr(ctlr)	register ctlr;{	register struct buf *bp, *dp;	register struct vba_ctlr *vm = vdminfo[ctlr];	register struct vba_device *vi;	register struct vdsoftc *vd = &vdsoftc[ctlr];	register status;	int timedout;	struct dksoftc *dk;	if (!vm->um_tab.b_active) {		printf("vd%d: stray interrupt\n", ctlr);		return;	}	/*	 * Get device and block structures, and a pointer	 * to the vba_device for the drive.	 */	dp = vm->um_tab.b_actf;	bp = dp->b_actf;	vi = vddinfo[vdunit(bp->b_dev)];	dk = &dksoftc[vi->ui_unit];	if (vi->ui_dk >= 0)		dk_busy &= ~(1<<vi->ui_dk);	timedout = (vd->vd_wticks >= VDMAXTIME);	/*	 * Check for and process errors on	 * either the drive or the controller.	 */	uncache(&vd->vd_dcb.operrsta);	status = vd->vd_dcb.operrsta;	if (bp->b_flags & B_FORMAT) {		dk->dk_operrsta = status;		uncache(&vd->vd_dcb.err_code);		/* ecodecnt gets err_code + err_wcnt from the same longword */		dk->dk_ecodecnt = *(long *)&vd->vd_dcb.err_code;		uncache(&vd->vd_dcb.err_trk);		/* erraddr gets error trk/sec/cyl from the same longword */		dk->dk_erraddr = *(long *)&vd->vd_dcb.err_trk;	} else if (status & VDERR_HARD || timedout) {		if (vd->vd_type == VDTYPE_SMDE)			uncache(&vd->vd_dcb.err_code);		if (status & DCBS_WPT) {			/*			 * Give up on write locked devices immediately.			 */			printf("dk%d: write locked\n", vi->ui_unit);			bp->b_flags |= B_ERROR;		} else if (status & VDERR_RETRY || timedout) {			if (status & VDERR_CTLR || timedout) {				vdharderr(timedout ?				    "controller timeout" : "controller err",				    vd, bp, &vd->vd_dcb);				printf("; resetting controller...");				vdreset_ctlr(vm);			} else if (status & VDERR_DRIVE) {				vdharderr("drive err", vd, bp, &vd->vd_dcb);				printf("; resetting drive...");				if (!vdreset_drive(vi))					dk->dk_state = CLOSED;			} else				vdharderr("data err", vd, bp, &vd->vd_dcb);			/*			 * Retry transfer once, unless reset failed.			 */			if (!vi->ui_alive || dp->b_errcnt++ >= 1) {				printf("\n");				goto hard;			}			printf(" retrying\n");			vm->um_tab.b_active = 0;	/* force retry */		} else  {			vdharderr("hard error", vd, bp, &vd->vd_dcb);			printf("\n");	hard:			bp->b_flags |= B_ERROR;		}	} else if (status & DCBS_SOFT)		vdsofterr(bp, &vd->vd_dcb);if (vd->vd_wticks > 3) {vd->vd_dcb.err_code = vd->vd_wticks;vdharderr("slow transfer (ecode is sec.)", vd, bp, &vd->vd_dcb);printf("\n");}	vd->vd_wticks = 0;	if (vm->um_tab.b_active) {		vm->um_tab.b_active = 0;		vm->um_tab.b_actf = dp->b_forw;		dp->b_active = 0;		dp->b_errcnt = 0;		dp->b_actf = bp->av_forw;		bp->b_resid = 0;		vbadone(bp, &vd->vd_rbuf);		biodone(bp);		/*		 * If this unit has more work to do,		 * then start it up right away.		 */		if (dp->b_actf)			vdustart(vi);		else if (dk->dk_openpart == 0)			wakeup((caddr_t)dk);	}	/*	 * If there are devices ready to	 * transfer, start the controller.	 */	if (vd->vd_flags & VD_WAIT) {		vd->vd_flags &= ~VD_WAIT;		wakeup((caddr_t)vd);	} else if (vm->um_tab.b_actf || vm->um_tab.b_seekf)		vdstart(vm);}vdharderr(what, vd, bp, dcb)	char *what;	struct vdsoftc *vd;	register struct buf *bp;	register struct dcb *dcb;{	int unit = vdunit(bp->b_dev), status = dcb->operrsta;	register struct disklabel *lp = &dklabel[unit];	int blkdone;	if (vd->vd_wticks < VDMAXTIME)		status &= ~DONTCARE;	blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *	    lp->d_nsectors + dcb->err_sec -	    lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>	    dksoftc[unit].dk_bshift) - bp->b_blkno;	diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp);	printf(", status %b", status, VDERRBITS);	if (vd->vd_type == VDTYPE_SMDE)		printf(" ecode %x", dcb->err_code);}vdsofterr(bp, dcb)	register struct buf *bp;	register struct dcb *dcb;{	int unit = vdunit(bp->b_dev);	struct disklabel *lp = &dklabel[unit];	int status = dcb->operrsta;	int blkdone;	blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *	    lp->d_nsectors + dcb->err_sec -	    lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>	    dksoftc[unit].dk_bshift) - bp->b_blkno;	if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) {		diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp);		addlog(", status %b ecode %x\n", status, VDERRBITS,		    dcb->err_code);	} else {		diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp);		addlog("\n");	}}vdioctl(dev, cmd, data, flag)	dev_t dev;	int cmd;	caddr_t data;	int flag;{	register int unit = vdunit(dev);	register struct disklabel *lp = &dklabel[unit];	register struct dksoftc *dk = &dksoftc[unit];	int error = 0, vdformat();	switch (cmd) {	case DIOCGDINFO:		*(struct disklabel *)data = *lp;		break;	case DIOCGPART:		((struct partinfo *)data)->disklab = lp;		((struct partinfo *)data)->part =		    &lp->d_partitions[vdpart(dev)];		break;	case DIOCSDINFO:		if ((flag & FWRITE) == 0)			error = EBADF;		else			error = setdisklabel(lp, (struct disklabel *)data,			    (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart);		if (error == 0 && dk->dk_state == OPENRAW &&		    vdreset_drive(vddinfo[unit]))			dk->dk_state = OPEN;		break;	case DIOCWLABEL:		if ((flag & FWRITE) == 0)			error = EBADF;		else			dk->dk_wlabel = *(int *)data;		break;	case DIOCWDINFO:		if ((flag & FWRITE) == 0)			error = EBADF;		else if ((error = setdisklabel(lp, (struct disklabel *)data,		    (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) {			int wlab;			if (error == 0 && dk->dk_state == OPENRAW &&			    vdreset_drive(vddinfo[unit]))				dk->dk_state = OPEN;			/* simulate opening partition 0 so write succeeds */			dk->dk_openpart |= (1 << 0);		/* XXX */			wlab = dk->dk_wlabel;			dk->dk_wlabel = 1;			error = writedisklabel(dev, vdstrategy, lp);			dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;			dk->dk_wlabel = wlab;		}		break;	case DIOCWFORMAT:	    {

⌨️ 快捷键说明

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