Index: sys/disk.h
===================================================================
RCS file: /cvsroot/src/sys/sys/disk.h,v
retrieving revision 1.63
diff -u -r1.63 disk.h
--- sys/disk.h  31 Dec 2014 20:13:41 -0000      1.63
+++ sys/disk.h  26 Apr 2015 20:31:27 -0000
@@ -470,18 +470,18 @@
       struct cpu_disklabel *dk_cpulabel;
};

+#ifdef _KERNEL
struct dkdriver {
       void    (*d_strategy)(struct buf *);
       void    (*d_minphys)(struct buf *);
-#ifdef notyet
-       int     (*d_open)(dev_t, int, int, struct proc *);
-       int     (*d_close)(dev_t, int, int, struct proc *);
-       int     (*d_ioctl)(dev_t, u_long, void *, int, struct proc *);
-       int     (*d_dump)(dev_t);
-       void    (*d_start)(struct buf *, daddr_t);
-       int     (*d_mklabel)(struct disk *);
-#endif
+       int     (*d_open)(dev_t, int, int, struct lwp *);
+       int     (*d_close)(dev_t, int, int, struct lwp *);
+       void    (*d_diskstart)(device_t);
+       void    (*d_iosize)(device_t, int *);
+       int     (*d_dumpblocks)(device_t, void *, daddr_t, int);
+       int     (*d_lastclose)(device_t);
};
+#endif

/* states */
#define        DK_CLOSED       0               /* drive is closed */
Index: dev/dksubr.c
===================================================================
RCS file: /cvsroot/src/sys/dev/dksubr.c,v
retrieving revision 1.58
diff -u -r1.58 dksubr.c
--- dev/dksubr.c        31 Dec 2014 19:52:05 -0000      1.58
+++ dev/dksubr.c        26 Apr 2015 20:31:28 -0000
@@ -46,6 +46,7 @@
#include <sys/fcntl.h>
#include <sys/namei.h>
#include <sys/module.h>
+#include <sys/syslog.h>

#include <dev/dkvar.h>
#include <miscfs/specfs/specdev.h> /* for v_rdev */
@@ -71,20 +72,35 @@
#define DKLABELDEV(dev)        \
       (MAKEDISKDEV(major((dev)), DISKUNIT((dev)), RAW_PART))

-static void    dk_makedisklabel(struct dk_intf *, struct dk_softc *);
+static void    dk_makedisklabel(struct dk_softc *);

void
-dk_sc_init(struct dk_softc *dksc, const char *xname)
+dk_init(struct dk_softc *dksc, device_t dev, int dtype)
{

       memset(dksc, 0x0, sizeof(*dksc));
-       strncpy(dksc->sc_xname, xname, DK_XNAME_SIZE);
+       dksc->sc_dtype = dtype;
+       dksc->sc_dev = dev;
+
+       strncpy(dksc->sc_xname, device_xname(dev), DK_XNAME_SIZE);
       dksc->sc_dkdev.dk_name = dksc->sc_xname;
}

+void
+dk_attach(struct dk_softc *dksc)
+{
+       dksc->sc_flags |= DKF_INITED | DKF_WARNLABEL | DKF_LABELSANITY;
+}
+
+void
+dk_detach(struct dk_softc *dksc)
+{
+       dksc->sc_flags &= ~DKF_INITED;
+}
+
/* ARGSUSED */
int
-dk_open(struct dk_intf *di, struct dk_softc *dksc, dev_t dev,
+dk_open(struct dk_softc *dksc, dev_t dev,
    int flags, int fmt, struct lwp *l)
{
       struct  disklabel *lp = dksc->sc_dkdev.dk_label;
@@ -94,7 +110,7 @@
       struct disk *dk = &dksc->sc_dkdev;

       DPRINTF_FOLLOW(("dk_open(%s, %p, 0x%"PRIx64", 0x%x)\n",
-           di->di_dkname, dksc, dev, flags));
+           dksc->sc_xname, dksc, dev, flags));

       mutex_enter(&dk->dk_openlock);
       part = DISKPART(dev);
@@ -115,17 +131,17 @@
        * update the in-core disklabel.
        */
       if ((dksc->sc_flags & DKF_INITED)) {
-               if (dk->dk_openmask == 0) {
-                       dk_getdisklabel(di, dksc, dev);
+               if ((dksc->sc_flags & DKF_VLABEL) == 0) {
+                       dksc->sc_flags |= DKF_VLABEL;
+                       dk_getdisklabel(dksc, dev);
               }
-               /* XXX re-discover wedges? */
       }

       /* Fail if we can't find the partition. */
-       if ((part != RAW_PART) &&
-           (((dksc->sc_flags & DKF_INITED) == 0) ||
-           ((part >= lp->d_npartitions) ||
-           (lp->d_partitions[part].p_fstype == FS_UNUSED)))) {
+       if (part != RAW_PART &&
+           ((dksc->sc_flags & DKF_VLABEL) == 0 ||
+            part >= lp->d_npartitions ||
+            lp->d_partitions[part].p_fstype == FS_UNUSED)) {
               ret = ENXIO;
               goto done;
       }
@@ -149,15 +165,16 @@

/* ARGSUSED */
int
-dk_close(struct dk_intf *di, struct dk_softc *dksc, dev_t dev,
+dk_close(struct dk_softc *dksc, dev_t dev,
    int flags, int fmt, struct lwp *l)
{
+       const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
       int     part = DISKPART(dev);
       int     pmask = 1 << part;
       struct disk *dk = &dksc->sc_dkdev;

       DPRINTF_FOLLOW(("dk_close(%s, %p, 0x%"PRIx64", 0x%x)\n",
-           di->di_dkname, dksc, dev, flags));
+           dksc->sc_xname, dksc, dev, flags));

       mutex_enter(&dk->dk_openlock);

@@ -171,13 +188,22 @@
       }
       dk->dk_openmask = dk->dk_copenmask | dk->dk_bopenmask;

+       if (dk->dk_openmask == 0) {
+               if (dkd->d_lastclose != NULL)
+                       (*dkd->d_lastclose)(dksc->sc_dev);
+       }
+
+       if ((dksc->sc_flags & DKF_KLABEL) == 0)
+               dksc->sc_flags &= ~DKF_VLABEL;
+
       mutex_exit(&dk->dk_openlock);
       return 0;
}

void
-dk_strategy(struct dk_intf *di, struct dk_softc *dksc, struct buf *bp)
+dk_strategy(struct dk_softc *dksc, struct buf *bp)
{
+       const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
       int     s, part;
       int     wlabel;
       daddr_t blkno;
@@ -187,7 +213,7 @@
       unsigned secsize;

       DPRINTF_FOLLOW(("dk_strategy(%s, %p, %p)\n",
-           di->di_dkname, dksc, bp));
+           dksc->sc_xname, dksc, bp));

       if (!(dksc->sc_flags & DKF_INITED)) {
               DPRINTF_FOLLOW(("dk_strategy: not inited\n"));
@@ -245,14 +271,33 @@
        */
       s = splbio();
       bufq_put(dksc->sc_bufq, bp);
-       di->di_diskstart(dksc);
+       dkd->d_diskstart(dksc->sc_dev);
       splx(s);
       return;
}

+void
+dk_done(struct dk_softc *dksc, struct buf *bp)
+{
+       struct disk *dk = &dksc->sc_dkdev;
+
+       if (bp->b_error != 0) {
+               diskerr(bp, dksc->sc_xname, "error", LOG_PRINTF, 0,
+                       dk->dk_label);
+               printf("\n");
+       }
+
+       disk_unbusy(dk, bp->b_bcount - bp->b_resid, (bp->b_flags & B_READ));
+#ifdef notyet
+       rnd_add_uint(&dksc->sc_rnd_source, bp->b_rawblkno);
+#endif
+       biodone(bp);
+}
+
int
-dk_size(struct dk_intf *di, struct dk_softc *dksc, dev_t dev)
+dk_size(struct dk_softc *dksc, dev_t dev)
{
+       const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
       struct  disklabel *lp;
       int     is_open;
       int     part;
@@ -264,7 +309,7 @@
       part = DISKPART(dev);
       is_open = dksc->sc_dkdev.dk_openmask & (1 << part);

-       if (!is_open && di->di_open(dev, 0, S_IFBLK, curlwp))
+       if (!is_open && dkd->d_open(dev, 0, S_IFBLK, curlwp))
               return -1;

       lp = dksc->sc_dkdev.dk_label;
@@ -274,16 +319,17 @@
               size = lp->d_partitions[part].p_size *
                   (lp->d_secsize / DEV_BSIZE);

-       if (!is_open && di->di_close(dev, 0, S_IFBLK, curlwp))
+       if (!is_open && dkd->d_close(dev, 0, S_IFBLK, curlwp))
               return 1;

       return size;
}

