disk.c 20 KB

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