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