xref: /plan9/sys/src/cmd/usb/disk/disk.c (revision 0641ea0915be9a7e191dbe21da4a7207d7e24bd4)
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