Module Name:    src
Committed By:   mlelstv
Date:           Sat Dec 10 10:26:38 UTC 2016

Modified Files:
        src/sys/dev: files.dev
        src/sys/dev/scsipi: cd.c cdvar.h sd.c sdvar.h

Log Message:
Refactored sd and cd to use common disk subroutines.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/sys/dev/files.dev
cvs rdiff -u -r1.333 -r1.334 src/sys/dev/scsipi/cd.c
cvs rdiff -u -r1.32 -r1.33 src/sys/dev/scsipi/cdvar.h
cvs rdiff -u -r1.319 -r1.320 src/sys/dev/scsipi/sd.c
cvs rdiff -u -r1.37 -r1.38 src/sys/dev/scsipi/sdvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/files.dev
diff -u src/sys/dev/files.dev:1.1 src/sys/dev/files.dev:1.2
--- src/sys/dev/files.dev:1.1	Fri Aug 21 02:18:18 2015
+++ src/sys/dev/files.dev	Sat Dec 10 10:26:38 2016
@@ -1,4 +1,4 @@
-#	$NetBSD: files.dev,v 1.1 2015/08/21 02:18:18 uebayasi Exp $
+#	$NetBSD: files.dev,v 1.2 2016/12/10 10:26:38 mlelstv Exp $
 
 file	dev/bio.c			bio			needs-flag
 file	dev/ccd.c			ccd
@@ -6,7 +6,7 @@ file	dev/cgd.c			cgd
 file	dev/cgd_crypto.c		cgd
 file	dev/clock_subr.c		kern	# XXX
 file	dev/clockctl.c			clockctl
-file	dev/dksubr.c			cgd | xbd | ccd | raid | dm | ld
+file	dev/dksubr.c			cgd | xbd | ccd | raid | dm | ld | sd | cd
 file	dev/dkwedge/dk.c		kern	# XXX
 file	dev/dkwedge/dkwedge_apple.c	dkwedge_method_apple
 file	dev/dkwedge/dkwedge_bsdlabel.c	dkwedge_method_bsdlabel

Index: src/sys/dev/scsipi/cd.c
diff -u src/sys/dev/scsipi/cd.c:1.333 src/sys/dev/scsipi/cd.c:1.334
--- src/sys/dev/scsipi/cd.c:1.333	Sun Nov 20 15:37:19 2016
+++ src/sys/dev/scsipi/cd.c	Sat Dec 10 10:26:38 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: cd.c,v 1.333 2016/11/20 15:37:19 mlelstv Exp $	*/
+/*	$NetBSD: cd.c,v 1.334 2016/12/10 10:26:38 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2001, 2003, 2004, 2005, 2008 The NetBSD Foundation,
@@ -50,7 +50,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cd.c,v 1.333 2016/11/20 15:37:19 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cd.c,v 1.334 2016/12/10 10:26:38 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -114,22 +114,26 @@ struct cd_formatted_toc {
 };
 
 struct cdbounce {
-	struct buf     *obp;			/* original buf */
-	int		doff;			/* byte offset in orig. buf */
-	int		soff;			/* byte offset in bounce buf */
-	int		resid;			/* residual i/o in orig. buf */
-	int		bcount;			/* actual obp bytes in bounce */
+	struct buf *obp;	/* original buf */
+	struct buf *lbp;	/* first buffer */
+	struct buf *rbp;	/* second buffer */
+	int lerr;		/* error returned for first buffer */
+	int rerr;		/* error returned for second buffer */
+	int head;		/* bytes skipped at the start */
+	int lcount;		/* bytes copied to first buffer */
+	int rcount;		/* bytes copied to second buffer */
 };
 
 static void	cdstart(struct scsipi_periph *);
 static void	cdrestart(void *);
 static void	cdminphys(struct buf *);
-static void	cdgetdefaultlabel(struct cd_softc *, struct cd_formatted_toc *,
-		    struct disklabel *);
-static void	cdgetdisklabel(struct cd_softc *);
 static void	cddone(struct scsipi_xfer *, int);
-static void	cdbounce(struct buf *);
 static int	cd_interpret_sense(struct scsipi_xfer *);
+static int	cd_diskstart(device_t, struct buf *);
+static void	cd_iosize(device_t, int *);
+static int	cd_lastclose(device_t);
+static int      cd_firstopen(device_t, dev_t, int, int);
+static void	cd_label(device_t, struct disklabel *);
 static u_long	cd_size(struct cd_softc *, int);
 static int	cd_play(struct cd_softc *, int, int);
 static int	cd_play_tracks(struct cd_softc *, struct cd_formatted_toc *,
@@ -230,8 +234,14 @@ const struct cdevsw cd_cdevsw = {
 };
 
 static struct dkdriver cddkdriver = {
+	.d_open = cdopen,
+	.d_close = cdclose,
 	.d_strategy = cdstrategy,
-	.d_minphys = cdminphys
+	.d_minphys = cdminphys,
+	.d_diskstart = cd_diskstart,
+	.d_firstopen = cd_firstopen,
+	.d_lastclose = cd_lastclose,
+	.d_label = cd_label,
 };
 
 static const struct scsipi_periphsw cd_switch = {
@@ -262,20 +272,37 @@ static void
 cdattach(device_t parent, device_t self, void *aux)
 {
 	struct cd_softc *cd = device_private(self);
+	struct dk_softc *dksc = &cd->sc_dksc;
 	struct scsipibus_attach_args *sa = aux;
 	struct scsipi_periph *periph = sa->sa_periph;
+	int dtype;
 
 	SC_DEBUG(periph, SCSIPI_DB2, ("cdattach: "));
 
-	cd->sc_dev = self;
+	switch (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(sa->sa_periph))) {
+	case SCSIPI_BUSTYPE_SCSI:
+		dtype = DKTYPE_SCSI;
+		if (periph->periph_version == 0)
+			cd->flags |= CDF_ANCIENT;
+		break; 
+	case SCSIPI_BUSTYPE_ATAPI:
+		dtype = DKTYPE_ATAPI;
+		break;
+	default:
+		dtype = DKTYPE_UNKNOWN;
+		break; 
+	}
 
-	mutex_init(&cd->sc_lock, MUTEX_DEFAULT, IPL_NONE);
+	/*
+	 * Initialize and attach the disk structure.
+	 */
+	dk_init(dksc, self, dtype);
+	disk_init(&dksc->sc_dkdev, dksc->sc_xname, &cddkdriver);
 
-	if (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(sa->sa_periph)) ==
-	    SCSIPI_BUSTYPE_SCSI && periph->periph_version == 0)
-		cd->flags |= CDF_ANCIENT;
+	dk_attach(dksc);
+	disk_attach(&dksc->sc_dkdev);
 
-	bufq_alloc(&cd->buf_queue, "disksort", BUFQ_SORT_RAWBLOCK);
+	bufq_alloc(&dksc->sc_bufq, "disksort", BUFQ_SORT_RAWBLOCK);
 
 	callout_init(&cd->sc_callout, 0);
 
@@ -284,7 +311,7 @@ cdattach(device_t parent, device_t self,
 	 */
 	cd->sc_periph = periph;
 
-	periph->periph_dev = cd->sc_dev;
+	periph->periph_dev = dksc->sc_dev;
 	periph->periph_switch = &cd_switch;
 
 	/*
@@ -296,17 +323,8 @@ cdattach(device_t parent, device_t self,
 	    SCSIPI_CHAN_MAX_PERIPH(periph->periph_channel);
 	periph->periph_flags |= PERIPH_GROW_OPENINGS;
 
-	/*
-	 * Initialize and attach the disk structure.
-	 */
-	disk_init(&cd->sc_dk, device_xname(cd->sc_dev), &cddkdriver);
-	disk_attach(&cd->sc_dk);
-
-	aprint_normal("\n");
 	aprint_naive("\n");
-
-	rnd_attach_source(&cd->rnd_source, device_xname(cd->sc_dev),
-			  RND_TYPE_DISK, RND_FLAG_DEFAULT);
+	aprint_normal("\n");
 
 	if (!pmf_device_register(self, NULL, NULL))
 		aprint_error_dev(self, "couldn't establish power handler\n");
@@ -316,16 +334,18 @@ static int
 cddetach(device_t self, int flags)
 {
 	struct cd_softc *cd = device_private(self);
+	struct dk_softc *dksc = &cd->sc_dksc;
 	struct scsipi_periph *periph = cd->sc_periph;
 	struct scsipi_channel *chan = periph->periph_channel;
-	int bmaj, cmaj, i, mn;
+	int bmaj, cmaj, i, mn, rc;
 
-	if (cd->sc_dk.dk_openmask != 0 && (flags & DETACH_FORCE) == 0)
-		return EBUSY;
+	if ((rc = disk_begindetach(&dksc->sc_dkdev, cd_lastclose, self, flags)) != 0)
+		return rc;
 
 	/* locate the major number */
 	bmaj = bdevsw_lookup_major(&cd_bdevsw);
 	cmaj = cdevsw_lookup_major(&cd_cdevsw);
+
 	/* Nuke the vnodes for any open instances */
 	for (i = 0; i < MAXPARTITIONS; i++) {
 		mn = CDMINOR(device_unit(self), i);
@@ -336,183 +356,185 @@ cddetach(device_t self, int flags)
 	/* kill any pending restart */
 	callout_stop(&cd->sc_callout);
 
-	mutex_enter(chan_mtx(chan));
-
-	/* Kill off any queued buffers. */
-	bufq_drain(cd->buf_queue);
+	dk_drain(dksc);
 
 	/* Kill off any pending commands. */
+	mutex_enter(chan_mtx(chan));
 	scsipi_kill_pending(cd->sc_periph);
-
 	mutex_exit(chan_mtx(chan));
 
-	bufq_free(cd->buf_queue);
-
-	mutex_destroy(&cd->sc_lock);
+	bufq_free(dksc->sc_bufq);
 
 	/* Detach from the disk list. */
-	disk_detach(&cd->sc_dk);
-	disk_destroy(&cd->sc_dk);
+	disk_detach(&dksc->sc_dkdev);
+	disk_destroy(&dksc->sc_dkdev);
+
+	dk_detach(dksc);
+
+	callout_destroy(&cd->sc_callout);
 
-	/* Unhook the entropy source. */
-	rnd_detach_source(&cd->rnd_source);
+	pmf_device_deregister(self);
 
 	return (0);
 }
 
 /*
+ * Serialized by caller
+ */
+static int
+cd_firstopen(device_t self, dev_t dev, int flag, int fmt)
+{
+        struct cd_softc *cd = device_private(self);
+        struct scsipi_periph *periph = cd->sc_periph;
+        struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
+        int error, silent;
+        int part;
+
+	part = CDPART(dev);
+
+        error = scsipi_adapter_addref(adapt);
+        if (error)
+                return error;
+
+        if ((part == RAW_PART && fmt == S_IFCHR) || (flag & FSILENT))
+                silent = XS_CTL_SILENT;
+        else
+                silent = 0;
+
+	/* make cdclose() loud again */
+	cd->flags &= ~CDF_EJECTED;
+
+	/* Check that it is still responding and ok. */
+	error = scsipi_test_unit_ready(periph,
+	    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE |
+	    XS_CTL_SILENT);
+
+	/*
+	 * Start the pack spinning if necessary. Always allow the
+	 * raw parition to be opened, for raw IOCTLs. Data transfers
+	 * will check for SDEV_MEDIA_LOADED.
+	 */
+	if (error == EIO) {
+		error = scsipi_start(periph, SSS_START, silent);
+		if (error == EINVAL)
+			error = EIO;
+	}
+	if (error)
+		goto bad;
+
+	/* Lock the pack in. */
+	error = scsipi_prevent(periph, SPAMR_PREVENT_DT,
+	    XS_CTL_IGNORE_ILLEGAL_REQUEST |
+	    XS_CTL_IGNORE_MEDIA_CHANGE);
+	SC_DEBUG(periph, SCSIPI_DB1,
+	    ("cdopen: scsipi_prevent, error=%d\n", error));
+	if (error)
+		goto bad;
+
+	if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
+		int param_error;
+
+		/* Load the physical device parameters. */
+		param_error = cd_get_parms(cd, 0);
+		if (param_error == CDGP_RESULT_OFFLINE) {
+			error = ENXIO;
+			goto bad2;
+		}
+		periph->periph_flags |= PERIPH_MEDIA_LOADED;
+
+		SC_DEBUG(periph, SCSIPI_DB3, ("Params loaded "));
+
+		cd_set_geometry(cd);
+	}
+
+	periph->periph_flags |= PERIPH_OPEN;
+	return 0;
+
+bad2:
+	scsipi_prevent(periph, SPAMR_ALLOW,
+	    XS_CTL_IGNORE_ILLEGAL_REQUEST |
+	    XS_CTL_IGNORE_MEDIA_CHANGE |
+	    XS_CTL_SILENT);
+
+bad:
+	scsipi_adapter_delref(adapt);
+	return error;
+
+}
+
+/*
  * open the device. Make sure the partition info is a up-to-date as can be.
  */
 static int
 cdopen(dev_t dev, int flag, int fmt, struct lwp *l)
 {
 	struct cd_softc *cd;
+	struct dk_softc *dksc;
 	struct scsipi_periph *periph;
-	struct scsipi_adapter *adapt;
-	int part;
+	int unit, part;
 	int error;
-	int rawpart;
 
-	cd = device_lookup_private(&cd_cd, CDUNIT(dev));
+	unit = CDUNIT(dev);
+	cd = device_lookup_private(&cd_cd, unit);
 	if (cd == NULL)
 		return (ENXIO);
+	dksc = &cd->sc_dksc;
 
 	periph = cd->sc_periph;
-	adapt = periph->periph_channel->chan_adapter;
 	part = CDPART(dev);
 
 	SC_DEBUG(periph, SCSIPI_DB1,
-	    ("cdopen: dev=0x%"PRIu64" (unit %"PRIu32" (of %d), partition %"PRId32")\n",dev,
-	    CDUNIT(dev), cd_cd.cd_ndevs, CDPART(dev)));
+	    ("cdopen: dev=0x%"PRIu64" (unit %"PRIu32" (of %d), partition %d)\n",
+	    dev, unit, cd_cd.cd_ndevs, CDPART(dev)));
 
 	/*
-	 * If this is the first open of this device, add a reference
-	 * to the adapter.
+	 * If any partition is open, but the disk has been invalidated,
+	 * disallow further opens of non-raw partition
 	 */
-	if (cd->sc_dk.dk_openmask == 0 &&
-	    (error = scsipi_adapter_addref(adapt)) != 0)
-		return (error);
-
-	mutex_enter(&cd->sc_lock);
-
-	rawpart = (part == RAW_PART && fmt == S_IFCHR);
-	if ((periph->periph_flags & PERIPH_OPEN) != 0) {
-		/*
-		 * If any partition is open, but the disk has been invalidated,
-		 * disallow further opens.
-		 */
-		if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0 &&
-			!rawpart) {
-			error = EIO;
-			goto bad3;
-		}
-	} else {
-		/* Check that it is still responding and ok. */
-		error = scsipi_test_unit_ready(periph,
-		    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE |
-		    XS_CTL_SILENT);
-
-		/*
-		 * Start the pack spinning if necessary. Always allow the
-		 * raw parition to be opened, for raw IOCTLs. Data transfers
-		 * will check for SDEV_MEDIA_LOADED.
-		 */
-		if (error == EIO) {
-			int error2;
-			int silent;
+	if ((periph->periph_flags & (PERIPH_OPEN | PERIPH_MEDIA_LOADED)) ==
+	    PERIPH_OPEN) {
+		if (part != RAW_PART || fmt != S_IFCHR)
+			return EIO;
+	}
 
-			if (rawpart)
-				silent = XS_CTL_SILENT;
-			else
-				silent = 0;
+	error = dk_open(dksc, dev, flag, fmt, l);
 
-			error2 = scsipi_start(periph, SSS_START, silent);
-			switch (error2) {
-			case 0:
-				error = 0;
-				break;
-			case EIO:
-			case EINVAL:
-				break;
-			default:
-				error = error2;
-				break;
-			}
-		}
-		if (error) {
-			if (rawpart)
-				goto out;
-			goto bad3;
-		}
+	SC_DEBUG(periph, SCSIPI_DB3, ("open complete\n"));
 
-		periph->periph_flags |= PERIPH_OPEN;
-
-		/* Lock the pack in. */
-		error = scsipi_prevent(periph, SPAMR_PREVENT_DT,
-		    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE);
-		SC_DEBUG(periph, SCSIPI_DB1,
-		    ("cdopen: scsipi_prevent, error=%d\n", error));
-		if (error) {
-			if (rawpart)
-				goto out;
-			goto bad;
-		}
+	return error;
+}
 
-		if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
-			/* Load the physical device parameters. */
-			if (cd_get_parms(cd, 0) != 0) {
-				if (rawpart)
-					goto out;
-				error = ENXIO;
-				goto bad;
-			}
-			periph->periph_flags |= PERIPH_MEDIA_LOADED;
-			SC_DEBUG(periph, SCSIPI_DB3, ("Params loaded "));
+/*      
+ * Serialized by caller
+ */     
+static int
+cd_lastclose(device_t self)
+{ 
+	struct cd_softc *cd = device_private(self);
+	struct scsipi_periph *periph = cd->sc_periph;
+	struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
+	int silent;
 
-			/* Fabricate a disk label. */
-			cdgetdisklabel(cd);
-			SC_DEBUG(periph, SCSIPI_DB3, ("Disklabel fabricated "));
+	if (cd->flags & CDF_EJECTED)
+		silent = XS_CTL_SILENT;
+	else
+		silent = 0;
 
-			cd_set_geometry(cd);
-		}
-	}
+	cdcachesync(periph, silent);
 
