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

Annotation of sys/dev/ata/ata_wdc.c, Revision 1.1

1.1     ! nbrk        1: /*      $OpenBSD: ata_wdc.c,v 1.30 2007/02/14 00:53:47 jsg Exp $       */
        !             2: /*     $NetBSD: ata_wdc.c,v 1.21 1999/08/09 09:43:11 bouyer Exp $      */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1998, 2001 Manuel Bouyer.
        !             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. Neither the name of the University nor the names of its contributors
        !            19:  *    may be used to endorse or promote products derived from this software
        !            20:  *    without specific prior written permission.
        !            21:  *
        !            22:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            23:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            24:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            25:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            26:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            27:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            28:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            29:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            30:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            31:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            32:  *
        !            33:  */
        !            34:
        !            35: /*-
        !            36:  * Copyright (c) 1998 The NetBSD Foundation, Inc.
        !            37:  * All rights reserved.
        !            38:  *
        !            39:  * This code is derived from software contributed to The NetBSD Foundation
        !            40:  * by Charles M. Hannum, by Onno van der Linden and by Manuel Bouyer.
        !            41:  *
        !            42:  * Redistribution and use in source and binary forms, with or without
        !            43:  * modification, are permitted provided that the following conditions
        !            44:  * are met:
        !            45:  * 1. Redistributions of source code must retain the above copyright
        !            46:  *    notice, this list of conditions and the following disclaimer.
        !            47:  * 2. Redistributions in binary form must reproduce the above copyright
        !            48:  *    notice, this list of conditions and the following disclaimer in the
        !            49:  *    documentation and/or other materials provided with the distribution.
        !            50:  * 3. All advertising materials mentioning features or use of this software
        !            51:  *    must display the following acknowledgement:
        !            52:  *        This product includes software developed by the NetBSD
        !            53:  *        Foundation, Inc. and its contributors.
        !            54:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            55:  *    contributors may be used to endorse or promote products derived
        !            56:  *    from this software without specific prior written permission.
        !            57:  *
        !            58:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            59:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            60:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            61:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            62:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            63:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            64:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            65:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            66:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            67:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            68:  * POSSIBILITY OF SUCH DAMAGE.
        !            69:  */
        !            70:
        !            71: #include <sys/param.h>
        !            72: #include <sys/systm.h>
        !            73: #include <sys/kernel.h>
        !            74: #include <sys/file.h>
        !            75: #include <sys/stat.h>
        !            76: #include <sys/buf.h>
        !            77: #include <sys/malloc.h>
        !            78: #include <sys/device.h>
        !            79: #include <sys/disklabel.h>
        !            80: #include <sys/syslog.h>
        !            81: #include <sys/proc.h>
        !            82:
        !            83: #include <machine/intr.h>
        !            84: #include <machine/bus.h>
        !            85:
        !            86: #include <dev/ata/atareg.h>
        !            87: #include <dev/ata/atavar.h>
        !            88: #include <dev/ic/wdcreg.h>
        !            89: #include <dev/ic/wdcvar.h>
        !            90: #include <dev/ata/wdvar.h>
        !            91:
        !            92: #define DEBUG_INTR   0x01
        !            93: #define DEBUG_XFERS  0x02
        !            94: #define DEBUG_STATUS 0x04
        !            95: #define DEBUG_FUNCS  0x08
        !            96: #define DEBUG_PROBE  0x10
        !            97:
        !            98: #ifdef WDCDEBUG
        !            99: #ifndef WDCDEBUG_WD_MASK
        !           100: #define WDCDEBUG_WD_MASK 0x00
        !           101: #endif
        !           102: int wdcdebug_wd_mask = WDCDEBUG_WD_MASK;
        !           103: #define WDCDEBUG_PRINT(args, level) do {       \
        !           104:        if ((wdcdebug_wd_mask & (level)) != 0)  \
        !           105:                printf args;                    \
        !           106: } while (0)
        !           107: #else
        !           108: #define WDCDEBUG_PRINT(args, level)
        !           109: #endif
        !           110:
        !           111: #define ATA_DELAY 10000 /* 10s for a drive I/O */
        !           112:
        !           113: struct cfdriver wdc_cd = {
        !           114:        NULL, "wdc", DV_DULL
        !           115: };
        !           116:
        !           117: void  wdc_ata_bio_start(struct channel_softc *, struct wdc_xfer *);
        !           118: void  _wdc_ata_bio_start(struct channel_softc *, struct wdc_xfer *);
        !           119: int   wdc_ata_bio_intr(struct channel_softc *, struct wdc_xfer *, int);
        !           120: void  wdc_ata_bio_kill_xfer(struct channel_softc *, struct wdc_xfer *);
        !           121: void  wdc_ata_bio_done(struct channel_softc *, struct wdc_xfer *);
        !           122: int   wdc_ata_ctrl_intr(struct channel_softc *, struct wdc_xfer *, int);
        !           123: int   wdc_ata_err(struct ata_drive_datas *, struct ata_bio *);
        !           124: #define WDC_ATA_NOERR 0x00 /* Drive doesn't report an error */
        !           125: #define WDC_ATA_RECOV 0x01 /* There was a recovered error */
        !           126: #define WDC_ATA_ERR   0x02 /* Drive reports an error */
        !           127:
        !           128: /*
        !           129:  * Handle block I/O operation. Return WDC_COMPLETE, WDC_QUEUED, or
        !           130:  * WDC_TRY_AGAIN. Must be called at splbio().
        !           131:  */
        !           132: int
        !           133: wdc_ata_bio(struct ata_drive_datas *drvp, struct ata_bio *ata_bio)
        !           134: {
        !           135:        struct wdc_xfer *xfer;
        !           136:        struct channel_softc *chp = drvp->chnl_softc;
        !           137:
        !           138:        xfer = wdc_get_xfer(WDC_NOSLEEP);
        !           139:        if (xfer == NULL)
        !           140:                return WDC_TRY_AGAIN;
        !           141:        if (ata_bio->flags & ATA_POLL)
        !           142:                xfer->c_flags |= C_POLL;
        !           143:        if (!(ata_bio->flags & ATA_POLL) &&
        !           144:            (drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) &&
        !           145:            (ata_bio->flags & ATA_SINGLE) == 0 &&
        !           146:            (ata_bio->bcount > 512 ||
        !           147:            (chp->wdc->quirks & WDC_QUIRK_NOSHORTDMA) == 0))
        !           148:                xfer->c_flags |= C_DMA;
        !           149:        xfer->drive = drvp->drive;
        !           150:        xfer->cmd = ata_bio;
        !           151:        xfer->databuf = ata_bio->databuf;
        !           152:        xfer->c_bcount = ata_bio->bcount;
        !           153:        xfer->c_start = wdc_ata_bio_start;
        !           154:        xfer->c_intr = wdc_ata_bio_intr;
        !           155:        xfer->c_kill_xfer = wdc_ata_bio_kill_xfer;
        !           156:        wdc_exec_xfer(chp, xfer);
        !           157:        return (ata_bio->flags & ATA_ITSDONE) ? WDC_COMPLETE : WDC_QUEUED;
        !           158: }
        !           159:
        !           160: void
        !           161: wdc_ata_bio_start(struct channel_softc *chp, struct wdc_xfer *xfer)
        !           162: {
        !           163:        struct ata_bio *ata_bio = xfer->cmd;
        !           164:        WDCDEBUG_PRINT(("wdc_ata_bio_start %s:%d:%d\n",
        !           165:            chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive),
        !           166:            DEBUG_XFERS);
        !           167:
        !           168:        /* start timeout machinery */
        !           169:        if ((ata_bio->flags & ATA_POLL) == 0)
        !           170:                timeout_add(&chp->ch_timo, ATA_DELAY / 1000 * hz);
        !           171:        _wdc_ata_bio_start(chp, xfer);
        !           172: }
        !           173:
        !           174: void
        !           175: _wdc_ata_bio_start(struct channel_softc *chp, struct wdc_xfer *xfer)
        !           176: {
        !           177:        struct ata_bio *ata_bio = xfer->cmd;
        !           178:        struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
        !           179:        u_int16_t cyl;
        !           180:        u_int8_t head, sect, cmd = 0;
        !           181:        int nblks;
        !           182:        int ata_delay;
        !           183:        int dma_flags = 0;
        !           184:
        !           185:        WDCDEBUG_PRINT(("_wdc_ata_bio_start %s:%d:%d\n",
        !           186:            chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive),
        !           187:            DEBUG_INTR | DEBUG_XFERS);
        !           188:        /* Do control operations specially. */
        !           189:        if (drvp->state < READY) {
        !           190:                /*
        !           191:                 * Actually, we want to be careful not to mess with the control
        !           192:                 * state if the device is currently busy, but we can assume
        !           193:                 * that we never get to this point if that's the case.
        !           194:                 */
        !           195:                /* at this point, we should only be in RECAL state */
        !           196:                if (drvp->state != RECAL) {
        !           197:                        printf("%s:%d:%d: bad state %d in _wdc_ata_bio_start\n",
        !           198:                            chp->wdc->sc_dev.dv_xname, chp->channel,
        !           199:                            xfer->drive, drvp->state);
        !           200:                        panic("_wdc_ata_bio_start: bad state");
        !           201:                }
        !           202:                xfer->c_intr = wdc_ata_ctrl_intr;
        !           203:                wdc_set_drive(chp, xfer->drive);
        !           204:                if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY) != 0)
        !           205:                        goto timeout;
        !           206:                wdccommandshort(chp, xfer->drive, WDCC_RECAL);
        !           207:                drvp->state = RECAL_WAIT;
        !           208:                if ((ata_bio->flags & ATA_POLL) == 0) {
        !           209:                        chp->ch_flags |= WDCF_IRQ_WAIT;
        !           210:                } else {
        !           211:                        /* Wait for at last 400ns for status bit to be valid */
        !           212:                        DELAY(1);
        !           213:                        wdc_ata_ctrl_intr(chp, xfer, 0);
        !           214:                }
        !           215:                return;
        !           216:        }
        !           217:
        !           218:        if (xfer->c_flags & C_DMA) {
        !           219:                if (drvp->n_xfers <= NXFER)
        !           220:                        drvp->n_xfers++;
        !           221:                dma_flags = (ata_bio->flags & ATA_READ) ?  WDC_DMA_READ : 0;
        !           222:                if (ata_bio->flags & ATA_LBA48)
        !           223:                        dma_flags |= WDC_DMA_LBA48;
        !           224:        }
        !           225:        if (ata_bio->flags & ATA_SINGLE)
        !           226:                ata_delay = ATA_DELAY;
        !           227:        else
        !           228:                ata_delay = ATA_DELAY;
        !           229: again:
        !           230:        /*
        !           231:         *
        !           232:         * When starting a multi-sector transfer, or doing single-sector
        !           233:         * transfers...
        !           234:         */
        !           235:        if (xfer->c_skip == 0 || (ata_bio->flags & ATA_SINGLE) != 0) {
        !           236:                if (ata_bio->flags & ATA_SINGLE)
        !           237:                        nblks = 1;
        !           238:                else
        !           239:                        nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
        !           240:                if (ata_bio->flags & ATA_LBA) {
        !           241:                        sect = (ata_bio->blkno >> 0) & 0xff;
        !           242:                        cyl = (ata_bio->blkno >> 8) & 0xffff;
        !           243:                        head = (ata_bio->blkno >> 24) & 0x0f;
        !           244:                        head |= WDSD_LBA;
        !           245:                } else {
        !           246:                        int blkno = ata_bio->blkno;
        !           247:                        sect = blkno % ata_bio->lp->d_nsectors;
        !           248:                        sect++;    /* Sectors begin with 1, not 0. */
        !           249:                        blkno /= ata_bio->lp->d_nsectors;
        !           250:                        head = blkno % ata_bio->lp->d_ntracks;
        !           251:                        blkno /= ata_bio->lp->d_ntracks;
        !           252:                        cyl = blkno;
        !           253:                        head |= WDSD_CHS;
        !           254:                }
        !           255:                if (xfer->c_flags & C_DMA) {
        !           256:                        ata_bio->nblks = nblks;
        !           257:                        ata_bio->nbytes = xfer->c_bcount;
        !           258:                        if (ata_bio->flags & ATA_LBA48)
        !           259:                                cmd = (ata_bio->flags & ATA_READ) ?
        !           260:                                    WDCC_READDMA_EXT : WDCC_WRITEDMA_EXT;
        !           261:                        else
        !           262:                                cmd = (ata_bio->flags & ATA_READ) ?
        !           263:                                    WDCC_READDMA : WDCC_WRITEDMA;
        !           264:                        /* Init the DMA channel. */
        !           265:                        if ((*chp->wdc->dma_init)(chp->wdc->dma_arg,
        !           266:                            chp->channel, xfer->drive,
        !           267:                            (char *)xfer->databuf + xfer->c_skip,
        !           268:                            ata_bio->nbytes, dma_flags) != 0) {
        !           269:                                ata_bio->error = ERR_DMA;
        !           270:                                ata_bio->r_error = 0;
        !           271:                                wdc_ata_bio_done(chp, xfer);
        !           272:                                return;
        !           273:                        }
        !           274:                        /* Initiate command */
        !           275:                        wdc_set_drive(chp, xfer->drive);
        !           276:                        if (wait_for_ready(chp, ata_delay) < 0)
        !           277:                                goto timeout;
        !           278:                        if (ata_bio->flags & ATA_LBA48) {
        !           279:                                wdccommandext(chp, xfer->drive, cmd,
        !           280:                                    (u_int64_t)ata_bio->blkno, nblks);
        !           281:                        } else {
        !           282:                                wdccommand(chp, xfer->drive, cmd, cyl,
        !           283:                                    head, sect, nblks, 0);
        !           284:                        }
        !           285:                        /* start the DMA channel */
        !           286:                        (*chp->wdc->dma_start)(chp->wdc->dma_arg,
        !           287:                            chp->channel, xfer->drive);
        !           288:                        chp->ch_flags |= WDCF_DMA_WAIT;
        !           289:                        /* wait for irq */
        !           290:                        goto intr;
        !           291:                } /* else not DMA */
        !           292:                ata_bio->nblks = min(nblks, ata_bio->multi);
        !           293:                ata_bio->nbytes = ata_bio->nblks * ata_bio->lp->d_secsize;
        !           294:                if (ata_bio->nblks > 1 && (ata_bio->flags & ATA_SINGLE) == 0) {
        !           295:                        if (ata_bio->flags & ATA_LBA48)
        !           296:                                cmd = (ata_bio->flags & ATA_READ) ?
        !           297:                                    WDCC_READMULTI_EXT : WDCC_WRITEMULTI_EXT;
        !           298:                        else
        !           299:                                cmd = (ata_bio->flags & ATA_READ) ?
        !           300:                                    WDCC_READMULTI : WDCC_WRITEMULTI;
        !           301:                } else {
        !           302:                        if (ata_bio->flags & ATA_LBA48)
        !           303:                                cmd = (ata_bio->flags & ATA_READ) ?
        !           304:                                    WDCC_READ_EXT : WDCC_WRITE_EXT;
        !           305:                        else
        !           306:                                cmd = (ata_bio->flags & ATA_READ) ?
        !           307:                                    WDCC_READ : WDCC_WRITE;
        !           308:                }
        !           309:                /* Initiate command! */
        !           310:                wdc_set_drive(chp, xfer->drive);
        !           311:                if (wait_for_ready(chp, ata_delay) < 0)
        !           312:                        goto timeout;
        !           313:                if (ata_bio->flags & ATA_LBA48) {
        !           314:                        wdccommandext(chp, xfer->drive, cmd,
        !           315:                            (u_int64_t)ata_bio->blkno, nblks);
        !           316:                } else {
        !           317:                        wdccommand(chp, xfer->drive, cmd, cyl,
        !           318:                            head, sect, nblks,
        !           319:                            (ata_bio->lp->d_type == DTYPE_ST506) ?
        !           320:                            ata_bio->lp->d_precompcyl / 4 : 0);
        !           321:                }
        !           322:        } else if (ata_bio->nblks > 1) {
        !           323:                /* The number of blocks in the last stretch may be smaller. */
        !           324:                nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
        !           325:                if (ata_bio->nblks > nblks) {
        !           326:                        ata_bio->nblks = nblks;
        !           327:                        ata_bio->nbytes = xfer->c_bcount;
        !           328:                }
        !           329:        }
        !           330:        /* If this was a write and not using DMA, push the data. */
        !           331:        if ((ata_bio->flags & ATA_READ) == 0) {
        !           332:                if (wait_for_drq(chp, ata_delay) != 0) {
        !           333:                        printf("%s:%d:%d: timeout waiting for DRQ, "
        !           334:                            "st=0x%b, err=0x%02x\n",
        !           335:                            chp->wdc->sc_dev.dv_xname, chp->channel,
        !           336:                            xfer->drive, chp->ch_status, WDCS_BITS,
        !           337:                            chp->ch_error);
        !           338:                        if (wdc_ata_err(drvp, ata_bio) != WDC_ATA_ERR)
        !           339:                                ata_bio->error = TIMEOUT;
        !           340:                        wdc_ata_bio_done(chp, xfer);
        !           341:                        return;
        !           342:                }
        !           343:                if (wdc_ata_err(drvp, ata_bio) == WDC_ATA_ERR) {
        !           344:                        wdc_ata_bio_done(chp, xfer);
        !           345:                        return;
        !           346:                }
        !           347:                wdc_output_bytes(drvp, (char *)xfer->databuf + xfer->c_skip,
        !           348:                    ata_bio->nbytes);
        !           349:        }
        !           350:
        !           351: intr:  /* Wait for IRQ (either real or polled) */
        !           352:        if ((ata_bio->flags & ATA_POLL) == 0) {
        !           353:                chp->ch_flags |= WDCF_IRQ_WAIT;
        !           354:        } else {
        !           355:                /* Wait for at last 400ns for status bit to be valid */
        !           356:                delay(1);
        !           357:                if (chp->ch_flags & WDCF_DMA_WAIT) {
        !           358:                        wdc_dmawait(chp, xfer, ATA_DELAY);
        !           359:                        chp->ch_flags &= ~WDCF_DMA_WAIT;
        !           360:                }
        !           361:                wdc_ata_bio_intr(chp, xfer, 0);
        !           362:                if ((ata_bio->flags & ATA_ITSDONE) == 0)
        !           363:                        goto again;
        !           364:        }
        !           365:        return;
        !           366: timeout:
        !           367:        printf("%s:%d:%d: not ready, st=0x%b, err=0x%02x\n",
        !           368:            chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
        !           369:            chp->ch_status, WDCS_BITS, chp->ch_error);
        !           370:        if (wdc_ata_err(drvp, ata_bio) != WDC_ATA_ERR)
        !           371:                ata_bio->error = TIMEOUT;
        !           372:        wdc_ata_bio_done(chp, xfer);
        !           373:        return;
        !           374: }
        !           375:
        !           376: int
        !           377: wdc_ata_bio_intr(struct channel_softc *chp, struct wdc_xfer *xfer, int irq)
        !           378: {
        !           379:        struct ata_bio *ata_bio = xfer->cmd;
        !           380:        struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
        !           381:        int drv_err;
        !           382:
        !           383:        WDCDEBUG_PRINT(("wdc_ata_bio_intr %s:%d:%d\n",
        !           384:            chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive),
        !           385:            DEBUG_INTR | DEBUG_XFERS);
        !           386:
        !           387:
        !           388:        /* Is it not a transfer, but a control operation? */
        !           389:        if (drvp->state < READY) {
        !           390:                printf("%s:%d:%d: bad state %d in wdc_ata_bio_intr\n",
        !           391:                    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
        !           392:                    drvp->state);
        !           393:                panic("wdc_ata_bio_intr: bad state");
        !           394:        }
        !           395:
        !           396:        /*
        !           397:         * reset on timeout. This will cause extra resets in the case
        !           398:         * of occasional lost interrupts
        !           399:         */
        !           400:        if (xfer->c_flags & C_TIMEOU)
        !           401:                goto timeout;
        !           402:
        !           403:        /* Ack interrupt done by wait_for_unbusy */
        !           404:        if (wait_for_unbusy(chp,
        !           405:            (irq == 0) ? ATA_DELAY : 0) < 0) {
        !           406:                if (irq)
        !           407:                        return 0; /* IRQ was not for us */
        !           408:                printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip%d\n",
        !           409:                    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
        !           410:                    xfer->c_bcount, xfer->c_skip);
        !           411:
        !           412:                goto timeout;
        !           413:        }
        !           414:        if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
        !           415:                chp->wdc->irqack(chp);
        !           416:
        !           417:        drv_err = wdc_ata_err(drvp, ata_bio);
        !           418:
        !           419:        if (xfer->c_flags & C_DMA) {
        !           420:                if (chp->wdc->dma_status != 0) {
        !           421:                        if (drv_err != WDC_ATA_ERR) {
        !           422:                                ata_bio->error = ERR_DMA;
        !           423:                                drv_err = WDC_ATA_ERR;
        !           424:                        }
        !           425:                }
        !           426:                if (chp->ch_status & WDCS_DRQ) {
        !           427:                        if (drv_err != WDC_ATA_ERR) {
        !           428:                                printf("%s:%d:%d: intr with DRQ (st=0x%b)\n",
        !           429:                                    chp->wdc->sc_dev.dv_xname, chp->channel,
        !           430:                                    xfer->drive, chp->ch_status, WDCS_BITS);
        !           431:                                ata_bio->error = TIMEOUT;
        !           432:                                drv_err = WDC_ATA_ERR;
        !           433:                        }
        !           434:                }
        !           435:                if (drv_err != WDC_ATA_ERR)
        !           436:                        goto end;
        !           437:                ata_dmaerr(drvp);
        !           438:        }
        !           439:
        !           440:        /* if we had an error, end */
        !           441:        if (drv_err == WDC_ATA_ERR) {
        !           442:                wdc_ata_bio_done(chp, xfer);
        !           443:                return 1;
        !           444:        }
        !           445:
        !           446:        /* If this was a read and not using DMA, fetch the data. */
        !           447:        if ((ata_bio->flags & ATA_READ) != 0) {
        !           448:                if ((chp->ch_status & WDCS_DRQ) != WDCS_DRQ) {
        !           449:                        printf("%s:%d:%d: read intr before drq\n",
        !           450:                            chp->wdc->sc_dev.dv_xname, chp->channel,
        !           451:                            xfer->drive);
        !           452:                        ata_bio->error = TIMEOUT;
        !           453:                        wdc_ata_bio_done(chp, xfer);
        !           454:                        return 1;
        !           455:                }
        !           456:                wdc_input_bytes(drvp, (char *)xfer->databuf + xfer->c_skip,
        !           457:                    ata_bio->nbytes);
        !           458:        }
        !           459: end:
        !           460:        ata_bio->blkno += ata_bio->nblks;
        !           461:        ata_bio->blkdone += ata_bio->nblks;
        !           462:        xfer->c_skip += ata_bio->nbytes;
        !           463:        xfer->c_bcount -= ata_bio->nbytes;
        !           464:        /* See if this transfer is complete. */
        !           465:        if (xfer->c_bcount > 0) {
        !           466:                if ((ata_bio->flags & ATA_POLL) == 0) {
        !           467:                        /* Start the next operation */
        !           468:                        _wdc_ata_bio_start(chp, xfer);
        !           469:                } else {
        !           470:                        /* Let _wdc_ata_bio_start do the loop */
        !           471:                        return 1;
        !           472:                }
        !           473:        } else { /* Done with this transfer */
        !           474:                ata_bio->error = NOERROR;
        !           475:                wdc_ata_bio_done(chp, xfer);
        !           476:        }
        !           477:        return 1;
        !           478:
        !           479: timeout:
        !           480:        if (xfer->c_flags & C_DMA)
        !           481:                ata_dmaerr(drvp);
        !           482:
        !           483:        ata_bio->error = TIMEOUT;
        !           484:        wdc_ata_bio_done(chp, xfer);
        !           485:        return 1;
        !           486: }
        !           487:
        !           488: void
        !           489: wdc_ata_bio_kill_xfer(struct channel_softc *chp, struct wdc_xfer *xfer)
        !           490: {
        !           491:        struct ata_bio *ata_bio = xfer->cmd;
        !           492:
        !           493:        timeout_del(&chp->ch_timo);
        !           494:        /* remove this command from xfer queue */
        !           495:        wdc_free_xfer(chp, xfer);
        !           496:
        !           497:        ata_bio->flags |= ATA_ITSDONE;
        !           498:        ata_bio->error = ERR_NODEV;
        !           499:        ata_bio->r_error = WDCE_ABRT;
        !           500:        if ((ata_bio->flags & ATA_POLL) == 0) {
        !           501:                WDCDEBUG_PRINT(("wdc_ata_done: wddone\n"), DEBUG_XFERS);
        !           502:                wddone(ata_bio->wd);
        !           503:        }
        !           504: }
        !           505:
        !           506: void
        !           507: wdc_ata_bio_done(struct channel_softc *chp, struct wdc_xfer *xfer)
        !           508: {
        !           509:        struct ata_bio *ata_bio = xfer->cmd;
        !           510:
        !           511:        WDCDEBUG_PRINT(("wdc_ata_bio_done %s:%d:%d: flags 0x%x\n",
        !           512:            chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
        !           513:            (u_int)xfer->c_flags),
        !           514:            DEBUG_XFERS);
        !           515:
        !           516:        timeout_del(&chp->ch_timo);
        !           517:
        !           518:        /* feed back residual bcount to our caller */
        !           519:        ata_bio->bcount = xfer->c_bcount;
        !           520:
        !           521:        /* remove this command from xfer queue */
        !           522:        wdc_free_xfer(chp, xfer);
        !           523:
        !           524:        ata_bio->flags |= ATA_ITSDONE;
        !           525:        if ((ata_bio->flags & ATA_POLL) == 0) {
        !           526:                WDCDEBUG_PRINT(("wdc_ata_done: wddone\n"), DEBUG_XFERS);
        !           527:                wddone(ata_bio->wd);
        !           528:        }
        !           529:        WDCDEBUG_PRINT(("wdcstart from wdc_ata_done, flags 0x%x\n",
        !           530:            chp->ch_flags), DEBUG_XFERS);
        !           531:        wdcstart(chp);
        !           532: }
        !           533:
        !           534: /*
        !           535:  * Implement operations needed before read/write.
        !           536:  */
        !           537: int
        !           538: wdc_ata_ctrl_intr(struct channel_softc *chp, struct wdc_xfer *xfer, int irq)
        !           539: {
        !           540:        struct ata_bio *ata_bio = xfer->cmd;
        !           541:        struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
        !           542:        char *errstring = NULL;
        !           543:        int delay = (irq == 0) ? ATA_DELAY : 0;
        !           544:
        !           545:        WDCDEBUG_PRINT(("wdc_ata_ctrl_intr: state %d\n", drvp->state),
        !           546:            DEBUG_FUNCS);
        !           547:
        !           548: again:
        !           549:        switch (drvp->state) {
        !           550:        case RECAL:    /* Should not be in this state here */
        !           551:                panic("wdc_ata_ctrl_intr: state==RECAL");
        !           552:                break;
        !           553:
        !           554:        case RECAL_WAIT:
        !           555:                errstring = "recal";
        !           556:                if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay))
        !           557:                        goto timeout;
        !           558:                if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
        !           559:                        chp->wdc->irqack(chp);
        !           560:                if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
        !           561:                        goto error;
        !           562:        /* FALLTHROUGH */
        !           563:
        !           564:        case PIOMODE:
        !           565:                /* Don't try to set modes if controller can't be adjusted */
        !           566:                if ((chp->wdc->cap & WDC_CAPABILITY_MODE) == 0)
        !           567:                        goto geometry;
        !           568:                /* Also don't try if the drive didn't report its mode */
        !           569:                if ((drvp->drive_flags & DRIVE_MODE) == 0)
        !           570:                        goto geometry;
        !           571:                /* SET FEATURES 0x08 is only for PIO mode > 2 */
        !           572:                if (drvp->PIO_mode <= 2)
        !           573:                        goto geometry;
        !           574:                wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
        !           575:                    0x08 | drvp->PIO_mode, WDSF_SET_MODE);
        !           576:                drvp->state = PIOMODE_WAIT;
        !           577:                break;
        !           578:
        !           579:        case PIOMODE_WAIT:
        !           580:                errstring = "piomode";
        !           581:                if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay))
        !           582:                        goto timeout;
        !           583:                if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
        !           584:                        chp->wdc->irqack(chp);
        !           585:                if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
        !           586:                        goto error;
        !           587:        /* FALLTHROUGH */
        !           588:
        !           589:        case DMAMODE:
        !           590:                if (drvp->drive_flags & DRIVE_UDMA) {
        !           591:                        wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
        !           592:                            0x40 | drvp->UDMA_mode, WDSF_SET_MODE);
        !           593:                } else if (drvp->drive_flags & DRIVE_DMA) {
        !           594:                        wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
        !           595:                            0x20 | drvp->DMA_mode, WDSF_SET_MODE);
        !           596:                } else {
        !           597:                        goto geometry;
        !           598:                }
        !           599:                drvp->state = DMAMODE_WAIT;
        !           600:                break;
        !           601:        case DMAMODE_WAIT:
        !           602:                errstring = "dmamode";
        !           603:                if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay))
        !           604:                        goto timeout;
        !           605:                if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
        !           606:                        chp->wdc->irqack(chp);
        !           607:                if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
        !           608:                        goto error;
        !           609:        /* FALLTHROUGH */
        !           610:
        !           611:        case GEOMETRY:
        !           612:        geometry:
        !           613:                if (ata_bio->flags & ATA_LBA)
        !           614:                        goto multimode;
        !           615:                wdccommand(chp, xfer->drive, WDCC_IDP,
        !           616:                    ata_bio->lp->d_ncylinders,
        !           617:                    ata_bio->lp->d_ntracks - 1, 0, ata_bio->lp->d_nsectors,
        !           618:                    (ata_bio->lp->d_type == DTYPE_ST506) ?
        !           619:                        ata_bio->lp->d_precompcyl / 4 : 0);
        !           620:                drvp->state = GEOMETRY_WAIT;
        !           621:                break;
        !           622:
        !           623:        case GEOMETRY_WAIT:
        !           624:                errstring = "geometry";
        !           625:                if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay))
        !           626:                        goto timeout;
        !           627:                if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
        !           628:                        chp->wdc->irqack(chp);
        !           629:                if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
        !           630:                        goto error;
        !           631:                /* FALLTHROUGH */
        !           632:
        !           633:        case MULTIMODE:
        !           634:        multimode:
        !           635:                if (ata_bio->multi == 1)
        !           636:                        goto ready;
        !           637:                wdccommand(chp, xfer->drive, WDCC_SETMULTI, 0, 0, 0,
        !           638:                    ata_bio->multi, 0);
        !           639:                drvp->state = MULTIMODE_WAIT;
        !           640:                break;
        !           641:
        !           642:        case MULTIMODE_WAIT:
        !           643:                errstring = "setmulti";
        !           644:                if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay))
        !           645:                        goto timeout;
        !           646:                if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
        !           647:                        chp->wdc->irqack(chp);
        !           648:                if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
        !           649:                        goto error;
        !           650:                /* FALLTHROUGH */
        !           651:
        !           652:        case READY:
        !           653:        ready:
        !           654:                drvp->state = READY;
        !           655:                /*
        !           656:                 * The drive is usable now
        !           657:                 */
        !           658:                xfer->c_intr = wdc_ata_bio_intr;
        !           659:                _wdc_ata_bio_start(chp, xfer);
        !           660:                return 1;
        !           661:        }
        !           662:
        !           663:        if ((ata_bio->flags & ATA_POLL) == 0) {
        !           664:                chp->ch_flags |= WDCF_IRQ_WAIT;
        !           665:        } else {
        !           666:                goto again;
        !           667:        }
        !           668:        return 1;
        !           669:
        !           670: timeout:
        !           671:        if (irq && (xfer->c_flags & C_TIMEOU) == 0) {
        !           672:                return 0; /* IRQ was not for us */
        !           673:        }
        !           674:        printf("%s:%d:%d: %s timed out\n",
        !           675:            chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, errstring);
        !           676:        ata_bio->error = TIMEOUT;
        !           677:        drvp->state = 0;
        !           678:        wdc_ata_bio_done(chp, xfer);
        !           679:        return 0;
        !           680: error:
        !           681:        printf("%s:%d:%d: %s ",
        !           682:            chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
        !           683:            errstring);
        !           684:        if (chp->ch_status & WDCS_DWF) {
        !           685:                printf("drive fault\n");
        !           686:                ata_bio->error = ERR_DF;
        !           687:        } else {
        !           688:                printf("error (%x)\n", chp->ch_error);
        !           689:                ata_bio->r_error = chp->ch_error;
        !           690:                ata_bio->error = ERROR;
        !           691:        }
        !           692:        drvp->state = 0;
        !           693:        wdc_ata_bio_done(chp, xfer);
        !           694:        return 1;
        !           695: }
        !           696:
        !           697: int
        !           698: wdc_ata_err(struct ata_drive_datas *drvp, struct ata_bio *ata_bio)
        !           699: {
        !           700:        struct channel_softc *chp = drvp->chnl_softc;
        !           701:        ata_bio->error = 0;
        !           702:        if (chp->ch_status & WDCS_BSY) {
        !           703:                ata_bio->error = TIMEOUT;
        !           704:                return WDC_ATA_ERR;
        !           705:        }
        !           706:
        !           707:        if (chp->ch_status & WDCS_DWF) {
        !           708:                ata_bio->error = ERR_DF;
        !           709:                return WDC_ATA_ERR;
        !           710:        }
        !           711:
        !           712:        if (chp->ch_status & WDCS_ERR) {
        !           713:                ata_bio->error = ERROR;
        !           714:                ata_bio->r_error = chp->ch_error;
        !           715:                if (drvp->drive_flags & DRIVE_UDMA &&
        !           716:                    (ata_bio->r_error & WDCE_CRC)) {
        !           717:                        /*
        !           718:                         * Record the CRC error, to avoid downgrading to
        !           719:                         * multiword DMA
        !           720:                         */
        !           721:                        drvp->drive_flags |= DRIVE_DMAERR;
        !           722:                }
        !           723:                if (ata_bio->r_error & (WDCE_BBK | WDCE_UNC | WDCE_IDNF |
        !           724:                    WDCE_ABRT | WDCE_TK0NF | WDCE_AMNF))
        !           725:                        return WDC_ATA_ERR;
        !           726:                return WDC_ATA_NOERR;
        !           727:        }
        !           728:
        !           729:        if (chp->ch_status & WDCS_CORR)
        !           730:                ata_bio->flags |= ATA_CORR;
        !           731:        return WDC_ATA_NOERR;
        !           732: }
        !           733:
        !           734: #if 0
        !           735: int
        !           736: wdc_ata_addref(drvp)
        !           737:        struct ata_drive_datas *drvp;
        !           738: {
        !           739:        struct channel_softc *chp = drvp->chnl_softc;
        !           740:
        !           741:        return (wdc_addref(chp));
        !           742: }
        !           743:
        !           744: void
        !           745: wdc_ata_delref(drvp)
        !           746:        struct ata_drive_datas *drvp;
        !           747: {
        !           748:        struct channel_softc *chp = drvp->chnl_softc;
        !           749:
        !           750:        wdc_delref(chp);
        !           751: }
        !           752: #endif

CVSweb