|
|
1.1 root 1: /*
2: * This is the generic SCSI part of the
3: * Adaptec AHA154x host adapter driver for the AT.
4: *
5: * $Log: scsi.c,v $
6: * Revision 1.2 92/08/04 12:54:20 bin
7: * upd for ker59
8: *
9: * Revision 1.10 92/01/17 11:38:37 bin
10: * update by hal... looks like final 321 version
11: *
12: * Revision 1.10 92/01/17 03:51:13 hal
13: * Cleanup for 3.2.1.
14: *
15: * Revision 1.9 91/11/11 12:32:58 hal
16: * Get SD_HDS and SD_SPT from tboot.
17: *
18: * Revision 1.8 91/10/25 14:50:39 hal
19: * Make DMA channel patchable.
20: *
21: * Revision 1.7 91/10/22 13:40:36 hal
22: * Use sys on kernel header includes.
23: *
24: * Revision 1.6 91/06/10 13:28:11 hal
25: * Refix startup problem with HDGETA. Text cleanup.
26: *
27: * Revision 1.5 91/06/10 12:58:04 hal
28: * Partial fix for HDGETA failing if partition table absent.
29: *
30: * Revision 1.4 91/06/03 13:50:06 hal
31: * Add HDSETA.
32: *
33: * Revision 1.3 91/05/08 11:00:30 root
34: * Make number of heads - SD_HDS - patchable for Tandy.
35: *
36: * Revision 1.2 91/05/01 04:50:11 root
37: * Debug code and d_time/sw_active imbalance fixed.
38: *
39: * Revision 1.1 91/04/30 11:02:22 root
40: * Shipped with COH 3.1.0
41: *
42: */
43:
44: #include <sys/coherent.h>
45: #include <sys/fdisk.h>
46: #include <sys/hdioctl.h>
47: #include <sys/sdioctl.h>
48: #include <sys/buf.h>
49: #include <sys/con.h>
50: #include <sys/stat.h>
51: #ifdef _I386
52: #include <sys/uproc.h>
53: #endif /* _I386 */
54: #include <errno.h>
55: #include <sys/scsiwork.h>
56: #include <sys/typed.h>
57: #ifdef _I386
58: #include <sys/mmu.h>
59: #endif /* _I386 */
60:
61: #ifndef _I386
62: extern saddr_t sds;
63: #endif /* _I386 */
64: extern short n_atdr;
65:
66: /*
67: * Configurable parameters
68: *
69: * Adaptec ROM translates at 64 heads, except the Tandy version, which
70: * uses 16 heads. Kernel variable SD_HDS is patchable for this reason.
71: */
72: #define DEF_AHA_HDS 64
73: #define DEF_AHA_SPT 32
74:
75: int SD_HDS = 0;
76: int SD_SPT = 0;
77:
78: #define NDRIVE (8 * 4) /* 8 SCSI ids and 4 LUNs */
79: #define SDMAJOR 13 /* Major Device Number */
80:
81: /*
82: * user configurable parameters
83: */
84: int SDIRQ = 11; /* Interrupt */
85: int SDBASE = 0x0330; /* Port base */
86: int SDDMA = 5; /* Used for first party DMA */
87:
88: /*
89: * LUN --------++
90: * device macros Special-+ ||
91: * minor device bits are of the form: 76543210
92: * ||| ||
93: * SCSI ID--+++ ||
94: * Partition ----++
95: * Partition mapping:
96: *
97: * Description Special Bit Partition # Device Type
98: * ----------- ----------- ----------- ------ ----
99: * partition a 0 00 /dev/sd??a disk
100: * partition b 0 01 /dev/sd??b disk
101: * partition c 0 10 /dev/sd??c disk
102: * partition d 0 11 /dev/sd??d disk
103: * partition table 1 00 /dev/sd??x disk
104: * no rewind tape 1 01 /dev/sd??n tape
105: * UNALLOCATED 1 10 --- ????
106: * rewind tape device 1 11 /dev/sd?? tape
107: */
108: #define DRIVENO(minor) (((minor) >> 2) & 0x1F) /* SCSI ID + LUN */
109: #define SCSIID(minor) (((minor) >> 4) & 0x7) /* SCSI ID */
110: #define LUN(minor) (((minor) >> 2) & 0x3) /* Logical Unit Number */
111: #define PARTITION(minor) ((minor) & 0x3) /* Partition */
112: #define sdmkdev(maj, s, drv) makedev((maj), ((s)|((drv)<<2)))
113:
114: /*
115: * Driver configuration.
116: */
117: void sdload();
118: void sdunload();
119: void sdopen();
120: void sdclose();
121: void sdread();
122: void sdwrite();
123: int sdioctl();
124: void sdblock();
125: int sdwatch();
126: int nulldev();
127: int nonedev();
128:
129: CON sdcon = {
130: DFBLK|DFCHR, /* Flags */
131: SDMAJOR, /* Major index */
132: sdopen, /* Open */
133: sdclose, /* Close */
134: sdblock, /* Block */
135: sdread, /* Read */
136: sdwrite, /* Write */
137: sdioctl, /* Ioctl */
138: nulldev, /* Powerfail */
139: sdwatch, /* Timeout */
140: sdload, /* Load */
141: sdunload /* Unload */
142: };
143:
144: /*
145: * host adapter routines
146: */
147: int aha_load(); /* initialize host adapter, DMA */
148: void aha_unload(); /* shutdown the host adapter */
149: int aha_start(); /* see if there's work */
150: int aha_command();
151:
152: /*
153: * Partition Parameters - copied from disk.
154: *
155: * There are NPARTN positions for the user partitions in array PPARM,
156: * plus 1 additional position to span the entire drive.
157: * Array pparmp[] contains a pointer to a kalloc()'ed PPARM
158: * entry if the drive actually exists, is a disk drive and if someone
159: * has attmpted to read a partition table from the drive.
160: */
161: typedef struct fdisk_s PPARM[NPARTN + 1]; /* 4 partitions + whole drive */
162: static PPARM *pparmp[NDRIVE]; /* one per possible drive */
163: #define WHOLE_DRIVE NPARTN /* index for whole drive */
164: #define PNULL ((PPARM *)0)
165:
166: /*
167: * Per disk controller data.
168: * Only one host adapter; no more, no less.
169: */
170: static
171: scsi_work_t sd;
172:
173: static BUF dbuf; /* For raw I/O */
174: static int sw_active;
175:
176: /**
177: *
178: * void
179: * sdload() - load routine.
180: *
181: * Action: The controller is reset and the interrupt vector is grabbed.
182: * The drive characteristics are set up at this time.
183: */
184: static void
185: sdload()
186: {
187: FIFO *ffp;
188: typed_space *tp;
189: extern typed_space boot_gift;
190:
191: /*
192: * Initialize Drive Controller.
193: */
194: sw_active = 0;
195: if (aha_load(SDDMA, SDIRQ, SDBASE, &sd) < 0) {
196: SET_U_ERROR(ENXIO, "aha_load() failed.");
197: return;
198: }
199:
200: /*
201: * Set values for # of heads and # of sectors per track.
202: *
203: * AHA translation mode uses the same # of heads
204: * and the same # of sectors per track for all drives.
205: *
206: * If these values are already patched, leave them alone.
207: * Otherwise, look in the data area written by tboot.
208: * If nothing from tboot, use default values.
209: */
210: if (SD_HDS == 0 || SD_SPT == 0) {
211: /* heads & spt not both patched */
212: SD_HDS = DEF_AHA_HDS;
213: SD_SPT = DEF_AHA_SPT;
214: if (F_NULL != (ffp = fifo_open(&boot_gift, 0))) {
215: if (T_NULL != (tp = fifo_read(ffp))) {
216: BIOS_DISK *bdp = (BIOS_DISK *)tp->ts_data;
217: if ((T_BIOS_DISK == tp->ts_type) &&
218: (n_atdr == bdp->dp_drive) ) {
219: /* got values from tboot */
220: SD_HDS = bdp->dp_heads;
221: SD_SPT = bdp->dp_sectors;
222: }
223: }
224: fifo_close(ffp);
225: }
226: }
227: printf(" SD_HDS=%d SD_SPT=%d\n", SD_HDS, SD_SPT);
228:
229: /* aha_device_info(); */ /* enable after this gets fixed */
230: }
231:
232: /**
233: *
234: * void
235: * sdunload() - unload routine.
236: */
237: static void
238: sdunload()
239: {
240: register int i;
241:
242: if (sw_active > 0)
243: printf("aha154x: sdunload() athough %d active\n", sw_active);
244: aha_unload(SDIRQ);
245: for (i = 0; i < NDRIVE; ++i)
246: if (pparmp[i] != PNULL)
247: kfree(pparmp[i]); /* free any partition tables */
248: }
249:
250: /*
251: * int
252: * sdgetpartitions(dev) - load partition table for specified drive
253: *
254: * - return 1 on success and 0 on failure
255: */
256: int sdgetpartitions(dev)
257: dev_t dev;
258: {
259: register int i;
260: scsi_cmd_t sc;
261: unsigned char *buffer;
262: struct fdisk_s *fdp;
263: int d = DRIVENO(minor(dev));
264:
265: pparmp[d] = kalloc(sizeof *pparmp[0]);
266: fdp = (struct fdisk_s *) pparmp[d]; /* point to first entry */
267: #ifdef _I386
268: buffer = palloc(36+1);
269: #else /* _I386 */
270: buffer = kalloc(36+1);
271: #endif /* _I386 */
272:
273: if (buffer == NULL || pparmp[d] == PNULL) {
274: printf("aha154x: out of kernel memory\n");
275: #ifdef _I386
276: SET_U_ERROR(ENOMEM, "aha154x: out of kernel memory");
277: #else /* _I386 */
278: u.u_error = EKSPACE;
279: #endif /* _I386 */
280: return 0;
281: }
282: kclear(pparmp[d], sizeof *pparmp[0]);
283: sc.unit = d;
284: sc.block = 0L;
285: sc.blklen = 0;
286:
287: #ifdef _I386
288: /* sc.buffer is a virtual-physical address (Ciaran Space.) */
289: sc.buffer = vtovp(buffer);
290: #else /* _I386 */
291: sc.buffer = VTOP2(buffer, sds);
292: #endif /* _I386 */
293: ++drvl[SDMAJOR].d_time;
294:
295: sc.cmd = ScmdREADCAPACITY;
296: sc.buflen = 8;
297:
298: for(i = 0; i < sc.buflen; ++i)
299: buffer[i] = 0;
300:
301: /*
302: * If we call aha_command() only once we get a capacity of
303: * 0. All ScmdREADCAPACITY calls after the first return a
304: * correct answer.
305: *
306: * This may be a bug in the aha154x.
307: */
308: aha_command(&sc);
309: aha_command(&sc);
310:
311: T_PIGGY( 0x20000, {
312: printf("buffer =");
313: for(i = 0; i < sc.buflen; ++i)
314: printf(" %x", buffer[i]);
315: printf("\n");
316: });
317:
318: sc.block = (buffer[0]<<8) | buffer[1];
319: sc.block <<= 16;
320: sc.block |= (buffer[2]<<8) | buffer[3];
321:
322: sc.blklen = (buffer[6]<<8) | buffer[7];
323:
324: T_PIGGY( 0x20000, {
325: printf("SCSI %D. blocks of size %d\n", sc.block, sc.blklen);
326: } );
327:
328: #ifdef _I386
329: pfree(buffer);
330: #else /* _I386 */
331: kfree(buffer);
332: #endif /* _I386 */
333: fdp[WHOLE_DRIVE].p_size = sc.block;
334: if (0 == fdp[WHOLE_DRIVE].p_size) {
335: /*
336: * If we are just opening this drive, make it so we can
337: * read the first block without an error.
338: */
339: fdp[WHOLE_DRIVE].p_size = 1;
340: }
341:
342: --drvl[SDMAJOR].d_time;
343: return fdisk(sdmkdev(major(dev), SDEV, d), pparmp[d]);
344: }
345:
346: /**
347: *
348: * void
349: * sdopen(dev, mode)
350: * dev_t dev;
351: * int mode;
352: *
353: * Input: dev = disk device to be opened.
354: * mode = access mode [IPR,IPW, IPR+IPW].
355: *
356: * Action: Validate the minor device.
357: * Update the paritition table if necessary.
358: */
359: static void
360: sdopen(dev, mode)
361: register dev_t dev;
362: {
363: register int p; /* partition */
364: register int d; /* drive (SCSI ID + LUN) */
365: struct fdisk_s *fdp; /* one partition entry */
366:
367: if (minor(dev) & SDEV) {
368: if (PARTITION(minor(dev)) != 0) { /* tape device ? */
369: /* not yet! */
370: SET_U_ERROR(ENXIO, "No tape yet");
371: devmsg(dev, "No tape yet");
372: } else {
373: ++drvl[SDMAJOR].d_time;
374: ++sw_active;
375: }
376: return;
377: }
378:
379: d = DRIVENO(minor(dev));
380: p = PARTITION(minor(dev));
381:
382: /*
383: * If partition not defined read partition characteristics.
384: */
385: if (pparmp[d] == PNULL) /* no entry yet for this drive ? */
386: if (!sdgetpartitions(dev)) {
387: SET_U_ERROR(ENXIO, "sdgetpartitions() failed.");
388: return;
389: }
390: /*
391: * Ensure partition lies within drive boundaries and is non-zero size.
392: */
393: fdp = (struct fdisk_s *) pparmp[d];
394: if ((fdp[p].p_base+fdp[p].p_size) > fdp[WHOLE_DRIVE].p_size) {
395: #ifdef _I386
396: SET_U_ERROR(EINVAL, "Partition exceeds drive size.");
397: #else /* _I386 */
398: u.u_error = EBADFMT;
399: #endif /* _I386 */
400: } else if (fdp[p].p_size == 0) {
401: SET_U_ERROR(ENODEV, "No such partition.");
402: } else {
403: ++drvl[SDMAJOR].d_time;
404: ++sw_active;
405: }
406: }
407:
408: void sdclose(dev)
409: {
410: --drvl[SDMAJOR].d_time;
411: --sw_active;
412: }
413:
414: /**
415: *
416: * void
417: * sdread(dev, iop) - write a block to the raw disk
418: * dev_t dev;
419: * IO * iop;
420: *
421: * Input: dev = disk device to be written to.
422: * iop = pointer to source I/O structure.
423: *
424: * Action: Invoke the common raw I/O processing code.
425: */
426: static void
427: sdread(dev, iop)
428: dev_t dev;
429: IO *iop;
430: {
431: ioreq(&dbuf, iop, dev, BREAD, BFRAW|BFBLK|BFIOC);
432: }
433:
434: /**
435: *
436: * void
437: * sdwrite(dev, iop) - write a block to the raw disk
438: * dev_t dev;
439: * IO * iop;
440: *
441: * Input: dev = disk device to be written to.
442: * iop = pointer to source I/O structure.
443: *
444: * Action: Invoke the common raw I/O processing code.
445: */
446: static void
447: sdwrite(dev, iop)
448: dev_t dev;
449: IO *iop;
450: {
451: ioreq(&dbuf, iop, dev, BWRITE, BFRAW|BFBLK|BFIOC);
452: }
453:
454: /**
455: *
456: * int
457: * sdioctl(dev, cmd, arg)
458: * dev_t dev;
459: * int cmd;
460: * char * vec;
461: *
462: * Input: dev = disk device to be operated on.
463: * cmd = input/output request to be performed.
464: * vec = (pointer to) optional argument.
465: *
466: * Action: Validate the minor device.
467: * Update the paritition table if necessary.
468: */
469: static int
470: sdioctl(dev, cmd, vec)
471: register dev_t dev;
472: int cmd;
473: char * vec;
474: {
475: int i; /* Integer for abusing. */
476: int d; /* Drive number. */
477: hdparm_t hdparm;
478: struct fdisk_s *fdp;
479: int do_getpt = 0; /* 1 if need to call sdgetpartitions() */
480:
481: d = DRIVENO(minor(dev));
482:
483: /*
484: * Identify input/output request.
485: */
486: switch (cmd) {
487:
488: case HDGETA:
489: /*
490: * If haven't loaded partition table yet for this drive,
491: * try to do it now. Note sdgetpartitions() will fail
492: * if there is a new drive (e.g. no signature). But all
493: * we need is allocation of pparmp[d] and capacity read
494: * properly from the drive.
495: */
496: if (pparmp[d] == PNULL) {
497: do_getpt = 1; /* REALLY just want Read Capacity */
498:
499: i = sdgetpartitions(dev);
500:
501: if (pparmp[d] == NULL) {
502: SET_U_ERROR(ENXIO, "sdgetparitions() failed.");
503: return -1;
504: }
505: }
506: fdp = (struct fdisk_s *) pparmp[d];
507: *(short *)&hdparm.landc[0] =
508: *(short *)&hdparm.ncyl[0] = fdp[WHOLE_DRIVE].p_size
509: / (SD_HDS * SD_SPT);
510: hdparm.nhead = SD_HDS;
511: hdparm.nspt = SD_SPT;
512: kucopy(&hdparm, vec, sizeof hdparm);
513: /*
514: * I know it's ugly. But it gets around startup Catch-22.
515: *
516: * The fdisk command needs HDGETA. HDGETA invokes
517: * sdgetpartitions(), but we want to call it again
518: * after the partition table has been created by the fdisk
519: * command.
520: */
521: if (do_getpt) {
522: kfree(pparmp[d]);
523: pparmp[d] = PNULL; /* force re-read of p. table */
524: }
525: return 0;
526: case HDSETA:
527: /*
528: * Set hard disk attributes.
529: */
530: fdp = (struct fdisk_s *) pparmp[d];
531: ukcopy(vec, &hdparm, sizeof hdparm);
532: SD_HDS = hdparm.nhead;
533: SD_SPT = hdparm.nspt;
534: fdp[WHOLE_DRIVE].p_size =
535: (long)(*(short *)&hdparm.ncyl[0])
536: * (long)SD_HDS * (long)SD_SPT;
537:
538: return 0;
539: case SCSI_HA_CMD:
540: return aha_ioctl(cmd, vec);
541: case SCSI_CMD:
542: return 0;
543: case SCSI_CMD_IN:
544: return 0;
545: case SCSI_CMD_OUT:
546: return 0;
547:
548: default:
549: SET_U_ERROR( EINVAL, "Illegal SCSI ioctl command." );
550: return -1;
551: }
552: }
553:
554: /**
555: *
556: * void
557: * sdblock(bp) - queue a block to the disk
558: *
559: * Input: bp = pointer to block to be queued.
560: *
561: * Action: Queue a block to the disk.
562: * Make sure that the transfer is within the disk partition.
563: */
564: static void
565: sdblock(bp)
566: register BUF *bp;
567: {
568: register scsi_work_t *sw;
569: register int s;
570: struct fdisk_s *fdp;
571:
572: int p = PARTITION(minor(bp->b_dev));
573: int drv = DRIVENO(minor(bp->b_dev));
574:
575: if (minor(bp->b_dev) & SDEV)
576: p = WHOLE_DRIVE;
577: bp->b_resid = bp->b_count;
578:
579: fdp = (struct fdisk_s *) pparmp[drv];
580:
581: /*
582: * Range check disk region.
583: */
584: if (pparmp[drv] == PNULL) {
585: if (p == WHOLE_DRIVE) {
586: #if 0
587: /* Why did we only allow people to access the first block of WHOLE_DRIVE?
588: in cases where there was not a valid partition table? */
589: if ((bp->b_bno != 0) || (bp->b_count != BSIZE)) {
590: bp->b_flag |= BFERR;
591: bdone(bp);
592: return;
593: }
594: #endif
595: } else {
596: printf("aha154x: no partition table\n");
597: bp->b_flag |= BFERR;
598: bdone(bp);
599: return;
600: }
601: } else if ((bp->b_bno + (bp->b_count/BSIZE)) > fdp[p].p_size) {
602:
603: T_PIGGY( 0x20000 , {
604: printf("\n(bp->b_bno: %x + (bp->b_count: %x /BSIZE): %x): %x > ",
605: bp->b_bno, bp->b_count, (bp->b_count/BSIZE),
606: (bp->b_bno + (bp->b_count/BSIZE)));
607: printf(" fdp[p].p_size: %x\n", fdp[p].p_size);
608: } );
609:
610: bp->b_flag |= BFERR;
611: bdone(bp);
612: return;
613: }
614:
615: bp->b_actf = NULL;
616: #ifdef _I386
617: sw = (scsi_work_t *)palloc(sizeof(*sw));
618: T_PIGGY(0x100000, printf("sw(%x)", sw); );
619: #else /* _I386 */
620: sw = (scsi_work_t *)kalloc(sizeof(*sw));
621: #endif /* _I386 */
622: if (sw == (scsi_work_t *)0) {
623: printf("aha154x: out of kernel memory\n");
624: bp->b_flag |= BFERR;
625: bdone(bp);
626: return;
627: }
628: sw->sw_bp = bp;
629: sw->sw_drv = drv;
630: sw->sw_type = 0;
631: if (p != WHOLE_DRIVE)
632: sw->sw_bno = fdp[p].p_base + bp->b_bno;
633: else
634: sw->sw_bno = bp->b_bno;
635: sw->sw_retry = 1;
636:
637: T_PIGGY( 0x20000,
638: printf("sdblock: drv %x bno %x:%x bp=%x, flag = %x\n",
639: drv, (long)sw->sw_bno, bp, bp->b_flag);
640: );
641:
642: s = sphi();
643: if (sd.sw_actf == NULL)
644: sd.sw_actf = sw;
645: else
646: sd.sw_actl->sw_actf = sw;
647: sd.sw_actl = sw;
648: spl(s);
649:
650: aha_start();
651: }
652:
653: sdwatch()
654: {
655: register int i;
656:
657: if (0 != (i = aha_start())) {
658: T_PIGGY( 0x20000, printf("sdwatch: started %d actions\n", i); );
659: }
660:
661: if ( 0!= (i = aha_completed())) {
662: T_PIGGY( 0x20000, printf("sdwatch: completed %d actions\n", i); );
663: }
664: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.