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