Charles.Forsyth20060303644188019 years agoHistory
1474 lines · 27.9 KB · C
RawDownload
/* * Storage Device. */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "ureg.h"#include "../port/error.h" #include "../port/sd.h" extern Dev sddevtab;extern SDifc* sdifc[]; typedef struct SDevgrp {	SDev*	dev;	int	nunits;		/* num units in dev */} SDevgrp; static SDevgrp* devs;			/* all devices */static QLock devslock;			/* insertion and removal of devices */static int ndevs;			/* total number of devices in the system */ enum {	Rawcmd,	Rawdata,	Rawstatus,}; enum {	Qtopdir		= 1,		/* top level directory */	Qtopbase,	Qtopctl = Qtopbase,	Qtopstat, 	Qunitdir,			/* directory per unit */	Qunitbase,	Qctl		= Qunitbase,	Qraw,	Qpart, 	TypeLOG		= 4,	NType		= (1<<TypeLOG),	TypeMASK	= (NType-1),	TypeSHIFT	= 0, 	PartLOG		= 8,	NPart		= (1<<PartLOG),	PartMASK	= (NPart-1),	PartSHIFT	= TypeLOG, 	UnitLOG		= 8,	NUnit		= (1<<UnitLOG),	UnitMASK	= (NUnit-1),	UnitSHIFT	= (PartLOG+TypeLOG), 	DevLOG		= 8,	NDev		= (1 << DevLOG),	DevMASK	= (NDev-1),	DevSHIFT = (UnitLOG+PartLOG+TypeLOG), 	Ncmd = 20,}; #define TYPE(q)		((((ulong)(q).path)>>TypeSHIFT) & TypeMASK)#define PART(q)		((((ulong)(q).path)>>PartSHIFT) & PartMASK)#define UNIT(q)		((((ulong)(q).path)>>UnitSHIFT) & UnitMASK)#define DEV(q)		((((ulong)(q).path)>>DevSHIFT) & DevMASK)#define QID(d,u, p, t)	(((d)<<DevSHIFT)|((u)<<UnitSHIFT)|\					 ((p)<<PartSHIFT)|((t)<<TypeSHIFT))  static voidsdaddpart(SDunit* unit, char* name, ulong start, ulong end){	SDpart *pp;	int i, partno; 	/*	 * Check name not already used	 * and look for a free slot.	 */	if(unit->part != nil){		partno = -1;		for(i = 0; i < unit->npart; i++){			pp = &unit->part[i];			if(!pp->valid){				if(partno == -1)					partno = i;				break;			}			if(strcmp(name, pp->name) == 0){				if(pp->start == start && pp->end == end)					return;				error(Ebadctl);			}		}	}	else{		if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil)			error(Enomem);		unit->npart = SDnpart;		partno = 0;	} 	/*	 * If no free slot found then increase the	 * array size (can't get here with unit->part == nil).	 */	if(partno == -1){		if(unit->npart >= NPart)			error(Enomem);		if((pp = malloc(sizeof(SDpart)*(unit->npart+SDnpart))) == nil)			error(Enomem);		memmove(pp, unit->part, sizeof(SDpart)*unit->npart);		free(unit->part);		unit->part = pp;		partno = unit->npart;		unit->npart += SDnpart;	} 	/*	 * Check size and extent are valid.	 */	if(start > end || end > unit->sectors)		error(Eio);	pp = &unit->part[partno];	pp->start = start;	pp->end = end;	kstrdup(&pp->name, name);	kstrdup(&pp->user, eve);	pp->perm = 0640;	pp->valid = 1;} static voidsddelpart(SDunit* unit,  char* name){	int i;	SDpart *pp; 	/*	 * Look for the partition to delete.	 * Can't delete if someone still has it open.	 */	pp = unit->part;	for(i = 0; i < unit->npart; i++){		if(strcmp(name, pp->name) == 0)			break;		pp++;	}	if(i >= unit->npart)		error(Ebadctl);	if(strcmp(up->env->user, pp->user) && !iseve())		error(Eperm);	pp->valid = 0;	pp->vers++;} static intsdinitpart(SDunit* unit){	int i, nf;	ulong start, end;	char *f[4], *p, *q, buf[10]; 	unit->vers++;	unit->sectors = unit->secsize = 0;	if(unit->part){		for(i = 0; i < unit->npart; i++){			unit->part[i].valid = 0;			unit->part[i].vers++;		}	} 	if(unit->inquiry[0] & 0xC0)		return 0;	switch(unit->inquiry[0] & 0x1F){	case 0x00:			/* DA */	case 0x04:			/* WORM */	case 0x05:			/* CD-ROM */	case 0x07:			/* MO */		break;	default:		return 0;	} 	if(unit->dev->ifc->online)		unit->dev->ifc->online(unit);	if(unit->sectors){		sdaddpart(unit, "data", 0, unit->sectors);			/*		 * Use partitions passed from boot program,		 * e.g.		 *	sdC0part=dos 63 123123/plan9 123123 456456		 * This happens before /boot sets hostname so the		 * partitions will have the null-string for user.		 * The gen functions patch it up.		 */		snprint(buf, sizeof buf, "%spart", unit->name);		for(p = getconf(buf); p != nil; p = q){			if(q = strchr(p, '/'))				*q++ = '\0';			nf = tokenize(p, f, nelem(f));			if(nf < 3)				continue;					start = strtoul(f[1], 0, 0);			end = strtoul(f[2], 0, 0);			if(!waserror()){				sdaddpart(unit, f[0], start, end);				poperror();			}		}				} 	return 1;} static SDev*sdgetdev(int idno){	SDev *sdev;	int i; 	qlock(&devslock);	for(i = 0; i != ndevs; i++)		if(devs[i].dev->idno == idno)			break;		if(i == ndevs)		sdev = nil;	else{		sdev = devs[i].dev;		incref(&sdev->r);	}	qunlock(&devslock);	return sdev;} static SDunit*sdgetunit(SDev* sdev, int subno){	SDunit *unit;	char buf[32]; 	/*	 * Associate a unit with a given device and sub-unit	 * number on that device.	 * The device will be probed if it has not already been	 * successfully accessed.	 */	qlock(&sdev->unitlock);	if(subno > sdev->nunit){		qunlock(&sdev->unitlock);		return nil;	} 	unit = sdev->unit[subno];	if(unit == nil){		/*		 * Probe the unit only once. This decision		 * may be a little severe and reviewed later.		 */		if(sdev->unitflg[subno]){			qunlock(&sdev->unitlock);			return nil;		}		if((unit = malloc(sizeof(SDunit))) == nil){			qunlock(&sdev->unitlock);			return nil;		}		sdev->unitflg[subno] = 1; 		snprint(buf, sizeof(buf), "%s%d", sdev->name, subno);		kstrdup(&unit->name, buf);		kstrdup(&unit->user, eve);		unit->perm = 0555;		unit->subno = subno;		unit->dev = sdev; 		if(sdev->enabled == 0 && sdev->ifc->enable)			sdev->ifc->enable(sdev);		sdev->enabled = 1; 		/*		 * No need to lock anything here as this is only		 * called before the unit is made available in the		 * sdunit[] array.		 */		if(unit->dev->ifc->verify(unit) == 0){			qunlock(&sdev->unitlock);			free(unit);			return nil;		}		sdev->unit[subno] = unit;	}	qunlock(&sdev->unitlock);	return unit;} static voidsdreset(void){	int i;	SDev *sdev, *tail, *sdlist; 	/*	 * Probe all configured controllers and make a list	 * of devices found, accumulating a possible maximum number	 * of units attached and marking each device with an index	 * into the linear top-level directory array of units.	 */	tail = sdlist = nil;	for(i = 0; sdifc[i] != nil; i++){		if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil)			continue;		if(sdlist != nil)			tail->next = sdev;		else			sdlist = sdev;		for(tail = sdev; tail->next != nil; tail = tail->next){			tail->unit = (SDunit**)malloc(tail->nunit * sizeof(SDunit*));			tail->unitflg = (int*)malloc(tail->nunit * sizeof(int));			assert(tail->unit && tail->unitflg);			ndevs++;		}		tail->unit = (SDunit**)malloc(tail->nunit * sizeof(SDunit*));		tail->unitflg = (int*)malloc(tail->nunit * sizeof(int));		ndevs++;	}		/*	 * Legacy and option code goes here. This will be hard...	 */ 	/*	 * The maximum number of possible units is known, allocate	 * placeholders for their datastructures; the units will be	 * probed and structures allocated when attached.	 * Allocate controller names for the different types.	 */	if(ndevs == 0)		return;	for(i = 0; sdifc[i] != nil; i++){		/*		 * BUG: no check is made here or later when a		 * unit is attached that the id and name are set.		 */		if(sdifc[i]->id)			sdifc[i]->id(sdlist);	} 	/* 	  * The IDs have been set, unlink the sdlist and copy the spec to	  * the devtab.	  */	devs = (SDevgrp*)malloc(ndevs * sizeof(SDevgrp));	memset(devs, 0, ndevs * sizeof(SDevgrp));	i = 0;	while(sdlist != nil){		devs[i].dev = sdlist;		devs[i].nunits = sdlist->nunit;		sdlist = sdlist->next;		devs[i].dev->next = nil;		i++;	}} static intsd2gen(Chan* c, int i, Dir* dp){	Qid q;	vlong l;	SDpart *pp;	SDperm *perm;	SDunit *unit;	SDev *sdev;	int rv; 	sdev = sdgetdev(DEV(c->qid));	assert(sdev);	unit = sdev->unit[UNIT(c->qid)]; 	rv = -1;	switch(i){	case Qctl:		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qctl), 			   unit->vers, QTFILE);		perm = &unit->ctlperm;		if(emptystr(perm->user)){			kstrdup(&perm->user, eve);			perm->perm = 0640;		}		devdir(c, q, "ctl", 0, perm->user, perm->perm, dp);		rv = 1;		break; 	case Qraw:		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qraw), 			   unit->vers, QTFILE);		perm = &unit->rawperm;		if(emptystr(perm->user)){			kstrdup(&perm->user, eve);			perm->perm = DMEXCL|0600;		}		devdir(c, q, "raw", 0, perm->user, perm->perm, dp);		rv = 1;		break; 	case Qpart:		pp = &unit->part[PART(c->qid)];		l = (pp->end - pp->start) * (vlong)unit->secsize;		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qpart), 			   unit->vers+pp->vers, QTFILE);		if(emptystr(pp->user))			kstrdup(&pp->user, eve);		devdir(c, q, pp->name, l, pp->user, pp->perm, dp);		rv = 1;		break;	}		decref(&sdev->r);	return rv;} static intsd1gen(Chan* c, int i, Dir* dp){	Qid q; 	switch(i){	case Qtopctl:		mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE);		devdir(c, q, "sdctl", 0, eve, 0640, dp);		return 1;	case Qtopstat:		mkqid(&q, QID(0, 0, 0, Qtopstat), 0, QTFILE);		devdir(c, q, "sdstat", 0, eve, 0640, dp);		return 1;	}	return -1;} static intsdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp){	Qid q;	vlong l;	int i, r;	SDpart *pp;	SDunit *unit;	SDev *sdev; 	switch(TYPE(c->qid)){	case Qtopdir:		if(s == DEVDOTDOT){			mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);			sprint(up->genbuf, "#%C", sddevtab.dc);			devdir(c, q, up->genbuf, 0, eve, 0555, dp);			return 1;		} 		if(s == 0 || s == 1)			return sd1gen(c, s + Qtopbase, dp);		s -= 2; 		qlock(&devslock);		for(i = 0; i != ndevs; i++){			if(s < devs[i].nunits)				break;			s -= devs[i].nunits;		}				if(i == ndevs){			/* Run of the end of the list */			qunlock(&devslock);			return -1;		} 		if((sdev = devs[i].dev) == nil){			qunlock(&devslock);			return 0;		} 		incref(&sdev->r);		qunlock(&devslock); 		if((unit = sdev->unit[s]) == nil)			if((unit = sdgetunit(sdev, s)) == nil){				decref(&sdev->r);				return 0;			} 		mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR);		if(emptystr(unit->user))

Lines 1–500 of 1474.