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

📄 sdmv50xx.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
		return 0;	drive = &ctlr->drive[unit->subno];	e = p+l;	op = p;	if(drive->state == Dready){		p = seprint(p, e, "model    %s\n", drive->model);		p = seprint(p, e, "serial   %s\n", drive->serial);		p = seprint(p, e, "firmware %s\n", drive->firmware);	}else		p = seprint(p, e, "no disk present\n");	p = seprint(p, e, "geometry %llud 512\n", drive->sectors);	p = rdinfo(p, e, drive->info);	p = rdregs(p, e, drive->chip->arb, regsarb, nelem(regsarb), nil);	p = rdregs(p, e, drive->bridge, regsbridge, nelem(regsbridge), nil);	p = rdregs(p, e, drive->edma, regsedma, nelem(regsedma), nil);	return p-op;}static intmv50wctl(SDunit *unit, Cmdbuf *cb){	Ctlr *ctlr;	Drive *drive;	USED(unit);	if(strcmp(cb->f[0], "reset") == 0){		ctlr = unit->dev->ctlr;		drive = &ctlr->drive[unit->subno];		ilock(drive);		updatedrive(drive, eDevDis);		iunlock(drive);		return 0;	}	cmderror(cb, Ebadctl);	return -1;}static char*mv50rtopctl(SDev *sdev, char *p, char *e){	char name[10];	Ctlr *ctlr;	ctlr = sdev->ctlr;	if(ctlr == nil)		return p;	snprint(name, sizeof name, "sd%c", sdev->idno);	p = rdregs(p, e, ctlr->mmio, regsctlr, nelem(regsctlr), name);	/* info for first disk */	p = rdregs(p, e, ctlr->chip[0].arb, regsarb, nelem(regsarb), name);	p = rdregs(p, e, &ctlr->chip[0].arb->bridge[0], regsbridge, nelem(regsbridge), name);	p = rdregs(p, e, &ctlr->chip[0].edma[0], regsedma, nelem(regsedma), name);	return p;}#endifstatic intmv50rio(SDreq *r){	int count, max, n, status;	uchar *cmd, *data;	uvlong lba;	Ctlr *ctlr;	Drive *drive;	SDunit *unit;	Srb *srb;	unit = r->unit;	ctlr = unit->dev->ctlr;	drive = &ctlr->drive[unit->subno];	cmd = r->cmd;	if((status = sdfakescsi(r, drive->info, sizeof drive->info)) != SDnostatus){		/* XXX check for SDcheck here */		r->status = status;		return status;	}	switch(cmd[0]){	case 0x28:	/* read */	case 0x2A:	/* write */		break;	default:		print("sdmv50xx: bad cmd 0x%.2ux\n", cmd[0]);		r->status = SDcheck;		return SDcheck;	}	lba = (cmd[2]<<24)|(cmd[3]<<16)|(cmd[4]<<8)|cmd[5];	count = (cmd[7]<<8)|cmd[8];	if(r->data == nil)		return SDok;	if(r->dlen < count*unit->secsize)		count = r->dlen/unit->secsize;	/*	 * Could arrange here to have an Srb always outstanding:	 *	 *	lsrb = nil;	 *	while(count > 0 || lsrb != nil){	 *		srb = nil;	 *		if(count > 0){	 *			srb = issue next srb;	 *		}	 *		if(lsrb){	 *			sleep on lsrb and handle it	 *		}	 *	}	 *	 * On the disks I tried, this didn't help.  If anything,	 * it's a little slower.		-rsc	 */	data = r->data;	while(count > 0){		/*		 * Max is 128 sectors (64kB) because prd->count is 16 bits.		 */		max = 128;		n = count;		if(n > max)			n = max;		srb = srbrw(cmd[0]==0x28 ? SRBread : SRBwrite, drive, data, n, lba);		ilock(drive);		startsrb(drive, srb);		iunlock(drive);		/*		 * Cannot let user interrupt the DMA.		 */		while(waserror())			;		tsleep(srb, srbdone, srb, 60*1000);		poperror();		if(!(srb->flag & SFdone)){			ilock(drive);			if(!(srb->flag & SFdone)){				/*				 * DMA didn't finish but we have to let go of				 * the data buffer.  Reset the drive to (try to) keep it				 * from using the buffer after we're gone.				 */				iprint("%s: i/o timeout\n", unit->name);				updatedrive(drive, eDevDis);				enabledrive(drive);				freesrb(srb);				iunlock(drive);				error("i/o timeout");			}			iunlock(drive);		}		if(srb->flag & SFerror){			freesrb(srb);			error("i/o error");		}		freesrb(srb);		count -= n;		lba += n;		data += n*unit->secsize;	}	r->rlen = data - (uchar*)r->data;	return SDok;err:	return SDeio;}SDifc sdmv50xxifc = {	"mv50xx",				/* name */	mv50pnp,			/* pnp */	nil,				/* legacy */#ifdef FS	nil,			/* id */#endif	mv50enable,		/* enable */	mv50disable,		/* disable */	mv50verify,			/* verify */	mv50online,			/* online */	mv50rio,				/* rio */#ifdef FS	nil,	nil,#else	mv50rctl,			/* rctl */	mv50wctl,			/* wctl */#endif	scsibio,			/* bio */#ifndef FS	nil,			/* probe */	mv50clear,			/* clear */	mv50rtopctl,			/* rtopctl */#endif};/* * file-server-specific routines * * mvide* routines implement the `m' device and call the mvsata* routines. */static Drive*mvsatapart(Drive *dp){	return dp;}static Drive*mvsatadriveprobe(int driveno){	Drive *drive;	drive = mvsatadrive[driveno];	if (drive == nil)		return nil;	if (drive->magic != Drvmagic)		print("mv50xx: mvsatadriveprobe(m%d): bad drive magic 0x%lux\n",			driveno, drive->magic);	drive->driveno = driveno;	if(drive->online == 0){		/* LBA assumed */		print("m%d: LBA %,llud sectors\n",			drive->driveno, (Wideoff)drive->sectors);		drive->online = 1;	}	return mvsatapart(drive);}/* find all the controllers, enable interrupts, set up SDevs & SDunits */intmvsatainit(void){	unsigned i;	SDev *sdp;	SDev **sdpp;	SDunit *sup;	SDunit **supp;	static int first = 1;	if (first)		first = 0;	else		return 0xFF;	mv50pnp();	for (sdpp = sdevs; sdpp < sdevs + nelem(sdevs); sdpp++) {		sdp = *sdpp;		if (sdp == nil)			continue;		i = sdpp - sdevs;		sdp->ifc = &sdmv50xxifc;		sdp->nunit = NCtlrdrv;		sdp->index = i;		sdp->idno = 'E' + i;		sdp->ctlr = mvsatactlr[i];		if (sdp->ctlr != nil)			mv50enable(sdp);	}	for (supp = sdunits; supp < sdunits + nelem(sdunits); supp++) {		sup = *supp;		if (sup == nil)			continue;		i = supp - sdunits;		sup->dev = sdevs[i/NCtlrdrv];	/* controller */		sup->subno = i%NCtlrdrv;	/* drive within controller */		snprint(sup->name, sizeof sup->name, "m%d", i);	}	statsinit();	return 0xFF;}Devsizemvsataseek(int driveno, Devsize offset){	Drive *drive = mvsatadrive[driveno];	if (drive == nil || !drive->online)		return -1;	drive->offset = offset;	return offset;}/* zero indicates failure; only otherinit() cares */intsetmv50part(int driveno, char *){	/* mvsatadriveprobe() sets drive->online */	if(mvsatadriveprobe(driveno) == nil)		return 0;	return 1;}static voidkeepstats(SDunit *unit, int dbytes){	Ctlr *ctlr = unit->dev->ctlr;	Target *tp = &ctlr->target[unit->subno];	qlock(tp);	if(tp->fflag == 0) {		dofilter(tp->work+0, C0a, C0b, 1);	/* was , 1000); */		dofilter(tp->work+1, C1a, C1b, 1);	/* was , 1000); */		dofilter(tp->work+2, C2a, C2b, 1);	/* was , 1000); */		dofilter(tp->rate+0, C0a, C0b, 1);		dofilter(tp->rate+1, C1a, C1b, 1);		dofilter(tp->rate+2, C2a, C2b, 1);		tp->fflag = 1;	}	tp->work[0].count++;	tp->work[1].count++;	tp->work[2].count++;	tp->rate[0].count += dbytes;	tp->rate[1].count += dbytes;	tp->rate[2].count += dbytes;	qunlock(tp);}static longmvsataxfer(Drive *dp, void *, int inout, Devsize start, long bytes){	unsigned driveno = dp->driveno;	ulong secsize = dp->unit->secsize, sects;	SDunit *unit;	SDunit **unitp = sdunits + driveno;	static int beenhere;	DPRINT("%s: mvsataxfer\n", dp->unit->name);	unit = *unitp;	if (unit == nil) {		print("mvsataxfer: nil unit\n");		return -1;	}	if (!beenhere && dp->unit != unit) {		beenhere = 1;		print("mvsataxfer: units differ: dp->unit %p unit %p\n",			dp->unit, unit);	}	if (dp->driveno == -1)		panic("mvsataxfer: dp->driveno unset");	if (unit->dev != sdevs[driveno/NCtlrdrv])		panic("mvsataxfer: SDunit[%d].dev is wrong controller", driveno);	if (unit->subno != driveno%NCtlrdrv)		panic("mvsataxfer: SDunit[%d].subno is %d, not %d",			driveno, unit->subno, driveno%NCtlrdrv);	if (unit->sectors == 0) {		unit->sectors = dp->sectors;		unit->secsize = secsize;	}	keepstats(unit, bytes);	sects = (bytes + secsize - 1) / secsize;	/* round up */	if (start%secsize != 0)		print("mvsataxfer: start offset not on sector boundary\n");	return scsibio(unit, 0, inout, dp->buf, sects, start/secsize);}/* * mvsataread & mvsatawrite do the real work; * mvideread & mvidewrite just call them. * mvsataread & mvsatawrite are called by the nvram routines. * mvideread & mvidewrite are called for normal file server I/O. */Offmvsataread(int driveno, void *a, long n){	int skip;	Off rv, i;	uchar *aa = a;//	Ctlr *cp;	Drive *dp;	DPRINT("m%d: mvsataread\n", driveno);	dp = mvsatadrive[driveno];	if(dp == nil || !dp->online)		return 0;	DPRINT("%s: mvsataread drive=%p\n", dp->unit->name, dp);//	cp = dp->ctlr;	if (dp->unit->secsize == 0)		panic("mvsataread: %s: sector size of zero", dp->unit->name);	skip = dp->offset % dp->unit->secsize;	for(rv = 0; rv < n; rv += i){		i = mvsataxfer(dp, nil, Read, dp->offset+rv-skip, n-rv+skip);		if(i == 0)			break;		if(i < 0) {			return -1;		}		i -= skip;		if(i > n - rv)			i = n - rv;		memmove(aa+rv, dp->buf + skip, i);		skip = 0;	}	dp->offset += rv;	return rv;}Offmvsatawrite(int driveno, void *a, long n){	Off rv, i, partial;	uchar *aa = a;//	Ctlr *cp;	Drive *dp;	DPRINT("m%d: mvsatawrite\n", driveno);	dp = mvsatadrive[driveno];	if(dp == nil || !dp->online)		return 0;	DPRINT("%s: mvsatawrite drive=%p\n", dp->unit->name, dp);//	cp = dp->ctlr;	/*	 *  if not starting on a sector boundary,	 *  read in the first sector before writing it out.	 */	if (dp->unit->secsize == 0)		panic("mvsatawrite: %s: sector size of zero", dp->unit->name);	partial = dp->offset % dp->unit->secsize;	if(partial){		if (mvsataxfer(dp, nil, Read, dp->offset-partial,		    dp->unit->secsize) < 0)			return -1;		if(partial+n > dp->unit->secsize)			rv = dp->unit->secsize - partial;		else			rv = n;		memmove(dp->buf+partial, aa, rv);		if (mvsataxfer(dp, nil, Write, dp->offset-partial,		    dp->unit->secsize) < 0)			return -1;	} else		rv = 0;	/*	 *  write out the full sectors (common case)	 */	partial = (n - rv) % dp->unit->secsize;	n -= partial;	for(; rv < n; rv += i){		i = n - rv;		if(i > Maxxfer)			i = Maxxfer;		memmove(dp->buf, aa+rv, i);		i = mvsataxfer(dp, nil, Write, dp->offset+rv, i);		if(i == 0)			break;		if(i < 0)			return -1;	}	/*	 *  if not ending on a sector boundary,	 *  read in the last sector before writing it out.	 */	if(partial){		if (mvsataxfer(dp, nil, Read, dp->offset+rv, dp->unit->secsize)		    < 0)			return -1;		memmove(dp->buf, aa+rv, partial);		if (mvsataxfer(dp, nil, Write, dp->offset+rv, dp->unit->secsize)		    < 0)			return -1;		rv += partial;	}	dp->offset += rv;	return rv;}/* * normal file server I/O interface *//* result is size of d in blocks of RBUFSIZE bytes */Devsizemvidesize(Device *d){	Drive *dp = d->private;	if (dp == nil)		return 0;	/*	 * dividing first is sloppy but reduces the range of intermediate	 * values, avoiding possible overflow.	 */	return (dp->sectors / RBUFSIZE) * dp->unit->secsize;}voidmvideinit(Device *d){	int driveno;	Drive *dp;	DPRINT("mvideinit\n");	mvsatainit();	if (d->private)		return;	/* call setmv50part() first in case we didn't boot off this drive */	driveno = d->wren.ctrl*NCtlrdrv + d->wren.targ;	DPRINT("%Z: mvideinit\n", d);	setmv50part(driveno, "disk");	dp = mvsatadriveprobe(driveno);	if (dp) {		print("mvideinit(ctrl %d targ %d) driveno %d\n",			d->wren.ctrl, d->wren.targ, dp->driveno);		if (dp->driveno != driveno)			panic("mvideinit: dp->dev != driveno");		if (dp->magic != Drvmagic)			panic("mvideinit: %Z: bad drive magic", d);		d->private = dp;		if (dp->unit == nil)			panic("mvideinit: %Z: nil dp->unit", d);		/* print the sizes now, not later */		print(	"  mvidesize(driveno %d):  %llud %lud-byte sectors -> %llud blocks\n",			dp->driveno, (Wideoff)dp->sectors, dp->unit->secsize,			(Wideoff)mvidesize(d));		if (dp->unit->secsize == 0)			panic("%Z: zero sector size", d);		if (dp->sectors == 0)			panic("%Z: zero sectors", d);	}}intmvideread(Device *d, Devsize b, void *c){	int x, driveno;	Drive *dp;	Ctlr *cp;	if (d == nil || d->private == nil) {		print("mvideread: %Z: nil d or d->private == nil\n", d);		return 1;	}	dp = d->private;	cp = dp->ctlr;	if (cp == nil)		panic("mvideread: no controller for drive");	qlock(&cp->idelock);	cp->idelock.name = "mvideio";	driveno = dp->driveno;	if (driveno == -1)		panic("mvideread: dp->driveno unset");	IDPRINT("mvideread(dev %lux, %lld, %lux, %d): %lux\n",		(ulong)d, (Wideoff)b, (ulong)c, driveno, (ulong)dp);	mvsataseek(driveno, b * RBUFSIZE);	x = mvsataread(driveno, c, RBUFSIZE) != RBUFSIZE;	qunlock(&cp->idelock);	return x;}intmvidewrite(Device *d, Devsize b, void *c){	int x, driveno;	Drive *dp;	Ctlr *cp;	if (d == nil || d->private == nil) {		print("mvidewrite: %Z: nil d or d->private == nil\n", d);		return 1;	}	dp = d->private;	cp = dp->ctlr;	if (cp == nil)		panic("mvidewrite: no controller for drive");	qlock(&cp->idelock);	cp->idelock.name = "mvideio";	driveno = dp->driveno;	if (driveno == -1)		panic("mvidewrite: dp->driveno unset");	IDPRINT("mvidewrite(%ux, %lld, %ux): driveno %d\n",		(int)d, (Wideoff)b, (int)c, driveno);	mvsataseek(driveno, b * RBUFSIZE);	x = mvsatawrite(driveno, c, RBUFSIZE) != RBUFSIZE;	qunlock(&cp->idelock);	return x;}static voidcmd_stat(int, char*[]){	Ctlr *ctlr;	int ctlrno, targetno;	Target *tp;	for(ctlrno = 0; ctlrno < nelem(mvsatactlr); ctlrno++){		ctlr = mvsatactlr[ctlrno];		if(ctlr == nil || ctlr->sdev == nil)			continue;		for(targetno = 0; targetno < NTarget; targetno++){			tp = &ctlr->target[targetno];			if(tp->fflag == 0)				continue;			print("\t%d.%d work =%7W%7W%7W xfrs\n",				ctlrno, targetno,				tp->work+0, tp->work+1, tp->work+2);			print("\t    rate =%7W%7W%7W tBps\n",				tp->rate+0, tp->rate+1, tp->rate+2);		}	}}static voidstatsinit(void){	cmd_install("statm", "-- marvell sata stats", cmd_stat);}/* Tab 4 Font* Copyright 2005* Coraid, Inc.** This software is provided `as-is,' without any express or implied* warranty.  In no event will the author be held liable for any damages* arising from the use of this software.** Permission is granted to anyone to use this software for any purpose,* including commercial applications, and to alter it and redistribute it* freely, subject to the following restrictions:** 1.  The origin of this software must not be misrepresented; you must* not claim that you wrote the original software.  If you use this* software in a product, an acknowledgment in the product documentation* would be appreciated but is not required.** 2.  Altered source versions must be plainly marked as such, and must* not be misrepresented as being the original software.** 3.  This notice may not be removed or altered from any source* distribution.*/

⌨️ 快捷键说明

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