xref: /plan9/sys/src/9/port/sdaoe.c (revision a587111c8770e522e3667ff2b63cba8a77811dd9)
121abd8f2SDavid du Colombier /*
221abd8f2SDavid du Colombier  * aoe sd driver, copyright © 2007 coraid
321abd8f2SDavid du Colombier  */
421abd8f2SDavid du Colombier 
521abd8f2SDavid du Colombier #include "u.h"
621abd8f2SDavid du Colombier #include "../port/lib.h"
721abd8f2SDavid du Colombier #include "mem.h"
821abd8f2SDavid du Colombier #include "dat.h"
921abd8f2SDavid du Colombier #include "fns.h"
1021abd8f2SDavid du Colombier #include "io.h"
1121abd8f2SDavid du Colombier #include "../port/error.h"
1221abd8f2SDavid du Colombier #include "../port/sd.h"
1321abd8f2SDavid du Colombier #include "../port/netif.h"
1421abd8f2SDavid du Colombier #include "../port/aoe.h"
1521abd8f2SDavid du Colombier 
1621abd8f2SDavid du Colombier #define uprint(...)	snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
1721abd8f2SDavid du Colombier 
1821abd8f2SDavid du Colombier enum {
1921abd8f2SDavid du Colombier 	Nctlr	= 32,
2021abd8f2SDavid du Colombier 	Maxpath	= 128,
21bc8903feSDavid du Colombier 
22bc8903feSDavid du Colombier 	Probeintvl	= 100,		/* ms. between probes */
2308d9be5dSDavid du Colombier 	Probemax	= 20,		/* max probes */
2421abd8f2SDavid du Colombier };
2521abd8f2SDavid du Colombier 
2621abd8f2SDavid du Colombier enum {
2721abd8f2SDavid du Colombier 	/* sync with ahci.h */
2821abd8f2SDavid du Colombier 	Dllba 	= 1<<0,
2921abd8f2SDavid du Colombier 	Dsmart	= 1<<1,
3021abd8f2SDavid du Colombier 	Dpower	= 1<<2,
3121abd8f2SDavid du Colombier 	Dnop	= 1<<3,
3221abd8f2SDavid du Colombier 	Datapi	= 1<<4,
3321abd8f2SDavid du Colombier 	Datapi16= 1<<5,
3421abd8f2SDavid du Colombier };
3521abd8f2SDavid du Colombier 
3621abd8f2SDavid du Colombier static char *flagname[] = {
3721abd8f2SDavid du Colombier 	"llba",
3821abd8f2SDavid du Colombier 	"smart",
3921abd8f2SDavid du Colombier 	"power",
4021abd8f2SDavid du Colombier 	"nop",
4121abd8f2SDavid du Colombier 	"atapi",
4221abd8f2SDavid du Colombier 	"atapi16",
4321abd8f2SDavid du Colombier };
4421abd8f2SDavid du Colombier 
4521abd8f2SDavid du Colombier typedef struct Ctlr Ctlr;
4621abd8f2SDavid du Colombier struct Ctlr{
4721abd8f2SDavid du Colombier 	QLock;
4821abd8f2SDavid du Colombier 
4921abd8f2SDavid du Colombier 	Ctlr	*next;
5021abd8f2SDavid du Colombier 	SDunit	*unit;
5121abd8f2SDavid du Colombier 
5221abd8f2SDavid du Colombier 	char	path[Maxpath];
5321abd8f2SDavid du Colombier 	Chan	*c;
5421abd8f2SDavid du Colombier 
5521abd8f2SDavid du Colombier 	ulong	vers;
5621abd8f2SDavid du Colombier 	uchar	mediachange;
5721abd8f2SDavid du Colombier 	uchar	flag;
5821abd8f2SDavid du Colombier 	uchar	smart;
5921abd8f2SDavid du Colombier 	uchar	smartrs;
6021abd8f2SDavid du Colombier 	uchar	feat;
6121abd8f2SDavid du Colombier 
6221abd8f2SDavid du Colombier 	uvlong	sectors;
6321abd8f2SDavid du Colombier 	char	serial[20+1];
6421abd8f2SDavid du Colombier 	char	firmware[8+1];
6521abd8f2SDavid du Colombier 	char	model[40+1];
6621abd8f2SDavid du Colombier 	char	ident[0x100];
6721abd8f2SDavid du Colombier };
6821abd8f2SDavid du Colombier 
6945dfec46SDavid du Colombier void	aoeidmove(char *p, ushort *a, unsigned n);
7045dfec46SDavid du Colombier 
7121abd8f2SDavid du Colombier static	Lock	ctlrlock;
7221abd8f2SDavid du Colombier static	Ctlr	*head;
7321abd8f2SDavid du Colombier static	Ctlr	*tail;
7421abd8f2SDavid du Colombier 
7521abd8f2SDavid du Colombier SDifc sdaoeifc;
7621abd8f2SDavid du Colombier 
7721abd8f2SDavid du Colombier static ushort
gbit16(void * a)7821abd8f2SDavid du Colombier gbit16(void *a)
7921abd8f2SDavid du Colombier {
8021abd8f2SDavid du Colombier 	uchar *i;
8121abd8f2SDavid du Colombier 
8221abd8f2SDavid du Colombier 	i = a;
8321abd8f2SDavid du Colombier 	return i[1] << 8 | i[0];
8421abd8f2SDavid du Colombier }
8521abd8f2SDavid du Colombier 
8691b330d9SDavid du Colombier static ulong
gbit32(void * a)8721abd8f2SDavid du Colombier gbit32(void *a)
8821abd8f2SDavid du Colombier {
8991b330d9SDavid du Colombier 	ulong j;
9021abd8f2SDavid du Colombier 	uchar *i;
9121abd8f2SDavid du Colombier 
9221abd8f2SDavid du Colombier 	i = a;
9321abd8f2SDavid du Colombier 	j  = i[3] << 24;
9421abd8f2SDavid du Colombier 	j |= i[2] << 16;
9521abd8f2SDavid du Colombier 	j |= i[1] << 8;
9621abd8f2SDavid du Colombier 	j |= i[0];
9721abd8f2SDavid du Colombier 	return j;
9821abd8f2SDavid du Colombier }
9921abd8f2SDavid du Colombier 
10021abd8f2SDavid du Colombier static uvlong
gbit64(void * a)10121abd8f2SDavid du Colombier gbit64(void *a)
10221abd8f2SDavid du Colombier {
10321abd8f2SDavid du Colombier 	uchar *i;
10421abd8f2SDavid du Colombier 
10521abd8f2SDavid du Colombier 	i = a;
10621abd8f2SDavid du Colombier 	return (uvlong)gbit32(i+4)<<32 | gbit32(i);
10721abd8f2SDavid du Colombier }
10821abd8f2SDavid du Colombier 
10921abd8f2SDavid du Colombier static int
identify(Ctlr * c,ushort * id)11021abd8f2SDavid du Colombier identify(Ctlr *c, ushort *id)
11121abd8f2SDavid du Colombier {
11221abd8f2SDavid du Colombier 	int i;
11321abd8f2SDavid du Colombier 	uchar oserial[21];
11421abd8f2SDavid du Colombier 	uvlong osectors, s;
11521abd8f2SDavid du Colombier 
11621abd8f2SDavid du Colombier 	osectors = c->sectors;
11721abd8f2SDavid du Colombier 	memmove(oserial, c->serial, sizeof c->serial);
11821abd8f2SDavid du Colombier 
11921abd8f2SDavid du Colombier 	c->feat &= ~(Dllba|Dpower|Dsmart|Dnop);
12021abd8f2SDavid du Colombier 	i = gbit16(id+83) | gbit16(id+86);
12121abd8f2SDavid du Colombier 	if(i & (1<<10)){
12221abd8f2SDavid du Colombier 		c->feat |= Dllba;
12321abd8f2SDavid du Colombier 		s = gbit64(id+100);
12421abd8f2SDavid du Colombier 	}else
12521abd8f2SDavid du Colombier 		s = gbit32(id+60);
12621abd8f2SDavid du Colombier 
12721abd8f2SDavid du Colombier 	i = gbit16(id+83);
12821abd8f2SDavid du Colombier 	if((i>>14) == 1) {
12921abd8f2SDavid du Colombier 		if(i & (1<<3))
13021abd8f2SDavid du Colombier 			c->feat |= Dpower;
13121abd8f2SDavid du Colombier 		i = gbit16(id+82);
13221abd8f2SDavid du Colombier 		if(i & 1)
13321abd8f2SDavid du Colombier 			c->feat |= Dsmart;
13421abd8f2SDavid du Colombier 		if(i & (1<<14))
13521abd8f2SDavid du Colombier 			c->feat |= Dnop;
13621abd8f2SDavid du Colombier 	}
13721abd8f2SDavid du Colombier 
13845dfec46SDavid du Colombier 	aoeidmove(c->serial, id+10, 20);
13945dfec46SDavid du Colombier 	aoeidmove(c->firmware, id+23, 8);
14045dfec46SDavid du Colombier 	aoeidmove(c->model, id+27, 40);
14121abd8f2SDavid du Colombier 
14221abd8f2SDavid du Colombier 	if((osectors == 0 || osectors != s) &&
14321abd8f2SDavid du Colombier 	    memcmp(oserial, c->serial, sizeof oserial) != 0){
14421abd8f2SDavid du Colombier 		c->sectors = s;
14521abd8f2SDavid du Colombier 		c->mediachange = 1;
14621abd8f2SDavid du Colombier 		c->vers++;
14721abd8f2SDavid du Colombier 	}
14821abd8f2SDavid du Colombier 	return 0;
14921abd8f2SDavid du Colombier }
15021abd8f2SDavid du Colombier 
15121abd8f2SDavid du Colombier /* must call with d qlocked */
15221abd8f2SDavid du Colombier static int
aoeidentify(Ctlr * d,SDunit * u)15321abd8f2SDavid du Colombier aoeidentify(Ctlr *d, SDunit *u)
15421abd8f2SDavid du Colombier {
15521abd8f2SDavid du Colombier 	Chan *c;
15621abd8f2SDavid du Colombier 
15721abd8f2SDavid du Colombier 	c = nil;
15821abd8f2SDavid du Colombier 	if(waserror()){
15921abd8f2SDavid du Colombier 		if(c)
16021abd8f2SDavid du Colombier 			cclose(c);
16121abd8f2SDavid du Colombier 		iprint("aoeidentify: %s\n", up->errstr);
162421195e0SDavid du Colombier 		nexterror();
16321abd8f2SDavid du Colombier 	}
16421abd8f2SDavid du Colombier 
16521abd8f2SDavid du Colombier 	uprint("%s/ident", d->path);
16621abd8f2SDavid du Colombier 	c = namec(up->genbuf, Aopen, OREAD, 0);
16721abd8f2SDavid du Colombier 	devtab[c->type]->read(c, d->ident, sizeof d->ident, 0);
16821abd8f2SDavid du Colombier 
16921abd8f2SDavid du Colombier 	poperror();
17021abd8f2SDavid du Colombier 	cclose(c);
17121abd8f2SDavid du Colombier 
17221abd8f2SDavid du Colombier 	d->feat = 0;
17321abd8f2SDavid du Colombier 	d->smart = 0;
17421abd8f2SDavid du Colombier 	identify(d, (ushort*)d->ident);
17521abd8f2SDavid du Colombier 
17621abd8f2SDavid du Colombier 	memset(u->inquiry, 0, sizeof u->inquiry);
17721abd8f2SDavid du Colombier 	u->inquiry[2] = 2;
17821abd8f2SDavid du Colombier 	u->inquiry[3] = 2;
17921abd8f2SDavid du Colombier 	u->inquiry[4] = sizeof u->inquiry - 4;
18021abd8f2SDavid du Colombier 	memmove(u->inquiry+8, d->model, 40);
18121abd8f2SDavid du Colombier 
18221abd8f2SDavid du Colombier 	return 0;
18321abd8f2SDavid du Colombier }
18421abd8f2SDavid du Colombier 
18521abd8f2SDavid du Colombier static Ctlr*
ctlrlookup(char * path)18621abd8f2SDavid du Colombier ctlrlookup(char *path)
18721abd8f2SDavid du Colombier {
18821abd8f2SDavid du Colombier 	Ctlr *c;
18921abd8f2SDavid du Colombier 
19021abd8f2SDavid du Colombier 	lock(&ctlrlock);
19121abd8f2SDavid du Colombier 	for(c = head; c; c = c->next)
19221abd8f2SDavid du Colombier 		if(strcmp(c->path, path) == 0)
19321abd8f2SDavid du Colombier 			break;
19421abd8f2SDavid du Colombier 	unlock(&ctlrlock);
19521abd8f2SDavid du Colombier 	return c;
19621abd8f2SDavid du Colombier }
19721abd8f2SDavid du Colombier 
19821abd8f2SDavid du Colombier static Ctlr*
newctlr(char * path)19921abd8f2SDavid du Colombier newctlr(char *path)
20021abd8f2SDavid du Colombier {
20121abd8f2SDavid du Colombier 	Ctlr *c;
20221abd8f2SDavid du Colombier 
20321abd8f2SDavid du Colombier 	/* race? */
20421abd8f2SDavid du Colombier 	if(ctlrlookup(path))
20521abd8f2SDavid du Colombier 		error(Eexist);
20621abd8f2SDavid du Colombier 
20721abd8f2SDavid du Colombier 	if((c = malloc(sizeof *c)) == nil)
20821abd8f2SDavid du Colombier 		return 0;
20921abd8f2SDavid du Colombier 	kstrcpy(c->path, path, sizeof c->path);
21021abd8f2SDavid du Colombier 	lock(&ctlrlock);
21121abd8f2SDavid du Colombier 	if(head != nil)
21221abd8f2SDavid du Colombier 		tail->next = c;
21321abd8f2SDavid du Colombier 	else
21421abd8f2SDavid du Colombier 		head = c;
21521abd8f2SDavid du Colombier 	tail = c;
21621abd8f2SDavid du Colombier 	unlock(&ctlrlock);
21721abd8f2SDavid du Colombier 	return c;
21821abd8f2SDavid du Colombier }
21921abd8f2SDavid du Colombier 
22021abd8f2SDavid du Colombier static void
delctlr(Ctlr * c)22121abd8f2SDavid du Colombier delctlr(Ctlr *c)
22221abd8f2SDavid du Colombier {
22321abd8f2SDavid du Colombier 	Ctlr *x, *prev;
22421abd8f2SDavid du Colombier 
22521abd8f2SDavid du Colombier 	lock(&ctlrlock);
22621abd8f2SDavid du Colombier 
22721abd8f2SDavid du Colombier 	for(prev = 0, x = head; x; prev = x, x = c->next)
22821abd8f2SDavid du Colombier 		if(strcmp(c->path, x->path) == 0)
22921abd8f2SDavid du Colombier 			break;
23021abd8f2SDavid du Colombier 	if(x == 0){
23121abd8f2SDavid du Colombier 		unlock(&ctlrlock);
23221abd8f2SDavid du Colombier 		error(Enonexist);
23321abd8f2SDavid du Colombier 	}
23421abd8f2SDavid du Colombier 
23521abd8f2SDavid du Colombier 	if(prev)
23621abd8f2SDavid du Colombier 		prev->next = x->next;
23721abd8f2SDavid du Colombier 	else
23821abd8f2SDavid du Colombier 		head = x->next;
23921abd8f2SDavid du Colombier 	if(x->next == nil)
24021abd8f2SDavid du Colombier 		tail = prev;
24121abd8f2SDavid du Colombier 	unlock(&ctlrlock);
24221abd8f2SDavid du Colombier 
24321abd8f2SDavid du Colombier 	if(x->c)
24421abd8f2SDavid du Colombier 		cclose(x->c);
24521abd8f2SDavid du Colombier 	free(x);
24621abd8f2SDavid du Colombier }
24721abd8f2SDavid du Colombier 
2482f205b96SDavid du Colombier /* don't call aoeprobe from within a loop; it loops internally retrying open. */
24921abd8f2SDavid du Colombier static SDev*
aoeprobe(char * path,SDev * s)25021abd8f2SDavid du Colombier aoeprobe(char *path, SDev *s)
25121abd8f2SDavid du Colombier {
25221abd8f2SDavid du Colombier 	int n, i;
25321abd8f2SDavid du Colombier 	char *p;
25421abd8f2SDavid du Colombier 	Chan *c;
25521abd8f2SDavid du Colombier 	Ctlr *ctlr;
25621abd8f2SDavid du Colombier 
25721abd8f2SDavid du Colombier 	if((p = strrchr(path, '/')) == 0)
25821abd8f2SDavid du Colombier 		error(Ebadarg);
25921abd8f2SDavid du Colombier 	*p = 0;
26021abd8f2SDavid du Colombier 	uprint("%s/ctl", path);
26121abd8f2SDavid du Colombier 	*p = '/';
26221abd8f2SDavid du Colombier 
26321abd8f2SDavid du Colombier 	c = namec(up->genbuf, Aopen, OWRITE, 0);
26421abd8f2SDavid du Colombier 	if(waserror()) {
26521abd8f2SDavid du Colombier 		cclose(c);
26621abd8f2SDavid du Colombier 		nexterror();
26721abd8f2SDavid du Colombier 	}
26821abd8f2SDavid du Colombier 	n = uprint("discover %s", p+1);
26921abd8f2SDavid du Colombier 	devtab[c->type]->write(c, up->genbuf, n, 0);
27021abd8f2SDavid du Colombier 	poperror();
27121abd8f2SDavid du Colombier 	cclose(c);
27221abd8f2SDavid du Colombier 
27320e402b4SDavid du Colombier 	for(i = 0; i < Probemax; i++){
274bc8903feSDavid du Colombier 		tsleep(&up->sleep, return0, 0, Probeintvl);
27521abd8f2SDavid du Colombier 		uprint("%s/ident", path);
276c9b6d007SDavid du Colombier 		if(!waserror()) {
27721abd8f2SDavid du Colombier 			c = namec(up->genbuf, Aopen, OREAD, 0);
27821abd8f2SDavid du Colombier 			poperror();
27921abd8f2SDavid du Colombier 			cclose(c);
28021abd8f2SDavid du Colombier 			break;
28121abd8f2SDavid du Colombier 		}
282c9b6d007SDavid du Colombier 	}
28320e402b4SDavid du Colombier 	if(i >= Probemax)
284c9b6d007SDavid du Colombier 		error(Etimedout);
285c9b6d007SDavid du Colombier 	uprint("%s/ident", path);
286c9b6d007SDavid du Colombier 	ctlr = newctlr(path);
287c9b6d007SDavid du Colombier 	if(ctlr == nil || s == nil && (s = malloc(sizeof *s)) == nil)
28821abd8f2SDavid du Colombier 		return nil;
28921abd8f2SDavid du Colombier 	s->ctlr = ctlr;
29021abd8f2SDavid du Colombier 	s->ifc = &sdaoeifc;
29121abd8f2SDavid du Colombier 	s->nunit = 1;
29221abd8f2SDavid du Colombier 	return s;
29321abd8f2SDavid du Colombier }
29421abd8f2SDavid du Colombier 
29521abd8f2SDavid du Colombier static char 	*probef[32];
29621abd8f2SDavid du Colombier static int 	nprobe;
29721abd8f2SDavid du Colombier 
29821abd8f2SDavid du Colombier static int
pnpprobeid(char * s)29921abd8f2SDavid du Colombier pnpprobeid(char *s)
30021abd8f2SDavid du Colombier {
30121abd8f2SDavid du Colombier 	if(strlen(s) < 2)
30221abd8f2SDavid du Colombier 		return 0;
30351d81ba6SDavid du Colombier 	return s[1] == '!'? s[0]: 'e';
30421abd8f2SDavid du Colombier }
30521abd8f2SDavid du Colombier 
30621abd8f2SDavid du Colombier static SDev*
aoepnp(void)30721abd8f2SDavid du Colombier aoepnp(void)
30821abd8f2SDavid du Colombier {
30921abd8f2SDavid du Colombier 	int i, id;
31021abd8f2SDavid du Colombier 	char *p;
31121abd8f2SDavid du Colombier 	SDev *h, *t, *s;
31221abd8f2SDavid du Colombier 
31321abd8f2SDavid du Colombier 	if((p = getconf("aoedev")) == 0)
31421abd8f2SDavid du Colombier 		return 0;
31521abd8f2SDavid du Colombier 	nprobe = tokenize(p, probef, nelem(probef));
31621abd8f2SDavid du Colombier 	h = t = 0;
31721abd8f2SDavid du Colombier 	for(i = 0; i < nprobe; i++){
31821abd8f2SDavid du Colombier 		id = pnpprobeid(probef[i]);
31921abd8f2SDavid du Colombier 		if(id == 0)
32021abd8f2SDavid du Colombier 			continue;
32121abd8f2SDavid du Colombier 		s = malloc(sizeof *s);
32221abd8f2SDavid du Colombier 		if(s == nil)
32321abd8f2SDavid du Colombier 			break;
32421abd8f2SDavid du Colombier 		s->ctlr = 0;
32521abd8f2SDavid du Colombier 		s->idno = id;
32621abd8f2SDavid du Colombier 		s->ifc = &sdaoeifc;
32721abd8f2SDavid du Colombier 		s->nunit = 1;
32821abd8f2SDavid du Colombier 
32921abd8f2SDavid du Colombier 		if(h)
33021abd8f2SDavid du Colombier 			t->next = s;
33121abd8f2SDavid du Colombier 		else
33221abd8f2SDavid du Colombier 			h = s;
33321abd8f2SDavid du Colombier 		t = s;
33421abd8f2SDavid du Colombier 	}
33521abd8f2SDavid du Colombier 	return h;
33621abd8f2SDavid du Colombier }
33721abd8f2SDavid du Colombier 
33821abd8f2SDavid du Colombier static Ctlr*
pnpprobe(SDev * sd)33921abd8f2SDavid du Colombier pnpprobe(SDev *sd)
34021abd8f2SDavid du Colombier {
3412f205b96SDavid du Colombier 	ulong start;
34221abd8f2SDavid du Colombier 	char *p;
34321abd8f2SDavid du Colombier 	static int i;
34421abd8f2SDavid du Colombier 
34521abd8f2SDavid du Colombier 	if(i > nprobe)
34621abd8f2SDavid du Colombier 		return 0;
34721abd8f2SDavid du Colombier 	p = probef[i++];
34821abd8f2SDavid du Colombier 	if(strlen(p) < 2)
34921abd8f2SDavid du Colombier 		return 0;
35021abd8f2SDavid du Colombier 	if(p[1] == '!')
35121abd8f2SDavid du Colombier 		p += 2;
35221abd8f2SDavid du Colombier 
35320e402b4SDavid du Colombier 	start = TK2MS(MACHP(0)->ticks);
3542f205b96SDavid du Colombier 	if(waserror()){
3552f205b96SDavid du Colombier 		print("#æ: pnpprobe failed in %lud ms: %s: %s\n",
3562f205b96SDavid du Colombier 			TK2MS(MACHP(0)->ticks) - start, probef[i-1],
3572f205b96SDavid du Colombier 			up->errstr);
358c9b6d007SDavid du Colombier 		return nil;
359c9b6d007SDavid du Colombier 	}
3602f205b96SDavid du Colombier 	sd = aoeprobe(p, sd);			/* does a round of probing */
3612f205b96SDavid du Colombier 	poperror();
3622f205b96SDavid du Colombier 	print("#æ: pnpprobe established %s in %lud ms\n",
3632f205b96SDavid du Colombier 		probef[i-1], TK2MS(MACHP(0)->ticks) - start);
36421abd8f2SDavid du Colombier 	return sd->ctlr;
36521abd8f2SDavid du Colombier }
36621abd8f2SDavid du Colombier 
36721abd8f2SDavid du Colombier 
36821abd8f2SDavid du Colombier static int
aoeverify(SDunit * u)36921abd8f2SDavid du Colombier aoeverify(SDunit *u)
37021abd8f2SDavid du Colombier {
37121abd8f2SDavid du Colombier 	SDev *s;
37221abd8f2SDavid du Colombier 	Ctlr *c;
37321abd8f2SDavid du Colombier 
37421abd8f2SDavid du Colombier 	s = u->dev;
37521abd8f2SDavid du Colombier 	c = s->ctlr;
37621abd8f2SDavid du Colombier 	if(c == nil && (s->ctlr = c = pnpprobe(s)) == nil)
37721abd8f2SDavid du Colombier 		return 0;
37821abd8f2SDavid du Colombier 	c->mediachange = 1;
37921abd8f2SDavid du Colombier 	return 1;
38021abd8f2SDavid du Colombier }
38121abd8f2SDavid du Colombier 
38221abd8f2SDavid du Colombier static int
aoeconnect(SDunit * u,Ctlr * c)38321abd8f2SDavid du Colombier aoeconnect(SDunit *u, Ctlr *c)
38421abd8f2SDavid du Colombier {
38521abd8f2SDavid du Colombier 	qlock(c);
38621abd8f2SDavid du Colombier 	if(waserror()){
38721abd8f2SDavid du Colombier 		qunlock(c);
38821abd8f2SDavid du Colombier 		return -1;
38921abd8f2SDavid du Colombier 	}
39021abd8f2SDavid du Colombier 
39121abd8f2SDavid du Colombier 	aoeidentify(u->dev->ctlr, u);
39221abd8f2SDavid du Colombier 	if(c->c)
39321abd8f2SDavid du Colombier 		cclose(c->c);
39421abd8f2SDavid du Colombier 	c->c = 0;
39521abd8f2SDavid du Colombier 	uprint("%s/data", c->path);
39621abd8f2SDavid du Colombier 	c->c = namec(up->genbuf, Aopen, ORDWR, 0);
39721abd8f2SDavid du Colombier 	qunlock(c);
39821abd8f2SDavid du Colombier 	poperror();
39921abd8f2SDavid du Colombier 
40021abd8f2SDavid du Colombier 	return 0;
40121abd8f2SDavid du Colombier }
40221abd8f2SDavid du Colombier 
40321abd8f2SDavid du Colombier static int
aoeonline(SDunit * u)40421abd8f2SDavid du Colombier aoeonline(SDunit *u)
40521abd8f2SDavid du Colombier {
40621abd8f2SDavid du Colombier 	Ctlr *c;
40721abd8f2SDavid du Colombier 	int r;
40821abd8f2SDavid du Colombier 
40921abd8f2SDavid du Colombier 	c = u->dev->ctlr;
41021abd8f2SDavid du Colombier 	r = 0;
41121abd8f2SDavid du Colombier 
41221abd8f2SDavid du Colombier 	if((c->feat&Datapi) && c->mediachange){
41321abd8f2SDavid du Colombier 		if(aoeconnect(u, c) == 0 && (r = scsionline(u)) > 0)
41421abd8f2SDavid du Colombier 			c->mediachange = 0;
41521abd8f2SDavid du Colombier 		return r;
41621abd8f2SDavid du Colombier 	}
41721abd8f2SDavid du Colombier 
41821abd8f2SDavid du Colombier 	if(c->mediachange){
41921abd8f2SDavid du Colombier 		if(aoeconnect(u, c) == -1)
42021abd8f2SDavid du Colombier 			return 0;
42121abd8f2SDavid du Colombier 		r = 2;
42221abd8f2SDavid du Colombier 		c->mediachange = 0;
42321abd8f2SDavid du Colombier 		u->sectors = c->sectors;
42421abd8f2SDavid du Colombier 		u->secsize = Aoesectsz;
4250774058cSDavid du Colombier 	} else
42621abd8f2SDavid du Colombier 		r = 1;
42721abd8f2SDavid du Colombier 
42821abd8f2SDavid du Colombier 	return r;
42921abd8f2SDavid du Colombier }
43021abd8f2SDavid du Colombier 
43121abd8f2SDavid du Colombier static int
aoerio(SDreq * r)43221abd8f2SDavid du Colombier aoerio(SDreq *r)
43321abd8f2SDavid du Colombier {
43421abd8f2SDavid du Colombier 	int i, count;
43521abd8f2SDavid du Colombier 	uvlong lba;
43621abd8f2SDavid du Colombier 	char *name;
43721abd8f2SDavid du Colombier 	uchar *cmd;
43821abd8f2SDavid du Colombier 	long (*rio)(Chan*, void*, long, vlong);
43921abd8f2SDavid du Colombier 	Ctlr *c;
44021abd8f2SDavid du Colombier 	SDunit *unit;
44121abd8f2SDavid du Colombier 
44221abd8f2SDavid du Colombier 	unit = r->unit;
44321abd8f2SDavid du Colombier 	c = unit->dev->ctlr;
44421abd8f2SDavid du Colombier //	if(c->feat & Datapi)
44521abd8f2SDavid du Colombier //		return aoeriopkt(r, d);
44621abd8f2SDavid du Colombier 
44721abd8f2SDavid du Colombier 	cmd = r->cmd;
44821abd8f2SDavid du Colombier 	name = unit->name;
44921abd8f2SDavid du Colombier 
45021abd8f2SDavid du Colombier 	if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){
45121abd8f2SDavid du Colombier //		qlock(c);
45221abd8f2SDavid du Colombier //		i = flushcache();
45321abd8f2SDavid du Colombier //		qunlock(c);
45421abd8f2SDavid du Colombier //		if(i == 0)
45521abd8f2SDavid du Colombier //			return sdsetsense(r, SDok, 0, 0, 0);
45621abd8f2SDavid du Colombier 		return sdsetsense(r, SDcheck, 3, 0xc, 2);
45721abd8f2SDavid du Colombier 	}
45821abd8f2SDavid du Colombier 
45921abd8f2SDavid du Colombier 	if((i = sdfakescsi(r, c->ident, sizeof c->ident)) != SDnostatus){
46021abd8f2SDavid du Colombier 		r->status = i;
46121abd8f2SDavid du Colombier 		return i;
46221abd8f2SDavid du Colombier 	}
46321abd8f2SDavid du Colombier 
46421abd8f2SDavid du Colombier 	switch(*cmd){
46521abd8f2SDavid du Colombier 	case 0x88:
46621abd8f2SDavid du Colombier 	case 0x28:
46721abd8f2SDavid du Colombier 		rio = devtab[c->c->type]->read;
46821abd8f2SDavid du Colombier 		break;
46921abd8f2SDavid du Colombier 	case 0x8a:
47021abd8f2SDavid du Colombier 	case 0x2a:
47121abd8f2SDavid du Colombier 		rio = devtab[c->c->type]->write;
47221abd8f2SDavid du Colombier 		break;
47321abd8f2SDavid du Colombier 	default:
474567483c8SDavid du Colombier 		print("%s: bad cmd %#.2ux\n", name, cmd[0]);
47521abd8f2SDavid du Colombier 		r->status = SDcheck;
47621abd8f2SDavid du Colombier 		return SDcheck;
47721abd8f2SDavid du Colombier 	}
47821abd8f2SDavid du Colombier 
47921abd8f2SDavid du Colombier 	if(r->data == nil)
48021abd8f2SDavid du Colombier 		return SDok;
48121abd8f2SDavid du Colombier 
48221abd8f2SDavid du Colombier 	if(r->clen == 16){
48321abd8f2SDavid du Colombier 		if(cmd[2] || cmd[3])
48421abd8f2SDavid du Colombier 			return sdsetsense(r, SDcheck, 3, 0xc, 2);
48521abd8f2SDavid du Colombier 		lba = (uvlong)cmd[4]<<40 | (uvlong)cmd[5]<<32;
48621abd8f2SDavid du Colombier 		lba |=   cmd[6]<<24 |  cmd[7]<<16 |  cmd[8]<<8 | cmd[9];
48721abd8f2SDavid du Colombier 		count = cmd[10]<<24 | cmd[11]<<16 | cmd[12]<<8 | cmd[13];
48821abd8f2SDavid du Colombier 	}else{
48921abd8f2SDavid du Colombier 		lba  = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5];
49021abd8f2SDavid du Colombier 		count = cmd[7]<<8 | cmd[8];
49121abd8f2SDavid du Colombier 	}
49221abd8f2SDavid du Colombier 
49321abd8f2SDavid du Colombier 	count *= Aoesectsz;
49421abd8f2SDavid du Colombier 
49521abd8f2SDavid du Colombier 	if(r->dlen < count)
49621abd8f2SDavid du Colombier 		count = r->dlen & ~0x1ff;
49721abd8f2SDavid du Colombier 
49821abd8f2SDavid du Colombier 	if(waserror()){
49921abd8f2SDavid du Colombier 		if(strcmp(up->errstr, Echange) == 0 ||
500*a587111cSDavid du Colombier 		    strcmp(up->errstr, Eaoedown) == 0)
50121abd8f2SDavid du Colombier 			unit->sectors = 0;
50221abd8f2SDavid du Colombier 		nexterror();
50321abd8f2SDavid du Colombier 	}
50421abd8f2SDavid du Colombier 	r->rlen = rio(c->c, r->data, count, Aoesectsz * lba);
50521abd8f2SDavid du Colombier 	poperror();
50621abd8f2SDavid du Colombier 	r->status = SDok;
50721abd8f2SDavid du Colombier 	return SDok;
50821abd8f2SDavid du Colombier }
50921abd8f2SDavid du Colombier 
51021abd8f2SDavid du Colombier static char *smarttab[] = {
51121abd8f2SDavid du Colombier 	"unset",
51221abd8f2SDavid du Colombier 	"error",
51321abd8f2SDavid du Colombier 	"threshold exceeded",
51421abd8f2SDavid du Colombier 	"normal"
51521abd8f2SDavid du Colombier };
51621abd8f2SDavid du Colombier 
51721abd8f2SDavid du Colombier static char *
pflag(char * s,char * e,uchar f)51821abd8f2SDavid du Colombier pflag(char *s, char *e, uchar f)
51921abd8f2SDavid du Colombier {
520060a30c6SDavid du Colombier 	uchar i;
52121abd8f2SDavid du Colombier 
522060a30c6SDavid du Colombier 	for(i = 0; i < 8; i++)
523060a30c6SDavid du Colombier 		if(f & (1 << i))
52421abd8f2SDavid du Colombier 			s = seprint(s, e, "%s ", flagname[i]);
52521abd8f2SDavid du Colombier 	return seprint(s, e, "\n");
52621abd8f2SDavid du Colombier }
52721abd8f2SDavid du Colombier 
52821abd8f2SDavid du Colombier static int
aoerctl(SDunit * u,char * p,int l)52921abd8f2SDavid du Colombier aoerctl(SDunit *u, char *p, int l)
53021abd8f2SDavid du Colombier {
53121abd8f2SDavid du Colombier 	Ctlr *c;
53221abd8f2SDavid du Colombier 	char *e, *op;
53321abd8f2SDavid du Colombier 
53421abd8f2SDavid du Colombier 	if((c = u->dev->ctlr) == nil)
53521abd8f2SDavid du Colombier 		return 0;
53621abd8f2SDavid du Colombier 	e = p+l;
53721abd8f2SDavid du Colombier 	op = p;
53821abd8f2SDavid du Colombier 
53921abd8f2SDavid du Colombier 	p = seprint(p, e, "model\t%s\n", c->model);
54021abd8f2SDavid du Colombier 	p = seprint(p, e, "serial\t%s\n", c->serial);
54121abd8f2SDavid du Colombier 	p = seprint(p, e, "firm	%s\n", c->firmware);
54221abd8f2SDavid du Colombier 	if(c->smartrs == 0xff)
54321abd8f2SDavid du Colombier 		p = seprint(p, e, "smart\tenable error\n");
54421abd8f2SDavid du Colombier 	else if(c->smartrs == 0)
54521abd8f2SDavid du Colombier 		p = seprint(p, e, "smart\tdisabled\n");
54621abd8f2SDavid du Colombier 	else
54721abd8f2SDavid du Colombier 		p = seprint(p, e, "smart\t%s\n", smarttab[c->smart]);
54821abd8f2SDavid du Colombier 	p = seprint(p, e, "flag	");
54921abd8f2SDavid du Colombier 	p = pflag(p, e, c->feat);
55021abd8f2SDavid du Colombier 	p = seprint(p, e, "geometry %llud %d\n", c->sectors, Aoesectsz);
55121abd8f2SDavid du Colombier 	return p-op;
55221abd8f2SDavid du Colombier }
55321abd8f2SDavid du Colombier 
55421abd8f2SDavid du Colombier static int
aoewctl(SDunit *,Cmdbuf * cmd)55521abd8f2SDavid du Colombier aoewctl(SDunit *, Cmdbuf *cmd)
55621abd8f2SDavid du Colombier {
55721abd8f2SDavid du Colombier 	cmderror(cmd, Ebadarg);
55821abd8f2SDavid du Colombier 	return 0;
55921abd8f2SDavid du Colombier }
56021abd8f2SDavid du Colombier 
56121abd8f2SDavid du Colombier static SDev*
aoeprobew(DevConf * c)56221abd8f2SDavid du Colombier aoeprobew(DevConf *c)
56321abd8f2SDavid du Colombier {
56421abd8f2SDavid du Colombier 	char *p;
56521abd8f2SDavid du Colombier 
56621abd8f2SDavid du Colombier 	p = strchr(c->type, '/');
56721abd8f2SDavid du Colombier 	if(p == nil || strlen(p) > Maxpath - 11)
56821abd8f2SDavid du Colombier 		error(Ebadarg);
56921abd8f2SDavid du Colombier 	if(p[1] == '#')
57021abd8f2SDavid du Colombier 		p++;			/* hack */
57121abd8f2SDavid du Colombier 	if(ctlrlookup(p))
57221abd8f2SDavid du Colombier 		error(Einuse);
57321abd8f2SDavid du Colombier 	return aoeprobe(p, 0);
57421abd8f2SDavid du Colombier }
57521abd8f2SDavid du Colombier 
57621abd8f2SDavid du Colombier static void
aoeclear(SDev * s)57721abd8f2SDavid du Colombier aoeclear(SDev *s)
57821abd8f2SDavid du Colombier {
57921abd8f2SDavid du Colombier 	delctlr((Ctlr *)s->ctlr);
58021abd8f2SDavid du Colombier }
58121abd8f2SDavid du Colombier 
58221abd8f2SDavid du Colombier static char*
aoertopctl(SDev * s,char * p,char * e)58321abd8f2SDavid du Colombier aoertopctl(SDev *s, char *p, char *e)
58421abd8f2SDavid du Colombier {
58521abd8f2SDavid du Colombier 	Ctlr *c;
58621abd8f2SDavid du Colombier 
58781fda2e3SDavid du Colombier 	if(s == nil || (c = s->ctlr) == nil)
58881fda2e3SDavid du Colombier 		return p;
58981fda2e3SDavid du Colombier 
59021abd8f2SDavid du Colombier 	return seprint(p, e, "%s aoe %s\n", s->name, c->path);
59121abd8f2SDavid du Colombier }
59221abd8f2SDavid du Colombier 
59321abd8f2SDavid du Colombier static int
aoewtopctl(SDev *,Cmdbuf * cmd)59421abd8f2SDavid du Colombier aoewtopctl(SDev *, Cmdbuf *cmd)
59521abd8f2SDavid du Colombier {
59621abd8f2SDavid du Colombier 	switch(cmd->nf){
59721abd8f2SDavid du Colombier 	default:
59821abd8f2SDavid du Colombier 		cmderror(cmd, Ebadarg);
59921abd8f2SDavid du Colombier 	}
60021abd8f2SDavid du Colombier 	return 0;
60121abd8f2SDavid du Colombier }
60221abd8f2SDavid du Colombier 
60321abd8f2SDavid du Colombier SDifc sdaoeifc = {
60421abd8f2SDavid du Colombier 	"aoe",
60521abd8f2SDavid du Colombier 
60621abd8f2SDavid du Colombier 	aoepnp,
60721abd8f2SDavid du Colombier 	nil,		/* legacy */
60821abd8f2SDavid du Colombier 	nil,		/* enable */
60921abd8f2SDavid du Colombier 	nil,		/* disable */
61021abd8f2SDavid du Colombier 
61121abd8f2SDavid du Colombier 	aoeverify,
61221abd8f2SDavid du Colombier 	aoeonline,
61321abd8f2SDavid du Colombier 	aoerio,
61421abd8f2SDavid du Colombier 	aoerctl,
61521abd8f2SDavid du Colombier 	aoewctl,
61621abd8f2SDavid du Colombier 
61721abd8f2SDavid du Colombier 	scsibio,
61821abd8f2SDavid du Colombier 	aoeprobew,	/* probe */
61921abd8f2SDavid du Colombier 	aoeclear,	/* clear */
62021abd8f2SDavid du Colombier 	aoertopctl,
62121abd8f2SDavid du Colombier 	aoewtopctl,
62221abd8f2SDavid du Colombier };
623