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