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