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