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