int
-dk_ioctl(struct dk_intf *di, struct dk_softc *dksc, dev_t dev,
+dk_ioctl(struct dk_softc *dksc, dev_t dev,
           u_long cmd, void *data, int flag, struct lwp *l)
{
+       const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
       struct  disklabel *lp;
       struct  disk *dk = &dksc->sc_dkdev;
#ifdef __HAVE_OLD_DISKLABEL
@@ -292,7 +338,7 @@
       int     error;

       DPRINTF_FOLLOW(("dk_ioctl(%s, %p, 0x%"PRIx64", 0x%lx)\n",
-           di->di_dkname, dksc, dev, cmd));
+           dksc->sc_xname, dksc, dev, cmd));

       /* ensure that the pseudo disk is open for writes for these commands */
       switch (cmd) {
@@ -315,6 +361,7 @@
       case DIOCSDINFO:
       case DIOCWDINFO:
       case DIOCGPART:
+       case DIOCKLABEL:
       case DIOCWLABEL:
       case DIOCGDEFLABEL:
       case DIOCAWEDGE:
@@ -366,7 +413,7 @@
#endif
                          )
                               error = writedisklabel(DKLABELDEV(dev),
-                                   di->di_strategy, dksc->sc_dkdev.dk_label,
+                                   dkd->d_strategy, dksc->sc_dkdev.dk_label,
                                   dksc->sc_dkdev.dk_cpulabel);
               }

@@ -374,6 +421,15 @@
               mutex_exit(&dk->dk_openlock);
               break;

+       case DIOCKLABEL:
+               if ((flag & FWRITE) == 0)
+                       return (EBADF);
+               if (*(int *)data != 0)
+                       dksc->sc_flags |= DKF_KLABEL;
+               else
+                       dksc->sc_flags &= ~DKF_KLABEL;
+               break;
+
       case DIOCWLABEL:
               if (*(int *)data != 0)
                       dksc->sc_flags |= DKF_WLABEL;
@@ -382,12 +438,12 @@
               break;

       case DIOCGDEFLABEL:
-               dk_getdefaultlabel(di, dksc, (struct disklabel *)data);
+               dk_getdefaultlabel(dksc, (struct disklabel *)data);
               break;

#ifdef __HAVE_OLD_DISKLABEL
       case ODIOCGDEFLABEL:
-               dk_getdefaultlabel(di, dksc, &newlabel);
+               dk_getdefaultlabel(dksc, &newlabel);
               if (newlabel.d_npartitions > OLDMAXPARTITIONS)
                       return ENOTTY;
               memcpy(data, &newlabel, sizeof (struct olddisklabel));
@@ -449,7 +505,6 @@
 * This requires substantially more framework than {s,w}ddump, and hence
 * is probably much more fragile.
 *
- * XXX: we currently do not implement this.
 */

#define DKF_READYFORDUMP       (DKF_INITED|DKF_TAKEDUMP)
@@ -458,9 +513,14 @@

/* ARGSUSED */
int
-dk_dump(struct dk_intf *di, struct dk_softc *dksc, dev_t dev,
-    daddr_t blkno, void *va, size_t size)
+dk_dump(struct dk_softc *dksc, dev_t dev,
+    daddr_t blkno, void *vav, size_t size)
{
+       const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
+       char *va = vav;
+       struct disklabel *lp;
+       int part, towrt, nsects, sectoff, maxblkcnt, nblk;
+       int maxxfer, rv = 0;

       /*
        * ensure that we consider this device to be safe for dumping,
@@ -474,17 +534,53 @@
               return EFAULT;
       dk_dumping = 1;

-       /* XXX: unimplemented */
+       if (dkd->d_dumpblocks == NULL)
+               return ENXIO;
+
+       /* device specific max transfer size */
+       maxxfer = MAXPHYS;
+       if (dkd->d_iosize != NULL)
+               (*dkd->d_iosize)(dksc->sc_dev, &maxxfer);
+
+       /* Convert to disk sectors.  Request must be a multiple of size. */
+       part = DISKPART(dev);
+       lp = dksc->sc_dkdev.dk_label;
+       if ((size % lp->d_secsize) != 0)
+               return (EFAULT);
+       towrt = size / lp->d_secsize;
+       blkno = dbtob(blkno) / lp->d_secsize;   /* blkno in secsize units */
+
+       nsects = lp->d_partitions[part].p_size;
+       sectoff = lp->d_partitions[part].p_offset;
+
+       /* Check transfer bounds against partition size. */
+       if ((blkno < 0) || ((blkno + towrt) > nsects))
+               return (EINVAL);
+
+       /* Offset block number to start of partition. */
+       blkno += sectoff;
+
+       /* Start dumping and return when done. */
+       maxblkcnt = howmany(maxxfer, lp->d_secsize);
+       while (towrt > 0) {
+               nblk = min(maxblkcnt, towrt);
+
+               if ((rv = (*dkd->d_dumpblocks)(dksc->sc_dev, va, blkno, nblk)) != 0)
+                       return (rv);
+
+               towrt -= nblk;
+               blkno += nblk;
+               va += nblk * lp->d_secsize;
+       }

       dk_dumping = 0;

-       /* XXX: actually for now, we are going to leave this alone */
-       return ENXIO;
+       return 0;
}

