1 /*
2 * aoe sd driver, copyright © 2007 coraid
3 */
4
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "../port/error.h"
11
12 #include "../port/netif.h"
13 #include "../port/sd.h"
14
15 #include "etherif.h"
16 #include "../port/aoe.h"
17
18 #define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__);
19
20 enum {
21 Nctlr = 32,
22 Maxpath = 128,
23
24 Probeintvl = 100, /* ms. between probes */
25 Probemax = 20, /* max probes */
26 };
27
28 enum {
29 /* sync with ahci.h */
30 Dllba = 1<<0,
31 Dsmart = 1<<1,
32 Dpower = 1<<2,
33 Dnop = 1<<3,
34 Datapi = 1<<4,
35 Datapi16= 1<<5,
36 };
37
38 static char *flagname[] = {
39 "llba",
40 "smart",
41 "power",
42 "nop",
43 "atapi",
44 "atapi16",
45 };
46
47 typedef struct Ctlr Ctlr;
48 struct Ctlr{
49 QLock;
50
51 Ctlr *next;
52 SDunit *unit;
53
54 char path[Maxpath];
55 Chan *c;
56
57 ulong vers;
58 uchar mediachange;
59 uchar flag;
60 uchar smart;
61 uchar smartrs;
62 uchar feat;
63
64 uvlong sectors;
65 char serial[20+1];
66 char firmware[8+1];
67 char model[40+1];
68 char ident[0x100];
69 };
70
71 void aoeidmove(char *p, ushort *a, unsigned n);
72
73 static Lock ctlrlock;
74 static Ctlr *head;
75 static Ctlr *tail;
76
77 SDifc sdaoeifc;
78
79 static ushort
gbit16(void * a)80 gbit16(void *a)
81 {
82 uchar *i;
83
84 i = a;
85 return i[1] << 8 | i[0];
86 }
87
88 static ulong
gbit32(void * a)89 gbit32(void *a)
90 {
91 ulong j;
92 uchar *i;
93
94 i = a;
95 j = i[3] << 24;
96 j |= i[2] << 16;
97 j |= i[1] << 8;
98 j |= i[0];
99 return j;
100 }
101
102 static uvlong
gbit64(void * a)103 gbit64(void *a)
104 {
105 uchar *i;
106
107 i = a;
108 return (uvlong)gbit32(i+4)<<32 | gbit32(i);
109 }
110
111 static int
identify(Ctlr * c,ushort * id)112 identify(Ctlr *c, ushort *id)
113 {
114 int i;
115 uchar oserial[21];
116 uvlong osectors, s;
117
118 osectors = c->sectors;
119 memmove(oserial, c->serial, sizeof c->serial);
120
121 c->feat &= ~(Dllba|Dpower|Dsmart|Dnop);
122 i = gbit16(id+83) | gbit16(id+86);
123 if(i & (1<<10)){
124 c->feat |= Dllba;
125 s = gbit64(id+100);
126 }else
127 s = gbit32(id+60);
128
129 i = gbit16(id+83);
130 if((i>>14) == 1) {
131 if(i & (1<<3))
132 c->feat |= Dpower;
133 i = gbit16(id+82);
134 if(i & 1)
135 c->feat |= Dsmart;
136 if(i & (1<<14))
137 c->feat |= Dnop;
138 }
139
140 aoeidmove(c->serial, id+10, 20);
141 aoeidmove(c->firmware, id+23, 8);
142 aoeidmove(c->model, id+27, 40);
143
144 if((osectors == 0 || osectors != s) &&
145 memcmp(oserial, c->serial, sizeof oserial) != 0){
146 c->sectors = s;
147 c->mediachange = 1;
148 c->vers++;
149 }
150 return 0;
151 }
152
153 /* must call with d qlocked */
154 static int
aoeidentify(Ctlr * d,SDunit * u)155 aoeidentify(Ctlr *d, SDunit *u)
156 {
157 Chan *c;
158
159 c = nil;
160 if(waserror()){
161 if(c)
162 cclose(c);
163 iprint("aoeidentify: %s\n", up->errstr);
164 nexterror();
165 }
166
167 uprint("%s/ident", d->path);
168 c = namec(up->genbuf, Aopen, OREAD, 0);
169 c->dev->read(c, d->ident, sizeof d->ident, 0);
170
171 poperror();
172 cclose(c);
173
174 d->feat = 0;
175 d->smart = 0;
176 identify(d, (ushort*)d->ident);
177
178 memset(u->inquiry, 0, sizeof u->inquiry);
179 u->inquiry[2] = 2;
180 u->inquiry[3] = 2;
181 u->inquiry[4] = sizeof u->inquiry - 4;
182 memmove(u->inquiry+8, d->model, 40);
183
184 return 0;
185 }
186
187 static Ctlr*
ctlrlookup(char * path)188 ctlrlookup(char *path)
189 {
190 Ctlr *c;
191
192 lock(&ctlrlock);
193 for(c = head; c; c = c->next)
194 if(strcmp(c->path, path) == 0)
195 break;
196 unlock(&ctlrlock);
197 return c;
198 }
199
200 static Ctlr*
newctlr(char * path)201 newctlr(char *path)
202 {
203 Ctlr *c;
204
205 /* race? */
206 if(ctlrlookup(path))
207 error(Eexist);
208
209 if((c = malloc(sizeof *c)) == nil)
210 return 0;
211 kstrcpy(c->path, path, sizeof c->path);
212 lock(&ctlrlock);
213 if(head != nil)
214 tail->next = c;
215 else
216 head = c;
217 tail = c;
218 unlock(&ctlrlock);
219 return c;
220 }
221
222 static void
delctlr(Ctlr * c)223 delctlr(Ctlr *c)
224 {
225 Ctlr *x, *prev;
226
227 lock(&ctlrlock);
228
229 for(prev = 0, x = head; x; prev = x, x = c->next)
230 if(strcmp(c->path, x->path) == 0)
231 break;
232 if(x == 0){
233 unlock(&ctlrlock);
234 error(Enonexist);
235 }
236
237 if(prev)
238 prev->next = x->next;
239 else
240 head = x->next;
241 if(x->next == nil)
242 tail = prev;
243 unlock(&ctlrlock);
244
245 if(x->c)
246 cclose(x->c);
247 free(x);
248 }
249
250 /* don't call aoeprobe from within a loop; it loops internally retrying open. */
251 static SDev*
aoeprobe(char * path,SDev * s)252 aoeprobe(char *path, SDev *s)
253 {
254 int n, i;
255 char *p;
256 Chan *c;
257 Ctlr *ctlr;
258
259 if((p = strrchr(path, '/')) == 0)
260 error(Ebadarg);
261 *p = 0;
262 uprint("%s/ctl", path);
263 *p = '/';
264
265 c = namec(up->genbuf, Aopen, OWRITE, 0);
266 if(waserror()) {
267 cclose(c);
268 nexterror();
269 }
270 n = uprint("discover %s", p+1);
271 c->dev->write(c, up->genbuf, n, 0);
272 poperror();
273 cclose(c);
274
275 for(i = 0; i < Probemax; i++){
276 tsleep(&up->sleep, return0, 0, Probeintvl);
277 uprint("%s/ident", path);
278 if(!waserror()) {
279 c = namec(up->genbuf, Aopen, OREAD, 0);
280 poperror();
281 cclose(c);
282 break;
283 }
284 }
285 if(i >= Probemax)
286 error(Etimedout);
287 uprint("%s/ident", path);
288 ctlr = newctlr(path);
289 if(ctlr == nil || s == nil && (s = malloc(sizeof *s)) == nil)
290 return nil;
291 s->ctlr = ctlr;
292 s->ifc = &sdaoeifc;
293 s->nunit = 1;
294 return s;
295 }
296
297 static char *probef[32];
298 static int nprobe;
299
300 static int
pnpprobeid(char * s)301 pnpprobeid(char *s)
302 {
303 if(strlen(s) < 2)
304 return 0;
305 return s[1] == '!'? s[0]: 'e';
306 }
307
308 static SDev*
aoepnp(void)309 aoepnp(void)
310 {
311 int i, id;
312 char *p;
313 SDev *h, *t, *s;
314
315 if((p = getconf("aoedev")) == 0)
316 return 0;
317 nprobe = tokenize(p, probef, nelem(probef));
318 h = t = 0;
319 for(i = 0; i < nprobe; i++){
320 id = pnpprobeid(probef[i]);
321 if(id == 0)
322 continue;
323 s = malloc(sizeof *s);
324 if(s == nil)
325 break;
326 s->ctlr = 0;
327 s->idno = id;
328 s->ifc = &sdaoeifc;
329 s->nunit = 1;
330
331 if(h)
332 t->next = s;
333 else
334 h = s;
335 t = s;
336 }
337 return h;
338 }
339
340 static Ctlr*
pnpprobe(SDev * sd)341 pnpprobe(SDev *sd)
342 {
343 ulong start;
344 char *p;
345 static int i;
346
347 if(i > nprobe)
348 return 0;
349 p = probef[i++];
350 if(strlen(p) < 2)
351 return 0;
352 if(p[1] == '!')
353 p += 2;
354
355 start = TK2MS(sys->ticks);
356 if(waserror()){
357 print("#æ: pnpprobe failed in %lud ms: %s: %s\n",
358 TK2MS(sys->ticks) - start, probef[i-1],
359 up->errstr);
360 return nil;
361 }
362 sd = aoeprobe(p, sd); /* does a round of probing */
363 poperror();
364 print("#æ: pnpprobe established %s in %lud ms\n",
365 probef[i-1], TK2MS(sys->ticks) - start);
366 return sd->ctlr;
367 }
368
369
370 static int
aoeverify(SDunit * u)371 aoeverify(SDunit *u)
372 {
373 SDev *s;
374 Ctlr *c;
375
376 s = u->dev;
377 c = s->ctlr;
378 if(c == nil && (s->ctlr = c = pnpprobe(s)) == nil)
379 return 0;
380 c->mediachange = 1;
381 return 1;
382 }
383
384 static int
aoeconnect(SDunit * u,Ctlr * c)385 aoeconnect(SDunit *u, Ctlr *c)
386 {
387 qlock(c);
388 if(waserror()){
389 qunlock(c);
390 return -1;
391 }
392
393 aoeidentify(u->dev->ctlr, u);
394 if(c->c)
395 cclose(c->c);
396 c->c = 0;
397 uprint("%s/data", c->path);
398 c->c = namec(up->genbuf, Aopen, ORDWR, 0);
399 qunlock(c);
400 poperror();
401
402 return 0;
403 }
404
405 static int
aoeonline(SDunit * u)406 aoeonline(SDunit *u)
407 {
408 Ctlr *c;
409 int r;
410
411 c = u->dev->ctlr;
412 r = 0;
413
414 if((c->feat&Datapi) && c->mediachange){
415 if(aoeconnect(u, c) == 0 && (r = scsionline(u)) > 0)
416 c->mediachange = 0;
417 return r;
418 }
419
420 if(c->mediachange){
421 if(aoeconnect(u, c) == -1)
422 return 0;
423 r = 2;
424 c->mediachange = 0;
425 u->sectors = c->sectors;
426 u->secsize = Aoesectsz;
427 } else
428 r = 1;
429
430 return r;
431 }
432
433 static int
aoerio(SDreq * r)434 aoerio(SDreq *r)
435 {
436 int i;
437 ulong count;
438 uvlong lba;
439 char *name;
440 uchar *cmd;
441 long (*rio)(Chan*, void*, long, vlong);
442 Ctlr *c;
443 SDunit *unit;
444
445 unit = r->unit;
446 c = unit->dev->ctlr;
447 // if(c->feat & Datapi)
448 // return aoeriopkt(r, d);
449
450 cmd = r->cmd;
451 name = unit->name;
452
453 if(*cmd == ScmdSynccache || *cmd == ScmdSynccache16)
454 // qlock(c);
455 // i = flushcache();
456 // qunlock(c);
457 // if(i == 0)
458 // return sdsetsense(r, SDok, 0, 0, 0);
459 return sdsetsense(r, SDcheck, 3, 0xc, 2);
460
461 if((i = sdfakescsi(r, c->ident, sizeof c->ident)) != SDnostatus){
462 r->status = i;
463 return i;
464 }
465
466 switch(*cmd){
467 case ScmdRead16:
468 case ScmdExtread:
469 rio = c->c->dev->read;
470 break;
471 case ScmdWrite16:
472 case ScmdExtwrite:
473 rio = c->c->dev->write;
474 break;
475 default:
476 print("%s: bad cmd %#.2ux\n", name, cmd[0]);
477 r->status = SDcheck;
478 return SDcheck;
479 }
480
481 if(r->data == nil)
482 return SDok;
483
484 if(r->clen == 16){
485 /* ata commands only go to 48-bit lba */
486 if(cmd[2] || cmd[3])
487 return sdsetsense(r, SDcheck, 3, 0xc, 2);
488 }
489 scsilbacount(cmd, r->clen, &lba, &count);
490 count *= Aoesectsz;
491
492 if(r->dlen < count)
493 count = r->dlen & ~0x1ff;
494
495 if(waserror()){
496 if(strcmp(up->errstr, Echange) == 0 ||
497 strcmp(up->errstr, Eaoedown) == 0)
498 unit->sectors = 0;
499 nexterror();
500 }
501 r->rlen = rio(c->c, r->data, count, Aoesectsz * lba);
502 poperror();
503 r->status = SDok;
504 return SDok;
505 }
506
507 static char *smarttab[] = {
508 "unset",
509 "error",
510 "threshold exceeded",
511 "normal"
512 };
513
514 static char *
pflag(char * s,char * e,uchar f)515 pflag(char *s, char *e, uchar f)
516 {
517 uchar i;
518
519 for(i = 0; i < 8; i++)
520 if(f & (1 << i))
521 s = seprint(s, e, "%s ", flagname[i]);
522 return seprint(s, e, "\n");
523 }
524
525 static int
aoerctl(SDunit * u,char * p,int l)526 aoerctl(SDunit *u, char *p, int l)
527 {
528 Ctlr *c;
529 char *e, *op;
530
531 if((c = u->dev->ctlr) == nil)
532 return 0;
533 e = p+l;
534 op = p;
535
536 p = seprint(p, e, "model\t%s\n", c->model);
537 p = seprint(p, e, "serial\t%s\n", c->serial);
538 p = seprint(p, e, "firm %s\n", c->firmware);
539 if(c->smartrs == 0xff)
540 p = seprint(p, e, "smart\tenable error\n");
541 else if(c->smartrs == 0)
542 p = seprint(p, e, "smart\tdisabled\n");
543 else
544 p = seprint(p, e, "smart\t%s\n", smarttab[c->smart]);
545 p = seprint(p, e, "flag ");
546 p = pflag(p, e, c->feat);
547 p = seprint(p, e, "geometry %llud %d\n", c->sectors, Aoesectsz);
548 return p-op;
549 }
550
551 static int
aoewctl(SDunit *,Cmdbuf * cmd)552 aoewctl(SDunit *, Cmdbuf *cmd)
553 {
554 cmderror(cmd, Ebadarg);
555 return 0;
556 }
557
558 static SDev*
aoeprobew(DevConf * c)559 aoeprobew(DevConf *c)
560 {
561 char *p;
562
563 p = strchr(c->type, '/');
564 if(p == nil || strlen(p) > Maxpath - 11)
565 error(Ebadarg);
566 if(p[1] == '#')
567 p++; /* hack */
568 if(ctlrlookup(p))
569 error(Einuse);
570 return aoeprobe(p, 0);
571 }
572
573 static void
aoeclear(SDev * s)574 aoeclear(SDev *s)
575 {
576 delctlr((Ctlr *)s->ctlr);
577 }
578
579 static char*
aoertopctl(SDev * s,char * p,char * e)580 aoertopctl(SDev *s, char *p, char *e)
581 {
582 Ctlr *c;
583
584 if(s == nil || (c = s->ctlr) == nil)
585 return p;
586
587 return seprint(p, e, "%s aoe %s\n", s->name, c->path);
588 }
589
590 static int
aoewtopctl(SDev *,Cmdbuf * cmd)591 aoewtopctl(SDev *, Cmdbuf *cmd)
592 {
593 switch(cmd->nf){
594 default:
595 cmderror(cmd, Ebadarg);
596 }
597 return 0;
598 }
599
600 SDifc sdaoeifc = {
601 "aoe",
602
603 aoepnp,
604 nil, /* legacy */
605 nil, /* enable */
606 nil, /* disable */
607
608 aoeverify,
609 aoeonline,
610 aoerio,
611 aoerctl,
612 aoewctl,
613
614 scsibio,
615 aoeprobew, /* probe */
616 aoeclear, /* clear */
617 aoertopctl,
618 aoewtopctl,
619 };
620