scsireq.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. #include <u.h>
  2. #include <libc.h>
  3. /*
  4. * BUGS:
  5. * no luns
  6. * and incomplete in many other ways
  7. */
  8. #include "scsireq.h"
  9. enum {
  10. Debug = 0,
  11. };
  12. extern long maxiosize;
  13. /*
  14. * exabyte tape drives, at least old ones like the 8200 and 8505,
  15. * are dumb: you have to read the exact block size on the tape,
  16. * they don't take 10-byte SCSI commands, and various other fine points.
  17. */
  18. extern int exabyte, force6bytecmds;
  19. static int debug = Debug;
  20. long
  21. SRready(ScsiReq *rp)
  22. {
  23. uchar cmd[6];
  24. memset(cmd, 0, sizeof(cmd));
  25. rp->cmd.p = cmd;
  26. rp->cmd.count = sizeof(cmd);
  27. rp->data.p = cmd;
  28. rp->data.count = 0;
  29. rp->data.write = 1;
  30. return SRrequest(rp);
  31. }
  32. long
  33. SRrewind(ScsiReq *rp)
  34. {
  35. uchar cmd[6];
  36. memset(cmd, 0, sizeof(cmd));
  37. cmd[0] = ScmdRewind;
  38. rp->cmd.p = cmd;
  39. rp->cmd.count = sizeof(cmd);
  40. rp->data.p = cmd;
  41. rp->data.count = 0;
  42. rp->data.write = 1;
  43. if(SRrequest(rp) >= 0){
  44. rp->offset = 0;
  45. return 0;
  46. }
  47. return -1;
  48. }
  49. long
  50. SRreqsense(ScsiReq *rp)
  51. {
  52. uchar cmd[6];
  53. ScsiReq req;
  54. long status;
  55. if(rp->status == Status_SD){
  56. rp->status = STok;
  57. return 0;
  58. }
  59. memset(cmd, 0, sizeof(cmd));
  60. cmd[0] = ScmdRsense;
  61. cmd[4] = sizeof(req.sense);
  62. memset(&req, 0, sizeof(req));
  63. req.fd = rp->fd;
  64. req.cmd.p = cmd;
  65. req.cmd.count = sizeof(cmd);
  66. req.data.p = rp->sense;
  67. req.data.count = sizeof(rp->sense);
  68. req.data.write = 0;
  69. status = SRrequest(&req);
  70. rp->status = req.status;
  71. return status;
  72. }
  73. long
  74. SRformat(ScsiReq *rp)
  75. {
  76. uchar cmd[6];
  77. memset(cmd, 0, sizeof(cmd));
  78. cmd[0] = ScmdFormat;
  79. rp->cmd.p = cmd;
  80. rp->cmd.count = sizeof(cmd);
  81. rp->data.p = cmd;
  82. rp->data.count = 6;
  83. rp->data.write = 0;
  84. return SRrequest(rp);
  85. }
  86. long
  87. SRrblimits(ScsiReq *rp, uchar *list)
  88. {
  89. uchar cmd[6];
  90. memset(cmd, 0, sizeof(cmd));
  91. cmd[0] = ScmdRblimits;
  92. rp->cmd.p = cmd;
  93. rp->cmd.count = sizeof(cmd);
  94. rp->data.p = list;
  95. rp->data.count = 6;
  96. rp->data.write = 0;
  97. return SRrequest(rp);
  98. }
  99. static int
  100. dirdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
  101. {
  102. long n;
  103. n = nbytes/rp->lbsize;
  104. if(rp->offset <= 0x1fffff && n <= 256 && (rp->flags & Frw10) == 0){
  105. cmd[1] = rp->offset>>16;
  106. cmd[2] = rp->offset>>8;
  107. cmd[3] = rp->offset;
  108. cmd[4] = n;
  109. cmd[5] = 0;
  110. return 6;
  111. }
  112. cmd[0] |= ScmdExtread;
  113. cmd[1] = 0;
  114. cmd[2] = rp->offset>>24;
  115. cmd[3] = rp->offset>>16;
  116. cmd[4] = rp->offset>>8;
  117. cmd[5] = rp->offset;
  118. cmd[6] = 0;
  119. cmd[7] = n>>8;
  120. cmd[8] = n;
  121. cmd[9] = 0;
  122. return 10;
  123. }
  124. static int
  125. seqdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
  126. {
  127. long n;
  128. cmd[1] = rp->flags&Fbfixed? 0x01: 0x00;
  129. /* cmd[1]&2 is the SILI bit: don't report `incorrect' block lengths */
  130. n = nbytes/rp->lbsize;
  131. cmd[2] = n>>16;
  132. cmd[3] = n>>8;
  133. cmd[4] = n;
  134. cmd[5] = 0;
  135. return 6;
  136. }
  137. long
  138. SRread(ScsiReq *rp, void *buf, long nbytes)
  139. {
  140. uchar cmd[10];
  141. long n;
  142. if((nbytes % rp->lbsize) || nbytes > maxiosize){
  143. rp->status = Status_BADARG;
  144. return -1;
  145. }
  146. cmd[0] = ScmdRead;
  147. if(rp->flags & Fseqdev)
  148. rp->cmd.count = seqdevrw(rp, cmd, nbytes);
  149. else
  150. rp->cmd.count = dirdevrw(rp, cmd, nbytes);
  151. rp->cmd.p = cmd;
  152. rp->data.p = buf;
  153. rp->data.count = nbytes;
  154. rp->data.write = 0;
  155. if((n = SRrequest(rp)) == -1){
  156. /* maybe we just read a short record? */
  157. if (exabyte) {
  158. fprint(2, "read error\n");
  159. rp->status = STcheck;
  160. return n;
  161. }
  162. if(rp->status != Status_SD || (rp->sense[0] & 0x80) == 0)
  163. return -1;
  164. if (debug)
  165. fprint(2, "SRread: SRrequest failed with sense data; reading byte count from sense\n");
  166. n = ((rp->sense[3]<<24)
  167. | (rp->sense[4]<<16)
  168. | (rp->sense[5]<<8)
  169. | rp->sense[6])
  170. * rp->lbsize;
  171. if(!(rp->flags & Fseqdev))
  172. return -1;
  173. if(rp->sense[2] == 0x80 || rp->sense[2] == 0x08)
  174. rp->data.count = nbytes - n;
  175. else if(rp->sense[2] == 0x20 && n > 0)
  176. rp->data.count = nbytes - n;
  177. else
  178. return -1;
  179. if (debug)
  180. fprint(2, "SRread: computing byte count from sense\n");
  181. n = rp->data.count;
  182. rp->status = STok;
  183. }
  184. rp->offset += n/rp->lbsize;
  185. return n;
  186. }
  187. long
  188. SRwrite(ScsiReq *rp, void *buf, long nbytes)
  189. {
  190. uchar cmd[10];
  191. long n;
  192. if((nbytes % rp->lbsize) || nbytes > maxiosize){
  193. rp->status = Status_BADARG;
  194. return -1;
  195. }
  196. cmd[0] = ScmdWrite;
  197. if(rp->flags & Fseqdev)
  198. rp->cmd.count = seqdevrw(rp, cmd, nbytes);
  199. else
  200. rp->cmd.count = dirdevrw(rp, cmd, nbytes);
  201. rp->cmd.p = cmd;
  202. rp->data.p = buf;
  203. rp->data.count = nbytes;
  204. rp->data.write = 1;
  205. if((n = SRrequest(rp)) == -1){
  206. if (exabyte) {
  207. fprint(2, "write error\n");
  208. rp->status = STcheck;
  209. return n;
  210. }
  211. if(rp->status != Status_SD || rp->sense[2] != 0x40)
  212. return -1;
  213. if(rp->sense[0] & 0x80){
  214. n -= ((rp->sense[3]<<24)
  215. | (rp->sense[4]<<16)
  216. | (rp->sense[5]<<8)
  217. | rp->sense[6])
  218. * rp->lbsize;
  219. rp->data.count = nbytes - n;
  220. }
  221. else
  222. rp->data.count = nbytes;
  223. n = rp->data.count;
  224. }
  225. rp->offset += n/rp->lbsize;
  226. return n;
  227. }
  228. long
  229. SRseek(ScsiReq *rp, long offset, int type)
  230. {
  231. uchar cmd[10];
  232. switch(type){
  233. case 0:
  234. break;
  235. case 1:
  236. offset += rp->offset;
  237. if(offset >= 0)
  238. break;
  239. /*FALLTHROUGH*/
  240. default:
  241. rp->status = Status_BADARG;
  242. return -1;
  243. }
  244. if(offset <= 0x1fffff && (rp->flags & Frw10) == 0){
  245. cmd[0] = ScmdSeek;
  246. cmd[1] = (offset>>16) & 0x1F;
  247. cmd[2] = offset>>8;
  248. cmd[3] = offset;
  249. cmd[4] = 0;
  250. cmd[5] = 0;
  251. rp->cmd.count = 6;
  252. }else{
  253. cmd[0] = ScmdExtseek;
  254. cmd[1] = 0;
  255. cmd[2] = offset>>24;
  256. cmd[3] = offset>>16;
  257. cmd[4] = offset>>8;
  258. cmd[5] = offset;
  259. cmd[6] = 0;
  260. cmd[7] = 0;
  261. cmd[8] = 0;
  262. cmd[9] = 0;
  263. rp->cmd.count = 10;
  264. }
  265. rp->cmd.p = cmd;
  266. rp->data.p = cmd;
  267. rp->data.count = 0;
  268. rp->data.write = 1;
  269. SRrequest(rp);
  270. if(rp->status == STok)
  271. return rp->offset = offset;
  272. return -1;
  273. }
  274. long
  275. SRfilemark(ScsiReq *rp, ulong howmany)
  276. {
  277. uchar cmd[6];
  278. cmd[0] = ScmdFmark;
  279. cmd[1] = 0;
  280. cmd[2] = howmany>>16;
  281. cmd[3] = howmany>>8;
  282. cmd[4] = howmany;
  283. cmd[5] = 0;
  284. rp->cmd.p = cmd;
  285. rp->cmd.count = sizeof(cmd);
  286. rp->data.p = cmd;
  287. rp->data.count = 0;
  288. rp->data.write = 1;
  289. return SRrequest(rp);
  290. }
  291. long
  292. SRspace(ScsiReq *rp, uchar code, long howmany)
  293. {
  294. uchar cmd[6];
  295. cmd[0] = ScmdSpace;
  296. cmd[1] = code;
  297. cmd[2] = howmany>>16;
  298. cmd[3] = howmany>>8;
  299. cmd[4] = howmany;
  300. cmd[5] = 0;
  301. rp->cmd.p = cmd;
  302. rp->cmd.count = sizeof(cmd);
  303. rp->data.p = cmd;
  304. rp->data.count = 0;
  305. rp->data.write = 1;
  306. /*
  307. * what about rp->offset?
  308. */
  309. return SRrequest(rp);
  310. }
  311. long
  312. SRinquiry(ScsiReq *rp)
  313. {
  314. uchar cmd[6];
  315. memset(cmd, 0, sizeof(cmd));
  316. cmd[0] = ScmdInq;
  317. cmd[4] = sizeof(rp->inquiry);
  318. rp->cmd.p = cmd;
  319. rp->cmd.count = sizeof(cmd);
  320. rp->data.p = rp->inquiry;
  321. rp->data.count = sizeof(rp->inquiry);
  322. rp->data.write = 0;
  323. if(SRrequest(rp) >= 0){
  324. rp->flags |= Finqok;
  325. return 0;
  326. }
  327. rp->flags &= ~Finqok;
  328. return -1;
  329. }
  330. long
  331. SRmodeselect6(ScsiReq *rp, uchar *list, long nbytes)
  332. {
  333. uchar cmd[6];
  334. memset(cmd, 0, sizeof(cmd));
  335. cmd[0] = ScmdMselect6;
  336. if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
  337. cmd[1] = 0x10;
  338. cmd[4] = nbytes;
  339. rp->cmd.p = cmd;
  340. rp->cmd.count = sizeof(cmd);
  341. rp->data.p = list;
  342. rp->data.count = nbytes;
  343. rp->data.write = 1;
  344. return SRrequest(rp);
  345. }
  346. long
  347. SRmodeselect10(ScsiReq *rp, uchar *list, long nbytes)
  348. {
  349. uchar cmd[10];
  350. memset(cmd, 0, sizeof(cmd));
  351. if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
  352. cmd[1] = 0x10;
  353. cmd[0] = ScmdMselect10;
  354. cmd[7] = nbytes>>8;
  355. cmd[8] = nbytes;
  356. rp->cmd.p = cmd;
  357. rp->cmd.count = sizeof(cmd);
  358. rp->data.p = list;
  359. rp->data.count = nbytes;
  360. rp->data.write = 1;
  361. return SRrequest(rp);
  362. }
  363. long
  364. SRmodesense6(ScsiReq *rp, uchar page, uchar *list, long nbytes)
  365. {
  366. uchar cmd[6];
  367. memset(cmd, 0, sizeof(cmd));
  368. cmd[0] = ScmdMsense6;
  369. cmd[2] = page;
  370. cmd[4] = nbytes;
  371. rp->cmd.p = cmd;
  372. rp->cmd.count = sizeof(cmd);
  373. rp->data.p = list;
  374. rp->data.count = nbytes;
  375. rp->data.write = 0;
  376. return SRrequest(rp);
  377. }
  378. long
  379. SRmodesense10(ScsiReq *rp, uchar page, uchar *list, long nbytes)
  380. {
  381. uchar cmd[10];
  382. memset(cmd, 0, sizeof(cmd));
  383. cmd[0] = ScmdMsense10;
  384. cmd[2] = page;
  385. cmd[7] = nbytes>>8;
  386. cmd[8] = nbytes;
  387. rp->cmd.p = cmd;
  388. rp->cmd.count = sizeof(cmd);
  389. rp->data.p = list;
  390. rp->data.count = nbytes;
  391. rp->data.write = 0;
  392. return SRrequest(rp);
  393. }
  394. long
  395. SRstart(ScsiReq *rp, uchar code)
  396. {
  397. uchar cmd[6];
  398. memset(cmd, 0, sizeof(cmd));
  399. cmd[0] = ScmdStart;
  400. cmd[4] = code;
  401. rp->cmd.p = cmd;
  402. rp->cmd.count = sizeof(cmd);
  403. rp->data.p = cmd;
  404. rp->data.count = 0;
  405. rp->data.write = 1;
  406. return SRrequest(rp);
  407. }
  408. long
  409. SRrcapacity(ScsiReq *rp, uchar *data)
  410. {
  411. uchar cmd[10];
  412. memset(cmd, 0, sizeof(cmd));
  413. cmd[0] = ScmdRcapacity;
  414. rp->cmd.p = cmd;
  415. rp->cmd.count = sizeof(cmd);
  416. rp->data.p = data;
  417. rp->data.count = 8;
  418. rp->data.write = 0;
  419. return SRrequest(rp);
  420. }
  421. static long
  422. request(int fd, ScsiPtr *cmd, ScsiPtr *data, int *status)
  423. {
  424. long n, r;
  425. char buf[16];
  426. /* this was an experiment but it seems to be a good idea */
  427. *status = STok;
  428. /* send SCSI command */
  429. if(write(fd, cmd->p, cmd->count) != cmd->count){
  430. fprint(2, "scsireq: write cmd: %r\n");
  431. *status = Status_SW;
  432. return -1;
  433. }
  434. /* read or write actual data */
  435. if(data->write)
  436. n = write(fd, data->p, data->count);
  437. else {
  438. n = read(fd, data->p, data->count);
  439. if (n < 0)
  440. memset(data->p, 0, data->count);
  441. else if (n < data->count)
  442. memset(data->p + n, 0, data->count - n);
  443. }
  444. if (n != data->count && n <= 0)
  445. fprint(2,
  446. "request: tried to %s %ld bytes of data for cmd 0x%x but got %r\n",
  447. (data->write? "write": "read"), data->count, cmd->p[0]);
  448. else if (n != data->count && (data->write || debug))
  449. fprint(2, "request: %s %ld of %ld bytes of actual data\n",
  450. (data->write? "wrote": "read"), n, data->count);
  451. /* read status */
  452. buf[0] = '\0';
  453. r = read(fd, buf, sizeof buf-1);
  454. if(exabyte && r <= 0 || !exabyte && r < 0){
  455. fprint(2, "scsireq: read status: %r\n");
  456. *status = Status_SW;
  457. return -1;
  458. }
  459. if (r >= 0)
  460. buf[r] = '\0';
  461. *status = atoi(buf);
  462. if(n < 0 && (exabyte || *status != STcheck))
  463. fprint(2, "scsireq: status 0x%2.2uX: data transfer: %r\n", *status);
  464. return n;
  465. }
  466. long
  467. SRrequest(ScsiReq *rp)
  468. {
  469. long n;
  470. int status;
  471. retry:
  472. n = request(rp->fd, &rp->cmd, &rp->data, &status);
  473. switch(rp->status = status){
  474. case STok:
  475. rp->data.count = n;
  476. break;
  477. case STcheck:
  478. if(rp->cmd.p[0] != ScmdRsense && SRreqsense(rp) != -1)
  479. rp->status = Status_SD;
  480. if (exabyte)
  481. fprint(2, "SRrequest: STcheck, returning -1\n");
  482. return -1;
  483. case STbusy:
  484. sleep(1000);
  485. goto retry;
  486. default:
  487. fprint(2, "status 0x%2.2uX\n", status);
  488. return -1;
  489. }
  490. return n;
  491. }
  492. int
  493. SRclose(ScsiReq *rp)
  494. {
  495. if((rp->flags & Fopen) == 0){
  496. rp->status = Status_BADARG;
  497. return -1;
  498. }
  499. close(rp->fd);
  500. rp->flags = 0;
  501. return 0;
  502. }
  503. static int
  504. dirdevopen(ScsiReq *rp)
  505. {
  506. ulong blocks;
  507. uchar data[8];
  508. if(SRstart(rp, 1) == -1 || SRrcapacity(rp, data) == -1)
  509. return -1;
  510. rp->lbsize = (data[4]<<28)|(data[5]<<16)|(data[6]<<8)|data[7];
  511. blocks = (data[0]<<24)|(data[1]<<16)|(data[2]<<8)|data[3];
  512. /* some newer dev's don't support 6-byte commands */
  513. if(blocks > 0x1fffff && !force6bytecmds)
  514. rp->flags |= Frw10;
  515. return 0;
  516. }
  517. static int
  518. seqdevopen(ScsiReq *rp)
  519. {
  520. uchar mode[16], limits[6];
  521. if(SRrblimits(rp, limits) == -1)
  522. return -1;
  523. if(limits[1] || limits[2] != limits[4] || limits[3] != limits[5]){
  524. /*
  525. * On some older hardware the optional 10-byte
  526. * modeselect command isn't implemented.
  527. */
  528. if (force6bytecmds)
  529. rp->flags |= Fmode6;
  530. if(!(rp->flags & Fmode6)){
  531. /* try 10-byte command first */
  532. memset(mode, 0, sizeof(mode));
  533. mode[3] = 0x10; /* device-specific param. */
  534. mode[7] = 8; /* block descriptor length */
  535. /*
  536. * exabytes can't handle this, and
  537. * modeselect(10) is optional.
  538. */
  539. if(SRmodeselect10(rp, mode, sizeof(mode)) != -1){
  540. rp->lbsize = 1;
  541. return 0; /* success */
  542. }
  543. /* can't do 10-byte commands, back off to 6-byte ones */
  544. rp->flags |= Fmode6;
  545. }
  546. /* 6-byte command */
  547. memset(mode, 0, sizeof(mode));
  548. mode[2] = 0x10; /* device-specific param. */
  549. mode[3] = 8; /* block descriptor length */
  550. /*
  551. * bsd sez exabytes need this bit (NBE) in vendor-specific
  552. * page (0), but so far we haven't needed it.
  553. */
  554. if (0)
  555. mode[12] |= 8;
  556. if(SRmodeselect6(rp, mode, 4+8) == -1)
  557. return -1;
  558. rp->lbsize = 1;
  559. }else{
  560. rp->flags |= Fbfixed;
  561. rp->lbsize = (limits[4]<<8)|limits[5];
  562. }
  563. return 0;
  564. }
  565. static int
  566. wormdevopen(ScsiReq *rp)
  567. {
  568. uchar list[MaxDirData];
  569. long status;
  570. if(SRstart(rp, 1) == -1)
  571. return -1;
  572. if((status = SRmodesense10(rp, 0x3F, list, sizeof(list))) == -1)
  573. return -1;
  574. if(((list[6]<<8)|list[3]) < 8)
  575. rp->lbsize = 2048;
  576. else
  577. rp->lbsize = (list[13]<<8)|(list[14]<<8)|list[15];
  578. return status;
  579. }
  580. int
  581. SRopenraw(ScsiReq *rp, char *unit)
  582. {
  583. char name[128];
  584. if(rp->flags & Fopen){
  585. rp->status = Status_BADARG;
  586. return -1;
  587. }
  588. memset(rp, 0, sizeof(*rp));
  589. rp->unit = unit;
  590. sprint(name, "%s/raw", unit);
  591. if((rp->fd = open(name, ORDWR)) == -1){
  592. rp->status = STtimeout;
  593. return -1;
  594. }
  595. rp->flags = Fopen;
  596. return 0;
  597. }
  598. int
  599. SRopen(ScsiReq *rp, char *unit)
  600. {
  601. if(SRopenraw(rp, unit) == -1)
  602. return -1;
  603. SRready(rp);
  604. if(SRinquiry(rp) >= 0){
  605. switch(rp->inquiry[0]){
  606. default:
  607. fprint(2, "unknown device type 0x%.2x\n", rp->inquiry[0]);
  608. rp->status = Status_SW;
  609. break;
  610. case 0x00: /* Direct access (disk) */
  611. case 0x05: /* CD-ROM */
  612. case 0x07: /* rewriteable MO */
  613. if(dirdevopen(rp) == -1)
  614. break;
  615. return 0;
  616. case 0x01: /* Sequential eg: tape */
  617. rp->flags |= Fseqdev;
  618. if(seqdevopen(rp) == -1)
  619. break;
  620. return 0;
  621. case 0x02: /* Printer */
  622. rp->flags |= Fprintdev;
  623. return 0;
  624. case 0x04: /* Worm */
  625. rp->flags |= Fwormdev;
  626. if(wormdevopen(rp) == -1)
  627. break;
  628. return 0;
  629. case 0x08: /* medium-changer */
  630. rp->flags |= Fchanger;
  631. return 0;
  632. }
  633. }
  634. SRclose(rp);
  635. return -1;
  636. }