|
|
1.1 root 1: /*-
2: * Copyright (c) 1990 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * William Jolitz.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
1.1.1.3 root 36: * from:@(#)wd.c 7.2 (Berkeley) 5/9/91
1.1 root 37: */
38:
1.1.1.4 ! root 39: /* Note: This code heavily modified by [email protected]; use at own risk! */
! 40: /* The following defines represent only a very small part of the mods, most */
! 41: /* of them are not marked in any way. -tih */
! 42:
! 43: #undef WDOPENLOCK /* Prevent reentrancy in wdopen() for testing */
! 44: #define TIHMODS /* wdopen() workaround, some splx() calls */
! 45: #define TIHBAD144 /* new bad144 bad sector handling */
! 46: #define QUIETWORKS /* define this when wdopen() can actually set DKFL_QUIET */
! 47: #define INSTRUMENT /* Add instrumentation stuff by Brad Parker */
1.1 root 48:
1.1.1.4 ! root 49: /* TODO: peel out buffer at low ipl, speed improvement */
! 50: /* TODO: find and fix the timing bugs apparent on some controllers */
1.1 root 51:
52: #include "wd.h"
1.1.1.4 ! root 53: #if NWDC > 0
1.1 root 54:
55: #include "param.h"
56: #include "dkbad.h"
57: #include "systm.h"
58: #include "conf.h"
59: #include "file.h"
60: #include "stat.h"
61: #include "ioctl.h"
62: #include "disklabel.h"
63: #include "buf.h"
64: #include "uio.h"
1.1.1.3 root 65: #include "malloc.h"
66: #include "machine/cpu.h"
1.1.1.4 ! root 67: #ifdef INSTRUMENT
! 68: #include "sys/dkstat.h"
! 69: #endif
! 70: #include "i386/isa/isa.h"
1.1 root 71: #include "i386/isa/isa_device.h"
72: #include "i386/isa/icu.h"
73: #include "i386/isa/wdreg.h"
74: #include "syslog.h"
75: #include "vm/vm.h"
76:
77: #define RETRIES 5 /* number of retries before giving up */
78:
1.1.1.3 root 79: #define wdnoreloc(dev) (minor(dev) & 0x80) /* ignore partition table */
80: #define wddospart(dev) (minor(dev) & 0x40) /* use dos partitions */
81: #define wdunit(dev) ((minor(dev) & 0x38) >> 3)
82: #define wdpart(dev) (minor(dev) & 0x7)
83: #define makewddev(maj, unit, part) (makedev(maj,((unit<<3)+part)))
84: #define WDRAW 3 /* 'd' partition isn't a partition! */
1.1 root 85:
86: #define b_cylin b_resid /* cylinder number for doing IO to */
87: /* shares an entry in the buf struct */
88:
89: /*
1.1.1.3 root 90: * Drive states. Used to initialize drive.
1.1 root 91: */
92:
93: #define CLOSED 0 /* disk is closed. */
94: #define WANTOPEN 1 /* open requested, not started */
95: #define RECAL 2 /* doing restore */
1.1.1.3 root 96: #define OPEN 3 /* done with open */
1.1 root 97:
98: /*
99: * The structure of a disk drive.
100: */
101: struct disk {
102: long dk_bc; /* byte count left */
1.1.1.4 ! root 103: long dk_bct; /* total byte count left */
1.1 root 104: short dk_skip; /* blocks already transferred */
1.1.1.4 ! root 105: short dk_skipm; /* blocks already transferred for multi */
! 106: char dk_ctrlr; /* physical controller number */
1.1 root 107: char dk_unit; /* physical unit number */
1.1.1.4 ! root 108: char dk_lunit; /* logical unit number */
1.1 root 109: char dk_state; /* control state */
110: u_char dk_status; /* copy of status reg. */
111: u_char dk_error; /* copy of error reg. */
1.1.1.3 root 112: short dk_port; /* i/o port base */
113:
1.1.1.4 ! root 114: u_long dk_copenpart; /* character units open on this drive */
! 115: u_long dk_bopenpart; /* block units open on this drive */
! 116: u_long dk_openpart; /* all units open on this drive */
1.1 root 117: short dk_wlabel; /* label writable? */
1.1.1.3 root 118: short dk_flags; /* drive characteistics found */
119: #define DKFL_DOSPART 0x00001 /* has DOS partition table */
120: #define DKFL_QUIET 0x00002 /* report errors back, but don't complain */
121: #define DKFL_SINGLE 0x00004 /* sector at a time mode */
122: #define DKFL_ERROR 0x00008 /* processing a disk error */
123: #define DKFL_BSDLABEL 0x00010 /* has a BSD disk label */
124: #define DKFL_BADSECT 0x00020 /* has a bad144 badsector table */
125: #define DKFL_WRITEPROT 0x00040 /* manual unit write protect */
126: struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */
127: struct disklabel dk_dd; /* device configuration data */
128: struct dos_partition
129: dk_dospartitions[NDOSPART]; /* DOS view of disk */
130: struct dkbad dk_bad; /* bad sector table */
1.1.1.4 ! root 131: #ifdef TIHBAD144
! 132: long dk_badsect[127]; /* 126 plus trailing -1 marker */
! 133: #endif
1.1 root 134: };
135:
1.1.1.4 ! root 136: #ifdef TIHBAD144
! 137: void bad144intern(struct disk *);
! 138: #endif
! 139: void wddisksort();
! 140:
1.1.1.3 root 141: struct disk *wddrives[NWD]; /* table of units */
1.1.1.4 ! root 142: struct buf wdtab[NWDC]; /* various per-controller info */
1.1.1.3 root 143: struct buf wdutab[NWD]; /* head of queue per drive */
144: struct buf rwdbuf[NWD]; /* buffers for raw IO */
145: long wdxfer[NWD]; /* count of transfers */
1.1.1.4 ! root 146:
! 147: #ifdef WDOPENLOCK
! 148: int wdopenbusy = 0;
1.1.1.3 root 149: #endif
1.1 root 150:
1.1.1.4 ! root 151: int wdprobe(), wdattach();
! 152:
! 153: struct isa_driver wdcdriver = {
! 154: wdprobe, wdattach, "wdc",
1.1 root 155: };
1.1.1.3 root 156:
157: void wdustart(struct disk *);
1.1.1.4 ! root 158: void wdstart(int);
1.1.1.3 root 159: int wdcommand(struct disk *, int);
160: int wdcontrol(struct buf *);
161: int wdsetctlr(dev_t, struct disk *);
162: int wdgetctlr(int, struct disk *);
163:
1.1 root 164: /*
1.1.1.3 root 165: * Probe for controller.
1.1 root 166: */
1.1.1.3 root 167: int
168: wdprobe(struct isa_device *dvp)
1.1 root 169: {
1.1.1.3 root 170: struct disk *du;
171: int wdc;
1.1 root 172:
1.1.1.4 ! root 173: #ifdef WDOPENLOCK
! 174: wdopenbusy = 0;
! 175: #endif
! 176:
! 177: if (dvp->id_unit >= NWDC)
1.1.1.3 root 178: return(0);
179:
1.1.1.4 ! root 180: du = (struct disk *) malloc (sizeof(struct disk), M_TEMP, M_NOWAIT);
! 181: bzero(du, sizeof(struct disk));
! 182:
! 183: du->dk_ctrlr = dvp->id_unit;
! 184: du->dk_unit = 0;
! 185: du->dk_lunit = 0;
1.1.1.3 root 186:
187: wdc = du->dk_port = dvp->id_iobase;
1.1.1.4 ! root 188:
1.1.1.3 root 189: /* check if we have registers that work */
1.1.1.4 ! root 190: outb(wdc+wd_error, 0x5a); /* error register not writable */
! 191: outb(wdc+wd_cyl_lo, 0xa5); /* but all of cyllo are implemented */
1.1.1.3 root 192: if(inb(wdc+wd_error) == 0x5a || inb(wdc+wd_cyl_lo) != 0xa5)
193: goto nodevice;
194:
195: /* reset the device */
196: outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS));
197: DELAY(1000);
198: outb(wdc+wd_ctlr, WDCTL_IDS);
199: DELAY(1000);
200:
201: /* execute a controller only command */
202: if (wdcommand(du, WDCC_DIAGNOSE) < 0)
203: goto nodevice;
204:
205: (void) inb(wdc+wd_error); /* XXX! */
206: outb(wdc+wd_ctlr, WDCTL_4BIT);
1.1.1.4 ! root 207: DELAY(1000);
! 208:
! 209: bzero(&wdtab[du->dk_ctrlr], sizeof(struct buf));
! 210:
! 211: free(du, M_TEMP);
! 212: return (8);
1.1.1.3 root 213:
214: nodevice:
215: free(du, M_TEMP);
1.1 root 216: return (0);
217: }
218:
219: /*
1.1.1.3 root 220: * Attach each drive if possible.
1.1 root 221: */
1.1.1.3 root 222: int
223: wdattach(struct isa_device *dvp)
1.1 root 224: {
1.1.1.4 ! root 225: int unit, lunit;
! 226: extern struct isa_device isa_biotab_wdc[];
! 227: struct isa_device *wdup;
! 228: struct disk *du;
! 229: int first = 0;
1.1 root 230:
1.1.1.4 ! root 231: if (dvp->id_unit >= NWDC)
! 232: return(0);
! 233:
! 234: for (wdup = isa_biotab_wdc; wdup->id_driver != 0; wdup++) {
! 235: if (wdup->id_iobase != dvp->id_iobase)
! 236: continue;
! 237: lunit = wdup->id_unit;
! 238: if (lunit >= NWD)
! 239: continue;
! 240: unit = wdup->id_physid;
! 241:
! 242: du = wddrives[lunit] = (struct disk *)
! 243: malloc(sizeof(struct disk), M_TEMP, M_NOWAIT);
! 244: bzero(du, sizeof(struct disk));
! 245: bzero(&wdutab[lunit], sizeof(struct buf));
! 246: bzero(&rwdbuf[lunit], sizeof(struct buf));
! 247: wdxfer[lunit] = 0;
! 248:
! 249: du->dk_ctrlr = dvp->id_unit;
! 250: du->dk_unit = unit;
! 251: du->dk_lunit = lunit;
! 252: du->dk_port = dvp->id_iobase;
! 253:
! 254: if(wdgetctlr(unit, du) == 0) {
! 255: int i, blank;
! 256: if(first==0) {
! 257: first = 1;
! 258: printf("wdc%d: <", dvp->id_unit);
! 259:
! 260: for (i=blank=0; i<sizeof(du->dk_params.wdp_model); i++) {
! 261: char c = du->dk_params.wdp_model[i];
! 262: if (blank && c == ' ')
! 263: continue;
! 264: if (blank && c != ' ') {
! 265: printf(" %c", c);
! 266: blank = 0;
! 267: continue;
! 268: }
! 269: if (c == ' ')
! 270: blank = 1;
! 271: else
! 272: printf("%c", c);
! 273: }
! 274: printf(">\n");
! 275: }
! 276: printf("wd%d at wdc%d slave %d\n", lunit, dvp->id_unit, unit);
! 277: } else {
! 278: /*printf("wd%d at wdc%d slave %d -- error\n",
! 279: lunit, dvp->id_unit, unit);*/
! 280: wddrives[lunit] = 0;
! 281: free(du, M_TEMP);
1.1.1.3 root 282: }
283: }
284: return(1);
1.1 root 285: }
286:
287: /* Read/write routine for a buffer. Finds the proper unit, range checks
288: * arguments, and schedules the transfer. Does not wait for the transfer
289: * to complete. Multi-page transfers are supported. All I/O requests must
290: * be a multiple of a sector in length.
291: */
1.1.1.3 root 292: int
293: wdstrategy(register struct buf *bp)
1.1 root 294: {
295: register struct buf *dp;
1.1.1.3 root 296: struct disk *du; /* Disk unit to do the IO. */
1.1.1.4 ! root 297: int lunit = wdunit(bp->b_dev);
1.1 root 298: int s;
1.1.1.4 ! root 299:
1.1.1.3 root 300: /* valid unit, controller, and request? */
1.1.1.4 ! root 301: if (lunit >= NWD || bp->b_blkno < 0 ||
! 302: howmany(bp->b_bcount, DEV_BSIZE) >= (1<<NBBY) ||
! 303: (du = wddrives[lunit]) == 0) {
1.1.1.3 root 304: bp->b_error = EINVAL;
1.1 root 305: bp->b_flags |= B_ERROR;
1.1.1.3 root 306: goto done;
1.1 root 307: }
1.1.1.4 ! root 308:
1.1.1.3 root 309: /* "soft" write protect check */
310: if ((du->dk_flags & DKFL_WRITEPROT) && (bp->b_flags & B_READ) == 0) {
311: bp->b_error = EROFS;
1.1 root 312: bp->b_flags |= B_ERROR;
1.1.1.3 root 313: goto done;
1.1 root 314: }
1.1.1.4 ! root 315:
1.1.1.3 root 316: /* have partitions and want to use them? */
317: if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW) {
318: /*
319: * do bounds checking, adjust transfer. if error, process.
320: * if end of partition, just return
321: */
322: if (bounds_check_with_label(bp, &du->dk_dd, du->dk_wlabel) <= 0)
323: goto done;
324: /* otherwise, process transfer request */
1.1 root 325: }
1.1.1.4 ! root 326:
1.1.1.3 root 327: /* queue transfer on drive, activate drive and controller if idle */
1.1.1.4 ! root 328: dp = &wdutab[lunit];
1.1.1.3 root 329: s = splbio();
1.1.1.4 ! root 330: wddisksort(dp, bp);
1.1 root 331: if (dp->b_active == 0)
1.1.1.3 root 332: wdustart(du); /* start drive */
1.1.1.4 ! root 333: if (wdtab[du->dk_ctrlr].b_active == 0)
! 334: wdstart(du->dk_ctrlr); /* start controller */
1.1 root 335: splx(s);
1.1.1.4 ! root 336: return 0;
! 337:
1.1.1.3 root 338: done:
339: /* toss transfer, we're done early */
1.1 root 340: biodone(bp);
1.1.1.4 ! root 341: return 0;
1.1 root 342: }
343:
1.1.1.3 root 344: /*
345: * Routine to queue a command to the controller. The unit's
346: * request is linked into the active list for the controller.
347: * If the controller is idle, the transfer is started.
1.1 root 348: */
1.1.1.3 root 349: static void
350: wdustart(register struct disk *du)
1.1 root 351: {
1.1.1.4 ! root 352: register struct buf *bp, *dp = &wdutab[du->dk_lunit];
! 353: int ctrlr = du->dk_ctrlr;
! 354:
1.1.1.3 root 355: /* unit already active? */
1.1 root 356: if (dp->b_active)
357: return;
1.1.1.4 ! root 358:
1.1.1.3 root 359: /* anything to start? */
1.1 root 360: bp = dp->b_actf;
361: if (bp == NULL)
362: return;
1.1.1.4 ! root 363:
1.1.1.3 root 364: /* link onto controller queue */
1.1 root 365: dp->b_forw = NULL;
1.1.1.4 ! root 366: if (wdtab[ctrlr].b_actf == NULL)
! 367: wdtab[ctrlr].b_actf = dp;
1.1 root 368: else
1.1.1.4 ! root 369: wdtab[ctrlr].b_actl->b_forw = dp;
! 370: wdtab[ctrlr].b_actl = dp;
! 371:
1.1.1.3 root 372: /* mark the drive unit as busy */
373: dp->b_active = 1;
1.1 root 374: }
375:
376: /*
377: * Controller startup routine. This does the calculation, and starts
378: * a single-sector read or write operation. Called to start a transfer,
379: * or from the interrupt routine to continue a multi-sector transfer.
380: * RESTRICTIONS:
381: * 1. The transfer length must be an exact multiple of the sector size.
382: */
1.1.1.3 root 383: static void
1.1.1.4 ! root 384: wdstart(int ctrlr)
1.1 root 385: {
386: register struct disk *du; /* disk unit for IO */
387: register struct buf *bp;
1.1.1.3 root 388: struct disklabel *lp;
1.1 root 389: struct buf *dp;
1.1.1.4 ! root 390: long blknum, cylin, head, sector;
! 391: long secpertrk, secpercyl, addr;
! 392: int lunit, wdc;
! 393: int xfrblknum;
! 394: unsigned char status;
! 395:
1.1 root 396: loop:
1.1.1.3 root 397: /* is there a drive for the controller to do a transfer with? */
1.1.1.4 ! root 398: dp = wdtab[ctrlr].b_actf;
1.1 root 399: if (dp == NULL)
400: return;
1.1.1.4 ! root 401:
1.1.1.3 root 402: /* is there a transfer to this drive ? if so, link it on
403: the controller's queue */
1.1 root 404: bp = dp->b_actf;
405: if (bp == NULL) {
1.1.1.4 ! root 406: wdtab[ctrlr].b_actf = dp->b_forw;
1.1 root 407: goto loop;
408: }
1.1.1.4 ! root 409:
1.1.1.3 root 410: /* obtain controller and drive information */
1.1.1.4 ! root 411: lunit = wdunit(bp->b_dev);
! 412: du = wddrives[lunit];
! 413:
1.1.1.3 root 414: /* if not really a transfer, do control operations specially */
415: if (du->dk_state < OPEN) {
416: (void) wdcontrol(bp);
1.1 root 417: return;
418: }
1.1.1.4 ! root 419:
1.1.1.3 root 420: /* calculate transfer details */
421: blknum = bp->b_blkno + du->dk_skip;
1.1 root 422: #ifdef WDDEBUG
1.1.1.3 root 423: if (du->dk_skip == 0)
1.1.1.4 ! root 424: printf("\nwdstart %d: %s %d@%d; map ", lunit,
1.1 root 425: (bp->b_flags & B_READ) ? "read" : "write",
426: bp->b_bcount, blknum);
1.1.1.3 root 427: else
1.1.1.4 ! root 428: printf(" %d)%x", du->dk_skip, inb(du->dk_port+wd_altsts));
1.1 root 429: #endif
430: addr = (int) bp->b_un.b_addr;
1.1.1.4 ! root 431: if (du->dk_skip == 0) {
1.1.1.3 root 432: du->dk_bc = bp->b_bcount;
1.1.1.4 ! root 433: }
! 434: if (du->dk_skipm == 0) {
! 435: struct buf *oldbp, *nextbp;
! 436: oldbp = bp;
! 437: nextbp = bp->av_forw;
! 438: du->dk_bct = du->dk_bc;
! 439: oldbp->b_flags |= B_XXX;
! 440: while( nextbp
! 441: && (oldbp->b_flags & DKFL_SINGLE) == 0
! 442: && oldbp->b_dev == nextbp->b_dev
! 443: && nextbp->b_blkno == (oldbp->b_blkno + (oldbp->b_bcount/DEV_BSIZE))
! 444: && (oldbp->b_flags & B_READ) == (nextbp->b_flags & B_READ)) {
! 445: if( (du->dk_bct+nextbp->b_bcount)/DEV_BSIZE >= 240) {
! 446: break;
! 447: }
! 448: du->dk_bct += nextbp->b_bcount;
! 449: oldbp->b_flags |= B_XXX;
! 450: oldbp = nextbp;
! 451: nextbp = nextbp->av_forw;
! 452: }
! 453: }
! 454:
1.1.1.3 root 455: lp = &du->dk_dd;
456: secpertrk = lp->d_nsectors;
457: secpercyl = lp->d_secpercyl;
1.1.1.4 ! root 458: if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW)
! 459: blknum += lp->d_partitions[wdpart(bp->b_dev)].p_offset;
1.1 root 460: cylin = blknum / secpercyl;
461: head = (blknum % secpercyl) / secpertrk;
462: sector = blknum % secpertrk;
1.1.1.4 ! root 463:
! 464: #ifdef TIHBAD144
! 465: /* Check for bad sectors if we have them, and not formatting */
! 466: /* Only do this in single-sector mode, or when starting a */
! 467: /* multiple-sector transfer. */
! 468: #ifdef B_FORMAT
! 469: if ((du->dk_flags & DKFL_BADSECT) && !(bp->b_flags & B_FORMAT) &&
! 470: ((du->dk_skipm == 0) || (du->dk_flags & DKFL_SINGLE))) {
! 471: #else
! 472: if ((du->dk_flags & DKFL_BADSECT) &&
! 473: ((du->dk_skipm == 0) || (du->dk_flags & DKFL_SINGLE))) {
1.1 root 474: #endif
1.1.1.4 ! root 475:
! 476: long blkchk, blkend, blknew;
! 477: int i;
! 478:
! 479: blkend = blknum + howmany(du->dk_bct, DEV_BSIZE) - 1;
! 480: for (i = 0; (blkchk = du->dk_badsect[i]) != -1; i++) {
! 481: if (blkchk > blkend) {
! 482: break; /* transfer is completely OK; done */
! 483: } else if (blkchk == blknum) {
! 484: blknew = lp->d_secperunit - lp->d_nsectors - i - 1;
! 485: cylin = blknew / secpercyl;
! 486: head = (blknew % secpercyl) / secpertrk;
! 487: sector = blknew % secpertrk;
! 488: du->dk_flags |= DKFL_SINGLE;
! 489: /* found and replaced first blk of transfer; done */
! 490: break;
! 491: } else if (blkchk > blknum) {
! 492: du->dk_flags |= DKFL_SINGLE;
! 493: break; /* bad block inside transfer; done */
! 494: }
1.1 root 495: }
496: }
1.1.1.4 ! root 497: #endif
! 498: if( du->dk_flags & DKFL_SINGLE) {
! 499: du->dk_bct = du->dk_bc;
! 500: du->dk_skipm = du->dk_skip;
! 501: }
! 502:
! 503: #ifdef WDDEBUG
! 504: pg("c%d h%d s%d ", cylin, head, sector);
! 505: #endif
1.1 root 506:
1.1.1.4 ! root 507: sector += 1; /* sectors begin with 1, not 0 */
! 508:
! 509: wdtab[ctrlr].b_active = 1; /* mark controller active */
1.1.1.3 root 510: wdc = du->dk_port;
1.1.1.4 ! root 511:
! 512: #ifdef INSTRUMENT
! 513: /* instrumentation */
! 514: if (du->dk_unit >= 0 && du->dk_skip == 0) {
! 515: dk_busy |= 1 << du->dk_lunit;
! 516: dk_wds[du->dk_lunit] += bp->b_bcount >> 6;
! 517: }
! 518: if (du->dk_unit >= 0 && du->dk_skipm == 0) {
! 519: ++dk_seek[du->dk_lunit];
! 520: ++dk_xfer[du->dk_lunit];
! 521: }
! 522: #endif
1.1 root 523:
1.1.1.3 root 524: /* if starting a multisector transfer, or doing single transfers */
1.1.1.4 ! root 525: if (du->dk_skipm == 0 || (du->dk_flags & DKFL_SINGLE)) {
! 526: if (wdtab[ctrlr].b_errcnt && (bp->b_flags & B_READ) == 0) {
1.1.1.3 root 527: du->dk_bc += DEV_BSIZE;
1.1.1.4 ! root 528: du->dk_bct += DEV_BSIZE;
! 529: }
1.1.1.3 root 530:
531: /* controller idle? */
532: while (inb(wdc+wd_status) & WDCS_BUSY)
533: ;
1.1.1.4 ! root 534:
1.1.1.3 root 535: /* stuff the task file */
536: outb(wdc+wd_precomp, lp->d_precompcyl / 4);
537: #ifdef B_FORMAT
538: if (bp->b_flags & B_FORMAT) {
539: outb(wdc+wd_sector, lp->d_gap3);
540: outb(wdc+wd_seccnt, lp->d_nsectors);
541: } else {
1.1.1.4 ! root 542: if (du->dk_flags & DKFL_SINGLE)
! 543: outb(wdc+wd_seccnt, 1);
! 544: else
! 545: outb(wdc+wd_seccnt, howmany(du->dk_bct, DEV_BSIZE));
! 546: outb(wdc+wd_sector, sector);
! 547: }
! 548: #else
1.1.1.3 root 549: if (du->dk_flags & DKFL_SINGLE)
550: outb(wdc+wd_seccnt, 1);
551: else
1.1.1.4 ! root 552: outb(wdc+wd_seccnt, howmany(du->dk_bct, DEV_BSIZE));
1.1.1.3 root 553: outb(wdc+wd_sector, sector);
554: #endif
555: outb(wdc+wd_cyl_lo, cylin);
556: outb(wdc+wd_cyl_hi, cylin >> 8);
1.1.1.4 ! root 557:
1.1.1.3 root 558: /* set up the SDH register (select drive) */
1.1.1.4 ! root 559: outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit<<4) | (head & 0xf));
! 560:
1.1.1.3 root 561: /* wait for drive to become ready */
562: while ((inb(wdc+wd_status) & WDCS_READY) == 0)
563: ;
1.1.1.4 ! root 564:
1.1.1.3 root 565: /* initiate command! */
566: #ifdef B_FORMAT
567: if (bp->b_flags & B_FORMAT)
568: outb(wdc+wd_command, WDCC_FORMAT);
569: else
1.1.1.4 ! root 570: outb(wdc+wd_command,
! 571: (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);
! 572: #else
! 573: outb(wdc+wd_command, (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);
1.1.1.3 root 574: #endif
575: #ifdef WDDEBUG
576: printf("sector %d cylin %d head %d addr %x sts %x\n",
1.1.1.4 ! root 577: sector, cylin, head, addr, inb(wdc+wd_altsts));
1.1.1.3 root 578: #endif
579: }
1.1.1.4 ! root 580:
1.1.1.3 root 581: /* if this is a read operation, just go away until it's done. */
1.1.1.4 ! root 582: if (bp->b_flags & B_READ)
! 583: return;
! 584:
1.1.1.3 root 585: /* ready to send data? */
1.1.1.4 ! root 586: while ((inb(wdc+wd_altsts) & WDCS_DRQ) == 0)
1.1.1.3 root 587: ;
1.1.1.4 ! root 588:
1.1.1.3 root 589: /* then send it! */
1.1.1.4 ! root 590: outagain:
1.1.1.3 root 591: outsw (wdc+wd_data, addr+du->dk_skip * DEV_BSIZE,
592: DEV_BSIZE/sizeof(short));
593: du->dk_bc -= DEV_BSIZE;
1.1.1.4 ! root 594: du->dk_bct -= DEV_BSIZE;
1.1 root 595: }
596:
597: /* Interrupt routine for the controller. Acknowledge the interrupt, check for
598: * errors on the current operation, mark it done if necessary, and start
599: * the next request. Also check for a partially done transfer, and
600: * continue with the next chunk if so.
601: */
1.1.1.3 root 602: void
603: wdintr(struct intrframe wdif)
1.1 root 604: {
605: register struct disk *du;
606: register struct buf *bp, *dp;
1.1.1.4 ! root 607: int status, wdc, ctrlr;
! 608:
! 609: ctrlr = wdif.if_vec;
1.1 root 610:
1.1.1.4 ! root 611: if (!wdtab[ctrlr].b_active) {
! 612: printf("wdc%d: extra interrupt\n", ctrlr);
1.1 root 613: return;
614: }
1.1.1.4 ! root 615:
! 616: dp = wdtab[ctrlr].b_actf;
1.1 root 617: bp = dp->b_actf;
1.1.1.3 root 618: du = wddrives[wdunit(bp->b_dev)];
619: wdc = du->dk_port;
1.1.1.4 ! root 620:
1.1.1.3 root 621: #ifdef WDDEBUG
1.1.1.4 ! root 622: printf("I%d ", ctrlr);
1.1.1.3 root 623: #endif
1.1.1.4 ! root 624:
! 625: while ((status = inb(wdc+wd_status)) & WDCS_BUSY)
! 626: ;
! 627:
1.1.1.3 root 628: /* is it not a transfer, but a control operation? */
629: if (du->dk_state < OPEN) {
1.1 root 630: if (wdcontrol(bp))
1.1.1.4 ! root 631: wdstart(ctrlr);
1.1 root 632: return;
633: }
1.1.1.4 ! root 634:
1.1.1.3 root 635: /* have we an error? */
1.1 root 636: if (status & (WDCS_ERR | WDCS_ECCCOR)) {
1.1.1.3 root 637: du->dk_status = status;
638: du->dk_error = inb(wdc + wd_error);
1.1 root 639: #ifdef WDDEBUG
1.1.1.3 root 640: printf("status %x error %x\n", status, du->dk_error);
1.1 root 641: #endif
1.1.1.3 root 642: if((du->dk_flags & DKFL_SINGLE) == 0) {
643: du->dk_flags |= DKFL_ERROR;
1.1 root 644: goto outt;
645: }
1.1.1.3 root 646: #ifdef B_FORMAT
647: if (bp->b_flags & B_FORMAT) {
1.1 root 648: bp->b_flags |= B_ERROR;
649: goto done;
1.1.1.3 root 650: }
651: #endif
1.1.1.4 ! root 652:
1.1.1.3 root 653: /* error or error correction? */
1.1 root 654: if (status & WDCS_ERR) {
1.1.1.4 ! root 655: if (++wdtab[ctrlr].b_errcnt < RETRIES) {
! 656: wdtab[ctrlr].b_active = 0;
1.1 root 657: } else {
1.1.1.4 ! root 658: if((du->dk_flags & DKFL_QUIET) == 0) {
1.1.1.3 root 659: diskerr(bp, "wd", "hard error",
660: LOG_PRINTF, du->dk_skip,
661: &du->dk_dd);
662: #ifdef WDDEBUG
663: printf( "status %b error %b\n",
664: status, WDCS_BITS,
665: inb(wdc+wd_error), WDERR_BITS);
666: #endif
667: }
1.1 root 668: bp->b_flags |= B_ERROR; /* flag the error */
669: }
1.1.1.4 ! root 670: } else if((du->dk_flags & DKFL_QUIET) == 0) {
! 671: diskerr(bp, "wd", "soft ecc", 0,
! 672: du->dk_skip, &du->dk_dd);
1.1.1.3 root 673: }
1.1 root 674: }
675: outt:
1.1.1.4 ! root 676:
1.1 root 677: /*
678: * If this was a successful read operation, fetch the data.
679: */
1.1.1.4 ! root 680: if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab[ctrlr].b_active) {
1.1 root 681: int chk, dummy;
1.1.1.4 ! root 682:
1.1.1.3 root 683: chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short));
1.1.1.4 ! root 684:
1.1.1.3 root 685: /* ready to receive data? */
686: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
687: ;
1.1.1.4 ! root 688:
1.1.1.3 root 689: /* suck in data */
690: insw (wdc+wd_data,
691: (int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk);
692: du->dk_bc -= chk * sizeof(short);
1.1.1.4 ! root 693: du->dk_bct -= chk * sizeof(short);
! 694:
1.1.1.3 root 695: /* for obselete fractional sector reads */
1.1.1.4 ! root 696: while (chk++ < (DEV_BSIZE / sizeof(short)))
! 697: insw(wdc+wd_data, &dummy, 1);
1.1 root 698: }
1.1.1.4 ! root 699:
! 700: wdxfer[du->dk_lunit]++;
! 701: if (wdtab[ctrlr].b_active) {
! 702: #ifdef INSTRUMENT
! 703: if (du->dk_unit >= 0)
! 704: dk_busy &=~ (1 << du->dk_unit);
! 705: #endif
1.1 root 706: if ((bp->b_flags & B_ERROR) == 0) {
1.1.1.4 ! root 707: du->dk_skip++; /* Add to succ. sect */
! 708: du->dk_skipm++; /* Add to succ. sect for multitransfer */
! 709: if (wdtab[ctrlr].b_errcnt && (du->dk_flags & DKFL_QUIET) == 0)
1.1.1.3 root 710: diskerr(bp, "wd", "soft error", 0,
711: du->dk_skip, &du->dk_dd);
1.1.1.4 ! root 712: wdtab[ctrlr].b_errcnt = 0;
! 713:
1.1 root 714: /* see if more to transfer */
1.1.1.3 root 715: if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) {
1.1.1.4 ! root 716: if( (du->dk_flags & DKFL_SINGLE)
! 717: || (du->dk_flags & B_READ) == 0)
! 718: wdstart(ctrlr);
! 719: return; /* next chunk is started */
! 720: } else if ((du->dk_flags & (DKFL_SINGLE|DKFL_ERROR)) == DKFL_ERROR) {
1.1 root 721: du->dk_skip = 0;
1.1.1.4 ! root 722: du->dk_skipm = 0;
1.1.1.3 root 723: du->dk_flags &= ~DKFL_ERROR;
724: du->dk_flags |= DKFL_SINGLE;
1.1.1.4 ! root 725: wdstart(ctrlr);
1.1 root 726: return; /* redo xfer sector by sector */
727: }
728: }
729:
730: done:
731: /* done with this transfer, with or without error */
1.1.1.3 root 732: du->dk_flags &= ~DKFL_SINGLE;
1.1.1.4 ! root 733: wdtab[ctrlr].b_errcnt = 0;
1.1 root 734: du->dk_skip = 0;
1.1.1.4 ! root 735: if( du->dk_bct == 0) {
! 736: wdtab[ctrlr].b_actf = dp->b_forw;
! 737: du->dk_skipm = 0;
! 738: dp->b_active = 0;
! 739: }
1.1 root 740: dp->b_actf = bp->av_forw;
741: dp->b_errcnt = 0;
742: bp->b_resid = 0;
1.1.1.4 ! root 743: bp->b_flags &= ~B_XXX;
1.1 root 744: biodone(bp);
745: }
1.1.1.4 ! root 746:
1.1.1.3 root 747: /* anything more on drive queue? */
1.1.1.4 ! root 748: if (dp->b_actf && du->dk_bct == 0)
1.1.1.3 root 749: wdustart(du);
1.1.1.4 ! root 750:
1.1.1.3 root 751: /* anything more for controller to do? */
1.1.1.4 ! root 752: if (wdtab[ctrlr].b_actf)
! 753: wdstart(ctrlr);
! 754:
! 755: if (!wdtab[ctrlr].b_actf)
! 756: wdtab[ctrlr].b_active = 0;
1.1 root 757: }
758:
759: /*
760: * Initialize a drive.
761: */
1.1.1.3 root 762: int
763: wdopen(dev_t dev, int flags, int fmt, struct proc *p)
1.1 root 764: {
1.1.1.4 ! root 765: register unsigned int lunit;
1.1 root 766: register struct disk *du;
1.1.1.4 ! root 767: int part = wdpart(dev), mask = 1 << part;
! 768: struct partition *pp;
! 769: int error = 0;
1.1.1.3 root 770: char *msg;
1.1.1.4 ! root 771:
! 772: lunit = wdunit(dev);
! 773: if (lunit >= NWD)
! 774: return (ENXIO);
! 775:
! 776: du = wddrives[lunit];
! 777:
! 778: if (du == 0)
! 779: return (ENXIO);
! 780:
! 781: #ifdef WDOPENLOCK
! 782: printf("[Enter wd%d%c]\n", lunit, part+'a');
! 783: if (wdopenbusy) {
! 784: printf("[Sleep wd%d%c]\n", lunit, part+'a');
! 785: while (wdopenbusy)
! 786: ;
! 787: }
! 788: printf("[Lock wd%d%c]\n", lunit, part+'a');
! 789: wdopenbusy = 1;
! 790: #endif
1.1 root 791:
1.1.1.4 ! root 792: #ifdef QUIETWORKS
! 793: if (part == WDRAW)
! 794: du->dk_flags |= DKFL_QUIET;
! 795: else
! 796: du->dk_flags &= ~DKFL_QUIET;
! 797: #else
! 798: du->dk_flags &= ~DKFL_QUIET;
! 799: #endif
! 800:
1.1.1.3 root 801: if ((du->dk_flags & DKFL_BSDLABEL) == 0) {
802: du->dk_flags |= DKFL_WRITEPROT;
1.1.1.4 ! root 803: #ifdef WDOPENLOCK
! 804: printf("[Init wd%d%c]\n", lunit, part+'a');
! 805: #endif
! 806: wdutab[lunit].b_actf = NULL;
1.1.1.3 root 807:
808: /*
809: * Use the default sizes until we've read the label,
810: * or longer if there isn't one there.
811: */
812: bzero(&du->dk_dd, sizeof(du->dk_dd));
813: #undef d_type /* fix goddamn segments.h! XXX */
814: du->dk_dd.d_type = DTYPE_ST506;
815: du->dk_dd.d_ncylinders = 1024;
816: du->dk_dd.d_secsize = DEV_BSIZE;
817: du->dk_dd.d_ntracks = 8;
818: du->dk_dd.d_nsectors = 17;
819: du->dk_dd.d_secpercyl = 17*8;
1.1.1.4 ! root 820: du->dk_dd.d_secperunit = 17*8*1024;
1.1.1.3 root 821: du->dk_state = WANTOPEN;
822:
1.1.1.4 ! root 823: /* read label using "raw" partition */
! 824: #if defined(TIHMODS) && defined(garbage)
! 825: /* wdsetctlr(dev, du); */ /* Maybe do this TIH */
! 826: msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW),
! 827: wdstrategy, &du->dk_dd, du->dk_dospartitions,
! 828: 0, 0);
! 829: wdsetctlr(dev, du);
! 830: msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW),
! 831: wdstrategy, &du->dk_dd, du->dk_dospartitions,
! 832: &du->dk_bad, 0);
! 833: if (msg) {
! 834: #ifdef QUIETWORKS
! 835: if((du->dk_flags & DKFL_QUIET) == 0) {
! 836: log(LOG_WARNING, "wd%d: cannot find label (%s)\n",
! 837: lunit, msg);
! 838: error = EINVAL; /* XXX needs translation */
! 839: }
! 840: #else
! 841: log(LOG_WARNING, "wd%d: cannot find label (%s)\n", lunit, msg);
! 842: if(part != WDRAW) {
! 843: error = EINVAL; /* XXX needs translation */
! 844: }
! 845: #endif
! 846: goto done;
! 847: } else {
! 848: wdsetctlr(dev, du);
! 849: du->dk_flags |= DKFL_BSDLABEL;
! 850: du->dk_flags &= ~DKFL_WRITEPROT;
! 851: if (du->dk_dd.d_flags & D_BADSECT)
! 852: du->dk_flags |= DKFL_BADSECT;
! 853: }
! 854: #else
1.1.1.3 root 855: if (msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW),
1.1.1.4 ! root 856: wdstrategy, &du->dk_dd, du->dk_dospartitions,
! 857: &du->dk_bad, 0)) {
! 858: if((du->dk_flags & DKFL_QUIET) == 0) {
1.1.1.3 root 859: log(LOG_WARNING, "wd%d: cannot find label (%s)\n",
1.1.1.4 ! root 860: lunit, msg);
1.1.1.3 root 861: error = EINVAL; /* XXX needs translation */
862: }
863: goto done;
864: } else {
865: wdsetctlr(dev, du);
866: du->dk_flags |= DKFL_BSDLABEL;
867: du->dk_flags &= ~DKFL_WRITEPROT;
868: if (du->dk_dd.d_flags & D_BADSECT)
869: du->dk_flags |= DKFL_BADSECT;
870: }
1.1.1.4 ! root 871: #endif
1.1.1.3 root 872:
1.1 root 873: done:
1.1.1.4 ! root 874: if (error) {
! 875: #ifdef WDOPENLOCK
! 876: printf("[Error wd%d%c]\n", lunit, part+'a');
! 877: wdopenbusy = 0;
! 878: #endif
1.1.1.3 root 879: return(error);
1.1.1.4 ! root 880: }
1.1.1.3 root 881: }
1.1 root 882:
1.1.1.4 ! root 883: #ifdef TIHBAD144
! 884: if (du->dk_flags & DKFL_BADSECT)
! 885: bad144intern(du);
! 886: #endif
1.1.1.3 root 887:
1.1.1.4 ! root 888: /*
! 889: * Warn if a partion is opened
! 890: * that overlaps another partition which is open
! 891: * unless one is the "raw" partition (whole disk).
! 892: */
! 893: if ((du->dk_openpart & mask) == 0 /*&& part != RAWPART*/ && part != WDRAW) {
! 894: int start, end;
! 895:
! 896: pp = &du->dk_dd.d_partitions[part];
! 897: start = pp->p_offset;
! 898: end = pp->p_offset + pp->p_size;
! 899: for (pp = du->dk_dd.d_partitions;
! 900: pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions]; pp++) {
! 901: if (pp->p_offset + pp->p_size <= start || pp->p_offset >= end)
! 902: continue;
! 903: /*if (pp - du->dk_dd.d_partitions == RAWPART)
! 904: continue; */
! 905: if (pp - du->dk_dd.d_partitions == WDRAW)
! 906: continue;
! 907: if (du->dk_openpart & (1 << (pp - du->dk_dd.d_partitions)))
! 908: log(LOG_WARNING,
! 909: "wd%d%c: overlaps open partition (%c)\n",
! 910: lunit, part + 'a',
! 911: pp - du->dk_dd.d_partitions + 'a');
! 912: }
! 913: }
! 914:
! 915: if (part >= du->dk_dd.d_npartitions && part != WDRAW) {
! 916: #ifdef WDOPENLOCK
! 917: printf("[ENXIO wd%d%c]\n", lunit, part+'a');
! 918: wdopenbusy = 0;
! 919: #endif
! 920: return (ENXIO);
! 921: }
! 922:
1.1.1.3 root 923: /* insure only one open at a time */
1.1.1.4 ! root 924: du->dk_openpart |= mask;
! 925: switch (fmt) {
! 926: case S_IFCHR:
! 927: du->dk_copenpart |= mask;
! 928: break;
! 929: case S_IFBLK:
! 930: du->dk_bopenpart |= mask;
! 931: break;
! 932: }
! 933: #ifdef WDOPENLOCK
! 934: printf("[Done wd%d%c]\n", lunit, part+'a');
! 935: wdopenbusy = 0;
! 936: #endif
1.1.1.3 root 937: return (0);
1.1 root 938: }
939:
940: /*
941: * Implement operations other than read/write.
942: * Called from wdstart or wdintr during opens and formats.
943: * Uses finite-state-machine to track progress of operation in progress.
944: * Returns 0 if operation still in progress, 1 if completed.
945: */
1.1.1.3 root 946: static int
947: wdcontrol(register struct buf *bp)
1.1 root 948: {
949: register struct disk *du;
1.1.1.4 ! root 950: register unit, lunit;
1.1 root 951: unsigned char stat;
1.1.1.4 ! root 952: int s, ctrlr;
! 953: int wdc;
! 954:
1.1.1.3 root 955: du = wddrives[wdunit(bp->b_dev)];
1.1.1.4 ! root 956: ctrlr = du->dk_ctrlr;
1.1 root 957: unit = du->dk_unit;
1.1.1.4 ! root 958: lunit = du->dk_lunit;
1.1.1.3 root 959: wdc = du->dk_port;
1.1.1.4 ! root 960:
1.1.1.3 root 961: switch (du->dk_state) {
1.1.1.4 ! root 962: tryagainrecal:
1.1 root 963: case WANTOPEN: /* set SDH, step rate, do restore */
964: #ifdef WDDEBUG
1.1.1.4 ! root 965: printf("wd%d: recal ", lunit);
1.1 root 966: #endif
967: s = splbio(); /* not called from intr level ... */
1.1.1.3 root 968: wdgetctlr(unit, du);
1.1.1.4 ! root 969: #ifdef TIPCAT
! 970: while ((inb(wdc+wd_status) & WDCS_READY) == 0)
! 971: ;
! 972: #endif
1.1 root 973: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
1.1.1.4 ! root 974: wdtab[ctrlr].b_active = 1;
1.1 root 975: outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
1.1.1.4 ! root 976: #ifdef TIPCAT
! 977: while ((inb(wdc+wd_status) & WDCS_READY) == 0)
! 978: ;
! 979: #endif
! 980: du->dk_state = RECAL;
1.1 root 981: splx(s);
982: return(0);
983: case RECAL:
984: if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
1.1.1.3 root 985: if ((du->dk_flags & DKFL_QUIET) == 0) {
1.1.1.4 ! root 986: printf("wd%d: recal", du->dk_lunit);
1.1 root 987: printf(": status %b error %b\n",
1.1.1.4 ! root 988: stat, WDCS_BITS, inb(wdc+wd_error),
! 989: WDERR_BITS);
1.1 root 990: }
1.1.1.4 ! root 991: if (++wdtab[ctrlr].b_errcnt < RETRIES)
1.1.1.3 root 992: goto tryagainrecal;
993: bp->b_error = ENXIO; /* XXX needs translation */
1.1 root 994: goto badopen;
995: }
996:
1.1.1.3 root 997: /* some controllers require this ... */
1.1 root 998: wdsetctlr(bp->b_dev, du);
1.1.1.4 ! root 999:
! 1000: wdtab[ctrlr].b_errcnt = 0;
1.1.1.3 root 1001: du->dk_state = OPEN;
1.1 root 1002: /*
1003: * The rest of the initialization can be done
1004: * by normal means.
1005: */
1006: return(1);
1007: default:
1008: panic("wdcontrol");
1009: }
1010: /* NOTREACHED */
1011:
1012: badopen:
1.1.1.3 root 1013: if ((du->dk_flags & DKFL_QUIET) == 0)
1014: printf(": status %b error %b\n",
1015: stat, WDCS_BITS, inb(wdc + wd_error), WDERR_BITS);
1016: bp->b_flags |= B_ERROR;
1.1 root 1017: return(1);
1018: }
1019:
1.1.1.3 root 1020: /*
1021: * send a command and wait uninterruptibly until controller is finished.
1022: * return -1 if controller busy for too long, otherwise
1023: * return status. intended for brief controller commands at critical points.
1024: * assumes interrupts are blocked.
1025: */
1026: static int
1.1.1.4 ! root 1027: wdcommand(struct disk *du, int cmd)
! 1028: {
! 1029: int timeout = 5000000, stat, wdc;
! 1030:
! 1031: DELAY(2000);
1.1.1.3 root 1032: /* controller ready for command? */
1033: wdc = du->dk_port;
1034: while (((stat = inb(wdc + wd_status)) & WDCS_BUSY) && timeout > 0)
1035: timeout--;
1036: if (timeout <= 0)
1037: return(-1);
1.1.1.4 ! root 1038:
1.1.1.3 root 1039: /* send command, await results */
1040: outb(wdc+wd_command, cmd);
1041: while (((stat = inb(wdc+wd_status)) & WDCS_BUSY) && timeout > 0)
1042: timeout--;
1043: if (timeout <= 0)
1044: return(-1);
1045: if (cmd != WDCC_READP)
1046: return (stat);
1.1.1.4 ! root 1047:
1.1.1.3 root 1048: /* is controller ready to return data? */
1049: while (((stat = inb(wdc+wd_status)) & (WDCS_ERR|WDCS_DRQ)) == 0 &&
1.1.1.4 ! root 1050: timeout > 0)
1.1.1.3 root 1051: timeout--;
1052: if (timeout <= 0)
1053: return(-1);
1054: return (stat);
1055: }
1056:
1057: /*
1058: * issue IDC to drive to tell it just what geometry it is to be.
1059: */
1060: static int
1.1.1.4 ! root 1061: wdsetctlr(dev_t dev, struct disk *du)
! 1062: {
1.1.1.3 root 1063: int stat, x, wdc;
1.1.1.4 ! root 1064:
! 1065: /*
! 1066: printf("wd(%d,%d) C%dH%dS%d\n", du->dk_ctrlr, du->dk_unit,
! 1067: du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks, du->dk_dd.d_nsectors);
! 1068: */
! 1069:
! 1070: DELAY(2000);
1.1.1.3 root 1071: x = splbio();
1072: wdc = du->dk_port;
1.1.1.4 ! root 1073: outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders); /* TIH: was ...ders+1 */
! 1074: outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders)>>8); /* TIH: was ...ders+1 */
! 1075: outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4) + du->dk_dd.d_ntracks-1);
1.1 root 1076: outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
1.1.1.3 root 1077: stat = wdcommand(du, WDCC_IDC);
1.1.1.4 ! root 1078:
! 1079: #ifndef TIHMODS
1.1.1.3 root 1080: if (stat < 0)
1081: return(stat);
1.1.1.4 ! root 1082: #endif
1.1.1.3 root 1083: if (stat & WDCS_ERR)
1084: printf("wdsetctlr: status %b error %b\n",
1085: stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
1086: splx(x);
1.1 root 1087: return(stat);
1088: }
1089:
1.1.1.3 root 1090: /*
1091: * issue READP to drive to ask it what it is.
1092: */
1093: static int
1.1.1.4 ! root 1094: wdgetctlr(int u, struct disk *du)
! 1095: {
1.1.1.3 root 1096: int stat, x, i, wdc;
1097: char tb[DEV_BSIZE];
1098: struct wdparams *wp;
1.1.1.4 ! root 1099: long timeout = 5000000;
! 1100:
1.1.1.3 root 1101: x = splbio(); /* not called from intr level ... */
1102: wdc = du->dk_port;
1.1.1.4 ! root 1103: #ifdef TIPCAT
! 1104: while ((inb(wdc+wd_status) & WDCS_READY) == 0 && timeout > 0)
! 1105: timeout--;
! 1106: if (timeout <= 0) {
! 1107: splx(x);
! 1108: return (-1);
! 1109: }
! 1110: #endif
1.1.1.3 root 1111: outb(wdc+wd_sdh, WDSD_IBM | (u << 4));
1112: stat = wdcommand(du, WDCC_READP);
1.1.1.4 ! root 1113: #ifdef TIPCAT
! 1114: while ((inb(wdc+wd_status) & WDCS_READY) == 0 && timeout > 0)
! 1115: timeout--;
! 1116: if (timeout <= 0) {
! 1117: splx(x);
! 1118: return (-1);
! 1119: }
! 1120: #endif
! 1121:
! 1122: #ifndef TIHMODS
1.1.1.3 root 1123: if (stat < 0)
1124: return(stat);
1.1.1.4 ! root 1125: #else
! 1126: if (stat < 0) {
! 1127: splx(x);
! 1128: return(stat);
! 1129: }
! 1130: #endif
1.1.1.3 root 1131: if (stat & WDCS_ERR) {
1132: splx(x);
1133: return(inb(wdc+wd_error));
1134: }
1.1.1.4 ! root 1135:
1.1.1.3 root 1136: /* obtain parameters */
1137: wp = &du->dk_params;
1138: insw(wdc+wd_data, tb, sizeof(tb)/sizeof(short));
1139: bcopy(tb, wp, sizeof(struct wdparams));
1.1.1.4 ! root 1140:
1.1.1.3 root 1141: /* shuffle string byte order */
1.1.1.4 ! root 1142: for (i=0; i < sizeof(wp->wdp_model); i+=2) {
1.1.1.3 root 1143: u_short *p;
1144: p = (u_short *) (wp->wdp_model + i);
1145: *p = ntohs(*p);
1146: }
1.1.1.4 ! root 1147: /*
! 1148: printf("gc %x cyl %d trk %d sec %d type %d sz %d model %s\n", wp->wdp_config,
! 1149: wp->wdp_fixedcyl+wp->wdp_removcyl, wp->wdp_heads, wp->wdp_sectors,
! 1150: wp->wdp_cntype, wp->wdp_cnsbsz, wp->wdp_model);
! 1151: */
! 1152:
1.1.1.3 root 1153: /* update disklabel given drive information */
1154: du->dk_dd.d_ncylinders = wp->wdp_fixedcyl + wp->wdp_removcyl /*+- 1*/;
1155: du->dk_dd.d_ntracks = wp->wdp_heads;
1156: du->dk_dd.d_nsectors = wp->wdp_sectors;
1157: du->dk_dd.d_secpercyl = du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
1.1.1.4 ! root 1158: du->dk_dd.d_partitions[1].p_size = du->dk_dd.d_secpercyl * wp->wdp_sectors;
1.1.1.3 root 1159: du->dk_dd.d_partitions[1].p_offset = 0;
1.1.1.4 ! root 1160:
1.1.1.3 root 1161: /* dubious ... */
1162: bcopy("ESDI/IDE", du->dk_dd.d_typename, 9);
1163: bcopy(wp->wdp_model+20, du->dk_dd.d_packname, 14-1);
1164: /* better ... */
1165: du->dk_dd.d_type = DTYPE_ESDI;
1166: du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
1.1.1.4 ! root 1167:
1.1.1.3 root 1168: /* XXX sometimes possibly needed */
1169: (void) inb(wdc+wd_status);
1.1.1.4 ! root 1170: #ifdef TIHMODS
! 1171: splx(x);
! 1172: #endif
1.1.1.3 root 1173: return (0);
1174: }
1175:
1176:
1.1 root 1177: /* ARGSUSED */
1.1.1.3 root 1178: int
1179: wdclose(dev_t dev, int flags, int fmt)
1.1 root 1180: {
1181: register struct disk *du;
1.1.1.4 ! root 1182: int part = wdpart(dev), mask = 1 << part;
! 1183:
1.1.1.3 root 1184: du = wddrives[wdunit(dev)];
1.1.1.4 ! root 1185:
1.1.1.3 root 1186: /* insure only one open at a time */
1.1.1.4 ! root 1187: du->dk_openpart &= ~mask;
! 1188: switch (fmt) {
! 1189: case S_IFCHR:
! 1190: du->dk_copenpart &= ~mask;
! 1191: break;
! 1192: case S_IFBLK:
! 1193: du->dk_bopenpart &= ~mask;
! 1194: break;
! 1195: }
1.1.1.2 root 1196: return(0);
1.1 root 1197: }
1198:
1.1.1.3 root 1199: int
1200: wdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
1.1 root 1201: {
1.1.1.4 ! root 1202: int lunit = wdunit(dev);
1.1 root 1203: register struct disk *du;
1204: int error = 0;
1205: struct uio auio;
1206: struct iovec aiov;
1.1.1.4 ! root 1207:
! 1208: du = wddrives[lunit];
! 1209:
1.1 root 1210: switch (cmd) {
1.1.1.3 root 1211: case DIOCSBAD:
1.1.1.4 ! root 1212: if ((flag & FWRITE) == 0)
! 1213: error = EBADF;
! 1214: else {
1.1.1.3 root 1215: du->dk_bad = *(struct dkbad *)addr;
1.1.1.4 ! root 1216: #ifdef TIHBAD144
! 1217: bad144intern(du);
! 1218: #endif
! 1219: }
1.1.1.3 root 1220: break;
1221:
1.1 root 1222: case DIOCGDINFO:
1223: *(struct disklabel *)addr = du->dk_dd;
1224: break;
1.1.1.4 ! root 1225:
! 1226: case DIOCGPART:
! 1227: ((struct partinfo *)addr)->disklab = &du->dk_dd;
! 1228: ((struct partinfo *)addr)->part =
! 1229: &du->dk_dd.d_partitions[wdpart(dev)];
! 1230: break;
! 1231:
! 1232: case DIOCSDINFO:
! 1233: if ((flag & FWRITE) == 0)
! 1234: error = EBADF;
! 1235: else
! 1236: error = setdisklabel(&du->dk_dd, (struct disklabel *)addr,
! 1237: /*(du->dk_flags&DKFL_BSDLABEL) ? du->dk_openpart : */0,
! 1238: du->dk_dospartitions);
! 1239: if (error == 0) {
1.1.1.3 root 1240: du->dk_flags |= DKFL_BSDLABEL;
1241: wdsetctlr(dev, du);
1242: }
1.1.1.4 ! root 1243: break;
! 1244:
! 1245: case DIOCWLABEL:
1.1.1.3 root 1246: du->dk_flags &= ~DKFL_WRITEPROT;
1.1.1.4 ! root 1247: if ((flag & FWRITE) == 0)
! 1248: error = EBADF;
! 1249: else
! 1250: du->dk_wlabel = *(int *)addr;
! 1251: break;
! 1252:
! 1253: case DIOCWDINFO:
1.1.1.3 root 1254: du->dk_flags &= ~DKFL_WRITEPROT;
1.1.1.4 ! root 1255: if ((flag & FWRITE) == 0)
! 1256: error = EBADF;
! 1257: else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr,
! 1258: /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart :*/ 0,
! 1259: du->dk_dospartitions)) == 0) {
! 1260: int wlab;
! 1261:
1.1.1.3 root 1262: du->dk_flags |= DKFL_BSDLABEL;
1.1 root 1263: wdsetctlr(dev, du);
1.1.1.4 ! root 1264:
! 1265: /* simulate opening partition 0 so write succeeds */
! 1266: du->dk_openpart |= (1 << 0); /* XXX */
! 1267: wlab = du->dk_wlabel;
! 1268: du->dk_wlabel = 1;
! 1269: error = writedisklabel(dev, wdstrategy,
1.1.1.3 root 1270: &du->dk_dd, du->dk_dospartitions);
1.1.1.4 ! root 1271: du->dk_openpart = du->dk_copenpart | du->dk_bopenpart;
! 1272: du->dk_wlabel = wlab;
! 1273: }
! 1274: break;
! 1275:
1.1 root 1276: #ifdef notyet
1277: case DIOCGDINFOP:
1278: *(struct disklabel **)addr = &(du->dk_dd);
1279: break;
1.1.1.4 ! root 1280:
1.1 root 1281: case DIOCWFORMAT:
1282: if ((flag & FWRITE) == 0)
1283: error = EBADF;
1284: else {
1285: register struct format_op *fop;
1.1.1.4 ! root 1286:
1.1 root 1287: fop = (struct format_op *)addr;
1288: aiov.iov_base = fop->df_buf;
1289: aiov.iov_len = fop->df_count;
1290: auio.uio_iov = &aiov;
1291: auio.uio_iovcnt = 1;
1292: auio.uio_resid = fop->df_count;
1293: auio.uio_segflg = 0;
1.1.1.4 ! root 1294: auio.uio_offset = fop->df_startblk * du->dk_dd.d_secsize;
! 1295: error = physio(wdformat, &rwdbuf[lunit], dev, B_WRITE,
1.1 root 1296: minphys, &auio);
1297: fop->df_count -= auio.uio_resid;
1298: fop->df_reg[0] = du->dk_status;
1299: fop->df_reg[1] = du->dk_error;
1300: }
1301: break;
1302: #endif
1.1.1.4 ! root 1303:
1.1 root 1304: default:
1305: error = ENOTTY;
1306: break;
1307: }
1308: return (error);
1309: }
1310:
1.1.1.3 root 1311: #ifdef B_FORMAT
1312: int
1313: wdformat(struct buf *bp)
1.1 root 1314: {
1315: bp->b_flags |= B_FORMAT;
1316: return (wdstrategy(bp));
1.1.1.3 root 1317: }
1318: #endif
1.1 root 1319:
1.1.1.3 root 1320: int
1321: wdsize(dev_t dev)
1.1 root 1322: {
1.1.1.4 ! root 1323: int lunit = wdunit(dev), part = wdpart(dev);
1.1.1.3 root 1324: struct disk *du;
1.1.1.4 ! root 1325:
! 1326: if (lunit >= NWD)
1.1.1.3 root 1327: return(-1);
1.1.1.4 ! root 1328:
! 1329: if ((du = wddrives[lunit]) == 0)
1.1.1.3 root 1330: return (-1);
1.1.1.4 ! root 1331:
! 1332: if (du->dk_state < OPEN || (du->dk_flags & DKFL_BSDLABEL) == 0) {
! 1333: int val;
! 1334: val = wdopen(makewddev(major(dev), lunit, WDRAW), FREAD, S_IFBLK, 0);
! 1335: if (val != 0)
! 1336: return (-1);
! 1337: }
! 1338:
! 1339: if ((du->dk_flags & (DKFL_WRITEPROT|DKFL_BSDLABEL)) != DKFL_BSDLABEL)
! 1340: return (-1);
! 1341: else
! 1342: return((int)du->dk_dd.d_partitions[part].p_size);
1.1 root 1343: }
1344:
1345: extern char *vmmap; /* poor name! */
1346:
1.1.1.4 ! root 1347: /* dump core after a system crash */
1.1.1.3 root 1348: int
1.1.1.4 ! root 1349: wddump(dev_t dev)
1.1 root 1350: {
1351: register struct disk *du; /* disk unit to do the IO */
1352: long num; /* number of sectors to write */
1.1.1.4 ! root 1353: int ctrlr, lunit, part, wdc;
! 1354: long blkoff, blknum;
1.1 root 1355: long cylin, head, sector, stat;
1356: long secpertrk, secpercyl, nblocks, i;
1357: char *addr;
1358: extern int Maxmem;
1.1.1.4 ! root 1359: static wddoingadump = 0;
1.1.1.3 root 1360: extern caddr_t CADDR1;
1.1.1.4 ! root 1361:
1.1 root 1362: addr = (char *) 0; /* starting address */
1.1.1.4 ! root 1363:
1.1.1.3 root 1364: /* toss any characters present prior to dump */
1365: while (sgetc(1))
1366: ;
1.1.1.4 ! root 1367:
1.1 root 1368: /* size of memory to dump */
1369: num = Maxmem;
1.1.1.4 ! root 1370: lunit = wdunit(dev); /* eventually support floppies? */
1.1 root 1371: part = wdpart(dev); /* file system */
1372: /* check for acceptable drive number */
1.1.1.4 ! root 1373: if (lunit >= NWD)
! 1374: return(ENXIO);
! 1375:
! 1376: du = wddrives[lunit];
! 1377: if (du == 0)
! 1378: return(ENXIO);
1.1 root 1379: /* was it ever initialized ? */
1.1.1.4 ! root 1380: if (du->dk_state < OPEN)
! 1381: return (ENXIO);
! 1382: if (du->dk_flags & DKFL_WRITEPROT)
! 1383: return(ENXIO);
1.1.1.3 root 1384: wdc = du->dk_port;
1.1.1.4 ! root 1385: ctrlr = du->dk_ctrlr;
! 1386:
1.1 root 1387: /* Convert to disk sectors */
1388: num = (u_long) num * NBPG / du->dk_dd.d_secsize;
1.1.1.4 ! root 1389:
1.1 root 1390: /* check if controller active */
1.1.1.4 ! root 1391: /*if (wdtab[ctrlr].b_active)
! 1392: return(EFAULT); */
! 1393: if (wddoingadump)
! 1394: return(EFAULT);
! 1395:
1.1 root 1396: secpertrk = du->dk_dd.d_nsectors;
1397: secpercyl = du->dk_dd.d_secpercyl;
1398: nblocks = du->dk_dd.d_partitions[part].p_size;
1.1.1.3 root 1399: blkoff = du->dk_dd.d_partitions[part].p_offset;
1.1.1.4 ! root 1400:
! 1401: /*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/
1.1 root 1402: /* check transfer bounds against partition size */
1403: if ((dumplo < 0) || ((dumplo + num) > nblocks))
1404: return(EINVAL);
1.1.1.4 ! root 1405:
! 1406: /* mark controller active for if we panic during the dump */
! 1407: /* wdtab[ctrlr].b_active = 1; */
! 1408: wddoingadump = 1;
! 1409: i = 200000000;
! 1410: while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0))
! 1411: ;
! 1412: outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit << 4));
1.1 root 1413: outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
1.1.1.4 ! root 1414: while (inb(wdc+wd_status) & WDCS_BUSY)
! 1415: ;
! 1416:
1.1 root 1417: /* some compaq controllers require this ... */
1418: wdsetctlr(dev, du);
1.1.1.4 ! root 1419:
1.1.1.3 root 1420: blknum = dumplo + blkoff;
1.1 root 1421: while (num > 0) {
1.1.1.3 root 1422: pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE);
1.1.1.4 ! root 1423:
1.1 root 1424: /* compute disk address */
1425: cylin = blknum / secpercyl;
1426: head = (blknum % secpercyl) / secpertrk;
1427: sector = blknum % secpertrk;
1.1.1.4 ! root 1428:
! 1429: #ifdef TIHBAD144
! 1430: if (du->dk_flags & DKFL_BADSECT) {
! 1431: long newblk;
! 1432: int i;
! 1433:
! 1434: for (i = 0; du->dk_badsect[i] != -1; i++) {
! 1435: if (blknum < du->dk_badsect[i]) {
! 1436: break; /* sorted list, passed our block by */
! 1437: } else if (blknum == du->dk_badsect[i]) {
! 1438: newblk = du->dk_dd.d_secperunit -
! 1439: du->dk_dd.d_nsectors - i - 1;
! 1440: cylin = newblk / secpercyl;
! 1441: head = (newblk % secpercyl) / secpertrk;
! 1442: sector = newblk % secpertrk;
! 1443: /* found and repl; done scanning bad144 table */
! 1444: break;
! 1445: }
1.1 root 1446: }
1.1.1.4 ! root 1447: }
1.1 root 1448: #endif
1449: sector++; /* origin 1 */
1.1.1.4 ! root 1450:
1.1 root 1451: /* select drive. */
1.1.1.4 ! root 1452: outb(wdc+wd_sdh, WDSD_IBM | (du->dk_unit<<4) | (head & 0xf));
! 1453: while ((inb(wdc+wd_status) & WDCS_READY) == 0)
! 1454: ;
! 1455:
1.1 root 1456: /* transfer some blocks */
1457: outb(wdc+wd_sector, sector);
1458: outb(wdc+wd_seccnt,1);
1459: outb(wdc+wd_cyl_lo, cylin);
1460: outb(wdc+wd_cyl_hi, cylin >> 8);
1461: #ifdef notdef
1462: /* lets just talk about this first...*/
1463: pg ("sdh 0%o sector %d cyl %d addr 0x%x",
1464: inb(wdc+wd_sdh), inb(wdc+wd_sector),
1.1.1.4 ! root 1465: inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr);
1.1 root 1466: #endif
1467: outb(wdc+wd_command, WDCC_WRITE);
1.1.1.4 ! root 1468:
1.1 root 1469: /* Ready to send data? */
1.1.1.4 ! root 1470: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
! 1471: ;
! 1472: if (inb(wdc+wd_status) & WDCS_ERR)
! 1473: return(EIO);
! 1474:
1.1 root 1475: outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256);
1.1.1.4 ! root 1476:
! 1477: if (inb(wdc+wd_status) & WDCS_ERR)
! 1478: return(EIO);
1.1 root 1479: /* Check data request (should be done). */
1.1.1.4 ! root 1480: if (inb(wdc+wd_status) & WDCS_DRQ)
! 1481: return(EIO);
! 1482:
1.1 root 1483: /* wait for completion */
1.1.1.4 ! root 1484: for (i=200000000; inb(wdc+wd_status) & WDCS_BUSY ; i--) {
! 1485: if (i < 0)
! 1486: return (EIO);
1.1 root 1487: }
1.1.1.4 ! root 1488:
1.1 root 1489: /* error check the xfer */
1.1.1.4 ! root 1490: if (inb(wdc+wd_status) & WDCS_ERR)
! 1491: return(EIO);
! 1492:
! 1493: if ((unsigned)addr % (1024*1024) == 0)
! 1494: printf("%d ", num/2048);
1.1.1.3 root 1495:
1.1 root 1496: /* update block count */
1497: num--;
1.1.1.4 ! root 1498: blknum++;
1.1.1.3 root 1499: (int) addr += 512;
1.1.1.4 ! root 1500:
1.1.1.3 root 1501: /* operator aborting dump? */
1502: if (sgetc(1))
1503: return(EINTR);
1.1 root 1504: }
1505: return(0);
1506: }
1507: #endif
1.1.1.4 ! root 1508:
! 1509: #ifdef TIHBAD144
! 1510: /*
! 1511: * Internalize the bad sector table.
! 1512: */
! 1513: void
! 1514: bad144intern(struct disk *du)
! 1515: {
! 1516: int i;
! 1517: if (du->dk_flags & DKFL_BADSECT) {
! 1518: for (i = 0; i < 127; i++) {
! 1519: du->dk_badsect[i] = -1;
! 1520: }
! 1521:
! 1522: for (i = 0; i < 126; i++) {
! 1523: if (du->dk_bad.bt_bad[i].bt_cyl == 0xffff) {
! 1524: break;
! 1525: } else {
! 1526: du->dk_badsect[i] =
! 1527: du->dk_bad.bt_bad[i].bt_cyl * du->dk_dd.d_secpercyl +
! 1528: (du->dk_bad.bt_bad[i].bt_trksec >> 8) * du->dk_dd.d_nsectors +
! 1529: (du->dk_bad.bt_bad[i].bt_trksec & 0x00ff);
! 1530: }
! 1531: }
! 1532: }
! 1533: }
! 1534: #endif
! 1535:
! 1536: wdprint() {}
! 1537:
! 1538:
! 1539: /* this routine was adopted from the kernel sources */
! 1540: /* more efficient because b_cylin is not really as useful at this level */
! 1541: /* so I eliminate the processing, I believe that sorting the sectors */
! 1542: /* is adequate */
! 1543: void
! 1544: wddisksort(struct buf *dp, struct buf *bp)
! 1545: {
! 1546: register struct buf *ap;
! 1547:
! 1548: /*
! 1549: * If nothing on the activity queue, then
! 1550: * we become the only thing.
! 1551: */
! 1552: ap = dp->b_actf;
! 1553: if(ap == NULL) {
! 1554: dp->b_actf = bp;
! 1555: dp->b_actl = bp;
! 1556: bp->av_forw = NULL;
! 1557: return;
! 1558: }
! 1559: while( ap->b_flags & B_XXX) {
! 1560: if( ap->av_forw == 0 || (ap->av_forw->b_flags & B_XXX) == 0)
! 1561: break;
! 1562: ap = ap->av_forw;
! 1563: }
! 1564: /*
! 1565: * If we lie after the first (currently active)
! 1566: * request, then we must locate the second request list
! 1567: * and add ourselves to it.
! 1568: */
! 1569: if (bp->b_blkno < ap->b_blkno) {
! 1570: while (ap->av_forw) {
! 1571: /*
! 1572: * Check for an ``inversion'' in the
! 1573: * normally ascending cylinder numbers,
! 1574: * indicating the start of the second request list.
! 1575: */
! 1576: if (ap->av_forw->b_blkno < ap->b_blkno) {
! 1577: /*
! 1578: * Search the second request list
! 1579: * for the first request at a larger
! 1580: * cylinder number. We go before that;
! 1581: * if there is no such request, we go at end.
! 1582: */
! 1583: do {
! 1584: if (bp->b_blkno < ap->av_forw->b_blkno)
! 1585: goto insert;
! 1586: ap = ap->av_forw;
! 1587: } while (ap->av_forw);
! 1588: goto insert; /* after last */
! 1589: }
! 1590: ap = ap->av_forw;
! 1591: }
! 1592: /*
! 1593: * No inversions... we will go after the last, and
! 1594: * be the first request in the second request list.
! 1595: */
! 1596: goto insert;
! 1597: }
! 1598: /*
! 1599: * Request is at/after the current request...
! 1600: * sort in the first request list.
! 1601: */
! 1602: while (ap->av_forw) {
! 1603: /*
! 1604: * We want to go after the current request
! 1605: * if there is an inversion after it (i.e. it is
! 1606: * the end of the first request list), or if
! 1607: * the next request is a larger cylinder than our request.
! 1608: */
! 1609: if (ap->av_forw->b_blkno < ap->b_blkno ||
! 1610: bp->b_blkno < ap->av_forw->b_blkno )
! 1611: goto insert;
! 1612: ap = ap->av_forw;
! 1613: }
! 1614: /*
! 1615: * Neither a second list nor a larger
! 1616: * request... we go at the end of the first list,
! 1617: * which is the same as the end of the whole schebang.
! 1618: */
! 1619: insert:
! 1620: bp->av_forw = ap->av_forw;
! 1621: ap->av_forw = bp;
! 1622: if (ap == dp->b_actl)
! 1623: dp->b_actl = bp;
! 1624: }
! 1625:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.