scsireq.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  1. /*
  2. * This is /sys/src/cmd/scuzz/scsireq.c
  3. * changed to add more debug support, to keep
  4. * disk compiling without a scuzz that includes these changes.
  5. * Also, this includes minor tweaks for usb:
  6. * we set req.lun/unit to rp->lun/unit in SRreqsense
  7. * we set the rp->sense[0] bit Sd0valid in SRreqsense
  8. * This does not use libdisk to retrieve the scsi error to make
  9. * user we see the diagnostics if we boot with debug enabled.
  10. *
  11. */
  12. #include <u.h>
  13. #include <libc.h>
  14. /*
  15. * BUGS:
  16. * no luns
  17. * and incomplete in many other ways
  18. */
  19. #include "scsireq.h"
  20. enum {
  21. Debug = 0,
  22. };
  23. /*
  24. * exabyte tape drives, at least old ones like the 8200 and 8505,
  25. * are dumb: you have to read the exact block size on the tape,
  26. * they don't take 10-byte SCSI commands, and various other fine points.
  27. */
  28. extern int exabyte, force6bytecmds;
  29. static int debug = Debug;
  30. static char *scmdnames[256] = {
  31. [ScmdTur] "Tur",
  32. [ScmdRewind] "Rewind",
  33. [ScmdRsense] "Rsense",
  34. [ScmdFormat] "Format",
  35. [ScmdRblimits] "Rblimits",
  36. [ScmdRead] "Read",
  37. [ScmdWrite] "Write",
  38. [ScmdSeek] "Seek",
  39. [ScmdFmark] "Fmark",
  40. [ScmdSpace] "Space",
  41. [ScmdInq] "Inq",
  42. [ScmdMselect6] "Mselect6",
  43. [ScmdMselect10] "Mselect10",
  44. [ScmdMsense6] "Msense6",
  45. [ScmdMsense10] "Msense10",
  46. [ScmdStart] "Start",
  47. [ScmdRcapacity] "Rcapacity",
  48. [ScmdRcapacity16] "Rcap16",
  49. [ScmdExtread] "Extread",
  50. [ScmdExtwrite] "Extwrite",
  51. [ScmdExtseek] "Extseek",
  52. [ScmdSynccache] "Synccache",
  53. [ScmdRTOC] "RTOC",
  54. [ScmdRdiscinfo] "Rdiscinfo",
  55. [ScmdRtrackinfo] "Rtrackinfo",
  56. [ScmdReserve] "Reserve",
  57. [ScmdBlank] "Blank",
  58. [ScmdCDpause] "CDpause",
  59. [ScmdCDstop] "CDstop",
  60. [ScmdCDplay] "CDplay",
  61. [ScmdCDload] "CDload",
  62. [ScmdCDscan] "CDscan",
  63. [ScmdCDstatus] "CDstatus",
  64. [Scmdgetconf] "getconf",
  65. };
  66. long
  67. SRready(ScsiReq *rp)
  68. {
  69. uchar cmd[6];
  70. memset(cmd, 0, sizeof cmd);
  71. rp->cmd.p = cmd;
  72. rp->cmd.count = sizeof cmd;
  73. rp->data.p = cmd;
  74. rp->data.count = 0;
  75. rp->data.write = 1;
  76. return SRrequest(rp);
  77. }
  78. long
  79. SRrewind(ScsiReq *rp)
  80. {
  81. uchar cmd[6];
  82. memset(cmd, 0, sizeof cmd);
  83. cmd[0] = ScmdRewind;
  84. rp->cmd.p = cmd;
  85. rp->cmd.count = sizeof cmd;
  86. rp->data.p = cmd;
  87. rp->data.count = 0;
  88. rp->data.write = 1;
  89. if(SRrequest(rp) >= 0){
  90. rp->offset = 0;
  91. return 0;
  92. }
  93. return -1;
  94. }
  95. long
  96. SRreqsense(ScsiReq *rp)
  97. {
  98. uchar cmd[6];
  99. ScsiReq req;
  100. long status;
  101. if(rp->status == Status_SD){
  102. rp->status = STok;
  103. return 0;
  104. }
  105. memset(cmd, 0, sizeof cmd);
  106. cmd[0] = ScmdRsense;
  107. cmd[4] = sizeof(req.sense);
  108. memset(&req, 0, sizeof(req));
  109. if(rp->flags&Fusb)
  110. req.flags |= Fusb;
  111. req.lun = rp->lun;
  112. req.unit = rp->unit;
  113. req.fd = rp->fd;
  114. req.umsc = rp->umsc;
  115. req.cmd.p = cmd;
  116. req.cmd.count = sizeof cmd;
  117. req.data.p = rp->sense;
  118. req.data.count = sizeof(rp->sense);
  119. req.data.write = 0;
  120. status = SRrequest(&req);
  121. rp->status = req.status;
  122. if(status != -1)
  123. rp->sense[0] |= Sd0valid;
  124. return status;
  125. }
  126. long
  127. SRformat(ScsiReq *rp)
  128. {
  129. uchar cmd[6];
  130. memset(cmd, 0, sizeof cmd);
  131. cmd[0] = ScmdFormat;
  132. rp->cmd.p = cmd;
  133. rp->cmd.count = sizeof cmd;
  134. rp->data.p = cmd;
  135. rp->data.count = 6;
  136. rp->data.write = 0;
  137. return SRrequest(rp);
  138. }
  139. long
  140. SRrblimits(ScsiReq *rp, uchar *list)
  141. {
  142. uchar cmd[6];
  143. memset(cmd, 0, sizeof cmd);
  144. cmd[0] = ScmdRblimits;
  145. rp->cmd.p = cmd;
  146. rp->cmd.count = sizeof cmd;
  147. rp->data.p = list;
  148. rp->data.count = 6;
  149. rp->data.write = 0;
  150. return SRrequest(rp);
  151. }
  152. static int
  153. dirdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
  154. {
  155. long n;
  156. n = nbytes / rp->lbsize;
  157. if(rp->offset <= Max24off && n <= 256 && (rp->flags & Frw10) == 0){
  158. PUTBE24(cmd+1, rp->offset);
  159. cmd[4] = n;
  160. cmd[5] = 0;
  161. return 6;
  162. }
  163. cmd[0] |= ScmdExtread;
  164. cmd[1] = 0;
  165. PUTBELONG(cmd+2, rp->offset);
  166. cmd[6] = 0;
  167. cmd[7] = n>>8;
  168. cmd[8] = n;
  169. cmd[9] = 0;
  170. return 10;
  171. }
  172. static int
  173. seqdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
  174. {
  175. long n;
  176. /* don't set Cmd1sili; we want the ILI bit instead of a fatal error */
  177. cmd[1] = rp->flags&Fbfixed? Cmd1fixed: 0;
  178. n = nbytes / rp->lbsize;
  179. PUTBE24(cmd+2, n);
  180. cmd[5] = 0;
  181. return 6;
  182. }
  183. long
  184. SRread(ScsiReq *rp, void *buf, long nbytes)
  185. {
  186. uchar cmd[10];
  187. long n;
  188. if((nbytes % rp->lbsize) || nbytes > maxiosize){
  189. rp->status = Status_BADARG;
  190. return -1;
  191. }
  192. /* set up scsi read cmd */
  193. cmd[0] = ScmdRead;
  194. if(rp->flags & Fseqdev)
  195. rp->cmd.count = seqdevrw(rp, cmd, nbytes);
  196. else
  197. rp->cmd.count = dirdevrw(rp, cmd, nbytes);
  198. rp->cmd.p = cmd;
  199. rp->data.p = buf;
  200. rp->data.count = nbytes;
  201. rp->data.write = 0;
  202. /* issue it */
  203. n = SRrequest(rp);
  204. if(n != -1){ /* it worked? */
  205. rp->offset += n / rp->lbsize;
  206. return n;
  207. }
  208. /* request failed; maybe we just read a short record? */
  209. if (exabyte) {
  210. fprint(2, "read error\n");
  211. rp->status = STcheck;
  212. return n;
  213. }
  214. if(rp->status != Status_SD || !(rp->sense[0] & Sd0valid))
  215. return -1;
  216. /* compute # of bytes not read */
  217. n = GETBELONG(rp->sense+3) * rp->lbsize;
  218. if(!(rp->flags & Fseqdev))
  219. return -1;
  220. /* device is a tape or something similar */
  221. if (rp->sense[2] == Sd2filemark || rp->sense[2] == 0x08 ||
  222. rp->sense[2] & Sd2ili && n > 0)
  223. rp->data.count = nbytes - n;
  224. else
  225. return -1;
  226. n = rp->data.count;
  227. if (!rp->readblock++ || debug)
  228. fprint(2, "SRread: tape data count %ld%s\n", n,
  229. (rp->sense[2] & Sd2ili? " with ILI": ""));
  230. rp->status = STok;
  231. rp->offset += n / rp->lbsize;
  232. return n;
  233. }
  234. long
  235. SRwrite(ScsiReq *rp, void *buf, long nbytes)
  236. {
  237. uchar cmd[10];
  238. long n;
  239. if((nbytes % rp->lbsize) || nbytes > maxiosize){
  240. rp->status = Status_BADARG;
  241. return -1;
  242. }
  243. /* set up scsi write cmd */
  244. cmd[0] = ScmdWrite;
  245. if(rp->flags & Fseqdev)
  246. rp->cmd.count = seqdevrw(rp, cmd, nbytes);
  247. else
  248. rp->cmd.count = dirdevrw(rp, cmd, nbytes);
  249. rp->cmd.p = cmd;
  250. rp->data.p = buf;
  251. rp->data.count = nbytes;
  252. rp->data.write = 1;
  253. /* issue it */
  254. if((n = SRrequest(rp)) == -1){
  255. if (exabyte) {
  256. fprint(2, "write error\n");
  257. rp->status = STcheck;
  258. return n;
  259. }
  260. if(rp->status != Status_SD || rp->sense[2] != Sd2eom)
  261. return -1;
  262. if(rp->sense[0] & Sd0valid){
  263. n -= GETBELONG(rp->sense+3) * rp->lbsize;
  264. rp->data.count = nbytes - n;
  265. }
  266. else
  267. rp->data.count = nbytes;
  268. n = rp->data.count;
  269. }
  270. rp->offset += n / rp->lbsize;
  271. return n;
  272. }
  273. long
  274. SRseek(ScsiReq *rp, long offset, int type)
  275. {
  276. uchar cmd[10];
  277. switch(type){
  278. case 0:
  279. break;
  280. case 1:
  281. offset += rp->offset;
  282. if(offset >= 0)
  283. break;
  284. /*FALLTHROUGH*/
  285. default:
  286. rp->status = Status_BADARG;
  287. return -1;
  288. }
  289. memset(cmd, 0, sizeof cmd);
  290. if(offset <= Max24off && (rp->flags & Frw10) == 0){
  291. cmd[0] = ScmdSeek;
  292. PUTBE24(cmd+1, offset & Max24off);
  293. rp->cmd.count = 6;
  294. }else{
  295. cmd[0] = ScmdExtseek;
  296. PUTBELONG(cmd+2, offset);
  297. rp->cmd.count = 10;
  298. }
  299. rp->cmd.p = cmd;
  300. rp->data.p = cmd;
  301. rp->data.count = 0;
  302. rp->data.write = 1;
  303. SRrequest(rp);
  304. if(rp->status == STok)
  305. return rp->offset = offset;
  306. return -1;
  307. }
  308. long
  309. SRfilemark(ScsiReq *rp, ulong howmany)
  310. {
  311. uchar cmd[6];
  312. memset(cmd, 0, sizeof cmd);
  313. cmd[0] = ScmdFmark;
  314. PUTBE24(cmd+2, howmany);
  315. rp->cmd.p = cmd;
  316. rp->cmd.count = sizeof cmd;
  317. rp->data.p = cmd;
  318. rp->data.count = 0;
  319. rp->data.write = 1;
  320. return SRrequest(rp);
  321. }
  322. long
  323. SRspace(ScsiReq *rp, uchar code, long howmany)
  324. {
  325. uchar cmd[6];
  326. memset(cmd, 0, sizeof cmd);
  327. cmd[0] = ScmdSpace;
  328. cmd[1] = code;
  329. PUTBE24(cmd+2, howmany);
  330. rp->cmd.p = cmd;
  331. rp->cmd.count = sizeof cmd;
  332. rp->data.p = cmd;
  333. rp->data.count = 0;
  334. rp->data.write = 1;
  335. /*
  336. * what about rp->offset?
  337. */
  338. return SRrequest(rp);
  339. }
  340. long
  341. SRinquiry(ScsiReq *rp)
  342. {
  343. uchar cmd[6];
  344. memset(cmd, 0, sizeof cmd);
  345. cmd[0] = ScmdInq;
  346. cmd[4] = sizeof rp->inquiry;
  347. rp->cmd.p = cmd;
  348. rp->cmd.count = sizeof cmd;
  349. memset(rp->inquiry, 0, sizeof rp->inquiry);
  350. rp->data.p = rp->inquiry;
  351. rp->data.count = sizeof rp->inquiry;
  352. rp->data.write = 0;
  353. if(SRrequest(rp) >= 0){
  354. rp->flags |= Finqok;
  355. return 0;
  356. }
  357. rp->flags &= ~Finqok;
  358. return -1;
  359. }
  360. long
  361. SRmodeselect6(ScsiReq *rp, uchar *list, long nbytes)
  362. {
  363. uchar cmd[6];
  364. memset(cmd, 0, sizeof cmd);
  365. cmd[0] = ScmdMselect6;
  366. if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
  367. cmd[1] = 0x10;
  368. cmd[4] = nbytes;
  369. rp->cmd.p = cmd;
  370. rp->cmd.count = sizeof cmd;
  371. rp->data.p = list;
  372. rp->data.count = nbytes;
  373. rp->data.write = 1;
  374. return SRrequest(rp);
  375. }
  376. long
  377. SRmodeselect10(ScsiReq *rp, uchar *list, long nbytes)
  378. {
  379. uchar cmd[10];
  380. memset(cmd, 0, sizeof cmd);
  381. if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
  382. cmd[1] = 0x10;
  383. cmd[0] = ScmdMselect10;
  384. cmd[7] = nbytes>>8;
  385. cmd[8] = nbytes;
  386. rp->cmd.p = cmd;
  387. rp->cmd.count = sizeof cmd;
  388. rp->data.p = list;
  389. rp->data.count = nbytes;
  390. rp->data.write = 1;
  391. return SRrequest(rp);
  392. }
  393. long
  394. SRmodesense6(ScsiReq *rp, uchar page, uchar *list, long nbytes)
  395. {
  396. uchar cmd[6];
  397. memset(cmd, 0, sizeof cmd);
  398. cmd[0] = ScmdMsense6;
  399. cmd[2] = page;
  400. cmd[4] = nbytes;
  401. rp->cmd.p = cmd;
  402. rp->cmd.count = sizeof cmd;
  403. rp->data.p = list;
  404. rp->data.count = nbytes;
  405. rp->data.write = 0;
  406. return SRrequest(rp);
  407. }
  408. long
  409. SRmodesense10(ScsiReq *rp, uchar page, uchar *list, long nbytes)
  410. {
  411. uchar cmd[10];
  412. memset(cmd, 0, sizeof cmd);
  413. cmd[0] = ScmdMsense10;
  414. cmd[2] = page;
  415. cmd[7] = nbytes>>8;
  416. cmd[8] = nbytes;
  417. rp->cmd.p = cmd;
  418. rp->cmd.count = sizeof cmd;
  419. rp->data.p = list;
  420. rp->data.count = nbytes;
  421. rp->data.write = 0;
  422. return SRrequest(rp);
  423. }
  424. long
  425. SRstart(ScsiReq *rp, uchar code)
  426. {
  427. uchar cmd[6];
  428. memset(cmd, 0, sizeof cmd);
  429. cmd[0] = ScmdStart;
  430. cmd[4] = code;
  431. rp->cmd.p = cmd;
  432. rp->cmd.count = sizeof cmd;
  433. rp->data.p = cmd;
  434. rp->data.count = 0;
  435. rp->data.write = 1;
  436. return SRrequest(rp);
  437. }
  438. long
  439. SRrcapacity(ScsiReq *rp, uchar *data)
  440. {
  441. uchar cmd[10];
  442. memset(cmd, 0, sizeof cmd);
  443. cmd[0] = ScmdRcapacity;
  444. rp->cmd.p = cmd;
  445. rp->cmd.count = sizeof cmd;
  446. rp->data.p = data;
  447. rp->data.count = 8;
  448. rp->data.write = 0;
  449. return SRrequest(rp);
  450. }
  451. long
  452. SRrcapacity16(ScsiReq *rp, uchar *data)
  453. {
  454. uchar cmd[16];
  455. uint i;
  456. i = 32;
  457. memset(cmd, 0, sizeof cmd);
  458. cmd[0] = ScmdRcapacity16;
  459. cmd[1] = 0x10;
  460. cmd[10] = i>>24;
  461. cmd[11] = i>>16;
  462. cmd[12] = i>>8;
  463. cmd[13] = i;
  464. rp->cmd.p = cmd;
  465. rp->cmd.count = sizeof cmd;
  466. rp->data.p = data;
  467. rp->data.count = i;
  468. rp->data.write = 0;
  469. return SRrequest(rp);
  470. }
  471. void
  472. scsidebug(int d)
  473. {
  474. debug = d;
  475. if(debug)
  476. fprint(2, "scsidebug on\n");
  477. }
  478. static long
  479. request(int fd, ScsiPtr *cmd, ScsiPtr *data, int *status)
  480. {
  481. long n, r;
  482. char buf[16];
  483. /* this was an experiment but it seems to be a good idea */
  484. *status = STok;
  485. /* send SCSI command */
  486. if(write(fd, cmd->p, cmd->count) != cmd->count){
  487. fprint(2, "scsireq: write cmd: %r\n");
  488. *status = Status_SW;
  489. return -1;
  490. }
  491. /* read or write actual data */
  492. werrstr("");
  493. if(data->write)
  494. n = write(fd, data->p, data->count);
  495. else {
  496. n = read(fd, data->p, data->count);
  497. if (n < 0)
  498. memset(data->p, 0, data->count);
  499. else if (n < data->count)
  500. memset(data->p + n, 0, data->count - n);
  501. }
  502. if (n != data->count && n <= 0) {
  503. if (debug)
  504. fprint(2,
  505. "request: tried to %s %ld bytes of data for cmd 0x%x but got %r\n",
  506. (data->write? "write": "read"),
  507. data->count, cmd->p[0]);
  508. } else if (n != data->count && (data->write || debug))
  509. fprint(2, "request: %s %ld of %ld bytes of actual data\n",
  510. (data->write? "wrote": "read"), n, data->count);
  511. /* read status */
  512. buf[0] = '\0';
  513. r = read(fd, buf, sizeof buf-1);
  514. if(exabyte && r <= 0 || !exabyte && r < 0){
  515. fprint(2, "scsireq: read status: %r\n");
  516. *status = Status_SW;
  517. return -1;
  518. }
  519. if (r >= 0)
  520. buf[r] = '\0';
  521. *status = atoi(buf);
  522. if(n < 0 && (exabyte || *status != STcheck))
  523. fprint(2, "scsireq: status 0x%2.2uX: data transfer: %r\n",
  524. *status);
  525. return n;
  526. }
  527. static char*
  528. seprintcmd(char *s, char* e, char *cmd, int count, int args)
  529. {
  530. uint c;
  531. if(count < 6)
  532. return seprint(s, e, "<short cmd>");
  533. c = cmd[0];
  534. if(scmdnames[c] != nil)
  535. s = seprint(s, e, "%s", scmdnames[c]);
  536. else
  537. s = seprint(s, e, "cmd:%#02uX", c);
  538. if(args != 0)
  539. switch(c){
  540. case ScmdRsense:
  541. case ScmdInq:
  542. case ScmdMselect6:
  543. case ScmdMsense6:
  544. s = seprint(s, e, " sz %d", cmd[4]);
  545. break;
  546. case ScmdSpace:
  547. s = seprint(s, e, " code %d", cmd[1]);
  548. break;
  549. case ScmdStart:
  550. s = seprint(s, e, " code %d", cmd[4]);
  551. break;
  552. }
  553. return s;
  554. }
  555. static char*
  556. seprintdata(char *s, char *se, uchar *p, int count)
  557. {
  558. int i;
  559. if(count == 0)
  560. return s;
  561. for(i = 0; i < 20 && i < count; i++)
  562. s = seprint(s, se, " %02x", p[i]);
  563. return s;
  564. }
  565. static void
  566. SRdumpReq(ScsiReq *rp)
  567. {
  568. char buf[128];
  569. char *s;
  570. char *se;
  571. se = buf+sizeof(buf);
  572. s = seprint(buf, se, "lun %d ", rp->lun);
  573. s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 1);
  574. s = seprint(s, se, " [%ld]", rp->data.count);
  575. if(rp->cmd.write)
  576. seprintdata(s, se, rp->data.p, rp->data.count);
  577. fprint(2, "scsi⇒ %s\n", buf);
  578. }
  579. static void
  580. SRdumpRep(ScsiReq *rp)
  581. {
  582. char buf[128];
  583. char *s;
  584. char *se;
  585. se = buf+sizeof(buf);
  586. s = seprint(buf, se, "lun %d ", rp->lun);
  587. s = seprintcmd(s, se, (char*)rp->cmd.p, rp->cmd.count, 0);
  588. switch(rp->status){
  589. case STok:
  590. s = seprint(s, se, " good [%ld] ", rp->data.count);
  591. if(rp->cmd.write == 0)
  592. s = seprintdata(s, se, rp->data.p, rp->data.count);
  593. break;
  594. case STnomem:
  595. s = seprint(s, se, " buffer allocation failed");
  596. break;
  597. case STharderr:
  598. s = seprint(s, se, " controller error");
  599. break;
  600. case STtimeout:
  601. s = seprint(s, se, " bus timeout");
  602. break;
  603. case STcheck:
  604. s = seprint(s, se, " check condition");
  605. break;
  606. case STcondmet:
  607. s = seprint(s, se, " condition met/good");
  608. break;
  609. case STbusy:
  610. s = seprint(s, se, " busy");
  611. break;
  612. case STintok:
  613. s = seprint(s, se, " intermediate/good");
  614. break;
  615. case STintcondmet:
  616. s = seprint(s, se, " intermediate/condition met/good");
  617. break;
  618. case STresconf:
  619. s = seprint(s, se, " reservation conflict");
  620. break;
  621. case STterminated:
  622. s = seprint(s, se, " command terminated");
  623. break;
  624. case STqfull:
  625. s = seprint(s, se, " queue full");
  626. break;
  627. default:
  628. s = seprint(s, se, " sts=%#x", rp->status);
  629. }
  630. USED(s);
  631. fprint(2, "scsi← %s\n", buf);
  632. }
  633. static char*
  634. scsierr(ScsiReq *rp)
  635. {
  636. int ec;
  637. switch(rp->status){
  638. case 0:
  639. return "";
  640. case Status_SD:
  641. ec = (rp->sense[12] << 8) | rp->sense[13];
  642. return scsierrmsg(ec);
  643. case Status_SW:
  644. return "software error";
  645. case Status_BADARG:
  646. return "bad argument";
  647. case Status_RO:
  648. return "device is read only";
  649. default:
  650. return "unknown";
  651. }
  652. }
  653. static void
  654. SRdumpErr(ScsiReq *rp)
  655. {
  656. char buf[128];
  657. char *se;
  658. se = buf+sizeof(buf);
  659. seprintcmd(buf, se, (char*)rp->cmd.p, rp->cmd.count, 0);
  660. print("\t%s status: %s\n", buf, scsierr(rp));
  661. }
  662. long
  663. SRrequest(ScsiReq *rp)
  664. {
  665. long n;
  666. int status;
  667. retry:
  668. if(debug)
  669. SRdumpReq(rp);
  670. if(rp->flags&Fusb)
  671. n = umsrequest(rp->umsc, &rp->cmd, &rp->data, &status);
  672. else
  673. n = request(rp->fd, &rp->cmd, &rp->data, &status);
  674. rp->status = status;
  675. if(status == STok)
  676. rp->data.count = n;
  677. if(debug)
  678. SRdumpRep(rp);
  679. switch(status){
  680. case STok:
  681. break;
  682. case STcheck:
  683. if(rp->cmd.p[0] != ScmdRsense && SRreqsense(rp) != -1)
  684. rp->status = Status_SD;
  685. if(debug || exabyte)
  686. SRdumpErr(rp);
  687. werrstr("%s", scsierr(rp));
  688. return -1;
  689. case STbusy:
  690. sleep(1000);
  691. goto retry;
  692. default:
  693. if(debug || exabyte)
  694. SRdumpErr(rp);
  695. werrstr("%s", scsierr(rp));
  696. return -1;
  697. }
  698. return n;
  699. }
  700. int
  701. SRclose(ScsiReq *rp)
  702. {
  703. if((rp->flags & Fopen) == 0){
  704. rp->status = Status_BADARG;
  705. return -1;
  706. }
  707. close(rp->fd);
  708. rp->flags = 0;
  709. return 0;
  710. }
  711. static int
  712. dirdevopen(ScsiReq *rp)
  713. {
  714. ulong blocks;
  715. uchar data[8];
  716. if(SRstart(rp, 1) == -1 || SRrcapacity(rp, data) == -1)
  717. return -1;
  718. rp->lbsize = GETBELONG(data+4);
  719. blocks = GETBELONG(data);
  720. if(blocks == 0xffffffff){
  721. if(SRrcapacity16(rp, data) == -1)
  722. return -1;
  723. rp->lbsize = GETBELONG(data + 8);
  724. blocks = (vlong)GETBELONG(data)<<32 | GETBELONG(data + 4);
  725. }
  726. /* some newer dev's don't support 6-byte commands */
  727. if(blocks > Max24off && !force6bytecmds)
  728. rp->flags |= Frw10;
  729. return 0;
  730. }
  731. static int
  732. seqdevopen(ScsiReq *rp)
  733. {
  734. uchar mode[16], limits[6];
  735. if(SRrblimits(rp, limits) == -1)
  736. return -1;
  737. if(limits[1] == 0 && limits[2] == limits[4] && limits[3] == limits[5]){
  738. rp->flags |= Fbfixed;
  739. rp->lbsize = limits[4]<<8 | limits[5];
  740. return 0;
  741. }
  742. /*
  743. * On some older hardware the optional 10-byte
  744. * modeselect command isn't implemented.
  745. */
  746. if (force6bytecmds)
  747. rp->flags |= Fmode6;
  748. if(!(rp->flags & Fmode6)){
  749. /* try 10-byte command first */
  750. memset(mode, 0, sizeof mode);
  751. mode[3] = 0x10; /* device-specific param. */
  752. mode[7] = 8; /* block descriptor length */
  753. /*
  754. * exabytes can't handle this, and
  755. * modeselect(10) is optional.
  756. */
  757. if(SRmodeselect10(rp, mode, sizeof mode) != -1){
  758. rp->lbsize = 1;
  759. return 0; /* success */
  760. }
  761. /* can't do 10-byte commands, back off to 6-byte ones */
  762. rp->flags |= Fmode6;
  763. }
  764. /* 6-byte command */
  765. memset(mode, 0, sizeof mode);
  766. mode[2] = 0x10; /* device-specific param. */
  767. mode[3] = 8; /* block descriptor length */
  768. /*
  769. * bsd sez exabytes need this bit (NBE: no busy enable) in
  770. * vendor-specific page (0), but so far we haven't needed it.
  771. mode[12] |= 8;
  772. */
  773. if(SRmodeselect6(rp, mode, 4+8) == -1)
  774. return -1;
  775. rp->lbsize = 1;
  776. return 0;
  777. }
  778. static int
  779. wormdevopen(ScsiReq *rp)
  780. {
  781. long status;
  782. uchar list[MaxDirData];
  783. if (SRstart(rp, 1) == -1 ||
  784. (status = SRmodesense10(rp, Allmodepages, list, sizeof list)) == -1)
  785. return -1;
  786. /* nbytes = list[0]<<8 | list[1]; */
  787. /* # of bytes of block descriptors of 8 bytes each; not even 1? */
  788. if((list[6]<<8 | list[7]) < 8)
  789. rp->lbsize = 2048;
  790. else
  791. /* last 3 bytes of block 0 descriptor */
  792. rp->lbsize = GETBE24(list+13);
  793. return status;
  794. }
  795. int
  796. SRopenraw(ScsiReq *rp, char *unit)
  797. {
  798. char name[128];
  799. if(rp->flags & Fopen){
  800. rp->status = Status_BADARG;
  801. return -1;
  802. }
  803. memset(rp, 0, sizeof *rp);
  804. rp->unit = unit;
  805. sprint(name, "%s/raw", unit);
  806. if((rp->fd = open(name, ORDWR)) == -1){
  807. rp->status = STtimeout;
  808. return -1;
  809. }
  810. rp->flags = Fopen;
  811. return 0;
  812. }
  813. int
  814. SRopen(ScsiReq *rp, char *unit)
  815. {
  816. if(SRopenraw(rp, unit) == -1)
  817. return -1;
  818. SRready(rp);
  819. if(SRinquiry(rp) >= 0){
  820. switch(rp->inquiry[0]){
  821. default:
  822. fprint(2, "unknown device type 0x%.2x\n", rp->inquiry[0]);
  823. rp->status = Status_SW;
  824. break;
  825. case 0x00: /* Direct access (disk) */
  826. case 0x05: /* CD-ROM */
  827. case 0x07: /* rewriteable MO */
  828. if(dirdevopen(rp) == -1)
  829. break;
  830. return 0;
  831. case 0x01: /* Sequential eg: tape */
  832. rp->flags |= Fseqdev;
  833. if(seqdevopen(rp) == -1)
  834. break;
  835. return 0;
  836. case 0x02: /* Printer */
  837. rp->flags |= Fprintdev;
  838. return 0;
  839. case 0x04: /* Worm */
  840. rp->flags |= Fwormdev;
  841. if(wormdevopen(rp) == -1)
  842. break;
  843. return 0;
  844. case 0x08: /* medium-changer */
  845. rp->flags |= Fchanger;
  846. return 0;
  847. }
  848. }
  849. SRclose(rp);
  850. return -1;
  851. }