sdscsi.c 8.3 KB

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