scsi.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. #include "all.h"
  2. #include "io.h"
  3. #include "mem.h"
  4. extern Scsiio buslogic(int, ISAConf*);
  5. extern Scsiio ncr53c8xxreset(int, ISAConf*);
  6. static struct {
  7. char* type;
  8. Scsiio (*reset)(int, ISAConf*);
  9. } scsictlr[] = {
  10. { "aha1542", buslogic, },
  11. { "buslogic", buslogic, },
  12. { "mylex", buslogic, }, /* the name 9load knows */
  13. { "ncr53c8xx", ncr53c8xxreset, },
  14. { 0, },
  15. };
  16. enum {
  17. Ninquiry = 255,
  18. Nsense = 255,
  19. CMDtest = 0x00,
  20. CMDreqsense = 0x03,
  21. CMDread6 = 0x08,
  22. CMDwrite6 = 0x0A,
  23. CMDinquiry = 0x12,
  24. CMDstart = 0x1B,
  25. CMDread10 = 0x28,
  26. CMDwrite10 = 0x2A,
  27. };
  28. typedef struct {
  29. ISAConf;
  30. Scsiio io;
  31. Target target[NTarget];
  32. } Ctlr;
  33. static Ctlr scsi[MaxScsi];
  34. static void
  35. cmd_stat(int, char*[])
  36. {
  37. Ctlr *ctlr;
  38. int ctlrno, targetno;
  39. Target *tp;
  40. for(ctlrno = 0; ctlrno < MaxScsi; ctlrno++){
  41. ctlr = &scsi[ctlrno];
  42. if(ctlr->io == 0)
  43. continue;
  44. for(targetno = 0; targetno < NTarget; targetno++){
  45. tp = &ctlr->target[targetno];
  46. if(tp->fflag == 0)
  47. continue;
  48. print("\t%d.%d work =%7W%7W%7W xfrs\n",
  49. ctlrno, targetno,
  50. tp->work+0, tp->work+1, tp->work+2);
  51. print("\t rate =%7W%7W%7W tBps\n",
  52. tp->rate+0, tp->rate+1, tp->rate+2);
  53. }
  54. }
  55. }
  56. void
  57. scsiinit(void)
  58. {
  59. Ctlr *ctlr;
  60. int ctlrno, n, targetno;
  61. Target *tp;
  62. for(ctlrno = 0; ctlrno < MaxScsi; ctlrno++){
  63. ctlr = &scsi[ctlrno];
  64. memset(ctlr, 0, sizeof(Ctlr));
  65. if(!isaconfig("scsi", ctlrno, ctlr))
  66. continue;
  67. for(n = 0; scsictlr[n].type; n++) {
  68. if(strcmp(scsictlr[n].type, ctlr->type))
  69. continue;
  70. if((ctlr->io = (*scsictlr[n].reset)(ctlrno, ctlr)) == 0)
  71. break;
  72. print("scsi#%d: %s: port 0x%lux irq %lud",
  73. ctlrno, ctlr->type, ctlr->port,
  74. ctlr->irq);
  75. if(ctlr->mem)
  76. print(" addr 0x%lux", ctlr->mem & ~KZERO);
  77. if(ctlr->size)
  78. print(" size 0x%lux", ctlr->size);
  79. print("\n");
  80. for(targetno = 0; targetno < NTarget; targetno++){
  81. tp = &ctlr->target[targetno];
  82. qlock(tp);
  83. qunlock(tp);
  84. sprint(tp->id, "scsi#%d.%d", ctlrno, targetno);
  85. tp->name = tp->id;
  86. tp->ctlrno = ctlrno;
  87. tp->targetno = targetno;
  88. tp->inquiry = ialloc(Ninquiry, 0);
  89. tp->sense = ialloc(Nsense, 0);
  90. }
  91. break;
  92. }
  93. if(ctlr->io == 0)
  94. print("scsi#%d: %s: port %lux Failed to INIT controller\n",
  95. ctlrno, ctlr->type, ctlr->port);
  96. }
  97. cmd_install("statd", "-- scsi stats", cmd_stat);
  98. }
  99. static uchar lastcmd[16];
  100. static int lastcmdsz;
  101. static int
  102. scsiexec(Target* tp, int rw, uchar* cmd, int cbytes, void* data, int* dbytes)
  103. {
  104. int s;
  105. /*
  106. * Call the device-specific I/O routine.
  107. */
  108. switch(s = scsi[tp->ctlrno].io(tp, rw, cmd, cbytes, data, dbytes)){
  109. case STcheck:
  110. memmove(lastcmd, cmd, cbytes);
  111. lastcmdsz = cbytes;
  112. /*FALLTHROUGH*/
  113. default:
  114. /*
  115. * It's more complicated than this. There are conditions which
  116. * are 'ok' but for which the returned status code is not 'STok'.
  117. * Also, not all conditions require a reqsense, there may be a
  118. * need to do a reqsense here when necessary and making it
  119. * available to the caller somehow.
  120. *
  121. * Later.
  122. */
  123. break;
  124. }
  125. return s;
  126. }
  127. static int
  128. scsitest(Target* tp, char lun)
  129. {
  130. uchar cmd[6];
  131. memset(cmd, 0, sizeof(cmd));
  132. cmd[0] = CMDtest;
  133. cmd[1] = lun<<5;
  134. return scsiexec(tp, SCSIread, cmd, sizeof(cmd), 0, 0);
  135. }
  136. static int
  137. scsistart(Target* tp, char lun, int start)
  138. {
  139. uchar cmd[6];
  140. memset(cmd, 0, sizeof cmd);
  141. cmd[0] = CMDstart;
  142. cmd[1] = lun<<5;
  143. if(start)
  144. cmd[4] = 1;
  145. return scsiexec(tp, SCSIread, cmd, sizeof(cmd), 0, 0);
  146. }
  147. static int
  148. scsiinquiry(Target* tp, char lun, int* nbytes)
  149. {
  150. uchar cmd[6];
  151. memset(cmd, 0, sizeof cmd);
  152. cmd[0] = CMDinquiry;
  153. cmd[1] = lun<<5;
  154. *nbytes = Ninquiry;
  155. cmd[4] = *nbytes;
  156. return scsiexec(tp, SCSIread, cmd, sizeof(cmd), tp->inquiry, nbytes);
  157. }
  158. static char *key[] =
  159. {
  160. "no sense",
  161. "recovered error",
  162. "not ready",
  163. "medium error",
  164. "hardware error",
  165. "illegal request",
  166. "unit attention",
  167. "data protect",
  168. "blank check",
  169. "vendor specific",
  170. "copy aborted",
  171. "aborted command",
  172. "equal",
  173. "volume overflow",
  174. "miscompare",
  175. "reserved"
  176. };
  177. static int
  178. scsireqsense(Target* tp, char lun, int* nbytes, int quiet)
  179. {
  180. char *s;
  181. int n, status, try;
  182. uchar cmd[6], *sense;
  183. sense = tp->sense;
  184. for(try = 0; try < 20; try++) {
  185. memset(cmd, 0, sizeof(cmd));
  186. cmd[0] = CMDreqsense;
  187. cmd[1] = lun<<5;
  188. cmd[4] = Ninquiry;
  189. memset(sense, 0, Ninquiry);
  190. *nbytes = Ninquiry;
  191. status = scsiexec(tp, SCSIread, cmd, sizeof(cmd), sense, nbytes);
  192. if(status != STok)
  193. return status;
  194. *nbytes = sense[0x07]+8;
  195. switch(sense[2] & 0x0F){
  196. case 6: /* unit attention */
  197. /*
  198. * 0x28 - not ready to ready transition,
  199. * medium may have changed.
  200. * 0x29 - power on, RESET or BUS DEVICE RESET occurred.
  201. */
  202. if(sense[12] != 0x28 && sense[12] != 0x29)
  203. goto buggery;
  204. /*FALLTHROUGH*/
  205. case 0: /* no sense */
  206. case 1: /* recovered error */
  207. return STok;
  208. case 8: /* blank data */
  209. return STblank;
  210. case 2: /* not ready */
  211. if(sense[12] == 0x3A) /* medium not present */
  212. goto buggery;
  213. /*FALLTHROUGH*/
  214. default:
  215. /*
  216. * If unit is becoming ready, rather than not ready,
  217. * then wait a little then poke it again; should this
  218. * be here or in the caller?
  219. */
  220. if((sense[12] == 0x04 && sense[13] == 0x01)){
  221. waitsec(500);
  222. scsitest(tp, lun);
  223. break;
  224. }
  225. goto buggery;
  226. }
  227. }
  228. buggery:
  229. if(quiet == 0){
  230. s = key[sense[2]&0x0F];
  231. print("%s: reqsense: '%s' code #%2.2ux #%2.2ux\n",
  232. tp->id, s, sense[12], sense[13]);
  233. print("%s: byte 2: #%2.2ux, bytes 15-17: #%2.2ux #%2.2ux #%2.2ux\n",
  234. tp->id, sense[2], sense[15], sense[16], sense[17]);
  235. print("lastcmd (%d): ", lastcmdsz);
  236. for(n = 0; n < lastcmdsz; n++)
  237. print(" #%2.2ux", lastcmd[n]);
  238. print("\n");
  239. }
  240. return STcheck;
  241. }
  242. static Target*
  243. scsitarget(Device* d)
  244. {
  245. int ctlrno, targetno;
  246. ctlrno = d->wren.ctrl;
  247. if(ctlrno < 0 || ctlrno >= MaxScsi || scsi[ctlrno].io == 0)
  248. return 0;
  249. targetno = d->wren.targ;
  250. if(targetno < 0 || targetno >= NTarget)
  251. return 0;
  252. return &scsi[ctlrno].target[targetno];
  253. }
  254. static void
  255. scsiprobe(Device* d)
  256. {
  257. Target *tp;
  258. int nbytes, s;
  259. uchar *sense;
  260. int acount;
  261. if((tp = scsitarget(d)) == 0)
  262. panic("scsiprobe: device = %Z\n", d);
  263. acount = 0;
  264. again:
  265. s = scsitest(tp, d->wren.lun);
  266. if(s < STok){
  267. print("%s: test, status %d\n", tp->id, s);
  268. return;
  269. }
  270. /*
  271. * Determine if the drive exists and is not ready or
  272. * is simply not responding.
  273. * If the status is OK but the drive came back with a 'power on' or
  274. * 'reset' status, try the test again to make sure the drive is really
  275. * ready.
  276. * If the drive is not ready and requires intervention, try to spin it
  277. * up.
  278. */
  279. s = scsireqsense(tp, d->wren.lun, &nbytes, acount);
  280. sense = tp->sense;
  281. switch(s){
  282. case STok:
  283. if((sense[2] & 0x0F) == 0x06 && (sense[12] == 0x28 || sense[12] == 0x29)){
  284. if(acount == 0){
  285. acount = 1;
  286. goto again;
  287. }
  288. }
  289. break;
  290. case STcheck:
  291. if((sense[2] & 0x0F) == 0x02){
  292. if(sense[12] == 0x3A)
  293. break;
  294. if(sense[12] == 0x04 && sense[13] == 0x02){
  295. print("%s: starting...\n", tp->id);
  296. if(scsistart(tp, d->wren.lun, 1) == STok)
  297. break;
  298. s = scsireqsense(tp, d->wren.lun, &nbytes, 0);
  299. }
  300. }
  301. /*FALLTHROUGH*/
  302. default:
  303. print("%s: unavailable, status %d\n", tp->id, s);
  304. return;
  305. }
  306. /*
  307. * Inquire to find out what the device is.
  308. * Hardware drivers may need some of the info.
  309. */
  310. s = scsiinquiry(tp, d->wren.lun, &nbytes);
  311. if(s != STok) {
  312. print("%s: inquiry failed, status %d\n", tp->id, s);
  313. return;
  314. }
  315. print("%s: %s\n", tp->id, (char*)tp->inquiry+8);
  316. tp->ok = 1;
  317. }
  318. int
  319. scsiio(Device* d, int rw, uchar* cmd, int cbytes, void* data, int dbytes)
  320. {
  321. Target *tp;
  322. int e, nbytes, s;
  323. if((tp = scsitarget(d)) == 0)
  324. panic("scsiio: device = %Z\n", d);
  325. qlock(tp);
  326. if(tp->ok == 0)
  327. scsiprobe(d);
  328. if(tp->fflag == 0) {
  329. /* last args were 1000, now 1 */
  330. dofilter(tp->work+0, C0a, C0b, 1);
  331. dofilter(tp->work+1, C1a, C1b, 1);
  332. dofilter(tp->work+2, C2a, C2b, 1);
  333. /* */
  334. dofilter(tp->rate+0, C0a, C0b, 1);
  335. dofilter(tp->rate+1, C1a, C1b, 1);
  336. dofilter(tp->rate+2, C2a, C2b, 1);
  337. tp->fflag = 1;
  338. }
  339. tp->work[0].count++;
  340. tp->work[1].count++;
  341. tp->work[2].count++;
  342. tp->rate[0].count += dbytes;
  343. tp->rate[1].count += dbytes;
  344. tp->rate[2].count += dbytes;
  345. qunlock(tp);
  346. s = STinit;
  347. for(e = 0; e < 10; e++){
  348. for(;;){
  349. nbytes = dbytes;
  350. s = scsiexec(tp, rw, cmd, cbytes, data, &nbytes);
  351. if(s == STok)
  352. break;
  353. s = scsireqsense(tp, d->wren.lun, &nbytes, 0);
  354. if(s == STblank && rw == SCSIread) {
  355. memset(data, 0, dbytes);
  356. return STok;
  357. }
  358. if(s != STok)
  359. break;
  360. }
  361. if(s == STok)
  362. break;
  363. }
  364. if(e)
  365. print("%s: retry %d cmd #%x\n", tp->id, e, cmd[0]);
  366. return s;
  367. }