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