sdscsi.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. #include "u.h"
  2. #include "lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "ureg.h"
  8. #include "error.h"
  9. #include "sd.h"
  10. static int
  11. scsitest(SDreq* r)
  12. {
  13. r->write = 0;
  14. memset(r->cmd, 0, sizeof(r->cmd));
  15. r->cmd[1] = r->lun<<5;
  16. r->clen = 6;
  17. r->data = nil;
  18. r->dlen = 0;
  19. r->flags = 0;
  20. r->status = ~0;
  21. // cgascreenputs("A", 1);
  22. return r->unit->dev->ifc->rio(r);
  23. }
  24. int
  25. scsiverify(SDunit* unit)
  26. {
  27. static SDreq *r;
  28. int i, status;
  29. static uchar *inquiry;
  30. if((r = sdmalloc(r, sizeof(SDreq))) == nil)
  31. return 0;
  32. if((inquiry = sdmalloc(inquiry, sizeof(unit->inquiry))) == nil)
  33. return 0;
  34. r->unit = unit;
  35. r->lun = 0; /* ??? */
  36. memset(unit->inquiry, 0, sizeof(unit->inquiry));
  37. r->write = 0;
  38. r->cmd[0] = 0x12;
  39. r->cmd[1] = r->lun<<5;
  40. r->cmd[4] = sizeof(unit->inquiry)-1;
  41. r->clen = 6;
  42. r->data = inquiry;
  43. r->dlen = sizeof(unit->inquiry)-1;
  44. r->flags = 0;
  45. r->status = ~0;
  46. // cgascreenputs("B", 1);
  47. if(unit->dev->ifc->rio(r) != SDok){
  48. return 0;
  49. }
  50. memmove(unit->inquiry, inquiry, r->dlen);
  51. SET(status);
  52. for(i = 0; i < 3; i++){
  53. while((status = scsitest(r)) == SDbusy)
  54. ;
  55. if(status == SDok || status != SDcheck)
  56. break;
  57. if(!(r->flags & SDvalidsense))
  58. break;
  59. if((r->sense[2] & 0x0F) != 0x02)
  60. continue;
  61. /*
  62. * Unit is 'not ready'.
  63. * If it is in the process of becoming ready or needs
  64. * an initialising command, set status so it will be spun-up
  65. * below.
  66. * If there's no medium, that's OK too, but don't
  67. * try to spin it up.
  68. */
  69. if(r->sense[12] == 0x04){
  70. if(r->sense[13] == 0x02 || r->sense[13] == 0x01){
  71. status = SDok;
  72. break;
  73. }
  74. }
  75. if(r->sense[12] == 0x3A)
  76. break;
  77. }
  78. if(status == SDok){
  79. /*
  80. * Try to ensure a direct-access device is spinning.
  81. * Ignore the result.
  82. */
  83. if((unit->inquiry[0] & 0x1F) == 0){
  84. memset(r->cmd, 0, sizeof(r->cmd));
  85. r->write = 0;
  86. r->cmd[0] = 0x1B;
  87. r->cmd[1] = r->lun<<5;
  88. r->cmd[4] = 1;
  89. r->clen = 6;
  90. r->data = nil;
  91. r->dlen = 0;
  92. r->flags = 0;
  93. r->status = ~0;
  94. unit->dev->ifc->rio(r);
  95. }
  96. return 1;
  97. }
  98. return 0;
  99. }
  100. int
  101. return0(void*)
  102. {
  103. return 0;
  104. }
  105. static int
  106. scsirio(SDreq* r)
  107. {
  108. /*
  109. * Perform an I/O request, returning
  110. * -1 failure
  111. * 0 ok
  112. * 2 retry
  113. * The contents of r may be altered so the
  114. * caller should re-initialise if necesary.
  115. */
  116. r->status = ~0;
  117. // cgascreenputs("C", 1);
  118. switch(r->unit->dev->ifc->rio(r)){
  119. default:
  120. return -1;
  121. case SDcheck:
  122. if(!(r->flags & SDvalidsense))
  123. return -1;
  124. switch(r->sense[2] & 0x0F){
  125. case 0x00: /* no sense */
  126. case 0x01: /* recovered error */
  127. return 2;
  128. case 0x06: /* check condition */
  129. /*
  130. * 0x28 - not ready to ready transition,
  131. * medium may have changed.
  132. * 0x29 - power on or some type of reset.
  133. */
  134. if(r->sense[12] == 0x28 && r->sense[13] == 0)
  135. return 2;
  136. if(r->sense[12] == 0x29)
  137. return 2;
  138. return -1;
  139. case 0x02: /* not ready */
  140. /*
  141. * If no medium present, bail out.
  142. * If unit is becoming ready, rather than not
  143. * not ready, wait a little then poke it again. */
  144. if(r->sense[12] == 0x3A)
  145. return -1;
  146. if(r->sense[12] != 0x04 || r->sense[13] != 0x01)
  147. return -1;
  148. tsleep(nil, return0, 0, 500);
  149. scsitest(r);
  150. return 2;
  151. default:
  152. return -1;
  153. }
  154. return -1;
  155. case SDok:
  156. return 0;
  157. }
  158. return -1;
  159. }
  160. int
  161. scsionline(SDunit* unit)
  162. {
  163. int ok;
  164. static SDreq *r;
  165. static uchar *p;
  166. if((r = sdmalloc(r, sizeof(SDreq))) == nil)
  167. return 0;
  168. if((p = sdmalloc(p, 8)) == nil)
  169. return 0;
  170. ok = 0;
  171. r->unit = unit;
  172. r->lun = 0; /* ??? */
  173. for(;;){
  174. /*
  175. * Read-capacity is mandatory for DA, WORM, CD-ROM and
  176. * MO. It may return 'not ready' if type DA is not
  177. * spun up, type MO or type CD-ROM are not loaded or just
  178. * plain slow getting their act together after a reset.
  179. */
  180. r->write = 0;
  181. memset(r->cmd, 0, sizeof(r->cmd));
  182. r->cmd[0] = 0x25;
  183. r->cmd[1] = r->lun<<5;
  184. r->clen = 10;
  185. r->data = p;
  186. r->dlen = 8;
  187. r->flags = 0;
  188. r->status = ~0;
  189. // cgascreenputs("F", 1);
  190. switch(scsirio(r)){
  191. default:
  192. break;
  193. case 0:
  194. unit->sectors = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
  195. /*
  196. * Read-capacity returns the LBA of the last sector,
  197. * therefore the number of sectors must be incremented.
  198. */
  199. unit->sectors++;
  200. unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7];
  201. ok = 1;
  202. break;
  203. case 2:
  204. continue;
  205. }
  206. break;
  207. }
  208. return ok;
  209. }
  210. int
  211. scsiexec(SDunit* unit, int write, uchar* cmd, int clen, void* data, int* dlen)
  212. {
  213. static SDreq *r;
  214. int status;
  215. if((r = sdmalloc(r, sizeof(SDreq))) == nil)
  216. return SDmalloc;
  217. r->unit = unit;
  218. r->lun = cmd[1]>>5; /* ??? */
  219. r->write = write;
  220. memmove(r->cmd, cmd, clen);
  221. r->clen = clen;
  222. r->data = data;
  223. if(dlen)
  224. r->dlen = *dlen;
  225. r->flags = 0;
  226. r->status = ~0;
  227. /*
  228. * Call the device-specific I/O routine.
  229. * There should be no calls to 'error()' below this
  230. * which percolate back up.
  231. */
  232. // cgascreenputs("D", 1);
  233. switch(status = unit->dev->ifc->rio(r)){
  234. case SDok:
  235. if(dlen)
  236. *dlen = r->rlen;
  237. /*FALLTHROUGH*/
  238. case SDcheck:
  239. /*FALLTHROUGH*/
  240. default:
  241. /*
  242. * It's more complicated than this. There are conditions
  243. * which are 'ok' but for which the returned status code
  244. * is not 'SDok'.
  245. * Also, not all conditions require a reqsense, might
  246. * need to do a reqsense here and make it available to the
  247. * caller somehow.
  248. *
  249. * Mañana.
  250. */
  251. break;
  252. }
  253. return status;
  254. }
  255. long
  256. scsibio(SDunit* unit, int lun, int write, void* data, long nb, long bno)
  257. {
  258. static SDreq *r;
  259. long rlen;
  260. if((r = sdmalloc(r, sizeof(SDreq))) == nil)
  261. return SDmalloc;
  262. r->unit = unit;
  263. r->lun = lun;
  264. again:
  265. r->write = write;
  266. if(write == 0)
  267. r->cmd[0] = 0x28;
  268. else
  269. r->cmd[0] = 0x2A;
  270. r->cmd[1] = (lun<<5);
  271. r->cmd[2] = bno>>24;
  272. r->cmd[3] = bno>>16;
  273. r->cmd[4] = bno>>8;
  274. r->cmd[5] = bno;
  275. r->cmd[6] = 0;
  276. r->cmd[7] = nb>>8;
  277. r->cmd[8] = nb;
  278. r->cmd[9] = 0;
  279. r->clen = 10;
  280. r->data = data;
  281. r->dlen = nb*unit->secsize;
  282. r->flags = 0;
  283. r->status = ~0;
  284. // cgascreenputs("E", 1);
  285. switch(scsirio(r)){
  286. default:
  287. rlen = -1;
  288. break;
  289. case 0:
  290. rlen = r->rlen;
  291. break;
  292. case 2:
  293. rlen = -1;
  294. if(!(r->flags & SDvalidsense))
  295. break;
  296. switch(r->sense[2] & 0x0F){
  297. default:
  298. break;
  299. case 0x06: /* check condition */
  300. /*
  301. * Check for a removeable media change.
  302. * If so, mark it and zap the geometry info
  303. * to force an online request.
  304. */
  305. if(r->sense[12] != 0x28 || r->sense[13] != 0)
  306. break;
  307. if(unit->inquiry[1] & 0x80){
  308. unit->sectors = 0;
  309. }
  310. break;
  311. case 0x02: /* not ready */
  312. /*
  313. * If unit is becoming ready,
  314. * rather than not not ready, try again.
  315. */
  316. if(r->sense[12] == 0x04 && r->sense[13] == 0x01)
  317. goto again;
  318. break;
  319. }
  320. break;
  321. }
  322. return rlen;
  323. }
  324. SDev*
  325. scsiid(SDev* sdev, SDifc* ifc)
  326. {
  327. static char idno[16] = "0123456789abcdef";
  328. static char *p = idno;
  329. while(sdev){
  330. if(sdev->ifc == ifc){
  331. sdev->idno = *p++;
  332. if(p >= &idno[sizeof(idno)])
  333. break;
  334. }
  335. sdev = sdev->next;
  336. }
  337. return nil;
  338. }