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

📄 juke.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include	"all.h"#define	SCSInone	SCSIread#define	MAXDRIVE	10#define	MAXSIDE		500#define	TWORM		MINUTE(10)#define	THYSTER		SECOND(10)typedef	struct	Side	Side;struct	Side{	QLock;			/* protects loading/unloading */	int	elem;		/* element number */	int	drive;		/* if loaded, where */	uchar	status;		/* Sunload, etc */	uchar	rot;		/* if backside */	int	ord;		/* ordinal number for labeling */	Timet	time;		/* time since last access, to unspin */	Timet	stime;		/* time since last spinup, for hysteresis */	long	nblock;		/* number of native blocks */	long	block;		/* bytes per native block */	long	mult;		/* multiplier to get plan9 blocks */	long	max;		/* max size in plan9 blocks */};typedef	struct	Juke	Juke;struct	Juke{	QLock;				/* protects drive mechanism */	Side	side[MAXSIDE];	int	nside;			/* how many storage elements (*2 if rev) */	int	ndrive;			/* number of transfer elements */	Device*	juke;			/* devworm of changer */	Device*	drive[MAXDRIVE];	/* devworm for i/o */	uchar	offline[MAXDRIVE];	/* drives removed from service */	long	fixedsize;		/* one size fits all */	int	probeok;		/* wait for init to probe */	/*	 * geometry returned by mode sense.	 * a *0 number (such as mt0) is the `element number' of the	 * first element of that type (e.g., mt, or motor transport).	 * an n* number is the quantity of them.	 */	int	mt0,	nmt;	/* motor transports (robot pickers) */	int	se0,	nse;	/* storage elements (discs, slots) */	int	ie0,	nie;	/* interchange elements (mailbox slots) */	int	dt0,	ndt;	/* drives (data transfer?) */	int	rot;		/* if true, discs are double-sided */	Juke*	link;};static	Juke*	jukelist;enum{	Sempty = 0,	/* does not exist */	Sunload,	/* on the shelf */	Sstart,		/* loaded and spinning */};extern int FIXEDSIZE;static	int	wormsense(Device*);static	Side*	wormunit(Device*);static	void	shelves(void);static	int	mmove(Juke*, int, int, int, int);static	int	bestdrive(Juke*, int);static	void	waitready(Device*);static	void	element(Juke*, int);/* * mounts and spins up the device *	locks the structure */staticSide*wormunit(Device *d){	int p, s, drive;	Side *v;	Juke *w;	uchar cmd[10], buf[8];	w = d->private;	p = d->wren.targ;	if(p < 0 || p >= w->nside) {//		panic("wormunit partition %Z\n", d);		return 0;	}	/*	 * if disk is unloaded, must load it	 * into next (circular) logical unit	 */	v = &w->side[p];	qlock(v);	if(v->status == Sunload) {		for(;;) {			qlock(w);			drive = bestdrive(w, p);			if(drive >= 0)				break;			qunlock(w);			waitsec(100);		}		print("	load   r%ld drive %Z\n", v-w->side, w->drive[drive]);		if(mmove(w, w->mt0, v->elem, w->dt0+drive, v->rot)) {			qunlock(w);			goto sbad;		}		v->drive = drive;		v->status = Sstart;		v->stime = toytime();		qunlock(w);		waitready(w->drive[drive]);		v->stime = toytime();	}	if(v->status != Sstart) {		if(v->status == Sempty)			print("worm: unit empty %Z\n", d);		else			print("worm: not started %Z\n", d);		goto sbad;	}	v->time = toytime();	if(v->block)		return v;	/*	 * capacity command	 */	memset(cmd, 0, sizeof(cmd));	memset(buf, 0, sizeof(buf));	cmd[0] = 0x25;	/* read capacity */	s = scsiio(w->drive[v->drive], SCSIread,		cmd, sizeof(cmd), buf, sizeof(buf));	if(s)		goto sbad;	v->nblock =		(buf[0]<<24) |		(buf[1]<<16) |		(buf[2]<<8) |		(buf[3]<<0);	v->block =		(buf[4]<<24) |		(buf[5]<<16) |		(buf[6]<<8) |		(buf[7]<<0);	v->mult =		(RBUFSIZE + v->block - 1) /		v->block;	v->max =		(v->nblock + 1) / v->mult;	print("	worm %Z: drive %Z\n", d, w->drive[v->drive]);	print("		%ld blocks at %ld bytes each\n",		v->nblock, v->block);	print("		%ld logical blocks at %d bytes each\n",		v->max, RBUFSIZE);	print("		%ld multiplier\n",		v->mult);	if(d->type != Devlworm)		return v;	/* check for label */	print("label %Z ordinal %d\n", d, v->ord);	qunlock(v);	return wormunit(d);sbad:	qunlock(v);//	panic("wormunit sbad");	return 0;}staticvoidwaitready(Device *d){	uchar cmd[6];	int s, e;	for(e=0;e<100;e++) {		memset(cmd, 0, sizeof(cmd));		s = scsiio(d, SCSInone, cmd, sizeof(cmd), cmd, 0);		if(s == 0)			break;		waitsec(100);	}}staticintbestdrive(Juke *w, int side){	Side *v, *bv[MAXDRIVE];	int i, s, e, drive;	Timet t, t0;loop:	/* build table of what platters on what drives */	for(i=0; i<w->ndt; i++)		bv[i] = 0;	v = &w->side[0];	for(i=0; i<w->nside; i++, v++) {		s = v->status;		if(s == Sstart) {			drive = v->drive;			if(drive >= 0 && drive < w->ndt)				bv[drive] = v;		}	}	/*	 * find oldest drive, but must be	 * at least THYSTER old.	 */	e = w->side[side].elem;	t0 = toytime() - THYSTER;	t = t0;	drive = -1;	for(i=0; i<w->ndt; i++) {		v = bv[i];		if(v == 0) {		/* 2nd priority: empty drive */			if(w->offline[i])				continue;			if(w->drive[i] != devnone) {				drive = i;				t = 0;			}			continue;		}		if(v->elem == e) {	/* 1st priority: other side */			drive = -1;			if(v->stime < t0)				drive = i;			break;		}		if(v->stime < t) {	/* 3rd priority: by time */			drive = i;			t = v->stime;		}	}	if(drive >= 0) {		v = bv[drive];		if(v) {			qlock(v);			if(v->status != Sstart) {				qunlock(v);				goto loop;			}			print("	unload r%ld drive %Z\n",				v-w->side, w->drive[drive]);			if(mmove(w, w->mt0, w->dt0+drive, v->elem, v->rot)) {				qunlock(v);				goto loop;			}			v->status = Sunload;			qunlock(v);		}	}	return drive;}Devsizewormsize(Device *d){	Side *v;	Juke *w;	Devsize size;	w = d->private;	if(w->fixedsize)		size = w->fixedsize;	else {		v = wormunit(d);		if(v == 0)			return 0;		size = v->max;		qunlock(v);		if(FIXEDSIZE) // TODO? push FIXEDSIZE into Device or Juke struct			w->fixedsize = size;	}	if(d->type == Devlworm)		return size-1;	return size;}/* * return a Devjuke or an mcat (normally of sides) from within d (or nil). * if it's an mcat, the caller must walk it. */static Device *devtojuke(Device *d, Device *top){	while (d != nil)		switch(d->type) {		default:			print("devtojuke: type of device %Z of %Z unknown\n",				d, top);			return nil;		case Devjuke:			/* jackpot!  d->private is a (Juke *) with nside, &c. */			/* FALL THROUGH */		case Devmcat:		case Devmlev:		case Devmirr:			/* squint hard & call an mlev or a mirr an mcat */			return d;		case Devworm:		case Devlworm:			/*			 * d->private is a (Juke *) with nside, etc.,			 * but we're not supposed to get here.			 */			print("devtojuke: (l)worm %Z of %Z encountered\n",				d, top);			/* FALL THROUGH */		case Devwren:		case Devide:			return nil;		case Devcw:			d = d->cw.w;			/* usually juke */			break;		case Devro:			d = d->ro.parent;		/* cw */			break;		case Devfworm:			d = d->fw.fw;			break;		case Devpart:			d = d->part.d;			break;		case Devswab:			d = d->swab.d;			break;		}	return d;}static intdevisside(Device *d){	return d->type == Devworm || d->type == Devlworm;}static Device *findside(Device *juke, int side, Device *top){	int i = 0;	Device *mcat = juke->j.m, *x;	Juke *w = juke->private;	for (x = mcat->cat.first; x != nil; x = x->link) {		if (!devisside(x)) {			print("wormsizeside: %Z of %Z of %Z type not (l)worm\n",				x, mcat, top);			return nil;		}		i = x->wren.targ;		if (i < 0 || i >= w->nside)			panic("wormsizeside: side %d in %Z out of range",				i, mcat);		if (i == side)			break;	}	if (x == nil)		return nil;	if (w->side[i].time == 0) {		print("wormsizeside: side %d not in jukebox %Z\n", i, juke);		return nil;	}	return x;}typedef struct {	int	sleft;		/* sides still to visit to reach desired side */	int	starget;	/* side of topdev we want */	Device	*topdev;	int	sawjuke;	/* passed by a jukebox */	int	sized;		/* flag: asked wormsize for size of starget */} Visit;/* * walk the Device tree from d looking for Devjukes, counting sides. * the main complication is mcats and the like with Devjukes in them. * use Devjuke's d->private as Juke* and see sides. */static Offvisitsides(Device *d, Device *parentj, Visit *vp){	Off size = 0;	Device *x;	Juke *w;	/*	 * find the first juke or mcat.	 * d==nil means we couldn't find one; typically harmless, due to a	 * mirror of dissimilar devices.	 */	d = devtojuke(d, vp->topdev);	if (d == nil || vp->sleft < 0)		return 0;	if (d->type == Devjuke) {    /* jackpot!  d->private is a (Juke *) */		vp->sawjuke = 1;		w = d->private;		/*		 * if there aren't enough sides in this jukebox to reach		 * the desired one, subtract these sides and pass.		 */		if (vp->sleft >= w->nside) {			vp->sleft -= w->nside;			return 0;		}		/* else this is the right juke, paw through mcat of sides */		return visitsides(d->j.m, d, vp);	}	/*	 * d will usually be an mcat of sides, but it could be an mcat of	 * jukes, for example.  in that case, we need to walk the mcat,	 * recursing as needed, until we find the right juke, then stop at	 * the right side within its mcat of sides, by comparing side	 * numbers, not just by counting (to allow for unused slots).	 */	x = d->cat.first;	if (x == nil) {		print("visitsides: %Z of %Z: empty mcat\n", d, vp->topdev);		return 0;	}	if (!devisside(x)) {		for (; x != nil && !vp->sized; x = x->link)			size = visitsides(x, parentj, vp);		return size;	}	/* the side we want is in this jukebox, thus this mcat (d) */	if (parentj == nil) {		print("visitsides: no parent juke for sides mcat %Z\n", d);		vp->sleft = -1;		return 0;	}	if (d != parentj->j.m)		panic("visitsides: mcat mismatch %Z vs %Z", d, parentj->j.m);	x = findside(parentj, vp->sleft, vp->topdev);	if (x == nil) {		vp->sleft = -1;		return 0;	}	/* we've turned vp->starget into the right Device* */	vp->sleft = 0;	vp->sized = 1;	return wormsize(x);}/* * d must be, or be within, a filesystem config that also contains * the jukebox that `side' resides on. * d is normally a Devcw, but could be Devwren, Devide, Devpart, Devfworm, * etc. if called from chk.c Ctouch code.  Note too that the worm part of * the Devcw might be other than a Devjuke. */Devsizewormsizeside(Device *d, int side){	Devsize size;	Visit visit;	memset(&visit, 0, sizeof visit);	visit.starget = visit.sleft = side;	visit.topdev = d;	size = visitsides(d, nil, &visit);	if (visit.sawjuke && (visit.sleft != 0 || !visit.sized)) {		print("wormsizeside: fewer than %d sides in %Z\n", side, d);		return 0;	}	return size;}/* * returns starts (in blocks) of side #side and #(side+1) of dev in *stp. * dev should be a Devcw. */voidwormsidestarts(Device *dev, int side, Sidestarts *stp){	int s;	Devsize dstart;	for (dstart = s = 0; s < side; s++)		dstart += wormsizeside(dev, s);	stp->sstart = dstart;	stp->s1start = dstart + wormsizeside(dev, side);}staticintwormiocmd(Device *d, int io, Off b, void *c){	Side *v;	Juke *w;	Off l;	int s;	long m;	uchar cmd[10];	w = d->private;	v = wormunit(d);	if(v == 0)		return 0x71;	if(b >= v->max) {		qunlock(v);		print("worm: wormiocmd out of range %Z(%lld)\n", d, (Wideoff)b);		return 0x071;	}	memset(cmd, 0, sizeof(cmd));	cmd[0] = 0x28;		/* extended read */	if(io != SCSIread)		cmd[0] = 0x2a;	/* extended write */	m = v->mult;	l = b * m;	cmd[2] = l>>24;	cmd[3] = l>>16;	cmd[4] = l>>8;	cmd[5] = l;	cmd[7] = m>>8;	cmd[8] = m;	s = scsiio(w->drive[v->drive], io, cmd, sizeof(cmd), c, RBUFSIZE);	qunlock(v);	return s;}intwormread(Device *d, Off b, void *c){	int s;	s = wormiocmd(d, SCSIread, b, c);	if(s) {		print("wormread: %Z(%lld) bad status #%x\n", d, (Wideoff)b, s);		cons.nwormre++;		return s;	}	return 0;}intwormwrite(Device *d, Off b, void *c){	int s;	s = wormiocmd(d, SCSIwrite, b, c);	if(s) {		print("wormwrite: %Z(%lld) bad status #%x\n", d, (Wideoff)b, s);		cons.nwormwe++;		return s;	}	return 0;}staticintmmove(Juke *w, int trans, int from, int to, int rot)

⌨️ 快捷键说明

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