|
|
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.2 (Berkeley) 5/9/91
37: */
38:
39: /* TODO:peel out buffer at low ipl,
40: speed improvement, rewrite to clean code from garbage artifacts */
41:
42:
43: #include "wd.h"
44: #if NWD > 0
45:
46: #include "param.h"
47: #include "dkbad.h"
48: #include "systm.h"
49: #include "conf.h"
50: #include "file.h"
51: #include "stat.h"
52: #include "ioctl.h"
53: #include "disklabel.h"
54: #include "buf.h"
55: #include "uio.h"
56: #include "i386/isa/isa_device.h"
57: #include "i386/isa/icu.h"
58: #include "i386/isa/wdreg.h"
59: #include "syslog.h"
60: #include "vm/vm.h"
61:
62: #define RETRIES 5 /* number of retries before giving up */
63: #define MAXTRANSFER 32 /* max size of transfer in page clusters */
64:
1.1.1.2 ! root 65: #define wdctlr(dev) ((minor(dev) & 0x20) >> 5)
! 66: #define wdunit(dev) ((minor(dev) & 0x18) >> 3)
! 67: #define wdpart(dev) ((minor(dev) & 0x7))
1.1 root 68:
69: #define b_cylin b_resid /* cylinder number for doing IO to */
70: /* shares an entry in the buf struct */
71:
72: /*
73: * Drive states. Used for open and format operations.
74: * States < OPEN (> 0) are transient, during an open operation.
75: * OPENRAW is used for unlabeled disks, and for floppies, to inhibit
76: * bad-sector forwarding.
77: */
78: #define RAWDISK 8 /* raw disk operation, no translation*/
79: #define ISRAWSTATE(s) (RAWDISK&(s)) /* are we in a raw state? */
80: #define DISKSTATE(s) (~RAWDISK&(s)) /* are we in a given state regardless
81: of raw or cooked mode? */
82:
83: #define CLOSED 0 /* disk is closed. */
84: /* "cooked" disk states */
85: #define WANTOPEN 1 /* open requested, not started */
86: #define RECAL 2 /* doing restore */
87: #define RDLABEL 3 /* reading pack label */
88: #define RDBADTBL 4 /* reading bad-sector table */
89: #define OPEN 5 /* done with open */
90:
91: #define WANTOPENRAW (WANTOPEN|RAWDISK) /* raw WANTOPEN */
92: #define RECALRAW (RECAL|RAWDISK) /* raw open, doing restore */
93: #define OPENRAW (OPEN|RAWDISK) /* open, but unlabeled disk or floppy */
94:
95:
96: /*
97: * The structure of a disk drive.
98: */
99: struct disk {
100: struct disklabel dk_dd; /* device configuration data */
101: long dk_bc; /* byte count left */
102: short dk_skip; /* blocks already transferred */
103: char dk_unit; /* physical unit number */
104: char dk_state; /* control state */
105: u_char dk_status; /* copy of status reg. */
106: u_char dk_error; /* copy of error reg. */
107: short dk_open; /* open/closed refcnt */
108: u_long dk_copenpart; /* character units open on this drive */
109: u_long dk_bopenpart; /* block units open on this drive */
110: u_long dk_openpart; /* all units open on this drive */
111: short dk_wlabel; /* label writable? */
112: };
113:
114: /*
115: * This label is used as a default when initializing a new or raw disk.
116: * It really only lets us access the first track until we know more.
117: */
118: struct disklabel dflt_sizes = {
119: DISKMAGIC, DTYPE_ST506, 0, "default", "",
120: 512, /* sector size */
121: 17, /* # of sectors per track */
122: 8, /* # of tracks per cylinder */
123: 766, /* # of cylinders per unit */
124: 17*8, /* # of sectors per cylinder */
125: 766*8*17, /* # of sectors per unit */
126: 0, /* # of spare sectors per track */
127: 0, /* # of spare sectors per cylinder */
128: 0, /* # of alt. cylinders per unit */
129: 3600, /* rotational speed */
130: 1, /* hardware sector interleave */
131: 0, /* sector 0 skew, per track */
132: 0, /* sector 0 skew, per cylinder */
133: 0, /* head switch time, usec */
134: 0, /* track-to-track seek, usec */
135: 0, /* generic flags */
136: 0,0,0,0,0,
137: 0,0,0,0,0,
138: DISKMAGIC,
139: 0,
140: 8,
141: 8192,
142: 8192,
143:
144: {{21600, 0, 0,0,0,0}, /* A=root filesystem */
1.1.1.2 ! root 145: {21600, 21600, 0,0,0,0},
1.1 root 146: {660890, 0, 0,0,0,0}, /* C=whole disk */
147: {216000, 80, 0,0,0,0},
148: {0, 0, 0,0,0,0},
149: {0, 0, 0,0,0,0},
150: {0, 0, 0,0,0,0},
151: {399600, 480, 0,0,0,0}}
152: };
153:
154: static struct dkbad dkbad[NWD];
155: struct disk wddrives[NWD] = {0}; /* table of units */
156: struct buf wdtab = {0};
157: struct buf wdutab[NWD] = {0}; /* head of queue per drive */
158: struct buf rwdbuf[NWD] = {0}; /* buffers for raw IO */
159: long wdxfer[NWD] = {0}; /* count of transfers */
160: int writeprotected[NWD] = { 0 };
161: int wdprobe(), wdattach(), wdintr();
162: struct isa_driver wddriver = {
163: wdprobe, wdattach, "wd",
164: };
165:
166: static wdc;
167: /*
168: * Probe routine
169: */
170: wdprobe(dvp)
171: struct isa_device *dvp;
172: {
173: wdc = dvp->id_iobase;
174:
175: #ifdef lint
176: wdintr(0);
177: #endif
178: /* XXX sorry, needs to be better */
179: outb(wdc+wd_error, 0x5a) ; /* error register not writable */
180: outb(wdc+wd_cyl_lo, 0xa5) ; /* but all of cyllo are implemented */
181: if(inb(wdc+wd_error) != 0x5a && inb(wdc+wd_cyl_lo) == 0xa5)
182: return(1) ;
183: return (0);
184: }
185:
186: /*
187: * attach each drive if possible.
188: */
189: wdattach(dvp)
190: struct isa_device *dvp;
191: {
192: int unit = dvp->id_unit;
193:
194: outb(wdc+wd_ctlr,12);
195: DELAY(1000);
196: outb(wdc+wd_ctlr,8);
197: }
198:
199: /* Read/write routine for a buffer. Finds the proper unit, range checks
200: * arguments, and schedules the transfer. Does not wait for the transfer
201: * to complete. Multi-page transfers are supported. All I/O requests must
202: * be a multiple of a sector in length.
203: */
204: wdstrategy(bp)
205: register struct buf *bp; /* IO operation to perform */
206: {
207: register struct buf *dp;
208: register struct disk *du; /* Disk unit to do the IO. */
209: register struct partition *p;
210: long maxsz, sz;
211: int unit = wdunit(bp->b_dev);
212: int s;
213:
214: if ((unit >= NWD) || (bp->b_blkno < 0)) {
215: printf("wdstrat: unit = %d, blkno = %d, bcount = %d\n",
216: unit, bp->b_blkno, bp->b_bcount);
217: pg("wd:error in wdstrategy");
218: bp->b_flags |= B_ERROR;
219: goto bad;
220: }
221: if (writeprotected[unit] && (bp->b_flags & B_READ) == 0) {
222: printf("wd%d: write protected\n", unit);
223: goto bad;
224: }
225: du = &wddrives[unit];
226: if (DISKSTATE(du->dk_state) != OPEN)
227: goto q;
228: #ifdef old
229: /*
230: * Convert DEV_BSIZE "blocks" to sectors.
231: * Note: doing the conversions this way limits the partition size
232: * to about 8 million sectors (1-8 Gb).
233: */
234: blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize;
235: if (((u_long) bp->b_blkno * DEV_BSIZE % du->dk_dd.d_secsize != 0) ||
236: bp->b_bcount >= MAXTRANSFER * CLBYTES) {
237: bp->b_flags |= B_ERROR;
238: goto bad;
239: }
240: nblocks = du->dk_dd.d_partitions[part].p_size;
241: cyloff = du->dk_dd.d_partitions[part].p_offset;
242: if (blknum + (bp->b_bcount / du->dk_dd.d_secsize) > nblocks) {
243: if (blknum == nblocks)
244: bp->b_resid = bp->b_bcount;
245: else
246: bp->b_flags |= B_ERROR;
247: goto bad;
248: }
249: bp->b_cylin = blknum / du->dk_dd.d_secpercyl + cyloff;
250: #else
251: /*
252: * Determine the size of the transfer, and make sure it is
253: * within the boundaries of the partition.
254: */
255: p = &du->dk_dd.d_partitions[wdpart(bp->b_dev)];
256: maxsz = p->p_size;
257: sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT;
258: if (bp->b_blkno + p->p_offset <= LABELSECTOR &&
259: #if LABELSECTOR != 0
260: bp->b_blkno + p->p_offset + sz > LABELSECTOR &&
261: #endif
262: (bp->b_flags & B_READ) == 0 && du->dk_wlabel == 0) {
263: bp->b_error = EROFS;
264: goto bad;
265: }
266: if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) {
267: /* if exactly at end of disk, return an EOF */
268: if (bp->b_blkno == maxsz) {
269: bp->b_resid = bp->b_bcount;
270: biodone(bp);
271: return;
272: }
273: /* or truncate if part of it fits */
274: sz = maxsz - bp->b_blkno;
275: if (sz <= 0)
276: goto bad;
277: bp->b_bcount = sz << DEV_BSHIFT;
278: }
279: bp->b_cylin = (bp->b_blkno + p->p_offset) / du->dk_dd.d_secpercyl;
280: #endif
281: q:
282: dp = &wdutab[unit];
283: s = splhigh();
284: disksort(dp, bp);
285: if (dp->b_active == 0)
286: wdustart(du); /* start drive if idle */
287: if (wdtab.b_active == 0)
288: wdstart(s); /* start IO if controller idle */
289: splx(s);
290: return;
291:
292: bad:
293: bp->b_error = EINVAL;
294: biodone(bp);
295: }
296:
297: /* Routine to queue a read or write command to the controller. The request is
298: * linked into the active list for the controller. If the controller is idle,
299: * the transfer is started.
300: */
301: wdustart(du)
302: register struct disk *du;
303: {
304: register struct buf *bp, *dp;
305:
306: dp = &wdutab[du->dk_unit];
307: if (dp->b_active)
308: return;
309: bp = dp->b_actf;
310: if (bp == NULL)
311: return;
312: dp->b_forw = NULL;
313: if (wdtab.b_actf == NULL) /* link unit into active list */
314: wdtab.b_actf = dp;
315: else
316: wdtab.b_actl->b_forw = dp;
317: wdtab.b_actl = dp;
318: dp->b_active = 1; /* mark the drive as busy */
319: }
320:
321: /*
322: * Controller startup routine. This does the calculation, and starts
323: * a single-sector read or write operation. Called to start a transfer,
324: * or from the interrupt routine to continue a multi-sector transfer.
325: * RESTRICTIONS:
326: * 1. The transfer length must be an exact multiple of the sector size.
327: */
328:
329: static wd_sebyse;
330:
331: wdstart()
332: {
333: register struct disk *du; /* disk unit for IO */
334: register struct buf *bp;
335: struct buf *dp;
336: register struct bt_bad *bt_ptr;
337: long blknum, pagcnt, cylin, head, sector;
338: long secpertrk, secpercyl, addr, i;
339: int unit, s;
340:
341: loop:
342: dp = wdtab.b_actf;
343: if (dp == NULL)
344: return;
345: bp = dp->b_actf;
346: if (bp == NULL) {
347: wdtab.b_actf = dp->b_forw;
348: goto loop;
349: }
350: unit = wdunit(bp->b_dev);
351: du = &wddrives[unit];
352: if (DISKSTATE(du->dk_state) <= RDLABEL) {
353: if (wdcontrol(bp)) {
354: dp->b_actf = bp->av_forw;
355: goto loop; /* done */
356: }
357: return;
358: }
359: secpertrk = du->dk_dd.d_nsectors;
360: secpercyl = du->dk_dd.d_secpercyl;
361: /*
362: * Convert DEV_BSIZE "blocks" to sectors.
363: */
364: blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize
365: + du->dk_skip;
366: #ifdef WDDEBUG
367: if (du->dk_skip == 0) {
368: dprintf(DDSK,"\nwdstart %d: %s %d@%d; map ", unit,
369: (bp->b_flags & B_READ) ? "read" : "write",
370: bp->b_bcount, blknum);
371: } else {
372: dprintf(DDSK," %d)%x", du->dk_skip, inb(wdc+wd_altsts));
373: }
374: #endif
375:
376: addr = (int) bp->b_un.b_addr;
377: if(du->dk_skip==0) du->dk_bc = bp->b_bcount;
378: cylin = blknum / secpercyl;
379: head = (blknum % secpercyl) / secpertrk;
380: sector = blknum % secpertrk;
381: if (DISKSTATE(du->dk_state) == OPEN)
382: cylin += du->dk_dd.d_partitions[wdpart(bp->b_dev)].p_offset
383: / secpercyl;
384:
385: /*
386: * See if the current block is in the bad block list.
387: * (If we have one, and not formatting.)
388: */
389: if (DISKSTATE(du->dk_state) == OPEN && wd_sebyse)
390: for (bt_ptr = dkbad[unit].bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) {
391: if (bt_ptr->bt_cyl > cylin)
392: /* Sorted list, and we passed our cylinder. quit. */
393: break;
394: if (bt_ptr->bt_cyl == cylin &&
395: bt_ptr->bt_trksec == (head << 8) + sector) {
396: /*
397: * Found bad block. Calculate new block addr.
398: * This starts at the end of the disk (skip the
399: * last track which is used for the bad block list),
400: * and works backwards to the front of the disk.
401: */
402: #ifdef WDDEBUG
403: dprintf(DDSK,"--- badblock code -> Old = %d; ",
404: blknum);
405: #endif
406: blknum = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors
407: - (bt_ptr - dkbad[unit].bt_bad) - 1;
408: cylin = blknum / secpercyl;
409: head = (blknum % secpercyl) / secpertrk;
410: sector = blknum % secpertrk;
411: #ifdef WDDEBUG
412: dprintf(DDSK, "new = %d\n", blknum);
413: #endif
414: break;
415: }
416: }
417: sector += 1; /* sectors begin with 1, not 0 */
418:
419: wdtab.b_active = 1; /* mark controller active */
420:
421: if(du->dk_skip==0 || wd_sebyse) {
422: if(wdtab.b_errcnt && (bp->b_flags & B_READ) == 0) du->dk_bc += 512;
423: while ((inb(wdc+wd_status) & WDCS_BUSY) != 0) ;
424: /*while ((inb(wdc+wd_status) & WDCS_DRQ)) inb(wdc+wd_data);*/
425: outb(wdc+wd_precomp, 0xff);
426: /*wr(wdc+wd_precomp, du->dk_dd.dk_precompcyl / 4);*/
427: /*if (bp->b_flags & B_FORMAT) {
428: wr(wdc+wd_sector, du->dk_dd.dk_gap3);
429: wr(wdc+wd_seccnt, du->dk_dd.dk_nsectors);
430: } else {*/
431: if(wd_sebyse)
432: outb(wdc+wd_seccnt, 1);
433: else
434: outb(wdc+wd_seccnt, ((du->dk_bc +511) / 512));
435: outb(wdc+wd_sector, sector);
436:
437: outb(wdc+wd_cyl_lo, cylin);
438: outb(wdc+wd_cyl_hi, cylin >> 8);
439:
440: /* Set up the SDH register (select drive). */
441: outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
442: while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
443:
444: /*if (bp->b_flags & B_FORMAT)
445: wr(wdc+wd_command, WDCC_FORMAT);
446: else*/
447: outb(wdc+wd_command,
448: (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);
1.1.1.2 ! root 449: /*printf("sector %d cylin %d head %d addr %x sts %x\n",
! 450: sector, cylin, head, addr, inb(wdc+wd_altsts));*/
1.1 root 451: }
452:
453: /* If this is a read operation, just go away until it's done. */
454: if (bp->b_flags & B_READ) return;
455:
456: /* Ready to send data? */
457: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0);
458:
459: /* ASSUMES CONTIGUOUS MEMORY */
460: outsw (wdc+wd_data, addr+du->dk_skip*512, 256);
461: du->dk_bc -= 512;
462: }
463:
464: /*
465: * these are globally defined so they can be found
466: * by the debugger easily in the case of a system crash
467: */
468: daddr_t wd_errsector;
469: daddr_t wd_errbn;
470: unsigned char wd_errstat;
471:
472: /* Interrupt routine for the controller. Acknowledge the interrupt, check for
473: * errors on the current operation, mark it done if necessary, and start
474: * the next request. Also check for a partially done transfer, and
475: * continue with the next chunk if so.
476: */
477: wdintr(unit)
478: {
479: register struct disk *du;
480: register struct buf *bp, *dp;
481: int status;
482: char partch ;
483: static wd_haderror;
484:
485: /* Shouldn't need this, but it may be a slow controller. */
486: while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ;
487: if (!wdtab.b_active) {
488: printf("wd: extra interrupt\n");
489: return;
490: }
491:
492: #ifdef WDDEBUG
493: dprintf(DDSK,"I ");
494: #endif
495: dp = wdtab.b_actf;
496: bp = dp->b_actf;
497: du = &wddrives[wdunit(bp->b_dev)];
498: partch = wdpart(bp->b_dev) + 'a';
499: if (DISKSTATE(du->dk_state) <= RDLABEL) {
500: if (wdcontrol(bp))
501: goto done;
502: return;
503: }
504: if (status & (WDCS_ERR | WDCS_ECCCOR)) {
505: wd_errstat = inb(wdc+wd_error); /* save error status */
506: #ifdef WDDEBUG
507: printf("status %x error %x\n", status, wd_errstat);
508: #endif
509: if(wd_sebyse == 0) {
510: wd_haderror = 1;
511: goto outt;
512: }
513: /*if (bp->b_flags & B_FORMAT) {
514: du->dk_status = status;
515: du->dk_error = wdp->wd_error;
516: bp->b_flags |= B_ERROR;
517: goto done;
518: }*/
519:
520: wd_errsector = (bp->b_cylin * du->dk_dd.d_secpercyl) +
521: (((unsigned long) bp->b_blkno * DEV_BSIZE /
522: du->dk_dd.d_secsize) % du->dk_dd.d_secpercyl) +
523: du->dk_skip;
524: wd_errbn = bp->b_blkno
525: + du->dk_skip * du->dk_dd.d_secsize / DEV_BSIZE ;
526: if (status & WDCS_ERR) {
527: if (++wdtab.b_errcnt < RETRIES) {
528: wdtab.b_active = 0;
529: } else {
530: printf("wd%d%c: ", du->dk_unit, partch);
531: printf(
532: "hard %s error, sn %d bn %d status %b error %b\n",
533: (bp->b_flags & B_READ)? "read":"write",
534: wd_errsector, wd_errbn, status, WDCS_BITS,
535: wd_errstat, WDERR_BITS);
536: bp->b_flags |= B_ERROR; /* flag the error */
537: }
538: } else
539: log(LOG_WARNING,"wd%d%c: soft ecc sn %d bn %d\n",
540: du->dk_unit, partch, wd_errsector,
541: wd_errbn);
542: }
543: outt:
544:
545: /*
546: * If this was a successful read operation, fetch the data.
547: */
548: if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) {
549: int chk, dummy;
550:
551: chk = min(256,du->dk_bc/2);
552: /* Ready to receive data? */
553: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
554:
555: /*dprintf(DDSK,"addr %x\n", (int)bp->b_un.b_addr + du->dk_skip * 512);*/
556: insw(wdc+wd_data,(int)bp->b_un.b_addr + du->dk_skip * 512 ,chk);
557: du->dk_bc -= 2*chk;
558: while (chk++ < 256) insw (wdc+wd_data,&dummy,1);
559: }
560:
561: wdxfer[du->dk_unit]++;
562: if (wdtab.b_active) {
563: if ((bp->b_flags & B_ERROR) == 0) {
564: du->dk_skip++; /* Add to successful sectors. */
565: if (wdtab.b_errcnt) {
566: log(LOG_WARNING, "wd%d%c: ",
567: du->dk_unit, partch);
568: log(LOG_WARNING,
569: "soft %s error, sn %d bn %d error %b retries %d\n",
570: (bp->b_flags & B_READ) ? "read" : "write",
571: wd_errsector, wd_errbn, wd_errstat,
572: WDERR_BITS, wdtab.b_errcnt);
573: }
574: wdtab.b_errcnt = 0;
575:
576: /* see if more to transfer */
577: /*if (du->dk_skip < (bp->b_bcount + 511) / 512) {*/
578: if (du->dk_bc > 0 && wd_haderror == 0) {
579: wdstart();
580: return; /* next chunk is started */
581: } else if (wd_haderror && wd_sebyse == 0) {
582: du->dk_skip = 0;
583: wd_haderror = 0;
584: wd_sebyse = 1;
585: wdstart();
586: return; /* redo xfer sector by sector */
587: }
588: }
589:
590: done:
591: wd_sebyse = 0;
592: /* done with this transfer, with or without error */
593: wdtab.b_actf = dp->b_forw;
594: wdtab.b_errcnt = 0;
595: du->dk_skip = 0;
596: dp->b_active = 0;
597: dp->b_actf = bp->av_forw;
598: dp->b_errcnt = 0;
599: bp->b_resid = 0;
600: biodone(bp);
601: }
602: wdtab.b_active = 0;
603: if (dp->b_actf)
604: wdustart(du); /* requeue disk if more io to do */
605: if (wdtab.b_actf)
606: wdstart(); /* start IO on next drive */
607: }
608:
609: /*
610: * Initialize a drive.
611: */
612: wdopen(dev, flags, fmt)
613: dev_t dev;
614: int flags, fmt;
615: {
616: register unsigned int unit;
617: register struct buf *bp;
618: register struct disk *du;
619: int part = wdpart(dev), mask = 1 << part;
620: struct partition *pp;
621: struct dkbad *db;
622: int i, error = 0;
623:
624: unit = wdunit(dev);
625: if (unit >= NWD) return (ENXIO) ;
626: du = &wddrives[unit];
627: #ifdef notdef
628: if (du->dk_open){
629: du->dk_open++ ;
630: return(0); /* already is open, don't mess with it */
631: }
632: #endif
633: du->dk_unit = unit;
634: wdutab[unit].b_actf = NULL;
635: /*if (flags & O_NDELAY)
636: du->dk_state = WANTOPENRAW;
637: else*/
638: du->dk_state = WANTOPEN;
639: /*
640: * Use the default sizes until we've read the label,
641: * or longer if there isn't one there.
642: */
643: du->dk_dd = dflt_sizes;
644:
645: /*
646: * Recal, read of disk label will be done in wdcontrol
647: * during first read operation.
648: */
649: bp = geteblk(512);
650: bp->b_dev = dev & 0xff00;
651: bp->b_bcount = 0;
652: bp->b_blkno = LABELSECTOR;
653: bp->b_flags = B_READ;
654: wdstrategy(bp);
655: biowait(bp);
656: if (bp->b_flags & B_ERROR) {
657: error = ENXIO;
658: du->dk_state = CLOSED;
659: goto done;
660: }
661: if (du->dk_state == OPENRAW) {
662: du->dk_state = OPENRAW;
663: goto done;
664: }
665: /*
666: * Read bad sector table into memory.
667: */
668: i = 0;
669: do {
670: bp->b_flags = B_BUSY | B_READ;
671: bp->b_blkno = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors
672: + i;
673: if (du->dk_dd.d_secsize > DEV_BSIZE)
674: bp->b_blkno *= du->dk_dd.d_secsize / DEV_BSIZE;
675: else
676: bp->b_blkno /= DEV_BSIZE / du->dk_dd.d_secsize;
677: bp->b_bcount = du->dk_dd.d_secsize;
678: bp->b_cylin = du->dk_dd.d_ncylinders - 1;
679: wdstrategy(bp);
680: biowait(bp);
681: } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 &&
682: i < du->dk_dd.d_nsectors);
683: db = (struct dkbad *)(bp->b_un.b_addr);
684: #define DKBAD_MAGIC 0x4321
685: if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 &&
686: db->bt_flag == DKBAD_MAGIC) {
687: dkbad[unit] = *db;
688: du->dk_state = OPEN;
689: } else {
690: printf("wd%d: %s bad-sector file\n", unit,
691: (bp->b_flags & B_ERROR) ? "can't read" : "format error in");
1.1.1.2 ! root 692: /*error = ENXIO ;
! 693: du->dk_state = OPENRAW;*/
! 694: du->dk_state = OPEN;
1.1 root 695: }
696: done:
697: bp->b_flags = B_INVAL | B_AGE;
698: brelse(bp);
699: if (error == 0)
700: du->dk_open = 1;
701:
702: /*
703: * Warn if a partion is opened
704: * that overlaps another partition which is open
705: * unless one is the "raw" partition (whole disk).
706: */
1.1.1.2 ! root 707: #define RAWPART 2 /* 'c' partition */ /* XXX */
1.1 root 708: if ((du->dk_openpart & mask) == 0 && part != RAWPART) {
709: int start, end;
710:
711: pp = &du->dk_dd.d_partitions[part];
712: start = pp->p_offset;
713: end = pp->p_offset + pp->p_size;
714: for (pp = du->dk_dd.d_partitions;
715: pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions];
716: pp++) {
717: if (pp->p_offset + pp->p_size <= start ||
718: pp->p_offset >= end)
719: continue;
720: if (pp - du->dk_dd.d_partitions == RAWPART)
721: continue;
722: if (du->dk_openpart & (1 << (pp -
723: du->dk_dd.d_partitions)))
724: log(LOG_WARNING,
725: "wd%d%c: overlaps open partition (%c)\n",
726: unit, part + 'a',
727: pp - du->dk_dd.d_partitions + 'a');
728: }
729: }
730: if (part >= du->dk_dd.d_npartitions)
731: return (ENXIO);
732: du->dk_openpart |= mask;
733: switch (fmt) {
734: case S_IFCHR:
735: du->dk_copenpart |= mask;
736: break;
737: case S_IFBLK:
738: du->dk_bopenpart |= mask;
739: break;
740: }
741: return (error);
742: }
743:
744: /*
745: * Implement operations other than read/write.
746: * Called from wdstart or wdintr during opens and formats.
747: * Uses finite-state-machine to track progress of operation in progress.
748: * Returns 0 if operation still in progress, 1 if completed.
749: */
750: wdcontrol(bp)
751: register struct buf *bp;
752: {
753: register struct disk *du;
754: register unit;
755: unsigned char stat;
756: int s, cnt;
757: extern int bootdev, cyloffset;
758:
759: du = &wddrives[wdunit(bp->b_dev)];
760: unit = du->dk_unit;
761: switch (DISKSTATE(du->dk_state)) {
762:
763: tryagainrecal:
764: case WANTOPEN: /* set SDH, step rate, do restore */
765: #ifdef WDDEBUG
766: dprintf(DDSK,"wd%d: recal ", unit);
767: #endif
768: s = splbio(); /* not called from intr level ... */
769: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
770: wdtab.b_active = 1;
771: outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
772: du->dk_state++;
773: splx(s);
774: return(0);
775:
776: case RECAL:
777: if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
778: printf("wd%d: recal", du->dk_unit);
779: if (unit == 0) {
780: printf(": status %b error %b\n",
781: stat, WDCS_BITS,
782: inb(wdc+wd_error), WDERR_BITS);
783: if (++wdtab.b_errcnt < RETRIES)
784: goto tryagainrecal;
785: }
786: goto badopen;
787: }
788:
789: /* some compaq controllers require this ... */
790: wdsetctlr(bp->b_dev, du);
791:
792: wdtab.b_errcnt = 0;
793: if (ISRAWSTATE(du->dk_state)) {
794: du->dk_state = OPENRAW;
795: return(1);
796: }
797: retry:
798: #ifdef WDDEBUG
799: dprintf(DDSK,"rdlabel ");
800: #endif
1.1.1.2 ! root 801: /*if( cyloffset < 0 || cyloffset > 8192) */cyloffset=0;
1.1 root 802: /*
803: * Read in sector LABELSECTOR to get the pack label
804: * and geometry.
805: */
806: outb(wdc+wd_precomp, 0xff);/* sometimes this is head bit 3 */
807: outb(wdc+wd_seccnt, 1);
808: outb(wdc+wd_sector, LABELSECTOR+1);
1.1.1.2 ! root 809: /*printf("sec %d ", LABELSECTOR);*/
1.1 root 810: /*if (bp->b_dev == bootdev) {
811: (wdc+wd_cyl_lo = cyloffset & 0xff;
812: (wdc+wd_cyl_hi = cyloffset >> 8;
813: } else {
814: (wdc+wd_cyl_lo = 0;
815: (wdc+wd_cyl_hi = 0;
816: }*/
817: outb(wdc+wd_cyl_lo, (cyloffset & 0xff));
818: outb(wdc+wd_cyl_hi, (cyloffset >> 8));
819: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
820: outb(wdc+wd_command, WDCC_READ);
821: du->dk_state = RDLABEL;
822: return(0);
823:
824: case RDLABEL:
825: if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
826: if (++wdtab.b_errcnt < RETRIES)
827: goto retry;
828: printf("wd%d: read label", unit);
829: goto badopen;
830: }
831:
832: insw(wdc+wd_data, bp->b_un.b_addr, 256);
833:
834: if (((struct disklabel *)
835: (bp->b_un.b_addr + LABELOFFSET))->d_magic == DISKMAGIC) {
836: du->dk_dd =
837: * (struct disklabel *) (bp->b_un.b_addr + LABELOFFSET);
838: } else {
1.1.1.2 ! root 839: printf("wd%d: bad disk label (%x)\n", du->dk_unit,
! 840: ((struct disklabel *)(bp->b_un.b_addr + LABELOFFSET))->d_magic
! 841: );
1.1 root 842: du->dk_state = OPENRAW;
843: }
844:
845: s = splbio(); /* not called from intr level ... */
846: while ((stat = inb(wdc+wd_status)) & WDCS_BUSY);
847:
848: wdsetctlr(bp->b_dev, du);
849:
850: outb(wdc+wd_seccnt, 0);
851: splx(s);
852:
853: if (du->dk_state == RDLABEL)
854: du->dk_state = RDBADTBL;
855: /*
856: * The rest of the initialization can be done
857: * by normal means.
858: */
859: return(1);
860:
861: default:
862: panic("wdcontrol");
863: }
864: /* NOTREACHED */
865:
866: badopen:
867: printf(": status %b error %b\n",
868: stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
869: du->dk_state = OPENRAW;
870: return(1);
871: }
872:
873: wdsetctlr(dev, du) dev_t dev; struct disk *du; {
874: int stat;
875:
1.1.1.2 ! root 876: outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders+1);
! 877: outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders+1)>>8);
1.1 root 878: outb(wdc+wd_sdh, WDSD_IBM | (wdunit(dev) << 4) + du->dk_dd.d_ntracks-1);
879: outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
880: outb(wdc+wd_command, 0x91);
881:
882: while ((stat = inb(wdc+wd_status)) & WDCS_BUSY) ;
883: stat = inb(wdc+wd_error);
884: return(stat);
885: }
886:
887: /* ARGSUSED */
888: wdclose(dev, flags, fmt)
889: dev_t dev;
890: int flags, fmt;
891: {
892: register struct disk *du;
893:
894: du = &wddrives[wdunit(dev)];
895: du->dk_open-- ;
896: /*if (du->dk_open == 0) du->dk_state = CLOSED ; does not work */
1.1.1.2 ! root 897: return(0);
1.1 root 898: }
899:
900: wdioctl(dev,cmd,addr,flag)
901: dev_t dev;
902: caddr_t addr;
903: {
904: int unit = wdunit(dev);
905: register struct disk *du;
906: int error = 0;
907: struct uio auio;
908: struct iovec aiov;
909: /*int wdformat();*/
910:
911: du = &wddrives[unit];
912:
913: switch (cmd) {
914:
915: case DIOCGDINFO:
916: *(struct disklabel *)addr = du->dk_dd;
917: break;
918:
919: case DIOCGPART:
920: ((struct partinfo *)addr)->disklab = &du->dk_dd;
921: ((struct partinfo *)addr)->part =
922: &du->dk_dd.d_partitions[wdpart(dev)];
923: break;
924:
925: case DIOCSDINFO:
926: if ((flag & FWRITE) == 0)
927: error = EBADF;
928: else
929: error = setdisklabel(&du->dk_dd,
930: (struct disklabel *)addr,
931: 0 /*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/);
932: /*if (error == 0 && dk->dk_state == OPENRAW &&
933: vdreset_drive(vddinfo[unit]))
934: dk->dk_state = OPEN;*/
935: wdsetctlr(dev, du);
936: break;
937:
938: case DIOCWLABEL:
939: if ((flag & FWRITE) == 0)
940: error = EBADF;
941: else
942: du->dk_wlabel = *(int *)addr;
943: break;
944:
945: case DIOCWDINFO:
946: if ((flag & FWRITE) == 0)
947: error = EBADF;
948: else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr,
949: 0/*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/)) == 0) {
950: int wlab;
951:
952: /*if (error == 0 && dk->dk_state == OPENRAW &&
953: vdreset_drive(vddinfo[unit]))
954: dk->dk_state = OPEN; */
955: wdsetctlr(dev, du);
956:
957: /* simulate opening partition 0 so write succeeds */
958: /* dk->dk_openpart |= (1 << 0); /* XXX */
959: wlab = du->dk_wlabel;
960: du->dk_wlabel = 1;
961: error = writedisklabel(dev, wdstrategy, &du->dk_dd,wdpart(dev));
962: /*dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;*/
963: du->dk_wlabel = wlab;
964: }
965: break;
966:
967: #ifdef notyet
968: case DIOCGDINFOP:
969: *(struct disklabel **)addr = &(du->dk_dd);
970: break;
971:
972: case DIOCWFORMAT:
973: if ((flag & FWRITE) == 0)
974: error = EBADF;
975: else {
976: register struct format_op *fop;
977:
978: fop = (struct format_op *)addr;
979: aiov.iov_base = fop->df_buf;
980: aiov.iov_len = fop->df_count;
981: auio.uio_iov = &aiov;
982: auio.uio_iovcnt = 1;
983: auio.uio_resid = fop->df_count;
984: auio.uio_segflg = 0;
985: auio.uio_offset =
986: fop->df_startblk * du->dk_dd.d_secsize;
987: error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE,
988: minphys, &auio);
989: fop->df_count -= auio.uio_resid;
990: fop->df_reg[0] = du->dk_status;
991: fop->df_reg[1] = du->dk_error;
992: }
993: break;
994: #endif
995:
996: default:
997: error = ENOTTY;
998: break;
999: }
1000: return (error);
1001: }
1002:
1003: /*wdformat(bp)
1004: struct buf *bp;
1005: {
1006:
1007: bp->b_flags |= B_FORMAT;
1008: return (wdstrategy(bp));
1009: }*/
1010:
1011: wdsize(dev)
1012: dev_t dev;
1013: {
1014: register unit = wdunit(dev);
1015: register part = wdpart(dev);
1016: register struct disk *du;
1017: register val ;
1018:
1019: if (unit >= NWD) return(-1);
1020: if (wddrives[unit].dk_state == 0) {
1021: val = wdopen (dev, 0);
1022: if (val < 0)
1023: return (-1);
1024: }
1025: du = &wddrives[unit];
1026: return((int)((u_long)du->dk_dd.d_partitions[part].p_size *
1027: du->dk_dd.d_secsize / 512));
1028: }
1029:
1030: extern char *vmmap; /* poor name! */
1031:
1032: wddump(dev) /* dump core after a system crash */
1033: dev_t dev;
1034: {
1035: register struct disk *du; /* disk unit to do the IO */
1036: register struct bt_bad *bt_ptr;
1037: long num; /* number of sectors to write */
1038: int unit, part;
1039: long cyloff, blknum, blkcnt;
1040: long cylin, head, sector, stat;
1041: long secpertrk, secpercyl, nblocks, i;
1042: char *addr;
1043: extern int Maxmem;
1044: static wddoingadump = 0 ;
1045: extern CMAP1;
1046: extern char CADDR1[];
1047:
1048:
1049: #ifdef ARGO
1050: outb(0x461,0); /* disable failsafe timer */
1051: #endif
1052: addr = (char *) 0; /* starting address */
1053: /* size of memory to dump */
1054: num = Maxmem;
1055: unit = wdunit(dev); /* eventually support floppies? */
1056: part = wdpart(dev); /* file system */
1057: /* check for acceptable drive number */
1058: if (unit >= NWD) return(ENXIO);
1059:
1060: du = &wddrives[unit];
1061: /* was it ever initialized ? */
1062: if (du->dk_state < OPEN) return (ENXIO) ;
1063:
1064: /* Convert to disk sectors */
1065: num = (u_long) num * NBPG / du->dk_dd.d_secsize;
1066:
1067: /* check if controller active */
1068: /*if (wdtab.b_active) return(EFAULT); */
1069: if (wddoingadump) return(EFAULT);
1070:
1071: secpertrk = du->dk_dd.d_nsectors;
1072: secpercyl = du->dk_dd.d_secpercyl;
1073: nblocks = du->dk_dd.d_partitions[part].p_size;
1074: cyloff = du->dk_dd.d_partitions[part].p_offset / secpercyl;
1075:
1076: /*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/
1077: /* check transfer bounds against partition size */
1078: if ((dumplo < 0) || ((dumplo + num) > nblocks))
1079: return(EINVAL);
1080:
1081: /*wdtab.b_active = 1; /* mark controller active for if we
1082: panic during the dump */
1083: wddoingadump = 1 ; i = 100000 ;
1084: while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0)) ;
1085: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
1086: outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
1087: while (inb(wdc+wd_status) & WDCS_BUSY) ;
1088:
1089: /* some compaq controllers require this ... */
1090: wdsetctlr(dev, du);
1091:
1092: blknum = dumplo;
1093: while (num > 0) {
1094: #ifdef notdef
1095: if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER;
1096: if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl)
1097: blkcnt = secpercyl - (blknum % secpercyl);
1098: /* keep transfer within current cylinder */
1099: #endif
1100: pmap_enter(pmap_kernel(), vmmap, addr, VM_PROT_READ, TRUE);
1101:
1102: /* compute disk address */
1103: cylin = blknum / secpercyl;
1104: head = (blknum % secpercyl) / secpertrk;
1105: sector = blknum % secpertrk;
1106: cylin += cyloff;
1107:
1108: #ifdef notyet
1109: /*
1110: * See if the current block is in the bad block list.
1111: * (If we have one.)
1112: */
1113: for (bt_ptr = dkbad[unit].bt_bad;
1114: bt_ptr->bt_cyl != -1; bt_ptr++) {
1115: if (bt_ptr->bt_cyl > cylin)
1116: /* Sorted list, and we passed our cylinder.
1117: quit. */
1118: break;
1119: if (bt_ptr->bt_cyl == cylin &&
1120: bt_ptr->bt_trksec == (head << 8) + sector) {
1121: /*
1122: * Found bad block. Calculate new block addr.
1123: * This starts at the end of the disk (skip the
1124: * last track which is used for the bad block list),
1125: * and works backwards to the front of the disk.
1126: */
1127: blknum = (du->dk_dd.d_secperunit)
1128: - du->dk_dd.d_nsectors
1129: - (bt_ptr - dkbad[unit].bt_bad) - 1;
1130: cylin = blknum / secpercyl;
1131: head = (blknum % secpercyl) / secpertrk;
1132: sector = blknum % secpertrk;
1133: break;
1134: }
1135:
1136: #endif
1137: sector++; /* origin 1 */
1138:
1139: /* select drive. */
1140: outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
1141: while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
1142:
1143: /* transfer some blocks */
1144: outb(wdc+wd_sector, sector);
1145: outb(wdc+wd_seccnt,1);
1146: outb(wdc+wd_cyl_lo, cylin);
1147: outb(wdc+wd_cyl_hi, cylin >> 8);
1148: #ifdef notdef
1149: /* lets just talk about this first...*/
1150: pg ("sdh 0%o sector %d cyl %d addr 0x%x",
1151: inb(wdc+wd_sdh), inb(wdc+wd_sector),
1152: inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr) ;
1153: #endif
1154: #ifdef ODYSSEUS
1155: if(cylin < 46 || cylin > 91)pg("oops");
1156: #endif
1157: #ifdef PRIAM
1158: if(cylin < 40 || cylin > 79)pg("oops");
1159: #endif
1160: outb(wdc+wd_command, WDCC_WRITE);
1161:
1162: /* Ready to send data? */
1163: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
1164: if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
1165:
1166: outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256);
1167: (int) addr += 512;
1168:
1169: if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
1170: /* Check data request (should be done). */
1171: if (inb(wdc+wd_status) & WDCS_DRQ) return(EIO) ;
1172:
1173: /* wait for completion */
1174: for ( i = 1000000 ; inb(wdc+wd_status) & WDCS_BUSY ; i--) {
1175: if (i < 0) return (EIO) ;
1176: }
1177: /* error check the xfer */
1178: if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
1179: /* update block count */
1180: num--;
1181: blknum++ ;
1182: if (num % 100 == 0) printf(".") ;
1183: }
1184: return(0);
1185: }
1186: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.