xref: /plan9-contrib/sys/src/9k/port/devsd.c (revision 465c1891ace366afe151a1d40ae292dba51c74ad)
19ef1f84bSDavid du Colombier /*
29ef1f84bSDavid du Colombier  * Storage Device.
39ef1f84bSDavid du Colombier  */
49ef1f84bSDavid du Colombier #include "u.h"
59ef1f84bSDavid du Colombier #include "../port/lib.h"
69ef1f84bSDavid du Colombier #include "mem.h"
79ef1f84bSDavid du Colombier #include "dat.h"
89ef1f84bSDavid du Colombier #include "fns.h"
99ef1f84bSDavid du Colombier #include "io.h"
109ef1f84bSDavid du Colombier #include "ureg.h"
119ef1f84bSDavid du Colombier #include "../port/error.h"
129ef1f84bSDavid du Colombier 
139ef1f84bSDavid du Colombier #include "../port/sd.h"
149ef1f84bSDavid du Colombier 
159ef1f84bSDavid du Colombier extern Dev sddevtab;
169ef1f84bSDavid du Colombier extern SDifc* sdifc[];
179ef1f84bSDavid du Colombier 
189ef1f84bSDavid du Colombier static char devletters[] = "0123456789"
199ef1f84bSDavid du Colombier 	"abcdefghijklmnopqrstuvwxyz"
209ef1f84bSDavid du Colombier 	"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
219ef1f84bSDavid du Colombier 
229ef1f84bSDavid du Colombier static SDev *devs[sizeof devletters-1];
239ef1f84bSDavid du Colombier static QLock devslock;
249ef1f84bSDavid du Colombier 
259ef1f84bSDavid du Colombier enum {
269ef1f84bSDavid du Colombier 	Rawcmd,
279ef1f84bSDavid du Colombier 	Rawdata,
289ef1f84bSDavid du Colombier 	Rawstatus,
299ef1f84bSDavid du Colombier };
309ef1f84bSDavid du Colombier 
319ef1f84bSDavid du Colombier enum {
329ef1f84bSDavid du Colombier 	Qtopdir		= 1,		/* top level directory */
339ef1f84bSDavid du Colombier 	Qtopbase,
349ef1f84bSDavid du Colombier 	Qtopctl		 = Qtopbase,
359ef1f84bSDavid du Colombier 
369ef1f84bSDavid du Colombier 	Qunitdir,			/* directory per unit */
379ef1f84bSDavid du Colombier 	Qunitbase,
389ef1f84bSDavid du Colombier 	Qctl		= Qunitbase,
399ef1f84bSDavid du Colombier 	Qraw,
409ef1f84bSDavid du Colombier 	Qpart,
419ef1f84bSDavid du Colombier 
429ef1f84bSDavid du Colombier 	TypeLOG		= 4,
439ef1f84bSDavid du Colombier 	NType		= (1<<TypeLOG),
449ef1f84bSDavid du Colombier 	TypeMASK	= (NType-1),
459ef1f84bSDavid du Colombier 	TypeSHIFT	= 0,
469ef1f84bSDavid du Colombier 
479ef1f84bSDavid du Colombier 	PartLOG		= 8,
489ef1f84bSDavid du Colombier 	NPart		= (1<<PartLOG),
499ef1f84bSDavid du Colombier 	PartMASK	= (NPart-1),
509ef1f84bSDavid du Colombier 	PartSHIFT	= TypeLOG,
519ef1f84bSDavid du Colombier 
529ef1f84bSDavid du Colombier 	UnitLOG		= 8,
539ef1f84bSDavid du Colombier 	NUnit		= (1<<UnitLOG),
549ef1f84bSDavid du Colombier 	UnitMASK	= (NUnit-1),
559ef1f84bSDavid du Colombier 	UnitSHIFT	= (PartLOG+TypeLOG),
569ef1f84bSDavid du Colombier 
579ef1f84bSDavid du Colombier 	DevLOG		= 8,
589ef1f84bSDavid du Colombier 	NDev		= (1 << DevLOG),
599ef1f84bSDavid du Colombier 	DevMASK		= (NDev-1),
609ef1f84bSDavid du Colombier 	DevSHIFT	 = (UnitLOG+PartLOG+TypeLOG),
619ef1f84bSDavid du Colombier 
629ef1f84bSDavid du Colombier 	Ncmd = 20,
639ef1f84bSDavid du Colombier };
649ef1f84bSDavid du Colombier 
659ef1f84bSDavid du Colombier #define TYPE(q)		((((ulong)(q).path)>>TypeSHIFT) & TypeMASK)
669ef1f84bSDavid du Colombier #define PART(q)		((((ulong)(q).path)>>PartSHIFT) & PartMASK)
679ef1f84bSDavid du Colombier #define UNIT(q)		((((ulong)(q).path)>>UnitSHIFT) & UnitMASK)
689ef1f84bSDavid du Colombier #define DEV(q)		((((ulong)(q).path)>>DevSHIFT) & DevMASK)
699ef1f84bSDavid du Colombier #define QID(d,u, p, t)	(((d)<<DevSHIFT)|((u)<<UnitSHIFT)|\
709ef1f84bSDavid du Colombier 					 ((p)<<PartSHIFT)|((t)<<TypeSHIFT))
719ef1f84bSDavid du Colombier 
729ef1f84bSDavid du Colombier 
739ef1f84bSDavid du Colombier void
sdaddpart(SDunit * unit,char * name,uvlong start,uvlong end)749ef1f84bSDavid du Colombier sdaddpart(SDunit* unit, char* name, uvlong start, uvlong end)
759ef1f84bSDavid du Colombier {
769ef1f84bSDavid du Colombier 	SDpart *pp;
779ef1f84bSDavid du Colombier 	int i, partno;
789ef1f84bSDavid du Colombier 
799ef1f84bSDavid du Colombier 	/*
809ef1f84bSDavid du Colombier 	 * Check name not already used
819ef1f84bSDavid du Colombier 	 * and look for a free slot.
829ef1f84bSDavid du Colombier 	 */
839ef1f84bSDavid du Colombier 	if(unit->part != nil){
849ef1f84bSDavid du Colombier 		partno = -1;
859ef1f84bSDavid du Colombier 		for(i = 0; i < unit->npart; i++){
869ef1f84bSDavid du Colombier 			pp = &unit->part[i];
879ef1f84bSDavid du Colombier 			if(!pp->valid){
889ef1f84bSDavid du Colombier 				if(partno == -1)
899ef1f84bSDavid du Colombier 					partno = i;
909ef1f84bSDavid du Colombier 				break;
919ef1f84bSDavid du Colombier 			}
929ef1f84bSDavid du Colombier 			if(strcmp(name, pp->name) == 0){
939ef1f84bSDavid du Colombier 				if(pp->start == start && pp->end == end)
949ef1f84bSDavid du Colombier 					return;
959ef1f84bSDavid du Colombier 				error(Ebadctl);
969ef1f84bSDavid du Colombier 			}
979ef1f84bSDavid du Colombier 		}
989ef1f84bSDavid du Colombier 	}
999ef1f84bSDavid du Colombier 	else{
1009ef1f84bSDavid du Colombier 		if((unit->part = malloc(sizeof(SDpart)*SDnpart)) == nil)
1019ef1f84bSDavid du Colombier 			error(Enomem);
1029ef1f84bSDavid du Colombier 		unit->npart = SDnpart;
1039ef1f84bSDavid du Colombier 		partno = 0;
1049ef1f84bSDavid du Colombier 	}
1059ef1f84bSDavid du Colombier 
1069ef1f84bSDavid du Colombier 	/*
1079ef1f84bSDavid du Colombier 	 * If no free slot found then increase the
1089ef1f84bSDavid du Colombier 	 * array size (can't get here with unit->part == nil).
1099ef1f84bSDavid du Colombier 	 */
1109ef1f84bSDavid du Colombier 	if(partno == -1){
1119ef1f84bSDavid du Colombier 		if(unit->npart >= NPart)
1129ef1f84bSDavid du Colombier 			error(Enomem);
1139ef1f84bSDavid du Colombier 		if((pp = malloc(sizeof(SDpart)*(unit->npart+SDnpart))) == nil)
1149ef1f84bSDavid du Colombier 			error(Enomem);
1159ef1f84bSDavid du Colombier 		memmove(pp, unit->part, sizeof(SDpart)*unit->npart);
1169ef1f84bSDavid du Colombier 		free(unit->part);
1179ef1f84bSDavid du Colombier 		unit->part = pp;
1189ef1f84bSDavid du Colombier 		partno = unit->npart;
1199ef1f84bSDavid du Colombier 		unit->npart += SDnpart;
1209ef1f84bSDavid du Colombier 	}
1219ef1f84bSDavid du Colombier 
1229ef1f84bSDavid du Colombier 	/*
1239ef1f84bSDavid du Colombier 	 * Check size and extent are valid.
1249ef1f84bSDavid du Colombier 	 */
1259ef1f84bSDavid du Colombier 	if(start > end || end > unit->sectors)
1269ef1f84bSDavid du Colombier 		error(Eio);
1279ef1f84bSDavid du Colombier 	pp = &unit->part[partno];
1289ef1f84bSDavid du Colombier 	pp->start = start;
1299ef1f84bSDavid du Colombier 	pp->end = end;
1309ef1f84bSDavid du Colombier 	kstrdup(&pp->name, name);
1319ef1f84bSDavid du Colombier 	kstrdup(&pp->user, eve);
1329ef1f84bSDavid du Colombier 	pp->perm = 0640;
1339ef1f84bSDavid du Colombier 	pp->valid = 1;
1349ef1f84bSDavid du Colombier }
1359ef1f84bSDavid du Colombier 
1369ef1f84bSDavid du Colombier static void
sddelpart(SDunit * unit,char * name)1379ef1f84bSDavid du Colombier sddelpart(SDunit* unit, char* name)
1389ef1f84bSDavid du Colombier {
1399ef1f84bSDavid du Colombier 	int i;
1409ef1f84bSDavid du Colombier 	SDpart *pp;
1419ef1f84bSDavid du Colombier 
1429ef1f84bSDavid du Colombier 	/*
1439ef1f84bSDavid du Colombier 	 * Look for the partition to delete.
1449ef1f84bSDavid du Colombier 	 * Can't delete if someone still has it open.
1459ef1f84bSDavid du Colombier 	 */
1469ef1f84bSDavid du Colombier 	pp = unit->part;
1479ef1f84bSDavid du Colombier 	for(i = 0; i < unit->npart; i++){
1489ef1f84bSDavid du Colombier 		if(strcmp(name, pp->name) == 0)
1499ef1f84bSDavid du Colombier 			break;
1509ef1f84bSDavid du Colombier 		pp++;
1519ef1f84bSDavid du Colombier 	}
1529ef1f84bSDavid du Colombier 	if(i >= unit->npart)
1539ef1f84bSDavid du Colombier 		error(Ebadctl);
1549ef1f84bSDavid du Colombier 	if(strcmp(up->user, pp->user) && !iseve())
1559ef1f84bSDavid du Colombier 		error(Eperm);
1569ef1f84bSDavid du Colombier 	pp->valid = 0;
1579ef1f84bSDavid du Colombier 	pp->vers++;
1589ef1f84bSDavid du Colombier }
1599ef1f84bSDavid du Colombier 
1609ef1f84bSDavid du Colombier static void
sdincvers(SDunit * unit)1619ef1f84bSDavid du Colombier sdincvers(SDunit *unit)
1629ef1f84bSDavid du Colombier {
1639ef1f84bSDavid du Colombier 	int i;
1649ef1f84bSDavid du Colombier 
1659ef1f84bSDavid du Colombier 	unit->vers++;
1669ef1f84bSDavid du Colombier 	if(unit->part){
1679ef1f84bSDavid du Colombier 		for(i = 0; i < unit->npart; i++){
1689ef1f84bSDavid du Colombier 			unit->part[i].valid = 0;
1699ef1f84bSDavid du Colombier 			unit->part[i].vers++;
1709ef1f84bSDavid du Colombier 		}
1719ef1f84bSDavid du Colombier 	}
1729ef1f84bSDavid du Colombier }
1739ef1f84bSDavid du Colombier 
1749ef1f84bSDavid du Colombier static int
sdinitpart(SDunit * unit)1759ef1f84bSDavid du Colombier sdinitpart(SDunit* unit)
1769ef1f84bSDavid du Colombier {
1779ef1f84bSDavid du Colombier 	int nf;
1789ef1f84bSDavid du Colombier 	uvlong start, end;
1799ef1f84bSDavid du Colombier 	char *f[4], *p, *q, buf[10];
1809ef1f84bSDavid du Colombier 
1819ef1f84bSDavid du Colombier 	if(unit->sectors > 0){
1829ef1f84bSDavid du Colombier 		unit->sectors = unit->secsize = 0;
1839ef1f84bSDavid du Colombier 		sdincvers(unit);
1849ef1f84bSDavid du Colombier 	}
1859ef1f84bSDavid du Colombier 
1869ef1f84bSDavid du Colombier 	/* device must be connected or not; other values are trouble */
1879ef1f84bSDavid du Colombier 	if(unit->inquiry[0] & 0xC0)	/* see SDinq0periphqual */
1889ef1f84bSDavid du Colombier 		return 0;
1899ef1f84bSDavid du Colombier 	switch(unit->inquiry[0] & SDinq0periphtype){
1909ef1f84bSDavid du Colombier 	case SDperdisk:
1919ef1f84bSDavid du Colombier 	case SDperworm:
1929ef1f84bSDavid du Colombier 	case SDpercd:
1939ef1f84bSDavid du Colombier 	case SDpermo:
1949ef1f84bSDavid du Colombier 		break;
1959ef1f84bSDavid du Colombier 	default:
1969ef1f84bSDavid du Colombier 		return 0;
1979ef1f84bSDavid du Colombier 	}
1989ef1f84bSDavid du Colombier 
1999ef1f84bSDavid du Colombier 	if(unit->dev->ifc->online)
2009ef1f84bSDavid du Colombier 		unit->dev->ifc->online(unit);
2019ef1f84bSDavid du Colombier 	if(unit->sectors){
2029ef1f84bSDavid du Colombier 		sdincvers(unit);
2039ef1f84bSDavid du Colombier 		sdaddpart(unit, "data", 0, unit->sectors);
2049ef1f84bSDavid du Colombier 
2059ef1f84bSDavid du Colombier 		/*
2069ef1f84bSDavid du Colombier 		 * Use partitions passed from boot program,
2079ef1f84bSDavid du Colombier 		 * e.g.
2089ef1f84bSDavid du Colombier 		 *	sdC0part=dos 63 123123/plan9 123123 456456
2099ef1f84bSDavid du Colombier 		 * This happens before /boot sets hostname so the
2109ef1f84bSDavid du Colombier 		 * partitions will have the null-string for user.
2119ef1f84bSDavid du Colombier 		 * The gen functions patch it up.
2129ef1f84bSDavid du Colombier 		 */
2139ef1f84bSDavid du Colombier 		snprint(buf, sizeof buf, "%spart", unit->name);
2149ef1f84bSDavid du Colombier 		for(p = getconf(buf); p != nil; p = q){
2159ef1f84bSDavid du Colombier 			if(q = strchr(p, '/'))
2169ef1f84bSDavid du Colombier 				*q++ = '\0';
2179ef1f84bSDavid du Colombier 			nf = tokenize(p, f, nelem(f));
2189ef1f84bSDavid du Colombier 			if(nf < 3)
2199ef1f84bSDavid du Colombier 				continue;
2209ef1f84bSDavid du Colombier 
2219ef1f84bSDavid du Colombier 			start = strtoull(f[1], 0, 0);
2229ef1f84bSDavid du Colombier 			end = strtoull(f[2], 0, 0);
2239ef1f84bSDavid du Colombier 			if(!waserror()){
2249ef1f84bSDavid du Colombier 				sdaddpart(unit, f[0], start, end);
2259ef1f84bSDavid du Colombier 				poperror();
2269ef1f84bSDavid du Colombier 			}
2279ef1f84bSDavid du Colombier 		}
2289ef1f84bSDavid du Colombier 	}
2299ef1f84bSDavid du Colombier 
2309ef1f84bSDavid du Colombier 	return 1;
2319ef1f84bSDavid du Colombier }
2329ef1f84bSDavid du Colombier 
2339ef1f84bSDavid du Colombier static int
sdindex(int idno)2349ef1f84bSDavid du Colombier sdindex(int idno)
2359ef1f84bSDavid du Colombier {
2369ef1f84bSDavid du Colombier 	char *p;
2379ef1f84bSDavid du Colombier 
2389ef1f84bSDavid du Colombier 	p = strchr(devletters, idno);
2399ef1f84bSDavid du Colombier 	if(p == nil)
2409ef1f84bSDavid du Colombier 		return -1;
2419ef1f84bSDavid du Colombier 	return p-devletters;
2429ef1f84bSDavid du Colombier }
2439ef1f84bSDavid du Colombier 
2449ef1f84bSDavid du Colombier static SDev*
sdgetdev(int idno)2459ef1f84bSDavid du Colombier sdgetdev(int idno)
2469ef1f84bSDavid du Colombier {
2479ef1f84bSDavid du Colombier 	SDev *sdev;
2489ef1f84bSDavid du Colombier 	int i;
2499ef1f84bSDavid du Colombier 
2509ef1f84bSDavid du Colombier 	if((i = sdindex(idno)) < 0)
2519ef1f84bSDavid du Colombier 		return nil;
2529ef1f84bSDavid du Colombier 
2539ef1f84bSDavid du Colombier 	qlock(&devslock);
2549ef1f84bSDavid du Colombier 	if(sdev = devs[i])
2559ef1f84bSDavid du Colombier 		incref(&sdev->r);
2569ef1f84bSDavid du Colombier 	qunlock(&devslock);
2579ef1f84bSDavid du Colombier 	return sdev;
2589ef1f84bSDavid du Colombier }
2599ef1f84bSDavid du Colombier 
2609ef1f84bSDavid du Colombier static SDunit*
sdgetunit(SDev * sdev,int subno)2619ef1f84bSDavid du Colombier sdgetunit(SDev* sdev, int subno)
2629ef1f84bSDavid du Colombier {
2639ef1f84bSDavid du Colombier 	SDunit *unit;
2649ef1f84bSDavid du Colombier 	char buf[32];
2659ef1f84bSDavid du Colombier 
2669ef1f84bSDavid du Colombier 	/*
2679ef1f84bSDavid du Colombier 	 * Associate a unit with a given device and sub-unit
2689ef1f84bSDavid du Colombier 	 * number on that device.
2699ef1f84bSDavid du Colombier 	 * The device will be probed if it has not already been
2709ef1f84bSDavid du Colombier 	 * successfully accessed.
2719ef1f84bSDavid du Colombier 	 */
2729ef1f84bSDavid du Colombier 	qlock(&sdev->unitlock);
2739ef1f84bSDavid du Colombier 	if(subno > sdev->nunit){
2749ef1f84bSDavid du Colombier 		qunlock(&sdev->unitlock);
2759ef1f84bSDavid du Colombier 		return nil;
2769ef1f84bSDavid du Colombier 	}
2779ef1f84bSDavid du Colombier 
2789ef1f84bSDavid du Colombier 	unit = sdev->unit[subno];
2799ef1f84bSDavid du Colombier 	if(unit == nil){
2809ef1f84bSDavid du Colombier 		/*
2819ef1f84bSDavid du Colombier 		 * Probe the unit only once. This decision
2829ef1f84bSDavid du Colombier 		 * may be a little severe and reviewed later.
2839ef1f84bSDavid du Colombier 		 */
2849ef1f84bSDavid du Colombier 		if(sdev->unitflg[subno]){
2859ef1f84bSDavid du Colombier 			qunlock(&sdev->unitlock);
2869ef1f84bSDavid du Colombier 			return nil;
2879ef1f84bSDavid du Colombier 		}
2889ef1f84bSDavid du Colombier 		if((unit = malloc(sizeof(SDunit))) == nil){
2899ef1f84bSDavid du Colombier 			qunlock(&sdev->unitlock);
2909ef1f84bSDavid du Colombier 			return nil;
2919ef1f84bSDavid du Colombier 		}
2929ef1f84bSDavid du Colombier 		sdev->unitflg[subno] = 1;
2939ef1f84bSDavid du Colombier 
2949ef1f84bSDavid du Colombier 		snprint(buf, sizeof(buf), "%s%d", sdev->name, subno);
2959ef1f84bSDavid du Colombier 		kstrdup(&unit->name, buf);
2969ef1f84bSDavid du Colombier 		kstrdup(&unit->user, eve);
2979ef1f84bSDavid du Colombier 		unit->perm = 0555;
2989ef1f84bSDavid du Colombier 		unit->subno = subno;
2999ef1f84bSDavid du Colombier 		unit->dev = sdev;
3009ef1f84bSDavid du Colombier 
3019ef1f84bSDavid du Colombier 		if(sdev->enabled == 0 && sdev->ifc->enable)
3029ef1f84bSDavid du Colombier 			sdev->ifc->enable(sdev);
3039ef1f84bSDavid du Colombier 		sdev->enabled = 1;
3049ef1f84bSDavid du Colombier 
3059ef1f84bSDavid du Colombier 		/*
3069ef1f84bSDavid du Colombier 		 * No need to lock anything here as this is only
3079ef1f84bSDavid du Colombier 		 * called before the unit is made available in the
3089ef1f84bSDavid du Colombier 		 * sdunit[] array.
3099ef1f84bSDavid du Colombier 		 */
3109ef1f84bSDavid du Colombier 		if(unit->dev->ifc->verify(unit) == 0){
3119ef1f84bSDavid du Colombier 			qunlock(&sdev->unitlock);
3129ef1f84bSDavid du Colombier 			free(unit);
3139ef1f84bSDavid du Colombier 			return nil;
3149ef1f84bSDavid du Colombier 		}
3159ef1f84bSDavid du Colombier 		sdev->unit[subno] = unit;
3169ef1f84bSDavid du Colombier 	}
3179ef1f84bSDavid du Colombier 	qunlock(&sdev->unitlock);
3189ef1f84bSDavid du Colombier 	return unit;
3199ef1f84bSDavid du Colombier }
3209ef1f84bSDavid du Colombier 
3219ef1f84bSDavid du Colombier static void
sdreset(void)3229ef1f84bSDavid du Colombier sdreset(void)
3239ef1f84bSDavid du Colombier {
3249ef1f84bSDavid du Colombier 	int i;
3259ef1f84bSDavid du Colombier 	SDev *sdev;
3269ef1f84bSDavid du Colombier 
3279ef1f84bSDavid du Colombier 	/*
3289ef1f84bSDavid du Colombier 	 * Probe all known controller types and register any devices found.
3299ef1f84bSDavid du Colombier 	 */
3309ef1f84bSDavid du Colombier 	for(i = 0; sdifc[i] != nil; i++){
3319ef1f84bSDavid du Colombier 		if(sdifc[i]->pnp == nil || (sdev = sdifc[i]->pnp()) == nil)
3329ef1f84bSDavid du Colombier 			continue;
3339ef1f84bSDavid du Colombier 		sdadddevs(sdev);
3349ef1f84bSDavid du Colombier 	}
3359ef1f84bSDavid du Colombier }
3369ef1f84bSDavid du Colombier 
3379ef1f84bSDavid du Colombier void
sdadddevs(SDev * sdev)3389ef1f84bSDavid du Colombier sdadddevs(SDev *sdev)
3399ef1f84bSDavid du Colombier {
3409ef1f84bSDavid du Colombier 	int i, j, id;
3419ef1f84bSDavid du Colombier 	SDev *next;
3429ef1f84bSDavid du Colombier 
3439ef1f84bSDavid du Colombier 	for(; sdev; sdev=next){
3449ef1f84bSDavid du Colombier 		next = sdev->next;
3459ef1f84bSDavid du Colombier 
3469ef1f84bSDavid du Colombier 		sdev->unit = (SDunit**)malloc(sdev->nunit * sizeof(SDunit*));
3479ef1f84bSDavid du Colombier 		sdev->unitflg = (int*)malloc(sdev->nunit * sizeof(int));
3489ef1f84bSDavid du Colombier 		if(sdev->unit == nil || sdev->unitflg == nil){
3499ef1f84bSDavid du Colombier 			print("sdadddevs: out of memory\n");
3509ef1f84bSDavid du Colombier 		giveup:
3519ef1f84bSDavid du Colombier 			free(sdev->unit);
3529ef1f84bSDavid du Colombier 			free(sdev->unitflg);
3539ef1f84bSDavid du Colombier 			if(sdev->ifc->clear)
3549ef1f84bSDavid du Colombier 				sdev->ifc->clear(sdev);
3559ef1f84bSDavid du Colombier 			free(sdev);
3569ef1f84bSDavid du Colombier 			continue;
3579ef1f84bSDavid du Colombier 		}
3589ef1f84bSDavid du Colombier 		id = sdindex(sdev->idno);
3599ef1f84bSDavid du Colombier 		if(id == -1){
3609ef1f84bSDavid du Colombier 			print("sdadddevs: bad id number %d (%C)\n", id, id);
3619ef1f84bSDavid du Colombier 			goto giveup;
3629ef1f84bSDavid du Colombier 		}
3639ef1f84bSDavid du Colombier 		qlock(&devslock);
3649ef1f84bSDavid du Colombier 		for(i=0; i<nelem(devs); i++){
3659ef1f84bSDavid du Colombier 			if(devs[j = (id+i)%nelem(devs)] == nil){
3669ef1f84bSDavid du Colombier 				sdev->idno = devletters[j];
3679ef1f84bSDavid du Colombier 				devs[j] = sdev;
3689ef1f84bSDavid du Colombier 				snprint(sdev->name, sizeof sdev->name, "sd%c", devletters[j]);
3699ef1f84bSDavid du Colombier 				break;
3709ef1f84bSDavid du Colombier 			}
3719ef1f84bSDavid du Colombier 		}
3729ef1f84bSDavid du Colombier 		qunlock(&devslock);
3739ef1f84bSDavid du Colombier 		if(i == nelem(devs)){
3749ef1f84bSDavid du Colombier 			print("sdadddevs: out of device letters\n");
3759ef1f84bSDavid du Colombier 			goto giveup;
3769ef1f84bSDavid du Colombier 		}
3779ef1f84bSDavid du Colombier 	}
3789ef1f84bSDavid du Colombier }
3799ef1f84bSDavid du Colombier 
3809ef1f84bSDavid du Colombier // void
3819ef1f84bSDavid du Colombier // sdrmdevs(SDev *sdev)
3829ef1f84bSDavid du Colombier // {
3839ef1f84bSDavid du Colombier // 	char buf[2];
3849ef1f84bSDavid du Colombier //
3859ef1f84bSDavid du Colombier // 	snprint(buf, sizeof buf, "%c", sdev->idno);
3869ef1f84bSDavid du Colombier // 	unconfigure(buf);
3879ef1f84bSDavid du Colombier // }
3889ef1f84bSDavid du Colombier 
3899ef1f84bSDavid du Colombier void
sdaddallconfs(void (* addconf)(SDunit *))3909ef1f84bSDavid du Colombier sdaddallconfs(void (*addconf)(SDunit *))
3919ef1f84bSDavid du Colombier {
3929ef1f84bSDavid du Colombier 	int i, u;
3939ef1f84bSDavid du Colombier 	SDev *sdev;
3949ef1f84bSDavid du Colombier 
3959ef1f84bSDavid du Colombier 	for(i = 0; i < nelem(devs); i++)		/* each controller */
3969ef1f84bSDavid du Colombier 		for(sdev = devs[i]; sdev; sdev = sdev->next)
3979ef1f84bSDavid du Colombier 			for(u = 0; u < sdev->nunit; u++)	/* each drive */
3989ef1f84bSDavid du Colombier 				(*addconf)(sdev->unit[u]);
3999ef1f84bSDavid du Colombier }
4009ef1f84bSDavid du Colombier 
4019ef1f84bSDavid du Colombier static int
sd2gen(Chan * c,int i,Dir * dp)4029ef1f84bSDavid du Colombier sd2gen(Chan* c, int i, Dir* dp)
4039ef1f84bSDavid du Colombier {
4049ef1f84bSDavid du Colombier 	Qid q;
4059ef1f84bSDavid du Colombier 	uvlong l;
4069ef1f84bSDavid du Colombier 	SDpart *pp;
4079ef1f84bSDavid du Colombier 	SDperm *perm;
4089ef1f84bSDavid du Colombier 	SDunit *unit;
4099ef1f84bSDavid du Colombier 	SDev *sdev;
4109ef1f84bSDavid du Colombier 	int rv;
4119ef1f84bSDavid du Colombier 
4129ef1f84bSDavid du Colombier 	sdev = sdgetdev(DEV(c->qid));
4139ef1f84bSDavid du Colombier 	assert(sdev);
4149ef1f84bSDavid du Colombier 	unit = sdev->unit[UNIT(c->qid)];
4159ef1f84bSDavid du Colombier 
4169ef1f84bSDavid du Colombier 	rv = -1;
4179ef1f84bSDavid du Colombier 	switch(i){
4189ef1f84bSDavid du Colombier 	case Qctl:
4199ef1f84bSDavid du Colombier 		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qctl),
4209ef1f84bSDavid du Colombier 			unit->vers, QTFILE);
4219ef1f84bSDavid du Colombier 		perm = &unit->ctlperm;
4229ef1f84bSDavid du Colombier 		if(emptystr(perm->user)){
4239ef1f84bSDavid du Colombier 			kstrdup(&perm->user, eve);
4249ef1f84bSDavid du Colombier 			perm->perm = 0644;	/* nothing secret in ctl */
4259ef1f84bSDavid du Colombier 		}
4269ef1f84bSDavid du Colombier 		devdir(c, q, "ctl", 0, perm->user, perm->perm, dp);
4279ef1f84bSDavid du Colombier 		rv = 1;
4289ef1f84bSDavid du Colombier 		break;
4299ef1f84bSDavid du Colombier 
4309ef1f84bSDavid du Colombier 	case Qraw:
4319ef1f84bSDavid du Colombier 		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qraw),
4329ef1f84bSDavid du Colombier 			unit->vers, QTFILE);
4339ef1f84bSDavid du Colombier 		perm = &unit->rawperm;
4349ef1f84bSDavid du Colombier 		if(emptystr(perm->user)){
4359ef1f84bSDavid du Colombier 			kstrdup(&perm->user, eve);
4369ef1f84bSDavid du Colombier 			perm->perm = DMEXCL|0600;
4379ef1f84bSDavid du Colombier 		}
4389ef1f84bSDavid du Colombier 		devdir(c, q, "raw", 0, perm->user, perm->perm, dp);
4399ef1f84bSDavid du Colombier 		rv = 1;
4409ef1f84bSDavid du Colombier 		break;
4419ef1f84bSDavid du Colombier 
4429ef1f84bSDavid du Colombier 	case Qpart:
4439ef1f84bSDavid du Colombier 		pp = &unit->part[PART(c->qid)];
4449ef1f84bSDavid du Colombier 		l = (pp->end - pp->start) * unit->secsize;
4459ef1f84bSDavid du Colombier 		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), PART(c->qid), Qpart),
4469ef1f84bSDavid du Colombier 			unit->vers+pp->vers, QTFILE);
4479ef1f84bSDavid du Colombier 		if(emptystr(pp->user))
4489ef1f84bSDavid du Colombier 			kstrdup(&pp->user, eve);
4499ef1f84bSDavid du Colombier 		devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
4509ef1f84bSDavid du Colombier 		rv = 1;
4519ef1f84bSDavid du Colombier 		break;
4529ef1f84bSDavid du Colombier 	}
4539ef1f84bSDavid du Colombier 
4549ef1f84bSDavid du Colombier 	decref(&sdev->r);
4559ef1f84bSDavid du Colombier 	return rv;
4569ef1f84bSDavid du Colombier }
4579ef1f84bSDavid du Colombier 
4589ef1f84bSDavid du Colombier static int
sd1gen(Chan * c,int i,Dir * dp)4599ef1f84bSDavid du Colombier sd1gen(Chan* c, int i, Dir* dp)
4609ef1f84bSDavid du Colombier {
4619ef1f84bSDavid du Colombier 	Qid q;
4629ef1f84bSDavid du Colombier 
4639ef1f84bSDavid du Colombier 	switch(i){
4649ef1f84bSDavid du Colombier 	case Qtopctl:
4659ef1f84bSDavid du Colombier 		mkqid(&q, QID(0, 0, 0, Qtopctl), 0, QTFILE);
4669ef1f84bSDavid du Colombier 		devdir(c, q, "sdctl", 0, eve, 0644, dp);	/* no secrets */
4679ef1f84bSDavid du Colombier 		return 1;
4689ef1f84bSDavid du Colombier 	}
4699ef1f84bSDavid du Colombier 	return -1;
4709ef1f84bSDavid du Colombier }
4719ef1f84bSDavid du Colombier 
4729ef1f84bSDavid du Colombier static int
sdgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)4739ef1f84bSDavid du Colombier sdgen(Chan* c, char*, Dirtab*, int, int s, Dir* dp)
4749ef1f84bSDavid du Colombier {
4759ef1f84bSDavid du Colombier 	Qid q;
4769ef1f84bSDavid du Colombier 	uvlong l;
4779ef1f84bSDavid du Colombier 	int i, r;
4789ef1f84bSDavid du Colombier 	SDpart *pp;
4799ef1f84bSDavid du Colombier 	SDunit *unit;
4809ef1f84bSDavid du Colombier 	SDev *sdev;
4819ef1f84bSDavid du Colombier 
4829ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)){
4839ef1f84bSDavid du Colombier 	case Qtopdir:
4849ef1f84bSDavid du Colombier 		if(s == DEVDOTDOT){
4859ef1f84bSDavid du Colombier 			mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
486406c76faSDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "#%C",
487406c76faSDavid du Colombier 				sddevtab.dc);
4889ef1f84bSDavid du Colombier 			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
4899ef1f84bSDavid du Colombier 			return 1;
4909ef1f84bSDavid du Colombier 		}
4919ef1f84bSDavid du Colombier 
4929ef1f84bSDavid du Colombier 		if(s+Qtopbase < Qunitdir)
4939ef1f84bSDavid du Colombier 			return sd1gen(c, s+Qtopbase, dp);
4949ef1f84bSDavid du Colombier 		s -= (Qunitdir-Qtopbase);
4959ef1f84bSDavid du Colombier 
4969ef1f84bSDavid du Colombier 		qlock(&devslock);
4979ef1f84bSDavid du Colombier 		for(i=0; i<nelem(devs); i++){
4989ef1f84bSDavid du Colombier 			if(devs[i]){
4999ef1f84bSDavid du Colombier 				if(s < devs[i]->nunit)
5009ef1f84bSDavid du Colombier 					break;
5019ef1f84bSDavid du Colombier 				s -= devs[i]->nunit;
5029ef1f84bSDavid du Colombier 			}
5039ef1f84bSDavid du Colombier 		}
5049ef1f84bSDavid du Colombier 
5059ef1f84bSDavid du Colombier 		if(i == nelem(devs)){
5069ef1f84bSDavid du Colombier 			/* Run off the end of the list */
5079ef1f84bSDavid du Colombier 			qunlock(&devslock);
5089ef1f84bSDavid du Colombier 			return -1;
5099ef1f84bSDavid du Colombier 		}
5109ef1f84bSDavid du Colombier 
5119ef1f84bSDavid du Colombier 		if((sdev = devs[i]) == nil){
5129ef1f84bSDavid du Colombier 			qunlock(&devslock);
5139ef1f84bSDavid du Colombier 			return 0;
5149ef1f84bSDavid du Colombier 		}
5159ef1f84bSDavid du Colombier 
5169ef1f84bSDavid du Colombier 		incref(&sdev->r);
5179ef1f84bSDavid du Colombier 		qunlock(&devslock);
5189ef1f84bSDavid du Colombier 
5199ef1f84bSDavid du Colombier 		if((unit = sdev->unit[s]) == nil)
5209ef1f84bSDavid du Colombier 			if((unit = sdgetunit(sdev, s)) == nil){
5219ef1f84bSDavid du Colombier 				decref(&sdev->r);
5229ef1f84bSDavid du Colombier 				return 0;
5239ef1f84bSDavid du Colombier 			}
5249ef1f84bSDavid du Colombier 
5259ef1f84bSDavid du Colombier 		mkqid(&q, QID(sdev->idno, s, 0, Qunitdir), 0, QTDIR);
5269ef1f84bSDavid du Colombier 		if(emptystr(unit->user))
5279ef1f84bSDavid du Colombier 			kstrdup(&unit->user, eve);
5289ef1f84bSDavid du Colombier 		devdir(c, q, unit->name, 0, unit->user, unit->perm, dp);
5299ef1f84bSDavid du Colombier 		decref(&sdev->r);
5309ef1f84bSDavid du Colombier 		return 1;
5319ef1f84bSDavid du Colombier 
5329ef1f84bSDavid du Colombier 	case Qunitdir:
5339ef1f84bSDavid du Colombier 		if(s == DEVDOTDOT){
5349ef1f84bSDavid du Colombier 			mkqid(&q, QID(0, 0, 0, Qtopdir), 0, QTDIR);
535406c76faSDavid du Colombier 			snprint(up->genbuf, sizeof up->genbuf, "#%C",
536406c76faSDavid du Colombier 				sddevtab.dc);
5379ef1f84bSDavid du Colombier 			devdir(c, q, up->genbuf, 0, eve, 0555, dp);
5389ef1f84bSDavid du Colombier 			return 1;
5399ef1f84bSDavid du Colombier 		}
5409ef1f84bSDavid du Colombier 
5419ef1f84bSDavid du Colombier 		if((sdev = sdgetdev(DEV(c->qid))) == nil){
5429ef1f84bSDavid du Colombier 			devdir(c, c->qid, "unavailable", 0, eve, 0, dp);
5439ef1f84bSDavid du Colombier 			return 1;
5449ef1f84bSDavid du Colombier 		}
5459ef1f84bSDavid du Colombier 
5469ef1f84bSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
5479ef1f84bSDavid du Colombier 		qlock(&unit->ctl);
5489ef1f84bSDavid du Colombier 
5499ef1f84bSDavid du Colombier 		/*
5509ef1f84bSDavid du Colombier 		 * Check for media change.
5519ef1f84bSDavid du Colombier 		 * If one has already been detected, sectors will be zero.
5529ef1f84bSDavid du Colombier 		 * If there is one waiting to be detected, online
5539ef1f84bSDavid du Colombier 		 * will return > 1.
5549ef1f84bSDavid du Colombier 		 * Online is a bit of a large hammer but does the job.
5559ef1f84bSDavid du Colombier 		 */
5569ef1f84bSDavid du Colombier 		if(unit->sectors == 0
5579ef1f84bSDavid du Colombier 		|| (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1))
5589ef1f84bSDavid du Colombier 			sdinitpart(unit);
5599ef1f84bSDavid du Colombier 
5609ef1f84bSDavid du Colombier 		i = s+Qunitbase;
5619ef1f84bSDavid du Colombier 		if(i < Qpart){
5629ef1f84bSDavid du Colombier 			r = sd2gen(c, i, dp);
5639ef1f84bSDavid du Colombier 			qunlock(&unit->ctl);
5649ef1f84bSDavid du Colombier 			decref(&sdev->r);
5659ef1f84bSDavid du Colombier 			return r;
5669ef1f84bSDavid du Colombier 		}
5679ef1f84bSDavid du Colombier 		i -= Qpart;
5689ef1f84bSDavid du Colombier 		if(unit->part == nil || i >= unit->npart){
5699ef1f84bSDavid du Colombier 			qunlock(&unit->ctl);
5709ef1f84bSDavid du Colombier 			decref(&sdev->r);
5719ef1f84bSDavid du Colombier 			break;
5729ef1f84bSDavid du Colombier 		}
5739ef1f84bSDavid du Colombier 		pp = &unit->part[i];
5749ef1f84bSDavid du Colombier 		if(!pp->valid){
5759ef1f84bSDavid du Colombier 			qunlock(&unit->ctl);
5769ef1f84bSDavid du Colombier 			decref(&sdev->r);
5779ef1f84bSDavid du Colombier 			return 0;
5789ef1f84bSDavid du Colombier 		}
5799ef1f84bSDavid du Colombier 		l = (pp->end - pp->start) * unit->secsize;
5809ef1f84bSDavid du Colombier 		mkqid(&q, QID(DEV(c->qid), UNIT(c->qid), i, Qpart),
5819ef1f84bSDavid du Colombier 			unit->vers+pp->vers, QTFILE);
5829ef1f84bSDavid du Colombier 		if(emptystr(pp->user))
5839ef1f84bSDavid du Colombier 			kstrdup(&pp->user, eve);
5849ef1f84bSDavid du Colombier 		devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
5859ef1f84bSDavid du Colombier 		qunlock(&unit->ctl);
5869ef1f84bSDavid du Colombier 		decref(&sdev->r);
5879ef1f84bSDavid du Colombier 		return 1;
5889ef1f84bSDavid du Colombier 	case Qraw:
5899ef1f84bSDavid du Colombier 	case Qctl:
5909ef1f84bSDavid du Colombier 	case Qpart:
5919ef1f84bSDavid du Colombier 		if((sdev = sdgetdev(DEV(c->qid))) == nil){
5929ef1f84bSDavid du Colombier 			devdir(c, q, "unavailable", 0, eve, 0, dp);
5939ef1f84bSDavid du Colombier 			return 1;
5949ef1f84bSDavid du Colombier 		}
5959ef1f84bSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
5969ef1f84bSDavid du Colombier 		qlock(&unit->ctl);
5979ef1f84bSDavid du Colombier 		r = sd2gen(c, TYPE(c->qid), dp);
5989ef1f84bSDavid du Colombier 		qunlock(&unit->ctl);
5999ef1f84bSDavid du Colombier 		decref(&sdev->r);
6009ef1f84bSDavid du Colombier 		return r;
6019ef1f84bSDavid du Colombier 	case Qtopctl:
6029ef1f84bSDavid du Colombier 		return sd1gen(c, TYPE(c->qid), dp);
6039ef1f84bSDavid du Colombier 	default:
6049ef1f84bSDavid du Colombier 		break;
6059ef1f84bSDavid du Colombier 	}
6069ef1f84bSDavid du Colombier 
6079ef1f84bSDavid du Colombier 	return -1;
6089ef1f84bSDavid du Colombier }
6099ef1f84bSDavid du Colombier 
6109ef1f84bSDavid du Colombier static Chan*
sdattach(char * spec)6119ef1f84bSDavid du Colombier sdattach(char* spec)
6129ef1f84bSDavid du Colombier {
6139ef1f84bSDavid du Colombier 	Chan *c;
6149ef1f84bSDavid du Colombier 	char *p;
6159ef1f84bSDavid du Colombier 	SDev *sdev;
6169ef1f84bSDavid du Colombier 	int idno, subno;
6179ef1f84bSDavid du Colombier 
6189ef1f84bSDavid du Colombier 	if(*spec == '\0'){
6199ef1f84bSDavid du Colombier 		c = devattach(sddevtab.dc, spec);
6209ef1f84bSDavid du Colombier 		mkqid(&c->qid, QID(0, 0, 0, Qtopdir), 0, QTDIR);
6219ef1f84bSDavid du Colombier 		return c;
6229ef1f84bSDavid du Colombier 	}
6239ef1f84bSDavid du Colombier 
6249ef1f84bSDavid du Colombier 	if(spec[0] != 's' || spec[1] != 'd')
6259ef1f84bSDavid du Colombier 		error(Ebadspec);
6269ef1f84bSDavid du Colombier 	idno = spec[2];
6279ef1f84bSDavid du Colombier 	subno = strtol(&spec[3], &p, 0);
6289ef1f84bSDavid du Colombier 	if(p == &spec[3])
6299ef1f84bSDavid du Colombier 		error(Ebadspec);
6309ef1f84bSDavid du Colombier 
6319ef1f84bSDavid du Colombier 	if((sdev=sdgetdev(idno)) == nil)
6329ef1f84bSDavid du Colombier 		error(Enonexist);
6339ef1f84bSDavid du Colombier 	if(sdgetunit(sdev, subno) == nil){
6349ef1f84bSDavid du Colombier 		decref(&sdev->r);
6359ef1f84bSDavid du Colombier 		error(Enonexist);
6369ef1f84bSDavid du Colombier 	}
6379ef1f84bSDavid du Colombier 
6389ef1f84bSDavid du Colombier 	c = devattach(sddevtab.dc, spec);
6399ef1f84bSDavid du Colombier 	mkqid(&c->qid, QID(sdev->idno, subno, 0, Qunitdir), 0, QTDIR);
6409ef1f84bSDavid du Colombier 	c->devno = (sdev->idno << UnitLOG) + subno;
6419ef1f84bSDavid du Colombier 	decref(&sdev->r);
6429ef1f84bSDavid du Colombier 	return c;
6439ef1f84bSDavid du Colombier }
6449ef1f84bSDavid du Colombier 
6459ef1f84bSDavid du Colombier static Walkqid*
sdwalk(Chan * c,Chan * nc,char ** name,int nname)6469ef1f84bSDavid du Colombier sdwalk(Chan* c, Chan* nc, char** name, int nname)
6479ef1f84bSDavid du Colombier {
6489ef1f84bSDavid du Colombier 	return devwalk(c, nc, name, nname, nil, 0, sdgen);
6499ef1f84bSDavid du Colombier }
6509ef1f84bSDavid du Colombier 
6519ef1f84bSDavid du Colombier static long
sdstat(Chan * c,uchar * db,long n)6529ef1f84bSDavid du Colombier sdstat(Chan* c, uchar* db, long n)
6539ef1f84bSDavid du Colombier {
6549ef1f84bSDavid du Colombier 	return devstat(c, db, n, nil, 0, sdgen);
6559ef1f84bSDavid du Colombier }
6569ef1f84bSDavid du Colombier 
6579ef1f84bSDavid du Colombier static Chan*
sdopen(Chan * c,int omode)6589ef1f84bSDavid du Colombier sdopen(Chan* c, int omode)
6599ef1f84bSDavid du Colombier {
6609ef1f84bSDavid du Colombier 	SDpart *pp;
6619ef1f84bSDavid du Colombier 	SDunit *unit;
6629ef1f84bSDavid du Colombier 	SDev *sdev;
6639ef1f84bSDavid du Colombier 	uchar tp;
6649ef1f84bSDavid du Colombier 
6659ef1f84bSDavid du Colombier 	c = devopen(c, omode, 0, 0, sdgen);
6669ef1f84bSDavid du Colombier 	if((tp = TYPE(c->qid)) != Qctl && tp != Qraw && tp != Qpart)
6679ef1f84bSDavid du Colombier 		return c;
6689ef1f84bSDavid du Colombier 
6699ef1f84bSDavid du Colombier 	sdev = sdgetdev(DEV(c->qid));
6709ef1f84bSDavid du Colombier 	if(sdev == nil)
6719ef1f84bSDavid du Colombier 		error(Enonexist);
6729ef1f84bSDavid du Colombier 
6739ef1f84bSDavid du Colombier 	unit = sdev->unit[UNIT(c->qid)];
6749ef1f84bSDavid du Colombier 
6759ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)){
6769ef1f84bSDavid du Colombier 	case Qctl:
6779ef1f84bSDavid du Colombier 		c->qid.vers = unit->vers;
6789ef1f84bSDavid du Colombier 		break;
6799ef1f84bSDavid du Colombier 	case Qraw:
6809ef1f84bSDavid du Colombier 		c->qid.vers = unit->vers;
6819ef1f84bSDavid du Colombier 		if(TAS(&unit->rawinuse) != 0){
6829ef1f84bSDavid du Colombier 			c->flag &= ~COPEN;
6839ef1f84bSDavid du Colombier 			decref(&sdev->r);
6849ef1f84bSDavid du Colombier 			error(Einuse);
6859ef1f84bSDavid du Colombier 		}
6869ef1f84bSDavid du Colombier 		unit->state = Rawcmd;
6879ef1f84bSDavid du Colombier 		break;
6889ef1f84bSDavid du Colombier 	case Qpart:
6899ef1f84bSDavid du Colombier 		qlock(&unit->ctl);
6909ef1f84bSDavid du Colombier 		if(waserror()){
6919ef1f84bSDavid du Colombier 			qunlock(&unit->ctl);
6929ef1f84bSDavid du Colombier 			c->flag &= ~COPEN;
6939ef1f84bSDavid du Colombier 			decref(&sdev->r);
6949ef1f84bSDavid du Colombier 			nexterror();
6959ef1f84bSDavid du Colombier 		}
6969ef1f84bSDavid du Colombier 		pp = &unit->part[PART(c->qid)];
6979ef1f84bSDavid du Colombier 		c->qid.vers = unit->vers+pp->vers;
6989ef1f84bSDavid du Colombier 		qunlock(&unit->ctl);
6999ef1f84bSDavid du Colombier 		poperror();
7009ef1f84bSDavid du Colombier 		break;
7019ef1f84bSDavid du Colombier 	}
7029ef1f84bSDavid du Colombier 	decref(&sdev->r);
7039ef1f84bSDavid du Colombier 	return c;
7049ef1f84bSDavid du Colombier }
7059ef1f84bSDavid du Colombier 
7069ef1f84bSDavid du Colombier static void
sdclose(Chan * c)7079ef1f84bSDavid du Colombier sdclose(Chan* c)
7089ef1f84bSDavid du Colombier {
7099ef1f84bSDavid du Colombier 	SDunit *unit;
7109ef1f84bSDavid du Colombier 	SDev *sdev;
7119ef1f84bSDavid du Colombier 
7129ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR)
7139ef1f84bSDavid du Colombier 		return;
7149ef1f84bSDavid du Colombier 	if(!(c->flag & COPEN))
7159ef1f84bSDavid du Colombier 		return;
7169ef1f84bSDavid du Colombier 
7179ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)){
7189ef1f84bSDavid du Colombier 	default:
7199ef1f84bSDavid du Colombier 		break;
7209ef1f84bSDavid du Colombier 	case Qraw:
7219ef1f84bSDavid du Colombier 		sdev = sdgetdev(DEV(c->qid));
7229ef1f84bSDavid du Colombier 		if(sdev){
7239ef1f84bSDavid du Colombier 			unit = sdev->unit[UNIT(c->qid)];
7249ef1f84bSDavid du Colombier 			unit->rawinuse = 0;
7259ef1f84bSDavid du Colombier 			decref(&sdev->r);
7269ef1f84bSDavid du Colombier 		}
7279ef1f84bSDavid du Colombier 		break;
7289ef1f84bSDavid du Colombier 	}
7299ef1f84bSDavid du Colombier }
7309ef1f84bSDavid du Colombier 
7319ef1f84bSDavid du Colombier static long
sdbio(Chan * c,int write,char * a,long len,vlong off)7329ef1f84bSDavid du Colombier sdbio(Chan* c, int write, char* a, long len, vlong off)
7339ef1f84bSDavid du Colombier {
7349ef1f84bSDavid du Colombier 	int nchange;
7359ef1f84bSDavid du Colombier 	uchar *b;
7369ef1f84bSDavid du Colombier 	SDpart *pp;
7379ef1f84bSDavid du Colombier 	SDunit *unit;
7389ef1f84bSDavid du Colombier 	SDev *sdev;
7399ef1f84bSDavid du Colombier 	vlong bno;
7409ef1f84bSDavid du Colombier 	long l, max, nb, offset;
7419ef1f84bSDavid du Colombier 
7429ef1f84bSDavid du Colombier 	sdev = sdgetdev(DEV(c->qid));
7439ef1f84bSDavid du Colombier 	if(sdev == nil){
7449ef1f84bSDavid du Colombier 		decref(&sdev->r);
7459ef1f84bSDavid du Colombier 		error(Enonexist);
7469ef1f84bSDavid du Colombier 	}
7479ef1f84bSDavid du Colombier 	unit = sdev->unit[UNIT(c->qid)];
7489ef1f84bSDavid du Colombier 	if(unit == nil)
7499ef1f84bSDavid du Colombier 		error(Enonexist);
7509ef1f84bSDavid du Colombier 
7519ef1f84bSDavid du Colombier 	nchange = 0;
7529ef1f84bSDavid du Colombier 	qlock(&unit->ctl);
7539ef1f84bSDavid du Colombier 	while(waserror()){
7549ef1f84bSDavid du Colombier 		/* notification of media change; go around again */
7559ef1f84bSDavid du Colombier 		if(strcmp(up->errstr, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){
7569ef1f84bSDavid du Colombier 			sdinitpart(unit);
7579ef1f84bSDavid du Colombier 			continue;
7589ef1f84bSDavid du Colombier 		}
7599ef1f84bSDavid du Colombier 
7609ef1f84bSDavid du Colombier 		/* other errors; give up */
7619ef1f84bSDavid du Colombier 		qunlock(&unit->ctl);
7629ef1f84bSDavid du Colombier 		decref(&sdev->r);
7639ef1f84bSDavid du Colombier 		nexterror();
7649ef1f84bSDavid du Colombier 	}
7659ef1f84bSDavid du Colombier 	pp = &unit->part[PART(c->qid)];
7669ef1f84bSDavid du Colombier 	if(unit->vers+pp->vers != c->qid.vers)
7679ef1f84bSDavid du Colombier 		error(Echange);
7689ef1f84bSDavid du Colombier 
7699ef1f84bSDavid du Colombier 	/*
7709ef1f84bSDavid du Colombier 	 * Check the request is within bounds.
7719ef1f84bSDavid du Colombier 	 * Removeable drives are locked throughout the I/O
7729ef1f84bSDavid du Colombier 	 * in case the media changes unexpectedly.
7739ef1f84bSDavid du Colombier 	 * Non-removeable drives are not locked during the I/O
7749ef1f84bSDavid du Colombier 	 * to allow the hardware to optimise if it can; this is
7759ef1f84bSDavid du Colombier 	 * a little fast and loose.
7769ef1f84bSDavid du Colombier 	 * It's assumed that non-removeable media parameters
7779ef1f84bSDavid du Colombier 	 * (sectors, secsize) can't change once the drive has
7789ef1f84bSDavid du Colombier 	 * been brought online.
7799ef1f84bSDavid du Colombier 	 */
7809ef1f84bSDavid du Colombier 	bno = (off/unit->secsize) + pp->start;
7819ef1f84bSDavid du Colombier 	nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
7829ef1f84bSDavid du Colombier 	max = SDmaxio/unit->secsize;
7839ef1f84bSDavid du Colombier 	if(nb > max)
7849ef1f84bSDavid du Colombier 		nb = max;
7859ef1f84bSDavid du Colombier 	if(bno+nb > pp->end)
7869ef1f84bSDavid du Colombier 		nb = pp->end - bno;
7879ef1f84bSDavid du Colombier 	if(bno >= pp->end || nb == 0){
7889ef1f84bSDavid du Colombier 		if(write)
7899ef1f84bSDavid du Colombier 			error(Eio);
7909ef1f84bSDavid du Colombier 		qunlock(&unit->ctl);
7919ef1f84bSDavid du Colombier 		decref(&sdev->r);
7929ef1f84bSDavid du Colombier 		poperror();
7939ef1f84bSDavid du Colombier 		return 0;
7949ef1f84bSDavid du Colombier 	}
7959ef1f84bSDavid du Colombier 	if(!(unit->inquiry[1] & SDinq1removable)){
7969ef1f84bSDavid du Colombier 		qunlock(&unit->ctl);
7979ef1f84bSDavid du Colombier 		poperror();
7989ef1f84bSDavid du Colombier 	}
7999ef1f84bSDavid du Colombier 
8009ef1f84bSDavid du Colombier 	b = sdmalloc(nb*unit->secsize);
8019ef1f84bSDavid du Colombier 	if(b == nil)
8029ef1f84bSDavid du Colombier 		error(Enomem);
8039ef1f84bSDavid du Colombier 	if(waserror()){
8049ef1f84bSDavid du Colombier 		sdfree(b);
8059ef1f84bSDavid du Colombier 		if(!(unit->inquiry[1] & SDinq1removable))
8069ef1f84bSDavid du Colombier 			decref(&sdev->r);		/* gadverdamme! */
8079ef1f84bSDavid du Colombier 		nexterror();
8089ef1f84bSDavid du Colombier 	}
8099ef1f84bSDavid du Colombier 
8109ef1f84bSDavid du Colombier 	offset = off%unit->secsize;
8119ef1f84bSDavid du Colombier 	if(offset+len > nb*unit->secsize)
8129ef1f84bSDavid du Colombier 		len = nb*unit->secsize - offset;
8139ef1f84bSDavid du Colombier 	if(write){
8149ef1f84bSDavid du Colombier 		if(offset || (len%unit->secsize)){
8159ef1f84bSDavid du Colombier 			l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
8169ef1f84bSDavid du Colombier 			if(l < 0)
8179ef1f84bSDavid du Colombier 				error(Eio);
8189ef1f84bSDavid du Colombier 			if(l < (nb*unit->secsize)){
8199ef1f84bSDavid du Colombier 				nb = l/unit->secsize;
8209ef1f84bSDavid du Colombier 				l = nb*unit->secsize - offset;
8219ef1f84bSDavid du Colombier 				if(len > l)
8229ef1f84bSDavid du Colombier 					len = l;
8239ef1f84bSDavid du Colombier 			}
8249ef1f84bSDavid du Colombier 		}
8259ef1f84bSDavid du Colombier 		memmove(b+offset, a, len);
8269ef1f84bSDavid du Colombier 		l = unit->dev->ifc->bio(unit, 0, 1, b, nb, bno);
8279ef1f84bSDavid du Colombier 		if(l < 0)
8289ef1f84bSDavid du Colombier 			error(Eio);
8299ef1f84bSDavid du Colombier 		if(l < offset)
8309ef1f84bSDavid du Colombier 			len = 0;
8319ef1f84bSDavid du Colombier 		else if(len > l - offset)
8329ef1f84bSDavid du Colombier 			len = l - offset;
8339ef1f84bSDavid du Colombier 	}
8349ef1f84bSDavid du Colombier 	else{
8359ef1f84bSDavid du Colombier 		l = unit->dev->ifc->bio(unit, 0, 0, b, nb, bno);
8369ef1f84bSDavid du Colombier 		if(l < 0)
8379ef1f84bSDavid du Colombier 			error(Eio);
8389ef1f84bSDavid du Colombier 		if(l < offset)
8399ef1f84bSDavid du Colombier 			len = 0;
8409ef1f84bSDavid du Colombier 		else if(len > l - offset)
8419ef1f84bSDavid du Colombier 			len = l - offset;
8429ef1f84bSDavid du Colombier 		memmove(a, b+offset, len);
8439ef1f84bSDavid du Colombier 	}
8449ef1f84bSDavid du Colombier 	sdfree(b);
8459ef1f84bSDavid du Colombier 	poperror();
8469ef1f84bSDavid du Colombier 
8479ef1f84bSDavid du Colombier 	if(unit->inquiry[1] & SDinq1removable){
8489ef1f84bSDavid du Colombier 		qunlock(&unit->ctl);
8499ef1f84bSDavid du Colombier 		poperror();
8509ef1f84bSDavid du Colombier 	}
8519ef1f84bSDavid du Colombier 
8529ef1f84bSDavid du Colombier 	decref(&sdev->r);
8539ef1f84bSDavid du Colombier 	return len;
8549ef1f84bSDavid du Colombier }
8559ef1f84bSDavid du Colombier 
8569ef1f84bSDavid du Colombier static long
sdrio(SDreq * r,void * a,long n)8579ef1f84bSDavid du Colombier sdrio(SDreq* r, void* a, long n)
8589ef1f84bSDavid du Colombier {
8599ef1f84bSDavid du Colombier 	void *data;
8609ef1f84bSDavid du Colombier 
8619ef1f84bSDavid du Colombier 	if(n >= SDmaxio || n < 0)
8629ef1f84bSDavid du Colombier 		error(Etoobig);
8639ef1f84bSDavid du Colombier 
8649ef1f84bSDavid du Colombier 	data = nil;
8659ef1f84bSDavid du Colombier 	if(n){
8669ef1f84bSDavid du Colombier 		if((data = sdmalloc(n)) == nil)
8679ef1f84bSDavid du Colombier 			error(Enomem);
8689ef1f84bSDavid du Colombier 		if(r->write)
8699ef1f84bSDavid du Colombier 			memmove(data, a, n);
8709ef1f84bSDavid du Colombier 	}
8719ef1f84bSDavid du Colombier 	r->data = data;
8729ef1f84bSDavid du Colombier 	r->dlen = n;
8739ef1f84bSDavid du Colombier 
8749ef1f84bSDavid du Colombier 	if(waserror()){
8759ef1f84bSDavid du Colombier 		sdfree(data);
8769ef1f84bSDavid du Colombier 		r->data = nil;
8779ef1f84bSDavid du Colombier 		nexterror();
8789ef1f84bSDavid du Colombier 	}
8799ef1f84bSDavid du Colombier 
8809ef1f84bSDavid du Colombier 	if(r->unit->dev->ifc->rio(r) != SDok)
8819ef1f84bSDavid du Colombier 		error(Eio);
8829ef1f84bSDavid du Colombier 
8839ef1f84bSDavid du Colombier 	if(!r->write && r->rlen > 0)
8849ef1f84bSDavid du Colombier 		memmove(a, data, r->rlen);
8859ef1f84bSDavid du Colombier 	sdfree(data);
8869ef1f84bSDavid du Colombier 	r->data = nil;
8879ef1f84bSDavid du Colombier 	poperror();
8889ef1f84bSDavid du Colombier 
8899ef1f84bSDavid du Colombier 	return r->rlen;
8909ef1f84bSDavid du Colombier }
8919ef1f84bSDavid du Colombier 
8929ef1f84bSDavid du Colombier /*
8939ef1f84bSDavid du Colombier  * SCSI simulation for non-SCSI devices
8949ef1f84bSDavid du Colombier  */
8959ef1f84bSDavid du Colombier int
sdsetsense(SDreq * r,int status,int key,int asc,int ascq)8969ef1f84bSDavid du Colombier sdsetsense(SDreq *r, int status, int key, int asc, int ascq)
8979ef1f84bSDavid du Colombier {
8989ef1f84bSDavid du Colombier 	int len;
8999ef1f84bSDavid du Colombier 	SDunit *unit;
9009ef1f84bSDavid du Colombier 
9019ef1f84bSDavid du Colombier 	unit = r->unit;
9029ef1f84bSDavid du Colombier 	unit->sense[2] = key;
9039ef1f84bSDavid du Colombier 	unit->sense[12] = asc;
9049ef1f84bSDavid du Colombier 	unit->sense[13] = ascq;
9059ef1f84bSDavid du Colombier 
9069ef1f84bSDavid du Colombier 	r->status = status;
9079ef1f84bSDavid du Colombier 	if(status == SDcheck && !(r->flags & SDnosense)){
9089ef1f84bSDavid du Colombier 		/* request sense case from sdfakescsi */
9099ef1f84bSDavid du Colombier 		len = sizeof unit->sense;
9109ef1f84bSDavid du Colombier 		if(len > sizeof r->sense-1)
9119ef1f84bSDavid du Colombier 			len = sizeof r->sense-1;
9129ef1f84bSDavid du Colombier 		memmove(r->sense, unit->sense, len);
9139ef1f84bSDavid du Colombier 		unit->sense[2] = 0;
9149ef1f84bSDavid du Colombier 		unit->sense[12] = 0;
9159ef1f84bSDavid du Colombier 		unit->sense[13] = 0;
9169ef1f84bSDavid du Colombier 		r->flags |= SDvalidsense;
9179ef1f84bSDavid du Colombier 		return SDok;
9189ef1f84bSDavid du Colombier 	}
9199ef1f84bSDavid du Colombier 	return status;
9209ef1f84bSDavid du Colombier }
9219ef1f84bSDavid du Colombier 
9229ef1f84bSDavid du Colombier int
sdmodesense(SDreq * r,uchar * cmd,void * info,int ilen)9239ef1f84bSDavid du Colombier sdmodesense(SDreq *r, uchar *cmd, void *info, int ilen)
9249ef1f84bSDavid du Colombier {
9259ef1f84bSDavid du Colombier 	int len;
9269ef1f84bSDavid du Colombier 	uchar *data;
9279ef1f84bSDavid du Colombier 
9289ef1f84bSDavid du Colombier 	/*
9299ef1f84bSDavid du Colombier 	 * Fake a vendor-specific request with page code 0,
9309ef1f84bSDavid du Colombier 	 * return the drive info.
9319ef1f84bSDavid du Colombier 	 */
9329ef1f84bSDavid du Colombier 	if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)
9339ef1f84bSDavid du Colombier 		return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
9349ef1f84bSDavid du Colombier 	len = (cmd[7]<<8)|cmd[8];
9359ef1f84bSDavid du Colombier 	if(len == 0)
9369ef1f84bSDavid du Colombier 		return SDok;
9379ef1f84bSDavid du Colombier 	if(len < 8+ilen)
9389ef1f84bSDavid du Colombier 		return sdsetsense(r, SDcheck, 0x05, 0x1A, 0);
9399ef1f84bSDavid du Colombier 	if(r->data == nil || r->dlen < len)
9409ef1f84bSDavid du Colombier 		return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
9419ef1f84bSDavid du Colombier 	data = r->data;
9429ef1f84bSDavid du Colombier 	memset(data, 0, 8);
9439ef1f84bSDavid du Colombier 	data[0] = ilen>>8;
9449ef1f84bSDavid du Colombier 	data[1] = ilen;
9459ef1f84bSDavid du Colombier 	if(ilen)
9469ef1f84bSDavid du Colombier 		memmove(data+8, info, ilen);
9479ef1f84bSDavid du Colombier 	r->rlen = 8+ilen;
9489ef1f84bSDavid du Colombier 	return sdsetsense(r, SDok, 0, 0, 0);
9499ef1f84bSDavid du Colombier }
9509ef1f84bSDavid du Colombier 
9519ef1f84bSDavid du Colombier int
sdfakescsi(SDreq * r,void * info,int ilen)9529ef1f84bSDavid du Colombier sdfakescsi(SDreq *r, void *info, int ilen)
9539ef1f84bSDavid du Colombier {
9549ef1f84bSDavid du Colombier 	uchar *cmd, *p;
9559ef1f84bSDavid du Colombier 	uvlong len;
9569ef1f84bSDavid du Colombier 	SDunit *unit;
9579ef1f84bSDavid du Colombier 
9589ef1f84bSDavid du Colombier 	cmd = r->cmd;
9599ef1f84bSDavid du Colombier 	r->rlen = 0;
9609ef1f84bSDavid du Colombier 	unit = r->unit;
9619ef1f84bSDavid du Colombier 
9629ef1f84bSDavid du Colombier 	/*
9639ef1f84bSDavid du Colombier 	 * Rewrite read(6)/write(6) into read(10)/write(10).
9649ef1f84bSDavid du Colombier 	 */
9659ef1f84bSDavid du Colombier 	switch(cmd[0]){
966a72b0d60SDavid du Colombier 	case ScmdRead:
967a72b0d60SDavid du Colombier 	case ScmdWrite:
9689ef1f84bSDavid du Colombier 		cmd[9] = 0;
9699ef1f84bSDavid du Colombier 		cmd[8] = cmd[4];
9709ef1f84bSDavid du Colombier 		cmd[7] = 0;
9719ef1f84bSDavid du Colombier 		cmd[6] = 0;
9729ef1f84bSDavid du Colombier 		cmd[5] = cmd[3];
9739ef1f84bSDavid du Colombier 		cmd[4] = cmd[2];
9749ef1f84bSDavid du Colombier 		cmd[3] = cmd[1] & 0x0F;
9759ef1f84bSDavid du Colombier 		cmd[2] = 0;
9769ef1f84bSDavid du Colombier 		cmd[1] &= 0xE0;
9779ef1f84bSDavid du Colombier 		cmd[0] |= 0x20;
9789ef1f84bSDavid du Colombier 		break;
9799ef1f84bSDavid du Colombier 	}
9809ef1f84bSDavid du Colombier 
9819ef1f84bSDavid du Colombier 	/*
9829ef1f84bSDavid du Colombier 	 * Map SCSI commands into ATA commands for discs.
9839ef1f84bSDavid du Colombier 	 * Fail any command with a LUN except INQUIRY which
9849ef1f84bSDavid du Colombier 	 * will return 'logical unit not supported'.
9859ef1f84bSDavid du Colombier 	 */
986a72b0d60SDavid du Colombier 	if((cmd[1]>>5) && cmd[0] != ScmdInq)
9879ef1f84bSDavid du Colombier 		return sdsetsense(r, SDcheck, 0x05, 0x25, 0);
9889ef1f84bSDavid du Colombier 
9899ef1f84bSDavid du Colombier 	switch(cmd[0]){
9909ef1f84bSDavid du Colombier 	default:
9919ef1f84bSDavid du Colombier 		return sdsetsense(r, SDcheck, 0x05, 0x20, 0);
9929ef1f84bSDavid du Colombier 
993a72b0d60SDavid du Colombier 	case ScmdTur:		/* test unit ready */
9949ef1f84bSDavid du Colombier 		return sdsetsense(r, SDok, 0, 0, 0);
9959ef1f84bSDavid du Colombier 
996a72b0d60SDavid du Colombier 	case ScmdRsense:	/* request sense */
9979ef1f84bSDavid du Colombier 		if(cmd[4] < sizeof unit->sense)
9989ef1f84bSDavid du Colombier 			len = cmd[4];
9999ef1f84bSDavid du Colombier 		else
10009ef1f84bSDavid du Colombier 			len = sizeof unit->sense;
10019ef1f84bSDavid du Colombier 		if(r->data && r->dlen >= len){
10029ef1f84bSDavid du Colombier 			memmove(r->data, unit->sense, len);
10039ef1f84bSDavid du Colombier 			r->rlen = len;
10049ef1f84bSDavid du Colombier 		}
10059ef1f84bSDavid du Colombier 		return sdsetsense(r, SDok, 0, 0, 0);
10069ef1f84bSDavid du Colombier 
1007a72b0d60SDavid du Colombier 	case ScmdInq:		/* inquiry */
10089ef1f84bSDavid du Colombier 		if(cmd[4] < sizeof unit->inquiry)
10099ef1f84bSDavid du Colombier 			len = cmd[4];
10109ef1f84bSDavid du Colombier 		else
10119ef1f84bSDavid du Colombier 			len = sizeof unit->inquiry;
10129ef1f84bSDavid du Colombier 		if(r->data && r->dlen >= len){
10139ef1f84bSDavid du Colombier 			memmove(r->data, unit->inquiry, len);
10149ef1f84bSDavid du Colombier 			r->rlen = len;
10159ef1f84bSDavid du Colombier 		}
10169ef1f84bSDavid du Colombier 		return sdsetsense(r, SDok, 0, 0, 0);
10179ef1f84bSDavid du Colombier 
1018a72b0d60SDavid du Colombier 	case ScmdStart:		/* start/stop unit */
10199ef1f84bSDavid du Colombier 		/*
10209ef1f84bSDavid du Colombier 		 * nop for now, can use power management later.
10219ef1f84bSDavid du Colombier 		 */
10229ef1f84bSDavid du Colombier 		return sdsetsense(r, SDok, 0, 0, 0);
10239ef1f84bSDavid du Colombier 
1024a72b0d60SDavid du Colombier 	case ScmdRcapacity:	/* read capacity */
10259ef1f84bSDavid du Colombier 		if((cmd[1] & 0x01) || cmd[2] || cmd[3])
10269ef1f84bSDavid du Colombier 			return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
10279ef1f84bSDavid du Colombier 		if(r->data == nil || r->dlen < 8)
10289ef1f84bSDavid du Colombier 			return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
10299ef1f84bSDavid du Colombier 
10309ef1f84bSDavid du Colombier 		/*
10319ef1f84bSDavid du Colombier 		 * Read capacity returns the LBA of the last sector.
10329ef1f84bSDavid du Colombier 		 */
10339ef1f84bSDavid du Colombier 		len = unit->sectors - 1;
10349ef1f84bSDavid du Colombier 		p = r->data;
10359ef1f84bSDavid du Colombier 		*p++ = len>>24;
10369ef1f84bSDavid du Colombier 		*p++ = len>>16;
10379ef1f84bSDavid du Colombier 		*p++ = len>>8;
10389ef1f84bSDavid du Colombier 		*p++ = len;
10399ef1f84bSDavid du Colombier 		len = 512;
10409ef1f84bSDavid du Colombier 		*p++ = len>>24;
10419ef1f84bSDavid du Colombier 		*p++ = len>>16;
10429ef1f84bSDavid du Colombier 		*p++ = len>>8;
10439ef1f84bSDavid du Colombier 		*p++ = len;
10449ef1f84bSDavid du Colombier 		r->rlen = p - (uchar*)r->data;
10459ef1f84bSDavid du Colombier 		return sdsetsense(r, SDok, 0, 0, 0);
10469ef1f84bSDavid du Colombier 
1047a72b0d60SDavid du Colombier 	case ScmdRcapacity16:	/* long read capacity */
10489ef1f84bSDavid du Colombier 		if((cmd[1] & 0x01) || cmd[2] || cmd[3])
10499ef1f84bSDavid du Colombier 			return sdsetsense(r, SDcheck, 0x05, 0x24, 0);
10509ef1f84bSDavid du Colombier 		if(r->data == nil || r->dlen < 8)
10519ef1f84bSDavid du Colombier 			return sdsetsense(r, SDcheck, 0x05, 0x20, 1);
10529ef1f84bSDavid du Colombier 		/*
10539ef1f84bSDavid du Colombier 		 * Read capcity returns the LBA of the last sector.
10549ef1f84bSDavid du Colombier 		 */
10559ef1f84bSDavid du Colombier 		len = unit->sectors - 1;
10569ef1f84bSDavid du Colombier 		p = r->data;
10579ef1f84bSDavid du Colombier 		*p++ = len>>56;
10589ef1f84bSDavid du Colombier 		*p++ = len>>48;
10599ef1f84bSDavid du Colombier 		*p++ = len>>40;
10609ef1f84bSDavid du Colombier 		*p++ = len>>32;
10619ef1f84bSDavid du Colombier 		*p++ = len>>24;
10629ef1f84bSDavid du Colombier 		*p++ = len>>16;
10639ef1f84bSDavid du Colombier 		*p++ = len>>8;
10649ef1f84bSDavid du Colombier 		*p++ = len;
10659ef1f84bSDavid du Colombier 		len = 512;
10669ef1f84bSDavid du Colombier 		*p++ = len>>24;
10679ef1f84bSDavid du Colombier 		*p++ = len>>16;
10689ef1f84bSDavid du Colombier 		*p++ = len>>8;
10699ef1f84bSDavid du Colombier 		*p++ = len;
10709ef1f84bSDavid du Colombier 		r->rlen = p - (uchar*)r->data;
10719ef1f84bSDavid du Colombier 		return sdsetsense(r, SDok, 0, 0, 0);
10729ef1f84bSDavid du Colombier 
1073a72b0d60SDavid du Colombier 	case ScmdMsense10:	/* mode sense */
10749ef1f84bSDavid du Colombier 		return sdmodesense(r, cmd, info, ilen);
10759ef1f84bSDavid du Colombier 
1076a72b0d60SDavid du Colombier 	case ScmdExtread:
1077a72b0d60SDavid du Colombier 	case ScmdExtwrite:
1078a72b0d60SDavid du Colombier 	case ScmdRead16:
1079a72b0d60SDavid du Colombier 	case ScmdWrite16:
10809ef1f84bSDavid du Colombier 		return SDnostatus;
10819ef1f84bSDavid du Colombier 	}
10829ef1f84bSDavid du Colombier }
10839ef1f84bSDavid du Colombier 
1084*465c1891SDavid du Colombier int
sdfakescsirw(SDreq * r,uvlong * llba,int * nsec,int * rwp)1085*465c1891SDavid du Colombier sdfakescsirw(SDreq *r, uvlong *llba, int *nsec, int *rwp)
1086*465c1891SDavid du Colombier {
1087*465c1891SDavid du Colombier 	uchar *c;
1088*465c1891SDavid du Colombier 	int rw, count;
1089*465c1891SDavid du Colombier 	uvlong lba;
1090*465c1891SDavid du Colombier 
1091*465c1891SDavid du Colombier 	c = r->cmd;
1092*465c1891SDavid du Colombier 	rw = 0;
1093*465c1891SDavid du Colombier 	if((c[0] & 0xf) == 0xa)
1094*465c1891SDavid du Colombier 		rw = 1;
1095*465c1891SDavid du Colombier 	switch(c[0]){
1096*465c1891SDavid du Colombier 	case 0x08:	/* read6 */
1097*465c1891SDavid du Colombier 	case 0x0a:
1098*465c1891SDavid du Colombier 		lba = (c[1] & 0xf)<<16 | c[2]<<8 | c[3];
1099*465c1891SDavid du Colombier 		count = c[4];
1100*465c1891SDavid du Colombier 		break;
1101*465c1891SDavid du Colombier 	case 0x28:	/* read10 */
1102*465c1891SDavid du Colombier 	case 0x2a:
1103*465c1891SDavid du Colombier 		lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1104*465c1891SDavid du Colombier 		count = c[7]<<8 | c[8];
1105*465c1891SDavid du Colombier 		break;
1106*465c1891SDavid du Colombier 	case 0xa8:	/* read12 */
1107*465c1891SDavid du Colombier 	case 0xaa:
1108*465c1891SDavid du Colombier 		lba = c[2]<<24 | c[3]<<16 | c[4]<<8 | c[5];
1109*465c1891SDavid du Colombier 		count = c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1110*465c1891SDavid du Colombier 		break;
1111*465c1891SDavid du Colombier 	case 0x88:	/* read16 */
1112*465c1891SDavid du Colombier 	case 0x8a:
1113*465c1891SDavid du Colombier 		/* ata commands only go to 48-bit lba */
1114*465c1891SDavid du Colombier 		if(c[2] || c[3])
1115*465c1891SDavid du Colombier 			return sdsetsense(r, SDcheck, 3, 0xc, 2);
1116*465c1891SDavid du Colombier 		lba = (uvlong)c[4]<<40 | (uvlong)c[5]<<32;
1117*465c1891SDavid du Colombier 		lba |= c[6]<<24 | c[7]<<16 | c[8]<<8 | c[9];
1118*465c1891SDavid du Colombier 		count = c[10]<<24 | c[11]<<16 | c[12]<<8 | c[13];
1119*465c1891SDavid du Colombier 		break;
1120*465c1891SDavid du Colombier 	default:
1121*465c1891SDavid du Colombier 		print("%s: bad cmd 0x%.2ux\n", r->unit->name, c[0]);
1122*465c1891SDavid du Colombier 		r->status  = sdsetsense(r, SDcheck, 0x05, 0x20, 0);
1123*465c1891SDavid du Colombier 		return SDcheck;
1124*465c1891SDavid du Colombier 	}
1125*465c1891SDavid du Colombier 	if(r->data == nil)
1126*465c1891SDavid du Colombier 		return SDok;
1127*465c1891SDavid du Colombier 	if(r->dlen < count * r->unit->secsize)
1128*465c1891SDavid du Colombier 		count = r->dlen/r->unit->secsize;
1129*465c1891SDavid du Colombier 	if(rwp)
1130*465c1891SDavid du Colombier 		*rwp = rw;
1131*465c1891SDavid du Colombier 	*llba = lba;
1132*465c1891SDavid du Colombier 	*nsec = count;
1133*465c1891SDavid du Colombier 	return SDnostatus;
1134*465c1891SDavid du Colombier }
1135*465c1891SDavid du Colombier 
11369ef1f84bSDavid du Colombier static long
sdread(Chan * c,void * a,long n,vlong off)11379ef1f84bSDavid du Colombier sdread(Chan *c, void *a, long n, vlong off)
11389ef1f84bSDavid du Colombier {
11399ef1f84bSDavid du Colombier 	char *p, *e, *buf;
11409ef1f84bSDavid du Colombier 	SDpart *pp;
11419ef1f84bSDavid du Colombier 	SDunit *unit;
11429ef1f84bSDavid du Colombier 	SDev *sdev;
11439ef1f84bSDavid du Colombier 	long offset;
11449ef1f84bSDavid du Colombier 	int i, l, m, status;
11459ef1f84bSDavid du Colombier 
11469ef1f84bSDavid du Colombier 	offset = off;
11479ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)){
11489ef1f84bSDavid du Colombier 	default:
11499ef1f84bSDavid du Colombier 		error(Eperm);
11509ef1f84bSDavid du Colombier 	case Qtopctl:
11519ef1f84bSDavid du Colombier 		m = 64*1024;	/* room for register dumps */
11529ef1f84bSDavid du Colombier 		p = buf = malloc(m);
11539ef1f84bSDavid du Colombier 		if(p == nil)
11549ef1f84bSDavid du Colombier 			error(Enomem);
11559ef1f84bSDavid du Colombier 		e = p + m;
11569ef1f84bSDavid du Colombier 		qlock(&devslock);
11579ef1f84bSDavid du Colombier 		for(i = 0; i < nelem(devs); i++){
11589ef1f84bSDavid du Colombier 			sdev = devs[i];
11599ef1f84bSDavid du Colombier 			if(sdev && sdev->ifc->rtopctl)
11609ef1f84bSDavid du Colombier 				p = sdev->ifc->rtopctl(sdev, p, e);
11619ef1f84bSDavid du Colombier 		}
11629ef1f84bSDavid du Colombier 		qunlock(&devslock);
11639ef1f84bSDavid du Colombier 		n = readstr(offset, a, n, buf);
11649ef1f84bSDavid du Colombier 		free(buf);
11659ef1f84bSDavid du Colombier 		return n;
11669ef1f84bSDavid du Colombier 
11679ef1f84bSDavid du Colombier 	case Qtopdir:
11689ef1f84bSDavid du Colombier 	case Qunitdir:
11699ef1f84bSDavid du Colombier 		return devdirread(c, a, n, 0, 0, sdgen);
11709ef1f84bSDavid du Colombier 
11719ef1f84bSDavid du Colombier 	case Qctl:
11729ef1f84bSDavid du Colombier 		sdev = sdgetdev(DEV(c->qid));
11739ef1f84bSDavid du Colombier 		if(sdev == nil)
11749ef1f84bSDavid du Colombier 			error(Enonexist);
11759ef1f84bSDavid du Colombier 
11769ef1f84bSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
11779ef1f84bSDavid du Colombier 		m = 16*1024;	/* room for register dumps */
11789ef1f84bSDavid du Colombier 		p = malloc(m);
11799ef1f84bSDavid du Colombier 		if(p == nil)
11809ef1f84bSDavid du Colombier 			error(Enomem);
11819ef1f84bSDavid du Colombier 		l = snprint(p, m, "inquiry %.48s\n",
11829ef1f84bSDavid du Colombier 			(char*)unit->inquiry+8);
11839ef1f84bSDavid du Colombier 		qlock(&unit->ctl);
11849ef1f84bSDavid du Colombier 		/*
11859ef1f84bSDavid du Colombier 		 * If there's a device specific routine it must
11869ef1f84bSDavid du Colombier 		 * provide all information pertaining to night geometry
11879ef1f84bSDavid du Colombier 		 * and the garscadden trains.
11889ef1f84bSDavid du Colombier 		 */
11899ef1f84bSDavid du Colombier 		if(unit->dev->ifc->rctl)
11909ef1f84bSDavid du Colombier 			l += unit->dev->ifc->rctl(unit, p+l, m-l);
11919ef1f84bSDavid du Colombier 		if(unit->sectors == 0)
11929ef1f84bSDavid du Colombier 			sdinitpart(unit);
11939ef1f84bSDavid du Colombier 		if(unit->sectors){
11949ef1f84bSDavid du Colombier 			if(unit->dev->ifc->rctl == nil)
11959ef1f84bSDavid du Colombier 				l += snprint(p+l, m-l,
11969ef1f84bSDavid du Colombier 					"geometry %llud %lud\n",
11979ef1f84bSDavid du Colombier 					unit->sectors, unit->secsize);
11989ef1f84bSDavid du Colombier 			pp = unit->part;
11999ef1f84bSDavid du Colombier 			for(i = 0; i < unit->npart; i++){
12009ef1f84bSDavid du Colombier 				if(pp->valid)
12019ef1f84bSDavid du Colombier 					l += snprint(p+l, m-l,
12029ef1f84bSDavid du Colombier 						"part %s %llud %llud\n",
12039ef1f84bSDavid du Colombier 						pp->name, pp->start, pp->end);
12049ef1f84bSDavid du Colombier 				pp++;
12059ef1f84bSDavid du Colombier 			}
12069ef1f84bSDavid du Colombier 		}
12079ef1f84bSDavid du Colombier 		qunlock(&unit->ctl);
12089ef1f84bSDavid du Colombier 		decref(&sdev->r);
12099ef1f84bSDavid du Colombier 		l = readstr(offset, a, n, p);
12109ef1f84bSDavid du Colombier 		free(p);
12119ef1f84bSDavid du Colombier 		return l;
12129ef1f84bSDavid du Colombier 
12139ef1f84bSDavid du Colombier 	case Qraw:
12149ef1f84bSDavid du Colombier 		sdev = sdgetdev(DEV(c->qid));
12159ef1f84bSDavid du Colombier 		if(sdev == nil)
12169ef1f84bSDavid du Colombier 			error(Enonexist);
12179ef1f84bSDavid du Colombier 
12189ef1f84bSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
12199ef1f84bSDavid du Colombier 		qlock(&unit->raw);
12209ef1f84bSDavid du Colombier 		if(waserror()){
12219ef1f84bSDavid du Colombier 			qunlock(&unit->raw);
12229ef1f84bSDavid du Colombier 			decref(&sdev->r);
12239ef1f84bSDavid du Colombier 			nexterror();
12249ef1f84bSDavid du Colombier 		}
12259ef1f84bSDavid du Colombier 		if(unit->state == Rawdata){
12269ef1f84bSDavid du Colombier 			unit->state = Rawstatus;
12279ef1f84bSDavid du Colombier 			i = sdrio(unit->req, a, n);
12289ef1f84bSDavid du Colombier 		}
12299ef1f84bSDavid du Colombier 		else if(unit->state == Rawstatus){
12309ef1f84bSDavid du Colombier 			status = unit->req->status;
12319ef1f84bSDavid du Colombier 			unit->state = Rawcmd;
12329ef1f84bSDavid du Colombier 			free(unit->req);
12339ef1f84bSDavid du Colombier 			unit->req = nil;
12349ef1f84bSDavid du Colombier 			i = readnum(0, a, n, status, NUMSIZE);
12359ef1f84bSDavid du Colombier 		} else
12369ef1f84bSDavid du Colombier 			i = 0;
12379ef1f84bSDavid du Colombier 		qunlock(&unit->raw);
12389ef1f84bSDavid du Colombier 		decref(&sdev->r);
12399ef1f84bSDavid du Colombier 		poperror();
12409ef1f84bSDavid du Colombier 		return i;
12419ef1f84bSDavid du Colombier 
12429ef1f84bSDavid du Colombier 	case Qpart:
12439ef1f84bSDavid du Colombier 		return sdbio(c, 0, a, n, off);
12449ef1f84bSDavid du Colombier 	}
12459ef1f84bSDavid du Colombier }
12469ef1f84bSDavid du Colombier 
12479ef1f84bSDavid du Colombier static void legacytopctl(Cmdbuf*);
12489ef1f84bSDavid du Colombier 
12499ef1f84bSDavid du Colombier static long
sdwrite(Chan * c,void * a,long n,vlong off)12509ef1f84bSDavid du Colombier sdwrite(Chan* c, void* a, long n, vlong off)
12519ef1f84bSDavid du Colombier {
12529ef1f84bSDavid du Colombier 	char *f0;
12539ef1f84bSDavid du Colombier 	int i;
12549ef1f84bSDavid du Colombier 	uvlong end, start;
12559ef1f84bSDavid du Colombier 	Cmdbuf *cb;
12569ef1f84bSDavid du Colombier 	SDifc *ifc;
12579ef1f84bSDavid du Colombier 	SDreq *req;
12589ef1f84bSDavid du Colombier 	SDunit *unit;
12599ef1f84bSDavid du Colombier 	SDev *sdev;
12609ef1f84bSDavid du Colombier 
12619ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)){
12629ef1f84bSDavid du Colombier 	default:
12639ef1f84bSDavid du Colombier 		error(Eperm);
12649ef1f84bSDavid du Colombier 	case Qtopctl:
12659ef1f84bSDavid du Colombier 		cb = parsecmd(a, n);
12669ef1f84bSDavid du Colombier 		if(waserror()){
12679ef1f84bSDavid du Colombier 			free(cb);
12689ef1f84bSDavid du Colombier 			nexterror();
12699ef1f84bSDavid du Colombier 		}
12709ef1f84bSDavid du Colombier 		if(cb->nf == 0)
12719ef1f84bSDavid du Colombier 			error("empty control message");
12729ef1f84bSDavid du Colombier 		f0 = cb->f[0];
12739ef1f84bSDavid du Colombier 		cb->f++;
12749ef1f84bSDavid du Colombier 		cb->nf--;
12759ef1f84bSDavid du Colombier 		if(strcmp(f0, "config") == 0){
12769ef1f84bSDavid du Colombier 			/* wormhole into ugly legacy interface */
12779ef1f84bSDavid du Colombier 			legacytopctl(cb);
12789ef1f84bSDavid du Colombier 			poperror();
12799ef1f84bSDavid du Colombier 			free(cb);
12809ef1f84bSDavid du Colombier 			break;
12819ef1f84bSDavid du Colombier 		}
12829ef1f84bSDavid du Colombier 		/*
12839ef1f84bSDavid du Colombier 		 * "ata arg..." invokes sdifc[i]->wtopctl(nil, cb),
12849ef1f84bSDavid du Colombier 		 * where sdifc[i]->name=="ata" and cb contains the args.
12859ef1f84bSDavid du Colombier 		 */
12869ef1f84bSDavid du Colombier 		ifc = nil;
12879ef1f84bSDavid du Colombier 		sdev = nil;
12889ef1f84bSDavid du Colombier 		for(i=0; sdifc[i]; i++){
12899ef1f84bSDavid du Colombier 			if(strcmp(sdifc[i]->name, f0) == 0){
12909ef1f84bSDavid du Colombier 				ifc = sdifc[i];
12919ef1f84bSDavid du Colombier 				sdev = nil;
12929ef1f84bSDavid du Colombier 				goto subtopctl;
12939ef1f84bSDavid du Colombier 			}
12949ef1f84bSDavid du Colombier 		}
12959ef1f84bSDavid du Colombier 		/*
12969ef1f84bSDavid du Colombier 		 * "sd1 arg..." invokes sdifc[i]->wtopctl(sdev, cb),
12979ef1f84bSDavid du Colombier 		 * where sdifc[i] and sdev match controller letter "1",
12989ef1f84bSDavid du Colombier 		 * and cb contains the args.
12999ef1f84bSDavid du Colombier 		 */
13009ef1f84bSDavid du Colombier 		if(f0[0]=='s' && f0[1]=='d' && f0[2] && f0[3] == 0){
13019ef1f84bSDavid du Colombier 			if((sdev = sdgetdev(f0[2])) != nil){
13029ef1f84bSDavid du Colombier 				ifc = sdev->ifc;
13039ef1f84bSDavid du Colombier 				goto subtopctl;
13049ef1f84bSDavid du Colombier 			}
13059ef1f84bSDavid du Colombier 		}
13069ef1f84bSDavid du Colombier 		error("unknown interface");
13079ef1f84bSDavid du Colombier 
13089ef1f84bSDavid du Colombier 	subtopctl:
13099ef1f84bSDavid du Colombier 		if(waserror()){
13109ef1f84bSDavid du Colombier 			if(sdev)
13119ef1f84bSDavid du Colombier 				decref(&sdev->r);
13129ef1f84bSDavid du Colombier 			nexterror();
13139ef1f84bSDavid du Colombier 		}
13149ef1f84bSDavid du Colombier 		if(ifc->wtopctl)
13159ef1f84bSDavid du Colombier 			ifc->wtopctl(sdev, cb);
13169ef1f84bSDavid du Colombier 		else
13179ef1f84bSDavid du Colombier 			error(Ebadctl);
13189ef1f84bSDavid du Colombier 		poperror();
13199ef1f84bSDavid du Colombier 		poperror();
13209ef1f84bSDavid du Colombier 		if(sdev)
13219ef1f84bSDavid du Colombier 			decref(&sdev->r);
13229ef1f84bSDavid du Colombier 		free(cb);
13239ef1f84bSDavid du Colombier 		break;
13249ef1f84bSDavid du Colombier 
13259ef1f84bSDavid du Colombier 	case Qctl:
13269ef1f84bSDavid du Colombier 		cb = parsecmd(a, n);
13279ef1f84bSDavid du Colombier 		sdev = sdgetdev(DEV(c->qid));
13289ef1f84bSDavid du Colombier 		if(sdev == nil)
13299ef1f84bSDavid du Colombier 			error(Enonexist);
13309ef1f84bSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
13319ef1f84bSDavid du Colombier 
13329ef1f84bSDavid du Colombier 		qlock(&unit->ctl);
13339ef1f84bSDavid du Colombier 		if(waserror()){
13349ef1f84bSDavid du Colombier 			qunlock(&unit->ctl);
13359ef1f84bSDavid du Colombier 			decref(&sdev->r);
13369ef1f84bSDavid du Colombier 			free(cb);
13379ef1f84bSDavid du Colombier 			nexterror();
13389ef1f84bSDavid du Colombier 		}
13399ef1f84bSDavid du Colombier 		if(unit->vers != c->qid.vers)
13409ef1f84bSDavid du Colombier 			error(Echange);
13419ef1f84bSDavid du Colombier 
13429ef1f84bSDavid du Colombier 		if(cb->nf < 1)
13439ef1f84bSDavid du Colombier 			error(Ebadctl);
13449ef1f84bSDavid du Colombier 		if(strcmp(cb->f[0], "part") == 0){
13459ef1f84bSDavid du Colombier 			if(cb->nf != 4)
13469ef1f84bSDavid du Colombier 				error(Ebadctl);
13479ef1f84bSDavid du Colombier 			if(unit->sectors == 0 && !sdinitpart(unit))
13489ef1f84bSDavid du Colombier 				error(Eio);
13499ef1f84bSDavid du Colombier 			start = strtoull(cb->f[2], 0, 0);
13509ef1f84bSDavid du Colombier 			end = strtoull(cb->f[3], 0, 0);
13519ef1f84bSDavid du Colombier 			sdaddpart(unit, cb->f[1], start, end);
13529ef1f84bSDavid du Colombier 		}
13539ef1f84bSDavid du Colombier 		else if(strcmp(cb->f[0], "delpart") == 0){
13549ef1f84bSDavid du Colombier 			if(cb->nf != 2 || unit->part == nil)
13559ef1f84bSDavid du Colombier 				error(Ebadctl);
13569ef1f84bSDavid du Colombier 			sddelpart(unit, cb->f[1]);
13579ef1f84bSDavid du Colombier 		}
13589ef1f84bSDavid du Colombier 		else if(unit->dev->ifc->wctl)
13599ef1f84bSDavid du Colombier 			unit->dev->ifc->wctl(unit, cb);
13609ef1f84bSDavid du Colombier 		else
13619ef1f84bSDavid du Colombier 			error(Ebadctl);
13629ef1f84bSDavid du Colombier 		qunlock(&unit->ctl);
13639ef1f84bSDavid du Colombier 		decref(&sdev->r);
13649ef1f84bSDavid du Colombier 		poperror();
13659ef1f84bSDavid du Colombier 		free(cb);
13669ef1f84bSDavid du Colombier 		break;
13679ef1f84bSDavid du Colombier 
13689ef1f84bSDavid du Colombier 	case Qraw:
13699ef1f84bSDavid du Colombier 		sdev = sdgetdev(DEV(c->qid));
13709ef1f84bSDavid du Colombier 		if(sdev == nil)
13719ef1f84bSDavid du Colombier 			error(Enonexist);
13729ef1f84bSDavid du Colombier 		unit = sdev->unit[UNIT(c->qid)];
13739ef1f84bSDavid du Colombier 		qlock(&unit->raw);
13749ef1f84bSDavid du Colombier 		if(waserror()){
13759ef1f84bSDavid du Colombier 			qunlock(&unit->raw);
13769ef1f84bSDavid du Colombier 			decref(&sdev->r);
13779ef1f84bSDavid du Colombier 			nexterror();
13789ef1f84bSDavid du Colombier 		}
13799ef1f84bSDavid du Colombier 		switch(unit->state){
13809ef1f84bSDavid du Colombier 		case Rawcmd:
13819ef1f84bSDavid du Colombier 			if(n < 6 || n > sizeof(req->cmd))
13829ef1f84bSDavid du Colombier 				error(Ebadarg);
13839ef1f84bSDavid du Colombier 			if((req = malloc(sizeof(SDreq))) == nil)
13849ef1f84bSDavid du Colombier 				error(Enomem);
13859ef1f84bSDavid du Colombier 			req->unit = unit;
13869ef1f84bSDavid du Colombier 			memmove(req->cmd, a, n);
13879ef1f84bSDavid du Colombier 			req->clen = n;
13889ef1f84bSDavid du Colombier 			req->flags = SDnosense;
13899ef1f84bSDavid du Colombier 			req->status = ~0;
13909ef1f84bSDavid du Colombier 
13919ef1f84bSDavid du Colombier 			unit->req = req;
13929ef1f84bSDavid du Colombier 			unit->state = Rawdata;
13939ef1f84bSDavid du Colombier 			break;
13949ef1f84bSDavid du Colombier 
13959ef1f84bSDavid du Colombier 		case Rawstatus:
13969ef1f84bSDavid du Colombier 			unit->state = Rawcmd;
13979ef1f84bSDavid du Colombier 			free(unit->req);
13989ef1f84bSDavid du Colombier 			unit->req = nil;
13999ef1f84bSDavid du Colombier 			error(Ebadusefd);
14009ef1f84bSDavid du Colombier 
14019ef1f84bSDavid du Colombier 		case Rawdata:
14029ef1f84bSDavid du Colombier 			unit->state = Rawstatus;
14039ef1f84bSDavid du Colombier 			unit->req->write = 1;
14049ef1f84bSDavid du Colombier 			n = sdrio(unit->req, a, n);
14059ef1f84bSDavid du Colombier 		}
14069ef1f84bSDavid du Colombier 		qunlock(&unit->raw);
14079ef1f84bSDavid du Colombier 		decref(&sdev->r);
14089ef1f84bSDavid du Colombier 		poperror();
14099ef1f84bSDavid du Colombier 		break;
14109ef1f84bSDavid du Colombier 	case Qpart:
14119ef1f84bSDavid du Colombier 		return sdbio(c, 1, a, n, off);
14129ef1f84bSDavid du Colombier 	}
14139ef1f84bSDavid du Colombier 
14149ef1f84bSDavid du Colombier 	return n;
14159ef1f84bSDavid du Colombier }
14169ef1f84bSDavid du Colombier 
14179ef1f84bSDavid du Colombier static long
sdwstat(Chan * c,uchar * dp,long n)14189ef1f84bSDavid du Colombier sdwstat(Chan* c, uchar* dp, long n)
14199ef1f84bSDavid du Colombier {
14209ef1f84bSDavid du Colombier 	Dir *d;
14219ef1f84bSDavid du Colombier 	SDpart *pp;
14229ef1f84bSDavid du Colombier 	SDperm *perm;
14239ef1f84bSDavid du Colombier 	SDunit *unit;
14249ef1f84bSDavid du Colombier 	SDev *sdev;
14259ef1f84bSDavid du Colombier 
14269ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR)
14279ef1f84bSDavid du Colombier 		error(Eperm);
14289ef1f84bSDavid du Colombier 
14299ef1f84bSDavid du Colombier 	sdev = sdgetdev(DEV(c->qid));
14309ef1f84bSDavid du Colombier 	if(sdev == nil)
14319ef1f84bSDavid du Colombier 		error(Enonexist);
14329ef1f84bSDavid du Colombier 	unit = sdev->unit[UNIT(c->qid)];
14339ef1f84bSDavid du Colombier 	qlock(&unit->ctl);
14349ef1f84bSDavid du Colombier 	d = nil;
14359ef1f84bSDavid du Colombier 	if(waserror()){
14369ef1f84bSDavid du Colombier 		free(d);
14379ef1f84bSDavid du Colombier 		qunlock(&unit->ctl);
14389ef1f84bSDavid du Colombier 		decref(&sdev->r);
14399ef1f84bSDavid du Colombier 		nexterror();
14409ef1f84bSDavid du Colombier 	}
14419ef1f84bSDavid du Colombier 
14429ef1f84bSDavid du Colombier 	switch(TYPE(c->qid)){
14439ef1f84bSDavid du Colombier 	default:
14449ef1f84bSDavid du Colombier 		error(Eperm);
14459ef1f84bSDavid du Colombier 	case Qctl:
14469ef1f84bSDavid du Colombier 		perm = &unit->ctlperm;
14479ef1f84bSDavid du Colombier 		break;
14489ef1f84bSDavid du Colombier 	case Qraw:
14499ef1f84bSDavid du Colombier 		perm = &unit->rawperm;
14509ef1f84bSDavid du Colombier 		break;
14519ef1f84bSDavid du Colombier 	case Qpart:
14529ef1f84bSDavid du Colombier 		pp = &unit->part[PART(c->qid)];
14539ef1f84bSDavid du Colombier 		if(unit->vers+pp->vers != c->qid.vers)
14549ef1f84bSDavid du Colombier 			error(Enonexist);
14559ef1f84bSDavid du Colombier 		perm = &pp->SDperm;
14569ef1f84bSDavid du Colombier 		break;
14579ef1f84bSDavid du Colombier 	}
14589ef1f84bSDavid du Colombier 
14599ef1f84bSDavid du Colombier 	if(strcmp(up->user, perm->user) && !iseve())
14609ef1f84bSDavid du Colombier 		error(Eperm);
14619ef1f84bSDavid du Colombier 
14629ef1f84bSDavid du Colombier 	d = smalloc(sizeof(Dir)+n);
14639ef1f84bSDavid du Colombier 	n = convM2D(dp, n, &d[0], (char*)&d[1]);
14649ef1f84bSDavid du Colombier 	if(n == 0)
14659ef1f84bSDavid du Colombier 		error(Eshortstat);
14669ef1f84bSDavid du Colombier 	if(!emptystr(d[0].uid))
14679ef1f84bSDavid du Colombier 		kstrdup(&perm->user, d[0].uid);
14689ef1f84bSDavid du Colombier 	if(d[0].mode != ~0UL)
14699ef1f84bSDavid du Colombier 		perm->perm = (perm->perm & ~0777) | (d[0].mode & 0777);
14709ef1f84bSDavid du Colombier 
14719ef1f84bSDavid du Colombier 	free(d);
14729ef1f84bSDavid du Colombier 	qunlock(&unit->ctl);
14739ef1f84bSDavid du Colombier 	decref(&sdev->r);
14749ef1f84bSDavid du Colombier 	poperror();
14759ef1f84bSDavid du Colombier 	return n;
14769ef1f84bSDavid du Colombier }
14779ef1f84bSDavid du Colombier 
14789ef1f84bSDavid du Colombier static int
configure(char * spec,DevConf * cf)14799ef1f84bSDavid du Colombier configure(char* spec, DevConf* cf)
14809ef1f84bSDavid du Colombier {
14819ef1f84bSDavid du Colombier 	SDev *s, *sdev;
14829ef1f84bSDavid du Colombier 	char *p;
14839ef1f84bSDavid du Colombier 	int i;
14849ef1f84bSDavid du Colombier 
14859ef1f84bSDavid du Colombier 	if(sdindex(*spec) < 0)
14869ef1f84bSDavid du Colombier 		error("bad sd spec");
14879ef1f84bSDavid du Colombier 
14889ef1f84bSDavid du Colombier 	if((p = strchr(cf->type, '/')) != nil)
14899ef1f84bSDavid du Colombier 		*p++ = '\0';
14909ef1f84bSDavid du Colombier 
14919ef1f84bSDavid du Colombier 	for(i = 0; sdifc[i] != nil; i++)
14929ef1f84bSDavid du Colombier 		if(strcmp(sdifc[i]->name, cf->type) == 0)
14939ef1f84bSDavid du Colombier 			break;
14949ef1f84bSDavid du Colombier 	if(sdifc[i] == nil)
14959ef1f84bSDavid du Colombier 		error("sd type not found");
14969ef1f84bSDavid du Colombier 	if(p)
14979ef1f84bSDavid du Colombier 		*(p-1) = '/';
14989ef1f84bSDavid du Colombier 
14999ef1f84bSDavid du Colombier 	if(sdifc[i]->probe == nil)
15009ef1f84bSDavid du Colombier 		error("sd type cannot probe");
15019ef1f84bSDavid du Colombier 
15029ef1f84bSDavid du Colombier 	sdev = sdifc[i]->probe(cf);
15039ef1f84bSDavid du Colombier 	for(s=sdev; s; s=s->next)
15049ef1f84bSDavid du Colombier 		s->idno = *spec;
15059ef1f84bSDavid du Colombier 	sdadddevs(sdev);
15069ef1f84bSDavid du Colombier 	return 0;
15079ef1f84bSDavid du Colombier }
15089ef1f84bSDavid du Colombier 
15099ef1f84bSDavid du Colombier static int
unconfigure(char * spec)15109ef1f84bSDavid du Colombier unconfigure(char* spec)
15119ef1f84bSDavid du Colombier {
15129ef1f84bSDavid du Colombier 	int i;
15139ef1f84bSDavid du Colombier 	SDev *sdev;
15149ef1f84bSDavid du Colombier 	SDunit *unit;
15159ef1f84bSDavid du Colombier 
15169ef1f84bSDavid du Colombier 	if((i = sdindex(*spec)) < 0)
15179ef1f84bSDavid du Colombier 		error(Enonexist);
15189ef1f84bSDavid du Colombier 
15199ef1f84bSDavid du Colombier 	qlock(&devslock);
15209ef1f84bSDavid du Colombier 	if((sdev = devs[i]) == nil){
15219ef1f84bSDavid du Colombier 		qunlock(&devslock);
15229ef1f84bSDavid du Colombier 		error(Enonexist);
15239ef1f84bSDavid du Colombier 	}
15249ef1f84bSDavid du Colombier 	if(sdev->r.ref){
15259ef1f84bSDavid du Colombier 		qunlock(&devslock);
15269ef1f84bSDavid du Colombier 		error(Einuse);
15279ef1f84bSDavid du Colombier 	}
15289ef1f84bSDavid du Colombier 	devs[i] = nil;
15299ef1f84bSDavid du Colombier 	qunlock(&devslock);
15309ef1f84bSDavid du Colombier 
15319ef1f84bSDavid du Colombier 	/* make sure no interrupts arrive anymore before removing resources */
15329ef1f84bSDavid du Colombier 	if(sdev->enabled && sdev->ifc->disable)
15339ef1f84bSDavid du Colombier 		sdev->ifc->disable(sdev);
15349ef1f84bSDavid du Colombier 
15359ef1f84bSDavid du Colombier 	for(i = 0; i != sdev->nunit; i++){
15369ef1f84bSDavid du Colombier 		if(unit = sdev->unit[i]){
15379ef1f84bSDavid du Colombier 			free(unit->name);
15389ef1f84bSDavid du Colombier 			free(unit->user);
15399ef1f84bSDavid du Colombier 			free(unit);
15409ef1f84bSDavid du Colombier 		}
15419ef1f84bSDavid du Colombier 	}
15429ef1f84bSDavid du Colombier 
15439ef1f84bSDavid du Colombier 	if(sdev->ifc->clear)
15449ef1f84bSDavid du Colombier 		sdev->ifc->clear(sdev);
15459ef1f84bSDavid du Colombier 	free(sdev);
15469ef1f84bSDavid du Colombier 	return 0;
15479ef1f84bSDavid du Colombier }
15489ef1f84bSDavid du Colombier 
15499ef1f84bSDavid du Colombier static int
sdconfig(int on,char * spec,DevConf * cf)15509ef1f84bSDavid du Colombier sdconfig(int on, char* spec, DevConf* cf)
15519ef1f84bSDavid du Colombier {
15529ef1f84bSDavid du Colombier 	if(on)
15539ef1f84bSDavid du Colombier 		return configure(spec, cf);
15549ef1f84bSDavid du Colombier 	return unconfigure(spec);
15559ef1f84bSDavid du Colombier }
15569ef1f84bSDavid du Colombier 
15579ef1f84bSDavid du Colombier Dev sddevtab = {
15589ef1f84bSDavid du Colombier 	'S',
15599ef1f84bSDavid du Colombier 	"sd",
15609ef1f84bSDavid du Colombier 
15619ef1f84bSDavid du Colombier 	sdreset,
15629ef1f84bSDavid du Colombier 	devinit,
15639ef1f84bSDavid du Colombier 	devshutdown,
15649ef1f84bSDavid du Colombier 	sdattach,
15659ef1f84bSDavid du Colombier 	sdwalk,
15669ef1f84bSDavid du Colombier 	sdstat,
15679ef1f84bSDavid du Colombier 	sdopen,
15689ef1f84bSDavid du Colombier 	devcreate,
15699ef1f84bSDavid du Colombier 	sdclose,
15709ef1f84bSDavid du Colombier 	sdread,
15719ef1f84bSDavid du Colombier 	devbread,
15729ef1f84bSDavid du Colombier 	sdwrite,
15739ef1f84bSDavid du Colombier 	devbwrite,
15749ef1f84bSDavid du Colombier 	devremove,
15759ef1f84bSDavid du Colombier 	sdwstat,
15769ef1f84bSDavid du Colombier 	devpower,
15779ef1f84bSDavid du Colombier 	sdconfig,	/* probe; only called for pcmcia-like devices */
15789ef1f84bSDavid du Colombier };
15799ef1f84bSDavid du Colombier 
15809ef1f84bSDavid du Colombier /*
15819ef1f84bSDavid du Colombier  * This is wrong for so many reasons.  This code must go.
15829ef1f84bSDavid du Colombier  */
15839ef1f84bSDavid du Colombier typedef struct Confdata Confdata;
15849ef1f84bSDavid du Colombier struct Confdata {
15859ef1f84bSDavid du Colombier 	int	on;
15869ef1f84bSDavid du Colombier 	char*	spec;
15879ef1f84bSDavid du Colombier 	DevConf	cf;
15889ef1f84bSDavid du Colombier };
15899ef1f84bSDavid du Colombier 
15909ef1f84bSDavid du Colombier static void
parseswitch(Confdata * cd,char * option)15919ef1f84bSDavid du Colombier parseswitch(Confdata* cd, char* option)
15929ef1f84bSDavid du Colombier {
15939ef1f84bSDavid du Colombier 	if(!strcmp("on", option))
15949ef1f84bSDavid du Colombier 		cd->on = 1;
15959ef1f84bSDavid du Colombier 	else if(!strcmp("off", option))
15969ef1f84bSDavid du Colombier 		cd->on = 0;
15979ef1f84bSDavid du Colombier 	else
15989ef1f84bSDavid du Colombier 		error(Ebadarg);
15999ef1f84bSDavid du Colombier }
16009ef1f84bSDavid du Colombier 
16019ef1f84bSDavid du Colombier static void
parsespec(Confdata * cd,char * option)16029ef1f84bSDavid du Colombier parsespec(Confdata* cd, char* option)
16039ef1f84bSDavid du Colombier {
16049ef1f84bSDavid du Colombier 	if(strlen(option) > 1)
16059ef1f84bSDavid du Colombier 		error(Ebadarg);
16069ef1f84bSDavid du Colombier 	cd->spec = option;
16079ef1f84bSDavid du Colombier }
16089ef1f84bSDavid du Colombier 
16099ef1f84bSDavid du Colombier static Devport*
getnewport(DevConf * dc)16109ef1f84bSDavid du Colombier getnewport(DevConf* dc)
16119ef1f84bSDavid du Colombier {
16129ef1f84bSDavid du Colombier 	Devport *p;
16139ef1f84bSDavid du Colombier 
16149ef1f84bSDavid du Colombier 	p = (Devport *)malloc((dc->nports + 1) * sizeof(Devport));
16159ef1f84bSDavid du Colombier 	if(p == nil)
16169ef1f84bSDavid du Colombier 		error(Enomem);
16179ef1f84bSDavid du Colombier 	if(dc->nports > 0){
16189ef1f84bSDavid du Colombier 		memmove(p, dc->ports, dc->nports * sizeof(Devport));
16199ef1f84bSDavid du Colombier 		free(dc->ports);
16209ef1f84bSDavid du Colombier 	}
16219ef1f84bSDavid du Colombier 	dc->ports = p;
16229ef1f84bSDavid du Colombier 	p = &dc->ports[dc->nports++];
16239ef1f84bSDavid du Colombier 	p->size = -1;
16249ef1f84bSDavid du Colombier 	p->port = (ulong)-1;
16259ef1f84bSDavid du Colombier 	return p;
16269ef1f84bSDavid du Colombier }
16279ef1f84bSDavid du Colombier 
16289ef1f84bSDavid du Colombier static void
parseport(Confdata * cd,char * option)16299ef1f84bSDavid du Colombier parseport(Confdata* cd, char* option)
16309ef1f84bSDavid du Colombier {
16319ef1f84bSDavid du Colombier 	char *e;
16329ef1f84bSDavid du Colombier 	Devport *p;
16339ef1f84bSDavid du Colombier 
16349ef1f84bSDavid du Colombier 	if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].port != (ulong)-1)
16359ef1f84bSDavid du Colombier 		p = getnewport(&cd->cf);
16369ef1f84bSDavid du Colombier 	else
16379ef1f84bSDavid du Colombier 		p = &cd->cf.ports[cd->cf.nports-1];
16389ef1f84bSDavid du Colombier 	p->port = strtol(option, &e, 0);
16399ef1f84bSDavid du Colombier 	if(e == nil || *e != '\0')
16409ef1f84bSDavid du Colombier 		error(Ebadarg);
16419ef1f84bSDavid du Colombier }
16429ef1f84bSDavid du Colombier 
16439ef1f84bSDavid du Colombier static void
parsesize(Confdata * cd,char * option)16449ef1f84bSDavid du Colombier parsesize(Confdata* cd, char* option)
16459ef1f84bSDavid du Colombier {
16469ef1f84bSDavid du Colombier 	char *e;
16479ef1f84bSDavid du Colombier 	Devport *p;
16489ef1f84bSDavid du Colombier 
16499ef1f84bSDavid du Colombier 	if(cd->cf.nports == 0 || cd->cf.ports[cd->cf.nports-1].size != -1)
16509ef1f84bSDavid du Colombier 		p = getnewport(&cd->cf);
16519ef1f84bSDavid du Colombier 	else
16529ef1f84bSDavid du Colombier 		p = &cd->cf.ports[cd->cf.nports-1];
16539ef1f84bSDavid du Colombier 	p->size = (int)strtol(option, &e, 0);
16549ef1f84bSDavid du Colombier 	if(e == nil || *e != '\0')
16559ef1f84bSDavid du Colombier 		error(Ebadarg);
16569ef1f84bSDavid du Colombier }
16579ef1f84bSDavid du Colombier 
16589ef1f84bSDavid du Colombier static void
parseirq(Confdata * cd,char * option)16599ef1f84bSDavid du Colombier parseirq(Confdata* cd, char* option)
16609ef1f84bSDavid du Colombier {
16619ef1f84bSDavid du Colombier 	char *e;
16629ef1f84bSDavid du Colombier 
16639ef1f84bSDavid du Colombier 	cd->cf.intnum = strtoul(option, &e, 0);
16649ef1f84bSDavid du Colombier 	if(e == nil || *e != '\0')
16659ef1f84bSDavid du Colombier 		error(Ebadarg);
16669ef1f84bSDavid du Colombier }
16679ef1f84bSDavid du Colombier 
16689ef1f84bSDavid du Colombier static void
parsetype(Confdata * cd,char * option)16699ef1f84bSDavid du Colombier parsetype(Confdata* cd, char* option)
16709ef1f84bSDavid du Colombier {
16719ef1f84bSDavid du Colombier 	cd->cf.type = option;
16729ef1f84bSDavid du Colombier }
16739ef1f84bSDavid du Colombier 
16749ef1f84bSDavid du Colombier static struct {
16759ef1f84bSDavid du Colombier 	char	*name;
16769ef1f84bSDavid du Colombier 	void	(*parse)(Confdata*, char*);
16779ef1f84bSDavid du Colombier } options[] = {
16789ef1f84bSDavid du Colombier 	"switch",	parseswitch,
16799ef1f84bSDavid du Colombier 	"spec",		parsespec,
16809ef1f84bSDavid du Colombier 	"port",		parseport,
16819ef1f84bSDavid du Colombier 	"size",		parsesize,
16829ef1f84bSDavid du Colombier 	"irq",		parseirq,
16839ef1f84bSDavid du Colombier 	"type",		parsetype,
16849ef1f84bSDavid du Colombier };
16859ef1f84bSDavid du Colombier 
16869ef1f84bSDavid du Colombier static void
legacytopctl(Cmdbuf * cb)16879ef1f84bSDavid du Colombier legacytopctl(Cmdbuf *cb)
16889ef1f84bSDavid du Colombier {
16899ef1f84bSDavid du Colombier 	char *opt;
16909ef1f84bSDavid du Colombier 	int i, j;
16919ef1f84bSDavid du Colombier 	Confdata cd;
16929ef1f84bSDavid du Colombier 
16939ef1f84bSDavid du Colombier 	memset(&cd, 0, sizeof cd);
16949ef1f84bSDavid du Colombier 	cd.on = -1;
16959ef1f84bSDavid du Colombier 	for(i=0; i<cb->nf; i+=2){
16969ef1f84bSDavid du Colombier 		if(i+2 > cb->nf)
16979ef1f84bSDavid du Colombier 			error(Ebadarg);
16989ef1f84bSDavid du Colombier 		opt = cb->f[i];
16999ef1f84bSDavid du Colombier 		for(j=0; j<nelem(options); j++)
17009ef1f84bSDavid du Colombier 			if(strcmp(opt, options[j].name) == 0){
17019ef1f84bSDavid du Colombier 				options[j].parse(&cd, cb->f[i+1]);
17029ef1f84bSDavid du Colombier 				break;
17039ef1f84bSDavid du Colombier 			}
17049ef1f84bSDavid du Colombier 		if(j == nelem(options))
17059ef1f84bSDavid du Colombier 			error(Ebadarg);
17069ef1f84bSDavid du Colombier 	}
17079ef1f84bSDavid du Colombier 	/* this has been rewritten to accomodate sdaoe */
17089ef1f84bSDavid du Colombier 	if(cd.on < 0 || cd.spec == 0)
17099ef1f84bSDavid du Colombier 		error(Ebadarg);
17109ef1f84bSDavid du Colombier 	if(cd.on && cd.cf.type == nil)
17119ef1f84bSDavid du Colombier 		error(Ebadarg);
17129ef1f84bSDavid du Colombier 	sdconfig(cd.on, cd.spec, &cd.cf);
17139ef1f84bSDavid du Colombier }
1714