Added support for wd detach (merge from NetBSD). Support for
authorcsapuntz <csapuntz@openbsd.org>
Mon, 10 Apr 2000 07:06:14 +0000 (07:06 +0000)
committercsapuntz <csapuntz@openbsd.org>
Mon, 10 Apr 2000 07:06:14 +0000 (07:06 +0000)
SCSI/ATAPI detach is not here yet.

Minor cleanup of wdc. Downgrade to UDMA mode 1 before going further.
Want to stay in UDMA modes because they're more error-resilient due to
a CRC.

Got rid of some of the ridiculous amount of softc sharing going on.
Hopefully, this will make the life of whoever goes in and fixes the
ref-counting to be correct easier.

sys/dev/ata/ata_wdc.c
sys/dev/ata/atavar.h
sys/dev/ata/wd.c
sys/dev/ata/wdvar.h
sys/dev/atapiscsi/atapiscsi.c
sys/dev/ic/wdc.c
sys/dev/ic/wdcvar.h
sys/dev/pci/pciide.c
sys/dev/pcmcia/wdc_pcmcia.c

index b9f075f..32147d4 100644 (file)
@@ -95,6 +95,7 @@
 #define DEBUG_STATUS 0x04
 #define DEBUG_FUNCS  0x08
 #define DEBUG_PROBE  0x10
+
 #ifdef WDCDEBUG
 int wdcdebug_wd_mask = 0;
 #define WDCDEBUG_PRINT(args, level) \
@@ -115,6 +116,7 @@ struct cfdriver wdc_cd = {
 void  wdc_ata_bio_start  __P((struct channel_softc *,struct wdc_xfer *));
 void  _wdc_ata_bio_start  __P((struct channel_softc *,struct wdc_xfer *));
 int   wdc_ata_bio_intr   __P((struct channel_softc *, struct wdc_xfer *, int));
+void  wdc_ata_bio_kill_xfer __P((struct channel_softc *,struct wdc_xfer *));
 void  wdc_ata_bio_done   __P((struct channel_softc *, struct wdc_xfer *)); 
 int   wdc_ata_ctrl_intr __P((struct channel_softc *, struct wdc_xfer *, int));
 int   wdc_ata_err __P((struct ata_drive_datas *, struct ata_bio *));
@@ -148,6 +150,7 @@ wdc_ata_bio(drvp, ata_bio)
        xfer->c_bcount = ata_bio->bcount;
        xfer->c_start = wdc_ata_bio_start;
        xfer->c_intr = wdc_ata_bio_intr;
+       xfer->c_kill_xfer = wdc_ata_bio_kill_xfer;
        wdc_exec_xfer(chp, xfer);
        return (ata_bio->flags & ATA_ITSDONE) ? WDC_COMPLETE : WDC_QUEUED;
 }
@@ -222,7 +225,7 @@ _wdc_ata_bio_start(chp, xfer)
                ata_delay = ATA_DELAY;
        else
                ata_delay = ATA_DELAY;
-again:
+ again:
        /*
         *
         * When starting a multi-sector transfer, or doing single-sector
@@ -238,7 +241,7 @@ again:
                        long blkdiff;
                        int i;
                        for (i = 0; (blkdiff = ata_bio->badsect[i]) != -1;
-                           i++) {
+                            i++) {
                                blkdiff -= ata_bio->blkno;
                                if (blkdiff < 0)
                                        continue;
@@ -255,7 +258,7 @@ again:
                                }
                                break;
                        }
-               /* Transfer is okay now. */
+                       /* Transfer is okay now. */
                }
                if (ata_bio->flags & ATA_LBA) {
                        sect = (ata_bio->blkno >> 0) & 0xff;
@@ -322,8 +325,8 @@ again:
                /* The number of blocks in the last stretch may be smaller. */
                nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
                if (ata_bio->nblks > nblks) {
-               ata_bio->nblks = nblks;
-               ata_bio->nbytes = xfer->c_bcount;
+                       ata_bio->nblks = nblks;
+                       ata_bio->nbytes = xfer->c_bcount;
                }
        }
        /* If this was a write and not using DMA, push the data. */
@@ -346,7 +349,7 @@ again:
                    ata_bio->nbytes);
        }
 
-intr:  /* Wait for IRQ (either real or polled) */
+ intr: /* Wait for IRQ (either real or polled) */
        if ((ata_bio->flags & ATA_POLL) == 0) {
                chp->ch_flags |= WDCF_IRQ_WAIT;
        } else {
@@ -357,7 +360,7 @@ intr:       /* Wait for IRQ (either real or polled) */
                        goto again;
        }
        return;
-timeout:
+ timeout:
        printf("%s:%d:%d: not ready, st=0x%02x, err=0x%02x\n",
            chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
            chp->ch_status, chp->ch_error);
@@ -506,6 +509,27 @@ end:
        return 1;
 }
 
+
+void
+wdc_ata_bio_kill_xfer(chp, xfer)
+       struct channel_softc *chp;
+       struct wdc_xfer *xfer;
+{
+       struct ata_bio *ata_bio = xfer->cmd;
+
+       untimeout(wdctimeout, chp);
+       /* remove this command from xfer queue */
+       wdc_free_xfer(chp, xfer);
+
+       ata_bio->flags |= ATA_ITSDONE;
+       ata_bio->error = ERR_NODEV;
+       ata_bio->r_error = WDCE_ABRT;
+       if ((ata_bio->flags & ATA_POLL) == 0) {
+               WDCDEBUG_PRINT(("wdc_ata_done: wddone\n"), DEBUG_XFERS);
+               wddone(ata_bio->wd);
+       }
+}
+
 void
 wdc_ata_bio_done(chp, xfer)
        struct channel_softc *chp;
@@ -536,7 +560,7 @@ wdc_ata_bio_done(chp, xfer)
        ata_bio->flags |= ATA_ITSDONE;
        if ((ata_bio->flags & ATA_POLL) == 0) {
                WDCDEBUG_PRINT(("wdc_ata_done: wddone\n"), DEBUG_XFERS);
-               wddone(chp->ch_drive[drive].drv_softc);
+               wddone(ata_bio->wd);
        }
        WDCDEBUG_PRINT(("wdcstart from wdc_ata_done, flags 0x%x\n",
            chp->ch_flags), DEBUG_XFERS);
index 859f76a..8448949 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: atavar.h,v 1.4 1999/10/09 03:42:03 csapuntz Exp $     */
+/*     $OpenBSD: atavar.h,v 1.5 2000/04/10 07:06:16 csapuntz Exp $     */
 /*     $NetBSD: atavar.h,v 1.13 1999/03/10 13:11:43 bouyer Exp $       */
 
 /*
@@ -55,6 +55,7 @@ struct ata_drive_datas {
 #define DRIVE_DMAERR   0x0100 /* Udma transfer had crc error, don't try DMA */
 #define DRIVE_DSCBA    0x0200 /* DSC in buffer availability mode */
 #define DRIVE_DSCWAIT  0x0400 /* In wait for DSC to be asserted */
+
     /*
      * Current setting of drive's PIO, DMA and UDMA modes.
      * Is initialised by the disks drivers at attach time, and may be
@@ -83,7 +84,8 @@ struct ata_drive_datas {
     /* downgrade mode after this many successive errors */
 #define NERRS_MAX 2
 
-    struct device *drv_softc; /* ATA/PI drive's softc, can be NULL */
+    char drive_name[31];
+    int  cf_flags;
     void *chnl_softc; /* channel softc */
 };
 
@@ -151,6 +153,8 @@ struct wdc_command {
     void *callback_arg;  /* argument passed to *callback() */
 };
 
