xref: /plan9/sys/src/9/port/devsd.c (revision a587111c8770e522e3667ff2b63cba8a77811dd9)
17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier  * Storage Device.
37dd7cddfSDavid du Colombier  */
47dd7cddfSDavid du Colombier #include "u.h"
57dd7cddfSDavid du Colombier #include "../port/lib.h"
67dd7cddfSDavid du Colombier #include "mem.h"
77dd7cddfSDavid du Colombier #include "dat.h"
87dd7cddfSDavid du Colombier #include "fns.h"
97dd7cddfSDavid du Colombier #include "io.h"
107dd7cddfSDavid du Colombier #include "ureg.h"
117dd7cddfSDavid du Colombier #include "../port/error.h"
127dd7cddfSDavid du Colombier 
1380ee5cbfSDavid du Colombier #include "../port/sd.h"
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier extern Dev sddevtab;
167dd7cddfSDavid du Colombier extern SDifc* sdifc[];
177dd7cddfSDavid du Colombier 
184de34a7eSDavid du Colombier static char devletters[] = "0123456789"
194de34a7eSDavid du Colombier 	"abcdefghijklmnopqrstuvwxyz"
204de34a7eSDavid du Colombier 	"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
214de34a7eSDavid du Colombier 
224de34a7eSDavid du Colombier static SDev *devs[sizeof devletters-1];
234de34a7eSDavid du Colombier static QLock devslock;
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier enum {
267dd7cddfSDavid du Colombier 	Rawcmd,
277dd7cddfSDavid du Colombier 	Rawdata,
287dd7cddfSDavid du Colombier 	Rawstatus,
297dd7cddfSDavid du Colombier };
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier enum {
327dd7cddfSDavid du Colombier 	Qtopdir		= 1,		/* top level directory */
337dd7cddfSDavid du Colombier 	Qtopbase,
349a747e4fSDavid du Colombier 	Qtopctl		 = Qtopbase,
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier 	Qunitdir,			/* directory per unit */
377dd7cddfSDavid du Colombier 	Qunitbase,
387dd7cddfSDavid du Colombier 	Qctl		= Qunitbase,
397dd7cddfSDavid du Colombier 	Qraw,
407dd7cddfSDavid du Colombier 	Qpart,
419a747e4fSDavid du Colombier 
429a747e4fSDavid du Colombier 	TypeLOG		= 4,
439a747e4fSDavid du Colombier 	NType		= (1<<TypeLOG),
449a747e4fSDavid du Colombier 	TypeMASK	= (NType-1),
459a747e4fSDavid du Colombier 	TypeSHIFT	= 0,
469a747e4fSDavid du Colombier 
479a747e4fSDavid du Colombier 	PartLOG		= 8,
489a747e4fSDavid du Colombier 	NPart		= (1<<PartLOG),
499a747e4fSDavid du Colombier 	PartMASK	= (NPart-1),
509a747e4fSDavid du Colombier 	PartSHIFT	= TypeLOG,
519a747e4fSDavid du Colombier 
529a747e4fSDavid du Colombier 	UnitLOG		= 8,
539a747e4fSDavid du Colombier 	NUnit		= (1<<UnitLOG),
549a747e4fSDavid du Colombier 	UnitMASK	= (NUnit-1),
559a747e4fSDavid du Colombier 	UnitSHIFT	= (PartLOG+TypeLOG),
569a747e4fSDavid du Colombier 
579a747e4fSDavid du Colombier 	DevLOG		= 8,
589a747e4fSDavid du Colombier 	NDev		= (1 << DevLOG),
599a747e4fSDavid du Colombier 	DevMASK		= (NDev-1),
609a747e4fSDavid du Colombier 	DevSHIFT	 = (UnitLOG+PartLOG+TypeLOG),
619a747e4fSDavid du Colombier 
629a747e4fSDavid du Colombier 	Ncmd = 20,
637dd7cddfSDavid du Colombier };
647dd7cddfSDavid du Colombier 
659a747e4fSDavid du Colombier #define TYPE(q)		((((ulong)(q).path)>>TypeSHIFT) & TypeMASK)
669a747e4fSDavid du Colombier #define PART(q)		((((ulong)(q).path)>>PartSHIFT) & PartMASK)
679a747e4fSDavid du Colombier #define UNIT(q)		((((ulong)(q).path)>>UnitSHIFT) & UnitMASK)
689a747e4fSDavid du Colombier #define DEV(q)		((((ulong)(q).path)>>DevSHIFT) & DevMASK)
699a747e4fSDavid du Colombier #define QID(d,u, p, t)	(((d)<<DevSHIFT)|((u)<<UnitSHIFT)|\
709a747e4fSDavid du Colombier 					 ((p)<<PartSHIFT)|((t)<<TypeSHIFT))
719a747e4fSDavid du Colombier 
727dd7cddfSDavid du Colombier 
732210c76eSDavid du Colombier void
sdaddpart(SDunit * unit,char * name,uvlong start,uvlong end)7417629263SDavid du Colombier sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
757dd7cddfSDavid du Colombier {
767dd7cddfSDavid du Colombier 	SDpart *pp;
777dd7cddfSDavid du Colombier 	int i, partno;
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier 	/*
807dd7cddfSDavid du Colombier 	 * Check name not already used
817dd7cddfSDavid du Colombier 	 * and look for a free slot.
827dd7cddfSDavid du Colombier 	 */
837dd7cddfSDavid du Colombier 	if(unit->part != nil){
847dd7cddfSDavid du Colombier 		partno = -1;
8559cc4ca5SDavid du Colombier 		for(i = 0; i < unit->npart; i++){
867dd7cddfSDavid du Colombier 			pp = &unit->part[i];
877dd7cddfSDavid du Colombier 			if(!pp->valid){
887dd7cddfSDavid du Colombier 				if(partno == -1)
897dd7cddfSDavid du Colombier 					partno = i;
907dd7cddfSDavid du Colombier 				break;
917dd7cddfSDavid du Colombier 			}
929a747e4fSDavid du Colombier 			if(strcmp(name, pp->name) == 0){
937dd7cddfSDavid du Colombier 				if(pp->start == start && pp->end == end)
947dd7cddfSDavid du Colombier 					return;
957dd7cddfSDavid du Colombier 				error(Ebadctl);
967dd7cddfSDavid du Colombier 			}
977dd7cddfSDavid du Colombier 		}
987dd7cddfSDavid du Colombier 	}
997dd7cddfSDavid du Colombier 	else{
1007dd7cddfSDavid du Colombier 		if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil)
1017dd7cddfSDavid du Colombier 			error(Enomem);
10259cc4ca5SDavid du Colombier 		unit->npart = SDnpart;
1037dd7cddfSDavid du Colombier 		partno = 0;
1047dd7cddfSDavid du Colombier 	}
1057dd7cddfSDavid du Colombier 
1067dd7cddfSDavid du Colombier 	/*
10759cc4ca5SDavid du Colombier 	 * If no free slot found then increase the
10859cc4ca5SDavid du Colombier 	 * array size (can't get here with unit->part == nil).
1097dd7cddfSDavid du Colombier 	 */
11059cc4ca5SDavid du Colombier 	if(partno == -1){
1119a747e4fSDavid du Colombier 		if(unit->npart >= NPart)
1129a747e4fSDavid du Colombier 			error(Enomem);
11359cc4ca5SDavid du Colombier 		if((pp = malloc(sizeof(SDpart)*(unit->npart+SDnpart))) == nil)
11459cc4ca5SDavid du Colombier 			error(Enomem);
11559cc4ca5SDavid du Colombier 		memmove(pp, unit->part, sizeof(SDpart)*unit->npart);
11659cc4ca5SDavid du Colombier 		free(unit->part);
11759cc4ca5SDavid du Colombier 		unit->part = pp;
11859cc4ca5SDavid du Colombier 		partno = unit->npart;
11959cc4ca5SDavid du Colombier 		unit->npart += SDnpart;
12059cc4ca5SDavid du Colombier 	}
12159cc4ca5SDavid du Colombier 
12259cc4ca5SDavid du Colombier 	/*
12359cc4ca5SDavid du Colombier 	 * Check size and extent are valid.
12459cc4ca5SDavid du Colombier 	 */
125223a736eSDavid du Colombier 	if(start > end || end > unit->sectors)
1267dd7cddfSDavid du Colombier 		error(Eio);
1277dd7cddfSDavid du Colombier 	pp = &unit->part[partno];
1287dd7cddfSDavid du Colombier 	pp->start = start;
1297dd7cddfSDavid du Colombier 	pp->end = end;
1309a747e4fSDavid du Colombier 	kstrdup(&pp->name, name);
1319a747e4fSDavid du Colombier 	kstrdup(&pp->user, eve);
1327dd7cddfSDavid du Colombier 	pp->perm = 0640;
1337dd7cddfSDavid du Colombier 	pp->valid = 1;
1347dd7cddfSDavid du Colombier }
1357dd7cddfSDavid du Colombier 
1367dd7cddfSDavid du Colombier static void
sddelpart(SDunit * unit,char * name)1377dd7cddfSDavid du Colombier sddelpart(SDunit* unit, char* name)
1387dd7cddfSDavid du Colombier {
1397dd7cddfSDavid du Colombier 	int i;
1407dd7cddfSDavid du Colombier 	SDpart *pp;
1417dd7cddfSDavid du Colombier 
1427dd7cddfSDavid du Colombier 	/*
1437dd7cddfSDavid du Colombier 	 * Look for the partition to delete.
1447dd7cddfSDavid du Colombier 	 * Can't delete if someone still has it open.
1457dd7cddfSDavid du Colombier 	 */
1467dd7cddfSDavid du Colombier 	pp = unit->part;
14759cc4ca5SDavid du Colombier 	for(i = 0; i < unit->npart; i++){
1489a747e4fSDavid du Colombier 		if(strcmp(name, pp->name) == 0)
1497dd7cddfSDavid du Colombier 			break;
1507dd7cddfSDavid du Colombier 		pp++;
1517dd7cddfSDavid du Colombier 	}
15259cc4ca5SDavid du Colombier 	if(i >= unit->npart)
1537dd7cddfSDavid du Colombier 		error(Ebadctl);
1549a747e4fSDavid du Colombier 	if(strcmp(up->user, pp->user) && !iseve())
1559a747e4fSDavid du Colombier 		error(Eperm);
1567dd7cddfSDavid du Colombier 	pp->valid = 0;
157223a736eSDavid du Colombier 	pp->vers++;
1587dd7cddfSDavid du Colombier }
1597dd7cddfSDavid du Colombier 
160d95be1c0SDavid du Colombier static void
sdincvers(SDunit * unit)161d95be1c0SDavid du Colombier sdincvers(SDunit *unit)
1627dd7cddfSDavid du Colombier {
163d95be1c0SDavid du Colombier 	int i;
1647dd7cddfSDavid du Colombier 
165223a736eSDavid du Colombier 	unit->vers++;
1667dd7cddfSDavid du Colombier 	if(unit->part){
16759cc4ca5SDavid du Colombier 		for(i = 0; i < unit->npart; i++){
168223a736eSDavid du Colombier 			unit->part[i].valid = 0;
169223a736eSDavid du Colombier 			unit->part[i].vers++;
170223a736eSDavid du Colombier 		}
1717dd7cddfSDavid du Colombier 	}
172d95be1c0SDavid du Colombier }
173d95be1c0SDavid du Colombier 
174d95be1c0SDavid du Colombier static int
sdinitpart(SDunit * unit)175d95be1c0SDavid du Colombier sdinitpart(SDunit* unit)
176d95be1c0SDavid du Colombier {
177d95be1c0SDavid du Colombier 	int nf;
17817629263SDavid du Colombier 	uvlong start, end;
179d95be1c0SDavid du Colombier 	char *f[4], *p, *q, buf[10];
180d95be1c0SDavid du Colombier 
181d95be1c0SDavid du Colombier 	if(unit->sectors > 0){
182d95be1c0SDavid du Colombier 		unit->sectors = unit->secsize = 0;
183d95be1c0SDavid du Colombier 		sdincvers(unit);
184d95be1c0SDavid du Colombier 	}
1857dd7cddfSDavid du Colombier 
18627522402SDavid du Colombier 	/* device must be connected or not; other values are trouble */
18727522402SDavid du Colombier 	if(unit->inquiry[0] & 0xC0)	/* see SDinq0periphqual */
1887dd7cddfSDavid du Colombier 		return 0;
18927522402SDavid du Colombier 	switch(unit->inquiry[0] & SDinq0periphtype){
19027522402SDavid du Colombier 	case SDperdisk:
19127522402SDavid du Colombier 	case SDperworm:
19227522402SDavid du Colombier 	case SDpercd:
19327522402SDavid du Colombier 	case SDpermo:
1947dd7cddfSDavid du Colombier 		break;
1957dd7cddfSDavid du Colombier 	default:
1967dd7cddfSDavid du Colombier 		return 0;
1977dd7cddfSDavid du Colombier 	}
1987dd7cddfSDavid du Colombier 
1997dd7cddfSDavid du Colombier 	if(unit->dev->ifc->online)
2007dd7cddfSDavid du Colombier 		unit->dev->ifc->online(unit);
2017dd7cddfSDavid du Colombier 	if(unit->sectors){
202d95be1c0SDavid du Colombier 		sdincvers(unit);
2037dd7cddfSDavid du Colombier 		sdaddpart(unit, "data", 0, unit->sectors);
2047dd7cddfSDavid du Colombier 
2057dd7cddfSDavid du Colombier 		/*
2067dd7cddfSDavid du Colombier 		 * Use partitions passed from boot program,
2077dd7cddfSDavid du Colombier 		 * e.g.
2087dd7cddfSDavid du Colombier 		 *	sdC0part=dos 63 123123/plan9 123123 456456
2097dd7cddfSDavid du Colombier 		 * This happens before /boot sets hostname so the
2107dd7cddfSDavid du Colombier 		 * partitions will have the null-string for user.
2117dd7cddfSDavid du Colombier 		 * The gen functions patch it up.
2127dd7cddfSDavid du Colombier 		 */
2137dd7cddfSDavid du Colombier 		snprint(buf, sizeof buf, "%spart", unit->name);
2147dd7cddfSDavid du Colombier 		for(p = getconf(buf); p != nil; p = q){
2157dd7cddfSDavid du Colombier 			if(q = strchr(p, '/'))
2167dd7cddfSDavid du Colombier 				*q++ = '\0';
2179a747e4fSDavid du Colombier 			nf = tokenize(p, f, nelem(f));
2187dd7cddfSDavid du Colombier 			if(nf < 3)
2197dd7cddfSDavid du Colombier 				continue;
2207dd7cddfSDavid du Colombier 
22117629263SDavid du Colombier 			start = strtoull(f[1], 0, 0);
22217629263SDavid du Colombier 			end = strtoull(f[2], 0, 0);
2237dd7cddfSDavid du Colombier 			if(!waserror()){
2247dd7cddfSDavid du Colombier 				sdaddpart(unit, f[0], start, end);
2257dd7cddfSDavid du Colombier 				poperror();
2267dd7cddfSDavid du Colombier 			}
2277dd7cddfSDavid du Colombier 		}
2287dd7cddfSDavid du Colombier 	}
2297dd7cddfSDavid du Colombier 
2307dd7cddfSDavid du Colombier 	return 1;
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier 
2334de34a7eSDavid du Colombier static int
sdindex(int idno)2344de34a7eSDavid du Colombier sdindex(int idno)
2354de34a7eSDavid du Colombier {
2364de34a7eSDavid du Colombier 	char *p;
2374de34a7eSDavid du Colombier 
2384de34a7eSDavid du Colombier 	p = strchr(devletters, idno);
2394de34a7eSDavid du Colombier 	if(p == nil)
2404de34a7eSDavid du Colombier 		return -1;
2414de34a7eSDavid du Colombier 	return p-devletters;
2424de34a7eSDavid du Colombier }
2434de34a7eSDavid du Colombier 
2449a747e4fSDavid du Colombier static SDev*
sdgetdev(int idno)2459a747e4fSDavid du Colombier sdgetdev(int idno)
2469a747e4fSDavid du Colombier {
2479a747e4fSDavid du Colombier 	SDev *sdev;
2489a747e4fSDavid du Colombier 	int i;
2499a747e4fSDavid du Colombier 
2504de34a7eSDavid du Colombier 	if((i = sdindex(idno)) < 0)
2514de34a7eSDavid du Colombier 		return nil;
2529a747e4fSDavid du Colombier 
2534de34a7eSDavid du Colombier 	qlock(&devslock);
2544de34a7eSDavid du Colombier 	if(sdev = devs[i])
2559a747e4fSDavid du Colombier 		incref(&sdev->r);
2569a747e4fSDavid du Colombier 	qunlock(&devslock);
2579a747e4fSDavid du Colombier 	return sdev;
2589a747e4fSDavid du Colombier }
2599a747e4fSDavid du Colombier 
2607dd7cddfSDavid du Colombier static SDunit*
sdgetunit(SDev * sdev,int subno)2617dd7cddfSDavid du Colombier sdgetunit(SDev* sdev, int subno)
2627dd7cddfSDavid du Colombier {
2637dd7cddfSDavid du Colombier 	SDunit *unit;
2649a747e4fSDavid du Colombier 	char buf[32];
2657dd7cddfSDavid du Colombier 
2667dd7cddfSDavid du Colombier 	/*
2677dd7cddfSDavid du Colombier 	 * Associate a unit with a given device and sub-unit
2687dd7cddfSDavid du Colombier 	 * number on that device.
2697dd7cddfSDavid du Colombier 	 * The device will be probed if it has not already been
2707dd7cddfSDavid du Colombier 	 * successfully accessed.
2717dd7cddfSDavid du Colombier 	 */
2729a747e4fSDavid du Colombier 	qlock(&sdev->unitlock);
2739a747e4fSDavid du Colombier 	if(subno > sdev->nunit){
2749a747e4fSDavid du Colombier 		qunlock(&sdev->unitlock);
2759a747e4fSDavid du Colombier 		return nil;
2769a747e4fSDavid du Colombier 	}
2779a747e4fSDavid du Colombier 
2789a747e4fSDavid du Colombier 	unit = sdev->unit[subno];
2797dd7cddfSDavid du Colombier 	if(unit == nil){
2807dd7cddfSDavid du Colombier 		/*
2817dd7cddfSDavid du Colombier 		 * Probe the unit only once. This decision
2827dd7cddfSDavid du Colombier 		 * may be a little severe and reviewed later.
2837dd7cddfSDavid du Colombier 		 */
2849a747e4fSDavid du Colombier 		if(sdev->unitflg[subno]){
2859a747e4fSDavid du Colombier 			qunlock(&sdev->unitlock);
2867dd7cddfSDavid du Colombier 			return nil;
2877dd7cddfSDavid du Colombier 		}
2887dd7cddfSDavid du Colombier 		if((unit = malloc(sizeof(SDunit))) == nil){
2899a747e4fSDavid du Colombier 			qunlock(&sdev->unitlock);
2907dd7cddfSDavid du Colombier 			return nil;
2917dd7cddfSDavid du Colombier 		}
2929a747e4fSDavid du Colombier 		sdev->unitflg[subno] = 1;
2937dd7cddfSDavid du Colombier 
2949a747e4fSDavid du Colombier 		snprint(buf, sizeof(buf), "%s%d", sdev->name, subno);
2959a747e4fSDavid du Colombier 		kstrdup(&unit->name, buf);
2969a747e4fSDavid du Colombier 		kstrdup(&unit->user, eve);
29759cc4ca5SDavid du Colombier 		unit->perm = 0555;
2987dd7cddfSDavid du Colombier 		unit->subno = subno;
2997dd7cddfSDavid du Colombier 		unit->dev = sdev;
3007dd7cddfSDavid du Colombier 
301dc5a79c1SDavid du Colombier 		if(sdev->enabled == 0 && sdev->ifc->enable)
302dc5a79c1SDavid du Colombier 			sdev->ifc->enable(sdev);
303dc5a79c1SDavid du Colombier 		sdev->enabled = 1;
304dc5a79c1SDavid du Colombier 
3057dd7cddfSDavid du Colombier 		/*
3067dd7cddfSDavid du Colombier 		 * No need to lock anything here as this is only
3077dd7cddfSDavid du Colombier 		 * called before the unit is made available in the
3087dd7cddfSDavid du Colombier 		 * sdunit[] array.
3097dd7cddfSDavid du Colombier 		 */
3107dd7cddfSDavid du Colombier 		if(unit->dev->ifc->verify(unit) == 0){
3119a747e4fSDavid du Colombier 			qunlock(&sdev->unitlock);
3127dd7cddfSDavid du Colombier 			free(unit);
3137dd7cddfSDavid du Colombier 			return nil;
3147dd7cddfSDavid du Colombier 		}
3159a747e4fSDavid du Colombier 		sdev->unit[subno] = unit;
3167dd7cddfSDavid du Colombier 	}
3179a747e4fSDavid du Colombier 	qunlock(&sdev->unitlock);
3187dd7cddfSDavid du Colombier 	return unit;
3197dd7cddfSDavid du Colombier }
3207dd7cddfSDavid du Colombier 
3217dd7cddfSDavid du Colombier static void
sdreset(void)3227dd7cddfSDavid du Colombier sdreset(void)
3237dd7cddfSDavid du Colombier {
3247dd7cddfSDavid du Colombier 	int i;
3254de34a7eSDavid du Colombier 	SDev *sdev;
3267dd7cddfSDavid du Colombier 
3277dd7cddfSDavid du Colombier 	/*
3284de34a7eSDavid du Colombier 	 * Probe all known controller types and register any devices found.
3297dd7cddfSDavid du Colombier 	 */
3307dd7cddfSDavid du Colombier 	for(i = 0; sdifc[i] != nil; i++){
3317dd7cddfSDavid du Colombier 		if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil)
3327dd7cddfSDavid du Colombier 			continue;
3334de34a7eSDavid du Colombier 		sdadddevs(sdev);
3347dd7cddfSDavid du Colombier 	}
3357dd7cddfSDavid du Colombier }
3367dd7cddfSDavid du Colombier 
3374de34a7eSDavid du Colombier void
sdadddevs(SDev * sdev)3384de34a7eSDavid du Colombier sdadddevs(SDev *sdev)
3394de34a7eSDavid du Colombier {
3404de34a7eSDavid du Colombier 	int i, j, id;
3414de34a7eSDavid du Colombier 	SDev *next;
3427dd7cddfSDavid du Colombier 
3434de34a7eSDavid du Colombier 	for(; sdev; sdev=next){
3444de34a7eSDavid du Colombier 		next = sdev->next;
3454de34a7eSDavid du Colombier 
3464de34a7eSDavid du Colombier 		sdev->unit = (SDunit**)malloc(sdev->nunit * sizeof(SDunit*));
3474de34a7eSDavid du Colombier 		sdev->unitflg = (int*)malloc(sdev->nunit * sizeof(int));
3484de34a7eSDavid du Colombier 		if(sdev->unit == nil || sdev->unitflg == nil){
3494de34a7eSDavid du Colombier 			print("sdadddevs: out of memory\n");
3504de34a7eSDavid du Colombier 		giveup:
3514de34a7eSDavid du Colombier 			free(sdev->unit);
3524de34a7eSDavid du Colombier 			free(sdev->unitflg);
3534de34a7eSDavid du Colombier 			if(sdev->ifc->clear)
3544de34a7eSDavid du Colombier 				sdev->ifc->clear(sdev);
3554de34a7eSDavid du Colombier 			free(sdev);
3564de34a7eSDavid du Colombier 			continue;
3577dd7cddfSDavid du Colombier 		}
3584de34a7eSDavid du Colombier 		id = sdindex(sdev->idno);
3594de34a7eSDavid du Colombier 		if(id == -1){
3604de34a7eSDavid du Colombier 			print("sdadddevs: bad id number %d (%C)\n", id, id);
3614de34a7eSDavid du Colombier 			goto giveup;
3624de34a7eSDavid du Colombier 		}
3634de34a7eSDavid du Colombier 		qlock(&devslock);
3644de34a7eSDavid du Colombier 		for(i=0; i<nelem(devs); i++){
3654de34a7eSDavid du Colombier 			if(devs[j = (id+i)%nelem(devs)] == nil){
3664de34a7eSDavid du Colombier 				sdev->idno = devletters[j];
3674de34a7eSDavid du Colombier 				devs[j] = sdev;
3684de34a7eSDavid du Colombier 				snprint(sdev->name, sizeof sdev->name, "sd%c", devletters[j]);
3694de34a7eSDavid du Colombier 				break;
3704de34a7eSDavid du Colombier 			}
3714de34a7eSDavid du Colombier 		}
3724de34a7eSDavid du Colombier 		qunlock(&devslock);
3734de34a7eSDavid du Colombier 		if(i == nelem(devs)){
3744de34a7eSDavid du Colombier 			print("sdadddevs: out of device letters\n");
3754de34a7eSDavid du Colombier 			goto giveup;
3764de34a7eSDavid du Colombier 		}
3779a747e4fSDavid du Colombier 	}
3787dd7cddfSDavid du Colombier }
3797dd7cddfSDavid du Colombier 
38017629263SDavid du Colombier // void
38117629263SDavid du Colombier // sdrmdevs(SDev *sdev)
38217629263SDavid du Colombier // {
38317629263SDavid du Colombier // 	char buf[2];
38417629263SDavid du Colombier //
38517629263SDavid du Colombier // 	snprint(buf, sizeof buf, "%c", sdev->idno);
38617629263SDavid du Colombier // 	unconfigure(buf);
38717629263SDavid du Colombier // }
38817629263SDavid du Colombier 
3892210c76eSDavid du Colombier void
sdaddallconfs(void (* addconf)(SDunit *))3902210c76eSDavid du Colombier sdaddallconfs(void (*addconf)(SDunit *))
3912210c76eSDavid du Colombier {
3922210c76eSDavid du Colombier 	int i, u;
3932210c76eSDavid du Colombier 	SDev *sdev;
3942210c76eSDavid du Colombier 
3952210c76eSDavid du Colombier 	for(i = 0; i < nelem(devs); i++)		/* each controller */
3962210c76eSDavid du Colombier 		for(sdev = devs[i]; sdev; sdev = sdev->next)
3972210c76eSDavid du Colombier 			for(u = 0; u < sdev->nunit; u++)	/* each drive */
3982210c76eSDavid du Colombier 				(*addconf)(sdev->unit[u]);
3992210c76eSDavid du Colombier }
4002210c76eSDavid du Colombier 
4017dd7cddfSDavid du Colombier static int
sd2gen(Chan * c,int i,Dir * dp)4027dd7cddfSDavid du Colombier sd2gen(Chan* c, int i, Dir* dp)
4037dd7cddfSDavid du Colombier {
4047dd7cddfSDavid du Colombier 	Qid q;
40517629263SDavid du Colombier 	uvlong l;
4067dd7cddfSDavid du Colombier 	SDpart *pp;
40759cc4ca5SDavid du Colombier 	SDperm *perm;
4087dd7cddfSDavid du Colombier 	SDunit *unit;
4099a747e4fSDavid du Colombier 	SDev *sdev;
4109a747e4fSDavid du Colombier 	int rv;
4117dd7cddfSDavid du Colombier 
4129a747e4fSDavid du Colombier 	sdev = sdgetdev(DEV(c->qid));
4139a747e4fSDavid du Colombier 	assert(sdev);
4149a747e4fSDavid du Colombier 	unit = sdev->unit[UNIT(c->qid)];
4159a747e4fSDavid du Colombier 
4169a747e4fSDavid du Colombier 	rv = -1;
4177dd7cddfSDavid du Colombier 	switch(i){
4187dd7cddfSDavid du Colombier 	case Qctl:
4199a747e4fSDavid du Colombier 		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qctl),
4209a747e4fSDavid du Colombier 			unit->vers, QTFILE);
42159cc4ca5SDavid du Colombier 		perm = &unit->ctlperm;
4229a747e4fSDavid du Colombier 		if(emptystr(perm->user)){
4239a747e4fSDavid du Colombier 			kstrdup(&perm->user, eve);
42427522402SDavid du Colombier 			perm->perm = 0644;	/* nothing secret in ctl */
42559cc4ca5SDavid du Colombier 		}
42659cc4ca5SDavid du Colombier 		devdir(c, q, "ctl", 0, perm->user, perm->perm, dp);
4279a747e4fSDavid du Colombier 		rv = 1;
4289a747e4fSDavid du Colombier 		break;
4299a747e4fSDavid du Colombier 
4307dd7cddfSDavid du Colombier 	case Qraw:
4319a747e4fSDavid du Colombier 		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qraw),
4329a747e4fSDavid du Colombier 			unit->vers, QTFILE);
43359cc4ca5SDavid du Colombier 		perm = &unit->rawperm;
4349a747e4fSDavid du Colombier 		if(emptystr(perm->user)){
4359a747e4fSDavid du Colombier 			kstrdup(&perm->user, eve);
4369a747e4fSDavid du Colombier 			perm->perm = DMEXCL|0600;
43759cc4ca5SDavid du Colombier 		}
43859cc4ca5SDavid du Colombier 		devdir(c, q, "raw", 0, perm->user, perm->perm, dp);
4399a747e4fSDavid du Colombier 		rv = 1;
4409a747e4fSDavid du Colombier 		break;
4419a747e4fSDavid du Colombier 
4427dd7cddfSDavid du Colombier 	case Qpart:
4437dd7cddfSDavid du Colombier 		pp = &unit->part[PART(c->qid)];
44417629263SDavid du Colombier 		l = (pp->end - pp->start) * unit->secsize;
4459a747e4fSDavid du Colombier 		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qpart),
4469a747e4fSDavid du Colombier 			unit->vers+pp->vers, QTFILE);
4479a747e4fSDavid du Colombier 		if(emptystr(pp->user))
4489a747e4fSDavid du Colombier 			kstrdup(&pp->user, eve);
4497dd7cddfSDavid du Colombier 		devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
4509a747e4fSDavid du Colombier 		rv = 1;
4519a747e4fSDavid du Colombier 		break;
4529a747e4fSDavid du Colombier 	}
4539a747e4fSDavid du Colombier 
4549a747e4fSDavid du Colombier 	decref(&sdev->r);
4559a747e4fSDavid du Colombier 	return rv;
4569a747e4fSDavid du Colombier }
4579a747e4fSDavid du Colombier 
4589a747e4fSDavid du Colombier static int
sd1gen(Chan * c,int i,Dir * dp)4599a747e4fSDavid du Colombier sd1gen(Chan* c, int i, Dir* dp)
4609a747e4fSDavid du Colombier {
4619a747e4fSDavid du Colombier 	Qid q;
4629a747e4fSDavid du Colombier 
4639a747e4fSDavid du Colombier 	switch(i){
4649a747e4fSDavid du Colombier 	case Qtopctl:
4659a747e4fSDavid du Colombier 		mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE);
46627522402SDavid du Colombier 		devdir(c, q, "sdctl", 0, eve, 0644, dp);	/* no secrets */
4679a747e4fSDavid du Colombier 		return 1;
4687dd7cddfSDavid du Colombier 	}
4697dd7cddfSDavid du Colombier 	return -1;
4707dd7cddfSDavid du Colombier }
4717dd7cddfSDavid du Colombier 
4727dd7cddfSDavid du Colombier static int
sdgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)4739a747e4fSDavid du Colombier sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
4747dd7cddfSDavid du Colombier {
4757dd7cddfSDavid du Colombier 	Qid q;
47617629263SDavid du Colombier 	uvlong l;
4777dd7cddfSDavid du Colombier 	int i, r;
4787dd7cddfSDavid du Colombier 	SDpart *pp;
4797dd7cddfSDavid du Colombier 	SDunit *unit;
4809a747e4fSDavid du Colombier 	SDev *sdev;
4817dd7cddfSDavid du Colombier 
4827dd7cddfSDavid du Colombier 	switch(TYPE(c->qid)){
4837dd7cddfSDavid du Colombier 	case Qtopdir:
4847dd7cddfSDavid du Colombier 		if(s == DEVDOTDOT){
4853c917a9eSDavid du Colombier 			mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
486*4e3613abSDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "#%C",
487*4e3613abSDavid du Colombier 				sddevtab.dc);
4889a747e4fSDavid du Colombier 			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
4897dd7cddfSDavid du Colombier 			return 1;
4907dd7cddfSDavid du Colombier 		}
4919a747e4fSDavid du Colombier 
4924de34a7eSDavid du Colombier 		if(s+Qtopbase < Qunitdir)
4939a747e4fSDavid du Colombier 			return sd1gen(c, s+Qtopbase, dp);
4944de34a7eSDavid du Colombier 		s -= (Qunitdir-Qtopbase);
4959a747e4fSDavid du Colombier 
4969a747e4fSDavid du Colombier 		qlock(&devslock);
4974de34a7eSDavid du Colombier 		for(i=0; i<nelem(devs); i++){
4984de34a7eSDavid du Colombier 			if(devs[i]){
4994de34a7eSDavid du Colombier 				if(s < devs[i]->nunit)
5009a747e4fSDavid du Colombier 					break;
5014de34a7eSDavid du Colombier 				s -= devs[i]->nunit;
5024de34a7eSDavid du Colombier 			}
5039a747e4fSDavid du Colombier 		}
5049a747e4fSDavid du Colombier 
5054de34a7eSDavid du Colombier 		if(i == nelem(devs)){
5064de34a7eSDavid du Colombier 			/* Run off the end of the list */
5079a747e4fSDavid du Colombier 			qunlock(&devslock);
5089a747e4fSDavid du Colombier 			return -1;
5099a747e4fSDavid du Colombier 		}
5109a747e4fSDavid du Colombier 
5114de34a7eSDavid du Colombier 		if((sdev = devs[i]) == nil){
5129a747e4fSDavid du Colombier 			qunlock(&devslock);
5137dd7cddfSDavid du Colombier 			return 0;
51459cc4ca5SDavid du Colombier 		}
5159a747e4fSDavid du Colombier 
5169a747e4fSDavid du Colombier 		incref(&sdev->r);
5179a747e4fSDavid du Colombier 		qunlock(&devslock);
5189a747e4fSDavid du Colombier 
5199a747e4fSDavid du Colombier 		if((unit = sdev->unit[s]) == nil)
5209a747e4fSDavid du Colombier 			if((unit = sdgetunit(sdev, s)) == nil){
5219a747e4fSDavid du Colombier 				decref(&sdev->r);
5229a747e4fSDavid du Colombier 				return 0;
5237dd7cddfSDavid du Colombier 			}
5249a747e4fSDavid du Colombier 
5259a747e4fSDavid du Colombier 		mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR);
5269a747e4fSDavid du Colombier 		if(emptystr(unit->user))
5279a747e4fSDavid du Colombier 			kstrdup(&unit->user, eve);
5289a747e4fSDavid du Colombier 		devdir(c, q, unit->name, 0, unit->user, unit->perm, dp);
5299a747e4fSDavid du Colombier 		decref(&sdev->r);
5309a747e4fSDavid du Colombier 		return 1;
5319a747e4fSDavid du Colombier 
5327dd7cddfSDavid du Colombier 	case Qunitdir:
5337dd7cddfSDavid du Colombier 		if(s == DEVDOTDOT){
5343c917a9eSDavid du Colombier 			mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
535*4e3613abSDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "#%C",
536*4e3613abSDavid du Colombier 				sddevtab.dc);
5379a747e4fSDavid du Colombier 			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
5387dd7cddfSDavid du Colombier 			return 1;
5397dd7cddfSDavid du Colombier 		}
5409a747e4fSDavid du Colombier 
5419a747e4fSDavid du Colombier 		if((sdev = sdgetdev(DEV(c->qid))) == nil){
542ec46fab0SDavid du Colombier 			devdir(c, c->qid, "unavailable", 0, eve, 0, dp);
5439a747e4fSDavid du Colombier 			return 1;
5449a747e4fSDavid du Colombier 		}
5459a747e4fSDavid du Colombier 
5469a747e4fSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
5477dd7cddfSDavid du Colombier 		qlock(&unit->ctl);
548223a736eSDavid du Colombier 
549223a736eSDavid du Colombier 		/*
550223a736eSDavid du Colombier 		 * Check for media change.
551223a736eSDavid du Colombier 		 * If one has already been detected, sectors will be zero.
55259cc4ca5SDavid du Colombier 		 * If there is one waiting to be detected, online
55359cc4ca5SDavid du Colombier 		 * will return > 1.
554223a736eSDavid du Colombier 		 * Online is a bit of a large hammer but does the job.
555223a736eSDavid du Colombier 		 */
55659cc4ca5SDavid du Colombier 		if(unit->sectors == 0
55759cc4ca5SDavid du Colombier 		|| (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1))
5587dd7cddfSDavid du Colombier 			sdinitpart(unit);
559223a736eSDavid du Colombier 
5607dd7cddfSDavid du Colombier 		i = s+Qunitbase;
5617dd7cddfSDavid du Colombier 		if(i < Qpart){
5627dd7cddfSDavid du Colombier 			r = sd2gen(c, i, dp);
5637dd7cddfSDavid du Colombier 			qunlock(&unit->ctl);
5649a747e4fSDavid du Colombier 			decref(&sdev->r);
5657dd7cddfSDavid du Colombier 			return r;
5667dd7cddfSDavid du Colombier 		}
5677dd7cddfSDavid du Colombier 		i -= Qpart;
56859cc4ca5SDavid du Colombier 		if(unit->part == nil || i >= unit->npart){
5697dd7cddfSDavid du Colombier 			qunlock(&unit->ctl);
5709a747e4fSDavid du Colombier 			decref(&sdev->r);
5717dd7cddfSDavid du Colombier 			break;
5727dd7cddfSDavid du Colombier 		}
5737dd7cddfSDavid du Colombier 		pp = &unit->part[i];
574223a736eSDavid du Colombier 		if(!pp->valid){
5757dd7cddfSDavid du Colombier 			qunlock(&unit->ctl);
5769a747e4fSDavid du Colombier 			decref(&sdev->r);
5777dd7cddfSDavid du Colombier 			return 0;
5787dd7cddfSDavid du Colombier 		}
57917629263SDavid du Colombier 		l = (pp->end - pp->start) * unit->secsize;
5809a747e4fSDavid du Colombier 		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
5819a747e4fSDavid du Colombier 			unit->vers+pp->vers, QTFILE);
5829a747e4fSDavid du Colombier 		if(emptystr(pp->user))
5839a747e4fSDavid du Colombier 			kstrdup(&pp->user, eve);
5847dd7cddfSDavid du Colombier 		devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
5857dd7cddfSDavid du Colombier 		qunlock(&unit->ctl);
5869a747e4fSDavid du Colombier 		decref(&sdev->r);
5877dd7cddfSDavid du Colombier 		return 1;
5887dd7cddfSDavid du Colombier 	case Qraw:
5897dd7cddfSDavid du Colombier 	case Qctl:
5907dd7cddfSDavid du Colombier 	case Qpart:
5919a747e4fSDavid du Colombier 		if((sdev = sdgetdev(DEV(c->qid))) == nil){
5929a747e4fSDavid du Colombier 			devdir(c, q, "unavailable", 0, eve, 0, dp);
5939a747e4fSDavid du Colombier 			return 1;
5949a747e4fSDavid du Colombier 		}
5959a747e4fSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
5967dd7cddfSDavid du Colombier 		qlock(&unit->ctl);
5977dd7cddfSDavid du Colombier 		r = sd2gen(c, TYPE(c->qid), dp);
5987dd7cddfSDavid du Colombier 		qunlock(&unit->ctl);
5999a747e4fSDavid du Colombier 		decref(&sdev->r);
6007dd7cddfSDavid du Colombier 		return r;
6019a747e4fSDavid du Colombier 	case Qtopctl:
6029a747e4fSDavid du Colombier 		return sd1gen(c, TYPE(c->qid), dp);
6037dd7cddfSDavid du Colombier 	default:
6047dd7cddfSDavid du Colombier 		break;
6057dd7cddfSDavid du Colombier 	}
6067dd7cddfSDavid du Colombier 
6077dd7cddfSDavid du Colombier 	return -1;
6087dd7cddfSDavid du Colombier }
6097dd7cddfSDavid du Colombier 
6107dd7cddfSDavid du Colombier static Chan*
sdattach(char * spec)6117dd7cddfSDavid du Colombier sdattach(char* spec)
6127dd7cddfSDavid du Colombier {
6137dd7cddfSDavid du Colombier 	Chan *c;
6147dd7cddfSDavid du Colombier 	char *p;
6157dd7cddfSDavid du Colombier 	SDev *sdev;
6164de34a7eSDavid du Colombier 	int idno, subno;
6177dd7cddfSDavid du Colombier 
6184de34a7eSDavid du Colombier 	if(*spec == '\0'){
6197dd7cddfSDavid du Colombier 		c = devattach(sddevtab.dc, spec);
6209a747e4fSDavid du Colombier 		mkqid(&c->qid, QID(0, 0, 0, Qtopdir), 0, QTDIR);
6217dd7cddfSDavid du Colombier 		return c;
6227dd7cddfSDavid du Colombier 	}
6237dd7cddfSDavid du Colombier 
6247dd7cddfSDavid du Colombier 	if(spec[0] != 's' || spec[1] != 'd')
6257dd7cddfSDavid du Colombier 		error(Ebadspec);
6267dd7cddfSDavid du Colombier 	idno = spec[2];
6277dd7cddfSDavid du Colombier 	subno = strtol(&spec[3], &p, 0);
6287dd7cddfSDavid du Colombier 	if(p == &spec[3])
6297dd7cddfSDavid du Colombier 		error(Ebadspec);
6309a747e4fSDavid du Colombier 
6314de34a7eSDavid du Colombier 	if((sdev=sdgetdev(idno)) == nil)
6324de34a7eSDavid du Colombier 		error(Enonexist);
6334de34a7eSDavid du Colombier 	if(sdgetunit(sdev, subno) == nil){
6344de34a7eSDavid du Colombier 		decref(&sdev->r);
6357dd7cddfSDavid du Colombier 		error(Enonexist);
6369a747e4fSDavid du Colombier 	}
6377dd7cddfSDavid du Colombier 
6387dd7cddfSDavid du Colombier 	c = devattach(sddevtab.dc, spec);
6399a747e4fSDavid du Colombier 	mkqid(&c->qid, QID(sdev->idno, subno, 0, Qunitdir), 0, QTDIR);
6409a747e4fSDavid du Colombier 	c->dev = (sdev->idno << UnitLOG) + subno;
6419a747e4fSDavid du Colombier 	decref(&sdev->r);
6427dd7cddfSDavid du Colombier 	return c;
6437dd7cddfSDavid du Colombier }
6447dd7cddfSDavid du Colombier 
6459a747e4fSDavid du Colombier static Walkqid*
sdwalk(Chan * c,Chan * nc,char ** name,int nname)6469a747e4fSDavid du Colombier sdwalk(Chan* c, Chan* nc, char** name, int nname)
6477dd7cddfSDavid du Colombier {
6489a747e4fSDavid du Colombier 	return devwalk(c, nc, name, nname, nil, 0, sdgen);
6497dd7cddfSDavid du Colombier }
6507dd7cddfSDavid du Colombier 
6517dd7cddfSDavid du Colombier static int
sdstat(Chan * c,uchar * db,int n)6529a747e4fSDavid du Colombier sdstat(Chan* c, uchar* db, int n)
6537dd7cddfSDavid du Colombier {
6549a747e4fSDavid du Colombier 	return devstat(c, db, n, nil, 0, sdgen);
6557dd7cddfSDavid du Colombier }
6567dd7cddfSDavid du Colombier 
6577dd7cddfSDavid du Colombier static Chan*
sdopen(Chan * c,int omode)6587dd7cddfSDavid du Colombier sdopen(Chan* c, int omode)
6597dd7cddfSDavid du Colombier {
6607dd7cddfSDavid du Colombier 	SDpart *pp;
6617dd7cddfSDavid du Colombier 	SDunit *unit;
6629a747e4fSDavid du Colombier 	SDev *sdev;
6639a747e4fSDavid du Colombier 	uchar tp;
6647dd7cddfSDavid du Colombier 
6657dd7cddfSDavid du Colombier 	c = devopen(c, omode, 0, 0, sdgen);
6669a747e4fSDavid du Colombier 	if((tp = TYPE(c->qid)) != Qctl && tp != Qraw && tp != Qpart)
6679a747e4fSDavid du Colombier 		return c;
6689a747e4fSDavid du Colombier 
6699a747e4fSDavid du Colombier 	sdev = sdgetdev(DEV(c->qid));
6709a747e4fSDavid du Colombier 	if(sdev == nil)
6719a747e4fSDavid du Colombier 		error(Enonexist);
6722cca75a1SDavid du Colombier 
6739a747e4fSDavid du Colombier 	unit = sdev->unit[UNIT(c->qid)];
6749a747e4fSDavid du Colombier 
6757dd7cddfSDavid du Colombier 	switch(TYPE(c->qid)){
676223a736eSDavid du Colombier 	case Qctl:
677223a736eSDavid du Colombier 		c->qid.vers = unit->vers;
678223a736eSDavid du Colombier 		break;
6797dd7cddfSDavid du Colombier 	case Qraw:
680223a736eSDavid du Colombier 		c->qid.vers = unit->vers;
6819a747e4fSDavid du Colombier 		if(tas(&unit->rawinuse) != 0){
6827dd7cddfSDavid du Colombier 			c->flag &= ~COPEN;
6832cca75a1SDavid du Colombier 			decref(&sdev->r);
6847dd7cddfSDavid du Colombier 			error(Einuse);
6857dd7cddfSDavid du Colombier 		}
6867dd7cddfSDavid du Colombier 		unit->state = Rawcmd;
6877dd7cddfSDavid du Colombier 		break;
6887dd7cddfSDavid du Colombier 	case Qpart:
6897dd7cddfSDavid du Colombier 		qlock(&unit->ctl);
6907dd7cddfSDavid du Colombier 		if(waserror()){
6917dd7cddfSDavid du Colombier 			qunlock(&unit->ctl);
6927dd7cddfSDavid du Colombier 			c->flag &= ~COPEN;
6932cca75a1SDavid du Colombier 			decref(&sdev->r);
6947dd7cddfSDavid du Colombier 			nexterror();
6957dd7cddfSDavid du Colombier 		}
6967dd7cddfSDavid du Colombier 		pp = &unit->part[PART(c->qid)];
697223a736eSDavid du Colombier 		c->qid.vers = unit->vers+pp->vers;
6987dd7cddfSDavid du Colombier 		qunlock(&unit->ctl);
6997dd7cddfSDavid du Colombier 		poperror();
7007dd7cddfSDavid du Colombier 		break;
7017dd7cddfSDavid du Colombier 	}
7029a747e4fSDavid du Colombier 	decref(&sdev->r);
7037dd7cddfSDavid du Colombier 	return c;
7047dd7cddfSDavid du Colombier }
7057dd7cddfSDavid du Colombier 
7067dd7cddfSDavid du Colombier static void
sdclose(Chan * c)7077dd7cddfSDavid du Colombier sdclose(Chan* c)
7087dd7cddfSDavid du Colombier {
7097dd7cddfSDavid du Colombier 	SDunit *unit;
7109a747e4fSDavid du Colombier 	SDev *sdev;
7117dd7cddfSDavid du Colombier 
7129a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
7137dd7cddfSDavid du Colombier 		return;
7147dd7cddfSDavid du Colombier 	if(!(c->flag & COPEN))
7157dd7cddfSDavid du Colombier 		return;
7167dd7cddfSDavid du Colombier 
7177dd7cddfSDavid du Colombier 	switch(TYPE(c->qid)){
7187dd7cddfSDavid du Colombier 	default:
7197dd7cddfSDavid du Colombier 		break;
7207dd7cddfSDavid du Colombier 	case Qraw:
7219a747e4fSDavid du Colombier 		sdev = sdgetdev(DEV(c->qid));
7229a747e4fSDavid du Colombier 		if(sdev){
7239a747e4fSDavid du Colombier 			unit = sdev->unit[UNIT(c->qid)];
7249a747e4fSDavid du Colombier 			unit->rawinuse = 0;
7259a747e4fSDavid du Colombier 			decref(&sdev->r);
7269a747e4fSDavid du Colombier 		}
7277dd7cddfSDavid du Colombier 		break;
7287dd7cddfSDavid du Colombier 	}
7297dd7cddfSDavid du Colombier }
7307dd7cddfSDavid du Colombier 
7317dd7cddfSDavid du Colombier static long
sdbio(Chan * c,int write,char * a,long len,uvlong off)73217629263SDavid du Colombier sdbio(Chan* c, int write, char* a, long len, uvlong off)
7337dd7cddfSDavid du Colombier {
734223a736eSDavid du Colombier 	int nchange;
7357dd7cddfSDavid du Colombier 	long l;
7367dd7cddfSDavid du Colombier 	uchar *b;
7377dd7cddfSDavid du Colombier 	SDpart *pp;
7387dd7cddfSDavid du Colombier 	SDunit *unit;
7399a747e4fSDavid du Colombier 	SDev *sdev;
74017629263SDavid du Colombier 	ulong max, nb, offset;
74117629263SDavid du Colombier 	uvlong bno;
7427dd7cddfSDavid du Colombier 
7439a747e4fSDavid du Colombier 	sdev = sdgetdev(DEV(c->qid));
7442cca75a1SDavid du Colombier 	if(sdev == nil){
7452cca75a1SDavid du Colombier 		decref(&sdev->r);
7469a747e4fSDavid du Colombier 		error(Enonexist);
7472cca75a1SDavid du Colombier 	}
7489a747e4fSDavid du Colombier 	unit = sdev->unit[UNIT(c->qid)];
7499a747e4fSDavid du Colombier 	if(unit == nil)
7509a747e4fSDavid du Colombier 		error(Enonexist);
7517dd7cddfSDavid du Colombier 
752223a736eSDavid du Colombier 	nchange = 0;
7537dd7cddfSDavid du Colombier 	qlock(&unit->ctl);
754223a736eSDavid du Colombier 	while(waserror()){
755223a736eSDavid du Colombier 		/* notification of media change; go around again */
7569a747e4fSDavid du Colombier 		if(strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){
757223a736eSDavid du Colombier 			sdinitpart(unit);
758223a736eSDavid du Colombier 			continue;
759223a736eSDavid du Colombier 		}
760223a736eSDavid du Colombier 
761223a736eSDavid du Colombier 		/* other errors; give up */
7627dd7cddfSDavid du Colombier 		qunlock(&unit->ctl);
7639a747e4fSDavid du Colombier 		decref(&sdev->r);
7647dd7cddfSDavid du Colombier 		nexterror();
7657dd7cddfSDavid du Colombier 	}
766223a736eSDavid du Colombier 	pp = &unit->part[PART(c->qid)];
767223a736eSDavid du Colombier 	if(unit->vers+pp->vers != c->qid.vers)
7684de34a7eSDavid du Colombier 		error(Echange);
7697dd7cddfSDavid du Colombier 
7707dd7cddfSDavid du Colombier 	/*
7717dd7cddfSDavid du Colombier 	 * Check the request is within bounds.
7727dd7cddfSDavid du Colombier 	 * Removeable drives are locked throughout the I/O
7737dd7cddfSDavid du Colombier 	 * in case the media changes unexpectedly.
7747dd7cddfSDavid du Colombier 	 * Non-removeable drives are not locked during the I/O
7757dd7cddfSDavid du Colombier 	 * to allow the hardware to optimise if it can; this is
7767dd7cddfSDavid du Colombier 	 * a little fast and loose.
7777dd7cddfSDavid du Colombier 	 * It's assumed that non-removeable media parameters
7787dd7cddfSDavid du Colombier 	 * (sectors, secsize) can't change once the drive has
7797dd7cddfSDavid du Colombier 	 * been brought online.
7807dd7cddfSDavid du Colombier 	 */
7817dd7cddfSDavid du Colombier 	bno = (off/unit->secsize) + pp->start;
7827dd7cddfSDavid du Colombier 	nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
7837dd7cddfSDavid du Colombier 	max = SDmaxio/unit->secsize;
7847dd7cddfSDavid du Colombier 	if(nb > max)
7857dd7cddfSDavid du Colombier 		nb = max;
7867dd7cddfSDavid du Colombier 	if(bno+nb > pp->end)
7877dd7cddfSDavid du Colombier 		nb = pp->end - bno;
7887dd7cddfSDavid du Colombier 	if(bno >= pp->end || nb == 0){
7897dd7cddfSDavid du Colombier 		if(write)
7907dd7cddfSDavid du Colombier 			error(Eio);
7917dd7cddfSDavid du Colombier 		qunlock(&unit->ctl);
7929a747e4fSDavid du Colombier 		decref(&sdev->r);
7937dd7cddfSDavid du Colombier 		poperror();
7947dd7cddfSDavid du Colombier 		return 0;
7957dd7cddfSDavid du Colombier 	}
79627522402SDavid du Colombier 	if(!(unit->inquiry[1] & SDinq1removable)){
7977dd7cddfSDavid du Colombier 		qunlock(&unit->ctl);
7987dd7cddfSDavid du Colombier 		poperror();
7997dd7cddfSDavid du Colombier 	}
8007dd7cddfSDavid du Colombier 
8017dd7cddfSDavid du Colombier 	b = sdmalloc(nb*unit->secsize);
8027dd7cddfSDavid du Colombier 	if(b == nil)
8037dd7cddfSDavid du Colombier 		error(Enomem);
8047dd7cddfSDavid du Colombier 	if(waserror()){
8057dd7cddfSDavid du Colombier 		sdfree(b);
80627522402SDavid du Colombier 		if(!(unit->inquiry[1] & SDinq1removable))
8079a747e4fSDavid du Colombier 			decref(&sdev->r);		/* gadverdamme! */
8087dd7cddfSDavid du Colombier 		nexterror();
8097dd7cddfSDavid du Colombier 	}
8107dd7cddfSDavid du Colombier 
8117dd7cddfSDavid du Colombier 	offset = off%unit->secsize;
8129a747e4fSDavid du Colombier 	if(offset+len > nb*unit->secsize)
8139a747e4fSDavid du Colombier 		len = nb*unit->secsize - offset;
8147dd7cddfSDavid du Colombier 	if(write){
8157dd7cddfSDavid du Colombier 		if(offset || (len%unit->secsize)){
8167dd7cddfSDavid du Colombier 			l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
8177dd7cddfSDavid du Colombier 			if(l < 0)
8187dd7cddfSDavid du Colombier 				error(Eio);
8197dd7cddfSDavid du Colombier 			if(l < (nb*unit->secsize)){
8207dd7cddfSDavid du Colombier 				nb = l/unit->secsize;
8217dd7cddfSDavid du Colombier 				l = nb*unit->secsize - offset;
8227dd7cddfSDavid du Colombier 				if(len > l)
8237dd7cddfSDavid du Colombier 					len = l;
8247dd7cddfSDavid du Colombier 			}
8257dd7cddfSDavid du Colombier 		}
8267dd7cddfSDavid du Colombier 		memmove(b+offset, a, len);
8277dd7cddfSDavid du Colombier 		l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
8287dd7cddfSDavid du Colombier 		if(l < 0)
8297dd7cddfSDavid du Colombier 			error(Eio);
8307dd7cddfSDavid du Colombier 		if(l < offset)
8317dd7cddfSDavid du Colombier 			len = 0;
8327dd7cddfSDavid du Colombier 		else if(len > l - offset)
8337dd7cddfSDavid du Colombier 			len = l - offset;
8347dd7cddfSDavid du Colombier 	}
8357dd7cddfSDavid du Colombier 	else{
8367dd7cddfSDavid du Colombier 		l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
8377dd7cddfSDavid du Colombier 		if(l < 0)
8387dd7cddfSDavid du Colombier 			error(Eio);
8397dd7cddfSDavid du Colombier 		if(l < offset)
8407dd7cddfSDavid du Colombier 			len = 0;
8417dd7cddfSDavid du Colombier 		else if(len > l - offset)
8427dd7cddfSDavid du Colombier 			len = l - offset;
8437dd7cddfSDavid du Colombier 		memmove(a, b+offset, len);
8447dd7cddfSDavid du Colombier 	}
8457dd7cddfSDavid du Colombier 	sdfree(b);
8467dd7cddfSDavid du Colombier 	poperror();
8477dd7cddfSDavid du Colombier 
84827522402SDavid du Colombier 	if(unit->inquiry[1] & SDinq1removable){
8497dd7cddfSDavid du Colombier 		qunlock(&unit->ctl);
8507dd7cddfSDavid du Colombier 		poperror();
8517dd7cddfSDavid du Colombier 	}
8527dd7cddfSDavid du Colombier 
8539a747e4fSDavid du Colombier 	decref(&sdev->r);
8547dd7cddfSDavid du Colombier 	return len;
8557dd7cddfSDavid du Colombier }
8567dd7cddfSDavid du Colombier 
8577dd7cddfSDavid du Colombier static long
sdrio(SDreq * r,void * a,long n)8587dd7cddfSDavid du Colombier sdrio(SDreq* r, void* a, long n)
8597dd7cddfSDavid du Colombier {
8607dd7cddfSDavid du Colombier 	void *data;
8617dd7cddfSDavid du Colombier 
8627dd7cddfSDavid du Colombier 	if(n >= SDmaxio || n < 0)
8637dd7cddfSDavid du Colombier 		error(Etoobig);
8647dd7cddfSDavid du Colombier 
8657dd7cddfSDavid du Colombier 	data = nil;
8667dd7cddfSDavid du Colombier 	if(n){
8677dd7cddfSDavid du Colombier 		if((data = sdmalloc(n)) == nil)
8687dd7cddfSDavid du Colombier 			error(Enomem);
8697dd7cddfSDavid du Colombier 		if(r->write)
8707dd7cddfSDavid du Colombier 			memmove(data, a, n);
8717dd7cddfSDavid du Colombier 	}
8727dd7cddfSDavid du Colombier 	r->data = data;
8737dd7cddfSDavid du Colombier 	r->dlen = n;
8747dd7cddfSDavid du Colombier 
8757dd7cddfSDavid du Colombier 	if(waserror()){
8767dd7cddfSDavid du Colombier 		sdfree(data);
8777dd7cddfSDavid du Colombier 		r->data = nil;
8787dd7cddfSDavid du Colombier 		nexterror();
8797dd7cddfSDavid du Colombier 	}
8807dd7cddfSDavid du Colombier 
8817dd7cddfSDavid du Colombier 	if(r->unit->dev->ifc->rio(r) != SDok)
8827dd7cddfSDavid du Colombier 		error(Eio);
8837dd7cddfSDavid du Colombier 
8847dd7cddfSDavid du Colombier 	if(!r->write && r->rlen > 0)
8857dd7cddfSDavid du Colombier 		memmove(a, data, r->rlen);
8867dd7cddfSDavid du Colombier 	sdfree(data);
8877dd7cddfSDavid du Colombier 	r->data = nil;
8887dd7cddfSDavid du Colombier 	poperror();
8897dd7cddfSDavid du Colombier 
8907dd7cddfSDavid du Colombier 	return r->rlen;
8917dd7cddfSDavid du Colombier }
8927dd7cddfSDavid du Colombier 
8934de34a7eSDavid du Colombier /*
8944de34a7eSDavid du Colombier  * SCSI simulation for non-SCSI devices
8954de34a7eSDavid du Colombier  */
8964de34a7eSDavid du Colombier int
sdsetsense(SDreq * r,int status,int key,int asc,int ascq)8974de34a7eSDavid du Colombier sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
8984de34a7eSDavid du Colombier {
8994de34a7eSDavid du Colombier 	int len;
9004de34a7eSDavid du Colombier 	SDunit *unit;
9014de34a7eSDavid du Colombier 
9024de34a7eSDavid du Colombier 	unit = r->unit;
9034de34a7eSDavid du Colombier 	unit->sense[2] = key;
9044de34a7eSDavid du Colombier 	unit->sense[12] = asc;
9054de34a7eSDavid du Colombier 	unit->sense[13] = ascq;
9064de34a7eSDavid du Colombier 
9075e1edbcaSDavid du Colombier 	r->status = status;
9084de34a7eSDavid du Colombier 	if(status == SDcheck && !(r->flags & SDnosense)){
9094de34a7eSDavid du Colombier 		/* request sense case from sdfakescsi */
9104de34a7eSDavid du Colombier 		len = sizeof unit->sense;
9114de34a7eSDavid du Colombier 		if(len > sizeof r->sense-1)
9124de34a7eSDavid du Colombier 			len = sizeof r->sense-1;
9134de34a7eSDavid du Colombier 		memmove(r->sense, unit->sense, len);
9144de34a7eSDavid du Colombier 		unit->sense[2] = 0;
9154de34a7eSDavid du Colombier 		unit->sense[12] = 0;
9164de34a7eSDavid du Colombier 		unit->sense[13] = 0;
9174de34a7eSDavid du Colombier 		r->flags |= SDvalidsense;
9184de34a7eSDavid du Colombier 		return SDok;
9194de34a7eSDavid du Colombier 	}
9204de34a7eSDavid du Colombier 	return status;
9214de34a7eSDavid du Colombier }
9224de34a7eSDavid du Colombier 
9234de34a7eSDavid du Colombier int
sdmodesense(SDreq * r,uchar * cmd,void * info,int ilen)9244de34a7eSDavid du Colombier sdmodesense(SDreq *r, uchar *cmd, void *info, int ilen)
9254de34a7eSDavid du Colombier {
9264de34a7eSDavid du Colombier 	int len;
9274de34a7eSDavid du Colombier 	uchar *data;
9284de34a7eSDavid du Colombier 
9294de34a7eSDavid du Colombier 	/*
9304de34a7eSDavid du Colombier 	 * Fake a vendor-specific request with page code 0,
9314de34a7eSDavid du Colombier 	 * return the drive info.
9324de34a7eSDavid du Colombier 	 */
9334de34a7eSDavid du Colombier 	if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)
9344de34a7eSDavid du Colombier 		return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
9354de34a7eSDavid du Colombier 	len = (cmd[7]<<8)|cmd[8];
9364de34a7eSDavid du Colombier 	if(len == 0)
9374de34a7eSDavid du Colombier 		return SDok;
9384de34a7eSDavid du Colombier 	if(len < 8+ilen)
9394de34a7eSDavid du Colombier 		return sdsetsense(r, SDcheck, 0x05, 0x1A, 0);
9404de34a7eSDavid du Colombier 	if(r->data == nil || r->dlen < len)
9414de34a7eSDavid du Colombier 		return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
9424de34a7eSDavid du Colombier 	data = r->data;
9434de34a7eSDavid du Colombier 	memset(data, 0, 8);
9444de34a7eSDavid du Colombier 	data[0] = ilen>>8;
9454de34a7eSDavid du Colombier 	data[1] = ilen;
9464de34a7eSDavid du Colombier 	if(ilen)
9474de34a7eSDavid du Colombier 		memmove(data+8, info, ilen);
9484de34a7eSDavid du Colombier 	r->rlen = 8+ilen;
9494de34a7eSDavid du Colombier 	return sdsetsense(r, SDok, 0, 0, 0);
9504de34a7eSDavid du Colombier }
9514de34a7eSDavid du Colombier 
9524de34a7eSDavid du Colombier int
sdfakescsi(SDreq * r,void * info,int ilen)9534de34a7eSDavid du Colombier sdfakescsi(SDreq *r, void *info, int ilen)
9544de34a7eSDavid du Colombier {
9554de34a7eSDavid du Colombier 	uchar *cmd, *p;
9564de34a7eSDavid du Colombier 	uvlong len;
9574de34a7eSDavid du Colombier 	SDunit *unit;
9584de34a7eSDavid du Colombier 
9594de34a7eSDavid du Colombier 	cmd = r->cmd;
9604de34a7eSDavid du Colombier 	r->rlen = 0;
9614de34a7eSDavid du Colombier 	unit = r->unit;
9624de34a7eSDavid du Colombier 
9634de34a7eSDavid du Colombier 	/*
9644de34a7eSDavid du Colombier 	 * Rewrite read(6)/write(6) into read(10)/write(10).
9654de34a7eSDavid du Colombier 	 */
9664de34a7eSDavid du Colombier 	switch(cmd[0]){
9674de34a7eSDavid du Colombier 	case 0x08:	/* read */
9684de34a7eSDavid du Colombier 	case 0x0A:	/* write */
9694de34a7eSDavid du Colombier 		cmd[9] = 0;
9704de34a7eSDavid du Colombier 		cmd[8] = cmd[4];
9714de34a7eSDavid du Colombier 		cmd[7] = 0;
9724de34a7eSDavid du Colombier 		cmd[6] = 0;
9734de34a7eSDavid du Colombier 		cmd[5] = cmd[3];
9744de34a7eSDavid du Colombier 		cmd[4] = cmd[2];
9754de34a7eSDavid du Colombier 		cmd[3] = cmd[1] & 0x0F;
9764de34a7eSDavid du Colombier 		cmd[2] = 0;
9774de34a7eSDavid du Colombier 		cmd[1] &= 0xE0;
9784de34a7eSDavid du Colombier 		cmd[0] |= 0x20;
9794de34a7eSDavid du Colombier 		break;
9804de34a7eSDavid du Colombier 	}
9814de34a7eSDavid du Colombier 
9824de34a7eSDavid du Colombier 	/*
9834de34a7eSDavid du Colombier 	 * Map SCSI commands into ATA commands for discs.
9844de34a7eSDavid du Colombier 	 * Fail any command with a LUN except INQUIRY which
9854de34a7eSDavid du Colombier 	 * will return 'logical unit not supported'.
9864de34a7eSDavid du Colombier 	 */
9874de34a7eSDavid du Colombier 	if((cmd[1]>>5) && cmd[0] != 0x12)
9884de34a7eSDavid du Colombier 		return sdsetsense(r, SDcheck, 0x05, 0x25, 0);
9894de34a7eSDavid du Colombier 
9904de34a7eSDavid du Colombier 	switch(cmd[0]){
9914de34a7eSDavid du Colombier 	default:
9924de34a7eSDavid du Colombier 		return sdsetsense(r, SDcheck, 0x05, 0x20, 0);
9934de34a7eSDavid du Colombier 
9944de34a7eSDavid du Colombier 	case 0x00:	/* test unit ready */
9954de34a7eSDavid du Colombier 		return sdsetsense(r, SDok, 0, 0, 0);
9964de34a7eSDavid du Colombier 
9974de34a7eSDavid du Colombier 	case 0x03:	/* request sense */
9984de34a7eSDavid du Colombier 		if(cmd[4] < sizeof unit->sense)
9994de34a7eSDavid du Colombier 			len = cmd[4];
10004de34a7eSDavid du Colombier 		else
10014de34a7eSDavid du Colombier 			len = sizeof unit->sense;
10024de34a7eSDavid du Colombier 		if(r->data && r->dlen >= len){
10034de34a7eSDavid du Colombier 			memmove(r->data, unit->sense, len);
10044de34a7eSDavid du Colombier 			r->rlen = len;
10054de34a7eSDavid du Colombier 		}
10064de34a7eSDavid du Colombier 		return sdsetsense(r, SDok, 0, 0, 0);
10074de34a7eSDavid du Colombier 
10084de34a7eSDavid du Colombier 	case 0x12:	/* inquiry */
10094de34a7eSDavid du Colombier 		if(cmd[4] < sizeof unit->inquiry)
10104de34a7eSDavid du Colombier 			len = cmd[4];
10114de34a7eSDavid du Colombier 		else
10124de34a7eSDavid du Colombier 			len = sizeof unit->inquiry;
10134de34a7eSDavid du Colombier 		if(r->data && r->dlen >= len){
1014d95be1c0SDavid du Colombier 			memmove(r->data, unit->inquiry, len);
10154de34a7eSDavid du Colombier 			r->rlen = len;
10164de34a7eSDavid du Colombier 		}
10174de34a7eSDavid du Colombier 		return sdsetsense(r, SDok, 0, 0, 0);
10184de34a7eSDavid du Colombier 
10194de34a7eSDavid du Colombier 	case 0x1B:	/* start/stop unit */
10204de34a7eSDavid du Colombier 		/*
10214de34a7eSDavid du Colombier 		 * nop for now, can use power management later.
10224de34a7eSDavid du Colombier 		 */
10234de34a7eSDavid du Colombier 		return sdsetsense(r, SDok, 0, 0, 0);
10244de34a7eSDavid du Colombier 
10254de34a7eSDavid du Colombier 	case 0x25:	/* read capacity */
10264de34a7eSDavid du Colombier 		if((cmd[1] & 0x01) || cmd[2] || cmd[3])
10274de34a7eSDavid du Colombier 			return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
10284de34a7eSDavid du Colombier 		if(r->data == nil || r->dlen < 8)
10294de34a7eSDavid du Colombier 			return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
10304de34a7eSDavid du Colombier 
10314de34a7eSDavid du Colombier 		/*
10324de34a7eSDavid du Colombier 		 * Read capacity returns the LBA of the last sector.
10334de34a7eSDavid du Colombier 		 */
10344de34a7eSDavid du Colombier 		len = unit->sectors - 1;
10354de34a7eSDavid du Colombier 		p = r->data;
10364de34a7eSDavid du Colombier 		*p++ = len>>24;
10374de34a7eSDavid du Colombier 		*p++ = len>>16;
10384de34a7eSDavid du Colombier 		*p++ = len>>8;
10394de34a7eSDavid du Colombier 		*p++ = len;
10404de34a7eSDavid du Colombier 		len = 512;
10414de34a7eSDavid du Colombier 		*p++ = len>>24;
10424de34a7eSDavid du Colombier 		*p++ = len>>16;
10434de34a7eSDavid du Colombier 		*p++ = len>>8;
10444de34a7eSDavid du Colombier 		*p++ = len;
10454de34a7eSDavid du Colombier 		r->rlen = p - (uchar*)r->data;
10464de34a7eSDavid du Colombier 		return sdsetsense(r, SDok, 0, 0, 0);
10474de34a7eSDavid du Colombier 
10484de34a7eSDavid du Colombier 	case 0x9E:	/* long read capacity */
10494de34a7eSDavid du Colombier 		if((cmd[1] & 0x01) || cmd[2] || cmd[3])
10504de34a7eSDavid du Colombier 			return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
10514de34a7eSDavid du Colombier 		if(r->data == nil || r->dlen < 8)
10524de34a7eSDavid du Colombier 			return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
10534de34a7eSDavid du Colombier 		/*
10544de34a7eSDavid du Colombier 		 * Read capcity returns the LBA of the last sector.
10554de34a7eSDavid du Colombier 		 */
10564de34a7eSDavid du Colombier 		len = unit->sectors - 1;
10574de34a7eSDavid du Colombier 		p = r->data;
10584de34a7eSDavid du Colombier 		*p++ = len>>56;
10594de34a7eSDavid du Colombier 		*p++ = len>>48;
10604de34a7eSDavid du Colombier 		*p++ = len>>40;
10614de34a7eSDavid du Colombier 		*p++ = len>>32;
10624de34a7eSDavid du Colombier 		*p++ = len>>24;
10634de34a7eSDavid du Colombier 		*p++ = len>>16;
10644de34a7eSDavid du Colombier 		*p++ = len>>8;
10654de34a7eSDavid du Colombier 		*p++ = len;
10664de34a7eSDavid du Colombier 		len = 512;
10674de34a7eSDavid du Colombier 		*p++ = len>>24;
10684de34a7eSDavid du Colombier 		*p++ = len>>16;
10694de34a7eSDavid du Colombier 		*p++ = len>>8;
10704de34a7eSDavid du Colombier 		*p++ = len;
10714de34a7eSDavid du Colombier 		r->rlen = p - (uchar*)r->data;
10724de34a7eSDavid du Colombier 		return sdsetsense(r, SDok, 0, 0, 0);
10734de34a7eSDavid du Colombier 
10744de34a7eSDavid du Colombier 	case 0x5A:	/* mode sense */
10754de34a7eSDavid du Colombier 		return sdmodesense(r, cmd, info, ilen);
10764de34a7eSDavid du Colombier 
10774de34a7eSDavid du Colombier 	case 0x28:	/* read */
10784de34a7eSDavid du Colombier 	case 0x2A:	/* write */
107917629263SDavid du Colombier 	case 0x88:	/* read16 */
108017629263SDavid du Colombier 	case 0x8a:	/* write16 */
10814de34a7eSDavid du Colombier 		return SDnostatus;
10824de34a7eSDavid du Colombier 	}
10834de34a7eSDavid du Colombier }
10844de34a7eSDavid du Colombier 
10857dd7cddfSDavid du Colombier static long
sdread(Chan * c,void * a,long n,vlong off)10867dd7cddfSDavid du Colombier sdread(Chan *c, void *a, long n, vlong off)
10877dd7cddfSDavid du Colombier {
10889a747e4fSDavid du Colombier 	char *p, *e, *buf;
10897dd7cddfSDavid du Colombier 	SDpart *pp;
10907dd7cddfSDavid du Colombier 	SDunit *unit;
10919a747e4fSDavid du Colombier 	SDev *sdev;
10927dd7cddfSDavid du Colombier 	ulong offset;
10934de34a7eSDavid du Colombier 	int i, l, m, status;
10947dd7cddfSDavid du Colombier 
10957dd7cddfSDavid du Colombier 	offset = off;
10967dd7cddfSDavid du Colombier 	switch(TYPE(c->qid)){
10977dd7cddfSDavid du Colombier 	default:
10987dd7cddfSDavid du Colombier 		error(Eperm);
10994de34a7eSDavid du Colombier 	case Qtopctl:
11004de34a7eSDavid du Colombier 		m = 64*1024;	/* room for register dumps */
11014de34a7eSDavid du Colombier 		p = buf = malloc(m);
1102aa72973aSDavid du Colombier 		if(p == nil)
1103aa72973aSDavid du Colombier 			error(Enomem);
11044de34a7eSDavid du Colombier 		e = p + m;
11059a747e4fSDavid du Colombier 		qlock(&devslock);
11064de34a7eSDavid du Colombier 		for(i = 0; i < nelem(devs); i++){
11074de34a7eSDavid du Colombier 			sdev = devs[i];
11084de34a7eSDavid du Colombier 			if(sdev && sdev->ifc->rtopctl)
11094de34a7eSDavid du Colombier 				p = sdev->ifc->rtopctl(sdev, p, e);
11109a747e4fSDavid du Colombier 		}
11119a747e4fSDavid du Colombier 		qunlock(&devslock);
11129a747e4fSDavid du Colombier 		n = readstr(off, a, n, buf);
11139a747e4fSDavid du Colombier 		free(buf);
11149a747e4fSDavid du Colombier 		return n;
11159a747e4fSDavid du Colombier 
11167dd7cddfSDavid du Colombier 	case Qtopdir:
11177dd7cddfSDavid du Colombier 	case Qunitdir:
11187dd7cddfSDavid du Colombier 		return devdirread(c, a, n, 0, 0, sdgen);
11199a747e4fSDavid du Colombier 
11207dd7cddfSDavid du Colombier 	case Qctl:
11219a747e4fSDavid du Colombier 		sdev = sdgetdev(DEV(c->qid));
11229a747e4fSDavid du Colombier 		if(sdev == nil)
11239a747e4fSDavid du Colombier 			error(Enonexist);
11249a747e4fSDavid du Colombier 
11259a747e4fSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
11264de34a7eSDavid du Colombier 		m = 16*1024;	/* room for register dumps */
11274de34a7eSDavid du Colombier 		p = malloc(m);
1128aa72973aSDavid du Colombier 		if(p == nil)
1129aa72973aSDavid du Colombier 			error(Enomem);
11304de34a7eSDavid du Colombier 		l = snprint(p, m, "inquiry %.48s\n",
11317dd7cddfSDavid du Colombier 			(char*)unit->inquiry+8);
11327dd7cddfSDavid du Colombier 		qlock(&unit->ctl);
11337dd7cddfSDavid du Colombier 		/*
11347dd7cddfSDavid du Colombier 		 * If there's a device specific routine it must
11357dd7cddfSDavid du Colombier 		 * provide all information pertaining to night geometry
11367dd7cddfSDavid du Colombier 		 * and the garscadden trains.
11377dd7cddfSDavid du Colombier 		 */
11387dd7cddfSDavid du Colombier 		if(unit->dev->ifc->rctl)
11394de34a7eSDavid du Colombier 			l += unit->dev->ifc->rctl(unit, p+l, m-l);
1140223a736eSDavid du Colombier 		if(unit->sectors == 0)
1141223a736eSDavid du Colombier 			sdinitpart(unit);
1142223a736eSDavid du Colombier 		if(unit->sectors){
11437dd7cddfSDavid du Colombier 			if(unit->dev->ifc->rctl == nil)
11444de34a7eSDavid du Colombier 				l += snprint(p+l, m-l,
114517629263SDavid du Colombier 					"geometry %llud %lud\n",
11467dd7cddfSDavid du Colombier 					unit->sectors, unit->secsize);
11477dd7cddfSDavid du Colombier 			pp = unit->part;
114859cc4ca5SDavid du Colombier 			for(i = 0; i < unit->npart; i++){
11497dd7cddfSDavid du Colombier 				if(pp->valid)
11504de34a7eSDavid du Colombier 					l += snprint(p+l, m-l,
115117629263SDavid du Colombier 						"part %s %llud %llud\n",
11529a747e4fSDavid du Colombier 						pp->name, pp->start, pp->end);
11537dd7cddfSDavid du Colombier 				pp++;
11547dd7cddfSDavid du Colombier 			}
11557dd7cddfSDavid du Colombier 		}
11567dd7cddfSDavid du Colombier 		qunlock(&unit->ctl);
11579a747e4fSDavid du Colombier 		decref(&sdev->r);
11587dd7cddfSDavid du Colombier 		l = readstr(offset, a, n, p);
11597dd7cddfSDavid du Colombier 		free(p);
11607dd7cddfSDavid du Colombier 		return l;
11619a747e4fSDavid du Colombier 
11627dd7cddfSDavid du Colombier 	case Qraw:
11639a747e4fSDavid du Colombier 		sdev = sdgetdev(DEV(c->qid));
11649a747e4fSDavid du Colombier 		if(sdev == nil)
11659a747e4fSDavid du Colombier 			error(Enonexist);
11669a747e4fSDavid du Colombier 
11679a747e4fSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
116880ee5cbfSDavid du Colombier 		qlock(&unit->raw);
116980ee5cbfSDavid du Colombier 		if(waserror()){
117080ee5cbfSDavid du Colombier 			qunlock(&unit->raw);
11719a747e4fSDavid du Colombier 			decref(&sdev->r);
117280ee5cbfSDavid du Colombier 			nexterror();
117380ee5cbfSDavid du Colombier 		}
11747dd7cddfSDavid du Colombier 		if(unit->state == Rawdata){
11757dd7cddfSDavid du Colombier 			unit->state = Rawstatus;
117680ee5cbfSDavid du Colombier 			i = sdrio(unit->req, a, n);
11777dd7cddfSDavid du Colombier 		}
11787dd7cddfSDavid du Colombier 		else if(unit->state == Rawstatus){
11797dd7cddfSDavid du Colombier 			status = unit->req->status;
11807dd7cddfSDavid du Colombier 			unit->state = Rawcmd;
11817dd7cddfSDavid du Colombier 			free(unit->req);
11827dd7cddfSDavid du Colombier 			unit->req = nil;
118380ee5cbfSDavid du Colombier 			i = readnum(0, a, n, status, NUMSIZE);
118480ee5cbfSDavid du Colombier 		} else
118580ee5cbfSDavid du Colombier 			i = 0;
118680ee5cbfSDavid du Colombier 		qunlock(&unit->raw);
11879a747e4fSDavid du Colombier 		decref(&sdev->r);
118880ee5cbfSDavid du Colombier 		poperror();
118980ee5cbfSDavid du Colombier 		return i;
11909a747e4fSDavid du Colombier 
11917dd7cddfSDavid du Colombier 	case Qpart:
11927dd7cddfSDavid du Colombier 		return sdbio(c, 0, a, n, off);
11937dd7cddfSDavid du Colombier 	}
11947dd7cddfSDavid du Colombier }
11957dd7cddfSDavid du Colombier 
11964de34a7eSDavid du Colombier static void legacytopctl(Cmdbuf*);
11979a747e4fSDavid du Colombier 
11987dd7cddfSDavid du Colombier static long
sdwrite(Chan * c,void * a,long n,vlong off)11997dd7cddfSDavid du Colombier sdwrite(Chan* c, void* a, long n, vlong off)
12007dd7cddfSDavid du Colombier {
12014de34a7eSDavid du Colombier 	char *f0;
12024de34a7eSDavid du Colombier 	int i;
120317629263SDavid du Colombier 	uvlong end, start;
12047dd7cddfSDavid du Colombier 	Cmdbuf *cb;
12054de34a7eSDavid du Colombier 	SDifc *ifc;
12067dd7cddfSDavid du Colombier 	SDreq *req;
12077dd7cddfSDavid du Colombier 	SDunit *unit;
12089a747e4fSDavid du Colombier 	SDev *sdev;
12097dd7cddfSDavid du Colombier 
12107dd7cddfSDavid du Colombier 	switch(TYPE(c->qid)){
12117dd7cddfSDavid du Colombier 	default:
12127dd7cddfSDavid du Colombier 		error(Eperm);
12134de34a7eSDavid du Colombier 	case Qtopctl:
12144de34a7eSDavid du Colombier 		cb = parsecmd(a, n);
12154de34a7eSDavid du Colombier 		if(waserror()){
12164de34a7eSDavid du Colombier 			free(cb);
12174de34a7eSDavid du Colombier 			nexterror();
12189a747e4fSDavid du Colombier 		}
12194de34a7eSDavid du Colombier 		if(cb->nf == 0)
12204de34a7eSDavid du Colombier 			error("empty control message");
12214de34a7eSDavid du Colombier 		f0 = cb->f[0];
12224de34a7eSDavid du Colombier 		cb->f++;
12234de34a7eSDavid du Colombier 		cb->nf--;
12244de34a7eSDavid du Colombier 		if(strcmp(f0, "config") == 0){
12254de34a7eSDavid du Colombier 			/* wormhole into ugly legacy interface */
12264de34a7eSDavid du Colombier 			legacytopctl(cb);
12274de34a7eSDavid du Colombier 			poperror();
12284de34a7eSDavid du Colombier 			free(cb);
12299a747e4fSDavid du Colombier 			break;
12309a747e4fSDavid du Colombier 		}
1231d649fdd7SDavid du Colombier 		/*
1232d649fdd7SDavid du Colombier 		 * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1233d649fdd7SDavid du Colombier 		 * where sdifc[i]->name=="ata" and cb contains the args.
1234d649fdd7SDavid du Colombier 		 */
12354de34a7eSDavid du Colombier 		ifc = nil;
12364de34a7eSDavid du Colombier 		sdev = nil;
12374de34a7eSDavid du Colombier 		for(i=0; sdifc[i]; i++){
12384de34a7eSDavid du Colombier 			if(strcmp(sdifc[i]->name, f0) == 0){
12394de34a7eSDavid du Colombier 				ifc = sdifc[i];
12404de34a7eSDavid du Colombier 				sdev = nil;
12414de34a7eSDavid du Colombier 				goto subtopctl;
12424de34a7eSDavid du Colombier 			}
12434de34a7eSDavid du Colombier 		}
1244d649fdd7SDavid du Colombier 		/*
1245d649fdd7SDavid du Colombier 		 * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1246d649fdd7SDavid du Colombier 		 * where sdifc[i] and sdev match controller letter "1",
1247d649fdd7SDavid du Colombier 		 * and cb contains the args.
1248d649fdd7SDavid du Colombier 		 */
12494de34a7eSDavid du Colombier 		if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
12504de34a7eSDavid du Colombier 			if((sdev = sdgetdev(f0[2])) != nil){
12514de34a7eSDavid du Colombier 				ifc = sdev->ifc;
12524de34a7eSDavid du Colombier 				goto subtopctl;
12534de34a7eSDavid du Colombier 			}
12544de34a7eSDavid du Colombier 		}
12554de34a7eSDavid du Colombier 		error("unknown interface");
12564de34a7eSDavid du Colombier 
12574de34a7eSDavid du Colombier 	subtopctl:
12584de34a7eSDavid du Colombier 		if(waserror()){
12594de34a7eSDavid du Colombier 			if(sdev)
12604de34a7eSDavid du Colombier 				decref(&sdev->r);
12614de34a7eSDavid du Colombier 			nexterror();
12624de34a7eSDavid du Colombier 		}
12634de34a7eSDavid du Colombier 		if(ifc->wtopctl)
12644de34a7eSDavid du Colombier 			ifc->wtopctl(sdev, cb);
12654de34a7eSDavid du Colombier 		else
12664de34a7eSDavid du Colombier 			error(Ebadctl);
12674de34a7eSDavid du Colombier 		poperror();
12684de34a7eSDavid du Colombier 		poperror();
12699e8a50a9SDavid du Colombier 		if (sdev)
12704de34a7eSDavid du Colombier 			decref(&sdev->r);
12714de34a7eSDavid du Colombier 		free(cb);
12724de34a7eSDavid du Colombier 		break;
12734de34a7eSDavid du Colombier 
12747dd7cddfSDavid du Colombier 	case Qctl:
12757dd7cddfSDavid du Colombier 		cb = parsecmd(a, n);
12769a747e4fSDavid du Colombier 		sdev = sdgetdev(DEV(c->qid));
12779a747e4fSDavid du Colombier 		if(sdev == nil)
12789a747e4fSDavid du Colombier 			error(Enonexist);
12799a747e4fSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
12807dd7cddfSDavid du Colombier 
12817dd7cddfSDavid du Colombier 		qlock(&unit->ctl);
12827dd7cddfSDavid du Colombier 		if(waserror()){
12837dd7cddfSDavid du Colombier 			qunlock(&unit->ctl);
12849a747e4fSDavid du Colombier 			decref(&sdev->r);
12857dd7cddfSDavid du Colombier 			free(cb);
12867dd7cddfSDavid du Colombier 			nexterror();
12877dd7cddfSDavid du Colombier 		}
1288223a736eSDavid du Colombier 		if(unit->vers != c->qid.vers)
12894de34a7eSDavid du Colombier 			error(Echange);
12907dd7cddfSDavid du Colombier 
12917dd7cddfSDavid du Colombier 		if(cb->nf < 1)
12927dd7cddfSDavid du Colombier 			error(Ebadctl);
12937dd7cddfSDavid du Colombier 		if(strcmp(cb->f[0], "part") == 0){
1294223a736eSDavid du Colombier 			if(cb->nf != 4)
12957dd7cddfSDavid du Colombier 				error(Ebadctl);
12967dd7cddfSDavid du Colombier 			if(unit->sectors == 0 && !sdinitpart(unit))
12977dd7cddfSDavid du Colombier 				error(Eio);
129817629263SDavid du Colombier 			start = strtoull(cb->f[2], 0, 0);
129917629263SDavid du Colombier 			end = strtoull(cb->f[3], 0, 0);
13007dd7cddfSDavid du Colombier 			sdaddpart(unit, cb->f[1], start, end);
13017dd7cddfSDavid du Colombier 		}
13027dd7cddfSDavid du Colombier 		else if(strcmp(cb->f[0], "delpart") == 0){
13037dd7cddfSDavid du Colombier 			if(cb->nf != 2 || unit->part == nil)
13047dd7cddfSDavid du Colombier 				error(Ebadctl);
13057dd7cddfSDavid du Colombier 			sddelpart(unit, cb->f[1]);
13067dd7cddfSDavid du Colombier 		}
13077dd7cddfSDavid du Colombier 		else if(unit->dev->ifc->wctl)
13087dd7cddfSDavid du Colombier 			unit->dev->ifc->wctl(unit, cb);
13097dd7cddfSDavid du Colombier 		else
13107dd7cddfSDavid du Colombier 			error(Ebadctl);
13117dd7cddfSDavid du Colombier 		qunlock(&unit->ctl);
13129a747e4fSDavid du Colombier 		decref(&sdev->r);
13137dd7cddfSDavid du Colombier 		poperror();
13147dd7cddfSDavid du Colombier 		free(cb);
13157dd7cddfSDavid du Colombier 		break;
13167dd7cddfSDavid du Colombier 
13177dd7cddfSDavid du Colombier 	case Qraw:
13189a747e4fSDavid du Colombier 		sdev = sdgetdev(DEV(c->qid));
13199a747e4fSDavid du Colombier 		if(sdev == nil)
13209a747e4fSDavid du Colombier 			error(Enonexist);
13219a747e4fSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
132280ee5cbfSDavid du Colombier 		qlock(&unit->raw);
132380ee5cbfSDavid du Colombier 		if(waserror()){
132480ee5cbfSDavid du Colombier 			qunlock(&unit->raw);
13259a747e4fSDavid du Colombier 			decref(&sdev->r);
132680ee5cbfSDavid du Colombier 			nexterror();
132780ee5cbfSDavid du Colombier 		}
13287dd7cddfSDavid du Colombier 		switch(unit->state){
13297dd7cddfSDavid du Colombier 		case Rawcmd:
13307dd7cddfSDavid du Colombier 			if(n < 6 || n > sizeof(req->cmd))
13317dd7cddfSDavid du Colombier 				error(Ebadarg);
13327dd7cddfSDavid du Colombier 			if((req = malloc(sizeof(SDreq))) == nil)
13337dd7cddfSDavid du Colombier 				error(Enomem);
13347dd7cddfSDavid du Colombier 			req->unit = unit;
13357dd7cddfSDavid du Colombier 			memmove(req->cmd, a, n);
13367dd7cddfSDavid du Colombier 			req->clen = n;
13377dd7cddfSDavid du Colombier 			req->flags = SDnosense;
13387dd7cddfSDavid du Colombier 			req->status = ~0;
13397dd7cddfSDavid du Colombier 
13407dd7cddfSDavid du Colombier 			unit->req = req;
13417dd7cddfSDavid du Colombier 			unit->state = Rawdata;
13427dd7cddfSDavid du Colombier 			break;
13437dd7cddfSDavid du Colombier 
13447dd7cddfSDavid du Colombier 		case Rawstatus:
13457dd7cddfSDavid du Colombier 			unit->state = Rawcmd;
13467dd7cddfSDavid du Colombier 			free(unit->req);
13477dd7cddfSDavid du Colombier 			unit->req = nil;
13487dd7cddfSDavid du Colombier 			error(Ebadusefd);
13497dd7cddfSDavid du Colombier 
13507dd7cddfSDavid du Colombier 		case Rawdata:
13517dd7cddfSDavid du Colombier 			unit->state = Rawstatus;
13527dd7cddfSDavid du Colombier 			unit->req->write = 1;
135380ee5cbfSDavid du Colombier 			n = sdrio(unit->req, a, n);
13547dd7cddfSDavid du Colombier 		}
135580ee5cbfSDavid du Colombier 		qunlock(&unit->raw);
13569a747e4fSDavid du Colombier 		decref(&sdev->r);
135780ee5cbfSDavid du Colombier 		poperror();
13589a747e4fSDavid du Colombier 		break;
13597dd7cddfSDavid du Colombier 	case Qpart:
13607dd7cddfSDavid du Colombier 		return sdbio(c, 1, a, n, off);
13617dd7cddfSDavid du Colombier 	}
13627dd7cddfSDavid du Colombier 
13637dd7cddfSDavid du Colombier 	return n;
13647dd7cddfSDavid du Colombier }
13657dd7cddfSDavid du Colombier 
13669a747e4fSDavid du Colombier static int
sdwstat(Chan * c,uchar * dp,int n)13679a747e4fSDavid du Colombier sdwstat(Chan* c, uchar* dp, int n)
13687dd7cddfSDavid du Colombier {
13699a747e4fSDavid du Colombier 	Dir *d;
13707dd7cddfSDavid du Colombier 	SDpart *pp;
137159cc4ca5SDavid du Colombier 	SDperm *perm;
13727dd7cddfSDavid du Colombier 	SDunit *unit;
13739a747e4fSDavid du Colombier 	SDev *sdev;
13747dd7cddfSDavid du Colombier 
13759a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
13767dd7cddfSDavid du Colombier 		error(Eperm);
13777dd7cddfSDavid du Colombier 
13789a747e4fSDavid du Colombier 	sdev = sdgetdev(DEV(c->qid));
13799a747e4fSDavid du Colombier 	if(sdev == nil)
13809a747e4fSDavid du Colombier 		error(Enonexist);
13819a747e4fSDavid du Colombier 	unit = sdev->unit[UNIT(c->qid)];
13827dd7cddfSDavid du Colombier 	qlock(&unit->ctl);
13839a747e4fSDavid du Colombier 	d = nil;
13847dd7cddfSDavid du Colombier 	if(waserror()){
13859a747e4fSDavid du Colombier 		free(d);
13867dd7cddfSDavid du Colombier 		qunlock(&unit->ctl);
13879a747e4fSDavid du Colombier 		decref(&sdev->r);
13887dd7cddfSDavid du Colombier 		nexterror();
13897dd7cddfSDavid du Colombier 	}
13907dd7cddfSDavid du Colombier 
139159cc4ca5SDavid du Colombier 	switch(TYPE(c->qid)){
139259cc4ca5SDavid du Colombier 	default:
139359cc4ca5SDavid du Colombier 		error(Eperm);
139459cc4ca5SDavid du Colombier 	case Qctl:
139559cc4ca5SDavid du Colombier 		perm = &unit->ctlperm;
139659cc4ca5SDavid du Colombier 		break;
139759cc4ca5SDavid du Colombier 	case Qraw:
139859cc4ca5SDavid du Colombier 		perm = &unit->rawperm;
139959cc4ca5SDavid du Colombier 		break;
140059cc4ca5SDavid du Colombier 	case Qpart:
14017dd7cddfSDavid du Colombier 		pp = &unit->part[PART(c->qid)];
1402223a736eSDavid du Colombier 		if(unit->vers+pp->vers != c->qid.vers)
14037dd7cddfSDavid du Colombier 			error(Enonexist);
140459cc4ca5SDavid du Colombier 		perm = &pp->SDperm;
140559cc4ca5SDavid du Colombier 		break;
140659cc4ca5SDavid du Colombier 	}
14077dd7cddfSDavid du Colombier 
14089a747e4fSDavid du Colombier 	if(strcmp(up->user, perm->user) && !iseve())
140959cc4ca5SDavid du Colombier 		error(Eperm);
14107dd7cddfSDavid du Colombier 
14119a747e4fSDavid du Colombier 	d = smalloc(sizeof(Dir)+n);
14129a747e4fSDavid du Colombier 	n = convM2D(dp, n, &d[0], (char*)&d[1]);
14139a747e4fSDavid du Colombier 	if(n == 0)
14149a747e4fSDavid du Colombier 		error(Eshortstat);
14159a747e4fSDavid du Colombier 	if(!emptystr(d[0].uid))
14169a747e4fSDavid du Colombier 		kstrdup(&perm->user, d[0].uid);
14179a747e4fSDavid du Colombier 	if(d[0].mode != ~0UL)
14189a747e4fSDavid du Colombier 		perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
14199a747e4fSDavid du Colombier 
14209a747e4fSDavid du Colombier 	free(d);
14217dd7cddfSDavid du Colombier 	qunlock(&unit->ctl);
14229a747e4fSDavid du Colombier 	decref(&sdev->r);
14237dd7cddfSDavid du Colombier 	poperror();
14249a747e4fSDavid du Colombier 	return n;
14259a747e4fSDavid du Colombier }
14269a747e4fSDavid du Colombier 
14279a747e4fSDavid du Colombier static int
configure(char * spec,DevConf * cf)14289a747e4fSDavid du Colombier configure(char* spec, DevConf* cf)
14299a747e4fSDavid du Colombier {
14304de34a7eSDavid du Colombier 	SDev *s, *sdev;
14314de34a7eSDavid du Colombier 	char *p;
14324de34a7eSDavid du Colombier 	int i;
14334de34a7eSDavid du Colombier 
14344de34a7eSDavid du Colombier 	if(sdindex(*spec) < 0)
14354de34a7eSDavid du Colombier 		error("bad sd spec");
14369a747e4fSDavid du Colombier 
14379a747e4fSDavid du Colombier 	if((p = strchr(cf->type, '/')) != nil)
14389a747e4fSDavid du Colombier 		*p++ = '\0';
14399a747e4fSDavid du Colombier 
14409a747e4fSDavid du Colombier 	for(i = 0; sdifc[i] != nil; i++)
14414de34a7eSDavid du Colombier 		if(strcmp(sdifc[i]->name, cf->type) == 0)
14429a747e4fSDavid du Colombier 			break;
14439a747e4fSDavid du Colombier 	if(sdifc[i] == nil)
14444de34a7eSDavid du Colombier 		error("sd type not found");
14454de34a7eSDavid du Colombier 	if(p)
14464de34a7eSDavid du Colombier 		*(p-1) = '/';
14479a747e4fSDavid du Colombier 
14484de34a7eSDavid du Colombier 	if(sdifc[i]->probe == nil)
14494de34a7eSDavid du Colombier 		error("sd type cannot probe");
14509a747e4fSDavid du Colombier 
14514de34a7eSDavid du Colombier 	sdev = sdifc[i]->probe(cf);
14524de34a7eSDavid du Colombier 	for(s=sdev; s; s=s->next)
14534de34a7eSDavid du Colombier 		s->idno = *spec;
14544de34a7eSDavid du Colombier 	sdadddevs(sdev);
14559a747e4fSDavid du Colombier 	return 0;
14569a747e4fSDavid du Colombier }
14579a747e4fSDavid du Colombier 
14589a747e4fSDavid du Colombier static int
unconfigure(char * spec)14599a747e4fSDavid du Colombier unconfigure(char* spec)
14609a747e4fSDavid du Colombier {
14619a747e4fSDavid du Colombier 	int i;
14629a747e4fSDavid du Colombier 	SDev *sdev;
14634de34a7eSDavid du Colombier 	SDunit *unit;
14649a747e4fSDavid du Colombier 
14654de34a7eSDavid du Colombier 	if((i = sdindex(*spec)) < 0)
14669a747e4fSDavid du Colombier 		error(Enonexist);
14679a747e4fSDavid du Colombier 
14684de34a7eSDavid du Colombier 	qlock(&devslock);
14694de34a7eSDavid du Colombier 	if((sdev = devs[i]) == nil){
14704de34a7eSDavid du Colombier 		qunlock(&devslock);
14714de34a7eSDavid du Colombier 		error(Enonexist);
14724de34a7eSDavid du Colombier 	}
14734de34a7eSDavid du Colombier 	if(sdev->r.ref){
14744de34a7eSDavid du Colombier 		qunlock(&devslock);
14759a747e4fSDavid du Colombier 		error(Einuse);
14764de34a7eSDavid du Colombier 	}
14774de34a7eSDavid du Colombier 	devs[i] = nil;
14784de34a7eSDavid du Colombier 	qunlock(&devslock);
14799a747e4fSDavid du Colombier 
14809a747e4fSDavid du Colombier 	/* make sure no interrupts arrive anymore before removing resources */
14819a747e4fSDavid du Colombier 	if(sdev->enabled && sdev->ifc->disable)
14829a747e4fSDavid du Colombier 		sdev->ifc->disable(sdev);
14839a747e4fSDavid du Colombier 
14844de34a7eSDavid du Colombier 	for(i = 0; i != sdev->nunit; i++){
14854de34a7eSDavid du Colombier 		if(unit = sdev->unit[i]){
14869a747e4fSDavid du Colombier 			free(unit->name);
14879a747e4fSDavid du Colombier 			free(unit->user);
14889a747e4fSDavid du Colombier 			free(unit);
14899a747e4fSDavid du Colombier 		}
14904de34a7eSDavid du Colombier 	}
14919a747e4fSDavid du Colombier 
14929a747e4fSDavid du Colombier 	if(sdev->ifc->clear)
14939a747e4fSDavid du Colombier 		sdev->ifc->clear(sdev);
14944de34a7eSDavid du Colombier 	free(sdev);
14959a747e4fSDavid du Colombier 	return 0;
14969a747e4fSDavid du Colombier }
14979a747e4fSDavid du Colombier 
14989a747e4fSDavid du Colombier static int
sdconfig(int on,char * spec,DevConf * cf)14999a747e4fSDavid du Colombier sdconfig(int on, char* spec, DevConf* cf)
15009a747e4fSDavid du Colombier {
15019a747e4fSDavid du Colombier 	if(on)
15029a747e4fSDavid du Colombier 		return configure(spec, cf);
15039a747e4fSDavid du Colombier 	return unconfigure(spec);
15047dd7cddfSDavid du Colombier }
15057dd7cddfSDavid du Colombier 
15067dd7cddfSDavid du Colombier Dev sddevtab = {
15077dd7cddfSDavid du Colombier 	'S',
15087dd7cddfSDavid du Colombier 	"sd",
15097dd7cddfSDavid du Colombier 
15107dd7cddfSDavid du Colombier 	sdreset,
15117dd7cddfSDavid du Colombier 	devinit,
15129a747e4fSDavid du Colombier 	devshutdown,
15137dd7cddfSDavid du Colombier 	sdattach,
15147dd7cddfSDavid du Colombier 	sdwalk,
15157dd7cddfSDavid du Colombier 	sdstat,
15167dd7cddfSDavid du Colombier 	sdopen,
15177dd7cddfSDavid du Colombier 	devcreate,
15187dd7cddfSDavid du Colombier 	sdclose,
15197dd7cddfSDavid du Colombier 	sdread,
15207dd7cddfSDavid du Colombier 	devbread,
15217dd7cddfSDavid du Colombier 	sdwrite,
15227dd7cddfSDavid du Colombier 	devbwrite,
15237dd7cddfSDavid du Colombier 	devremove,
15247dd7cddfSDavid du Colombier 	sdwstat,
15259a747e4fSDavid du Colombier 	devpower,
1526aa72973aSDavid du Colombier 	sdconfig,	/* probe; only called for pcmcia-like devices */
15277dd7cddfSDavid du Colombier };
15284de34a7eSDavid du Colombier 
15294de34a7eSDavid du Colombier /*
15304de34a7eSDavid du Colombier  * This is wrong for so many reasons.  This code must go.
15314de34a7eSDavid du Colombier  */
15324de34a7eSDavid du Colombier typedef struct Confdata Confdata;
15334de34a7eSDavid du Colombier struct Confdata {
15344de34a7eSDavid du Colombier 	int	on;
15354de34a7eSDavid du Colombier 	char*	spec;
15364de34a7eSDavid du Colombier 	DevConf	cf;
15374de34a7eSDavid du Colombier };
15384de34a7eSDavid du Colombier 
15394de34a7eSDavid du Colombier static void
parseswitch(Confdata * cd,char * option)15404de34a7eSDavid du Colombier parseswitch(Confdata* cd, char* option)
15414de34a7eSDavid du Colombier {
15424de34a7eSDavid du Colombier 	if(!strcmp("on", option))
15434de34a7eSDavid du Colombier 		cd->on = 1;
15444de34a7eSDavid du Colombier 	else if(!strcmp("off", option))
15454de34a7eSDavid du Colombier 		cd->on = 0;
15464de34a7eSDavid du Colombier 	else
15474de34a7eSDavid du Colombier 		error(Ebadarg);
15484de34a7eSDavid du Colombier }
15494de34a7eSDavid du Colombier 
15504de34a7eSDavid du Colombier static void
parsespec(Confdata * cd,char * option)15514de34a7eSDavid du Colombier parsespec(Confdata* cd, char* option)
15524de34a7eSDavid du Colombier {
15534de34a7eSDavid du Colombier 	if(strlen(option) > 1)
15544de34a7eSDavid du Colombier 		error(Ebadarg);
15554de34a7eSDavid du Colombier 	cd->spec = option;
15564de34a7eSDavid du Colombier }
15574de34a7eSDavid du Colombier 
15584de34a7eSDavid du Colombier static Devport*
getnewport(DevConf * dc)15594de34a7eSDavid du Colombier getnewport(DevConf* dc)
15604de34a7eSDavid du Colombier {
15614de34a7eSDavid du Colombier 	Devport *p;
15624de34a7eSDavid du Colombier 
15634de34a7eSDavid du Colombier 	p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
1564aa72973aSDavid du Colombier 	if(p == nil)
1565aa72973aSDavid du Colombier 		error(Enomem);
15664de34a7eSDavid du Colombier 	if(dc->nports > 0){
15674de34a7eSDavid du Colombier 		memmove(p, dc->ports, dc->nports * sizeof(Devport));
15684de34a7eSDavid du Colombier 		free(dc->ports);
15694de34a7eSDavid du Colombier 	}
15704de34a7eSDavid du Colombier 	dc->ports = p;
15714de34a7eSDavid du Colombier 	p = &dc->ports[dc->nports++];
15724de34a7eSDavid du Colombier 	p->size = -1;
15734de34a7eSDavid du Colombier 	p->port = (ulong)-1;
15744de34a7eSDavid du Colombier 	return p;
15754de34a7eSDavid du Colombier }
15764de34a7eSDavid du Colombier 
15774de34a7eSDavid du Colombier static void
parseport(Confdata * cd,char * option)15784de34a7eSDavid du Colombier parseport(Confdata* cd, char* option)
15794de34a7eSDavid du Colombier {
15804de34a7eSDavid du Colombier 	char *e;
15814de34a7eSDavid du Colombier 	Devport *p;
15824de34a7eSDavid du Colombier 
15834de34a7eSDavid du Colombier 	if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
15844de34a7eSDavid du Colombier 		p = getnewport(&cd->cf);
15854de34a7eSDavid du Colombier 	else
15864de34a7eSDavid du Colombier 		p = &cd->cf.ports[cd->cf.nports-1];
15874de34a7eSDavid du Colombier 	p->port = strtol(option, &e, 0);
15884de34a7eSDavid du Colombier 	if(e == nil || *e != '\0')
15894de34a7eSDavid du Colombier 		error(Ebadarg);
15904de34a7eSDavid du Colombier }
15914de34a7eSDavid du Colombier 
15924de34a7eSDavid du Colombier static void
parsesize(Confdata * cd,char * option)15934de34a7eSDavid du Colombier parsesize(Confdata* cd, char* option)
15944de34a7eSDavid du Colombier {
15954de34a7eSDavid du Colombier 	char *e;
15964de34a7eSDavid du Colombier 	Devport *p;
15974de34a7eSDavid du Colombier 
15984de34a7eSDavid du Colombier 	if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
15994de34a7eSDavid du Colombier 		p = getnewport(&cd->cf);
16004de34a7eSDavid du Colombier 	else
16014de34a7eSDavid du Colombier 		p = &cd->cf.ports[cd->cf.nports-1];
16024de34a7eSDavid du Colombier 	p->size = (int)strtol(option, &e, 0);
16034de34a7eSDavid du Colombier 	if(e == nil || *e != '\0')
16044de34a7eSDavid du Colombier 		error(Ebadarg);
16054de34a7eSDavid du Colombier }
16064de34a7eSDavid du Colombier 
16074de34a7eSDavid du Colombier static void
parseirq(Confdata * cd,char * option)16084de34a7eSDavid du Colombier parseirq(Confdata* cd, char* option)
16094de34a7eSDavid du Colombier {
16104de34a7eSDavid du Colombier 	char *e;
16114de34a7eSDavid du Colombier 
16124de34a7eSDavid du Colombier 	cd->cf.intnum = strtoul(option, &e, 0);
16134de34a7eSDavid du Colombier 	if(e == nil || *e != '\0')
16144de34a7eSDavid du Colombier 		error(Ebadarg);
16154de34a7eSDavid du Colombier }
16164de34a7eSDavid du Colombier 
16174de34a7eSDavid du Colombier static void
parsetype(Confdata * cd,char * option)16184de34a7eSDavid du Colombier parsetype(Confdata* cd, char* option)
16194de34a7eSDavid du Colombier {
16204de34a7eSDavid du Colombier 	cd->cf.type = option;
16214de34a7eSDavid du Colombier }
16224de34a7eSDavid du Colombier 
16234de34a7eSDavid du Colombier static struct {
16244de34a7eSDavid du Colombier 	char	*name;
16254de34a7eSDavid du Colombier 	void	(*parse)(Confdata*, char*);
16264de34a7eSDavid du Colombier } options[] = {
16274de34a7eSDavid du Colombier 	"switch",	parseswitch,
16284de34a7eSDavid du Colombier 	"spec",		parsespec,
16294de34a7eSDavid du Colombier 	"port",		parseport,
16304de34a7eSDavid du Colombier 	"size",		parsesize,
16314de34a7eSDavid du Colombier 	"irq",		parseirq,
16324de34a7eSDavid du Colombier 	"type",		parsetype,
16334de34a7eSDavid du Colombier };
16344de34a7eSDavid du Colombier 
16354de34a7eSDavid du Colombier static void
legacytopctl(Cmdbuf * cb)16364de34a7eSDavid du Colombier legacytopctl(Cmdbuf *cb)
16374de34a7eSDavid du Colombier {
16384de34a7eSDavid du Colombier 	char *opt;
16394de34a7eSDavid du Colombier 	int i, j;
16404de34a7eSDavid du Colombier 	Confdata cd;
16414de34a7eSDavid du Colombier 
16424de34a7eSDavid du Colombier 	memset(&cd, 0, sizeof cd);
16434de34a7eSDavid du Colombier 	cd.on = -1;
16444de34a7eSDavid du Colombier 	for(i=0; i<cb->nf; i+=2){
16454de34a7eSDavid du Colombier 		if(i+2 > cb->nf)
16464de34a7eSDavid du Colombier 			error(Ebadarg);
16474de34a7eSDavid du Colombier 		opt = cb->f[i];
16484de34a7eSDavid du Colombier 		for(j=0; j<nelem(options); j++)
16494de34a7eSDavid du Colombier 			if(strcmp(opt, options[j].name) == 0){
16504de34a7eSDavid du Colombier 				options[j].parse(&cd, cb->f[i+1]);
16514de34a7eSDavid du Colombier 				break;
16524de34a7eSDavid du Colombier 			}
16534de34a7eSDavid du Colombier 		if(j == nelem(options))
16544de34a7eSDavid du Colombier 			error(Ebadarg);
16554de34a7eSDavid du Colombier 	}
1656479935bcSDavid du Colombier 	/* this has been rewritten to accomodate sdaoe */
1657479935bcSDavid du Colombier 	if(cd.on < 0 || cd.spec == 0)
16584de34a7eSDavid du Colombier 		error(Ebadarg);
1659479935bcSDavid du Colombier 	if(cd.on && cd.cf.type == nil)
16604de34a7eSDavid du Colombier 		error(Ebadarg);
16614de34a7eSDavid du Colombier 	sdconfig(cd.on, cd.spec, &cd.cf);
16624de34a7eSDavid du Colombier }
1663