|
|
1.1 root 1: /*-
2: * Copyright (c) 1990 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * William Jolitz.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: * @(#)wd.c 7.3 (Berkeley) 5/4/91
1.1.1.4 ! root 37: *
! 38: * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
! 39: * -------------------- ----- ----------------------
! 40: * CURRENT PATCH LEVEL: 1 00049
! 41: * -------------------- ----- ----------------------
! 42: *
! 43: * 06 Sep 92 Robert D. Thrush Fix for HD not booting after install
1.1 root 44: */
45:
46: /* device driver for winchester disk */
47:
48: #include "param.h"
49: #include "dkbad.h"
50: #include "disklabel.h"
51: #include "i386/isa/isa.h"
52: #include "i386/isa/wdreg.h"
53: #include "saio.h"
54:
1.1.1.3 root 55: #define SMALL
56: #define NWD 1 /* number of hard disk units supported, max 2 */
1.1 root 57: #define RETRIES 5 /* number of retries before giving up */
58:
59: int noretries, wdquiet;
1.1.1.3 root 60: /* #define WDDEBUG*/
1.1 root 61:
62: #ifdef SMALL
63: extern struct disklabel disklabel;
64: #else
65: struct disklabel wdsizes[NWD];
66: #endif
67:
68: extern cyloffset ; /* bootstrap's idea of cylinder for disklabel */
69:
70: /*
71: * Record for the bad block forwarding code.
72: * This is initialized to be empty until the bad-sector table
73: * is read from the disk.
74: */
75: #define TRKSEC(trk,sec) ((trk << 8) + sec)
76:
77: struct dkbad dkbad[NWD];
78: static wdcport;
79:
80: wdopen(io)
81: register struct iob *io;
82: {
83: register struct disklabel *dd;
84:
85: #ifdef WDDEBUG
86: printf("wdopen ");
87: #endif
88: #ifdef SMALL
89: dd = &disklabel;
90: #else
91: dd = &wdsizes[io->i_unit];
92: if (io->i_part > 8)
93: _stop("Invalid partition number");
94: if(io->i_ctlr > 1)
95: _stop("Invalid controller number");
96: #endif
97: if (wdinit(io))
98: _stop("wd initialization error");
99: io->i_boff = dd->d_partitions[io->i_part].p_offset ;
1.1.1.3 root 100: /*printf("boff %d ", io->i_boff);*/
1.1 root 101: return(0);
102: }
103:
104: wdstrategy(io,func)
105: register struct iob *io;
106: {
107: register int iosize; /* number of sectors to do IO for this loop */
108: register daddr_t sector;
109: int nblocks, cyloff;
110: int unit, partition;
111: char *address;
112: register struct disklabel *dd;
113:
114: unit = io->i_unit;
115: partition = io->i_part;
116: #ifdef WDDEBUG
117: printf("wdstrat %d %d ", unit, partition);
118: #endif
119: #ifdef SMALL
120: dd = &disklabel;
121: #else
122: dd = &wdsizes[unit];
123: #endif
124: iosize = io->i_cc / dd->d_secsize;
125: /*
126: * Convert PGSIZE "blocks" to sectors.
127: * Note: doing the conversions this way limits the partition size
128: * to about 8 million sectors (1-8 Gb).
129: */
1.1.1.3 root 130: /*printf("bn%d ", io->i_bn);*/
1.1 root 131: sector = (unsigned long) io->i_bn * DEV_BSIZE / dd->d_secsize;
132: nblocks = dd->d_partitions[partition].p_size;
133: #ifndef SMALL
134: if (iosize < 0 || sector + iosize > nblocks || sector < 0) {
135: #ifdef WDDEBUG
136: printf("bn = %d; sectors = %d; partition = %d; fssize = %d\n",
137: io->i_bn, iosize, partition, nblocks);
138: #endif
139: printf("wdstrategy - I/O out of filesystem boundaries\n");
140: return(-1);
141: }
142: if (io->i_bn * DEV_BSIZE % dd->d_secsize) {
143: printf("wdstrategy - transfer starts in midsector\n");
144: return(-1);
145: }
146: if (io->i_cc % dd->d_secsize) {
147: printf("wd: transfer of partial sector\n");
148: return(-1);
149: }
150: #endif
1.1.1.3 root 151: sector += io->i_boff;
1.1 root 152:
153: address = io->i_ma;
154: while (iosize > 0) {
155: if (wdio(func, unit, sector, address))
156: return(-1);
157: iosize--;
158: sector++;
159: address += dd->d_secsize;
160: }
161: return(io->i_cc);
162: }
163:
164: /*
165: * Routine to do a one-sector I/O operation, and wait for it
166: * to complete.
167: */
168: wdio(func, unit, blknm, addr)
169: short *addr;
170: {
171: struct disklabel *dd;
172: register wdc = wdcport;
173: struct bt_bad *bt_ptr;
174: int i;
175: int retries = 0;
176: long cylin, head, sector;
177: u_char opcode, erro;
178:
179: #ifdef SMALL
180: dd = &disklabel;
181: #else
182: dd = &wdsizes[unit];
183: #endif
184: if (func == F_WRITE)
185: opcode = WDCC_WRITE;
186: else
187: opcode = WDCC_READ;
188:
189: /* Calculate data for output. */
190: cylin = blknm / dd->d_secpercyl;
191: head = (blknm % dd->d_secpercyl) / dd->d_nsectors;
192: sector = blknm % dd->d_nsectors;
193:
194: /*
195: * See if the current block is in the bad block list.
196: */
197: if (blknm > BBSIZE/DEV_BSIZE) /* should be BBSIZE */
198: for (bt_ptr = dkbad[unit].bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) {
199: if (bt_ptr->bt_cyl > cylin)
200: /* Sorted list, and we passed our cylinder. quit. */
201: break;
202: if (bt_ptr->bt_cyl == cylin &&
203: bt_ptr->bt_trksec == (head << 8) + sector) {
204: /*
205: * Found bad block. Calculate new block addr.
206: * This starts at the end of the disk (skip the
207: * last track which is used for the bad block list),
208: * and works backwards to the front of the disk.
209: */
210: #ifdef WDDEBUG
211: printf("--- badblock code -> Old = %d; ",
212: blknm);
213: #endif
1.1.1.3 root 214: printf("--- badblock code -> Old = %d; ",
215: blknm);
1.1 root 216: blknm = dd->d_secperunit - dd->d_nsectors
217: - (bt_ptr - dkbad[unit].bt_bad) - 1;
218: cylin = blknm / dd->d_secpercyl;
219: head = (blknm % dd->d_secpercyl) / dd->d_nsectors;
220: sector = blknm % dd->d_nsectors;
221: #ifdef WDDEBUG
222: printf("new = %d\n", blknm);
223: #endif
224: break;
225: }
226: }
227:
228: sector += 1;
229: retry:
230: #ifdef WDDEBUG
231: printf("sec %d sdh %x cylin %d ", sector,
232: WDSD_IBM | (unit<<4) | (head & 0xf), cylin);
233: #endif
1.1.1.3 root 234: /*printf("c %d h %d s %d ", cylin, head, sector);*/
1.1 root 235: outb(wdc+wd_precomp, 0xff);
236: outb(wdc+wd_seccnt, 1);
237: outb(wdc+wd_sector, sector);
238: outb(wdc+wd_cyl_lo, cylin);
239: outb(wdc+wd_cyl_hi, cylin >> 8);
240:
241: /* Set up the SDH register (select drive). */
242: outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
243: while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
244:
245: outb(wdc+wd_command, opcode);
246: while (opcode == WDCC_READ && (inb(wdc+wd_status) & WDCS_BUSY))
247: ;
248: /* Did we get an error? */
249: if (opcode == WDCC_READ && (inb(wdc+wd_status) & WDCS_ERR))
250: goto error;
251:
252: /* Ready to remove data? */
253: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
254:
255: if (opcode == WDCC_READ)
256: insw(wdc+wd_data,addr,256);
257: else outsw(wdc+wd_data,addr,256);
258:
259: /* Check data request (should be done). */
260: if (inb(wdc+wd_status) & WDCS_DRQ) goto error;
261:
262: while (opcode == WDCC_WRITE && (inb(wdc+wd_status) & WDCS_BUSY)) ;
263:
264: if (inb(wdc+wd_status) & WDCS_ERR) goto error;
265:
266: #ifdef WDDEBUG
1.1.1.2 root 267: printf("addr %x",addr);
1.1 root 268: #endif
269: return (0);
270: error:
271: erro = inb(wdc+wd_error);
272: if (++retries < RETRIES)
273: goto retry;
274: if (!wdquiet)
275: printf("wd%d: hard %s error: sector %d status %b error %b\n", unit,
276: opcode == WDCC_READ? "read" : "write", blknm,
277: inb(wdc+wd_status), WDCS_BITS, erro, WDERR_BITS);
278: return (-1);
279: }
280:
281: wdinit(io)
282: struct iob *io;
283: {
284: register wdc;
285: struct disklabel *dd;
286: unsigned int unit;
287: struct dkbad *db;
288: int i, errcnt = 0;
289: char buf[512];
290: static open[NWD];
291:
292: unit = io->i_unit;
293: if (open[unit]) return(0);
294:
295: wdcport = io->i_ctlr ? IO_WD2 : IO_WD1;
296: wdc = wdcport;
297:
298: #ifdef SMALL
299: dd = &disklabel;
300: #else
301: dd = &wdsizes[unit];
1.1.1.3 root 302: #endif
303:
304: /* reset controller */
305: outb(wdc+wd_ctlr,6);
306: DELAY(1000);
307: outb(wdc+wd_ctlr,2);
308: DELAY(1000);
1.1.1.4 ! root 309: while(inb(wdc+wd_status) & WDCS_BUSY); /* 06 Sep 92*/
1.1.1.3 root 310: outb(wdc+wd_ctlr,8);
1.1 root 311:
312: /* set SDH, step rate, do restore to recalibrate drive */
1.1.1.3 root 313: tryagainrecal:
1.1 root 314: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
315: wdwait();
316: outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
317: wdwait();
318: if ((i = inb(wdc+wd_status)) & WDCS_ERR) {
319: printf("wd%d: recal status %b error %b\n",
320: unit, i, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
321: if (++errcnt < 10)
322: goto tryagainrecal;
323: return(-1);
324: }
325:
1.1.1.3 root 326: #ifndef SMALL
1.1 root 327: /*
328: * Some controllers require this (after a recal they
329: * revert to a logical translation mode to compensate for
330: * dos limitation on 10-bit cylinders -- *shudder* -wfj)
1.1.1.3 root 331: * note: heads *must* be fewer than or equal to 8 to
1.1 root 332: * compensate for some IDE drives that latch this for all time.
333: */
334: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4) + 8 -1);
335: outb(wdc+wd_seccnt, 35 );
336: outb(wdc+wd_cyl_lo, 1224);
337: outb(wdc+wd_cyl_hi, 1224/256);
338: outb(wdc+wd_command, 0x91);
339: while (inb(wdc+wd_status) & WDCS_BUSY) ;
340:
341: errcnt = 0;
342: retry:
343: /*
344: * Read in LABELSECTOR to get the pack label and geometry.
345: */
346: outb(wdc+wd_precomp, 0xff); /* sometimes this is head bit 3 */
347: outb(wdc+wd_seccnt, 1);
348: outb(wdc+wd_sector, LABELSECTOR + 1);
349: outb(wdc+wd_cyl_lo, (cyloffset & 0xff));
350: outb(wdc+wd_cyl_hi, (cyloffset >> 8));
351: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
352: wdwait();
353: outb(wdc+wd_command, WDCC_READ);
354: wdwait();
355: if ((i = inb(wdc+wd_status)) & WDCS_ERR) {
356: int err;
357:
358: err = inb(wdc+wd_error);
359: if (++errcnt < RETRIES)
360: goto retry;
361: if (!wdquiet)
362: printf("wd%d: reading label, status %b error %b\n",
363: unit, i, WDCS_BITS, err, WDERR_BITS);
364: return(-1);
365: }
366:
367: /* Ready to remove data? */
368: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
369:
370: i = insw(wdc+wd_data, buf, 256);
371:
372: #ifdef WDDEBUG
373: printf("magic %x,insw %x, %x\n",
374: ((struct disklabel *) (buf + LABELOFFSET))->d_magic, i, buf);
375: #endif
376: if (((struct disklabel *) (buf + LABELOFFSET))->d_magic == DISKMAGIC) {
377: *dd = * (struct disklabel *) (buf + LABELOFFSET);
378: open[unit] = 1;
379: } else {
380: if (!wdquiet)
381: printf("wd%d: bad disk label\n", unit);
382: if (io->i_flgs & F_FILE) return(-1);
383: dkbad[unit].bt_bad[0].bt_cyl = -1;
384: dd->d_secpercyl = 1999999 ; dd->d_nsectors = 17 ;
385: dd->d_secsize = 512;
386: outb(wdc+wd_precomp, 0xff); /* force head 3 bit off */
387: return (0) ;
388: }
389: #ifdef WDDEBUG
390: printf("magic %x sect %d\n", dd->d_magic, dd->d_nsectors);
391: #endif
1.1.1.3 root 392: #endif !SMALL
1.1 root 393:
1.1.1.3 root 394: /*printf("C%dH%dS%d ", dd->d_ncylinders, dd->d_ntracks, dd->d_nsectors);*/
1.1 root 395:
396: /* now that we know the disk geometry, tell the controller */
1.1.1.3 root 397: outb(wdc+wd_cyl_lo, dd->d_ncylinders+1);
398: outb(wdc+wd_cyl_hi, (dd->d_ncylinders+1)>>8);
1.1 root 399: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4) + dd->d_ntracks-1);
400: outb(wdc+wd_seccnt, dd->d_nsectors);
401: outb(wdc+wd_command, 0x91);
402: while (inb(wdc+wd_status) & WDCS_BUSY) ;
403:
404: dkbad[unit].bt_bad[0].bt_cyl = -1;
405:
1.1.1.3 root 406: if (dd->d_flags & D_BADSECT) {
1.1 root 407: /*
408: * Read bad sector table into memory.
409: */
410: i = 0;
411: do {
412: int blknm = dd->d_secperunit - dd->d_nsectors + i;
413: errcnt = wdio(F_READ, unit, blknm, buf);
414: } while (errcnt && (i += 2) < 10 && i < dd->d_nsectors);
415: db = (struct dkbad *)(buf);
416: #define DKBAD_MAGIC 0x4321
417: if (errcnt == 0 && db->bt_mbz == 0 && db->bt_flag == DKBAD_MAGIC)
418: dkbad[unit] = *db;
419: else {
420: if (!wdquiet)
421: printf("wd%d: error in bad-sector file\n", unit);
422: dkbad[unit].bt_bad[0].bt_cyl = -1;
423: }
1.1.1.3 root 424: }
1.1 root 425: return(0);
426: }
427:
428: wdwait()
429: {
430: register wdc = wdcport;
431: register i = 0;
432:
433: while (inb(wdc+wd_status) & WDCS_BUSY)
434: ;
435: while ((inb(wdc+wd_status) & WDCS_READY) == 0)
436: if (i++ > 100000)
437: return(-1);
438: return(0);
439: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.