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