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