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