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

Annotation of src/sys/dev/ic/wdc.c, Revision 1.6.2.2

1.6.2.2 ! mellon      1: /*     $NetBSD: wdc.c,v 1.6.2.1 1997/10/27 20:02:03 mellon Exp $ */
1.2       bouyer      2:
                      3: /*
                      4:  * Copyright (c) 1994, 1995 Charles M. Hannum.  All rights reserved.
                      5:  *
                      6:  * DMA and multi-sector PIO handling are derived from code contributed by
                      7:  * Onno van der Linden.
                      8:  *
                      9:  * Atapi support added by Manuel Bouyer.
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *     This product includes software developed by Charles M. Hannum.
                     22:  * 4. The name of the author may not be used to endorse or promote products
                     23:  *    derived from this software without specific prior written permission.
                     24:  *
                     25:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     26:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     27:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     28:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     29:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     30:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     31:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     32:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     33:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     34:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     35:  */
                     36:
                     37: #include <sys/param.h>
                     38: #include <sys/systm.h>
                     39: #include <sys/kernel.h>
                     40: #include <sys/conf.h>
                     41: #include <sys/file.h>
                     42: #include <sys/stat.h>
                     43: #include <sys/ioctl.h>
                     44: #include <sys/buf.h>
                     45: #include <sys/uio.h>
                     46: #include <sys/malloc.h>
                     47: #include <sys/device.h>
                     48: #include <sys/disklabel.h>
                     49: #include <sys/disk.h>
                     50: #include <sys/syslog.h>
                     51: #include <sys/proc.h>
                     52:
                     53: #include <vm/vm.h>
                     54:
                     55: #include <machine/cpu.h>
                     56: #include <machine/intr.h>
                     57: #include <machine/bus.h>
                     58: #include <machine/pio.h>
                     59:
                     60: #include <dev/isa/isavar.h>
                     61: #include <dev/isa/isadmavar.h>
                     62: #include <dev/isa/wdreg.h>
                     63: #include <dev/isa/wdlink.h>
                     64: #include "atapibus.h"
                     65: #include "wd.h"
                     66:
                     67: #if NATAPIBUS > 0
                     68: #include <dev/scsipi/scsipi_all.h>
                     69: #include <dev/scsipi/atapiconf.h>
                     70: #endif
                     71:
                     72: #define        WAITTIME        (10 * hz)       /* time to wait for a completion */
                     73:        /* this is a lot for hard drives, but not for cdroms */
                     74: #define RECOVERYTIME hz/2
                     75: #define WDCDELAY       100
                     76: #define WDCNDELAY      100000  /* delay = 100us; so 10s for a controller state change */
                     77: #if 0
                     78: /* If you enable this, it will report any delays more than 100us * N long. */
                     79: #define WDCNDELAY_DEBUG        50
                     80: #endif
                     81:
                     82: #define        WDIORETRIES     5               /* number of retries before giving up */
                     83:
                     84: #define        WDPART(dev)                     DISKPART(dev)
                     85:
                     86: LIST_HEAD(xfer_free_list, wdc_xfer) xfer_free_list;
                     87:
                     88: int    wdcprobe        __P((struct device *, void *, void *));
                     89: void   wdcattach       __P((struct device *, struct device *, void *));
                     90: int    wdcintr         __P((void *));
                     91:
                     92: struct cfattach wdc_ca = {
                     93:        sizeof(struct wdc_softc), wdcprobe, wdcattach
                     94: };
                     95:
                     96: struct cfdriver wdc_cd = {
                     97:        NULL, "wdc", DV_DULL
                     98: };
                     99:
                    100: void   wdcstart        __P((struct wdc_softc *));
                    101: int            wdcreset        __P((struct wdc_softc *, int));
                    102: #define VERBOSE 1
                    103: #define SILENT 0
                    104: void   wdcrestart      __P((void *arg));
                    105: void   wdcunwedge      __P((struct wdc_softc *));
                    106: void   wdctimeout      __P((void *arg));
                    107: int            wdccontrol      __P((struct wdc_softc*, struct wd_link *));
                    108: void   wdc_free_xfer   __P((struct wdc_xfer *));
                    109: void   wdcerror        __P((struct wdc_softc*, char *));
                    110: void   wdcbit_bucket   __P(( struct wdc_softc *, int));
                    111: #if NWD > 0
                    112: int            wdprint                 __P((void *, const char *));
                    113: int            wdsetctlr               __P((struct wd_link *));
                    114: int            wdc_ata_intr    __P((struct wdc_softc *,struct wdc_xfer *));
                    115: void   wdc_ata_start   __P((struct wdc_softc *,struct wdc_xfer *));
                    116: void   wdc_ata_done    __P((struct wdc_softc *, struct wdc_xfer *));
                    117: #endif /* NWD > 0 */
                    118: #if NATAPIBUS > 0
                    119: void   wdc_atapi_minphys __P((struct buf *bp));
                    120: void   wdc_atapi_start __P((struct wdc_softc *,struct wdc_xfer *));
                    121: int            wdc_atapi_intr  __P((struct wdc_softc *, struct wdc_xfer *));
                    122: void   wdc_atapi_done  __P((struct wdc_softc *, struct wdc_xfer *));
                    123: int            wdc_atapi_send_command_packet __P((struct scsipi_xfer *sc_xfer));
                    124: #define MAX_SIZE MAXPHYS /* XXX */
                    125: #endif
                    126:
