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