sdscsi.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include "u.h"
  10. #include "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include "../port/error.h"
  15. #include "../port/sd.h"
  16. static int
  17. scsitest(SDreq* r)
  18. {
  19. r->write = 0;
  20. memset(r->cmd, 0, sizeof(r->cmd));
  21. r->cmd[1] = r->lun<<5;
  22. r->clen = 6;
  23. r->data = nil;
  24. r->dlen = 0;
  25. r->flags = 0;
  26. r->status = ~0;
  27. return r->unit->dev->ifc->rio(r);
  28. }
  29. int
  30. scsiverify(SDunit* unit)
  31. {
  32. SDreq *r;
  33. int i, status;
  34. uint8_t *inquiry;
  35. if((r = malloc(sizeof(SDreq))) == nil)
  36. return 0;
  37. if((inquiry = sdmalloc(sizeof(unit->inquiry))) == nil){
  38. free(r);
  39. return 0;
  40. }
  41. r->unit = unit;
  42. r->lun = 0; /* ??? */
  43. memset(unit->inquiry, 0, sizeof(unit->inquiry));
  44. r->write = 0;
  45. r->cmd[0] = 0x12;
  46. r->cmd[1] = r->lun<<5;
  47. r->cmd[4] = sizeof(unit->inquiry)-1;
  48. r->clen = 6;
  49. r->data = inquiry;
  50. r->dlen = sizeof(unit->inquiry)-1;
  51. r->flags = 0;
  52. r->status = ~0;
  53. if(unit->dev->ifc->rio(r) != SDok){
  54. free(r);
  55. return 0;
  56. }
  57. memmove(unit->inquiry, inquiry, r->dlen);
  58. free(inquiry);
  59. SET(status);
  60. for(i = 0; i < 3; i++){
  61. while((status = scsitest(r)) == SDbusy)
  62. ;
  63. if(status == SDok || status != SDcheck)
  64. break;
  65. if(!(r->flags & SDvalidsense))
  66. break;
  67. if((r->sense[2] & 0x0F) != 0x02)
  68. continue;
  69. /*
  70. * Unit is 'not ready'.
  71. * If it is in the process of becoming ready or needs
  72. * an initialising command, set status so it will be spun-up
  73. * below.
  74. * If there's no medium, that's OK too, but don't
  75. * try to spin it up.
  76. */
  77. if(r->sense[12] == 0x04){
  78. if(r->sense[13] == 0x02 || r->sense[13] == 0x01){
  79. status = SDok;
  80. break;
  81. }
  82. }
  83. if(r->sense[12] == 0x3A)
  84. break;
  85. }
  86. if(status == SDok){
  87. /*
  88. * Try to ensure a direct-access device is spinning.
  89. * Don't wait for completion, ignore the result.
  90. */
  91. if((unit->inquiry[0] & 0x1F) == 0){
  92. memset(r->cmd, 0, sizeof(r->cmd));
  93. r->write = 0;
  94. r->cmd[0] = 0x1B;
  95. r->cmd[1] = (r->lun<<5)|0x01;
  96. r->cmd[4] = 1;
  97. r->clen = 6;
  98. r->data = nil;
  99. r->dlen = 0;
  100. r->flags = 0;
  101. r->status = ~0;
  102. unit->dev->ifc->rio(r);
  103. }
  104. }
  105. free(r);
  106. if(status == SDok || status == SDcheck)
  107. return 1;
  108. return 0;
  109. }
  110. static int
  111. scsirio(SDreq* r)
  112. {
  113. /*
  114. * Perform an I/O request, returning
  115. * -1 failure
  116. * 0 ok
  117. * 1 no medium present
  118. * 2 retry
  119. * The contents of r may be altered so the
  120. * caller should re-initialise if necesary.
  121. */
  122. r->status = ~0;
  123. switch(r->unit->dev->ifc->rio(r)){
  124. default:
  125. break;
  126. case SDcheck:
  127. if(!(r->flags & SDvalidsense))
  128. break;
  129. switch(r->sense[2] & 0x0F){
  130. case 0x00: /* no sense */
  131. case 0x01: /* recovered error */
  132. return 2;
  133. case 0x06: /* check condition */
  134. /*
  135. * 0x28 - not ready to ready transition,
  136. * medium may have changed.
  137. * 0x29 - power on or some type of reset.
  138. */
  139. if(r->sense[12] == 0x28 && r->sense[13] == 0)
  140. return 2;
  141. if(r->sense[12] == 0x29)
  142. return 2;
  143. break;
  144. case 0x02: /* not ready */
  145. /*
  146. * If no medium present, bail out.
  147. * If unit is becoming ready, rather than not
  148. * not ready, wait a little then poke it again. */
  149. if(r->sense[12] == 0x3A)
  150. break;
  151. if(r->sense[12] != 0x04 || r->sense[13] != 0x01)
  152. break;
  153. while(waserror())
  154. ;
  155. tsleep(&up->sleep, return0, 0, 500);
  156. poperror();
  157. scsitest(r);
  158. return 2;
  159. default:
  160. break;
  161. }
  162. break;
  163. case SDok:
  164. return 0;
  165. }
  166. return -1;
  167. }
  168. int
  169. scsionline(SDunit* unit)
  170. {
  171. SDreq *r;
  172. uint8_t *p;
  173. int ok, retries;
  174. if((r = malloc(sizeof(SDreq))) == nil)
  175. return 0;
  176. if((p = sdmalloc(8)) == nil){
  177. free(r);
  178. return 0;
  179. }
  180. ok = 0;
  181. r->unit = unit;
  182. r->lun = 0; /* ??? */
  183. for(retries = 0; retries < 10; retries++){
  184. /*
  185. * Read-capacity is mandatory for DA, WORM, CD-ROM and
  186. * MO. It may return 'not ready' if type DA is not
  187. * spun up, type MO or type CD-ROM are not loaded or just
  188. * plain slow getting their act together after a reset.
  189. */
  190. r->write = 0;
  191. memset(r->cmd, 0, sizeof(r->cmd));
  192. r->cmd[0] = 0x25;
  193. r->cmd[1] = r->lun<<5;
  194. r->clen = 10;
  195. r->data = p;
  196. r->dlen = 8;
  197. r->flags = 0;
  198. r->status = ~0;
  199. switch(scsirio(r)){
  200. default:
  201. break;
  202. case 0:
  203. unit->sectors = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
  204. unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7];
  205. /*
  206. * Some ATAPI CD readers lie about the block size.
  207. * Since we don't read audio via this interface
  208. * it's okay to always fudge this.
  209. */
  210. if(unit->secsize == 2352)
  211. unit->secsize = 2048;
  212. /*
  213. * Devices with removable media may return 0 sectors
  214. * when they have empty media (e.g. sata dvd writers);
  215. * if so, keep the count zero.
  216. *
  217. * Read-capacity returns the LBA of the last sector,
  218. * therefore the number of sectors must be incremented.
  219. */
  220. if(unit->sectors != 0)
  221. unit->sectors++;
  222. ok = 1;
  223. break;
  224. case 1:
  225. ok = 1;
  226. break;
  227. case 2:
  228. continue;
  229. }
  230. break;
  231. }
  232. free(p);
  233. free(r);
  234. if(ok)
  235. return ok+retries;
  236. else
  237. return 0;
  238. }
  239. int
  240. scsiexec(SDunit* unit, int write, uint8_t* cmd, int clen, void* data,
  241. int* dlen)
  242. {
  243. SDreq *r;
  244. int status;
  245. if((r = malloc(sizeof(SDreq))) == nil)
  246. return SDmalloc;
  247. r->unit = unit;
  248. r->lun = cmd[1]>>5; /* ??? */
  249. r->write = write;
  250. memmove(r->cmd, cmd, clen);
  251. r->clen = clen;
  252. r->data = data;
  253. if(dlen)
  254. r->dlen = *dlen;
  255. r->flags = 0;
  256. r->status = ~0;
  257. /*
  258. * Call the device-specific I/O routine.
  259. * There should be no calls to 'error()' below this
  260. * which percolate back up.
  261. */
  262. switch(status = unit->dev->ifc->rio(r)){
  263. case SDok:
  264. if(dlen)
  265. *dlen = r->rlen;
  266. /*FALLTHROUGH*/
  267. case SDcheck:
  268. /*FALLTHROUGH*/
  269. default:
  270. /*
  271. * It's more complicated than this. There are conditions
  272. * which are 'ok' but for which the returned status code
  273. * is not 'SDok'.
  274. * Also, not all conditions require a reqsense, might
  275. * need to do a reqsense here and make it available to the
  276. * caller somehow.
  277. *
  278. * Mañana.
  279. */
  280. break;
  281. }
  282. sdfree(r);
  283. return status;
  284. }
  285. static void
  286. scsifmt10(SDreq *r, int write, int lun, int32_t nb, int64_t bno)
  287. {
  288. uint8_t *c;
  289. c = r->cmd;
  290. if(write == 0)
  291. c[0] = 0x28;
  292. else
  293. c[0] = 0x2A;
  294. c[1] = lun<<5;
  295. c[2] = bno>>24;
  296. c[3] = bno>>16;
  297. c[4] = bno>>8;
  298. c[5] = bno;
  299. c[6] = 0;
  300. c[7] = nb>>8;
  301. c[8] = nb;
  302. c[9] = 0;
  303. r->clen = 10;
  304. }
  305. static void
  306. scsifmt16(SDreq *r, int write, int lun, int32_t nb, int64_t bno)
  307. {
  308. uint8_t *c;
  309. c = r->cmd;
  310. if(write == 0)
  311. c[0] = 0x88;
  312. else
  313. c[0] = 0x8A;
  314. c[1] = lun<<5; /* so wrong */
  315. c[2] = bno>>56;
  316. c[3] = bno>>48;
  317. c[4] = bno>>40;
  318. c[5] = bno>>32;
  319. c[6] = bno>>24;
  320. c[7] = bno>>16;
  321. c[8] = bno>>8;
  322. c[9] = bno;
  323. c[10] = nb>>24;
  324. c[11] = nb>>16;
  325. c[12] = nb>>8;
  326. c[13] = nb;
  327. c[14] = 0;
  328. c[15] = 0;
  329. r->clen = 16;
  330. }
  331. int32_t
  332. scsibio(SDunit* unit, int lun, int write, void* data, int32_t nb,
  333. int64_t bno)
  334. {
  335. SDreq *r;
  336. int32_t rlen;
  337. if((r = malloc(sizeof(SDreq))) == nil)
  338. error(Enomem);
  339. r->unit = unit;
  340. r->lun = lun;
  341. again:
  342. r->write = write;
  343. if(bno >= (1ULL<<32))
  344. scsifmt16(r, write, lun, nb, bno);
  345. else
  346. scsifmt10(r, write, lun, nb, bno);
  347. r->data = data;
  348. r->dlen = nb*unit->secsize;
  349. r->flags = 0;
  350. r->status = ~0;
  351. switch(scsirio(r)){
  352. default:
  353. rlen = -1;
  354. break;
  355. case 0:
  356. rlen = r->rlen;
  357. break;
  358. case 2:
  359. rlen = -1;
  360. if(!(r->flags & SDvalidsense))
  361. break;
  362. switch(r->sense[2] & 0x0F){
  363. default:
  364. break;
  365. case 0x01: /* recovered error */
  366. print("%s: recovered error at sector %llud\n",
  367. unit->name, bno);
  368. rlen = r->rlen;
  369. break;
  370. case 0x06: /* check condition */
  371. /*
  372. * Check for a removeable media change.
  373. * If so, mark it by zapping the geometry info
  374. * to force an online request.
  375. */
  376. if(r->sense[12] != 0x28 || r->sense[13] != 0)
  377. break;
  378. if(unit->inquiry[1] & 0x80)
  379. unit->sectors = 0;
  380. break;
  381. case 0x02: /* not ready */
  382. /*
  383. * If unit is becoming ready,
  384. * rather than not not ready, try again.
  385. */
  386. if(r->sense[12] == 0x04 && r->sense[13] == 0x01)
  387. goto again;
  388. break;
  389. }
  390. break;
  391. }
  392. free(r);
  393. return rlen;
  394. }