+extern int at_poll;
+
 int wdc_exec_command __P((struct ata_drive_datas *, struct wdc_command*));
 #define WDC_COMPLETE 0x01
 #define WDC_QUEUED   0x02
index 5f14d80..6aa3eb0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: wd.c,v 1.11 2000/04/07 09:12:44 niklas Exp $ */
+/*     $OpenBSD: wd.c,v 1.12 2000/04/10 07:06:16 csapuntz Exp $ */
 /*     $NetBSD: wd.c,v 1.193 1999/02/28 17:15:27 explorer Exp $ */
 
 /*
@@ -88,6 +88,7 @@
 #if NRND > 0
 #include <sys/rnd.h>
 #endif
+#include <sys/vnode.h>
 
 #include <vm/vm.h>
 
 
 #define        WDUNIT(dev)             DISKUNIT(dev)
 #define        WDPART(dev)             DISKPART(dev)
+#define WDMINOR(unit, part)     DISKMINOR(unit, part)
 #define        MAKEWDDEV(maj, unit, part)      MAKEDISKDEV(maj, unit, part)
 
 #define        WDLABELDEV(dev) (MAKEWDDEV(major(dev), WDUNIT(dev), RAW_PART))
@@ -136,7 +138,6 @@ struct wd_softc {
        /* IDE disk soft states */
        struct ata_bio sc_wdc_bio; /* current transfer */
        struct buf *sc_bp; /* buf being transfered */
-       void *wdc_softc;   /* pointer to our parent */
        struct ata_drive_datas *drvp; /* Our controller's infos */
        int openings;
        struct ataparams sc_params;/* drive characteistics found */
@@ -152,6 +153,7 @@ struct wd_softc {
 #define WDF_LOADED       0x10 /* parameters loaded */
 #define WDF_WAIT       0x20 /* waiting for resources */
 #define WDF_LBA         0x40 /* using LBA mode */
+
        int sc_capacity;
        int cyl; /* actual drive parameters */
        int heads;
@@ -160,6 +162,7 @@ struct wd_softc {
 #if NRND > 0
        rndsource_element_t     rnd_source;
 #endif
+       void *sc_sdhook;
 };
 
 #define sc_drive sc_wdc_bio.drive
@@ -173,10 +176,14 @@ int       wdprobe         __P((struct device *, struct cfdata *, void *));
 int    wdprobe         __P((struct device *, void *, void *));
 #endif
 void   wdattach        __P((struct device *, struct device *, void *));
+int     wddetach __P((struct device *, int));
+int     wdactivate __P((struct device *, enum devact));
+void    wdzeroref __P((struct device *));
 int    wdprint __P((void *, char *));
 
 struct cfattach wd_ca = {
-       sizeof(struct wd_softc), wdprobe, wdattach
+       sizeof(struct wd_softc), wdprobe, wdattach,
+       wddetach, wdactivate, wdzeroref
 };
 
 #ifdef __OpenBSD__
@@ -228,8 +235,11 @@ bdev_decl(wd);
 #ifdef DKBAD
 void   bad144intern __P((struct wd_softc *));
 #endif
-int    wdlock  __P((struct wd_softc *));
-void   wdunlock        __P((struct wd_softc *));
+
+#define wdlock(wd)  disk_lock(&(wd)->sc_dk)
+#define wdunlock(wd)  disk_unlock(&(wd)->sc_dk)
+#define wdlookup(unit) (struct wd_softc *)device_lookup(&wd_cd, (unit))
+
 
 int
 wdprobe(parent, match_, aux)
@@ -282,13 +292,14 @@ wdattach(parent, self, aux)
        WDCDEBUG_PRINT(("wdattach\n"), DEBUG_FUNCS | DEBUG_PROBE);
 
        wd->openings = aa_link->aa_openings;
-       wd->drvp = aa_link->aa_drv_data;;
-       wd->wdc_softc = parent;
-       /* give back our softc to our caller */
-       wd->drvp->drv_softc = &wd->sc_dev;
+       wd->drvp = aa_link->aa_drv_data;
+
+       strncpy(wd->drvp->drive_name, wd->sc_dev.dv_xname, 
+               sizeof(wd->drvp->drive_name) - 1);
+       wd->drvp->cf_flags = wd->sc_dev.dv_cfdata->cf_flags;
 
        /* read our drive info */
-       if (wd_get_params(wd, AT_POLL, &wd->sc_params) != 0) {
+       if (wd_get_params(wd, at_poll, &wd->sc_params) != 0) {
                printf("%s: IDENTIFY failed\n", wd->sc_dev.dv_xname);
                return;
        }
@@ -364,7 +375,8 @@ wdattach(parent, self, aux)
        wd->sc_dk.dk_name = wd->sc_dev.dv_xname;
        disk_attach(&wd->sc_dk);
        wd->sc_wdc_bio.lp = wd->sc_dk.dk_label;
-       if (shutdownhook_establish(wd_shutdown, wd) == NULL)
+       wd->sc_sdhook = shutdownhook_establish(wd_shutdown, wd);
+       if (wd->sc_sdhook == NULL)
                printf("%s: WARNING: unable to establish shutdown hook\n",
                    wd->sc_dev.dv_xname); 
 #if NRND > 0
@@ -373,6 +385,79 @@ wdattach(parent, self, aux)
 #endif
 }
 
+int
+wdactivate(self, act)
+        struct device *self;
+        enum devact act;
+{
+        int rv = 0;
+
+        switch (act) {
+        case DVACT_ACTIVATE:
+                break;
+
+        case DVACT_DEACTIVATE:
+                /*
+                 * Nothing to do; we key off the device's DVF_ACTIVATE.
+                 */
+                break;
+        }
+        return (rv);
+}
+
+
+int
+wddetach(self, flags)
+        struct device *self;
+        int flags;
+{
+        struct wd_softc *sc = (struct wd_softc *)self;
+        struct buf *dp, *bp;
+        int s, bmaj, cmaj, mn;
+
+       /* Remove unprocessed buffers from queue */
+       s = splbio();
+       for (dp = &sc->sc_q; (bp = dp->b_actf) != NULL; ) {
+               dp->b_actf = bp->b_actf;
+               
+               bp->b_error = ENXIO;
+               bp->b_flags |= B_ERROR;
+               biodone(bp);
+       }
+       splx(s);
+
+        /* locate the major number */
+        mn = WDMINOR(self->dv_unit, 0);
+
+        for (bmaj = 0; bmaj < nblkdev; bmaj++)
+                if (bdevsw[bmaj].d_open == wdopen)
+                       vdevgone(bmaj, mn, mn + MAXPARTITIONS - 1, VBLK);
+        for (cmaj = 0; cmaj < nchrdev; cmaj++)
+                if (cdevsw[cmaj].d_open == wdopen)
+                       vdevgone(cmaj, mn, mn + MAXPARTITIONS - 1, VCHR);
+
+       /* Get rid of the shutdown hook. */
+       if (sc->sc_sdhook != NULL)
+               shutdownhook_disestablish(sc->sc_sdhook);
+
+#if NRND > 0
+        /* Unhook the entropy source. */
+        rnd_detach_source(&sc->rnd_source);
+#endif
+
+        return (0);
+}
+
+void
+wdzeroref(self)
+        struct device *self;
+{
+        struct wd_softc *sc = (struct wd_softc *)self;
+
+        /* Detach disk. */
+        disk_detach(&sc->sc_dk);
+}
+
 /*
  * Read/write routine for a buffer.  Validates the arguments and schedules the
  * transfer.  Does not wait for the transfer to complete.
@@ -381,8 +466,15 @@ void
 wdstrategy(bp)
        struct buf *bp;
 {
-       struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(bp->b_dev)];
+       struct wd_softc *wd;
        int s;
+
+       wd = wdlookup(WDUNIT(bp->b_dev));
+       if (wd == NULL) {
+               bp->b_error = ENXIO;
+               goto bad;
+       }
+
        WDCDEBUG_PRINT(("wdstrategy (%s)\n", wd->sc_dev.dv_xname),
            DEBUG_XFERS);
        
@@ -417,6 +509,7 @@ wdstrategy(bp)
        disksort(&wd->sc_q, bp);
        wdstart(wd);
        splx(s);
+       device_unref(&wd->sc_dev);
        return;
 bad:
        bp->b_flags |= B_ERROR;
@@ -424,6 +517,8 @@ done:
        /* Toss transfer; we're done early. */
        bp->b_resid = bp->b_bcount;
        biodone(bp);
+       if (wd != NULL)
+               device_unref(&wd->sc_dev);
 }
 
 /*
@@ -486,6 +581,7 @@ __wdstart(wd, bp)
                wd->sc_wdc_bio.flags |= ATA_READ;
        wd->sc_wdc_bio.bcount = bp->b_bcount;
        wd->sc_wdc_bio.databuf = bp->b_data;
+       wd->sc_wdc_bio.wd = wd;
        /* Instrumentation. */
        disk_busy(&wd->sc_dk);
        switch (wdc_ata_bio(wd->drvp, &wd->sc_wdc_bio)) {
@@ -515,6 +611,10 @@ wddone(v)
        bp->b_resid = wd->sc_wdc_bio.bcount;
        errbuf[0] = '\0';
        switch (wd->sc_wdc_bio.error) {
+       case ERR_NODEV:
+               bp->b_flags |= B_ERROR;
+               bp->b_error = ENXIO;
+               break;
        case ERR_DMA:
                errbuf = "DMA error";
                goto retry;
@@ -530,7 +630,8 @@ wddone(v)
                    (wd->sc_wdc_bio.r_error & ~(WDCE_MC | WDCE_MCR)) == 0)
                        goto noerror;
                ata_perror(wd->drvp, wd->sc_wdc_bio.r_error, errbuf);
-retry:         /* Just reset and retry. Can we do more ? */
+retry:
+               /* Just reset and retry. Can we do more ? */
                wdc_reset_channel(wd->drvp);
                diskerr(bp, "wd", errbuf, LOG_PRINTF,
                    wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label);
@@ -594,53 +695,6 @@ wdwrite(dev, uio, flags)
        return (physio(wdstrategy, NULL, dev, B_WRITE, minphys, uio));
 }
 
