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