1892 lines · 35.4 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[]; static	char	Echange[]	= "media or partition has changed";static	char	Enoata[]		= "raw ata commands not supported";static	char	Enoscsi[]	= "raw scsi commands not supported"; static char devletters[] = "0123456789"	"abcdefghijklmnopqrstuvwxyz"	"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; static SDev *devs[sizeof devletters-1];static QLock devslock;static SDunit topctlunit; enum {	Ahdrsz		= 2,}; enum {	Rawcmd,	Rawdata,	Rawstatus,}; enum {	Qtopdir		= 1,		/* top level directory */	Qtopbase,	Qtopctl		 = Qtopbase, 	Qunitdir,			/* directory per unit */	Qunitbase,	Qctl		= Qunitbase,	Qraw,	Qpart,	Qextra, 	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, 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;	ulong vers0;	uvlong start, end;	char *f[4], *p, *q, buf[10]; 	vers0 = unit->vers;	if(unit->sectors > 0){		unit->sectors = unit->secsize = 0;		sdincvers(unit);	} 	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){		sdincvers(unit);		sdaddpart(unit, "data", 0, unit->sectors);	}	if(unit->sectors && vers0 == 0){		/*		 * 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%x", 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; 	/*	 * Probe all known controller types and register any devices found.	 */	for(i = 0; sdifc[i] != nil; i++){		if(sdifc[i]->pnp == nil)			continue;		sdadddevs(sdifc[i]->pnp());	}} voidsdadddevs(SDev *sdev){	int i, j, id;	SDev *next; 	for(; sdev; sdev=next){		next = sdev->next; 		sdev->unit = malloc(sdev->nunit * sizeof(SDunit*));		sdev->unitflg = 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);// } static intsd2gen(Chan* c, int i, Dir* dp){	Qid q;	uvlong l;	SDfile *e;	SDpart *pp;	SDperm *perm;	SDunit *unit;	SDev *sdev;	int rv, t; 	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;		}		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;	case Qextra:		t = PART(c->qid);		if(t >= unit->nefile)			break;		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qextra),			unit->vers, QTFILE);		e = unit->efile + t;		if(emptystr(e->user))			kstrdup(&e->user, eve);		devdir(c, q, e->name, 0, e->user, e->perm, dp);		rv = 1;		break;	} 	decref(&sdev->r);	return rv;} static intsd1gen(Chan* c, int i, Dir* dp){	Qid q;	SDperm *p; 	switch(i){	case Qtopctl:		mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE);		qlock(&topctlunit.ctl);		p = &topctlunit.ctlperm;		if(p->user == nil || p->user[0] == 0){			kstrdup(&p->name, "sdctl");			kstrdup(&p->user, eve);			p->perm = 0640;		}		devdir(c, q, p->name, 0, p->user, p->perm, dp);		qunlock(&topctlunit.ctl);		return 1;	}	return -1;} static intefilegen(Chan *c, SDunit *unit, int i, Dir *dp){	Qid q;	SDfile *e; 	i -= SDnpart;	if(unit->nefile == 0 || i >= unit->nefile)

Lines 1–500 of 1892.