disk.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. * usb/disk - usb mass storage file server
  11. *
  12. * supports only the scsi command interface, not ata.
  13. */
  14. #include <u.h>
  15. #include <libc.h>
  16. #include <ctype.h>
  17. #include <fcall.h>
  18. #include <thread.h>
  19. #include <disk.h>
  20. #include <usb/scsireq.h>
  21. #include <usb/usb.h>
  22. #include <usb/usbfs.h>
  23. #include <usb/ums.h>
  24. enum
  25. {
  26. Qdir = 0,
  27. Qctl,
  28. Qraw,
  29. Qdata,
  30. Qmax,
  31. };
  32. typedef struct Dirtab Dirtab;
  33. struct Dirtab
  34. {
  35. char *name;
  36. int mode;
  37. };
  38. static Dirtab dirtab[] =
  39. {
  40. [Qdir] = "/", DMDIR|0555,
  41. [Qctl] = "ctl", 0664, /* nothing secret here */
  42. [Qraw] = "raw", 0640,
  43. [Qdata] = "data", 0640,
  44. };
  45. /*
  46. * These are used by scuzz scsireq
  47. */
  48. int exabyte, force6bytecmds;
  49. int diskdebug;
  50. static int
  51. getmaxlun(Dev *dev)
  52. {
  53. uint8_t max;
  54. int r;
  55. max = 0;
  56. r = Rd2h|Rclass|Riface;
  57. if(usbcmd(dev, r, Getmaxlun, 0, 0, &max, 1) < 0){
  58. dprint(2, "disk: %s: getmaxlun failed: %r\n", dev->dir);
  59. }else{
  60. max &= 017; /* 15 is the max. allowed */
  61. dprint(2, "disk: %s: maxlun %d\n", dev->dir, max);
  62. }
  63. return max;
  64. }
  65. static int
  66. umsreset(Ums *ums)
  67. {
  68. int r;
  69. r = Rh2d|Rclass|Riface;
  70. if(usbcmd(ums->dev, r, Umsreset, 0, 0, nil, 0) < 0){
  71. fprint(2, "disk: reset: %r\n");
  72. return -1;
  73. }
  74. return 0;
  75. }
  76. static int
  77. umsrecover(Ums *ums)
  78. {
  79. if(umsreset(ums) < 0)
  80. return -1;
  81. if(unstall(ums->dev, ums->epin, Ein) < 0)
  82. dprint(2, "disk: unstall epin: %r\n");
  83. /* do we need this when epin == epout? */
  84. if(unstall(ums->dev, ums->epout, Eout) < 0)
  85. dprint(2, "disk: unstall epout: %r\n");
  86. return 0;
  87. }
  88. static void
  89. umsfatal(Ums *ums)
  90. {
  91. int i;
  92. devctl(ums->dev, "detach");
  93. for(i = 0; i < ums->maxlun; i++)
  94. usbfsdel(&ums->lun[i].fs);
  95. }
  96. static int
  97. ispow2(uint64_t ul)
  98. {
  99. return (ul & (ul - 1)) == 0;
  100. }
  101. /*
  102. * return smallest power of 2 >= n
  103. */
  104. static int
  105. log2(int n)
  106. {
  107. int i;
  108. for(i = 0; (1 << i) < n; i++)
  109. ;
  110. return i;
  111. }
  112. static int
  113. umscapacity(Umsc *lun)
  114. {
  115. uint8_t data[32];
  116. lun->blocks = 0;
  117. lun->capacity = 0;
  118. lun->ScsiReq.lbsize = 0;
  119. memset(data, 0, sizeof data);
  120. if(SRrcapacity(&lun->ScsiReq, data) < 0 && SRrcapacity(&lun->ScsiReq, data) < 0)
  121. return -1;
  122. lun->blocks = GETBELONG(data);
  123. lun->ScsiReq.lbsize = GETBELONG(data+4);
  124. if(lun->blocks == 0xFFFFFFFF){
  125. if(SRrcapacity16(&lun->ScsiReq, data) < 0){
  126. lun->ScsiReq.lbsize = 0;
  127. lun->blocks = 0;
  128. return -1;
  129. }else{
  130. lun->ScsiReq.lbsize = GETBELONG(data + 8);
  131. lun->blocks = (uint64_t)GETBELONG(data)<<32 |
  132. GETBELONG(data + 4);
  133. }
  134. }
  135. lun->blocks++; /* SRcapacity returns LBA of last block */
  136. lun->capacity = (int64_t)lun->blocks * lun->ScsiReq.lbsize;
  137. if(diskdebug)
  138. fprint(2, "disk: logical block size %lu, # blocks %llu\n",
  139. lun->ScsiReq.lbsize, lun->blocks);
  140. return 0;
  141. }
  142. static int
  143. umsinit(Ums *ums)
  144. {
  145. uint8_t i;
  146. Umsc *lun;
  147. int some;
  148. umsreset(ums);
  149. ums->maxlun = getmaxlun(ums->dev);
  150. ums->lun = mallocz((ums->maxlun+1) * sizeof(*ums->lun), 1);
  151. some = 0;
  152. for(i = 0; i <= ums->maxlun; i++){
  153. lun = &ums->lun[i];
  154. lun->ums = ums;
  155. lun->ScsiReq.umsc = lun;
  156. lun->ScsiReq.lun = i;
  157. lun->ScsiReq.flags = Fopen | Fusb | Frw10;
  158. if(SRinquiry(&lun->ScsiReq) < 0 && SRinquiry(&lun->ScsiReq) < 0){
  159. dprint(2, "disk: lun %d inquiry failed\n", i);
  160. continue;
  161. }
  162. switch(lun->ScsiReq.inquiry[0]){
  163. case Devdir:
  164. case Devworm: /* a little different than the others */
  165. case Devcd:
  166. case Devmo:
  167. break;
  168. default:
  169. fprint(2, "disk: lun %d is not a disk (type %#02x)\n",
  170. i, lun->ScsiReq.inquiry[0]);
  171. continue;
  172. }
  173. SRstart(&lun->ScsiReq, 1);
  174. /*
  175. * we ignore the device type reported by inquiry.
  176. * Some devices return a wrong value but would still work.
  177. */
  178. some++;
  179. lun->inq = smprint("%.48s", (char *)lun->ScsiReq.inquiry+8);
  180. umscapacity(lun);
  181. }
  182. if(some == 0){
  183. dprint(2, "disk: all luns failed\n");
  184. devctl(ums->dev, "detach");
  185. return -1;
  186. }
  187. return 0;
  188. }
  189. /*
  190. * called by SR*() commands provided by scuzz's scsireq
  191. */
  192. int32_t
  193. umsrequest(Umsc *umsc, ScsiPtr *cmd, ScsiPtr *data, int *status)
  194. {
  195. Cbw cbw;
  196. Csw csw;
  197. int n, nio, left;
  198. Ums *ums;
  199. ums = umsc->ums;
  200. memcpy(cbw.signature, "USBC", 4);
  201. cbw.tag = ++ums->seq;
  202. cbw.datalen = data->count;
  203. cbw.flags = data->write? CbwDataOut: CbwDataIn;
  204. cbw.lun = umsc->ScsiReq.lun;
  205. if(cmd->count < 1 || cmd->count > 16)
  206. fprint(2, "disk: umsrequest: bad cmd count: %ld\n", cmd->count);
  207. cbw.len = cmd->count;
  208. assert(cmd->count <= sizeof(cbw.command));
  209. memcpy(cbw.command, cmd->p, cmd->count);
  210. memset(cbw.command + cmd->count, 0, sizeof(cbw.command) - cmd->count);
  211. werrstr(""); /* we use %r later even for n == 0 */
  212. if(diskdebug){
  213. fprint(2, "disk: cmd: tag %#lx: ", cbw.tag);
  214. for(n = 0; n < cbw.len; n++)
  215. fprint(2, " %2.2x", cbw.command[n]&0xFF);
  216. fprint(2, " datalen: %ld\n", cbw.datalen);
  217. }
  218. /* issue tunnelled scsi command */
  219. if(write(ums->epout->dfd, &cbw, CbwLen) != CbwLen){
  220. fprint(2, "disk: cmd: %r\n");
  221. goto Fail;
  222. }
  223. /* transfer the data */
  224. nio = data->count;
  225. if(nio != 0){
  226. if(data->write)
  227. n = write(ums->epout->dfd, data->p, nio);
  228. else{
  229. n = read(ums->epin->dfd, data->p, nio);
  230. left = nio - n;
  231. if (n >= 0 && left > 0) /* didn't fill data->p? */
  232. memset(data->p + n, 0, left);
  233. }
  234. nio = n;
  235. if(diskdebug)
  236. if(n < 0)
  237. fprint(2, "disk: data: %r\n");
  238. else
  239. fprint(2, "disk: data: %d bytes\n", n);
  240. if(n <= 0)
  241. if(data->write == 0)
  242. unstall(ums->dev, ums->epin, Ein);
  243. }
  244. /* read the transfer's status */
  245. n = read(ums->epin->dfd, &csw, CswLen);
  246. if(n <= 0){
  247. /* n == 0 means "stalled" */
  248. unstall(ums->dev, ums->epin, Ein);
  249. n = read(ums->epin->dfd, &csw, CswLen);
  250. }
  251. if(n != CswLen || strncmp(csw.signature, "USBS", 4) != 0){
  252. dprint(2, "disk: read n=%d: status: %r\n", n);
  253. goto Fail;
  254. }
  255. if(csw.tag != cbw.tag){
  256. dprint(2, "disk: status tag mismatch\n");
  257. goto Fail;
  258. }
  259. if(csw.status >= CswPhaseErr){
  260. dprint(2, "disk: phase error\n");
  261. goto Fail;
  262. }
  263. if(csw.dataresidue == 0 || ums->wrongresidues)
  264. csw.dataresidue = data->count - nio;
  265. if(diskdebug){
  266. fprint(2, "disk: status: %2.2x residue: %ld\n",
  267. csw.status, csw.dataresidue);
  268. if(cbw.command[0] == ScmdRsense){
  269. fprint(2, "sense data:");
  270. for(n = 0; n < data->count - csw.dataresidue; n++)
  271. fprint(2, " %2.2x", data->p[n]);
  272. fprint(2, "\n");
  273. }
  274. }
  275. switch(csw.status){
  276. case CswOk:
  277. *status = STok;
  278. break;
  279. case CswFailed:
  280. *status = STcheck;
  281. break;
  282. default:
  283. dprint(2, "disk: phase error\n");
  284. goto Fail;
  285. }
  286. ums->nerrs = 0;
  287. return data->count - csw.dataresidue;
  288. Fail:
  289. *status = STharderr;
  290. if(ums->nerrs++ > 15){
  291. fprint(2, "disk: %s: too many errors: device detached\n", ums->dev->dir);
  292. umsfatal(ums);
  293. }else
  294. umsrecover(ums);
  295. return -1;
  296. }
  297. static int
  298. dwalk(Usbfs *fs, Fid *fid, char *name)
  299. {
  300. int i;
  301. Qid qid;
  302. qid = fid->qid;
  303. if((qid.type & QTDIR) == 0){
  304. werrstr("walk in non-directory");
  305. return -1;
  306. }
  307. if(strcmp(name, "..") == 0)
  308. return 0;
  309. for(i = 1; i < nelem(dirtab); i++)
  310. if(strcmp(name, dirtab[i].name) == 0){
  311. qid.path = i | fs->qid;
  312. qid.vers = 0;
  313. qid.type = dirtab[i].mode >> 24;
  314. fid->qid = qid;
  315. return 0;
  316. }
  317. werrstr(Enotfound);
  318. return -1;
  319. }
  320. static void
  321. dostat(Usbfs *fs, int path, Dir *d)
  322. {
  323. Dirtab *t;
  324. Umsc *lun;
  325. t = &dirtab[path];
  326. d->qid.path = path;
  327. d->qid.type = t->mode >> 24;
  328. d->mode = t->mode;
  329. d->name = t->name;
  330. lun = fs->aux;
  331. if(path == Qdata)
  332. d->length = lun->capacity;
  333. else
  334. d->length = 0;
  335. }
  336. static int
  337. dirgen(Usbfs *fs, Qid _1, int i, Dir *d, void*_2)
  338. {
  339. i++; /* skip dir */
  340. if(i >= Qmax)
  341. return -1;
  342. else{
  343. dostat(fs, i, d);
  344. d->qid.path |= fs->qid;
  345. return 0;
  346. }
  347. }
  348. static int
  349. dstat(Usbfs *fs, Qid qid, Dir *d)
  350. {
  351. int path;
  352. path = qid.path & ~fs->qid;
  353. dostat(fs, path, d);
  354. d->qid.path |= fs->qid;
  355. return 0;
  356. }
  357. static int
  358. dopen(Usbfs *fs, Fid *fid, int _1)
  359. {
  360. uint32_t path;
  361. Umsc *lun;
  362. path = fid->qid.path & ~fs->qid;
  363. lun = fs->aux;
  364. switch(path){
  365. case Qraw:
  366. lun->phase = Pcmd;
  367. break;
  368. }
  369. return 0;
  370. }
  371. /*
  372. * check i/o parameters and compute values needed later.
  373. * we shift & mask manually to avoid run-time calls to _divv and _modv,
  374. * since we don't need general division nor its cost.
  375. */
  376. static int
  377. setup(Umsc *lun, char *data, int count, int64_t offset)
  378. {
  379. int32_t nb, lbsize, lbshift, lbmask;
  380. uint64_t bno;
  381. if(count < 0 || lun->ScsiReq.lbsize <= 0 && umscapacity(lun) < 0 ||
  382. lun->ScsiReq.lbsize == 0)
  383. return -1;
  384. lbsize = lun->ScsiReq.lbsize;
  385. assert(ispow2(lbsize));
  386. lbshift = log2(lbsize);
  387. lbmask = lbsize - 1;
  388. bno = offset >> lbshift; /* offset / lbsize */
  389. nb = ((offset + count + lbsize - 1) >> lbshift) - bno;
  390. if(bno + nb > lun->blocks) /* past end of device? */
  391. nb = lun->blocks - bno;
  392. if(nb * lbsize > Maxiosize)
  393. nb = Maxiosize / lbsize;
  394. lun->nb = nb;
  395. if(bno >= lun->blocks || nb == 0)
  396. return 0;
  397. lun->ScsiReq.offset = bno;
  398. lun->off = offset & lbmask; /* offset % lbsize */
  399. if(lun->off == 0 && (count & lbmask) == 0)
  400. lun->bufp = data;
  401. else
  402. /* not transferring full, aligned blocks; need intermediary */
  403. lun->bufp = lun->buf;
  404. return count;
  405. }
  406. /*
  407. * Upon SRread/SRwrite errors we assume the medium may have changed,
  408. * and ask again for the capacity of the media.
  409. * BUG: How to proceed to avoid confusing dossrv??
  410. *
  411. * ctl reads must match the format documented in sd(3) exactly
  412. * to interoperate with the rest of the system.
  413. */
  414. static int32_t
  415. dread(Usbfs *fs, Fid *fid, void *data, int32_t count, int64_t offset)
  416. {
  417. int32_t n;
  418. uint32_t path;
  419. char buf[1024];
  420. char *s, *e;
  421. Umsc *lun;
  422. Ums *ums;
  423. Qid q;
  424. q = fid->qid;
  425. path = fid->qid.path & ~fs->qid;
  426. ums = fs->dev->aux;
  427. lun = fs->aux;
  428. qlock(&ums->QLock);
  429. switch(path){
  430. case Qdir:
  431. count = usbdirread(fs, q, data, count, offset, dirgen, nil);
  432. break;
  433. case Qctl:
  434. /*
  435. * Some usb disks need an extra opportunity to divulge their
  436. * capacity (e.g. M-Systems/SanDisk 1GB flash drive).
  437. */
  438. if(lun->ScsiReq.lbsize <= 0)
  439. umscapacity(lun);
  440. s = buf;
  441. e = buf + sizeof(buf);
  442. if(lun->ScsiReq.flags & Finqok)
  443. s = seprint(s, e, "inquiry %s lun %ld: %s\n",
  444. fs->dev->dir, lun - &ums->lun[0], lun->inq);
  445. if(lun->blocks > 0)
  446. s = seprint(s, e, "geometry %llu %ld\n",
  447. lun->blocks, lun->ScsiReq.lbsize);
  448. count = usbreadbuf(data, count, offset, buf, s - buf);
  449. break;
  450. case Qraw:
  451. if(lun->ScsiReq.lbsize <= 0 && umscapacity(lun) < 0){
  452. count = -1;
  453. break;
  454. }
  455. switch(lun->phase){
  456. case Pcmd:
  457. qunlock(&ums->QLock);
  458. werrstr("phase error");
  459. return -1;
  460. case Pdata:
  461. lun->ScsiReq.data.p = data;
  462. lun->ScsiReq.data.count = count;
  463. lun->ScsiReq.data.write = 0;
  464. count = umsrequest(lun,&lun->ScsiReq.cmd,&lun->ScsiReq.data,&lun->ScsiReq.status);
  465. lun->phase = Pstatus;
  466. if(count < 0)
  467. lun->ScsiReq.lbsize = 0; /* medium may have changed */
  468. break;
  469. case Pstatus:
  470. n = snprint(buf, sizeof buf, "%11.0ud ", lun->ScsiReq.status);
  471. count = usbreadbuf(data, count, 0LL, buf, n);
  472. lun->phase = Pcmd;
  473. break;
  474. }
  475. break;
  476. case Qdata:
  477. count = setup(lun, data, count, offset);
  478. if (count <= 0)
  479. break;
  480. n = SRread(&lun->ScsiReq, lun->bufp, lun->nb * lun->ScsiReq.lbsize);
  481. if(n < 0){
  482. lun->ScsiReq.lbsize = 0; /* medium may have changed */
  483. count = -1;
  484. } else if (lun->bufp == data)
  485. count = n;
  486. else{
  487. /*
  488. * if n == lun->nb*lun->lbsize (as expected),
  489. * just copy count bytes.
  490. */
  491. if(lun->off + count > n)
  492. count = n - lun->off; /* short read */
  493. if(count > 0)
  494. memmove(data, lun->bufp + lun->off, count);
  495. }
  496. break;
  497. }
  498. qunlock(&ums->QLock);
  499. return count;
  500. }
  501. static int32_t
  502. dwrite(Usbfs *fs, Fid *fid, void *data, int32_t count, int64_t offset)
  503. {
  504. int32_t len, ocount;
  505. uint32_t path;
  506. uint64_t bno;
  507. Ums *ums;
  508. Umsc *lun;
  509. ums = fs->dev->aux;
  510. lun = fs->aux;
  511. path = fid->qid.path & ~fs->qid;
  512. qlock(&ums->QLock);
  513. switch(path){
  514. default:
  515. werrstr(Eperm);
  516. count = -1;
  517. break;
  518. case Qctl:
  519. dprint(2, "usb/disk: ctl ignored\n");
  520. break;
  521. case Qraw:
  522. if(lun->ScsiReq.lbsize <= 0 && umscapacity(lun) < 0){
  523. count = -1;
  524. break;
  525. }
  526. switch(lun->phase){
  527. case Pcmd:
  528. if(count != 6 && count != 10){
  529. qunlock(&ums->QLock);
  530. werrstr("bad command length");
  531. return -1;
  532. }
  533. memmove(lun->rawcmd, data, count);
  534. lun->ScsiReq.cmd.p = lun->rawcmd;
  535. lun->ScsiReq.cmd.count = count;
  536. lun->ScsiReq.cmd.write = 1;
  537. lun->phase = Pdata;
  538. break;
  539. case Pdata:
  540. lun->ScsiReq.data.p = data;
  541. lun->ScsiReq.data.count = count;
  542. lun->ScsiReq.data.write = 1;
  543. count = umsrequest(lun,&lun->ScsiReq.cmd,&lun->ScsiReq.data,&lun->ScsiReq.status);
  544. lun->phase = Pstatus;
  545. if(count < 0)
  546. lun->ScsiReq.lbsize = 0; /* medium may have changed */
  547. break;
  548. case Pstatus:
  549. lun->phase = Pcmd;
  550. werrstr("phase error");
  551. count = -1;
  552. break;
  553. }
  554. break;
  555. case Qdata:
  556. len = ocount = count;
  557. count = setup(lun, data, count, offset);
  558. if (count <= 0)
  559. break;
  560. bno = lun->ScsiReq.offset;
  561. if (lun->bufp == lun->buf) {
  562. count = SRread(&lun->ScsiReq, lun->bufp, lun->nb * lun->ScsiReq.lbsize);
  563. if(count < 0) {
  564. lun->ScsiReq.lbsize = 0; /* medium may have changed */
  565. break;
  566. }
  567. /*
  568. * if count == lun->nb*lun->lbsize, as expected, just
  569. * copy len (the original count) bytes of user data.
  570. */
  571. if(lun->off + len > count)
  572. len = count - lun->off; /* short read */
  573. if(len > 0)
  574. memmove(lun->bufp + lun->off, data, len);
  575. }
  576. lun->ScsiReq.offset = bno;
  577. count = SRwrite(&lun->ScsiReq, lun->bufp, lun->nb * lun->ScsiReq.lbsize);
  578. if(count < 0)
  579. lun->ScsiReq.lbsize = 0; /* medium may have changed */
  580. else{
  581. if(lun->off + len > count)
  582. count -= lun->off; /* short write */
  583. /* never report more bytes written than requested */
  584. if(count < 0)
  585. count = 0;
  586. else if(count > ocount)
  587. count = ocount;
  588. }
  589. break;
  590. }
  591. qunlock(&ums->QLock);
  592. return count;
  593. }
  594. int
  595. findendpoints(Ums *ums)
  596. {
  597. Ep *ep;
  598. Usbdev *ud;
  599. uint32_t csp, sc;
  600. int i, epin, epout;
  601. epin = epout = -1;
  602. ud = ums->dev->usb;
  603. for(i = 0; i < nelem(ud->ep); i++){
  604. if((ep = ud->ep[i]) == nil)
  605. continue;
  606. csp = ep->iface->csp;
  607. sc = Subclass(csp);
  608. if(!(Class(csp) == Clstorage && (Proto(csp) == Protobulk)))
  609. continue;
  610. if(sc != Subatapi && sc != Sub8070 && sc != Subscsi)
  611. fprint(2, "disk: subclass %#ulx not supported. trying anyway\n", sc);
  612. if(ep->type == Ebulk){
  613. if(ep->dir == Eboth || ep->dir == Ein)
  614. if(epin == -1)
  615. epin = ep->id;
  616. if(ep->dir == Eboth || ep->dir == Eout)
  617. if(epout == -1)
  618. epout = ep->id;
  619. }
  620. }
  621. dprint(2, "disk: ep ids: in %d out %d\n", epin, epout);
  622. if(epin == -1 || epout == -1)
  623. return -1;
  624. ums->epin = openep(ums->dev, epin);
  625. if(ums->epin == nil){
  626. fprint(2, "disk: openep %d: %r\n", epin);
  627. return -1;
  628. }
  629. if(epout == epin){
  630. incref(&ums->epin->Ref);
  631. ums->epout = ums->epin;
  632. }else
  633. ums->epout = openep(ums->dev, epout);
  634. if(ums->epout == nil){
  635. fprint(2, "disk: openep %d: %r\n", epout);
  636. closedev(ums->epin);
  637. return -1;
  638. }
  639. if(ums->epin == ums->epout)
  640. opendevdata(ums->epin, ORDWR);
  641. else{
  642. opendevdata(ums->epin, OREAD);
  643. opendevdata(ums->epout, OWRITE);
  644. }
  645. if(ums->epin->dfd < 0 || ums->epout->dfd < 0){
  646. fprint(2, "disk: open i/o ep data: %r\n");
  647. closedev(ums->epin);
  648. closedev(ums->epout);
  649. return -1;
  650. }
  651. dprint(2, "disk: ep in %s out %s\n", ums->epin->dir, ums->epout->dir);
  652. devctl(ums->epin, "timeout 2000");
  653. devctl(ums->epout, "timeout 2000");
  654. if(usbdebug > 1 || diskdebug > 2){
  655. devctl(ums->epin, "debug 1");
  656. devctl(ums->epout, "debug 1");
  657. devctl(ums->dev, "debug 1");
  658. }
  659. return 0;
  660. }
  661. static int
  662. usage(void)
  663. {
  664. werrstr("usage: usb/disk [-d] [-N nb]");
  665. return -1;
  666. }
  667. static void
  668. umsdevfree(void *a)
  669. {
  670. Ums *ums = a;
  671. if(ums == nil)
  672. return;
  673. closedev(ums->epin);
  674. closedev(ums->epout);
  675. ums->epin = ums->epout = nil;
  676. free(ums->lun);
  677. free(ums);
  678. }
  679. static Usbfs diskfs = {
  680. .walk = dwalk,
  681. .open = dopen,
  682. .read = dread,
  683. .write = dwrite,
  684. .stat = dstat,
  685. };
  686. int
  687. diskmain(Dev *dev, int argc, char **argv)
  688. {
  689. Ums *ums;
  690. Umsc *lun;
  691. int i, devid;
  692. devid = dev->id;
  693. ARGBEGIN{
  694. case 'd':
  695. scsidebug(diskdebug);
  696. diskdebug++;
  697. break;
  698. case 'N':
  699. devid = atoi(EARGF(usage()));
  700. break;
  701. default:
  702. return usage();
  703. }ARGEND
  704. if(argc != 0) {
  705. return usage();
  706. }
  707. // notify(ding);
  708. ums = dev->aux = emallocz(sizeof(Ums), 1);
  709. ums->maxlun = -1;
  710. ums->dev = dev;
  711. dev->free = umsdevfree;
  712. if(findendpoints(ums) < 0){
  713. werrstr("disk: endpoints not found");
  714. return -1;
  715. }
  716. /*
  717. * SanDISK 512M gets residues wrong.
  718. */
  719. if(dev->usb->vid == 0x0781 && dev->usb->did == 0x5150)
  720. ums->wrongresidues = 1;
  721. if(umsinit(ums) < 0){
  722. dprint(2, "disk: umsinit: %r\n");
  723. return -1;
  724. }
  725. for(i = 0; i <= ums->maxlun; i++){
  726. lun = &ums->lun[i];
  727. lun->fs = diskfs;
  728. snprint(lun->fs.name, sizeof(lun->fs.name), "sdU%d.%d", devid, i);
  729. lun->fs.dev = dev;
  730. incref(&dev->Ref);
  731. lun->fs.aux = lun;
  732. usbfsadd(&lun->fs);
  733. }
  734. return 0;
  735. }