|
|
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:
65: #define wdctlr(dev) ((minor(dev) & 0x80) >> 7)
66: #define wdunit(dev) ((minor(dev) & 0x60) >> 5)
67: #define wdpart(dev) ((minor(dev) & 0x1f))
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 */
145: {21600, 40, 0,0,0,0},
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);
449: #ifdef WDDEBUG
450: dprintf(DDSK,"sector %d cylin %d head %d addr %x sts %x\n",
451: sector, cylin, head, addr, inb(wdc+wd_altsts));
452: #endif
453: }
454:
455: /* If this is a read operation, just go away until it's done. */
456: if (bp->b_flags & B_READ) return;
457:
458: /* Ready to send data? */
459: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0);
460:
461: /* ASSUMES CONTIGUOUS MEMORY */
462: outsw (wdc+wd_data, addr+du->dk_skip*512, 256);
463: du->dk_bc -= 512;
464: }
465:
466: /*
467: * these are globally defined so they can be found
468: * by the debugger easily in the case of a system crash
469: */
470: daddr_t wd_errsector;
471: daddr_t wd_errbn;
472: unsigned char wd_errstat;
473:
474: /* Interrupt routine for the controller. Acknowledge the interrupt, check for
475: * errors on the current operation, mark it done if necessary, and start
476: * the next request. Also check for a partially done transfer, and
477: * continue with the next chunk if so.
478: */
479: wdintr(unit)
480: {
481: register struct disk *du;
482: register struct buf *bp, *dp;
483: int status;
484: char partch ;
485: static wd_haderror;
486:
487: /* Shouldn't need this, but it may be a slow controller. */
488: while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ;
489: if (!wdtab.b_active) {
490: printf("wd: extra interrupt\n");
491: return;
492: }
493:
494: #ifdef WDDEBUG
495: dprintf(DDSK,"I ");
496: #endif
497: dp = wdtab.b_actf;
498: bp = dp->b_actf;
499: du = &wddrives[wdunit(bp->b_dev)];
500: partch = wdpart(bp->b_dev) + 'a';
501: if (DISKSTATE(du->dk_state) <= RDLABEL) {
502: if (wdcontrol(bp))
503: goto done;
504: return;
505: }
506: if (status & (WDCS_ERR | WDCS_ECCCOR)) {
507: wd_errstat = inb(wdc+wd_error); /* save error status */
508: #ifdef WDDEBUG
509: printf("status %x error %x\n", status, wd_errstat);
510: #endif
511: if(wd_sebyse == 0) {
512: wd_haderror = 1;
513: goto outt;
514: }
515: /*if (bp->b_flags & B_FORMAT) {
516: du->dk_status = status;
517: du->dk_error = wdp->wd_error;
518: bp->b_flags |= B_ERROR;
519: goto done;
520: }*/
521:
522: wd_errsector = (bp->b_cylin * du->dk_dd.d_secpercyl) +
523: (((unsigned long) bp->b_blkno * DEV_BSIZE /
524: du->dk_dd.d_secsize) % du->dk_dd.d_secpercyl) +
525: du->dk_skip;
526: wd_errbn = bp->b_blkno
527: + du->dk_skip * du->dk_dd.d_secsize / DEV_BSIZE ;
528: if (status & WDCS_ERR) {
529: if (++wdtab.b_errcnt < RETRIES) {
530: wdtab.b_active = 0;
531: } else {
532: printf("wd%d%c: ", du->dk_unit, partch);
533: printf(
534: "hard %s error, sn %d bn %d status %b error %b\n",
535: (bp->b_flags & B_READ)? "read":"write",
536: wd_errsector, wd_errbn, status, WDCS_BITS,
537: wd_errstat, WDERR_BITS);
538: bp->b_flags |= B_ERROR; /* flag the error */
539: }
540: } else
541: log(LOG_WARNING,"wd%d%c: soft ecc sn %d bn %d\n",
542: du->dk_unit, partch, wd_errsector,
543: wd_errbn);
544: }
545: outt:
546:
547: /*
548: * If this was a successful read operation, fetch the data.
549: */
550: if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) {
551: int chk, dummy;
552:
553: chk = min(256,du->dk_bc/2);
554: /* Ready to receive data? */
555: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
556:
557: /*dprintf(DDSK,"addr %x\n", (int)bp->b_un.b_addr + du->dk_skip * 512);*/
558: insw(wdc+wd_data,(int)bp->b_un.b_addr + du->dk_skip * 512 ,chk);
559: du->dk_bc -= 2*chk;
560: while (chk++ < 256) insw (wdc+wd_data,&dummy,1);
561: }
562:
563: wdxfer[du->dk_unit]++;
564: if (wdtab.b_active) {
565: if ((bp->b_flags & B_ERROR) == 0) {
566: du->dk_skip++; /* Add to successful sectors. */
567: if (wdtab.b_errcnt) {
568: log(LOG_WARNING, "wd%d%c: ",
569: du->dk_unit, partch);
570: log(LOG_WARNING,
571: "soft %s error, sn %d bn %d error %b retries %d\n",
572: (bp->b_flags & B_READ) ? "read" : "write",
573: wd_errsector, wd_errbn, wd_errstat,
574: WDERR_BITS, wdtab.b_errcnt);
575: }
576: wdtab.b_errcnt = 0;
577:
578: /* see if more to transfer */
579: /*if (du->dk_skip < (bp->b_bcount + 511) / 512) {*/
580: if (du->dk_bc > 0 && wd_haderror == 0) {
581: wdstart();
582: return; /* next chunk is started */
583: } else if (wd_haderror && wd_sebyse == 0) {
584: du->dk_skip = 0;
585: wd_haderror = 0;
586: wd_sebyse = 1;
587: wdstart();
588: return; /* redo xfer sector by sector */
589: }
590: }
591:
592: done:
593: wd_sebyse = 0;
594: /* done with this transfer, with or without error */
595: wdtab.b_actf = dp->b_forw;
596: wdtab.b_errcnt = 0;
597: du->dk_skip = 0;
598: dp->b_active = 0;
599: dp->b_actf = bp->av_forw;
600: dp->b_errcnt = 0;
601: bp->b_resid = 0;
602: biodone(bp);
603: }
604: wdtab.b_active = 0;
605: if (dp->b_actf)
606: wdustart(du); /* requeue disk if more io to do */
607: if (wdtab.b_actf)
608: wdstart(); /* start IO on next drive */
609: }
610:
611: /*
612: * Initialize a drive.
613: */
614: wdopen(dev, flags, fmt)
615: dev_t dev;
616: int flags, fmt;
617: {
618: register unsigned int unit;
619: register struct buf *bp;
620: register struct disk *du;
621: int part = wdpart(dev), mask = 1 << part;
622: struct partition *pp;
623: struct dkbad *db;
624: int i, error = 0;
625:
626: unit = wdunit(dev);
627: if (unit >= NWD) return (ENXIO) ;
628: du = &wddrives[unit];
629: #ifdef notdef
630: if (du->dk_open){
631: du->dk_open++ ;
632: return(0); /* already is open, don't mess with it */
633: }
634: #endif
635: du->dk_unit = unit;
636: wdutab[unit].b_actf = NULL;
637: /*if (flags & O_NDELAY)
638: du->dk_state = WANTOPENRAW;
639: else*/
640: du->dk_state = WANTOPEN;
641: /*
642: * Use the default sizes until we've read the label,
643: * or longer if there isn't one there.
644: */
645: du->dk_dd = dflt_sizes;
646:
647: /*
648: * Recal, read of disk label will be done in wdcontrol
649: * during first read operation.
650: */
651: bp = geteblk(512);
652: bp->b_dev = dev & 0xff00;
653: bp->b_bcount = 0;
654: bp->b_blkno = LABELSECTOR;
655: bp->b_flags = B_READ;
656: wdstrategy(bp);
657: biowait(bp);
658: if (bp->b_flags & B_ERROR) {
659: error = ENXIO;
660: du->dk_state = CLOSED;
661: goto done;
662: }
663: if (du->dk_state == OPENRAW) {
664: du->dk_state = OPENRAW;
665: goto done;
666: }
667: /*
668: * Read bad sector table into memory.
669: */
670: i = 0;
671: do {
672: bp->b_flags = B_BUSY | B_READ;
673: bp->b_blkno = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors
674: + i;
675: if (du->dk_dd.d_secsize > DEV_BSIZE)
676: bp->b_blkno *= du->dk_dd.d_secsize / DEV_BSIZE;
677: else
678: bp->b_blkno /= DEV_BSIZE / du->dk_dd.d_secsize;
679: bp->b_bcount = du->dk_dd.d_secsize;
680: bp->b_cylin = du->dk_dd.d_ncylinders - 1;
681: wdstrategy(bp);
682: biowait(bp);
683: } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 &&
684: i < du->dk_dd.d_nsectors);
685: db = (struct dkbad *)(bp->b_un.b_addr);
686: #define DKBAD_MAGIC 0x4321
687: if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 &&
688: db->bt_flag == DKBAD_MAGIC) {
689: dkbad[unit] = *db;
690: du->dk_state = OPEN;
691: } else {
692: printf("wd%d: %s bad-sector file\n", unit,
693: (bp->b_flags & B_ERROR) ? "can't read" : "format error in");
694: error = ENXIO ;
695: du->dk_state = OPENRAW;
696: }
697: done:
698: bp->b_flags = B_INVAL | B_AGE;
699: brelse(bp);
700: if (error == 0)
701: du->dk_open = 1;
702:
703: /*
704: * Warn if a partion is opened
705: * that overlaps another partition which is open
706: * unless one is the "raw" partition (whole disk).
707: */
708: #define RAWPART 8 /* 'x' partition */ /* XXX */
709: if ((du->dk_openpart & mask) == 0 && part != RAWPART) {
710: int start, end;
711:
712: pp = &du->dk_dd.d_partitions[part];
713: start = pp->p_offset;
714: end = pp->p_offset + pp->p_size;
715: for (pp = du->dk_dd.d_partitions;
716: pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions];
717: pp++) {
718: if (pp->p_offset + pp->p_size <= start ||
719: pp->p_offset >= end)
720: continue;
721: if (pp - du->dk_dd.d_partitions == RAWPART)
722: continue;
723: if (du->dk_openpart & (1 << (pp -
724: du->dk_dd.d_partitions)))
725: log(LOG_WARNING,
726: "wd%d%c: overlaps open partition (%c)\n",
727: unit, part + 'a',
728: pp - du->dk_dd.d_partitions + 'a');
729: }
730: }
731: if (part >= du->dk_dd.d_npartitions)
732: return (ENXIO);
733: du->dk_openpart |= mask;
734: switch (fmt) {
735: case S_IFCHR:
736: du->dk_copenpart |= mask;
737: break;
738: case S_IFBLK:
739: du->dk_bopenpart |= mask;
740: break;
741: }
742: return (error);
743: }
744:
745: /*
746: * Implement operations other than read/write.
747: * Called from wdstart or wdintr during opens and formats.
748: * Uses finite-state-machine to track progress of operation in progress.
749: * Returns 0 if operation still in progress, 1 if completed.
750: */
751: wdcontrol(bp)
752: register struct buf *bp;
753: {
754: register struct disk *du;
755: register unit;
756: unsigned char stat;
757: int s, cnt;
758: extern int bootdev, cyloffset;
759:
760: du = &wddrives[wdunit(bp->b_dev)];
761: unit = du->dk_unit;
762: switch (DISKSTATE(du->dk_state)) {
763:
764: tryagainrecal:
765: case WANTOPEN: /* set SDH, step rate, do restore */
766: #ifdef WDDEBUG
767: dprintf(DDSK,"wd%d: recal ", unit);
768: #endif
769: s = splbio(); /* not called from intr level ... */
770: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
771: wdtab.b_active = 1;
772: outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
773: du->dk_state++;
774: splx(s);
775: return(0);
776:
777: case RECAL:
778: if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
779: printf("wd%d: recal", du->dk_unit);
780: if (unit == 0) {
781: printf(": status %b error %b\n",
782: stat, WDCS_BITS,
783: inb(wdc+wd_error), WDERR_BITS);
784: if (++wdtab.b_errcnt < RETRIES)
785: goto tryagainrecal;
786: }
787: goto badopen;
788: }
789:
790: /* some compaq controllers require this ... */
791: wdsetctlr(bp->b_dev, du);
792:
793: wdtab.b_errcnt = 0;
794: if (ISRAWSTATE(du->dk_state)) {
795: du->dk_state = OPENRAW;
796: return(1);
797: }
798: retry:
799: #ifdef WDDEBUG
800: dprintf(DDSK,"rdlabel ");
801: #endif
802: if( cyloffset < 0 || cyloffset > 8192) cyloffset=0;
803: /*
804: * Read in sector LABELSECTOR to get the pack label
805: * and geometry.
806: */
807: outb(wdc+wd_precomp, 0xff);/* sometimes this is head bit 3 */
808: outb(wdc+wd_seccnt, 1);
809: outb(wdc+wd_sector, LABELSECTOR+1);
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 {
839: printf("wd%d: bad disk label\n", du->dk_unit);
840: du->dk_state = OPENRAW;
841: }
842:
843: s = splbio(); /* not called from intr level ... */
844: while ((stat = inb(wdc+wd_status)) & WDCS_BUSY);
845:
846: wdsetctlr(bp->b_dev, du);
847:
848: outb(wdc+wd_seccnt, 0);
849: splx(s);
850:
851: if (du->dk_state == RDLABEL)
852: du->dk_state = RDBADTBL;
853: /*
854: * The rest of the initialization can be done
855: * by normal means.
856: */
857: return(1);
858:
859: default:
860: panic("wdcontrol");
861: }
862: /* NOTREACHED */
863:
864: badopen:
865: printf(": status %b error %b\n",
866: stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
867: du->dk_state = OPENRAW;
868: return(1);
869: }
870:
871: wdsetctlr(dev, du) dev_t dev; struct disk *du; {
872: int stat;
873:
874: outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders);
875: outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders)>>8);
876: outb(wdc+wd_sdh, WDSD_IBM | (wdunit(dev) << 4) + du->dk_dd.d_ntracks-1);
877: outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
878: outb(wdc+wd_command, 0x91);
879:
880: while ((stat = inb(wdc+wd_status)) & WDCS_BUSY) ;
881: stat = inb(wdc+wd_error);
882: return(stat);
883: }
884:
885: /* ARGSUSED */
886: wdclose(dev, flags, fmt)
887: dev_t dev;
888: int flags, fmt;
889: {
890: register struct disk *du;
891:
892: du = &wddrives[wdunit(dev)];
893: du->dk_open-- ;
894: /*if (du->dk_open == 0) du->dk_state = CLOSED ; does not work */
895: }
896:
897: wdioctl(dev,cmd,addr,flag)
898: dev_t dev;
899: caddr_t addr;
900: {
901: int unit = wdunit(dev);
902: register struct disk *du;
903: int error = 0;
904: struct uio auio;
905: struct iovec aiov;
906: /*int wdformat();*/
907:
908: du = &wddrives[unit];
909:
910: switch (cmd) {
911:
912: case DIOCGDINFO:
913: *(struct disklabel *)addr = du->dk_dd;
914: break;
915:
916: case DIOCGPART:
917: ((struct partinfo *)addr)->disklab = &du->dk_dd;
918: ((struct partinfo *)addr)->part =
919: &du->dk_dd.d_partitions[wdpart(dev)];
920: break;
921:
922: case DIOCSDINFO:
923: if ((flag & FWRITE) == 0)
924: error = EBADF;
925: else
926: error = setdisklabel(&du->dk_dd,
927: (struct disklabel *)addr,
928: 0 /*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/);
929: /*if (error == 0 && dk->dk_state == OPENRAW &&
930: vdreset_drive(vddinfo[unit]))
931: dk->dk_state = OPEN;*/
932: wdsetctlr(dev, du);
933: break;
934:
935: case DIOCWLABEL:
936: if ((flag & FWRITE) == 0)
937: error = EBADF;
938: else
939: du->dk_wlabel = *(int *)addr;
940: break;
941:
942: case DIOCWDINFO:
943: if ((flag & FWRITE) == 0)
944: error = EBADF;
945: else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr,
946: 0/*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/)) == 0) {
947: int wlab;
948:
949: /*if (error == 0 && dk->dk_state == OPENRAW &&
950: vdreset_drive(vddinfo[unit]))
951: dk->dk_state = OPEN; */
952: wdsetctlr(dev, du);
953:
954: /* simulate opening partition 0 so write succeeds */
955: /* dk->dk_openpart |= (1 << 0); /* XXX */
956: wlab = du->dk_wlabel;
957: du->dk_wlabel = 1;
958: error = writedisklabel(dev, wdstrategy, &du->dk_dd,wdpart(dev));
959: /*dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;*/
960: du->dk_wlabel = wlab;
961: }
962: break;
963:
964: #ifdef notyet
965: case DIOCGDINFOP:
966: *(struct disklabel **)addr = &(du->dk_dd);
967: break;
968:
969: case DIOCWFORMAT:
970: if ((flag & FWRITE) == 0)
971: error = EBADF;
972: else {
973: register struct format_op *fop;
974:
975: fop = (struct format_op *)addr;
976: aiov.iov_base = fop->df_buf;
977: aiov.iov_len = fop->df_count;
978: auio.uio_iov = &aiov;
979: auio.uio_iovcnt = 1;
980: auio.uio_resid = fop->df_count;
981: auio.uio_segflg = 0;
982: auio.uio_offset =
983: fop->df_startblk * du->dk_dd.d_secsize;
984: error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE,
985: minphys, &auio);
986: fop->df_count -= auio.uio_resid;
987: fop->df_reg[0] = du->dk_status;
988: fop->df_reg[1] = du->dk_error;
989: }
990: break;
991: #endif
992:
993: default:
994: error = ENOTTY;
995: break;
996: }
997: return (error);
998: }
999:
1000: /*wdformat(bp)
1001: struct buf *bp;
1002: {
1003:
1004: bp->b_flags |= B_FORMAT;
1005: return (wdstrategy(bp));
1006: }*/
1007:
1008: /*
1009: * Routines to do raw IO for a unit.
1010: */
1011: wdread(dev, uio) /* character read routine */
1012: dev_t dev;
1013: struct uio *uio;
1014: {
1015: int unit = wdunit(dev) ;
1016:
1017: if (unit >= NWD) return(ENXIO);
1018: return(physio(wdstrategy, &rwdbuf[unit], dev, B_READ, minphys, uio));
1019: }
1020:
1021:
1022: wdwrite(dev, uio) /* character write routine */
1023: dev_t dev;
1024: struct uio *uio;
1025: {
1026: int unit = wdunit(dev) ;
1027:
1028: if (unit >= NWD) return(ENXIO);
1029: return(physio(wdstrategy, &rwdbuf[unit], dev, B_WRITE, minphys, uio));
1030: }
1031:
1032: wdsize(dev)
1033: dev_t dev;
1034: {
1035: register unit = wdunit(dev);
1036: register part = wdpart(dev);
1037: register struct disk *du;
1038: register val ;
1039:
1040: if (unit >= NWD) return(-1);
1041: if (wddrives[unit].dk_state == 0) {
1042: val = wdopen (dev, 0);
1043: if (val < 0)
1044: return (-1);
1045: }
1046: du = &wddrives[unit];
1047: return((int)((u_long)du->dk_dd.d_partitions[part].p_size *
1048: du->dk_dd.d_secsize / 512));
1049: }
1050:
1051: extern char *vmmap; /* poor name! */
1052:
1053: wddump(dev) /* dump core after a system crash */
1054: dev_t dev;
1055: {
1056: register struct disk *du; /* disk unit to do the IO */
1057: register struct bt_bad *bt_ptr;
1058: long num; /* number of sectors to write */
1059: int unit, part;
1060: long cyloff, blknum, blkcnt;
1061: long cylin, head, sector, stat;
1062: long secpertrk, secpercyl, nblocks, i;
1063: char *addr;
1064: extern int Maxmem;
1065: static wddoingadump = 0 ;
1066: extern CMAP1;
1067: extern char CADDR1[];
1068:
1069:
1070: #ifdef ARGO
1071: outb(0x461,0); /* disable failsafe timer */
1072: #endif
1073: addr = (char *) 0; /* starting address */
1074: /* size of memory to dump */
1075: num = Maxmem;
1076: unit = wdunit(dev); /* eventually support floppies? */
1077: part = wdpart(dev); /* file system */
1078: /* check for acceptable drive number */
1079: if (unit >= NWD) return(ENXIO);
1080:
1081: du = &wddrives[unit];
1082: /* was it ever initialized ? */
1083: if (du->dk_state < OPEN) return (ENXIO) ;
1084:
1085: /* Convert to disk sectors */
1086: num = (u_long) num * NBPG / du->dk_dd.d_secsize;
1087:
1088: /* check if controller active */
1089: /*if (wdtab.b_active) return(EFAULT); */
1090: if (wddoingadump) return(EFAULT);
1091:
1092: secpertrk = du->dk_dd.d_nsectors;
1093: secpercyl = du->dk_dd.d_secpercyl;
1094: nblocks = du->dk_dd.d_partitions[part].p_size;
1095: cyloff = du->dk_dd.d_partitions[part].p_offset / secpercyl;
1096:
1097: /*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/
1098: /* check transfer bounds against partition size */
1099: if ((dumplo < 0) || ((dumplo + num) > nblocks))
1100: return(EINVAL);
1101:
1102: /*wdtab.b_active = 1; /* mark controller active for if we
1103: panic during the dump */
1104: wddoingadump = 1 ; i = 100000 ;
1105: while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0)) ;
1106: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
1107: outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
1108: while (inb(wdc+wd_status) & WDCS_BUSY) ;
1109:
1110: /* some compaq controllers require this ... */
1111: wdsetctlr(dev, du);
1112:
1113: blknum = dumplo;
1114: while (num > 0) {
1115: #ifdef notdef
1116: if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER;
1117: if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl)
1118: blkcnt = secpercyl - (blknum % secpercyl);
1119: /* keep transfer within current cylinder */
1120: #endif
1121: pmap_enter(pmap_kernel(), vmmap, addr, VM_PROT_READ, TRUE);
1122:
1123: /* compute disk address */
1124: cylin = blknum / secpercyl;
1125: head = (blknum % secpercyl) / secpertrk;
1126: sector = blknum % secpertrk;
1127: cylin += cyloff;
1128:
1129: #ifdef notyet
1130: /*
1131: * See if the current block is in the bad block list.
1132: * (If we have one.)
1133: */
1134: for (bt_ptr = dkbad[unit].bt_bad;
1135: bt_ptr->bt_cyl != -1; bt_ptr++) {
1136: if (bt_ptr->bt_cyl > cylin)
1137: /* Sorted list, and we passed our cylinder.
1138: quit. */
1139: break;
1140: if (bt_ptr->bt_cyl == cylin &&
1141: bt_ptr->bt_trksec == (head << 8) + sector) {
1142: /*
1143: * Found bad block. Calculate new block addr.
1144: * This starts at the end of the disk (skip the
1145: * last track which is used for the bad block list),
1146: * and works backwards to the front of the disk.
1147: */
1148: blknum = (du->dk_dd.d_secperunit)
1149: - du->dk_dd.d_nsectors
1150: - (bt_ptr - dkbad[unit].bt_bad) - 1;
1151: cylin = blknum / secpercyl;
1152: head = (blknum % secpercyl) / secpertrk;
1153: sector = blknum % secpertrk;
1154: break;
1155: }
1156:
1157: #endif
1158: sector++; /* origin 1 */
1159:
1160: /* select drive. */
1161: outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
1162: while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
1163:
1164: /* transfer some blocks */
1165: outb(wdc+wd_sector, sector);
1166: outb(wdc+wd_seccnt,1);
1167: outb(wdc+wd_cyl_lo, cylin);
1168: outb(wdc+wd_cyl_hi, cylin >> 8);
1169: #ifdef notdef
1170: /* lets just talk about this first...*/
1171: pg ("sdh 0%o sector %d cyl %d addr 0x%x",
1172: inb(wdc+wd_sdh), inb(wdc+wd_sector),
1173: inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr) ;
1174: #endif
1175: #ifdef ODYSSEUS
1176: if(cylin < 46 || cylin > 91)pg("oops");
1177: #endif
1178: #ifdef PRIAM
1179: if(cylin < 40 || cylin > 79)pg("oops");
1180: #endif
1181: outb(wdc+wd_command, WDCC_WRITE);
1182:
1183: /* Ready to send data? */
1184: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
1185: if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
1186:
1187: outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256);
1188: (int) addr += 512;
1189:
1190: if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
1191: /* Check data request (should be done). */
1192: if (inb(wdc+wd_status) & WDCS_DRQ) return(EIO) ;
1193:
1194: /* wait for completion */
1195: for ( i = 1000000 ; inb(wdc+wd_status) & WDCS_BUSY ; i--) {
1196: if (i < 0) return (EIO) ;
1197: }
1198: /* error check the xfer */
1199: if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
1200: /* update block count */
1201: num--;
1202: blknum++ ;
1203: if (num % 100 == 0) printf(".") ;
1204: }
1205: return(0);
1206: }
1207: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.