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