|
|
1.1 root 1: /* (-lgl
2: * COHERENT Driver Kit Version 1.1.0
3: * Copyright (c) 1982, 1990 by Mark Williams Company.
4: * All rights reserved. May not be copied without permission.
5: *
6: -lgl) */
7: /*
8: * This is a driver for the
9: * hard disk on the AT.
10: *
11: * Reads drive characteristics from ROM (thru interrupt vector 0x41 and 0x46).
12: * Reads partition information from disk.
13: */
14:
15: /*
16: * -----------------------------------------------------------------
17: * Includes.
18: */
19: #include <sys/coherent.h>
20: #include <sys/fdisk.h>
21: #include <sys/hdioctl.h>
22: #include <sys/buf.h>
23: #include <sys/con.h>
24: #include <sys/devices.h>
25: #include <sys/stat.h>
26: #include <sys/typed.h>
27: #include <errno.h>
28:
29: /*
30: * -----------------------------------------------------------------
31: * Definitions.
32: * Constants.
33: * Macros with argument lists.
34: * Typedefs.
35: * Enums.
36: */
37: /*
38: * Configurable parameters
39: */
40: #define HDIRQ 14 /* Level 14 */
41: #define HDBASE 0x01F0 /* Port base */
42: #define NDRIVE 2 /* only two drives supported */
43: #define SOFTLIM 6 /* (7) num of retries before diag */
44: #define HARDLIM 8 /* number of retries before fail */
45: #define BADLIM 100 /* num to stop recov if flagged bad */
46:
47: #define BIT(n) (1 << (n))
48:
49: #define CMOSA 0x70 /* write cmos address to this port */
50: #define CMOSD 0x71 /* read cmos data through this port */
51:
52: #ifdef _I386
53: # define ATCACHE 0 /* no cache for us in this driver code */
54: # define VERBOSE 1
55: #else
56: # ifndef ATCACHE
57: # if VERBOSE > 0
58: # define ATCACHE 2 /* local cache size in blocks */
59: # else
60: # define ATCACHE 0 /* no cache for small code */
61: # endif
62: # endif
63: #endif
64:
65: /*
66: * I/O Port Addresses
67: */
68: #define DATA_REG (HDBASE+0) /* data (r/w) */
69: #define AUX_REG (HDBASE+1) /* error(r), write precomp cyl/4 (w) */
70: #define NSEC_REG (HDBASE+2) /* sector count (r/w) */
71: #define SEC_REG (HDBASE+3) /* sector number (r/w) */
72: #define LCYL_REG (HDBASE+4) /* low cylinder (r/w) */
73: #define HCYL_REG (HDBASE+5) /* high cylinder (r/w) */
74: #define HDRV_REG (HDBASE+6) /* drive/head (r/w) (D<<4)+(1<<H) */
75: #define CSR_REG (HDBASE+7) /* status (r), command (w) */
76: #define HF_REG (HDBASE+0x206) /* Usually 0x3F6 */
77:
78: /*
79: * Error from AUX_REG (r)
80: */
81: #define DAM_ERR BIT(0) /* data address mark not found */
82: #define TR0_ERR BIT(1) /* track 000 not found */
83: #define ABT_ERR BIT(2) /* aborted command */
84: #define ID_ERR BIT(4) /* id not found */
85: #define ECC_ERR BIT(6) /* data ecc error */
86: #define BAD_ERR BIT(7) /* bad block detect */
87:
88: /*
89: * Status from CSR_REG (r)
90: */
91: #define ERR_ST BIT(0) /* error occurred */
92: #define INDEX_ST BIT(1) /* index pulse */
93: #define SOFT_ST BIT(2) /* soft (corrected) ECC error */
94: #define DRQ_ST BIT(3) /* data request */
95: #define SKC_ST BIT(4) /* seek complete */
96: #define WFLT_ST BIT(5) /* improper drive operation */
97: #define RDY_ST BIT(6) /* drive is ready */
98: #define BSY_ST BIT(7) /* controller is busy */
99:
100: /*
101: * Commands to CSR_REG (w)
102: */
103: #define RESTORE(rate) (0x10+(rate)) /* X */
104: #define SEEK(rate) (0x70+(rate)) /* X */
105: #define READ_CMD (0x20) /* X */
106: #define WRITE_CMD (0x30) /* X */
107: #define FORMAT_CMD (0x50) /* X */
108: #define VERIFY_CMD (0x40) /* X */
109: #define DIAGNOSE_CMD (0x90) /* X */
110: #define SETPARM_CMD (0x91) /* X */
111:
112: /*
113: * Device States.
114: */
115: #define SIDLE 0 /* controller idle */
116: #define SRETRY 1 /* seeking */
117: #define SREAD 2 /* reading */
118: #define SWRITE 3 /* writing */
119:
120: /*
121: * -----------------------------------------------------------------
122: * Functions.
123: * Import Functions.
124: * Export Functions.
125: * Local Functions.
126: */
127: extern int nulldev();
128: extern int nonedev();
129:
130: /*
131: * Driver configuration.
132: */
133: static void atload();
134: static void atunload();
135: static void atopen();
136: static void atread();
137: static void atwrite();
138: static int atioctl();
139: static void atwatch();
140: static void atblock();
141:
142: /*
143: * Forward Referenced Functions.
144: */
145: static void atreset();
146: static int atdequeue();
147: static void atstart();
148: static void atintr();
149: static void atdefer();
150: static int aterror();
151: static void atrecov();
152: static void atdone();
153:
154: /*
155: * -----------------------------------------------------------------
156: * Global Data.
157: * Import Variables.
158: * Export Variables.
159: * Local Variables.
160: */
161: extern typed_space boot_gift;
162: extern short n_atdr;
163:
164: #ifndef _I386
165: extern saddr_t sds;
166: #endif
167:
168: CON atcon = {
169: DFBLK|DFCHR, /* Flags */
170: AT_MAJOR, /* Major index */
171: atopen, /* Open */
172: nulldev, /* Close */
173: atblock, /* Block */
174: atread, /* Read */
175: atwrite, /* Write */
176: atioctl, /* Ioctl */
177: nulldev, /* Powerfail */
178: atwatch, /* Timeout */
179: atload, /* Load */
180: atunload /* Unload */
181: };
182:
183: /*
184: * Patchable variables.
185: * ATSECS is number of seconds to wait for an expected interrupt.
186: * ATSREG needs to be 3F6 for most new IDE drives; needs to be
187: * 1F7 for Perstor controllers and some old IDE drives.
188: * Either value works with most drives.
189: */
190: int ATSECS = 6;
191: int ATSREG = 0x3F6;
192:
193: /*
194: * Drive Parameters - copied from ROM.
195: * If patched, use the given values instead of reading from the ROM.
196: * NOTE: Exactly duplicates hdparm_s struct.
197: */
198: struct dparm_s {
199: unsigned short d_ncyl; /* number of cylinders */
200: unsigned char d_nhead; /* number of heads */
201: #pragma align 1
202: unsigned short d_rwcc; /* reduced write current cyl */
203: unsigned short d_wpcc; /* write pre-compensation cyl */
204: #pragma align
205: unsigned char d_eccl; /* max ecc data length */
206: unsigned char d_ctrl; /* control byte */
207: unsigned char d_fill2[3];
208: unsigned short d_landc; /* landing zone cylinder */
209: unsigned char d_nspt; /* number of sectors per track */
210: unsigned char d_fill3;
211:
212: } atparm[ NDRIVE ] = {
213: 0 /* Initialized to allow patching */
214: };
215:
216: /*
217: * Partition Parameters - copied from disk.
218: *
219: * There are NDRIVE * NPARTN positions for the user partitions,
220: * plus NDRIVE additional partitions to span each drive.
221: *
222: * Aligning partitions on cylinder boundaries:
223: * Optimal partition size: 2 * 3 * 4 * 5 * 7 * 17 = 14280 blocks
224: * Acceptable partition size: 3 * 4 * 5 * 7 * 17 = 7140 blocks
225: */
226: static struct fdisk_s pparm[NDRIVE*NPARTN + NDRIVE];
227:
228: /*
229: * Per disk controller data.
230: * Only one controller; no more, no less.
231: */
232: static struct at {
233: BUF *at_actf; /* Link to first */
234: BUF *at_actl; /* Link to last */
235: #ifdef _I386
236: paddr_t at_addr; /* Source/Dest virtual address */
237: #else
238: faddr_t at_addr;
239: #endif
240: daddr_t at_bno; /* Block # on disk */
241: unsigned at_nsec; /* # of sectors on current transfer */
242: unsigned at_drv;
243: unsigned at_head;
244: unsigned at_cyl;
245: unsigned at_sec;
246: unsigned at_partn;
247: unsigned char at_dtype[ NDRIVE ]; /* drive type, 0 if unused */
248: unsigned char at_tries;
249: unsigned char at_state;
250: unsigned char at_caching; /* caching in progress */
251: #if ATCACHE > 0
252: unsigned char at_cdrv[ ATCACHE ]; /* cached drive */
253: daddr_t at_cbno[ ATCACHE ]; /* cached block number */
254: unsigned char * at_cbuf[ ATCACHE ]; /* cached block */
255: #endif
256: unsigned at_bad_drv;
257: unsigned at_bad_head;
258: unsigned at_bad_cyl;
259: } at;
260:
261: static BUF dbuf; /* For raw I/O */
262:
263: static char timeout_msg[] = "at%d: TO\n";
264:
265: /**
266: *
267: * void
268: * atload() - load routine.
269: *
270: * Action: The controller is reset and the interrupt vector is grabbed.
271: * The drive characteristics are set up at this time.
272: */
273: static void
274: atload()
275: {
276: register unsigned int u;
277: register struct dparm_s * dp;
278: struct { unsigned short off, seg; } p;
279:
280: if (n_atdr <= 0)
281: return;
282:
283: /* Flag drives 0, 1 as present or not. */
284: at.at_dtype[0] = 1;
285: at.at_dtype[1] = n_atdr > 1 ? 1 : 0;
286:
287: #if 0
288: /* hex dump boot gift */
289: {
290: int bgi;
291: unsigned char * bgp = (char *)&boot_gift;
292: printf("&boot_gift = %lx", &boot_gift);
293: for (bgi = 0; bgi < 80; bgi++) {
294: printf(" %x", (*bgp++));
295: }
296: }
297: #endif
298:
299: /*
300: * Obtain Drive Characteristics.
301: */
302: for (u = 0, dp = &atparm[0]; u < n_atdr; ++dp, ++u) {
303: struct dparm_s int_dp;
304:
305: if (dp->d_ncyl == 0) {
306: /*
307: * Not patched.
308: *
309: * If tertiary boot sent us parameters,
310: * Use "fifo" routines to fetch them.
311: * This only gives us ncyl, nhead, and nspt.
312: * Make educated guesses for other parameters:
313: * Set landc to ncyl, wpcc to -1.
314: * Set ctrl to 0 or 8 depending on head count.
315: *
316: * Follow INT 0x41/46 to get drive static BIOS drive
317: * parameters, if any.
318: *
319: * If there were no parameters from tertiary boot,
320: * or if INT 0x4? nhead and nspt match tboot parms,
321: * use "INT" parameters (will give better match on
322: * wpcc, landc, and ctrl fields, which tboot can't
323: * give us).
324: */
325:
326: FIFO *ffp;
327: typed_space *tp;
328: int found, parm_int;
329:
330: if (F_NULL != (ffp = fifo_open(&boot_gift, 0))) {
331: for (found = 0; !found && (tp = fifo_read(ffp)); ) {
332: BIOS_DISK *bdp = (BIOS_DISK *)tp->ts_data;
333: if ((T_BIOS_DISK == tp->ts_type) &&
334: (u == bdp->dp_drive) ) {
335: found = 1;
336: dp->d_ncyl = bdp->dp_cylinders;
337: dp->d_nhead = bdp->dp_heads;
338: dp->d_nspt = bdp->dp_sectors;
339: dp->d_wpcc = 0xffff;
340: dp->d_landc = dp->d_ncyl;
341: if (dp->d_nhead > 8)
342: dp->d_ctrl |= 8;
343: }
344: }
345: fifo_close(ffp);
346: }
347:
348: if (u == 0)
349: parm_int = 0x41;
350: else /* (u == 1) */
351: parm_int = 0x46;
352: #ifdef _I386
353: pxcopy((paddr_t)(parm_int*4), &p, sizeof p, SEG_386_KD);
354: pxcopy((paddr_t)(p.seg<<4L)+p.off,
355: &int_dp, sizeof(int_dp), SEG_386_KD);
356: #else
357: pkcopy((paddr_t)(parm_int*4), &p, sizeof p);
358: pkcopy((paddr_t) (p.seg << 4L) + p.off,
359: &int_dp, sizeof(int_dp));
360: #endif
361: if (!found ||
362: (dp->d_nhead == int_dp.d_nhead
363: && dp->d_nspt == int_dp.d_nspt)) {
364: *dp = int_dp;
365: printf("Using INT 0x%x",parm_int);
366: } else
367: printf("Using INT 0x13(08)");
368: } else {
369: printf("Using patched");
370: /*
371: * Avoid incomplete patching.
372: */
373: if (at.at_dtype[u] == 0)
374: at.at_dtype[u] = 1;
375: if (dp->d_nspt == 0)
376: dp->d_nspt = 17;
377: #if FORCE_CTRL_8
378: if (dp->d_nhead > 8)
379: dp->d_ctrl |= 8;
380: #endif
381:
382: }
383: #if VERBOSE > 0
384: printf(" drive %d parameters\n", u);
385:
386: /* intersegment printf only gets 6 words of arguments */
387: printf( "at%d: ncyl=%d nhead=%d wpcc=%d ",
388: u, dp->d_ncyl, dp->d_nhead, dp->d_wpcc);
389: printf(" eccl=%d ctrl=%d landc=%d nspt=%d\n",
390: dp->d_eccl, dp->d_ctrl, dp->d_landc, dp->d_nspt);
391: #endif
392: }
393:
394: /*
395: * Initialize Drive Size.
396: */
397: for (u = 0, dp = &atparm[0]; u < n_atdr; ++dp, ++u) {
398:
399: if (at.at_dtype[u] == 0)
400: continue;
401:
402: pparm[NDRIVE*NPARTN + u].p_size =
403: (long) dp->d_ncyl * dp->d_nhead * dp->d_nspt;
404: }
405:
406: /*
407: * Initialize Drive Controller.
408: */
409: atreset();
410:
411: setivec(HDIRQ, atintr);
412:
413: #if ATCACHE > 0
414: at.at_cdrv[0] = -1;
415: at.at_cbuf[0] = kalloc(BSIZE);
416: #endif
417:
418: #if ATCACHE > 1
419: at.at_cdrv[1] = -1;
420: at.at_cbuf[1] = kalloc(BSIZE);
421: #endif
422:
423: at.at_bad_drv = -1;
424: }
425:
426: /**
427: *
428: * void
429: * atunload() - unload routine.
430: */
431: static void
432: atunload()
433: {
434: clrivec(HDIRQ);
435: }
436:
437: /**
438: *
439: * void
440: * atreset() -- reset hard disk controller, define drive characteristics.
441: */
442: static void
443: atreset()
444: {
445: register int u;
446: register struct dparm_s * dp;
447:
448: /*
449: * Reset controller for a minimum of 4.8 microseconds.
450: */
451: outb(HF_REG, 4);
452: for (u = 100; --u != 0;)
453: ;
454: outb(HF_REG, atparm[0].d_ctrl & 0x0F);
455: myatbsyw(0);
456: if (inb(AUX_REG) != 0x01) {
457: /*
458: * Some IDE drives always timeout on initial reset.
459: * So don't report first timeout.
460: */
461: static one_bad;
462:
463: if (one_bad) {
464: printf("at: hd controller reset timeout\n");
465: } else
466: one_bad = 1;
467: }
468:
469: /*
470: * Initialize drive parameters.
471: */
472: for (u = 0, dp = &atparm[0]; u < n_atdr; ++dp, ++u) {
473:
474: if (at.at_dtype[u] == 0)
475: continue;
476:
477: myatbsyw(u);
478:
479: /*
480: * Set drive characteristics.
481: * 0x1F1 - AUX_REG
482: * 0x1F2 - NSEC_REG
483: * 0x1F3 - SEC_REG
484: * 0x1F4 - LCYL_REG
485: * 0x1F5 - HCYL_REG
486: * 0x1F6 - HDRV_REG
487: * 0x1F7 - CSR_REG
488: */
489: outb(HF_REG, dp->d_ctrl);
490: outb(AUX_REG, dp->d_wpcc / 4);
491: outb(NSEC_REG, dp->d_nspt);
492: outb(SEC_REG, 0x01);
493: outb(LCYL_REG, (char)(dp->d_ncyl));
494: outb(HCYL_REG, (char)(dp->d_ncyl >> 8));
495: outb(HDRV_REG, 0xA0 + (u<<4) + dp->d_nhead - 1);
496: outb(CSR_REG, SETPARM_CMD);
497: myatbsyw(u);
498:
499: /*
500: * Restore heads.
501: */
502: outb(CSR_REG, RESTORE(0));
503: myatbsyw(u);
504: }
505: }
506:
507: /**
508: *
509: * void
510: * atopen(dev, mode)
511: * dev_t dev;
512: * int mode;
513: *
514: * Input: dev = disk device to be opened.
515: * mode = access mode [IPR,IPW, IPR+IPW].
516: *
517: * Action: Validate the minor device.
518: * Update the paritition table if necessary.
519: */
520: static void
521: atopen(dev, mode)
522: register dev_t dev;
523: {
524: register int d; /* drive */
525: register int p; /* partition */
526:
527: p = minor(dev) % (NDRIVE*NPARTN);
528:
529: if (minor(dev) & SDEV) {
530: d = minor(dev) % NDRIVE;
531: p += NDRIVE * NPARTN;
532: }
533: else
534: d = minor(dev) / NPARTN;
535:
536: if ((d >= NDRIVE) || (at.at_dtype[d] == 0)) {
537: printf("atopen: drive not present ");
538: u.u_error = ENXIO;
539: return;
540: }
541:
542: if (minor(dev) & SDEV) {
543: return;
544: }
545:
546: /*
547: * If partition not defined read partition characteristics.
548: */
549: if (pparm[p].p_size == 0)
550: fdisk(makedev(major(dev), SDEV + d), &pparm[ d * NPARTN ]);
551:
552: /*
553: * Ensure partition lies within drive boundaries and is non-zero size.
554: */
555: if ((pparm[p].p_base+pparm[p].p_size) > pparm[d+NDRIVE*NPARTN].p_size) {
556: #ifdef _I386
557: printf("atopen: p_size too big ");
558: u.u_error = EINVAL;
559: #else
560: u.u_error = EBADFMT;
561: #endif
562: } else if (pparm[p].p_size == 0) {
563: printf("atopen: p_size zero ");
564: u.u_error = ENODEV;
565: }
566: }
567:
568: /**
569: *
570: * void
571: * atread(dev, iop) - write a block to the raw disk
572: * dev_t dev;
573: * IO * iop;
574: *
575: * Input: dev = disk device to be written to.
576: * iop = pointer to source I/O structure.
577: *
578: * Action: Invoke the common raw I/O processing code.
579: */
580: static void
581: atread(dev, iop)
582: dev_t dev;
583: IO *iop;
584: {
585: ioreq(&dbuf, iop, dev, BREAD, BFRAW|BFBLK|BFIOC);
586: }
587:
588: /**
589: *
590: * void
591: * atwrite(dev, iop) - write a block to the raw disk
592: * dev_t dev;
593: * IO * iop;
594: *
595: * Input: dev = disk device to be written to.
596: * iop = pointer to source I/O structure.
597: *
598: * Action: Invoke the common raw I/O processing code.
599: */
600: static void
601: atwrite(dev, iop)
602: dev_t dev;
603: IO *iop;
604: {
605: ioreq(&dbuf, iop, dev, BWRITE, BFRAW|BFBLK|BFIOC);
606: }
607:
608: /**
609: *
610: * int
611: * atioctl(dev, cmd, arg)
612: * dev_t dev;
613: * int cmd;
614: * char * vec;
615: *
616: * Input: dev = disk device to be operated on.
617: * cmd = input/output request to be performed.
618: * vec = (pointer to) optional argument.
619: *
620: * Action: Validate the minor device.
621: * Update the paritition table if necessary.
622: */
623: static int
624: atioctl(dev, cmd, vec)
625: register dev_t dev;
626: int cmd;
627: char * vec;
628: {
629: int d;
630:
631: /*
632: * Identify drive number.
633: */
634: if (minor(dev) & SDEV)
635: d = minor(dev) % NDRIVE;
636: else
637: d = minor(dev) / NPARTN;
638:
639: /*
640: * Identify input/output request.
641: */
642: switch (cmd) {
643:
644: case HDGETA:
645: /*
646: * Get hard disk attributes.
647: */
648: kucopy(&atparm[d], vec, sizeof(atparm[0]));
649: return(0);
650:
651: case HDSETA:
652: /* Set hard disk attributes. */
653: ukcopy(vec, &atparm[d], sizeof(atparm[0]));
654: at.at_dtype[d] = 1; /* set drive type nonzero */
655: pparm[NDRIVE * NPARTN + d].p_size =
656: (long) atparm[d].d_ncyl * atparm[d].d_nhead * atparm[d].d_nspt;
657: atreset();
658: return 0;
659:
660: default:
661: u.u_error = EINVAL;
662: return(-1);
663: }
664: }
665:
666: /**
667: *
668: * void
669: * atwatch() - guard against lost interrupt
670: *
671: * Action: If drvl[AT_MAJOR] is greater than zero, decrement it.
672: * If it decrements to zero, simulate a hardware interrupt.
673: */
674: static void
675: atwatch()
676: {
677: register BUF * bp = at.at_actf;
678: register int s;
679:
680: s = sphi();
681: if (--drvl[AT_MAJOR].d_time > 0) {
682: spl(s);
683: return;
684: }
685: printf("at%d%c: bno=%U head=%u cyl=%u <Watchdog Timeout>\n",
686: at.at_drv,
687: (bp->b_dev & SDEV) ? 'x' : at.at_partn % NPARTN + 'a',
688: bp->b_bno, at.at_head, at.at_cyl);
689:
690: /*
691: * Reset hard disk controller.
692: *
693: * Mark current cylinder as bad so atstart() will fail.
694: * Otherwise would lock up if this track NEVER gives enough IRQ's.
695: */
696: at.at_bad_drv = at.at_drv;
697: at.at_bad_head = at.at_head;
698: at.at_bad_cyl = at.at_cyl;
699: atreset();
700: atstart();
701: spl(s);
702: }
703:
704: /**
705: *
706: * void
707: * atblock(bp) - queue a block to the disk
708: *
709: * Input: bp = pointer to block to be queued.
710: *
711: * Action: Queue a block to the disk.
712: * Make sure that the transfer is within the disk partition.
713: */
714: static void
715: atblock(bp)
716: register BUF *bp;
717: {
718: register struct fdisk_s *pp;
719: int partn = minor(bp->b_dev) % (NDRIVE*NPARTN);
720:
721: bp->b_resid = bp->b_count;
722:
723: if (minor(bp->b_dev) & SDEV)
724: partn += NDRIVE * NPARTN;
725:
726: pp = &pparm[ partn ];
727:
728: /*
729: * Check for read at end of partition.
730: */
731: if ((bp->b_req == BREAD) && (bp->b_bno == pp->p_size)) {
732: bdone(bp);
733: return;
734: }
735:
736: /*
737: * Range check disk region.
738: */
739: if (((bp->b_bno + (bp->b_count/BSIZE)) > pp->p_size)
740: || (bp->b_count % BSIZE) || bp->b_count == 0) {
741: bp->b_flag |= BFERR;
742: bdone(bp);
743: return;
744: }
745:
746: bp->b_actf = NULL;
747: if (at.at_actf == NULL)
748: at.at_actf = bp;
749: else
750: at.at_actl->b_actf = bp;
751: at.at_actl = bp;
752:
753: if (at.at_state == SIDLE)
754: if (atdequeue())
755: atstart();
756: }
757:
758: /**
759: *
760: * int
761: * atdequeue() - obtain next disk read/write operation
762: *
763: * Action: Pull some work from the disk queue.
764: *
765: * Return: 0 = no work.
766: * * = work to do.
767: */
768: static int
769: atdequeue()
770: {
771: register BUF * bp;
772: register struct fdisk_s * pp;
773: unsigned int nspt;
774:
775: for (;;) {
776: at.at_caching = 0;
777: at.at_tries = 0;
778:
779: if ((bp = at.at_actf) == NULL)
780: return (0);
781:
782: at.at_partn = minor(bp->b_dev) % (NDRIVE*NPARTN);
783:
784: if (minor(bp->b_dev) & SDEV) {
785: at.at_partn += (NDRIVE*NPARTN);
786: at.at_drv = minor(bp->b_dev) % NDRIVE;
787: }
788: else
789: at.at_drv = minor(bp->b_dev) / NPARTN;
790: nspt = atparm[at.at_drv].d_nspt;
791:
792: pp = &pparm[ at.at_partn ];
793: at.at_bno = pp->p_base + bp->b_bno;
794: at.at_nsec = bp->b_count / BSIZE;
795: #ifdef _I386
796: at.at_addr = bp->b_paddr;
797: #else
798: at.at_addr = bp->b_faddr;
799: #endif
800:
801: #if ATCACHE > 0
802: if (bp->b_req == BWRITE) {
803:
804: /*
805: * Invalidate cache if write might overlap.
806: */
807: if (at.at_nsec > 1) {
808: at.at_cdrv[0] = -1;
809: #if ATCACHE > 1
810: at.at_cdrv[1] = -1;
811: #endif
812: }
813: else if (at.at_bno == at.at_cbno[0])
814: at.at_cdrv[0] = -1;
815: #if ATCACHE > 1
816: else if (at.at_bno == at.at_cbno[1])
817: at.at_cdrv[1] = -1;
818: #endif
819: }
820: else if (at.at_nsec == 1) {
821:
822: /*
823: * Test for cache hit on block 0.
824: */
825: if ((at.at_drv == at.at_cdrv[0])
826: && (at.at_bno == at.at_cbno[0])) {
827: #ifdef _I386
828: xpcopy(at.at_cbuf[0], bp->b_paddr,
829: BSIZE, SEG_386_KD+SEG_VIRT);
830: #else
831: kpcopy(at.at_cbuf[0], bp->b_paddr, BSIZE);
832: #endif
833: at.at_actf = bp->b_actf;
834: bp->b_resid = 0;
835: bdone(bp);
836: continue;
837: }
838:
839: #if ATCACHE > 1
840: /*
841: * Test for cache hit on block 1.
842: */
843: if ((at.at_drv == at.at_cdrv[1])
844: && (at.at_bno == at.at_cbno[1])) {
845: #ifdef _I386
846: xpcopy(at.at_cbuf[1], bp->b_paddr,
847: BSIZE, SEG_386_KD|SEG_VIRT);
848: #else
849: kpcopy(at.at_cbuf[1], bp->b_paddr, BSIZE);
850: #endif
851: at.at_actf = bp->b_actf;
852: bp->b_resid = 0;
853: bdone(bp);
854: continue;
855: }
856: #endif
857:
858: /*
859: * Enable caching if no backlog for disk i/o.
860: */
861: if (bp->b_actf == NULL) {
862: /*
863: * Enable caching on single block reads
864: * when at least one block left on same track.
865: */
866: at.at_caching = nspt - 1 - (at.at_bno % nspt);
867: #if ATCACHE > 1
868: if (at.at_caching >= 2) {
869: at.at_caching = 2;
870: at.at_cdrv[2-1] = -1;
871: }
872: #endif
873:
874: if (at.at_caching) {
875: at.at_nsec += at.at_caching;
876: at.at_cdrv[1-1] = -1;
877: }
878: }
879: }
880: #endif
881:
882: return (1);
883: }
884: }
885:
886: /**
887: *
888: * void
889: * atstart() - start or restart next disk read/write operation.
890: *
891: * Action: Initiate disk read/write operation.
892: */
893: static void
894: atstart()
895: {
896: register struct dparm_s *dp;
897:
898: dp = &atparm[ at.at_drv ];
899:
900: at.at_cyl = (at.at_bno / dp->d_nspt) / dp->d_nhead;
901: at.at_head = (at.at_bno / dp->d_nspt) % dp->d_nhead;
902: at.at_sec = (at.at_bno % dp->d_nspt) + 1;
903:
904: /*
905: * Check for repeated access to most recently identified bad track.
906: */
907: if ((at.at_drv == at.at_bad_drv)
908: && (at.at_cyl == at.at_bad_cyl)
909: && (at.at_head == at.at_bad_head)) {
910: BUF * bp = at.at_actf;
911: printf("at%d%c: bno=%U head=%u cyl=%u <Track Flagged Bad>\n",
912: at.at_drv,
913: (bp->b_dev & SDEV) ? 'x' : at.at_partn % NPARTN + 'a',
914: bp->b_bno,
915: at.at_head,
916: at.at_cyl);
917: bp->b_flag |= BFERR;
918: atdone(bp);
919: return;
920: }
921:
922: myatbsyw(at.at_drv);
923:
924: outb(HF_REG, dp->d_ctrl);
925: outb(AUX_REG, dp->d_wpcc / 4);
926: outb(NSEC_REG, at.at_nsec);
927: outb(SEC_REG, at.at_sec);
928: outb(LCYL_REG, at.at_cyl);
929: outb(HCYL_REG, at.at_cyl >> 8);
930: outb(HDRV_REG, (at.at_drv << 4) + at.at_head + 0xA0);
931:
932: if (at.at_actf->b_req == BWRITE) {
933:
934: outb(CSR_REG, WRITE_CMD);
935:
936: while (atdrq() == 0)
937: printf(timeout_msg, at.at_drv);
938:
939: atsend(at.at_addr);
940: at.at_state = SWRITE;
941: }
942: else {
943: outb(CSR_REG, READ_CMD);
944: at.at_state = SREAD;
945: }
946: drvl[AT_MAJOR].d_time = ATSECS;
947: }
948:
949: /**
950: *
951: * void
952: * atintr() - Interrupt routine.
953: *
954: * Clear interrupt then defer actual processing.
955: */
956: static void
957: atintr()
958: {
959: inb(CSR_REG); /* clears controller interrupt */
960: defer(atdefer, 0);
961: }
962:
963: /**
964: *
965: * void
966: * atdefer() - Deferred service of hard disk interrupt.
967: *
968: * Action: Service disk interrupt.
969: * Transfer required data.
970: * Update state.
971: */
972: static void
973: atdefer()
974: {
975: register BUF * bp = at.at_actf;
976:
977: switch (at.at_state) {
978:
979: case SRETRY:
980: atstart();
981: break;
982:
983: case SREAD:
984: /*
985: * Check for I/O error before waiting for data.
986: */
987: if (aterror()) {
988: atrecov();
989: break;
990: }
991:
992: /*
993: * Wait for data, or forever.
994: */
995: if (atdrq() == 0)
996: printf(timeout_msg, at.at_drv);
997:
998: #if ATCACHE > 0
999: /*
1000: * Cache data block.
1001: */
1002: if (at.at_caching == at.at_nsec) {
1003: #ifdef _I386
1004: atrecv(at.at_cbuf[ at.at_nsec - 1 ]);
1005: #else
1006: atrecv(at.at_cbuf[ at.at_nsec - 1 ], sds);
1007: #endif
1008: } else
1009: #endif
1010: /*
1011: * Read data block.
1012: */
1013: atrecv(at.at_addr);
1014:
1015: /*
1016: * Check for I/O error after reading data.
1017: */
1018: if (aterror()) {
1019: atrecov();
1020: break;
1021: }
1022:
1023: #if ATCACHE > 0
1024: /*
1025: * Validate cached blocks.
1026: */
1027: if (at.at_caching == at.at_nsec) {
1028: at.at_cbno[ at.at_nsec - 1 ] = at.at_bno;
1029: at.at_cdrv[ at.at_nsec - 1 ] = at.at_drv;
1030: at.at_caching--;
1031: }
1032: else
1033: #endif
1034: {
1035: #ifdef _I386
1036: at.at_addr += BSIZE;
1037: #else
1038: FP_OFF(at.at_addr) += BSIZE;
1039: #endif
1040: bp->b_resid -= BSIZE;
1041: }
1042:
1043: at.at_tries = 0;
1044: at.at_bno++;
1045:
1046: /*
1047: * Check for end of transfer.
1048: */
1049: if (--at.at_nsec == 0)
1050: atdone(bp);
1051: break;
1052:
1053: case SWRITE:
1054: /*
1055: * Check for I/O error.
1056: */
1057: if (aterror()) {
1058: atrecov();
1059: break;
1060: }
1061:
1062: #ifdef _I386
1063: at.at_addr += BSIZE;
1064: #else
1065: FP_OFF(at.at_addr) += BSIZE;
1066: #endif
1067: bp->b_resid -= BSIZE;
1068: at.at_tries = 0;
1069: at.at_bno++;
1070:
1071: /*
1072: * Check for end of transfer.
1073: */
1074: if (--at.at_nsec == 0) {
1075: atdone(bp);
1076: break;
1077: }
1078:
1079: /*
1080: * Wait for ability to send data, or forever.
1081: */
1082: while (atdrq() == 0)
1083: printf(timeout_msg, at.at_drv);
1084:
1085: /*
1086: * Send data block.
1087: */
1088: atsend(at.at_addr);
1089: }
1090: }
1091:
1092: /**
1093: *
1094: * int
1095: * aterror()
1096: *
1097: * Action: Check for drive error.
1098: * If found, increment error count and report it.
1099: *
1100: * Return: 0 = No error found.
1101: * 1 = Error occurred.
1102: */
1103: static int
1104: aterror()
1105: {
1106: register BUF * bp = at.at_actf;
1107: register int csr;
1108: register int aux;
1109:
1110: if ((csr = inb(ATSREG)) & (ERR_ST|WFLT_ST)) {
1111:
1112: aux = inb(AUX_REG);
1113:
1114: /*
1115: * Don't retry or report failures on cache reads.
1116: */
1117: #if ATCACHE > 0
1118: if ((at.at_state == SREAD) && (at.at_caching == at.at_nsec)) {
1119: at.at_tries = BADLIM;
1120: return 1;
1121: }
1122: #endif
1123:
1124: if (aux & BAD_ERR) {
1125: at.at_tries = BADLIM;
1126: at.at_bad_drv = at.at_drv;
1127: at.at_bad_head = at.at_head;
1128: at.at_bad_cyl = at.at_cyl;
1129: }
1130: else if (++at.at_tries < SOFTLIM)
1131: return 1;
1132:
1133: printf("at%d%c: bno=%U head=%u cyl=%u",
1134: at.at_drv,
1135: (bp->b_dev & SDEV) ? 'x' : at.at_partn % NPARTN + 'a',
1136: (bp->b_count/BSIZE) + bp->b_bno
1137: + at.at_caching - at.at_nsec,
1138: at.at_head, at.at_cyl);
1139:
1140: #if VERBOSE > 0
1141: if ((csr & RDY_ST) == 0)
1142: printf(" <Drive Not Ready>");
1143: if (csr & WFLT_ST)
1144: printf(" <Write Fault>");
1145:
1146: if (aux & DAM_ERR)
1147: printf(" <No Data Addr Mark>");
1148: if (aux & TR0_ERR)
1149: printf(" <Track 0 Not Found>");
1150: if (aux & ID_ERR)
1151: printf(" <ID Not Found>");
1152: if (aux & ECC_ERR)
1153: printf(" <Bad Data Checksum>");
1154: if (aux & ABT_ERR)
1155: printf(" <Command Aborted>");
1156: #else
1157: if ((csr & (RDY_ST|WFLT_ST)) != RDY_ST)
1158: printf(" csr=%x", csr);
1159: if (aux & (DAM_ERR|TR0_ERR|ID_ERR|ECC_ERR|ABT_ERR))
1160: printf(" aux=%x", aux);
1161: #endif
1162: if (aux & BAD_ERR)
1163: printf(" <Block Flagged Bad>");
1164:
1165: if (at.at_tries < HARDLIM)
1166: printf(" retrying...");
1167: printf("\n");
1168: return 1;
1169: }
1170: return 0;
1171: }
1172:
1173: /**
1174: *
1175: * void
1176: * atrecov()
1177: *
1178: * Action: Attempt recovery.
1179: */
1180: static void
1181: atrecov()
1182: {
1183: register BUF *bp = at.at_actf;
1184: register int cmd = SEEK(0);
1185: register int cyl = at.at_cyl;
1186:
1187: switch (at.at_tries) {
1188:
1189: case 1:
1190: case 2:
1191: /*
1192: * Move in 1 cylinder, then retry operation
1193: */
1194: if (--cyl < 0)
1195: cyl += 2;
1196: break;
1197:
1198: case 3:
1199: case 4:
1200: /*
1201: * Move out 1 cylinder, then retry operation
1202: */
1203: if (++cyl >= atparm[ at.at_drv ].d_ncyl)
1204: cyl -= 2;
1205: break;
1206:
1207: case 5:
1208: case 6:
1209: /*
1210: * Seek to cylinder 0, then retry operation
1211: */
1212: cyl = 0;
1213: break;
1214:
1215: default:
1216: /*
1217: * Restore drive, then retry operation
1218: */
1219: cmd = RESTORE(0);
1220: cyl = 0;
1221: break;
1222: }
1223:
1224: /*
1225: * Retry operation [after repositioning head]
1226: */
1227: if (at.at_tries < HARDLIM) {
1228: drvl[AT_MAJOR].d_time = (cmd == RESTORE(0))
1229: ? (ATSECS * 2) : ATSECS;
1230: outb(LCYL_REG, cyl);
1231: outb(HCYL_REG, cyl >> 8);
1232: outb(HDRV_REG, (at.at_drv << 4) + 0xA0);
1233: outb(CSR_REG, cmd);
1234: at.at_state = SRETRY;
1235: }
1236:
1237: /*
1238: * Give up on block.
1239: */
1240: else {
1241: /*
1242: * Not a cache-read error.
1243: */
1244: #if ATCACHE > 0
1245: if ((at.at_state != SREAD) || (at.at_caching != at.at_nsec))
1246: #endif
1247: bp->b_flag |= BFERR;
1248:
1249: atdone(bp);
1250: }
1251: }
1252:
1253: /**
1254: *
1255: * void
1256: * atdone(bp)
1257: * BUF * bp;
1258: *
1259: * Action: Release current i/o buffer to the O/S.
1260: */
1261: static void
1262: atdone(bp)
1263: register BUF * bp;
1264: {
1265: drvl[AT_MAJOR].d_time = 0;
1266: at.at_state = SIDLE;
1267: at.at_actf = bp->b_actf;
1268: bdone(bp);
1269:
1270: if (atdequeue())
1271: atstart();
1272: }
1273:
1274: int
1275: notBusy()
1276: {
1277: return (inb(ATSREG) & BSY_ST) == 0;
1278: }
1279:
1280: int
1281: dataRequested()
1282: {
1283: return inb(ATSREG) & DRQ_ST;
1284: }
1285:
1286: /*
1287: * Wait while controller is busy.
1288: *
1289: * Return 0 if timeout, nonzero if not busy.
1290: */
1291: int
1292: myatbsyw(unit) int unit;
1293: {
1294: if (busyWait(notBusy, ATSECS * HZ))
1295: return 1;
1296: printf(timeout_msg, unit);
1297: return 0;
1298: }
1299:
1300: /*
1301: * Wait for controller to initiate request.
1302: *
1303: * Return 0 if timeout, 1 if data requested.
1304: */
1305: int
1306: atdrq()
1307: {
1308: return busyWait(dataRequested, ATSECS * HZ);
1309: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.