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