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