scsi.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. /*
  2. * Now thread-safe.
  3. *
  4. * The codeqlock guarantees that once codes != nil, that pointer will never
  5. * change nor become invalid.
  6. *
  7. * The QLock in the Scsi structure moderates access to the raw device.
  8. * We should probably export some of the already-locked routines, but
  9. * there hasn't been a need.
  10. */
  11. #include <u.h>
  12. #include <libc.h>
  13. #include <disk.h>
  14. enum {
  15. Readtoc = 0x43,
  16. };
  17. int scsiverbose;
  18. #define codefile "/sys/lib/scsicodes"
  19. static char *codes;
  20. static QLock codeqlock;
  21. static void
  22. getcodes(void)
  23. {
  24. Dir *d;
  25. int n, fd;
  26. if(codes != nil)
  27. return;
  28. qlock(&codeqlock);
  29. if(codes != nil) {
  30. qunlock(&codeqlock);
  31. return;
  32. }
  33. if((d = dirstat(codefile)) == nil || (fd = open(codefile, OREAD)) < 0) {
  34. qunlock(&codeqlock);
  35. return;
  36. }
  37. codes = malloc(1+d->length+1);
  38. if(codes == nil) {
  39. close(fd);
  40. qunlock(&codeqlock);
  41. free(d);
  42. return;
  43. }
  44. codes[0] = '\n'; /* for searches */
  45. n = readn(fd, codes+1, d->length);
  46. close(fd);
  47. free(d);
  48. if(n < 0) {
  49. free(codes);
  50. codes = nil;
  51. qunlock(&codeqlock);
  52. return;
  53. }
  54. codes[n] = '\0';
  55. qunlock(&codeqlock);
  56. }
  57. char*
  58. scsierror(int asc, int ascq)
  59. {
  60. char *p, *q;
  61. static char search[32];
  62. static char buf[128];
  63. getcodes();
  64. if(codes) {
  65. sprint(search, "\n%.2ux%.2ux ", asc, ascq);
  66. if(p = strstr(codes, search)) {
  67. p += 6;
  68. if((q = strchr(p, '\n')) == nil)
  69. q = p+strlen(p);
  70. snprint(buf, sizeof buf, "%.*s", (int)(q-p), p);
  71. return buf;
  72. }
  73. sprint(search, "\n%.2ux00", asc);
  74. if(p = strstr(codes, search)) {
  75. p += 6;
  76. if((q = strchr(p, '\n')) == nil)
  77. q = p+strlen(p);
  78. snprint(buf, sizeof buf, "(ascq #%.2ux) %.*s", ascq, (int)(q-p), p);
  79. return buf;
  80. }
  81. }
  82. sprint(buf, "scsi #%.2ux %.2ux", asc, ascq);
  83. return buf;
  84. }
  85. static int
  86. _scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io, int dolock)
  87. {
  88. uchar resp[16];
  89. int n;
  90. long status;
  91. if(dolock)
  92. qlock(s);
  93. if(write(s->rawfd, cmd, ccount) != ccount) {
  94. werrstr("cmd write: %r");
  95. if(dolock)
  96. qunlock(s);
  97. return -1;
  98. }
  99. switch(io){
  100. case Sread:
  101. n = read(s->rawfd, data, dcount);
  102. /* read toc errors are frequent and not very interesting */
  103. if(n < 0 && (scsiverbose == 1 ||
  104. scsiverbose == 2 && cmd[0] != Readtoc))
  105. fprint(2, "dat read: %r: cmd 0x%2.2uX\n", cmd[0]);
  106. break;
  107. case Swrite:
  108. n = write(s->rawfd, data, dcount);
  109. if(n != dcount && scsiverbose)
  110. fprint(2, "dat write: %r: cmd 0x%2.2uX\n", cmd[0]);
  111. break;
  112. default:
  113. case Snone:
  114. n = write(s->rawfd, resp, 0);
  115. if(n != 0 && scsiverbose)
  116. fprint(2, "none write: %r: cmd 0x%2.2uX\n", cmd[0]);
  117. break;
  118. }
  119. memset(resp, 0, sizeof(resp));
  120. if(read(s->rawfd, resp, sizeof(resp)) < 0) {
  121. werrstr("resp read: %r\n");
  122. if(dolock)
  123. qunlock(s);
  124. return -1;
  125. }
  126. if(dolock)
  127. qunlock(s);
  128. resp[sizeof(resp)-1] = '\0';
  129. status = atoi((char*)resp);
  130. if(status == 0)
  131. return n;
  132. werrstr("cmd %2.2uX: status %luX dcount %d n %d", cmd[0], status, dcount, n);
  133. return -1;
  134. }
  135. int
  136. scsicmd(Scsi *s, uchar *cmd, int ccount, void *data, int dcount, int io)
  137. {
  138. return _scsicmd(s, cmd, ccount, data, dcount, io, 1);
  139. }
  140. static int
  141. _scsiready(Scsi *s, int dolock)
  142. {
  143. uchar cmd[6], resp[16];
  144. int status, i;
  145. if(dolock)
  146. qlock(s);
  147. for(i=0; i<3; i++) {
  148. memset(cmd, 0, sizeof(cmd));
  149. cmd[0] = 0x00; /* unit ready */
  150. if(write(s->rawfd, cmd, sizeof(cmd)) != sizeof(cmd)) {
  151. if(scsiverbose)
  152. fprint(2, "ur cmd write: %r\n");
  153. goto bad;
  154. }
  155. write(s->rawfd, resp, 0);
  156. if(read(s->rawfd, resp, sizeof(resp)) < 0) {
  157. if(scsiverbose)
  158. fprint(2, "ur resp read: %r\n");
  159. goto bad;
  160. }
  161. resp[sizeof(resp)-1] = '\0';
  162. status = atoi((char*)resp);
  163. if(status == 0 || status == 0x02) {
  164. if(dolock)
  165. qunlock(s);
  166. return 0;
  167. }
  168. if(scsiverbose)
  169. fprint(2, "target: bad status: %x\n", status);
  170. bad:;
  171. }
  172. if(dolock)
  173. qunlock(s);
  174. return -1;
  175. }
  176. int
  177. scsiready(Scsi *s)
  178. {
  179. return _scsiready(s, 1);
  180. }
  181. int
  182. scsi(Scsi *s, uchar *cmd, int ccount, void *v, int dcount, int io)
  183. {
  184. uchar req[6], sense[255], *data;
  185. int tries, code, key, n;
  186. char *p;
  187. data = v;
  188. SET(key, code);
  189. qlock(s);
  190. for(tries=0; tries<2; tries++) {
  191. n = _scsicmd(s, cmd, ccount, data, dcount, io, 0);
  192. if(n >= 0) {
  193. qunlock(s);
  194. return n;
  195. }
  196. /*
  197. * request sense
  198. */
  199. memset(req, 0, sizeof(req));
  200. req[0] = 0x03;
  201. req[4] = sizeof(sense);
  202. memset(sense, 0xFF, sizeof(sense));
  203. if((n=_scsicmd(s, req, sizeof(req), sense, sizeof(sense), Sread, 0)) < 14)
  204. if(scsiverbose)
  205. fprint(2, "reqsense scsicmd %d: %r\n", n);
  206. if(_scsiready(s, 0) < 0)
  207. if(scsiverbose)
  208. fprint(2, "unit not ready\n");
  209. key = sense[2];
  210. code = sense[12];
  211. if(code == 0x17 || code == 0x18) { /* recovered errors */
  212. qunlock(s);
  213. return dcount;
  214. }
  215. if(code == 0x28 && cmd[0] == Readtoc) {
  216. /* read toc and media changed */
  217. s->nchange++;
  218. s->changetime = time(0);
  219. continue;
  220. }
  221. }
  222. /* drive not ready, or medium not present */
  223. if(cmd[0] == Readtoc && key == 2 && (code == 0x3a || code == 0x04)) {
  224. s->changetime = 0;
  225. qunlock(s);
  226. return -1;
  227. }
  228. qunlock(s);
  229. if(cmd[0] == Readtoc && key == 5 && code == 0x24) /* blank media */
  230. return -1;
  231. p = scsierror(code, sense[13]);
  232. werrstr("cmd #%.2ux: %s", cmd[0], p);
  233. if(scsiverbose)
  234. fprint(2, "scsi cmd #%.2ux: %.2ux %.2ux %.2ux: %s\n",
  235. cmd[0], key, code, sense[13], p);
  236. // if(key == 0)
  237. // return dcount;
  238. return -1;
  239. }
  240. Scsi*
  241. openscsi(char *dev)
  242. {
  243. Scsi *s;
  244. int rawfd, ctlfd, l, n;
  245. char *name, *p, buf[512];
  246. l = strlen(dev)+1+3+1;
  247. name = malloc(l);
  248. if(name == nil)
  249. return nil;
  250. snprint(name, l, "%s/raw", dev);
  251. if((rawfd = open(name, ORDWR)) < 0) {
  252. free(name);
  253. return nil;
  254. }
  255. snprint(name, l, "%s/ctl", dev);
  256. if((ctlfd = open(name, ORDWR)) < 0) {
  257. free(name);
  258. Error:
  259. close(rawfd);
  260. return nil;
  261. }
  262. free(name);
  263. n = readn(ctlfd, buf, sizeof buf);
  264. close(ctlfd);
  265. if(n <= 0)
  266. goto Error;
  267. if(strncmp(buf, "inquiry ", 8) != 0 || (p = strchr(buf, '\n')) == nil)
  268. goto Error;
  269. *p = '\0';
  270. if((p = strdup(buf+8)) == nil)
  271. goto Error;
  272. s = mallocz(sizeof(*s), 1);
  273. if(s == nil) {
  274. Error1:
  275. free(p);
  276. goto Error;
  277. }
  278. s->rawfd = rawfd;
  279. s->inquire = p;
  280. s->changetime = time(0);
  281. if(scsiready(s) < 0)
  282. goto Error1;
  283. return s;
  284. }
  285. void
  286. closescsi(Scsi *s)
  287. {
  288. close(s->rawfd);
  289. free(s->inquire);
  290. free(s);
  291. }