[BACK]Return to wd.c CVS log [TXT][DIR] Up to [local] / sys / dev / ata

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