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