-	/* Check that the partition exists. */
-	if (part != RAW_PART &&
-	    (part >= cd->sc_dk.dk_label->d_npartitions ||
-	    cd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
-		error = ENXIO;
-		goto bad;
-	}
+	scsipi_wait_drain(periph);  
 
-out:	/* Insure only one open at a time. */
-	switch (fmt) {
-	case S_IFCHR:
-		cd->sc_dk.dk_copenmask |= (1 << part);
-		break;
-	case S_IFBLK:
-		cd->sc_dk.dk_bopenmask |= (1 << part);
-		break;
-	}
-	cd->sc_dk.dk_openmask =
-	    cd->sc_dk.dk_copenmask | cd->sc_dk.dk_bopenmask;
+	scsipi_prevent(periph, SPAMR_ALLOW,
+	    XS_CTL_IGNORE_ILLEGAL_REQUEST |
+	    XS_CTL_IGNORE_NOT_READY |
+	    XS_CTL_SILENT);
+	periph->periph_flags &= ~PERIPH_OPEN;
 
-	SC_DEBUG(periph, SCSIPI_DB3, ("open complete\n"));
-	mutex_exit(&cd->sc_lock);
-	return (0);
+	scsipi_wait_drain(periph);
 
-bad:
-	if (cd->sc_dk.dk_openmask == 0) {
-		scsipi_prevent(periph, SPAMR_ALLOW,
-		    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE);
-		periph->periph_flags &= ~PERIPH_OPEN;
-	}
+	scsipi_adapter_delref(adapt); 
 
-bad3:
-	mutex_exit(&cd->sc_lock);
-	if (cd->sc_dk.dk_openmask == 0)
-		scsipi_adapter_delref(adapt);
-	return (error);
+	return 0;
 }
 
 /*
@@ -522,49 +544,149 @@ bad3:
 static int
 cdclose(dev_t dev, int flag, int fmt, struct lwp *l)
 {
-	struct cd_softc *cd = device_lookup_private(&cd_cd, CDUNIT(dev));
-	struct scsipi_periph *periph = cd->sc_periph;
-	struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
-	int part = CDPART(dev);
-	int silent = 0;
+	struct cd_softc *cd;
+	struct dk_softc *dksc;
+	int unit;
 
-	if (part == RAW_PART && ((cd->sc_dk.dk_label->d_npartitions == 0) ||
-	    (part < cd->sc_dk.dk_label->d_npartitions &&
-	    cd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)))
-		silent = XS_CTL_SILENT;
+	unit = CDUNIT(dev);
+	cd = device_lookup_private(&cd_cd, unit);
+	dksc = &cd->sc_dksc;
 
-	mutex_enter(&cd->sc_lock);
+	return dk_close(dksc, dev, flag, fmt, l);
+}
 
-	switch (fmt) {
-	case S_IFCHR:
-		cd->sc_dk.dk_copenmask &= ~(1 << part);
-		break;
-	case S_IFBLK:
-		cd->sc_dk.dk_bopenmask &= ~(1 << part);
-		break;
+static void
+cd_bounce_buffer_done(struct buf *bp)
+{
+	struct cdbounce *bounce = bp->b_private;
+	struct buf *obp = bounce->obp;
+
+	if (bp == bounce->lbp) {
+		if ((bounce->lerr = bp->b_error) == 0)
+			memcpy(obp->b_data, (char *)bp->b_data + bounce->head, bounce->lcount);
+		bounce->lbp = NULL;
 	}
-	cd->sc_dk.dk_openmask =
-	    cd->sc_dk.dk_copenmask | cd->sc_dk.dk_bopenmask;
 
-	if (cd->sc_dk.dk_openmask == 0) {
-		/* synchronise caches on last close */
-		cdcachesync(periph, silent);
+	if (bp == bounce->rbp) {
+		if ((bounce->rerr = bp->b_error) == 0)
+			memcpy((char *)obp->b_data + bounce->lcount, bp->b_data, bounce->rcount);
+		bounce->rbp = NULL;
+	}
 
-		/* drain outstanding calls */
-		scsipi_wait_drain(periph);
+	free(bp->b_data, M_DEVBUF);
+	putiobuf(bp);
 
-		scsipi_prevent(periph, SPAMR_ALLOW,
-		    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE |
-		    XS_CTL_IGNORE_NOT_READY | silent);
-		periph->periph_flags &= ~PERIPH_OPEN;
+	if (bounce->lbp != NULL || bounce->rbp != NULL)
+		return;
 
-		scsipi_wait_drain(periph);
+	obp->b_error = bounce->rerr;
+	if (bounce->lerr)
+		obp->b_error = bounce->lerr;
+
+	obp->b_resid = 0;
+	if (obp->b_error)
+		obp->b_resid = obp->b_bcount;
 
-		scsipi_adapter_delref(adapt);
-	}
+	free(bounce, M_DEVBUF);
+	biodone(obp);
+}
 
-	mutex_exit(&cd->sc_lock);
-	return (0);
+static int
+cd_make_bounce_buffer(struct cd_softc *cd, struct buf *bp, daddr_t blkno, int count, struct buf **nbpp, void *priv)
+{
+	struct buf *nbp;
+
+	/* We don't support bouncing writes */
+	if ((bp->b_flags & B_READ) == 0)
+		return EACCES; /* XXX */
+
+	nbp = getiobuf(NULL, false);
+	if (nbp == NULL)
+		return ENOMEM;
+
+	nbp->b_data = malloc(count, M_DEVBUF, M_NOWAIT);
+	if (nbp->b_data == NULL) {
+		putiobuf(nbp);
+		return ENOMEM;
+	}
+
+	/* Set up the IOP to the bounce buffer */
+	nbp->b_error = 0;
+	nbp->b_dev = bp->b_dev;
+	nbp->b_proc = bp->b_proc;
+	nbp->b_bcount = count;
+	nbp->b_bufsize = count;
+	nbp->b_blkno = blkno;
+	nbp->b_flags = bp->b_flags | B_READ;
+	nbp->b_oflags = bp->b_oflags;
+	nbp->b_cflags = bp->b_cflags;
+	nbp->b_iodone = cd_bounce_buffer_done;
+	nbp->b_private = priv;
+
+	BIO_COPYPRIO(nbp, bp);
+
+	*nbpp = nbp;
+	return 0;
+}
+
+static int
+cd_make_bounce(struct cd_softc *cd, struct buf *bp, struct cdbounce **bouncep)
+{
+	struct dk_softc *dksc = &cd->sc_dksc;
+	unsigned secsize = dksc->sc_dkdev.dk_geom.dg_secsize;
+	struct cdbounce *bounce;
+	int bps, nblks, skip, total, count;
+	daddr_t blkno;
+	struct buf *lbp, *rbp;
+	int error;
+
+	bounce = malloc(sizeof(struct cdbounce), M_DEVBUF, M_NOWAIT|M_ZERO);
+	if (bounce == NULL)
+		return ENOMEM;
+
+	bps = howmany(secsize, DEV_BSIZE);
+	nblks = howmany(bp->b_bcount, DEV_BSIZE);
+
+	skip = bp->b_blkno % bps;
+
+	blkno = bp->b_blkno - skip;
+	total = roundup(nblks + skip, bps) * DEV_BSIZE;
+
+	count = total;
+	cd_iosize(dksc->sc_dev, &count);
+
+	bounce->head = skip * DEV_BSIZE;
+	bounce->lcount = count - bounce->head;
+	bounce->rcount = bp->b_bcount - bounce->lcount;
+
+	error = cd_make_bounce_buffer(cd, bp, blkno, count, &lbp, bounce);
+	if (error)
+		goto bad;
+
+	blkno += howmany(count, DEV_BSIZE);
+	count = total - count;
+
+	if (count > 0) {
+		bounce->lbp->b_private = bounce;
+		error = cd_make_bounce_buffer(cd, bp, blkno, count, &rbp, bounce);
+		if (error) {
+			putiobuf(bounce->lbp);
+			goto bad;
+		}
+	} else
+		rbp = NULL;
+
+	bounce->obp = bp;
+	bounce->lbp = lbp;
+	bounce->rbp = rbp;
+
+	*bouncep = bounce;
+
+	return 0;
+
+bad:
+	free(bounce, M_DEVBUF);
+	return error;
 }
 
 /*
@@ -576,345 +698,220 @@ static void
 cdstrategy(struct buf *bp)
 {
 	struct cd_softc *cd = device_lookup_private(&cd_cd,CDUNIT(bp->b_dev));
-	struct disklabel *lp;
+	struct dk_softc *dksc = &cd->sc_dksc;
 	struct scsipi_periph *periph = cd->sc_periph;
-	struct scsipi_channel *chan = periph->periph_channel;
-	daddr_t blkno;
+	int error;
 
 	SC_DEBUG(cd->sc_periph, SCSIPI_DB2, ("cdstrategy "));
 	SC_DEBUG(cd->sc_periph, SCSIPI_DB1,
 	    ("%d bytes @ blk %" PRId64 "\n", bp->b_bcount, bp->b_blkno));
+
 	/*
 	 * If the device has been made invalid, error out
 	 * maybe the media changed
 	 */
 	if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
 		if (periph->periph_flags & PERIPH_OPEN)
-			bp->b_error = EIO;
+			error = EIO;
 		else
-			bp->b_error = ENODEV;
-		goto done;
-	}
-
-	lp = cd->sc_dk.dk_label;
-
-	/*
-	 * The transfer must be a whole number of blocks, 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, adjust transfer. if error, process.
-	 * If end of partition, just return.
-	 */
-	if (CDPART(bp->b_dev) == RAW_PART) {
-		if (bounds_check_with_mediasize(bp, DEV_BSIZE,
-		    cd->params.disksize512) <= 0)
-			goto done;
-	} else {
-		if (bounds_check_with_label(&cd->sc_dk, bp,
-		    (cd->flags & (CDF_WLABEL|CDF_LABELLING)) != 0) <= 0)
-			goto done;
+			error = ENODEV;
+		goto bad;
 	}
 
 	/*
-	 * Now convert the block number to absolute and put it in
-	 * terms of the device's logical block size.
-	 */
-	blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
-	if (CDPART(bp->b_dev) != RAW_PART)
-		blkno += lp->d_partitions[CDPART(bp->b_dev)].p_offset;
-
-	bp->b_rawblkno = blkno;
-
-	/*
-	 * If the disklabel sector size does not match the device
-	 * sector size we may need to do some extra work.
+	 * If label and device don't agree in sector size use a bounce buffer
 	 */
-	if (lp->d_secsize != cd->params.blksize) {
-
-		/*
-		 * If the xfer is not a multiple of the device block size
-		 * or it is not block aligned, we need to bounce it.
-		 */
-		if ((bp->b_bcount % cd->params.blksize) != 0 ||
-			((blkno * lp->d_secsize) % cd->params.blksize) != 0) {
-			struct cdbounce *bounce;
-			struct buf *nbp;
-			long count;
-
-			if ((bp->b_flags & B_READ) == 0) {
-
-				/* XXXX We don't support bouncing writes. */
-				bp->b_error = EACCES;
-				goto done;
-			}
-
-			bounce = malloc(sizeof(*bounce), M_DEVBUF, M_NOWAIT);
-			if (!bounce) {
-				/* No memory -- fail the iop. */
-				bp->b_error = ENOMEM;
-				goto done;
-			}
+	if (dksc->sc_dkdev.dk_label->d_secsize != dksc->sc_dkdev.dk_geom.dg_secsize) {
+		struct cdbounce *bounce;
 
-			bounce->obp = bp;
-			bounce->resid = bp->b_bcount;
-			bounce->doff = 0;
-			count = ((blkno * lp->d_secsize) % cd->params.blksize);
-			bounce->soff = count;
-			count += bp->b_bcount;
-			count = roundup(count, cd->params.blksize);
-			bounce->bcount = bounce->resid;
-			if (count > MAXPHYS) {
-				bounce->bcount = MAXPHYS - bounce->soff;
-				count = MAXPHYS;
-			}
-
-			blkno = ((blkno * lp->d_secsize) / cd->params.blksize);
-			nbp = getiobuf(NULL, false);
-			if (!nbp) {
-				/* No memory -- fail the iop. */
-				free(bounce, M_DEVBUF);
-				bp->b_error = ENOMEM;
-				goto done;
-			}
-			nbp->b_data = malloc(count, M_DEVBUF, M_NOWAIT);
-			if (!nbp->b_data) {
-				/* No memory -- fail the iop. */
-				free(bounce, M_DEVBUF);
-				putiobuf(nbp);
-				bp->b_error = ENOMEM;
-				goto done;
-			}
-
-			/* Set up the IOP to the bounce buffer. */
-			nbp->b_error = 0;
-			nbp->b_proc = bp->b_proc;
-			nbp->b_bcount = count;
-			nbp->b_bufsize = count;
-			nbp->b_rawblkno = blkno;
-			nbp->b_flags = bp->b_flags | B_READ;
-			nbp->b_oflags = bp->b_oflags;
-			nbp->b_cflags = bp->b_cflags;
-			nbp->b_iodone = cdbounce;
-
-			/* store bounce state in b_private and use new buf */
-			nbp->b_private = bounce;
-
-			BIO_COPYPRIO(nbp, bp);
+		error = cd_make_bounce(cd, bp, &bounce);
+		if (error)
+			goto bad;
 
-			bp = nbp;
+		dk_strategy(dksc, bounce->lbp);
+		if (bounce->rbp != NULL)
+			dk_strategy(dksc, bounce->rbp);
 
-		} else {
-			/* Xfer is aligned -- just adjust the start block */
-			bp->b_rawblkno = (blkno * lp->d_secsize) /
-				cd->params.blksize;
-		}
+		return;
 	}
-	mutex_enter(chan_mtx(chan));
-
-	/*
-	 * Place it in the queue of disk activities for this disk.
-	 *
-	 * XXX Only do disksort() if the current operating mode does not
-	 * XXX include tagged queueing.
-	 */
-	bufq_put(cd->buf_queue, bp);
-
-	/*
-	 * Tell the device to get going on the transfer if it's
-	 * not doing anything, otherwise just wait for completion
-	 */
-	cdstart(periph);
-
-	mutex_exit(chan_mtx(chan));
+	
+	dk_strategy(dksc, bp);
 	return;
 
-done:
-	/*
-	 * Correctly set the buf to indicate a completed xfer
-	 */
+bad:
+	bp->b_error = error;
 	bp->b_resid = bp->b_bcount;
 	biodone(bp);
 }
 
 /*
- * cdstart looks to see if there is a buf waiting for the device
- * and that the device is not already busy. If both are true,
- * It deques the buf and creates a scsi command to perform the
- * transfer in the buf. The transfer request will call scsipi_done
- * on completion, which will in turn call this routine again
- * so that the next queued transfer is performed.
- * The bufs are queued by the strategy routine (cdstrategy)
- *
- * This routine is also called after other non-queued requests
- * have been made of the scsi driver, to ensure that the queue
- * continues to be drained.
+ * Issue single I/O command
  *
- * must be called with channel lock held
- * cdstart() is called from cdstrategy, cdrestart and scsipi_done
+ * Called from dk_start and implicitely from dk_strategy
  */
