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