scsireq.c 13 KB

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