1 /* $OpenBSD: wd.c,v 1.19 2001/08/06 20:50:28 miod Exp $ */ 2 /* $NetBSD: wd.c,v 1.193 1999/02/28 17:15:27 explorer Exp $ */ 3 4 /* 5 * Copyright (c) 1998 Manuel Bouyer. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Manuel Bouyer. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /*- 34 * Copyright (c) 1998 The NetBSD Foundation, Inc. 35 * All rights reserved. 36 * 37 * This code is derived from software contributed to The NetBSD Foundation 38 * by Charles M. Hannum and by Onno van der Linden. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. All advertising materials mentioning features or use of this software 49 * must display the following acknowledgement: 50 * This product includes software developed by the NetBSD 51 * Foundation, Inc. and its contributors. 52 * 4. Neither the name of The NetBSD Foundation nor the names of its 53 * contributors may be used to endorse or promote products derived 54 * from this software without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 57 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 58 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 59 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 60 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 61 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 62 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 63 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 64 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 65 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 66 * POSSIBILITY OF SUCH DAMAGE. 67 */ 68 69 #if 0 70 #include "rnd.h" 71 #endif 72 73 #include <sys/param.h> 74 #include <sys/systm.h> 75 #include <sys/kernel.h> 76 #include <sys/conf.h> 77 #include <sys/file.h> 78 #include <sys/stat.h> 79 #include <sys/ioctl.h> 80 #include <sys/buf.h> 81 #include <sys/uio.h> 82 #include <sys/malloc.h> 83 #include <sys/device.h> 84 #include <sys/disklabel.h> 85 #include <sys/disk.h> 86 #include <sys/syslog.h> 87 #include <sys/proc.h> 88 #if NRND > 0 89 #include <sys/rnd.h> 90 #endif 91 #include <sys/vnode.h> 92 93 #include <vm/vm.h> 94 95 #include <machine/intr.h> 96 #include <machine/bus.h> 97 98 #include <dev/ata/atareg.h> 99 #include <dev/ata/atavar.h> 100 #include <dev/ata/wdvar.h> 101 #include <dev/ic/wdcreg.h> 102 #include <dev/ic/wdcvar.h> 103 #if 0 104 #include "locators.h" 105 #endif 106 107 #define WDIORETRIES_SINGLE 4 /* number of retries before single-sector */ 108 #define WDIORETRIES 5 /* number of retries before giving up */ 109 #define RECOVERYTIME hz/2 /* time to wait before retrying a cmd */ 110 111 #define WDUNIT(dev) DISKUNIT(dev) 112 #define WDPART(dev) DISKPART(dev) 113 #define WDMINOR(unit, part) DISKMINOR(unit, part) 114 #define MAKEWDDEV(maj, unit, part) MAKEDISKDEV(maj, unit, part) 115 116 #define WDLABELDEV(dev) (MAKEWDDEV(major(dev), WDUNIT(dev), RAW_PART)) 117 118 #define DEBUG_INTR 0x01 119 #define DEBUG_XFERS 0x02 120 #define DEBUG_STATUS 0x04 121 #define DEBUG_FUNCS 0x08 122 #define DEBUG_PROBE 0x10 123 #ifdef WDCDEBUG 124 extern int wdcdebug_wd_mask; /* init'ed in ata_wdc.c */ 125 #define WDCDEBUG_PRINT(args, level) \ 126 if (wdcdebug_wd_mask & (level)) \ 127 printf args 128 #else 129 #define WDCDEBUG_PRINT(args, level) 130 #endif 131 132 struct wd_softc { 133 /* General disk infos */ 134 struct device sc_dev; 135 struct disk sc_dk; 136 struct buf sc_q; 137 /* IDE disk soft states */ 138 struct ata_bio sc_wdc_bio; /* current transfer */ 139 struct buf *sc_bp; /* buf being transferred */ 140 struct ata_drive_datas *drvp; /* Our controller's infos */ 141 int openings; 142 struct ataparams sc_params;/* drive characteistics found */ 143 int sc_flags; 144 #define WDF_LOCKED 0x01 145 #define WDF_WANTED 0x02 146 #define WDF_WLABEL 0x04 /* label is writable */ 147 #define WDF_LABELLING 0x08 /* writing label */ 148 /* 149 * XXX Nothing resets this yet, but disk change sensing will when ATA-4 is 150 * more fully implemented. 151 */ 152 #define WDF_LOADED 0x10 /* parameters loaded */ 153 #define WDF_WAIT 0x20 /* waiting for resources */ 154 #define WDF_LBA 0x40 /* using LBA mode */ 155 156 int sc_capacity; 157 int cyl; /* actual drive parameters */ 158 int heads; 159 int sectors; 160 int retries; /* number of xfer retry */ 161 #if NRND > 0 162 rndsource_element_t rnd_source; 163 #endif 164 struct timeout sc_restart_timeout; 165 void *sc_sdhook; 166 }; 167 168 #define sc_drive sc_wdc_bio.drive 169 #define sc_mode sc_wdc_bio.mode 170 #define sc_multi sc_wdc_bio.multi 171 #define sc_badsect sc_wdc_bio.badsect 172 173 #ifndef __OpenBSD__ 174 int wdprobe __P((struct device *, struct cfdata *, void *)); 175 #else 176 int wdprobe __P((struct device *, void *, void *)); 177 #endif 178 void wdattach __P((struct device *, struct device *, void *)); 179 int wddetach __P((struct device *, int)); 180 int wdactivate __P((struct device *, enum devact)); 181 void wdzeroref __P((struct device *)); 182 int wdprint __P((void *, char *)); 183 184 struct cfattach wd_ca = { 185 sizeof(struct wd_softc), wdprobe, wdattach, 186 wddetach, wdactivate, wdzeroref 187 }; 188 189 #ifdef __OpenBSD__ 190 struct cfdriver wd_cd = { 191 NULL, "wd", DV_DISK 192 }; 193 #else 194 extern struct cfdriver wd_cd; 195 #endif 196 197 void wdgetdefaultlabel __P((struct wd_softc *, struct disklabel *)); 198 void wdgetdisklabel __P((dev_t dev, struct wd_softc *, 199 struct disklabel *, 200 struct cpu_disklabel *, int)); 201 void wdstrategy __P((struct buf *)); 202 void wdstart __P((void *)); 203 void __wdstart __P((struct wd_softc*, struct buf *)); 204 void wdrestart __P((void*)); 205 int wd_get_params __P((struct wd_softc *, u_int8_t, struct ataparams *)); 206 void wd_flushcache __P((struct wd_softc *, int)); 207 void wd_shutdown __P((void*)); 208 209 struct dkdriver wddkdriver = { wdstrategy }; 210 211 /* XXX: these should go elsewhere */ 212 cdev_decl(wd); 213 bdev_decl(wd); 214 215 #ifdef DKBAD 216 void bad144intern __P((struct wd_softc *)); 217 #endif 218 219 #define wdlock(wd) disk_lock(&(wd)->sc_dk) 220 #define wdunlock(wd) disk_unlock(&(wd)->sc_dk) 221 #define wdlookup(unit) (struct wd_softc *)device_lookup(&wd_cd, (unit)) 222 223 224 int 225 wdprobe(parent, match_, aux) 226 struct device *parent; 227 #ifndef __OpenBSD__ 228 struct cfdata *match; 229 #else 230 void *match_; 231 #endif 232 void *aux; 233 { 234 struct ata_atapi_attach *aa_link = aux; 235 struct cfdata *match = match_; 236 237 if (aa_link == NULL) 238 return 0; 239 if (aa_link->aa_type != T_ATA) 240 return 0; 241 242 #ifndef __OpenBSD__ 243 if (match->cf_loc[ATACF_CHANNEL] != ATACF_CHANNEL_DEFAULT && 244 match->cf_loc[ATACF_CHANNEL] != aa_link->aa_channel) 245 return 0; 246 247 if (match->cf_loc[ATACF_DRIVE] != ATACF_DRIVE_DEFAULT && 248 match->cf_loc[ATACF_DRIVE] != aa_link->aa_drv_data->drive) 249 return 0; 250 #else 251 if (match->cf_loc[0] != -1 && 252 match->cf_loc[0] != aa_link->aa_channel) 253 return 0; 254 255 if (match->cf_loc[1] != -1 && 256 match->cf_loc[1] != aa_link->aa_drv_data->drive) 257 return 0; 258 #endif 259 260 return 1; 261 } 262 263 void 264 wdattach(parent, self, aux) 265 struct device *parent, *self; 266 void *aux; 267 { 268 struct wd_softc *wd = (void *)self; 269 struct ata_atapi_attach *aa_link= aux; 270 int i, blank; 271 char buf[41], c, *p, *q; 272 WDCDEBUG_PRINT(("wdattach\n"), DEBUG_FUNCS | DEBUG_PROBE); 273 274 wd->openings = aa_link->aa_openings; 275 wd->drvp = aa_link->aa_drv_data; 276 277 strncpy(wd->drvp->drive_name, wd->sc_dev.dv_xname, 278 sizeof(wd->drvp->drive_name) - 1); 279 wd->drvp->cf_flags = wd->sc_dev.dv_cfdata->cf_flags; 280 281 if ((NERRS_MAX - 2) > 0) 282 wd->drvp->n_dmaerrs = NERRS_MAX - 2; 283 else 284 wd->drvp->n_dmaerrs = 0; 285 286 /* read our drive info */ 287 if (wd_get_params(wd, at_poll, &wd->sc_params) != 0) { 288 printf("%s: IDENTIFY failed\n", wd->sc_dev.dv_xname); 289 return; 290 } 291 292 for (blank = 0, p = wd->sc_params.atap_model, q = buf, i = 0; 293 i < sizeof(wd->sc_params.atap_model); i++) { 294 c = *p++; 295 if (c == '\0') 296 break; 297 if (c != ' ') { 298 if (blank) { 299 *q++ = ' '; 300 blank = 0; 301 } 302 *q++ = c; 303 } else 304 blank = 1; 305 } 306 *q++ = '\0'; 307 308 printf(": <%s>\n", buf); 309 310 wdc_probe_caps(wd->drvp, &wd->sc_params); 311 wdc_print_caps(wd->drvp); 312 313 if ((wd->sc_params.atap_multi & 0xff) > 1) { 314 wd->sc_multi = wd->sc_params.atap_multi & 0xff; 315 } else { 316 wd->sc_multi = 1; 317 } 318 319 printf("%s: %d-sector PIO,", wd->sc_dev.dv_xname, wd->sc_multi); 320 321 /* Prior to ATA-4, LBA was optional. */ 322 if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0) 323 wd->sc_flags |= WDF_LBA; 324 #if 0 325 /* ATA-4 requires LBA. */ 326 if (wd->sc_params.atap_ataversion != 0xffff && 327 wd->sc_params.atap_ataversion >= WDC_VER_ATA4) 328 wd->sc_flags |= WDF_LBA; 329 #endif 330 331 if ((wd->sc_flags & WDF_LBA) != 0) { 332 wd->sc_capacity = 333 (wd->sc_params.atap_capacity[1] << 16) | 334 wd->sc_params.atap_capacity[0]; 335 printf(" LBA, %dMB, %d cyl, %d head, %d sec, %d sectors\n", 336 wd->sc_capacity / (1048576 / DEV_BSIZE), 337 wd->sc_params.atap_cylinders, 338 wd->sc_params.atap_heads, 339 wd->sc_params.atap_sectors, 340 wd->sc_capacity); 341 } else { 342 wd->sc_capacity = 343 wd->sc_params.atap_cylinders * 344 wd->sc_params.atap_heads * 345 wd->sc_params.atap_sectors; 346 printf(" CHS, %dMB, %d cyl, %d head, %d sec, %d sectors\n", 347 wd->sc_capacity / (1048576 / DEV_BSIZE), 348 wd->sc_params.atap_cylinders, 349 wd->sc_params.atap_heads, 350 wd->sc_params.atap_sectors, 351 wd->sc_capacity); 352 } 353 WDCDEBUG_PRINT(("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n", 354 self->dv_xname, wd->sc_params.atap_dmatiming_mimi, 355 wd->sc_params.atap_dmatiming_recom), DEBUG_PROBE); 356 /* 357 * Initialize and attach the disk structure. 358 */ 359 wd->sc_dk.dk_driver = &wddkdriver; 360 wd->sc_dk.dk_name = wd->sc_dev.dv_xname; 361 disk_attach(&wd->sc_dk); 362 wd->sc_wdc_bio.lp = wd->sc_dk.dk_label; 363 wd->sc_sdhook = shutdownhook_establish(wd_shutdown, wd); 364 if (wd->sc_sdhook == NULL) 365 printf("%s: WARNING: unable to establish shutdown hook\n", 366 wd->sc_dev.dv_xname); 367 #if NRND > 0 368 rnd_attach_source(&wd->rnd_source, wd->sc_dev.dv_xname, 369 RND_TYPE_DISK, 0); 370 #endif 371 timeout_set(&wd->sc_restart_timeout, wdrestart, wd); 372 } 373 374 int 375 wdactivate(self, act) 376 struct device *self; 377 enum devact act; 378 { 379 int rv = 0; 380 381 switch (act) { 382 case DVACT_ACTIVATE: 383 break; 384 385 case DVACT_DEACTIVATE: 386 /* 387 * Nothing to do; we key off the device's DVF_ACTIVATE. 388 */ 389 break; 390 } 391 return (rv); 392 } 393 394 395 int 396 wddetach(self, flags) 397 struct device *self; 398 int flags; 399 { 400 struct wd_softc *sc = (struct wd_softc *)self; 401 struct buf *dp, *bp; 402 int s, bmaj, cmaj, mn; 403 404 /* Remove unprocessed buffers from queue */ 405 s = splbio(); 406 for (dp = &sc->sc_q; (bp = dp->b_actf) != NULL; ) { 407 dp->b_actf = bp->b_actf; 408 409 bp->b_error = ENXIO; 410 bp->b_flags |= B_ERROR; 411 biodone(bp); 412 } 413 splx(s); 414 415 /* locate the major number */ 416 mn = WDMINOR(self->dv_unit, 0); 417 418 for (bmaj = 0; bmaj < nblkdev; bmaj++) 419 if (bdevsw[bmaj].d_open == wdopen) 420 vdevgone(bmaj, mn, mn + MAXPARTITIONS - 1, VBLK); 421 for (cmaj = 0; cmaj < nchrdev; cmaj++) 422 if (cdevsw[cmaj].d_open == wdopen) 423 vdevgone(cmaj, mn, mn + MAXPARTITIONS - 1, VCHR); 424 425 /* Get rid of the shutdown hook. */ 426 if (sc->sc_sdhook != NULL) 427 shutdownhook_disestablish(sc->sc_sdhook); 428 429 #if NRND > 0 430 /* Unhook the entropy source. */ 431 rnd_detach_source(&sc->rnd_source); 432 #endif 433 434 return (0); 435 } 436 437 void 438 wdzeroref(self) 439 struct device *self; 440 { 441 struct wd_softc *sc = (struct wd_softc *)self; 442 443 /* Detach disk. */ 444 disk_detach(&sc->sc_dk); 445 } 446 447 /* 448 * Read/write routine for a buffer. Validates the arguments and schedules the 449 * transfer. Does not wait for the transfer to complete. 450 */ 451 void 452 wdstrategy(bp) 453 struct buf *bp; 454 { 455 struct wd_softc *wd; 456 int s; 457 458 wd = wdlookup(WDUNIT(bp->b_dev)); 459 if (wd == NULL) { 460 bp->b_error = ENXIO; 461 goto bad; 462 } 463 464 WDCDEBUG_PRINT(("wdstrategy (%s)\n", wd->sc_dev.dv_xname), 465 DEBUG_XFERS); 466 467 /* Valid request? */ 468 if (bp->b_blkno < 0 || 469 (bp->b_bcount % wd->sc_dk.dk_label->d_secsize) != 0 || 470 (bp->b_bcount / wd->sc_dk.dk_label->d_secsize) >= (1 << NBBY)) { 471 bp->b_error = EINVAL; 472 goto bad; 473 } 474 475 /* If device invalidated (e.g. media change, door open), error. */ 476 if ((wd->sc_flags & WDF_LOADED) == 0) { 477 bp->b_error = EIO; 478 goto bad; 479 } 480 481 /* If it's a null transfer, return immediately. */ 482 if (bp->b_bcount == 0) 483 goto done; 484 485 /* 486 * Do bounds checking, adjust transfer. if error, process. 487 * If end of partition, just return. 488 */ 489 if (WDPART(bp->b_dev) != RAW_PART && 490 bounds_check_with_label(bp, wd->sc_dk.dk_label, wd->sc_dk.dk_cpulabel, 491 (wd->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0) 492 goto done; 493 /* Queue transfer on drive, activate drive and controller if idle. */ 494 s = splbio(); 495 disksort(&wd->sc_q, bp); 496 wdstart(wd); 497 splx(s); 498 device_unref(&wd->sc_dev); 499 return; 500 bad: 501 bp->b_flags |= B_ERROR; 502 done: 503 /* Toss transfer; we're done early. */ 504 bp->b_resid = bp->b_bcount; 505 biodone(bp); 506 if (wd != NULL) 507 device_unref(&wd->sc_dev); 508 } 509 510 /* 511 * Queue a drive for I/O. 512 */ 513 void 514 wdstart(arg) 515 void *arg; 516 { 517 struct wd_softc *wd = arg; 518 struct buf *dp, *bp=0; 519 520 WDCDEBUG_PRINT(("wdstart %s\n", wd->sc_dev.dv_xname), 521 DEBUG_XFERS); 522 while (wd->openings > 0) { 523 524 /* Is there a buf for us ? */ 525 dp = &wd->sc_q; 526 if ((bp = dp->b_actf) == NULL) /* yes, an assign */ 527 return; 528 dp->b_actf = bp->b_actf; 529 530 /* 531 * Make the command. First lock the device 532 */ 533 wd->openings--; 534 535 wd->retries = 0; 536 __wdstart(wd, bp); 537 } 538 } 539 540 void 541 __wdstart(wd, bp) 542 struct wd_softc *wd; 543 struct buf *bp; 544 { 545 daddr_t p_offset; 546 if (WDPART(bp->b_dev) != RAW_PART) 547 p_offset = 548 wd->sc_dk.dk_label->d_partitions[WDPART(bp->b_dev)].p_offset; 549 else 550 p_offset = 0; 551 wd->sc_wdc_bio.blkno = bp->b_blkno + p_offset; 552 wd->sc_wdc_bio.blkno /= (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE); 553 wd->sc_wdc_bio.blkdone =0; 554 wd->sc_bp = bp; 555 /* 556 * If we're retrying, retry in single-sector mode. This will give us 557 * the sector number of the problem, and will eventually allow the 558 * transfer to succeed. 559 */ 560 if (wd->sc_multi == 1 || wd->retries >= WDIORETRIES_SINGLE) 561 wd->sc_wdc_bio.flags = ATA_SINGLE; 562 else 563 wd->sc_wdc_bio.flags = 0; 564 if (wd->sc_flags & WDF_LBA) 565 wd->sc_wdc_bio.flags |= ATA_LBA; 566 if (bp->b_flags & B_READ) 567 wd->sc_wdc_bio.flags |= ATA_READ; 568 wd->sc_wdc_bio.bcount = bp->b_bcount; 569 wd->sc_wdc_bio.databuf = bp->b_data; 570 wd->sc_wdc_bio.wd = wd; 571 /* Instrumentation. */ 572 disk_busy(&wd->sc_dk); 573 switch (wdc_ata_bio(wd->drvp, &wd->sc_wdc_bio)) { 574 case WDC_TRY_AGAIN: 575 timeout_add(&wd->sc_restart_timeout, hz); 576 break; 577 case WDC_QUEUED: 578 break; 579 case WDC_COMPLETE: 580 /* 581 * This code is never executed because we never set 582 * the ATA_POLL flag above 583 */ 584 #if 0 585 if (wd->sc_wdc_bio.flags & ATA_POLL) 586 wddone(wd); 587 #endif 588 break; 589 default: 590 panic("__wdstart: bad return code from wdc_ata_bio()"); 591 } 592 } 593 594 void 595 wddone(v) 596 void *v; 597 { 598 struct wd_softc *wd = v; 599 struct buf *bp = wd->sc_bp; 600 char buf[256], *errbuf = buf; 601 WDCDEBUG_PRINT(("wddone %s\n", wd->sc_dev.dv_xname), 602 DEBUG_XFERS); 603 604 bp->b_resid = wd->sc_wdc_bio.bcount; 605 errbuf[0] = '\0'; 606 switch (wd->sc_wdc_bio.error) { 607 case ERR_NODEV: 608 bp->b_flags |= B_ERROR; 609 bp->b_error = ENXIO; 610 break; 611 case ERR_DMA: 612 errbuf = "DMA error"; 613 goto retry; 614 case ERR_DF: 615 errbuf = "device fault"; 616 goto retry; 617 case TIMEOUT: 618 errbuf = "device timeout"; 619 goto retry; 620 case ERROR: 621 /* Don't care about media change bits */ 622 if (wd->sc_wdc_bio.r_error != 0 && 623 (wd->sc_wdc_bio.r_error & ~(WDCE_MC | WDCE_MCR)) == 0) 624 goto noerror; 625 ata_perror(wd->drvp, wd->sc_wdc_bio.r_error, errbuf); 626 retry: 627 /* Just reset and retry. Can we do more ? */ 628 wdc_reset_channel(wd->drvp); 629 diskerr(bp, "wd", errbuf, LOG_PRINTF, 630 wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label); 631 if (wd->retries++ < WDIORETRIES) { 632 printf(", retrying\n"); 633 timeout_add(&wd->sc_restart_timeout, RECOVERYTIME); 634 return; 635 } 636 printf("\n"); 637 bp->b_flags |= B_ERROR; 638 bp->b_error = EIO; 639 break; 640 case NOERROR: 641 noerror: if ((wd->sc_wdc_bio.flags & ATA_CORR) || wd->retries > 0) 642 printf("%s: soft error (corrected)\n", 643 wd->sc_dev.dv_xname); 644 } 645 disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid)); 646 #if NRND > 0 647 rnd_add_uint32(&wd->rnd_source, bp->b_blkno); 648 #endif 649 biodone(bp); 650 wd->openings++; 651 wdstart(wd); 652 } 653 654 void 655 wdrestart(v) 656 void *v; 657 { 658 struct wd_softc *wd = v; 659 struct buf *bp = wd->sc_bp; 660 int s; 661 WDCDEBUG_PRINT(("wdrestart %s\n", wd->sc_dev.dv_xname), 662 DEBUG_XFERS); 663 664 s = splbio(); 665 __wdstart(v, bp); 666 splx(s); 667 } 668 669 int 670 wdread(dev, uio, flags) 671 dev_t dev; 672 struct uio *uio; 673 int flags; 674 { 675 676 WDCDEBUG_PRINT(("wdread\n"), DEBUG_XFERS); 677 return (physio(wdstrategy, NULL, dev, B_READ, minphys, uio)); 678 } 679 680 int 681 wdwrite(dev, uio, flags) 682 dev_t dev; 683 struct uio *uio; 684 int flags; 685 { 686 687 WDCDEBUG_PRINT(("wdwrite\n"), DEBUG_XFERS); 688 return (physio(wdstrategy, NULL, dev, B_WRITE, minphys, uio)); 689 } 690 691 int 692 wdopen(dev, flag, fmt, p) 693 dev_t dev; 694 int flag, fmt; 695 struct proc *p; 696 { 697 struct wd_softc *wd; 698 int unit, part; 699 int error; 700 701 WDCDEBUG_PRINT(("wdopen\n"), DEBUG_FUNCS); 702 703 unit = WDUNIT(dev); 704 wd = wdlookup(unit); 705 if (wd == NULL) 706 return ENXIO; 707 708 /* 709 * If this is the first open of this device, add a reference 710 * to the adapter. 711 */ 712 #ifndef __OpenBSD__ 713 if (wd->sc_dk.dk_openmask == 0 && 714 (error = wdc_ata_addref(wd->drvp)) != 0) 715 return (error); 716 #endif 717 718 if ((error = wdlock(wd)) != 0) 719 goto bad4; 720 721 if (wd->sc_dk.dk_openmask != 0) { 722 /* 723 * If any partition is open, but the disk has been invalidated, 724 * disallow further opens. 725 */ 726 if ((wd->sc_flags & WDF_LOADED) == 0) { 727 error = EIO; 728 goto bad3; 729 } 730 } else { 731 if ((wd->sc_flags & WDF_LOADED) == 0) { 732 wd->sc_flags |= WDF_LOADED; 733 734 /* Load the physical device parameters. */ 735 wd_get_params(wd, AT_WAIT, &wd->sc_params); 736 737 /* Load the partition info if not already loaded. */ 738 wdgetdisklabel(dev, wd, wd->sc_dk.dk_label, 739 wd->sc_dk.dk_cpulabel, 0); 740 } 741 } 742 743 part = WDPART(dev); 744 745 /* Check that the partition exists. */ 746 if (part != RAW_PART && 747 (part >= wd->sc_dk.dk_label->d_npartitions || 748 wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { 749 error = ENXIO; 750 goto bad; 751 } 752 753 /* Insure only one open at a time. */ 754 switch (fmt) { 755 case S_IFCHR: 756 wd->sc_dk.dk_copenmask |= (1 << part); 757 break; 758 case S_IFBLK: 759 wd->sc_dk.dk_bopenmask |= (1 << part); 760 break; 761 } 762 wd->sc_dk.dk_openmask = 763 wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; 764 765 wdunlock(wd); 766 device_unref(&wd->sc_dev); 767 return 0; 768 769 bad: 770 if (wd->sc_dk.dk_openmask == 0) { 771 } 772 773 bad3: 774 wdunlock(wd); 775 bad4: 776 #ifndef __OpenBSD__ 777 if (wd->sc_dk.dk_openmask == 0) 778 wdc_ata_delref(wd->drvp); 779 #endif 780 device_unref(&wd->sc_dev); 781 return error; 782 } 783 784 int 785 wdclose(dev, flag, fmt, p) 786 dev_t dev; 787 int flag, fmt; 788 struct proc *p; 789 { 790 struct wd_softc *wd; 791 int part = WDPART(dev); 792 int error = 0; 793 794 wd = wdlookup(WDUNIT(dev)); 795 if (wd == NULL) 796 return ENXIO; 797 798 WDCDEBUG_PRINT(("wdclose\n"), DEBUG_FUNCS); 799 if ((error = wdlock(wd)) != 0) 800 goto exit; 801 802 switch (fmt) { 803 case S_IFCHR: 804 wd->sc_dk.dk_copenmask &= ~(1 << part); 805 break; 806 case S_IFBLK: 807 wd->sc_dk.dk_bopenmask &= ~(1 << part); 808 break; 809 } 810 wd->sc_dk.dk_openmask = 811 wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask; 812 813 if (wd->sc_dk.dk_openmask == 0) { 814 wd_flushcache(wd,0); 815 /* XXXX Must wait for I/O to complete! */ 816 #ifndef __OpenBSD__ 817 wdc_ata_delref(wd->drvp); 818 #endif 819 } 820 821 wdunlock(wd); 822 823 exit: 824 device_unref(&wd->sc_dev); 825 return (error); 826 } 827 828 void 829 wdgetdefaultlabel(wd, lp) 830 struct wd_softc *wd; 831 struct disklabel *lp; 832 { 833 WDCDEBUG_PRINT(("wdgetdefaultlabel\n"), DEBUG_FUNCS); 834 bzero(lp, sizeof(struct disklabel)); 835 836 lp->d_secsize = DEV_BSIZE; 837 lp->d_ntracks = wd->sc_params.atap_heads; 838 lp->d_nsectors = wd->sc_params.atap_sectors; 839 lp->d_ncylinders = wd->sc_params.atap_cylinders; 840 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 841 if (wd->drvp->ata_vers == -1) { 842 lp->d_type = DTYPE_ST506; 843 strncpy(lp->d_typename, "ST506/MFM/RLL", 16); 844 } else { 845 lp->d_type = DTYPE_ESDI; 846 strncpy(lp->d_typename, "ESDI/IDE disk", 16); 847 } 848 /* XXX - user viscopy() like sd.c */ 849 strncpy(lp->d_packname, wd->sc_params.atap_model, 16); 850 lp->d_secperunit = wd->sc_capacity; 851 lp->d_rpm = 3600; 852 lp->d_interleave = 1; 853 lp->d_flags = 0; 854 855 lp->d_partitions[RAW_PART].p_offset = 0; 856 lp->d_partitions[RAW_PART].p_size = 857 lp->d_secperunit * (lp->d_secsize / DEV_BSIZE); 858 lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; 859 lp->d_npartitions = RAW_PART + 1; 860 861 lp->d_magic = DISKMAGIC; 862 lp->d_magic2 = DISKMAGIC; 863 lp->d_checksum = dkcksum(lp); 864 } 865 866 /* 867 * Fabricate a default disk label, and try to read the correct one. 868 */ 869 void 870 wdgetdisklabel(dev, wd, lp, clp, spoofonly) 871 dev_t dev; 872 struct wd_softc *wd; 873 struct disklabel *lp; 874 struct cpu_disklabel *clp; 875 int spoofonly; 876 { 877 char *errstring; 878 879 WDCDEBUG_PRINT(("wdgetdisklabel\n"), DEBUG_FUNCS); 880 881 bzero(clp, sizeof(struct cpu_disklabel)); 882 883 wdgetdefaultlabel(wd, lp); 884 885 wd->sc_badsect[0] = -1; 886 887 if (wd->drvp->state > RECAL) 888 wd->drvp->drive_flags |= DRIVE_RESET; 889 errstring = readdisklabel(WDLABELDEV(dev), 890 wdstrategy, lp, clp, spoofonly); 891 if (errstring) { 892 /* 893 * This probably happened because the drive's default 894 * geometry doesn't match the DOS geometry. We 895 * assume the DOS geometry is now in the label and try 896 * again. XXX This is a kluge. 897 */ 898 if (wd->drvp->state > RECAL) 899 wd->drvp->drive_flags |= DRIVE_RESET; 900 errstring = readdisklabel(WDLABELDEV(dev), 901 wdstrategy, lp, clp, spoofonly); 902 } 903 if (errstring) { 904 printf("%s: %s\n", wd->sc_dev.dv_xname, errstring); 905 return; 906 } 907 908 if (wd->drvp->state > RECAL) 909 wd->drvp->drive_flags |= DRIVE_RESET; 910 #ifdef DKBAD 911 if ((lp->d_flags & D_BADSECT) != 0) 912 bad144intern(wd); 913 #endif 914 } 915 916 int 917 wdioctl(dev, xfer, addr, flag, p) 918 dev_t dev; 919 u_long xfer; 920 caddr_t addr; 921 int flag; 922 struct proc *p; 923 { 924 struct wd_softc *wd; 925 int error = 0; 926 927 WDCDEBUG_PRINT(("wdioctl\n"), DEBUG_FUNCS); 928 929 wd = wdlookup(WDUNIT(dev)); 930 if (wd == NULL) 931 return ENXIO; 932 933 if ((wd->sc_flags & WDF_LOADED) == 0) { 934 error = EIO; 935 goto exit; 936 } 937 938 switch (xfer) { 939 #ifdef DKBAD 940 case DIOCSBAD: 941 if ((flag & FWRITE) == 0) 942 return EBADF; 943 DKBAD(wd->sc_dk.dk_cpulabel) = *(struct dkbad *)addr; 944 wd->sc_dk.dk_label->d_flags |= D_BADSECT; 945 bad144intern(wd); 946 goto exit; 947 #endif 948 949 case DIOCRLDINFO: 950 wdgetdisklabel(dev, wd, wd->sc_dk.dk_label, 951 wd->sc_dk.dk_cpulabel, 0); 952 goto exit; 953 case DIOCGPDINFO: { 954 struct cpu_disklabel osdep; 955 956 wdgetdisklabel(dev, wd, (struct disklabel *)addr, 957 &osdep, 1); 958 goto exit; 959 } 960 961 case DIOCGDINFO: 962 *(struct disklabel *)addr = *(wd->sc_dk.dk_label); 963 goto exit; 964 965 case DIOCGPART: 966 ((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label; 967 ((struct partinfo *)addr)->part = 968 &wd->sc_dk.dk_label->d_partitions[WDPART(dev)]; 969 goto exit; 970 971 case DIOCWDINFO: 972 case DIOCSDINFO: 973 if ((flag & FWRITE) == 0) { 974 error = EBADF; 975 goto exit; 976 } 977 978 if ((error = wdlock(wd)) != 0) 979 goto exit; 980 wd->sc_flags |= WDF_LABELLING; 981 982 error = setdisklabel(wd->sc_dk.dk_label, 983 (struct disklabel *)addr, /*wd->sc_dk.dk_openmask : */0, 984 wd->sc_dk.dk_cpulabel); 985 if (error == 0) { 986 if (wd->drvp->state > RECAL) 987 wd->drvp->drive_flags |= DRIVE_RESET; 988 if (xfer == DIOCWDINFO) 989 error = writedisklabel(WDLABELDEV(dev), 990 wdstrategy, wd->sc_dk.dk_label, 991 wd->sc_dk.dk_cpulabel); 992 } 993 994 wd->sc_flags &= ~WDF_LABELLING; 995 wdunlock(wd); 996 goto exit; 997 998 case DIOCWLABEL: 999 if ((flag & FWRITE) == 0) { 1000 error = EBADF; 1001 goto exit; 1002 } 1003 1004 if (*(int *)addr) 1005 wd->sc_flags |= WDF_WLABEL; 1006 else 1007 wd->sc_flags &= ~WDF_WLABEL; 1008 goto exit; 1009 1010 #ifndef __OpenBSD__ 1011 case DIOCGDEFLABEL: 1012 wdgetdefaultlabel(wd, (struct disklabel *)addr); 1013 goto exit; 1014 #endif 1015 1016 #ifdef notyet 1017 case DIOCWFORMAT: 1018 if ((flag & FWRITE) == 0) 1019 return EBADF; 1020 { 1021 register struct format_op *fop; 1022 struct iovec aiov; 1023 struct uio auio; 1024 1025 fop = (struct format_op *)addr; 1026 aiov.iov_base = fop->df_buf; 1027 aiov.iov_len = fop->df_count; 1028 auio.uio_iov = &aiov; 1029 auio.uio_iovcnt = 1; 1030 auio.uio_resid = fop->df_count; 1031 auio.uio_segflg = 0; 1032 auio.uio_offset = 1033 fop->df_startblk * wd->sc_dk.dk_label->d_secsize; 1034 auio.uio_procp = p; 1035 error = physio(wdformat, NULL, dev, B_WRITE, minphys, 1036 &auio); 1037 fop->df_count -= auio.uio_resid; 1038 fop->df_reg[0] = wdc->sc_status; 1039 fop->df_reg[1] = wdc->sc_error; 1040 goto exit; 1041 } 1042 #endif 1043 1044 default: 1045 error = wdc_ioctl(wd->drvp, xfer, addr, flag); 1046 goto exit; 1047 } 1048 1049 #ifdef DIAGNOSTIC 1050 panic("wdioctl: impossible"); 1051 #endif 1052 1053 exit: 1054 device_unref(&wd->sc_dev); 1055 return (error); 1056 } 1057 1058 #ifdef B_FORMAT 1059 int 1060 wdformat(struct buf *bp) 1061 { 1062 1063 bp->b_flags |= B_FORMAT; 1064 return wdstrategy(bp); 1065 } 1066 #endif 1067 1068 int 1069 wdsize(dev) 1070 dev_t dev; 1071 { 1072 struct wd_softc *wd; 1073 int part, omask; 1074 int size; 1075 1076 WDCDEBUG_PRINT(("wdsize\n"), DEBUG_FUNCS); 1077 1078 wd = wdlookup(WDUNIT(dev)); 1079 if (wd == NULL) 1080 return (-1); 1081 1082 part = WDPART(dev); 1083 omask = wd->sc_dk.dk_openmask & (1 << part); 1084 1085 if (omask == 0 && wdopen(dev, 0, S_IFBLK, NULL) != 0) { 1086 size = -1; 1087 goto exit; 1088 } 1089 1090 if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) 1091 size = -1; 1092 else 1093 size = wd->sc_dk.dk_label->d_partitions[part].p_size * 1094 (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE); 1095 if (omask == 0 && wdclose(dev, 0, S_IFBLK, NULL) != 0) 1096 size = -1; 1097 1098 exit: 1099 device_unref(&wd->sc_dev); 1100 return (size); 1101 } 1102 1103 /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */ 1104 static int wddoingadump = 0; 1105 static int wddumprecalibrated = 0; 1106 static int wddumpmulti = 1; 1107 1108 /* 1109 * Dump core after a system crash. 1110 */ 1111 int 1112 wddump(dev, blkno, va, size) 1113 dev_t dev; 1114 daddr_t blkno; 1115 caddr_t va; 1116 size_t size; 1117 { 1118 struct wd_softc *wd; /* disk unit to do the I/O */ 1119 struct disklabel *lp; /* disk's disklabel */ 1120 int unit, part; 1121 int nblks; /* total number of sectors left to write */ 1122 int err; 1123 char errbuf[256]; 1124 1125 /* Check if recursive dump; if so, punt. */ 1126 if (wddoingadump) 1127 return EFAULT; 1128 wddoingadump = 1; 1129 1130 unit = WDUNIT(dev); 1131 wd = wdlookup(unit); 1132 if (wd == NULL) 1133 return ENXIO; 1134 1135 part = WDPART(dev); 1136 1137 /* Make sure it was initialized. */ 1138 if (wd->drvp->state < READY) 1139 return ENXIO; 1140 1141 /* Convert to disk sectors. Request must be a multiple of size. */ 1142 lp = wd->sc_dk.dk_label; 1143 if ((size % lp->d_secsize) != 0) 1144 return EFAULT; 1145 nblks = size / lp->d_secsize; 1146 blkno = blkno / (lp->d_secsize / DEV_BSIZE); 1147 1148 /* Check transfer bounds against partition size. */ 1149 if ((blkno < 0) || ((blkno + nblks) > lp->d_partitions[part].p_size)) 1150 return EINVAL; 1151 1152 /* Offset block number to start of partition. */ 1153 blkno += lp->d_partitions[part].p_offset; 1154 1155 /* Recalibrate, if first dump transfer. */ 1156 if (wddumprecalibrated == 0) { 1157 wddumpmulti = wd->sc_multi; 1158 wddumprecalibrated = 1; 1159 wd->drvp->state = RECAL; 1160 } 1161 1162 while (nblks > 0) { 1163 again: 1164 wd->sc_wdc_bio.blkno = blkno; 1165 wd->sc_wdc_bio.flags = ATA_POLL; 1166 if (wddumpmulti == 1) 1167 wd->sc_wdc_bio.flags |= ATA_SINGLE; 1168 if (wd->sc_flags & WDF_LBA) 1169 wd->sc_wdc_bio.flags |= ATA_LBA; 1170 wd->sc_wdc_bio.bcount = 1171 min(nblks, wddumpmulti) * lp->d_secsize; 1172 wd->sc_wdc_bio.databuf = va; 1173 wd->sc_wdc_bio.wd = wd; 1174 #ifndef WD_DUMP_NOT_TRUSTED 1175 switch (wdc_ata_bio(wd->drvp, &wd->sc_wdc_bio)) { 1176 case WDC_TRY_AGAIN: 1177 panic("wddump: try again"); 1178 break; 1179 case WDC_QUEUED: 1180 panic("wddump: polled command has been queued"); 1181 break; 1182 case WDC_COMPLETE: 1183 break; 1184 } 1185 switch(wd->sc_wdc_bio.error) { 1186 case TIMEOUT: 1187 printf("wddump: device timed out"); 1188 err = EIO; 1189 break; 1190 case ERR_DF: 1191 printf("wddump: drive fault"); 1192 err = EIO; 1193 break; 1194 case ERR_DMA: 1195 printf("wddump: DMA error"); 1196 err = EIO; 1197 break; 1198 case ERROR: 1199 errbuf[0] = '\0'; 1200 ata_perror(wd->drvp, wd->sc_wdc_bio.r_error, errbuf); 1201 printf("wddump: %s", errbuf); 1202 err = EIO; 1203 break; 1204 case NOERROR: 1205 err = 0; 1206 break; 1207 default: 1208 panic("wddump: unknown error type"); 1209 } 1210 if (err != 0) { 1211 if (wddumpmulti != 1) { 1212 wddumpmulti = 1; /* retry in single-sector */ 1213 printf(", retrying\n"); 1214 goto again; 1215 } 1216 printf("\n"); 1217 return err; 1218 } 1219 #else /* WD_DUMP_NOT_TRUSTED */ 1220 /* Let's just talk about this first... */ 1221 printf("wd%d: dump addr 0x%x, cylin %d, head %d, sector %d\n", 1222 unit, va, cylin, head, sector); 1223 delay(500 * 1000); /* half a second */ 1224 #endif 1225 1226 /* update block count */ 1227 nblks -= min(nblks, wddumpmulti); 1228 blkno += min(nblks, wddumpmulti); 1229 va += min(nblks, wddumpmulti) * lp->d_secsize; 1230 } 1231 1232 wddoingadump = 0; 1233 return 0; 1234 } 1235 1236 #ifdef DKBAD 1237 /* 1238 * Internalize the bad sector table. 1239 */ 1240 void 1241 bad144intern(wd) 1242 struct wd_softc *wd; 1243 { 1244 struct dkbad *bt = &DKBAD(wd->sc_dk.dk_cpulabel); 1245 struct disklabel *lp = wd->sc_dk.dk_label; 1246 int i = 0; 1247 1248 WDCDEBUG_PRINT(("bad144intern\n"), DEBUG_XFERS); 1249 1250 for (; i < NBT_BAD; i++) { 1251 if (bt->bt_bad[i].bt_cyl == 0xffff) 1252 break; 1253 wd->sc_badsect[i] = 1254 bt->bt_bad[i].bt_cyl * lp->d_secpercyl + 1255 (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors + 1256 (bt->bt_bad[i].bt_trksec & 0xff); 1257 } 1258 for (; i < NBT_BAD+1; i++) 1259 wd->sc_badsect[i] = -1; 1260 } 1261 #endif 1262 1263 int 1264 wd_get_params(wd, flags, params) 1265 struct wd_softc *wd; 1266 u_int8_t flags; 1267 struct ataparams *params; 1268 { 1269 switch (ata_get_params(wd->drvp, flags, params)) { 1270 case CMD_AGAIN: 1271 return 1; 1272 case CMD_ERR: 1273 /* 1274 * We `know' there's a drive here; just assume it's old. 1275 * This geometry is only used to read the MBR and print a 1276 * (false) attach message. 1277 */ 1278 strncpy(params->atap_model, "ST506", 1279 sizeof params->atap_model); 1280 params->atap_config = ATA_CFG_FIXED; 1281 params->atap_cylinders = 1024; 1282 params->atap_heads = 8; 1283 params->atap_sectors = 17; 1284 params->atap_multi = 1; 1285 params->atap_capabilities1 = params->atap_capabilities2 = 0; 1286 wd->drvp->ata_vers = -1; /* Mark it as pre-ATA */ 1287 return 0; 1288 case CMD_OK: 1289 return 0; 1290 default: 1291 panic("wd_get_params: bad return code from ata_get_params"); 1292 /* NOTREACHED */ 1293 } 1294 } 1295 1296 void 1297 wd_flushcache(wd, flags) 1298 struct wd_softc *wd; 1299 int flags; 1300 { 1301 struct wdc_command wdc_c; 1302 1303 if (wd->drvp->ata_vers < 4) /* WDCC_FLUSHCACHE is here since ATA-4 */ 1304 return; 1305 bzero(&wdc_c, sizeof(struct wdc_command)); 1306 wdc_c.r_command = WDCC_FLUSHCACHE; 1307 wdc_c.r_st_bmask = WDCS_DRDY; 1308 wdc_c.r_st_pmask = WDCS_DRDY; 1309 if (flags != 0) { 1310 wdc_c.flags = AT_POLL; 1311 } else { 1312 wdc_c.flags = AT_WAIT; 1313 } 1314 wdc_c.timeout = 30000; /* 30s timeout */ 1315 if (wdc_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) { 1316 printf("%s: flush cache command didn't complete\n", 1317 wd->sc_dev.dv_xname); 1318 } 1319 if (wdc_c.flags & AT_TIMEOU) { 1320 printf("%s: flush cache command timeout\n", 1321 wd->sc_dev.dv_xname); 1322 } 1323 if (wdc_c.flags & AT_DF) { 1324 printf("%s: flush cache command: drive fault\n", 1325 wd->sc_dev.dv_xname); 1326 } 1327 /* 1328 * Ignore error register, it shouldn't report anything else 1329 * than COMMAND ABORTED, which means the device doesn't support 1330 * flush cache 1331 */ 1332 } 1333 1334 void 1335 wd_shutdown(arg) 1336 void *arg; 1337 { 1338 struct wd_softc *wd = arg; 1339 wd_flushcache(wd, AT_POLL); 1340 } 1341