xref: /plan9-contrib/sys/src/9/port/devsd.c (revision 5a0d9eb88ca55781e08c555cdd7c85653de80b34)
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);
4864e3613abSDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "#%C",
4874e3613abSDavid 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);
5354e3613abSDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "#%C",
5364e3613abSDavid 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]){
967fef25afaSDavid du Colombier 	case ScmdRead:
968fef25afaSDavid du Colombier 	case ScmdWrite:
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 	 */
987fef25afaSDavid du Colombier 	if((cmd[1]>>5) && cmd[0] != ScmdInq)
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 
994fef25afaSDavid du Colombier 	case ScmdTur:		/* test unit ready */
9954de34a7eSDavid du Colombier 		return sdsetsense(r, SDok, 0, 0, 0);
9964de34a7eSDavid du Colombier 
997fef25afaSDavid du Colombier 	case ScmdRsense:	/* 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 
1008fef25afaSDavid du Colombier 	case ScmdInq:		/* 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 
1019fef25afaSDavid du Colombier 	case ScmdStart:		/* 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 
1025fef25afaSDavid du Colombier 	case ScmdRcapacity:	/* 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 
1048fef25afaSDavid du Colombier 	case ScmdRcapacity16:	/* 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 
1074fef25afaSDavid du Colombier 	case ScmdMsense10:	/* mode sense */
10754de34a7eSDavid du Colombier 		return sdmodesense(r, cmd, info, ilen);
10764de34a7eSDavid du Colombier 
1077fef25afaSDavid du Colombier 	case ScmdExtread:
1078fef25afaSDavid du Colombier 	case ScmdExtwrite:
1079fef25afaSDavid du Colombier 	case ScmdRead16:
1080fef25afaSDavid du Colombier 	case ScmdWrite16:
10814de34a7eSDavid du Colombier 		return SDnostatus;
10824de34a7eSDavid du Colombier 	}
10834de34a7eSDavid du Colombier }
10844de34a7eSDavid du Colombier 
1085*5a0d9eb8SDavid du Colombier int
sdfakescsirw(SDreq * r,uvlong * llba,int * nsec,int * rwp)1086*5a0d9eb8SDavid du Colombier sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp)
1087*5a0d9eb8SDavid du Colombier {
1088*5a0d9eb8SDavid du Colombier 	uchar *c;
1089*5a0d9eb8SDavid du Colombier 	int rw, count;
1090*5a0d9eb8SDavid du Colombier 	uvlong lba;
1091*5a0d9eb8SDavid du Colombier 
1092*5a0d9eb8SDavid du Colombier 	c = r->cmd;
1093*5a0d9eb8SDavid du Colombier 	rw = 0;
1094*5a0d9eb8SDavid du Colombier 	if((c[0] & 0xf) == 0xa)
1095*5a0d9eb8SDavid du Colombier 		rw = 1;
1096*5a0d9eb8SDavid du Colombier 	switch(c[0]){
1097*5a0d9eb8SDavid du Colombier 	case 0x08:	/* read6 */
1098*5a0d9eb8SDavid du Colombier 	case 0x0a:
1099*5a0d9eb8SDavid du Colombier 		lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3];
1100*5a0d9eb8SDavid du Colombier 		count = c[4];
1101*5a0d9eb8SDavid du Colombier 		break;
1102*5a0d9eb8SDavid du Colombier 	case 0x28:	/* read10 */
1103*5a0d9eb8SDavid du Colombier 	case 0x2a:
1104*5a0d9eb8SDavid du Colombier 		lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1105*5a0d9eb8SDavid du Colombier 		count = c[7]<<8 | c[8];
1106*5a0d9eb8SDavid du Colombier 		break;
1107*5a0d9eb8SDavid du Colombier 	case 0xa8:	/* read12 */
1108*5a0d9eb8SDavid du Colombier 	case 0xaa:
1109*5a0d9eb8SDavid du Colombier 		lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1110*5a0d9eb8SDavid du Colombier 		count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1111*5a0d9eb8SDavid du Colombier 		break;
1112*5a0d9eb8SDavid du Colombier 	case 0x88:	/* read16 */
1113*5a0d9eb8SDavid du Colombier 	case 0x8a:
1114*5a0d9eb8SDavid du Colombier 		/* ata commands only go to 48-bit lba */
1115*5a0d9eb8SDavid du Colombier 		if(c[2] || c[3])
1116*5a0d9eb8SDavid du Colombier 			return sdsetsense(r, SDcheck, 3, 0xc, 2);
1117*5a0d9eb8SDavid du Colombier 		lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32;
1118*5a0d9eb8SDavid du Colombier 		lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1119*5a0d9eb8SDavid du Colombier 		count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13];
1120*5a0d9eb8SDavid du Colombier 		break;
1121*5a0d9eb8SDavid du Colombier 	default:
1122*5a0d9eb8SDavid du Colombier 		print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]);
1123*5a0d9eb8SDavid du Colombier 		r->status  = sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1124*5a0d9eb8SDavid du Colombier 		return SDcheck;
1125*5a0d9eb8SDavid du Colombier 	}
1126*5a0d9eb8SDavid du Colombier 	if(r->data == nil)
1127*5a0d9eb8SDavid du Colombier 		return SDok;
1128*5a0d9eb8SDavid du Colombier 	if(r->dlen < count * r->unit->secsize)
1129*5a0d9eb8SDavid du Colombier 		count = r->dlen/r->unit->secsize;
1130*5a0d9eb8SDavid du Colombier 	if(rwp)
1131*5a0d9eb8SDavid du Colombier 		*rwp = rw;
1132*5a0d9eb8SDavid du Colombier 	*llba = lba;
1133*5a0d9eb8SDavid du Colombier 	*nsec = count;
1134*5a0d9eb8SDavid du Colombier 	return SDnostatus;
1135*5a0d9eb8SDavid du Colombier }
1136*5a0d9eb8SDavid du Colombier 
11377dd7cddfSDavid du Colombier static long
sdread(Chan * c,void * a,long n,vlong off)11387dd7cddfSDavid du Colombier sdread(Chan *c, void *a, long n, vlong off)
11397dd7cddfSDavid du Colombier {
11409a747e4fSDavid du Colombier 	char *p, *e, *buf;
11417dd7cddfSDavid du Colombier 	SDpart *pp;
11427dd7cddfSDavid du Colombier 	SDunit *unit;
11439a747e4fSDavid du Colombier 	SDev *sdev;
11447dd7cddfSDavid du Colombier 	ulong offset;
11454de34a7eSDavid du Colombier 	int i, l, m, status;
11467dd7cddfSDavid du Colombier 
11477dd7cddfSDavid du Colombier 	offset = off;
11487dd7cddfSDavid du Colombier 	switch(TYPE(c->qid)){
11497dd7cddfSDavid du Colombier 	default:
11507dd7cddfSDavid du Colombier 		error(Eperm);
11514de34a7eSDavid du Colombier 	case Qtopctl:
11524de34a7eSDavid du Colombier 		m = 64*1024;	/* room for register dumps */
11534de34a7eSDavid du Colombier 		p = buf = malloc(m);
1154aa72973aSDavid du Colombier 		if(p == nil)
1155aa72973aSDavid du Colombier 			error(Enomem);
11564de34a7eSDavid du Colombier 		e = p + m;
11579a747e4fSDavid du Colombier 		qlock(&devslock);
11584de34a7eSDavid du Colombier 		for(i = 0; i < nelem(devs); i++){
11594de34a7eSDavid du Colombier 			sdev = devs[i];
11604de34a7eSDavid du Colombier 			if(sdev && sdev->ifc->rtopctl)
11614de34a7eSDavid du Colombier 				p = sdev->ifc->rtopctl(sdev, p, e);
11629a747e4fSDavid du Colombier 		}
11639a747e4fSDavid du Colombier 		qunlock(&devslock);
11649a747e4fSDavid du Colombier 		n = readstr(off, a, n, buf);
11659a747e4fSDavid du Colombier 		free(buf);
11669a747e4fSDavid du Colombier 		return n;
11679a747e4fSDavid du Colombier 
11687dd7cddfSDavid du Colombier 	case Qtopdir:
11697dd7cddfSDavid du Colombier 	case Qunitdir:
11707dd7cddfSDavid du Colombier 		return devdirread(c, a, n, 0, 0, sdgen);
11719a747e4fSDavid du Colombier 
11727dd7cddfSDavid du Colombier 	case Qctl:
11739a747e4fSDavid du Colombier 		sdev = sdgetdev(DEV(c->qid));
11749a747e4fSDavid du Colombier 		if(sdev == nil)
11759a747e4fSDavid du Colombier 			error(Enonexist);
11769a747e4fSDavid du Colombier 
11779a747e4fSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
11784de34a7eSDavid du Colombier 		m = 16*1024;	/* room for register dumps */
11794de34a7eSDavid du Colombier 		p = malloc(m);
1180aa72973aSDavid du Colombier 		if(p == nil)
1181aa72973aSDavid du Colombier 			error(Enomem);
11824de34a7eSDavid du Colombier 		l = snprint(p, m, "inquiry %.48s\n",
11837dd7cddfSDavid du Colombier 			(char*)unit->inquiry+8);
11847dd7cddfSDavid du Colombier 		qlock(&unit->ctl);
11857dd7cddfSDavid du Colombier 		/*
11867dd7cddfSDavid du Colombier 		 * If there's a device specific routine it must
11877dd7cddfSDavid du Colombier 		 * provide all information pertaining to night geometry
11887dd7cddfSDavid du Colombier 		 * and the garscadden trains.
11897dd7cddfSDavid du Colombier 		 */
11907dd7cddfSDavid du Colombier 		if(unit->dev->ifc->rctl)
11914de34a7eSDavid du Colombier 			l += unit->dev->ifc->rctl(unit, p+l, m-l);
1192223a736eSDavid du Colombier 		if(unit->sectors == 0)
1193223a736eSDavid du Colombier 			sdinitpart(unit);
1194223a736eSDavid du Colombier 		if(unit->sectors){
11957dd7cddfSDavid du Colombier 			if(unit->dev->ifc->rctl == nil)
11964de34a7eSDavid du Colombier 				l += snprint(p+l, m-l,
119717629263SDavid du Colombier 					"geometry %llud %lud\n",
11987dd7cddfSDavid du Colombier 					unit->sectors, unit->secsize);
11997dd7cddfSDavid du Colombier 			pp = unit->part;
120059cc4ca5SDavid du Colombier 			for(i = 0; i < unit->npart; i++){
12017dd7cddfSDavid du Colombier 				if(pp->valid)
12024de34a7eSDavid du Colombier 					l += snprint(p+l, m-l,
120317629263SDavid du Colombier 						"part %s %llud %llud\n",
12049a747e4fSDavid du Colombier 						pp->name, pp->start, pp->end);
12057dd7cddfSDavid du Colombier 				pp++;
12067dd7cddfSDavid du Colombier 			}
12077dd7cddfSDavid du Colombier 		}
12087dd7cddfSDavid du Colombier 		qunlock(&unit->ctl);
12099a747e4fSDavid du Colombier 		decref(&sdev->r);
12107dd7cddfSDavid du Colombier 		l = readstr(offset, a, n, p);
12117dd7cddfSDavid du Colombier 		free(p);
12127dd7cddfSDavid du Colombier 		return l;
12139a747e4fSDavid du Colombier 
12147dd7cddfSDavid du Colombier 	case Qraw:
12159a747e4fSDavid du Colombier 		sdev = sdgetdev(DEV(c->qid));
12169a747e4fSDavid du Colombier 		if(sdev == nil)
12179a747e4fSDavid du Colombier 			error(Enonexist);
12189a747e4fSDavid du Colombier 
12199a747e4fSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
122080ee5cbfSDavid du Colombier 		qlock(&unit->raw);
122180ee5cbfSDavid du Colombier 		if(waserror()){
122280ee5cbfSDavid du Colombier 			qunlock(&unit->raw);
12239a747e4fSDavid du Colombier 			decref(&sdev->r);
122480ee5cbfSDavid du Colombier 			nexterror();
122580ee5cbfSDavid du Colombier 		}
12267dd7cddfSDavid du Colombier 		if(unit->state == Rawdata){
12277dd7cddfSDavid du Colombier 			unit->state = Rawstatus;
122880ee5cbfSDavid du Colombier 			i = sdrio(unit->req, a, n);
12297dd7cddfSDavid du Colombier 		}
12307dd7cddfSDavid du Colombier 		else if(unit->state == Rawstatus){
12317dd7cddfSDavid du Colombier 			status = unit->req->status;
12327dd7cddfSDavid du Colombier 			unit->state = Rawcmd;
12337dd7cddfSDavid du Colombier 			free(unit->req);
12347dd7cddfSDavid du Colombier 			unit->req = nil;
123580ee5cbfSDavid du Colombier 			i = readnum(0, a, n, status, NUMSIZE);
123680ee5cbfSDavid du Colombier 		} else
123780ee5cbfSDavid du Colombier 			i = 0;
123880ee5cbfSDavid du Colombier 		qunlock(&unit->raw);
12399a747e4fSDavid du Colombier 		decref(&sdev->r);
124080ee5cbfSDavid du Colombier 		poperror();
124180ee5cbfSDavid du Colombier 		return i;
12429a747e4fSDavid du Colombier 
12437dd7cddfSDavid du Colombier 	case Qpart:
12447dd7cddfSDavid du Colombier 		return sdbio(c, 0, a, n, off);
12457dd7cddfSDavid du Colombier 	}
12467dd7cddfSDavid du Colombier }
12477dd7cddfSDavid du Colombier 
12484de34a7eSDavid du Colombier static void legacytopctl(Cmdbuf*);
12499a747e4fSDavid du Colombier 
12507dd7cddfSDavid du Colombier static long
sdwrite(Chan * c,void * a,long n,vlong off)12517dd7cddfSDavid du Colombier sdwrite(Chan* c, void* a, long n, vlong off)
12527dd7cddfSDavid du Colombier {
12534de34a7eSDavid du Colombier 	char *f0;
12544de34a7eSDavid du Colombier 	int i;
125517629263SDavid du Colombier 	uvlong end, start;
12567dd7cddfSDavid du Colombier 	Cmdbuf *cb;
12574de34a7eSDavid du Colombier 	SDifc *ifc;
12587dd7cddfSDavid du Colombier 	SDreq *req;
12597dd7cddfSDavid du Colombier 	SDunit *unit;
12609a747e4fSDavid du Colombier 	SDev *sdev;
12617dd7cddfSDavid du Colombier 
12627dd7cddfSDavid du Colombier 	switch(TYPE(c->qid)){
12637dd7cddfSDavid du Colombier 	default:
12647dd7cddfSDavid du Colombier 		error(Eperm);
12654de34a7eSDavid du Colombier 	case Qtopctl:
12664de34a7eSDavid du Colombier 		cb = parsecmd(a, n);
12674de34a7eSDavid du Colombier 		if(waserror()){
12684de34a7eSDavid du Colombier 			free(cb);
12694de34a7eSDavid du Colombier 			nexterror();
12709a747e4fSDavid du Colombier 		}
12714de34a7eSDavid du Colombier 		if(cb->nf == 0)
12724de34a7eSDavid du Colombier 			error("empty control message");
12734de34a7eSDavid du Colombier 		f0 = cb->f[0];
12744de34a7eSDavid du Colombier 		cb->f++;
12754de34a7eSDavid du Colombier 		cb->nf--;
12764de34a7eSDavid du Colombier 		if(strcmp(f0, "config") == 0){
12774de34a7eSDavid du Colombier 			/* wormhole into ugly legacy interface */
12784de34a7eSDavid du Colombier 			legacytopctl(cb);
12794de34a7eSDavid du Colombier 			poperror();
12804de34a7eSDavid du Colombier 			free(cb);
12819a747e4fSDavid du Colombier 			break;
12829a747e4fSDavid du Colombier 		}
1283d649fdd7SDavid du Colombier 		/*
1284d649fdd7SDavid du Colombier 		 * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
1285d649fdd7SDavid du Colombier 		 * where sdifc[i]->name=="ata" and cb contains the args.
1286d649fdd7SDavid du Colombier 		 */
12874de34a7eSDavid du Colombier 		ifc = nil;
12884de34a7eSDavid du Colombier 		sdev = nil;
12894de34a7eSDavid du Colombier 		for(i=0; sdifc[i]; i++){
12904de34a7eSDavid du Colombier 			if(strcmp(sdifc[i]->name, f0) == 0){
12914de34a7eSDavid du Colombier 				ifc = sdifc[i];
12924de34a7eSDavid du Colombier 				sdev = nil;
12934de34a7eSDavid du Colombier 				goto subtopctl;
12944de34a7eSDavid du Colombier 			}
12954de34a7eSDavid du Colombier 		}
1296d649fdd7SDavid du Colombier 		/*
1297d649fdd7SDavid du Colombier 		 * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
1298d649fdd7SDavid du Colombier 		 * where sdifc[i] and sdev match controller letter "1",
1299d649fdd7SDavid du Colombier 		 * and cb contains the args.
1300d649fdd7SDavid du Colombier 		 */
13014de34a7eSDavid du Colombier 		if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
13024de34a7eSDavid du Colombier 			if((sdev = sdgetdev(f0[2])) != nil){
13034de34a7eSDavid du Colombier 				ifc = sdev->ifc;
13044de34a7eSDavid du Colombier 				goto subtopctl;
13054de34a7eSDavid du Colombier 			}
13064de34a7eSDavid du Colombier 		}
13074de34a7eSDavid du Colombier 		error("unknown interface");
13084de34a7eSDavid du Colombier 
13094de34a7eSDavid du Colombier 	subtopctl:
13104de34a7eSDavid du Colombier 		if(waserror()){
13114de34a7eSDavid du Colombier 			if(sdev)
13124de34a7eSDavid du Colombier 				decref(&sdev->r);
13134de34a7eSDavid du Colombier 			nexterror();
13144de34a7eSDavid du Colombier 		}
13154de34a7eSDavid du Colombier 		if(ifc->wtopctl)
13164de34a7eSDavid du Colombier 			ifc->wtopctl(sdev, cb);
13174de34a7eSDavid du Colombier 		else
13184de34a7eSDavid du Colombier 			error(Ebadctl);
13194de34a7eSDavid du Colombier 		poperror();
13204de34a7eSDavid du Colombier 		poperror();
13219e8a50a9SDavid du Colombier 		if (sdev)
13224de34a7eSDavid du Colombier 			decref(&sdev->r);
13234de34a7eSDavid du Colombier 		free(cb);
13244de34a7eSDavid du Colombier 		break;
13254de34a7eSDavid du Colombier 
13267dd7cddfSDavid du Colombier 	case Qctl:
13277dd7cddfSDavid du Colombier 		cb = parsecmd(a, n);
13289a747e4fSDavid du Colombier 		sdev = sdgetdev(DEV(c->qid));
13299a747e4fSDavid du Colombier 		if(sdev == nil)
13309a747e4fSDavid du Colombier 			error(Enonexist);
13319a747e4fSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
13327dd7cddfSDavid du Colombier 
13337dd7cddfSDavid du Colombier 		qlock(&unit->ctl);
13347dd7cddfSDavid du Colombier 		if(waserror()){
13357dd7cddfSDavid du Colombier 			qunlock(&unit->ctl);
13369a747e4fSDavid du Colombier 			decref(&sdev->r);
13377dd7cddfSDavid du Colombier 			free(cb);
13387dd7cddfSDavid du Colombier 			nexterror();
13397dd7cddfSDavid du Colombier 		}
1340223a736eSDavid du Colombier 		if(unit->vers != c->qid.vers)
13414de34a7eSDavid du Colombier 			error(Echange);
13427dd7cddfSDavid du Colombier 
13437dd7cddfSDavid du Colombier 		if(cb->nf < 1)
13447dd7cddfSDavid du Colombier 			error(Ebadctl);
13457dd7cddfSDavid du Colombier 		if(strcmp(cb->f[0], "part") == 0){
1346223a736eSDavid du Colombier 			if(cb->nf != 4)
13477dd7cddfSDavid du Colombier 				error(Ebadctl);
13487dd7cddfSDavid du Colombier 			if(unit->sectors == 0 && !sdinitpart(unit))
13497dd7cddfSDavid du Colombier 				error(Eio);
135017629263SDavid du Colombier 			start = strtoull(cb->f[2], 0, 0);
135117629263SDavid du Colombier 			end = strtoull(cb->f[3], 0, 0);
13527dd7cddfSDavid du Colombier 			sdaddpart(unit, cb->f[1], start, end);
13537dd7cddfSDavid du Colombier 		}
13547dd7cddfSDavid du Colombier 		else if(strcmp(cb->f[0], "delpart") == 0){
13557dd7cddfSDavid du Colombier 			if(cb->nf != 2 || unit->part == nil)
13567dd7cddfSDavid du Colombier 				error(Ebadctl);
13577dd7cddfSDavid du Colombier 			sddelpart(unit, cb->f[1]);
13587dd7cddfSDavid du Colombier 		}
13597dd7cddfSDavid du Colombier 		else if(unit->dev->ifc->wctl)
13607dd7cddfSDavid du Colombier 			unit->dev->ifc->wctl(unit, cb);
13617dd7cddfSDavid du Colombier 		else
13627dd7cddfSDavid du Colombier 			error(Ebadctl);
13637dd7cddfSDavid du Colombier 		qunlock(&unit->ctl);
13649a747e4fSDavid du Colombier 		decref(&sdev->r);
13657dd7cddfSDavid du Colombier 		poperror();
13667dd7cddfSDavid du Colombier 		free(cb);
13677dd7cddfSDavid du Colombier 		break;
13687dd7cddfSDavid du Colombier 
13697dd7cddfSDavid du Colombier 	case Qraw:
13709a747e4fSDavid du Colombier 		sdev = sdgetdev(DEV(c->qid));
13719a747e4fSDavid du Colombier 		if(sdev == nil)
13729a747e4fSDavid du Colombier 			error(Enonexist);
13739a747e4fSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
137480ee5cbfSDavid du Colombier 		qlock(&unit->raw);
137580ee5cbfSDavid du Colombier 		if(waserror()){
137680ee5cbfSDavid du Colombier 			qunlock(&unit->raw);
13779a747e4fSDavid du Colombier 			decref(&sdev->r);
137880ee5cbfSDavid du Colombier 			nexterror();
137980ee5cbfSDavid du Colombier 		}
13807dd7cddfSDavid du Colombier 		switch(unit->state){
13817dd7cddfSDavid du Colombier 		case Rawcmd:
13827dd7cddfSDavid du Colombier 			if(n < 6 || n > sizeof(req->cmd))
13837dd7cddfSDavid du Colombier 				error(Ebadarg);
13847dd7cddfSDavid du Colombier 			if((req = malloc(sizeof(SDreq))) == nil)
13857dd7cddfSDavid du Colombier 				error(Enomem);
13867dd7cddfSDavid du Colombier 			req->unit = unit;
13877dd7cddfSDavid du Colombier 			memmove(req->cmd, a, n);
13887dd7cddfSDavid du Colombier 			req->clen = n;
13897dd7cddfSDavid du Colombier 			req->flags = SDnosense;
13907dd7cddfSDavid du Colombier 			req->status = ~0;
13917dd7cddfSDavid du Colombier 
13927dd7cddfSDavid du Colombier 			unit->req = req;
13937dd7cddfSDavid du Colombier 			unit->state = Rawdata;
13947dd7cddfSDavid du Colombier 			break;
13957dd7cddfSDavid du Colombier 
13967dd7cddfSDavid du Colombier 		case Rawstatus:
13977dd7cddfSDavid du Colombier 			unit->state = Rawcmd;
13987dd7cddfSDavid du Colombier 			free(unit->req);
13997dd7cddfSDavid du Colombier 			unit->req = nil;
14007dd7cddfSDavid du Colombier 			error(Ebadusefd);
14017dd7cddfSDavid du Colombier 
14027dd7cddfSDavid du Colombier 		case Rawdata:
14037dd7cddfSDavid du Colombier 			unit->state = Rawstatus;
14047dd7cddfSDavid du Colombier 			unit->req->write = 1;
140580ee5cbfSDavid du Colombier 			n = sdrio(unit->req, a, n);
14067dd7cddfSDavid du Colombier 		}
140780ee5cbfSDavid du Colombier 		qunlock(&unit->raw);
14089a747e4fSDavid du Colombier 		decref(&sdev->r);
140980ee5cbfSDavid du Colombier 		poperror();
14109a747e4fSDavid du Colombier 		break;
14117dd7cddfSDavid du Colombier 	case Qpart:
14127dd7cddfSDavid du Colombier 		return sdbio(c, 1, a, n, off);
14137dd7cddfSDavid du Colombier 	}
14147dd7cddfSDavid du Colombier 
14157dd7cddfSDavid du Colombier 	return n;
14167dd7cddfSDavid du Colombier }
14177dd7cddfSDavid du Colombier 
14189a747e4fSDavid du Colombier static int
sdwstat(Chan * c,uchar * dp,int n)14199a747e4fSDavid du Colombier sdwstat(Chan* c, uchar* dp, int n)
14207dd7cddfSDavid du Colombier {
14219a747e4fSDavid du Colombier 	Dir *d;
14227dd7cddfSDavid du Colombier 	SDpart *pp;
142359cc4ca5SDavid du Colombier 	SDperm *perm;
14247dd7cddfSDavid du Colombier 	SDunit *unit;
14259a747e4fSDavid du Colombier 	SDev *sdev;
14267dd7cddfSDavid du Colombier 
14279a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
14287dd7cddfSDavid du Colombier 		error(Eperm);
14297dd7cddfSDavid du Colombier 
14309a747e4fSDavid du Colombier 	sdev = sdgetdev(DEV(c->qid));
14319a747e4fSDavid du Colombier 	if(sdev == nil)
14329a747e4fSDavid du Colombier 		error(Enonexist);
14339a747e4fSDavid du Colombier 	unit = sdev->unit[UNIT(c->qid)];
14347dd7cddfSDavid du Colombier 	qlock(&unit->ctl);
14359a747e4fSDavid du Colombier 	d = nil;
14367dd7cddfSDavid du Colombier 	if(waserror()){
14379a747e4fSDavid du Colombier 		free(d);
14387dd7cddfSDavid du Colombier 		qunlock(&unit->ctl);
14399a747e4fSDavid du Colombier 		decref(&sdev->r);
14407dd7cddfSDavid du Colombier 		nexterror();
14417dd7cddfSDavid du Colombier 	}
14427dd7cddfSDavid du Colombier 
144359cc4ca5SDavid du Colombier 	switch(TYPE(c->qid)){
144459cc4ca5SDavid du Colombier 	default:
144559cc4ca5SDavid du Colombier 		error(Eperm);
144659cc4ca5SDavid du Colombier 	case Qctl:
144759cc4ca5SDavid du Colombier 		perm = &unit->ctlperm;
144859cc4ca5SDavid du Colombier 		break;
144959cc4ca5SDavid du Colombier 	case Qraw:
145059cc4ca5SDavid du Colombier 		perm = &unit->rawperm;
145159cc4ca5SDavid du Colombier 		break;
145259cc4ca5SDavid du Colombier 	case Qpart:
14537dd7cddfSDavid du Colombier 		pp = &unit->part[PART(c->qid)];
1454223a736eSDavid du Colombier 		if(unit->vers+pp->vers != c->qid.vers)
14557dd7cddfSDavid du Colombier 			error(Enonexist);
145659cc4ca5SDavid du Colombier 		perm = &pp->SDperm;
145759cc4ca5SDavid du Colombier 		break;
145859cc4ca5SDavid du Colombier 	}
14597dd7cddfSDavid du Colombier 
14609a747e4fSDavid du Colombier 	if(strcmp(up->user, perm->user) && !iseve())
146159cc4ca5SDavid du Colombier 		error(Eperm);
14627dd7cddfSDavid du Colombier 
14639a747e4fSDavid du Colombier 	d = smalloc(sizeof(Dir)+n);
14649a747e4fSDavid du Colombier 	n = convM2D(dp, n, &d[0], (char*)&d[1]);
14659a747e4fSDavid du Colombier 	if(n == 0)
14669a747e4fSDavid du Colombier 		error(Eshortstat);
14679a747e4fSDavid du Colombier 	if(!emptystr(d[0].uid))
14689a747e4fSDavid du Colombier 		kstrdup(&perm->user, d[0].uid);
14699a747e4fSDavid du Colombier 	if(d[0].mode != ~0UL)
14709a747e4fSDavid du Colombier 		perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
14719a747e4fSDavid du Colombier 
14729a747e4fSDavid du Colombier 	free(d);
14737dd7cddfSDavid du Colombier 	qunlock(&unit->ctl);
14749a747e4fSDavid du Colombier 	decref(&sdev->r);
14757dd7cddfSDavid du Colombier 	poperror();
14769a747e4fSDavid du Colombier 	return n;
14779a747e4fSDavid du Colombier }
14789a747e4fSDavid du Colombier 
14799a747e4fSDavid du Colombier static int
configure(char * spec,DevConf * cf)14809a747e4fSDavid du Colombier configure(char* spec, DevConf* cf)
14819a747e4fSDavid du Colombier {
14824de34a7eSDavid du Colombier 	SDev *s, *sdev;
14834de34a7eSDavid du Colombier 	char *p;
14844de34a7eSDavid du Colombier 	int i;
14854de34a7eSDavid du Colombier 
14864de34a7eSDavid du Colombier 	if(sdindex(*spec) < 0)
14874de34a7eSDavid du Colombier 		error("bad sd spec");
14889a747e4fSDavid du Colombier 
14899a747e4fSDavid du Colombier 	if((p = strchr(cf->type, '/')) != nil)
14909a747e4fSDavid du Colombier 		*p++ = '\0';
14919a747e4fSDavid du Colombier 
14929a747e4fSDavid du Colombier 	for(i = 0; sdifc[i] != nil; i++)
14934de34a7eSDavid du Colombier 		if(strcmp(sdifc[i]->name, cf->type) == 0)
14949a747e4fSDavid du Colombier 			break;
14959a747e4fSDavid du Colombier 	if(sdifc[i] == nil)
14964de34a7eSDavid du Colombier 		error("sd type not found");
14974de34a7eSDavid du Colombier 	if(p)
14984de34a7eSDavid du Colombier 		*(p-1) = '/';
14999a747e4fSDavid du Colombier 
15004de34a7eSDavid du Colombier 	if(sdifc[i]->probe == nil)
15014de34a7eSDavid du Colombier 		error("sd type cannot probe");
15029a747e4fSDavid du Colombier 
15034de34a7eSDavid du Colombier 	sdev = sdifc[i]->probe(cf);
15044de34a7eSDavid du Colombier 	for(s=sdev; s; s=s->next)
15054de34a7eSDavid du Colombier 		s->idno = *spec;
15064de34a7eSDavid du Colombier 	sdadddevs(sdev);
15079a747e4fSDavid du Colombier 	return 0;
15089a747e4fSDavid du Colombier }
15099a747e4fSDavid du Colombier 
15109a747e4fSDavid du Colombier static int
unconfigure(char * spec)15119a747e4fSDavid du Colombier unconfigure(char* spec)
15129a747e4fSDavid du Colombier {
15139a747e4fSDavid du Colombier 	int i;
15149a747e4fSDavid du Colombier 	SDev *sdev;
15154de34a7eSDavid du Colombier 	SDunit *unit;
15169a747e4fSDavid du Colombier 
15174de34a7eSDavid du Colombier 	if((i = sdindex(*spec)) < 0)
15189a747e4fSDavid du Colombier 		error(Enonexist);
15199a747e4fSDavid du Colombier 
15204de34a7eSDavid du Colombier 	qlock(&devslock);
15214de34a7eSDavid du Colombier 	if((sdev = devs[i]) == nil){
15224de34a7eSDavid du Colombier 		qunlock(&devslock);
15234de34a7eSDavid du Colombier 		error(Enonexist);
15244de34a7eSDavid du Colombier 	}
15254de34a7eSDavid du Colombier 	if(sdev->r.ref){
15264de34a7eSDavid du Colombier 		qunlock(&devslock);
15279a747e4fSDavid du Colombier 		error(Einuse);
15284de34a7eSDavid du Colombier 	}
15294de34a7eSDavid du Colombier 	devs[i] = nil;
15304de34a7eSDavid du Colombier 	qunlock(&devslock);
15319a747e4fSDavid du Colombier 
15329a747e4fSDavid du Colombier 	/* make sure no interrupts arrive anymore before removing resources */
15339a747e4fSDavid du Colombier 	if(sdev->enabled && sdev->ifc->disable)
15349a747e4fSDavid du Colombier 		sdev->ifc->disable(sdev);
15359a747e4fSDavid du Colombier 
15364de34a7eSDavid du Colombier 	for(i = 0; i != sdev->nunit; i++){
15374de34a7eSDavid du Colombier 		if(unit = sdev->unit[i]){
15389a747e4fSDavid du Colombier 			free(unit->name);
15399a747e4fSDavid du Colombier 			free(unit->user);
15409a747e4fSDavid du Colombier 			free(unit);
15419a747e4fSDavid du Colombier 		}
15424de34a7eSDavid du Colombier 	}
15439a747e4fSDavid du Colombier 
15449a747e4fSDavid du Colombier 	if(sdev->ifc->clear)
15459a747e4fSDavid du Colombier 		sdev->ifc->clear(sdev);
15464de34a7eSDavid du Colombier 	free(sdev);
15479a747e4fSDavid du Colombier 	return 0;
15489a747e4fSDavid du Colombier }
15499a747e4fSDavid du Colombier 
15509a747e4fSDavid du Colombier static int
sdconfig(int on,char * spec,DevConf * cf)15519a747e4fSDavid du Colombier sdconfig(int on, char* spec, DevConf* cf)
15529a747e4fSDavid du Colombier {
15539a747e4fSDavid du Colombier 	if(on)
15549a747e4fSDavid du Colombier 		return configure(spec, cf);
15559a747e4fSDavid du Colombier 	return unconfigure(spec);
15567dd7cddfSDavid du Colombier }
15577dd7cddfSDavid du Colombier 
15587dd7cddfSDavid du Colombier Dev sddevtab = {
15597dd7cddfSDavid du Colombier 	'S',
15607dd7cddfSDavid du Colombier 	"sd",
15617dd7cddfSDavid du Colombier 
15627dd7cddfSDavid du Colombier 	sdreset,
15637dd7cddfSDavid du Colombier 	devinit,
15649a747e4fSDavid du Colombier 	devshutdown,
15657dd7cddfSDavid du Colombier 	sdattach,
15667dd7cddfSDavid du Colombier 	sdwalk,
15677dd7cddfSDavid du Colombier 	sdstat,
15687dd7cddfSDavid du Colombier 	sdopen,
15697dd7cddfSDavid du Colombier 	devcreate,
15707dd7cddfSDavid du Colombier 	sdclose,
15717dd7cddfSDavid du Colombier 	sdread,
15727dd7cddfSDavid du Colombier 	devbread,
15737dd7cddfSDavid du Colombier 	sdwrite,
15747dd7cddfSDavid du Colombier 	devbwrite,
15757dd7cddfSDavid du Colombier 	devremove,
15767dd7cddfSDavid du Colombier 	sdwstat,
15779a747e4fSDavid du Colombier 	devpower,
1578aa72973aSDavid du Colombier 	sdconfig,	/* probe; only called for pcmcia-like devices */
15797dd7cddfSDavid du Colombier };
15804de34a7eSDavid du Colombier 
15814de34a7eSDavid du Colombier /*
15824de34a7eSDavid du Colombier  * This is wrong for so many reasons.  This code must go.
15834de34a7eSDavid du Colombier  */
15844de34a7eSDavid du Colombier typedef struct Confdata Confdata;
15854de34a7eSDavid du Colombier struct Confdata {
15864de34a7eSDavid du Colombier 	int	on;
15874de34a7eSDavid du Colombier 	char*	spec;
15884de34a7eSDavid du Colombier 	DevConf	cf;
15894de34a7eSDavid du Colombier };
15904de34a7eSDavid du Colombier 
15914de34a7eSDavid du Colombier static void
parseswitch(Confdata * cd,char * option)15924de34a7eSDavid du Colombier parseswitch(Confdata* cd, char* option)
15934de34a7eSDavid du Colombier {
15944de34a7eSDavid du Colombier 	if(!strcmp("on", option))
15954de34a7eSDavid du Colombier 		cd->on = 1;
15964de34a7eSDavid du Colombier 	else if(!strcmp("off", option))
15974de34a7eSDavid du Colombier 		cd->on = 0;
15984de34a7eSDavid du Colombier 	else
15994de34a7eSDavid du Colombier 		error(Ebadarg);
16004de34a7eSDavid du Colombier }
16014de34a7eSDavid du Colombier 
16024de34a7eSDavid du Colombier static void
parsespec(Confdata * cd,char * option)16034de34a7eSDavid du Colombier parsespec(Confdata* cd, char* option)
16044de34a7eSDavid du Colombier {
16054de34a7eSDavid du Colombier 	if(strlen(option) > 1)
16064de34a7eSDavid du Colombier 		error(Ebadarg);
16074de34a7eSDavid du Colombier 	cd->spec = option;
16084de34a7eSDavid du Colombier }
16094de34a7eSDavid du Colombier 
16104de34a7eSDavid du Colombier static Devport*
getnewport(DevConf * dc)16114de34a7eSDavid du Colombier getnewport(DevConf* dc)
16124de34a7eSDavid du Colombier {
16134de34a7eSDavid du Colombier 	Devport *p;
16144de34a7eSDavid du Colombier 
16154de34a7eSDavid du Colombier 	p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
1616aa72973aSDavid du Colombier 	if(p == nil)
1617aa72973aSDavid du Colombier 		error(Enomem);
16184de34a7eSDavid du Colombier 	if(dc->nports > 0){
16194de34a7eSDavid du Colombier 		memmove(p, dc->ports, dc->nports * sizeof(Devport));
16204de34a7eSDavid du Colombier 		free(dc->ports);
16214de34a7eSDavid du Colombier 	}
16224de34a7eSDavid du Colombier 	dc->ports = p;
16234de34a7eSDavid du Colombier 	p = &dc->ports[dc->nports++];
16244de34a7eSDavid du Colombier 	p->size = -1;
16254de34a7eSDavid du Colombier 	p->port = (ulong)-1;
16264de34a7eSDavid du Colombier 	return p;
16274de34a7eSDavid du Colombier }
16284de34a7eSDavid du Colombier 
16294de34a7eSDavid du Colombier static void
parseport(Confdata * cd,char * option)16304de34a7eSDavid du Colombier parseport(Confdata* cd, char* option)
16314de34a7eSDavid du Colombier {
16324de34a7eSDavid du Colombier 	char *e;
16334de34a7eSDavid du Colombier 	Devport *p;
16344de34a7eSDavid du Colombier 
16354de34a7eSDavid du Colombier 	if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
16364de34a7eSDavid du Colombier 		p = getnewport(&cd->cf);
16374de34a7eSDavid du Colombier 	else
16384de34a7eSDavid du Colombier 		p = &cd->cf.ports[cd->cf.nports-1];
16394de34a7eSDavid du Colombier 	p->port = strtol(option, &e, 0);
16404de34a7eSDavid du Colombier 	if(e == nil || *e != '\0')
16414de34a7eSDavid du Colombier 		error(Ebadarg);
16424de34a7eSDavid du Colombier }
16434de34a7eSDavid du Colombier 
16444de34a7eSDavid du Colombier static void
parsesize(Confdata * cd,char * option)16454de34a7eSDavid du Colombier parsesize(Confdata* cd, char* option)
16464de34a7eSDavid du Colombier {
16474de34a7eSDavid du Colombier 	char *e;
16484de34a7eSDavid du Colombier 	Devport *p;
16494de34a7eSDavid du Colombier 
16504de34a7eSDavid du Colombier 	if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
16514de34a7eSDavid du Colombier 		p = getnewport(&cd->cf);
16524de34a7eSDavid du Colombier 	else
16534de34a7eSDavid du Colombier 		p = &cd->cf.ports[cd->cf.nports-1];
16544de34a7eSDavid du Colombier 	p->size = (int)strtol(option, &e, 0);
16554de34a7eSDavid du Colombier 	if(e == nil || *e != '\0')
16564de34a7eSDavid du Colombier 		error(Ebadarg);
16574de34a7eSDavid du Colombier }
16584de34a7eSDavid du Colombier 
16594de34a7eSDavid du Colombier static void
parseirq(Confdata * cd,char * option)16604de34a7eSDavid du Colombier parseirq(Confdata* cd, char* option)
16614de34a7eSDavid du Colombier {
16624de34a7eSDavid du Colombier 	char *e;
16634de34a7eSDavid du Colombier 
16644de34a7eSDavid du Colombier 	cd->cf.intnum = strtoul(option, &e, 0);
16654de34a7eSDavid du Colombier 	if(e == nil || *e != '\0')
16664de34a7eSDavid du Colombier 		error(Ebadarg);
16674de34a7eSDavid du Colombier }
16684de34a7eSDavid du Colombier 
16694de34a7eSDavid du Colombier static void
parsetype(Confdata * cd,char * option)16704de34a7eSDavid du Colombier parsetype(Confdata* cd, char* option)
16714de34a7eSDavid du Colombier {
16724de34a7eSDavid du Colombier 	cd->cf.type = option;
16734de34a7eSDavid du Colombier }
16744de34a7eSDavid du Colombier 
16754de34a7eSDavid du Colombier static struct {
16764de34a7eSDavid du Colombier 	char	*name;
16774de34a7eSDavid du Colombier 	void	(*parse)(Confdata*, char*);
16784de34a7eSDavid du Colombier } options[] = {
16794de34a7eSDavid du Colombier 	"switch",	parseswitch,
16804de34a7eSDavid du Colombier 	"spec",		parsespec,
16814de34a7eSDavid du Colombier 	"port",		parseport,
16824de34a7eSDavid du Colombier 	"size",		parsesize,
16834de34a7eSDavid du Colombier 	"irq",		parseirq,
16844de34a7eSDavid du Colombier 	"type",		parsetype,
16854de34a7eSDavid du Colombier };
16864de34a7eSDavid du Colombier 
16874de34a7eSDavid du Colombier static void
legacytopctl(Cmdbuf * cb)16884de34a7eSDavid du Colombier legacytopctl(Cmdbuf *cb)
16894de34a7eSDavid du Colombier {
16904de34a7eSDavid du Colombier 	char *opt;
16914de34a7eSDavid du Colombier 	int i, j;
16924de34a7eSDavid du Colombier 	Confdata cd;
16934de34a7eSDavid du Colombier 
16944de34a7eSDavid du Colombier 	memset(&cd, 0, sizeof cd);
16954de34a7eSDavid du Colombier 	cd.on = -1;
16964de34a7eSDavid du Colombier 	for(i=0; i<cb->nf; i+=2){
16974de34a7eSDavid du Colombier 		if(i+2 > cb->nf)
16984de34a7eSDavid du Colombier 			error(Ebadarg);
16994de34a7eSDavid du Colombier 		opt = cb->f[i];
17004de34a7eSDavid du Colombier 		for(j=0; j<nelem(options); j++)
17014de34a7eSDavid du Colombier 			if(strcmp(opt, options[j].name) == 0){
17024de34a7eSDavid du Colombier 				options[j].parse(&cd, cb->f[i+1]);
17034de34a7eSDavid du Colombier 				break;
17044de34a7eSDavid du Colombier 			}
17054de34a7eSDavid du Colombier 		if(j == nelem(options))
17064de34a7eSDavid du Colombier 			error(Ebadarg);
17074de34a7eSDavid du Colombier 	}
1708479935bcSDavid du Colombier 	/* this has been rewritten to accomodate sdaoe */
1709479935bcSDavid du Colombier 	if(cd.on < 0 || cd.spec == 0)
17104de34a7eSDavid du Colombier 		error(Ebadarg);
1711479935bcSDavid du Colombier 	if(cd.on && cd.cf.type == nil)
17124de34a7eSDavid du Colombier 		error(Ebadarg);
17134de34a7eSDavid du Colombier 	sdconfig(cd.on, cd.spec, &cd.cf);
17144de34a7eSDavid du Colombier }
1715