Annotation of sys/dev/ata/wd.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: wd.c,v 1.66 2007/06/20 18:15:46 deraadt Exp $ */
! 2: /* $NetBSD: wd.c,v 1.193 1999/02/28 17:15:27 explorer Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1998, 2001 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: #include <sys/vnode.h>
! 89:
! 90: #include <uvm/uvm_extern.h>
! 91:
! 92: #include <machine/intr.h>
! 93: #include <machine/bus.h>
! 94:
! 95: #include <dev/ata/atareg.h>
! 96: #include <dev/ata/atavar.h>
! 97: #include <dev/ata/wdvar.h>
! 98: #include <dev/ic/wdcreg.h>
! 99: #include <dev/ic/wdcvar.h>
! 100: #if 0
! 101: #include "locators.h"
! 102: #endif
! 103:
! 104: #define LBA48_THRESHOLD (0xfffffff) /* 128GB / DEV_BSIZE */
! 105:
! 106: #define WDIORETRIES_SINGLE 4 /* number of retries before single-sector */
! 107: #define WDIORETRIES 5 /* number of retries before giving up */
! 108: #define RECOVERYTIME hz/2 /* time to wait before retrying a cmd */
! 109:
! 110: #define DEBUG_INTR 0x01
! 111: #define DEBUG_XFERS 0x02
! 112: #define DEBUG_STATUS 0x04
! 113: #define DEBUG_FUNCS 0x08
! 114: #define DEBUG_PROBE 0x10
! 115: #ifdef WDCDEBUG
! 116: extern int wdcdebug_wd_mask; /* init'ed in ata_wdc.c */
! 117: #define WDCDEBUG_PRINT(args, level) do { \
! 118: if ((wdcdebug_wd_mask & (level)) != 0) \
! 119: printf args; \
! 120: } while (0)
! 121: #else
! 122: #define WDCDEBUG_PRINT(args, level)
! 123: #endif
! 124:
! 125: struct wd_softc {
! 126: /* General disk infos */
! 127: struct device sc_dev;
! 128: struct disk sc_dk;
! 129: struct buf sc_q;
! 130: /* IDE disk soft states */
! 131: struct ata_bio sc_wdc_bio; /* current transfer */
! 132: struct buf *sc_bp; /* buf being transferred */
! 133: struct ata_drive_datas *drvp; /* Our controller's infos */
! 134: int openings;
! 135: struct ataparams sc_params;/* drive characteristics found */
! 136: int sc_flags;
! 137: #define WDF_LOCKED 0x01
! 138: #define WDF_WANTED 0x02
! 139: #define WDF_WLABEL 0x04 /* label is writable */
! 140: #define WDF_LABELLING 0x08 /* writing label */
! 141: /*
! 142: * XXX Nothing resets this yet, but disk change sensing will when ATA-4 is
! 143: * more fully implemented.
! 144: */
! 145: #define WDF_LOADED 0x10 /* parameters loaded */
! 146: #define WDF_WAIT 0x20 /* waiting for resources */
! 147: #define WDF_LBA 0x40 /* using LBA mode */
! 148: #define WDF_LBA48 0x80 /* using 48-bit LBA mode */
! 149:
! 150: u_int64_t sc_capacity;
! 151: int cyl; /* actual drive parameters */
! 152: int heads;
! 153: int sectors;
! 154: int retries; /* number of xfer retry */
! 155: struct timeout sc_restart_timeout;
! 156: void *sc_sdhook;
! 157: };
! 158:
! 159: #define sc_drive sc_wdc_bio.drive
! 160: #define sc_mode sc_wdc_bio.mode
! 161: #define sc_multi sc_wdc_bio.multi
! 162:
! 163: int wdprobe(struct device *, void *, void *);
! 164: void wdattach(struct device *, struct device *, void *);
! 165: int wddetach(struct device *, int);
! 166: int wdactivate(struct device *, enum devact);
! 167: int wdprint(void *, char *);
! 168:
! 169: struct cfattach wd_ca = {
! 170: sizeof(struct wd_softc), wdprobe, wdattach,
! 171: wddetach, wdactivate
! 172: };
! 173:
! 174: struct cfdriver wd_cd = {
! 175: NULL, "wd", DV_DISK
! 176: };
! 177:
! 178: void wdgetdefaultlabel(struct wd_softc *, struct disklabel *);
! 179: void wdgetdisklabel(dev_t dev, struct wd_softc *, struct disklabel *, int);
! 180: void wdstrategy(struct buf *);
! 181: void wdstart(void *);
! 182: void __wdstart(struct wd_softc*, struct buf *);
! 183: void wdrestart(void *);
! 184: int wd_get_params(struct wd_softc *, u_int8_t, struct ataparams *);
! 185: void wd_flushcache(struct wd_softc *, int);
! 186: void wd_shutdown(void *);
! 187:
! 188: struct dkdriver wddkdriver = { wdstrategy };
! 189:
! 190: /* XXX: these should go elsewhere */
! 191: cdev_decl(wd);
! 192: bdev_decl(wd);
! 193:
! 194: #define wdlock(wd) disk_lock(&(wd)->sc_dk)
! 195: #define wdunlock(wd) disk_unlock(&(wd)->sc_dk)
! 196: #define wdlookup(unit) (struct wd_softc *)device_lookup(&wd_cd, (unit))
! 197:
! 198:
! 199: int
! 200: wdprobe(struct device *parent, void *match_, void *aux)
! 201: {
! 202: struct ata_atapi_attach *aa_link = aux;
! 203: struct cfdata *match = match_;
! 204:
! 205: if (aa_link == NULL)
! 206: return 0;
! 207: if (aa_link->aa_type != T_ATA)
! 208: return 0;
! 209:
! 210: if (match->cf_loc[0] != -1 &&
! 211: match->cf_loc[0] != aa_link->aa_channel)
! 212: return 0;
! 213:
! 214: if (match->cf_loc[1] != -1 &&
! 215: match->cf_loc[1] != aa_link->aa_drv_data->drive)
! 216: return 0;
! 217:
! 218: return 1;
! 219: }
! 220:
! 221: void
! 222: wdattach(struct device *parent, struct device *self, void *aux)
! 223: {
! 224: struct wd_softc *wd = (void *)self;
! 225: struct ata_atapi_attach *aa_link= aux;
! 226: struct wdc_command wdc_c;
! 227: int i, blank;
! 228: char buf[41], c, *p, *q;
! 229: WDCDEBUG_PRINT(("wdattach\n"), DEBUG_FUNCS | DEBUG_PROBE);
! 230:
! 231: wd->openings = aa_link->aa_openings;
! 232: wd->drvp = aa_link->aa_drv_data;
! 233:
! 234: strlcpy(wd->drvp->drive_name, wd->sc_dev.dv_xname,
! 235: sizeof(wd->drvp->drive_name));
! 236: wd->drvp->cf_flags = wd->sc_dev.dv_cfdata->cf_flags;
! 237:
! 238: if ((NERRS_MAX - 2) > 0)
! 239: wd->drvp->n_dmaerrs = NERRS_MAX - 2;
! 240: else
! 241: wd->drvp->n_dmaerrs = 0;
! 242:
! 243: /* read our drive info */
! 244: if (wd_get_params(wd, at_poll, &wd->sc_params) != 0) {
! 245: printf("%s: IDENTIFY failed\n", wd->sc_dev.dv_xname);
! 246: return;
! 247: }
! 248:
! 249: for (blank = 0, p = wd->sc_params.atap_model, q = buf, i = 0;
! 250: i < sizeof(wd->sc_params.atap_model); i++) {
! 251: c = *p++;
! 252: if (c == '\0')
! 253: break;
! 254: if (c != ' ') {
! 255: if (blank) {
! 256: *q++ = ' ';
! 257: blank = 0;
! 258: }
! 259: *q++ = c;
! 260: } else
! 261: blank = 1;
! 262: }
! 263: *q++ = '\0';
! 264:
! 265: printf(": <%s>\n", buf);
! 266:
! 267: wdc_probe_caps(wd->drvp, &wd->sc_params);
! 268: wdc_print_caps(wd->drvp);
! 269:
! 270: if ((wd->sc_params.atap_multi & 0xff) > 1) {
! 271: wd->sc_multi = wd->sc_params.atap_multi & 0xff;
! 272: } else {
! 273: wd->sc_multi = 1;
! 274: }
! 275:
! 276: printf("%s: %d-sector PIO,", wd->sc_dev.dv_xname, wd->sc_multi);
! 277:
! 278: /* use 48-bit LBA if enabled */
! 279: /* XXX: shall we use it if drive capacity < 137Gb? */
! 280: if ((wd->sc_params.atap_cmd2_en & ATAPI_CMD2_48AD) != 0)
! 281: wd->sc_flags |= WDF_LBA48;
! 282:
! 283: /* Prior to ATA-4, LBA was optional. */
! 284: if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0)
! 285: wd->sc_flags |= WDF_LBA;
! 286: #if 0
! 287: /* ATA-4 requires LBA. */
! 288: if (wd->sc_params.atap_ataversion != 0xffff &&
! 289: wd->sc_params.atap_ataversion >= WDC_VER_ATA4)
! 290: wd->sc_flags |= WDF_LBA;
! 291: #endif
! 292:
! 293: if ((wd->sc_flags & WDF_LBA48) != 0) {
! 294: wd->sc_capacity =
! 295: (((u_int64_t)wd->sc_params.atap_max_lba[3] << 48) |
! 296: ((u_int64_t)wd->sc_params.atap_max_lba[2] << 32) |
! 297: ((u_int64_t)wd->sc_params.atap_max_lba[1] << 16) |
! 298: (u_int64_t)wd->sc_params.atap_max_lba[0]);
! 299: printf(" LBA48, %lluMB, %llu sectors\n",
! 300: wd->sc_capacity / (1048576 / DEV_BSIZE),
! 301: wd->sc_capacity);
! 302: } else if ((wd->sc_flags & WDF_LBA) != 0) {
! 303: wd->sc_capacity =
! 304: (wd->sc_params.atap_capacity[1] << 16) |
! 305: wd->sc_params.atap_capacity[0];
! 306: printf(" LBA, %lluMB, %llu sectors\n",
! 307: wd->sc_capacity / (1048576 / DEV_BSIZE),
! 308: wd->sc_capacity);
! 309: } else {
! 310: wd->sc_capacity =
! 311: wd->sc_params.atap_cylinders *
! 312: wd->sc_params.atap_heads *
! 313: wd->sc_params.atap_sectors;
! 314: printf(" CHS, %lluMB, %d cyl, %d head, %d sec, %llu sectors\n",
! 315: wd->sc_capacity / (1048576 / DEV_BSIZE),
! 316: wd->sc_params.atap_cylinders,
! 317: wd->sc_params.atap_heads,
! 318: wd->sc_params.atap_sectors,
! 319: wd->sc_capacity);
! 320: }
! 321: WDCDEBUG_PRINT(("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n",
! 322: self->dv_xname, wd->sc_params.atap_dmatiming_mimi,
! 323: wd->sc_params.atap_dmatiming_recom), DEBUG_PROBE);
! 324:
! 325: /*
! 326: * FREEZE LOCK the drive so malicous users can't lock it on us.
! 327: * As there is no harm in issuing this to drives that don't
! 328: * support the security feature set we just send it, and don't
! 329: * bother checking if the drive sends a command abort to tell us it
! 330: * doesn't support it.
! 331: */
! 332: bzero(&wdc_c, sizeof(struct wdc_command));
! 333:
! 334: wdc_c.r_command = WDCC_SEC_FREEZE_LOCK;
! 335: wdc_c.timeout = 1000;
! 336: wdc_c.flags = at_poll;
! 337: if (wdc_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) {
! 338: printf("%s: freeze lock command didn't complete\n",
! 339: wd->sc_dev.dv_xname);
! 340: }
! 341:
! 342: /*
! 343: * Initialize and attach the disk structure.
! 344: */
! 345: wd->sc_dk.dk_driver = &wddkdriver;
! 346: wd->sc_dk.dk_name = wd->sc_dev.dv_xname;
! 347: disk_attach(&wd->sc_dk);
! 348: wd->sc_wdc_bio.lp = wd->sc_dk.dk_label;
! 349: wd->sc_sdhook = shutdownhook_establish(wd_shutdown, wd);
! 350: if (wd->sc_sdhook == NULL)
! 351: printf("%s: WARNING: unable to establish shutdown hook\n",
! 352: wd->sc_dev.dv_xname);
! 353: timeout_set(&wd->sc_restart_timeout, wdrestart, wd);
! 354: }
! 355:
! 356: int
! 357: wdactivate(struct device *self, enum devact act)
! 358: {
! 359: int rv = 0;
! 360:
! 361: switch (act) {
! 362: case DVACT_ACTIVATE:
! 363: break;
! 364:
! 365: case DVACT_DEACTIVATE:
! 366: /*
! 367: * Nothing to do; we key off the device's DVF_ACTIVATE.
! 368: */
! 369: break;
! 370: }
! 371: return (rv);
! 372: }
! 373:
! 374: int
! 375: wddetach(struct device *self, int flags)
! 376: {
! 377: struct wd_softc *sc = (struct wd_softc *)self;
! 378: struct buf *dp, *bp;
! 379: int s, bmaj, cmaj, mn;
! 380:
! 381: /* Remove unprocessed buffers from queue */
! 382: s = splbio();
! 383: for (dp = &sc->sc_q; (bp = dp->b_actf) != NULL; ) {
! 384: dp->b_actf = bp->b_actf;
! 385: bp->b_error = ENXIO;
! 386: bp->b_flags |= B_ERROR;
! 387: biodone(bp);
! 388: }
! 389: splx(s);
! 390:
! 391: /* Locate the lowest minor number to be detached. */
! 392: mn = DISKMINOR(self->dv_unit, 0);
! 393:
! 394: for (bmaj = 0; bmaj < nblkdev; bmaj++)
! 395: if (bdevsw[bmaj].d_open == wdopen)
! 396: vdevgone(bmaj, mn, mn + MAXPARTITIONS - 1, VBLK);
! 397: for (cmaj = 0; cmaj < nchrdev; cmaj++)
! 398: if (cdevsw[cmaj].d_open == wdopen)
! 399: vdevgone(cmaj, mn, mn + MAXPARTITIONS - 1, VCHR);
! 400:
! 401: /* Get rid of the shutdown hook. */
! 402: if (sc->sc_sdhook != NULL)
! 403: shutdownhook_disestablish(sc->sc_sdhook);
! 404:
! 405: /* Detach disk. */
! 406: disk_detach(&sc->sc_dk);
! 407:
! 408: return (0);
! 409: }
! 410:
! 411: /*
! 412: * Read/write routine for a buffer. Validates the arguments and schedules the
! 413: * transfer. Does not wait for the transfer to complete.
! 414: */
! 415: void
! 416: wdstrategy(struct buf *bp)
! 417: {
! 418: struct wd_softc *wd;
! 419: int s;
! 420:
! 421: wd = wdlookup(DISKUNIT(bp->b_dev));
! 422: if (wd == NULL) {
! 423: bp->b_error = ENXIO;
! 424: goto bad;
! 425: }
! 426:
! 427: WDCDEBUG_PRINT(("wdstrategy (%s)\n", wd->sc_dev.dv_xname),
! 428: DEBUG_XFERS);
! 429:
! 430: /* Valid request? */
! 431: if (bp->b_blkno < 0 ||
! 432: (bp->b_bcount % wd->sc_dk.dk_label->d_secsize) != 0 ||
! 433: (bp->b_bcount / wd->sc_dk.dk_label->d_secsize) >= (1 << NBBY)) {
! 434: bp->b_error = EINVAL;
! 435: goto bad;
! 436: }
! 437:
! 438: /* If device invalidated (e.g. media change, door open), error. */
! 439: if ((wd->sc_flags & WDF_LOADED) == 0) {
! 440: bp->b_error = EIO;
! 441: goto bad;
! 442: }
! 443:
! 444: /* If it's a null transfer, return immediately. */
! 445: if (bp->b_bcount == 0)
! 446: goto done;
! 447:
! 448: /*
! 449: * Do bounds checking, adjust transfer. if error, process.
! 450: * If end of partition, just return.
! 451: */
! 452: if (DISKPART(bp->b_dev) != RAW_PART &&
! 453: bounds_check_with_label(bp, wd->sc_dk.dk_label,
! 454: (wd->sc_flags & (WDF_WLABEL|WDF_LABELLING)) != 0) <= 0)
! 455: goto done;
! 456: /* Queue transfer on drive, activate drive and controller if idle. */
! 457: s = splbio();
! 458: disksort(&wd->sc_q, bp);
! 459: wdstart(wd);
! 460: splx(s);
! 461: device_unref(&wd->sc_dev);
! 462: return;
! 463: bad:
! 464: bp->b_flags |= B_ERROR;
! 465: done:
! 466: /* Toss transfer; we're done early. */
! 467: bp->b_resid = bp->b_bcount;
! 468: s = splbio();
! 469: biodone(bp);
! 470: splx(s);
! 471: if (wd != NULL)
! 472: device_unref(&wd->sc_dev);
! 473: }
! 474:
! 475: /*
! 476: * Queue a drive for I/O.
! 477: */
! 478: void
! 479: wdstart(void *arg)
! 480: {
! 481: struct wd_softc *wd = arg;
! 482: struct buf *dp, *bp = NULL;
! 483:
! 484: WDCDEBUG_PRINT(("wdstart %s\n", wd->sc_dev.dv_xname),
! 485: DEBUG_XFERS);
! 486: while (wd->openings > 0) {
! 487:
! 488: /* Is there a buf for us ? */
! 489: dp = &wd->sc_q;
! 490: if ((bp = dp->b_actf) == NULL) /* yes, an assign */
! 491: return;
! 492: dp->b_actf = bp->b_actf;
! 493:
! 494: /*
! 495: * Make the command. First lock the device
! 496: */
! 497: wd->openings--;
! 498:
! 499: wd->retries = 0;
! 500: __wdstart(wd, bp);
! 501: }
! 502: }
! 503:
! 504: void
! 505: __wdstart(struct wd_softc *wd, struct buf *bp)
! 506: {
! 507: daddr64_t nblks;
! 508:
! 509: wd->sc_wdc_bio.blkno = bp->b_blkno +
! 510: DL_GETPOFFSET(&wd->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]);
! 511: wd->sc_wdc_bio.blkno /= (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
! 512: wd->sc_wdc_bio.blkdone =0;
! 513: wd->sc_bp = bp;
! 514: /*
! 515: * If we're retrying, retry in single-sector mode. This will give us
! 516: * the sector number of the problem, and will eventually allow the
! 517: * transfer to succeed.
! 518: */
! 519: if (wd->sc_multi == 1 || wd->retries >= WDIORETRIES_SINGLE)
! 520: wd->sc_wdc_bio.flags = ATA_SINGLE;
! 521: else
! 522: wd->sc_wdc_bio.flags = 0;
! 523: nblks = bp->b_bcount / wd->sc_dk.dk_label->d_secsize;
! 524: if ((wd->sc_flags & WDF_LBA48) &&
! 525: /* use LBA48 only if really need */
! 526: ((wd->sc_wdc_bio.blkno + nblks - 1 > LBA48_THRESHOLD) ||
! 527: (nblks > 0xff)))
! 528: wd->sc_wdc_bio.flags |= ATA_LBA48;
! 529: if (wd->sc_flags & WDF_LBA)
! 530: wd->sc_wdc_bio.flags |= ATA_LBA;
! 531: if (bp->b_flags & B_READ)
! 532: wd->sc_wdc_bio.flags |= ATA_READ;
! 533: wd->sc_wdc_bio.bcount = bp->b_bcount;
! 534: wd->sc_wdc_bio.databuf = bp->b_data;
! 535: wd->sc_wdc_bio.wd = wd;
! 536: /* Instrumentation. */
! 537: disk_busy(&wd->sc_dk);
! 538: switch (wdc_ata_bio(wd->drvp, &wd->sc_wdc_bio)) {
! 539: case WDC_TRY_AGAIN:
! 540: timeout_add(&wd->sc_restart_timeout, hz);
! 541: break;
! 542: case WDC_QUEUED:
! 543: break;
! 544: case WDC_COMPLETE:
! 545: /*
! 546: * This code is never executed because we never set
! 547: * the ATA_POLL flag above
! 548: */
! 549: #if 0
! 550: if (wd->sc_wdc_bio.flags & ATA_POLL)
! 551: wddone(wd);
! 552: #endif
! 553: break;
! 554: default:
! 555: panic("__wdstart: bad return code from wdc_ata_bio()");
! 556: }
! 557: }
! 558:
! 559: void
! 560: wddone(void *v)
! 561: {
! 562: struct wd_softc *wd = v;
! 563: struct buf *bp = wd->sc_bp;
! 564: char buf[256], *errbuf = buf;
! 565: WDCDEBUG_PRINT(("wddone %s\n", wd->sc_dev.dv_xname),
! 566: DEBUG_XFERS);
! 567:
! 568: bp->b_resid = wd->sc_wdc_bio.bcount;
! 569: errbuf[0] = '\0';
! 570: switch (wd->sc_wdc_bio.error) {
! 571: case ERR_NODEV:
! 572: bp->b_flags |= B_ERROR;
! 573: bp->b_error = ENXIO;
! 574: break;
! 575: case ERR_DMA:
! 576: errbuf = "DMA error";
! 577: goto retry;
! 578: case ERR_DF:
! 579: errbuf = "device fault";
! 580: goto retry;
! 581: case TIMEOUT:
! 582: errbuf = "device timeout";
! 583: goto retry;
! 584: case ERROR:
! 585: /* Don't care about media change bits */
! 586: if (wd->sc_wdc_bio.r_error != 0 &&
! 587: (wd->sc_wdc_bio.r_error & ~(WDCE_MC | WDCE_MCR)) == 0)
! 588: goto noerror;
! 589: ata_perror(wd->drvp, wd->sc_wdc_bio.r_error, errbuf,
! 590: sizeof buf);
! 591: retry:
! 592: /* Just reset and retry. Can we do more ? */
! 593: wdc_reset_channel(wd->drvp);
! 594: diskerr(bp, "wd", errbuf, LOG_PRINTF,
! 595: wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label);
! 596: if (wd->retries++ < WDIORETRIES) {
! 597: printf(", retrying\n");
! 598: timeout_add(&wd->sc_restart_timeout, RECOVERYTIME);
! 599: return;
! 600: }
! 601: printf("\n");
! 602: bp->b_flags |= B_ERROR;
! 603: bp->b_error = EIO;
! 604: break;
! 605: case NOERROR:
! 606: noerror: if ((wd->sc_wdc_bio.flags & ATA_CORR) || wd->retries > 0)
! 607: printf("%s: soft error (corrected)\n",
! 608: wd->sc_dev.dv_xname);
! 609: }
! 610: disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid),
! 611: (bp->b_flags & B_READ));
! 612: biodone(bp);
! 613: wd->openings++;
! 614: wdstart(wd);
! 615: }
! 616:
! 617: void
! 618: wdrestart(void *v)
! 619: {
! 620: struct wd_softc *wd = v;
! 621: struct buf *bp = wd->sc_bp;
! 622: int s;
! 623: WDCDEBUG_PRINT(("wdrestart %s\n", wd->sc_dev.dv_xname),
! 624: DEBUG_XFERS);
! 625:
! 626: s = splbio();
! 627: disk_unbusy(&wd->sc_dk, 0, (bp->b_flags & B_READ));
! 628: __wdstart(v, bp);
! 629: splx(s);
! 630: }
! 631:
! 632: int
! 633: wdread(dev_t dev, struct uio *uio, int flags)
! 634: {
! 635:
! 636: WDCDEBUG_PRINT(("wdread\n"), DEBUG_XFERS);
! 637: return (physio(wdstrategy, NULL, dev, B_READ, minphys, uio));
! 638: }
! 639:
! 640: int
! 641: wdwrite(dev_t dev, struct uio *uio, int flags)
! 642: {
! 643:
! 644: WDCDEBUG_PRINT(("wdwrite\n"), DEBUG_XFERS);
! 645: return (physio(wdstrategy, NULL, dev, B_WRITE, minphys, uio));
! 646: }
! 647:
! 648: int
! 649: wdopen(dev_t dev, int flag, int fmt, struct proc *p)
! 650: {
! 651: struct wd_softc *wd;
! 652: int unit, part;
! 653: int error;
! 654:
! 655: WDCDEBUG_PRINT(("wdopen\n"), DEBUG_FUNCS);
! 656:
! 657: unit = DISKUNIT(dev);
! 658: wd = wdlookup(unit);
! 659: if (wd == NULL)
! 660: return ENXIO;
! 661:
! 662: /*
! 663: * If this is the first open of this device, add a reference
! 664: * to the adapter.
! 665: */
! 666: if ((error = wdlock(wd)) != 0)
! 667: goto bad4;
! 668:
! 669: if (wd->sc_dk.dk_openmask != 0) {
! 670: /*
! 671: * If any partition is open, but the disk has been invalidated,
! 672: * disallow further opens.
! 673: */
! 674: if ((wd->sc_flags & WDF_LOADED) == 0) {
! 675: error = EIO;
! 676: goto bad3;
! 677: }
! 678: } else {
! 679: if ((wd->sc_flags & WDF_LOADED) == 0) {
! 680: wd->sc_flags |= WDF_LOADED;
! 681:
! 682: /* Load the physical device parameters. */
! 683: wd_get_params(wd, AT_WAIT, &wd->sc_params);
! 684:
! 685: /* Load the partition info if not already loaded. */
! 686: wdgetdisklabel(dev, wd, wd->sc_dk.dk_label, 0);
! 687: }
! 688: }
! 689:
! 690: part = DISKPART(dev);
! 691:
! 692: /* Check that the partition exists. */
! 693: if (part != RAW_PART &&
! 694: (part >= wd->sc_dk.dk_label->d_npartitions ||
! 695: wd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
! 696: error = ENXIO;
! 697: goto bad;
! 698: }
! 699:
! 700: /* Insure only one open at a time. */
! 701: switch (fmt) {
! 702: case S_IFCHR:
! 703: wd->sc_dk.dk_copenmask |= (1 << part);
! 704: break;
! 705: case S_IFBLK:
! 706: wd->sc_dk.dk_bopenmask |= (1 << part);
! 707: break;
! 708: }
! 709: wd->sc_dk.dk_openmask =
! 710: wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
! 711:
! 712: wdunlock(wd);
! 713: device_unref(&wd->sc_dev);
! 714: return 0;
! 715:
! 716: bad:
! 717: if (wd->sc_dk.dk_openmask == 0) {
! 718: }
! 719:
! 720: bad3:
! 721: wdunlock(wd);
! 722: bad4:
! 723: device_unref(&wd->sc_dev);
! 724: return error;
! 725: }
! 726:
! 727: int
! 728: wdclose(dev_t dev, int flag, int fmt, struct proc *p)
! 729: {
! 730: struct wd_softc *wd;
! 731: int part = DISKPART(dev);
! 732: int error = 0;
! 733:
! 734: wd = wdlookup(DISKUNIT(dev));
! 735: if (wd == NULL)
! 736: return ENXIO;
! 737:
! 738: WDCDEBUG_PRINT(("wdclose\n"), DEBUG_FUNCS);
! 739: if ((error = wdlock(wd)) != 0)
! 740: goto exit;
! 741:
! 742: switch (fmt) {
! 743: case S_IFCHR:
! 744: wd->sc_dk.dk_copenmask &= ~(1 << part);
! 745: break;
! 746: case S_IFBLK:
! 747: wd->sc_dk.dk_bopenmask &= ~(1 << part);
! 748: break;
! 749: }
! 750: wd->sc_dk.dk_openmask =
! 751: wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
! 752:
! 753: if (wd->sc_dk.dk_openmask == 0) {
! 754: wd_flushcache(wd, 0);
! 755: /* XXXX Must wait for I/O to complete! */
! 756: }
! 757:
! 758: wdunlock(wd);
! 759:
! 760: exit:
! 761: device_unref(&wd->sc_dev);
! 762: return (error);
! 763: }
! 764:
! 765: void
! 766: wdgetdefaultlabel(struct wd_softc *wd, struct disklabel *lp)
! 767: {
! 768: WDCDEBUG_PRINT(("wdgetdefaultlabel\n"), DEBUG_FUNCS);
! 769: bzero(lp, sizeof(struct disklabel));
! 770:
! 771: lp->d_secsize = DEV_BSIZE;
! 772: DL_SETDSIZE(lp, wd->sc_capacity);
! 773: lp->d_ntracks = wd->sc_params.atap_heads;
! 774: lp->d_nsectors = wd->sc_params.atap_sectors;
! 775: lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
! 776: lp->d_ncylinders = DL_GETDSIZE(lp) / lp->d_secpercyl;
! 777: if (wd->drvp->ata_vers == -1) {
! 778: lp->d_type = DTYPE_ST506;
! 779: strncpy(lp->d_typename, "ST506/MFM/RLL", sizeof lp->d_typename);
! 780: } else {
! 781: lp->d_type = DTYPE_ESDI;
! 782: strncpy(lp->d_typename, "ESDI/IDE disk", sizeof lp->d_typename);
! 783: }
! 784: /* XXX - user viscopy() like sd.c */
! 785: strncpy(lp->d_packname, wd->sc_params.atap_model, sizeof lp->d_packname);
! 786: lp->d_rpm = 3600;
! 787: lp->d_interleave = 1;
! 788: lp->d_flags = 0;
! 789: lp->d_version = 1;
! 790:
! 791: lp->d_magic = DISKMAGIC;
! 792: lp->d_magic2 = DISKMAGIC;
! 793: lp->d_checksum = dkcksum(lp);
! 794: }
! 795:
! 796: /*
! 797: * Fabricate a default disk label, and try to read the correct one.
! 798: */
! 799: void
! 800: wdgetdisklabel(dev_t dev, struct wd_softc *wd, struct disklabel *lp,
! 801: int spoofonly)
! 802: {
! 803: char *errstring;
! 804:
! 805: WDCDEBUG_PRINT(("wdgetdisklabel\n"), DEBUG_FUNCS);
! 806:
! 807: wdgetdefaultlabel(wd, lp);
! 808:
! 809: if (wd->drvp->state > RECAL)
! 810: wd->drvp->drive_flags |= DRIVE_RESET;
! 811: errstring = readdisklabel(DISKLABELDEV(dev), wdstrategy, lp,
! 812: spoofonly);
! 813: if (wd->drvp->state > RECAL)
! 814: wd->drvp->drive_flags |= DRIVE_RESET;
! 815: if (errstring) {
! 816: /*printf("%s: %s\n", wd->sc_dev.dv_xname, errstring);*/
! 817: }
! 818: }
! 819:
! 820: int
! 821: wdioctl(dev_t dev, u_long xfer, caddr_t addr, int flag, struct proc *p)
! 822: {
! 823: struct wd_softc *wd;
! 824: struct disklabel *lp;
! 825: int error = 0;
! 826:
! 827: WDCDEBUG_PRINT(("wdioctl\n"), DEBUG_FUNCS);
! 828:
! 829: wd = wdlookup(DISKUNIT(dev));
! 830: if (wd == NULL)
! 831: return ENXIO;
! 832:
! 833: if ((wd->sc_flags & WDF_LOADED) == 0) {
! 834: error = EIO;
! 835: goto exit;
! 836: }
! 837:
! 838: switch (xfer) {
! 839: case DIOCRLDINFO:
! 840: lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
! 841: wdgetdisklabel(dev, wd, lp, 0);
! 842: bcopy(lp, wd->sc_dk.dk_label, sizeof(*lp));
! 843: free(lp, M_TEMP);
! 844: goto exit;
! 845:
! 846: case DIOCGPDINFO:
! 847: wdgetdisklabel(dev, wd, (struct disklabel *)addr, 1);
! 848: goto exit;
! 849:
! 850: case DIOCGDINFO:
! 851: *(struct disklabel *)addr = *(wd->sc_dk.dk_label);
! 852: goto exit;
! 853:
! 854: case DIOCGPART:
! 855: ((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label;
! 856: ((struct partinfo *)addr)->part =
! 857: &wd->sc_dk.dk_label->d_partitions[DISKPART(dev)];
! 858: goto exit;
! 859:
! 860: case DIOCWDINFO:
! 861: case DIOCSDINFO:
! 862: if ((flag & FWRITE) == 0) {
! 863: error = EBADF;
! 864: goto exit;
! 865: }
! 866:
! 867: if ((error = wdlock(wd)) != 0)
! 868: goto exit;
! 869: wd->sc_flags |= WDF_LABELLING;
! 870:
! 871: error = setdisklabel(wd->sc_dk.dk_label,
! 872: (struct disklabel *)addr, /*wd->sc_dk.dk_openmask : */0);
! 873: if (error == 0) {
! 874: if (wd->drvp->state > RECAL)
! 875: wd->drvp->drive_flags |= DRIVE_RESET;
! 876: if (xfer == DIOCWDINFO)
! 877: error = writedisklabel(DISKLABELDEV(dev),
! 878: wdstrategy, wd->sc_dk.dk_label);
! 879: }
! 880:
! 881: wd->sc_flags &= ~WDF_LABELLING;
! 882: wdunlock(wd);
! 883: goto exit;
! 884:
! 885: case DIOCWLABEL:
! 886: if ((flag & FWRITE) == 0) {
! 887: error = EBADF;
! 888: goto exit;
! 889: }
! 890:
! 891: if (*(int *)addr)
! 892: wd->sc_flags |= WDF_WLABEL;
! 893: else
! 894: wd->sc_flags &= ~WDF_WLABEL;
! 895: goto exit;
! 896:
! 897: #ifdef notyet
! 898: case DIOCWFORMAT:
! 899: if ((flag & FWRITE) == 0)
! 900: return EBADF;
! 901: {
! 902: struct format_op *fop;
! 903: struct iovec aiov;
! 904: struct uio auio;
! 905:
! 906: fop = (struct format_op *)addr;
! 907: aiov.iov_base = fop->df_buf;
! 908: aiov.iov_len = fop->df_count;
! 909: auio.uio_iov = &aiov;
! 910: auio.uio_iovcnt = 1;
! 911: auio.uio_resid = fop->df_count;
! 912: auio.uio_segflg = 0;
! 913: auio.uio_offset =
! 914: fop->df_startblk * wd->sc_dk.dk_label->d_secsize;
! 915: auio.uio_procp = p;
! 916: error = physio(wdformat, NULL, dev, B_WRITE, minphys,
! 917: &auio);
! 918: fop->df_count -= auio.uio_resid;
! 919: fop->df_reg[0] = wdc->sc_status;
! 920: fop->df_reg[1] = wdc->sc_error;
! 921: goto exit;
! 922: }
! 923: #endif
! 924:
! 925: default:
! 926: error = wdc_ioctl(wd->drvp, xfer, addr, flag, p);
! 927: goto exit;
! 928: }
! 929:
! 930: #ifdef DIAGNOSTIC
! 931: panic("wdioctl: impossible");
! 932: #endif
! 933:
! 934: exit:
! 935: device_unref(&wd->sc_dev);
! 936: return (error);
! 937: }
! 938:
! 939: #ifdef B_FORMAT
! 940: int
! 941: wdformat(struct buf *bp)
! 942: {
! 943:
! 944: bp->b_flags |= B_FORMAT;
! 945: return wdstrategy(bp);
! 946: }
! 947: #endif
! 948:
! 949: daddr64_t
! 950: wdsize(dev_t dev)
! 951: {
! 952: struct wd_softc *wd;
! 953: int part, omask;
! 954: int64_t size;
! 955:
! 956: WDCDEBUG_PRINT(("wdsize\n"), DEBUG_FUNCS);
! 957:
! 958: wd = wdlookup(DISKUNIT(dev));
! 959: if (wd == NULL)
! 960: return (-1);
! 961:
! 962: part = DISKPART(dev);
! 963: omask = wd->sc_dk.dk_openmask & (1 << part);
! 964:
! 965: if (omask == 0 && wdopen(dev, 0, S_IFBLK, NULL) != 0) {
! 966: size = -1;
! 967: goto exit;
! 968: }
! 969:
! 970: size = DL_GETPSIZE(&wd->sc_dk.dk_label->d_partitions[part]) *
! 971: (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
! 972: if (omask == 0 && wdclose(dev, 0, S_IFBLK, NULL) != 0)
! 973: size = -1;
! 974:
! 975: exit:
! 976: device_unref(&wd->sc_dev);
! 977: return (size);
! 978: }
! 979:
! 980: /* #define WD_DUMP_NOT_TRUSTED if you just want to watch */
! 981: static int wddoingadump = 0;
! 982: static int wddumprecalibrated = 0;
! 983: static int wddumpmulti = 1;
! 984:
! 985: /*
! 986: * Dump core after a system crash.
! 987: */
! 988: int
! 989: wddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size)
! 990: {
! 991: struct wd_softc *wd; /* disk unit to do the I/O */
! 992: struct disklabel *lp; /* disk's disklabel */
! 993: int unit, part;
! 994: int nblks; /* total number of sectors left to write */
! 995: int err;
! 996: char errbuf[256];
! 997:
! 998: /* Check if recursive dump; if so, punt. */
! 999: if (wddoingadump)
! 1000: return EFAULT;
! 1001: wddoingadump = 1;
! 1002:
! 1003: unit = DISKUNIT(dev);
! 1004: wd = wdlookup(unit);
! 1005: if (wd == NULL)
! 1006: return ENXIO;
! 1007:
! 1008: part = DISKPART(dev);
! 1009:
! 1010: /* Make sure it was initialized. */
! 1011: if (wd->drvp->state < READY)
! 1012: return ENXIO;
! 1013:
! 1014: /* Convert to disk sectors. Request must be a multiple of size. */
! 1015: lp = wd->sc_dk.dk_label;
! 1016: if ((size % lp->d_secsize) != 0)
! 1017: return EFAULT;
! 1018: nblks = size / lp->d_secsize;
! 1019: blkno = blkno / (lp->d_secsize / DEV_BSIZE);
! 1020:
! 1021: /* Check transfer bounds against partition size. */
! 1022: if ((blkno < 0) || ((blkno + nblks) > DL_GETPSIZE(&lp->d_partitions[part])))
! 1023: return EINVAL;
! 1024:
! 1025: /* Offset block number to start of partition. */
! 1026: blkno += DL_GETPOFFSET(&lp->d_partitions[part]);
! 1027:
! 1028: /* Recalibrate, if first dump transfer. */
! 1029: if (wddumprecalibrated == 0) {
! 1030: wddumpmulti = wd->sc_multi;
! 1031: wddumprecalibrated = 1;
! 1032: wd->drvp->state = RECAL;
! 1033: }
! 1034:
! 1035: while (nblks > 0) {
! 1036: again:
! 1037: wd->sc_wdc_bio.blkno = blkno;
! 1038: wd->sc_wdc_bio.flags = ATA_POLL;
! 1039: if (wddumpmulti == 1)
! 1040: wd->sc_wdc_bio.flags |= ATA_SINGLE;
! 1041: if (wd->sc_flags & WDF_LBA48)
! 1042: wd->sc_wdc_bio.flags |= ATA_LBA48;
! 1043: if (wd->sc_flags & WDF_LBA)
! 1044: wd->sc_wdc_bio.flags |= ATA_LBA;
! 1045: wd->sc_wdc_bio.bcount =
! 1046: min(nblks, wddumpmulti) * lp->d_secsize;
! 1047: wd->sc_wdc_bio.databuf = va;
! 1048: wd->sc_wdc_bio.wd = wd;
! 1049: #ifndef WD_DUMP_NOT_TRUSTED
! 1050: switch (wdc_ata_bio(wd->drvp, &wd->sc_wdc_bio)) {
! 1051: case WDC_TRY_AGAIN:
! 1052: panic("wddump: try again");
! 1053: break;
! 1054: case WDC_QUEUED:
! 1055: panic("wddump: polled command has been queued");
! 1056: break;
! 1057: case WDC_COMPLETE:
! 1058: break;
! 1059: }
! 1060: switch(wd->sc_wdc_bio.error) {
! 1061: case TIMEOUT:
! 1062: printf("wddump: device timed out");
! 1063: err = EIO;
! 1064: break;
! 1065: case ERR_DF:
! 1066: printf("wddump: drive fault");
! 1067: err = EIO;
! 1068: break;
! 1069: case ERR_DMA:
! 1070: printf("wddump: DMA error");
! 1071: err = EIO;
! 1072: break;
! 1073: case ERROR:
! 1074: errbuf[0] = '\0';
! 1075: ata_perror(wd->drvp, wd->sc_wdc_bio.r_error, errbuf,
! 1076: sizeof errbuf);
! 1077: printf("wddump: %s", errbuf);
! 1078: err = EIO;
! 1079: break;
! 1080: case NOERROR:
! 1081: err = 0;
! 1082: break;
! 1083: default:
! 1084: panic("wddump: unknown error type");
! 1085: }
! 1086: if (err != 0) {
! 1087: if (wddumpmulti != 1) {
! 1088: wddumpmulti = 1; /* retry in single-sector */
! 1089: printf(", retrying\n");
! 1090: goto again;
! 1091: }
! 1092: printf("\n");
! 1093: return err;
! 1094: }
! 1095: #else /* WD_DUMP_NOT_TRUSTED */
! 1096: /* Let's just talk about this first... */
! 1097: printf("wd%d: dump addr 0x%x, cylin %d, head %d, sector %d\n",
! 1098: unit, va, cylin, head, sector);
! 1099: delay(500 * 1000); /* half a second */
! 1100: #endif
! 1101:
! 1102: /* update block count */
! 1103: nblks -= min(nblks, wddumpmulti);
! 1104: blkno += min(nblks, wddumpmulti);
! 1105: va += min(nblks, wddumpmulti) * lp->d_secsize;
! 1106: }
! 1107:
! 1108: wddoingadump = 0;
! 1109: return 0;
! 1110: }
! 1111:
! 1112: int
! 1113: wd_get_params(struct wd_softc *wd, u_int8_t flags, struct ataparams *params)
! 1114: {
! 1115: switch (ata_get_params(wd->drvp, flags, params)) {
! 1116: case CMD_AGAIN:
! 1117: return 1;
! 1118: case CMD_ERR:
! 1119: /* If we already have drive parameters, reuse them. */
! 1120: if (wd->sc_params.atap_cylinders != 0) {
! 1121: if (params != &wd->sc_params)
! 1122: bcopy(&wd->sc_params, params,
! 1123: sizeof(struct ataparams));
! 1124: return 0;
! 1125: }
! 1126: /*
! 1127: * We `know' there's a drive here; just assume it's old.
! 1128: * This geometry is only used to read the MBR and print a
! 1129: * (false) attach message.
! 1130: */
! 1131: bzero(params, sizeof(struct ataparams));
! 1132: strncpy(params->atap_model, "ST506",
! 1133: sizeof params->atap_model);
! 1134: params->atap_config = ATA_CFG_FIXED;
! 1135: params->atap_cylinders = 1024;
! 1136: params->atap_heads = 8;
! 1137: params->atap_sectors = 17;
! 1138: params->atap_multi = 1;
! 1139: params->atap_capabilities1 = params->atap_capabilities2 = 0;
! 1140: wd->drvp->ata_vers = -1; /* Mark it as pre-ATA */
! 1141: return 0;
! 1142: case CMD_OK:
! 1143: return 0;
! 1144: default:
! 1145: panic("wd_get_params: bad return code from ata_get_params");
! 1146: /* NOTREACHED */
! 1147: }
! 1148: }
! 1149:
! 1150: void
! 1151: wd_flushcache(struct wd_softc *wd, int flags)
! 1152: {
! 1153: struct wdc_command wdc_c;
! 1154:
! 1155: if (wd->drvp->ata_vers < 4) /* WDCC_FLUSHCACHE is here since ATA-4 */
! 1156: return;
! 1157: bzero(&wdc_c, sizeof(struct wdc_command));
! 1158: wdc_c.r_command = (wd->sc_flags & WDF_LBA48 ? WDCC_FLUSHCACHE_EXT :
! 1159: WDCC_FLUSHCACHE);
! 1160: wdc_c.r_st_bmask = WDCS_DRDY;
! 1161: wdc_c.r_st_pmask = WDCS_DRDY;
! 1162: if (flags != 0) {
! 1163: wdc_c.flags = AT_POLL;
! 1164: } else {
! 1165: wdc_c.flags = AT_WAIT;
! 1166: }
! 1167: wdc_c.timeout = 30000; /* 30s timeout */
! 1168: if (wdc_exec_command(wd->drvp, &wdc_c) != WDC_COMPLETE) {
! 1169: printf("%s: flush cache command didn't complete\n",
! 1170: wd->sc_dev.dv_xname);
! 1171: }
! 1172: if (wdc_c.flags & AT_TIMEOU) {
! 1173: printf("%s: flush cache command timeout\n",
! 1174: wd->sc_dev.dv_xname);
! 1175: }
! 1176: if (wdc_c.flags & AT_DF) {
! 1177: printf("%s: flush cache command: drive fault\n",
! 1178: wd->sc_dev.dv_xname);
! 1179: }
! 1180: /*
! 1181: * Ignore error register, it shouldn't report anything else
! 1182: * than COMMAND ABORTED, which means the device doesn't support
! 1183: * flush cache
! 1184: */
! 1185: }
! 1186:
! 1187: void
! 1188: wd_shutdown(void *arg)
! 1189: {
! 1190: struct wd_softc *wd = arg;
! 1191: wd_flushcache(wd, AT_POLL);
! 1192: }
CVSweb