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