|
|
1.1 root 1: /***********************************************************************
2: * Module: haiscsi.c
3: *
4: * This is the interface between the Coherent kernel, the host
5: * adapter module and the SCSI device modules. It's just a simple
6: * dispatcher that determines which routine to call based upon the
7: * calling device's Target ID. The target ID should be set in bits
8: * 4-6 of the device's minor number.
9: *
10: * Copyright (c) 1993, Christopher Sean Hilton, All Rights Reserved.
11: *
12: * Last Modified: Sat Jul 24 08:08:28 1993 by [chris]
13: */
14:
15: #include <stddef.h>
16: #include <sys/coherent.h>
17: #include <sys/con.h>
18: #include <sys/buf.h>
19: #include <sys/io.h>
20: #include <sys/sched.h>
21: #include <sys/stat.h>
22:
23: #include <sys/uproc.h>
24: #include <errno.h>
25:
26: #include <sys/haiscsi.h>
27: #include <sys/haiioctl.h>
28:
29: /*
30: * Constants.
31: */
32: #define GROUPMASK 0xe0
33: #define GROUP0 0x00 /* SCSI-1/2 */
34: #define GROUP1 0x20 /* SCSI-1/2 */
35: #define GROUP2 0x40 /* SCSI-2 */
36: #define GROUP5 0xa0 /* SCSI-1/2 */
37:
38: /* Configurable variables - see /etc/conf/hai/Space.c. */
39: extern int HAI_DISK;
40: extern int HAI_TAPE;
41:
42: extern int nonedev(); /* Set error and exit. */
43: extern int nulldev(); /* Do nothing and exit. */
44:
45: /*
46: * Device type entry points.
47: */
48: extern dca_t sddca; /* Fixed disk control routines */
49: extern dca_t ctdca; /* Cartridge tape control routines */
50: extern dca_t haict3600; /* Cartridge tape (Tandberg TDC3600) */
51:
52: dca_t mdca[MAXDEVS]; /* Initialized by setup_mdca(). */
53:
54: static void scsi_open(); /* Open dispatcher */
55: static void scsi_close(); /* Close dispatcher */
56: static void scsi_block(); /* Block dispatcher */
57: static void scsi_read(); /* Read dispatcher */
58: static void scsi_write(); /* Write dispatcher */
59: static void scsi_ioctl(); /* I/O Control dispatcher */
60: static int scsi_load(); /* Load driver */
61: static int scsi_unload(); /* Unload driver */
62:
63: static void setup_mdca(); /* Put device handlers into SCSI id table. */
64:
65: CON scsicon = {
66: DFBLK | DFCHR,
67: SCSIMAJOR,
68: scsi_open, /* Open entry point */
69: scsi_close, /* Close entry point */
70: scsi_block, /* Block entry point. */
71: scsi_read, /* Read Entry point */
72: scsi_write, /* write entry point */
73: scsi_ioctl, /* IO control entry point */
74: nulldev, /* No powerfail entry (yet?) */
75: hatimer, /* timeout entry point */
76: scsi_load, /* Load entry point */
77: scsi_unload, /* Unload entry point */
78: nulldev /* No poll entry yet either. */
79: };
80:
81: static char *errstr[] = {
82: "No sense",
83: "Recovered error",
84: "Not ready",
85: "Medium error",
86: "Hardware error",
87: "Illegal request",
88: "Unit attention",
89: "Data protect",
90: "Blank check",
91: "Vendor unique error",
92: "Copy Aborted",
93: "Aborted command",
94: "Equal",
95: "Volume overflow",
96: "Miscompare",
97: "Reserved"
98: };
99:
100: char iofailmsg[] = "%s: status(0x%x)";
101: int HAI_HAID = 7;
102:
103: extern int hapresent; /* Provided/Controled by host adapter module */
104: extern dca_p mdca[MAXDEVS]; /* See haicfg.c */
105:
106: /***********************************************************************
107: * int scsi_open(dev_t dev, int mode)
108: *
109: * Open a device on the SCSI bus at target ID: tid(dev). This is
110: * Accomplished by calling the open routine at mdca[tid(dev)]->d_open
111: */
112:
113: static void scsi_open(dev, mode)
114: register dev_t dev;
115: int mode;
116: {
117: register dca_p d = mdca[tid(dev)];
118:
119: if (!hapresent || !d)
120: u. u_error = EINVAL;
121: else
122: (*(d->d_open))(dev, mode);
123: } /* scsi_open() */
124:
125: /***********************************************************************
126: * void scsi_close()
127: *
128: * Close entry point for all devices at major index SCSIMAJOR.
129: */
130:
131: static void scsi_close(dev)
132: register dev_t dev;
133: {
134: register dca_p d = mdca[tid(dev)];
135:
136: if (!hapresent || !d)
137: u. u_error = EINVAL;
138: else
139: (*(d->d_close))(dev);
140: } /* scsi_close() */
141:
142: /***********************************************************************
143: * void scsi_block()
144: *
145: * Block Entry point.
146: */
147:
148: static void scsi_block(bp)
149: register BUF *bp;
150: {
151: register dca_p d = mdca[tid(bp->b_dev)];
152:
153: if (!hapresent || !d) {
154: bp->b_resid = bp->b_count;
155: bp->b_flag |= BFERR;
156: bdone(bp);
157: }
158: else
159: (*(d->d_block))(bp);
160: } /* scsi_block() */
161:
162: /***********************************************************************
163: * void scsi_read()
164: *
165: * Read entry point.
166: */
167:
168: void scsi_read(dev, iop)
169: register dev_t dev;
170: register IO *iop;
171: {
172: register dca_p d = mdca[tid(dev)];
173: if (!hapresent || !d)
174: u. u_error = EINVAL;
175: else
176: (*(d->d_read))(dev, iop);
177: } /* scsi_read() */
178:
179: /***********************************************************************
180: * int scsi_write()
181: *
182: * Write entry point.
183: */
184:
185: void scsi_write(dev, iop)
186: register dev_t dev;
187: IO *iop;
188: {
189: register dca_p d = mdca[tid(dev)];
190: if (!hapresent || !d)
191: u. u_error = EINVAL;
192: else
193: (*(d->d_write))(dev, iop);
194: } /* scsi_write() */
195:
196: /***********************************************************************
197: * scsi_ioctl()
198: *
199: * IO Control entry point.
200: */
201:
202: static void scsi_ioctl(dev, cmd, vec)
203: register dev_t dev;
204: int cmd;
205: char *vec;
206: {
207: register dca_p d = mdca[tid(dev)];
208:
209: if (!hapresent || !d)
210: u. u_error = EINVAL;
211: else
212: (*(d->d_ioctl))(dev, cmd, vec);
213: } /* scsi_ioctl() */
214:
215: /***********************************************************************
216: * scsi_load()
217: *
218: * Load Entry point.
219: */
220:
221: static int scsi_load()
222:
223: {
224: register int id;
225: register dca_p d;
226:
227: printf("Host Adapter Independent SCSI Driver v1.1\n");
228: hainit();
229: if (!hapresent)
230: printf("Host Adapter Initialization failed.\n");
231:
232: setup_mdca();
233:
234: for (id = 0; id < MAXDEVS; ++id) {
235: if ((d = mdca[id]) && d->d_load) {
236: printf("ID %d: ", id);
237: if (!(*(d->d_load))(id))
238: printf("\tLoad() failed.\n");
239: }
240: }
241: return;
242: } /* scsi_load() */
243:
244: /***********************************************************************
245: * scsi_unload()
246: *
247: * SCSI unload routine.
248: */
249:
250: int scsi_unload()
251:
252: {
253: register int id;
254: register dca_p d;
255:
256: for (id = 0; id < MAXDEVS; ++id)
257: if ((d = mdca[id]) && d->d_unload)
258: (*(d->d_unload))(id);
259: } /* scsi_unload() */
260:
261: /***********************************************************************
262: * Utility Routines
263: */
264:
265: /***********************************************************************
266: * char *swapbytes()
267: *
268: * Swap bytes in an object from big to little endian or vice versa.
269: */
270:
271: char *swapbytes(mem, size)
272: char *mem;
273: size_t size;
274:
275: {
276: register char *p = mem;
277: register char *q = p + size - 1;
278:
279: while (q > p) {
280: *p ^= *q;
281: *q ^= *p;
282: *p ^= *q;
283: p++;
284: q--;
285: }
286: return mem;
287: } /* swapbytes() */
288:
289: /***********************************************************************
290: * cpycdb()
291: *
292: * Copy a SCSI Command/Data Block. Return the number of bytes copied.
293: */
294:
295: int cpycdb(dst, src)
296: register cdb_p dst;
297: register cdb_p src;
298: {
299: switch (src->g0. opcode & GROUPMASK) {
300: case GROUP0:
301: memcpy(dst, src, sizeof(g0cmd_t));
302: return sizeof(g0cmd_t);
303: case GROUP1:
304: case GROUP2:
305: memcpy(dst, src, sizeof(g1cmd_t));
306: return sizeof(g1cmd_t);
307: case GROUP5:
308: memcpy(dst, src, sizeof(g5cmd_t));
309: return sizeof(g5cmd_t);
310: default:
311: return 0;
312: }
313: } /* cpycdb() */
314:
315: /***********************************************************************
316: * dumpmem()
317: *
318: * Dump memory from (p) for (s) bytes.
319: */
320:
321: static char hexchars[] = "0123456789abcdef",
322: linebuf[] = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................\n";
323:
324: void dumpmem(m, p, s)
325: char m[];
326: register unsigned char *p;
327: register size_t s;
328: {
329: register int i;
330: char *l;
331:
332: if (m)
333: printf(m);
334: printf(" (0x%x)\n", (unsigned) p);
335: memset(linebuf, ' ', sizeof(linebuf) - 2);
336: linebuf[48] = '|';
337: l = linebuf;
338: for (i = 0; i < s; ++i, ++p) {
339: *l++ = hexchars[(*p >> 4) & 0x0f];
340: *l++ = hexchars[*p & 0x0f];
341: *l++ = ' ';
342: linebuf[50 + (i & 15)] = (*p >= ' ' && *p <= '~') ? *p : '.';
343: if ((i & 15) == 15) {
344: printf(linebuf);
345: memset(linebuf, ' ', sizeof(linebuf) - 2);
346: linebuf[48] = '|';
347: l = linebuf;
348: }
349: }
350: if ((s & 15) != 0)
351: printf(linebuf);
352: } /* dumpmem() */
353:
354: /***********************************************************************
355: * scsidone()
356: *
357: * Wake up processes sleeping on SRB (r).
358: */
359:
360: static int scsidone(r)
361: register srb_p r;
362: {
363: wakeup(&(r->status));
364: }
365:
366: /***********************************************************************
367: * reqsense()
368: *
369: * Issue a request sense command device loaded into the target/lun
370: * fields of the given srb r. Uses v_sleep().
371: */
372:
373: void reqsense(r)
374: register srb_p r;
375: {
376: int s;
377: unsigned short status;
378: unsigned short tries;
379: unsigned short timeout;
380: bufaddr_t buf;
381: unsigned short xferdir;
382: int (*cleanup)();
383: cdb_t cdb;
384:
385: if (r->status == ST_CHKCOND) {
386: status = ST_CHKCOND;
387: tries = r->tries;
388: timeout = r->timeout;
389: memcpy(&buf, &(r->buf), sizeof(bufaddr_t));
390: xferdir = r->xferdir;
391: cleanup = r->cleanup;
392: memcpy(&cdb, &(r->cdb), sizeof(cdb_t));
393:
394: r->timeout = 4;
395: r->buf. space = KRNL_ADDR;
396: r->buf. addr. caddr = (caddr_t) r->sensebuf;
397: r->buf. size = sizeof(r->sensebuf);
398: r->xferdir = DMAREAD;
399: r->cleanup = &scsidone;
400: memset(&(r->cdb), 0, sizeof(cdb_t));
401: r->cdb. g0. opcode = 0x03;
402: r->cdb. g0. lun_lba = (r->lun << 5);
403: r->cdb. g0. xfr_len = r->buf. size;
404: s = sphi();
405: startscsi(r);
406: while (r->status == ST_PENDING) {
407: if (x_sleep(&(r->status), pritape, slpriSigCatch, "reqsense")) {
408: u. u_error = EINTR;
409: status = ST_USRABRT;
410: break;
411: }
412: }
413: spl(s);
414:
415: r->tries = tries;
416: r->timeout = timeout;
417: memcpy(&(r->buf), &buf, sizeof(bufaddr_t));
418: r->xferdir = xferdir;
419: r->cleanup = cleanup;
420: memcpy(&(r->cdb), &(cdb), sizeof(cdb_t));
421: r->status = status;
422: }
423: } /* reqsense() */
424:
425: /***********************************************************************
426: * doscsi()
427: *
428: * An alternative to startscsi() which handles everything including
429: * any request sense commands necessary if the command failed. All
430: * information is returned in given srb. Note: you can only use
431: * this routine when the u structure for a process is available (from
432: * an open, close, read, write, or ioctl routine). Since this calls
433: * sleep it will screw things up something fierce if you call it from
434: * a load, unload, block, timer or interrupt routine. Also note
435: * that some host adapters do the sense part this automatically.
436: */
437:
438: void doscsi(r, retrylimit, schedPri, sleepPri, reason)
439: register srb_p r;
440: int retrylimit;
441: int schedPri;
442: int sleepPri;
443: char reason[];
444: {
445: int s;
446:
447: r->cleanup = &scsidone;
448: for (r->tries = 0; r->tries < retrylimit; ) {
449: if (startscsi(r)) {
450: s = sphi();
451: while (r->status == ST_PENDING) {
452: if (x_sleep(&(r->status), schedPri, sleepPri, reason)) {
453: abortscsi(r);
454: r->status = ST_USRABRT;
455: u. u_error = EINTR;
456: }
457: }
458: spl(s);
459: if (r->status == ST_GOOD)
460: return;
461:
462: if (r->status == ST_CHKCOND)
463: reqsense(r);
464: }
465: else
466: r->status = ST_TIMEOUT;
467: }
468: } /* doscsi() */
469:
470: /***********************************************************************
471: * printsense()
472: *
473: * Print out the results in the given sense buffer. This is done
474: * in English, almost.
475: */
476:
477: void printsense(dev, msg, e)
478: register dev_t dev;
479: register char *msg;
480: register extsense_p e;
481: {
482: long info;
483: if ((e->errorcode & 0x70) != 0x70)
484: devmsg(dev, "%s: Bad sensekey", msg);
485: else {
486: if ((e->errorcode & 0x80) != 0x80)
487: devmsg(dev,
488: "%s: %s - key: (0x%x)",
489: msg,
490: errstr[e->sensekey & 0x0f],
491: (e->sensekey & 0xe0));
492: else {
493: info = (long) e->info;
494: flip(info);
495: devmsg(dev,
496: "%s: %s - addr: %d key: (0x%x)",
497: msg,
498: errstr[e->sensekey & 0x0f],
499: info,
500: (e->sensekey & 0xe0));
501: }
502: }
503: } /* printsense() */
504:
505: /***********************************************************************
506: * printerror()
507: *
508: * Print an error after command completion. Be silent if the command
509: * was aborted by the user.
510: */
511:
512: int printerror(r, msg)
513: register srb_p r;
514: register char *msg;
515: {
516: if (r->status == ST_USRABRT)
517: return 0;
518: else {
519: if (r->status != ST_CHKCOND)
520: devmsg(r->dev, iofailmsg, msg, r->status);
521: else
522: printsense(r->dev, msg, r->sensebuf);
523: return 1;
524: }
525: } /* printerror() */
526:
527: /***********************************************************************
528: * haiioctl() -- I/O Controls common to all devices.
529: *
530: * This function provides I/O Control functions common to all SCSI
531: * devices. The chain of operation should be as follows:
532: *
533: * You:
534: * 1) Make sure that the device is in an appropriate state to
535: * perform the I/O Control. (It might not be a good idea to
536: * format the disk drive with the root partition).
537: *
538: * 2) Call haiioctl() with your srb and cmd from I/O Control.
539: */
540:
541: void haiioctl(r, cmd, vec)
542: register srb_p r; /* Device's srb */
543: register int cmd; /* Command to do */
544: register char *vec; /* Additional information (if needed) */
545: {
546: haiusercdb_t h;
547:
548: switch (cmd) {
549: case HAIINQUIRY:
550: case HAIMDSNS0:
551: case HAIMDSLCT0:
552: case HAIMDSNS2:
553: case HAIMDSLCT2:
554: u. u_error = ENXIO;
555: return;
556: case HAIUSERCDB:
557: if (super()) {
558: if (!ukcopy(vec, &h, sizeof(haiusercdb_t)))
559: return;
560: r->buf. space = USER_ADDR;
561: r->buf. addr. caddr = vec + sizeof(haiusercdb_t);
562: r->buf. size = h. buflen;
563: r->xferdir = h. xferdir;
564: r->timeout = h. timeout;
565: memcpy(&(r->cdb), &(h. cdb), sizeof(cdb_t));
566: doscsi(r, 1, pritty, slpriSigCatch, "haiioctl");
567: if (!kucopy(r->sensebuf, ((haiusercdb_p) vec)->sensebuf, SENSELEN))
568: return;
569: }
570: return;
571: default:
572: u. u_error = ENXIO;
573: return;
574: }
575: return;
576: } /* haiioctl() */
577:
578: /***********************************************************************
579: * hainonblk() -- Block entry point for devices that shouldn't
580: * have block entry points.
581: *
582: * Since this is a multiplexing driver and some devices behind it
583: * will have block entry points and some shouldn't. ALL do.
584: */
585:
586: void hainonblk(bp)
587: register BUF *bp;
588: {
589: bp->b_flag |= BFERR;
590: bdone(bp);
591: } /* hainonblk() */
592:
593: /*
594: * setup_mdca
595: *
596: * Load mdca table based on globals HAI_DISK and HAI_TAPE.
597: */
598: void
599: setup_mdca()
600: {
601: int id, mask;
602: extern dca_t sddca;
603: extern dca_t ctdca;
604:
605: for (id = 0; id < 8; id ++) {
606: mask = 1 << id;
607: if (HAI_DISK & mask)
608: mdca[id] = & sddca;
609: if (HAI_TAPE & mask)
610: mdca[id] = & ctdca;
611: }
612: }
613:
614: /* End of file */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.