1 /* 2 * usb/disk - usb mass storage file server 3 * 4 * supports only the scsi command interface, not ata. 5 */ 6 7 #include <u.h> 8 #include <libc.h> 9 #include <ctype.h> 10 #include <fcall.h> 11 #include <thread.h> 12 #include "scsireq.h" 13 #include "usb.h" 14 #include "usbfs.h" 15 #include "ums.h" 16 17 enum 18 { 19 Qdir = 0, 20 Qctl, 21 Qraw, 22 Qdata, 23 Qmax, 24 }; 25 26 typedef struct Dirtab Dirtab; 27 struct Dirtab 28 { 29 char *name; 30 int mode; 31 }; 32 33 static Dirtab dirtab[] = 34 { 35 [Qdir] "/", DMDIR|0555, 36 [Qctl] "ctl", 0664, /* nothing secret here */ 37 [Qraw] "raw", 0640, 38 [Qdata] "data", 0640, 39 }; 40 41 /* 42 * These are used by scuzz scsireq 43 */ 44 int exabyte, force6bytecmds; 45 46 int diskdebug; 47 48 static void 49 ding(void *, char *msg) 50 { 51 if(strstr(msg, "alarm") != nil) 52 noted(NCONT); 53 noted(NDFLT); 54 } 55 56 static int 57 getmaxlun(Dev *dev) 58 { 59 uchar max; 60 int r; 61 62 max = 0; 63 r = Rd2h|Rclass|Riface; 64 if(usbcmd(dev, r, Getmaxlun, 0, 0, &max, 1) < 0){ 65 dprint(2, "disk: %s: getmaxlun failed: %r\n", dev->dir); 66 }else{ 67 max &= 017; /* 15 is the max. allowed */ 68 dprint(2, "disk: %s: maxlun %d\n", dev->dir, max); 69 } 70 return max; 71 } 72 73 static int 74 umsreset(Ums *ums) 75 { 76 int r; 77 78 r = Rh2d|Rclass|Riface; 79 if(usbcmd(ums->dev, r, Umsreset, 0, 0, nil, 0) < 0){ 80 fprint(2, "disk: reset: %r\n"); 81 return -1; 82 } 83 return 0; 84 } 85 86 static int 87 umsrecover(Ums *ums) 88 { 89 if(umsreset(ums) < 0) 90 return -1; 91 if(unstall(ums->dev, ums->epin, Ein) < 0) 92 dprint(2, "disk: unstall epin: %r\n"); 93 94 /* do we need this when epin == epout? */ 95 if(unstall(ums->dev, ums->epout, Eout) < 0) 96 dprint(2, "disk: unstall epout: %r\n"); 97 return 0; 98 } 99 100 static void 101 umsfatal(Ums *ums) 102 { 103 int i; 104 105 devctl(ums->dev, "detach"); 106 for(i = 0; i < ums->maxlun; i++) 107 usbfsdel(&ums->lun[i].fs); 108 } 109 110 static int 111 ispow2(uvlong ul) 112 { 113 return (ul & (ul - 1)) == 0; 114 } 115 116 /* 117 * return smallest power of 2 >= n 118 */ 119 static int 120 log2(int n) 121 { 122 int i; 123 124 for(i = 0; (1 << i) < n; i++) 125 ; 126 return i; 127 } 128 129 static int 130 umscapacity(Umsc *lun) 131 { 132 uchar data[32]; 133 134 lun->blocks = 0; 135 lun->capacity = 0; 136 lun->lbsize = 0; 137 memset(data, 0, sizeof data); 138 if(SRrcapacity(lun, data) < 0 && SRrcapacity(lun, data) < 0) 139 return -1; 140 lun->blocks = GETBELONG(data); 141 lun->lbsize = GETBELONG(data+4); 142 if(lun->blocks == 0xFFFFFFFF){ 143 if(SRrcapacity16(lun, data) < 0){ 144 lun->lbsize = 0; 145 lun->blocks = 0; 146 return -1; 147 }else{ 148 lun->lbsize = GETBELONG(data + 8); 149 lun->blocks = (uvlong)GETBELONG(data)<<32 | 150 GETBELONG(data + 4); 151 } 152 } 153 lun->blocks++; /* SRcapacity returns LBA of last block */ 154 lun->capacity = (vlong)lun->blocks * lun->lbsize; 155 if(diskdebug) 156 fprint(2, "disk: logical block size %lud, # blocks %llud\n", 157 lun->lbsize, lun->blocks); 158 return 0; 159 } 160 161 static int 162 umsinit(Ums *ums) 163 { 164 uchar i; 165 Umsc *lun; 166 int some; 167 168 umsreset(ums); 169 ums->maxlun = getmaxlun(ums->dev); 170 ums->lun = mallocz((ums->maxlun+1) * sizeof(*ums->lun), 1); 171 some = 0; 172 for(i = 0; i <= ums->maxlun; i++){ 173 lun = &ums->lun[i]; 174 lun->ums = ums; 175 lun->umsc = lun; 176 lun->lun = i; 177 lun->flags = Fopen | Fusb | Frw10; 178 if(SRinquiry(lun) < 0 && SRinquiry(lun) < 0){ 179 dprint(2, "disk: lun %d inquiry failed\n", i); 180 continue; 181 } 182 switch(lun->inquiry[0]){ 183 case Devdir: 184 case Devworm: /* a little different than the others */ 185 case Devcd: 186 case Devmo: 187 break; 188 default: 189 fprint(2, "disk: lun %d is not a disk (type %#02x)\n", 190 i, lun->inquiry[0]); 191 continue; 192 } 193 SRstart(lun, 1); 194 /* 195 * we ignore the device type reported by inquiry. 196 * Some devices return a wrong value but would still work. 197 */ 198 some++; 199 lun->inq = smprint("%.48s", (char *)lun->inquiry+8); 200 umscapacity(lun); 201 } 202 if(some == 0){ 203 dprint(2, "disk: all luns failed\n"); 204 devctl(ums->dev, "detach"); 205 return -1; 206 } 207 return 0; 208 } 209 210 211 /* 212 * called by SR*() commands provided by scuzz's scsireq 213 */ 214 long 215 umsrequest(Umsc *umsc, ScsiPtr *cmd, ScsiPtr *data, int *status) 216 { 217 Cbw cbw; 218 Csw csw; 219 int n, nio, left; 220 Ums *ums; 221 222 ums = umsc->ums; 223 224 memcpy(cbw.signature, "USBC", 4); 225 cbw.tag = ++ums->seq; 226 cbw.datalen = data->count; 227 cbw.flags = data->write? CbwDataOut: CbwDataIn; 228 cbw.lun = umsc->lun; 229 if(cmd->count < 1 || cmd->count > 16) 230 fprint(2, "disk: umsrequest: bad cmd count: %ld\n", cmd->count); 231 232 cbw.len = cmd->count; 233 assert(cmd->count <= sizeof(cbw.command)); 234 memcpy(cbw.command, cmd->p, cmd->count); 235 memset(cbw.command + cmd->count, 0, sizeof(cbw.command) - cmd->count); 236 237 werrstr(""); /* we use %r later even for n == 0 */ 238 if(diskdebug){ 239 fprint(2, "disk: cmd: tag %#lx: ", cbw.tag); 240 for(n = 0; n < cbw.len; n++) 241 fprint(2, " %2.2x", cbw.command[n]&0xFF); 242 fprint(2, " datalen: %ld\n", cbw.datalen); 243 } 244 245 /* issue tunnelled scsi command */ 246 if(write(ums->epout->dfd, &cbw, CbwLen) != CbwLen){ 247 fprint(2, "disk: cmd: %r\n"); 248 goto Fail; 249 } 250 251 /* transfer the data */ 252 nio = data->count; 253 if(nio != 0){ 254 if(data->write) 255 n = write(ums->epout->dfd, data->p, nio); 256 else{ 257 n = read(ums->epin->dfd, data->p, nio); 258 left = nio - n; 259 if (n >= 0 && left > 0) /* didn't fill data->p? */ 260 memset(data->p + n, 0, left); 261 } 262 nio = n; 263 if(diskdebug) 264 if(n < 0) 265 fprint(2, "disk: data: %r\n"); 266 else 267 fprint(2, "disk: data: %d bytes\n", n); 268 if(n <= 0) 269 if(data->write == 0) 270 unstall(ums->dev, ums->epin, Ein); 271 } 272 273 /* read the transfer's status */ 274 n = read(ums->epin->dfd, &csw, CswLen); 275 if(n <= 0){ 276 /* n == 0 means "stalled" */ 277 unstall(ums->dev, ums->epin, Ein); 278 n = read(ums->epin->dfd, &csw, CswLen); 279 } 280 281 if(n != CswLen || strncmp(csw.signature, "USBS", 4) != 0){ 282 dprint(2, "disk: read n=%d: status: %r\n", n); 283 goto Fail; 284 } 285 if(csw.tag != cbw.tag){ 286 dprint(2, "disk: status tag mismatch\n"); 287 goto Fail; 288 } 289 if(csw.status >= CswPhaseErr){ 290 dprint(2, "disk: phase error\n"); 291 goto Fail; 292 } 293 if(csw.dataresidue == 0 || ums->wrongresidues) 294 csw.dataresidue = data->count - nio; 295 if(diskdebug){ 296 fprint(2, "disk: status: %2.2ux residue: %ld\n", 297 csw.status, csw.dataresidue); 298 if(cbw.command[0] == ScmdRsense){ 299 fprint(2, "sense data:"); 300 for(n = 0; n < data->count - csw.dataresidue; n++) 301 fprint(2, " %2.2x", data->p[n]); 302 fprint(2, "\n"); 303 } 304 } 305 switch(csw.status){ 306 case CswOk: 307 *status = STok; 308 break; 309 case CswFailed: 310 *status = STcheck; 311 break; 312 default: 313 dprint(2, "disk: phase error\n"); 314 goto Fail; 315 } 316 ums->nerrs = 0; 317 return data->count - csw.dataresidue; 318 319 Fail: 320 *status = STharderr; 321 if(ums->nerrs++ > 15){ 322 fprint(2, "disk: %s: too many errors: device detached\n", ums->dev->dir); 323 umsfatal(ums); 324 }else 325 umsrecover(ums); 326 return -1; 327 } 328 329 static int 330 dwalk(Usbfs *fs, Fid *fid, char *name) 331 { 332 int i; 333 Qid qid; 334 335 qid = fid->qid; 336 if((qid.type & QTDIR) == 0){ 337 werrstr("walk in non-directory"); 338 return -1; 339 } 340 341 if(strcmp(name, "..") == 0) 342 return 0; 343 344 for(i = 1; i < nelem(dirtab); i++) 345 if(strcmp(name, dirtab[i].name) == 0){ 346 qid.path = i | fs->qid; 347 qid.vers = 0; 348 qid.type = dirtab[i].mode >> 24; 349 fid->qid = qid; 350 return 0; 351 } 352 werrstr(Enotfound); 353 return -1; 354 } 355 356 static void 357 dostat(Usbfs *fs, int path, Dir *d) 358 { 359 Dirtab *t; 360 Umsc *lun; 361 362 t = &dirtab[path]; 363 d->qid.path = path; 364 d->qid.type = t->mode >> 24; 365 d->mode = t->mode; 366 d->name = t->name; 367 lun = fs->aux; 368 if(path == Qdata) 369 d->length = lun->capacity; 370 else 371 d->length = 0; 372 } 373 374 static int 375 dirgen(Usbfs *fs, Qid, int i, Dir *d, void*) 376 { 377 i++; /* skip dir */ 378 if(i >= Qmax) 379 return -1; 380 else{ 381 dostat(fs, i, d); 382 d->qid.path |= fs->qid; 383 return 0; 384 } 385 } 386 387 static int 388 dstat(Usbfs *fs, Qid qid, Dir *d) 389 { 390 int path; 391 392 path = qid.path & ~fs->qid; 393 dostat(fs, path, d); 394 d->qid.path |= fs->qid; 395 return 0; 396 } 397 398 static int 399 dopen(Usbfs *fs, Fid *fid, int) 400 { 401 ulong path; 402 Umsc *lun; 403 404 path = fid->qid.path & ~fs->qid; 405 lun = fs->aux; 406 switch(path){ 407 case Qraw: 408 lun->phase = Pcmd; 409 break; 410 } 411 return 0; 412 } 413 414 /* 415 * check i/o parameters and compute values needed later. 416 * we shift & mask manually to avoid run-time calls to _divv and _modv, 417 * since we don't need general division nor its cost. 418 */ 419 static int 420 setup(Umsc *lun, char *data, int count, vlong offset) 421 { 422 long nb, lbsize, lbshift, lbmask; 423 uvlong bno; 424 425 if(count < 0 || lun->lbsize <= 0 && umscapacity(lun) < 0 || 426 lun->lbsize == 0) 427 return -1; 428 lbsize = lun->lbsize; 429 assert(ispow2(lbsize)); 430 lbshift = log2(lbsize); 431 lbmask = lbsize - 1; 432 433 bno = offset >> lbshift; /* offset / lbsize */ 434 nb = ((offset + count + lbsize - 1) >> lbshift) - bno; 435 436 if(bno + nb > lun->blocks) /* past end of device? */ 437 nb = lun->blocks - bno; 438 if(nb * lbsize > Maxiosize) 439 nb = Maxiosize / lbsize; 440 lun->nb = nb; 441 if(bno >= lun->blocks || nb == 0) 442 return 0; 443 444 lun->offset = bno; 445 lun->off = offset & lbmask; /* offset % lbsize */ 446 if(lun->off == 0 && (count & lbmask) == 0) 447 lun->bufp = data; 448 else 449 /* not transferring full, aligned blocks; need intermediary */ 450 lun->bufp = lun->buf; 451 return count; 452 } 453 454 /* 455 * Upon SRread/SRwrite errors we assume the medium may have changed, 456 * and ask again for the capacity of the media. 457 * BUG: How to proceed to avoid confusing dossrv?? 458 * 459 * ctl reads must match the format documented in sd(3) exactly 460 * to interoperate with the rest of the system. 461 */ 462 static long 463 dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset) 464 { 465 long n; 466 ulong path; 467 char buf[1024]; 468 char *s, *e; 469 Umsc *lun; 470 Ums *ums; 471 Qid q; 472 473 q = fid->qid; 474 path = fid->qid.path & ~fs->qid; 475 ums = fs->dev->aux; 476 lun = fs->aux; 477 478 qlock(ums); 479 switch(path){ 480 case Qdir: 481 count = usbdirread(fs, q, data, count, offset, dirgen, nil); 482 break; 483 case Qctl: 484 /* 485 * Some usb disks need an extra opportunity to divulge their 486 * capacity (e.g. M-Systems/SanDisk 1GB flash drive). 487 */ 488 if(lun->lbsize <= 0) 489 umscapacity(lun); 490 491 s = buf; 492 e = buf + sizeof(buf); 493 if(lun->flags & Finqok) 494 s = seprint(s, e, "inquiry %s lun %ld: %s\n", 495 fs->dev->dir, lun - &ums->lun[0], lun->inq); 496 if(lun->blocks > 0) 497 s = seprint(s, e, "geometry %llud %ld\n", 498 lun->blocks, lun->lbsize); 499 count = usbreadbuf(data, count, offset, buf, s - buf); 500 break; 501 case Qraw: 502 if(lun->lbsize <= 0 && umscapacity(lun) < 0){ 503 count = -1; 504 break; 505 } 506 switch(lun->phase){ 507 case Pcmd: 508 qunlock(ums); 509 werrstr("phase error"); 510 return -1; 511 case Pdata: 512 lun->data.p = data; 513 lun->data.count = count; 514 lun->data.write = 0; 515 count = umsrequest(lun,&lun->cmd,&lun->data,&lun->status); 516 lun->phase = Pstatus; 517 if(count < 0) 518 lun->lbsize = 0; /* medium may have changed */ 519 break; 520 case Pstatus: 521 n = snprint(buf, sizeof buf, "%11.0ud ", lun->status); 522 count = usbreadbuf(data, count, 0LL, buf, n); 523 lun->phase = Pcmd; 524 break; 525 } 526 break; 527 case Qdata: 528 count = setup(lun, data, count, offset); 529 if (count <= 0) 530 break; 531 n = SRread(lun, lun->bufp, lun->nb * lun->lbsize); 532 if(n < 0){ 533 lun->lbsize = 0; /* medium may have changed */ 534 count = -1; 535 } else if (lun->bufp == data) 536 count = n; 537 else{ 538 /* 539 * if n == lun->nb*lun->lbsize (as expected), 540 * just copy count bytes. 541 */ 542 if(lun->off + count > n) 543 count = n - lun->off; /* short read */ 544 if(count > 0) 545 memmove(data, lun->bufp + lun->off, count); 546 } 547 break; 548 } 549 qunlock(ums); 550 return count; 551 } 552 553 static long 554 dwrite(Usbfs *fs, Fid *fid, void *data, long count, vlong offset) 555 { 556 long len, ocount; 557 ulong path; 558 uvlong bno; 559 Ums *ums; 560 Umsc *lun; 561 562 ums = fs->dev->aux; 563 lun = fs->aux; 564 path = fid->qid.path & ~fs->qid; 565 566 qlock(ums); 567 switch(path){ 568 default: 569 werrstr(Eperm); 570 count = -1; 571 break; 572 case Qctl: 573 dprint(2, "usb/disk: ctl ignored\n"); 574 break; 575 case Qraw: 576 if(lun->lbsize <= 0 && umscapacity(lun) < 0){ 577 count = -1; 578 break; 579 } 580 switch(lun->phase){ 581 case Pcmd: 582 if(count != 6 && count != 10){ 583 qunlock(ums); 584 werrstr("bad command length"); 585 return -1; 586 } 587 memmove(lun->rawcmd, data, count); 588 lun->cmd.p = lun->rawcmd; 589 lun->cmd.count = count; 590 lun->cmd.write = 1; 591 lun->phase = Pdata; 592 break; 593 case Pdata: 594 lun->data.p = data; 595 lun->data.count = count; 596 lun->data.write = 1; 597 count = umsrequest(lun,&lun->cmd,&lun->data,&lun->status); 598 lun->phase = Pstatus; 599 if(count < 0) 600 lun->lbsize = 0; /* medium may have changed */ 601 break; 602 case Pstatus: 603 lun->phase = Pcmd; 604 werrstr("phase error"); 605 count = -1; 606 break; 607 } 608 break; 609 case Qdata: 610 len = ocount = count; 611 count = setup(lun, data, count, offset); 612 if (count <= 0) 613 break; 614 bno = lun->offset; 615 if (lun->bufp == lun->buf) { 616 count = SRread(lun, lun->bufp, lun->nb * lun->lbsize); 617 if(count < 0) { 618 lun->lbsize = 0; /* medium may have changed */ 619 break; 620 } 621 /* 622 * if count == lun->nb*lun->lbsize, as expected, just 623 * copy len (the original count) bytes of user data. 624 */ 625 if(lun->off + len > count) 626 len = count - lun->off; /* short read */ 627 if(len > 0) 628 memmove(lun->bufp + lun->off, data, len); 629 } 630 631 lun->offset = bno; 632 count = SRwrite(lun, lun->bufp, lun->nb * lun->lbsize); 633 if(count < 0) 634 lun->lbsize = 0; /* medium may have changed */ 635 else{ 636 if(lun->off + len > count) 637 count -= lun->off; /* short write */ 638 /* never report more bytes written than requested */ 639 if(count < 0) 640 count = 0; 641 else if(count > ocount) 642 count = ocount; 643 } 644 break; 645 } 646 qunlock(ums); 647 return count; 648 } 649 650 int 651 findendpoints(Ums *ums) 652 { 653 Ep *ep; 654 Usbdev *ud; 655 ulong csp, sc; 656 int i, epin, epout; 657 658 epin = epout = -1; 659 ud = ums->dev->usb; 660 for(i = 0; i < nelem(ud->ep); i++){ 661 if((ep = ud->ep[i]) == nil) 662 continue; 663 csp = ep->iface->csp; 664 sc = Subclass(csp); 665 if(!(Class(csp) == Clstorage && (Proto(csp) == Protobulk))) 666 continue; 667 if(sc != Subatapi && sc != Sub8070 && sc != Subscsi) 668 fprint(2, "disk: subclass %#ulx not supported. trying anyway\n", sc); 669 if(ep->type == Ebulk){ 670 if(ep->dir == Eboth || ep->dir == Ein) 671 if(epin == -1) 672 epin = ep->id; 673 if(ep->dir == Eboth || ep->dir == Eout) 674 if(epout == -1) 675 epout = ep->id; 676 } 677 } 678 dprint(2, "disk: ep ids: in %d out %d\n", epin, epout); 679 if(epin == -1 || epout == -1) 680 return -1; 681 ums->epin = openep(ums->dev, epin); 682 if(ums->epin == nil){ 683 fprint(2, "disk: openep %d: %r\n", epin); 684 return -1; 685 } 686 if(epout == epin){ 687 incref(ums->epin); 688 ums->epout = ums->epin; 689 }else 690 ums->epout = openep(ums->dev, epout); 691 if(ums->epout == nil){ 692 fprint(2, "disk: openep %d: %r\n", epout); 693 closedev(ums->epin); 694 return -1; 695 } 696 if(ums->epin == ums->epout) 697 opendevdata(ums->epin, ORDWR); 698 else{ 699 opendevdata(ums->epin, OREAD); 700 opendevdata(ums->epout, OWRITE); 701 } 702 if(ums->epin->dfd < 0 || ums->epout->dfd < 0){ 703 fprint(2, "disk: open i/o ep data: %r\n"); 704 closedev(ums->epin); 705 closedev(ums->epout); 706 return -1; 707 } 708 dprint(2, "disk: ep in %s out %s\n", ums->epin->dir, ums->epout->dir); 709 710 devctl(ums->epin, "timeout 2000"); 711 devctl(ums->epout, "timeout 2000"); 712 713 if(usbdebug > 1 || diskdebug > 2){ 714 devctl(ums->epin, "debug 1"); 715 devctl(ums->epout, "debug 1"); 716 devctl(ums->dev, "debug 1"); 717 } 718 return 0; 719 } 720 721 static int 722 usage(void) 723 { 724 werrstr("usage: usb/disk [-d] [-N nb]"); 725 return -1; 726 } 727 728 static void 729 umsdevfree(void *a) 730 { 731 Ums *ums = a; 732 733 if(ums == nil) 734 return; 735 closedev(ums->epin); 736 closedev(ums->epout); 737 ums->epin = ums->epout = nil; 738 free(ums->lun); 739 free(ums); 740 } 741 742 static Usbfs diskfs = { 743 .walk = dwalk, 744 .open = dopen, 745 .read = dread, 746 .write = dwrite, 747 .stat = dstat, 748 }; 749 750 int 751 diskmain(Dev *dev, int argc, char **argv) 752 { 753 Ums *ums; 754 Umsc *lun; 755 int i, devid; 756 757 devid = dev->id; 758 ARGBEGIN{ 759 case 'd': 760 scsidebug(diskdebug); 761 diskdebug++; 762 break; 763 case 'N': 764 devid = atoi(EARGF(usage())); 765 break; 766 default: 767 return usage(); 768 }ARGEND 769 if(argc != 0) { 770 return usage(); 771 } 772 773 // notify(ding); 774 ums = dev->aux = emallocz(sizeof(Ums), 1); 775 ums->maxlun = -1; 776 ums->dev = dev; 777 dev->free = umsdevfree; 778 if(findendpoints(ums) < 0){ 779 werrstr("disk: endpoints not found"); 780 return -1; 781 } 782 783 /* 784 * SanDISK 512M gets residues wrong. 785 */ 786 if(dev->usb->vid == 0x0781 && dev->usb->did == 0x5150) 787 ums->wrongresidues = 1; 788 789 if(umsinit(ums) < 0){ 790 dprint(2, "disk: umsinit: %r\n"); 791 return -1; 792 } 793 794 for(i = 0; i <= ums->maxlun; i++){ 795 lun = &ums->lun[i]; 796 lun->fs = diskfs; 797 snprint(lun->fs.name, sizeof(lun->fs.name), "sdU%d.%d", devid, i); 798 lun->fs.dev = dev; 799 incref(dev); 800 lun->fs.aux = lun; 801 usbfsadd(&lun->fs); 802 } 803 return 0; 804 } 805