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