xref: /plan9-contrib/sys/src/9k/port/sdaoe.c (revision 05ffe48f6a7c47e3c5823db8baa092dde4ecb671)
19ef1f84bSDavid du Colombier /*
29ef1f84bSDavid du Colombier  * aoe sd driver, copyright © 2007 coraid
39ef1f84bSDavid du Colombier  */
49ef1f84bSDavid du Colombier 
59ef1f84bSDavid du Colombier #include "u.h"
69ef1f84bSDavid du Colombier #include "../port/lib.h"
79ef1f84bSDavid du Colombier #include "mem.h"
89ef1f84bSDavid du Colombier #include "dat.h"
99ef1f84bSDavid du Colombier #include "fns.h"
109ef1f84bSDavid du Colombier #include "../port/error.h"
119ef1f84bSDavid du Colombier 
129ef1f84bSDavid du Colombier #include "../port/netif.h"
139ef1f84bSDavid du Colombier #include "../port/sd.h"
149ef1f84bSDavid du Colombier 
159ef1f84bSDavid du Colombier #include "etherif.h"
169ef1f84bSDavid du Colombier #include "../port/aoe.h"
179ef1f84bSDavid du Colombier 
189ef1f84bSDavid du Colombier #define uprint(...)	snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
199ef1f84bSDavid du Colombier 
209ef1f84bSDavid du Colombier enum {
219ef1f84bSDavid du Colombier 	Nctlr	= 32,
229ef1f84bSDavid du Colombier 	Maxpath	= 128,
239ef1f84bSDavid du Colombier 
249ef1f84bSDavid du Colombier 	Probeintvl	= 100,		/* ms. between probes */
259ef1f84bSDavid du Colombier 	Probemax	= 20,		/* max probes */
269ef1f84bSDavid du Colombier };
279ef1f84bSDavid du Colombier 
289ef1f84bSDavid du Colombier enum {
299ef1f84bSDavid du Colombier 	/* sync with ahci.h */
309ef1f84bSDavid du Colombier 	Dllba 	= 1<<0,
319ef1f84bSDavid du Colombier 	Dsmart	= 1<<1,
329ef1f84bSDavid du Colombier 	Dpower	= 1<<2,
339ef1f84bSDavid du Colombier 	Dnop	= 1<<3,
349ef1f84bSDavid du Colombier 	Datapi	= 1<<4,
359ef1f84bSDavid du Colombier 	Datapi16= 1<<5,
369ef1f84bSDavid du Colombier };
379ef1f84bSDavid du Colombier 
389ef1f84bSDavid du Colombier static char *flagname[] = {
399ef1f84bSDavid du Colombier 	"llba",
409ef1f84bSDavid du Colombier 	"smart",
419ef1f84bSDavid du Colombier 	"power",
429ef1f84bSDavid du Colombier 	"nop",
439ef1f84bSDavid du Colombier 	"atapi",
449ef1f84bSDavid du Colombier 	"atapi16",
459ef1f84bSDavid du Colombier };
469ef1f84bSDavid du Colombier 
479ef1f84bSDavid du Colombier typedef struct Ctlr Ctlr;
489ef1f84bSDavid du Colombier struct Ctlr{
499ef1f84bSDavid du Colombier 	QLock;
509ef1f84bSDavid du Colombier 
519ef1f84bSDavid du Colombier 	Ctlr	*next;
529ef1f84bSDavid du Colombier 	SDunit	*unit;
539ef1f84bSDavid du Colombier 
549ef1f84bSDavid du Colombier 	char	path[Maxpath];
559ef1f84bSDavid du Colombier 	Chan	*c;
569ef1f84bSDavid du Colombier 
579ef1f84bSDavid du Colombier 	ulong	vers;
589ef1f84bSDavid du Colombier 	uchar	mediachange;
599ef1f84bSDavid du Colombier 	uchar	flag;
609ef1f84bSDavid du Colombier 	uchar	smart;
619ef1f84bSDavid du Colombier 	uchar	smartrs;
629ef1f84bSDavid du Colombier 	uchar	feat;
639ef1f84bSDavid du Colombier 
649ef1f84bSDavid du Colombier 	uvlong	sectors;
659ef1f84bSDavid du Colombier 	char	serial[20+1];
669ef1f84bSDavid du Colombier 	char	firmware[8+1];
679ef1f84bSDavid du Colombier 	char	model[40+1];
689ef1f84bSDavid du Colombier 	char	ident[0x100];
699ef1f84bSDavid du Colombier };
709ef1f84bSDavid du Colombier 
719ef1f84bSDavid du Colombier void	aoeidmove(char *p, ushort *a, unsigned n);
729ef1f84bSDavid du Colombier 
739ef1f84bSDavid du Colombier static	Lock	ctlrlock;
749ef1f84bSDavid du Colombier static	Ctlr	*head;
759ef1f84bSDavid du Colombier static	Ctlr	*tail;
769ef1f84bSDavid du Colombier 
779ef1f84bSDavid du Colombier SDifc sdaoeifc;
789ef1f84bSDavid du Colombier 
799ef1f84bSDavid du Colombier static ushort
gbit16(void * a)809ef1f84bSDavid du Colombier gbit16(void *a)
819ef1f84bSDavid du Colombier {
829ef1f84bSDavid du Colombier 	uchar *i;
839ef1f84bSDavid du Colombier 
849ef1f84bSDavid du Colombier 	i = a;
859ef1f84bSDavid du Colombier 	return i[1] << 8 | i[0];
869ef1f84bSDavid du Colombier }
879ef1f84bSDavid du Colombier 
889ef1f84bSDavid du Colombier static ulong
gbit32(void * a)899ef1f84bSDavid du Colombier gbit32(void *a)
909ef1f84bSDavid du Colombier {
919ef1f84bSDavid du Colombier 	ulong j;
929ef1f84bSDavid du Colombier 	uchar *i;
939ef1f84bSDavid du Colombier 
949ef1f84bSDavid du Colombier 	i = a;
959ef1f84bSDavid du Colombier 	j  = i[3] << 24;
969ef1f84bSDavid du Colombier 	j |= i[2] << 16;
979ef1f84bSDavid du Colombier 	j |= i[1] << 8;
989ef1f84bSDavid du Colombier 	j |= i[0];
999ef1f84bSDavid du Colombier 	return j;
1009ef1f84bSDavid du Colombier }
1019ef1f84bSDavid du Colombier 
1029ef1f84bSDavid du Colombier static uvlong
gbit64(void * a)1039ef1f84bSDavid du Colombier gbit64(void *a)
1049ef1f84bSDavid du Colombier {
1059ef1f84bSDavid du Colombier 	uchar *i;
1069ef1f84bSDavid du Colombier 
1079ef1f84bSDavid du Colombier 	i = a;
1089ef1f84bSDavid du Colombier 	return (uvlong)gbit32(i+4)<<32 | gbit32(i);
1099ef1f84bSDavid du Colombier }
1109ef1f84bSDavid du Colombier 
1119ef1f84bSDavid du Colombier static int
identify(Ctlr * c,ushort * id)1129ef1f84bSDavid du Colombier identify(Ctlr *c, ushort *id)
1139ef1f84bSDavid du Colombier {
1149ef1f84bSDavid du Colombier 	int i;
1159ef1f84bSDavid du Colombier 	uchar oserial[21];
1169ef1f84bSDavid du Colombier 	uvlong osectors, s;
1179ef1f84bSDavid du Colombier 
1189ef1f84bSDavid du Colombier 	osectors = c->sectors;
1199ef1f84bSDavid du Colombier 	memmove(oserial, c->serial, sizeof c->serial);
1209ef1f84bSDavid du Colombier 
1219ef1f84bSDavid du Colombier 	c->feat &= ~(Dllba|Dpower|Dsmart|Dnop);
1229ef1f84bSDavid du Colombier 	i = gbit16(id+83) | gbit16(id+86);
1239ef1f84bSDavid du Colombier 	if(i & (1<<10)){
1249ef1f84bSDavid du Colombier 		c->feat |= Dllba;
1259ef1f84bSDavid du Colombier 		s = gbit64(id+100);
1269ef1f84bSDavid du Colombier 	}else
1279ef1f84bSDavid du Colombier 		s = gbit32(id+60);
1289ef1f84bSDavid du Colombier 
1299ef1f84bSDavid du Colombier 	i = gbit16(id+83);
1309ef1f84bSDavid du Colombier 	if((i>>14) == 1) {
1319ef1f84bSDavid du Colombier 		if(i & (1<<3))
1329ef1f84bSDavid du Colombier 			c->feat |= Dpower;
1339ef1f84bSDavid du Colombier 		i = gbit16(id+82);
1349ef1f84bSDavid du Colombier 		if(i & 1)
1359ef1f84bSDavid du Colombier 			c->feat |= Dsmart;
1369ef1f84bSDavid du Colombier 		if(i & (1<<14))
1379ef1f84bSDavid du Colombier 			c->feat |= Dnop;
1389ef1f84bSDavid du Colombier 	}
1399ef1f84bSDavid du Colombier 
1409ef1f84bSDavid du Colombier 	aoeidmove(c->serial, id+10, 20);
1419ef1f84bSDavid du Colombier 	aoeidmove(c->firmware, id+23, 8);
1429ef1f84bSDavid du Colombier 	aoeidmove(c->model, id+27, 40);
1439ef1f84bSDavid du Colombier 
1449ef1f84bSDavid du Colombier 	if((osectors == 0 || osectors != s) &&
1459ef1f84bSDavid du Colombier 	    memcmp(oserial, c->serial, sizeof oserial) != 0){
1469ef1f84bSDavid du Colombier 		c->sectors = s;
1479ef1f84bSDavid du Colombier 		c->mediachange = 1;
1489ef1f84bSDavid du Colombier 		c->vers++;
1499ef1f84bSDavid du Colombier 	}
1509ef1f84bSDavid du Colombier 	return 0;
1519ef1f84bSDavid du Colombier }
1529ef1f84bSDavid du Colombier 
1539ef1f84bSDavid du Colombier /* must call with d qlocked */
1549ef1f84bSDavid du Colombier static int
aoeidentify(Ctlr * d,SDunit * u)1559ef1f84bSDavid du Colombier aoeidentify(Ctlr *d, SDunit *u)
1569ef1f84bSDavid du Colombier {
1579ef1f84bSDavid du Colombier 	Chan *c;
1589ef1f84bSDavid du Colombier 
1599ef1f84bSDavid du Colombier 	c = nil;
1609ef1f84bSDavid du Colombier 	if(waserror()){
1619ef1f84bSDavid du Colombier 		if(c)
1629ef1f84bSDavid du Colombier 			cclose(c);
1639ef1f84bSDavid du Colombier 		iprint("aoeidentify: %s\n", up->errstr);
1649ef1f84bSDavid du Colombier 		nexterror();
1659ef1f84bSDavid du Colombier 	}
1669ef1f84bSDavid du Colombier 
1679ef1f84bSDavid du Colombier 	uprint("%s/ident", d->path);
1689ef1f84bSDavid du Colombier 	c = namec(up->genbuf, Aopen, OREAD, 0);
1699ef1f84bSDavid du Colombier 	c->dev->read(c, d->ident, sizeof d->ident, 0);
1709ef1f84bSDavid du Colombier 
1719ef1f84bSDavid du Colombier 	poperror();
1729ef1f84bSDavid du Colombier 	cclose(c);
1739ef1f84bSDavid du Colombier 
1749ef1f84bSDavid du Colombier 	d->feat = 0;
1759ef1f84bSDavid du Colombier 	d->smart = 0;
1769ef1f84bSDavid du Colombier 	identify(d, (ushort*)d->ident);
1779ef1f84bSDavid du Colombier 
1789ef1f84bSDavid du Colombier 	memset(u->inquiry, 0, sizeof u->inquiry);
1799ef1f84bSDavid du Colombier 	u->inquiry[2] = 2;
1809ef1f84bSDavid du Colombier 	u->inquiry[3] = 2;
1819ef1f84bSDavid du Colombier 	u->inquiry[4] = sizeof u->inquiry - 4;
1829ef1f84bSDavid du Colombier 	memmove(u->inquiry+8, d->model, 40);
1839ef1f84bSDavid du Colombier 
1849ef1f84bSDavid du Colombier 	return 0;
1859ef1f84bSDavid du Colombier }
1869ef1f84bSDavid du Colombier 
1879ef1f84bSDavid du Colombier static Ctlr*
ctlrlookup(char * path)1889ef1f84bSDavid du Colombier ctlrlookup(char *path)
1899ef1f84bSDavid du Colombier {
1909ef1f84bSDavid du Colombier 	Ctlr *c;
1919ef1f84bSDavid du Colombier 
1929ef1f84bSDavid du Colombier 	lock(&ctlrlock);
1939ef1f84bSDavid du Colombier 	for(c = head; c; c = c->next)
1949ef1f84bSDavid du Colombier 		if(strcmp(c->path, path) == 0)
1959ef1f84bSDavid du Colombier 			break;
1969ef1f84bSDavid du Colombier 	unlock(&ctlrlock);
1979ef1f84bSDavid du Colombier 	return c;
1989ef1f84bSDavid du Colombier }
1999ef1f84bSDavid du Colombier 
2009ef1f84bSDavid du Colombier static Ctlr*
newctlr(char * path)2019ef1f84bSDavid du Colombier newctlr(char *path)
2029ef1f84bSDavid du Colombier {
2039ef1f84bSDavid du Colombier 	Ctlr *c;
2049ef1f84bSDavid du Colombier 
2059ef1f84bSDavid du Colombier 	/* race? */
2069ef1f84bSDavid du Colombier 	if(ctlrlookup(path))
2079ef1f84bSDavid du Colombier 		error(Eexist);
2089ef1f84bSDavid du Colombier 
2099ef1f84bSDavid du Colombier 	if((c = malloc(sizeof *c)) == nil)
2109ef1f84bSDavid du Colombier 		return 0;
2119ef1f84bSDavid du Colombier 	kstrcpy(c->path, path, sizeof c->path);
2129ef1f84bSDavid du Colombier 	lock(&ctlrlock);
2139ef1f84bSDavid du Colombier 	if(head != nil)
2149ef1f84bSDavid du Colombier 		tail->next = c;
2159ef1f84bSDavid du Colombier 	else
2169ef1f84bSDavid du Colombier 		head = c;
2179ef1f84bSDavid du Colombier 	tail = c;
2189ef1f84bSDavid du Colombier 	unlock(&ctlrlock);
2199ef1f84bSDavid du Colombier 	return c;
2209ef1f84bSDavid du Colombier }
2219ef1f84bSDavid du Colombier 
2229ef1f84bSDavid du Colombier static void
delctlr(Ctlr * c)2239ef1f84bSDavid du Colombier delctlr(Ctlr *c)
2249ef1f84bSDavid du Colombier {
2259ef1f84bSDavid du Colombier 	Ctlr *x, *prev;
2269ef1f84bSDavid du Colombier 
2279ef1f84bSDavid du Colombier 	lock(&ctlrlock);
2289ef1f84bSDavid du Colombier 
2299ef1f84bSDavid du Colombier 	for(prev = 0, x = head; x; prev = x, x = c->next)
2309ef1f84bSDavid du Colombier 		if(strcmp(c->path, x->path) == 0)
2319ef1f84bSDavid du Colombier 			break;
2329ef1f84bSDavid du Colombier 	if(x == 0){
2339ef1f84bSDavid du Colombier 		unlock(&ctlrlock);
2349ef1f84bSDavid du Colombier 		error(Enonexist);
2359ef1f84bSDavid du Colombier 	}
2369ef1f84bSDavid du Colombier 
2379ef1f84bSDavid du Colombier 	if(prev)
2389ef1f84bSDavid du Colombier 		prev->next = x->next;
2399ef1f84bSDavid du Colombier 	else
2409ef1f84bSDavid du Colombier 		head = x->next;
2419ef1f84bSDavid du Colombier 	if(x->next == nil)
2429ef1f84bSDavid du Colombier 		tail = prev;
2439ef1f84bSDavid du Colombier 	unlock(&ctlrlock);
2449ef1f84bSDavid du Colombier 
2459ef1f84bSDavid du Colombier 	if(x->c)
2469ef1f84bSDavid du Colombier 		cclose(x->c);
2479ef1f84bSDavid du Colombier 	free(x);
2489ef1f84bSDavid du Colombier }
2499ef1f84bSDavid du Colombier 
2509ef1f84bSDavid du Colombier /* don't call aoeprobe from within a loop; it loops internally retrying open. */
2519ef1f84bSDavid du Colombier static SDev*
aoeprobe(char * path,SDev * s)2529ef1f84bSDavid du Colombier aoeprobe(char *path, SDev *s)
2539ef1f84bSDavid du Colombier {
2549ef1f84bSDavid du Colombier 	int n, i;
2559ef1f84bSDavid du Colombier 	char *p;
2569ef1f84bSDavid du Colombier 	Chan *c;
2579ef1f84bSDavid du Colombier 	Ctlr *ctlr;
2589ef1f84bSDavid du Colombier 
2599ef1f84bSDavid du Colombier 	if((p = strrchr(path, '/')) == 0)
2609ef1f84bSDavid du Colombier 		error(Ebadarg);
2619ef1f84bSDavid du Colombier 	*p = 0;
2629ef1f84bSDavid du Colombier 	uprint("%s/ctl", path);
2639ef1f84bSDavid du Colombier 	*p = '/';
2649ef1f84bSDavid du Colombier 
2659ef1f84bSDavid du Colombier 	c = namec(up->genbuf, Aopen, OWRITE, 0);
2669ef1f84bSDavid du Colombier 	if(waserror()) {
2679ef1f84bSDavid du Colombier 		cclose(c);
2689ef1f84bSDavid du Colombier 		nexterror();
2699ef1f84bSDavid du Colombier 	}
2709ef1f84bSDavid du Colombier 	n = uprint("discover %s", p+1);
2719ef1f84bSDavid du Colombier 	c->dev->write(c, up->genbuf, n, 0);
2729ef1f84bSDavid du Colombier 	poperror();
2739ef1f84bSDavid du Colombier 	cclose(c);
2749ef1f84bSDavid du Colombier 
2759ef1f84bSDavid du Colombier 	for(i = 0; i < Probemax; i++){
2769ef1f84bSDavid du Colombier 		tsleep(&up->sleep, return0, 0, Probeintvl);
2779ef1f84bSDavid du Colombier 		uprint("%s/ident", path);
2789ef1f84bSDavid du Colombier 		if(!waserror()) {
2799ef1f84bSDavid du Colombier 			c = namec(up->genbuf, Aopen, OREAD, 0);
2809ef1f84bSDavid du Colombier 			poperror();
2819ef1f84bSDavid du Colombier 			cclose(c);
2829ef1f84bSDavid du Colombier 			break;
2839ef1f84bSDavid du Colombier 		}
2849ef1f84bSDavid du Colombier 	}
2859ef1f84bSDavid du Colombier 	if(i >= Probemax)
2869ef1f84bSDavid du Colombier 		error(Etimedout);
2879ef1f84bSDavid du Colombier 	uprint("%s/ident", path);
2889ef1f84bSDavid du Colombier 	ctlr = newctlr(path);
2899ef1f84bSDavid du Colombier 	if(ctlr == nil || s == nil && (s = malloc(sizeof *s)) == nil)
2909ef1f84bSDavid du Colombier 		return nil;
2919ef1f84bSDavid du Colombier 	s->ctlr = ctlr;
2929ef1f84bSDavid du Colombier 	s->ifc = &sdaoeifc;
2939ef1f84bSDavid du Colombier 	s->nunit = 1;
2949ef1f84bSDavid du Colombier 	return s;
2959ef1f84bSDavid du Colombier }
2969ef1f84bSDavid du Colombier 
2979ef1f84bSDavid du Colombier static char 	*probef[32];
2989ef1f84bSDavid du Colombier static int 	nprobe;
2999ef1f84bSDavid du Colombier 
3009ef1f84bSDavid du Colombier static int
pnpprobeid(char * s)3019ef1f84bSDavid du Colombier pnpprobeid(char *s)
3029ef1f84bSDavid du Colombier {
3039ef1f84bSDavid du Colombier 	if(strlen(s) < 2)
3049ef1f84bSDavid du Colombier 		return 0;
3059ef1f84bSDavid du Colombier 	return s[1] == '!'? s[0]: 'e';
3069ef1f84bSDavid du Colombier }
3079ef1f84bSDavid du Colombier 
3089ef1f84bSDavid du Colombier static SDev*
aoepnp(void)3099ef1f84bSDavid du Colombier aoepnp(void)
3109ef1f84bSDavid du Colombier {
3119ef1f84bSDavid du Colombier 	int i, id;
3129ef1f84bSDavid du Colombier 	char *p;
3139ef1f84bSDavid du Colombier 	SDev *h, *t, *s;
3149ef1f84bSDavid du Colombier 
3159ef1f84bSDavid du Colombier 	if((p = getconf("aoedev")) == 0)
3169ef1f84bSDavid du Colombier 		return 0;
3179ef1f84bSDavid du Colombier 	nprobe = tokenize(p, probef, nelem(probef));
3189ef1f84bSDavid du Colombier 	h = t = 0;
3199ef1f84bSDavid du Colombier 	for(i = 0; i < nprobe; i++){
3209ef1f84bSDavid du Colombier 		id = pnpprobeid(probef[i]);
3219ef1f84bSDavid du Colombier 		if(id == 0)
3229ef1f84bSDavid du Colombier 			continue;
3239ef1f84bSDavid du Colombier 		s = malloc(sizeof *s);
3249ef1f84bSDavid du Colombier 		if(s == nil)
3259ef1f84bSDavid du Colombier 			break;
3269ef1f84bSDavid du Colombier 		s->ctlr = 0;
3279ef1f84bSDavid du Colombier 		s->idno = id;
3289ef1f84bSDavid du Colombier 		s->ifc = &sdaoeifc;
3299ef1f84bSDavid du Colombier 		s->nunit = 1;
3309ef1f84bSDavid du Colombier 
3319ef1f84bSDavid du Colombier 		if(h)
3329ef1f84bSDavid du Colombier 			t->next = s;
3339ef1f84bSDavid du Colombier 		else
3349ef1f84bSDavid du Colombier 			h = s;
3359ef1f84bSDavid du Colombier 		t = s;
3369ef1f84bSDavid du Colombier 	}
3379ef1f84bSDavid du Colombier 	return h;
3389ef1f84bSDavid du Colombier }
3399ef1f84bSDavid du Colombier 
3409ef1f84bSDavid du Colombier static Ctlr*
pnpprobe(SDev * sd)3419ef1f84bSDavid du Colombier pnpprobe(SDev *sd)
3429ef1f84bSDavid du Colombier {
3439ef1f84bSDavid du Colombier 	ulong start;
3449ef1f84bSDavid du Colombier 	char *p;
3459ef1f84bSDavid du Colombier 	static int i;
3469ef1f84bSDavid du Colombier 
3479ef1f84bSDavid du Colombier 	if(i > nprobe)
3489ef1f84bSDavid du Colombier 		return 0;
3499ef1f84bSDavid du Colombier 	p = probef[i++];
3509ef1f84bSDavid du Colombier 	if(strlen(p) < 2)
3519ef1f84bSDavid du Colombier 		return 0;
3529ef1f84bSDavid du Colombier 	if(p[1] == '!')
3539ef1f84bSDavid du Colombier 		p += 2;
3549ef1f84bSDavid du Colombier 
3559ef1f84bSDavid du Colombier 	start = TK2MS(sys->ticks);
3569ef1f84bSDavid du Colombier 	if(waserror()){
3579ef1f84bSDavid du Colombier 		print("#æ: pnpprobe failed in %lud ms: %s: %s\n",
3589ef1f84bSDavid du Colombier 			TK2MS(sys->ticks) - start, probef[i-1],
3599ef1f84bSDavid du Colombier 			up->errstr);
3609ef1f84bSDavid du Colombier 		return nil;
3619ef1f84bSDavid du Colombier 	}
3629ef1f84bSDavid du Colombier 	sd = aoeprobe(p, sd);			/* does a round of probing */
3639ef1f84bSDavid du Colombier 	poperror();
3649ef1f84bSDavid du Colombier 	print("#æ: pnpprobe established %s in %lud ms\n",
3659ef1f84bSDavid du Colombier 		probef[i-1], TK2MS(sys->ticks) - start);
3669ef1f84bSDavid du Colombier 	return sd->ctlr;
3679ef1f84bSDavid du Colombier }
3689ef1f84bSDavid du Colombier 
3699ef1f84bSDavid du Colombier 
3709ef1f84bSDavid du Colombier static int
aoeverify(SDunit * u)3719ef1f84bSDavid du Colombier aoeverify(SDunit *u)
3729ef1f84bSDavid du Colombier {
3739ef1f84bSDavid du Colombier 	SDev *s;
3749ef1f84bSDavid du Colombier 	Ctlr *c;
3759ef1f84bSDavid du Colombier 
3769ef1f84bSDavid du Colombier 	s = u->dev;
3779ef1f84bSDavid du Colombier 	c = s->ctlr;
3789ef1f84bSDavid du Colombier 	if(c == nil && (s->ctlr = c = pnpprobe(s)) == nil)
3799ef1f84bSDavid du Colombier 		return 0;
3809ef1f84bSDavid du Colombier 	c->mediachange = 1;
3819ef1f84bSDavid du Colombier 	return 1;
3829ef1f84bSDavid du Colombier }
3839ef1f84bSDavid du Colombier 
3849ef1f84bSDavid du Colombier static int
aoeconnect(SDunit * u,Ctlr * c)3859ef1f84bSDavid du Colombier aoeconnect(SDunit *u, Ctlr *c)
3869ef1f84bSDavid du Colombier {
3879ef1f84bSDavid du Colombier 	qlock(c);
3889ef1f84bSDavid du Colombier 	if(waserror()){
3899ef1f84bSDavid du Colombier 		qunlock(c);
3909ef1f84bSDavid du Colombier 		return -1;
3919ef1f84bSDavid du Colombier 	}
3929ef1f84bSDavid du Colombier 
3939ef1f84bSDavid du Colombier 	aoeidentify(u->dev->ctlr, u);
3949ef1f84bSDavid du Colombier 	if(c->c)
3959ef1f84bSDavid du Colombier 		cclose(c->c);
3969ef1f84bSDavid du Colombier 	c->c = 0;
3979ef1f84bSDavid du Colombier 	uprint("%s/data", c->path);
3989ef1f84bSDavid du Colombier 	c->c = namec(up->genbuf, Aopen, ORDWR, 0);
3999ef1f84bSDavid du Colombier 	qunlock(c);
4009ef1f84bSDavid du Colombier 	poperror();
4019ef1f84bSDavid du Colombier 
4029ef1f84bSDavid du Colombier 	return 0;
4039ef1f84bSDavid du Colombier }
4049ef1f84bSDavid du Colombier 
4059ef1f84bSDavid du Colombier static int
aoeonline(SDunit * u)4069ef1f84bSDavid du Colombier aoeonline(SDunit *u)
4079ef1f84bSDavid du Colombier {
4089ef1f84bSDavid du Colombier 	Ctlr *c;
4099ef1f84bSDavid du Colombier 	int r;
4109ef1f84bSDavid du Colombier 
4119ef1f84bSDavid du Colombier 	c = u->dev->ctlr;
4129ef1f84bSDavid du Colombier 	r = 0;
4139ef1f84bSDavid du Colombier 
4149ef1f84bSDavid du Colombier 	if((c->feat&Datapi) && c->mediachange){
4159ef1f84bSDavid du Colombier 		if(aoeconnect(u, c) == 0 && (r = scsionline(u)) > 0)
4169ef1f84bSDavid du Colombier 			c->mediachange = 0;
4179ef1f84bSDavid du Colombier 		return r;
4189ef1f84bSDavid du Colombier 	}
4199ef1f84bSDavid du Colombier 
4209ef1f84bSDavid du Colombier 	if(c->mediachange){
4219ef1f84bSDavid du Colombier 		if(aoeconnect(u, c) == -1)
4229ef1f84bSDavid du Colombier 			return 0;
4239ef1f84bSDavid du Colombier 		r = 2;
4249ef1f84bSDavid du Colombier 		c->mediachange = 0;
4259ef1f84bSDavid du Colombier 		u->sectors = c->sectors;
4269ef1f84bSDavid du Colombier 		u->secsize = Aoesectsz;
4279ef1f84bSDavid du Colombier 	} else
4289ef1f84bSDavid du Colombier 		r = 1;
4299ef1f84bSDavid du Colombier 
4309ef1f84bSDavid du Colombier 	return r;
4319ef1f84bSDavid du Colombier }
4329ef1f84bSDavid du Colombier 
4339ef1f84bSDavid du Colombier static int
aoerio(SDreq * r)4349ef1f84bSDavid du Colombier aoerio(SDreq *r)
4359ef1f84bSDavid du Colombier {
436*05ffe48fSDavid du Colombier 	int i;
437*05ffe48fSDavid du Colombier 	ulong count;
4389ef1f84bSDavid du Colombier 	uvlong lba;
4399ef1f84bSDavid du Colombier 	char *name;
4409ef1f84bSDavid du Colombier 	uchar *cmd;
4419ef1f84bSDavid du Colombier 	long (*rio)(Chan*, void*, long, vlong);
4429ef1f84bSDavid du Colombier 	Ctlr *c;
4439ef1f84bSDavid du Colombier 	SDunit *unit;
4449ef1f84bSDavid du Colombier 
4459ef1f84bSDavid du Colombier 	unit = r->unit;
4469ef1f84bSDavid du Colombier 	c = unit->dev->ctlr;
4479ef1f84bSDavid du Colombier //	if(c->feat & Datapi)
4489ef1f84bSDavid du Colombier //		return aoeriopkt(r, d);
4499ef1f84bSDavid du Colombier 
4509ef1f84bSDavid du Colombier 	cmd = r->cmd;
4519ef1f84bSDavid du Colombier 	name = unit->name;
4529ef1f84bSDavid du Colombier 
453a72b0d60SDavid du Colombier 	if(*cmd == ScmdSynccache || *cmd == ScmdSynccache16)
4549ef1f84bSDavid du Colombier //		qlock(c);
4559ef1f84bSDavid du Colombier //		i = flushcache();
4569ef1f84bSDavid du Colombier //		qunlock(c);
4579ef1f84bSDavid du Colombier //		if(i == 0)
4589ef1f84bSDavid du Colombier //			return sdsetsense(r, SDok, 0, 0, 0);
4599ef1f84bSDavid du Colombier 		return sdsetsense(r, SDcheck, 3, 0xc, 2);
4609ef1f84bSDavid du Colombier 
4619ef1f84bSDavid du Colombier 	if((i = sdfakescsi(r, c->ident, sizeof c->ident)) != SDnostatus){
4629ef1f84bSDavid du Colombier 		r->status = i;
4639ef1f84bSDavid du Colombier 		return i;
4649ef1f84bSDavid du Colombier 	}
4659ef1f84bSDavid du Colombier 
4669ef1f84bSDavid du Colombier 	switch(*cmd){
467a72b0d60SDavid du Colombier 	case ScmdRead16:
468a72b0d60SDavid du Colombier 	case ScmdExtread:
4699ef1f84bSDavid du Colombier 		rio = c->c->dev->read;
4709ef1f84bSDavid du Colombier 		break;
471a72b0d60SDavid du Colombier 	case ScmdWrite16:
472a72b0d60SDavid du Colombier 	case ScmdExtwrite:
4739ef1f84bSDavid du Colombier 		rio = c->c->dev->write;
4749ef1f84bSDavid du Colombier 		break;
4759ef1f84bSDavid du Colombier 	default:
4769ef1f84bSDavid du Colombier 		print("%s: bad cmd %#.2ux\n", name, cmd[0]);
4779ef1f84bSDavid du Colombier 		r->status = SDcheck;
4789ef1f84bSDavid du Colombier 		return SDcheck;
4799ef1f84bSDavid du Colombier 	}
4809ef1f84bSDavid du Colombier 
4819ef1f84bSDavid du Colombier 	if(r->data == nil)
4829ef1f84bSDavid du Colombier 		return SDok;
4839ef1f84bSDavid du Colombier 
4849ef1f84bSDavid du Colombier 	if(r->clen == 16){
485*05ffe48fSDavid du Colombier 		/* ata commands only go to 48-bit lba */
4869ef1f84bSDavid du Colombier 		if(cmd[2] || cmd[3])
4879ef1f84bSDavid du Colombier 			return sdsetsense(r, SDcheck, 3, 0xc, 2);
4889ef1f84bSDavid du Colombier 	}
489*05ffe48fSDavid du Colombier 	scsilbacount(cmd, r->clen, &lba, &count);
4909ef1f84bSDavid du Colombier 	count *= Aoesectsz;
4919ef1f84bSDavid du Colombier 
4929ef1f84bSDavid du Colombier 	if(r->dlen < count)
4939ef1f84bSDavid du Colombier 		count = r->dlen & ~0x1ff;
4949ef1f84bSDavid du Colombier 
4959ef1f84bSDavid du Colombier 	if(waserror()){
4969ef1f84bSDavid du Colombier 		if(strcmp(up->errstr, Echange) == 0 ||
497406c76faSDavid du Colombier 		    strcmp(up->errstr, Eaoedown) == 0)
4989ef1f84bSDavid du Colombier 			unit->sectors = 0;
4999ef1f84bSDavid du Colombier 		nexterror();
5009ef1f84bSDavid du Colombier 	}
5019ef1f84bSDavid du Colombier 	r->rlen = rio(c->c, r->data, count, Aoesectsz * lba);
5029ef1f84bSDavid du Colombier 	poperror();
5039ef1f84bSDavid du Colombier 	r->status = SDok;
5049ef1f84bSDavid du Colombier 	return SDok;
5059ef1f84bSDavid du Colombier }
5069ef1f84bSDavid du Colombier 
5079ef1f84bSDavid du Colombier static char *smarttab[] = {
5089ef1f84bSDavid du Colombier 	"unset",
5099ef1f84bSDavid du Colombier 	"error",
5109ef1f84bSDavid du Colombier 	"threshold exceeded",
5119ef1f84bSDavid du Colombier 	"normal"
5129ef1f84bSDavid du Colombier };
5139ef1f84bSDavid du Colombier 
5149ef1f84bSDavid du Colombier static char *
pflag(char * s,char * e,uchar f)5159ef1f84bSDavid du Colombier pflag(char *s, char *e, uchar f)
5169ef1f84bSDavid du Colombier {
5179ef1f84bSDavid du Colombier 	uchar i;
5189ef1f84bSDavid du Colombier 
5199ef1f84bSDavid du Colombier 	for(i = 0; i < 8; i++)
5209ef1f84bSDavid du Colombier 		if(f & (1 << i))
5219ef1f84bSDavid du Colombier 			s = seprint(s, e, "%s ", flagname[i]);
5229ef1f84bSDavid du Colombier 	return seprint(s, e, "\n");
5239ef1f84bSDavid du Colombier }
5249ef1f84bSDavid du Colombier 
5259ef1f84bSDavid du Colombier static int
aoerctl(SDunit * u,char * p,int l)5269ef1f84bSDavid du Colombier aoerctl(SDunit *u, char *p, int l)
5279ef1f84bSDavid du Colombier {
5289ef1f84bSDavid du Colombier 	Ctlr *c;
5299ef1f84bSDavid du Colombier 	char *e, *op;
5309ef1f84bSDavid du Colombier 
5319ef1f84bSDavid du Colombier 	if((c = u->dev->ctlr) == nil)
5329ef1f84bSDavid du Colombier 		return 0;
5339ef1f84bSDavid du Colombier 	e = p+l;
5349ef1f84bSDavid du Colombier 	op = p;
5359ef1f84bSDavid du Colombier 
5369ef1f84bSDavid du Colombier 	p = seprint(p, e, "model\t%s\n", c->model);
5379ef1f84bSDavid du Colombier 	p = seprint(p, e, "serial\t%s\n", c->serial);
5389ef1f84bSDavid du Colombier 	p = seprint(p, e, "firm	%s\n", c->firmware);
5399ef1f84bSDavid du Colombier 	if(c->smartrs == 0xff)
5409ef1f84bSDavid du Colombier 		p = seprint(p, e, "smart\tenable error\n");
5419ef1f84bSDavid du Colombier 	else if(c->smartrs == 0)
5429ef1f84bSDavid du Colombier 		p = seprint(p, e, "smart\tdisabled\n");
5439ef1f84bSDavid du Colombier 	else
5449ef1f84bSDavid du Colombier 		p = seprint(p, e, "smart\t%s\n", smarttab[c->smart]);
5459ef1f84bSDavid du Colombier 	p = seprint(p, e, "flag	");
5469ef1f84bSDavid du Colombier 	p = pflag(p, e, c->feat);
5479ef1f84bSDavid du Colombier 	p = seprint(p, e, "geometry %llud %d\n", c->sectors, Aoesectsz);
5489ef1f84bSDavid du Colombier 	return p-op;
5499ef1f84bSDavid du Colombier }
5509ef1f84bSDavid du Colombier 
5519ef1f84bSDavid du Colombier static int
aoewctl(SDunit *,Cmdbuf * cmd)5529ef1f84bSDavid du Colombier aoewctl(SDunit *, Cmdbuf *cmd)
5539ef1f84bSDavid du Colombier {
5549ef1f84bSDavid du Colombier 	cmderror(cmd, Ebadarg);
5559ef1f84bSDavid du Colombier 	return 0;
5569ef1f84bSDavid du Colombier }
5579ef1f84bSDavid du Colombier 
5589ef1f84bSDavid du Colombier static SDev*
aoeprobew(DevConf * c)5599ef1f84bSDavid du Colombier aoeprobew(DevConf *c)
5609ef1f84bSDavid du Colombier {
5619ef1f84bSDavid du Colombier 	char *p;
5629ef1f84bSDavid du Colombier 
5639ef1f84bSDavid du Colombier 	p = strchr(c->type, '/');
5649ef1f84bSDavid du Colombier 	if(p == nil || strlen(p) > Maxpath - 11)
5659ef1f84bSDavid du Colombier 		error(Ebadarg);
5669ef1f84bSDavid du Colombier 	if(p[1] == '#')
5679ef1f84bSDavid du Colombier 		p++;			/* hack */
5689ef1f84bSDavid du Colombier 	if(ctlrlookup(p))
5699ef1f84bSDavid du Colombier 		error(Einuse);
5709ef1f84bSDavid du Colombier 	return aoeprobe(p, 0);
5719ef1f84bSDavid du Colombier }
5729ef1f84bSDavid du Colombier 
5739ef1f84bSDavid du Colombier static void
aoeclear(SDev * s)5749ef1f84bSDavid du Colombier aoeclear(SDev *s)
5759ef1f84bSDavid du Colombier {
5769ef1f84bSDavid du Colombier 	delctlr((Ctlr *)s->ctlr);
5779ef1f84bSDavid du Colombier }
5789ef1f84bSDavid du Colombier 
5799ef1f84bSDavid du Colombier static char*
aoertopctl(SDev * s,char * p,char * e)5809ef1f84bSDavid du Colombier aoertopctl(SDev *s, char *p, char *e)
5819ef1f84bSDavid du Colombier {
5829ef1f84bSDavid du Colombier 	Ctlr *c;
5839ef1f84bSDavid du Colombier 
5849ef1f84bSDavid du Colombier 	if(s == nil || (c = s->ctlr) == nil)
5859ef1f84bSDavid du Colombier 		return p;
5869ef1f84bSDavid du Colombier 
5879ef1f84bSDavid du Colombier 	return seprint(p, e, "%s aoe %s\n", s->name, c->path);
5889ef1f84bSDavid du Colombier }
5899ef1f84bSDavid du Colombier 
5909ef1f84bSDavid du Colombier static int
aoewtopctl(SDev *,Cmdbuf * cmd)5919ef1f84bSDavid du Colombier aoewtopctl(SDev *, Cmdbuf *cmd)
5929ef1f84bSDavid du Colombier {
5939ef1f84bSDavid du Colombier 	switch(cmd->nf){
5949ef1f84bSDavid du Colombier 	default:
5959ef1f84bSDavid du Colombier 		cmderror(cmd, Ebadarg);
5969ef1f84bSDavid du Colombier 	}
5979ef1f84bSDavid du Colombier 	return 0;
5989ef1f84bSDavid du Colombier }
5999ef1f84bSDavid du Colombier 
6009ef1f84bSDavid du Colombier SDifc sdaoeifc = {
6019ef1f84bSDavid du Colombier 	"aoe",
6029ef1f84bSDavid du Colombier 
6039ef1f84bSDavid du Colombier 	aoepnp,
6049ef1f84bSDavid du Colombier 	nil,		/* legacy */
6059ef1f84bSDavid du Colombier 	nil,		/* enable */
6069ef1f84bSDavid du Colombier 	nil,		/* disable */
6079ef1f84bSDavid du Colombier 
6089ef1f84bSDavid du Colombier 	aoeverify,
6099ef1f84bSDavid du Colombier 	aoeonline,
6109ef1f84bSDavid du Colombier 	aoerio,
6119ef1f84bSDavid du Colombier 	aoerctl,
6129ef1f84bSDavid du Colombier 	aoewctl,
6139ef1f84bSDavid du Colombier 
6149ef1f84bSDavid du Colombier 	scsibio,
6159ef1f84bSDavid du Colombier 	aoeprobew,	/* probe */
6169ef1f84bSDavid du Colombier 	aoeclear,	/* clear */
6179ef1f84bSDavid du Colombier 	aoertopctl,
6189ef1f84bSDavid du Colombier 	aoewtopctl,
6199ef1f84bSDavid du Colombier };
620