-static void
-cdstart(struct scsipi_periph *periph)
+static int
+cd_diskstart(device_t dev, struct buf *bp)
 {
-	struct cd_softc *cd = device_private(periph->periph_dev);
-	struct buf *bp = 0;
+	struct cd_softc *cd = device_private(dev);
+        struct scsipi_periph *periph = cd->sc_periph;
+        struct scsipi_channel *chan = periph->periph_channel;
 	struct scsipi_rw_10 cmd_big;
 	struct scsi_rw_6 cmd_small;
 	struct scsipi_generic *cmdp;
 	struct scsipi_xfer *xs;
-	int flags, nblks, cmdlen, error __diagused;
+	int error, flags, nblks, cmdlen;
 
 	SC_DEBUG(periph, SCSIPI_DB2, ("cdstart "));
 
+	mutex_enter(chan_mtx(chan));
+
+	if (periph->periph_active >= periph->periph_openings) {
+		error = EAGAIN;
+		goto out;
+	}
+
 	/*
-	 * Check if the device has room for another command
+	 * there is excess capacity, but a special waits
+	 * It'll need the adapter as soon as we clear out of the
+	 * way and let it run (user level wait).
+	 */
+	if (periph->periph_flags & PERIPH_WAITING) {
+		periph->periph_flags &= ~PERIPH_WAITING;
+		cv_broadcast(periph_cv_periph(periph));
+		error = EAGAIN;
+		goto out;
+	}
+
+	/*
+	 * If the device has become invalid, abort all the
+	 * reads and writes until all files have been closed and
+	 * re-opened
 	 */
-	while (periph->periph_active < periph->periph_openings) {
-		/*
-		 * there is excess capacity, but a special waits
-		 * It'll need the adapter as soon as we clear out of the
-		 * way and let it run (user level wait).
-		 */
-		if (periph->periph_flags & PERIPH_WAITING) {
-			periph->periph_flags &= ~PERIPH_WAITING;
-			cv_broadcast(periph_cv_periph(periph));
-			return;
-		}
+	if (__predict_false(
+	    (periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)) {
+		error = EIO;
+		goto out;
+	}
 
-		/*
-		 * If the device has become invalid, abort all the
-		 * reads and writes until all files have been closed and
-		 * re-opened
-		 */
-		if (__predict_false(
-		    (periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)) {
-			if ((bp = bufq_get(cd->buf_queue)) != NULL) {
-				bp->b_error = EIO;
-				bp->b_resid = bp->b_bcount;
-				biodone(bp);
-				continue;
-			} else {
-				return;
-			}
-		}
+	nblks = howmany(bp->b_bcount, cd->params.blksize);
 
+	/*
+	 *  Fill out the scsi command.  If the transfer will
+	 *  fit in a "small" cdb, use it.
+	 */
+	if (((bp->b_rawblkno & 0x1fffff) == bp->b_rawblkno) &&
+	    ((nblks & 0xff) == nblks) &&
+	    !(periph->periph_quirks & PQUIRK_ONLYBIG)) {
 		/*
-		 * See if there is a buf with work for us to do..
+		 * We can fit in a small cdb.
 		 */
-		if ((bp = bufq_peek(cd->buf_queue)) == NULL)
-			return;
-
+		memset(&cmd_small, 0, sizeof(cmd_small));
+		cmd_small.opcode = (bp->b_flags & B_READ) ?
+		    SCSI_READ_6_COMMAND : SCSI_WRITE_6_COMMAND;
+		_lto3b(bp->b_rawblkno, cmd_small.addr);
+		cmd_small.length = nblks & 0xff;
+		cmdlen = sizeof(cmd_small);
+		cmdp = (struct scsipi_generic *)&cmd_small;
+	} else {
 		/*
-		 * We have a buf, now we should make a command.
+		 * Need a large cdb.
 		 */
+		memset(&cmd_big, 0, sizeof(cmd_big));
+		cmd_big.opcode = (bp->b_flags & B_READ) ?
+		    READ_10 : WRITE_10;
+		_lto4b(bp->b_rawblkno, cmd_big.addr);
+		_lto2b(nblks, cmd_big.length);
+		cmdlen = sizeof(cmd_big);
+		cmdp = (struct scsipi_generic *)&cmd_big;
+	}
 
-		nblks = howmany(bp->b_bcount, cd->params.blksize);
+	/*
+	 * Figure out what flags to use.
+	 */
+	flags = XS_CTL_NOSLEEP|XS_CTL_ASYNC|XS_CTL_SIMPLE_TAG;
+	if (bp->b_flags & B_READ)
+		flags |= XS_CTL_DATA_IN;
+	else
+		flags |= XS_CTL_DATA_OUT;
 
+	/*
+	 * Call the routine that chats with the adapter.
+	 * Note: we cannot sleep as we may be an interrupt
+	 */
+	xs = scsipi_make_xs_locked(periph, cmdp, cmdlen,
+	    (u_char *)bp->b_data, bp->b_bcount,
+	    CDRETRIES, 30000, bp, flags);
+	if (__predict_false(xs == NULL)) {
 		/*
-		 *  Fill out the scsi command.  If the transfer will
-		 *  fit in a "small" cdb, use it.
+		 * out of memory. Keep this buffer in the queue, and
+		 * retry later.
 		 */
-		if (((bp->b_rawblkno & 0x1fffff) == bp->b_rawblkno) &&
-		    ((nblks & 0xff) == nblks) &&
-		    !(periph->periph_quirks & PQUIRK_ONLYBIG)) {
-			/*
-			 * We can fit in a small cdb.
-			 */
-			memset(&cmd_small, 0, sizeof(cmd_small));
-			cmd_small.opcode = (bp->b_flags & B_READ) ?
-			    SCSI_READ_6_COMMAND : SCSI_WRITE_6_COMMAND;
-			_lto3b(bp->b_rawblkno, cmd_small.addr);
-			cmd_small.length = nblks & 0xff;
-			cmdlen = sizeof(cmd_small);
-			cmdp = (struct scsipi_generic *)&cmd_small;
-		} else {
-			/*
-			 * Need a large cdb.
-			 */
-			memset(&cmd_big, 0, sizeof(cmd_big));
-			cmd_big.opcode = (bp->b_flags & B_READ) ?
-			    READ_10 : WRITE_10;
-			_lto4b(bp->b_rawblkno, cmd_big.addr);
-			_lto2b(nblks, cmd_big.length);
-			cmdlen = sizeof(cmd_big);
-			cmdp = (struct scsipi_generic *)&cmd_big;
-		}
+		callout_reset(&cd->sc_callout, hz / 2, cdrestart,
+		    periph);
+		error = 0;
+		goto out;
+	}
 
-		/* Instrumentation. */
-		disk_busy(&cd->sc_dk);
+	error = scsipi_execute_xs(xs);
+	/* with a scsipi_xfer preallocated, scsipi_command can't fail */
+	KASSERT(error == 0);
 
-		/*
-		 * Figure out what flags to use.
-		 */
-		flags = XS_CTL_NOSLEEP|XS_CTL_ASYNC|XS_CTL_SIMPLE_TAG;
-		if (bp->b_flags & B_READ)
-			flags |= XS_CTL_DATA_IN;
-		else
-			flags |= XS_CTL_DATA_OUT;
+out:
+	mutex_exit(chan_mtx(chan));
 
-		/*
-		 * Call the routine that chats with the adapter.
-		 * Note: we cannot sleep as we may be an interrupt
-		 */
-		xs = scsipi_make_xs_locked(periph, cmdp, cmdlen,
-		    (u_char *)bp->b_data, bp->b_bcount,
-		    CDRETRIES, 30000, bp, flags);
-		if (__predict_false(xs == NULL)) {
-			/*
-			 * out of memory. Keep this buffer in the queue, and
-			 * retry later.
-			 */
-			callout_reset(&cd->sc_callout, hz / 2, cdrestart,
-			    periph);
-			return;
-		}
-		/*
-		 * need to dequeue the buffer before queuing the command,
-		 * because cdstart may be called recursively from the
-		 * HBA driver
-		 */
-#ifdef DIAGNOSTIC
-		if (bufq_get(cd->buf_queue) != bp)
-			panic("cdstart(): dequeued wrong buf");
-#else
-		bufq_get(cd->buf_queue);
-#endif
-		error = scsipi_execute_xs(xs);
-		/* with a scsipi_xfer preallocated, scsipi_command can't fail */
-		KASSERT(error == 0);
-	}
+	return error;
 }
 
+/*
+ * Recover I/O request after memory shortage
+ *
+ * Called from callout
+ */
 static void
 cdrestart(void *v)
 {
-	struct scsipi_periph *periph = (struct scsipi_periph *)v;
+	struct cd_softc *cd = v;
+	struct dk_softc *dksc = &cd->sc_dksc;
+
+	dk_start(dksc, NULL);
+}
+
+/*
+ * Recover I/O request after memory shortage
+ *
+ * Called from scsipi midlayer when resources have been freed
+ * with channel lock held
+ */
+static void
+cdstart(struct scsipi_periph *periph)
+{
+	struct cd_softc *cd = device_private(periph->periph_dev);
+	struct dk_softc *dksc = &cd->sc_dksc;
 	struct scsipi_channel *chan = periph->periph_channel;
 
-	mutex_enter(chan_mtx(chan));
-	cdstart((struct scsipi_periph *)v);
+	/*
+	 * release channel lock as dk_start may need to acquire
+	 * other locks
+	 *
+	 * cdstart is called from scsipi_put_xs and all its callers
+	 * release the lock afterwards. So releasing it here
+	 * doesn't matter.
+	 */
 	mutex_exit(chan_mtx(chan));
+
+	dk_start(dksc, NULL);
+
+	mutex_enter(chan_mtx(chan));
 }
 
 static void
 cddone(struct scsipi_xfer *xs, int error)
 {
 	struct cd_softc *cd = device_private(xs->xs_periph->periph_dev);
+	struct dk_softc *dksc = &cd->sc_dksc;
 	struct buf *bp = xs->bp;
 
 	if (bp) {
-		/* note, bp->b_resid is NOT initialised */
 		bp->b_error = error;
 		bp->b_resid = xs->resid;
 		if (error) {
@@ -922,102 +919,10 @@ cddone(struct scsipi_xfer *xs, int error
 			bp->b_resid = bp->b_bcount;
 		}
 
-		disk_unbusy(&cd->sc_dk, bp->b_bcount - bp->b_resid,
-		    (bp->b_flags & B_READ));
-		rnd_add_uint32(&cd->rnd_source, bp->b_rawblkno);
-
-		biodone(bp);
+		dk_done(dksc, bp);
 	}
 }
 
-static void
-cdbounce(struct buf *bp)
-{
-	struct cdbounce *bounce = (struct cdbounce *)bp->b_private;
-	struct buf *obp = bounce->obp;
-	struct cd_softc *cd =
-	    device_lookup_private(&cd_cd, CDUNIT(obp->b_dev));
-	struct disklabel *lp = cd->sc_dk.dk_label;
-
-	if (bp->b_error != 0) {
-		/* EEK propagate the error and free the memory */
-		goto done;
-	}
-
-	KASSERT(obp->b_flags & B_READ);
-
-	/* copy bounce buffer to final destination */
-	memcpy((char *)obp->b_data + bounce->doff,
-	    (char *)bp->b_data + bounce->soff, bounce->bcount);
-
-	/* check if we need more I/O, i.e. bounce put us over MAXPHYS */
-	KASSERT(bounce->resid >= bounce->bcount);
-	bounce->resid -= bounce->bcount;
-	if (bounce->resid > 0) {
-		struct buf *nbp;
-		daddr_t blkno;
-		long count;
-
-		blkno = obp->b_rawblkno +
-		    ((obp->b_bcount - bounce->resid) / lp->d_secsize);
-		count = ((blkno * lp->d_secsize) % cd->params.blksize);
-		blkno = (blkno * lp->d_secsize) / cd->params.blksize;
-		bounce->soff = count;
-		bounce->doff += bounce->bcount;
-		count += bounce->resid;
-		count = roundup(count, cd->params.blksize);
-		bounce->bcount = bounce->resid;
-		if (count > MAXPHYS) {
-			bounce->bcount = MAXPHYS - bounce->soff;
-			count = MAXPHYS;
-		}
-
-		nbp = getiobuf(NULL, false);
-		if (!nbp) {
-			/* No memory -- fail the iop. */
-			bp->b_error = ENOMEM;
-			goto done;
-		}
-
-		/* Set up the IOP to the bounce buffer. */
-		nbp->b_error = 0;
-		nbp->b_proc = obp->b_proc;
-		nbp->b_bcount = count;
-		nbp->b_bufsize = count;
-		nbp->b_data = bp->b_data;
-		nbp->b_rawblkno = blkno;
-		nbp->b_flags = obp->b_flags | B_READ;
-		nbp->b_oflags = obp->b_oflags;
-		nbp->b_cflags = obp->b_cflags;
-		nbp->b_iodone = cdbounce;
-
-		/* store bounce state in b_private and use new buf */
-		nbp->b_private = bounce;
-
-		BIO_COPYPRIO(nbp, obp);
-
-		bp->b_data = NULL;
-		putiobuf(bp);
-
-		/* enqueue the request and return */
-		mutex_enter(chan_mtx(cd->sc_periph->periph_channel));
-		bufq_put(cd->buf_queue, nbp);
-		cdstart(cd->sc_periph);
-		mutex_exit(chan_mtx(cd->sc_periph->periph_channel));
-
-		return;
-	}
-
-done:
-	obp->b_error = bp->b_error;
-	obp->b_resid = bp->b_resid;
-	free(bp->b_data, M_DEVBUF);
-	free(bounce, M_DEVBUF);
-	bp->b_data = NULL;
-	putiobuf(bp);
-	biodone(obp);
-}
-
 static int
 cd_interpret_sense(struct scsipi_xfer *xs)
 {
@@ -1105,6 +1010,7 @@ static void
 cdminphys(struct buf *bp)
 {
 	struct cd_softc *cd = device_lookup_private(&cd_cd, CDUNIT(bp->b_dev));
+	struct dk_softc *dksc = &cd->sc_dksc;
 	long xmax;
 
 	/*
@@ -1119,13 +1025,28 @@ cdminphys(struct buf *bp)
 	 * in a 10-byte read/write actually means 0 blocks.
 	 */
 	if (cd->flags & CDF_ANCIENT) {
-		xmax = cd->sc_dk.dk_label->d_secsize * 0xff;
+		xmax = dksc->sc_dkdev.dk_geom.dg_secsize * 0xff;
 
 		if (bp->b_bcount > xmax)
 			bp->b_bcount = xmax;
 	}
 
-	(*cd->sc_periph->periph_channel->chan_adapter->adapt_minphys)(bp);
+	scsipi_adapter_minphys(cd->sc_periph->periph_channel, bp);
+}
+
+static void
+cd_iosize(device_t dev, int *count)
+{
+	struct buf B;
+	int bmaj;
+
+	bmaj       = bdevsw_lookup_major(&cd_bdevsw);
+	B.b_dev    = MAKECDDEV(bmaj,device_unit(dev),RAW_PART);
+	B.b_bcount = *count;
+
+	cdminphys(&B);
+
+	*count = B.b_bcount;
 }
 
 static int
@@ -1201,7 +1122,7 @@ cdreadmsaddr(struct cd_softc *cd, struct
 	return 0;
 }
 
-/* synchronise caches code from sd.c, move to scsipi_ioctl.c ? */
+/* synchronise caches code from cd.c, move to scsipi_ioctl.c ? */
 static int
 cdcachesync(struct scsipi_periph *periph, int flags) {
 	struct scsi_synchronize_cache_10 cmd;
@@ -1271,13 +1192,11 @@ static int
 cdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
 {
 	struct cd_softc *cd = device_lookup_private(&cd_cd, CDUNIT(dev));
+	struct dk_softc *dksc = &cd->sc_dksc;
 	struct scsipi_periph *periph = cd->sc_periph;
 	struct cd_formatted_toc toc;
 	int part = CDPART(dev);
 	int error;
-#ifdef __HAVE_OLD_DISKLABEL
-	struct disklabel *newlabel = NULL;
-#endif
 
 	SC_DEBUG(cd->sc_periph, SCSIPI_DB2, ("cdioctl 0x%lx ", cmd));
 
@@ -1285,128 +1204,11 @@ cdioctl(dev_t dev, u_long cmd, void *add
 	 * If the device is not valid, some IOCTLs can still be
 	 * handled on the raw partition. Check this here.
 	 */
-	if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
-		switch (cmd) {
-		case DIOCWLABEL:
-		case DIOCLOCK:
-		case ODIOCEJECT:
-		case DIOCEJECT:
-		case DIOCCACHESYNC:
-		case DIOCTUR:
-		case SCIOCIDENTIFY:
-		case OSCIOCIDENTIFY:
-		case SCIOCCOMMAND:
-		case SCIOCDEBUG:
-		case CDIOCGETVOL:
-		case CDIOCSETVOL:
-		case CDIOCSETMONO:
-		case CDIOCSETSTEREO:
-		case CDIOCSETMUTE:
-		case CDIOCSETLEFT:
-		case CDIOCSETRIGHT:
-		case CDIOCCLOSE:
-		case CDIOCEJECT:
-		case CDIOCALLOW:
-		case CDIOCPREVENT:
-		case CDIOCSETDEBUG:
-		case CDIOCCLRDEBUG:
-		case CDIOCRESET:
-		case SCIOCRESET:
-		case CDIOCLOADUNLOAD:
-		case DVD_AUTH:
-		case DVD_READ_STRUCT:
-		case DIOCGSTRATEGY:
-		case DIOCSSTRATEGY:
-			if (part == RAW_PART)
-				break;
-		/* FALLTHROUGH */
-		default:
-			if ((periph->periph_flags & PERIPH_OPEN) == 0)
-				return (ENODEV);
-			else
-				return (EIO);
-		}
-	}
-
-	error = disk_ioctl(&cd->sc_dk, dev, cmd, addr, flag, l); 
-	if (error != EPASSTHROUGH)
-		return (error);
+	if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0 &&
+	    part != RAW_PART)
+		return (EIO);
 
-	error = 0;
 	switch (cmd) {
-	case DIOCWDINFO:
-	case DIOCSDINFO:
-#ifdef __HAVE_OLD_DISKLABEL
-	case ODIOCWDINFO:
-	case ODIOCSDINFO:
-#endif
-	{
-		struct disklabel *lp;
-
-		if ((flag & FWRITE) == 0)
-			return (EBADF);
-
-#ifdef __HAVE_OLD_DISKLABEL
-		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
-			newlabel = malloc(sizeof (*newlabel), M_TEMP,
-			    M_WAITOK | M_ZERO);
-			if (newlabel == NULL)
-				return (EIO);
-			memcpy(newlabel, addr, sizeof (struct olddisklabel));
-			lp = newlabel;
-		} else
-#endif
-		lp = addr;
-
-		mutex_enter(&cd->sc_lock);
-		cd->flags |= CDF_LABELLING;
-
-		error = setdisklabel(cd->sc_dk.dk_label,
-		    lp, /*cd->sc_dk.dk_openmask : */0,
-		    cd->sc_dk.dk_cpulabel);
-		if (error == 0) {
-			/* XXX ? */
-		}
-
-		cd->flags &= ~CDF_LABELLING;
-		mutex_exit(&cd->sc_lock);
-#ifdef __HAVE_OLD_DISKLABEL
-		if (newlabel != NULL)
-			free(newlabel, M_TEMP);
-#endif
-		return (error);
-	}
-
-	case DIOCWLABEL:
-		return (EBADF);
-
-	case DIOCGDEFLABEL:
-		cdgetdefaultlabel(cd, &toc, addr);
-		return (0);
-
-#ifdef __HAVE_OLD_DISKLABEL
-	case ODIOCGDEFLABEL:
-		newlabel = malloc(sizeof (*newlabel), M_TEMP, M_WAITOK);
-		if (newlabel == NULL)
-			return (EIO);
-		cdgetdefaultlabel(cd, &toc, newlabel);
-		if (newlabel->d_npartitions > OLDMAXPARTITIONS)
-			error = ENOTTY;
-		else
-			memcpy(addr, newlabel, sizeof (struct olddisklabel));
-		free(newlabel, M_TEMP);
-		return error;
-#endif
-
-	case DIOCTUR: {
-		/* test unit ready */
-		error = scsipi_test_unit_ready(cd->sc_periph, XS_CTL_SILENT);
-		*((int*)addr) = (error == 0);
-		if (error == ENODEV || error == EIO || error == 0)
-			return 0;			
-		return error;
-	}
-
 	case CDIOCPLAYTRACKS: {
 		/* PLAY_MSF command */
 		struct ioc_play_track *args = addr;
@@ -1557,13 +1359,12 @@ cdioctl(dev_t dev, u_long cmd, void *add
 		    XS_CTL_IGNORE_NOT_READY | XS_CTL_IGNORE_MEDIA_CHANGE));
 	case DIOCEJECT:
 		if (*(int *)addr == 0) {
+			int pmask = 1 << part;
 			/*
 			 * Don't force eject: check that we are the only
 			 * partition open. If so, unlock it.
 			 */
-			if ((cd->sc_dk.dk_openmask & ~(1 << part)) == 0 &&
-			    cd->sc_dk.dk_bopenmask + cd->sc_dk.dk_copenmask ==
-			    cd->sc_dk.dk_openmask) {
+			if (DK_BUSY(dksc, pmask) == 0) {
 				error = scsipi_prevent(periph, SPAMR_ALLOW,
 				    XS_CTL_IGNORE_NOT_READY);
 				if (error)
@@ -1576,22 +1377,9 @@ cdioctl(dev_t dev, u_long cmd, void *add
 	case CDIOCEJECT: /* FALLTHROUGH */
 	case ODIOCEJECT:
 		error = scsipi_start(periph, SSS_STOP|SSS_LOEJ, 0);
-		if (error == 0) {
-			int i;
-
-			/*
-			 * We have just successfully ejected the medium,
-			 * all partitions cached are meaningless now.
-			 * Make sure cdclose() will do silent operations
-			 * now by marking all partitions unused.
-			 * Before any real access, a new (default-)disk-
-			 * label will be generated anyway.
-			 */
-			for (i = 0; i < cd->sc_dk.dk_label->d_npartitions;
-			    i++)
-				cd->sc_dk.dk_label->d_partitions[i].p_fstype =
-					FS_UNUSED;
-		}
+		if (error == 0)
+			/* Make sure cdclose() will do silent operations */
+			cd->flags |= CDF_EJECTED;
 		return error;
 	case DIOCCACHESYNC:
 		/* SYNCHRONISE CACHES command */
@@ -1639,51 +1427,11 @@ cdioctl(dev_t dev, u_long cmd, void *add
 	case MMCSETUPWRITEPARAMS :
 		/* MODE SENSE page 5, MODE_SELECT page 5 commands */
 		return mmc_setup_writeparams(periph, (struct mmc_writeparams *) addr);
-	case DIOCGSTRATEGY:
-	    {
-		struct disk_strategy *dks = addr;
-		int s;
-
-		s = splbio();
-		strlcpy(dks->dks_name, bufq_getstrategyname(cd->buf_queue),
-		    sizeof(dks->dks_name));
-		splx(s);
-		dks->dks_paramlen = 0;
-
-		return 0;
-	    }
-	case DIOCSSTRATEGY:
-	    {
-		struct disk_strategy *dks = addr;
-		struct bufq_state *new;
-		struct bufq_state *old;
-		int s;
-
-		if ((flag & FWRITE) == 0) {
-			return EBADF;
-		}
-		if (dks->dks_param != NULL) {
-			return EINVAL;
-		}
-		dks->dks_name[sizeof(dks->dks_name) - 1] = 0; /* ensure term */
-		error = bufq_alloc(&new, dks->dks_name,
-		    BUFQ_EXACT|BUFQ_SORT_RAWBLOCK);
-		if (error) {
-			return error;
-		}
-		s = splbio();
-		old = cd->buf_queue;
-		bufq_move(new, old);
-		cd->buf_queue = new;
-		splx(s);
-		bufq_free(old);
-
-		return 0;
-	    }
 	default:
-		if (part != RAW_PART)
-			return (ENOTTY);
-		return (scsipi_do_ioctl(periph, dev, cmd, addr, flag, l));
+		error = dk_ioctl(dksc, dev, cmd, addr, flag, l); 
+		if (error == ENOTTY)
+			error = scsipi_do_ioctl(periph, dev, cmd, addr, flag, l);
+		return (error);
 	}
 
 #ifdef DIAGNOSTIC
@@ -1692,40 +1440,17 @@ cdioctl(dev_t dev, u_long cmd, void *add
 }
 
 static void
-cdgetdefaultlabel(struct cd_softc *cd, struct cd_formatted_toc *toc,
-    struct disklabel *lp)
+cd_label(device_t self, struct disklabel *lp)
 {
+	struct cd_softc *cd = device_private(self);
+	struct cd_formatted_toc toc;
 	int lastsession;
 
-	memset(lp, 0, sizeof(struct disklabel));
-
-	lp->d_secsize = cd->params.blksize;
-	lp->d_ntracks = 1;
-	lp->d_nsectors = 100;
-	lp->d_ncylinders = (cd->params.disksize / 100) + 1;
-	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
-
-	switch (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(cd->sc_periph))) {
-	case SCSIPI_BUSTYPE_SCSI:
-		lp->d_type = DKTYPE_SCSI;
-		break;
-	case SCSIPI_BUSTYPE_ATAPI:
-		lp->d_type = DKTYPE_ATAPI;
-		break;
-	}
-	/*
-	 * XXX
-	 * We could probe the mode pages to figure out what kind of disc it is.
-	 * Is this worthwhile?
-	 */
 	strncpy(lp->d_typename, "optical media", 16);
-	strncpy(lp->d_packname, "fictitious", 16);
-	lp->d_secperunit = cd->params.disksize;
 	lp->d_rpm = 300;
-	lp->d_interleave = 1;
-	lp->d_flags = D_REMOVABLE | D_SCSI_MMC;
+	lp->d_flags |= D_REMOVABLE | D_SCSI_MMC;
 
-	if (cdreadmsaddr(cd, toc, &lastsession) != 0)
+	if (cdreadmsaddr(cd, &toc, &lastsession) != 0)
 		lastsession = 0;
 
 	lp->d_partitions[0].p_offset = 0;
@@ -1736,51 +1461,6 @@ cdgetdefaultlabel(struct cd_softc *cd, s
 	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_UDF;
-
-	lp->d_npartitions = RAW_PART + 1;
-
-	lp->d_magic = DISKMAGIC;
-	lp->d_magic2 = DISKMAGIC;
-	lp->d_checksum = dkcksum(lp);
-}
-
-/*
- * Load the label information on the named device
- * Actually fabricate a disklabel
- *
- * EVENTUALLY take information about different
- * data tracks from the TOC and put it in the disklabel
- */
-static void
-cdgetdisklabel(struct cd_softc *cd)
-{
-	struct disklabel *lp = cd->sc_dk.dk_label;
-	struct cd_formatted_toc toc;
-	const char *errstring;
-	int bmajor;
-
-	memset(cd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
-
-	cdgetdefaultlabel(cd, &toc, lp);
-
-	/*
-	 * Call the generic disklabel extraction routine
-	 *
-	 * bmajor follows ata_raid code
-	 */
-	bmajor = devsw_name2blk(device_xname(cd->sc_dev), NULL, 0);
-	errstring = readdisklabel(MAKECDDEV(bmajor,
-	    device_unit(cd->sc_dev), RAW_PART),
-	    cdstrategy, lp, cd->sc_dk.dk_cpulabel);
-
-	/* if all went OK, we are passed a NULL error string */
-	if (errstring == NULL)
-		return;
-
-	/* Reset to default label -- after printing error and the warning */
-	aprint_error_dev(cd->sc_dev, "%s\n", errstring);
-	memset(cd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
-	cdgetdefaultlabel(cd, &toc, lp);
 }
 
 /*
@@ -3920,12 +3600,15 @@ mmc_setup_writeparams(struct scsipi_peri
 static void
 cd_set_geometry(struct cd_softc *cd)
 {
-	struct disk_geom *dg = &cd->sc_dk.dk_geom;
+	struct dk_softc *dksc = &cd->sc_dksc;
+	struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
 
 	memset(dg, 0, sizeof(*dg));
 
 	dg->dg_secperunit = cd->params.disksize;
 	dg->dg_secsize = cd->params.blksize;
+	dg->dg_nsectors = 100;
+	dg->dg_ntracks = 1;
 
-	disk_set_info(cd->sc_dev, &cd->sc_dk, NULL);
+	disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL);
 }

Index: src/sys/dev/scsipi/cdvar.h
diff -u src/sys/dev/scsipi/cdvar.h:1.32 src/sys/dev/scsipi/cdvar.h:1.33
--- src/sys/dev/scsipi/cdvar.h:1.32	Tue Apr 14 20:32:36 2015
+++ src/sys/dev/scsipi/cdvar.h	Sat Dec 10 10:26:38 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: cdvar.h,v 1.32 2015/04/14 20:32:36 riastradh Exp $	*/
+/*	$NetBSD: cdvar.h,v 1.33 2016/12/10 10:26:38 mlelstv Exp $	*/
 
 /*
  * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
@@ -24,19 +24,16 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <sys/rndsource.h>
+#include <dev/dkvar.h>
 
 #define	CDRETRIES	4
 
 struct cd_softc {
-	device_t sc_dev;
-	struct disk sc_dk;
-	kmutex_t sc_lock;
+	struct dk_softc sc_dksc;
 
 	int flags;
-#define	CDF_WLABEL	0x04		/* label is writable */
-#define	CDF_LABELLING	0x08		/* writing label */
 #define	CDF_ANCIENT	0x10		/* disk is ancient; for minphys */
+#define	CDF_EJECTED	0x20		/* be silent when flushing cache */
 
 	struct scsipi_periph *sc_periph;
 
@@ -46,8 +43,9 @@ struct cd_softc {
 		u_long disksize512;	/* total number sectors */
 	} params;
 
-	struct bufq_state *buf_queue;
 	struct callout sc_callout;
-
-	krndsource_t	rnd_source;
 };
+
+#define CDGP_RESULT_OK          0       /* parameters obtained */
+#define CDGP_RESULT_OFFLINE     1       /* no media, or otherwise losing */
+#define CDGP_RESULT_UNFORMATTED 2       /* unformatted media (max params) */

Index: src/sys/dev/scsipi/sd.c
diff -u src/sys/dev/scsipi/sd.c:1.319 src/sys/dev/scsipi/sd.c:1.320
--- src/sys/dev/scsipi/sd.c:1.319	Sun Nov 20 15:37:19 2016
+++ src/sys/dev/scsipi/sd.c	Sat Dec 10 10:26:38 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: sd.c,v 1.319 2016/11/20 15:37:19 mlelstv Exp $	*/
+/*	$NetBSD: sd.c,v 1.320 2016/12/10 10:26:38 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2003, 2004 The NetBSD Foundation, Inc.
@@ -47,14 +47,12 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.319 2016/11/20 15:37:19 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.320 2016/12/10 10:26:38 mlelstv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_scsi.h"
 #endif
 
-#define SD_MPSAFE D_MPSAFE
-
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
@@ -73,7 +71,6 @@ __KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.319
 #include <sys/proc.h>
 #include <sys/conf.h>
 #include <sys/vnode.h>
-#include <sys/rndsource.h>
 
 #include <dev/scsipi/scsi_spc.h>
 #include <dev/scsipi/scsipi_all.h>
@@ -96,15 +93,18 @@ __KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.319
 #define	SD_DEFAULT_BLKSIZE	512
 
 static void	sdminphys(struct buf *);
-static void	sdgetdefaultlabel(struct sd_softc *, struct disklabel *);
-static int	sdgetdisklabel(struct sd_softc *);
 static void	sdstart(struct scsipi_periph *);
 static void	sdrestart(void *);
 static void	sddone(struct scsipi_xfer *, int);
 static bool	sd_suspend(device_t, const pmf_qual_t *);
 static bool	sd_shutdown(device_t, int);
 static int	sd_interpret_sense(struct scsipi_xfer *);
-static int	sdlastclose(device_t);
+static int	sd_diskstart(device_t, struct buf *);
+static int	sd_dumpblocks(device_t, void *, daddr_t, int);
+static void	sd_iosize(device_t, int *);
+static int	sd_lastclose(device_t);
+static int	sd_firstopen(device_t, dev_t, int, int);
+static void	sd_label(device_t, struct disklabel *);
 
 static int	sd_mode_sense(struct sd_softc *, u_int8_t, void *, size_t, int,
 		    int, int *);
@@ -167,7 +167,7 @@ const struct bdevsw sd_bdevsw = {
 	.d_dump = sddump,
 	.d_psize = sdsize,
 	.d_discard = nodiscard,
-	.d_flag = D_DISK | SD_MPSAFE
+	.d_flag = D_DISK | D_MPSAFE
 };
 
 const struct cdevsw sd_cdevsw = {
@@ -182,12 +182,20 @@ const struct cdevsw sd_cdevsw = {
 	.d_mmap = nommap,
 	.d_kqfilter = nokqfilter,
 	.d_discard = nodiscard,
-	.d_flag = D_DISK | SD_MPSAFE
+	.d_flag = D_DISK | D_MPSAFE
 };
 
 static struct dkdriver sddkdriver = {
+	.d_open = sdopen,
+	.d_close = sdclose,
 	.d_strategy = sdstrategy,
-	.d_minphys = sdminphys
+	.d_minphys = sdminphys,
+	.d_diskstart = sd_diskstart,
+	.d_dumpblocks = sd_dumpblocks,
+	.d_iosize = sd_iosize,
+	.d_firstopen = sd_firstopen,
+	.d_lastclose = sd_lastclose,
+	.d_label = sd_label,
 };
 
 static const struct scsipi_periphsw sd_switch = {
@@ -236,25 +244,44 @@ static void
 sdattach(device_t parent, device_t self, void *aux)
 {
 	struct sd_softc *sd = device_private(self);
+	struct dk_softc *dksc = &sd->sc_dksc;
 	struct scsipibus_attach_args *sa = aux;
 	struct scsipi_periph *periph = sa->sa_periph;
-	int error, result;
+	int error, result, dtype;
 	struct disk_parms *dp = &sd->params;
 	char pbuf[9];
 
 	SC_DEBUG(periph, SCSIPI_DB2, ("sdattach: "));
 
-	sd->sc_dev = self;
 	sd->type = (sa->sa_inqbuf.type & SID_TYPE);
 	strncpy(sd->name, sa->sa_inqbuf.product, sizeof(sd->name));
+
 	if (sd->type == T_SIMPLE_DIRECT)
 		periph->periph_quirks |= PQUIRK_ONLYBIG | PQUIRK_NOBIGMODESENSE;
 
-	if (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(sa->sa_periph)) ==
-	    SCSIPI_BUSTYPE_SCSI && periph->periph_version == 0)
-		sd->flags |= SDF_ANCIENT;
+	switch (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(sa->sa_periph))) {
+	case SCSIPI_BUSTYPE_SCSI:
+		dtype = DKTYPE_SCSI;
+		if (periph->periph_version == 0)
+			sd->flags |= SDF_ANCIENT;
+		break;
+	case SCSIPI_BUSTYPE_ATAPI:
+		dtype = DKTYPE_ATAPI;
+		break;
+	default:
+		dtype = DKTYPE_UNKNOWN;
+		break;
+	}
+
+	/* Initialize dk and disk structure. */
+	dk_init(dksc, self, dtype);
+	disk_init(&dksc->sc_dkdev, dksc->sc_xname, &sddkdriver);
+
+	/* Attach dk and disk subsystems */
+	dk_attach(dksc);
+	disk_attach(&dksc->sc_dkdev);
 
-	bufq_alloc(&sd->buf_queue, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK);
+	bufq_alloc(&dksc->sc_bufq, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK);
 
 	callout_init(&sd->sc_callout, 0);
 
@@ -263,7 +290,7 @@ sdattach(device_t parent, device_t self,
 	 */
 	sd->sc_periph = periph;
 
-	periph->periph_dev = sd->sc_dev;
+	periph->periph_dev = dksc->sc_dev;
 	periph->periph_switch = &sd_switch;
 
         /*
@@ -276,12 +303,6 @@ sdattach(device_t parent, device_t self,
 	periph->periph_flags |= PERIPH_GROW_OPENINGS;
 
 	/*
-	 * Initialize and attach the disk structure.
-	 */
-	disk_init(&sd->sc_dk, device_xname(sd->sc_dev), &sddkdriver);
-	disk_attach(&sd->sc_dk);
-
-	/*
 	 * Use the subdriver to request information regarding the drive.
 	 */
 	aprint_naive("\n");
@@ -293,12 +314,12 @@ sdattach(device_t parent, device_t self,
 	error = scsipi_test_unit_ready(periph,
 	    XS_CTL_DISCOVERY | XS_CTL_IGNORE_ILLEGAL_REQUEST |
 	    XS_CTL_IGNORE_MEDIA_CHANGE | XS_CTL_SILENT_NODEV);
-
 	if (error)
 		result = SDGP_RESULT_OFFLINE;
 	else
 		result = sd_get_parms(sd, &sd->params, XS_CTL_DISCOVERY);
-	aprint_normal_dev(sd->sc_dev, "");
+
+	aprint_normal_dev(dksc->sc_dev, "");
 	switch (result) {
 	case SDGP_RESULT_OK:
 		format_bytes(pbuf, sizeof(pbuf),
@@ -325,6 +346,9 @@ sdattach(device_t parent, device_t self,
 	}
 	aprint_normal("\n");
 
+	/* Discover wedges on this disk. */
+	dkwedge_discover(&dksc->sc_dkdev);
+
 	/*
 	 * Establish a shutdown hook so that we can ensure that
 	 * our data has actually made it onto the platter at
@@ -335,36 +359,18 @@ sdattach(device_t parent, device_t self,
 	 */
 	if (!pmf_device_register1(self, sd_suspend, NULL, sd_shutdown))
 		aprint_error_dev(self, "couldn't establish power handler\n");
-
-	/*
-	 * attach the device into the random source list
-	 */
-	rnd_attach_source(&sd->rnd_source, device_xname(sd->sc_dev),
-			  RND_TYPE_DISK, RND_FLAG_DEFAULT);
-
-	/* Discover wedges on this disk. */
-	dkwedge_discover(&sd->sc_dk);
-
-	/*
-	 * Disk insertion and removal times can be a useful source
-	 * of entropy, though the estimator should never _count_
-	 * these bits, on insertion, because the deltas to the
-	 * nonexistent) previous event should never allow it.
-	 */
-	rnd_add_uint32(&sd->rnd_source, 0);
 }
 
 static int
 sddetach(device_t self, int flags)
 {
 	struct sd_softc *sd = device_private(self);
+	struct dk_softc *dksc = &sd->sc_dksc;
 	struct scsipi_periph *periph = sd->sc_periph;
 	struct scsipi_channel *chan = periph->periph_channel;
 	int bmaj, cmaj, i, mn, rc;
 
-	rnd_add_uint32(&sd->rnd_source, 0);
-
-	if ((rc = disk_begindetach(&sd->sc_dk, sdlastclose, self, flags)) != 0)
+	if ((rc = disk_begindetach(&dksc->sc_dkdev, sd_lastclose, self, flags)) != 0)
 		return rc;
 
 	/* locate the major number */
@@ -381,227 +387,172 @@ sddetach(device_t self, int flags)
 	/* kill any pending restart */
 	callout_stop(&sd->sc_callout);
 
-	/* Delete all of our wedges. */
-	dkwedge_delall(&sd->sc_dk);
-
-	mutex_enter(chan_mtx(chan));
-
-	/* Kill off any queued buffers. */
-	bufq_drain(sd->buf_queue);
+	dk_drain(dksc);
 
 	/* Kill off any pending commands. */
-	scsipi_kill_pending(sd->sc_periph);
-
+	mutex_enter(chan_mtx(chan));
+	scsipi_kill_pending(periph);
 	mutex_exit(chan_mtx(chan));
 
-	bufq_free(sd->buf_queue);
+	bufq_free(dksc->sc_bufq);
+
+	/* Delete all of our wedges. */
+	dkwedge_delall(&dksc->sc_dkdev);
 
 	/* Detach from the disk list. */
-	disk_detach(&sd->sc_dk);
-	disk_destroy(&sd->sc_dk);
+	disk_detach(&dksc->sc_dkdev);
+	disk_destroy(&dksc->sc_dkdev);
+
+	dk_detach(dksc);
 
 	callout_destroy(&sd->sc_callout);
 
 	pmf_device_deregister(self);
 
-	/* Unhook the entropy source. */
-	rnd_detach_source(&sd->rnd_source);
-
 	return (0);
 }
 
 /*
- * open the device. Make sure the partition info is a up-to-date as can be.
+ * Serialized by caller
  */
 static int
-sdopen(dev_t dev, int flag, int fmt, struct lwp *l)
+sd_firstopen(device_t self, dev_t dev, int flag, int fmt)
 {
-	struct sd_softc *sd;
-	struct scsipi_periph *periph;
-	struct scsipi_adapter *adapt;
-	int unit, part;
-	int error;
+	struct sd_softc *sd = device_private(self);
+	struct scsipi_periph *periph = sd->sc_periph;
+	struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
+	int error, silent;
+	int part, removable;
 
-	unit = SDUNIT(dev);
-	sd = device_lookup_private(&sd_cd, unit);
-	if (sd == NULL)
-		return (ENXIO);
+	part = SDPART(dev);
 
-	if (!device_is_active(sd->sc_dev))
-		return (ENODEV);
+	error = scsipi_adapter_addref(adapt);
+	if (error)
+		return error;
 
-	part = SDPART(dev);
+	if ((part == RAW_PART && fmt == S_IFCHR) || (flag & FSILENT))
+		silent = XS_CTL_SILENT;
+	else
+		silent = 0;
 
-	mutex_enter(&sd->sc_dk.dk_openlock);
+	/* Check that it is still responding and ok. */
+	error = scsipi_test_unit_ready(periph,
+	    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE |
+	    silent);
 
 	/*
-	 * If there are wedges, and this is not RAW_PART, then we
-	 * need to fail.
+	 * Start the pack spinning if necessary. Always allow the
+	 * raw parition to be opened, for raw IOCTLs. Data transfers
+	 * will check for SDEV_MEDIA_LOADED.
 	 */
-	if (sd->sc_dk.dk_nwedges != 0 && part != RAW_PART) {
-		error = EBUSY;
-		goto bad1;
+	if (error == EIO) {
+		error = scsipi_start(periph, SSS_START, silent);
+		if (error == EINVAL)
+			error = EIO;
 	}
+	if (error)
+		goto bad;
 
-	periph = sd->sc_periph;
-	adapt = periph->periph_channel->chan_adapter;
-
-	SC_DEBUG(periph, SCSIPI_DB1,
-	    ("sdopen: dev=0x%"PRIx64" (unit %d (of %d), partition %d)\n", dev, unit,
-	    sd_cd.cd_ndevs, part));
+	removable = (periph->periph_flags & PERIPH_REMOVABLE) != 0;
+	if (removable) {
+		/* Lock the pack in. */
+		error = scsipi_prevent(periph, SPAMR_PREVENT_DT,
+		    XS_CTL_IGNORE_ILLEGAL_REQUEST |
+		    XS_CTL_IGNORE_MEDIA_CHANGE |
+		    XS_CTL_SILENT);
+		if (error)
+			goto bad;
+	}
 
-	/*
-	 * If this is the first open of this device, add a reference
-	 * to the adapter.
-	 */
-	if (sd->sc_dk.dk_openmask == 0 &&
-	    (error = scsipi_adapter_addref(adapt)) != 0)
-		goto bad1;
+	if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
+		int param_error;
 
-	if ((periph->periph_flags & PERIPH_OPEN) != 0) {
 		/*
-		 * If any partition is open, but the disk has been invalidated,
-		 * disallow further opens of non-raw partition
+		 * Load the physical device parameters.
+		 *
+		 * Note that if media is present but unformatted,
+		 * we allow the open (so that it can be formatted!).
+		 * The drive should refuse real I/O, if the media is
+		 * unformatted.
 		 */
-		if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0 &&
-		    (part != RAW_PART || fmt != S_IFCHR)) {
-			error = EIO;
+		param_error = sd_get_parms(sd, &sd->params, 0);
+		if (param_error == SDGP_RESULT_OFFLINE) {
+			error = ENXIO;
 			goto bad2;
 		}
-	} else {
-		int silent;
+		periph->periph_flags |= PERIPH_MEDIA_LOADED;
 
-		if ((part == RAW_PART && fmt == S_IFCHR) || (flag & FSILENT))
-			silent = XS_CTL_SILENT;
-		else
-			silent = 0;
+		SC_DEBUG(periph, SCSIPI_DB3, ("Params loaded "));
+	}
 
-		/* Check that it is still responding and ok. */
-		error = scsipi_test_unit_ready(periph,
-		    XS_CTL_IGNORE_ILLEGAL_REQUEST | XS_CTL_IGNORE_MEDIA_CHANGE |
-		    silent);
+	periph->periph_flags |= PERIPH_OPEN;
+	return 0;
 
-		/*
-		 * Start the pack spinning if necessary. Always allow the
-		 * raw parition to be opened, for raw IOCTLs. Data transfers
-		 * will check for SDEV_MEDIA_LOADED.
-		 */
-		if (error == EIO) {
-			int error2;
+bad2:
+	if (removable)
+		scsipi_prevent(periph, SPAMR_ALLOW,
+		    XS_CTL_IGNORE_ILLEGAL_REQUEST |
+		    XS_CTL_IGNORE_MEDIA_CHANGE |
+		    XS_CTL_SILENT);
 
-			error2 = scsipi_start(periph, SSS_START, silent);
-			switch (error2) {
-			case 0:
-				error = 0;
-				break;
-			case EIO:
-			case EINVAL:
-				break;
-			default:
-				error = error2;
-				break;
-			}
-		}
-		if (error) {
-			if (silent && (flag & FSILENT) == 0)
-				goto out;
-			goto bad2;
-		}
+bad:
+	scsipi_adapter_delref(adapt);
+	return error;
+}
 
-		periph->periph_flags |= PERIPH_OPEN;
+/*
+ * open the device. Make sure the partition info is a up-to-date as can be.
+ */
+static int
+sdopen(dev_t dev, int flag, int fmt, struct lwp *l)
+{
+	struct sd_softc *sd;
+	struct dk_softc *dksc;
+	struct scsipi_periph *periph;
+	int unit, part;
+	int error;
 
-		if (periph->periph_flags & PERIPH_REMOVABLE) {
-			/* Lock the pack in. */
-			error = scsipi_prevent(periph, SPAMR_PREVENT_DT,
-			    XS_CTL_IGNORE_ILLEGAL_REQUEST |
-			    XS_CTL_IGNORE_MEDIA_CHANGE |
-			    XS_CTL_SILENT);
-			if (error)
-				goto bad3;
-		}
+	unit = SDUNIT(dev);
+	sd = device_lookup_private(&sd_cd, unit);
+	if (sd == NULL)
+		return (ENXIO);
+	dksc = &sd->sc_dksc;
 
-		if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
-			int param_error;
-			periph->periph_flags |= PERIPH_MEDIA_LOADED;
+	if (!device_is_active(dksc->sc_dev))
+		return (ENODEV);
 
-			/*
-			 * Load the physical device parameters.
-			 *
-			 * Note that if media is present but unformatted,
-			 * we allow the open (so that it can be formatted!).
-			 * The drive should refuse real I/O, if the media is
-			 * unformatted.
-			 */
-			if ((param_error = sd_get_parms(sd, &sd->params, 0))
-			     == SDGP_RESULT_OFFLINE) {
-				error = ENXIO;
-				periph->periph_flags &= ~PERIPH_MEDIA_LOADED;
-				goto bad3;
-			}
-			SC_DEBUG(periph, SCSIPI_DB3, ("Params loaded "));
+	periph = sd->sc_periph;
+	part = SDPART(dev);
 
-			/* Load the partition info if not already loaded. */
-			if (param_error == 0) {
-				if ((sdgetdisklabel(sd) != 0) && (part != RAW_PART)) {
-					error = EIO;
-					goto bad3;
-				}
-				SC_DEBUG(periph, SCSIPI_DB3,
-				     ("Disklabel loaded "));
-			}
-		}
-	}
+	SC_DEBUG(periph, SCSIPI_DB1,
+	    ("sdopen: dev=0x%"PRIx64" (unit %d (of %d), partition %d)\n",
+	    dev, unit, sd_cd.cd_ndevs, SDPART(dev)));
 
-	/* Check that the partition exists. */
-	if (part != RAW_PART &&
-	    (part >= sd->sc_dk.dk_label->d_npartitions ||
-	     sd->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
-		error = ENXIO;
-		goto bad3;
+	/*
+	 * If any partition is open, but the disk has been invalidated,
+	 * disallow further opens of non-raw partition
+	 */
+	if ((periph->periph_flags & (PERIPH_OPEN | PERIPH_MEDIA_LOADED)) ==
+	    PERIPH_OPEN) {
+		if (part != RAW_PART || fmt != S_IFCHR)
+			return EIO;
 	}
 
- out:	/* Insure only one open at a time. */
-	switch (fmt) {
-	case S_IFCHR:
-		sd->sc_dk.dk_copenmask |= (1 << part);
-		break;
-	case S_IFBLK:
-		sd->sc_dk.dk_bopenmask |= (1 << part);
-		break;
-	}
-	sd->sc_dk.dk_openmask =
-	    sd->sc_dk.dk_copenmask | sd->sc_dk.dk_bopenmask;
+	error = dk_open(dksc, dev, flag, fmt, l);
 
 	SC_DEBUG(periph, SCSIPI_DB3, ("open complete\n"));
-	mutex_exit(&sd->sc_dk.dk_openlock);
-	return (0);
 
- bad3:
-	if (sd->sc_dk.dk_openmask == 0) {
-		if (periph->periph_flags & PERIPH_REMOVABLE)
-			scsipi_prevent(periph, SPAMR_ALLOW,
-			    XS_CTL_IGNORE_ILLEGAL_REQUEST |
-			    XS_CTL_IGNORE_MEDIA_CHANGE |
-			    XS_CTL_SILENT);
-		periph->periph_flags &= ~PERIPH_OPEN;
-	}
-
- bad2:
-	if (sd->sc_dk.dk_openmask == 0)
-		scsipi_adapter_delref(adapt);
-
- bad1:
-	mutex_exit(&sd->sc_dk.dk_openlock);
-	return (error);
+	return error;
 }
 
 /*
- * Caller must hold sd->sc_dk.dk_openlock.
+ * Serialized by caller
  */
 static int
-sdlastclose(device_t self)
+sd_lastclose(device_t self)
 {
 	struct sd_softc *sd = device_private(self);
+	struct dk_softc *dksc = &sd->sc_dksc;
 	struct scsipi_periph *periph = sd->sc_periph;
 	struct scsipi_adapter *adapt = periph->periph_channel->chan_adapter;
 
@@ -611,7 +562,7 @@ sdlastclose(device_t self)
 	 */
 	if ((sd->flags & SDF_DIRTY) != 0) {
 		if (sd_flush(sd, 0)) {
-			aprint_error_dev(sd->sc_dev,
+			aprint_error_dev(dksc->sc_dev,
 				"cache synchronization failed\n");
 			sd->flags &= ~SDF_FLUSHING;
 		} else
@@ -641,26 +592,15 @@ sdlastclose(device_t self)
 static int
 sdclose(dev_t dev, int flag, int fmt, struct lwp *l)
 {
-	struct sd_softc *sd = device_lookup_private(&sd_cd, SDUNIT(dev));
-	int part = SDPART(dev);
-
-	mutex_enter(&sd->sc_dk.dk_openlock);
-	switch (fmt) {
-	case S_IFCHR:
-		sd->sc_dk.dk_copenmask &= ~(1 << part);
-		break;
-	case S_IFBLK:
-		sd->sc_dk.dk_bopenmask &= ~(1 << part);
-		break;
-	}
-	sd->sc_dk.dk_openmask =
-	    sd->sc_dk.dk_copenmask | sd->sc_dk.dk_bopenmask;
+	struct sd_softc *sd;
+	struct dk_softc *dksc;
+	int unit;
 
-	if (sd->sc_dk.dk_openmask == 0)
-		sdlastclose(sd->sc_dev);
+	unit = SDUNIT(dev);
+	sd = device_lookup_private(&sd_cd, unit);
+	dksc = &sd->sc_dksc;
 
-	mutex_exit(&sd->sc_dk.dk_openlock);
-	return (0);
+	return dk_close(dksc, dev, flag, fmt, l);
 }
 
 /*
@@ -672,285 +612,209 @@ static void
 sdstrategy(struct buf *bp)
 {
 	struct sd_softc *sd = device_lookup_private(&sd_cd, SDUNIT(bp->b_dev));
+	struct dk_softc *dksc = &sd->sc_dksc;
 	struct scsipi_periph *periph = sd->sc_periph;
-	struct scsipi_channel *chan = periph->periph_channel;
-	struct disklabel *lp;
-	daddr_t blkno;
-	bool sector_aligned;
 
 	SC_DEBUG(sd->sc_periph, SCSIPI_DB2, ("sdstrategy "));
 	SC_DEBUG(sd->sc_periph, SCSIPI_DB1,
 	    ("%d bytes @ blk %" PRId64 "\n", bp->b_bcount, bp->b_blkno));
+
 	/*
 	 * If the device has been made invalid, error out
 	 */
 	if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0 ||
-	    !device_is_active(sd->sc_dev)) {
+	    !device_is_active(dksc->sc_dev)) {
 		if (periph->periph_flags & PERIPH_OPEN)
 			bp->b_error = EIO;
 		else
 			bp->b_error = ENODEV;
-		goto done;
+
+		bp->b_resid = bp->b_bcount;
+		biodone(bp);
+		return;
 	}
 
-	lp = sd->sc_dk.dk_label;
+	dk_strategy(dksc, bp);
+}
+
+/*
+ * Issue single I/O command
+ *
+ * Called from dk_start and implicitely from dk_strategy
+ */
+static int
+sd_diskstart(device_t dev, struct buf *bp)
+{
+	struct sd_softc *sd = device_private(dev);
+	struct scsipi_periph *periph = sd->sc_periph;
+	struct scsipi_channel *chan = periph->periph_channel;
+	struct scsipi_rw_16 cmd16;
+	struct scsipi_rw_10 cmd_big;
+	struct scsi_rw_6 cmd_small;
+	struct scsipi_generic *cmdp;
+	struct scsipi_xfer *xs;
+	int error, flags, nblks, cmdlen;
+
+	mutex_enter(chan_mtx(chan));
+
+	if (periph->periph_active >= periph->periph_openings) {
+		error = EAGAIN;
+		goto out;
+	}
 
 	/*
-	 * The transfer must be a whole number of blocks, offset must not be
-	 * negative.
-	 */
-	if (lp->d_secsize == DEV_BSIZE) {
-		sector_aligned = (bp->b_bcount & (DEV_BSIZE - 1)) == 0;
-	} else {
-		sector_aligned = (bp->b_bcount % lp->d_secsize) == 0;
+	 * there is excess capacity, but a special waits
+	 * It'll need the adapter as soon as we clear out of the
+	 * way and let it run (user level wait).
+	 */
+	if (periph->periph_flags & PERIPH_WAITING) {
+		periph->periph_flags &= ~PERIPH_WAITING;
+		cv_broadcast(periph_cv_periph(periph));
+		error = EAGAIN;
+		goto out;
 	}
-	if (!sector_aligned || bp->b_blkno < 0) {
-		bp->b_error = EINVAL;
-		goto done;
+
+	/*
+	 * If the device has become invalid, abort all the
+	 * reads and writes until all files have been closed and
+	 * re-opened
+	 */
+	if (__predict_false(
+	    (periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)) {
+		error = EIO;
+		goto out;
 	}
+
 	/*
-	 * If it's a null transfer, return immediatly
+	 * Mark the disk dirty so that the cache will be
+	 * flushed on close.
 	 */
-	if (bp->b_bcount == 0)
-		goto done;
+	if ((bp->b_flags & B_READ) == 0)
+		sd->flags |= SDF_DIRTY;
+
+	if (sd->params.blksize == DEV_BSIZE)
+		nblks = bp->b_bcount >> DEV_BSHIFT;
+	else
+		nblks = howmany(bp->b_bcount, sd->params.blksize);
 
 	/*
-	 * Do bounds checking, adjust transfer. if error, process.
-	 * If end of partition, just return.
+	 * Fill out the scsi command.  Use the smallest CDB possible
+	 * (6-byte, 10-byte, or 16-byte).
 	 */
-	if (SDPART(bp->b_dev) == RAW_PART) {
-		if (bounds_check_with_mediasize(bp, DEV_BSIZE,
-		    sd->params.disksize512) <= 0)
-			goto done;
+	if (((bp->b_rawblkno & 0x1fffff) == bp->b_rawblkno) &&
+	    ((nblks & 0xff) == nblks) &&
+	    !(periph->periph_quirks & PQUIRK_ONLYBIG)) {
+		/* 6-byte CDB */
+		memset(&cmd_small, 0, sizeof(cmd_small));
+		cmd_small.opcode = (bp->b_flags & B_READ) ?
+		    SCSI_READ_6_COMMAND : SCSI_WRITE_6_COMMAND;
+		_lto3b(bp->b_rawblkno, cmd_small.addr);
+		cmd_small.length = nblks & 0xff;
+		cmdlen = sizeof(cmd_small);
+		cmdp = (struct scsipi_generic *)&cmd_small;
+	} else if ((bp->b_rawblkno & 0xffffffff) == bp->b_rawblkno) {
+		/* 10-byte CDB */
+		memset(&cmd_big, 0, sizeof(cmd_big));
+		cmd_big.opcode = (bp->b_flags & B_READ) ?
+		    READ_10 : WRITE_10;
+		_lto4b(bp->b_rawblkno, cmd_big.addr);
+		_lto2b(nblks, cmd_big.length);
+		cmdlen = sizeof(cmd_big);
+		cmdp = (struct scsipi_generic *)&cmd_big;
 	} else {
-		if (bounds_check_with_label(&sd->sc_dk, bp,
-		    (sd->flags & (SDF_WLABEL|SDF_LABELLING)) != 0) <= 0)
-			goto done;
+		/* 16-byte CDB */
+		memset(&cmd16, 0, sizeof(cmd16));
+		cmd16.opcode = (bp->b_flags & B_READ) ?
+		    READ_16 : WRITE_16;
+		_lto8b(bp->b_rawblkno, cmd16.addr);
+		_lto4b(nblks, cmd16.length);
+		cmdlen = sizeof(cmd16);
+		cmdp = (struct scsipi_generic *)&cmd16;
 	}
 
 	/*
-	 * Now 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);
+	 * Figure out what flags to use.
+	 */
+	flags = XS_CTL_NOSLEEP|XS_CTL_ASYNC|XS_CTL_SIMPLE_TAG;
+	if (bp->b_flags & B_READ)
+		flags |= XS_CTL_DATA_IN;
 	else
-		blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize);
-
-	if (SDPART(bp->b_dev) != RAW_PART)
-		blkno += lp->d_partitions[SDPART(bp->b_dev)].p_offset;
-
-	bp->b_rawblkno = blkno;
-
-	mutex_enter(chan_mtx(chan));
+		flags |= XS_CTL_DATA_OUT;
 
 	/*
-	 * Place it in the queue of disk activities for this disk.
-	 *
-	 * XXX Only do disksort() if the current operating mode does not
-	 * XXX include tagged queueing.
+	 * Call the routine that chats with the adapter.
+	 * Note: we cannot sleep as we may be an interrupt
 	 */
-	bufq_put(sd->buf_queue, bp);
+	xs = scsipi_make_xs_locked(periph, cmdp, cmdlen,
+	    (u_char *)bp->b_data, bp->b_bcount,
+	    SDRETRIES, SD_IO_TIMEOUT, bp, flags);
+	if (__predict_false(xs == NULL)) {
+		/*
+		 * out of memory. Keep this buffer in the queue, and
+		 * retry later.
+		 */
+		callout_reset(&sd->sc_callout, hz / 2, sdrestart, sd);
+		error = 0;
+		goto out;
+	}
 
-	/*
-	 * Tell the device to get going on the transfer if it's
-	 * not doing anything, otherwise just wait for completion
-	 */
-	sdstart(periph);
+	error = scsipi_execute_xs(xs);
+	/* with a scsipi_xfer preallocated, scsipi_command can't fail */
+	KASSERT(error == 0);
 
+out:
 	mutex_exit(chan_mtx(chan));
-	return;
 
-done:
-	/*
-	 * Correctly set the buf to indicate a completed xfer
-	 */
-	bp->b_resid = bp->b_bcount;
-	biodone(bp);
+	return error;
 }
 
 /*
- * sdstart looks to see if there is a buf waiting for the device
- * and that the device is not already busy. If both are true,
- * It dequeues the buf and creates a scsi command to perform the
- * transfer in the buf. The transfer request will call scsipi_done
- * on completion, which will in turn call this routine again
- * so that the next queued transfer is performed.
- * The bufs are queued by the strategy routine (sdstrategy)
+ * Recover I/O request after memory shortage
  *
- * This routine is also called after other non-queued requests
- * have been made of the scsi driver, to ensure that the queue
- * continues to be drained.
+ * Called from callout
+ */
+static void
+sdrestart(void *v)
+{
+	struct sd_softc *sd = v;
+	struct dk_softc *dksc = &sd->sc_dksc;
+
+	dk_start(dksc, NULL);
+}
+
+/*
+ * Recover I/O request after memory shortage
  *
- * must be called with channel lock held
- * sdstart() is called from sdstrategy, sdrestart and scsipi_done
+ * Called from scsipi midlayer when resources have been freed
+ * with channel lock held
  */
 static void
 sdstart(struct scsipi_periph *periph)
 {
 	struct sd_softc *sd = device_private(periph->periph_dev);
-	struct disklabel *lp = sd->sc_dk.dk_label;
-	struct buf *bp = 0;
-	struct scsipi_rw_16 cmd16;
-	struct scsipi_rw_10 cmd_big;
-	struct scsi_rw_6 cmd_small;
-	struct scsipi_generic *cmdp;
-	struct scsipi_xfer *xs;
-	int nblks, cmdlen, error __diagused, flags;
-
-	SC_DEBUG(periph, SCSIPI_DB2, ("sdstart "));
+	struct dk_softc *dksc = &sd->sc_dksc;
+	struct scsipi_channel *chan = periph->periph_channel;
 
 	/*
-	 * Check if the device has room for another command
+	 * release channel lock as dk_start may need to acquire
+	 * other locks
+	 *
+	 * sdstart is called from scsipi_put_xs and all its callers
+	 * release the lock afterwards. So releasing it here
+	 * doesn't matter.
 	 */
-	while (periph->periph_active < periph->periph_openings) {
-		/*
-		 * there is excess capacity, but a special waits
-		 * It'll need the adapter as soon as we clear out of the
-		 * way and let it run (user level wait).
-		 */
-		if (periph->periph_flags & PERIPH_WAITING) {
-			periph->periph_flags &= ~PERIPH_WAITING;
-			cv_broadcast(periph_cv_periph(periph));
-			return;
-		}
-
-		/*
-		 * If the device has become invalid, abort all the
-		 * reads and writes until all files have been closed and
-		 * re-opened
-		 */
-		if (__predict_false(
-		    (periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)) {
-			if ((bp = bufq_get(sd->buf_queue)) != NULL) {
-				bp->b_error = EIO;
-				bp->b_resid = bp->b_bcount;
-				biodone(bp);
-				continue;
-			} else {
-				return;
-			}
-		}
-
-		/*
-		 * See if there is a buf with work for us to do..
-		 */
-		if ((bp = bufq_peek(sd->buf_queue)) == NULL)
-			return;
-
-		/*
-		 * We have a buf, now we should make a command.
-		 */
-
-		if (lp->d_secsize == DEV_BSIZE)
-			nblks = bp->b_bcount >> DEV_BSHIFT;
-		else
-			nblks = howmany(bp->b_bcount, lp->d_secsize);
-
-		/*
-		 * Fill out the scsi command.  Use the smallest CDB possible
-		 * (6-byte, 10-byte, or 16-byte).
-		 */
-		if (((bp->b_rawblkno & 0x1fffff) == bp->b_rawblkno) &&
-		    ((nblks & 0xff) == nblks) &&
-		    !(periph->periph_quirks & PQUIRK_ONLYBIG)) {
-			/* 6-byte CDB */
-			memset(&cmd_small, 0, sizeof(cmd_small));
-			cmd_small.opcode = (bp->b_flags & B_READ) ?
-			    SCSI_READ_6_COMMAND : SCSI_WRITE_6_COMMAND;
-			_lto3b(bp->b_rawblkno, cmd_small.addr);
-			cmd_small.length = nblks & 0xff;
-			cmdlen = sizeof(cmd_small);
-			cmdp = (struct scsipi_generic *)&cmd_small;
-		} else if ((bp->b_rawblkno & 0xffffffff) == bp->b_rawblkno) {
-			/* 10-byte CDB */
-			memset(&cmd_big, 0, sizeof(cmd_big));
-			cmd_big.opcode = (bp->b_flags & B_READ) ?
-			    READ_10 : WRITE_10;
-			_lto4b(bp->b_rawblkno, cmd_big.addr);
-			_lto2b(nblks, cmd_big.length);
-			cmdlen = sizeof(cmd_big);
-			cmdp = (struct scsipi_generic *)&cmd_big;
-		} else {
-			/* 16-byte CDB */
-			memset(&cmd16, 0, sizeof(cmd16));
-			cmd16.opcode = (bp->b_flags & B_READ) ?
-			    READ_16 : WRITE_16;
-			_lto8b(bp->b_rawblkno, cmd16.addr);
-			_lto4b(nblks, cmd16.length);
-			cmdlen = sizeof(cmd16);
-			cmdp = (struct scsipi_generic *)&cmd16;
-		}
-
-		/* Instrumentation. */
-		disk_busy(&sd->sc_dk);
-
-		/*
-		 * Mark the disk dirty so that the cache will be
-		 * flushed on close.
-		 */
-		if ((bp->b_flags & B_READ) == 0)
-			sd->flags |= SDF_DIRTY;
-
-		/*
-		 * Figure out what flags to use.
-		 */
-		flags = XS_CTL_NOSLEEP|XS_CTL_ASYNC|XS_CTL_SIMPLE_TAG;
-		if (bp->b_flags & B_READ)
-			flags |= XS_CTL_DATA_IN;
-		else
-			flags |= XS_CTL_DATA_OUT;
-
-		/*
-		 * Call the routine that chats with the adapter.
-		 * Note: we cannot sleep as we may be an interrupt
-		 */
-		xs = scsipi_make_xs_locked(periph, cmdp, cmdlen,
-		    (u_char *)bp->b_data, bp->b_bcount,
-		    SDRETRIES, SD_IO_TIMEOUT, bp, flags);
-		if (__predict_false(xs == NULL)) {
-			/*
-			 * out of memory. Keep this buffer in the queue, and
-			 * retry later.
-			 */
-			callout_reset(&sd->sc_callout, hz / 2, sdrestart,
-			    periph);
-			return;
-		}
-		/*
-		 * need to dequeue the buffer before queuing the command,
-		 * because cdstart may be called recursively from the
-		 * HBA driver
-		 */
-#ifdef DIAGNOSTIC
-		if (bufq_get(sd->buf_queue) != bp)
-			panic("sdstart(): dequeued wrong buf");
-#else
-		bufq_get(sd->buf_queue);
-#endif
-		error = scsipi_execute_xs(xs);
-		/* with a scsipi_xfer preallocated, scsipi_command can't fail */
-		KASSERT(error == 0);
-	}
-}
+	mutex_exit(chan_mtx(chan));
 
-static void
-sdrestart(void *v)
-{
-	struct scsipi_periph *periph = v;
-	struct scsipi_channel *chan = periph->periph_channel;
+	dk_start(dksc, NULL);
 
 	mutex_enter(chan_mtx(chan));
-	sdstart((struct scsipi_periph *)v);
-	mutex_exit(chan_mtx(chan));
 }
 
 static void
 sddone(struct scsipi_xfer *xs, int error)
 {
 	struct sd_softc *sd = device_private(xs->xs_periph->periph_dev);
+	struct dk_softc *dksc = &sd->sc_dksc;
 	struct buf *bp = xs->bp;
 
 	if (sd->flags & SDF_FLUSHING) {
@@ -966,11 +830,7 @@ sddone(struct scsipi_xfer *xs, int error
 			bp->b_resid = bp->b_bcount;
 		}
 
-		disk_unbusy(&sd->sc_dk, bp->b_bcount - bp->b_resid,
-		    (bp->b_flags & B_READ));
-		rnd_add_uint32(&sd->rnd_source, bp->b_rawblkno);
-
-		biodone(bp);
+		dk_done(dksc, bp);
 	}
 }
 
@@ -978,6 +838,7 @@ static void
 sdminphys(struct buf *bp)
 {
 	struct sd_softc *sd = device_lookup_private(&sd_cd, SDUNIT(bp->b_dev));
+	struct dk_softc *dksc = &sd->sc_dksc;
 	long xmax;
 
 	/*
@@ -994,7 +855,7 @@ sdminphys(struct buf *bp)
 	if ((sd->flags & SDF_ANCIENT) &&
 	    ((sd->sc_periph->periph_flags &
 	    (PERIPH_REMOVABLE | PERIPH_MEDIA_LOADED)) != PERIPH_REMOVABLE)) {
-		xmax = sd->sc_dk.dk_label->d_secsize * 0xff;
+		xmax = dksc->sc_dkdev.dk_geom.dg_secsize * 0xff;
 
 		if (bp->b_bcount > xmax)
 			bp->b_bcount = xmax;
@@ -1003,6 +864,21 @@ sdminphys(struct buf *bp)
 	scsipi_adapter_minphys(sd->sc_periph->periph_channel, bp);
 }
 
+static void
+sd_iosize(device_t dev, int *count)
+{
+	struct buf B;
+	int bmaj;
+
+	bmaj       = bdevsw_lookup_major(&sd_bdevsw);
+	B.b_dev    = MAKESDDEV(bmaj,device_unit(dev),RAW_PART);
+	B.b_bcount = *count;
+
+	sdminphys(&B);
+
+	*count = B.b_bcount;
+}
+
 static int
 sdread(dev_t dev, struct uio *uio, int ioflag)
 {
@@ -1025,12 +901,11 @@ static int
 sdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
 {
 	struct sd_softc *sd = device_lookup_private(&sd_cd, SDUNIT(dev));
+	struct dk_softc *dksc = &sd->sc_dksc;
 	struct scsipi_periph *periph = sd->sc_periph;
+
 	int part = SDPART(dev);
 	int error;
-#ifdef __HAVE_OLD_DISKLABEL
-	struct disklabel *newlabel = NULL;
-#endif
 
 	SC_DEBUG(sd->sc_periph, SCSIPI_DB2, ("sdioctl 0x%lx ", cmd));
 
@@ -1038,110 +913,17 @@ sdioctl(dev_t dev, u_long cmd, void *add
 	 * If the device is not valid, some IOCTLs can still be
 	 * handled on the raw partition. Check this here.
 	 */
-	if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0) {
-		switch (cmd) {
-		case DIOCKLABEL:
-		case DIOCWLABEL:
-		case DIOCLOCK:
-		case DIOCEJECT:
-		case ODIOCEJECT:
-		case DIOCGCACHE:
-		case DIOCSCACHE:
-		case DIOCGSTRATEGY:
-		case DIOCSSTRATEGY:
-		case SCIOCIDENTIFY:
-		case OSCIOCIDENTIFY:
-		case SCIOCCOMMAND:
-		case SCIOCDEBUG:
-			if (part == RAW_PART)
-				break;
-		/* FALLTHROUGH */
-		default:
-			if ((periph->periph_flags & PERIPH_OPEN) == 0)
-				return (ENODEV);
-			else
-				return (EIO);
-		}
-	}
-
-	error = disk_ioctl(&sd->sc_dk, dev, cmd, addr, flag, l); 
-	if (error != EPASSTHROUGH)
-		return (error);
+	if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0 &&
+	    part != RAW_PART)
+		return (EIO);
 
-	error = 0;
 	switch (cmd) {
-	case DIOCWDINFO:
-	case DIOCSDINFO:
-#ifdef __HAVE_OLD_DISKLABEL
-	case ODIOCWDINFO:
-	case ODIOCSDINFO:
-#endif
-	{
-		struct disklabel *lp;
-
-		if ((flag & FWRITE) == 0)
-			return (EBADF);
-
-#ifdef __HAVE_OLD_DISKLABEL
- 		if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
-			newlabel = malloc(sizeof *newlabel, M_TEMP,
-			    M_WAITOK | M_ZERO);
-			if (newlabel == NULL)
-				return EIO;
-			memcpy(newlabel, addr, sizeof (struct olddisklabel));
-			lp = newlabel;
-		} else
-#endif
-		lp = (struct disklabel *)addr;
-
-		mutex_enter(&sd->sc_dk.dk_openlock);
-		sd->flags |= SDF_LABELLING;
-
-		error = setdisklabel(sd->sc_dk.dk_label,
-		    lp, /*sd->sc_dk.dk_openmask : */0,
-		    sd->sc_dk.dk_cpulabel);
-		if (error == 0) {
-			if (cmd == DIOCWDINFO
-#ifdef __HAVE_OLD_DISKLABEL
-			    || cmd == ODIOCWDINFO
-#endif
-			   )
-				error = writedisklabel(SDLABELDEV(dev),
-				    sdstrategy, sd->sc_dk.dk_label,
-				    sd->sc_dk.dk_cpulabel);
-		}
-
-		sd->flags &= ~SDF_LABELLING;
-		mutex_exit(&sd->sc_dk.dk_openlock);
-#ifdef __HAVE_OLD_DISKLABEL
-		if (newlabel != NULL)
-			free(newlabel, M_TEMP);
-#endif
-		return (error);
-	}
-
-	case DIOCKLABEL:
-		if (*(int *)addr)
-			periph->periph_flags |= PERIPH_KEEP_LABEL;
-		else
-			periph->periph_flags &= ~PERIPH_KEEP_LABEL;
-		return (0);
-
-	case DIOCWLABEL:
-		if ((flag & FWRITE) == 0)
-			return (EBADF);
-		if (*(int *)addr)
-			sd->flags |= SDF_WLABEL;
-		else
-			sd->flags &= ~SDF_WLABEL;
-		return (0);
-
 	case DIOCLOCK:
 		if (periph->periph_flags & PERIPH_REMOVABLE)
 			return (scsipi_prevent(periph,
 			    (*(int *)addr) ?
 			    SPAMR_PREVENT_DT : SPAMR_ALLOW, 0));
-		else
+		else 
 			return (ENOTTY);
 
 	case DIOCEJECT:
@@ -1152,9 +934,7 @@ sdioctl(dev_t dev, u_long cmd, void *add
 			 * Don't force eject: check that we are the only
 			 * partition open. If so, unlock it.
 			 */
-			if ((sd->sc_dk.dk_openmask & ~(1 << part)) == 0 &&
-			    sd->sc_dk.dk_bopenmask + sd->sc_dk.dk_copenmask ==
-			    sd->sc_dk.dk_openmask) {
+			if (DK_BUSY(dksc, part) == 0) {
 				error = scsipi_prevent(periph, SPAMR_ALLOW,
 				    XS_CTL_IGNORE_NOT_READY);
 				if (error)
@@ -1168,24 +948,6 @@ sdioctl(dev_t dev, u_long cmd, void *add
 		return ((periph->periph_flags & PERIPH_REMOVABLE) == 0 ?
 		    ENOTTY : scsipi_start(periph, SSS_STOP|SSS_LOEJ, 0));
 
-	case DIOCGDEFLABEL:
-		sdgetdefaultlabel(sd, (struct disklabel *)addr);
-		return (0);
-
-#ifdef __HAVE_OLD_DISKLABEL
-	case ODIOCGDEFLABEL:
-		newlabel = malloc(sizeof *newlabel, M_TEMP, M_WAITOK);
-		if (newlabel == NULL)
-			return EIO;
-		sdgetdefaultlabel(sd, newlabel);
-		if (newlabel->d_npartitions <= OLDMAXPARTITIONS)
-			memcpy(addr, newlabel, sizeof (struct olddisklabel));
-		else
-			error = ENOTTY;
-		free(newlabel, M_TEMP);
-		return error;
-#endif
-
 	case DIOCGCACHE:
 		return (sd_getcache(sd, (int *) addr));
 
@@ -1203,61 +965,19 @@ sdioctl(dev_t dev, u_long cmd, void *add
 			return (EBADF);
 		if (((sd->flags & SDF_DIRTY) != 0 || *(int *)addr != 0)) {
 			error = sd_flush(sd, 0);
-			if (error)
+			if (error) {
 				sd->flags &= ~SDF_FLUSHING;
-			else
-				sd->flags &= ~(SDF_FLUSHING|SDF_DIRTY);
-		}
-		return (error);
-
-	case DIOCGSTRATEGY:
-	    {
-		struct disk_strategy *dks = addr;
-		int s;
-
-		s = splbio();
-		strlcpy(dks->dks_name, bufq_getstrategyname(sd->buf_queue),
-		    sizeof(dks->dks_name));
-		splx(s);
-		dks->dks_paramlen = 0;
-
-		return 0;
-	    }
-
-	case DIOCSSTRATEGY:
-	    {
-		struct disk_strategy *dks = addr;
-		struct bufq_state *new_bufq;
-		struct bufq_state *old_bufq;
-		int s;
-
-		if ((flag & FWRITE) == 0) {
-			return EBADF;
-		}
-
-		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;
+				return (error);
+			}
+			sd->flags &= ~(SDF_FLUSHING|SDF_DIRTY);
 		}
-		s = splbio();
-		old_bufq = sd->buf_queue;
-		bufq_move(new_bufq, old_bufq);
-		sd->buf_queue = new_bufq;
-		splx(s);
-		bufq_free(old_bufq);
-		
-		return 0;
-	    }
+		return (0);
 
 	default:
-		if (part != RAW_PART)
-			return (ENOTTY);
-		return (scsipi_do_ioctl(periph, dev, cmd, addr, flag, l));
+		error = dk_ioctl(dksc, dev, cmd, addr, flag, l); 
+		if (error == ENOTTY)
+			error = scsipi_do_ioctl(periph, dev, cmd, addr, flag, l);
+		return (error);
 	}
 
 #ifdef DIAGNOSTIC
@@ -1266,86 +986,21 @@ sdioctl(dev_t dev, u_long cmd, void *add
 }
 
 static void
-sdgetdefaultlabel(struct sd_softc *sd, struct disklabel *lp)
-{
-
-	memset(lp, 0, sizeof(struct disklabel));
-
-	lp->d_secsize = sd->params.blksize;
-	lp->d_ntracks = sd->params.heads;
-	lp->d_nsectors = sd->params.sectors;
-	lp->d_ncylinders = sd->params.cyls;
-	lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
+sd_label(device_t self, struct disklabel *lp)
+{               
+	struct sd_softc *sd = device_private(self);
 
-	switch (SCSIPI_BUSTYPE_TYPE(scsipi_periph_bustype(sd->sc_periph))) {
-	case SCSIPI_BUSTYPE_SCSI:
-		lp->d_type = DKTYPE_SCSI;
-		break;
-	case SCSIPI_BUSTYPE_ATAPI:
-		lp->d_type = DKTYPE_ATAPI;
-		break;
-	}
-	/*
-	 * XXX
-	 * We could probe the mode pages to figure out what kind of disc it is.
-	 * Is this worthwhile?
-	 */
 	strncpy(lp->d_typename, sd->name, 16);
-	strncpy(lp->d_packname, "fictitious", 16);
-	if (sd->params.disksize > UINT32_MAX)
-		lp->d_secperunit = UINT32_MAX;
-	else
-		lp->d_secperunit = sd->params.disksize;
 	lp->d_rpm = sd->params.rot_rate;
-	lp->d_interleave = 1;
-	lp->d_flags = sd->sc_periph->periph_flags & PERIPH_REMOVABLE ?
-	    D_REMOVABLE : 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);
-}
-
-
-/*
- * Load the label information on the named device
- */
-static int
-sdgetdisklabel(struct sd_softc *sd)
-{
-	struct disklabel *lp = sd->sc_dk.dk_label;
-	const char *errstring;
-
-	memset(sd->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
-
-	sdgetdefaultlabel(sd, lp);
-
-	if (lp->d_secpercyl == 0) {
-		lp->d_secpercyl = 100;
-		/* as long as it's not 0 - readdisklabel divides by it (?) */
-	}
-
-	/*
-	 * Call the generic disklabel extraction routine
-	 */
-	errstring = readdisklabel(MAKESDDEV(0, device_unit(sd->sc_dev),
-	    RAW_PART), sdstrategy, lp, sd->sc_dk.dk_cpulabel);
-	if (errstring) {
-		aprint_error_dev(sd->sc_dev, "%s\n", errstring);
-		return EIO;
-	}
-	return 0;
+	if (sd->sc_periph->periph_flags & PERIPH_REMOVABLE)
+		lp->d_flags |= D_REMOVABLE;
 }
 
 static bool
 sd_shutdown(device_t self, int how)
 {
 	struct sd_softc *sd = device_private(self);
+	struct dk_softc *dksc = &sd->sc_dksc;
 
 	/*
 	 * If the disk cache needs to be flushed, and the disk supports
@@ -1354,7 +1009,7 @@ sd_shutdown(device_t self, int how)
 	 */
 	if ((sd->flags & SDF_DIRTY) != 0) {
 		if (sd_flush(sd, XS_CTL_NOSLEEP|XS_CTL_POLL)) {
-			aprint_error_dev(sd->sc_dev,
+			aprint_error_dev(dksc->sc_dev,
 				"cache synchronization failed\n");
 			sd->flags &= ~SDF_FLUSHING;
 		} else
@@ -1379,6 +1034,7 @@ sd_interpret_sense(struct scsipi_xfer *x
 	struct scsipi_channel *chan = periph->periph_channel;
 	struct scsi_sense_data *sense = &xs->sense.scsi_sense;
 	struct sd_softc *sd = device_private(periph->periph_dev);
+	struct dk_softc *dksc = &sd->sc_dksc;
 	int error, retval = EJUSTRETURN;
 
 	/*
@@ -1428,7 +1084,7 @@ sd_interpret_sense(struct scsipi_xfer *x
 			 * Unit In The Process Of Becoming Ready.
 			 */
 			printf("%s: waiting for pack to spin up...\n",
-			    device_xname(sd->sc_dev));
+			    dksc->sc_xname);
 			if (!callout_pending(&periph->periph_callout))
 				scsipi_periph_freeze(periph, 1);
 			callout_reset(&periph->periph_callout,
@@ -1436,7 +1092,7 @@ sd_interpret_sense(struct scsipi_xfer *x
 			retval = ERESTART;
 		} else if (sense->ascq == 0x02) {
 			printf("%s: pack is stopped, restarting...\n",
-			    device_xname(sd->sc_dev));
+			    dksc->sc_xname);
 			mutex_enter(chan_mtx(chan));
 			periph->periph_flags |= PERIPH_RECOVERING;
 			mutex_exit(chan_mtx(chan));
@@ -1444,7 +1100,7 @@ sd_interpret_sense(struct scsipi_xfer *x
 			    XS_CTL_URGENT|XS_CTL_HEAD_TAG|
 			    XS_CTL_THAW_PERIPH|XS_CTL_FREEZE_PERIPH);
 			if (error) {
-				aprint_error_dev(sd->sc_dev,
+				aprint_error_dev(dksc->sc_dev,
 					"unable to restart pack\n");
 				retval = error;
 			} else
@@ -1468,37 +1124,23 @@ static int
 sdsize(dev_t dev)
 {
 	struct sd_softc *sd;
-	int part, unit, omask;
-	int size;
+	struct dk_softc *dksc;
+	int unit;
 
 	unit = SDUNIT(dev);
 	sd = device_lookup_private(&sd_cd, unit);
 	if (sd == NULL)
 		return (-1);
+	dksc = &sd->sc_dksc;
 
-	if (!device_is_active(sd->sc_dev))
+	if (!device_is_active(dksc->sc_dev))
 		return (-1);
 
-	part = SDPART(dev);
-	omask = sd->sc_dk.dk_openmask & (1 << part);
-
-	if (omask == 0 && sdopen(dev, 0, S_IFBLK, NULL) != 0)
-		return (-1);
-	if ((sd->sc_periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)
-		size = -1;
-	else if (sd->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
-		size = -1;
-	else
-		size = sd->sc_dk.dk_label->d_partitions[part].p_size *
-		    (sd->sc_dk.dk_label->d_secsize / DEV_BSIZE);
-	if (omask == 0 && sdclose(dev, 0, S_IFBLK, NULL) != 0)
-		return (-1);
-	return (size);
+	return dk_size(dksc, dev);
 }
 
 /* #define SD_DUMP_NOT_TRUSTED if you just want to watch */
 static struct scsipi_xfer sx;
-static int sddoingadump;
 
 /*
  * dump all of physical memory into the partition specified, starting
@@ -1507,115 +1149,90 @@ static int sddoingadump;
 static int
 sddump(dev_t dev, daddr_t blkno, void *va, size_t size)
 {
-	struct sd_softc *sd;	/* disk unit to do the I/O */
-	struct disklabel *lp;	/* disk's disklabel */
-	int	unit, part;
-	int	sectorsize;	/* size of a disk sector */
-	int	nsects;		/* number of sectors in partition */
-	int	sectoff;	/* sector offset of partition */
-	int	totwrt;		/* total number of sectors left to write */
-	int	nwrt;		/* current number of sectors to write */
-	struct scsipi_rw_10 cmd;	/* write command */
-	struct scsipi_xfer *xs;	/* ... convenience */
+	struct sd_softc *sd;
+	struct dk_softc *dksc;
 	struct scsipi_periph *periph;
-	struct scsipi_channel *chan;
-
-	/* Check if recursive dump; if so, punt. */
-	if (sddoingadump)
-		return (EFAULT);
-
-	/* Mark as active early. */
-	sddoingadump = 1;
+	int unit;
 
-	unit = SDUNIT(dev);	/* Decompose unit & partition. */
-	part = SDPART(dev);
-
-	/* Check for acceptable drive number. */
-	sd = device_lookup_private(&sd_cd, unit);
-	if (sd == NULL)
+	unit = SDUNIT(dev);
+	if ((sd = device_lookup_private(&sd_cd, unit)) == NULL)
 		return (ENXIO);
+	dksc = &sd->sc_dksc;
 
-	if (!device_is_active(sd->sc_dev))
+	if (!device_is_active(dksc->sc_dev))
 		return (ENODEV);
 
 	periph = sd->sc_periph;
-	chan = periph->periph_channel;
 
 	/* Make sure it was initialized. */
 	if ((periph->periph_flags & PERIPH_MEDIA_LOADED) == 0)
 		return (ENXIO);
 
-	/* Convert to disk sectors.  Request must be a multiple of size. */
-	lp = sd->sc_dk.dk_label;
-	sectorsize = lp->d_secsize;
-	if ((size % sectorsize) != 0)
-		return (EFAULT);
-	totwrt = size / sectorsize;
-	blkno = dbtob(blkno) / sectorsize;	/* 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 + totwrt) > nsects))
-		return (EINVAL);
+	return dk_dump(dksc, dev, blkno, va, size);
+}
+
+static int
+sd_dumpblocks(device_t dev, void *va, daddr_t blkno, int nblk)
+{
+	struct sd_softc *sd = device_private(dev);
+	struct dk_softc *dksc = &sd->sc_dksc;
+	struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
+	struct scsipi_rw_10 cmd;	/* write command */
+	struct scsipi_xfer *xs;		/* ... convenience */
+	struct scsipi_periph *periph;
+	struct scsipi_channel *chan;
+	size_t sectorsize;
+
+	periph = sd->sc_periph;
+	chan = periph->periph_channel;
 
-	/* Offset block number to start of partition. */
-	blkno += sectoff;
+	sectorsize = dg->dg_secsize;
 
 	xs = &sx;
 
-	while (totwrt > 0) {
-		nwrt = totwrt;		/* XXX */
 #ifndef	SD_DUMP_NOT_TRUSTED
-		/*
-		 *  Fill out the scsi command
-		 */
-		memset(&cmd, 0, sizeof(cmd));
-		cmd.opcode = WRITE_10;
-		_lto4b(blkno, cmd.addr);
-		_lto2b(nwrt, cmd.length);
-		/*
-		 * Fill out the scsipi_xfer structure
-		 *    Note: we cannot sleep as we may be an interrupt
-		 * don't use scsipi_command() as it may want to wait
-		 * for an xs.
-		 */
-		memset(xs, 0, sizeof(sx));
-		xs->xs_control |= XS_CTL_NOSLEEP | XS_CTL_POLL |
-		    XS_CTL_DATA_OUT;
-		xs->xs_status = 0;
-		xs->xs_periph = periph;
-		xs->xs_retries = SDRETRIES;
-		xs->timeout = 10000;	/* 10000 millisecs for a disk ! */
-		xs->cmd = (struct scsipi_generic *)&cmd;
-		xs->cmdlen = sizeof(cmd);
-		xs->resid = nwrt * sectorsize;
-		xs->error = XS_NOERROR;
-		xs->bp = 0;
-		xs->data = va;
-		xs->datalen = nwrt * sectorsize;
-		callout_init(&xs->xs_callout, 0);
-
-		/*
-		 * Pass all this info to the scsi driver.
-		 */
-		scsipi_adapter_request(chan, ADAPTER_REQ_RUN_XFER, xs);
-		if ((xs->xs_status & XS_STS_DONE) == 0 ||
-		    xs->error != XS_NOERROR)
-			return (EIO);
+	/*
+	 *  Fill out the scsi command
+	 */
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.opcode = WRITE_10;
+	_lto4b(blkno, cmd.addr);
+	_lto2b(nblk, cmd.length);
+	/*
+	 * Fill out the scsipi_xfer structure
+	 *    Note: we cannot sleep as we may be an interrupt
+	 * don't use scsipi_command() as it may want to wait
+	 * for an xs.
+	 */
+	memset(xs, 0, sizeof(sx));
+	xs->xs_control |= XS_CTL_NOSLEEP | XS_CTL_POLL |
+	    XS_CTL_DATA_OUT;
+	xs->xs_status = 0;
+	xs->xs_periph = periph;
+	xs->xs_retries = SDRETRIES;
+	xs->timeout = 10000;	/* 10000 millisecs for a disk ! */
+	xs->cmd = (struct scsipi_generic *)&cmd;
+	xs->cmdlen = sizeof(cmd);
+	xs->resid = nblk * sectorsize;
+	xs->error = XS_NOERROR;
+	xs->bp = 0;
+	xs->data = va;
+	xs->datalen = nblk * sectorsize;
+	callout_init(&xs->xs_callout, 0);
+
+	/*
+	 * Pass all this info to the scsi driver.
+	 */
+	scsipi_adapter_request(chan, ADAPTER_REQ_RUN_XFER, xs);
+	if ((xs->xs_status & XS_STS_DONE) == 0 ||
+	    xs->error != XS_NOERROR)
+		return (EIO);
 #else	/* SD_DUMP_NOT_TRUSTED */
-		/* Let's just talk about this first... */
-		printf("sd%d: dump addr 0x%x, blk %d\n", unit, va, blkno);
-		delay(500 * 1000);	/* half a second */
+	/* Let's just talk about this first... */
+	printf("sd%d: dump addr 0x%x, blk %d\n", unit, va, blkno);
+	delay(500 * 1000);	/* half a second */
 #endif	/* SD_DUMP_NOT_TRUSTED */
 
-		/* update block count */
-		totwrt -= nwrt;
-		blkno += nwrt;
-		va = (char *)va + sectorsize * nwrt;
-	}
-	sddoingadump = 0;
 	return (0);
 }
 
@@ -2084,6 +1701,7 @@ printf("page 5 ok\n");
 static int
 sd_get_parms(struct sd_softc *sd, struct disk_parms *dp, int flags)
 {
+	struct dk_softc *dksc = &sd->sc_dksc;
 	int error;
 
 	/*
@@ -2115,7 +1733,7 @@ sd_get_parms(struct sd_softc *sd, struct
 	}
 
 page0:
-	printf("%s: fabricating a geometry\n", device_xname(sd->sc_dev));
+	printf("%s: fabricating a geometry\n", dksc->sc_xname);
 	/* Try calling driver's method for figuring out geometry. */
 	if (!sd->sc_periph->periph_channel->chan_adapter->adapt_getgeom ||
 	    !(*sd->sc_periph->periph_channel->chan_adapter->adapt_getgeom)
@@ -2272,7 +1890,8 @@ sd_setcache(struct sd_softc *sd, int bit
 static void
 sd_set_geometry(struct sd_softc *sd)
 {
-	struct disk_geom *dg = &sd->sc_dk.dk_geom;
+	struct dk_softc *dksc = &sd->sc_dksc;
+	struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
 
 	memset(dg, 0, sizeof(*dg));
 
@@ -2282,5 +1901,5 @@ sd_set_geometry(struct sd_softc *sd)
 	dg->dg_ntracks = sd->params.heads;
 	dg->dg_ncylinders = sd->params.cyls;
 
-	disk_set_info(sd->sc_dev, &sd->sc_dk, NULL);
+	disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL);
 }

Index: src/sys/dev/scsipi/sdvar.h
diff -u src/sys/dev/scsipi/sdvar.h:1.37 src/sys/dev/scsipi/sdvar.h:1.38
--- src/sys/dev/scsipi/sdvar.h:1.37	Mon Aug 24 23:13:15 2015
+++ src/sys/dev/scsipi/sdvar.h	Sat Dec 10 10:26:38 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdvar.h,v 1.37 2015/08/24 23:13:15 pooka Exp $	*/
+/*	$NetBSD: sdvar.h,v 1.38 2016/12/10 10:26:38 mlelstv Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
@@ -53,7 +53,7 @@
 #include "opt_scsi.h"
 #endif
 
-#include <sys/rndsource.h>
+#include <dev/dkvar.h>
 
 #ifndef	SDRETRIES
 #define	SDRETRIES	4
@@ -74,12 +74,9 @@ struct disk_parms {
 };
 
 struct sd_softc {
-	device_t sc_dev;
-	struct disk sc_dk;
+	struct dk_softc sc_dksc;
 
 	int flags;
-#define	SDF_WLABEL	0x04		/* label is writable */
-#define	SDF_LABELLING	0x08		/* writing label */
 #define	SDF_ANCIENT	0x10		/* disk is ancient; for minphys */
 #define	SDF_DIRTY	0x20		/* disk is dirty; needs cache flush */
 #define	SDF_FLUSHING	0x40		/* flushing, for sddone() */
@@ -88,12 +85,9 @@ struct sd_softc {
 
 	struct disk_parms params;
 
-	struct bufq_state *buf_queue;
 	callout_t sc_callout;
 	u_int8_t type;
 	char name[16]; /* product name, for default disklabel */
-
-	krndsource_t rnd_source;
 };
 
 #define	SDGP_RESULT_OK		0	/* parameters obtained */

Reply via email to