|
|
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.3 ! root 39: /* TODO:peel out buffer at low ipl, speed improvement */
1.1 root 40:
41:
42: #include "wd.h"
43: #if NWD > 0
44:
45: #include "param.h"
46: #include "dkbad.h"
47: #include "systm.h"
48: #include "conf.h"
49: #include "file.h"
50: #include "stat.h"
51: #include "ioctl.h"
52: #include "disklabel.h"
53: #include "buf.h"
54: #include "uio.h"
1.1.1.3 ! root 55: #include "malloc.h"
! 56: #include "machine/cpu.h"
1.1 root 57: #include "i386/isa/isa_device.h"
58: #include "i386/isa/icu.h"
59: #include "i386/isa/wdreg.h"
60: #include "syslog.h"
61: #include "vm/vm.h"
62:
63: #define RETRIES 5 /* number of retries before giving up */
64: #define MAXTRANSFER 32 /* max size of transfer in page clusters */
65:
1.1.1.3 ! root 66: #define wdnoreloc(dev) (minor(dev) & 0x80) /* ignore partition table */
! 67: #define wddospart(dev) (minor(dev) & 0x40) /* use dos partitions */
! 68: #define wdunit(dev) ((minor(dev) & 0x38) >> 3)
! 69: #define wdpart(dev) (minor(dev) & 0x7)
! 70: #define makewddev(maj, unit, part) (makedev(maj,((unit<<3)+part)))
! 71: #define WDRAW 3 /* 'd' partition isn't a partition! */
1.1 root 72:
73: #define b_cylin b_resid /* cylinder number for doing IO to */
74: /* shares an entry in the buf struct */
75:
76: /*
1.1.1.3 ! root 77: * Drive states. Used to initialize drive.
1.1 root 78: */
79:
80: #define CLOSED 0 /* disk is closed. */
81: #define WANTOPEN 1 /* open requested, not started */
82: #define RECAL 2 /* doing restore */
1.1.1.3 ! root 83: #define OPEN 3 /* done with open */
1.1 root 84:
85: /*
86: * The structure of a disk drive.
87: */
88: struct disk {
89: long dk_bc; /* byte count left */
90: short dk_skip; /* blocks already transferred */
91: char dk_unit; /* physical unit number */
92: char dk_state; /* control state */
93: u_char dk_status; /* copy of status reg. */
94: u_char dk_error; /* copy of error reg. */
1.1.1.3 ! root 95: short dk_port; /* i/o port base */
! 96:
1.1 root 97: u_long dk_copenpart; /* character units open on this drive */
98: u_long dk_bopenpart; /* block units open on this drive */
99: u_long dk_openpart; /* all units open on this drive */
100: short dk_wlabel; /* label writable? */
1.1.1.3 ! root 101: short dk_flags; /* drive characteistics found */
! 102: #define DKFL_DOSPART 0x00001 /* has DOS partition table */
! 103: #define DKFL_QUIET 0x00002 /* report errors back, but don't complain */
! 104: #define DKFL_SINGLE 0x00004 /* sector at a time mode */
! 105: #define DKFL_ERROR 0x00008 /* processing a disk error */
! 106: #define DKFL_BSDLABEL 0x00010 /* has a BSD disk label */
! 107: #define DKFL_BADSECT 0x00020 /* has a bad144 badsector table */
! 108: #define DKFL_WRITEPROT 0x00040 /* manual unit write protect */
! 109: struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */
! 110: struct disklabel dk_dd; /* device configuration data */
! 111: struct dos_partition
! 112: dk_dospartitions[NDOSPART]; /* DOS view of disk */
! 113: struct dkbad dk_bad; /* bad sector table */
1.1 root 114: };
115:
1.1.1.3 ! root 116: struct disk *wddrives[NWD]; /* table of units */
! 117: struct buf wdtab;
! 118: struct buf wdutab[NWD]; /* head of queue per drive */
! 119: struct buf rwdbuf[NWD]; /* buffers for raw IO */
! 120: long wdxfer[NWD]; /* count of transfers */
! 121: #ifdef WDDEBUG
! 122: int wddebug;
! 123: #endif
1.1 root 124:
125: struct isa_driver wddriver = {
126: wdprobe, wdattach, "wd",
127: };
1.1.1.3 ! root 128:
! 129: void wdustart(struct disk *);
! 130: void wdstart();
! 131: int wdcommand(struct disk *, int);
! 132: int wdcontrol(struct buf *);
! 133: int wdsetctlr(dev_t, struct disk *);
! 134: int wdgetctlr(int, struct disk *);
! 135:
1.1 root 136: /*
1.1.1.3 ! root 137: * Probe for controller.
1.1 root 138: */
1.1.1.3 ! root 139: int
! 140: wdprobe(struct isa_device *dvp)
1.1 root 141: {
1.1.1.3 ! root 142: int unit = dvp->id_unit;
! 143: struct disk *du;
! 144: int wdc;
1.1 root 145:
1.1.1.3 ! root 146: if (unit > NWD)
! 147: return(0);
! 148:
! 149: if ((du = wddrives[unit]) == 0) {
! 150: du = wddrives[unit] = (struct disk *)
! 151: malloc (sizeof(struct disk), M_TEMP, M_NOWAIT);
! 152: du->dk_unit = unit;
! 153: }
! 154:
! 155: wdc = du->dk_port = dvp->id_iobase;
! 156:
! 157: /* check if we have registers that work */
1.1 root 158: outb(wdc+wd_error, 0x5a) ; /* error register not writable */
159: outb(wdc+wd_cyl_lo, 0xa5) ; /* but all of cyllo are implemented */
1.1.1.3 ! root 160: if(inb(wdc+wd_error) == 0x5a || inb(wdc+wd_cyl_lo) != 0xa5)
! 161: goto nodevice;
! 162:
! 163: /* reset the device */
! 164: outb(wdc+wd_ctlr, (WDCTL_RST|WDCTL_IDS));
! 165: DELAY(1000);
! 166: outb(wdc+wd_ctlr, WDCTL_IDS);
! 167: DELAY(1000);
! 168:
! 169: /* execute a controller only command */
! 170: if (wdcommand(du, WDCC_DIAGNOSE) < 0)
! 171: goto nodevice;
! 172:
! 173: (void) inb(wdc+wd_error); /* XXX! */
! 174: outb(wdc+wd_ctlr, WDCTL_4BIT);
! 175: return (1);
! 176:
! 177: nodevice:
! 178: free(du, M_TEMP);
! 179: wddrives[unit] = 0;
1.1 root 180: return (0);
181: }
182:
183: /*
1.1.1.3 ! root 184: * Attach each drive if possible.
1.1 root 185: */
1.1.1.3 ! root 186: int
! 187: wdattach(struct isa_device *dvp)
1.1 root 188: {
189: int unit = dvp->id_unit;
1.1.1.3 ! root 190: struct disk *du = wddrives[unit];
1.1 root 191:
1.1.1.3 ! root 192: if(wdgetctlr(unit, du) == 0) {
! 193: int i, blank;
! 194: char c;
! 195:
! 196: printf(" <");
! 197: for (i = blank = 0 ; i < sizeof(du->dk_params.wdp_model); i++) {
! 198: char c = du->dk_params.wdp_model[i];
! 199:
! 200: if (blank && c == ' ') continue;
! 201: if (blank && c != ' ') {
! 202: printf(" %c", c);
! 203: blank = 0;
! 204: continue;
! 205: }
! 206: if (c == ' ')
! 207: blank = 1;
! 208: else
! 209: printf("%c", c);
! 210: }
! 211: printf(">");
! 212: }
! 213: /* check for index pulses from each drive. if present, report and
! 214: allocate a bios drive position to it, which will be used by read disklabel */
! 215: du->dk_unit = unit;
! 216: return(1);
1.1 root 217: }
218:
219: /* Read/write routine for a buffer. Finds the proper unit, range checks
220: * arguments, and schedules the transfer. Does not wait for the transfer
221: * to complete. Multi-page transfers are supported. All I/O requests must
222: * be a multiple of a sector in length.
223: */
1.1.1.3 ! root 224: int
! 225: wdstrategy(register struct buf *bp)
1.1 root 226: {
227: register struct buf *dp;
1.1.1.3 ! root 228: struct disklabel *lp;
1.1 root 229: register struct partition *p;
1.1.1.3 ! root 230: struct disk *du; /* Disk unit to do the IO. */
1.1 root 231: long maxsz, sz;
232: int unit = wdunit(bp->b_dev);
233: int s;
234:
1.1.1.3 ! root 235: /* valid unit, controller, and request? */
! 236: if (unit >= NWD || bp->b_blkno < 0 || (du = wddrives[unit]) == 0) {
! 237: bp->b_error = EINVAL;
1.1 root 238: bp->b_flags |= B_ERROR;
1.1.1.3 ! root 239: goto done;
1.1 root 240: }
1.1.1.3 ! root 241:
! 242: /* "soft" write protect check */
! 243: if ((du->dk_flags & DKFL_WRITEPROT) && (bp->b_flags & B_READ) == 0) {
! 244: bp->b_error = EROFS;
1.1 root 245: bp->b_flags |= B_ERROR;
1.1.1.3 ! root 246: goto done;
1.1 root 247: }
1.1.1.3 ! root 248:
! 249: /* have partitions and want to use them? */
! 250: if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW) {
! 251:
! 252: /*
! 253: * do bounds checking, adjust transfer. if error, process.
! 254: * if end of partition, just return
! 255: */
! 256: if (bounds_check_with_label(bp, &du->dk_dd, du->dk_wlabel) <= 0)
! 257: goto done;
! 258: /* otherwise, process transfer request */
1.1 root 259: }
1.1.1.3 ! root 260:
1.1 root 261: q:
1.1.1.3 ! root 262: /* queue transfer on drive, activate drive and controller if idle */
1.1 root 263: dp = &wdutab[unit];
1.1.1.3 ! root 264: s = splbio();
1.1 root 265: disksort(dp, bp);
266: if (dp->b_active == 0)
1.1.1.3 ! root 267: wdustart(du); /* start drive */
1.1 root 268: if (wdtab.b_active == 0)
1.1.1.3 ! root 269: wdstart(s); /* start controller */
1.1 root 270: splx(s);
271: return;
272:
1.1.1.3 ! root 273: done:
! 274: /* toss transfer, we're done early */
1.1 root 275: biodone(bp);
276: }
277:
1.1.1.3 ! root 278: /*
! 279: * Routine to queue a command to the controller. The unit's
! 280: * request is linked into the active list for the controller.
! 281: * If the controller is idle, the transfer is started.
1.1 root 282: */
1.1.1.3 ! root 283: static void
! 284: wdustart(register struct disk *du)
1.1 root 285: {
1.1.1.3 ! root 286: register struct buf *bp, *dp = &wdutab[du->dk_unit];
1.1 root 287:
1.1.1.3 ! root 288: /* unit already active? */
1.1 root 289: if (dp->b_active)
290: return;
1.1.1.3 ! root 291:
! 292: /* anything to start? */
1.1 root 293: bp = dp->b_actf;
294: if (bp == NULL)
295: return;
1.1.1.3 ! root 296:
! 297: /* link onto controller queue */
1.1 root 298: dp->b_forw = NULL;
1.1.1.3 ! root 299: if (wdtab.b_actf == NULL)
1.1 root 300: wdtab.b_actf = dp;
301: else
302: wdtab.b_actl->b_forw = dp;
303: wdtab.b_actl = dp;
1.1.1.3 ! root 304:
! 305: /* mark the drive unit as busy */
! 306: dp->b_active = 1;
1.1 root 307: }
308:
309: /*
310: * Controller startup routine. This does the calculation, and starts
311: * a single-sector read or write operation. Called to start a transfer,
312: * or from the interrupt routine to continue a multi-sector transfer.
313: * RESTRICTIONS:
314: * 1. The transfer length must be an exact multiple of the sector size.
315: */
316:
1.1.1.3 ! root 317: static void
1.1 root 318: wdstart()
319: {
320: register struct disk *du; /* disk unit for IO */
321: register struct buf *bp;
1.1.1.3 ! root 322: struct disklabel *lp;
1.1 root 323: struct buf *dp;
324: register struct bt_bad *bt_ptr;
325: long blknum, pagcnt, cylin, head, sector;
326: long secpertrk, secpercyl, addr, i;
1.1.1.3 ! root 327: int unit, s, wdc;
1.1 root 328:
329: loop:
1.1.1.3 ! root 330: /* is there a drive for the controller to do a transfer with? */
1.1 root 331: dp = wdtab.b_actf;
332: if (dp == NULL)
333: return;
1.1.1.3 ! root 334:
! 335: /* is there a transfer to this drive ? if so, link it on
! 336: the controller's queue */
1.1 root 337: bp = dp->b_actf;
338: if (bp == NULL) {
339: wdtab.b_actf = dp->b_forw;
340: goto loop;
341: }
1.1.1.3 ! root 342:
! 343: /* obtain controller and drive information */
1.1 root 344: unit = wdunit(bp->b_dev);
1.1.1.3 ! root 345: du = wddrives[unit];
! 346:
! 347: /* if not really a transfer, do control operations specially */
! 348: if (du->dk_state < OPEN) {
! 349: (void) wdcontrol(bp);
1.1 root 350: return;
351: }
1.1.1.3 ! root 352:
! 353: /* calculate transfer details */
! 354: blknum = bp->b_blkno + du->dk_skip;
! 355: /*if(wddebug)printf("bn%d ", blknum);*/
1.1 root 356: #ifdef WDDEBUG
1.1.1.3 ! root 357: if (du->dk_skip == 0)
! 358: printf("\nwdstart %d: %s %d@%d; map ", unit,
1.1 root 359: (bp->b_flags & B_READ) ? "read" : "write",
360: bp->b_bcount, blknum);
1.1.1.3 ! root 361: else
! 362: printf(" %d)%x", du->dk_skip, inb(wdc+wd_altsts));
1.1 root 363: #endif
364: addr = (int) bp->b_un.b_addr;
1.1.1.3 ! root 365: if (du->dk_skip == 0)
! 366: du->dk_bc = bp->b_bcount;
! 367:
! 368: lp = &du->dk_dd;
! 369: secpertrk = lp->d_nsectors;
! 370: secpercyl = lp->d_secpercyl;
1.1 root 371: cylin = blknum / secpercyl;
372: head = (blknum % secpercyl) / secpertrk;
373: sector = blknum % secpertrk;
1.1.1.3 ! root 374: if ((du->dk_flags & DKFL_BSDLABEL) != 0 && wdpart(bp->b_dev) != WDRAW)
! 375: cylin += lp->d_partitions[wdpart(bp->b_dev)].p_offset
1.1 root 376: / secpercyl;
377:
378: /*
379: * See if the current block is in the bad block list.
380: * (If we have one, and not formatting.)
381: */
1.1.1.3 ! root 382: if ((du->dk_flags & (/*DKFL_SINGLE|*/DKFL_BADSECT))
! 383: == (/*DKFL_SINGLE|*/DKFL_BADSECT))
! 384: for (bt_ptr = du->dk_bad.bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) {
1.1 root 385: if (bt_ptr->bt_cyl > cylin)
386: /* Sorted list, and we passed our cylinder. quit. */
387: break;
388: if (bt_ptr->bt_cyl == cylin &&
389: bt_ptr->bt_trksec == (head << 8) + sector) {
390: /*
391: * Found bad block. Calculate new block addr.
392: * This starts at the end of the disk (skip the
393: * last track which is used for the bad block list),
394: * and works backwards to the front of the disk.
395: */
396: #ifdef WDDEBUG
1.1.1.3 ! root 397: printf("--- badblock code -> Old = %d; ",
1.1 root 398: blknum);
399: #endif
1.1.1.3 ! root 400: blknum = lp->d_secperunit - lp->d_nsectors
! 401: - (bt_ptr - du->dk_bad.bt_bad) - 1;
1.1 root 402: cylin = blknum / secpercyl;
403: head = (blknum % secpercyl) / secpertrk;
404: sector = blknum % secpertrk;
405: #ifdef WDDEBUG
1.1.1.3 ! root 406: printf("new = %d\n", blknum);
1.1 root 407: #endif
408: break;
409: }
410: }
1.1.1.3 ! root 411: /*if(wddebug)pg("c%d h%d s%d ", cylin, head, sector);*/
1.1 root 412: sector += 1; /* sectors begin with 1, not 0 */
413:
414: wdtab.b_active = 1; /* mark controller active */
1.1.1.3 ! root 415: wdc = du->dk_port;
1.1 root 416:
1.1.1.3 ! root 417: /* if starting a multisector transfer, or doing single transfers */
! 418: if (du->dk_skip == 0 || (du->dk_flags & DKFL_SINGLE)) {
! 419: if (wdtab.b_errcnt && (bp->b_flags & B_READ) == 0)
! 420: du->dk_bc += DEV_BSIZE;
! 421:
! 422: /* controller idle? */
! 423: while (inb(wdc+wd_status) & WDCS_BUSY)
! 424: ;
! 425:
! 426: /* stuff the task file */
! 427: outb(wdc+wd_precomp, lp->d_precompcyl / 4);
! 428: #ifdef B_FORMAT
! 429: if (bp->b_flags & B_FORMAT) {
! 430: outb(wdc+wd_sector, lp->d_gap3);
! 431: outb(wdc+wd_seccnt, lp->d_nsectors);
! 432: } else {
! 433: #endif
! 434: if (du->dk_flags & DKFL_SINGLE)
! 435: outb(wdc+wd_seccnt, 1);
! 436: else
! 437: outb(wdc+wd_seccnt, howmany(du->dk_bc, DEV_BSIZE));
! 438: outb(wdc+wd_sector, sector);
! 439:
! 440: #ifdef B_FORMAT
! 441: }
! 442: #endif
1.1 root 443:
1.1.1.3 ! root 444: outb(wdc+wd_cyl_lo, cylin);
! 445: outb(wdc+wd_cyl_hi, cylin >> 8);
! 446:
! 447: /* set up the SDH register (select drive) */
! 448: outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
1.1 root 449:
1.1.1.3 ! root 450: /* wait for drive to become ready */
! 451: while ((inb(wdc+wd_status) & WDCS_READY) == 0)
! 452: ;
! 453:
! 454: /* initiate command! */
! 455: #ifdef B_FORMAT
! 456: if (bp->b_flags & B_FORMAT)
! 457: outb(wdc+wd_command, WDCC_FORMAT);
! 458: else
! 459: #endif
1.1 root 460: outb(wdc+wd_command,
461: (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE);
1.1.1.3 ! root 462: #ifdef WDDEBUG
! 463: printf("sector %d cylin %d head %d addr %x sts %x\n",
! 464: sector, cylin, head, addr, inb(wdc+wd_altsts));
! 465: #endif
! 466: }
1.1 root 467:
1.1.1.3 ! root 468: /* if this is a read operation, just go away until it's done. */
! 469: if (bp->b_flags & B_READ) return;
1.1 root 470:
1.1.1.3 ! root 471: /* ready to send data? */
! 472: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
! 473: ;
! 474:
! 475: /* then send it! */
! 476: outsw (wdc+wd_data, addr+du->dk_skip * DEV_BSIZE,
! 477: DEV_BSIZE/sizeof(short));
! 478: du->dk_bc -= DEV_BSIZE;
1.1 root 479: }
480:
481: /* Interrupt routine for the controller. Acknowledge the interrupt, check for
482: * errors on the current operation, mark it done if necessary, and start
483: * the next request. Also check for a partially done transfer, and
484: * continue with the next chunk if so.
485: */
1.1.1.3 ! root 486: void
! 487: wdintr(struct intrframe wdif)
1.1 root 488: {
489: register struct disk *du;
490: register struct buf *bp, *dp;
1.1.1.3 ! root 491: int status, wdc;
1.1 root 492: char partch ;
493:
494: if (!wdtab.b_active) {
1.1.1.3 ! root 495: #ifdef nyet
1.1 root 496: printf("wd: extra interrupt\n");
1.1.1.3 ! root 497: #endif
1.1 root 498: return;
499: }
500:
501: dp = wdtab.b_actf;
502: bp = dp->b_actf;
1.1.1.3 ! root 503: du = wddrives[wdunit(bp->b_dev)];
! 504: wdc = du->dk_port;
! 505:
! 506: #ifdef WDDEBUG
! 507: printf("I ");
! 508: #endif
! 509:
! 510: while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ;
! 511:
! 512: /* is it not a transfer, but a control operation? */
! 513: if (du->dk_state < OPEN) {
1.1 root 514: if (wdcontrol(bp))
1.1.1.3 ! root 515: wdstart();
1.1 root 516: return;
517: }
1.1.1.3 ! root 518:
! 519: /* have we an error? */
1.1 root 520: if (status & (WDCS_ERR | WDCS_ECCCOR)) {
1.1.1.3 ! root 521:
! 522: du->dk_status = status;
! 523: du->dk_error = inb(wdc + wd_error);
1.1 root 524: #ifdef WDDEBUG
1.1.1.3 ! root 525: printf("status %x error %x\n", status, du->dk_error);
1.1 root 526: #endif
1.1.1.3 ! root 527: if((du->dk_flags & DKFL_SINGLE) == 0) {
! 528: du->dk_flags |= DKFL_ERROR;
1.1 root 529: goto outt;
530: }
1.1.1.3 ! root 531: #ifdef B_FORMAT
! 532: if (bp->b_flags & B_FORMAT) {
1.1 root 533: bp->b_flags |= B_ERROR;
534: goto done;
1.1.1.3 ! root 535: }
! 536: #endif
1.1 root 537:
1.1.1.3 ! root 538: /* error or error correction? */
1.1 root 539: if (status & WDCS_ERR) {
540: if (++wdtab.b_errcnt < RETRIES) {
541: wdtab.b_active = 0;
542: } else {
1.1.1.3 ! root 543: if((du->dk_flags&DKFL_QUIET) == 0) {
! 544: diskerr(bp, "wd", "hard error",
! 545: LOG_PRINTF, du->dk_skip,
! 546: &du->dk_dd);
! 547: #ifdef WDDEBUG
! 548: printf( "status %b error %b\n",
! 549: status, WDCS_BITS,
! 550: inb(wdc+wd_error), WDERR_BITS);
! 551: #endif
! 552: }
1.1 root 553: bp->b_flags |= B_ERROR; /* flag the error */
554: }
1.1.1.3 ! root 555: } else if((du->dk_flags&DKFL_QUIET) == 0) {
! 556: diskerr(bp, "wd", "soft ecc", 0,
! 557: du->dk_skip, &du->dk_dd);
! 558: }
1.1 root 559: }
560: outt:
561:
562: /*
563: * If this was a successful read operation, fetch the data.
564: */
565: if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) {
566: int chk, dummy;
567:
1.1.1.3 ! root 568: chk = min(DEV_BSIZE / sizeof(short), du->dk_bc / sizeof(short));
! 569:
! 570: /* ready to receive data? */
! 571: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0)
! 572: ;
! 573:
! 574: /* suck in data */
! 575: insw (wdc+wd_data,
! 576: (int)bp->b_un.b_addr + du->dk_skip * DEV_BSIZE, chk);
! 577: du->dk_bc -= chk * sizeof(short);
1.1 root 578:
1.1.1.3 ! root 579: /* for obselete fractional sector reads */
! 580: while (chk++ < 256) insw (wdc+wd_data, &dummy, 1);
1.1 root 581: }
582:
583: wdxfer[du->dk_unit]++;
584: if (wdtab.b_active) {
585: if ((bp->b_flags & B_ERROR) == 0) {
586: du->dk_skip++; /* Add to successful sectors. */
1.1.1.3 ! root 587: if (wdtab.b_errcnt && (du->dk_flags & DKFL_QUIET) == 0)
! 588: diskerr(bp, "wd", "soft error", 0,
! 589: du->dk_skip, &du->dk_dd);
1.1 root 590: wdtab.b_errcnt = 0;
591:
592: /* see if more to transfer */
1.1.1.3 ! root 593: if (du->dk_bc > 0 && (du->dk_flags & DKFL_ERROR) == 0) {
1.1 root 594: wdstart();
595: return; /* next chunk is started */
1.1.1.3 ! root 596: } else if ((du->dk_flags & (DKFL_SINGLE|DKFL_ERROR))
! 597: == DKFL_ERROR) {
1.1 root 598: du->dk_skip = 0;
1.1.1.3 ! root 599: du->dk_flags &= ~DKFL_ERROR;
! 600: du->dk_flags |= DKFL_SINGLE;
1.1 root 601: wdstart();
602: return; /* redo xfer sector by sector */
603: }
604: }
605:
606: done:
607: /* done with this transfer, with or without error */
1.1.1.3 ! root 608: du->dk_flags &= ~DKFL_SINGLE;
1.1 root 609: wdtab.b_actf = dp->b_forw;
610: wdtab.b_errcnt = 0;
611: du->dk_skip = 0;
612: dp->b_active = 0;
613: dp->b_actf = bp->av_forw;
614: dp->b_errcnt = 0;
615: bp->b_resid = 0;
616: biodone(bp);
617: }
1.1.1.3 ! root 618:
! 619: /* controller idle */
1.1 root 620: wdtab.b_active = 0;
1.1.1.3 ! root 621:
! 622: /* anything more on drive queue? */
1.1 root 623: if (dp->b_actf)
1.1.1.3 ! root 624: wdustart(du);
! 625: /* anything more for controller to do? */
1.1 root 626: if (wdtab.b_actf)
1.1.1.3 ! root 627: wdstart();
1.1 root 628: }
629:
630: /*
631: * Initialize a drive.
632: */
1.1.1.3 ! root 633: int
! 634: wdopen(dev_t dev, int flags, int fmt, struct proc *p)
1.1 root 635: {
636: register unsigned int unit;
637: register struct disk *du;
638: int part = wdpart(dev), mask = 1 << part;
639: struct partition *pp;
640: struct dkbad *db;
641: int i, error = 0;
1.1.1.3 ! root 642: char *msg;
1.1 root 643:
644: unit = wdunit(dev);
645: if (unit >= NWD) return (ENXIO) ;
646:
1.1.1.3 ! root 647: du = wddrives[unit];
! 648: if (du == 0 && (unit&1) && wddrives[unit&~1]) { /*XXX*/
! 649: du = wddrives[unit] = (struct disk *) /*XXX*/
! 650: malloc (sizeof(struct disk), M_TEMP, M_NOWAIT); /*XXX*/
! 651: du->dk_port = wddrives[unit&~1]->dk_port; /*XXX*/
! 652: } /*XXX*/
! 653: if (du == 0) return (ENXIO) ;
! 654:
! 655: if ((du->dk_flags & DKFL_BSDLABEL) == 0) {
! 656: du->dk_flags |= DKFL_WRITEPROT;
! 657: wdutab[unit].b_actf = NULL;
! 658:
! 659: /*
! 660: * Use the default sizes until we've read the label,
! 661: * or longer if there isn't one there.
! 662: */
! 663: bzero(&du->dk_dd, sizeof(du->dk_dd));
! 664: #undef d_type /* fix goddamn segments.h! XXX */
! 665: du->dk_dd.d_type = DTYPE_ST506;
! 666: du->dk_dd.d_ncylinders = 1024;
! 667: du->dk_dd.d_secsize = DEV_BSIZE;
! 668: du->dk_dd.d_ntracks = 8;
! 669: du->dk_dd.d_nsectors = 17;
! 670: du->dk_dd.d_secpercyl = 17*8;
! 671: du->dk_state = WANTOPEN;
! 672: du->dk_unit = unit;
! 673: if (part == WDRAW)
! 674: du->dk_flags |= DKFL_QUIET;
1.1 root 675: else
1.1.1.3 ! root 676: du->dk_flags &= ~DKFL_QUIET;
! 677:
! 678: /* read label using "c" partition */
! 679: if (msg = readdisklabel(makewddev(major(dev), wdunit(dev), WDRAW),
! 680: wdstrategy, &du->dk_dd, du->dk_dospartitions,
! 681: &du->dk_bad, 0)) {
! 682: if((du->dk_flags&DKFL_QUIET) == 0) {
! 683: log(LOG_WARNING, "wd%d: cannot find label (%s)\n",
! 684: unit, msg);
! 685: error = EINVAL; /* XXX needs translation */
! 686: }
! 687: goto done;
! 688: } else {
! 689:
! 690: wdsetctlr(dev, du);
! 691: du->dk_flags |= DKFL_BSDLABEL;
! 692: du->dk_flags &= ~DKFL_WRITEPROT;
! 693: if (du->dk_dd.d_flags & D_BADSECT)
! 694: du->dk_flags |= DKFL_BADSECT;
! 695: }
! 696:
1.1 root 697: done:
1.1.1.3 ! root 698: if (error)
! 699: return(error);
1.1 root 700:
1.1.1.3 ! root 701: }
1.1 root 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.3 ! root 707: if ((du->dk_openpart & mask) == 0 /*&& part != RAWPART*/ && part != WDRAW) {
1.1 root 708: int start, end;
709:
710: pp = &du->dk_dd.d_partitions[part];
711: start = pp->p_offset;
712: end = pp->p_offset + pp->p_size;
713: for (pp = du->dk_dd.d_partitions;
714: pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions];
715: pp++) {
716: if (pp->p_offset + pp->p_size <= start ||
717: pp->p_offset >= end)
718: continue;
1.1.1.3 ! root 719: /*if (pp - du->dk_dd.d_partitions == RAWPART)
! 720: continue; */
! 721: if (pp - du->dk_dd.d_partitions == WDRAW)
1.1 root 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: }
1.1.1.3 ! root 731: if (part >= du->dk_dd.d_npartitions && part != WDRAW)
1.1 root 732: return (ENXIO);
1.1.1.3 ! root 733:
! 734: /* insure only one open at a time */
1.1 root 735: du->dk_openpart |= mask;
736: switch (fmt) {
737: case S_IFCHR:
738: du->dk_copenpart |= mask;
739: break;
740: case S_IFBLK:
741: du->dk_bopenpart |= mask;
742: break;
743: }
1.1.1.3 ! root 744: return (0);
1.1 root 745: }
746:
747: /*
748: * Implement operations other than read/write.
749: * Called from wdstart or wdintr during opens and formats.
750: * Uses finite-state-machine to track progress of operation in progress.
751: * Returns 0 if operation still in progress, 1 if completed.
752: */
1.1.1.3 ! root 753: static int
! 754: wdcontrol(register struct buf *bp)
1.1 root 755: {
756: register struct disk *du;
757: register unit;
758: unsigned char stat;
759: int s, cnt;
1.1.1.3 ! root 760: extern int bootdev;
! 761: int cyl, trk, sec, i, wdc;
! 762: struct wdparams foo;
1.1 root 763:
1.1.1.3 ! root 764: du = wddrives[wdunit(bp->b_dev)];
1.1 root 765: unit = du->dk_unit;
1.1.1.3 ! root 766: wdc = du->dk_port;
! 767:
! 768: switch (du->dk_state) {
1.1 root 769:
770: tryagainrecal:
771: case WANTOPEN: /* set SDH, step rate, do restore */
772: #ifdef WDDEBUG
1.1.1.3 ! root 773: printf("wd%d: recal ", unit);
1.1 root 774: #endif
775: s = splbio(); /* not called from intr level ... */
1.1.1.3 ! root 776: wdgetctlr(unit, du);
! 777:
1.1 root 778: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
779: wdtab.b_active = 1;
780: outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
781: du->dk_state++;
782: splx(s);
783: return(0);
784:
785: case RECAL:
786: if ((stat = inb(wdc+wd_status)) & WDCS_ERR) {
1.1.1.3 ! root 787: if ((du->dk_flags & DKFL_QUIET) == 0) {
! 788: printf("wd%d: recal", du->dk_unit);
1.1 root 789: printf(": status %b error %b\n",
1.1.1.3 ! root 790: stat, WDCS_BITS, inb(wdc+wd_error),
! 791: WDERR_BITS);
1.1 root 792: }
793: if (++wdtab.b_errcnt < RETRIES)
1.1.1.3 ! root 794: goto tryagainrecal;
! 795: bp->b_error = ENXIO; /* XXX needs translation */
1.1 root 796: goto badopen;
797: }
798:
1.1.1.3 ! root 799: /* some controllers require this ... */
1.1 root 800: wdsetctlr(bp->b_dev, du);
801:
1.1.1.3 ! root 802: wdtab.b_errcnt = 0;
! 803: du->dk_state = OPEN;
1.1 root 804: /*
805: * The rest of the initialization can be done
806: * by normal means.
807: */
808: return(1);
809:
810: default:
811: panic("wdcontrol");
812: }
813: /* NOTREACHED */
814:
815: badopen:
1.1.1.3 ! root 816: if ((du->dk_flags & DKFL_QUIET) == 0)
! 817: printf(": status %b error %b\n",
! 818: stat, WDCS_BITS, inb(wdc + wd_error), WDERR_BITS);
! 819: bp->b_flags |= B_ERROR;
1.1 root 820: return(1);
821: }
822:
1.1.1.3 ! root 823: /*
! 824: * send a command and wait uninterruptibly until controller is finished.
! 825: * return -1 if controller busy for too long, otherwise
! 826: * return status. intended for brief controller commands at critical points.
! 827: * assumes interrupts are blocked.
! 828: */
! 829: static int
! 830: wdcommand(struct disk *du, int cmd) {
! 831: int timeout = 1000000, stat, wdc;
! 832:
! 833: /* controller ready for command? */
! 834: wdc = du->dk_port;
! 835: while (((stat = inb(wdc + wd_status)) & WDCS_BUSY) && timeout > 0)
! 836: timeout--;
! 837: if (timeout <= 0)
! 838: return(-1);
! 839:
! 840: /* send command, await results */
! 841: outb(wdc+wd_command, cmd);
! 842: while (((stat = inb(wdc+wd_status)) & WDCS_BUSY) && timeout > 0)
! 843: timeout--;
! 844: if (timeout <= 0)
! 845: return(-1);
! 846: if (cmd != WDCC_READP)
! 847: return (stat);
! 848:
! 849: /* is controller ready to return data? */
! 850: while (((stat = inb(wdc+wd_status)) & (WDCS_ERR|WDCS_DRQ)) == 0 &&
! 851: timeout > 0)
! 852: timeout--;
! 853: if (timeout <= 0)
! 854: return(-1);
! 855:
! 856: return (stat);
! 857: }
! 858:
! 859: /*
! 860: * issue IDC to drive to tell it just what geometry it is to be.
! 861: */
! 862: static int
! 863: wdsetctlr(dev_t dev, struct disk *du) {
! 864: int stat, x, wdc;
! 865:
! 866: /*printf("C%dH%dS%d ", du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks,
! 867: du->dk_dd.d_nsectors);*/
1.1 root 868:
1.1.1.3 ! root 869: x = splbio();
! 870: wdc = du->dk_port;
1.1.1.2 root 871: outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders+1);
872: outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders+1)>>8);
1.1 root 873: outb(wdc+wd_sdh, WDSD_IBM | (wdunit(dev) << 4) + du->dk_dd.d_ntracks-1);
874: outb(wdc+wd_seccnt, du->dk_dd.d_nsectors);
1.1.1.3 ! root 875: stat = wdcommand(du, WDCC_IDC);
1.1 root 876:
1.1.1.3 ! root 877: if (stat < 0)
! 878: return(stat);
! 879: if (stat & WDCS_ERR)
! 880: printf("wdsetctlr: status %b error %b\n",
! 881: stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS);
! 882: splx(x);
1.1 root 883: return(stat);
884: }
885:
1.1.1.3 ! root 886: /*
! 887: * issue READP to drive to ask it what it is.
! 888: */
! 889: static int
! 890: wdgetctlr(int u, struct disk *du) {
! 891: int stat, x, i, wdc;
! 892: char tb[DEV_BSIZE];
! 893: struct wdparams *wp;
! 894:
! 895: x = splbio(); /* not called from intr level ... */
! 896: wdc = du->dk_port;
! 897: outb(wdc+wd_sdh, WDSD_IBM | (u << 4));
! 898: stat = wdcommand(du, WDCC_READP);
! 899:
! 900: if (stat < 0)
! 901: return(stat);
! 902: if (stat & WDCS_ERR) {
! 903: splx(x);
! 904: return(inb(wdc+wd_error));
! 905: }
! 906:
! 907: /* obtain parameters */
! 908: wp = &du->dk_params;
! 909: insw(wdc+wd_data, tb, sizeof(tb)/sizeof(short));
! 910: bcopy(tb, wp, sizeof(struct wdparams));
! 911:
! 912: /* shuffle string byte order */
! 913: for (i=0; i < sizeof(wp->wdp_model) ;i+=2) {
! 914: u_short *p;
! 915: p = (u_short *) (wp->wdp_model + i);
! 916: *p = ntohs(*p);
! 917: }
! 918: /*printf("gc %x cyl %d trk %d sec %d type %d sz %d model %s\n", wp->wdp_config,
! 919: wp->wdp_fixedcyl+wp->wdp_removcyl, wp->wdp_heads, wp->wdp_sectors,
! 920: wp->wdp_cntype, wp->wdp_cnsbsz, wp->wdp_model);*/
! 921:
! 922: /* update disklabel given drive information */
! 923: du->dk_dd.d_ncylinders = wp->wdp_fixedcyl + wp->wdp_removcyl /*+- 1*/;
! 924: du->dk_dd.d_ntracks = wp->wdp_heads;
! 925: du->dk_dd.d_nsectors = wp->wdp_sectors;
! 926: du->dk_dd.d_secpercyl = du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
! 927: du->dk_dd.d_partitions[1].p_size = du->dk_dd.d_secpercyl *
! 928: wp->wdp_sectors;
! 929: du->dk_dd.d_partitions[1].p_offset = 0;
! 930: /* dubious ... */
! 931: bcopy("ESDI/IDE", du->dk_dd.d_typename, 9);
! 932: bcopy(wp->wdp_model+20, du->dk_dd.d_packname, 14-1);
! 933: /* better ... */
! 934: du->dk_dd.d_type = DTYPE_ESDI;
! 935: du->dk_dd.d_subtype |= DSTYPE_GEOMETRY;
! 936:
! 937: /* XXX sometimes possibly needed */
! 938: (void) inb(wdc+wd_status);
! 939: return (0);
! 940: }
! 941:
! 942:
1.1 root 943: /* ARGSUSED */
1.1.1.3 ! root 944: int
! 945: wdclose(dev_t dev, int flags, int fmt)
1.1 root 946: {
947: register struct disk *du;
1.1.1.3 ! root 948: int part = wdpart(dev), mask = 1 << part;
! 949:
! 950: du = wddrives[wdunit(dev)];
1.1 root 951:
1.1.1.3 ! root 952: /* insure only one open at a time */
! 953: du->dk_openpart &= ~mask;
! 954: switch (fmt) {
! 955: case S_IFCHR:
! 956: du->dk_copenpart &= ~mask;
! 957: break;
! 958: case S_IFBLK:
! 959: du->dk_bopenpart &= ~mask;
! 960: break;
! 961: }
1.1.1.2 root 962: return(0);
1.1 root 963: }
964:
1.1.1.3 ! root 965: int
! 966: wdioctl(dev_t dev, int cmd, caddr_t addr, int flag)
1.1 root 967: {
968: int unit = wdunit(dev);
969: register struct disk *du;
970: int error = 0;
971: struct uio auio;
972: struct iovec aiov;
973:
1.1.1.3 ! root 974: du = wddrives[unit];
1.1 root 975:
976: switch (cmd) {
977:
1.1.1.3 ! root 978: case DIOCSBAD:
! 979: if ((flag & FWRITE) == 0)
! 980: error = EBADF;
! 981: else
! 982: du->dk_bad = *(struct dkbad *)addr;
! 983: break;
! 984:
1.1 root 985: case DIOCGDINFO:
986: *(struct disklabel *)addr = du->dk_dd;
987: break;
988:
989: case DIOCGPART:
990: ((struct partinfo *)addr)->disklab = &du->dk_dd;
991: ((struct partinfo *)addr)->part =
992: &du->dk_dd.d_partitions[wdpart(dev)];
993: break;
994:
995: case DIOCSDINFO:
996: if ((flag & FWRITE) == 0)
997: error = EBADF;
998: else
999: error = setdisklabel(&du->dk_dd,
1000: (struct disklabel *)addr,
1.1.1.3 ! root 1001: /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart : */0,
! 1002: du->dk_dospartitions);
! 1003: if (error == 0) {
! 1004: du->dk_flags |= DKFL_BSDLABEL;
! 1005: wdsetctlr(dev, du);
! 1006: }
1.1 root 1007: break;
1008:
1009: case DIOCWLABEL:
1.1.1.3 ! root 1010: du->dk_flags &= ~DKFL_WRITEPROT;
1.1 root 1011: if ((flag & FWRITE) == 0)
1012: error = EBADF;
1013: else
1014: du->dk_wlabel = *(int *)addr;
1015: break;
1016:
1017: case DIOCWDINFO:
1.1.1.3 ! root 1018: du->dk_flags &= ~DKFL_WRITEPROT;
1.1 root 1019: if ((flag & FWRITE) == 0)
1020: error = EBADF;
1021: else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr,
1.1.1.3 ! root 1022: /*(du->dk_flags & DKFL_BSDLABEL) ? du->dk_openpart :*/ 0,
! 1023: du->dk_dospartitions)) == 0) {
1.1 root 1024: int wlab;
1025:
1.1.1.3 ! root 1026: du->dk_flags |= DKFL_BSDLABEL;
1.1 root 1027: wdsetctlr(dev, du);
1028:
1029: /* simulate opening partition 0 so write succeeds */
1.1.1.3 ! root 1030: du->dk_openpart |= (1 << 0); /* XXX */
1.1 root 1031: wlab = du->dk_wlabel;
1032: du->dk_wlabel = 1;
1.1.1.3 ! root 1033: error = writedisklabel(dev, wdstrategy,
! 1034: &du->dk_dd, du->dk_dospartitions);
! 1035: du->dk_openpart = du->dk_copenpart | du->dk_bopenpart;
1.1 root 1036: du->dk_wlabel = wlab;
1037: }
1038: break;
1039:
1040: #ifdef notyet
1041: case DIOCGDINFOP:
1042: *(struct disklabel **)addr = &(du->dk_dd);
1043: break;
1044:
1045: case DIOCWFORMAT:
1046: if ((flag & FWRITE) == 0)
1047: error = EBADF;
1048: else {
1049: register struct format_op *fop;
1050:
1051: fop = (struct format_op *)addr;
1052: aiov.iov_base = fop->df_buf;
1053: aiov.iov_len = fop->df_count;
1054: auio.uio_iov = &aiov;
1055: auio.uio_iovcnt = 1;
1056: auio.uio_resid = fop->df_count;
1057: auio.uio_segflg = 0;
1058: auio.uio_offset =
1059: fop->df_startblk * du->dk_dd.d_secsize;
1060: error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE,
1061: minphys, &auio);
1062: fop->df_count -= auio.uio_resid;
1063: fop->df_reg[0] = du->dk_status;
1064: fop->df_reg[1] = du->dk_error;
1065: }
1066: break;
1067: #endif
1068:
1069: default:
1070: error = ENOTTY;
1071: break;
1072: }
1073: return (error);
1074: }
1075:
1.1.1.3 ! root 1076: #ifdef B_FORMAT
! 1077: int
! 1078: wdformat(struct buf *bp)
1.1 root 1079: {
1080:
1081: bp->b_flags |= B_FORMAT;
1082: return (wdstrategy(bp));
1.1.1.3 ! root 1083: }
! 1084: #endif
1.1 root 1085:
1.1.1.3 ! root 1086: int
! 1087: wdsize(dev_t dev)
1.1 root 1088: {
1.1.1.3 ! root 1089: int unit = wdunit(dev), part = wdpart(dev), val;
! 1090: struct disk *du;
1.1 root 1091:
1.1.1.3 ! root 1092: if (unit >= NWD)
! 1093: return(-1);
! 1094:
! 1095: du = wddrives[unit];
! 1096: if (du == 0 || du->dk_state == 0)
! 1097: val = wdopen (makewddev(major(dev), unit, WDRAW), FREAD, S_IFBLK, 0);
! 1098: if (du == 0 || val != 0 || du->dk_flags & DKFL_WRITEPROT)
! 1099: return (-1);
! 1100:
! 1101: return((int)du->dk_dd.d_partitions[part].p_size);
1.1 root 1102: }
1103:
1104: extern char *vmmap; /* poor name! */
1105:
1.1.1.3 ! root 1106: int
! 1107: wddump(dev_t dev) /* dump core after a system crash */
1.1 root 1108: {
1109: register struct disk *du; /* disk unit to do the IO */
1110: register struct bt_bad *bt_ptr;
1111: long num; /* number of sectors to write */
1.1.1.3 ! root 1112: int unit, part, wdc;
! 1113: long blkoff, blknum, blkcnt;
1.1 root 1114: long cylin, head, sector, stat;
1115: long secpertrk, secpercyl, nblocks, i;
1116: char *addr;
1117: extern int Maxmem;
1118: static wddoingadump = 0 ;
1.1.1.3 ! root 1119: extern caddr_t CADDR1;
1.1 root 1120:
1121: addr = (char *) 0; /* starting address */
1.1.1.3 ! root 1122:
! 1123: /* toss any characters present prior to dump */
! 1124: while (sgetc(1))
! 1125: ;
! 1126:
1.1 root 1127: /* size of memory to dump */
1128: num = Maxmem;
1129: unit = wdunit(dev); /* eventually support floppies? */
1130: part = wdpart(dev); /* file system */
1131: /* check for acceptable drive number */
1132: if (unit >= NWD) return(ENXIO);
1133:
1.1.1.3 ! root 1134: du = wddrives[unit];
! 1135: if (du == 0) return(ENXIO);
1.1 root 1136: /* was it ever initialized ? */
1137: if (du->dk_state < OPEN) return (ENXIO) ;
1.1.1.3 ! root 1138: if (du->dk_flags & DKFL_WRITEPROT) return(ENXIO);
! 1139: wdc = du->dk_port;
1.1 root 1140:
1141: /* Convert to disk sectors */
1142: num = (u_long) num * NBPG / du->dk_dd.d_secsize;
1143:
1144: /* check if controller active */
1145: /*if (wdtab.b_active) return(EFAULT); */
1146: if (wddoingadump) return(EFAULT);
1147:
1148: secpertrk = du->dk_dd.d_nsectors;
1149: secpercyl = du->dk_dd.d_secpercyl;
1150: nblocks = du->dk_dd.d_partitions[part].p_size;
1.1.1.3 ! root 1151: blkoff = du->dk_dd.d_partitions[part].p_offset;
1.1 root 1152:
1153: /*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/
1154: /* check transfer bounds against partition size */
1155: if ((dumplo < 0) || ((dumplo + num) > nblocks))
1156: return(EINVAL);
1157:
1158: /*wdtab.b_active = 1; /* mark controller active for if we
1159: panic during the dump */
1160: wddoingadump = 1 ; i = 100000 ;
1161: while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0)) ;
1162: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4));
1163: outb(wdc+wd_command, WDCC_RESTORE | WD_STEP);
1164: while (inb(wdc+wd_status) & WDCS_BUSY) ;
1165:
1166: /* some compaq controllers require this ... */
1167: wdsetctlr(dev, du);
1168:
1.1.1.3 ! root 1169: blknum = dumplo + blkoff;
1.1 root 1170: while (num > 0) {
1171: #ifdef notdef
1172: if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER;
1173: if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl)
1174: blkcnt = secpercyl - (blknum % secpercyl);
1175: /* keep transfer within current cylinder */
1176: #endif
1.1.1.3 ! root 1177: pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE);
1.1 root 1178:
1179: /* compute disk address */
1180: cylin = blknum / secpercyl;
1181: head = (blknum % secpercyl) / secpertrk;
1182: sector = blknum % secpertrk;
1183:
1184: #ifdef notyet
1185: /*
1186: * See if the current block is in the bad block list.
1187: * (If we have one.)
1188: */
1.1.1.3 ! root 1189: for (bt_ptr = du->dk_bad.bt_bad;
1.1 root 1190: bt_ptr->bt_cyl != -1; bt_ptr++) {
1191: if (bt_ptr->bt_cyl > cylin)
1192: /* Sorted list, and we passed our cylinder.
1193: quit. */
1194: break;
1195: if (bt_ptr->bt_cyl == cylin &&
1196: bt_ptr->bt_trksec == (head << 8) + sector) {
1197: /*
1198: * Found bad block. Calculate new block addr.
1199: * This starts at the end of the disk (skip the
1200: * last track which is used for the bad block list),
1201: * and works backwards to the front of the disk.
1202: */
1203: blknum = (du->dk_dd.d_secperunit)
1204: - du->dk_dd.d_nsectors
1.1.1.3 ! root 1205: - (bt_ptr - du->dk_bad.bt_bad) - 1;
1.1 root 1206: cylin = blknum / secpercyl;
1207: head = (blknum % secpercyl) / secpertrk;
1208: sector = blknum % secpertrk;
1209: break;
1210: }
1211:
1212: #endif
1213: sector++; /* origin 1 */
1214:
1215: /* select drive. */
1216: outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf));
1217: while ((inb(wdc+wd_status) & WDCS_READY) == 0) ;
1218:
1219: /* transfer some blocks */
1220: outb(wdc+wd_sector, sector);
1221: outb(wdc+wd_seccnt,1);
1222: outb(wdc+wd_cyl_lo, cylin);
1223: outb(wdc+wd_cyl_hi, cylin >> 8);
1224: #ifdef notdef
1225: /* lets just talk about this first...*/
1226: pg ("sdh 0%o sector %d cyl %d addr 0x%x",
1227: inb(wdc+wd_sdh), inb(wdc+wd_sector),
1228: inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr) ;
1229: #endif
1230: outb(wdc+wd_command, WDCC_WRITE);
1231:
1232: /* Ready to send data? */
1233: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ;
1234: if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
1235:
1236: outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256);
1237:
1238: if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
1239: /* Check data request (should be done). */
1240: if (inb(wdc+wd_status) & WDCS_DRQ) return(EIO) ;
1241:
1242: /* wait for completion */
1243: for ( i = 1000000 ; inb(wdc+wd_status) & WDCS_BUSY ; i--) {
1244: if (i < 0) return (EIO) ;
1245: }
1246: /* error check the xfer */
1247: if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ;
1.1.1.3 ! root 1248:
! 1249: if ((unsigned)addr % (1024*1024) == 0) printf("%d ", num/2048) ;
1.1 root 1250: /* update block count */
1251: num--;
1252: blknum++ ;
1.1.1.3 ! root 1253: (int) addr += 512;
! 1254:
! 1255: /* operator aborting dump? */
! 1256: if (sgetc(1))
! 1257: return(EINTR);
1.1 root 1258: }
1259: return(0);
1260: }
1261: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.