-/*
- * Wait interruptibly for an exclusive lock.
- *
- * XXX
- * Several drivers do this; it should be abstracted and made MP-safe.
- */
-int
-wdlock(wd)
-       struct wd_softc *wd;
-{
-       int error;
-       int s;
-
-       WDCDEBUG_PRINT(("wdlock\n"), DEBUG_FUNCS);
-
-       s = splbio();
-
-       while ((wd->sc_flags & WDF_LOCKED) != 0) {
-               wd->sc_flags |= WDF_WANTED;
-               if ((error = tsleep(wd, PRIBIO | PCATCH,
-                   "wdlck", 0)) != 0) {
-                       splx(s);
-                       return error;
-               }
-       }
-       wd->sc_flags |= WDF_LOCKED;
-       splx(s);
-       return 0;
-}
-
-/*
- * Unlock and wake up any waiters.
- */
-void
-wdunlock(wd)
-       struct wd_softc *wd;
-{
-
-       WDCDEBUG_PRINT(("wdunlock\n"), DEBUG_FUNCS);
-
-       wd->sc_flags &= ~WDF_LOCKED;
-       if ((wd->sc_flags & WDF_WANTED) != 0) {
-               wd->sc_flags &= ~WDF_WANTED;
-               wakeup(wd);
-       }
-}
-
 int
 wdopen(dev, flag, fmt, p)
        dev_t dev;
@@ -652,10 +706,9 @@ wdopen(dev, flag, fmt, p)
        int error;
 
        WDCDEBUG_PRINT(("wdopen\n"), DEBUG_FUNCS);
+
        unit = WDUNIT(dev);
-       if (unit >= wd_cd.cd_ndevs)
-               return ENXIO;
-       wd = wd_cd.cd_devs[unit];
+       wd = wdlookup(unit);
        if (wd == NULL)
                return ENXIO;
 
@@ -717,6 +770,7 @@ wdopen(dev, flag, fmt, p)
            wd->sc_dk.dk_copenmask | wd->sc_dk.dk_bopenmask;
 
        wdunlock(wd);
+       device_unref(&wd->sc_dev);
        return 0;
 
 bad:
@@ -730,6 +784,7 @@ bad4:
        if (wd->sc_dk.dk_openmask == 0)
                wdc_ata_delref(wd->drvp);
 #endif
+       device_unref(&wd->sc_dev);
        return error;
 }
 
@@ -739,13 +794,17 @@ wdclose(dev, flag, fmt, p)
        int flag, fmt;
        struct proc *p;
 {
-       struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(dev)];
+       struct wd_softc *wd;
        int part = WDPART(dev);
-       int error;
+       int error = 0;
+
+       wd = wdlookup(WDUNIT(dev));
+       if (wd == NULL)
+               return ENXIO;
        
        WDCDEBUG_PRINT(("wdclose\n"), DEBUG_FUNCS);
        if ((error = wdlock(wd)) != 0)
-               return error;
+               goto exit;
 
        switch (fmt) {
        case S_IFCHR:
@@ -767,7 +826,10 @@ wdclose(dev, flag, fmt, p)
        }
 
        wdunlock(wd);
-       return 0;
+
+ exit:
+       device_unref(&wd->sc_dev);
+       return (error);
 }
 
 void
