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