2 * usb/disk - usb mass storage file server
4 * supports only the scsi command interface, not ata.
30 typedef struct Dirtab Dirtab;
40 * Partition management (adapted from disk/partfs)
44 lookpart(Umsc *lun, char *name)
49 for(p=part; p < &part[Qmax]; p++){
50 if(p->inuse && strcmp(p->name, name) == 0)
62 for(p=part; p < &part[Qmax]; p++){
70 addpart(Umsc *lun, char *name, vlong start, vlong end, ulong mode)
74 if(start < 0 || start > end || end > lun->blocks){
75 werrstr("bad partition boundaries");
78 p = lookpart(lun, name);
80 /* adding identical partition is no-op */
81 if(p->offset == start && p->length == end - start && p->mode == mode)
83 werrstr("partition name already in use");
88 werrstr("no free partition slots");
93 p->id = p - lun->part;
94 p->name = estrdup(name);
96 p->length = end - start;
102 delpart(Umsc *lun, char *s)
106 p = lookpart(lun, s);
107 if(p == nil || p->id <= Qdata){
108 werrstr("partition not found");
119 fixlength(Umsc *lun, vlong blocks)
124 part[Qdata].length = blocks;
125 for(p=&part[Qdata+1]; p < &part[Qmax]; p++){
126 if(p->inuse && p->offset + p->length > blocks){
127 if(p->offset > blocks){
131 p->length = blocks - p->offset;
139 addpart(lun, "/", 0, 0, DMDIR | 0555);
140 addpart(lun, "ctl", 0, 0, 0664);
141 addpart(lun, "raw", 0, 0, 0640);
142 addpart(lun, "data", 0, lun->blocks, 0640);
146 * ctl parsing & formatting (adapted from partfs)
155 part = &lun->part[0];
158 fmtprint(&fmt, "dev %s\n", dev->dir);
159 fmtprint(&fmt, "lun %ld\n", lun - &ums->lun[0]);
160 if(lun->flags & Finqok)
161 fmtprint(&fmt, "inquiry %s\n", lun->inq);
163 fmtprint(&fmt, "geometry %llud %ld\n", lun->blocks, lun->lbsize);
164 for (p = &part[Qdata+1]; p < &part[Qmax]; p++)
166 fmtprint(&fmt, "part %s %lld %lld\n",
167 p->name, p->offset, p->offset + p->length);
168 return fmtstrflush(&fmt);
172 ctlparse(Umsc *lun, char *msg)
178 argc = tokenize(msg, argv, nelem(argv));
181 werrstr("empty control message");
185 if(strcmp(argv[0], "part") == 0){
187 werrstr("part takes 3 args");
190 start = strtoll(argv[2], 0, 0);
191 end = strtoll(argv[3], 0, 0);
192 return addpart(lun, argv[1], start, end, 0640);
193 }else if(strcmp(argv[0], "delpart") == 0){
195 werrstr("delpart takes 1 arg");
198 return delpart(lun, argv[1]);
200 werrstr("unknown ctl");
205 * These are used by scuzz scsireq
207 int exabyte, force6bytecmds;
212 ding(void *, char *msg)
214 if(strstr(msg, "alarm") != nil)
226 r = Rd2h|Rclass|Riface;
227 if(usbcmd(dev, r, Getmaxlun, 0, 0, &max, 1) < 0){
228 dprint(2, "disk: %s: getmaxlun failed: %r\n", dev->dir);
230 max &= 017; /* 15 is the max. allowed */
231 dprint(2, "disk: %s: maxlun %d\n", dev->dir, max);
241 r = Rh2d|Rclass|Riface;
242 if(usbcmd(dev, r, Umsreset, 0, 0, nil, 0) < 0){
243 fprint(2, "disk: reset: %r\n");
254 if(unstall(dev, ums->epin, Ein) < 0)
255 dprint(2, "disk: unstall epin: %r\n");
257 /* do we need this when epin == epout? */
258 if(unstall(dev, ums->epout, Eout) < 0)
259 dprint(2, "disk: unstall epout: %r\n");
267 return (ul & (ul - 1)) == 0;
271 * return smallest power of 2 >= n
278 for(i = 0; (1 << i) < n; i++)
284 umscapacity(Umsc *lun)
291 memset(data, 0, sizeof data);
292 if(SRrcapacity(lun, data) < 0 && SRrcapacity(lun, data) < 0)
294 lun->blocks = GETBELONG(data);
295 lun->lbsize = GETBELONG(data+4);
296 if(lun->blocks == 0xFFFFFFFF){
297 if(SRrcapacity16(lun, data) < 0){
302 lun->lbsize = GETBELONG(data + 8);
303 lun->blocks = (uvlong)GETBELONG(data)<<32 |
307 lun->blocks++; /* SRcapacity returns LBA of last block */
308 lun->capacity = (vlong)lun->blocks * lun->lbsize;
309 fixlength(lun, lun->blocks);
311 fprint(2, "disk: logical block size %lud, # blocks %llud\n",
312 lun->lbsize, lun->blocks);
324 ums->maxlun = getmaxlun();
325 ums->lun = mallocz((ums->maxlun+1) * sizeof(*ums->lun), 1);
327 for(i = 0; i <= ums->maxlun; i++){
332 lun->flags = Fopen | Fusb | Frw10;
333 if(SRinquiry(lun) < 0 && SRinquiry(lun) < 0){
334 dprint(2, "disk: lun %d inquiry failed\n", i);
337 switch(lun->inquiry[0]){
339 case Devworm: /* a little different than the others */
344 fprint(2, "disk: lun %d is not a disk (type %#02x)\n",
349 if(SRready(lun) < 0 && SRready(lun) < 0 && SRready(lun) < 0)
350 dprint(2, "disk: lun %d not ready\n", i);
352 if((lun->inquiry[0] & 0x1F) == 0){
358 * we ignore the device type reported by inquiry.
359 * Some devices return a wrong value but would still work.
362 lun->inq = smprint("%.48s", (char *)lun->inquiry+8);
366 dprint(2, "disk: all luns failed\n");
367 devctl(dev, "detach");
375 * called by SR*() commands provided by scuzz's scsireq
378 umsrequest(Umsc *umsc, ScsiPtr *cmd, ScsiPtr *data, int *status)
387 memcpy(cbw.signature, "USBC", 4);
388 cbw.tag = ++ums->seq;
389 cbw.datalen = data->count;
390 cbw.flags = data->write? CbwDataOut: CbwDataIn;
392 if(cmd->count < 1 || cmd->count > 16)
393 print("disk: umsrequest: bad cmd count: %ld\n", cmd->count);
395 cbw.len = cmd->count;
396 assert(cmd->count <= sizeof(cbw.command));
397 memcpy(cbw.command, cmd->p, cmd->count);
398 memset(cbw.command + cmd->count, 0, sizeof(cbw.command) - cmd->count);
400 werrstr(""); /* we use %r later even for n == 0 */
402 fprint(2, "disk: cmd: tag %#lx: ", cbw.tag);
403 for(n = 0; n < cbw.len; n++)
404 fprint(2, " %2.2x", cbw.command[n]&0xFF);
405 fprint(2, " datalen: %ld\n", cbw.datalen);
408 /* issue tunnelled scsi command */
409 if(write(ums->epout->dfd, &cbw, CbwLen) != CbwLen){
410 fprint(2, "disk: cmd: %r\n");
414 /* transfer the data */
418 n = write(ums->epout->dfd, data->p, nio);
420 n = read(ums->epin->dfd, data->p, nio);
422 if (n >= 0 && left > 0) /* didn't fill data->p? */
423 memset(data->p + n, 0, left);
428 fprint(2, "disk: data: %r\n");
430 fprint(2, "disk: data: %d bytes\n", n);
433 unstall(dev, ums->epin, Ein);
436 /* read the transfer's status */
437 n = read(ums->epin->dfd, &csw, CswLen);
439 /* n == 0 means "stalled" */
440 unstall(dev, ums->epin, Ein);
441 n = read(ums->epin->dfd, &csw, CswLen);
444 if(n != CswLen || strncmp(csw.signature, "USBS", 4) != 0){
445 dprint(2, "disk: read n=%d: status: %r\n", n);
448 if(csw.tag != cbw.tag){
449 dprint(2, "disk: status tag mismatch\n");
452 if(csw.status >= CswPhaseErr){
453 dprint(2, "disk: phase error\n");
456 if(csw.dataresidue == 0 || ums->wrongresidues)
457 csw.dataresidue = data->count - nio;
459 fprint(2, "disk: status: %2.2ux residue: %ld\n",
460 csw.status, csw.dataresidue);
461 if(cbw.command[0] == ScmdRsense){
462 fprint(2, "sense data:");
463 for(n = 0; n < data->count - csw.dataresidue; n++)
464 fprint(2, " %2.2x", data->p[n]);
476 dprint(2, "disk: phase error\n");
480 return data->count - csw.dataresidue;
484 if(ums->nerrs++ > 15)
485 sysfatal("%s: too many errors", dev->dir);
493 req->fid->qid = (Qid) {0, 0, QTDIR};
494 req->ofcall.qid = req->fid->qid;
499 dwalk(Fid *fid, char *name, Qid *qid)
504 if((fid->qid.type & QTDIR) == 0)
505 return "walk in non-directory";
506 if(strcmp(name, "..") == 0){
507 fid->qid = (Qid){0, 0, QTDIR};
511 if(fid->qid.path == 0){
512 for(lun = ums->lun; lun <= ums->lun + ums->maxlun; lun++)
513 if(strcmp(lun->name, name) == 0){
514 fid->qid.path = (lun - ums->lun + 1) << 16;
516 fid->qid.type = QTDIR;
520 return "does not exist";
522 lun = ums->lun + (fid->qid.path >> 16) - 1;
523 p = lookpart(lun, name);
525 return "does not exist";
526 fid->qid.path |= p->id;
527 fid->qid.vers = p->vers;
528 fid->qid.type = p->mode >> 24;
534 dostat(Umsc *lun, int path, Dir *d)
538 p = &lun->part[path];
540 d->qid.vers = p->vers;
541 d->qid.type =p->mode >> 24;
543 d->length = (vlong) p->length * lun->lbsize;
544 d->name = strdup(p->name);
545 d->uid = strdup(getuser());
546 d->gid = strdup(d->uid);
547 d->muid = strdup(d->uid);
551 dirgen(int n, Dir* d, void *aux)
557 for(i = Qctl; i < Qmax; i++){
558 if(lun->part[i].inuse == 0)
566 d->qid.path |= (lun - ums->lun) << 16;
571 rootgen(int n, Dir *d, void *)
578 d->qid.path = (n + 1) << 16;
580 d->mode = 0555 | DMDIR;
581 d->name = strdup(lun->name);
582 d->uid = strdup(getuser());
583 d->gid = strdup(d->uid);
584 d->muid = strdup(d->uid);
597 d->qid = req->fid->qid;
598 if(req->fid->qid.path == 0){
599 d->name = strdup("");
600 d->mode = 0555 | DMDIR;
601 d->uid = strdup(getuser());
602 d->gid = strdup(d->uid);
603 d->muid = strdup(d->uid);
605 path = req->fid->qid.path & 0xFFFF;
606 lun = ums->lun + (req->fid->qid.path >> 16) - 1;
607 dostat(lun, path, d);
618 if(req->ofcall.qid.path == 0){
622 path = req->ofcall.qid.path & 0xFFFF;
623 lun = ums->lun + (req->ofcall.qid.path >> 16) - 1;
626 srvrelease(req->srv);
630 srvacquire(req->srv);
637 * check i/o parameters and compute values needed later.
638 * we shift & mask manually to avoid run-time calls to _divv and _modv,
639 * since we don't need general division nor its cost.
642 setup(Umsc *lun, Part *p, char *data, int count, vlong offset)
644 long nb, lbsize, lbshift, lbmask;
647 if(count < 0 || lun->lbsize <= 0 && umscapacity(lun) < 0 ||
650 lbsize = lun->lbsize;
651 assert(ispow2(lbsize));
652 lbshift = log2(lbsize);
655 bno = offset >> lbshift; /* offset / lbsize */
656 nb = ((offset + count + lbsize - 1) >> lbshift) - bno;
658 if(bno + nb > p->length) /* past end of partition? */
659 nb = p->length - bno;
660 if(nb * lbsize > Maxiosize)
661 nb = Maxiosize / lbsize;
663 if(bno >= p->length || nb == 0)
666 bno += p->offset; /* start of partition */
668 lun->off = offset & lbmask; /* offset % lbsize */
669 if(lun->off == 0 && (count & lbmask) == 0)
672 /* not transferring full, aligned blocks; need intermediary */
673 lun->bufp = lun->buf;
678 * Upon SRread/SRwrite errors we assume the medium may have changed,
679 * and ask again for the capacity of the media.
680 * BUG: How to proceed to avoid confussing dossrv??
699 dirread9p(req, rootgen, nil);
703 path = q.path & 0xFFFF;
704 lun = ums->lun + (q.path >> 16) - 1;
705 count = req->ifcall.count;
706 data = req->ofcall.data;
707 offset = req->ifcall.offset;
711 dirread9p(req, dirgen, lun);
727 if(lun->lbsize <= 0 && umscapacity(lun) < 0){
728 respond(req, "phase error");
733 respond(req, "phase error");
737 lun->data.count = count;
739 count = umsrequest(lun,&lun->cmd,&lun->data,&lun->status);
740 lun->phase = Pstatus;
742 lun->lbsize = 0; /* medium may have changed */
745 req->ofcall.count = count;
750 n = snprint(buf, sizeof buf, "%11.0ud ", lun->status);
751 readbuf(req, buf, n);
759 p = &lun->part[path];
761 respond(req, "permission denied");
764 count = setup(lun, p, data, count, offset);
769 n = SRread(lun, lun->bufp, lun->nb * lun->lbsize);
771 lun->lbsize = 0; /* medium may have changed */
774 } else if (lun->bufp == data)
778 * if n == lun->nb*lun->lbsize (as expected),
779 * just copy count bytes.
781 if(lun->off + count > n)
782 count = n - lun->off; /* short read */
784 memmove(data, lun->bufp + lun->off, count);
786 req->ofcall.count = count;
809 lun = ums->lun + (req->fid->qid.path >> 16) - 1;
810 path = req->fid->qid.path & 0xFFFF;
811 count = req->ifcall.count;
812 data = req->ifcall.data;
813 offset = req->ifcall.offset;
821 s = emallocz(count+1, 1);
822 memmove(s, data, count);
823 if(s[count-1] == '\n')
825 if(ctlparse(lun, s) == -1)
828 req->ofcall.count = count;
834 if(lun->lbsize <= 0 && umscapacity(lun) < 0){
835 respond(req, "phase error");
840 if(count != 6 && count != 10 && count != 12 && count != 16){
841 respond(req, "bad command length");
844 memmove(lun->rawcmd, data, count);
845 lun->cmd.p = lun->rawcmd;
846 lun->cmd.count = count;
849 req->ofcall.count = count;
854 lun->data.count = count;
856 count = umsrequest(lun,&lun->cmd,&lun->data,&lun->status);
857 lun->phase = Pstatus;
859 lun->lbsize = 0; /* medium may have changed */
862 req->ofcall.count = count;
868 respond(req, "phase error");
874 p = &lun->part[path];
876 respond(req, "permission denied");
879 len = ocount = count;
880 count = setup(lun, p, data, count, offset);
886 if (lun->bufp == lun->buf) {
887 count = SRread(lun, lun->bufp, lun->nb * lun->lbsize);
889 lun->lbsize = 0; /* medium may have changed */
894 * if count == lun->nb*lun->lbsize, as expected, just
895 * copy len (the original count) bytes of user data.
897 if(lun->off + len > count)
898 len = count - lun->off; /* short read */
900 memmove(lun->bufp + lun->off, data, len);
904 count = SRwrite(lun, lun->bufp, lun->nb * lun->lbsize);
906 lun->lbsize = 0; /* medium may have changed */
910 if(lun->off + len > count)
911 count -= lun->off; /* short write */
912 /* never report more bytes written than requested */
915 else if(count > ocount)
918 req->ofcall.count = count;
928 findendpoints(Ums *ums)
937 for(i = 0; i < nelem(ud->ep); i++){
938 if((ep = ud->ep[i]) == nil)
940 csp = ep->iface->csp;
942 if(!(Class(csp) == Clstorage && (Proto(csp) == Protobulk)))
944 if(sc != Subatapi && sc != Sub8070 && sc != Subscsi)
945 fprint(2, "disk: subclass %#ulx not supported. trying anyway\n", sc);
946 if(ep->type == Ebulk){
947 if(ep->dir == Eboth || ep->dir == Ein)
950 if(ep->dir == Eboth || ep->dir == Eout)
955 dprint(2, "disk: ep ids: in %d out %d\n", epin, epout);
956 if(epin == -1 || epout == -1)
958 ums->epin = openep(dev, epin);
959 if(ums->epin == nil){
960 fprint(2, "disk: openep %d: %r\n", epin);
965 ums->epout = ums->epin;
967 ums->epout = openep(dev, epout);
968 if(ums->epout == nil){
969 fprint(2, "disk: openep %d: %r\n", epout);
973 if(ums->epin == ums->epout)
974 opendevdata(ums->epin, ORDWR);
976 opendevdata(ums->epin, OREAD);
977 opendevdata(ums->epout, OWRITE);
979 if(ums->epin->dfd < 0 || ums->epout->dfd < 0){
980 fprint(2, "disk: open i/o ep data: %r\n");
982 closedev(ums->epout);
985 dprint(2, "disk: ep in %s out %s\n", ums->epin->dir, ums->epout->dir);
987 devctl(ums->epin, "timeout 2000");
988 devctl(ums->epout, "timeout 2000");
990 if(usbdebug > 1 || diskdebug > 2){
991 devctl(ums->epin, "debug 1");
992 devctl(ums->epout, "debug 1");
993 devctl(dev, "debug 1");
1001 fprint(2, "usage: %s [-d] devid\n", argv0);
1012 closedev(ums->epin);
1013 closedev(ums->epout);
1014 ums->epin = ums->epout = nil;
1020 * some devices like usb modems appear as mass storage
1021 * for windows driver installation. switch mode here
1022 * and exit if we detect one so the real driver can
1026 notreallyums(Dev *dev)
1029 if(dev->usb->vid == 0x12d1 && dev->usb->did == 0x1003){
1030 usbcmd(dev, Rh2d|Rstd|Rdev, Rsetfeature, Fdevremotewakeup, 0x02, nil, 0);
1031 exits("mode switch");
1035 static Srv diskfs = {
1045 main(int argc, char **argv)
1056 scsidebug(diskdebug);
1065 dev = getdev(*argv);
1067 sysfatal("getdev: %r");
1069 ums = dev->aux = emallocz(sizeof(Ums), 1);
1071 dev->free = umsdevfree;
1072 if(findendpoints(ums) < 0)
1073 sysfatal("endpoints not found");
1076 * SanDISK 512M gets residues wrong.
1078 if(dev->usb->vid == 0x0781 && dev->usb->did == 0x5150)
1079 ums->wrongresidues = 1;
1082 sysfatal("umsinit: %r\n");
1084 for(i = 0; i <= ums->maxlun; i++){
1087 snprint(lun->name, sizeof(lun->name), "sdU%s.%d", dev->hname, i);
1089 snprint(lun->name, sizeof(lun->name), "sdU%s", dev->hname);
1092 snprint(buf, sizeof buf, "%d.disk", dev->id);
1093 postsharesrv(&diskfs, nil, "usb", buf);