1 /* 2 * usb/disk - usb mass storage file server 3 */ 4 #include <u.h> 5 #include <libc.h> 6 #include <ctype.h> 7 #include <bio.h> 8 #include <fcall.h> 9 #include <thread.h> 10 #include <9p.h> 11 #include "scsireq.h" 12 #include "usb.h" 13 14 /* 15 * mass storage transport protocols and subclasses, 16 * from usb mass storage class specification overview rev 1.2 17 */ 18 enum { 19 Protocbi = 0, /* control/bulk/interrupt; mainly floppies */ 20 Protocb = 1, /* " with no interrupt; mainly floppies */ 21 Protobulk = 0x50, /* bulk only */ 22 23 Subrbc = 1, /* reduced blk cmds */ 24 Subatapi = 2, /* cd/dvd using sff-8020i or mmc-2 cmd blks */ 25 Subqic = 3, /* QIC-157 tapes */ 26 Subufi = 4, /* floppy */ 27 Sub8070 = 5, /* removable media, atapi-like */ 28 Subscsi = 6, /* scsi transparent cmd set */ 29 Subisd200 = 7, /* ISD200 ATA */ 30 Subdev = 0xff, /* use device's value */ 31 }; 32 33 enum { 34 GET_MAX_LUN_T = RD2H | Rclass | Rinterface, 35 GET_MAX_LUN = 0xFE, 36 UMS_RESET_T = RH2D | Rclass | Rinterface, 37 UMS_RESET = 0xFF, 38 39 MaxIOsize = 256*1024, /* max. I/O size */ 40 // Maxlun = 256, 41 Maxlun = 32, 42 }; 43 44 #define PATH(type, n) ((type) | (n)<<8) 45 #define TYPE(path) ((uchar)(path)) 46 #define NUM(path) ((uint)(path)>>8) 47 48 enum { 49 Qdir = 0, 50 Qctl, 51 Qn, 52 Qraw, 53 Qdata, 54 55 CMreset = 1, 56 57 Pcmd = 0, 58 Pdata, 59 Pstatus, 60 }; 61 62 static char *subclass[] = { 63 "?", 64 "rbc", 65 "atapi", 66 "qic tape", 67 "ufi floppy", 68 "8070 removable", 69 "scsi transparent", 70 "isd200 ata", 71 }; 72 73 typedef struct Dirtab Dirtab; 74 struct Dirtab { 75 char *name; 76 int mode; 77 }; 78 Dirtab dirtab[] = { 79 ".", DMDIR|0555, 80 "ctl", 0640, 81 nil, DMDIR|0750, 82 "raw", 0640, 83 "data", 0640, 84 }; 85 86 Cmdtab cmdtab[] = { 87 CMreset, "reset", 1, 88 }; 89 90 /* these are 600 bytes each; ScsiReq is not tiny */ 91 typedef struct Umsc Umsc; 92 struct Umsc { 93 ScsiReq; 94 ulong blocks; 95 vlong capacity; 96 uchar rawcmd[10]; 97 uchar phase; 98 char *inq; 99 }; 100 101 typedef struct Ums Ums; 102 struct Ums { 103 Umsc *lun; 104 uchar maxlun; 105 int fd2; 106 int fd; 107 int setupfd; 108 int ctlfd; 109 uchar epin; 110 uchar epout; 111 char dev[64]; 112 }; 113 114 int exabyte, force6bytecmds; 115 long starttime; 116 long maxiosize = MaxIOsize; 117 118 volatile int timedout; 119 120 char *owner; 121 122 static Ums ums; 123 static int freakout; /* flag: if true, drive freaks out if reset */ 124 125 extern int debug; 126 127 static void umsreset(Ums *umsc, int doinit); 128 129 /* 130 * USB transparent SCSI devices 131 */ 132 typedef struct Cbw Cbw; /* command block wrapper */ 133 struct Cbw { 134 char signature[4]; /* "USBC" */ 135 long tag; 136 long datalen; 137 uchar flags; 138 uchar lun; 139 uchar len; 140 char command[16]; 141 }; 142 143 typedef struct Csw Csw; /* command status wrapper */ 144 struct Csw { 145 char signature[4]; /* "USBS" */ 146 long tag; 147 long dataresidue; 148 uchar status; 149 }; 150 151 enum { 152 CbwLen = 31, 153 CbwDataIn = 0x80, 154 CbwDataOut = 0x00, 155 CswLen = 13, 156 CswOk = 0, 157 CswFailed = 1, 158 CswPhaseErr = 2, 159 }; 160 161 void 162 statuscmd(int fd, int type, int req, int value, int index, char *data, 163 int count) 164 { 165 char *wp; 166 167 wp = emalloc9p(count + 8); 168 wp[0] = type; 169 wp[1] = req; 170 PUT2(wp + 2, value); 171 PUT2(wp + 4, index); 172 PUT2(wp + 6, count); 173 if(data != nil) 174 memmove(wp + 8, data, count); 175 if(write(fd, wp, count + 8) != count + 8) 176 sysfatal("statuscmd: %r"); 177 } 178 179 void 180 statusread(int fd, char *buf, int count) 181 { 182 if(read(fd, buf, count) < 0) 183 sysfatal("statusread: %r"); 184 } 185 186 void 187 getmaxlun(Ums *ums) 188 { 189 uchar max; 190 191 statuscmd(ums->setupfd, GET_MAX_LUN_T, GET_MAX_LUN, 0, 0, nil, 0); 192 statusread(ums->setupfd, (char *)&max, 1); 193 fprint(2, "%s: maxlun %d\n", argv0, max); // DEBUG 194 ums->lun = mallocz((max + 1) * sizeof *ums->lun, 1); 195 assert(ums->lun); 196 ums->maxlun = max; 197 } 198 199 int 200 umsinit(Ums *ums, int epin, int epout) 201 { 202 uchar data[8], i; 203 char fin[128]; 204 Umsc *lun; 205 206 if(ums->ctlfd == -1) { 207 snprint(fin, sizeof fin, "%s/ctl", ums->dev); 208 if((ums->ctlfd = open(fin, OWRITE)) == -1) 209 return -1; 210 if(epin == epout) { 211 if(fprint(ums->ctlfd, "ep %d bulk rw 64 16", epin) < 0) 212 return -1; 213 } else { 214 if(fprint(ums->ctlfd, "ep %d bulk r 64 16", epin) < 0 || 215 fprint(ums->ctlfd, "ep %d bulk w 64 16", epout) < 0) 216 return -1; 217 } 218 snprint(fin, sizeof fin, "%s/ep%ddata", ums->dev, epin); 219 if((ums->fd = open(fin, OREAD)) == -1) 220 return -1; 221 snprint(fin, sizeof fin, "%s/ep%ddata", ums->dev, epout); 222 if((ums->fd2 = open(fin, OWRITE)) == -1) 223 return -1; 224 snprint(fin, sizeof fin, "%s/setup", ums->dev); 225 if ((ums->setupfd = open(fin, ORDWR)) == -1) 226 return -1; 227 } 228 229 ums->epin = epin; 230 ums->epout = epout; 231 umsreset(ums, 0); 232 getmaxlun(ums); 233 for(i = 0; i <= ums->maxlun; i++) { 234 lun = &ums->lun[i]; 235 lun->lun = i; 236 lun->umsc = lun; /* pointer to self */ 237 lun->flags = Fopen | Fusb | Frw10; 238 if(SRinquiry(lun) == -1) 239 return -1; 240 lun->inq = smprint("%.48s", (char *)lun->inquiry+8); 241 SRstart(lun, 1); 242 if (SRrcapacity(lun, data) == -1 && 243 SRrcapacity(lun, data) == -1) { 244 lun->blocks = 0; 245 lun->capacity = 0; 246 lun->lbsize = 0; 247 } else { 248 lun->lbsize = data[4]<<24|data[5]<<16|data[6]<<8|data[7]; 249 lun->blocks = data[0]<<24|data[1]<<16|data[2]<<8|data[3]; 250 lun->blocks++; /* SRcapacity returns LBA of last block */ 251 lun->capacity = (vlong)lun->blocks * lun->lbsize; 252 } 253 } 254 return 0; 255 } 256 257 static void 258 unstall(Ums *ums, int ep) 259 { 260 if(fprint(ums->ctlfd, "unstall %d", ep & 0xF) < 0) 261 fprint(2, "ctl write failed\n"); 262 if(fprint(ums->ctlfd, "data %d 0", ep & 0xF) < 0) 263 fprint(2, "ctl write failed\n"); 264 265 statuscmd(ums->setupfd, RH2D | Rstandard | Rendpt, CLEAR_FEATURE, 0, 266 0<<8 | ep, nil, 0); 267 } 268 269 static void 270 umsreset(Ums *umsc, int doinit) 271 { 272 if (!freakout) 273 statuscmd(umsc->setupfd, UMS_RESET_T, UMS_RESET, 0, 0, nil, 0); 274 275 unstall(umsc, umsc->epin|0x80); 276 unstall(umsc, umsc->epout); 277 if(doinit && umsinit(&ums, umsc->epin, umsc->epout) < 0) 278 sysfatal("device error"); 279 } 280 281 long 282 umsrequest(Umsc *umsc, ScsiPtr *cmd, ScsiPtr *data, int *status) 283 { 284 Cbw cbw; 285 Csw csw; 286 int n; 287 static int seq = 0; 288 289 memcpy(cbw.signature, "USBC", 4); 290 cbw.tag = ++seq; 291 cbw.datalen = data->count; 292 cbw.flags = data->write? CbwDataOut: CbwDataIn; 293 cbw.lun = umsc->lun; 294 cbw.len = cmd->count; 295 memcpy(cbw.command, cmd->p, cmd->count); 296 memset(cbw.command + cmd->count, 0, sizeof(cbw.command) - cmd->count); 297 298 if(debug) { 299 fprint(2, "cmd:"); 300 for (n = 0; n < cbw.len; n++) 301 fprint(2, " %2.2x", cbw.command[n]&0xFF); 302 fprint(2, " datalen: %ld\n", cbw.datalen); 303 } 304 if(write(ums.fd2, &cbw, CbwLen) != CbwLen){ 305 fprint(2, "usbscsi: write cmd: %r\n"); 306 goto reset; 307 } 308 if(data->count != 0) { 309 if(data->write) 310 n = write(ums.fd2, data->p, data->count); 311 else 312 n = read(ums.fd, data->p, data->count); 313 if(n == -1){ 314 if(debug) 315 fprint(2, "usbscsi: data %sput: %r\n", 316 data->write? "out": "in"); 317 if(data->write) 318 unstall(&ums, ums.epout); 319 else 320 unstall(&ums, ums.epin | 0x80); 321 } 322 } 323 n = read(ums.fd, &csw, CswLen); 324 if(n == -1){ 325 unstall(&ums, ums.epin | 0x80); 326 n = read(ums.fd, &csw, CswLen); 327 } 328 if(n != CswLen || strncmp(csw.signature, "USBS", 4) != 0){ 329 fprint(2, "usbscsi: read status: %r\n"); 330 goto reset; 331 } 332 if(csw.tag != cbw.tag) { 333 fprint(2, "usbscsi: status tag mismatch\n"); 334 goto reset; 335 } 336 if(csw.status >= CswPhaseErr){ 337 fprint(2, "usbscsi: phase error\n"); 338 goto reset; 339 } 340 if(debug) { 341 fprint(2, "status: %2.2ux residue: %ld\n", 342 csw.status, csw.dataresidue); 343 if(cbw.command[0] == ScmdRsense) { 344 fprint(2, "sense data:"); 345 for (n = 0; n < data->count - csw.dataresidue; n++) 346 fprint(2, " %2.2x", data->p[n]); 347 fprint(2, "\n"); 348 } 349 } 350 351 if(csw.status == CswOk) 352 *status = STok; 353 else 354 *status = STcheck; 355 return data->count - csw.dataresidue; 356 357 reset: 358 umsreset(&ums, 0); 359 *status = STharderr; 360 return -1; 361 } 362 363 int 364 findendpoints(Device *d, int *epin, int *epout) 365 { 366 Endpt *ep; 367 ulong csp; 368 int i, addr, nendpt; 369 370 *epin = *epout = -1; 371 nendpt = 0; 372 if(d->nconf < 1) 373 return -1; 374 for(i=0; i<d->nconf; i++) { 375 if (d->config[i] == nil) 376 d->config[i] = mallocz(sizeof(*d->config[i]),1); 377 loadconfig(d, i); 378 } 379 for(i = 0; i < Nendpt; i++){ 380 if((ep = d->ep[i]) == nil) 381 continue; 382 nendpt++; 383 csp = ep->csp; 384 if(!(Class(csp) == CL_STORAGE && (Proto(csp) == 0x50))) 385 continue; 386 if(ep->type == Ebulk) { 387 addr = ep->addr; 388 if (debug) 389 print("findendpoints: bulk; ep->addr %ux\n", 390 ep->addr); 391 if (ep->dir == Eboth || addr&0x80) 392 if(*epin == -1) 393 *epin = addr&0xF; 394 if (ep->dir == Eboth || !(addr&0x80)) 395 if(*epout == -1) 396 *epout = addr&0xF; 397 } 398 } 399 if(nendpt == 0) { 400 if(*epin == -1) 401 *epin = *epout; 402 if(*epout == -1) 403 *epout = *epin; 404 } 405 if (*epin == -1 || *epout == -1) 406 return -1; 407 return 0; 408 } 409 410 int 411 timeoutok(void) 412 { 413 if (freakout) 414 return 1; /* OK; keep trying */ 415 else if (1) { /* TODO: set */ 416 fprint(2, 417 "%s: no response from device. unplug and replug it and try again with -f\n", 418 argv0); 419 420 return 0; /* die */ 421 } 422 return 1; /* keep trying */ 423 } 424 425 int 426 notifyf(void *, char *s) 427 { 428 if(strcmp(s, "alarm") != 0) 429 return 0; /* die */ 430 if (!timeoutok()) { 431 fprint(2, "%s: timed out\n", argv0); 432 return 0; /* die */ 433 } 434 alarm(120*1000); 435 fprint(2, "%s: resetting alarm\n", argv0); 436 timedout = 1; 437 return 1; /* keep going */ 438 } 439 440 int 441 devokay(int ctlrno, int id) 442 { 443 int epin = -1, epout = -1; 444 long time; 445 Device *d; 446 static int beenhere; 447 448 if (!beenhere) { 449 atnotify(notifyf, 1); 450 beenhere = 1; 451 } 452 time = alarm(15*1000); 453 d = opendev(ctlrno, id); 454 if (describedevice(d) < 0) { 455 perror(""); 456 closedev(d); 457 alarm(time); 458 return 0; 459 } 460 if (findendpoints(d, &epin, &epout) < 0) { 461 fprint(2, "%s: bad usb configuration for ctlr %d id %d\n", 462 argv0, ctlrno, id); 463 closedev(d); 464 alarm(time); 465 return 0; 466 } 467 closedev(d); 468 469 snprint(ums.dev, sizeof ums.dev, "/dev/usb%d/%d", ctlrno, id); 470 if (umsinit(&ums, epin, epout) < 0) { 471 alarm(time); 472 fprint(2, "%s: initialisation: %r\n", argv0); 473 return 0; 474 } 475 alarm(time); 476 return 1; 477 } 478 479 static char * 480 subclname(int subcl) 481 { 482 if ((unsigned)subcl < nelem(subclass)) 483 return subclass[subcl]; 484 return "**GOK**"; /* traditional */ 485 } 486 487 static int 488 scanstatus(int ctlrno, int id) 489 { 490 int winner; 491 ulong csp; 492 char *p, *hex; 493 char buf[64]; 494 Biobuf *f; 495 496 /* read port status file */ 497 sprint(buf, "/dev/usb%d/%d/status", ctlrno, id); 498 f = Bopen(buf, OREAD); 499 if (f == nil) 500 sysfatal("can't open %s: %r", buf); 501 if (debug) 502 fprint(2, "\n%s: reading %s\n", argv0, buf); 503 winner = 0; 504 while (!winner && (p = Brdline(f, '\n')) != nil) { 505 p[Blinelen(f)-1] = '\0'; 506 if (debug && *p == 'E') /* Enabled? */ 507 fprint(2, "%s: %s\n", argv0, p); 508 for (hex = p; *hex != '\0' && *hex != '0'; hex++) 509 continue; 510 csp = atol(hex); 511 512 if (Class(csp) == CL_STORAGE && Proto(csp) == Protobulk) { 513 if (0) 514 fprint(2, 515 "%s: /dev/usb%d/%d: bulk storage of subclass %s\n", 516 argv0, ctlrno, id, 517 subclname(Subclass(csp))); 518 switch (Subclass(csp)) { 519 case Subatapi: 520 case Sub8070: 521 case Subscsi: 522 winner++; 523 break; 524 } 525 } 526 } 527 Bterm(f); 528 return winner; 529 } 530 531 static int 532 findums(int *ctlrp, int *idp) 533 { 534 int ctlrno, id, winner, devfd, ctlrfd, nctlr, nport; 535 char buf[64]; 536 Dir *ctlrs, *cdp, *ports, *pdp; 537 538 *ctlrp = *idp = -1; 539 winner = 0; 540 541 /* walk controllers */ 542 devfd = open("/dev", OREAD); 543 if (devfd < 0) 544 sysfatal("can't open /dev: %r"); 545 nctlr = dirreadall(devfd, &ctlrs); 546 if (nctlr < 0) 547 sysfatal("can't read /dev: %r"); 548 for (cdp = ctlrs; nctlr-- > 0 && !winner; cdp++) { 549 if (strncmp(cdp->name, "usb", 3) != 0) 550 continue; 551 ctlrno = atoi(cdp->name + 3); 552 553 /* walk ports within a controller */ 554 snprint(buf, sizeof buf, "/dev/%s", cdp->name); 555 ctlrfd = open(buf, OREAD); 556 if (ctlrfd < 0) 557 sysfatal("can't open %s: %r", buf); 558 nport = dirreadall(ctlrfd, &ports); 559 if (nport < 0) 560 sysfatal("can't read %s: %r", buf); 561 for (pdp = ports; nport-- > 0 && !winner; pdp++) { 562 if (!isdigit(*pdp->name)) 563 continue; 564 id = atoi(pdp->name); 565 566 /* read port status file */ 567 winner = scanstatus(ctlrno, id); 568 if (winner) 569 if (devokay(ctlrno, id)) { 570 *ctlrp = ctlrno; 571 *idp = id; 572 } else 573 winner = 0; 574 } 575 free(ports); 576 close(ctlrfd); 577 } 578 free(ctlrs); 579 close(devfd); 580 if (!winner) 581 return -1; 582 else 583 return 0; 584 } 585 586 void 587 rattach(Req *r) 588 { 589 r->ofcall.qid.path = PATH(Qdir, 0); 590 r->ofcall.qid.type = dirtab[Qdir].mode >> 24; 591 r->fid->qid = r->ofcall.qid; 592 respond(r, nil); 593 } 594 595 char* 596 rwalk1(Fid *fid, char *name, Qid *qid) 597 { 598 int i, n; 599 char buf[32]; 600 ulong path; 601 602 path = fid->qid.path; 603 if(!(fid->qid.type & QTDIR)) 604 return "walk in non-directory"; 605 606 if(strcmp(name, "..") == 0) 607 switch(TYPE(path)) { 608 case Qn: 609 qid->path = PATH(Qn, NUM(path)); 610 qid->type = dirtab[Qn].mode >> 24; 611 return nil; 612 case Qdir: 613 return nil; 614 default: 615 return "bug in rwalk1"; 616 } 617 618 for(i = TYPE(path)+1; i < nelem(dirtab); i++) { 619 if(i==Qn){ 620 n = atoi(name); 621 snprint(buf, sizeof buf, "%d", n); 622 if(n <= ums.maxlun && strcmp(buf, name) == 0){ 623 qid->path = PATH(i, n); 624 qid->type = dirtab[i].mode>>24; 625 return nil; 626 } 627 break; 628 } 629 if(strcmp(name, dirtab[i].name) == 0) { 630 qid->path = PATH(i, NUM(path)); 631 qid->type = dirtab[i].mode >> 24; 632 return nil; 633 } 634 if(dirtab[i].mode & DMDIR) 635 break; 636 } 637 return "directory entry not found"; 638 } 639 640 void 641 dostat(int path, Dir *d) 642 { 643 Dirtab *t; 644 645 memset(d, 0, sizeof(*d)); 646 d->uid = estrdup9p(owner); 647 d->gid = estrdup9p(owner); 648 d->qid.path = path; 649 d->atime = d->mtime = starttime; 650 t = &dirtab[TYPE(path)]; 651 if(t->name) 652 d->name = estrdup9p(t->name); 653 else { 654 d->name = smprint("%ud", NUM(path)); 655 if(d->name == nil) 656 sysfatal("out of memory"); 657 } 658 if(TYPE(path) == Qdata) 659 d->length = ums.lun[NUM(path)].capacity; 660 d->qid.type = t->mode >> 24; 661 d->mode = t->mode; 662 } 663 664 static int 665 dirgen(int i, Dir *d, void*) 666 { 667 i += Qdir + 1; 668 if(i <= Qn) { 669 dostat(i, d); 670 return 0; 671 } 672 i -= Qn; 673 if(i <= ums.maxlun) { 674 dostat(PATH(Qn, i), d); 675 return 0; 676 } 677 return -1; 678 } 679 680 static int 681 lungen(int i, Dir *d, void *aux) 682 { 683 int *c; 684 685 c = aux; 686 i += Qn + 1; 687 if(i <= Qdata){ 688 dostat(PATH(i, NUM(*c)), d); 689 return 0; 690 } 691 return -1; 692 } 693 694 void 695 rstat(Req *r) 696 { 697 dostat((long)r->fid->qid.path, &r->d); 698 respond(r, nil); 699 } 700 701 void 702 ropen(Req *r) 703 { 704 ulong path; 705 706 path = r->fid->qid.path; 707 switch(TYPE(path)) { 708 case Qraw: 709 ums.lun[NUM(path)].phase = Pcmd; 710 break; 711 } 712 respond(r, nil); 713 } 714 715 void 716 rread(Req *r) 717 { 718 int bno, nb, len, offset, n; 719 ulong path; 720 uchar i; 721 char buf[8192], *p; 722 Umsc *lun; 723 724 path = r->fid->qid.path; 725 switch(TYPE(path)) { 726 case Qdir: 727 dirread9p(r, dirgen, 0); 728 break; 729 case Qn: 730 dirread9p(r, lungen, &path); 731 break; 732 case Qctl: 733 n = 0; 734 for(i = 0; i <= ums.maxlun; i++) { 735 lun = &ums.lun[i]; 736 n += snprint(buf + n, sizeof buf - n, "%d: ", i); 737 if(lun->flags & Finqok) 738 n += snprint(buf + n, sizeof buf - n, 739 "inquiry %s ", lun->inq); 740 if(lun->blocks > 0) 741 n += snprint(buf + n, sizeof buf - n, 742 "geometry %ld %ld", lun->blocks, 743 lun->lbsize); 744 n += snprint(buf + n, sizeof buf - n, "\n"); 745 } 746 readbuf(r, buf, n); 747 break; 748 case Qraw: 749 lun = &ums.lun[NUM(path)]; 750 if(lun->lbsize <= 0) { 751 respond(r, "no media on this lun"); 752 return; 753 } 754 switch(lun->phase) { 755 case Pcmd: 756 respond(r, "phase error"); 757 return; 758 case Pdata: 759 lun->data.p = (uchar*)r->ofcall.data; 760 lun->data.count = r->ifcall.count; 761 lun->data.write = 0; 762 n = umsrequest(lun, &lun->cmd, &lun->data, &lun->status); 763 lun->phase = Pstatus; 764 if (n == -1) { 765 respond(r, "IO error"); 766 return; 767 } 768 r->ofcall.count = n; 769 break; 770 case Pstatus: 771 n = snprint(buf, sizeof buf, "%11.0ud ", lun->status); 772 if (r->ifcall.count < n) 773 n = r->ifcall.count; 774 memmove(r->ofcall.data, buf, n); 775 r->ofcall.count = n; 776 lun->phase = Pcmd; 777 break; 778 } 779 break; 780 case Qdata: 781 lun = &ums.lun[NUM(path)]; 782 if(lun->lbsize <= 0) { 783 respond(r, "no media on this lun"); 784 return; 785 } 786 bno = r->ifcall.offset / lun->lbsize; 787 nb = (r->ifcall.offset + r->ifcall.count + lun->lbsize - 1) 788 / lun->lbsize - bno; 789 if(bno + nb > lun->blocks) 790 nb = lun->blocks - bno; 791 if(bno >= lun->blocks || nb == 0) { 792 r->ofcall.count = 0; 793 break; 794 } 795 if(nb * lun->lbsize > maxiosize) 796 nb = maxiosize / lun->lbsize; 797 p = malloc(nb * lun->lbsize); 798 if (p == 0) { 799 respond(r, "no mem"); 800 return; 801 } 802 lun->offset = r->ifcall.offset / lun->lbsize; 803 n = SRread(lun, p, nb * lun->lbsize); 804 if(n == -1) { 805 free(p); 806 respond(r, "IO error"); 807 return; 808 } 809 len = r->ifcall.count; 810 offset = r->ifcall.offset % lun->lbsize; 811 if(offset + len > n) 812 len = n - offset; 813 r->ofcall.count = len; 814 memmove(r->ofcall.data, p + offset, len); 815 free(p); 816 break; 817 } 818 respond(r, nil); 819 } 820 821 void 822 rwrite(Req *r) 823 { 824 int n, bno, nb, len, offset; 825 ulong path; 826 char *p; 827 Cmdbuf *cb; 828 Cmdtab *ct; 829 Umsc *lun; 830 831 n = r->ifcall.count; 832 r->ofcall.count = 0; 833 path = r->fid->qid.path; 834 switch(TYPE(path)) { 835 case Qctl: 836 cb = parsecmd(r->ifcall.data, n); 837 ct = lookupcmd(cb, cmdtab, nelem(cmdtab)); 838 if(ct == 0) { 839 respondcmderror(r, cb, "%r"); 840 return; 841 } 842 switch(ct->index) { 843 case CMreset: 844 umsreset(&ums, 1); 845 } 846 break; 847 case Qraw: 848 lun = &ums.lun[NUM(path)]; 849 if(lun->lbsize <= 0) { 850 respond(r, "no media on this lun"); 851 return; 852 } 853 n = r->ifcall.count; 854 switch(lun->phase) { 855 case Pcmd: 856 if(n != 6 && n != 10) { 857 respond(r, "bad command length"); 858 return; 859 } 860 memmove(lun->rawcmd, r->ifcall.data, n); 861 lun->cmd.p = lun->rawcmd; 862 lun->cmd.count = n; 863 lun->cmd.write = 1; 864 lun->phase = Pdata; 865 break; 866 case Pdata: 867 lun->data.p = (uchar*)r->ifcall.data; 868 lun->data.count = n; 869 lun->data.write = 1; 870 n = umsrequest(lun, &lun->cmd, &lun->data, &lun->status); 871 lun->phase = Pstatus; 872 if(n == -1) { 873 respond(r, "IO error"); 874 return; 875 } 876 break; 877 case Pstatus: 878 lun->phase = Pcmd; 879 respond(r, "phase error"); 880 return; 881 } 882 break; 883 case Qdata: 884 lun = &ums.lun[NUM(path)]; 885 if(lun->lbsize <= 0) { 886 respond(r, "no media on this lun"); 887 return; 888 } 889 bno = r->ifcall.offset / lun->lbsize; 890 nb = (r->ifcall.offset + r->ifcall.count + lun->lbsize-1) 891 / lun->lbsize - bno; 892 if(bno + nb > lun->blocks) 893 nb = lun->blocks - bno; 894 if(bno >= lun->blocks || nb == 0) { 895 r->ofcall.count = 0; 896 break; 897 } 898 if(nb * lun->lbsize > maxiosize) 899 nb = maxiosize / lun->lbsize; 900 p = malloc(nb * lun->lbsize); 901 if(p == 0) { 902 respond(r, "no mem"); 903 return; 904 } 905 offset = r->ifcall.offset % lun->lbsize; 906 len = r->ifcall.count; 907 if(offset || (len % lun->lbsize) != 0) { 908 lun->offset = r->ifcall.offset / lun->lbsize; 909 n = SRread(lun, p, nb * lun->lbsize); 910 if(n == -1) { 911 free(p); 912 respond(r, "IO error"); 913 return; 914 } 915 if(offset + len > n) 916 len = n - offset; 917 } 918 memmove(p+offset, r->ifcall.data, len); 919 lun->offset = r->ifcall.offset / lun->lbsize; 920 n = SRwrite(lun, p, nb * lun->lbsize); 921 if(n == -1) { 922 free(p); 923 respond(r, "IO error"); 924 return; 925 } 926 if(offset+len > n) 927 len = n - offset; 928 r->ofcall.count = len; 929 free(p); 930 break; 931 } 932 r->ofcall.count = n; 933 respond(r, nil); 934 } 935 936 Srv usbssrv = { 937 .attach = rattach, 938 .walk1 = rwalk1, 939 .open = ropen, 940 .read = rread, 941 .write = rwrite, 942 .stat = rstat, 943 }; 944 945 void (*dprinter[])(Device *, int, ulong, void *b, int n) = { 946 [STRING] pstring, 947 [DEVICE] pdevice, 948 }; 949 950 void 951 usage(void) 952 { 953 fprint(2, "usage: %s [-Ddf] [-m mountpoint] [-s srvname] [ctrno id]\n", 954 argv0); 955 exits("usage"); 956 } 957 958 void 959 main(int argc, char **argv) 960 { 961 int ctlrno, id; 962 char *srvname, *mntname; 963 964 mntname = "/n/disk"; 965 srvname = nil; 966 ctlrno = 0; 967 id = 1; 968 969 ARGBEGIN{ 970 case 'd': 971 debug = Dbginfo; 972 break; 973 case 'f': 974 freakout++; 975 break; 976 case 'm': 977 mntname = EARGF(usage()); 978 break; 979 case 's': 980 srvname = EARGF(usage()); 981 break; 982 case 'D': 983 ++chatty9p; 984 break; 985 default: 986 usage(); 987 }ARGEND 988 989 ums.ctlfd = ums.setupfd = ums.fd = ums.fd2 = -1; 990 ums.maxlun = -1; 991 if (argc == 0) { 992 if (findums(&ctlrno, &id) < 0) { 993 sleep(5*1000); 994 if (findums(&ctlrno, &id) < 0) 995 sysfatal("no usb mass storage device found"); 996 } 997 } else if (argc == 2 && isdigit(argv[0][0]) && isdigit(argv[1][0])) { 998 ctlrno = atoi(argv[0]); 999 id = atoi(argv[1]); 1000 if (!devokay(ctlrno, id)) 1001 sysfatal("no usable usb mass storage device at %d/%d", 1002 ctlrno, id); 1003 } else 1004 usage(); 1005 1006 starttime = time(0); 1007 owner = getuser(); 1008 1009 postmountsrv(&usbssrv, srvname, mntname, 0); 1010 exits(0); 1011 } 1012