1*8a8c2d74SCharles.Forsyth /*
2*8a8c2d74SCharles.Forsyth * aoe sd bootstrap driver, copyright © 2007 coraid
3*8a8c2d74SCharles.Forsyth */
4*8a8c2d74SCharles.Forsyth
5*8a8c2d74SCharles.Forsyth #include "u.h"
6*8a8c2d74SCharles.Forsyth #include "mem.h"
7*8a8c2d74SCharles.Forsyth #include "lib.h"
8*8a8c2d74SCharles.Forsyth #include "dat.h"
9*8a8c2d74SCharles.Forsyth #include "fns.h"
10*8a8c2d74SCharles.Forsyth #include "io.h"
11*8a8c2d74SCharles.Forsyth #include "sd.h"
12*8a8c2d74SCharles.Forsyth #include "aoe.h"
13*8a8c2d74SCharles.Forsyth
14*8a8c2d74SCharles.Forsyth
15*8a8c2d74SCharles.Forsyth enum {
16*8a8c2d74SCharles.Forsyth Nctlr = 4,
17*8a8c2d74SCharles.Forsyth };
18*8a8c2d74SCharles.Forsyth
19*8a8c2d74SCharles.Forsyth enum {
20*8a8c2d74SCharles.Forsyth /* sync with ahci.h */
21*8a8c2d74SCharles.Forsyth Dllba = 1<<0,
22*8a8c2d74SCharles.Forsyth Dsmart = 1<<1,
23*8a8c2d74SCharles.Forsyth Dpower = 1<<2,
24*8a8c2d74SCharles.Forsyth Dnop = 1<<3,
25*8a8c2d74SCharles.Forsyth Datapi = 1<<4,
26*8a8c2d74SCharles.Forsyth Datapi16= 1<<5,
27*8a8c2d74SCharles.Forsyth };
28*8a8c2d74SCharles.Forsyth
29*8a8c2d74SCharles.Forsyth enum {
30*8a8c2d74SCharles.Forsyth Tfree = -1,
31*8a8c2d74SCharles.Forsyth Tmgmt,
32*8a8c2d74SCharles.Forsyth };
33*8a8c2d74SCharles.Forsyth
34*8a8c2d74SCharles.Forsyth typedef struct Ctlr Ctlr;
35*8a8c2d74SCharles.Forsyth struct Ctlr{
36*8a8c2d74SCharles.Forsyth Ctlr *next;
37*8a8c2d74SCharles.Forsyth SDunit *unit;
38*8a8c2d74SCharles.Forsyth
39*8a8c2d74SCharles.Forsyth int ctlrno;
40*8a8c2d74SCharles.Forsyth int major;
41*8a8c2d74SCharles.Forsyth int minor;
42*8a8c2d74SCharles.Forsyth uchar ea[Eaddrlen];
43*8a8c2d74SCharles.Forsyth ushort lasttag;
44*8a8c2d74SCharles.Forsyth
45*8a8c2d74SCharles.Forsyth ulong vers;
46*8a8c2d74SCharles.Forsyth uchar mediachange;
47*8a8c2d74SCharles.Forsyth uchar flag;
48*8a8c2d74SCharles.Forsyth uchar smart;
49*8a8c2d74SCharles.Forsyth uchar smartrs;
50*8a8c2d74SCharles.Forsyth uchar feat;
51*8a8c2d74SCharles.Forsyth
52*8a8c2d74SCharles.Forsyth uvlong sectors;
53*8a8c2d74SCharles.Forsyth char serial[20+1];
54*8a8c2d74SCharles.Forsyth char firmware[8+1];
55*8a8c2d74SCharles.Forsyth char model[40+1];
56*8a8c2d74SCharles.Forsyth char ident[0x100];
57*8a8c2d74SCharles.Forsyth };
58*8a8c2d74SCharles.Forsyth
59*8a8c2d74SCharles.Forsyth static Ctlr *head;
60*8a8c2d74SCharles.Forsyth static Ctlr *tail;
61*8a8c2d74SCharles.Forsyth
62*8a8c2d74SCharles.Forsyth static int aoeether[10];
63*8a8c2d74SCharles.Forsyth
64*8a8c2d74SCharles.Forsyth SDifc sdaoeifc;
65*8a8c2d74SCharles.Forsyth
66*8a8c2d74SCharles.Forsyth static void
hnputs(uchar * p,ushort i)67*8a8c2d74SCharles.Forsyth hnputs(uchar *p, ushort i)
68*8a8c2d74SCharles.Forsyth {
69*8a8c2d74SCharles.Forsyth p[0] = i >> 8;
70*8a8c2d74SCharles.Forsyth p[1] = i;
71*8a8c2d74SCharles.Forsyth }
72*8a8c2d74SCharles.Forsyth
73*8a8c2d74SCharles.Forsyth static void
hnputl(uchar * p,ulong i)74*8a8c2d74SCharles.Forsyth hnputl(uchar *p, ulong i)
75*8a8c2d74SCharles.Forsyth {
76*8a8c2d74SCharles.Forsyth p[0] = i >> 24;
77*8a8c2d74SCharles.Forsyth p[1] = i >> 16;
78*8a8c2d74SCharles.Forsyth p[2] = i >> 8;
79*8a8c2d74SCharles.Forsyth p[3] = i;
80*8a8c2d74SCharles.Forsyth }
81*8a8c2d74SCharles.Forsyth
82*8a8c2d74SCharles.Forsyth static ushort
nhgets(uchar * p)83*8a8c2d74SCharles.Forsyth nhgets(uchar *p)
84*8a8c2d74SCharles.Forsyth {
85*8a8c2d74SCharles.Forsyth return *p<<8 | p[1];
86*8a8c2d74SCharles.Forsyth }
87*8a8c2d74SCharles.Forsyth
88*8a8c2d74SCharles.Forsyth static ulong
nhgetl(uchar * p)89*8a8c2d74SCharles.Forsyth nhgetl(uchar *p)
90*8a8c2d74SCharles.Forsyth {
91*8a8c2d74SCharles.Forsyth return p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3];
92*8a8c2d74SCharles.Forsyth }
93*8a8c2d74SCharles.Forsyth
94*8a8c2d74SCharles.Forsyth static int
newtag(Ctlr * d)95*8a8c2d74SCharles.Forsyth newtag(Ctlr *d)
96*8a8c2d74SCharles.Forsyth {
97*8a8c2d74SCharles.Forsyth int t;
98*8a8c2d74SCharles.Forsyth
99*8a8c2d74SCharles.Forsyth for(;;){
100*8a8c2d74SCharles.Forsyth t = ++d->lasttag << 16;
101*8a8c2d74SCharles.Forsyth t |= m->ticks & 0xffff;
102*8a8c2d74SCharles.Forsyth switch(t) {
103*8a8c2d74SCharles.Forsyth case Tfree:
104*8a8c2d74SCharles.Forsyth case Tmgmt:
105*8a8c2d74SCharles.Forsyth break;
106*8a8c2d74SCharles.Forsyth default:
107*8a8c2d74SCharles.Forsyth return t;
108*8a8c2d74SCharles.Forsyth }
109*8a8c2d74SCharles.Forsyth }
110*8a8c2d74SCharles.Forsyth }
111*8a8c2d74SCharles.Forsyth
112*8a8c2d74SCharles.Forsyth static int
hset(Ctlr * d,Aoehdr * h,int cmd)113*8a8c2d74SCharles.Forsyth hset(Ctlr *d, Aoehdr *h, int cmd)
114*8a8c2d74SCharles.Forsyth {
115*8a8c2d74SCharles.Forsyth int tag;
116*8a8c2d74SCharles.Forsyth
117*8a8c2d74SCharles.Forsyth memmove(h->dst, d->ea, Eaddrlen);
118*8a8c2d74SCharles.Forsyth hnputs(h->type, Aoetype);
119*8a8c2d74SCharles.Forsyth h->verflag = Aoever << 4;
120*8a8c2d74SCharles.Forsyth hnputs(h->major, d->major);
121*8a8c2d74SCharles.Forsyth h->minor = d->minor;
122*8a8c2d74SCharles.Forsyth h->cmd = cmd;
123*8a8c2d74SCharles.Forsyth hnputl(h->tag, tag = newtag(d));
124*8a8c2d74SCharles.Forsyth return tag;
125*8a8c2d74SCharles.Forsyth }
126*8a8c2d74SCharles.Forsyth
127*8a8c2d74SCharles.Forsyth static void
idmove(char * p,ushort * a,int n)128*8a8c2d74SCharles.Forsyth idmove(char *p, ushort *a, int n)
129*8a8c2d74SCharles.Forsyth {
130*8a8c2d74SCharles.Forsyth int i;
131*8a8c2d74SCharles.Forsyth char *op, *e;
132*8a8c2d74SCharles.Forsyth
133*8a8c2d74SCharles.Forsyth op = p;
134*8a8c2d74SCharles.Forsyth for(i = 0; i < n / 2; i++){
135*8a8c2d74SCharles.Forsyth *p++ = a[i] >> 8;
136*8a8c2d74SCharles.Forsyth *p++ = a[i];
137*8a8c2d74SCharles.Forsyth }
138*8a8c2d74SCharles.Forsyth *p = 0;
139*8a8c2d74SCharles.Forsyth while(p > op && *--p == ' ')
140*8a8c2d74SCharles.Forsyth *p = 0;
141*8a8c2d74SCharles.Forsyth e = p;
142*8a8c2d74SCharles.Forsyth p = op;
143*8a8c2d74SCharles.Forsyth while(*p == ' ')
144*8a8c2d74SCharles.Forsyth p++;
145*8a8c2d74SCharles.Forsyth memmove(op, p, n - (e - p));
146*8a8c2d74SCharles.Forsyth }
147*8a8c2d74SCharles.Forsyth
148*8a8c2d74SCharles.Forsyth static ushort
gbit16(void * a)149*8a8c2d74SCharles.Forsyth gbit16(void *a)
150*8a8c2d74SCharles.Forsyth {
151*8a8c2d74SCharles.Forsyth uchar *i;
152*8a8c2d74SCharles.Forsyth
153*8a8c2d74SCharles.Forsyth i = a;
154*8a8c2d74SCharles.Forsyth return i[1]<<8 | i[0];
155*8a8c2d74SCharles.Forsyth }
156*8a8c2d74SCharles.Forsyth
157*8a8c2d74SCharles.Forsyth static ulong
gbit32(void * a)158*8a8c2d74SCharles.Forsyth gbit32(void *a)
159*8a8c2d74SCharles.Forsyth {
160*8a8c2d74SCharles.Forsyth uchar *i;
161*8a8c2d74SCharles.Forsyth ulong j;
162*8a8c2d74SCharles.Forsyth
163*8a8c2d74SCharles.Forsyth i = a;
164*8a8c2d74SCharles.Forsyth j = i[3] << 24;
165*8a8c2d74SCharles.Forsyth j |= i[2] << 16;
166*8a8c2d74SCharles.Forsyth j |= i[1] << 8;
167*8a8c2d74SCharles.Forsyth j |= i[0];
168*8a8c2d74SCharles.Forsyth return j;
169*8a8c2d74SCharles.Forsyth }
170*8a8c2d74SCharles.Forsyth
171*8a8c2d74SCharles.Forsyth static uvlong
gbit64(void * a)172*8a8c2d74SCharles.Forsyth gbit64(void *a)
173*8a8c2d74SCharles.Forsyth {
174*8a8c2d74SCharles.Forsyth uchar *i;
175*8a8c2d74SCharles.Forsyth
176*8a8c2d74SCharles.Forsyth i = a;
177*8a8c2d74SCharles.Forsyth return (uvlong)gbit32(i+4) << 32 | gbit32(a);
178*8a8c2d74SCharles.Forsyth }
179*8a8c2d74SCharles.Forsyth
180*8a8c2d74SCharles.Forsyth static int
ataidentify(Ctlr * c,ushort * id)181*8a8c2d74SCharles.Forsyth ataidentify(Ctlr *c, ushort *id)
182*8a8c2d74SCharles.Forsyth {
183*8a8c2d74SCharles.Forsyth vlong s;
184*8a8c2d74SCharles.Forsyth int i;
185*8a8c2d74SCharles.Forsyth
186*8a8c2d74SCharles.Forsyth i = gbit16(id+83) | gbit16(id+86);
187*8a8c2d74SCharles.Forsyth if(i & (1 << 10)){
188*8a8c2d74SCharles.Forsyth c->feat |= Dllba;
189*8a8c2d74SCharles.Forsyth s = gbit64(id+100);
190*8a8c2d74SCharles.Forsyth }else
191*8a8c2d74SCharles.Forsyth s = gbit32(id+60);
192*8a8c2d74SCharles.Forsyth
193*8a8c2d74SCharles.Forsyth idmove(c->serial, id+10, 20);
194*8a8c2d74SCharles.Forsyth idmove(c->firmware, id+23, 8);
195*8a8c2d74SCharles.Forsyth idmove(c->model, id+27, 40);
196*8a8c2d74SCharles.Forsyth
197*8a8c2d74SCharles.Forsyth print("aoe discovers %d.%d: %s %s\n", c->major, c->minor, c->model, c->serial);
198*8a8c2d74SCharles.Forsyth
199*8a8c2d74SCharles.Forsyth c->sectors = s;
200*8a8c2d74SCharles.Forsyth c->mediachange = 1;
201*8a8c2d74SCharles.Forsyth return 0;
202*8a8c2d74SCharles.Forsyth }
203*8a8c2d74SCharles.Forsyth
204*8a8c2d74SCharles.Forsyth static void
identifydump(Aoeata * a)205*8a8c2d74SCharles.Forsyth identifydump(Aoeata *a)
206*8a8c2d74SCharles.Forsyth {
207*8a8c2d74SCharles.Forsyth print("%E %E type=%.4ux verflag=%x error=%x %d.%d cmd=%d tag=%.8lux\n",
208*8a8c2d74SCharles.Forsyth a->dst, a->src, nhgets(a->type), a->verflag, a->error,
209*8a8c2d74SCharles.Forsyth nhgets(a->major), a->minor, a->cmd, nhgetl(a->tag));
210*8a8c2d74SCharles.Forsyth print(" aflag=%x errfeat=%ux scnt=%d cmdstat=%ux, lba=%d? res=%.4ux\n",
211*8a8c2d74SCharles.Forsyth a->aflag, a->errfeat, a->scnt, a->cmdstat, 0, nhgets(a->res));
212*8a8c2d74SCharles.Forsyth }
213*8a8c2d74SCharles.Forsyth
214*8a8c2d74SCharles.Forsyth static int
idpkt(Ctlr * c,Aoeata * a)215*8a8c2d74SCharles.Forsyth idpkt(Ctlr *c, Aoeata *a)
216*8a8c2d74SCharles.Forsyth {
217*8a8c2d74SCharles.Forsyth memset(a, 0, sizeof *a);
218*8a8c2d74SCharles.Forsyth a->cmdstat = Cid;
219*8a8c2d74SCharles.Forsyth a->scnt = 1;
220*8a8c2d74SCharles.Forsyth a->lba[3] = 0xa0;
221*8a8c2d74SCharles.Forsyth return hset(c, a, ACata);
222*8a8c2d74SCharles.Forsyth }
223*8a8c2d74SCharles.Forsyth
224*8a8c2d74SCharles.Forsyth static int
chktag(int * out,int nout,int tag)225*8a8c2d74SCharles.Forsyth chktag(int *out, int nout, int tag)
226*8a8c2d74SCharles.Forsyth {
227*8a8c2d74SCharles.Forsyth int j;
228*8a8c2d74SCharles.Forsyth
229*8a8c2d74SCharles.Forsyth for(j = 0; j <= nout; j++)
230*8a8c2d74SCharles.Forsyth if(out[j] == tag)
231*8a8c2d74SCharles.Forsyth return 0;
232*8a8c2d74SCharles.Forsyth print("wrong tag\n");
233*8a8c2d74SCharles.Forsyth for(j = 0; j <= nout; j++)
234*8a8c2d74SCharles.Forsyth print("%.8ux != %.8ux\n", out[j], tag);
235*8a8c2d74SCharles.Forsyth return -1;
236*8a8c2d74SCharles.Forsyth }
237*8a8c2d74SCharles.Forsyth
238*8a8c2d74SCharles.Forsyth /*
239*8a8c2d74SCharles.Forsyth * ignore the tag for identify. better than ignoring
240*8a8c2d74SCharles.Forsyth * a response to the wrong identify request
241*8a8c2d74SCharles.Forsyth */
242*8a8c2d74SCharles.Forsyth static int
identify(Ctlr * c)243*8a8c2d74SCharles.Forsyth identify(Ctlr *c)
244*8a8c2d74SCharles.Forsyth {
245*8a8c2d74SCharles.Forsyth int tag[5], i, n;
246*8a8c2d74SCharles.Forsyth Aoeata *a;
247*8a8c2d74SCharles.Forsyth Etherpkt p;
248*8a8c2d74SCharles.Forsyth
249*8a8c2d74SCharles.Forsyth memset(&p, 0, sizeof p);
250*8a8c2d74SCharles.Forsyth a = (Aoeata*)&p;
251*8a8c2d74SCharles.Forsyth i = 0;
252*8a8c2d74SCharles.Forsyth do {
253*8a8c2d74SCharles.Forsyth if(i == 5){
254*8a8c2d74SCharles.Forsyth print("aoe: identify timeout\n");
255*8a8c2d74SCharles.Forsyth return -1;
256*8a8c2d74SCharles.Forsyth }
257*8a8c2d74SCharles.Forsyth tag[i] = idpkt(c, a);
258*8a8c2d74SCharles.Forsyth ethertxpkt(c->ctlrno, &p, sizeof *a, 0);
259*8a8c2d74SCharles.Forsyth memset(&p, 0, sizeof p);
260*8a8c2d74SCharles.Forsyth next:
261*8a8c2d74SCharles.Forsyth n = etherrxpkt(c->ctlrno, &p, 125);
262*8a8c2d74SCharles.Forsyth if(n == 0){
263*8a8c2d74SCharles.Forsyth i++;
264*8a8c2d74SCharles.Forsyth continue;
265*8a8c2d74SCharles.Forsyth }
266*8a8c2d74SCharles.Forsyth if(nhgets(a->type) != Aoetype)
267*8a8c2d74SCharles.Forsyth goto next;
268*8a8c2d74SCharles.Forsyth if(nhgets(a->major) != c->major || a->minor != c->minor){
269*8a8c2d74SCharles.Forsyth print("wrong device %d.%d want %d.%d; %d\n",
270*8a8c2d74SCharles.Forsyth nhgets(a->major), a->minor,
271*8a8c2d74SCharles.Forsyth c->major, c->minor, n);
272*8a8c2d74SCharles.Forsyth goto next;
273*8a8c2d74SCharles.Forsyth }
274*8a8c2d74SCharles.Forsyth if(chktag(tag, i, nhgetl(a->tag)) == -1)
275*8a8c2d74SCharles.Forsyth goto next;
276*8a8c2d74SCharles.Forsyth if(a->cmdstat & 0xa9){
277*8a8c2d74SCharles.Forsyth print("aoe: ata error on identify: %2ux\n", a->cmdstat);
278*8a8c2d74SCharles.Forsyth return -1;
279*8a8c2d74SCharles.Forsyth }
280*8a8c2d74SCharles.Forsyth } while (a->scnt != 1);
281*8a8c2d74SCharles.Forsyth
282*8a8c2d74SCharles.Forsyth c->feat = 0;
283*8a8c2d74SCharles.Forsyth ataidentify(c, (ushort*)(a+1));
284*8a8c2d74SCharles.Forsyth return 0;
285*8a8c2d74SCharles.Forsyth }
286*8a8c2d74SCharles.Forsyth
287*8a8c2d74SCharles.Forsyth static Ctlr*
ctlrlookup(int major,int minor)288*8a8c2d74SCharles.Forsyth ctlrlookup(int major, int minor)
289*8a8c2d74SCharles.Forsyth {
290*8a8c2d74SCharles.Forsyth Ctlr *c;
291*8a8c2d74SCharles.Forsyth
292*8a8c2d74SCharles.Forsyth for(c = head; c; c = c->next)
293*8a8c2d74SCharles.Forsyth if(c->major == major && c->minor == minor)
294*8a8c2d74SCharles.Forsyth break;
295*8a8c2d74SCharles.Forsyth return c;
296*8a8c2d74SCharles.Forsyth }
297*8a8c2d74SCharles.Forsyth
298*8a8c2d74SCharles.Forsyth static Ctlr*
newctlr(Etherpkt * p)299*8a8c2d74SCharles.Forsyth newctlr(Etherpkt *p)
300*8a8c2d74SCharles.Forsyth {
301*8a8c2d74SCharles.Forsyth int major, minor;
302*8a8c2d74SCharles.Forsyth Aoeqc *q;
303*8a8c2d74SCharles.Forsyth Ctlr *c;
304*8a8c2d74SCharles.Forsyth
305*8a8c2d74SCharles.Forsyth q = (Aoeqc*)p;
306*8a8c2d74SCharles.Forsyth if(nhgets(q->type) != Aoetype)
307*8a8c2d74SCharles.Forsyth return 0;
308*8a8c2d74SCharles.Forsyth major = nhgets(q->major);
309*8a8c2d74SCharles.Forsyth minor = q->minor;
310*8a8c2d74SCharles.Forsyth
311*8a8c2d74SCharles.Forsyth if(major == 0xffff || minor == 0xff)
312*8a8c2d74SCharles.Forsyth return 0;
313*8a8c2d74SCharles.Forsyth
314*8a8c2d74SCharles.Forsyth if(ctlrlookup(major, minor)){
315*8a8c2d74SCharles.Forsyth print("duplicate shelf.slot\n");
316*8a8c2d74SCharles.Forsyth return 0;
317*8a8c2d74SCharles.Forsyth }
318*8a8c2d74SCharles.Forsyth
319*8a8c2d74SCharles.Forsyth if((c = malloc(sizeof *c)) == 0)
320*8a8c2d74SCharles.Forsyth return 0;
321*8a8c2d74SCharles.Forsyth c->major = major;
322*8a8c2d74SCharles.Forsyth c->minor = minor;
323*8a8c2d74SCharles.Forsyth memmove(c->ea, q->src, Eaddrlen);
324*8a8c2d74SCharles.Forsyth
325*8a8c2d74SCharles.Forsyth if(head != 0)
326*8a8c2d74SCharles.Forsyth tail->next = c;
327*8a8c2d74SCharles.Forsyth else
328*8a8c2d74SCharles.Forsyth head = c;
329*8a8c2d74SCharles.Forsyth tail = c;
330*8a8c2d74SCharles.Forsyth return c;
331*8a8c2d74SCharles.Forsyth }
332*8a8c2d74SCharles.Forsyth
333*8a8c2d74SCharles.Forsyth static void
discover(int major,int minor)334*8a8c2d74SCharles.Forsyth discover(int major, int minor)
335*8a8c2d74SCharles.Forsyth {
336*8a8c2d74SCharles.Forsyth int i;
337*8a8c2d74SCharles.Forsyth Aoehdr *h;
338*8a8c2d74SCharles.Forsyth Etherpkt p;
339*8a8c2d74SCharles.Forsyth
340*8a8c2d74SCharles.Forsyth for(i = 0; i < nelem(aoeether); i++){
341*8a8c2d74SCharles.Forsyth if(aoeether[i] == 0)
342*8a8c2d74SCharles.Forsyth continue;
343*8a8c2d74SCharles.Forsyth memset(&p, 0, ETHERMINTU);
344*8a8c2d74SCharles.Forsyth h = (Aoehdr*)&p;
345*8a8c2d74SCharles.Forsyth memset(h->dst, 0xff, sizeof h->dst);
346*8a8c2d74SCharles.Forsyth hnputs(h->type, Aoetype);
347*8a8c2d74SCharles.Forsyth h->verflag = Aoever << 4;
348*8a8c2d74SCharles.Forsyth hnputs(h->major, major);
349*8a8c2d74SCharles.Forsyth h->minor = minor;
350*8a8c2d74SCharles.Forsyth h->cmd = ACconfig;
351*8a8c2d74SCharles.Forsyth ethertxpkt(i, &p, ETHERMINTU, 0);
352*8a8c2d74SCharles.Forsyth }
353*8a8c2d74SCharles.Forsyth }
354*8a8c2d74SCharles.Forsyth
355*8a8c2d74SCharles.Forsyth static int
rxany(Etherpkt * p,int t)356*8a8c2d74SCharles.Forsyth rxany(Etherpkt *p, int t)
357*8a8c2d74SCharles.Forsyth {
358*8a8c2d74SCharles.Forsyth int i, n;
359*8a8c2d74SCharles.Forsyth
360*8a8c2d74SCharles.Forsyth for(i = 0; i < nelem(aoeether); i++){
361*8a8c2d74SCharles.Forsyth if(aoeether[i] == 0)
362*8a8c2d74SCharles.Forsyth continue;
363*8a8c2d74SCharles.Forsyth while ((n = etherrxpkt(i, p, t)) != 0)
364*8a8c2d74SCharles.Forsyth if(nhgets(p->type) == Aoetype)
365*8a8c2d74SCharles.Forsyth return n;
366*8a8c2d74SCharles.Forsyth }
367*8a8c2d74SCharles.Forsyth return 0;
368*8a8c2d74SCharles.Forsyth }
369*8a8c2d74SCharles.Forsyth
370*8a8c2d74SCharles.Forsyth static int
aoeprobe(int major,int minor,SDev * s)371*8a8c2d74SCharles.Forsyth aoeprobe(int major, int minor, SDev *s)
372*8a8c2d74SCharles.Forsyth {
373*8a8c2d74SCharles.Forsyth Ctlr *ctlr;
374*8a8c2d74SCharles.Forsyth Etherpkt p;
375*8a8c2d74SCharles.Forsyth int n, i;
376*8a8c2d74SCharles.Forsyth
377*8a8c2d74SCharles.Forsyth for(i = 0;; i += 200){
378*8a8c2d74SCharles.Forsyth if(i > 8000)
379*8a8c2d74SCharles.Forsyth return -1;
380*8a8c2d74SCharles.Forsyth discover(major, minor);
381*8a8c2d74SCharles.Forsyth again:
382*8a8c2d74SCharles.Forsyth n = rxany(&p, 100);
383*8a8c2d74SCharles.Forsyth if(n > 0 && (ctlr = newctlr(&p)))
384*8a8c2d74SCharles.Forsyth break;
385*8a8c2d74SCharles.Forsyth if(n > 0)
386*8a8c2d74SCharles.Forsyth goto again;
387*8a8c2d74SCharles.Forsyth }
388*8a8c2d74SCharles.Forsyth
389*8a8c2d74SCharles.Forsyth s->ctlr = ctlr;
390*8a8c2d74SCharles.Forsyth s->ifc = &sdaoeifc;
391*8a8c2d74SCharles.Forsyth s->nunit = 1;
392*8a8c2d74SCharles.Forsyth return 0;
393*8a8c2d74SCharles.Forsyth }
394*8a8c2d74SCharles.Forsyth
395*8a8c2d74SCharles.Forsyth static char *probef[32];
396*8a8c2d74SCharles.Forsyth static int nprobe;
397*8a8c2d74SCharles.Forsyth
398*8a8c2d74SCharles.Forsyth int
pnpprobeid(char * s)399*8a8c2d74SCharles.Forsyth pnpprobeid(char *s)
400*8a8c2d74SCharles.Forsyth {
401*8a8c2d74SCharles.Forsyth int id;
402*8a8c2d74SCharles.Forsyth
403*8a8c2d74SCharles.Forsyth if(strlen(s) < 2)
404*8a8c2d74SCharles.Forsyth return 0;
405*8a8c2d74SCharles.Forsyth id = 'e';
406*8a8c2d74SCharles.Forsyth if(s[1] == '!')
407*8a8c2d74SCharles.Forsyth id = s[0];
408*8a8c2d74SCharles.Forsyth return id;
409*8a8c2d74SCharles.Forsyth }
410*8a8c2d74SCharles.Forsyth
411*8a8c2d74SCharles.Forsyth int
tokenize(char * s,char ** args,int maxargs)412*8a8c2d74SCharles.Forsyth tokenize(char *s, char **args, int maxargs)
413*8a8c2d74SCharles.Forsyth {
414*8a8c2d74SCharles.Forsyth int nargs;
415*8a8c2d74SCharles.Forsyth
416*8a8c2d74SCharles.Forsyth for(nargs = 0; nargs < maxargs; nargs++){
417*8a8c2d74SCharles.Forsyth while(*s != '\0' && strchr("\t\n ", *s) != nil)
418*8a8c2d74SCharles.Forsyth s++;
419*8a8c2d74SCharles.Forsyth if(*s == '\0')
420*8a8c2d74SCharles.Forsyth break;
421*8a8c2d74SCharles.Forsyth args[nargs] = s;
422*8a8c2d74SCharles.Forsyth while(*s != '\0' && strchr("\t\n ", *s) == nil)
423*8a8c2d74SCharles.Forsyth s++;
424*8a8c2d74SCharles.Forsyth if(*s != '\0')
425*8a8c2d74SCharles.Forsyth *s++ = 0;
426*8a8c2d74SCharles.Forsyth }
427*8a8c2d74SCharles.Forsyth return nargs;
428*8a8c2d74SCharles.Forsyth }
429*8a8c2d74SCharles.Forsyth
430*8a8c2d74SCharles.Forsyth int
aoepnp0(void)431*8a8c2d74SCharles.Forsyth aoepnp0(void)
432*8a8c2d74SCharles.Forsyth {
433*8a8c2d74SCharles.Forsyth int i;
434*8a8c2d74SCharles.Forsyth char *p, c;
435*8a8c2d74SCharles.Forsyth
436*8a8c2d74SCharles.Forsyth if((p = getconf("aoeif")) == nil)
437*8a8c2d74SCharles.Forsyth return 0;
438*8a8c2d74SCharles.Forsyth print("aoeif = %s\n", p);
439*8a8c2d74SCharles.Forsyth nprobe = tokenize(p, probef, nelem(probef));
440*8a8c2d74SCharles.Forsyth for(i = 0; i < nprobe; i++){
441*8a8c2d74SCharles.Forsyth if(strncmp(probef[i], "ether", 5) != 0)
442*8a8c2d74SCharles.Forsyth continue;
443*8a8c2d74SCharles.Forsyth c = probef[i][5];
444*8a8c2d74SCharles.Forsyth if(c > '9' || c < '0')
445*8a8c2d74SCharles.Forsyth continue;
446*8a8c2d74SCharles.Forsyth aoeether[c - '0'] = 1;
447*8a8c2d74SCharles.Forsyth }
448*8a8c2d74SCharles.Forsyth
449*8a8c2d74SCharles.Forsyth if((p = getconf("aoedev")) == nil)
450*8a8c2d74SCharles.Forsyth return 0;
451*8a8c2d74SCharles.Forsyth return nprobe = tokenize(p, probef, nelem(probef));
452*8a8c2d74SCharles.Forsyth }
453*8a8c2d74SCharles.Forsyth
454*8a8c2d74SCharles.Forsyth int
probeshelf(char * s,int * shelf,int * slot)455*8a8c2d74SCharles.Forsyth probeshelf(char *s, int *shelf, int *slot)
456*8a8c2d74SCharles.Forsyth {
457*8a8c2d74SCharles.Forsyth int a, b;
458*8a8c2d74SCharles.Forsyth char *r;
459*8a8c2d74SCharles.Forsyth
460*8a8c2d74SCharles.Forsyth for(r = s + strlen(s) - 1; r > s; r--)
461*8a8c2d74SCharles.Forsyth if((*r < '0' || *r > '9') && *r != '.'){
462*8a8c2d74SCharles.Forsyth r++;
463*8a8c2d74SCharles.Forsyth break;
464*8a8c2d74SCharles.Forsyth }
465*8a8c2d74SCharles.Forsyth a = strtoul(r, &r, 10);
466*8a8c2d74SCharles.Forsyth if(*r++ != '.')
467*8a8c2d74SCharles.Forsyth return -1;
468*8a8c2d74SCharles.Forsyth b = strtoul(r, 0, 10);
469*8a8c2d74SCharles.Forsyth
470*8a8c2d74SCharles.Forsyth *shelf = a;
471*8a8c2d74SCharles.Forsyth *slot = b;
472*8a8c2d74SCharles.Forsyth print(" shelf=%d.%d\n", a, b);
473*8a8c2d74SCharles.Forsyth return 0;
474*8a8c2d74SCharles.Forsyth }
475*8a8c2d74SCharles.Forsyth
476*8a8c2d74SCharles.Forsyth Ctlr*
pnpprobe(SDev * sd)477*8a8c2d74SCharles.Forsyth pnpprobe(SDev *sd)
478*8a8c2d74SCharles.Forsyth {
479*8a8c2d74SCharles.Forsyth int shelf, slot;
480*8a8c2d74SCharles.Forsyth char *p;
481*8a8c2d74SCharles.Forsyth static int i;
482*8a8c2d74SCharles.Forsyth
483*8a8c2d74SCharles.Forsyth if(i >= nprobe)
484*8a8c2d74SCharles.Forsyth return 0;
485*8a8c2d74SCharles.Forsyth p = probef[i++];
486*8a8c2d74SCharles.Forsyth if(strlen(p) < 2)
487*8a8c2d74SCharles.Forsyth return 0;
488*8a8c2d74SCharles.Forsyth if(p[1] == '!'){
489*8a8c2d74SCharles.Forsyth sd->idno = p[0];
490*8a8c2d74SCharles.Forsyth p += 2;
491*8a8c2d74SCharles.Forsyth }
492*8a8c2d74SCharles.Forsyth if(probeshelf(p, &shelf, &slot) == -1 ||
493*8a8c2d74SCharles.Forsyth aoeprobe(shelf, slot, sd) == -1 ||
494*8a8c2d74SCharles.Forsyth identify(sd->ctlr) == -1)
495*8a8c2d74SCharles.Forsyth return 0;
496*8a8c2d74SCharles.Forsyth return sd->ctlr;
497*8a8c2d74SCharles.Forsyth }
498*8a8c2d74SCharles.Forsyth
499*8a8c2d74SCharles.Forsyth /*
500*8a8c2d74SCharles.Forsyth * we may need to pretend we found something
501*8a8c2d74SCharles.Forsyth */
502*8a8c2d74SCharles.Forsyth
503*8a8c2d74SCharles.Forsyth SDev*
aoepnp(void)504*8a8c2d74SCharles.Forsyth aoepnp(void)
505*8a8c2d74SCharles.Forsyth {
506*8a8c2d74SCharles.Forsyth int n, i, id;
507*8a8c2d74SCharles.Forsyth char *p;
508*8a8c2d74SCharles.Forsyth SDev *h, *t, *s;
509*8a8c2d74SCharles.Forsyth
510*8a8c2d74SCharles.Forsyth p = getconf("aoeif");
511*8a8c2d74SCharles.Forsyth if (p)
512*8a8c2d74SCharles.Forsyth print("aoepnp: aoeif=%s\n", p);
513*8a8c2d74SCharles.Forsyth
514*8a8c2d74SCharles.Forsyth if((n = aoepnp0()) == 0)
515*8a8c2d74SCharles.Forsyth n = 2;
516*8a8c2d74SCharles.Forsyth t = h = 0;
517*8a8c2d74SCharles.Forsyth for(i = 0; i < n; i++){
518*8a8c2d74SCharles.Forsyth id = 'e';
519*8a8c2d74SCharles.Forsyth s = malloc(sizeof *s);
520*8a8c2d74SCharles.Forsyth if(s == 0)
521*8a8c2d74SCharles.Forsyth break;
522*8a8c2d74SCharles.Forsyth s->ctlr = 0;
523*8a8c2d74SCharles.Forsyth s->idno = id;
524*8a8c2d74SCharles.Forsyth s->ifc = &sdaoeifc;
525*8a8c2d74SCharles.Forsyth s->nunit = 1;
526*8a8c2d74SCharles.Forsyth pnpprobe(s);
527*8a8c2d74SCharles.Forsyth
528*8a8c2d74SCharles.Forsyth if(h)
529*8a8c2d74SCharles.Forsyth t->next = s;
530*8a8c2d74SCharles.Forsyth else
531*8a8c2d74SCharles.Forsyth h = s;
532*8a8c2d74SCharles.Forsyth t = s;
533*8a8c2d74SCharles.Forsyth }
534*8a8c2d74SCharles.Forsyth return h;
535*8a8c2d74SCharles.Forsyth }
536*8a8c2d74SCharles.Forsyth
537*8a8c2d74SCharles.Forsyth static int
aoeverify(SDunit * u)538*8a8c2d74SCharles.Forsyth aoeverify(SDunit *u)
539*8a8c2d74SCharles.Forsyth {
540*8a8c2d74SCharles.Forsyth Ctlr *c;
541*8a8c2d74SCharles.Forsyth SDev *s;
542*8a8c2d74SCharles.Forsyth
543*8a8c2d74SCharles.Forsyth s = u->dev;
544*8a8c2d74SCharles.Forsyth c = s->ctlr;
545*8a8c2d74SCharles.Forsyth if(c == 0){
546*8a8c2d74SCharles.Forsyth aoepnp0();
547*8a8c2d74SCharles.Forsyth if((s->ctlr = c = pnpprobe(s)) == nil)
548*8a8c2d74SCharles.Forsyth return 0;
549*8a8c2d74SCharles.Forsyth }
550*8a8c2d74SCharles.Forsyth c->mediachange = 1;
551*8a8c2d74SCharles.Forsyth return 1;
552*8a8c2d74SCharles.Forsyth }
553*8a8c2d74SCharles.Forsyth
554*8a8c2d74SCharles.Forsyth static int
aoeonline(SDunit * u)555*8a8c2d74SCharles.Forsyth aoeonline(SDunit *u)
556*8a8c2d74SCharles.Forsyth {
557*8a8c2d74SCharles.Forsyth int r;
558*8a8c2d74SCharles.Forsyth Ctlr *c;
559*8a8c2d74SCharles.Forsyth
560*8a8c2d74SCharles.Forsyth c = u->dev->ctlr;
561*8a8c2d74SCharles.Forsyth if(c->mediachange){
562*8a8c2d74SCharles.Forsyth r = 2;
563*8a8c2d74SCharles.Forsyth c->mediachange = 0;
564*8a8c2d74SCharles.Forsyth u->sectors = c->sectors;
565*8a8c2d74SCharles.Forsyth u->secsize = 512;
566*8a8c2d74SCharles.Forsyth } else
567*8a8c2d74SCharles.Forsyth r = 1;
568*8a8c2d74SCharles.Forsyth return r;
569*8a8c2d74SCharles.Forsyth }
570*8a8c2d74SCharles.Forsyth
571*8a8c2d74SCharles.Forsyth static int
rio(Ctlr * c,Aoeata * a,int n,int scnt)572*8a8c2d74SCharles.Forsyth rio(Ctlr *c, Aoeata *a, int n, int scnt)
573*8a8c2d74SCharles.Forsyth {
574*8a8c2d74SCharles.Forsyth int i, tag, cmd;
575*8a8c2d74SCharles.Forsyth
576*8a8c2d74SCharles.Forsyth for(i = 0; i < 5; i++){
577*8a8c2d74SCharles.Forsyth tag = hset(c, a, ACata);
578*8a8c2d74SCharles.Forsyth cmd = a->cmdstat;
579*8a8c2d74SCharles.Forsyth ethertxpkt(c->ctlrno, (Etherpkt*)a, n, 0);
580*8a8c2d74SCharles.Forsyth memset(a, 0, sizeof *a);
581*8a8c2d74SCharles.Forsyth again:
582*8a8c2d74SCharles.Forsyth n = etherrxpkt(c->ctlrno, (Etherpkt*)a, 125);
583*8a8c2d74SCharles.Forsyth if(n == 0)
584*8a8c2d74SCharles.Forsyth continue;
585*8a8c2d74SCharles.Forsyth if(nhgets(a->type) != Aoetype || nhgetl(a->tag) != tag ||
586*8a8c2d74SCharles.Forsyth nhgets(a->major) != c->major || a->minor != c->minor)
587*8a8c2d74SCharles.Forsyth goto again;
588*8a8c2d74SCharles.Forsyth if(a->cmdstat & 0xa9){
589*8a8c2d74SCharles.Forsyth print("aoe: ata rio error: %2ux\n", a->cmdstat);
590*8a8c2d74SCharles.Forsyth return 0;
591*8a8c2d74SCharles.Forsyth }
592*8a8c2d74SCharles.Forsyth switch(cmd){
593*8a8c2d74SCharles.Forsyth case Crd:
594*8a8c2d74SCharles.Forsyth case Crdext:
595*8a8c2d74SCharles.Forsyth if(n - sizeof *a < scnt * 512){
596*8a8c2d74SCharles.Forsyth print("aoe: runt expect %d got %d\n",
597*8a8c2d74SCharles.Forsyth scnt*512 + sizeof *a, n);
598*8a8c2d74SCharles.Forsyth return 0;
599*8a8c2d74SCharles.Forsyth }
600*8a8c2d74SCharles.Forsyth return n - sizeof *a;
601*8a8c2d74SCharles.Forsyth case Cwr:
602*8a8c2d74SCharles.Forsyth case Cwrext:
603*8a8c2d74SCharles.Forsyth return scnt * 512;
604*8a8c2d74SCharles.Forsyth default:
605*8a8c2d74SCharles.Forsyth print("unknown cmd %ux\n", cmd);
606*8a8c2d74SCharles.Forsyth break;
607*8a8c2d74SCharles.Forsyth }
608*8a8c2d74SCharles.Forsyth }
609*8a8c2d74SCharles.Forsyth print("aoe: rio timeout\n");
610*8a8c2d74SCharles.Forsyth return 0;
611*8a8c2d74SCharles.Forsyth }
612*8a8c2d74SCharles.Forsyth
613*8a8c2d74SCharles.Forsyth static void
putlba(Aoeata * a,vlong lba)614*8a8c2d74SCharles.Forsyth putlba(Aoeata *a, vlong lba)
615*8a8c2d74SCharles.Forsyth {
616*8a8c2d74SCharles.Forsyth uchar *c;
617*8a8c2d74SCharles.Forsyth
618*8a8c2d74SCharles.Forsyth c = a->lba;
619*8a8c2d74SCharles.Forsyth c[0] = lba;
620*8a8c2d74SCharles.Forsyth c[1] = lba >> 8;
621*8a8c2d74SCharles.Forsyth c[2] = lba >> 16;
622*8a8c2d74SCharles.Forsyth c[3] = lba >> 24;
623*8a8c2d74SCharles.Forsyth c[4] = lba >> 32;
624*8a8c2d74SCharles.Forsyth c[5] = lba >> 40;
625*8a8c2d74SCharles.Forsyth }
626*8a8c2d74SCharles.Forsyth
627*8a8c2d74SCharles.Forsyth /*
628*8a8c2d74SCharles.Forsyth * you'll need to loop if you want to read more than 2 sectors. for now
629*8a8c2d74SCharles.Forsyth * i'm cheeting and not bothering with a loop.
630*8a8c2d74SCharles.Forsyth */
631*8a8c2d74SCharles.Forsyth static uchar pktbuf[1024 + sizeof(Aoeata)];
632*8a8c2d74SCharles.Forsyth
633*8a8c2d74SCharles.Forsyth static int
aoebuild(Ctlr * c,uchar * cmd,char * data,vlong lba,int scnt)634*8a8c2d74SCharles.Forsyth aoebuild(Ctlr *c, uchar *cmd, char *data, vlong lba, int scnt)
635*8a8c2d74SCharles.Forsyth {
636*8a8c2d74SCharles.Forsyth int n;
637*8a8c2d74SCharles.Forsyth Aoeata *a;
638*8a8c2d74SCharles.Forsyth
639*8a8c2d74SCharles.Forsyth memset(pktbuf, 0, sizeof pktbuf);
640*8a8c2d74SCharles.Forsyth a = (Aoeata*)pktbuf;
641*8a8c2d74SCharles.Forsyth hset(c, a, ACata);
642*8a8c2d74SCharles.Forsyth putlba(a, lba);
643*8a8c2d74SCharles.Forsyth
644*8a8c2d74SCharles.Forsyth a->cmdstat = 0x20;
645*8a8c2d74SCharles.Forsyth if(c->flag & Dllba){
646*8a8c2d74SCharles.Forsyth a->aflag |= AAFext;
647*8a8c2d74SCharles.Forsyth a->cmdstat |= 4;
648*8a8c2d74SCharles.Forsyth }else{
649*8a8c2d74SCharles.Forsyth a->lba[3] &= 0xf;
650*8a8c2d74SCharles.Forsyth a->lba[3] |= 0xe0; /* LBA bit+obsolete 0xa0 */
651*8a8c2d74SCharles.Forsyth }
652*8a8c2d74SCharles.Forsyth
653*8a8c2d74SCharles.Forsyth n = scnt;
654*8a8c2d74SCharles.Forsyth if(n > 2)
655*8a8c2d74SCharles.Forsyth n = 2;
656*8a8c2d74SCharles.Forsyth a->scnt = n;
657*8a8c2d74SCharles.Forsyth
658*8a8c2d74SCharles.Forsyth switch(*cmd){
659*8a8c2d74SCharles.Forsyth case 0x2a:
660*8a8c2d74SCharles.Forsyth a->aflag |= AAFwrite;
661*8a8c2d74SCharles.Forsyth a->cmdstat |= 10;
662*8a8c2d74SCharles.Forsyth memmove(a+1, data, n*512);
663*8a8c2d74SCharles.Forsyth n = sizeof *a + n*512;
664*8a8c2d74SCharles.Forsyth break;
665*8a8c2d74SCharles.Forsyth case 0x28:
666*8a8c2d74SCharles.Forsyth n = sizeof *a;
667*8a8c2d74SCharles.Forsyth break;
668*8a8c2d74SCharles.Forsyth default:
669*8a8c2d74SCharles.Forsyth print("aoe: bad cmd 0x%.2ux\n", cmd[0]);
670*8a8c2d74SCharles.Forsyth return -1;
671*8a8c2d74SCharles.Forsyth }
672*8a8c2d74SCharles.Forsyth return n;
673*8a8c2d74SCharles.Forsyth }
674*8a8c2d74SCharles.Forsyth
675*8a8c2d74SCharles.Forsyth static int
aoerio(SDreq * r)676*8a8c2d74SCharles.Forsyth aoerio(SDreq *r)
677*8a8c2d74SCharles.Forsyth {
678*8a8c2d74SCharles.Forsyth int size, nsec, n;
679*8a8c2d74SCharles.Forsyth vlong lba;
680*8a8c2d74SCharles.Forsyth char *data;
681*8a8c2d74SCharles.Forsyth uchar *cmd;
682*8a8c2d74SCharles.Forsyth Aoeata *a;
683*8a8c2d74SCharles.Forsyth Ctlr *c;
684*8a8c2d74SCharles.Forsyth SDunit *unit;
685*8a8c2d74SCharles.Forsyth
686*8a8c2d74SCharles.Forsyth unit = r->unit;
687*8a8c2d74SCharles.Forsyth c = unit->dev->ctlr;
688*8a8c2d74SCharles.Forsyth if(r->data == nil)
689*8a8c2d74SCharles.Forsyth return SDok;
690*8a8c2d74SCharles.Forsyth cmd = r->cmd;
691*8a8c2d74SCharles.Forsyth
692*8a8c2d74SCharles.Forsyth lba = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5]; /* sic. */
693*8a8c2d74SCharles.Forsyth nsec = cmd[7]<<8 | cmd[8];
694*8a8c2d74SCharles.Forsyth a = (Aoeata*)pktbuf;
695*8a8c2d74SCharles.Forsyth data = r->data;
696*8a8c2d74SCharles.Forsyth r->rlen = 0;
697*8a8c2d74SCharles.Forsyth
698*8a8c2d74SCharles.Forsyth for(; nsec > 0; nsec -= n){
699*8a8c2d74SCharles.Forsyth // print("aoebuild(%2x, %p, %lld, %d)\n", *cmd, data, lba, nsec);
700*8a8c2d74SCharles.Forsyth size = aoebuild(c, cmd, data, lba, nsec);
701*8a8c2d74SCharles.Forsyth if(size < 0){
702*8a8c2d74SCharles.Forsyth r->status = SDcheck;
703*8a8c2d74SCharles.Forsyth return SDcheck;
704*8a8c2d74SCharles.Forsyth }
705*8a8c2d74SCharles.Forsyth n = a->scnt;
706*8a8c2d74SCharles.Forsyth r->rlen += rio(c, a, size, n);
707*8a8c2d74SCharles.Forsyth if(*cmd == 0x28)
708*8a8c2d74SCharles.Forsyth memmove(r->data, a + 1, n * 512);
709*8a8c2d74SCharles.Forsyth data += n * 512;
710*8a8c2d74SCharles.Forsyth lba += n;
711*8a8c2d74SCharles.Forsyth }
712*8a8c2d74SCharles.Forsyth
713*8a8c2d74SCharles.Forsyth r->status = SDok;
714*8a8c2d74SCharles.Forsyth return SDok;
715*8a8c2d74SCharles.Forsyth }
716*8a8c2d74SCharles.Forsyth
717*8a8c2d74SCharles.Forsyth SDifc sdaoeifc = {
718*8a8c2d74SCharles.Forsyth "aoe",
719*8a8c2d74SCharles.Forsyth
720*8a8c2d74SCharles.Forsyth aoepnp,
721*8a8c2d74SCharles.Forsyth nil, /* legacy */
722*8a8c2d74SCharles.Forsyth nil, /* id */
723*8a8c2d74SCharles.Forsyth nil, /* enable */
724*8a8c2d74SCharles.Forsyth nil, /* disable */
725*8a8c2d74SCharles.Forsyth
726*8a8c2d74SCharles.Forsyth aoeverify,
727*8a8c2d74SCharles.Forsyth aoeonline,
728*8a8c2d74SCharles.Forsyth aoerio,
729*8a8c2d74SCharles.Forsyth nil,
730*8a8c2d74SCharles.Forsyth nil,
731*8a8c2d74SCharles.Forsyth
732*8a8c2d74SCharles.Forsyth scsibio,
733*8a8c2d74SCharles.Forsyth };
734