1671 lines · 31.5 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * 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[]; static char devletters[] = "0123456789"	"abcdefghijklmnopqrstuvwxyz"	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static SDev *devs[sizeof devletters-1];static QLock devslock; enum {	Rawcmd,	Rawdata,	Rawstatus,}; enum {	Qtopdir		= 1,		/* top level directory */	Qtopbase,	Qtopctl		 = Qtopbase, 	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))  voidsdaddpart(SDunit* unit, char* name, uvlong start, uvlong 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->user, pp->user) && !iseve())		error(Eperm);	pp->valid = 0;	pp->vers++;} static voidsdincvers(SDunit *unit){	int i; 	unit->vers++;	if(unit->part){		for(i = 0; i < unit->npart; i++){			unit->part[i].valid = 0;			unit->part[i].vers++;		}	}} static intsdinitpart(SDunit* unit){	int nf;	uvlong start, end;	char *f[4], *p, *q, buf[10]; 	if(unit->sectors > 0){		unit->sectors = unit->secsize = 0;		sdincvers(unit);	} 	/* device must be connected or not; other values are trouble */	if(unit->inquiry[0] & 0xC0)	/* see SDinq0periphqual */		return 0;	switch(unit->inquiry[0] & SDinq0periphtype){	case SDperdisk:	case SDperworm:	case SDpercd:	case SDpermo:		break;	default:		return 0;	} 	if(unit->dev->ifc->online)		unit->dev->ifc->online(unit);	if(unit->sectors){		sdincvers(unit);		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 = strtoull(f[1], 0, 0);			end = strtoull(f[2], 0, 0);			if(!waserror()){				sdaddpart(unit, f[0], start, end);				poperror();			}		}	} 	return 1;} static intsdindex(int idno){	char *p; 	p = strchr(devletters, idno);	if(p == nil)		return -1;	return p-devletters;} static SDev*sdgetdev(int idno){	SDev *sdev;	int i; 	if((i = sdindex(idno)) < 0)		return nil; 	qlock(&devslock);	if(sdev = devs[i])		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; 	/*	 * Probe all known controller types and register any devices found.	 */	for(i = 0; sdifc[i] != nil; i++){		if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil)			continue;		sdadddevs(sdev);	}} voidsdadddevs(SDev *sdev){	int i, j, id;	SDev *next; 	for(; sdev; sdev=next){		next = sdev->next; 		sdev->unit = (SDunit**)malloc(sdev->nunit * sizeof(SDunit*));		sdev->unitflg = (int*)malloc(sdev->nunit * sizeof(int));		if(sdev->unit == nil || sdev->unitflg == nil){			print("sdadddevs: out of memory\n");		giveup:			free(sdev->unit);			free(sdev->unitflg);			if(sdev->ifc->clear)				sdev->ifc->clear(sdev);			free(sdev);			continue;		}		id = sdindex(sdev->idno);		if(id == -1){			print("sdadddevs: bad id number %d (%C)\n", id, id);			goto giveup;		}		qlock(&devslock);		for(i=0; i<nelem(devs); i++){			if(devs[j = (id+i)%nelem(devs)] == nil){				sdev->idno = devletters[j];				devs[j] = sdev;				snprint(sdev->name, sizeof sdev->name, "sd%c", devletters[j]);				break;			}		}		qunlock(&devslock);		if(i == nelem(devs)){			print("sdadddevs: out of device letters\n");			goto giveup;		}	}} // void// sdrmdevs(SDev *sdev)// {// 	char buf[2];//// 	snprint(buf, sizeof buf, "%c", sdev->idno);// 	unconfigure(buf);// } voidsdaddallconfs(void (*addconf)(SDunit *)){	int i, u;	SDev *sdev; 	for(i = 0; i < nelem(devs); i++)		/* each controller */		for(sdev = devs[i]; sdev; sdev = sdev->next)			for(u = 0; u < sdev->nunit; u++)	/* each drive */				(*addconf)(sdev->unit[u]);} static intsd2gen(Chan* c, int i, Dir* dp){	Qid q;	uvlong 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 = 0644;	/* nothing secret in ctl */		}		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) * 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, 0644, dp);	/* no secrets */		return 1;	}	return -1;} static intsdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp){	Qid q;	uvlong 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);			snprint(up->genbuf, sizeof up->genbuf, "#%C",				sddevtab.dc);			devdir(c, q, up->genbuf, 0, eve, 0555, dp);			return 1;		} 

Lines 1–500 of 1671.