/* ARGSUSED */
void
-dk_getdefaultlabel(struct dk_intf *di, struct dk_softc *dksc,
+dk_getdefaultlabel(struct dk_softc *dksc,
                     struct disklabel *lp)
{
       struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
@@ -501,8 +597,8 @@
       lp->d_ncylinders = dg->dg_ncylinders;
       lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;

-       strncpy(lp->d_typename, di->di_dkname, sizeof(lp->d_typename));
-       lp->d_type = di->di_dtype;
+       strncpy(lp->d_typename, dksc->sc_xname, sizeof(lp->d_typename));
+       lp->d_type = dksc->sc_dtype;
       strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
       lp->d_rpm = 3600;
       lp->d_interleave = 1;
@@ -520,21 +616,22 @@

/* ARGSUSED */
void
-dk_getdisklabel(struct dk_intf *di, struct dk_softc *dksc, dev_t dev)
+dk_getdisklabel(struct dk_softc *dksc, dev_t dev)
{
+       const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
       struct   disklabel *lp = dksc->sc_dkdev.dk_label;
       struct   cpu_disklabel *clp = dksc->sc_dkdev.dk_cpulabel;
-       struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
+       struct   disk_geom *dg = &dksc->sc_dkdev.dk_geom;
       struct   partition *pp;
       int      i;
       const char      *errstring;

       memset(clp, 0x0, sizeof(*clp));
-       dk_getdefaultlabel(di, dksc, lp);
-       errstring = readdisklabel(DKLABELDEV(dev), di->di_strategy,
+       dk_getdefaultlabel(dksc, lp);
+       errstring = readdisklabel(DKLABELDEV(dev), dkd->d_strategy,
           dksc->sc_dkdev.dk_label, dksc->sc_dkdev.dk_cpulabel);
       if (errstring) {
-               dk_makedisklabel(di, dksc);
+               dk_makedisklabel(dksc);
               if (dksc->sc_flags & DKF_WARNLABEL)
                       printf("%s: %s\n", dksc->sc_xname, errstring);
               return;
@@ -549,7 +646,7 @@
               lp->d_secperunit > dg->dg_secperunit)
               printf("WARNING: %s: total sector size in disklabel (%ju) "
                   "!= the size of %s (%ju)\n", dksc->sc_xname,
-                   (uintmax_t)lp->d_secperunit, di->di_dkname,
+                   (uintmax_t)lp->d_secperunit, dksc->sc_xname,
                   (uintmax_t)dg->dg_secperunit);

       for (i=0; i < lp->d_npartitions; i++) {
@@ -557,14 +654,14 @@
               if (pp->p_offset + pp->p_size > dg->dg_secperunit)
                       printf("WARNING: %s: end of partition `%c' exceeds "
                           "the size of %s (%ju)\n", dksc->sc_xname,
-                           'a' + i, di->di_dkname,
+                           'a' + i, dksc->sc_xname,
                           (uintmax_t)dg->dg_secperunit);
       }
}

/* ARGSUSED */
static void
-dk_makedisklabel(struct dk_intf *di, struct dk_softc *dksc)
+dk_makedisklabel(struct dk_softc *dksc)
{
       struct  disklabel *lp = dksc->sc_dkdev.dk_label;

Index: dev/dkvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/dkvar.h,v
retrieving revision 1.19
diff -u -r1.19 dkvar.h
--- dev/dkvar.h 25 May 2014 19:23:49 -0000      1.19
+++ dev/dkvar.h 26 Apr 2015 20:31:28 -0000
@@ -31,7 +31,6 @@

struct pathbuf; /* from namei.h */

-
/* literally this is not a softc, but is intended to be included in
 * the pseudo-disk's softc and passed to calls in dksubr.c.  It
 * should include the common elements of the pseudo-disk's softc.
@@ -46,6 +45,7 @@
       char                     sc_xname[DK_XNAME_SIZE]; /* external name */
       struct disk              sc_dkdev;      /* generic disk info */
       struct bufq_state       *sc_bufq;       /* buffer queue */
+       int                      sc_dtype;      /* disk type */
};

/* sc_flags:
@@ -59,23 +59,13 @@
#define DKF_WARNLABEL  0x00080000 /* warn if disklabel not present */
#define DKF_LABELSANITY        0x00100000 /* warn if disklabel not sane */
#define DKF_TAKEDUMP   0x00200000 /* allow dumping */
+#define DKF_KLABEL      0x00400000 /* keep label on close */
+#define DKF_VLABEL      0x00800000 /* label is valid */

/* Mask of flags that dksubr.c understands, other flags are fair game */
#define DK_FLAGMASK    0xffff0000

-/*
- * This defines the interface to the routines in dksubr.c.  This
- * should be a single static structure per pseudo-disk driver.
- * We only define the functions that we currently need.
- */
-struct dk_intf {
-       int       di_dtype;                     /* disk type */
-       const char *di_dkname;                  /* disk type name */
-       int     (*di_open)(dev_t, int, int, struct lwp *);
-       int     (*di_close)(dev_t, int, int, struct lwp *);
-       void    (*di_strategy)(struct buf *);
-       void    (*di_diskstart)(struct dk_softc *);
-};
+#define DK_ATTACHED(_dksc) ((_dksc)->sc_flags & DKF_INITED)

#define DK_BUSY(_dksc, _pmask)                         \
       (((_dksc)->sc_dkdev.dk_openmask & ~(_pmask)) || \
@@ -86,20 +76,22 @@
 * Functions that are exported to the pseudo disk implementations:
 */

-void   dk_sc_init(struct dk_softc *, const char *);
+void   dk_init(struct dk_softc *, device_t, int);
+void   dk_attach(struct dk_softc *);
+void   dk_detach(struct dk_softc *);

-int    dk_open(struct dk_intf *, struct dk_softc *, dev_t,
+int    dk_open(struct dk_softc *, dev_t,
               int, int, struct lwp *);
-int    dk_close(struct dk_intf *, struct dk_softc *, dev_t,
+int    dk_close(struct dk_softc *, dev_t,
                int, int, struct lwp *);
-void   dk_strategy(struct dk_intf *, struct dk_softc *, struct buf *);
-int    dk_size(struct dk_intf *, struct dk_softc *, dev_t);
-int    dk_ioctl(struct dk_intf *, struct dk_softc *, dev_t,
+void   dk_strategy(struct dk_softc *, struct buf *);
+void   dk_done(struct dk_softc *, struct buf *);
+int    dk_size(struct dk_softc *, dev_t);
+int    dk_ioctl(struct dk_softc *, dev_t,
                u_long, void *, int, struct lwp *);
-int    dk_dump(struct dk_intf *, struct dk_softc *, dev_t,
+int    dk_dump(struct dk_softc *, dev_t,
               daddr_t, void *, size_t);
-void   dk_getdisklabel(struct dk_intf *, struct dk_softc *, dev_t);
-void   dk_getdefaultlabel(struct dk_intf *, struct dk_softc *,
-                          struct disklabel *);
+void   dk_getdisklabel(struct dk_softc *, dev_t);
+void   dk_getdefaultlabel(struct dk_softc *, struct disklabel *);

int    dk_lookup(struct pathbuf *, struct lwp *, struct vnode **);
Index: dev/ld.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ld.c,v
retrieving revision 1.82
diff -u -r1.82 ld.c
--- dev/ld.c    13 Apr 2015 16:33:23 -0000      1.82
+++ dev/ld.c    26 Apr 2015 20:31:28 -0000
@@ -60,15 +60,16 @@

#include <prop/proplib.h>

-static void    ldgetdefaultlabel(struct ld_softc *, struct disklabel *);
-static void    ldgetdisklabel(struct ld_softc *);
static void    ldminphys(struct buf *bp);
static bool    ld_suspend(device_t, const pmf_qual_t *);
static bool    ld_shutdown(device_t, int);
-static void    ldstart(struct ld_softc *, struct buf *);
+static void    ld_start(device_t);
+static void    ld_iosize(device_t, int *);
+static int     ld_dumpblocks(device_t, void *, daddr_t, int);
+static void    ld_fake_geometry(struct ld_softc *);
static void    ld_set_geometry(struct ld_softc *);
static void    ld_config_interrupts (device_t);
-static int     ldlastclose(device_t);
+static int     ld_lastclose(device_t);

extern struct  cfdriver ld_cd;

@@ -107,72 +108,59 @@
       .d_flag = D_DISK
};

-static struct  dkdriver lddkdriver = { ldstrategy, ldminphys };
+static struct  dkdriver lddkdriver = {
+       .d_open = ldopen,
+       .d_close = ldclose,
+       .d_strategy = ldstrategy,
+       .d_iosize = ld_iosize,
+       .d_minphys  = ldminphys,
+       .d_diskstart = ld_start,
+       .d_dumpblocks = ld_dumpblocks,
+       .d_lastclose = ld_lastclose
+};

void
ldattach(struct ld_softc *sc)
{
-       char tbuf[9];
+       device_t self = sc->sc_dv;
+       struct dk_softc *dksc = &sc->sc_dksc;

       mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM);

       if ((sc->sc_flags & LDF_ENABLED) == 0) {
-               aprint_normal_dev(sc->sc_dv, "disabled\n");
               return;
       }

-       /* Initialise and attach the disk structure. */
-       disk_init(&sc->sc_dk, device_xname(sc->sc_dv), &lddkdriver);
-       disk_attach(&sc->sc_dk);
+       /* Initialise dk and disk structure. */
+       dk_init(dksc, self, DKTYPE_LD);
+       disk_init(&dksc->sc_dkdev, dksc->sc_xname, &lddkdriver);
+
+       /* Attach the device into the rnd source list. */
+       rnd_attach_source(&sc->sc_rnd_source, dksc->sc_xname,
+           RND_TYPE_DISK, RND_FLAG_DEFAULT);

       if (sc->sc_maxxfer > MAXPHYS)
               sc->sc_maxxfer = MAXPHYS;

       /* Build synthetic geometry if necessary. */
       if (sc->sc_nheads == 0 || sc->sc_nsectors == 0 ||
-           sc->sc_ncylinders == 0) {
-               uint64_t ncyl;
-
-               if (sc->sc_secperunit <= 528 * 2048)            /* 528MB */
-                       sc->sc_nheads = 16;
-               else if (sc->sc_secperunit <= 1024 * 2048)      /* 1GB */
-                       sc->sc_nheads = 32;
-               else if (sc->sc_secperunit <= 21504 * 2048)     /* 21GB */
-                       sc->sc_nheads = 64;
-               else if (sc->sc_secperunit <= 43008 * 2048)     /* 42GB */
-                       sc->sc_nheads = 128;
-               else
-                       sc->sc_nheads = 255;
+           sc->sc_ncylinders == 0)
+           ld_fake_geometry(sc);

-               sc->sc_nsectors = 63;
-               sc->sc_ncylinders = INT_MAX;
-               ncyl = sc->sc_secperunit /
-                   (sc->sc_nheads * sc->sc_nsectors);
-               if (ncyl < INT_MAX)
-                       sc->sc_ncylinders = (int)ncyl;
-       }
-
-       format_bytes(tbuf, sizeof(tbuf), sc->sc_secperunit *
-           sc->sc_secsize);
-       aprint_normal_dev(sc->sc_dv, "%s, %d cyl, %d head, %d sec, "
-           "%d bytes/sect x %"PRIu64" sectors\n",
-           tbuf, sc->sc_ncylinders, sc->sc_nheads,
-           sc->sc_nsectors, sc->sc_secsize, sc->sc_secperunit);
       sc->sc_disksize512 = sc->sc_secperunit * sc->sc_secsize / DEV_BSIZE;

+       /* Attach dk and disk subsystems */
+       dk_attach(dksc);
+       disk_attach(&dksc->sc_dkdev);
       ld_set_geometry(sc);

-       /* Attach the device into the rnd source list. */
-       rnd_attach_source(&sc->sc_rnd_source, device_xname(sc->sc_dv),
-           RND_TYPE_DISK, RND_FLAG_DEFAULT);
+       bufq_alloc(&dksc->sc_bufq, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK);

       /* Register with PMF */
-       if (!pmf_device_register1(sc->sc_dv, ld_suspend, NULL, ld_shutdown))
-               aprint_error_dev(sc->sc_dv,
+       if (!pmf_device_register1(dksc->sc_dev, ld_suspend, NULL, ld_shutdown))
+               aprint_error_dev(dksc->sc_dev,
                   "couldn't establish power handler\n");

-       bufq_alloc(&sc->sc_bufq, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK);
-
       /* Discover wedges on this disk. */
       config_interrupts(sc->sc_dv, ld_config_interrupts);
}
@@ -192,19 +180,22 @@
int
ldbegindetach(struct ld_softc *sc, int flags)
{
+       struct dk_softc *dksc = &sc->sc_dksc;
       int s, rv = 0;

       if ((sc->sc_flags & LDF_ENABLED) == 0)
               return (0);

-       rv = disk_begindetach(&sc->sc_dk, ldlastclose, sc->sc_dv, flags);
+       rv = disk_begindetach(&dksc->sc_dkdev, ld_lastclose, dksc->sc_dev, flags);

       if (rv != 0)
               return rv;

       s = splbio();
       sc->sc_maxqueuecnt = 0;
-       sc->sc_flags |= LDF_DETACH;
+
+       dk_detach(dksc);
+
       while (sc->sc_queuecnt > 0) {
               sc->sc_flags |= LDF_DRAIN;
               rv = tsleep(&sc->sc_queuecnt, PRIBIO, "lddrn", 0);
@@ -219,6 +210,7 @@
void
ldenddetach(struct ld_softc *sc)
{
+       struct dk_softc *dksc = &sc->sc_dksc;
       int s, bmaj, cmaj, i, mn;

       if ((sc->sc_flags & LDF_ENABLED) == 0)
@@ -227,7 +219,7 @@
       /* Wait for commands queued with the hardware to complete. */
       if (sc->sc_queuecnt != 0)
               if (tsleep(&sc->sc_queuecnt, PRIBIO, "lddtch", 30 * hz))
-                       printf("%s: not drained\n", device_xname(sc->sc_dv));
+                       printf("%s: not drained\n", dksc->sc_xname);

       /* Locate the major numbers. */
       bmaj = bdevsw_lookup_major(&ld_bdevsw);
@@ -235,30 +227,30 @@

       /* Kill off any queued buffers. */
       s = splbio();
-       bufq_drain(sc->sc_bufq);
+       bufq_drain(dksc->sc_bufq);
       splx(s);

-       bufq_free(sc->sc_bufq);
+       bufq_free(dksc->sc_bufq);

       /* Nuke the vnodes for any open instances. */
       for (i = 0; i < MAXPARTITIONS; i++) {
-               mn = DISKMINOR(device_unit(sc->sc_dv), i);
+               mn = DISKMINOR(device_unit(dksc->sc_dev), i);
               vdevgone(bmaj, mn, mn, VBLK);
               vdevgone(cmaj, mn, mn, VCHR);
       }

       /* Delete all of our wedges. */
-       dkwedge_delall(&sc->sc_dk);
+       dkwedge_delall(&dksc->sc_dkdev);

       /* Detach from the disk list. */
-       disk_detach(&sc->sc_dk);
-       disk_destroy(&sc->sc_dk);
+       disk_detach(&dksc->sc_dkdev);
+       disk_destroy(&dksc->sc_dkdev);

       /* Unhook the entropy source. */
       rnd_detach_source(&sc->sc_rnd_source);

       /* Deregister with PMF */
-       pmf_device_deregister(sc->sc_dv);
+       pmf_device_deregister(dksc->sc_dev);

       /*
        * XXX We can't really flush the cache here, beceause the
@@ -269,7 +261,7 @@
       /* Flush the device's cache. */
       if (sc->sc_flush != NULL)
               if ((*sc->sc_flush)(sc, 0) != 0)
-                       aprint_error_dev(sc->sc_dv, "unable to flush cache\n");
+                       aprint_error_dev(dksc->sc_dev, "unable to flush cache\n");
#endif
       mutex_destroy(&sc->sc_mutex);
}
@@ -286,9 +278,10 @@
ld_shutdown(device_t dev, int flags)
{
       struct ld_softc *sc = device_private(dev);
+       struct dk_softc *dksc = &sc->sc_dksc;

       if (sc->sc_flush != NULL && (*sc->sc_flush)(sc, LDFL_POLL) != 0) {
-               printf("%s: unable to flush cache\n", device_xname(dev));
+               printf("%s: unable to flush cache\n", dksc->sc_xname);
               return false;
       }

@@ -300,90 +293,41 @@
ldopen(dev_t dev, int flags, int fmt, struct lwp *l)
{
       struct ld_softc *sc;
-       int error, unit, part;
+       struct dk_softc *dksc;
+       int unit;

       unit = DISKUNIT(dev);
       if ((sc = device_lookup_private(&ld_cd, unit)) == NULL)
               return (ENXIO);
-       if ((sc->sc_flags & LDF_ENABLED) == 0)
-               return (ENODEV);
-       part = DISKPART(dev);
-
-       mutex_enter(&sc->sc_dk.dk_openlock);
-
-       if (sc->sc_dk.dk_openmask == 0) {
-               /* Load the partition info if not already loaded. */
-               if ((sc->sc_flags & LDF_VLABEL) == 0)
-                       ldgetdisklabel(sc);
-       }
-
-       /* Check that the partition exists. */
-       if (part != RAW_PART && (part >= sc->sc_dk.dk_label->d_npartitions ||
-           sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
-               error = ENXIO;
-               goto bad1;
-       }
-
-       /* Ensure only one open at a time. */
-       switch (fmt) {
-       case S_IFCHR:
-               sc->sc_dk.dk_copenmask |= (1 << part);
-               break;
-       case S_IFBLK:
-               sc->sc_dk.dk_bopenmask |= (1 << part);
-               break;
-       }
-       sc->sc_dk.dk_openmask =
-           sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
+       dksc = &sc->sc_dksc;

-       error = 0;
- bad1:
-       mutex_exit(&sc->sc_dk.dk_openlock);
-       return (error);
+       return dk_open(dksc, dev, flags, fmt, l);
}

static int
-ldlastclose(device_t self)
+ld_lastclose(device_t self)
{
       struct ld_softc *sc = device_private(self);
-
+
       if (sc->sc_flush != NULL && (*sc->sc_flush)(sc, 0) != 0)
               aprint_error_dev(self, "unable to flush cache\n");
-       if ((sc->sc_flags & LDF_KLABEL) == 0)
-               sc->sc_flags &= ~LDF_VLABEL;
-
+
       return 0;
-}
+}

/* ARGSUSED */
static int
ldclose(dev_t dev, int flags, int fmt, struct lwp *l)
{
       struct ld_softc *sc;
-       int part, unit;
+       struct dk_softc *dksc;
+       int unit;

       unit = DISKUNIT(dev);
-       part = DISKPART(dev);
       sc = device_lookup_private(&ld_cd, unit);
+       dksc = &sc->sc_dksc;

-       mutex_enter(&sc->sc_dk.dk_openlock);
-
-       switch (fmt) {
-       case S_IFCHR:
-               sc->sc_dk.dk_copenmask &= ~(1 << part);
-               break;
-       case S_IFBLK:
-               sc->sc_dk.dk_bopenmask &= ~(1 << part);
-               break;
-       }
-       sc->sc_dk.dk_openmask =
-           sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
-
-       if (sc->sc_dk.dk_openmask == 0)
-               ldlastclose(sc->sc_dv);
-
-       mutex_exit(&sc->sc_dk.dk_openlock);
-       return (0);
+       return dk_close(dksc, dev, flags, fmt, l);
}

/* ARGSUSED */
@@ -407,89 +351,24 @@
ldioctl(dev_t dev, u_long cmd, void *addr, int32_t flag, struct lwp *l)
{
       struct ld_softc *sc;
+       struct dk_softc *dksc;
       int unit, error;
-#ifdef __HAVE_OLD_DISKLABEL
-       struct disklabel newlabel;
-#endif
-       struct disklabel *lp;

       unit = DISKUNIT(dev);
       sc = device_lookup_private(&ld_cd, unit);
+       dksc = &sc->sc_dksc;

-       error = disk_ioctl(&sc->sc_dk, dev, cmd, addr, flag, l);
+       error = disk_ioctl(&dksc->sc_dkdev, dev, cmd, addr, flag, l);
       if (error != EPASSTHROUGH)
               return (error);

-       error = 0;
-       switch (cmd) {
-       case DIOCWDINFO:
-       case DIOCSDINFO:
-#ifdef __HAVE_OLD_DISKLABEL
-       case ODIOCWDINFO:
-       case ODIOCSDINFO:
-
-               if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
-                       memset(&newlabel, 0, sizeof newlabel);
-                       memcpy(&newlabel, addr, sizeof (struct olddisklabel));
-                       lp = &newlabel;
-               } else
-#endif
-               lp = (struct disklabel *)addr;
-
-               if ((flag & FWRITE) == 0)
-                       return (EBADF);
-
-               mutex_enter(&sc->sc_dk.dk_openlock);
-               sc->sc_flags |= LDF_LABELLING;
-
-               error = setdisklabel(sc->sc_dk.dk_label,
-                   lp, /*sc->sc_dk.dk_openmask : */0,
-                   sc->sc_dk.dk_cpulabel);
-               if (error == 0 && (cmd == DIOCWDINFO
-#ifdef __HAVE_OLD_DISKLABEL
-                   || cmd == ODIOCWDINFO
-#endif
-                   ))
-                       error = writedisklabel(
-                           MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART),
-                           ldstrategy, sc->sc_dk.dk_label,
-                           sc->sc_dk.dk_cpulabel);
-
-               sc->sc_flags &= ~LDF_LABELLING;
-               mutex_exit(&sc->sc_dk.dk_openlock);
-               break;
-
-       case DIOCKLABEL:
-               if ((flag & FWRITE) == 0)
-                       return (EBADF);
-               if (*(int *)addr)
-                       sc->sc_flags |= LDF_KLABEL;
-               else
-                       sc->sc_flags &= ~LDF_KLABEL;
-               break;
-
-       case DIOCWLABEL:
-               if ((flag & FWRITE) == 0)
-                       return (EBADF);
-               if (*(int *)addr)
-                       sc->sc_flags |= LDF_WLABEL;
-               else
-                       sc->sc_flags &= ~LDF_WLABEL;
-               break;
-
-       case DIOCGDEFLABEL:
-               ldgetdefaultlabel(sc, (struct disklabel *)addr);
-               break;
+       error = dk_ioctl(dksc, dev, cmd, addr, flag, l);
+       if (error != EPASSTHROUGH)
+               return (error);

-#ifdef __HAVE_OLD_DISKLABEL
-       case ODIOCGDEFLABEL:
-               ldgetdefaultlabel(sc, &newlabel);
-               if (newlabel.d_npartitions > OLDMAXPARTITIONS)
-                       return ENOTTY;
-               memcpy(addr, &newlabel, sizeof (struct olddisklabel));
-               break;
-#endif
+       error = 0;

+       switch (cmd) {
       case DIOCCACHESYNC:
               /*
                * XXX Do we really need to care about having a writable
@@ -502,45 +381,6 @@
               else
                       error = 0;      /* XXX Error out instead? */
               break;
-
-       case DIOCGSTRATEGY:
-           {
-               struct disk_strategy *dks = (void *)addr;
-
-               mutex_enter(&sc->sc_mutex);
-               strlcpy(dks->dks_name, bufq_getstrategyname(sc->sc_bufq),
-                   sizeof(dks->dks_name));
-               mutex_exit(&sc->sc_mutex);
-               dks->dks_paramlen = 0;
-
-               return 0;
-           }
-       case DIOCSSTRATEGY:
-           {
-               struct disk_strategy *dks = (void *)addr;
-               struct bufq_state *new_bufq, *old_bufq;
-
-               if ((flag & FWRITE) == 0)
-                       return EPERM;
-
-               if (dks->dks_param != NULL)
-                       return EINVAL;
-
-               dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */
-               error = bufq_alloc(&new_bufq, dks->dks_name,
-                   BUFQ_EXACT|BUFQ_SORT_RAWBLOCK);
-               if (error)
-                       return error;
-
-               mutex_enter(&sc->sc_mutex);
-               old_bufq = sc->sc_bufq;
-               bufq_move(new_bufq, old_bufq);
-               sc->sc_bufq = new_bufq;
-               mutex_exit(&sc->sc_mutex);
-               bufq_free(old_bufq);
-
-               return 0;
-           }
       default:
               error = ENOTTY;
               break;
@@ -553,89 +393,32 @@
ldstrategy(struct buf *bp)
{
       struct ld_softc *sc;
-       struct disklabel *lp;
-       daddr_t blkno;
-       int s, part;
-
-       sc = device_lookup_private(&ld_cd, DISKUNIT(bp->b_dev));
-       part = DISKPART(bp->b_dev);
-
-       if ((sc->sc_flags & LDF_DETACH) != 0) {
-               bp->b_error = EIO;
-               goto done;
-       }
-
-       lp = sc->sc_dk.dk_label;
-
-       /*
-        * The transfer must be a whole number of blocks and the offset must
-        * not be negative.
-        */
-       if ((bp->b_bcount % lp->d_secsize) != 0 || bp->b_blkno < 0) {
-               bp->b_error = EINVAL;
-               goto done;
-       }
-
-       /* If it's a null transfer, return immediately. */
-       if (bp->b_bcount == 0)
-               goto done;
-
-       /*
-        * Do bounds checking and adjust the transfer.  If error, process.
-        * If past the end of partition, just return.
-        */
-       if (part == RAW_PART) {
-               if (bounds_check_with_mediasize(bp, DEV_BSIZE,
-                   sc->sc_disksize512) <= 0)
-                       goto done;
-       } else {
-               if (bounds_check_with_label(&sc->sc_dk, bp,
-                   (sc->sc_flags & (LDF_WLABEL | LDF_LABELLING)) != 0) <= 0)
-                       goto done;
-       }
-
-       /*
-        * Convert the block number to absolute and put it in terms
-        * of the device's logical block size.
-        */
-       if (lp->d_secsize == DEV_BSIZE)
-               blkno = bp->b_blkno;
-       else if (lp->d_secsize > DEV_BSIZE)
-               blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
-       else
-               blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize);
-
-       if (part != RAW_PART)
-               blkno += lp->d_partitions[part].p_offset;
-
-       bp->b_rawblkno = blkno;
+       struct dk_softc *dksc;
+       int unit;

-       s = splbio();
-       ldstart(sc, bp);
-       splx(s);
-       return;
+       unit = DISKUNIT(bp->b_dev);
+       sc = device_lookup_private(&ld_cd, unit);
+       dksc = &sc->sc_dksc;

- done:
-       bp->b_resid = bp->b_bcount;
-       biodone(bp);
+       return dk_strategy(dksc, bp);
}

static void
-ldstart(struct ld_softc *sc, struct buf *bp)
+ld_start(device_t dev)
{
+       struct ld_softc *sc = device_private(dev);
+       struct dk_softc *dksc = &sc->sc_dksc;
+       struct buf *bp;
       int error;

       mutex_enter(&sc->sc_mutex);

-       if (bp != NULL)
-               bufq_put(sc->sc_bufq, bp);
-
       while (sc->sc_queuecnt < sc->sc_maxqueuecnt) {
               /* See if there is work to do. */
-               if ((bp = bufq_peek(sc->sc_bufq)) == NULL)
+               if ((bp = bufq_peek(dksc->sc_bufq)) == NULL)
                       break;

-               disk_busy(&sc->sc_dk);
+               disk_busy(&dksc->sc_dkdev);
               sc->sc_queuecnt++;

               if (__predict_true((error = (*sc->sc_start)(sc, bp)) == 0)) {
@@ -643,9 +426,9 @@
                        * The back-end is running the job; remove it from
                        * the queue.
                        */
-                       (void) bufq_get(sc->sc_bufq);
+                       (void) bufq_get(dksc->sc_bufq);
               } else  {
-                       disk_unbusy(&sc->sc_dk, 0, (bp->b_flags & B_READ));
+                       disk_unbusy(&dksc->sc_dkdev, 0, (bp->b_flags & B_READ));
                       sc->sc_queuecnt--;
                       if (error == EAGAIN) {
                               /*
@@ -658,7 +441,7 @@
                                */
                               break;
                       } else {
-                               (void) bufq_get(sc->sc_bufq);
+                               (void) bufq_get(dksc->sc_bufq);
                               bp->b_error = error;
                               bp->b_resid = bp->b_bcount;
                               mutex_exit(&sc->sc_mutex);
@@ -674,16 +457,9 @@
void
lddone(struct ld_softc *sc, struct buf *bp)
{
+       struct dk_softc *dksc = &sc->sc_dksc;

-       if (bp->b_error != 0) {
-               diskerr(bp, "ld", "error", LOG_PRINTF, 0, sc->sc_dk.dk_label);
-               printf("\n");
-       }
-
-       disk_unbusy(&sc->sc_dk, bp->b_bcount - bp->b_resid,
-           (bp->b_flags & B_READ));
-       rnd_add_uint32(&sc->sc_rnd_source, bp->b_rawblkno);
-       biodone(bp);
+       dk_done(dksc, bp);

       mutex_enter(&sc->sc_mutex);
       if (--sc->sc_queuecnt <= sc->sc_maxqueuecnt) {
@@ -692,7 +468,7 @@
                       wakeup(&sc->sc_queuecnt);
               }
               mutex_exit(&sc->sc_mutex);
-               ldstart(sc, NULL);
+               ld_start(dksc->sc_dev);
       } else
               mutex_exit(&sc->sc_mutex);
}
@@ -701,143 +477,50 @@
ldsize(dev_t dev)
{
       struct ld_softc *sc;
-       int part, unit, omask, size;
+       struct dk_softc *dksc;
+       int unit;

       unit = DISKUNIT(dev);
       if ((sc = device_lookup_private(&ld_cd, unit)) == NULL)
               return (ENODEV);
+       dksc = &sc->sc_dksc;
+
       if ((sc->sc_flags & LDF_ENABLED) == 0)
               return (ENODEV);
-       part = DISKPART(dev);
-
-       omask = sc->sc_dk.dk_openmask & (1 << part);
-
-       if (omask == 0 && ldopen(dev, 0, S_IFBLK, NULL) != 0)
-               return (-1);
-       else if (sc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
-               size = -1;
-       else
-               size = sc->sc_dk.dk_label->d_partitions[part].p_size *
-                   (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE);
-       if (omask == 0 && ldclose(dev, 0, S_IFBLK, NULL) != 0)
-               return (-1);
-
-       return (size);
-}
-
-/*
- * Load the label information from the specified device.
- */
-static void
-ldgetdisklabel(struct ld_softc *sc)
-{
-       const char *errstring;
-
-       ldgetdefaultlabel(sc, sc->sc_dk.dk_label);
-
-       /* Call the generic disklabel extraction routine. */
-       errstring = readdisklabel(MAKEDISKDEV(0, device_unit(sc->sc_dv),
-           RAW_PART), ldstrategy, sc->sc_dk.dk_label, sc->sc_dk.dk_cpulabel);
-       if (errstring != NULL)
-               printf("%s: %s\n", device_xname(sc->sc_dv), errstring);
-
-       /* In-core label now valid. */
-       sc->sc_flags |= LDF_VLABEL;
-}

-/*
- * Construct a ficticious label.
- */
-static void
-ldgetdefaultlabel(struct ld_softc *sc, struct disklabel *lp)
-{
-
-       memset(lp, 0, sizeof(struct disklabel));
-
-       lp->d_secsize = sc->sc_secsize;
-       lp->d_ntracks = sc->sc_nheads;
-       lp->d_nsectors = sc->sc_nsectors;
-       lp->d_ncylinders = sc->sc_ncylinders;
-       lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
-       lp->d_type = DKTYPE_LD;
-       strlcpy(lp->d_typename, "unknown", sizeof(lp->d_typename));
-       strlcpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
-       if (sc->sc_secperunit > UINT32_MAX)
-               lp->d_secperunit = UINT32_MAX;
-       else
-               lp->d_secperunit = sc->sc_secperunit;
-       lp->d_rpm = 7200;
-       lp->d_interleave = 1;
-       lp->d_flags = 0;
-
-       lp->d_partitions[RAW_PART].p_offset = 0;
-       lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
-       lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
-       lp->d_npartitions = RAW_PART + 1;
-
-       lp->d_magic = DISKMAGIC;
-       lp->d_magic2 = DISKMAGIC;
-       lp->d_checksum = dkcksum(lp);
+       return dk_size(dksc, dev);
}

/*
 * Take a dump.
 */
static int
-lddump(dev_t dev, daddr_t blkno, void *vav, size_t size)
+lddump(dev_t dev, daddr_t blkno, void *va, size_t size)
{
-       char *va = vav;
       struct ld_softc *sc;
-       struct disklabel *lp;
-       int unit, part, nsects, sectoff, towrt, nblk, maxblkcnt, rv;
-       static int dumping;
+       struct dk_softc *dksc;
+       int unit;

       unit = DISKUNIT(dev);
       if ((sc = device_lookup_private(&ld_cd, unit)) == NULL)
               return (ENXIO);
+       dksc = &sc->sc_dksc;
+
       if ((sc->sc_flags & LDF_ENABLED) == 0)
               return (ENODEV);
+
+       return dk_dump(dksc, dev, blkno, va, size);
+}
+
+static int
+ld_dumpblocks(device_t dev, void *va, daddr_t blkno, int nblk)
+{
+       struct ld_softc *sc = device_private(dev);
+
       if (sc->sc_dump == NULL)
               return (ENXIO);

-       /* Check if recursive dump; if so, punt. */
-       if (dumping)
-               return (EFAULT);
-       dumping = 1;
-
-       /* Convert to disk sectors.  Request must be a multiple of size. */
-       part = DISKPART(dev);
-       lp = sc->sc_dk.dk_label;
-       if ((size % lp->d_secsize) != 0)
-               return (EFAULT);
-       towrt = size / lp->d_secsize;
-       blkno = dbtob(blkno) / lp->d_secsize;   /* blkno in DEV_BSIZE units */
-
-       nsects = lp->d_partitions[part].p_size;
-       sectoff = lp->d_partitions[part].p_offset;
-
-       /* Check transfer bounds against partition size. */
-       if ((blkno < 0) || ((blkno + towrt) > nsects))
-               return (EINVAL);
-
-       /* Offset block number to start of partition. */
-       blkno += sectoff;
-
-       /* Start dumping and return when done. */
-       maxblkcnt = sc->sc_maxxfer / sc->sc_secsize - 1;
-       while (towrt > 0) {
-               nblk = min(maxblkcnt, towrt);
-
-               if ((rv = (*sc->sc_dump)(sc, va, blkno, nblk)) != 0)
-                       return (rv);
-
-               towrt -= nblk;
-               blkno += nblk;
-               va += nblk * sc->sc_secsize;
-       }
-
-       dumping = 0;
-       return (0);
+       return (*sc->sc_dump)(sc, va, blkno, nblk);
}

/*
@@ -846,34 +529,78 @@
static void
ldminphys(struct buf *bp)
{
+       int unit;
       struct ld_softc *sc;

-       sc = device_lookup_private(&ld_cd, DISKUNIT(bp->b_dev));
+       unit = DISKUNIT(bp->b_dev);
+       sc = device_lookup_private(&ld_cd, unit);

-       if (bp->b_bcount > sc->sc_maxxfer)
-               bp->b_bcount = sc->sc_maxxfer;
+       ld_iosize(sc->sc_dv, &bp->b_bcount);
       minphys(bp);
}

static void
-ld_set_geometry(struct ld_softc *ld)
+ld_iosize(device_t d, int *countp)
{
-       struct disk_geom *dg = &ld->sc_dk.dk_geom;
+       struct ld_softc *sc = device_private(d);

-       memset(dg, 0, sizeof(*dg));
+       if (*countp > sc->sc_maxxfer)
+               *countp = sc->sc_maxxfer;
+}
+
+static void
+ld_fake_geometry(struct ld_softc *sc)
+{
+       uint64_t ncyl;
+
+       if (sc->sc_secperunit <= 528 * 2048)            /* 528MB */
+               sc->sc_nheads = 16;
+       else if (sc->sc_secperunit <= 1024 * 2048)      /* 1GB */
+               sc->sc_nheads = 32;
+       else if (sc->sc_secperunit <= 21504 * 2048)     /* 21GB */
+               sc->sc_nheads = 64;
+       else if (sc->sc_secperunit <= 43008 * 2048)     /* 42GB */
+               sc->sc_nheads = 128;
+       else
+               sc->sc_nheads = 255;
+
+       sc->sc_nsectors = 63;
+       sc->sc_ncylinders = INT_MAX;
+       ncyl = sc->sc_secperunit /
+           (sc->sc_nheads * sc->sc_nsectors);
+       if (ncyl < INT_MAX)
+               sc->sc_ncylinders = (int)ncyl;
+}
+
+static void
+ld_set_geometry(struct ld_softc *sc)
+{
+       struct dk_softc *dksc = &sc->sc_dksc;
+       struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
+       char tbuf[9];
+
+       format_bytes(tbuf, sizeof(tbuf), sc->sc_secperunit *
+           sc->sc_secsize);
+       aprint_normal_dev(dksc->sc_dev, "%s, %d cyl, %d head, %d sec, "
+           "%d bytes/sect x %"PRIu64" sectors\n",
+           tbuf, sc->sc_ncylinders, sc->sc_nheads,
+           sc->sc_nsectors, sc->sc_secsize, sc->sc_secperunit);

-       dg->dg_secperunit = ld->sc_secperunit;
-       dg->dg_secsize = ld->sc_secsize;
-       dg->dg_nsectors = ld->sc_nsectors;
-       dg->dg_ntracks = ld->sc_nheads;
-       dg->dg_ncylinders = ld->sc_ncylinders;
+       memset(dg, 0, sizeof(*dg));
+       dg->dg_secperunit = sc->sc_secperunit;
+       dg->dg_secsize = sc->sc_secsize;
+       dg->dg_nsectors = sc->sc_nsectors;
+       dg->dg_ntracks = sc->sc_nheads;
+       dg->dg_ncylinders = sc->sc_ncylinders;

-       disk_set_info(ld->sc_dv, &ld->sc_dk, NULL);
+       disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL);
}

static void
ld_config_interrupts(device_t d)
{
       struct ld_softc *sc = device_private(d);
-       dkwedge_discover(&sc->sc_dk);
+       struct dk_softc *dksc = &sc->sc_dksc;
+
+       dkwedge_discover(&dksc->sc_dkdev);
}
Index: dev/ldvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ldvar.h,v
retrieving revision 1.22
diff -u -r1.22 ldvar.h
--- dev/ldvar.h 13 Apr 2015 16:33:23 -0000      1.22
+++ dev/ldvar.h 26 Apr 2015 20:31:28 -0000
@@ -33,15 +33,15 @@
#define        _DEV_LDVAR_H_

#include <sys/mutex.h>
-#include <sys/device.h>        /* for device_t */
#include <sys/rndsource.h>

+#include <dev/dkvar.h> /* for dk_softc */
+
struct ld_softc {
-       device_t sc_dv;
-       struct  disk sc_dk;
-       struct  bufq_state *sc_bufq;
+       struct  dk_softc sc_dksc;
       kmutex_t sc_mutex;
       krndsource_t    sc_rnd_source;
+
       int     sc_queuecnt;            /* current h/w queue depth */
       int     sc_ncylinders;          /* # cylinders */
       int     sc_nheads;              /* # heads */
@@ -51,7 +51,8 @@
       /*
        * The following are filled by hardware specific attachment code.
        */
-       int     sc_flags;               /* control flags */
+       device_t        sc_dv;
+       int     sc_flags;               /* control flags */
       uint64_t        sc_secperunit;          /* # sectors in total */
       int     sc_secsize;             /* sector size in bytes */
       int     sc_maxxfer;             /* max xfer size in bytes */
@@ -64,12 +65,7 @@

/* sc_flags */
#define        LDF_ENABLED     0x001           /* device enabled */
-#define        LDF_WLABEL      0x008           /* label is writable */
-#define        LDF_LABELLING   0x010           /* writing label */
#define        LDF_DRAIN       0x020           /* maxqueuecnt has changed; drain */
-#define        LDF_DETACH      0x040           /* detach pending */
-#define        LDF_KLABEL      0x080           /* keep label on close */
-#define        LDF_VLABEL      0x100           /* label is valid */

/* sc_flush() flags */
#define        LDFL_POLL       0x001           /* poll for completion */
Index: dev/cgd.c
===================================================================
RCS file: /cvsroot/src/sys/dev/cgd.c,v
retrieving revision 1.97
diff -u -r1.97 cgd.c
--- dev/cgd.c   25 Apr 2015 13:06:11 -0000      1.97
+++ dev/cgd.c   26 Apr 2015 20:31:28 -0000
@@ -104,7 +104,7 @@

/* Internal Functions */

-static void    cgdstart(struct dk_softc *);
+static void    cgd_start(device_t);
static void    cgdiodone(struct buf *);

static int     cgd_ioctl_set(struct cgd_softc *, void *, struct lwp *);
@@ -115,21 +115,15 @@
static void    cgd_cipher(struct cgd_softc *, void *, void *,
                          size_t, daddr_t, size_t, int);

-/* Pseudo-disk Interface */
-
-static struct dk_intf the_dkintf = {
-       DKTYPE_CGD,
-       "cgd",
-       cgdopen,
-       cgdclose,
-       cgdstrategy,
-       cgdstart,
-};
-static struct dk_intf *di = &the_dkintf;
-
static struct dkdriver cgddkdriver = {
-       .d_strategy = cgdstrategy,
-       .d_minphys = minphys,
+        .d_minphys  = minphys,
+        .d_open = cgdopen,
+        .d_close = cgdclose,
+        .d_strategy = cgdstrategy,
+        .d_iosize = NULL,
+        .d_diskstart = cgd_start,
+        .d_dumpblocks = NULL,
+        .d_lastclose = NULL
};

CFATTACH_DECL3_NEW(cgd, sizeof(struct cgd_softc),
@@ -205,11 +199,10 @@
       struct cgd_softc *sc = device_private(self);

       mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_BIO);
-       dk_sc_init(&sc->sc_dksc, device_xname(self));
-       sc->sc_dksc.sc_dev = self;
+       dk_init(&sc->sc_dksc, self, DKTYPE_CGD);
       disk_init(&sc->sc_dksc.sc_dkdev, sc->sc_dksc.sc_xname, &cgddkdriver);

-        if (!pmf_device_register(self, NULL, NULL))
+       if (!pmf_device_register(self, NULL, NULL))
               aprint_error_dev(self, "unable to register power management hooks\n");
}

@@ -225,7 +218,7 @@
       if (DK_BUSY(dksc, pmask))
               return EBUSY;

-       if ((dksc->sc_flags & DKF_INITED) != 0 &&
+       if (DK_ATTACHED(dksc) &&
           (ret = cgd_ioctl_clr(sc, curlwp)) != 0)
               return ret;

@@ -281,7 +274,7 @@

       DPRINTF_FOLLOW(("cgdopen(0x%"PRIx64", %d)\n", dev, flags));
       GETCGD_SOFTC(cs, dev);
-       return dk_open(di, &cs->sc_dksc, dev, flags, fmt, l);
+       return dk_open(&cs->sc_dksc, dev, flags, fmt, l);
}

static int
@@ -294,10 +287,10 @@
       DPRINTF_FOLLOW(("cgdclose(0x%"PRIx64", %d)\n", dev, flags));
       GETCGD_SOFTC(cs, dev);
       dksc = &cs->sc_dksc;
-       if ((error =  dk_close(di, dksc, dev, flags, fmt, l)) != 0)
+       if ((error =  dk_close(dksc, dev, flags, fmt, l)) != 0)
               return error;

-       if ((dksc->sc_flags & DKF_INITED) == 0) {
+       if (!DK_ATTACHED(dksc)) {
               if ((error = cgd_destroy(cs->sc_dksc.sc_dev)) != 0) {
                       aprint_error_dev(dksc->sc_dev,
                           "unable to detach instance\n");
@@ -330,7 +323,7 @@
       }

       /* XXXrcd: Should we test for (cs != NULL)? */
-       dk_strategy(di, &cs->sc_dksc, bp);
+       dk_strategy(&cs->sc_dksc, bp);
       return;
}

@@ -342,7 +335,7 @@
       DPRINTF_FOLLOW(("cgdsize(0x%"PRIx64")\n", dev));
       if (!cs)
               return -1;
-       return dk_size(di, &cs->sc_dksc, dev);
+       return dk_size(&cs->sc_dksc, dev);
}

/*
@@ -387,9 +380,10 @@
}

static void
-cgdstart(struct dk_softc *dksc)
+cgd_start(device_t dev)
{
-       struct  cgd_softc *cs = (struct cgd_softc *)dksc;
+       struct  cgd_softc *cs = device_private(dev);
+       struct  dk_softc *dksc = &cs->sc_dksc;
       struct  buf *bp, *nbp;
#ifdef DIAGNOSTIC
       struct  buf *qbp;
@@ -401,7 +395,7 @@

       while ((bp = bufq_peek(dksc->sc_bufq)) != NULL) {

-               DPRINTF_FOLLOW(("cgdstart(%p, %p)\n", dksc, bp));
+               DPRINTF_FOLLOW(("cgd_start(%p, %p)\n", dksc, bp));
               disk_busy(&dksc->sc_dkdev);

               bn = bp->b_rawblkno;
@@ -506,7 +500,7 @@
       disk_unbusy(&dksc->sc_dkdev, obp->b_bcount - obp->b_resid,
           (obp->b_flags & B_READ));
       biodone(obp);
-       cgdstart(dksc);
+       cgd_start(dksc->sc_dev);
       splx(s);
}

@@ -521,7 +515,7 @@
           (unsigned long long)dev, uio, flags));
       GETCGD_SOFTC(cs, dev);
       dksc = &cs->sc_dksc;
-       if ((dksc->sc_flags & DKF_INITED) == 0)
+       if (!DK_ATTACHED(dksc))
               return ENXIO;
       return physio(cgdstrategy, NULL, dev, B_READ, minphys, uio);
}
@@ -536,7 +530,7 @@
       DPRINTF_FOLLOW(("cgdwrite(0x%"PRIx64", %p, %d)\n", dev, uio, flags));
       GETCGD_SOFTC(cs, dev);
       dksc = &cs->sc_dksc;
-       if ((dksc->sc_flags & DKF_INITED) == 0)
+       if (!DK_ATTACHED(dksc))
               return ENXIO;
       return physio(cgdstrategy, NULL, dev, B_WRITE, minphys, uio);
}
@@ -568,7 +562,7 @@

       switch (cmd) {
       case CGDIOCSET:
-               if (dksc->sc_flags & DKF_INITED)
+               if (DK_ATTACHED(dksc))
                       return EBUSY;
               return cgd_ioctl_set(cs, data, l);
       case CGDIOCCLR:
@@ -588,7 +582,7 @@
                */
               return VOP_IOCTL(cs->sc_tvn, cmd, data, flag, l->l_cred);
       default:
-               return dk_ioctl(di, dksc, dev, cmd, data, flag, l);
+               return dk_ioctl(dksc, dev, cmd, data, flag, l);
       case CGDIOCGET:
               KASSERT(0);
               return EINVAL;
@@ -603,7 +597,7 @@
       DPRINTF_FOLLOW(("cgddump(0x%"PRIx64", %" PRId64 ", %p, %lu)\n",
           dev, blkno, va, (unsigned long)size));
       GETCGD_SOFTC(cs, dev);
-       return dk_dump(di, &cs->sc_dksc, dev, blkno, va, size);
+       return dk_dump(&cs->sc_dksc, dev, blkno, va, size);
}

/*
@@ -717,15 +711,14 @@
       cs->sc_data = malloc(MAXPHYS, M_DEVBUF, M_WAITOK);
       cs->sc_data_used = 0;

-       dksc->sc_flags |= DKF_INITED;
-
-       disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL);
-
       /* Attach the disk. */
+       dk_attach(dksc);
       disk_attach(&dksc->sc_dkdev);

+       disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL);
+
       /* Try and read the disklabel. */
-       dk_getdisklabel(di, dksc, 0 /* XXX ? (cause of PR 41704) */);
+       dk_getdisklabel(dksc, 0 /* XXX ? (cause of PR 41704) */);

       /* Discover wedges on this disk. */
       dkwedge_discover(&dksc->sc_dkdev);
@@ -745,7 +738,7 @@
       int     s;
       struct  dk_softc *dksc = &cs->sc_dksc;

-       if ((dksc->sc_flags & DKF_INITED) == 0)
+       if (!DK_ATTACHED(dksc))
               return ENXIO;

       /* Delete all of our wedges. */
@@ -762,7 +755,7 @@
       free(cs->sc_tpath, M_DEVBUF);
       free(cs->sc_data, M_DEVBUF);
       cs->sc_data_used = 0;
-       dksc->sc_flags &= ~DKF_INITED;
+       dk_detach(dksc);
       disk_detach(&dksc->sc_dkdev);

       return 0;
@@ -789,7 +782,7 @@
               return EINVAL;  /* XXX: should this be ENXIO? */

       cs = device_lookup_private(&cgd_cd, unit);
-       if (cs == NULL || (dksc->sc_flags & DKF_INITED) == 0) {
+       if (cs == NULL || !DK_ATTACHED(dksc)) {
               cgu->cgu_dev = 0;
               cgu->cgu_alg[0] = '\0';
               cgu->cgu_blocksize = 0;
Index: arch/xen/xen/xbd_xenbus.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/xen/xbd_xenbus.c,v
retrieving revision 1.70
diff -u -r1.70 xbd_xenbus.c
--- arch/xen/xen/xbd_xenbus.c   13 Apr 2015 21:18:40 -0000      1.70
+++ arch/xen/xen/xbd_xenbus.c   26 Apr 2015 20:31:28 -0000
@@ -168,7 +168,7 @@
static bool xbd_xenbus_resume(device_t, const pmf_qual_t *);

static int  xbd_handler(void *);
-static void xbdstart(struct dk_softc *);
+static void xbdstart(device_t);
static void xbd_backend_changed(void *, XenbusState);
static void xbd_connect(struct xbd_xenbus_softc *);

@@ -218,19 +218,12 @@

extern struct cfdriver xbd_cd;

-/* Pseudo-disk Interface */
-static struct dk_intf dkintf_esdi = {
-        DKTYPE_ESDI,
-       "Xen Virtual ESDI",
-       xbdopen,
-       xbdclose,
-       xbdstrategy,
-       xbdstart,
-}, *di = &dkintf_esdi;
-
static struct dkdriver xbddkdriver = {
        .d_strategy = xbdstrategy,
       .d_minphys = xbdminphys,
+       .d_open = xbdopen,
+       .d_close = xbdclose,
+       .d_diskstart = xbdstart,
};

static int
@@ -265,8 +258,8 @@
       config_pending_incr(self);
       aprint_normal(": Xen Virtual Block Device Interface\n");

-       dk_sc_init(&sc->sc_dksc, device_xname(self));
-       sc->sc_dksc.sc_dev = self;
+       dk_init(&sc->sc_dksc, self, DKTYPE_ESDI);
+       disk_init(&sc->sc_dksc.sc_dkdev, device_xname(self), &xbddkdriver);

#ifdef XBD_DEBUG
       printf("path: %s\n", xa->xa_xbusd->xbusd_path);
@@ -293,7 +286,6 @@
       sc->sc_xbusd = xa->xa_xbusd;
       sc->sc_xbusd->xbusd_otherend_changed = xbd_backend_changed;

-       disk_init(&sc->sc_dksc.sc_dkdev, device_xname(self), &xbddkdriver);
       /* initialize free requests list */
       SLIST_INIT(&sc->sc_xbdreq_head);
       for (i = 0; i < XBD_RING_SIZE; i++) {
@@ -380,6 +372,7 @@
               /* detach disk */
               disk_detach(&sc->sc_dksc.sc_dkdev);
               disk_destroy(&sc->sc_dksc.sc_dkdev);
+               dk_detach(&sc->sc_dksc);
               /* Unhook the entropy source. */
               rnd_detach_source(&sc->sc_rnd_source);
       }
@@ -580,13 +573,13 @@
               dg->dg_ncylinders = dg->dg_secperunit / dg->dg_nsectors;

               bufq_alloc(&sc->sc_dksc.sc_bufq, "fcfs", 0);
-               sc->sc_dksc.sc_flags |= DKF_INITED;
+               dk_attach(&sc->sc_dksc);
               disk_attach(&sc->sc_dksc.sc_dkdev);

               sc->sc_backend_status = BLKIF_STATE_CONNECTED;

               /* try to read the disklabel */
-               dk_getdisklabel(di, &sc->sc_dksc, 0 /* XXX ? */);
+               dk_getdisklabel(&sc->sc_dksc, 0 /* XXX ? */);
               format_bytes(buf, sizeof(buf), sc->sc_sectors * sc->sc_secsize);
               aprint_verbose_dev(sc->sc_dksc.sc_dev,
                               "%s, %d bytes/sect x %" PRIu64 " sectors\n",
@@ -727,7 +720,7 @@
       if (sc->sc_xbdreq_wait)
               wakeup(&sc->sc_xbdreq_wait);
       else
-               xbdstart(&sc->sc_dksc);
+               xbdstart(sc->sc_dksc.sc_dev);
       return 1;
}

@@ -752,7 +745,7 @@
               return EROFS;

       DPRINTF(("xbdopen(0x%04x, %d)\n", dev, flags));
-       return dk_open(di, &sc->sc_dksc, dev, flags, fmt, l);
+       return dk_open(&sc->sc_dksc, dev, flags, fmt, l);
}

int
@@ -763,7 +756,7 @@
       sc = device_lookup_private(&xbd_cd, DISKUNIT(dev));

       DPRINTF(("xbdclose(%d, %d)\n", dev, flags));
-       return dk_close(di, &sc->sc_dksc, dev, flags, fmt, l);
+       return dk_close(&sc->sc_dksc, dev, flags, fmt, l);
}

void
@@ -788,7 +781,7 @@
               return;
       }

-       dk_strategy(di, &sc->sc_dksc, bp);
+       dk_strategy(&sc->sc_dksc, bp);
       return;
}

@@ -802,7 +795,7 @@
       sc = device_lookup_private(&xbd_cd, DISKUNIT(dev));
       if (sc == NULL || sc->sc_shutdown != BLKIF_SHUTDOWN_RUN)
               return -1;
-       return dk_size(di, &sc->sc_dksc, dev);
+       return dk_size(&sc->sc_dksc, dev);
}

int
@@ -812,7 +805,7 @@
           device_lookup_private(&xbd_cd, DISKUNIT(dev));
       struct  dk_softc *dksc = &sc->sc_dksc;

-       if ((dksc->sc_flags & DKF_INITED) == 0)
+       if (!DK_ATTACHED(dksc))
               return ENXIO;
       return physio(xbdstrategy, NULL, dev, B_READ, xbdminphys, uio);
}
@@ -824,7 +817,7 @@
           device_lookup_private(&xbd_cd, DISKUNIT(dev));
       struct  dk_softc *dksc = &sc->sc_dksc;

-       if ((dksc->sc_flags & DKF_INITED) == 0)
+       if (!DK_ATTACHED(dksc))
               return ENXIO;
       if (__predict_false(sc->sc_info & VDISK_READONLY))
               return EROFS;
@@ -904,7 +897,7 @@
               break;

       default:
-               error = dk_ioctl(di, dksc, dev, cmd, data, flag, l);
+               error = dk_ioctl(dksc, dev, cmd, data, flag, l);
               break;
       }

@@ -922,13 +915,14 @@

       DPRINTF(("xbddump(%d, %" PRId64 ", %p, %lu)\n", dev, blkno, va,
           (unsigned long)size));
-       return dk_dump(di, &sc->sc_dksc, dev, blkno, va, size);
+       return dk_dump(&sc->sc_dksc, dev, blkno, va, size);
}

static void
-xbdstart(struct dk_softc *dksc)
+xbdstart(device_t self)
{
-       struct xbd_xenbus_softc *sc = (struct xbd_xenbus_softc *)dksc;
+       struct xbd_xenbus_softc *sc = device_private(self);
+       struct dk_softc *dksc = &sc->sc_dksc;
       struct buf *bp;
#ifdef DIAGNOSTIC
       struct  buf *qbp;
Index: arch/xen/include/xbdvar.h
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/include/xbdvar.h,v
retrieving revision 1.16
diff -u -r1.16 xbdvar.h
--- arch/xen/include/xbdvar.h   14 Apr 2015 20:32:35 -0000      1.16
+++ arch/xen/include/xbdvar.h   26 Apr 2015 20:31:28 -0000
@@ -36,7 +36,6 @@
       device_t                sc_dev;         /* base device glue */
       struct dk_softc         sc_dksc;        /* generic disk interface */
       unsigned long           sc_xd_device;   /* cookie identifying device */
-       struct dk_intf          *sc_di;         /* pseudo-disk interface */
       int                     sc_shutdown;    /* about to be removed */
       krndsource_t    sc_rnd_source;
};
@@ -44,7 +43,6 @@
struct xbd_attach_args {
       const char              *xa_device;
       vdisk_t                 *xa_xd;
-       struct dk_intf          *xa_dkintf;
       struct sysctlnode       *xa_diskcookies;
};