scsireq.c 11 KB

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