[BACK]Return to ata_wdc.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / ata

Annotation of src/sys/dev/ata/ata_wdc.c, Revision 1.6

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

CVSweb <webmaster@jp.NetBSD.org>