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