@@ -775,7 +837,6 @@ wdgetdefaultlabel(wd, lp)
        struct wd_softc *wd;
        struct disklabel *lp;
 {
-
        WDCDEBUG_PRINT(("wdgetdefaultlabel\n"), DEBUG_FUNCS);
        bzero(lp, sizeof(struct disklabel));
 
@@ -867,13 +928,19 @@ wdioctl(dev, xfer, addr, flag, p)
        int flag;
        struct proc *p;
 {
-       struct wd_softc *wd = wd_cd.cd_devs[WDUNIT(dev)];
-       int error;
+       struct wd_softc *wd;
+       int error = 0;
 
        WDCDEBUG_PRINT(("wdioctl\n"), DEBUG_FUNCS);
 
-       if ((wd->sc_flags & WDF_LOADED) == 0)
-               return EIO;
+       wd = wdlookup(WDUNIT(dev));
+       if (wd == NULL)
+               return ENXIO;
+       
+       if ((wd->sc_flags & WDF_LOADED) == 0) {
+               error = EIO;
+               goto exit;
+       }
 
        switch (xfer) {
 #ifdef DKBAD
@@ -883,38 +950,40 @@ wdioctl(dev, xfer, addr, flag, p)
                DKBAD(wd->sc_dk.dk_cpulabel) = *(struct dkbad *)addr;
                wd->sc_dk.dk_label->d_flags |= D_BADSECT;
                bad144intern(wd);
-               return 0;
+               goto exit;
 #endif
 
        case DIOCRLDINFO:
                wdgetdisklabel(dev, wd, wd->sc_dk.dk_label,
                    wd->sc_dk.dk_cpulabel, 0);
-               return 0;
+               goto exit;
        case DIOCGPDINFO: {
                        struct cpu_disklabel osdep;
 
                        wdgetdisklabel(dev, wd, (struct disklabel *)addr,
                            &osdep, 1);
-                       return 0;
+                       goto exit;
                }
 
        case DIOCGDINFO:
                *(struct disklabel *)addr = *(wd->sc_dk.dk_label);
-               return 0;
+               goto exit;
        
        case DIOCGPART:
                ((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label;
                ((struct partinfo *)addr)->part =
                    &wd->sc_dk.dk_label->d_partitions[WDPART(dev)];
-               return 0;
+               goto exit;
        
        case DIOCWDINFO:
        case DIOCSDINFO:
-               if ((flag & FWRITE) == 0)
-                       return EBADF;
+               if ((flag & FWRITE) == 0) {
+                       error = EBADF;
+                       goto exit;
+               }
 
                if ((error = wdlock(wd)) != 0)
-                       return error;
+                       goto exit;
                wd->sc_flags |= WDF_LABELLING;
 
                error = setdisklabel(wd->sc_dk.dk_label,
@@ -931,21 +1000,24 @@ wdioctl(dev, xfer, addr, flag, p)
 
                wd->sc_flags &= ~WDF_LABELLING;
                wdunlock(wd);
-               return error;
+               goto exit;
        
        case DIOCWLABEL:
-               if ((flag & FWRITE) == 0)
-                       return EBADF;
+               if ((flag & FWRITE) == 0) {
+                       error = EBADF;
+                       goto exit;
+               }
+
                if (*(int *)addr)
                        wd->sc_flags |= WDF_WLABEL;
                else
                        wd->sc_flags &= ~WDF_WLABEL;
-               return 0;
+               goto exit;
 
 #ifndef __OpenBSD__
        case DIOCGDEFLABEL:
                wdgetdefaultlabel(wd, (struct disklabel *)addr);
-               return 0;
+               goto exit;
 #endif
 
 #ifdef notyet
@@ -972,7 +1044,7 @@ wdioctl(dev, xfer, addr, flag, p)
                fop->df_count -= auio.uio_resid;
                fop->df_reg[0] = wdc->sc_status;
                fop->df_reg[1] = wdc->sc_error;
-               return error;
+               goto exit;
                }
 #endif
 
@@ -981,8 +1053,10 @@ wdioctl(dev, xfer, addr, flag, p)
                 * Make sure this command is (relatively) safe first
                 */
                if ((((atareq_t *) addr)->flags & ATACMD_READ) == 0 &&
-                   (flag & FWRITE) == 0)
-                       return (EBADF);
+                   (flag & FWRITE) == 0) {
+                       error = EBADF;
+                       goto exit;
+               }
                {
                struct wd_ioctl *wi;
                atareq_t *atareq = (atareq_t *) addr;
@@ -1020,16 +1094,21 @@ wdioctl(dev, xfer, addr, flag, p)
                }
                *atareq = wi->wi_atareq;
                wi_free(wi);
-               return(error);
+               goto exit;
                }
 
        default:
-               return ENOTTY;
+               error = ENOTTY;
+               goto exit;
        }
 
 #ifdef DIAGNOSTIC
        panic("wdioctl: impossible");
 #endif
+
+ exit:
+       device_unref(&wd->sc_dev);
+       return (error);
 }
 
 #ifdef B_FORMAT
@@ -1047,30 +1126,33 @@ wdsize(dev)
        dev_t dev;
 {
        struct wd_softc *wd;
-       int part, unit, omask;
+       int part, omask;
        int size;
 
        WDCDEBUG_PRINT(("wdsize\n"), DEBUG_FUNCS);
 
-       unit = WDUNIT(dev);
-       if (unit >= wd_cd.cd_ndevs)
-               return (-1);
-       wd = wd_cd.cd_devs[unit];
+       wd = wdlookup(WDUNIT(dev));
        if (wd == NULL)
                return (-1);
 
        part = WDPART(dev);
        omask = wd->sc_dk.dk_openmask & (1 << part);
 
-       if (omask == 0 && wdopen(dev, 0, S_IFBLK, NULL) != 0)
-               return (-1);
+       if (omask == 0 && wdopen(dev, 0, S_IFBLK, NULL) != 0) {
+               size = -1;
+               goto exit;
+       }
+
        if (wd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
                size = -1;
        else
                size = wd->sc_dk.dk_label->d_partitions[part].p_size *
                    (wd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
        if (omask == 0 && wdclose(dev, 0, S_IFBLK, NULL) != 0)
-               return (-1);
+               size = -1;
+
+ exit:
+       device_unref(&wd->sc_dev);
        return (size);
 }
 
@@ -1103,10 +1185,8 @@ wddump(dev, blkno, va, size)
        wddoingadump = 1;
 
        unit = WDUNIT(dev);
-       if (unit >= wd_cd.cd_ndevs)
-               return ENXIO;
-       wd = wd_cd.cd_devs[unit];
-       if (wd == (struct wd_softc *)0)
+       wd = wdlookup(unit);
+       if (wd == NULL)
                return ENXIO;
 
        part = WDPART(dev);
@@ -1147,6 +1227,7 @@ again:
                wd->sc_wdc_bio.bcount =
                        min(nblks, wddumpmulti) * lp->d_secsize;
                wd->sc_wdc_bio.databuf = va;
+               wd->sc_wdc_bio.wd = wd;
 #ifndef WD_DUMP_NOT_TRUSTED
                switch (wdc_ata_bio(wd->drvp, &wd->sc_wdc_bio)) {
                case WDC_TRY_AGAIN:
index 46fb4ee..5dc67ff 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: wdvar.h,v 1.1 1999/07/18 21:25:18 csapuntz Exp $      */
+/*     $OpenBSD: wdvar.h,v 1.2 2000/04/10 07:06:16 csapuntz Exp $      */
 /*     $NetBSD: wdvar.h,v 1.3 1998/11/11 19:38:27 bouyer Exp $ */
 
 /*
@@ -58,8 +58,10 @@ struct ata_bio {
 #define ERR_DF 2 /* Drive fault */
 #define ERR_DMA 3 /* DMA error */
 #define TIMEOUT 4 /* device timed out */
+#define ERR_NODEV 5 /* device bas been detached */
     u_int8_t r_error; /* copy of error register */
     daddr_t badsect[127];    /* 126 plus trailing -1 marker */
+    struct wd_softc *wd;
 };
 
 /* drive states stored in ata_drive_datas */
index d888f69..d8a5aab 100644 (file)
@@ -1,4 +1,4 @@
-/*      $OpenBSD: atapiscsi.c,v 1.24 2000/01/12 17:14:02 csapuntz Exp $     */
+/*      $OpenBSD: atapiscsi.c,v 1.25 2000/04/10 07:06:17 csapuntz Exp $     */
 
 /*
  * This code is derived from code with the copyright below.
@@ -241,8 +241,11 @@ atapiscsi_attach(parent, self, aux)
                    (wdc_atapi_get_params(chp, drive, id) == COMPLETE)) {
                        /* Temporarily, the device will be called
                           atapiscsi. */
-                       drvp->drv_softc = (struct device*)as;
-                       wdc_probe_caps(drvp, id);
+                       strncpy(drvp->drive_name, as->sc_dev.dv_xname,
+                           sizeof(drvp->drive_name) - 1);
+                       drvp->cf_flags = as->sc_dev.dv_cfdata->cf_flags;
+
+                       wdc_probe_caps(drvp, id); 
 
                        WDCDEBUG_PRINT(
                            ("general config %04x capabilities %04x ",
@@ -283,10 +286,13 @@ atapiscsi_attach(parent, self, aux)
                        struct scsi_link *link = scsi->sc_link[drive][0];
                        struct ata_drive_datas *drvp = &chp->ch_drive[drive];
 
-                       if (drvp->drv_softc == (struct device *)as && link) {
-                               drvp->drv_softc = link->device_softc;
-                               wdc_print_caps(drvp);
-                       }
+                       if (!link) continue;
+
+                       strncpy(drvp->drive_name, 
+                               ((struct device *)(link->device_softc))->dv_xname, 
+                               sizeof(drvp->drive_name) - 1);
+                       
+                       wdc_print_caps(drvp);
                }
        }
 }
@@ -344,7 +350,7 @@ wdc_atapi_get_params(chp, drive, id)
        wdc_c.r_command = ATAPI_SOFT_RESET;
        wdc_c.r_st_bmask = 0;
        wdc_c.r_st_pmask = 0;
-       wdc_c.flags = AT_POLL;
+       wdc_c.flags = at_poll;
        wdc_c.timeout = ATAPI_RESET_WAIT;
        if (wdc_exec_command(drvp, &wdc_c) != WDC_COMPLETE) {
                printf("wdc_atapi_get_params: ATAPI_SOFT_RESET failed for"
@@ -367,7 +373,7 @@ wdc_atapi_get_params(chp, drive, id)
        delay(5000);
 
  retry:
-       if (ata_get_params(drvp, AT_POLL, id) != 0) {
+       if (ata_get_params(drvp, at_poll, id) != 0) {
                WDCDEBUG_PRINT(("wdc_atapi_get_params: ATAPI_IDENTIFY_DEVICE "
                    "failed for drive %s:%d:%d\n",
                    chp->wdc->sc_dev.dv_xname, chp->channel, drive), 
@@ -1451,7 +1457,6 @@ wdc_atapi_done(chp, xfer, timeout)
        int timeout;
 {
        struct scsi_xfer *sc_xfer = xfer->cmd;
-       int need_done = xfer->c_flags & C_NEEDDONE;
        struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
        int doing_dma = xfer->c_flags & C_DMA;
 
@@ -1471,7 +1476,7 @@ wdc_atapi_done(chp, xfer, timeout)
                        wdc_downgrade_mode(drvp);
        }
 
-       if (need_done) {
+       if (!(xfer->c_flags & C_POLL)) {
                WDCDEBUG_PRINT(("wdc_atapi_done: scsi_done\n"), DEBUG_XFERS);
                scsi_done(sc_xfer);
        }
index 0601039..6760fd1 100644 (file)
@@ -1,4 +1,4 @@
-/*      $OpenBSD: wdc.c,v 1.15 1999/12/14 08:28:15 csapuntz Exp $     */
+/*      $OpenBSD: wdc.c,v 1.16 2000/04/10 07:06:14 csapuntz Exp $     */
 /*     $NetBSD: wdc.c,v 1.68 1999/06/23 19:00:17 bouyer Exp $ */
 
 
@@ -109,6 +109,7 @@ void  __wdccommand_done __P((struct channel_softc *, struct wdc_xfer *));
 void  __wdccommand_start __P((struct channel_softc *, struct wdc_xfer *));     
 int   __wdccommand_intr __P((struct channel_softc *, struct wdc_xfer *, int));
 int   wdprint __P((void *, const char *));
+void  wdc_kill_pending __P((struct channel_softc *));
 
 
 #define DEBUG_INTR   0x01
@@ -118,6 +119,7 @@ int   wdprint __P((void *, const char *));
 #define DEBUG_PROBE  0x10
 #define DEBUG_STATUSX 0x20
 #define DEBUG_SDRIVE 0x40
+#define DEBUG_DETACH 0x80
 
 #ifdef WDCDEBUG
 int wdcdebug_mask = 0;
@@ -127,6 +129,7 @@ int wdc_nxfer = 0;
 #define WDCDEBUG_PRINT(args, level)
 #endif
 
+int at_poll = AT_POLL;
 
 u_int8_t wdc_default_read_reg __P((struct channel_softc *, enum wdc_regs));
 void wdc_default_write_reg __P((struct channel_softc *, enum wdc_regs, u_int8_t));
@@ -366,7 +369,6 @@ wdcprobe(chp)
        /*
         * Sanity check to see if the wdc channel responds at all.
         */
-
        if (chp->wdc == NULL ||
            (chp->wdc->cap & WDC_CAPABILITY_NO_EXTRA_RESETS) == 0) {
                CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM);
@@ -384,7 +386,7 @@ wdcprobe(chp)
                        ret_value &= ~0x01;
                if (st1 == 0xff)
                        ret_value &= ~0x02;
-               if (ret_value == 0)
+               if (ret_value == 0) 
                        return 0;
        }
 
@@ -446,6 +448,24 @@ wdcprobe(chp)
        return (ret_value);     
 }
 
+/*
+ * Call activate routine of underlying devices.
+ */
+int
+wdcactivate(self, act)
+       struct device *self;
+       enum devact act;
+{
+       int error = 0;
+       int s;
+
+       s = splbio();
+       config_activate_children(self, act);
+       splx(s);
+
+       return (error);
+}
+
 void
 wdcattach(chp)
        struct channel_softc *chp;
@@ -457,6 +477,10 @@ wdcattach(chp)
        struct ata_atapi_attach aa_link;
        struct ataparams params;
        static int inited = 0;
+       extern int cold;
+
+       if (!cold)
+               at_poll = AT_WAIT;
 
 #ifndef __OpenBSD__
        if ((error = wdc_addref(chp)) != 0) {
@@ -482,7 +506,7 @@ wdcattach(chp)
                inited++;
        }
        TAILQ_INIT(&chp->ch_queue->sc_xfer);
-
+       
        for (i = 0; i < 2; i++) {
                chp->ch_drive[i].chnl_softc = chp;
                chp->ch_drive[i].drive = i;
@@ -498,7 +522,7 @@ wdcattach(chp)
                        chp->ch_flags |= WDCF_ONESLAVE;
 
                /* Issue a IDENTIFY command, to try to detect slave ghost */
-               if (ata_get_params(&chp->ch_drive[i], AT_POLL, &params) ==
+               if (ata_get_params(&chp->ch_drive[i], at_poll, &params) ==
                    CMD_OK) {
                        /* If IDENTIFY succeded, this is not an OLD ctrl */
                        chp->ch_drive[0].drive_flags &= ~DRIVE_OLD;
@@ -600,7 +624,7 @@ wdcattach(chp)
         *  ones
         */
        for (i = 0; i < 2; i++) {
-               if (chp->ch_drive[i].drv_softc == NULL)
+               if (chp->ch_drive[i].drive_name[0] == 0)
                        chp->ch_drive[i].drive_flags = 0;
                else
                        chp->ch_drive[i].state = 0;
@@ -685,6 +709,22 @@ wdcstart(chp)
        xfer->c_start(chp, xfer);
 }
 
+int
+wdcdetach(chp, flags)
+       struct channel_softc *chp;
+       int flags;
+{
+       int s, rv;
+
+       s = splbio();
+       wdc_kill_pending(chp);
+
+       rv = config_detach_children((struct device *)chp->wdc, flags);
+       splx(s);
+
+       return (rv);
+}
+
 /* restart an interrupted I/O */
 void
 wdcrestart(v)
@@ -711,6 +751,7 @@ wdcintr(arg)
 {
        struct channel_softc *chp = arg;
        struct wdc_xfer *xfer;
+       int ret;
 
        if ((chp->ch_flags & WDCF_IRQ_WAIT) == 0) {
                WDCDEBUG_PRINT(("wdcintr: inactive controller\n"), DEBUG_INTR);
@@ -721,7 +762,12 @@ wdcintr(arg)
        untimeout(wdctimeout, chp);
        chp->ch_flags &= ~WDCF_IRQ_WAIT;
        xfer = chp->ch_queue->sc_xfer.tqh_first;
-       return xfer->c_intr(chp, xfer, 1);
+        ret = xfer->c_intr(chp, xfer, 1);
+#if notyet
+       if (ret == 0)
+               chp->ch_flags |= WDCF_IRQ_WAIT;
+#endif
+       return (ret);
 }
 
 /* Put all disk in RESET state */
@@ -746,6 +792,9 @@ wdcreset(chp, verb)
 {
        int drv_mask1, drv_mask2;
 
+       if (!chp->_vtbl)
+               chp->_vtbl = &wdc_default_vtbl;
+
        CHP_WRITE_REG(chp, wdr_sdh, WDSD_IBM); /* master */
        CHP_WRITE_REG(chp, wdr_ctlr, WDCTL_RST | WDCTL_IDS);
        delay(1000);
@@ -941,10 +990,9 @@ wdc_probe_caps(drvp, params)
        struct ataparams *params;
 {
        struct channel_softc *chp = drvp->chnl_softc;
-       struct device *drv_dev = drvp->drv_softc;
        struct wdc_softc *wdc = chp->wdc;
        int i, printed;
-       int cf_flags;
+       int cf_flags = drvp->cf_flags;
 
        if ((wdc->cap & (WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32)) ==
            (WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32)) {
@@ -956,7 +1004,7 @@ wdc_probe_caps(drvp, params)
                 * and compare results.
                 */
                drvp->drive_flags |= DRIVE_CAP32;
-               ata_get_params(drvp, AT_POLL, &params2);
+               ata_get_params(drvp, at_poll, &params2);
                if (bcmp(params, &params2, sizeof(struct ataparams)) != 0) {
                        /* Not good. fall back to 16bits */
                        drvp->drive_flags &= ~DRIVE_CAP32;
@@ -1006,7 +1054,7 @@ wdc_probe_caps(drvp, params)
                         */
                        if ((wdc->cap & WDC_CAPABILITY_MODE) != 0)
                                if (ata_set_mode(drvp, 0x08 | (i + 3),
-                                  AT_POLL) != CMD_OK)
+                                  at_poll) != CMD_OK)
                                        continue;
                        if (!printed) { 
                                printed = 1;
@@ -1036,7 +1084,7 @@ wdc_probe_caps(drvp, params)
                                continue;
                        if ((wdc->cap & WDC_CAPABILITY_DMA) &&
                            (wdc->cap & WDC_CAPABILITY_MODE))
-                               if (ata_set_mode(drvp, 0x20 | i, AT_POLL)
+                               if (ata_set_mode(drvp, 0x20 | i, at_poll)
                                    != CMD_OK)
                                        continue;
                        if (!printed) {
@@ -1060,7 +1108,7 @@ wdc_probe_caps(drvp, params)
                                if ((wdc->cap & WDC_CAPABILITY_MODE) &&
                                    (wdc->cap & WDC_CAPABILITY_UDMA))
                                        if (ata_set_mode(drvp, 0x40 | i,
-                                           AT_POLL) != CMD_OK)
+                                           at_poll) != CMD_OK)
                                                continue;
                                if (wdc->cap & WDC_CAPABILITY_UDMA) {
                                        if ((wdc->cap & WDC_CAPABILITY_MODE) &&
@@ -1082,7 +1130,6 @@ wdc_probe_caps(drvp, params)
                else if (drvp->PIO_cap > 2)
                        drvp->ata_vers = 2; /* should be at last ATA-2 */
        }
-       cf_flags = drv_dev->dv_cfdata->cf_flags;
        if (cf_flags & ATA_CONFIG_PIO_SET) {
                drvp->PIO_mode =
                    (cf_flags & ATA_CONFIG_PIO_MODES) >> ATA_CONFIG_PIO_OFF;
@@ -1178,9 +1225,7 @@ void
 wdc_print_caps(drvp)
        struct ata_drive_datas *drvp;
 {
-       struct device *drv_dev = drvp->drv_softc;
-
-       printf("%s: can use ", drv_dev->dv_xname);
+       printf("%s: can use ", drvp->drive_name);
 
        if (drvp->drive_flags & DRIVE_CAP32) {
                printf("32-bit");
@@ -1209,9 +1254,8 @@ wdc_downgrade_mode(drvp)
        struct ata_drive_datas *drvp;
 {
        struct channel_softc *chp = drvp->chnl_softc;
-       struct device *drv_dev = drvp->drv_softc;
        struct wdc_softc *wdc = chp->wdc;
-       int cf_flags = drv_dev->dv_cfdata->cf_flags;
+       int cf_flags = drvp->cf_flags;
 
        /* if drive or controller don't know its mode, we can't do much */
        if ((drvp->drive_flags & DRIVE_MODE) == 0 ||
@@ -1227,31 +1271,29 @@ wdc_downgrade_mode(drvp)
         * If we were using Ultra-DMA mode > 2, downgrade to mode 2 first.
         * Maybe we didn't properly notice the cable type
         */
-       if ((drvp->drive_flags & DRIVE_UDMA) && drvp->UDMA_mode > 2) {
-               drvp->UDMA_mode = 2;
-               printf("%s: transfer error, downgrading to DMA mode %d\n",
-                   drv_dev->dv_xname, drvp->UDMA_mode);
-       }
-
-       /*
-        * If we were using ultra-DMA, don't downgrade to multiword DMA
-        * if we noticed a CRC error. It has been noticed that CRC errors
-        * in ultra-DMA lead to silent data corruption in multiword DMA.
-        * Data corruption is less likely to occur in PIO mode.
-        */
-
-       if ((drvp->drive_flags & DRIVE_UDMA) &&
+       if ((drvp->drive_flags & DRIVE_UDMA) && drvp->UDMA_mode >= 2) {
+               drvp->UDMA_mode = (drvp->UDMA_mode == 2) ? 1 : 2;
+               printf("%s: transfer error, downgrading to Ultra-DMA mode %d\n",
+                   drvp->drive_name, drvp->UDMA_mode);
+       } else  if ((drvp->drive_flags & DRIVE_UDMA) &&
            (drvp->drive_flags & DRIVE_DMAERR) == 0) {
+               /* 
+                * If we were using ultra-DMA, don't downgrade to
+                * multiword DMA if we noticed a CRC error. It has
+                * been noticed that CRC errors in ultra-DMA lead to
+                * silent data corruption in multiword DMA.  Data
+                * corruption is less likely to occur in PIO mode.  
+                */
                drvp->drive_flags &= ~DRIVE_UDMA;
                drvp->drive_flags |= DRIVE_DMA;
                drvp->DMA_mode = drvp->DMA_cap;
                printf("%s: transfer error, downgrading to DMA mode %d\n",
-                   drv_dev->dv_xname, drvp->DMA_mode);
+                   drvp->drive_name, drvp->DMA_mode);
        } else if (drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) {
                drvp->drive_flags &= ~(DRIVE_DMA | DRIVE_UDMA);
                drvp->PIO_mode = drvp->PIO_cap;
                printf("%s: transfer error, downgrading to PIO mode %d\n",
-                   drv_dev->dv_xname, drvp->PIO_mode);
+                   drvp->drive_name, drvp->PIO_mode);
        } else /* already using PIO, can't downgrade */
                return 0;
 
@@ -1289,6 +1331,7 @@ wdc_exec_command(drvp, wdc_c)
        xfer->cmd = wdc_c;
        xfer->c_start = __wdccommand_start;
        xfer->c_intr = __wdccommand_intr;
+       xfer->c_kill_xfer = __wdccommand_done;
 
        s = splbio();
        wdc_exec_xfer(chp, xfer);
@@ -1413,7 +1456,6 @@ __wdccommand_done(chp, xfer)
        struct channel_softc *chp;
        struct wdc_xfer *xfer;
 {
-       int needdone = xfer->c_flags & C_NEEDDONE;
        struct wdc_command *wdc_c = xfer->cmd;
 
        WDCDEBUG_PRINT(("__wdccommand_done %s:%d:%d\n",
@@ -1442,12 +1484,12 @@ __wdccommand_done(chp, xfer)
        }
        wdc_free_xfer(chp, xfer);
        WDCDEBUG_PRINT(("__wdccommand_done before callback\n"), DEBUG_INTR);
-       if (needdone) {
-               if (wdc_c->flags & AT_WAIT)
-                       wakeup(wdc_c);
-               else
+
+       if (wdc_c->flags & AT_WAIT)
+               wakeup(wdc_c);
+       else
+               if (wdc_c->callback)
                        wdc_c->callback(wdc_c->callback_arg);
-       }
        wdcstart(chp);
        WDCDEBUG_PRINT(("__wdccommand_done returned\n"), DEBUG_INTR);
        return;
@@ -1532,7 +1574,6 @@ wdc_exec_xfer(chp, xfer)
        WDCDEBUG_PRINT(("wdcstart from wdc_exec_xfer, flags 0x%x\n",
            chp->ch_flags), DEBUG_XFERS);
        wdcstart(chp);
-       xfer->c_flags |= C_NEEDDONE; /* we can now call upper level done() */
 }
 
 struct wdc_xfer *
@@ -1591,6 +1632,24 @@ wdc_free_xfer(chp, xfer)
        splx(s);
 }
 
+
+/*
+ * Kill off all pending xfers for a channel_softc.
+ *
+ * Must be called at splbio().
+ */
+void
+wdc_kill_pending(chp)
+       struct channel_softc *chp;
+{
+       struct wdc_xfer *xfer;
+
+       while ((xfer = TAILQ_FIRST(&chp->ch_queue->sc_xfer)) != NULL) {
+               chp = xfer->chp;
+               (*xfer->c_kill_xfer)(chp, xfer);
+       }
+}
+
 static void
 __wdcerror(chp, msg) 
        struct channel_softc *chp;
@@ -1600,18 +1659,11 @@ __wdcerror(chp, msg)
        if (xfer == NULL)
                printf("%s:%d: %s\n", chp->wdc->sc_dev.dv_xname, chp->channel,
                    msg);
-       else {
-               struct device *drv_dev = chp->ch_drive[xfer->drive].drv_softc;
-
-               if (drv_dev) {
-                       printf("%s(%s:%d:%d): %s\n", drv_dev->dv_xname,
-                              chp->wdc->sc_dev.dv_xname,
-                              chp->channel, xfer->drive, msg);
-               } else {
-                       printf("%s:%d:%d: %s\n", chp->wdc->sc_dev.dv_xname,
-                              chp->channel, xfer->drive, msg);
-               }
-       }
+       else 
+               printf("%s(%s:%d:%d): %s\n", 
+                   chp->ch_drive[xfer->drive].drive_name,
+                   chp->wdc->sc_dev.dv_xname,
+                   chp->channel, xfer->drive, msg);
 }
 
 /* 
index efc9a1c..3aedbec 100644 (file)
@@ -1,4 +1,4 @@
-/*      $OpenBSD: wdcvar.h,v 1.7 1999/12/14 18:07:43 csapuntz Exp $     */
+/*      $OpenBSD: wdcvar.h,v 1.8 2000/04/10 07:06:15 csapuntz Exp $     */
 /*     $NetBSD: wdcvar.h,v 1.17 1999/04/11 20:50:29 bouyer Exp $       */
 
 /*-
@@ -70,7 +70,7 @@ struct channel_softc { /* Per channel data */
        u_int8_t ch_error;          /* copy of error register */
        /* per-drive infos */
        struct ata_drive_datas ch_drive[2];
-       
+
        /*
         * channel queues. May be the same for all channels, if hw channels
         * are not independants
@@ -205,6 +205,7 @@ struct wdc_xfer {
        void (*c_start) __P((struct channel_softc *, struct wdc_xfer *));
        int  (*c_intr)  __P((struct channel_softc *, struct wdc_xfer *, int));
        int (*c_done)  __P((struct channel_softc *, struct wdc_xfer *, int));
+        void (*c_kill_xfer) __P((struct channel_softc *, struct wdc_xfer *));
 
        /* Used by ATAPISCSI */
        int timeout;
@@ -226,6 +227,8 @@ struct wdc_xfer {
 
 int   wdcprobe __P((struct channel_softc *));
 void  wdcattach __P((struct channel_softc *));
+int   wdcdetach __P((struct channel_softc *, int));
+int   wdcactivate __P((struct device *, enum devact));
 int   wdcintr __P((void *));
 void  wdc_exec_xfer __P((struct channel_softc *, struct wdc_xfer *));
 struct wdc_xfer *wdc_get_xfer __P((int)); /* int = WDC_NOSLEEP/CANSLEEP */
@@ -238,7 +241,8 @@ int   wdcreset      __P((struct channel_softc *, int));
 #define VERBOSE 1 
 #define SILENT 0 /* wdcreset will not print errors */
 int   wdcwait __P((struct channel_softc *, int, int, int));
-void  wdcbit_bucket __P(( struct channel_softc *, int));
+void  wdcbit_bucket __P((struct channel_softc *, int));
+
 void  wdccommand __P((struct channel_softc *, u_int8_t, u_int8_t, u_int16_t,
                          u_int8_t, u_int8_t, u_int8_t, u_int8_t));
 void   wdccommandshort __P((struct channel_softc *, int, int));
index 55b0712..e62efc2 100644 (file)
@@ -1,4 +1,4 @@
-/*      $OpenBSD: pciide.c,v 1.21 2000/03/24 17:47:41 chris Exp $     */
+/*      $OpenBSD: pciide.c,v 1.22 2000/04/10 07:06:17 csapuntz Exp $     */
 /*     $NetBSD: pciide.c,v 1.48 1999/11/28 20:05:18 bouyer Exp $       */
 
 /*
@@ -1114,7 +1114,7 @@ pciide_print_modes(cp)
                if ((drvp->drive_flags & DRIVE) == 0)
                        continue;
                printf("%s(%s:%d:%d): using PIO mode %d",
-                   drvp->drv_softc->dv_xname,
+                   drvp->drive_name,
                    sc->sc_wdcdev.sc_dev.dv_xname,
                    chp->channel, drive, drvp->PIO_mode);
                if (drvp->drive_flags & DRIVE_DMA)
index eac7ba8..d93033f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: wdc_pcmcia.c,v 1.7 2000/02/01 17:01:48 fgsch Exp $    */
+/*     $OpenBSD: wdc_pcmcia.c,v 1.8 2000/04/10 07:06:15 csapuntz Exp $ */
 /*     $NetBSD: wdc_pcmcia.c,v 1.19 1999/02/19 21:49:43 abs Exp $ */
 
 /*-
@@ -80,13 +80,18 @@ struct wdc_pcmcia_softc {
        int sc_auxiowindow;
        void *sc_ih;
        struct pcmcia_function *sc_pf;
+       int sc_flags;
+#define WDC_PCMCIA_ATTACH       0x0001
 };
 
 static int wdc_pcmcia_match    __P((struct device *, void *, void *));
 static void wdc_pcmcia_attach  __P((struct device *, struct device *, void *));
+int    wdc_pcmcia_detach   __P((struct device *, int));
+int    wdc_pcmcia_activate __P((struct device *, enum devact));
 
 struct cfattach wdc_pcmcia_ca = {
-       sizeof(struct wdc_pcmcia_softc), wdc_pcmcia_match, wdc_pcmcia_attach
+       sizeof(struct wdc_pcmcia_softc), wdc_pcmcia_match, wdc_pcmcia_attach,
+       wdc_pcmcia_detach, wdc_pcmcia_activate
 };
 
 struct wdc_pcmcia_product {
@@ -280,14 +285,14 @@ wdc_pcmcia_attach(parent, self, aux)
 
        if (cfe == NULL) {
                printf(": can't handle card info\n");
-               return;
+               goto no_config_entry;
        }
 
        /* Enable the card. */
        pcmcia_function_init(pa->pf, cfe);
        if (pcmcia_function_enable(pa->pf)) {
                printf(": function enable failed\n");
-               return;
+               goto enable_failed;
        }
 
        /*
@@ -306,9 +311,8 @@ wdc_pcmcia_attach(parent, self, aux)
        if (pcmcia_io_map(pa->pf, quirks & WDC_PCMCIA_FORCE_16BIT_IO ?
            PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_AUTO, 0,
            sc->sc_pioh.size, &sc->sc_pioh, &sc->sc_iowindow)) {
-               /* XXX should unallocate */
                printf(": can't map first I/O space\n");
-               return;
+               goto iomap_failed;
        } 
 
        /*
@@ -316,12 +320,12 @@ wdc_pcmcia_attach(parent, self, aux)
         * So whether the work around like above is necessary or not
         * is unknown.  XXX.
         */
-       if (cfe->num_iospace > 1 &&
-           pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0,
+       if (cfe->num_iospace <= 1)
+               sc->sc_auxiowindow = -1;
+       else if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0,
            sc->sc_auxpioh.size, &sc->sc_auxpioh, &sc->sc_auxiowindow)) {
-               /* XXX should unallocate */
                printf(": can't map second I/O space\n");
-               return;
+               goto iomapaux_failed;
        }
 
        printf(" port 0x%lx/%d",
@@ -347,7 +351,7 @@ wdc_pcmcia_attach(parent, self, aux)
            M_DEVBUF, M_NOWAIT);
        if (sc->wdc_channel.ch_queue == NULL) {
                printf("can't allocate memory for command queue\n");
-               return;
+               goto ch_queue_alloc_failed;
        }
        if (quirks & WDC_PCMCIA_NO_EXTRA_RESETS)
                sc->sc_wdcdev.cap |= WDC_CAPABILITY_NO_EXTRA_RESETS;
@@ -372,36 +376,139 @@ wdc_pcmcia_attach(parent, self, aux)
 
        printf("\n");
 
+       sc->sc_flags |= WDC_PCMCIA_ATTACH;
        wdcattach(&sc->wdc_channel);
+       sc->sc_flags &= ~WDC_PCMCIA_ATTACH;
+       return;
+
+ ch_queue_alloc_failed:
+        /* Unmap our aux i/o window. */
+        if (sc->sc_auxiowindow != -1)
+                pcmcia_io_unmap(sc->sc_pf, sc->sc_auxiowindow);
+
+ iomapaux_failed:
+        /* Unmap our i/o window. */
+        pcmcia_io_unmap(sc->sc_pf, sc->sc_iowindow);
+
+ iomap_failed:
+        /* Disable the function */
+        pcmcia_function_disable(sc->sc_pf);
+
+ enable_failed:
+        /* Unmap our i/o space. */
+        pcmcia_io_free(sc->sc_pf, &sc->sc_pioh);
+        if (cfe->num_iospace == 2)
+                pcmcia_io_free(sc->sc_pf, &sc->sc_auxpioh);
+
+ no_config_entry:
+        sc->sc_iowindow = -1;
 }
 
 int
-wdc_pcmcia_enable(arg, onoff)
-       void *arg;
-       int onoff;
+wdc_pcmcia_detach(self, flags)
+       struct device *self;
+       int  flags;
 {
-       struct wdc_pcmcia_softc *sc = arg;
+        struct wdc_pcmcia_softc *sc = (struct wdc_pcmcia_softc *)self;
+        int error;
+
+        if (sc->sc_iowindow == -1)
+                /* Nothing to detach */
+                return (0);
+       
+       if ((error = wdcdetach(&sc->wdc_channel, flags)) != 0) 
+               return (error);
+
+        if (sc->wdc_channel.ch_queue != NULL)
+                free(sc->wdc_channel.ch_queue, M_DEVBUF);
+
+        /* Unmap our i/o window and i/o space. */
+        pcmcia_io_unmap(sc->sc_pf, sc->sc_iowindow);
+        pcmcia_io_free(sc->sc_pf, &sc->sc_pioh);
+        if (sc->sc_auxiowindow != -1) {
+                pcmcia_io_unmap(sc->sc_pf, sc->sc_auxiowindow);
+                pcmcia_io_free(sc->sc_pf, &sc->sc_auxpioh);
+        }
+
+        return (0);
+}
 
-       if (onoff) {
-               /* Establish the interrupt handler. */
-               sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, wdcintr,
-                   &sc->wdc_channel);
+int
+wdc_pcmcia_activate(self, act)
+       struct device *self;
+       enum devact act;
+{
+       struct wdc_pcmcia_softc *sc = (struct wdc_pcmcia_softc *)self;
+       int rv = 0, s;
+
+       s = splbio();
+       switch (act) {
+       case DVACT_ACTIVATE:
+               sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, 
+                   wdcintr, &sc->wdc_channel);
                if (sc->sc_ih == NULL) {
-                       printf("%s: couldn't establish interrupt handler\n",
+                       printf("%s: "
+                           "couldn't establish interrupt handler\n",
                            sc->sc_wdcdev.sc_dev.dv_xname);
-                       return (EIO);
+                       rv = EIO;
+                       break;
                }
 
                if (pcmcia_function_enable(sc->sc_pf)) {
                        printf("%s: couldn't enable PCMCIA function\n",
                            sc->sc_wdcdev.sc_dev.dv_xname);
                        pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
-                       return (EIO);
+                       rv = EIO;
+                       break;
                }
-       } else {
+
+               wdcreset(&sc->wdc_channel, VERBOSE);
+               rv = wdcactivate(self, act);
+               break;
+
+       case DVACT_DEACTIVATE:
                pcmcia_function_disable(sc->sc_pf);
                pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
+               rv = wdcactivate(self, act);
+               break;
+       }
+       splx(s);
+       return (rv);
+}
+
+#if 0
+int
+wdc_pcmcia_enable(arg, onoff)
+       void *arg;
+       int onoff;
+{
+       struct wdc_pcmcia_softc *sc = arg;
+
+       if (onoff) {
+                if ((sc->sc_flags & WDC_PCMCIA_ATTACH) == 0) {
+                       sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, 
+                           wdcintr, &sc->wdc_channel);
+                       if (sc->sc_ih == NULL) {
+                               printf("%s: "
+                                   "couldn't establish interrupt handler\n",
+                                   sc->sc_wdcdev.sc_dev.dv_xname);
+                               return (EIO);
+                       }
+
+                       if (pcmcia_function_enable(sc->sc_pf)) {
+                               printf("%s: couldn't enable PCMCIA function\n",
+                                   sc->sc_wdcdev.sc_dev.dv_xname);
+                               pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
+                               return (EIO);
+                       }
+                       wdcreset(&sc->wdc_channel, VERBOSE);
+               }
+       } else {
+               pcmcia_function_disable(sc->sc_pf);
+                if ((sc->sc_flags & WDC_PCMCIA_ATTACH) == 0)
+                       pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
        }
 
        return (0);
 }
+#endif