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