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