scsi.c 8.5 KB

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