|
|
1.1 root 1: /***********************************************************************
2: * Module: haisd.c
3: *
4: * Unix device driver functions for accessing SCSI hard drives as
5: * block devices. Conforms to Mark Williams Coherent definition of
6: * the Unix Device Driver interface.
7: *
8: * Copyright (c) 1993, Christopher Sean Hilton. All rights reserved.
9: *
10: * Last Modified: Mon Jul 26 17:16:43 1993 by [chris]
11: *
12: * This code assumes BSIZE == (1 << 9).
13: *
14: * $Id: haisd.c,v 2.3 93/08/09 13:45:26 bin Exp Locker: bin $
15: *
16: * $Log: haisd.c,v $
17: * Revision 2.3 93/08/09 13:45:26 bin
18: * Kernel 82 changes
19: *
20: */
21:
22: #include <stddef.h>
23: #include <sys/fdisk.h>
24: #include <sys/coherent.h>
25: #include <sys/buf.h>
26: #include <sys/inode.h>
27: #include <sys/stat.h>
28: #include <sys/sched.h>
29: #include <sys/sdioctl.h> /* This is not the Coherent sdioctl.h */
30: #include <sys/hdioctl.h> /* All this is to make fdisk work... */
31: #include <errno.h>
32:
33: #include <sys/haiscsi.h>
34:
35: #define REMOVABLE_MEDIA 0 /* Support Removable media? */
36:
37: #define INQBUFSZ 64
38:
39: #define SDIDLE 0
40: #define SDINIT 1
41: #define SDIO 2
42: #define SDSENSE 3
43: #define SDIOCTL 4
44:
45: #define INQUIRY 0x12
46: #define GETCAPACITY 0x25
47: #define REQSENSE 0x03
48: #define G1READ 0x28
49: #define G1WRITE 0x2a
50:
51: typedef struct partlim_s *partlim_p;
52:
53: typedef struct partlim_s {
54: unsigned long base; /* base of the partition (blocks) */
55: unsigned long size; /* size of the partition (blocks) */
56: } partlim_t;
57:
58: typedef struct sdctrl_s *sdctrl_p;
59:
60: typedef struct sdctrl_s {
61: unsigned short state;
62: unsigned short lastclose;
63: BUF *actf,
64: *actl;
65: srb_t srb;
66: partlim_t plim[1 + 4]; /* special device (1) + all partitions (4) */
67: BUF buf;
68: } sdctrl_t;
69:
70: static int sdload(); /* Initialize a SCSI device at (id) */
71: static void sdopen(); /* Open SCSI DASD at (dev) */
72: static void sdclose(); /* Close SCSI DASD at (dev) */
73: static void sdblock(); /* Block Entry Point */
74: static void sdread(); /* Read SCSI DASD at (dev) */
75: static void sdwrite(); /* Write SCSI DASD at (dev) */
76: static void sdioctl(); /* I/O Control for DASD. */
77:
78: extern int nulldev();
79: extern int nonedev();
80:
81: static void sdstart();
82: static void sdfinish();
83:
84: #define partindex(d) ((((d) & (SPECIAL | PARTMASK)) == 0x80) ? 0 : ((d) & PARTMASK) + 1)
85:
86: dca_t sddca = {
87: sdopen, /* Open */
88: sdclose, /* Close */
89: sdblock, /* Block */
90: sdread, /* Read */
91: sdwrite, /* Write */
92: sdioctl, /* Ioctl */
93: sdload, /* Load */
94: nulldev, /* Unload */
95: nulldev /* Poll */
96: };
97:
98: #if REMOVABLE_MEDIA
99: static int rmsdload(); /* Removable Media Disks */
100:
101: dca_t rmsddca = {
102: sdopen, /* Open */
103: sdclose, /* Close */
104: sdblock, /* Block */
105: sdread, /* Read */
106: sdwrite, /* Write */
107: sdioctl, /* Ioctl */
108: rmsdload, /* Load */
109: nulldev, /* Unload */
110: nulldev /* Poll */
111: };
112: #endif
113:
114: static sdctrl_p sddevs[MAXDEVS];
115:
116: /***********************************************************************
117: * sdload()
118: *
119: * Start up a DASD device at (id).
120: *
121: * 1) Make sure that it's a disk drive and that we can support it.
122: * 2) Get its size and blocksize to make sure that we can use it.
123: * 3) Set up a control structure for it.
124: */
125:
126: static int sdload(id)
127: register int id;
128: {
129: register sdctrl_p c;
130: register srb_p r;
131: int timeout;
132: char inqbuf[INQBUFSZ];
133: long diskcap[2];
134:
135: _CHIRP('Q', 143);
136: c = kalloc(sizeof(sdctrl_t));
137: if (!c) {
138: printf("\tout of memory in sdload(): ");
139: return 0;
140: }
141:
142: memset(c, 0, sizeof(sdctrl_t));
143: c->state = SDINIT;
144: r = &(c->srb);
145: r->dev = makedev(SCSIMAJOR, SPECIAL | (id << 4));
146: r->target = id;
147: r->lun = 0;
148: r->timeout = 0;
149: r->cleanup = NULL;
150: r->xferdir = DMAREAD;
151:
152: /* Request Sense to clear reset condition. */
153: r->buf. space = KRNL_ADDR;
154: r->buf. addr. caddr = (caddr_t) r->sensebuf;
155: r->buf. size = sizeof(r->sensebuf);
156: memset(&(r->cdb), 0, sizeof(cdb_t));
157: r->cdb. g0. opcode = REQSENSE;
158: r->cdb. g0. xfr_len = sizeof(r->sensebuf);
159: startscsi(r);
160: timeout = 1000000L;
161: while (r->status == ST_PENDING && --timeout > 0L)
162: ;
163:
164: if (r->status != ST_GOOD) {
165: printf("\tRequest sense failed: status (0x%x)\n", r->status);
166: kfree(c);
167: return 0;
168: }
169:
170: /* Inquiry to make sure that this is a disk drive */
171: r->buf. space = KRNL_ADDR;
172: r->buf. addr. caddr = (caddr_t) inqbuf;
173: r->buf. size = sizeof(inqbuf);
174: memset(&(r->cdb), 0, sizeof(cdb_t));
175: r->cdb. g0. opcode = INQUIRY;
176: r->cdb. g0. xfr_len = sizeof(inqbuf);
177: startscsi(r);
178: timeout = 1000000L;
179: while (r->status == ST_PENDING && --timeout > 0L)
180: ;
181:
182: if (r->status != ST_GOOD) {
183: printf("\tInquiry failed status: (0x%x)\n", r->status);
184: kfree(c);
185: return 0;
186: }
187: if (inqbuf[0] != 0) {
188: printf("\tDevice type byte: (0x%x) - not a DASD\n", inqbuf[0]);
189: kfree(c);
190: return 0;
191: }
192: else if (inqbuf[1] & 0x80) {
193: printf("\tRemovable Media Not supported yet.\n");
194: kfree(c);
195: return 0;
196: }
197:
198: /* Get Capacity to set up the drive for use */
199: r->buf. space = KRNL_ADDR;
200: r->buf. addr. caddr = (caddr_t) diskcap;
201: r->buf. size = sizeof(diskcap);
202: diskcap[0] = diskcap[1] = 0;
203: memset(&r->cdb, 0, sizeof(cdb_t));
204: r->cdb. g1. opcode = GETCAPACITY;
205: startscsi(r);
206: timeout = 1000000L;
207: while (r->status == ST_PENDING && --timeout > 0L)
208: ;
209:
210: if (r->status != ST_GOOD) {
211: printf("\tGet Capacity Failed: 0x%x\n", r->status);
212: kfree(c);
213: return 0;
214: }
215: flip(diskcap[0]);
216: flip(diskcap[1]);
217: if (diskcap[1] != BSIZE) {
218: printf("\tInvalid Block Size %d Reformat with %d Bytes/Block\n", diskcap[1], BSIZE);
219: kfree(c);
220: return 0;
221: }
222:
223: inqbuf[36] = '\0';
224: printf("\t%s %d MB\n", (inqbuf + 8), (diskcap[0] + bit(10)) >> 11);
225: sddevs[id] = c;
226: sddevs[id]->state = SDIDLE;
227: sddevs[id]->plim[0]. base = 0;
228: sddevs[id]->plim[0]. size = diskcap[0];
229: sddevs[id]->actf = sddevs[id]->actl = NULL;
230: return 1;
231: } /* sdload() */
232:
233: #if REMOVABLE_MEDIA
234: static int rmsdload(id)
235: register int id;
236: {
237: register sdctrl_p c;
238: register srb_p r;
239: int timeout;
240: long diskcap[2];
241:
242: c = kalloc(sizeof(sdctrl_t));
243: if (!c) {
244: printf("\tout of memory in rmsdload(): ");
245: return 0;
246: }
247:
248: memset(c, 0, sizeof(sdctrl_t));
249: c->state = SDINIT;
250: r = &(c->srb);
251: r->dev = makedev(SCSIMAJOR, SPECIAL | (id << 4));
252: r->target = id;
253: r->lun = 0;
254: r->timeout = 0;
255: r->cleanup = NULL;
256: r->xferdir = DMAREAD;
257:
258: /* Request Sense to clear reset condition. */
259: r->buf. space = KRNL_ADDR;
260: r->buf. addr. caddr = (caddr_t) r->sensebuf;
261: r->buf. size = sizeof(r->sensebuf);
262: memset(&(r->cdb), 0, sizeof(cdb_t));
263: r->cdb. g0. opcode = REQSENSE;
264: r->cdb. g0. xfr_len = sizeof(r->sensebuf);
265: startscsi(r);
266: timeout = 1000000L;
267: while (r->status == ST_PENDING && --timeout > 0L)
268: ;
269:
270: if (r->status != ST_GOOD) {
271: printf("\tRequest sense failed: status (0x%x)\n", r->status);
272: kfree(c);
273: return 0;
274: }
275:
276: /* Inquiry to make sure that this is a disk drive */
277: r->buf. space = KRNL_ADDR;
278: r->buf. addr. caddr = (caddr_t) c->inqbuf;
279: r->buf. size = sizeof(c->inqbuf);
280: memset(&(r->cdb), 0, sizeof(cdb_t));
281: r->cdb. g0. opcode = INQUIRY;
282: r->cdb. g0. xfr_len = sizeof(c->inqbuf);
283: startscsi(r);
284: timeout = 1000000L;
285: while (r->status == ST_PENDING && --timeout > 0L)
286: ;
287:
288: if (r->status != ST_GOOD) {
289: printf("\tInquiry failed status: (0x%x)\n", r->status);
290: kfree(c);
291: return 0;
292: }
293: if (c->inqbuf[0] != 0) {
294: printf("\tDevice type byte: (0x%x) - not a DASD\n", c->inqbuf[0]);
295: kfree(c);
296: return 0;
297: }
298: else if ((c->inqbuf[1] & 0x80) == 0)
299: printf("\tConfiguration error ID %d is fixed media.\n", id);
300:
301: /* Get Capacity to set up the drive for use */
302: r->buf. space = KRNL_ADDR;
303: r->buf. addr. caddr = (caddr_t) diskcap;
304: r->buf. size = sizeof(diskcap);
305: diskcap[0] = diskcap[1] = 0;
306: memset(&r->cdb, 0, sizeof(cdb_t));
307: r->cdb. g1. opcode = GETCAPACITY;
308: startscsi(r);
309: timeout = 1000000L;
310: while (r->status == ST_PENDING && --timeout > 0L)
311: ;
312:
313: if (r->status != ST_GOOD) {
314: printf("\tGet Capacity Failed: 0x%x\n", r->status);
315: kfree(c);
316: return 0;
317: }
318: flip(diskcap[0]);
319: flip(diskcap[1]);
320: printf("Get Capacity results count: %d, size %d\n", diskcap[0], diskcap[1]);
321: /* if (diskcap[1] != BSIZE) {
322: printf("\tInvalid Block Size %d Reformat with %d Bytes/Block\n", diskcap[1], BSIZE);
323: kfree(c);
324: return 0;
325: }
326: */
327: c->inqbuf[36] = '\0';
328: printf("\t%s %d MB\n", (c->inqbuf + 8), (diskcap[0] + bit(10)) >> 11);
329: sddevs[id] = c;
330: sddevs[id]->state = SDIDLE;
331: sddevs[id]->plim[0]. base = 0;
332: sddevs[id]->plim[0]. size = diskcap[0];
333: sddevs[id]->actf = sddevs[id]->actl = NULL;
334: return 1;
335: } /* rmsdload() */
336: #endif
337:
338: #if 0
339: /***********************************************************************
340: * sdunload()
341: *
342: * Unload routine. Right now unused so ifdefed out.
343: */
344:
345: static void sdunload(id)
346: register int id;
347: {
348: if (sddevs[id]) {
349: kfree(sddevs[id]);
350: sddevs[id] = NULL;
351: }
352: } /* sdunload() */
353: #endif
354:
355: /***********************************************************************
356: * loadptable()
357: *
358: * Read the master boot record from the Fixed disk and set the block
359: * limits on the individual partition devices. Wouldn't it be nice if
360: * there were more than four partition slots available?!
361: */
362:
363: static int loadptable(dev)
364: register dev_t dev;
365: {
366: struct fdisk_s fp[4];
367: register sdctrl_p c;
368: register int i;
369:
370: if (!partindex(dev))
371: return 0;
372:
373: if (fdisk(makedev(major(dev), (minor(dev) & ~PARTMASK) | SPECIAL), fp)) {
374: for (c = sddevs[tid(dev)], i = 1; i < 5; ++i) {
375: c->plim[i]. base = fp[i-1]. p_base;
376: c->plim[i]. size = fp[i-1]. p_size;
377: }
378: return 1;
379: }
380: else {
381: printf("fdisk failed\n");
382: return -1;
383: }
384: } /* loadptable() */
385:
386: /***********************************************************************
387: * sdopen()
388: *
389: * Open Entry point for SCSI DASD devices.
390: */
391:
392: static void sdopen(dev /*, mode */)
393: dev_t dev;
394: /* int mode; */
395: {
396: register sdctrl_p c;
397:
398: c = sddevs[tid(dev)];
399: if (!c || loadptable(dev) == -1) {
400: u. u_error = ENXIO;
401: return;
402: }
403: ++c->lastclose;
404: return;
405: } /* sdopen() */
406:
407: /***********************************************************************
408: * sdclose()
409: *
410: * Close the SCSI DASD device at dev.
411: */
412:
413: static void sdclose(dev)
414: dev_t dev;
415: {
416: register sdctrl_p c;
417:
418: c = sddevs[tid(dev)];
419: if (!c)
420: u. u_error = ENXIO;
421: else if (c->lastclose)
422: --c->lastclose;
423: } /* sdclose() */
424:
425: /***********************************************************************
426: * sdfinish()
427: *
428: * Finish up a fixed disk srb.
429: */
430:
431: static void sdfinish(r)
432: register srb_p r;
433: {
434: register sdctrl_p c;
435: register BUF *bp;
436: extsense_p e;
437:
438: c = sddevs[r->target];
439: bp = c->actf;
440: switch (c->state) {
441: case SDIO:
442: switch (r->status) {
443: case ST_GOOD:
444: bp->b_resid = bp->b_count - r->buf. size;
445: break;
446: case ST_CHKCOND:
447: r->timeout = 4;
448: r->buf. space = KRNL_ADDR;
449: r->buf. addr. caddr = (caddr_t) r->sensebuf;
450: r->buf. size = sizeof(r->sensebuf);
451: r->xferdir = DMAREAD;
452: memset(&(r->cdb), 0, sizeof(cdb_t));
453: r->cdb. g0. opcode = REQSENSE;
454: r->cdb. g0. lun_lba = (r->lun << 5);
455: r->cdb. g0. xfr_len = r->buf. size;
456: if (startscsi(r))
457: c->state = SDSENSE;
458: return;
459: default:
460: devmsg(r->dev,
461: "%s failed at block %d: status (0x%x)",
462: (bp->b_req == BREAD) ? "Read" : "Write",
463: bp->b_bno,
464: r->status);
465: bp->b_resid = bp->b_count;
466: bp->b_flag |= BFERR;
467: break;
468: }
469: break;
470: case SDSENSE:
471: if (r->status != ST_GOOD)
472: devmsg(r->dev, "%s sense failed at block %d",
473: (bp->b_req == BREAD) ? "Read" : "Write",
474: bp->b_bno);
475: else {
476: e = r->sensebuf;
477: printsense(r->dev,
478: (bp->b_req == BREAD) ? "Read failed" : "Write failed",
479: e);
480: if ((e->errorcode & 0x70) == 0x70 && (e->sensekey & 0x0f) == 0x01)
481: bp->b_resid = bp->b_count - r->buf. size;
482: else {
483: bp->b_resid = bp->b_count;
484: bp->b_flag |= BFERR;
485: }
486: }
487: break;
488: default:
489: bp->b_resid = bp->b_count;
490: bp->b_flag |= BFERR;
491: break;
492: }
493: c->actf = c->actf->b_actf;
494: bdone(bp);
495: c->state = SDIDLE;
496: sdstart(c);
497: return;
498: } /* sdfinish() */
499:
500: /***********************************************************************
501: * sdstart()
502: *
503: * Start/restart the Fixed disk request queue.
504: */
505:
506: static void sdstart(c)
507: sdctrl_p c;
508: {
509: register BUF *bp;
510: register g1cmd_p g1;
511: register srb_p r = &(c->srb);
512: unsigned long blkcnt;
513: int i;
514:
515: if (!(bp = c->actf) || c->state != SDIDLE)
516: return;
517:
518: i = partindex(bp->b_dev);
519: blkcnt = bp->b_count >> 9;
520: if (bp->b_bno + blkcnt > c->plim[i]. size)
521: blkcnt = c->plim[i]. size - bp->b_bno;
522:
523: r->dev = bp->b_dev;
524: r->target = tid(bp->b_dev);
525: r->lun = lun(bp->b_dev);
526: r->timeout = 4;
527: r->buf. space = SYSGLBL_ADDR;
528: r->buf. addr. paddr = bp->b_paddr;
529: r->buf. size = (blkcnt << 9);
530: r->xferdir = (bp->b_req == BREAD) ? DMAREAD : DMAWRITE;
531: r->cleanup = &sdfinish;
532: g1 = &(r->cdb. g1);
533: memset(g1, 0, sizeof(cdb_t));
534: g1->opcode = (bp->b_req == BREAD) ? G1READ : G1WRITE;
535: g1->lun = (r->lun << 5);
536: g1->lba = c->plim[i]. base + bp->b_bno;
537: flip(g1->lba);
538: g1->xfr_len = blkcnt;
539: flip(g1->xfr_len);
540: if (startscsi(r))
541: c->state = SDIO;
542: } /* sdstart() */
543:
544: /***********************************************************************
545: * sdblock()
546: *
547: * Block/strategy entry point for SCSI fixed disks.
548: */
549:
550: static void sdblock(bp)
551: register BUF *bp;
552: {
553: int i, s;
554: register sdctrl_p c;
555:
556: c = sddevs[tid(bp->b_dev)];
557: i = partindex(bp->b_dev);
558:
559: bp->b_resid = bp->b_count;
560: if (bp->b_bno > c->plim[i]. size || (bp->b_count & (BSIZE-1)) != 0) {
561: bp->b_flag |= BFERR;
562: bdone(bp);
563: return;
564: }
565:
566: if (bp->b_bno == c->plim[i]. size) {
567: if (bp->b_req != BREAD)
568: bp->b_flag |= BFERR;
569: bdone(bp);
570: return;
571: }
572:
573: s = sphi();
574: bp->b_actf = NULL;
575: if (!c->actf)
576: c->actf = bp;
577: else
578: c->actl->b_actf = bp;
579: c->actl = bp;
580: while (c->state == SDIDLE && c->actf)
581: sdstart(c);
582: spl(s);
583: } /* sdblock() */
584:
585: /***********************************************************************
586: * sdread()
587: *
588: * Read entry point for SCSI DASD devices.
589: */
590:
591: static void sdread(dev, iop)
592: dev_t dev;
593: register IO *iop;
594: {
595: register sdctrl_p c;
596:
597: c = sddevs[tid(dev)];
598: ioreq(&(c->buf), iop, dev, BREAD, BFIOC | BFRAW);
599: } /* sdread() */
600:
601: /***********************************************************************
602: * sdwrite()
603: *
604: * Write entry point for SCSI DASD devices.
605: */
606:
607: static void sdwrite(dev, iop)
608: dev_t dev;
609: register IO *iop;
610: {
611: register sdctrl_p c;
612:
613: c = sddevs[tid(dev)];
614: ioreq(&(c->buf), iop, dev, BWRITE, BFIOC | BFRAW);
615: } /* sdwrite() */
616:
617: /***********************************************************************
618: * sdioctl()
619: *
620: * I/O Control for DASD's right now. The options here are for the
621: * self configuring SCSI kernel.
622: */
623:
624: static void sdioctl(dev, cmd, vec)
625: register dev_t dev;
626: register int cmd;
627: char *vec;
628: {
629: register sdctrl_p c = sddevs[tid(dev)];
630: int s;
631: hdparm_t hdp;
632:
633: switch (cmd) {
634: case HDGETA:
635: haihdgeta(&hdp, c->plim[0]. size);
636: kucopy(&hdp, vec, sizeof(hdparm_t));
637: break;
638: case HDSETA:
639: if (ukcopy(vec, &hdp, sizeof(hdparm_t)))
640: haihdseta(&hdp);
641: break;
642: default:
643: if (c->lastclose > 1) {
644: u. u_error = EACCES; /* Only one open on this device */
645: return;
646: }
647:
648: s = sphi();
649: while (c->state != SDIDLE)
650: /* Where is the wakeup for this sleep? */
651: if (x_sleep(&(c->state), pridisk, slpriSigCatch, "sdioctl")) {
652: u. u_error = EINTR;
653: return;
654: }
655: c->state = SDIOCTL;
656: haiioctl(&(c->srb), cmd, vec);
657: c->state = SDIDLE;
658: spl(s);
659: break;
660: }
661: } /* sdioctl() */
662:
663: /* End of file */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.