1.6.2.2 ! mellon    127: #ifdef ATAPI_DEBUG2
1.2       bouyer    128: static int wdc_nxfer;
                    129: #endif
                    130:
                    131: #ifdef WDDEBUG
                    132: #define WDDEBUG_PRINT(args)    printf args
                    133: #else
                    134: #define WDDEBUG_PRINT(args)
                    135: #endif
                    136:
                    137: #if NATAPIBUS > 0
                    138: static struct scsipi_adapter wdc_switch  = {
                    139:        wdc_atapi_send_command_packet,
                    140:        wdc_atapi_minphys,
                    141:        0,
                    142:        0
                    143: };
                    144: #endif
                    145:
                    146: int
                    147: wdcprobe(parent, match, aux)
                    148:        struct device *parent;
                    149:        void *match, *aux;
                    150: {
                    151:        struct wdc_softc *wdc = match;
                    152:        struct isa_attach_args *ia = aux;
                    153:        int iobase;
                    154:
                    155:        wdc->sc_iobase = iobase = ia->ia_iobase;
                    156:
1.6.2.1   mellon    157:        if (wdcreset(wdc, SILENT) != 0) {
1.2       bouyer    158:                /*
1.6.2.1   mellon    159:                 * if the reset failed, there is no master. test for ATAPI signature
                    160:                 * on the slave device. If no ATAPI slave, wait 5s and retry a reset.
1.2       bouyer    161:                 */
                    162:                outb(iobase+wd_sdh, WDSD_IBM | 0x10); /* slave */
1.6.2.1   mellon    163:                if (inb(iobase + wd_cyl_lo) == 0x14 &&
                    164:                        inb(iobase + wd_cyl_hi) == 0xeb) {
                    165:                        wdc->sc_flags |= WDCF_ONESLAVE;
                    166:                        goto drivefound;
                    167:                } else {
1.2       bouyer    168:                        delay(500000);
                    169:                        if (wdcreset(wdc, SILENT) != 0)
                    170:                                return 0;
                    171:                }
1.6.2.1   mellon    172:        }
                    173:        /* reset succeeded. Test registers */
                    174:        if (inb(iobase + wd_cyl_lo) == 0x14 &&
                    175:                inb(iobase + wd_cyl_hi) == 0xeb)
                    176:                goto drivefound;
                    177:        /* not ATAPI. Test registers */
                    178:        outb(iobase+wd_error, 0x58);    /* Error register not writable, */
                    179:        outb(iobase+wd_cyl_lo, 0xa5);   /* but all of cyllo are. */
                    180:        if (inb(iobase+wd_error) != 0x58 && inb(iobase+wd_cyl_lo) == 0xa5)
                    181:                goto drivefound;
                    182:        /* No master. Test atapi signature on slave */
                    183:        outb(iobase+wd_sdh, WDSD_IBM | 0x10);
                    184:        if (inb(iobase + wd_cyl_lo) == 0x14 &&
                    185:                inb(iobase + wd_cyl_hi) == 0xeb) {
1.2       bouyer    186:                wdc->sc_flags |= WDCF_ONESLAVE;
1.6.2.1   mellon    187:                goto drivefound;
1.2       bouyer    188:        }
1.6.2.1   mellon    189:        return 0;
                    190: drivefound:
1.2       bouyer    191:        /* Select drive 0 or ATAPI slave device */
                    192:        if (wdc->sc_flags & WDCF_ONESLAVE)
                    193:                outb(iobase+wd_sdh, WDSD_IBM | 0x10);
                    194:        else
                    195:                outb(iobase+wd_sdh, WDSD_IBM);
                    196:
                    197:        /* Wait for controller to become ready. */
                    198:        if (wait_for_unbusy(wdc) < 0)
                    199:                return 0;
                    200:
                    201:        /* Start drive diagnostics. */
                    202:        outb(iobase+wd_command, WDCC_DIAGNOSE);
                    203:
                    204:        /* Wait for command to complete. */
                    205:        if (wait_for_unbusy(wdc) < 0)
                    206:                return 0;
                    207:
                    208:        ia->ia_iosize = 8;
                    209:        ia->ia_msize = 0;
                    210:        return 1;
                    211: }
                    212:
                    213: void
                    214: wdcattach(parent, self, aux)
                    215:        struct device *parent, *self;
                    216:        void *aux;
                    217: {
                    218:        struct wdc_softc *wdc = (void *)self;
                    219:        struct isa_attach_args *ia = aux;
                    220: #if NWD > 0
                    221:        int drive;
                    222: #endif
                    223:
                    224:        TAILQ_INIT(&wdc->sc_xfer);
                    225:        wdc->sc_drq = ia->ia_drq;
                    226:
                    227:        printf("\n");
                    228:        if (wdc->sc_drq != -1) {
                    229:                if (isa_dmamap_create(parent, wdc->sc_drq, MAXPHYS,
                    230:                        BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
                    231:                                printf("%s: can't create map for drq %d\n",
                    232:                                        wdc->sc_dev.dv_xname, wdc->sc_drq);
                    233:                                wdc->sc_drq = -1;
                    234:                }
                    235:        }
                    236:
                    237:        wdc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
                    238:            IPL_BIO, wdcintr, wdc);
                    239:
1.6.2.2 ! mellon    240: #ifdef ATAPI_DEBUG2
1.2       bouyer    241:        wdc_nxfer = 0;
                    242: #endif
                    243:
                    244: #if NATAPIBUS > 0
                    245:        /*
                    246:         * Attach an ATAPI bus, if configured.
                    247:         */
                    248:        wdc->ab_link = malloc(sizeof(struct scsipi_link), M_DEVBUF, M_NOWAIT);
                    249:        if (wdc->ab_link == NULL) {
                    250:                printf("%s: can't allocate ATAPI link\n", self->dv_xname);
                    251:                return;
                    252:        }
                    253:        bzero(wdc->ab_link,sizeof(struct scsipi_link));
                    254:        wdc->ab_link->type = BUS_ATAPI;
                    255:        wdc->ab_link->openings = 1;
                    256:        wdc->ab_link->scsipi_atapi.type = ATAPI;
                    257:        wdc->ab_link->scsipi_atapi.channel = 0;
                    258:        wdc->ab_link->adapter_softc = (caddr_t)wdc;
                    259:        wdc->ab_link->adapter = &wdc_switch;
                    260:        (void)config_found(self, (void *)wdc->ab_link, NULL);
                    261: #endif /* NATAPIBUS > 0 */
                    262: #if NWD > 0
                    263:        /*
                    264:         * Attach standard IDE/ESDI/etc. disks to the controller.
                    265:         */
                    266:        for (drive = 0; drive < 2; drive++) {
1.4       bouyer    267:                /* if a disk is already present, skip */
                    268:                if ((wdc->sc_drives_mask & (1 << drive)) != 0) {
                    269:                        continue;
                    270:                }
1.2       bouyer    271:                /* controller active while autoconf */
                    272:                wdc->sc_flags |= WDCF_ACTIVE;
                    273:
                    274:                if (wdccommandshort(wdc, drive, WDCC_RECAL) != 0 ||
                    275:                    wait_for_ready(wdc) != 0) {
                    276:                        wdc->d_link[drive] = NULL;
                    277:                        wdc->sc_flags &= ~WDCF_ACTIVE;
                    278:                } else {
                    279:                        wdc->sc_flags &= ~WDCF_ACTIVE;
                    280:                        wdc->d_link[drive] = malloc(sizeof(struct wd_link),
                    281:                            M_DEVBUF, M_NOWAIT);
                    282:                        if (wdc->d_link[drive] == NULL) {
                    283:                                printf("%s: can't allocate link for drive %d\n",
                    284:                                    self->dv_xname, drive);
                    285:                                continue;
                    286:                        }
                    287:                        bzero(wdc->d_link[drive],sizeof(struct wd_link));
                    288:                        wdc->d_link[drive]->type = ATA;
                    289:                        wdc->d_link[drive]->wdc_softc =(caddr_t) wdc;
                    290:                        wdc->d_link[drive]->drive = drive;
                    291:                        if (wdc->sc_drq != DRQUNK)
                    292:                                wdc->d_link[drive]->sc_mode = WDM_DMA;
                    293:                        else
                    294:                                wdc->d_link[drive]->sc_mode = 0;
                    295:
1.4       bouyer    296:                        wdc->sc_drives_mask |= (1 << drive);
1.2       bouyer    297:                        (void)config_found(self, (void *)wdc->d_link[drive],
                    298:                            wdprint);
                    299:                }
                    300:        }
                    301: #endif /* NWD > 0 */
1.6.2.1   mellon    302:        /* explicitely select an existing drive, to avoid spurious interrupts */
                    303:        if (wdc->sc_flags & WDCF_ONESLAVE)
                    304:                outb(wdc->sc_iobase+wd_sdh, WDSD_IBM | 0x10); /* slave */
                    305:        else
                    306:                outb(wdc->sc_iobase+wd_sdh, WDSD_IBM); /* master */
1.6.2.2 ! mellon    307:        /*
        !           308:         * Reset controller. The probe, with some combinations of ATA/ATAPI
        !           309:         * device keep it in a mostly working, but strange state (with busy
        !           310:         * led on)
        !           311:         */
        !           312:        wdcreset(wdc, VERBOSE);
1.2       bouyer    313: }
                    314:
                    315: /*
                    316:  * Start I/O on a controller.  This does the calculation, and starts a read or
                    317:  * write operation.  Called to from wdstart() to start a transfer, from
                    318:  * wdcintr() to continue a multi-sector transfer or start the next transfer, or
                    319:  * wdcrestart() after recovering from an error.
                    320:  */
                    321: void
                    322: wdcstart(wdc)
                    323:        struct wdc_softc *wdc;
                    324: {
                    325:        struct wdc_xfer *xfer;
                    326:
                    327:        if ((wdc->sc_flags & WDCF_ACTIVE) != 0 ) {
                    328:                WDDEBUG_PRINT(("wdcstart: already active\n"));
                    329:                return; /* controller aleady active */
                    330:        }
                    331: #ifdef DIAGNOSTIC
                    332:        if ((wdc->sc_flags & WDCF_IRQ_WAIT) != 0)
                    333:                panic("wdcstart: controller waiting for irq\n");
                    334: #endif
                    335:        /* is there a xfer ? */
                    336:        xfer = wdc->sc_xfer.tqh_first;
                    337:        if (xfer == NULL) {
                    338: #ifdef ATAPI_DEBUG2
                    339:                printf("wdcstart: null xfer\n");
                    340: #endif
                    341:                /*
                    342:                 * XXX
                    343:                 * This is a kluge.  See comments in wd_get_parms().
                    344:                 */
                    345:                if ((wdc->sc_flags & WDCF_WANTED) != 0) {
1.6.2.2 ! mellon    346: #ifdef ATAPI_DEBUG2
1.2       bouyer    347:                        printf("WDCF_WANTED\n");
                    348: #endif
                    349:                        wdc->sc_flags &= ~WDCF_WANTED;
                    350:                        wakeup(wdc);
                    351:                }
                    352:                return;
                    353:        }
                    354:        wdc->sc_flags |= WDCF_ACTIVE;
                    355: #ifdef ATAPI_DEBUG2
                    356:                printf("wdcstart: drive %d\n", (int)xfer->d_link->drive);
                    357: #endif
                    358:     outb(wdc->sc_iobase+wd_sdh, WDSD_IBM | xfer->d_link->drive << 4);
                    359: #if NATAPIBUS > 0 && NWD > 0
                    360:        if (xfer->c_flags & C_ATAPI) {
                    361: #ifdef ATAPI_DEBUG_WDC
                    362:                printf("wdcstart: atapi\n");
                    363: #endif
                    364:                wdc_atapi_start(wdc,xfer);
                    365:        } else
                    366:                wdc_ata_start(wdc,xfer);
                    367: #else /* NATAPIBUS > 0 && NWD > 0 */
                    368: #if NATAPIBUS > 0
                    369: #ifdef ATAPI_DEBUG_WDC
                    370:        printf("wdcstart: atapi\n");
                    371: #endif
                    372:        wdc_atapi_start(wdc,xfer);
                    373: #endif /* NATAPIBUS > */
                    374: #if NWD > 0
                    375:        wdc_ata_start(wdc,xfer);
                    376: #endif /* NWD > 0 */
                    377: #endif /* NATAPIBUS > 0 && NWD > 0 */
                    378: }
                    379:
                    380: #if NWD > 0
                    381: int
                    382: wdprint(aux, wdc)
                    383:        void *aux;
                    384:        const char *wdc;
                    385: {
                    386:        struct wd_link *d_link = aux;
                    387:
                    388:        if (!wdc)
                    389:                printf(" drive %d", d_link->drive);
                    390:        return QUIET;
                    391: }
                    392:
                    393: void
                    394: wdc_ata_start(wdc, xfer)
                    395:        struct wdc_softc *wdc;
                    396:        struct wdc_xfer *xfer;
                    397: {
                    398:        struct wd_link *d_link;
                    399:        struct buf *bp = xfer->c_bp;
                    400:        int nblks;
                    401:
                    402:        d_link=xfer->d_link;
                    403:
                    404:        if (wdc->sc_errors >= WDIORETRIES) {
                    405:                wderror(d_link, bp, "wdc_ata_start hard error");
                    406:                xfer->c_flags |= C_ERROR;
                    407:                wdc_ata_done(wdc, xfer);
                    408:                return;
                    409:        }
                    410:
                    411:        /* Do control operations specially. */
                    412:        if (d_link->sc_state < READY) {
                    413:                /*
                    414:                 * Actually, we want to be careful not to mess with the control
                    415:                 * state if the device is currently busy, but we can assume
                    416:                 * that we never get to this point if that's the case.
                    417:                 */
                    418:                if (wdccontrol(wdc, d_link) == 0) {
                    419:                        /* The drive is busy.  Wait. */
                    420:                        return;
                    421:                }
                    422:        }
                    423:
                    424:        /*
                    425:         * WDCF_ERROR is set by wdcunwedge() and wdcintr() when an error is
                    426:         * encountered.  If we are in multi-sector mode, then we switch to
                    427:         * single-sector mode and retry the operation from the start.
                    428:         */
                    429:        if (wdc->sc_flags & WDCF_ERROR) {
                    430:                wdc->sc_flags &= ~WDCF_ERROR;
                    431:                if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
                    432:                        wdc->sc_flags |= WDCF_SINGLE;
                    433:                        xfer->c_skip = 0;
                    434:                }
                    435:        }
                    436:
                    437:
                    438:        /* When starting a transfer... */
                    439:        if (xfer->c_skip == 0) {
                    440:                daddr_t blkno;
                    441:
                    442:                WDDEBUG_PRINT(("\n%s: wdc_ata_start %s %d@%d; map ",
                    443:                    wdc->sc_dev.dv_xname,
                    444:                    (xfer->c_flags & B_READ) ? "read" : "write",
                    445:                    xfer->c_bcount, xfer->c_blkno));
                    446:
                    447:                blkno = xfer->c_blkno+xfer->c_p_offset;
                    448:                xfer->c_blkno = blkno / (d_link->sc_lp->d_secsize / DEV_BSIZE);
                    449:        } else {
                    450:                WDDEBUG_PRINT((" %d)%x", xfer->c_skip,
                    451:                    inb(wdc->sc_iobase + wd_altsts)));
                    452:        }
                    453:
                    454:        /*
                    455:         * When starting a multi-sector transfer, or doing single-sector
                    456:         * transfers...
                    457:         */
                    458:        if (xfer->c_skip == 0 || (wdc->sc_flags & WDCF_SINGLE) != 0 ||
                    459:            d_link->sc_mode == WDM_DMA) {
                    460:                daddr_t blkno = xfer->c_blkno;
                    461:                long cylin, head, sector;
                    462:                int command;
                    463:
                    464:                if ((wdc->sc_flags & WDCF_SINGLE) != 0)
                    465:                        nblks = 1;
                    466:                else if (d_link->sc_mode != WDM_DMA)
                    467:                        nblks = xfer->c_bcount / d_link->sc_lp->d_secsize;
                    468:                else
                    469:                        nblks =
                    470:                            min(xfer->c_bcount / d_link->sc_lp->d_secsize, 8);
                    471:
                    472:                /* Check for bad sectors and adjust transfer, if necessary. */
                    473:                if ((d_link->sc_lp->d_flags & D_BADSECT) != 0
                    474: #ifdef B_FORMAT
                    475:                    && (bp->b_flags & B_FORMAT) == 0
                    476: #endif
                    477:                    ) {
                    478:                        long blkdiff;
                    479:                        int i;
                    480:
                    481:                        for (i = 0;
                    482:                            (blkdiff = d_link->sc_badsect[i]) != -1; i++) {
                    483:                                blkdiff -= blkno;
                    484:                                if (blkdiff < 0)
                    485:                                        continue;
                    486:                                if (blkdiff == 0) {
                    487:                                        /* Replace current block of transfer. */
                    488:                                        blkno =
                    489:                                            d_link->sc_lp->d_secperunit -
                    490:                                            d_link->sc_lp->d_nsectors - i - 1;
                    491:                                }
                    492:                                if (blkdiff < nblks) {
                    493:                                        /* Bad block inside transfer. */
                    494:                                        wdc->sc_flags |= WDCF_SINGLE;
                    495:                                        nblks = 1;
                    496:                                }
                    497:                                break;
                    498:                        }
                    499:                        /* Tranfer is okay now. */
                    500:                }
                    501:
                    502:                if ((d_link->sc_params.wdp_capabilities & WD_CAP_LBA) != 0) {
                    503:                        sector = (blkno >> 0) & 0xff;
                    504:                        cylin = (blkno >> 8) & 0xffff;
                    505:                        head = (blkno >> 24) & 0xf;
                    506:                        head |= WDSD_LBA;
                    507:                } else {
                    508:                        sector = blkno % d_link->sc_lp->d_nsectors;
                    509:                        sector++;       /* Sectors begin with 1, not 0. */
                    510:                        blkno /= d_link->sc_lp->d_nsectors;
                    511:                        head = blkno % d_link->sc_lp->d_ntracks;
                    512:                        blkno /= d_link->sc_lp->d_ntracks;
                    513:                        cylin = blkno;
                    514:                        head |= WDSD_CHS;
                    515:                }
                    516:
                    517:                if (d_link->sc_mode == WDM_PIOSINGLE ||
                    518:                    (wdc->sc_flags & WDCF_SINGLE) != 0)
                    519:                        xfer->c_nblks = 1;
                    520:                else if (d_link->sc_mode == WDM_PIOMULTI)
                    521:                        xfer->c_nblks = min(nblks, d_link->sc_multiple);
                    522:                else
                    523:                        xfer->c_nblks = nblks;
                    524:                xfer->c_nbytes = xfer->c_nblks * d_link->sc_lp->d_secsize;
                    525:
                    526: #ifdef B_FORMAT
                    527:                if (bp->b_flags & B_FORMAT) {
                    528:                        sector = d_link->sc_lp->d_gap3;
                    529:                        nblks = d_link->sc_lp->d_nsectors;
                    530:                        command = WDCC_FORMAT;
                    531:                } else
                    532: #endif
                    533:                switch (d_link->sc_mode) {
                    534:                case WDM_DMA:
                    535:                        command = (xfer->c_flags & B_READ) ?
                    536:                            WDCC_READDMA : WDCC_WRITEDMA;
                    537:                        /* Start the DMA channel. */
                    538:                        isa_dmastart(wdc->sc_dev.dv_parent, wdc->sc_drq,
                    539:                                xfer->databuf + xfer->c_skip, xfer->c_nbytes,
                    540:                                NULL,
                    541:                                xfer->c_flags & B_READ ? DMAMODE_READ : DMAMODE_WRITE,
                    542:                                BUS_DMA_NOWAIT);
                    543:                        break;
                    544:
                    545:                case WDM_PIOMULTI:
                    546:                        command = (xfer->c_flags & B_READ) ?
                    547:                            WDCC_READMULTI : WDCC_WRITEMULTI;
                    548:                        break;
                    549:
                    550:                case WDM_PIOSINGLE:
                    551:                        command = (xfer->c_flags & B_READ) ?
                    552:                            WDCC_READ : WDCC_WRITE;
                    553:                        break;
                    554:
                    555:                default:
                    556: #ifdef DIAGNOSTIC
                    557:                        panic("bad wd mode");
                    558: #endif
                    559:                        return;
                    560:                }
                    561:
                    562:                /* Initiate command! */
                    563:                if (wdccommand(wdc, d_link, command, d_link->drive,
                    564:                    cylin, head, sector, nblks) != 0) {
                    565:                        wderror(d_link, NULL,
                    566:                            "wdc_ata_start: timeout waiting for unbusy");
                    567:                        wdcunwedge(wdc);
                    568:                        return;
                    569:                }
                    570:
                    571:                WDDEBUG_PRINT(("sector %d cylin %d head %d addr %x sts %x\n",
                    572:                    sector, cylin, head, xfer->databuf,
                    573:                    inb(wdc->sc_iobase + wd_altsts)));
                    574:
                    575:        } else if (xfer->c_nblks > 1) {
                    576:                /* The number of blocks in the last stretch may be smaller. */
                    577:                nblks = xfer->c_bcount / d_link->sc_lp->d_secsize;
                    578:                if (xfer->c_nblks > nblks) {
                    579:                        xfer->c_nblks = nblks;
                    580:                        xfer->c_nbytes = xfer->c_bcount;
                    581:                }
                    582:        }
                    583:
                    584:        /* If this was a write and not using DMA, push the data. */
                    585:        if (d_link->sc_mode != WDM_DMA &&
                    586:            (xfer->c_flags & (B_READ|B_WRITE)) == B_WRITE) {
                    587:                if (wait_for_drq(wdc) < 0) {
                    588:                        wderror(d_link, NULL,
                    589:                            "wdc_ata_start: timeout waiting for drq");
                    590:                        wdcunwedge(wdc);
                    591:                        return;
                    592:                }
                    593:
                    594:                /* Push out data. */
                    595:                if ((d_link->sc_flags & WDF_32BIT) == 0)
                    596:                        outsw(wdc->sc_iobase + wd_data,
                    597:                            xfer->databuf + xfer->c_skip,
                    598:                            xfer->c_nbytes >> 1);
                    599:                else
                    600:                        outsl(wdc->sc_iobase + wd_data,
                    601:                            xfer->databuf + xfer->c_skip,
                    602:                            xfer->c_nbytes >> 2);
                    603:        }
                    604:
                    605:        wdc->sc_flags |= WDCF_IRQ_WAIT;
                    606:        WDDEBUG_PRINT(("wdc_ata_start: timeout "));
                    607:        timeout(wdctimeout, wdc, WAITTIME);
                    608:        WDDEBUG_PRINT(("done\n"));
                    609: }
                    610:
                    611: int
                    612: wdc_ata_intr(wdc,xfer)
                    613:        struct wdc_softc *wdc;
                    614:        struct wdc_xfer *xfer;
                    615: {
                    616:        struct wd_link *d_link;
                    617:
                    618:        d_link = xfer->d_link;
                    619:
                    620:        if (wait_for_unbusy(wdc) < 0) {
                    621:                wdcerror(wdc, "wdcintr: timeout waiting for unbusy");
1.5       bouyer    622:                return 0;
1.2       bouyer    623:        }
                    624:
1.6.2.2 ! mellon    625:        wdc->sc_flags &= ~WDCF_IRQ_WAIT;
1.2       bouyer    626:        untimeout(wdctimeout, wdc);
                    627:
                    628:        /* Is it not a transfer, but a control operation? */
                    629:        if (d_link->sc_state < READY) {
                    630:                if (wdccontrol(wdc, d_link) == 0) {
                    631:                        /* The drive is busy.  Wait. */
                    632:                        return 1;
                    633:                }
                    634:                WDDEBUG_PRINT(("wdc_ata_start from wdc_ata_intr(open) flags 0x%x\n",
                    635:                    dc->sc_flags));
                    636:                wdc_ata_start(wdc,xfer);
                    637:                return 1;
                    638:        }
                    639:
                    640:        /* Turn off the DMA channel. */
                    641:        if (d_link->sc_mode == WDM_DMA)
                    642:                isa_dmadone(wdc->sc_dev.dv_parent, wdc->sc_drq);
                    643:
                    644:        /* Have we an error? */
                    645:        if (wdc->sc_status & WDCS_ERR) {
                    646: #ifdef WDDEBUG
                    647:                wderror(d_link, NULL, "wdc_ata_start");
                    648: #endif
                    649:                if ((wdc->sc_flags & WDCF_SINGLE) == 0) {
                    650:                        wdc->sc_flags |= WDCF_ERROR;
                    651:                        goto restart;
                    652:                }
                    653:
                    654: #ifdef B_FORMAT
                    655:                if (bp->b_flags & B_FORMAT)
                    656:                        goto bad;
                    657: #endif
                    658:
                    659:                if (++wdc->sc_errors < WDIORETRIES) {
                    660:                        if (wdc->sc_errors == (WDIORETRIES + 1) / 2) {
                    661: #if 0
                    662:                                wderror(wd, NULL, "wedgie");
                    663: #endif
                    664:                                wdcunwedge(wdc);
                    665:                                return 1;
                    666:                        }
                    667:                        goto restart;
                    668:                }
                    669:                wderror(d_link, xfer->c_bp, "wdc_ata_intr hard error");
                    670:
                    671: #ifdef B_FORMAT
                    672:        bad:
                    673: #endif
                    674:                xfer->c_flags |= C_ERROR;
                    675:                goto done;
                    676:        }
                    677:
                    678:        /* If this was a read and not using DMA, fetch the data. */
                    679:        if (d_link->sc_mode != WDM_DMA &&
                    680:            (xfer->c_flags & (B_READ|B_WRITE)) == B_READ) {
                    681:                if ((wdc->sc_status & (WDCS_DRDY | WDCS_DSC | WDCS_DRQ))
                    682:                    != (WDCS_DRDY | WDCS_DSC | WDCS_DRQ)) {
                    683:                        wderror(d_link, NULL, "wdcintr: read intr before drq");
                    684:                        wdcunwedge(wdc);
                    685:                        return 1;
                    686:                }
                    687:
                    688:                /* Pull in data. */
                    689:                if ((d_link->sc_flags & WDF_32BIT) == 0)
                    690:                        insw(wdc->sc_iobase+wd_data,
                    691:                            xfer->databuf + xfer->c_skip, xfer->c_nbytes >> 1);
                    692:                else
                    693:                        insl(wdc->sc_iobase+wd_data,
                    694:                            xfer->databuf + xfer->c_skip, xfer->c_nbytes >> 2);
                    695:        }
                    696:
                    697:        /* If we encountered any abnormalities, flag it as a soft error. */
                    698:        if (wdc->sc_errors > 0 ||
                    699:            (wdc->sc_status & WDCS_CORR) != 0) {
                    700:                wderror(d_link, xfer->c_bp, "soft error (corrected)");
                    701:                wdc->sc_errors = 0;
                    702:        }
                    703:
                    704:        /* Adjust pointers for the next block, if any. */
                    705:        xfer->c_blkno += xfer->c_nblks;
                    706:        xfer->c_skip += xfer->c_nbytes;
                    707:        xfer->c_bcount -= xfer->c_nbytes;
                    708:
                    709:        /* See if this transfer is complete. */
                    710:        if (xfer->c_bcount > 0)
                    711:                goto restart;
                    712:
                    713: done:
                    714:        /* Done with this transfer, with or without error. */
                    715:        wdc_ata_done(wdc, xfer);
1.5       bouyer    716:        return 1;
1.2       bouyer    717:
                    718: restart:
                    719:        /* Start the next operation */
                    720:        WDDEBUG_PRINT(("wdc_ata_start from wdcintr flags 0x%x\n",
                    721:            wdc->sc_flags));
                    722:        wdc_ata_start(wdc, xfer);
                    723:
                    724:        return 1;
                    725: }
                    726:
                    727: void
                    728: wdc_ata_done(wdc, xfer)
                    729:        struct wdc_softc *wdc;
                    730:        struct wdc_xfer *xfer;
                    731: {
                    732:        struct buf *bp = xfer->c_bp;
                    733:        struct wd_link *d_link = xfer->d_link;
                    734:        int s;
                    735:
                    736:        WDDEBUG_PRINT(("wdc_ata_done\n"));
                    737:
                    738:        /* remove this command from xfer queue */
                    739:        s = splbio();
                    740:        TAILQ_REMOVE(&wdc->sc_xfer, xfer, c_xferchain);
                    741:        wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR | WDCF_ACTIVE);
                    742:        wdc->sc_errors = 0;
                    743:        if (bp) {
                    744:                if (xfer->c_flags & C_ERROR) {
                    745:                        bp->b_flags |= B_ERROR;
                    746:                        bp->b_error = EIO;
                    747:                }
                    748:                bp->b_resid = xfer->c_bcount;
                    749:                wddone(d_link, bp);
                    750:                biodone(bp);
                    751:        } else {
                    752:                wakeup(xfer->databuf);
                    753:        }
                    754:        xfer->c_skip = 0;
                    755:        wdc_free_xfer(xfer);
                    756:        d_link->openings++;
                    757:        wdstart((void*)d_link->wd_softc);
                    758:        WDDEBUG_PRINT(("wdcstart from wdc_ata_done, flags 0x%x\n",
                    759:            wdc->sc_flags));
                    760:        wdcstart(wdc);
                    761:        splx(s);
                    762: }
                    763:
                    764: /*
                    765:  * Get the drive parameters, if ESDI or ATA, or create fake ones for ST506.
                    766:  */
                    767: int
                    768: wdc_get_parms(wdc, d_link)
                    769:        struct wdc_softc * wdc;
                    770:        struct wd_link *d_link;
                    771: {
                    772:        int i;
                    773:        char tb[DEV_BSIZE];
                    774:        int s, error;
                    775:
                    776:        /*
                    777:         * XXX
                    778:         * The locking done here, and the length of time this may keep the rest
                    779:         * of the system suspended, is a kluge.  This should be rewritten to
                    780:         * set up a transfer and queue it through wdstart(), but it's called
                    781:         * infrequently enough that this isn't a pressing matter.
                    782:         */
                    783:
                    784:        s = splbio();
                    785:
                    786:        while ((wdc->sc_flags & WDCF_ACTIVE) != 0) {
                    787:                wdc->sc_flags |= WDCF_WANTED;
                    788:                if ((error = tsleep(wdc, PRIBIO | PCATCH, "wdprm", 0)) != 0) {
                    789:                        splx(s);
                    790:                        return error;
                    791:                }
                    792:        }
                    793:
                    794:        wdc->sc_flags |= WDCF_ACTIVE;
                    795:
                    796:        if (wdccommandshort(wdc, d_link->drive, WDCC_IDENTIFY) != 0 ||
                    797:            wait_for_drq(wdc) != 0) {
                    798:                /*
                    799:                 * We `know' there's a drive here; just assume it's old.
                    800:                 * This geometry is only used to read the MBR and print a
                    801:                 * (false) attach message.
                    802:                 */
                    803:                strncpy(d_link->sc_lp->d_typename, "ST506",
                    804:                    sizeof d_link->sc_lp->d_typename);
                    805:                d_link->sc_lp->d_type = DTYPE_ST506;
                    806:
                    807:                strncpy(d_link->sc_params.wdp_model, "unknown",
                    808:                    sizeof d_link->sc_params.wdp_model);
                    809:                d_link->sc_params.wdp_config = WD_CFG_FIXED;
                    810:                d_link->sc_params.wdp_cylinders = 1024;
                    811:                d_link->sc_params.wdp_heads = 8;
                    812:                d_link->sc_params.wdp_sectors = 17;
                    813:                d_link->sc_params.wdp_maxmulti = 0;
                    814:                d_link->sc_params.wdp_usedmovsd = 0;
                    815:                d_link->sc_params.wdp_capabilities = 0;
                    816:        } else {
                    817:                strncpy(d_link->sc_lp->d_typename, "ESDI/IDE",
                    818:                    sizeof d_link->sc_lp->d_typename);
                    819:                d_link->sc_lp->d_type = DTYPE_ESDI;
                    820:
                    821:                /* Read in parameter block. */
                    822:                insw(wdc->sc_iobase + wd_data, tb, sizeof(tb) / sizeof(short));
                    823:                bcopy(tb, &d_link->sc_params, sizeof(struct wdparams));
                    824:
                    825:                /* Shuffle string byte order. */
                    826:                for (i = 0; i < sizeof(d_link->sc_params.wdp_model); i += 2) {
                    827:                        u_short *p;
                    828:                        p = (u_short *)(d_link->sc_params.wdp_model + i);
                    829:                        *p = ntohs(*p);
                    830:                }
                    831:        }
                    832:
                    833:        /* Clear any leftover interrupt. */
                    834:        (void) inb(wdc->sc_iobase + wd_status);
                    835:
                    836:        /* Restart the queue. */
                    837:        WDDEBUG_PRINT(("wdcstart from wdc_get_parms flags 0x%x\n",
                    838:            wdc->sc_flags));
                    839:        wdc->sc_flags &= ~WDCF_ACTIVE;
                    840:        wdcstart(wdc);
                    841:
                    842:        splx(s);
                    843:        return 0;
                    844: }
                    845:
                    846: /*
                    847:  * Implement operations needed before read/write.
                    848:  * Returns 0 if operation still in progress, 1 if completed.
                    849:  */
                    850: int
                    851: wdccontrol(wdc, d_link)
                    852:        struct wdc_softc *wdc;
                    853:        struct wd_link *d_link;
                    854: {
                    855:        WDDEBUG_PRINT(("wdccontrol\n"));
                    856:
                    857:        switch (d_link->sc_state) {
                    858:        case RECAL:     /* Set SDH, step rate, do recal. */
                    859:                if (wdccommandshort(wdc, d_link->drive, WDCC_RECAL) != 0) {
                    860:                        wderror(d_link, NULL, "wdccontrol: recal failed (1)");
                    861:                        goto bad;
                    862:                }
                    863:                d_link->sc_state = RECAL_WAIT;
                    864:                break;
                    865:
                    866:        case RECAL_WAIT:
                    867:                if (wdc->sc_status & WDCS_ERR) {
                    868:                        wderror(d_link, NULL, "wdccontrol: recal failed (2)");
                    869:                        goto bad;
                    870:                }
                    871:                /* fall through */
                    872:
                    873:        case GEOMETRY:
                    874:                if ((d_link->sc_params.wdp_capabilities & WD_CAP_LBA) != 0)
                    875:                        goto multimode;
                    876:                if (wdsetctlr(d_link) != 0) {
                    877:                        /* Already printed a message. */
                    878:                        goto bad;
                    879:                }
                    880:                d_link->sc_state = GEOMETRY_WAIT;
                    881:                break;
                    882:
                    883:        case GEOMETRY_WAIT:
                    884:                if (wdc->sc_status & WDCS_ERR) {
                    885:                        wderror(d_link, NULL, "wdccontrol: geometry failed");
                    886:                        goto bad;
                    887:                }
                    888:                /* fall through */
                    889:
                    890:        case MULTIMODE:
                    891:        multimode:
                    892:                if (d_link->sc_mode != WDM_PIOMULTI)
                    893:                        goto ready;
                    894:                outb(wdc->sc_iobase + wd_seccnt, d_link->sc_multiple);
                    895:                if (wdccommandshort(wdc, d_link->drive,
                    896:                    WDCC_SETMULTI) != 0) {
                    897:                        wderror(d_link, NULL,
                    898:                            "wdccontrol: setmulti failed (1)");
                    899:                        goto bad;
                    900:                }
                    901:                d_link->sc_state = MULTIMODE_WAIT;
                    902:                break;
                    903:
                    904:        case MULTIMODE_WAIT:
                    905:                if (wdc->sc_status & WDCS_ERR) {
                    906:                        wderror(d_link, NULL,
                    907:                            "wdccontrol: setmulti failed (2)");
                    908:                        goto bad;
                    909:                }
                    910:                /* fall through */
                    911:
                    912:        case READY:
                    913:        ready:
                    914:                wdc->sc_errors = 0;
                    915:                d_link->sc_state = READY;
                    916:                /*
                    917:                 * The rest of the initialization can be done by normal means.
                    918:                 */
                    919:                return 1;
                    920:
                    921:        bad:
                    922:                wdcunwedge(wdc);
                    923:                return 0;
                    924:        }
                    925:
                    926:        wdc->sc_flags |= WDCF_IRQ_WAIT;
                    927:        timeout(wdctimeout, wdc, WAITTIME);
                    928:        return 0;
                    929: }
                    930:
                    931: #endif /* NWD > 0 */
                    932:
                    933:
                    934: /*
                    935:  * Interrupt routine for the controller.  Acknowledge the interrupt, check for
                    936:  * errors on the current operation, mark it done if necessary, and start the
                    937:  * next request.  Also check for a partially done transfer, and continue with
                    938:  * the next chunk if so.
                    939:  */
                    940: int
                    941: wdcintr(arg)
                    942:        void *arg;
                    943: {
                    944:        struct wdc_softc *wdc = arg;
                    945:        struct wdc_xfer *xfer;
                    946:
                    947:        if ((wdc->sc_flags & WDCF_IRQ_WAIT) == 0) {
                    948:                /* Clear the pending interrupt and abort. */
                    949:                u_char s = inb(wdc->sc_iobase+wd_status);
                    950:
                    951: #ifdef ATAPI_DEBUG_WDC
                    952:                u_char e = inb(wdc->sc_iobase+wd_error);
                    953:                u_char i = inb(wdc->sc_iobase+wd_seccnt);
                    954:                printf("wdcintr: inactive controller, "
                    955:                    "punting st=%02x er=%02x irr=%02x\n", s, e, i);
                    956: #else
                    957:                inb(wdc->sc_iobase+wd_error);
                    958:                inb(wdc->sc_iobase+wd_seccnt);
                    959: #endif
                    960:
                    961:                if (s & WDCS_DRQ) {
                    962:                        int len = inb (wdc->sc_iobase + wd_cyl_lo) +
                    963:                            256 * inb (wdc->sc_iobase + wd_cyl_hi);
                    964: #ifdef ATAPI_DEBUG_WDC
                    965:                        printf ("wdcintr: clearing up %d bytes\n", len);
                    966: #endif
                    967:                        wdcbit_bucket (wdc, len);
                    968:                }
                    969:                return 0;
                    970:        }
                    971:
                    972:        WDDEBUG_PRINT(("wdcintr\n"));
                    973:
                    974:        xfer = wdc->sc_xfer.tqh_first;
                    975: #if NATAPIBUS > 0 && NWD > 0
                    976:        if (xfer->c_flags & C_ATAPI) {
1.5       bouyer    977:                return wdc_atapi_intr(wdc,xfer);
1.2       bouyer    978:        } else
                    979:                return wdc_ata_intr(wdc,xfer);
                    980: #else /* NATAPIBUS > 0  && NWD > 0 */
                    981: #if NATAPIBUS > 0
1.5       bouyer    982:        return wdc_atapi_intr(wdc,xfer);
1.2       bouyer    983: #endif /* NATAPIBUS > 0 */
                    984: #if NWD > 0
                    985:        return wdc_ata_intr(wdc,xfer);
                    986: #endif /* NWD > 0 */
                    987: #endif /* NATAPIBUS > 0  && NWD > 0 */
                    988: }
                    989:
                    990: int
                    991: wdcreset(wdc, verb)
                    992:        struct wdc_softc *wdc;
                    993:        int verb;
                    994: {
                    995:        int iobase = wdc->sc_iobase;
                    996:
                    997:        /* Reset the device. */
                    998:        outb(iobase+wd_ctlr, WDCTL_RST | WDCTL_IDS);
                    999:        delay(1000);
                   1000:        outb(iobase+wd_ctlr, WDCTL_IDS);
                   1001:        delay(1000);
                   1002:        (void) inb(iobase+wd_error);
                   1003:        outb(iobase+wd_ctlr, WDCTL_4BIT);
                   1004:
                   1005:        if (wait_for_unbusy(wdc) < 0) {
                   1006:                if (verb)
                   1007:                        printf("%s: reset failed\n", wdc->sc_dev.dv_xname);
                   1008:                return 1;
                   1009:        }
                   1010:
                   1011:        return 0;
                   1012: }
                   1013:
                   1014: void
                   1015: wdcrestart(arg)
                   1016:        void *arg;
                   1017: {
                   1018:        struct wdc_softc *wdc = arg;
                   1019:        int s;
                   1020:
                   1021:        s = splbio();
                   1022:        wdcstart(wdc);
                   1023:        splx(s);
                   1024: }
                   1025:
                   1026: /*
                   1027:  * Unwedge the controller after an unexpected error.  We do this by resetting
                   1028:  * it, marking all drives for recalibration, and stalling the queue for a short
                   1029:  * period to give the reset time to finish.
                   1030:  * NOTE: We use a timeout here, so this routine must not be called during
                   1031:  * autoconfig or dump.
                   1032:  */
                   1033: void
                   1034: wdcunwedge(wdc)
                   1035:        struct wdc_softc *wdc;
                   1036: {
                   1037:        int unit;
                   1038:
                   1039: #ifdef ATAPI_DEBUG
                   1040:        printf("wdcunwedge\n");
                   1041: #endif
                   1042:
                   1043:        untimeout(wdctimeout, wdc);
                   1044:        wdc->sc_flags &= ~WDCF_IRQ_WAIT;
                   1045:        (void) wdcreset(wdc, VERBOSE);
                   1046:
                   1047:        /* Schedule recalibrate for all drives on this controller. */
                   1048:        for (unit = 0; unit < 2; unit++) {
1.6.2.2 ! mellon   1049:                if (!wdc->d_link[unit])
        !          1050:                        wdccommandshort(wdc, unit, ATAPI_SOFT_RESET);
        !          1051:                else if (wdc->d_link[unit]->sc_state > RECAL)
1.2       bouyer   1052:                        wdc->d_link[unit]->sc_state = RECAL;
                   1053:        }
                   1054:
                   1055:        wdc->sc_flags |= WDCF_ERROR;
                   1056:        ++wdc->sc_errors;
                   1057:
                   1058:        /* Wake up in a little bit and restart the operation. */
                   1059:        WDDEBUG_PRINT(("wdcrestart from wdcunwedge\n"));
                   1060:        wdc->sc_flags &= ~WDCF_ACTIVE;
                   1061:        timeout(wdcrestart, wdc, RECOVERYTIME);
                   1062: }
                   1063:
                   1064: int
                   1065: wdcwait(wdc, mask)
                   1066:        struct wdc_softc *wdc;
                   1067:        int mask;
                   1068: {
                   1069:        int iobase = wdc->sc_iobase;
                   1070:        int timeout = 0;
                   1071:        u_char status;
                   1072: #ifdef WDCNDELAY_DEBUG
                   1073:        extern int cold;
                   1074: #endif
                   1075:
                   1076:        WDDEBUG_PRINT(("wdcwait iobase %x\n", iobase));
                   1077:
                   1078:        for (;;) {
                   1079:                wdc->sc_status = status = inb(iobase+wd_status);
                   1080:                /*
                   1081:                 * XXX
                   1082:                 * If a single slave ATAPI device is attached, it may
                   1083:                 * have released the bus. Select it and try again.
                   1084:                 */
                   1085:                if (status == 0xff && wdc->sc_flags & WDCF_ONESLAVE) {
                   1086:                        outb(iobase+wd_sdh, WDSD_IBM | 0x10);
                   1087:                        wdc->sc_status = status = inb(iobase+wd_status);
                   1088:                }
                   1089:                if ((status & WDCS_BSY) == 0 && (status & mask) == mask)
                   1090:                        break;
                   1091:                if (++timeout > WDCNDELAY) {
1.3       bouyer   1092: #ifdef ATAPI_DEBUG
1.2       bouyer   1093:                        printf("wdcwait: timeout, status %x error %x\n", status, inb(iobase+wd_error));
                   1094: #endif
                   1095:                        return -1;
                   1096:                }
                   1097:                delay(WDCDELAY);
                   1098:        }
                   1099:        if (status & WDCS_ERR) {
                   1100:                wdc->sc_error = inb(iobase+wd_error);
                   1101:                return WDCS_ERR;
                   1102:        }
                   1103: #ifdef WDCNDELAY_DEBUG
                   1104:        /* After autoconfig, there should be no long delays. */
                   1105:        if (!cold && timeout > WDCNDELAY_DEBUG) {
                   1106:                struct wdc_xfer *xfer = wdc->sc_xfer.tqh_first;
                   1107:                if (xfer == NULL)
                   1108:                        printf("%s: warning: busy-wait took %dus\n",
                   1109:                        wdc->sc_dev.dv_xname, WDCDELAY * timeout);
                   1110:                else
                   1111:                        printf("%s(%s): warning: busy-wait took %dus\n",
                   1112:                                wdc->sc_dev.dv_xname,
                   1113:                            ((struct device*)xfer->d_link->wd_softc)->dv_xname,
                   1114:                                WDCDELAY * timeout);
                   1115:        }
                   1116: #endif
                   1117:        return 0;
                   1118: }
                   1119:
                   1120: void
                   1121: wdctimeout(arg)
                   1122:        void *arg;
                   1123: {
                   1124:        struct wdc_softc *wdc = (struct wdc_softc *)arg;
1.6.2.2 ! mellon   1125:        struct wdc_xfer *xfer = wdc->sc_xfer.tqh_first;
1.2       bouyer   1126:        int s;
                   1127:
                   1128:        WDDEBUG_PRINT(("wdctimeout\n"));
                   1129:
                   1130:        s = splbio();
                   1131:        if ((wdc->sc_flags & WDCF_IRQ_WAIT) != 0) {
                   1132:                wdcerror(wdc, "lost interrupt");
1.6.2.2 ! mellon   1133:                printf("\ttype: %s\n", (xfer->c_flags & C_ATAPI) ? "atapi":"ata");
        !          1134:                printf("\tc_bcount: %d\n", xfer->c_bcount);
        !          1135:                printf("\tc_skip: %d\n", xfer->c_skip);
        !          1136:                wdcintr(wdc);
        !          1137:                wdc->sc_flags &= ~WDCF_IRQ_WAIT;
1.2       bouyer   1138:                wdcunwedge(wdc);
                   1139:        } else
                   1140:                wdcerror(wdc, "missing untimeout");
                   1141:        splx(s);
                   1142: }
                   1143:
                   1144: /*
                   1145:  * Wait for the drive to become ready and send a command.
                   1146:  * Return -1 if busy for too long or 0 otherwise.
                   1147:  * Assumes interrupts are blocked.
                   1148:  */
                   1149: int
                   1150: wdccommand(wdc, d_link, command, drive, cylin, head, sector, count)
                   1151:                struct wdc_softc *wdc;
                   1152:         struct wd_link *d_link;
                   1153:         int command;
                   1154:         int drive, cylin, head, sector, count;
                   1155: {
                   1156:         int iobase = wdc->sc_iobase;
                   1157:         int stat;
                   1158:
                   1159:        WDDEBUG_PRINT(("wdccommand drive %d\n", drive));
                   1160:
                   1161: #if defined(DIAGNOSTIC) && defined(WDCDEBUG)
                   1162:        if ((wdc->sc_flags & WDCF_ACTIVE) == 0)
                   1163:                printf("wdccommand: controler not active (drive %d)\n", drive);
                   1164: #endif
                   1165:
                   1166:         /* Select drive, head, and addressing mode. */
                   1167:         outb(iobase+wd_sdh, WDSD_IBM | (drive << 4) | head);
                   1168:
                   1169:         /* Wait for it to become ready to accept a command. */
                   1170:         if (command == WDCC_IDP || d_link->type == ATAPI)
                   1171:                 stat = wait_for_unbusy(wdc);
                   1172:         else
                   1173:                 stat = wdcwait(wdc, WDCS_DRDY);
                   1174:
                   1175:         if (stat < 0) {
                   1176: #ifdef ATAPI_DEBUG
                   1177:                printf("wdcommand: xfer failed (wait_for_unbusy) status %d\n",
                   1178:                    stat);
                   1179: #endif
                   1180:                 return -1;
                   1181:        }
                   1182:
                   1183:         /* Load parameters. */
                   1184:         if (d_link->type == ATA && d_link->sc_lp->d_type == DTYPE_ST506)
                   1185:                 outb(iobase + wd_precomp, d_link->sc_lp->d_precompcyl / 4);
                   1186:         else
                   1187:                 outb(iobase + wd_features, 0);
                   1188:         outb(iobase + wd_cyl_lo, cylin);
                   1189:         outb(iobase + wd_cyl_hi, cylin >> 8);
                   1190:         outb(iobase + wd_sector, sector);
                   1191:         outb(iobase + wd_seccnt, count);
                   1192:
                   1193:         /* Send command. */
                   1194:         outb(iobase + wd_command, command);
                   1195:
                   1196:         return 0;
                   1197: }
                   1198:
                   1199: /*
                   1200:  * Simplified version of wdccommand().
                   1201:  */
                   1202: int
                   1203: wdccommandshort(wdc, drive, command)
                   1204:        struct wdc_softc *wdc;
                   1205:         int drive;
                   1206:         int command;
                   1207: {
                   1208:        int iobase = wdc->sc_iobase;
                   1209:
                   1210:        WDDEBUG_PRINT(("wdccommandshort\n"));
                   1211:
                   1212: #if defined(DIAGNOSTIC) && defined(WDCDEBUG)
                   1213:        if ((wdc->sc_flags & WDCF_ACTIVE) == 0)
                   1214:                printf("wdccommandshort: controler not active (drive %d)\n",
                   1215:                    drive);
                   1216: #endif
                   1217:
                   1218:         /* Select drive. */
                   1219:         outb(iobase + wd_sdh, WDSD_IBM | (drive << 4));
                   1220:
                   1221:         if (wdcwait(wdc, WDCS_DRDY) < 0)
                   1222:                 return -1;
                   1223:
                   1224:         outb(iobase + wd_command, command);
                   1225:
                   1226:        return 0;
                   1227: }
                   1228:
                   1229: void
                   1230: wdc_exec_xfer(wdc, d_link, xfer)
                   1231:        struct wdc_softc *wdc;
                   1232:        struct wd_link *d_link;
                   1233:        struct wdc_xfer *xfer;
                   1234: {
                   1235:        int s;
                   1236:
                   1237:        WDDEBUG_PRINT(("wdc_exec_xfer\n"));
                   1238:
                   1239:        s = splbio();
                   1240:
                   1241:        /* insert at the end of command list */
                   1242:        TAILQ_INSERT_TAIL(&wdc->sc_xfer,xfer , c_xferchain)
                   1243:        WDDEBUG_PRINT(("wdcstart from wdc_exec_xfer, flags 0x%x\n",
                   1244:            wdc->sc_flags));
                   1245:        wdcstart(wdc);
                   1246:        xfer->c_flags |= C_NEEDDONE; /* we can now call upper level done() */
                   1247:        splx(s);
                   1248: }
                   1249:
                   1250: struct wdc_xfer *
                   1251: wdc_get_xfer(flags)
                   1252:        int flags;
                   1253: {
                   1254:        struct wdc_xfer *xfer;
                   1255:        int s;
                   1256:
                   1257:        s = splbio();
                   1258:        if ((xfer = xfer_free_list.lh_first) != NULL) {
                   1259:                LIST_REMOVE(xfer, free_list);
                   1260:                splx(s);
                   1261: #ifdef DIAGNOSTIC
                   1262:                if ((xfer->c_flags & C_INUSE) != 0)
                   1263:                        panic("wdc_get_xfer: xfer already in use\n");
                   1264: #endif
                   1265:        } else {
                   1266:                splx(s);
1.6.2.2 ! mellon   1267: #ifdef ATAPI_DEBUG2
1.2       bouyer   1268:                printf("wdc:making xfer %d\n",wdc_nxfer);
                   1269: #endif
                   1270:                xfer = malloc(sizeof(*xfer), M_DEVBUF,
                   1271:                    ((flags & IDE_NOSLEEP) != 0 ? M_NOWAIT : M_WAITOK));
                   1272:                if (xfer == NULL)
                   1273:                        return 0;
                   1274:
                   1275: #ifdef DIAGNOSTIC
                   1276:                xfer->c_flags &= ~C_INUSE;
                   1277: #endif
1.6.2.2 ! mellon   1278: #ifdef ATAPI_DEBUG2
1.2       bouyer   1279:                wdc_nxfer++;
                   1280: #endif
                   1281:        }
                   1282: #ifdef DIAGNOSTIC
                   1283:        if ((xfer->c_flags & C_INUSE) != 0)
                   1284:                panic("wdc_get_xfer: xfer already in use\n");
                   1285: #endif
                   1286:        bzero(xfer,sizeof(struct wdc_xfer));
                   1287:        xfer->c_flags = C_INUSE;
                   1288:        return xfer;
                   1289: }
                   1290:
                   1291: void
                   1292: wdc_free_xfer(xfer)
                   1293:        struct wdc_xfer *xfer;
                   1294: {
                   1295:        int s;
                   1296:
                   1297:        s = splbio();
                   1298:        xfer->c_flags &= ~C_INUSE;
                   1299:        LIST_INSERT_HEAD(&xfer_free_list, xfer, free_list);
                   1300:        splx(s);
                   1301: }
                   1302:
                   1303: void
                   1304: wdcerror(wdc, msg)
                   1305:        struct wdc_softc *wdc;
                   1306:        char *msg;
                   1307: {
                   1308:        struct wdc_xfer *xfer = wdc->sc_xfer.tqh_first;
                   1309:        if (xfer == NULL)
                   1310:                printf("%s: %s\n", wdc->sc_dev.dv_xname, msg);
                   1311:        else
                   1312:                printf("%s(%d): %s\n", wdc->sc_dev.dv_xname,
                   1313:                    xfer->d_link->drive, msg);
                   1314: }
                   1315:
                   1316: /*
                   1317:  * the bit bucket
                   1318:  */
                   1319: void
                   1320: wdcbit_bucket(wdc, size)
                   1321:        struct wdc_softc *wdc;
                   1322:        int size;
                   1323: {
                   1324:        int iobase = wdc->sc_iobase;
                   1325:        int i;
                   1326:
                   1327:        for (i = 0 ; i < size / 2 ; i++) {
                   1328:                short null;
                   1329:                (void)insw(iobase + wd_data, &null, 1);
                   1330:        }
                   1331:
                   1332:        if (size % 2)
                   1333:                (void)inb(iobase + wd_data);
                   1334: }
                   1335:
                   1336:
                   1337: #if NATAPIBUS > 0
                   1338:
                   1339: void
                   1340: wdc_atapi_minphys (struct buf *bp)
                   1341: {
                   1342:     if(bp->b_bcount > MAX_SIZE)
                   1343:                bp->b_bcount = MAX_SIZE;
                   1344:        minphys(bp);
                   1345: }
                   1346:
                   1347:
                   1348: void
                   1349: wdc_atapi_start(wdc, xfer)
                   1350:        struct wdc_softc *wdc;
                   1351:        struct wdc_xfer *xfer;
                   1352: {
                   1353:        struct scsipi_xfer *sc_xfer = xfer->atapi_cmd;
                   1354:
                   1355: #ifdef ATAPI_DEBUG_WDC
                   1356:        printf("wdc_atapi_start, acp flags %x \n",sc_xfer->flags);
                   1357: #endif
                   1358:        if (wdc->sc_errors >= WDIORETRIES) {
                   1359:                if ((wdc->sc_status & WDCS_ERR) == 0) {
                   1360:                        sc_xfer->error = XS_DRIVER_STUFFUP; /* XXX do we know more ? */
                   1361:                } else {
                   1362:                        sc_xfer->error = XS_SENSE;
                   1363:                        sc_xfer->sense.atapi_sense = inb (wdc->sc_iobase + wd_error);
                   1364:                }
                   1365:                wdc_atapi_done(wdc, xfer);
                   1366:                return;
                   1367:        }
                   1368:        if (wait_for_unbusy(wdc) != 0) {
                   1369:                if ((wdc->sc_status & WDCS_ERR) == 0) {
                   1370:                        printf("wdc_atapi_start: not ready, st = %02x\n",
                   1371:                            wdc->sc_status);
                   1372:                        sc_xfer->error = XS_SELTIMEOUT;
                   1373:                }
                   1374: #if 0 /* don't get the sense yet, as this may be just UNIT ATTENTION */
                   1375:                else {
                   1376: #ifdef ATAPI_DEBUG_WDC
                   1377:                        printf("wdc_atapi_start: sense %02x\n", wdc->sc_error);
                   1378: #endif
                   1379:                        sc_xfer->error = XS_SENSE;
                   1380:                        sc_xfer->sense.atapi_sense = wdc->sc_error;
                   1381:                }
                   1382:                wdc_atapi_done(wdc, xfer);
                   1383:                return;
                   1384: #endif
                   1385:        }
                   1386:
                   1387:        if (wdccommand(wdc, (struct wd_link*)xfer->d_link, ATAPI_PACKET_COMMAND,
                   1388:            sc_xfer->sc_link->scsipi_atapi.drive, sc_xfer->datalen,
                   1389:                0, 0, 0) != 0) {
                   1390:                printf("wdc_atapi_start: can't send atapi paket command\n");
                   1391:                sc_xfer->error = XS_DRIVER_STUFFUP;
                   1392:                wdc_atapi_done(wdc, xfer);
                   1393:                return;
                   1394:        }
                   1395:        if ((sc_xfer->sc_link->scsipi_atapi.cap  & 0x0300) != ACAP_DRQ_INTR) {
                   1396:                int i, phase;
                   1397:                for (i=20000; i>0; --i) {
                   1398:                        phase = (inb(wdc->sc_iobase + wd_ireason) &
                   1399:                            (WDCI_CMD | WDCI_IN)) |
                   1400:                            (inb(wdc->sc_iobase + wd_status) & WDCS_DRQ);
                   1401:                        if (phase == PHASE_CMDOUT)
                   1402:                                break;
                   1403:                        delay(10);
                   1404:                }
                   1405:                if (phase != PHASE_CMDOUT ) {
                   1406:                        printf("wdc_atapi_start: timout waiting PHASE_CMDOUT");
                   1407:                        sc_xfer->error = XS_SELTIMEOUT;
                   1408:                        wdc_atapi_done(wdc, xfer);
                   1409:                        return;
                   1410:                }
                   1411:                outsw(wdc->sc_iobase + wd_data, sc_xfer->cmd,
                   1412:                    sc_xfer->cmdlen / sizeof(short));
                   1413:        }
                   1414:        wdc->sc_flags |= WDCF_IRQ_WAIT;
                   1415:
                   1416: #ifdef ATAPI_DEBUG2
                   1417:        printf("wdc_atapi_start: timeout\n");
                   1418: #endif
                   1419:        timeout(wdctimeout, wdc, WAITTIME);
                   1420:        return;
                   1421: }
                   1422:
                   1423:
                   1424: int
                   1425: wdc_atapi_get_params(ab_link, drive, id)
                   1426:        struct scsipi_link *ab_link;
                   1427:        u_int8_t drive;
                   1428:        struct atapi_identify *id;
                   1429: {
                   1430:        struct wdc_softc *wdc = (void*)ab_link->adapter_softc;
                   1431:        int status, len, excess = 0;
                   1432:        int s, error;
                   1433:
1.4       bouyer   1434:        /* if a disk is already present, skip */
                   1435:        if ((wdc->sc_drives_mask & (1 << drive)) != 0) {
1.2       bouyer   1436: #ifdef ATAPI_DEBUG_PROBE
1.4       bouyer   1437:                printf("wdc_atapi_get_params: drive %d present\n", drive);
1.2       bouyer   1438: #endif
                   1439:                return 0;
                   1440:        }
                   1441:
                   1442:        /*
                   1443:         * If there is only one ATAPI slave on the bus,don't probe
                   1444:         * drive 0 (master)
                   1445:         */
                   1446:
                   1447:        if (wdc->sc_flags & WDCF_ONESLAVE && drive != 1)
                   1448:                return 0;
                   1449:
                   1450: #ifdef ATAPI_DEBUG_PROBE
                   1451:        printf("wdc_atapi_get_params: probing drive %d\n", drive);
                   1452: #endif
                   1453:
                   1454:        /*
                   1455:         * XXX
                   1456:         * The locking done here, and the length of time this may keep the rest
                   1457:         * of the system suspended, is a kluge.  This should be rewritten to
                   1458:         * set up a transfer and queue it through wdstart(), but it's called
                   1459:         * infrequently enough that this isn't a pressing matter.
                   1460:         */
                   1461:
                   1462:        s = splbio();
                   1463:
                   1464:        while ((wdc->sc_flags & WDCF_ACTIVE) != 0) {
                   1465:                wdc->sc_flags |= WDCF_WANTED;
                   1466:                if ((error = tsleep(wdc, PRIBIO | PCATCH, "atprm", 0)) != 0) {
                   1467:                        splx(s);
                   1468:                        return error;
                   1469:                }
                   1470:        }
                   1471:
                   1472:        wdc->sc_flags |= WDCF_ACTIVE;
                   1473:        error = 1;
                   1474:        (void)wdcreset(wdc, VERBOSE);
                   1475:        if ((status = wdccommand(wdc, (struct wd_link*)(&(ab_link->scsipi_atapi)),
                   1476:            ATAPI_SOFT_RESET, drive, 0, 0, 0, 0)) != 0) {
                   1477: #ifdef ATAPI_DEBUG
                   1478:                printf("wdc_atapi_get_params: ATAPI_SOFT_RESET"
                   1479:                    "failed for drive %d: status %d error %d\n",
                   1480:                    drive, status, wdc->sc_error);
                   1481: #endif
                   1482:                error = 0;
                   1483:                goto end;
                   1484:        }
                   1485:        if ((status = wait_for_unbusy(wdc)) != 0) {
                   1486: #ifdef ATAPI_DEBUG
                   1487:        printf("wdc_atapi_get_params: wait_for_unbusy failed "
                   1488:            "for drive %d: status %d error %d\n",
                   1489:            drive, status, wdc->sc_error);
                   1490: #endif
                   1491:                error = 0;
                   1492:                goto end;
                   1493:        }
                   1494:
                   1495:        if (wdccommand(wdc, (struct wd_link*)(&(ab_link->scsipi_atapi)),
                   1496:                ATAPI_IDENTIFY_DEVICE, drive, sizeof(struct atapi_identify),
                   1497:                0, 0, 0) != 0 ||
                   1498:            atapi_ready(wdc) != 0) {
                   1499: #ifdef ATAPI_DEBUG_PROBE
                   1500:                printf("ATAPI_IDENTIFY_DEVICE failed for drive %d\n", drive);
                   1501: #endif
                   1502:                error = 0;
                   1503:                goto end;
                   1504:        }
                   1505:        len = inb(wdc->sc_iobase + wd_cyl_lo) + 256 *
                   1506:            inb(wdc->sc_iobase + wd_cyl_hi);
                   1507:        if (len != sizeof(struct atapi_identify)) {
                   1508:                printf("Warning drive %d returned %d/%d of "
                   1509:                    "indentify device data\n", drive, len,
                   1510:                    sizeof(struct atapi_identify));
                   1511:                excess = len - sizeof(struct atapi_identify);
                   1512:                if (excess < 0)
                   1513:                        excess = 0;
                   1514:        }
                   1515:        insw(wdc->sc_iobase + wd_data, id,
                   1516:            sizeof(struct atapi_identify)/sizeof(short));
                   1517:        wdcbit_bucket(wdc, excess);
1.4       bouyer   1518:        wdc->sc_drives_mask |= (1 << drive);
1.2       bouyer   1519:
                   1520:  end:  /* Restart the queue. */
                   1521:        WDDEBUG_PRINT(("wdcstart from wdc_atapi_get_parms flags 0x%x\n",
                   1522:            wdc->sc_flags));
                   1523:        wdc->sc_flags &= ~WDCF_ACTIVE;
                   1524:        wdcstart(wdc);
                   1525:        splx(s);
                   1526:        return error;
                   1527: }
                   1528:
                   1529: int
                   1530: wdc_atapi_send_command_packet(sc_xfer)
                   1531:        struct scsipi_xfer *sc_xfer;
                   1532: {
                   1533:        struct scsipi_link *sc_link = sc_xfer->sc_link;
                   1534:        struct wdc_softc *wdc = (void*)sc_link->adapter_softc;
                   1535:        struct wdc_xfer *xfer;
                   1536:        int flags = sc_xfer->flags;
1.6.2.2 ! mellon   1537:
1.2       bouyer   1538:        if (flags & SCSI_POLL) {   /* should use the queue and wdc_atapi_start */
                   1539:                struct wdc_xfer xfer_s;
                   1540:                int i, s;
                   1541:
                   1542:                s = splbio();
                   1543: #ifdef ATAPI_DEBUG_WDC
                   1544:                printf("wdc_atapi_send_cmd: "
                   1545:                    "flags 0x%x drive %d cmdlen %d datalen %d",
                   1546:                    sc_xfer->flags, sc_link->scsipi_atapi.drive, sc_xfer->cmdlen,
                   1547:                        sc_xfer->datalen);
                   1548: #endif
                   1549:                xfer = &xfer_s;
                   1550:                bzero(xfer, sizeof(xfer_s));
                   1551:                xfer->c_flags = C_INUSE|C_ATAPI|flags;
                   1552:                xfer->d_link = (struct wd_link *)(&sc_link->scsipi_atapi);
                   1553:                xfer->c_bp = sc_xfer->bp;
                   1554:                xfer->atapi_cmd = sc_xfer;
                   1555:                xfer->c_blkno = 0;
                   1556:                xfer->databuf = sc_xfer->data;
                   1557:                xfer->c_bcount = sc_xfer->datalen;
                   1558:                if (wait_for_unbusy (wdc) != 0)  {
                   1559:                        if ((wdc->sc_status & WDCS_ERR) == 0) {
                   1560:                                printf("wdc_atapi_send_command: not ready, "
                   1561:                                    "st = %02x\n", wdc->sc_status);
                   1562:                                sc_xfer->error = XS_SELTIMEOUT;
                   1563:                        } else {
                   1564:                                sc_xfer->error = XS_SENSE;
                   1565:                                sc_xfer->sense.atapi_sense = wdc->sc_error;
                   1566:                        }
                   1567:                        splx(s);
                   1568:                        return COMPLETE;
                   1569:                }
                   1570:
                   1571:                if (wdccommand(wdc, (struct wd_link*)(&sc_link->scsipi_atapi),
                   1572:                    ATAPI_PACKET_COMMAND, sc_link->scsipi_atapi.drive, sc_xfer->datalen,
                   1573:                    0, 0, 0) != 0) {
                   1574:                        printf("can't send atapi paket command\n");
                   1575:                        sc_xfer->error = XS_DRIVER_STUFFUP;
                   1576:                        splx(s);
                   1577:                        return COMPLETE;
                   1578:                }
                   1579:
                   1580:                /* Wait for cmd i/o phase. */
                   1581:                for (i = 20000; i > 0; --i) {
                   1582:                        int phase;
                   1583:                        phase = (inb(wdc->sc_iobase + wd_ireason) &
                   1584:                            (WDCI_CMD | WDCI_IN)) |
                   1585:                            (inb(wdc->sc_iobase + wd_status) & WDCS_DRQ);
                   1586:                        if (phase == PHASE_CMDOUT)
                   1587:                                break;
                   1588:                        delay(10);
                   1589:                }
                   1590: #ifdef ATAPI_DEBUG_WDC
                   1591:                printf("Wait for cmd i/o phase: i = %d\n", i);
                   1592: #endif
                   1593:
                   1594:                outsw(wdc->sc_iobase + wd_data, sc_xfer->cmd,
                   1595:                    sc_xfer->cmdlen/ sizeof (short));
                   1596:
                   1597:                /* Wait for data i/o phase. */
                   1598:                for ( i= 20000; i > 0; --i) {
                   1599:                        int phase;
                   1600:                        phase = (inb(wdc->sc_iobase + wd_ireason) &
                   1601:                            (WDCI_CMD | WDCI_IN)) |
                   1602:                            (inb(wdc->sc_iobase + wd_status) & WDCS_DRQ);
                   1603:                        if (phase != PHASE_CMDOUT)
                   1604:                                break;
                   1605:                        delay(10);
                   1606:                }
                   1607:
                   1608: #ifdef ATAPI_DEBUG_WDC
                   1609:                printf("Wait for data i/o phase: i = %d\n", i);
                   1610: #endif
1.6.2.2 ! mellon   1611:                wdc->sc_flags |= WDCF_IRQ_WAIT;
1.5       bouyer   1612:                while ((sc_xfer->flags & ITSDONE) == 0) {
                   1613:                        wdc_atapi_intr(wdc, xfer);
1.2       bouyer   1614:                        for (i = 2000; i > 0; --i)
                   1615:                                if ((inb(wdc->sc_iobase + wd_status)
                   1616:                                    & WDCS_DRQ) == 0)
                   1617:                                        break;
                   1618: #ifdef ATAPI_DEBUG_WDC
                   1619:                        printf("wdc_atapi_intr: i = %d\n", i);
                   1620: #endif
                   1621:                }
                   1622:                wdc->sc_flags &= ~(WDCF_IRQ_WAIT | WDCF_SINGLE | WDCF_ERROR);
                   1623:                wdc->sc_errors = 0;
                   1624:                xfer->c_skip = 0;
                   1625:                splx(s);
                   1626:                return COMPLETE;
                   1627:        } else {        /* POLLED */
                   1628:                xfer = wdc_get_xfer(flags & SCSI_NOSLEEP ? IDE_NOSLEEP : 0);
                   1629:                if (xfer == NULL) {
                   1630:                        return TRY_AGAIN_LATER;
                   1631:                }
                   1632:                xfer->c_flags |= C_ATAPI|sc_xfer->flags;
                   1633:                xfer->d_link = (struct wd_link*)(&sc_link->scsipi_atapi);
                   1634:                xfer->c_bp = sc_xfer->bp;
                   1635:                xfer->atapi_cmd = sc_xfer;
                   1636:                xfer->c_blkno = 0;
                   1637:                xfer->databuf = sc_xfer->data;
                   1638:                xfer->c_bcount = sc_xfer->datalen;
                   1639:                wdc_exec_xfer(wdc, xfer->d_link, xfer);
                   1640: #ifdef ATAPI_DEBUG_WDC
                   1641:                printf("wdc_atapi_send_command_packet: wdc_exec_xfer, flags 0x%x\n",
                   1642:                        sc_xfer->flags);
                   1643: #endif
                   1644:                return (sc_xfer->flags & ITSDONE) ? COMPLETE : SUCCESSFULLY_QUEUED;
                   1645:        }
                   1646: }
                   1647:
                   1648: int
                   1649: wdc_atapi_intr(wdc, xfer)
                   1650:        struct wdc_softc *wdc;
                   1651:        struct wdc_xfer *xfer;
                   1652: {
                   1653:        struct scsipi_xfer *sc_xfer = xfer->atapi_cmd;
                   1654:        int len, phase, i, retries=0;
                   1655:        int err, st, ire;
                   1656:
                   1657: #ifdef ATAPI_DEBUG2
                   1658:        printf("wdc_atapi_intr: %s\n", wdc->sc_dev.dv_xname);
                   1659: #endif
                   1660:
                   1661:        if (wait_for_unbusy(wdc) < 0) {
                   1662:                if ((wdc->sc_status & WDCS_ERR) == 0) {
                   1663:                        printf("wdc_atapi_intr: controller busy\n");
1.5       bouyer   1664:                        return 0;
1.2       bouyer   1665:                } else {
                   1666:                        sc_xfer->error = XS_SENSE;
                   1667:                        sc_xfer->sense.atapi_sense = wdc->sc_error;
                   1668:                }
                   1669: #ifdef ATAPI_DEBUG_WDC
                   1670:                printf("wdc_atapi_intr: wdc_atapi_done(), error %d\n",
                   1671:                        sc_xfer->error);
                   1672: #endif
                   1673:                wdc_atapi_done(wdc, xfer);
                   1674:                return 0;
                   1675:        }
                   1676:
                   1677:
                   1678: again:
                   1679:        len = inb(wdc->sc_iobase + wd_cyl_lo) +
                   1680:            256 * inb(wdc->sc_iobase + wd_cyl_hi);
                   1681:
                   1682:        st = inb(wdc->sc_iobase + wd_status);
                   1683:        err = inb(wdc->sc_iobase + wd_error);
                   1684:        ire = inb(wdc->sc_iobase + wd_ireason);
                   1685:
                   1686:        phase = (ire & (WDCI_CMD | WDCI_IN)) | (st & WDCS_DRQ);
                   1687: #ifdef ATAPI_DEBUG_WDC
                   1688:        printf("wdc_atapi_intr: len %d st %d err %d ire %d :",
                   1689:            len, st, err, ire);
                   1690: #endif
                   1691:        switch (phase) {
                   1692:        case PHASE_CMDOUT:
                   1693:                /* send packet command */
                   1694: #ifdef ATAPI_DEBUG_WDC
                   1695:                printf("PHASE_CMDOUT\n");
                   1696: #endif
                   1697:
                   1698: #ifdef ATAPI_DEBUG_WDC
                   1699:                {
                   1700:                        int i;
                   1701:                        char *c = (char *)sc_xfer->cmd;
                   1702:                        printf("wdc_atapi_intr: cmd ");
                   1703:                        for (i = 0; i < sc_xfer->cmdlen; i++)
                   1704:                                printf("%x ", c[i]);
                   1705:                        printf("\n");
                   1706:                }
                   1707: #endif
                   1708:
                   1709:                outsw(wdc->sc_iobase + wd_data, sc_xfer->cmd,
                   1710:                    sc_xfer->cmdlen/ sizeof (short));
                   1711:                return 1;
                   1712:
                   1713:        case PHASE_DATAOUT:
                   1714:                /* write data */
                   1715: #ifdef ATAPI_DEBUG_WDC
                   1716:                printf("PHASE_DATAOUT\n");
                   1717: #endif
                   1718:                if ((sc_xfer->flags & SCSI_DATA_OUT) == 0) {
                   1719:                        printf("wdc_atapi_intr: bad data phase\n");
                   1720:                        sc_xfer->error = XS_DRIVER_STUFFUP;
1.5       bouyer   1721:                        return 0;
1.2       bouyer   1722:                }
                   1723:                if (xfer->c_bcount < len) {
                   1724:                        printf("wdc_atapi_intr: warning: write only "
                   1725:                            "%d of %d requested bytes\n", xfer->c_bcount, len);
                   1726:                        outsw(wdc->sc_iobase + wd_data,
                   1727:                            xfer->databuf + xfer->c_skip,
                   1728:                            xfer->c_bcount / sizeof(short));
                   1729:                        for (i = xfer->c_bcount; i < len; i += sizeof(short))
                   1730:                                outw(wdc->sc_iobase + wd_data, 0);
1.6.2.2 ! mellon   1731:                        xfer->c_skip += xfer->c_bcount;
1.2       bouyer   1732:                        xfer->c_bcount = 0;
                   1733:                } else {
                   1734:                        outsw(wdc->sc_iobase + wd_data,
                   1735:                            xfer->databuf + xfer->c_skip, len / sizeof(short));
                   1736:                        xfer->c_skip += len;
                   1737:                        xfer->c_bcount -= len;
                   1738:                }
1.6.2.2 ! mellon   1739:                return 1;
1.2       bouyer   1740:
                   1741:        case PHASE_DATAIN:
                   1742:                /* Read data */
                   1743: #ifdef ATAPI_DEBUG_WDC
                   1744:                printf("PHASE_DATAIN\n");
                   1745: #endif
                   1746:                if ((sc_xfer->flags & SCSI_DATA_IN) == 0) {
                   1747:                        printf("wdc_atapi_intr: bad data phase\n");
                   1748:                        sc_xfer->error = XS_DRIVER_STUFFUP;
1.5       bouyer   1749:                        return 0;
1.2       bouyer   1750:                }
                   1751:                if (xfer->c_bcount < len) {
                   1752:                        printf("wdc_atapi_intr: warning: reading only "
                   1753:                            "%d of %d bytes\n", xfer->c_bcount, len);
                   1754:                        insw(wdc->sc_iobase + wd_data,
                   1755:                            xfer->databuf + xfer->c_skip,
                   1756:                            xfer->c_bcount / sizeof(short));
                   1757:                        wdcbit_bucket(wdc, len - xfer->c_bcount);
1.6.2.2 ! mellon   1758:                        xfer->c_skip += xfer->c_bcount;
1.2       bouyer   1759:                        xfer->c_bcount = 0;
                   1760:                } else {
                   1761:                        insw(wdc->sc_iobase + wd_data,
                   1762:                            xfer->databuf + xfer->c_skip, len / sizeof(short));
                   1763:                        xfer->c_skip += len;
                   1764:                        xfer->c_bcount -=len;
                   1765:                }
1.6.2.2 ! mellon   1766:                return 1;
1.2       bouyer   1767:
                   1768:        case PHASE_ABORTED:
                   1769:        case PHASE_COMPLETED:
                   1770: #ifdef ATAPI_DEBUG_WDC
                   1771:                printf("PHASE_COMPLETED\n");
                   1772: #endif
                   1773:                if (st & WDCS_ERR) {
                   1774:                        sc_xfer->error = XS_SENSE;
                   1775:                        sc_xfer->sense.atapi_sense = inb (wdc->sc_iobase + wd_error);
                   1776:                }
                   1777: #ifdef ATAPI_DEBUG_WDC
                   1778:                if (xfer->c_bcount != 0) {
                   1779:                        printf("wdc_atapi_intr warning: bcount value "
                   1780:                            "is %d after io\n", xfer->c_bcount);
                   1781:                }
                   1782: #endif
                   1783:                break;
                   1784:
                   1785:        default:
                   1786:         if (++retries<500) {
                   1787:             DELAY(100);
                   1788:             goto again;
                   1789:         }
                   1790:                printf("wdc_atapi_intr: unknown phase %d\n", phase);
                   1791:                if (st & WDCS_ERR) {
                   1792:                        sc_xfer->error = XS_SENSE;
                   1793:                        sc_xfer->sense.atapi_sense = inb (wdc->sc_iobase + wd_error);
                   1794:                } else {
                   1795:                        sc_xfer->error = XS_DRIVER_STUFFUP;
                   1796:                }
                   1797:        }
                   1798:
                   1799: #ifdef ATAPI_DEBUG_WDC
                   1800:                printf("wdc_atapi_intr: wdc_atapi_done() (end), error %d\n",
                   1801:                        sc_xfer->error);
                   1802: #endif
                   1803:        wdc_atapi_done(wdc, xfer);
1.5       bouyer   1804:        return (1);
1.2       bouyer   1805: }
                   1806:
                   1807:
                   1808: void
                   1809: wdc_atapi_done(wdc, xfer)
                   1810:        struct wdc_softc *wdc;
                   1811:        struct wdc_xfer *xfer;
                   1812: {
                   1813:        struct scsipi_xfer *sc_xfer = xfer->atapi_cmd;
                   1814:        int s;
                   1815:        int need_done =  xfer->c_flags & C_NEEDDONE;
                   1816:
                   1817: #ifdef ATAPI_DEBUG
                   1818:        printf("wdc_atapi_done: flags 0x%x\n", (u_int)xfer->c_flags);
                   1819: #endif
                   1820:        sc_xfer->resid = xfer->c_bcount;
1.6.2.2 ! mellon   1821:        wdc->sc_flags &= ~WDCF_IRQ_WAIT;
1.2       bouyer   1822:
                   1823:        /* remove this command from xfer queue */
                   1824:        wdc->sc_errors = 0;
                   1825:        xfer->c_skip = 0;
                   1826:        if ((xfer->c_flags & SCSI_POLL) == 0) {
                   1827:                s = splbio();
                   1828:                untimeout(wdctimeout, wdc);
                   1829:                TAILQ_REMOVE(&wdc->sc_xfer, xfer, c_xferchain);
                   1830:                wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR | WDCF_ACTIVE);
                   1831:                wdc_free_xfer(xfer);
                   1832:                sc_xfer->flags |= ITSDONE;
                   1833:                if (need_done) {
                   1834: #ifdef ATAPI_DEBUG
                   1835:                printf("wdc_atapi_done: scsipi_done\n");
                   1836: #endif
                   1837:                        scsipi_done(sc_xfer);
                   1838:                }
                   1839: #ifdef WDDEBUG
                   1840:                printf("wdcstart from wdc_atapi_intr, flags 0x%x\n",
                   1841:                    wdc->sc_flags);
                   1842: #endif
                   1843:                wdcstart(wdc);
                   1844:            splx(s);
1.6.2.2 ! mellon   1845:        } else {
1.2       bouyer   1846:                wdc->sc_flags &= ~(WDCF_SINGLE | WDCF_ERROR | WDCF_ACTIVE);
1.6.2.2 ! mellon   1847:                sc_xfer->flags |= ITSDONE;
        !          1848:        }
1.2       bouyer   1849: }
                   1850:
                   1851: #endif /* NATAPIBUS > 0 */

CVSweb <webmaster@jp.NetBSD.org>