1 /* $NetBSD: wd.c,v 1.122 1994/12/14 15:23:49 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Charles Hannum. All rights reserved. 5 * 6 * DMA and multi-sector PIO handling are derived from code contributed by 7 * Onno van der Linden. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by Charles Hannum. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * Copyright (c) 1990 The Regents of the University of California. 24 * All rights reserved. 25 * 26 * This code is derived from software contributed to Berkeley by 27 * William Jolitz. 28 * 29 * Redistribution and use in source and binary forms, with or without 30 * modification, are permitted provided that the following conditions 31 * are met: 32 * 1. Redistributions of source code must retain the above copyright 33 * notice, this list of conditions and the following disclaimer. 34 * 2. Redistributions in binary form must reproduce the above copyright 35 * notice, this list of conditions and the following disclaimer in the 36 * documentation and/or other materials provided with the distribution. 37 * 3. All advertising materials mentioning features or use of this software 38 * must display the following acknowledgement: 39 * This product includes software developed by the University of 40 * California, Berkeley and its contributors. 41 * 4. Neither the name of the University nor the names of its contributors 42 * may be used to endorse or promote products derived from this software 43 * without specific prior written permission. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 * SUCH DAMAGE. 56 * 57 * @(#)wd.c 7.2 (Berkeley) 5/9/91 58 */ 59 60 #define INSTRUMENT /* instrumentation stuff by Brad Parker */ 61 62 #include <sys/param.h> 63 #include <sys/systm.h> 64 #include <sys/kernel.h> 65 #include <sys/conf.h> 66 #include <sys/file.h> 67 #include <sys/stat.h> 68 #include <sys/ioctl.h> 69 #include <sys/buf.h> 70 #include <sys/uio.h> 71 #include <sys/malloc.h> 72 #include <sys/device.h> 73 #include <sys/disklabel.h> 74 #include <sys/disk.h> 75 #include <sys/syslog.h> 76 #ifdef INSTRUMENT 77 #include <sys/dkstat.h> 78 #endif 79 80 #include <vm/vm.h> 81 82 #include <machine/cpu.h> 83 #include <machine/pio.h> 84 85 #include <i386/isa/isavar.h> 86 #include <i386/isa/wdreg.h> 87 88 #define WDCNDELAY 100000 /* delay = 100us; so 10s for a controller state change */ 89 #define WDCDELAY 100 90 91 #define WAITTIME (4 * hz) /* time to wait for a completion */ 92 #define RECOVERYTIME (hz / 2) /* time to recover from an error */ 93 94 #if 0 95 /* If you enable this, it will report any delays more than 100us * N long. */ 96 #define WDCNDELAY_DEBUG 10 97 #endif 98 99 #define WDIORETRIES 5 /* number of retries before giving up */ 100 101 #define WDUNIT(dev) DISKUNIT(dev) 102 #define WDPART(dev) DISKPART(dev) 103 #define MAKEWDDEV(maj, unit, part) MAKEDISKDEV(maj, unit, part) 104 105 #define WDLABELDEV(dev) (MAKEWDDEV(major(dev), WDUNIT(dev), RAW_PART)) 106 107 #define b_cylin b_resid /* cylinder number for doing IO to */ 108 /* shares an entry in the buf struct */ 109 110 /* 111 * Drive status. 112 */ 113 struct wd_softc { 114 struct device sc_dev; 115 struct dkdevice sc_dk; 116 117 long sc_bcount; /* byte count left */ 118 short sc_skip; /* blocks already transferred */ 119 char sc_drive; /* physical unit number */ 120 char sc_state; /* control state */ 121 #define RECAL 0 /* recalibrate */ 122 #define RECAL_WAIT 1 /* done recalibrating */ 123 #define GEOMETRY 2 /* upload geometry */ 124 #define GEOMETRY_WAIT 3 /* done uploading geometry */ 125 #define MULTIMODE 4 /* set multiple mode */ 126 #define MULTIMODE_WAIT 5 /* done setting multiple mode */ 127 #define OPEN 6 /* done with open */ 128 char sc_mode; /* transfer mode */ 129 #define WDM_PIOSINGLE 0 /* single-sector PIO */ 130 #define WDM_PIOMULTI 1 /* multi-sector PIO */ 131 #define WDM_DMA 2 /* DMA */ 132 u_char sc_multiple; /* multiple for WDM_PIOMULTI */ 133 u_char sc_flags; /* drive characteistics found */ 134 #define WDF_LOCKED 0x01 135 #define WDF_WANTED 0x02 136 #define WDF_LOADED 0x04 137 #define WDF_BSDLABEL 0x08 /* has a BSD disk label */ 138 #define WDF_WLABEL 0x10 /* label is writable */ 139 #define WDF_32BIT 0x20 /* can do 32-bit transfer */ 140 TAILQ_ENTRY(wd_softc) sc_drivechain; 141 struct buf sc_q; 142 struct wdparams sc_params; /* ESDI/IDE drive/controller parameters */ 143 long sc_badsect[127]; /* 126 plus trailing -1 marker */ 144 }; 145 146 struct wdc_softc { 147 struct device sc_dev; 148 struct intrhand sc_ih; 149 150 u_char sc_flags; 151 #define WDCF_ACTIVE 0x01 /* controller is active */ 152 #define WDCF_SINGLE 0x02 /* sector at a time mode */ 153 #define WDCF_ERROR 0x04 /* processing a disk error */ 154 u_char sc_status; /* copy of status register */ 155 u_char sc_error; /* copy of error register */ 156 int sc_iobase; /* I/O port base */ 157 int sc_drq; /* DMA channel */ 158 int sc_errors; /* count of errors during current transfer */ 159 int sc_nblks; /* number of blocks currently transferring */ 160 TAILQ_HEAD(drivehead, wd_softc) sc_drives; 161 }; 162 163 int wdcprobe __P((struct device *, void *, void *)); 164 void wdcattach __P((struct device *, struct device *, void *)); 165 166 struct cfdriver wdccd = { 167 NULL, "wdc", wdcprobe, wdcattach, DV_DULL, sizeof(struct wd_softc) 168 }; 169 170 int wdprobe __P((struct device *, void *, void *)); 171 void wdattach __P((struct device *, struct device *, void *)); 172 173 struct cfdriver wdcd = { 174 NULL, "wd", wdprobe, wdattach, DV_DISK, sizeof(struct wd_softc) 175 }; 176 177 void wdgetdisklabel __P((struct wd_softc *)); 178 int wd_get_parms __P((struct wd_softc *)); 179 void wdstrategy __P((struct buf *)); 180 void wdstart __P((struct wd_softc *)); 181 182 struct dkdriver wddkdriver = { wdstrategy }; 183 184 void wdfinish __P((struct wd_softc *, struct buf *)); 185 int wdcintr __P((struct wdc_softc *)); 186 static void wdcstart __P((struct wdc_softc *)); 187 static int wdcommand __P((struct wd_softc *, int, int, int, int, int)); 188 static int wdcommandshort __P((struct wdc_softc *, int, int)); 189 static int wdcontrol __P((struct wd_softc *)); 190 static int wdsetctlr __P((struct wd_softc *)); 191 static void bad144intern __P((struct wd_softc *)); 192 static int wdcreset __P((struct wdc_softc *)); 193 static void wdcrestart __P((void *arg)); 194 static void wdcunwedge __P((struct wdc_softc *)); 195 static void wdctimeout __P((void *arg)); 196 static void wderror __P((void *, struct buf *, char *)); 197 int wdcwait __P((struct wdc_softc *, int)); 198 /* ST506 spec says that if READY or SEEKCMPLT go off, then the read or write 199 command is aborted. */ 200 #define wait_for_drq(d) wdcwait(d, WDCS_DRDY | WDCS_DSC | WDCS_DRQ) 201 #define wait_for_ready(d) wdcwait(d, WDCS_DRDY | WDCS_DSC) 202 #define wait_for_unbusy(d) wdcwait(d, 0) 203 204 /* 205 * Probe for controller. 206 */ 207 int 208 wdcprobe(parent, match, aux) 209 struct device *parent; 210 void *match, *aux; 211 { 212 struct wdc_softc *wdc = match; 213 struct isa_attach_args *ia = aux; 214 int iobase; 215 216 wdc->sc_iobase = iobase = ia->ia_iobase; 217 218 /* Check if we have registers that work. */ 219 outb(iobase+wd_error, 0x5a); /* Error register not writable. */ 220 outb(iobase+wd_cyl_lo, 0xa5); /* But all of cyllo are implemented. */ 221 if (inb(iobase+wd_error) == 0x5a || inb(iobase+wd_cyl_lo) != 0xa5) 222 return 0; 223 224 if (wdcreset(wdc) != 0) { 225 delay(500000); 226 if (wdcreset(wdc) != 0) 227 return 0; 228 } 229 230 outb(iobase+wd_sdh, WDSD_IBM | 0); 231 232 /* Wait for controller to become ready. */ 233 if (wait_for_unbusy(wdc) < 0) 234 return 0; 235 236 /* Send command. */ 237 outb(iobase+wd_command, WDCC_DIAGNOSE); 238 239 /* Wait for command to complete. */ 240 if (wait_for_unbusy(wdc) < 0) 241 return 0; 242 243 ia->ia_iosize = 8; 244 ia->ia_msize = 0; 245 return 1; 246 } 247 248 struct wdc_attach_args { 249 int wa_drive; 250 }; 251 252 int 253 wdprint(aux, wdc) 254 void *aux; 255 char *wdc; 256 { 257 struct wdc_attach_args *wa = aux; 258 259 if (!wdc) 260 printf(" drive %d", wa->wa_drive); 261 return QUIET; 262 } 263 264 void 265 wdcattach(parent, self, aux) 266 struct device *parent, *self; 267 void *aux; 268 { 269 struct wdc_softc *wdc = (void *)self; 270 struct isa_attach_args *ia = aux; 271 struct wdc_attach_args wa; 272 273 TAILQ_INIT(&wdc->sc_drives); 274 wdc->sc_drq = ia->ia_drq; 275 276 printf("\n"); 277 278 wdc->sc_ih.ih_fun = wdcintr; 279 wdc->sc_ih.ih_arg = wdc; 280 wdc->sc_ih.ih_level = IPL_BIO; 281 intr_establish(ia->ia_irq, &wdc->sc_ih); 282 283 for (wa.wa_drive = 0; wa.wa_drive < 2; wa.wa_drive++) 284 (void)config_found(self, (void *)&wa, wdprint); 285 } 286 287 int 288 wdprobe(parent, match, aux) 289 struct device *parent; 290 void *match, *aux; 291 { 292 struct wdc_softc *wdc = (void *)parent; 293 struct cfdata *cf = match; 294 struct wdc_attach_args *wa = aux; 295 int drive = wa->wa_drive; 296 297 if (cf->cf_loc[0] != -1 && cf->cf_loc[0] != drive) 298 return 0; 299 300 if (wdcommandshort(wdc, drive, WDCC_RECAL) != 0 || 301 wait_for_ready(wdc) != 0) 302 return 0; 303 304 return 1; 305 } 306 307 void 308 wdattach(parent, self, aux) 309 struct device *parent, *self; 310 void *aux; 311 { 312 struct wd_softc *wd = (void *)self; 313 struct wdc_softc *wdc = (void *)parent; 314 struct wdc_attach_args *wa = aux; 315 int i, blank; 316 317 wd->sc_drive = wa->wa_drive; 318 319 wd_get_parms(wd); 320 printf(": %dMB, %d cyl, %d head, %d sec, %d bytes/sec <", 321 wd->sc_params.wdp_cylinders * 322 (wd->sc_params.wdp_heads * wd->sc_params.wdp_sectors) / 323 (1048576 / DEV_BSIZE), 324 wd->sc_params.wdp_cylinders, 325 wd->sc_params.wdp_heads, 326 wd->sc_params.wdp_sectors, 327 DEV_BSIZE); 328 for (i = blank = 0; i < sizeof(wd->sc_params.wdp_model); i++) { 329 char c = wd->sc_params.wdp_model[i]; 330 if (c == '\0') 331 break; 332 if (c != ' ') { 333 if (blank) 334 printf(" %c", c); 335 else 336 printf("%c", c); 337 blank = 0; 338 } else 339 blank = 1; 340 } 341 printf(">\n"); 342 343 if ((wd->sc_params.wdp_capabilities & WD_CAP_DMA) != 0 && 344 wdc->sc_drq != DRQUNK) { 345 wd->sc_mode = WDM_DMA; 346 } else if (wd->sc_params.wdp_maxmulti > 1) { 347 wd->sc_mode = WDM_PIOMULTI; 348 wd->sc_multiple = min(wd->sc_params.wdp_maxmulti, 16); 349 } else { 350 wd->sc_mode = WDM_PIOSINGLE; 351 wd->sc_multiple = 1; 352 } 353 354 printf("%s: using", wd->sc_dev.dv_xname); 355 if (wd->sc_mode == WDM_DMA) 356 printf(" dma transfers,"); 357 else 358 printf(" %d-sector %d-bit pio transfers,", 359 wd->sc_multiple, (wd->sc_flags & WDF_32BIT) == 0 ? 16 : 32); 360 if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) 361 printf(" lba addressing\n"); 362 else 363 printf(" chs addressing\n"); 364 365 wd->sc_dk.dk_driver = &wddkdriver; 366 } 367 368 /* 369 * Read/write routine for a buffer. Finds the proper unit, range checks 370 * arguments, and schedules the transfer. Does not wait for the transfer to 371 * complete. Multi-page transfers are supported. All I/O requests must be a 372 * multiple of a sector in length. 373 */ 374 void 375 wdstrategy(bp) 376 struct buf *bp; 377 { 378 struct wd_softc *wd; /* disk unit to do the IO */ 379 int unit = WDUNIT(bp->b_dev); 380 int s; 381 382 /* Valid unit, controller, and request? */ 383 if (unit >= wdcd.cd_ndevs || 384 (wd = wdcd.cd_devs[unit]) == 0 || 385 bp->b_blkno < 0 || 386 (bp->b_bcount % DEV_BSIZE) != 0 || 387 (bp->b_bcount / DEV_BSIZE) >= (1 << NBBY)) { 388 bp->b_error = EINVAL; 389 goto bad; 390 } 391 392 #if 0 393 /* "Soft" write protect check. */ 394 if ((wd->sc_flags & WDF_WRITEPROT) && (bp->b_flags & B_READ) == 0) { 395 bp->b_error = EROFS; 396 goto bad; 397 } 398 #endif 399 400 /* If it's a null transfer, return immediately. */ 401 if (bp->b_bcount == 0) 402 goto done; 403 404 /* Have partitions and want to use them? */ 405 if (WDPART(bp->b_dev) != RAW_PART) { 406 if ((wd->sc_flags & WDF_BSDLABEL) == 0) { 407 bp->b_error = EIO; 408 goto bad; 409 } 410 /* 411 * Do bounds checking, adjust transfer. if error, process. 412 * If end of partition, just return. 413 */ 414 if (bounds_check_with_label(bp, &wd->sc_dk.dk_label, 415 (wd->sc_flags & WDF_WLABEL) != 0) <= 0) 416 goto done; 417 /* Otherwise, process transfer request. */ 418 } 419 420 /* Don't bother doing rotational optimization. */ 421 bp->b_cylin = 0; 422 423 /* Queue transfer on drive, activate drive and controller if idle. */ 424 s = splbio(); 425 disksort(&wd->sc_q, bp); 426 if (!wd->sc_q.b_active) 427 wdstart(wd); /* Start drive. */ 428 #if 0 429 else { 430 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; 431 if ((wdc->sc_flags & (WDCF_ACTIVE|WDCF_ERROR)) == 0) { 432 printf("wdstrategy: controller inactive\n"); 433 wdcstart(wdc); 434 } 435 } 436 #endif 437 splx(s); 438 return; 439 440 bad: 441 bp->b_flags |= B_ERROR; 442 done: 443 /* Toss transfer; we're done early. */ 444 biodone(bp); 445 } 446 447 /* 448 * Routine to queue a command to the controller. The unit's request is linked 449 * into the active list for the controller. If the controller is idle, the 450 * transfer is started. 451 */ 452 void 453 wdstart(wd) 454 struct wd_softc *wd; 455 { 456 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; 457 int active = wdc->sc_drives.tqh_first != 0; 458 459 /* Link onto controller queue. */ 460 wd->sc_q.b_active = 1; 461 TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, sc_drivechain); 462 463 /* If controller not already active, start it. */ 464 if (!active) 465 wdcstart(wdc); 466 } 467 468 void 469 wdfinish(wd, bp) 470 struct wd_softc *wd; 471 struct buf *bp; 472 { 473 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; 474 475 #ifdef INSTRUMENT 476 dk_busy &= ~(1 << wd->sc_dev.dv_unit); 477 #endif 478 wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR); 479 wdc->sc_errors = 0; 480 /* 481 * Move this drive to the end of the queue to give others a `fair' 482 * chance. 483 */ 484 if (wd->sc_drivechain.tqe_next) { 485 TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain); 486 if (bp->b_actf) { 487 TAILQ_INSERT_TAIL(&wdc->sc_drives, wd, 488 sc_drivechain); 489 } else 490 wd->sc_q.b_active = 0; 491 } 492 bp->b_resid = wd->sc_bcount; 493 wd->sc_skip = 0; 494 wd->sc_q.b_actf = bp->b_actf; 495 biodone(bp); 496 } 497 498 /* 499 * Controller startup routine. This does the calculation, and starts a 500 * single-sector read or write operation. Called to start a transfer, or from 501 * the interrupt routine to continue a multi-sector transfer. 502 * RESTRICTIONS: 503 * 1. The transfer length must be an exact multiple of the sector size. 504 */ 505 static void 506 wdcstart(wdc) 507 struct wdc_softc *wdc; 508 { 509 struct wd_softc *wd; /* disk unit for IO */ 510 struct buf *bp; 511 int nblks; 512 513 loop: 514 /* Is there a drive for the controller to do a transfer with? */ 515 wd = wdc->sc_drives.tqh_first; 516 if (wd == NULL) 517 return; 518 519 /* Is there a transfer to this drive? If not, deactivate drive. */ 520 bp = wd->sc_q.b_actf; 521 if (bp == NULL) { 522 TAILQ_REMOVE(&wdc->sc_drives, wd, sc_drivechain); 523 wd->sc_q.b_active = 0; 524 goto loop; 525 } 526 527 if (wdc->sc_errors >= WDIORETRIES) { 528 wderror(wd, bp, "hard error"); 529 bp->b_error = EIO; 530 bp->b_flags |= B_ERROR; 531 wdfinish(wd, bp); 532 goto loop; 533 } 534 535 /* Do control operations specially. */ 536 if (wd->sc_state < OPEN) { 537 /* 538 * Actually, we want to be careful not to mess with the control 539 * state if the device is currently busy, but we can assume 540 * that we never get to this point if that's the case. 541 */ 542 if (wdcontrol(wd) == 0) { 543 /* The drive is busy. Wait. */ 544 return; 545 } 546 } 547 548 /* 549 * WDCF_ERROR is set by wdcunwedge() and wdcintr() when an error is 550 * encountered. If we are in multi-sector mode, then we switch to 551 * single-sector mode and retry the operation from the start. 552 */ 553 if (wdc->sc_flags & WDCF_ERROR) { 554 wdc->sc_flags &= ~WDCF_ERROR; 555 if ((wdc->sc_flags & WDCF_SINGLE) == 0) { 556 wdc->sc_flags |= WDCF_SINGLE; 557 wd->sc_skip = 0; 558 } 559 } 560 561 if (wd->sc_skip == 0) { 562 #ifdef WDDEBUG 563 printf("\n%s: wdcstart %s %d@%d; map ", wd->sc_dev.dv_xname, 564 (bp->b_flags & B_READ) ? "read" : "write", bp->b_bcount, 565 bp->b_blkno); 566 #endif 567 wd->sc_bcount = bp->b_bcount; 568 #ifdef INSTRUMENT 569 dk_busy |= (1 << wd->sc_dev.dv_unit); 570 dk_wds[wd->sc_dev.dv_unit] += bp->b_bcount >> 6; 571 #endif 572 } else { 573 #ifdef WDDEBUG 574 printf(" %d)%x", wd->sc_skip, inb(wd->sc_iobase+wd_altsts)); 575 #endif 576 } 577 578 /* If starting a multisector transfer, or doing single transfers. */ 579 if (wd->sc_skip == 0 || (wdc->sc_flags & WDCF_SINGLE) != 0) { 580 struct disklabel *lp; 581 long blkno; 582 long cylin, head, sector; 583 int command; 584 585 lp = &wd->sc_dk.dk_label; 586 blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE) + wd->sc_skip; 587 if (WDPART(bp->b_dev) != RAW_PART) 588 blkno += lp->d_partitions[WDPART(bp->b_dev)].p_offset; 589 if ((wdc->sc_flags & WDCF_SINGLE) != 0) 590 nblks = 1; 591 else if (wd->sc_mode != WDM_DMA) 592 nblks = wd->sc_bcount / DEV_BSIZE; 593 else 594 nblks = min(wd->sc_bcount / DEV_BSIZE, 8); 595 596 /* Check for bad sectors and adjust transfer, if necessary. */ 597 if ((lp->d_flags & D_BADSECT) != 0 598 #ifdef B_FORMAT 599 && (bp->b_flags & B_FORMAT) == 0 600 #endif 601 ) { 602 long blkdiff; 603 int i; 604 605 for (i = 0; (blkdiff = wd->sc_badsect[i]) != -1; i++) { 606 blkdiff -= blkno; 607 if (blkdiff < 0) 608 continue; 609 if (blkdiff == 0) { 610 /* Replace current block of transfer. */ 611 blkno = 612 lp->d_secperunit - lp->d_nsectors - i - 1; 613 } 614 if (blkdiff < nblks) { 615 /* Bad block inside transfer. */ 616 wdc->sc_flags |= WDCF_SINGLE; 617 nblks = 1; 618 } 619 break; 620 } 621 /* Tranfer is okay now. */ 622 } 623 624 if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) { 625 sector = (blkno >> 0) & 0xff; 626 cylin = (blkno >> 8) & 0xffff; 627 head = (blkno >> 24) & 0xf; 628 head |= WDSD_LBA; 629 } else { 630 sector = blkno % lp->d_nsectors; 631 sector++; /* Sectors begin with 1, not 0. */ 632 blkno /= lp->d_nsectors; 633 head = blkno % lp->d_ntracks; 634 blkno /= lp->d_ntracks; 635 cylin = blkno; 636 head |= WDSD_CHS; 637 } 638 639 #ifdef INSTRUMENT 640 ++dk_seek[wd->sc_dev.dv_unit]; 641 ++dk_xfer[wd->sc_dev.dv_unit]; 642 #endif 643 644 #ifdef B_FORMAT 645 if (bp->b_flags & B_FORMAT) { 646 sector = lp->d_gap3; 647 nblks = lp->d_nsectors; 648 command = WDCC_FORMAT; 649 } else 650 #endif 651 switch (wd->sc_mode) { 652 case WDM_DMA: 653 command = (bp->b_flags & B_READ) ? 654 WDCC_READDMA : WDCC_WRITEDMA; 655 isa_dmastart(bp->b_flags & B_READ, bp->b_data, 656 nblks * DEV_BSIZE, wdc->sc_drq); 657 break; 658 case WDM_PIOMULTI: 659 command = (bp->b_flags & B_READ) ? 660 WDCC_READMULTI : WDCC_WRITEMULTI; 661 break; 662 case WDM_PIOSINGLE: 663 command = (bp->b_flags & B_READ) ? 664 WDCC_READ : WDCC_WRITE; 665 break; 666 } 667 668 /* Initiate command! */ 669 if (wdcommand(wd, command, cylin, head, sector, nblks) != 0) { 670 wderror(wd, NULL, 671 "wdcstart: timeout waiting for unbusy"); 672 wdcunwedge(wdc); 673 return; 674 } 675 #ifdef WDDEBUG 676 printf("sector %d cylin %d head %d addr %x sts %x\n", sector, 677 cylin, head, bp->b_data, inb(wd->sc_iobase+wd_altsts)); 678 #endif 679 } 680 681 if (wd->sc_mode == WDM_PIOSINGLE || 682 (wdc->sc_flags & WDCF_SINGLE) != 0) 683 nblks = 1; 684 else if (wd->sc_mode != WDM_DMA) 685 nblks = min(wd->sc_bcount / DEV_BSIZE, wd->sc_multiple); 686 else 687 nblks = min(wd->sc_bcount / DEV_BSIZE, 8); 688 wdc->sc_nblks = nblks; 689 690 /* If this was a write and not using DMA, push the data. */ 691 if (wd->sc_mode != WDM_DMA && 692 (bp->b_flags & B_READ) == 0) { 693 if (wait_for_drq(wdc) < 0) { 694 wderror(wd, NULL, "wdcstart: timeout waiting for drq"); 695 wdcunwedge(wdc); 696 return; 697 } 698 699 /* Then send it! */ 700 if ((wd->sc_flags & WDF_32BIT) == 0) 701 outsw(wdc->sc_iobase+wd_data, 702 bp->b_data + wd->sc_skip * DEV_BSIZE, 703 nblks * DEV_BSIZE / sizeof(short)); 704 else 705 outsl(wdc->sc_iobase+wd_data, 706 bp->b_data + wd->sc_skip * DEV_BSIZE, 707 nblks * DEV_BSIZE / sizeof(long)); 708 } 709 710 wdc->sc_flags |= WDCF_ACTIVE; 711 timeout(wdctimeout, wdc, WAITTIME); 712 } 713 714 /* 715 * Interrupt routine for the controller. Acknowledge the interrupt, check for 716 * errors on the current operation, mark it done if necessary, and start the 717 * next request. Also check for a partially done transfer, and continue with 718 * the next chunk if so. 719 */ 720 int 721 wdcintr(wdc) 722 struct wdc_softc *wdc; 723 { 724 struct wd_softc *wd; 725 struct buf *bp; 726 int nblks; 727 728 if ((wdc->sc_flags & WDCF_ACTIVE) == 0) { 729 /* Clear the pending interrupt. */ 730 (void) inb(wdc->sc_iobase+wd_status); 731 return 0; 732 } 733 734 wdc->sc_flags &= ~WDCF_ACTIVE; 735 untimeout(wdctimeout, wdc); 736 737 wd = wdc->sc_drives.tqh_first; 738 bp = wd->sc_q.b_actf; 739 740 #ifdef WDDEBUG 741 printf("I%d ", ctrlr); 742 #endif 743 744 if (wait_for_unbusy(wdc) < 0) { 745 wderror(wd, NULL, "wdcintr: timeout waiting for unbusy"); 746 wdc->sc_status |= WDCS_ERR; /* XXX */ 747 } 748 749 /* Is it not a transfer, but a control operation? */ 750 if (wd->sc_state < OPEN) { 751 if (wdcontrol(wd) == 0) { 752 /* The drive is busy. Wait. */ 753 return 1; 754 } 755 wdcstart(wdc); 756 return 1; 757 } 758 759 nblks = wdc->sc_nblks; 760 761 if (wd->sc_mode == WDM_DMA) 762 isa_dmadone(bp->b_flags & B_READ, bp->b_data, 763 nblks * DEV_BSIZE, wdc->sc_drq); 764 765 /* Have we an error? */ 766 if (wdc->sc_status & WDCS_ERR) { 767 lose: 768 #ifdef WDDEBUG 769 wderror(wd, NULL, "wdcintr"); 770 #endif 771 if ((wdc->sc_flags & WDCF_SINGLE) == 0) { 772 wdc->sc_flags |= WDCF_ERROR; 773 goto restart; 774 } 775 776 #ifdef B_FORMAT 777 if (bp->b_flags & B_FORMAT) 778 goto bad; 779 #endif 780 781 if (++wdc->sc_errors < WDIORETRIES) 782 goto restart; 783 wderror(wd, bp, "hard error"); 784 785 bad: 786 bp->b_error = EIO; 787 bp->b_flags |= B_ERROR; 788 goto done; 789 } 790 791 if (wdc->sc_status & WDCS_CORR) 792 wderror(wd, bp, "soft ecc"); 793 794 /* If this was a read and not using DMA, fetch the data. */ 795 if (wd->sc_mode != WDM_DMA && 796 (bp->b_flags & B_READ) != 0) { 797 if ((wdc->sc_status & (WDCS_DRDY | WDCS_DSC | WDCS_DRQ)) 798 != (WDCS_DRDY | WDCS_DSC | WDCS_DRQ)) { 799 wderror(wd, NULL, "wdcintr: read intr before drq"); 800 wdcunwedge(wdc); 801 return 1; 802 } 803 804 /* Suck in data. */ 805 if ((wd->sc_flags & WDF_32BIT) == 0) 806 insw(wdc->sc_iobase+wd_data, 807 bp->b_data + wd->sc_skip * DEV_BSIZE, 808 nblks * DEV_BSIZE / sizeof(short)); 809 else 810 insl(wdc->sc_iobase+wd_data, 811 bp->b_data + wd->sc_skip * DEV_BSIZE, 812 nblks * DEV_BSIZE / sizeof(long)); 813 } 814 815 /* If we encountered any abnormalities, flag it as a soft error. */ 816 if (wdc->sc_errors) { 817 wderror(wd, bp, "soft error"); 818 wdc->sc_errors = 0; 819 } 820 821 /* Ready for the next block, if any. */ 822 wd->sc_skip += nblks; 823 wd->sc_bcount -= nblks * DEV_BSIZE; 824 825 /* See if more to transfer. */ 826 if (wd->sc_bcount > 0) 827 goto restart; 828 829 done: 830 /* Done with this transfer, with or without error. */ 831 wdfinish(wd, bp); 832 833 restart: 834 /* Start the next transfer, if any. */ 835 wdcstart(wdc); 836 837 return 1; 838 } 839 840 /* 841 * Initialize a drive. 842 */ 843 int 844 wdopen(dev, flag, fmt) 845 dev_t dev; 846 int flag, fmt; 847 { 848 int error; 849 int unit, part; 850 struct wd_softc *wd; 851 852 unit = WDUNIT(dev); 853 if (unit >= wdcd.cd_ndevs) 854 return ENXIO; 855 wd = wdcd.cd_devs[unit]; 856 if (wd == 0) 857 return ENXIO; 858 859 part = WDPART(dev); 860 861 while ((wd->sc_flags & WDF_LOCKED) != 0) { 862 wd->sc_flags |= WDF_WANTED; 863 if ((error = tsleep(wd, PRIBIO | PCATCH, "wdopn", 0)) != 0) 864 return error; 865 } 866 867 if (wd->sc_dk.dk_openmask != 0) { 868 /* 869 * If any partition is open, but the disk has been invalidated, 870 * disallow further opens. 871 */ 872 if ((wd->sc_flags & WDF_LOADED) == 0) 873 return ENXIO; 874 } else { 875 wd->sc_flags |= WDF_LOCKED; 876 877 if ((wd->sc_flags & WDF_LOADED) == 0) { 878 wd->sc_flags &= ~WDF_BSDLABEL; 879 wd->sc_flags |= WDF_LOADED; 880 881 /* Load the physical device parameters. */ 882 if (wd_get_parms(wd) != 0) { 883 error = ENXIO; 884 goto bad2; 885 } 886 887 /* Load the partition info if not already loaded. */ 888 wdgetdisklabel(wd); 889 } 890 891 wd->sc_flags &= ~WDF_LOCKED; 892 if ((wd->sc_flags & WDF_WANTED) != 0) { 893 wd->sc_flags &= ~WDF_WANTED; 894 wakeup(wd); 895 } 896 } 897 898 /* Check that the partition exists. */ 899 if (part != RAW_PART && 900 (part >= wd->sc_dk.dk_label.d_npartitions || 901 wd->sc_dk.dk_label.d_partitions[part].p_fstype == FS_UNUSED)) { 902 error = ENXIO; 903 goto bad; 904 } 905 906 /* Insure only one open at a time. */ 907 switch (fmt) { 908 case S_IFCHR: 909 wd->sc_dk.dk_copenmask |= (1 << part); 910 break; 911 case S_IFBLK: 912 wd->sc_dk.dk_bopenmask |= (1 << part); 913 break; 914 } 915 wd->sc_dk.dk_openmask = wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; 916 917 return 0; 918 919 bad2: 920 wd->sc_flags &= ~WDF_LOADED; 921 922 bad: 923 if (wd->sc_dk.dk_openmask == 0) { 924 wd->sc_flags &= ~WDF_LOCKED; 925 if ((wd->sc_flags & WDF_WANTED) != 0) { 926 wd->sc_flags &= ~WDF_WANTED; 927 wakeup(wd); 928 } 929 } 930 931 return error; 932 } 933 934 void 935 wdgetdisklabel(wd) 936 struct wd_softc *wd; 937 { 938 char *errstring; 939 940 if ((wd->sc_flags & WDF_BSDLABEL) != 0) 941 return; 942 943 bzero(&wd->sc_dk.dk_label, sizeof(struct disklabel)); 944 bzero(&wd->sc_dk.dk_cpulabel, sizeof(struct cpu_disklabel)); 945 946 wd->sc_dk.dk_label.d_secsize = DEV_BSIZE; 947 wd->sc_dk.dk_label.d_ntracks = wd->sc_params.wdp_heads; 948 wd->sc_dk.dk_label.d_nsectors = wd->sc_params.wdp_sectors; 949 wd->sc_dk.dk_label.d_ncylinders = wd->sc_params.wdp_cylinders; 950 wd->sc_dk.dk_label.d_secpercyl = 951 wd->sc_dk.dk_label.d_ntracks * wd->sc_dk.dk_label.d_nsectors; 952 953 #if 0 954 strncpy(wd->sc_dk.dk_label.d_typename, "ST506 disk", 16); 955 wd->sc_dk.dk_label.d_type = DTYPE_ST506; 956 #endif 957 strncpy(wd->sc_dk.dk_label.d_packname, wd->sc_params.wdp_model, 16); 958 wd->sc_dk.dk_label.d_secperunit = 959 wd->sc_dk.dk_label.d_secpercyl * wd->sc_dk.dk_label.d_ncylinders; 960 wd->sc_dk.dk_label.d_rpm = 3600; 961 wd->sc_dk.dk_label.d_interleave = 1; 962 wd->sc_dk.dk_label.d_flags = 0; 963 964 wd->sc_dk.dk_label.d_partitions[RAW_PART].p_offset = 0; 965 wd->sc_dk.dk_label.d_partitions[RAW_PART].p_size = 966 wd->sc_dk.dk_label.d_secperunit * 967 (wd->sc_dk.dk_label.d_secsize / DEV_BSIZE); 968 wd->sc_dk.dk_label.d_partitions[RAW_PART].p_fstype = FS_UNUSED; 969 wd->sc_dk.dk_label.d_npartitions = RAW_PART + 1; 970 971 wd->sc_dk.dk_label.d_magic = DISKMAGIC; 972 wd->sc_dk.dk_label.d_magic2 = DISKMAGIC; 973 wd->sc_dk.dk_label.d_checksum = dkcksum(&wd->sc_dk.dk_label); 974 975 wd->sc_badsect[0] = -1; 976 977 if (wd->sc_state > RECAL) 978 wd->sc_state = RECAL; 979 errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART), 980 wdstrategy, &wd->sc_dk.dk_label, &wd->sc_dk.dk_cpulabel); 981 if (errstring) { 982 /* 983 * This probably happened because the drive's default 984 * geometry doesn't match the DOS geometry. We 985 * assume the DOS geometry is now in the label and try 986 * again. XXX This is a kluge. 987 */ 988 if (wd->sc_state > GEOMETRY) 989 wd->sc_state = GEOMETRY; 990 errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART), 991 wdstrategy, &wd->sc_dk.dk_label, &wd->sc_dk.dk_cpulabel); 992 } 993 if (errstring) { 994 printf("%s: %s\n", wd->sc_dev.dv_xname, errstring); 995 return; 996 } 997 998 if (wd->sc_state > GEOMETRY) 999 wd->sc_state = GEOMETRY; 1000 if ((wd->sc_dk.dk_label.d_flags & D_BADSECT) != 0) 1001 bad144intern(wd); 1002 1003 wd->sc_flags |= WDF_BSDLABEL; 1004 } 1005 1006 /* 1007 * Implement operations other than read/write. 1008 * Called from wdcstart or wdcintr during opens and formats. 1009 * Uses finite-state-machine to track progress of operation in progress. 1010 * Returns 0 if operation still in progress, 1 if completed. 1011 */ 1012 static int 1013 wdcontrol(wd) 1014 struct wd_softc *wd; 1015 { 1016 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; 1017 1018 switch (wd->sc_state) { 1019 case RECAL: /* Set SDH, step rate, do recal. */ 1020 if (wdcommandshort(wdc, wd->sc_drive, WDCC_RECAL) != 0) { 1021 wderror(wd, NULL, "wdcontrol: recal failed (1)"); 1022 goto bad; 1023 } 1024 wd->sc_state = RECAL_WAIT; 1025 break; 1026 1027 case RECAL_WAIT: 1028 if (wdc->sc_status & WDCS_ERR) { 1029 wderror(wd, NULL, "wdcontrol: recal failed (2)"); 1030 goto bad; 1031 } 1032 /* fall through */ 1033 case GEOMETRY: 1034 if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) 1035 goto multimode; 1036 if (wdsetctlr(wd) != 0) { 1037 /* Already printed a message. */ 1038 goto bad; 1039 } 1040 wd->sc_state = GEOMETRY_WAIT; 1041 break; 1042 1043 case GEOMETRY_WAIT: 1044 if (wdc->sc_status & WDCS_ERR) { 1045 wderror(wd, NULL, "wdcontrol: geometry failed"); 1046 goto bad; 1047 } 1048 /* fall through */ 1049 case MULTIMODE: 1050 multimode: 1051 if (wd->sc_mode != WDM_PIOMULTI) 1052 goto open; 1053 outb(wdc->sc_iobase+wd_seccnt, wd->sc_multiple); 1054 if (wdcommandshort(wdc, wd->sc_drive, WDCC_SETMULTI) != 0) { 1055 wderror(wd, NULL, "wdcontrol: setmulti failed (1)"); 1056 goto bad; 1057 } 1058 wd->sc_state = MULTIMODE_WAIT; 1059 break; 1060 1061 case MULTIMODE_WAIT: 1062 if (wdc->sc_status & WDCS_ERR) { 1063 wderror(wd, NULL, "wdcontrol: setmulti failed (2)"); 1064 goto bad; 1065 } 1066 /* fall through */ 1067 case OPEN: 1068 open: 1069 wdc->sc_errors = 0; 1070 wd->sc_state = OPEN; 1071 /* 1072 * The rest of the initialization can be done by normal means. 1073 */ 1074 return 1; 1075 1076 bad: 1077 wdcunwedge(wdc); 1078 return 0; 1079 } 1080 1081 wdc->sc_flags |= WDCF_ACTIVE; 1082 timeout(wdctimeout, wdc, WAITTIME); 1083 return 0; 1084 } 1085 1086 /* 1087 * Send a command and wait uninterruptibly until controller is finished. 1088 * Return -1 if controller busy for too long, otherwise return non-zero if 1089 * error. Intended for brief controller commands at critical points. 1090 * Assumes interrupts are blocked. 1091 */ 1092 static int 1093 wdcommand(wd, command, cylin, head, sector, count) 1094 struct wd_softc *wd; 1095 int command; 1096 int cylin, head, sector, count; 1097 { 1098 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; 1099 int iobase = wdc->sc_iobase; 1100 int stat; 1101 1102 /* Select drive, head, and addressing mode. */ 1103 outb(iobase+wd_sdh, WDSD_IBM | (wd->sc_drive << 4) | head); 1104 1105 /* Wait for it to become ready to accept a command. */ 1106 if (command == WDCC_IDP) 1107 stat = wait_for_unbusy(wdc); 1108 else 1109 stat = wdcwait(wdc, WDCS_DRDY); 1110 if (stat < 0) 1111 return -1; 1112 1113 /* Load parameters. */ 1114 if (wd->sc_dk.dk_label.d_type == DTYPE_ST506) 1115 outb(iobase+wd_precomp, wd->sc_dk.dk_label.d_precompcyl / 4); 1116 else 1117 outb(iobase+wd_features, 0); 1118 outb(iobase+wd_cyl_lo, cylin); 1119 outb(iobase+wd_cyl_hi, cylin >> 8); 1120 outb(iobase+wd_sector, sector); 1121 outb(iobase+wd_seccnt, count); 1122 1123 /* Send command. */ 1124 outb(iobase+wd_command, command); 1125 1126 return 0; 1127 } 1128 1129 int 1130 wdcommandshort(wdc, drive, command) 1131 struct wdc_softc *wdc; 1132 int drive; 1133 int command; 1134 { 1135 int iobase = wdc->sc_iobase; 1136 1137 /* Select drive. */ 1138 outb(iobase+wd_sdh, WDSD_IBM | (drive << 4)); 1139 1140 if (wdcwait(wdc, WDCS_DRDY) < 0) 1141 return -1; 1142 1143 outb(iobase+wd_command, command); 1144 1145 return 0; 1146 } 1147 1148 /* 1149 * Issue IDP to drive to tell it just what geometry it is to be. 1150 */ 1151 static int 1152 wdsetctlr(wd) 1153 struct wd_softc *wd; 1154 { 1155 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; 1156 1157 #ifdef WDDEBUG 1158 printf("wd(%d,%d) C%dH%dS%d\n", wd->sc_dev.dv_unit, wd->sc_drive, 1159 wd->sc_dk.dk_label.d_ncylinders, wd->sc_dk.dk_label.d_ntracks, 1160 wd->sc_dk.dk_label.d_nsectors); 1161 #endif 1162 1163 if (wdcommand(wd, WDCC_IDP, wd->sc_dk.dk_label.d_ncylinders, 1164 wd->sc_dk.dk_label.d_ntracks - 1, 0, wd->sc_dk.dk_label.d_nsectors) 1165 != 0) { 1166 wderror(wd, NULL, "wdsetctlr: geometry upload failed"); 1167 return -1; 1168 } 1169 1170 return 0; 1171 } 1172 1173 /* 1174 * Issue IDENTIFY to drive to ask it what it is. 1175 */ 1176 int 1177 wd_get_parms(wd) 1178 struct wd_softc *wd; 1179 { 1180 struct wdc_softc *wdc = (void *)wd->sc_dev.dv_parent; 1181 int i; 1182 char tb[DEV_BSIZE]; 1183 1184 if (wdcommandshort(wdc, wd->sc_drive, WDCC_IDENTIFY) != 0 || 1185 wait_for_drq(wdc) != 0) { 1186 /* 1187 * We `know' there's a drive here; just assume it's old. 1188 */ 1189 strncpy(wd->sc_dk.dk_label.d_typename, "ST506", 1190 sizeof wd->sc_dk.dk_label.d_typename); 1191 wd->sc_dk.dk_label.d_type = DTYPE_ST506; 1192 1193 strncpy(wd->sc_params.wdp_model, "unknown", 1194 sizeof wd->sc_params.wdp_model); 1195 wd->sc_params.wdp_config = WD_CFG_FIXED; 1196 wd->sc_params.wdp_cylinders = 1024; 1197 wd->sc_params.wdp_heads = 8; 1198 wd->sc_params.wdp_sectors = 17; 1199 wd->sc_params.wdp_maxmulti = 0; 1200 wd->sc_params.wdp_usedmovsd = 0; 1201 wd->sc_params.wdp_capabilities = 0; 1202 } else { 1203 /* Obtain parameters. */ 1204 insw(wdc->sc_iobase+wd_data, tb, sizeof(tb) / sizeof(short)); 1205 bcopy(tb, &wd->sc_params, sizeof(struct wdparams)); 1206 1207 /* Shuffle string byte order. */ 1208 for (i = 0; i < sizeof(wd->sc_params.wdp_model); i += 2) { 1209 u_short *p; 1210 p = (u_short *)(wd->sc_params.wdp_model + i); 1211 *p = ntohs(*p); 1212 } 1213 1214 strncpy(wd->sc_dk.dk_label.d_typename, "ESDI/IDE", 1215 sizeof wd->sc_dk.dk_label.d_typename); 1216 wd->sc_dk.dk_label.d_type = DTYPE_ESDI; 1217 } 1218 1219 #if 0 1220 printf("gc %x cyl %d trk %d sec %d type %d sz %d model %s\n", 1221 wp->wdp_config, wp->wdp_cylinders, wp->wdp_heads, wp->wdp_sectors, 1222 wp->wdp_buftype, wp->wdp_bufsize, wp->wdp_model); 1223 #endif 1224 1225 /* XXX sometimes possibly needed */ 1226 (void) inb(wdc->sc_iobase+wd_status); 1227 1228 return 0; 1229 } 1230 1231 int 1232 wdclose(dev, flag, fmt) 1233 dev_t dev; 1234 int flag, fmt; 1235 { 1236 struct wd_softc *wd = wdcd.cd_devs[WDUNIT(dev)]; 1237 int part = WDPART(dev); 1238 int s; 1239 1240 switch (fmt) { 1241 case S_IFCHR: 1242 wd->sc_dk.dk_copenmask &= ~(1 << part); 1243 break; 1244 case S_IFBLK: 1245 wd->sc_dk.dk_bopenmask &= ~(1 << part); 1246 break; 1247 } 1248 wd->sc_dk.dk_openmask = wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; 1249 1250 if (wd->sc_dk.dk_openmask == 0) { 1251 wd->sc_flags |= WDF_LOCKED; 1252 1253 #if 0 1254 s = splbio(); 1255 while (...) { 1256 wd->sc_flags |= WDF_WAITING; 1257 if ((error = tsleep(wd, PRIBIO | PCATCH, "wdcls", 0)) != 0) 1258 return error; 1259 } 1260 splx(s); 1261 #endif 1262 1263 wd->sc_flags &= ~WDF_LOCKED; 1264 if ((wd->sc_flags & WDF_WANTED) != 0) { 1265 wd->sc_flags &= WDF_WANTED; 1266 wakeup(wd); 1267 } 1268 } 1269 1270 return 0; 1271 } 1272 1273 int 1274 wdioctl(dev, command, addr, flag, p) 1275 dev_t dev; 1276 u_long command; 1277 caddr_t addr; 1278 int flag; 1279 struct proc *p; 1280 { 1281 struct wd_softc *wd = wdcd.cd_devs[WDUNIT(dev)]; 1282 int error; 1283 1284 if ((wd->sc_flags & WDF_LOADED) == 0) 1285 return EIO; 1286 1287 switch (command) { 1288 case DIOCSBAD: 1289 if ((flag & FWRITE) == 0) 1290 return EBADF; 1291 wd->sc_dk.dk_cpulabel.bad = *(struct dkbad *)addr; 1292 wd->sc_dk.dk_label.d_flags |= D_BADSECT; 1293 bad144intern(wd); 1294 return 0; 1295 1296 case DIOCGDINFO: 1297 *(struct disklabel *)addr = wd->sc_dk.dk_label; 1298 return 0; 1299 1300 case DIOCGPART: 1301 ((struct partinfo *)addr)->disklab = &wd->sc_dk.dk_label; 1302 ((struct partinfo *)addr)->part = 1303 &wd->sc_dk.dk_label.d_partitions[WDPART(dev)]; 1304 return 0; 1305 1306 case DIOCSDINFO: 1307 if ((flag & FWRITE) == 0) 1308 return EBADF; 1309 error = setdisklabel(&wd->sc_dk.dk_label, 1310 (struct disklabel *)addr, 1311 /*(wd->sc_flags & WDF_BSDLABEL) ? wd->sc_dk.dk_openmask : */0, 1312 &wd->sc_dk.dk_cpulabel); 1313 if (error == 0) { 1314 wd->sc_flags |= WDF_BSDLABEL; 1315 if (wd->sc_state > GEOMETRY) 1316 wd->sc_state = GEOMETRY; 1317 } 1318 return error; 1319 1320 case DIOCWLABEL: 1321 if ((flag & FWRITE) == 0) 1322 return EBADF; 1323 if (*(int *)addr) 1324 wd->sc_flags |= WDF_WLABEL; 1325 else 1326 wd->sc_flags &= ~WDF_WLABEL; 1327 return 0; 1328 1329 case DIOCWDINFO: 1330 if ((flag & FWRITE) == 0) 1331 return EBADF; 1332 error = setdisklabel(&wd->sc_dk.dk_label, 1333 (struct disklabel *)addr, 1334 /*(wd->sc_flags & WDF_BSDLABEL) ? wd->sc_dk.dk_openmask : */0, 1335 &wd->sc_dk.dk_cpulabel); 1336 if (error == 0) { 1337 wd->sc_flags |= WDF_BSDLABEL; 1338 if (wd->sc_state > GEOMETRY) 1339 wd->sc_state = GEOMETRY; 1340 1341 /* Simulate opening partition 0 so write succeeds. */ 1342 wd->sc_dk.dk_openmask |= (1 << 0); /* XXX */ 1343 error = writedisklabel(WDLABELDEV(dev), wdstrategy, 1344 &wd->sc_dk.dk_label, &wd->sc_dk.dk_cpulabel); 1345 wd->sc_dk.dk_openmask = 1346 wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; 1347 } 1348 return error; 1349 1350 #ifdef notyet 1351 case DIOCGDINFOP: 1352 *(struct disklabel **)addr = &wd->sc_dk.dk_label; 1353 return 0; 1354 1355 case DIOCWFORMAT: 1356 if ((flag & FWRITE) == 0) 1357 return EBADF; 1358 { 1359 register struct format_op *fop; 1360 struct iovec aiov; 1361 struct uio auio; 1362 1363 fop = (struct format_op *)addr; 1364 aiov.iov_base = fop->df_buf; 1365 aiov.iov_len = fop->df_count; 1366 auio.uio_iov = &aiov; 1367 auio.uio_iovcnt = 1; 1368 auio.uio_resid = fop->df_count; 1369 auio.uio_segflg = 0; 1370 auio.uio_offset = 1371 fop->df_startblk * wd->sc_dk.dk_label.d_secsize; 1372 auio.uio_procp = p; 1373 error = physio(wdformat, NULL, dev, B_WRITE, minphys, 1374 &auio); 1375 fop->df_count -= auio.uio_resid; 1376 fop->df_reg[0] = wdc->sc_status; 1377 fop->df_reg[1] = wdc->sc_error; 1378 return error; 1379 } 1380 #endif 1381 1382 default: 1383 return ENOTTY; 1384 } 1385 1386 #ifdef DIAGNOSTIC 1387 panic("wdioctl: impossible"); 1388 #endif 1389 } 1390 1391 #ifdef B_FORMAT 1392 int 1393 wdformat(struct buf *bp) 1394 { 1395 1396 bp->b_flags |= B_FORMAT; 1397 return wdstrategy(bp); 1398 } 1399 #endif 1400 1401 int 1402 wdsize(dev) 1403 dev_t dev; 1404 { 1405 struct wd_softc *wd; 1406 int part; 1407 int size; 1408 1409 if (wdopen(dev, 0, S_IFBLK) != 0) 1410 return -1; 1411 wd = wdcd.cd_devs[WDUNIT(dev)]; 1412 part = WDPART(dev); 1413 if ((wd->sc_flags & WDF_BSDLABEL) == 0 || 1414 wd->sc_dk.dk_label.d_partitions[part].p_fstype != FS_SWAP) 1415 size = -1; 1416 else 1417 size = wd->sc_dk.dk_label.d_partitions[part].p_size; 1418 if (wdclose(dev, 0, S_IFBLK) != 0) 1419 return -1; 1420 return size; 1421 } 1422 1423 /* 1424 * Dump core after a system crash. 1425 */ 1426 int 1427 wddump(dev) 1428 dev_t dev; 1429 { 1430 struct wd_softc *wd; /* disk unit to do the IO */ 1431 struct wdc_softc *wdc; 1432 struct disklabel *lp; 1433 int unit, part; 1434 long rblkno, nblks; 1435 char *addr; 1436 static wddoingadump = 0; 1437 extern caddr_t CADDR1; 1438 extern pt_entry_t *CMAP1; 1439 1440 if (wddoingadump) 1441 return EFAULT; 1442 wddoingadump = 1; 1443 1444 unit = WDUNIT(dev); 1445 /* Check for acceptable drive number. */ 1446 if (unit >= wdcd.cd_ndevs) 1447 return ENXIO; 1448 wd = wdcd.cd_devs[unit]; 1449 /* Was it ever initialized? */ 1450 if (wd == 0 || wd->sc_state < OPEN) 1451 return ENXIO; 1452 1453 wdc = (void *)wd->sc_dev.dv_parent; 1454 addr = (char *)0; /* starting address */ 1455 lp = &wd->sc_dk.dk_label; 1456 part = WDPART(dev); 1457 1458 /* Convert to disk sectors. */ 1459 rblkno = lp->d_partitions[part].p_offset + dumplo; 1460 nblks = min(ctob(physmem) / lp->d_secsize, 1461 lp->d_partitions[part].p_size - dumplo); 1462 1463 /* Check transfer bounds against partition size. */ 1464 if (dumplo < 0 || nblks <= 0) 1465 return EINVAL; 1466 1467 /* Recalibrate. */ 1468 if (wdcommandshort(wdc, wd->sc_drive, WDCC_RECAL) != 0 || 1469 wait_for_ready(wdc) != 0 || wdsetctlr(wd) != 0 || 1470 wait_for_ready(wdc) != 0) { 1471 wderror(wd, NULL, "wddump: recal failed"); 1472 return EIO; 1473 } 1474 1475 while (nblks > 0) { 1476 long blkno; 1477 long cylin, head, sector; 1478 1479 blkno = rblkno; 1480 1481 if ((lp->d_flags & D_BADSECT) != 0) { 1482 long blkdiff; 1483 int i; 1484 1485 for (i = 0; (blkdiff = wd->sc_badsect[i]) != -1; i++) { 1486 blkdiff -= blkno; 1487 if (blkdiff < 0) 1488 continue; 1489 if (blkdiff == 0) { 1490 /* Replace current block of transfer. */ 1491 blkno = 1492 lp->d_secperunit - lp->d_nsectors - i - 1; 1493 } 1494 break; 1495 } 1496 /* Tranfer is okay now. */ 1497 } 1498 1499 if ((wd->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) { 1500 sector = (blkno >> 0) & 0xff; 1501 cylin = (blkno >> 8) & 0xffff; 1502 head = (blkno >> 24) & 0xf; 1503 head |= WDSD_LBA; 1504 } else { 1505 sector = blkno % lp->d_nsectors; 1506 sector++; /* Sectors begin with 1, not 0. */ 1507 blkno /= lp->d_nsectors; 1508 head = blkno % lp->d_ntracks; 1509 blkno /= lp->d_ntracks; 1510 cylin = blkno; 1511 head |= WDSD_CHS; 1512 } 1513 1514 #ifdef notdef 1515 /* Let's just talk about this first. */ 1516 printf("cylin %d, head %d, sector %d, addr 0x%x", cylin, head, 1517 sector, addr); 1518 #endif 1519 if (wdcommand(wd, WDCC_WRITE, cylin, head, sector, 1) != 0 || 1520 wait_for_drq(wdc) != 0) { 1521 wderror(wd, NULL, "wddump: write failed"); 1522 return EIO; 1523 } 1524 1525 #ifdef notdef /* Cannot use this since this address was mapped differently. */ 1526 pmap_enter(kernel_pmap, CADDR1, trunc_page(addr), VM_PROT_READ, TRUE); 1527 #else 1528 *CMAP1 = PG_V | PG_KW | ctob((long)addr); 1529 tlbflush(); 1530 #endif 1531 1532 outsw(wdc->sc_iobase+wd_data, CADDR1 + ((int)addr & PGOFSET), 1533 DEV_BSIZE / sizeof(short)); 1534 1535 /* Check data request (should be done). */ 1536 if (wait_for_ready(wdc) != 0) { 1537 wderror(wd, NULL, "wddump: timeout waiting for ready"); 1538 return EIO; 1539 } 1540 if (wdc->sc_status & WDCS_DRQ) { 1541 wderror(wd, NULL, "wddump: extra drq"); 1542 return EIO; 1543 } 1544 1545 if ((unsigned)addr % 1048576 == 0) 1546 printf("%d ", nblks / (1048576 / DEV_BSIZE)); 1547 1548 /* Update block count. */ 1549 nblks--; 1550 rblkno++; 1551 (int)addr += DEV_BSIZE; 1552 } 1553 1554 return 0; 1555 } 1556 1557 /* 1558 * Internalize the bad sector table. 1559 */ 1560 void 1561 bad144intern(wd) 1562 struct wd_softc *wd; 1563 { 1564 struct dkbad *bt = &wd->sc_dk.dk_cpulabel.bad; 1565 struct disklabel *lp = &wd->sc_dk.dk_label; 1566 int i = 0; 1567 1568 for (; i < 126; i++) { 1569 if (bt->bt_bad[i].bt_cyl == 0xffff) 1570 break; 1571 wd->sc_badsect[i] = 1572 bt->bt_bad[i].bt_cyl * lp->d_secpercyl + 1573 (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors + 1574 (bt->bt_bad[i].bt_trksec & 0xff); 1575 } 1576 for (; i < 127; i++) 1577 wd->sc_badsect[i] = -1; 1578 } 1579 1580 static int 1581 wdcreset(wdc) 1582 struct wdc_softc *wdc; 1583 { 1584 int iobase = wdc->sc_iobase; 1585 1586 /* Reset the device. */ 1587 outb(iobase+wd_ctlr, WDCTL_RST | WDCTL_IDS); 1588 delay(1000); 1589 outb(iobase+wd_ctlr, WDCTL_IDS); 1590 delay(1000); 1591 (void) inb(iobase+wd_error); 1592 outb(iobase+wd_ctlr, WDCTL_4BIT); 1593 1594 if (wait_for_unbusy(wdc) < 0) { 1595 printf("%s: reset failed\n", wdc->sc_dev.dv_xname); 1596 return 1; 1597 } 1598 1599 return 0; 1600 } 1601 1602 static void 1603 wdcrestart(arg) 1604 void *arg; 1605 { 1606 struct wdc_softc *wdc = (struct wdc_softc *)arg; 1607 int s; 1608 1609 s = splbio(); 1610 wdcstart(wdc); 1611 splx(s); 1612 } 1613 1614 /* 1615 * Unwedge the controller after an unexpected error. We do this by resetting 1616 * it, marking all drives for recalibration, and stalling the queue for a short 1617 * period to give the reset time to finish. 1618 * NOTE: We use a timeout here, so this routine must not be called during 1619 * autoconfig or dump. 1620 */ 1621 static void 1622 wdcunwedge(wdc) 1623 struct wdc_softc *wdc; 1624 { 1625 int unit; 1626 1627 untimeout(wdctimeout, wdc); 1628 (void) wdcreset(wdc); 1629 1630 /* Schedule recalibrate for all drives on this controller. */ 1631 for (unit = 0; unit < wdcd.cd_ndevs; unit++) { 1632 struct wd_softc *wd = wdcd.cd_devs[unit]; 1633 if (!wd || (void *)wd->sc_dev.dv_parent != wdc) 1634 continue; 1635 if (wd->sc_state > RECAL) 1636 wd->sc_state = RECAL; 1637 } 1638 1639 wdc->sc_flags |= WDCF_ERROR; 1640 ++wdc->sc_errors; 1641 1642 /* Wake up in a little bit and restart the operation. */ 1643 timeout(wdcrestart, wdc, RECOVERYTIME); 1644 } 1645 1646 int 1647 wdcwait(wdc, mask) 1648 struct wdc_softc *wdc; 1649 int mask; 1650 { 1651 int iobase = wdc->sc_iobase; 1652 int timeout = 0; 1653 u_char status; 1654 extern int cold; 1655 1656 for (;;) { 1657 wdc->sc_status = status = inb(iobase+wd_status); 1658 if ((status & WDCS_BSY) == 0 && (status & mask) == mask) 1659 break; 1660 if (++timeout > WDCNDELAY) 1661 return -1; 1662 delay(WDCDELAY); 1663 } 1664 if (status & WDCS_ERR) { 1665 wdc->sc_error = inb(iobase+wd_error); 1666 return WDCS_ERR; 1667 } 1668 #ifdef WDCNDELAY_DEBUG 1669 /* After autoconfig, there should be no long delays. */ 1670 if (!cold && timeout > WDCNDELAY_DEBUG) 1671 printf("%s: warning: busy-wait took %dus\n", 1672 wdc->sc_dev.dv_xname, WDCDELAY * timeout); 1673 #endif 1674 return 0; 1675 } 1676 1677 static void 1678 wdctimeout(arg) 1679 void *arg; 1680 { 1681 struct wdc_softc *wdc = (struct wdc_softc *)arg; 1682 int s; 1683 1684 s = splbio(); 1685 if ((wdc->sc_flags & WDCF_ACTIVE) != 0) { 1686 wdc->sc_flags &= ~WDCF_ACTIVE; 1687 wderror(wdc, NULL, "lost interrupt"); 1688 wdcunwedge(wdc); 1689 } else 1690 wderror(wdc, NULL, "missing untimeout"); 1691 splx(s); 1692 } 1693 1694 static void 1695 wderror(dev, bp, msg) 1696 void *dev; 1697 struct buf *bp; 1698 char *msg; 1699 { 1700 struct wd_softc *wd = dev; 1701 struct wdc_softc *wdc = dev; 1702 1703 if (bp) { 1704 diskerr(bp, "wd", msg, LOG_PRINTF, wd->sc_skip, 1705 &wd->sc_dk.dk_label); 1706 printf("\n"); 1707 } else 1708 printf("%s: %s: status %b error %b\n", wdc->sc_dev.dv_xname, 1709 msg, wdc->sc_status, WDCS_BITS, wdc->sc_error, WDERR_BITS); 1710 } 1711