scsireq.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  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 <= Max24off && n <= 256 && (rp->flags & Frw10) == 0){
  105. PUTBE24(cmd+1, rp->offset);
  106. cmd[4] = n;
  107. cmd[5] = 0;
  108. return 6;
  109. }
  110. cmd[0] |= ScmdExtread;
  111. cmd[1] = 0;
  112. PUTBELONG(cmd+2, rp->offset);
  113. cmd[6] = 0;
  114. cmd[7] = n>>8;
  115. cmd[8] = n;
  116. cmd[9] = 0;
  117. return 10;
  118. }
  119. static int
  120. seqdevrw(ScsiReq *rp, uchar *cmd, long nbytes)
  121. {
  122. long n;
  123. /* don't set Cmd1sili; we want the ILI bit instead of a fatal error */
  124. cmd[1] = rp->flags&Fbfixed? Cmd1fixed: 0;
  125. n = nbytes / rp->lbsize;
  126. PUTBE24(cmd+2, n);
  127. cmd[5] = 0;
  128. return 6;
  129. }
  130. long
  131. SRread(ScsiReq *rp, void *buf, long nbytes)
  132. {
  133. uchar cmd[10];
  134. long n;
  135. if((nbytes % rp->lbsize) || nbytes > maxiosize){
  136. rp->status = Status_BADARG;
  137. return -1;
  138. }
  139. /* set up scsi read cmd */
  140. cmd[0] = ScmdRead;
  141. if(rp->flags & Fseqdev)
  142. rp->cmd.count = seqdevrw(rp, cmd, nbytes);
  143. else
  144. rp->cmd.count = dirdevrw(rp, cmd, nbytes);
  145. rp->cmd.p = cmd;
  146. rp->data.p = buf;
  147. rp->data.count = nbytes;
  148. rp->data.write = 0;
  149. /* issue it */
  150. n = SRrequest(rp);
  151. if(n != -1){ /* it worked? */
  152. rp->offset += n / rp->lbsize;
  153. return n;
  154. }
  155. /* request failed; maybe we just read a short record? */
  156. if (exabyte) {
  157. fprint(2, "read error\n");
  158. rp->status = STcheck;
  159. return n;
  160. }
  161. if(rp->status != Status_SD || !(rp->sense[0] & Sd0valid))
  162. return -1;
  163. /* compute # of bytes not read */
  164. n = GETBELONG(rp->sense+3) * rp->lbsize;
  165. if (debug)
  166. fprint(2,
  167. "SRread: request failed with sense data; sense byte count %ld\n",
  168. n);
  169. if(!(rp->flags & Fseqdev))
  170. return -1;
  171. /* device is a tape or something similar */
  172. if (rp->sense[2] == Sd2filemark || rp->sense[2] == 0x08 ||
  173. rp->sense[2] & Sd2ili && n > 0)
  174. rp->data.count = nbytes - n;
  175. else
  176. return -1;
  177. n = rp->data.count;
  178. if (!rp->readblock++ || debug)
  179. fprint(2, "SRread: tape data count %ld%s\n", n,
  180. (rp->sense[2] & Sd2ili? " with ILI": ""));
  181. rp->status = STok;
  182. rp->offset += n / rp->lbsize;
  183. return n;
  184. }
  185. long
  186. SRwrite(ScsiReq *rp, void *buf, long nbytes)
  187. {
  188. uchar cmd[10];
  189. long n;
  190. if((nbytes % rp->lbsize) || nbytes > maxiosize){
  191. rp->status = Status_BADARG;
  192. return -1;
  193. }
  194. /* set up scsi write cmd */
  195. cmd[0] = ScmdWrite;
  196. if(rp->flags & Fseqdev)
  197. rp->cmd.count = seqdevrw(rp, cmd, nbytes);
  198. else
  199. rp->cmd.count = dirdevrw(rp, cmd, nbytes);
  200. rp->cmd.p = cmd;
  201. rp->data.p = buf;
  202. rp->data.count = nbytes;
  203. rp->data.write = 1;
  204. /* issue it */
  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] != Sd2eom)
  212. return -1;
  213. if(rp->sense[0] & Sd0valid){
  214. n -= GETBELONG(rp->sense+3) * rp->lbsize;
  215. rp->data.count = nbytes - n;
  216. }
  217. else
  218. rp->data.count = nbytes;
  219. n = rp->data.count;
  220. }
  221. rp->offset += n / rp->lbsize;
  222. return n;
  223. }
  224. long
  225. SRseek(ScsiReq *rp, long offset, int type)
  226. {
  227. uchar cmd[10];
  228. switch(type){
  229. case 0:
  230. break;
  231. case 1:
  232. offset += rp->offset;
  233. if(offset >= 0)
  234. break;
  235. /*FALLTHROUGH*/
  236. default:
  237. rp->status = Status_BADARG;
  238. return -1;
  239. }
  240. memset(cmd, 0, sizeof cmd);
  241. if(offset <= Max24off && (rp->flags & Frw10) == 0){
  242. cmd[0] = ScmdSeek;
  243. PUTBE24(cmd+1, offset & Max24off);
  244. rp->cmd.count = 6;
  245. }else{
  246. cmd[0] = ScmdExtseek;
  247. PUTBELONG(cmd+2, offset);
  248. rp->cmd.count = 10;
  249. }
  250. rp->cmd.p = cmd;
  251. rp->data.p = cmd;
  252. rp->data.count = 0;
  253. rp->data.write = 1;
  254. SRrequest(rp);
  255. if(rp->status == STok)
  256. return rp->offset = offset;
  257. return -1;
  258. }
  259. long
  260. SRfilemark(ScsiReq *rp, ulong howmany)
  261. {
  262. uchar cmd[6];
  263. memset(cmd, 0, sizeof cmd);
  264. cmd[0] = ScmdFmark;
  265. PUTBE24(cmd+2, howmany);
  266. rp->cmd.p = cmd;
  267. rp->cmd.count = sizeof cmd;
  268. rp->data.p = cmd;
  269. rp->data.count = 0;
  270. rp->data.write = 1;
  271. return SRrequest(rp);
  272. }
  273. long
  274. SRspace(ScsiReq *rp, uchar code, long howmany)
  275. {
  276. uchar cmd[6];
  277. memset(cmd, 0, sizeof cmd);
  278. cmd[0] = ScmdSpace;
  279. cmd[1] = code;
  280. PUTBE24(cmd+2, howmany);
  281. rp->cmd.p = cmd;
  282. rp->cmd.count = sizeof cmd;
  283. rp->data.p = cmd;
  284. rp->data.count = 0;
  285. rp->data.write = 1;
  286. /*
  287. * what about rp->offset?
  288. */
  289. return SRrequest(rp);
  290. }
  291. long
  292. SRinquiry(ScsiReq *rp)
  293. {
  294. uchar cmd[6];
  295. memset(cmd, 0, sizeof cmd);
  296. cmd[0] = ScmdInq;
  297. cmd[4] = sizeof rp->inquiry;
  298. rp->cmd.p = cmd;
  299. rp->cmd.count = sizeof cmd;
  300. rp->data.p = rp->inquiry;
  301. rp->data.count = sizeof rp->inquiry;
  302. rp->data.write = 0;
  303. if(SRrequest(rp) >= 0){
  304. rp->flags |= Finqok;
  305. return 0;
  306. }
  307. rp->flags &= ~Finqok;
  308. return -1;
  309. }
  310. long
  311. SRmodeselect6(ScsiReq *rp, uchar *list, long nbytes)
  312. {
  313. uchar cmd[6];
  314. memset(cmd, 0, sizeof cmd);
  315. cmd[0] = ScmdMselect6;
  316. if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
  317. cmd[1] = 0x10;
  318. cmd[4] = nbytes;
  319. rp->cmd.p = cmd;
  320. rp->cmd.count = sizeof cmd;
  321. rp->data.p = list;
  322. rp->data.count = nbytes;
  323. rp->data.write = 1;
  324. return SRrequest(rp);
  325. }
  326. long
  327. SRmodeselect10(ScsiReq *rp, uchar *list, long nbytes)
  328. {
  329. uchar cmd[10];
  330. memset(cmd, 0, sizeof cmd);
  331. if((rp->flags & Finqok) && (rp->inquiry[2] & 0x07) >= 2)
  332. cmd[1] = 0x10;
  333. cmd[0] = ScmdMselect10;
  334. cmd[7] = nbytes>>8;
  335. cmd[8] = nbytes;
  336. rp->cmd.p = cmd;
  337. rp->cmd.count = sizeof cmd;
  338. rp->data.p = list;
  339. rp->data.count = nbytes;
  340. rp->data.write = 1;
  341. return SRrequest(rp);
  342. }
  343. long
  344. SRmodesense6(ScsiReq *rp, uchar page, uchar *list, long nbytes)
  345. {
  346. uchar cmd[6];
  347. memset(cmd, 0, sizeof cmd);
  348. cmd[0] = ScmdMsense6;
  349. cmd[2] = page;
  350. cmd[4] = nbytes;
  351. rp->cmd.p = cmd;
  352. rp->cmd.count = sizeof cmd;
  353. rp->data.p = list;
  354. rp->data.count = nbytes;
  355. rp->data.write = 0;
  356. return SRrequest(rp);
  357. }
  358. long
  359. SRmodesense10(ScsiReq *rp, uchar page, uchar *list, long nbytes)
  360. {
  361. uchar cmd[10];
  362. memset(cmd, 0, sizeof cmd);
  363. cmd[0] = ScmdMsense10;
  364. cmd[2] = page;
  365. cmd[7] = nbytes>>8;
  366. cmd[8] = nbytes;
  367. rp->cmd.p = cmd;
  368. rp->cmd.count = sizeof cmd;
  369. rp->data.p = list;
  370. rp->data.count = nbytes;
  371. rp->data.write = 0;
  372. return SRrequest(rp);
  373. }
  374. long
  375. SRstart(ScsiReq *rp, uchar code)
  376. {
  377. uchar cmd[6];
  378. memset(cmd, 0, sizeof cmd);
  379. cmd[0] = ScmdStart;
  380. cmd[4] = code;
  381. rp->cmd.p = cmd;
  382. rp->cmd.count = sizeof cmd;
  383. rp->data.p = cmd;
  384. rp->data.count = 0;
  385. rp->data.write = 1;
  386. return SRrequest(rp);
  387. }
  388. long
  389. SRrcapacity(ScsiReq *rp, uchar *data)
  390. {
  391. uchar cmd[10];
  392. memset(cmd, 0, sizeof cmd);
  393. cmd[0] = ScmdRcapacity;
  394. rp->cmd.p = cmd;
  395. rp->cmd.count = sizeof cmd;
  396. rp->data.p = data;
  397. rp->data.count = 8;
  398. rp->data.write = 0;
  399. return SRrequest(rp);
  400. }
  401. static long
  402. request(int fd, ScsiPtr *cmd, ScsiPtr *data, int *status)
  403. {
  404. long n, r;
  405. char buf[16];
  406. /* this was an experiment but it seems to be a good idea */
  407. *status = STok;
  408. /* send SCSI command */
  409. if(write(fd, cmd->p, cmd->count) != cmd->count){
  410. fprint(2, "scsireq: write cmd: %r\n");
  411. *status = Status_SW;
  412. return -1;
  413. }
  414. /* read or write actual data */
  415. werrstr("");
  416. if(data->write)
  417. n = write(fd, data->p, data->count);
  418. else {
  419. n = read(fd, data->p, data->count);
  420. if (n < 0)
  421. memset(data->p, 0, data->count);
  422. else if (n < data->count)
  423. memset(data->p + n, 0, data->count - n);
  424. }
  425. if (n != data->count && n <= 0) {
  426. if (debug)
  427. fprint(2,
  428. "request: tried to %s %ld bytes of data for cmd 0x%x but got %r\n",
  429. (data->write? "write": "read"),
  430. data->count, cmd->p[0]);
  431. } else if (n != data->count && (data->write || debug))
  432. fprint(2, "request: %s %ld of %ld bytes of actual data\n",
  433. (data->write? "wrote": "read"), n, data->count);
  434. /* read status */
  435. buf[0] = '\0';
  436. r = read(fd, buf, sizeof buf-1);
  437. if(exabyte && r <= 0 || !exabyte && r < 0){
  438. fprint(2, "scsireq: read status: %r\n");
  439. *status = Status_SW;
  440. return -1;
  441. }
  442. if (r >= 0)
  443. buf[r] = '\0';
  444. *status = atoi(buf);
  445. if(n < 0 && (exabyte || *status != STcheck))
  446. fprint(2, "scsireq: status 0x%2.2uX: data transfer: %r\n",
  447. *status);
  448. return n;
  449. }
  450. long
  451. SRrequest(ScsiReq *rp)
  452. {
  453. long n;
  454. int status;
  455. retry:
  456. n = request(rp->fd, &rp->cmd, &rp->data, &status);
  457. switch(rp->status = status){
  458. case STok:
  459. rp->data.count = n;
  460. break;
  461. case STcheck:
  462. if(rp->cmd.p[0] != ScmdRsense && SRreqsense(rp) != -1)
  463. rp->status = Status_SD;
  464. if (exabyte)
  465. fprint(2, "SRrequest: STcheck, returning -1\n");
  466. return -1;
  467. case STbusy:
  468. sleep(1000);
  469. goto retry;
  470. default:
  471. fprint(2, "status 0x%2.2uX\n", status);
  472. return -1;
  473. }
  474. return n;
  475. }
  476. int
  477. SRclose(ScsiReq *rp)
  478. {
  479. if((rp->flags & Fopen) == 0){
  480. rp->status = Status_BADARG;
  481. return -1;
  482. }
  483. close(rp->fd);
  484. rp->flags = 0;
  485. return 0;
  486. }
  487. static int
  488. dirdevopen(ScsiReq *rp)
  489. {
  490. ulong blocks;
  491. uchar data[8];
  492. if(SRstart(rp, 1) == -1 || SRrcapacity(rp, data) == -1)
  493. return -1;
  494. rp->lbsize = GETBELONG(data+4);
  495. blocks = GETBELONG(data);
  496. /* some newer dev's don't support 6-byte commands */
  497. if(blocks > Max24off && !force6bytecmds)
  498. rp->flags |= Frw10;
  499. return 0;
  500. }
  501. static int
  502. seqdevopen(ScsiReq *rp)
  503. {
  504. uchar mode[16], limits[6];
  505. if(SRrblimits(rp, limits) == -1)
  506. return -1;
  507. if(limits[1] == 0 && limits[2] == limits[4] && limits[3] == limits[5]){
  508. rp->flags |= Fbfixed;
  509. rp->lbsize = limits[4]<<8 | limits[5];
  510. return 0;
  511. }
  512. /*
  513. * On some older hardware the optional 10-byte
  514. * modeselect command isn't implemented.
  515. */
  516. if (force6bytecmds)
  517. rp->flags |= Fmode6;
  518. if(!(rp->flags & Fmode6)){
  519. /* try 10-byte command first */
  520. memset(mode, 0, sizeof mode);
  521. mode[3] = 0x10; /* device-specific param. */
  522. mode[7] = 8; /* block descriptor length */
  523. /*
  524. * exabytes can't handle this, and
  525. * modeselect(10) is optional.
  526. */
  527. if(SRmodeselect10(rp, mode, sizeof mode) != -1){
  528. rp->lbsize = 1;
  529. return 0; /* success */
  530. }
  531. /* can't do 10-byte commands, back off to 6-byte ones */
  532. rp->flags |= Fmode6;
  533. }
  534. /* 6-byte command */
  535. memset(mode, 0, sizeof mode);
  536. mode[2] = 0x10; /* device-specific param. */
  537. mode[3] = 8; /* block descriptor length */
  538. /*
  539. * bsd sez exabytes need this bit (NBE: no busy enable) in
  540. * vendor-specific page (0), but so far we haven't needed it.
  541. mode[12] |= 8;
  542. */
  543. if(SRmodeselect6(rp, mode, 4+8) == -1)
  544. return -1;
  545. rp->lbsize = 1;
  546. return 0;
  547. }
  548. static int
  549. wormdevopen(ScsiReq *rp)
  550. {
  551. uchar list[MaxDirData];
  552. long status, blen;
  553. if (SRstart(rp, 1) == -1 ||
  554. (status = SRmodesense10(rp, Allmodepages, list, sizeof list)) == -1)
  555. return -1;
  556. /* nbytes = list[0]<<8 | list[1]; */
  557. /* # of bytes of block descriptors of 8 bytes each */
  558. blen = list[6]<<8 | list[7];
  559. if(blen < 8) /* not even 1 block descriptor? */
  560. rp->lbsize = 2048;
  561. else
  562. /* last 3 bytes of block 0 descriptor */
  563. rp->lbsize = GETBE24(list+13);
  564. return status;
  565. }
  566. int
  567. SRopenraw(ScsiReq *rp, char *unit)
  568. {
  569. char name[128];
  570. if(rp->flags & Fopen){
  571. rp->status = Status_BADARG;
  572. return -1;
  573. }
  574. memset(rp, 0, sizeof *rp);
  575. rp->unit = unit;
  576. sprint(name, "%s/raw", unit);
  577. if((rp->fd = open(name, ORDWR)) == -1){
  578. rp->status = STtimeout;
  579. return -1;
  580. }
  581. rp->flags = Fopen;
  582. return 0;
  583. }
  584. int
  585. SRopen(ScsiReq *rp, char *unit)
  586. {
  587. if(SRopenraw(rp, unit) == -1)
  588. return -1;
  589. SRready(rp);
  590. if(SRinquiry(rp) >= 0){
  591. switch(rp->inquiry[0]){
  592. default:
  593. fprint(2, "unknown device type 0x%.2x\n", rp->inquiry[0]);
  594. rp->status = Status_SW;
  595. break;
  596. case 0x00: /* Direct access (disk) */
  597. case 0x05: /* CD-ROM */
  598. case 0x07: /* rewriteable MO */
  599. if(dirdevopen(rp) == -1)
  600. break;
  601. return 0;
  602. case 0x01: /* Sequential eg: tape */
  603. rp->flags |= Fseqdev;
  604. if(seqdevopen(rp) == -1)
  605. break;
  606. return 0;
  607. case 0x02: /* Printer */
  608. rp->flags |= Fprintdev;
  609. return 0;
  610. case 0x04: /* Worm */
  611. rp->flags |= Fwormdev;
  612. if(wormdevopen(rp) == -1)
  613. break;
  614. return 0;
  615. case 0x08: /* medium-changer */
  616. rp->flags |= Fchanger;
  617. return 0;
  618. }
  619. }
  620. SRclose(rp);
  621. return -1;
  622. }