PSARC 2009/646 bd - generic block device driver
authorGarrett D'Amore <gdamore@opensolaris.org>
Mon, 17 May 2010 21:17:01 -0700
changeset 12426 cdff5d2ea989
parent 12425 9536977222c7
child 12427 08c46c2548be
PSARC 2009/646 bd - generic block device driver PSARC 2009/648 sdcard conversion to bd, EOF blk2scsa 6952618 deliver blkdev (PSARC 2009/646)
usr/src/Makefile.lint
usr/src/cmd/hal/hald/solaris/devinfo.c
usr/src/cmd/hal/hald/solaris/devinfo_storage.c
usr/src/cmd/hal/hald/solaris/devinfo_storage.h
usr/src/lib/cfgadm_plugins/Makefile
usr/src/lib/cfgadm_plugins/sdcard/Makefile
usr/src/lib/cfgadm_plugins/sdcard/Makefile.com
usr/src/lib/cfgadm_plugins/sdcard/amd64/Makefile
usr/src/lib/cfgadm_plugins/sdcard/common/cfga_sdcard.c
usr/src/lib/cfgadm_plugins/sdcard/common/cfga_sdcard.h
usr/src/lib/cfgadm_plugins/sdcard/common/mapfile-vers
usr/src/lib/cfgadm_plugins/sdcard/i386/Makefile
usr/src/lib/cfgadm_plugins/sdcard/sdcard.xcl
usr/src/lib/cfgadm_plugins/sdcard/sparc/Makefile
usr/src/lib/cfgadm_plugins/sdcard/sparcv9/Makefile
usr/src/lib/libsmedia/library/common/l_defines.h
usr/src/lib/libsmedia/library/inc/smedia.h
usr/src/lib/libsmedia/plugins/Makefile
usr/src/lib/libsmedia/plugins/blkdev/Makefile
usr/src/lib/libsmedia/plugins/blkdev/Makefile.targ
usr/src/lib/libsmedia/plugins/blkdev/amd64/Makefile
usr/src/lib/libsmedia/plugins/blkdev/common/b_generic.c
usr/src/lib/libsmedia/plugins/blkdev/common/mapfile-vers
usr/src/lib/libsmedia/plugins/blkdev/i386/Makefile
usr/src/lib/libsmedia/plugins/blkdev/sparc/Makefile
usr/src/lib/libsmedia/plugins/blkdev/sparcv9/Makefile
usr/src/pkg/manifests/driver-storage-blkdev.mf
usr/src/pkg/manifests/driver-storage-sdcard.mf
usr/src/pkg/manifests/service-storage-removable-media.mf
usr/src/pkg/manifests/system-header.mf
usr/src/pkg/manifests/system-kernel.mf
usr/src/pkg/manifests/system-library.mf
usr/src/tools/scripts/bfu.sh
usr/src/uts/common/Makefile.files
usr/src/uts/common/Makefile.rules
usr/src/uts/common/io/blkdev/blkdev.c
usr/src/uts/common/io/scsi/adapters/blk2scsa/blk2scsa.c
usr/src/uts/common/io/sdcard/adapters/sdhost/sdhost.c
usr/src/uts/common/io/sdcard/impl/mapfile
usr/src/uts/common/io/sdcard/impl/sda_cmd.c
usr/src/uts/common/io/sdcard/impl/sda_host.c
usr/src/uts/common/io/sdcard/impl/sda_mem.c
usr/src/uts/common/io/sdcard/impl/sda_mod.c
usr/src/uts/common/io/sdcard/impl/sda_nexus.c
usr/src/uts/common/io/sdcard/impl/sda_slot.c
usr/src/uts/common/io/sdcard/targets/sdcard/sdcard.c
usr/src/uts/common/io/warlock/blk2scsa.wlcmd
usr/src/uts/common/io/warlock/sdhost.wlcmd
usr/src/uts/common/sys/Makefile
usr/src/uts/common/sys/blkdev.h
usr/src/uts/common/sys/dkio.h
usr/src/uts/common/sys/scsi/adapters/blk2scsa.h
usr/src/uts/common/sys/sdcard/sda.h
usr/src/uts/common/sys/sdcard/sda_impl.h
usr/src/uts/intel/Makefile.intel.shared
usr/src/uts/intel/blk2scsa/Makefile
usr/src/uts/intel/blkdev/Makefile
usr/src/uts/intel/sda/Makefile
usr/src/uts/intel/sdcard/Makefile
usr/src/uts/intel/sdhost/Makefile
usr/src/uts/intel/warlock/Makefile
usr/src/uts/sparc/Makefile.sparc.shared
usr/src/uts/sparc/blk2scsa/Makefile
usr/src/uts/sparc/blkdev/Makefile
usr/src/uts/sparc/warlock/Makefile
--- a/usr/src/Makefile.lint	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/Makefile.lint	Mon May 17 21:17:01 2010 -0700
@@ -329,7 +329,6 @@
 	lib/auditd_plugins \
 	lib/brand/sn1 \
 	lib/brand/solaris10 \
-	lib/cfgadm_plugins/sdcard \
 	lib/crypt_modules \
 	lib/extendedFILE \
 	lib/libadutils \
--- a/usr/src/cmd/hal/hald/solaris/devinfo.c	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/cmd/hal/hald/solaris/devinfo.c	Mon May 17 21:17:01 2010 -0700
@@ -2,8 +2,7 @@
  *
  * devinfo.c : main file for libdevinfo-based device enumeration
  *
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  *
  * Licensed under the Academic Free License version 2.1
  *
@@ -133,6 +132,7 @@
 	&devinfo_ide_handler,
 	&devinfo_scsi_handler,
 	&devinfo_pcata_handler,
+	&devinfo_blkdev_handler,
 	&devinfo_floppy_handler,
 	&devinfo_usb_handler,
 	&devinfo_ieee1394_handler,
--- a/usr/src/cmd/hal/hald/solaris/devinfo_storage.c	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/cmd/hal/hald/solaris/devinfo_storage.c	Mon May 17 21:17:01 2010 -0700
@@ -2,8 +2,7 @@
  *
  * devinfo_storage.c : storage devices
  *
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  *
  * Licensed under the Academic Free License version 2.1
  *
@@ -63,6 +62,8 @@
 static HalDevice *devinfo_scsi_storage_add(HalDevice *parent, di_node_t node, char *devfs_path);
 HalDevice *devinfo_pcata_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
 static HalDevice *devinfo_pcata_storage_add(HalDevice *parent, di_node_t node, char *devfs_path);
+HalDevice *devinfo_blkdev_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
+static HalDevice *devinfo_blkdev_storage_add(HalDevice *parent, di_node_t node, char *devfs_path);
 HalDevice *devinfo_floppy_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
 static void devinfo_floppy_add_volume(HalDevice *parent, di_node_t node);
 static HalDevice *devinfo_lofi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
@@ -110,6 +111,14 @@
 	NULL,
         NULL
 };
+DevinfoDevHandler devinfo_blkdev_handler = {
+        devinfo_blkdev_add,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+        NULL
+};
 DevinfoDevHandler devinfo_floppy_handler = {
         devinfo_floppy_add,
 	NULL,
@@ -433,6 +442,74 @@
 	return (d);
 }
 
+/* blkdev */
+
+HalDevice *
+devinfo_blkdev_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
+{
+	int	*i;
+	char	*driver_name;
+	HalDevice *d;
+	char	udi[HAL_PATH_MAX];
+
+	driver_name = di_driver_name (node);
+	if ((driver_name == NULL) || (strcmp (driver_name, "blkdev") != 0)) {
+		return (NULL);
+	}
+
+	d = hal_device_new ();
+
+	devinfo_set_default_properties (d, parent, node, devfs_path);
+	hal_device_property_set_string (d, "info.subsystem", "pseudo");
+
+        hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+                "%s/%s%d", hal_device_get_udi (parent), di_node_name(node), di_instance (node));
+        hal_device_set_udi (d, udi);
+        hal_device_property_set_string (d, "info.udi", udi);
+        hal_device_property_set_string (d, "info.product", "Block Device");
+
+        devinfo_add_enqueue (d, devfs_path, &devinfo_blkdev_handler);
+
+        return (devinfo_blkdev_storage_add (d, node, devfs_path));
+}
+
+static HalDevice *
+devinfo_blkdev_storage_add(HalDevice *parent, di_node_t node, char *devfs_path)
+{
+	HalDevice *d;
+	char	*driver_name;
+	int	*i;
+	char	*s;
+	char	udi[HAL_PATH_MAX];
+
+	d = hal_device_new ();
+
+	devinfo_set_default_properties (d, parent, node, devfs_path);
+	hal_device_property_set_string (d, "info.category", "storage");
+
+	hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+		"%s/blkdev%d", hal_device_get_udi (parent), di_instance (node));
+	hal_device_set_udi (d, udi);
+	hal_device_property_set_string (d, "info.udi", udi);
+
+	hal_device_add_capability (d, "storage");
+
+	hal_device_property_set_int (d, "storage.lun", 0);
+
+	PROP_BOOL(d, node, i, "hotpluggable", "storage.hotpluggable");
+	PROP_BOOL(d, node, i, "removable-media", "storage.removable");
+
+	hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
+	hal_device_property_set_bool (d, "storage.media_check_enabled", TRUE);
+       	hal_device_property_set_string (d, "storage.drive_type", "disk");
+
+	hal_device_add_capability (d, "block");
+
+	devinfo_storage_minors (d, node, devfs_path, FALSE);
+
+	return (d);
+}
+
 /* floppy */
 
 HalDevice *
--- a/usr/src/cmd/hal/hald/solaris/devinfo_storage.h	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/cmd/hal/hald/solaris/devinfo_storage.h	Mon May 17 21:17:01 2010 -0700
@@ -2,15 +2,12 @@
  *
  * devinfo_storage.h : definitions for storage devices
  *
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  *
  * Licensed under the Academic Free License version 2.1
  *
  **************************************************************************/
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifndef DEVINFO_STORAGE_H
 #define DEVINFO_STORAGE_H
 
@@ -19,6 +16,7 @@
 extern DevinfoDevHandler devinfo_ide_handler;
 extern DevinfoDevHandler devinfo_scsi_handler;
 extern DevinfoDevHandler devinfo_pcata_handler;
+extern DevinfoDevHandler devinfo_blkdev_handler;
 extern DevinfoDevHandler devinfo_floppy_handler;
 extern DevinfoDevHandler devinfo_lofi_handler;
 
--- a/usr/src/lib/cfgadm_plugins/Makefile	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/lib/cfgadm_plugins/Makefile	Mon May 17 21:17:01 2010 -0700
@@ -19,15 +19,14 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 # lib/cfgadm_plugins/Makefile
 #
 
 include $(SRC)/Makefile.master
 
-COMMON_SUBDIRS= scsi sdcard pci usb ib fp shp sbd
+COMMON_SUBDIRS= scsi pci usb ib fp shp sbd
 sparc_SUBDIRS=	ac sysctrl
 
 i386_SUBDIRS= sata
--- a/usr/src/lib/cfgadm_plugins/sdcard/Makefile	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-include		../../Makefile.lib
-
-SUBDIRS =	$(MACH)
-$(BUILD64)SUBDIRS += $(MACH64)
-
-all :=		TARGET= all
-clean :=	TARGET= clean
-clobber :=	TARGET= clobber
-delete :=	TARGET= delete
-install :=	TARGET= install
-lint := 	TARGET= lint
-_msg :=		TARGET= _msg
-package := 	TARGET= package
-
-TEXT_DOMAIN= 	SUNW_OST_OSLIB
-XGETFLAGS=	-a -x sdcard.xcl
-POFILE=		sdcard.po
-POFILES=	generic.po
-
-SED=	sed
-GREP=	grep
-CP=	cp
-
-.KEEP_STATE:
-
-all clean clobber delete install lint package: $(SUBDIRS)
-
-$(SUBDIRS):	FRC
-	@cd $@; pwd; $(MAKE) $(TARGET)
-
-_msg:	$(MSGDOMAIN) $(POFILE)
-	$(RM) $(MSGDOMAIN)/$(POFILE)
-	$(CP) $(POFILE) $(MSGDOMAIN)
-
-$(POFILE):	$(POFILES)
-	$(RM) $@
-	$(CAT) $(POFILES) > $@
-
-$(POFILES):
-	$(RM) messages.po
-	$(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext */*.[ch]`
-	$(SED) -e '/^# msg/d' -e '/^domain/d' messages.po > $@
-	$(RM) messages.po
-
-FRC:
--- a/usr/src/lib/cfgadm_plugins/sdcard/Makefile.com	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-LIBRARY= sdcard.a
-VERS= .1
-
-OBJECTS= cfga_sdcard.o
-
-# include library definitions
-include ../../../Makefile.lib
-
-SRCDIR =	../common
-ROOTLIBDIR=	$(ROOT)/usr/lib/cfgadm
-ROOTLIBDIR64=	$(ROOTLIBDIR)/$(MACH64)
-
-LIBS=	$(DYNLIB)
-
-LINTFLAGS +=	-DDEBUG
-LINTFLAGS64 +=	-DDEBUG
-
-CFLAGS +=	$(CCVERBOSE)
-CFLAGS64 +=	$(CCVERBOSE)
-
-LDLIBS +=	-lc -ldevice -ldevinfo -lrcm
-
-.KEEP_STATE:
-
-all:	$(LIBS)
-
-lint:	lintcheck
-
-# Install rules
-
-$(ROOTLIBDIR)/%: % $(ROOTLIBDIR)
-	$(INS.file)
-
-$(ROOTLIBDIR64)/%: % $(ROOTLIBDIR64)
-	$(INS.file)
-
-$(ROOTLIBDIR) $(ROOTLIBDIR64):
-	$(INS.dir)
-
-# include library targets
-include ../../../Makefile.targ
-
-objs/%.o pics/%.o: ../common/%.c
-	$(COMPILE.c) -o $@ $<
-	$(POST_PROCESS_O)
--- a/usr/src/lib/cfgadm_plugins/sdcard/amd64/Makefile	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-include ../Makefile.com
-include ../../../Makefile.lib.64
-CFLAGS += -D_POSIX_PTHREAD_SEMANTICS
-LINTFLAGS += -D_POSIX_PTHREAD_SEMANTICS
-
-.KEEP_STATE:
-
-install: all $(ROOTLIBS64) $(ROOTLINKS64) 
--- a/usr/src/lib/cfgadm_plugins/sdcard/common/cfga_sdcard.c	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1933 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <string.h>
-#include <dirent.h>
-#include "cfga_sdcard.h"
-
-/*
- * This file contains the entry points to the plug-in as defined in the
- * config_admin(3X) man page.
- */
-
-/*
- * Set the version number for the cfgadm library's use.
- */
-int cfga_version = CFGA_HSL_V2;
-
-enum {
-	HELP_HEADER = 1,
-	HELP_CONFIG,
-	HELP_RESET_SLOT,
-	HELP_UNKNOWN
-};
-
-/* SDCARD specific help messages */
-static char *sdcard_help[] = {
-	NULL,
-	"SD card specific commands:\n",
-	" cfgadm -c [configure|unconfigure|disconnect|connect] ap_id "
-	"[ap_id...]\n",
-	" cfgadm -x sdcard_reset_slot ap_id [ap_id...]\n",
-	"\tunknown command or option:\n",
-	NULL
-};	/* End help messages */
-
-
-/*
- * Messages.
- */
-static msgcvt_t sdcard_msgs[] = {
-	/* CFGA_SDCARD_OK */
-	{ CVT, CFGA_OK, "" },
-
-	/* CFGA_SDCARD_NACK */
-	{ CVT, CFGA_NACK, "" },
-
-	/* CFGA_SDCARD_UNKNOWN / CFGA_LIB_ERROR -> "Library error" */
-	{ CVT, CFGA_LIB_ERROR, "Unknown message; internal error" },
-
-	/* CFGA_SDCARD_PRIV / CFGA_PRIV -> "Insufficient privileges" */
-	{ CVT, CFGA_PRIV, "" },
-
-	/*
-	 * CFGA_SDCARD_DYNAMIC_AP /
-	 * CFGA_LIB_ERROR -> "Configuration operation invalid"
-	 */
-	{ CVT, CFGA_INVAL, "Cannot identify attached device" },
-
-	/* CFGA_SDCARD_INTERNAL_ERROR / CFGA_LIB_ERROR -> "Library error" */
-	{ CVT, CFGA_LIB_ERROR, "Internal error" },
-
-	/* CFGA_SDCARD_ALLOC_FAIL / CFGA_LIB_ERROR -> "Library error" */
-	{ CVT, CFGA_LIB_ERROR, "Memory allocation failure" },
-
-	/* CFGA_SDCARD_IOCTL / CFGA_ERROR -> "Hardware specific failure"  */
-	{ CVT, CFGA_ERROR, "Driver ioctl failed " },
-
-	/* CFGA_SDCARD_DEVCTL / CFGA_LIB_ERROR -> "Library error" */
-	{ CVT, CFGA_LIB_ERROR, "Internal error: "
-	    "Cannot allocate devctl handle " },
-
-	/* CFGA_SDCARD_AP / CFGA_APID_NOEXIST -> "Attachment point not found" */
-	{ CVT, CFGA_APID_NOEXIST, "" },
-
-	/*
-	 * CFGA_SDCARD_BUSY /
-	 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
-	 */
-	{ CVT, CFGA_SYSTEM_BUSY, "" },
-
-	/* CFGA_SDCARD_DEVLINK / CFGA_LIB_ERROR -> "Library error" */
-	{ CVT, CFGA_LIB_ERROR, "Could not find /dev/cfg link for " },
-
-	/*
-	 * CFGA_SDCARD_INVALID_DEVNAME /
-	 * CFGA_INVAL -> "Configuration operation invalid"
-	 */
-	{ CVT, CFGA_INVAL, "Cannot specify device name" },
-
-	/* CFGA_SDCARD_DATA_ERROR / CFGA_DATA_ERROR -> "Data error" */
-	{ CVT, CFGA_DATA_ERROR, "cfgadm data error" },
-
-	/*
-	 * CFGA_SDCARD_DEV_CONFIGURE /
-	 * CFGA_ERROR -> "Hardware specific failure"
-	 */
-	{ CVT, CFGA_ERROR, "Failed to config device at " },
-
-	/*
-	 * CFGA_SDCARD_DEV_UNCONFIGURE /
-	 * CFGA_ERROR -> "Hardware specific failure"
-	 */
-	{ CVT, CFGA_ERROR, "Failed to unconfig device at " },
-
-	/*
-	 * CFGA_SDCARD_NOT_CONNECTED
-	 * CFGA_INVAL -> "Configuration operation invalid"
-	 */
-	{ CVT, CFGA_INVAL, "No device connected to " },
-
-	/*
-	 * CFGA_SDCARD_DISCONNECTED
-	 * CFGA_INVAL -> "Configuration operation invalid"
-	 */
-	{ CVT, CFGA_INVAL, "Slot already disconnected at " },
-
-	/*
-	 * CFGA_SDCARD_NOT_CONFIGURED /
-	 * CFGA_INVAL -> "Configuration operation invalid"
-	 */
-	{ CVT, CFGA_INVAL, "No device configured at " },
-
-	/*
-	 * CFGA_SDCARD_ALREADY_CONNECTED /
-	 * CFGA_INVAL -> "Configuration operation invalid"
-	 */
-	{ CVT, CFGA_INVAL, "Device already connected to " },
-
-	/*
-	 * CFGA_SDCARD_ALREADY_CONFIGURED /
-	 * CFGA_INVAL -> "Configuration operation invalid"
-	 */
-	{ CVT, CFGA_INVAL, "Device already configured at " },
-
-	/* CFGA_SDCARD_DEVICE_UNCONFIGURED */
-	{ CVT, CFGA_OK, "Device unconfigured prior to disconnect" },
-
-	/*
-	 * CFGA_SDCARD_OPNOTSUPP /
-	 * CFGA_OPNOTSUPP -> "Configuration operation not supported"
-	 */
-	{ CVT, CFGA_OPNOTSUPP, "Operation not supported" },
-
-	/*
-	 * CFGA_SDCARD_HWOPNOTSUPP /
-	 * CFGA_ERROR -> "Hardware specific failure"
-	 */
-	{ CVT, CFGA_ERROR, "Hardware specific operation not supported" },
-
-	/* CFGA_SDCARD_OPTIONS / CFGA_ERROR -> "Hardware specific failure" */
-	{ CVT, CFGA_ERROR, "Hardware specific option not supported" },
-
-	/* CFGA_SDCARD_STATE / CFGA_LIB_ERROR -> "Library error" */
-	{ CVT, CFGA_LIB_ERROR, "Internal error: Unrecognized ap state" },
-
-	/* CFGA_SDCARD_OPEN / CFGA_LIB_ERROR -> "Library error" */
-	{ CVT, CFGA_LIB_ERROR, "Cannot open " },
-
-	/*
-	 * CFGA_SDCARD_RCM_HANDLE /
-	 * CFGA_ERROR -> "Hardware specific failure"
-	 */
-	{ CVT, CFGA_ERROR, "cannot get RCM handle"},
-
-	/*
-	 * CFGA_SDCARD_RCM_OFFLINE /
-	 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
-	 */
-	{ CVT, CFGA_SYSTEM_BUSY, "failed to offline: "},
-
-	/*
-	 * CFGA_SDCARD_RCM_REMOVE /
-	 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
-	 */
-	{ CVT, CFGA_SYSTEM_BUSY, "failed to remove: "},
-
-	/*
-	 * CFGA_SDCARD_RCM_ONLINE /
-	 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
-	 */
-	{ CVT, CFGA_ERROR, "failed to online: "},
-
-	/* CFGA_SDCARD_CONFIRM_RESET */
-	{ CVT, CFGA_OK, "Reset the device at %s?\n"
-	    "This will operation will disrupt activity on the SD card.\n"
-	    "Continue"
-	},
-
-	/* CFGA_SDCARD_CONFIRM_UNCONFIGURE */
-	{ CVT, CFGA_OK, "Unconfigure the device at %s?\n"
-	    "This will operation will disrupt activity on the SD card.\n"
-	    "Continue"
-	},
-
-	/* CFGA_SDCARD_CONFIRM_DISCONNECT */
-	{ CVT, CFGA_OK, "Disconnect the device at %s?\n"
-	    "This will operation will disrupt activity on the SD card.\n"
-	    "Continue"
-	}
-};
-
-static cfga_err_t
-sdcard_err_msg(char **errstring, cfga_sdcard_ret_t ret, const char *, int);
-
-static cfga_sdcard_ret_t
-verify_params(const char *ap_id, const char *options, char **errstring);
-
-static cfga_sdcard_ret_t
-setup_for_devctl_cmd(const char *ap_id, devctl_hdl_t *devctl_hdl, uint_t oflag);
-
-static cfga_sdcard_ret_t
-slot_state(devctl_hdl_t hdl, ap_rstate_t *rstate, ap_ostate_t *ostate);
-
-static cfga_sdcard_ret_t
-do_control_ioctl(const char *ap_id, int subcommand, void *data, size_t size);
-
-static void
-cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl);
-
-static cfga_sdcard_ret_t
-sdcard_get_devicepath(const char *ap_id, char *devpath);
-
-static cfga_sdcard_ret_t
-sdcard_reset_slot(const char *ap_id);
-
-static int
-sdcard_confirm(struct cfga_confirm *confp, char *msg);
-
-static cfga_sdcard_ret_t
-sdcard_rcm_offline(char *, char **, cfga_flags_t);
-
-static void
-sdcard_rcm_online(char *, char **);
-
-static void
-sdcard_rcm_remove(char *, char **);
-
-static void
-sdcard_rcm_info_table(rcm_info_t *, char **);
-
-static cfga_sdcard_ret_t
-sdcard_rcm_init(void);
-
-
-
-/* Utilities */
-
-static cfga_sdcard_ret_t
-physpath_to_devlink(const char *basedir, const char *node_path,
-    char **logpp, int *l_errnop)
-{
-	char *linkpath;
-	char *buf;
-	char *real_path;
-	DIR *dp;
-	struct dirent *dep, *newdep;
-	int deplen;
-	boolean_t found = B_FALSE;
-	int err = 0;
-	struct stat sb;
-	char *p;
-	cfga_sdcard_ret_t rv = CFGA_SDCARD_INTERNAL_ERROR;
-
-	/*
-	 * Using libdevinfo for this is overkill and kills performance
-	 * when multiple consumers of libcfgadm are executing
-	 * concurrently.
-	 */
-	if ((dp = opendir(basedir)) == NULL) {
-		*l_errnop = errno;
-		return (CFGA_SDCARD_INTERNAL_ERROR);
-	}
-
-	linkpath = malloc(PATH_MAX);
-	buf = malloc(PATH_MAX);
-	real_path = malloc(PATH_MAX);
-
-	deplen = pathconf(basedir, _PC_NAME_MAX);
-	deplen = (deplen <= 0 ? MAXNAMELEN : deplen) +
-	    sizeof (struct dirent);
-	dep = (struct dirent *)malloc(deplen);
-
-	if (dep == NULL || linkpath == NULL || buf == NULL ||
-	    real_path == NULL) {
-		*l_errnop = ENOMEM;
-		rv = CFGA_SDCARD_ALLOC_FAIL;
-		goto pp_cleanup;
-	}
-
-	*logpp = NULL;
-
-	while (!found && (err = readdir_r(dp, dep, &newdep)) == 0 &&
-	    newdep != NULL) {
-
-		assert(newdep == dep);
-
-		if (strcmp(dep->d_name, ".") == 0 ||
-		    strcmp(dep->d_name, "..") == 0)
-			continue;
-
-		(void) snprintf(linkpath, MAXPATHLEN,
-		    "%s/%s", basedir, dep->d_name);
-
-		if (lstat(linkpath, &sb) < 0)
-			continue;
-
-		if (S_ISDIR(sb.st_mode)) {
-
-			if ((rv = physpath_to_devlink(linkpath, node_path,
-			    logpp, l_errnop)) != CFGA_SDCARD_OK) {
-
-				goto pp_cleanup;
-			}
-
-			if (*logpp != NULL)
-				found = B_TRUE;
-
-		} else if (S_ISLNK(sb.st_mode)) {
-
-			bzero(buf, PATH_MAX);
-			if (readlink(linkpath, buf, PATH_MAX) < 0)
-				continue;
-
-
-			/*
-			 * realpath() is too darn slow, so fake
-			 * it, by using what we know about /dev
-			 * links: they are always of the form:
-			 * <"../">+/devices/<path>
-			 */
-			p = buf;
-			while (strncmp(p, "../", 3) == 0)
-				p += 3;
-
-			if (p != buf)
-				p--;	/* back up to get a slash */
-
-			assert (*p == '/');
-
-			if (strcmp(p, node_path) == 0) {
-				*logpp = strdup(linkpath);
-				if (*logpp == NULL) {
-
-					rv = CFGA_SDCARD_ALLOC_FAIL;
-					goto pp_cleanup;
-				}
-
-				found = B_TRUE;
-			}
-		}
-	}
-
-	free(linkpath);
-	free(buf);
-	free(real_path);
-	free(dep);
-	(void) closedir(dp);
-
-	if (err != 0) {
-		*l_errnop = err;
-		return (CFGA_SDCARD_INTERNAL_ERROR);
-	}
-
-	return (CFGA_SDCARD_OK);
-
-pp_cleanup:
-
-	if (dp)
-		(void) closedir(dp);
-	if (dep)
-		free(dep);
-	if (linkpath)
-		free(linkpath);
-	if (buf)
-		free(buf);
-	if (real_path)
-		free(real_path);
-	if (*logpp) {
-		free(*logpp);
-		*logpp = NULL;
-	}
-	return (rv);
-}
-
-
-/*
- * Given the index into a table (msgcvt_t) of messages, get the message
- * string, converting it to the proper locale if necessary.
- * NOTE: Indexes are defined in cfga_sdcard.h
- */
-static const char *
-get_msg(uint_t msg_index, msgcvt_t *msg_tbl, uint_t tbl_size)
-{
-	if (msg_index >= tbl_size) {
-		msg_index = CFGA_SDCARD_UNKNOWN;
-	}
-
-	return ((msg_tbl[msg_index].intl) ?
-	    dgettext(TEXT_DOMAIN, msg_tbl[msg_index].msgstr) :
-	    msg_tbl[msg_index].msgstr);
-}
-
-/*
- * Allocates and creates a message string (in *ret_str),
- * by concatenating all the (char *) args together, in order.
- * Last arg MUST be NULL.
- */
-static void
-set_msg(char **ret_str, ...)
-{
-	char    *str;
-	size_t  total_len;
-	va_list valist;
-
-	va_start(valist, ret_str);
-
-	total_len = (*ret_str == NULL) ? 0 : strlen(*ret_str);
-
-	while ((str = va_arg(valist, char *)) != NULL) {
-		size_t  len = strlen(str);
-		char    *old_str = *ret_str;
-
-		*ret_str = (char *)realloc(*ret_str, total_len + len + 1);
-		if (*ret_str == NULL) {
-			/* We're screwed */
-			free(old_str);
-			va_end(valist);
-			return;
-		}
-
-		(void) strcpy(*ret_str + total_len, str);
-		total_len += len;
-	}
-
-	va_end(valist);
-}
-
-/*
- * Error message handling.
- * For the rv passed in, looks up the corresponding error message string(s),
- * internationalized if necessary, and concatenates it into a new
- * memory buffer, and points *errstring to it.
- * Note not all rvs will result in an error message return, as not all
- * error conditions warrant an SD-specific error message - for those
- * conditions the cfgadm generic messages are sufficient.
- *
- * Some messages may display ap_id or errno, which is why they are passed
- * in.
- */
-cfga_err_t
-sdcard_err_msg(
-	char **errstring,
-	cfga_sdcard_ret_t rv,
-	const char *ap_id,
-	int l_errno)
-{
-	if (errstring == NULL) {
-		return (sdcard_msgs[rv].cfga_err);
-	}
-
-	/*
-	 * Generate the appropriate SDCARD-specific error message(s) (if any).
-	 */
-	switch (rv) {
-	case CFGA_SDCARD_OK:
-	case CFGA_NACK:
-		/* Special case - do nothing.  */
-		break;
-
-	case CFGA_SDCARD_UNKNOWN:
-	case CFGA_SDCARD_PRIV:
-	case CFGA_SDCARD_DYNAMIC_AP:
-	case CFGA_SDCARD_INTERNAL_ERROR:
-	case CFGA_SDCARD_ALLOC_FAIL:
-	case CFGA_SDCARD_DATA_ERROR:
-	case CFGA_SDCARD_OPNOTSUPP:
-	case CFGA_SDCARD_OPTIONS:
-	case CFGA_SDCARD_STATE:
-
-		/* These messages require no additional strings passed. */
-		set_msg(errstring, ERR_STR(rv), NULL);
-		break;
-
-	case CFGA_SDCARD_HWOPNOTSUPP:
-		/* hardware-specific help needed */
-		set_msg(errstring, ERR_STR(rv), NULL);
-		set_msg(errstring, "\n",
-		    dgettext(TEXT_DOMAIN, sdcard_help[HELP_HEADER]), NULL);
-		set_msg(errstring, sdcard_help[HELP_RESET_SLOT], NULL);
-		break;
-
-	case CFGA_SDCARD_AP:
-	case CFGA_SDCARD_BUSY:
-	case CFGA_SDCARD_DEVLINK:
-	case CFGA_SDCARD_DEV_CONFIGURE:
-	case CFGA_SDCARD_DEV_UNCONFIGURE:
-	case CFGA_SDCARD_NOT_CONNECTED:
-	case CFGA_SDCARD_DISCONNECTED:
-	case CFGA_SDCARD_NOT_CONFIGURED:
-	case CFGA_SDCARD_ALREADY_CONNECTED:
-	case CFGA_SDCARD_ALREADY_CONFIGURED:
-
-	case CFGA_SDCARD_RCM_HANDLE:
-	case CFGA_SDCARD_RCM_ONLINE:
-	case CFGA_SDCARD_RCM_OFFLINE:
-	case CFGA_SDCARD_RCM_REMOVE:
-		/* These messages also print ap_id.  */
-		set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "", NULL);
-		break;
-
-
-	case CFGA_SDCARD_IOCTL:
-		/* These messages also print errno.  */
-		{
-			char *errno_str = l_errno ? strerror(l_errno) : "";
-
-			set_msg(errstring, ERR_STR(rv), errno_str,
-			    l_errno ? "\n" : "", NULL);
-			break;
-		}
-
-	case CFGA_SDCARD_OPEN:
-		/* These messages also apid and errno.  */
-		{
-			char *errno_str = l_errno ? strerror(l_errno) : "";
-
-			set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "\n",
-			    errno_str, l_errno ? "\n" : "", NULL);
-			break;
-		}
-
-	default:
-		set_msg(errstring, ERR_STR(CFGA_SDCARD_INTERNAL_ERROR), NULL);
-
-	} /* end switch */
-
-
-	/*
-	 * Determine the proper error code to send back to the cfgadm library.
-	 */
-	return (sdcard_msgs[rv].cfga_err);
-}
-
-
-/*
- * Entry points
- */
-/* cfgadm entry point */
-/*ARGSUSED*/
-cfga_err_t
-cfga_change_state(
-	cfga_cmd_t state_change_cmd,
-	const char *ap_id,
-	const char *options,
-	struct cfga_confirm *confp,
-	struct cfga_msg *msgp,
-	char **errstring,
-	cfga_flags_t flags)
-{
-	int		ret;
-	ap_rstate_t	rstate;
-	ap_ostate_t	ostate;
-	devctl_hdl_t	hdl = NULL;
-	cfga_sdcard_ret_t	rv = CFGA_SDCARD_OK;
-	char		*pdyn;
-	int		i;
-	char		devpath[MAXPATHLEN];
-	char		msg[256];
-
-	/*
-	 * All sub-commands which can change state of device require
-	 * root privileges.
-	 */
-	if (geteuid() != 0) {
-		rv = CFGA_SDCARD_PRIV;
-		goto bailout;
-	}
-
-	if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SDCARD_OK) {
-		(void) cfga_help(msgp, options, flags);
-		goto bailout;
-	}
-
-	if ((rv = setup_for_devctl_cmd(ap_id, &hdl, DC_RDONLY)) !=
-	    CFGA_SDCARD_OK) {
-		goto bailout;
-	}
-
-	switch (state_change_cmd) {
-	case CFGA_CMD_CONFIGURE:
-		if ((rv = slot_state(hdl, &rstate, &ostate)) != CFGA_SDCARD_OK)
-			goto bailout;
-
-		if (ostate == AP_OSTATE_CONFIGURED) {
-			rv = CFGA_SDCARD_ALREADY_CONFIGURED;
-			goto bailout;
-		}
-		/* Disallow dynamic AP name component */
-		if (GET_DYN(ap_id) != NULL) {
-			rv = CFGA_SDCARD_INVALID_DEVNAME;
-			goto bailout;
-		}
-
-		if (rstate == AP_RSTATE_EMPTY) {
-			rv = CFGA_SDCARD_NOT_CONNECTED;
-			goto bailout;
-		}
-		rv = CFGA_SDCARD_OK;
-
-		if (devctl_ap_configure(hdl, NULL) != 0) {
-			rv = CFGA_SDCARD_DEV_CONFIGURE;
-			goto bailout;
-		}
-
-		for (i = 0; i < 15; i++) {
-			/*
-			 * We wait up to ~30 seconds for this to complete.
-			 * Hotplug is done asynchronously.
-			 */
-			rv = sdcard_get_devicepath(ap_id, devpath);
-			if (rv == CFGA_SDCARD_OK)
-				break;
-			(void) sleep(2);
-		}
-		if (rv != CFGA_SDCARD_OK) {
-			rv = CFGA_SDCARD_DEV_CONFIGURE;
-			goto bailout;
-		}
-
-		break;
-
-	case CFGA_CMD_UNCONFIGURE:
-		if ((rv = slot_state(hdl, &rstate, &ostate)) != CFGA_SDCARD_OK)
-			goto bailout;
-
-		if (rstate != AP_RSTATE_CONNECTED) {
-			rv = CFGA_SDCARD_NOT_CONNECTED;
-			goto bailout;
-		}
-
-		if (ostate != AP_OSTATE_CONFIGURED) {
-			rv = CFGA_SDCARD_NOT_CONFIGURED;
-			goto bailout;
-		}
-		/* Strip off AP name dynamic component, if present */
-		if ((pdyn = GET_DYN(ap_id)) != NULL) {
-			*pdyn = '\0';
-		}
-
-		rv = CFGA_SDCARD_OK;
-
-		/*LINTED E_SEC_PRINTF_VAR_FMT*/
-		(void) snprintf(msg, sizeof (msg),
-		    ERR_STR(CFGA_SDCARD_CONFIRM_UNCONFIGURE), ap_id);
-
-		if (!sdcard_confirm(confp, msg)) {
-			rv = CFGA_SDCARD_NACK;
-			break;
-		}
-
-		if (sdcard_get_devicepath(ap_id, devpath) != CFGA_SDCARD_OK) {
-			(void) printf("cfga_change_state: "
-			    "get device path failed\n");
-			rv = CFGA_SDCARD_DEV_UNCONFIGURE;
-			break;
-		}
-
-		rv = sdcard_rcm_offline(devpath, errstring, flags);
-		if (rv != CFGA_SDCARD_OK) {
-			break;
-		}
-
-		ret = devctl_ap_unconfigure(hdl, NULL);
-
-		if (ret != 0) {
-			rv = CFGA_SDCARD_DEV_UNCONFIGURE;
-			if (errno == EBUSY) {
-				rv = CFGA_SDCARD_BUSY;
-			}
-			sdcard_rcm_online(devpath, errstring);
-		} else {
-			sdcard_rcm_remove(devpath, errstring);
-		}
-
-		break;
-
-	case CFGA_CMD_DISCONNECT:
-		if ((rv = slot_state(hdl, &rstate, &ostate)) != CFGA_SDCARD_OK)
-			goto bailout;
-
-		if (rstate == AP_RSTATE_DISCONNECTED) {
-			rv = CFGA_SDCARD_DISCONNECTED;
-			goto bailout;
-		}
-
-		/* Strip off AP name dynamic component, if present */
-		if ((pdyn = GET_DYN(ap_id)) != NULL) {
-			*pdyn = '\0';
-		}
-
-
-		rv = CFGA_SDCARD_OK; /* other statuses don't matter */
-
-
-		/*
-		 * If the port originally with device attached and was
-		 * unconfigured already, the devicepath for the sd will be
-		 * removed. sdcard_get_devicepath in this case is not necessary.
-		 */
-
-		/* only call rcm_offline if the state was CONFIGURED */
-		if (ostate == AP_OSTATE_CONFIGURED) {
-			if (sdcard_get_devicepath(ap_id, devpath) !=
-			    CFGA_SDCARD_OK) {
-				(void) printf(
-				    "cfga_change_state: get path failed\n");
-				rv = CFGA_SDCARD_DEV_UNCONFIGURE;
-				break;
-			}
-
-			/*LINTED E_SEC_PRINTF_VAR_FMT*/
-			(void) snprintf(msg, sizeof (msg),
-			    ERR_STR(CFGA_SDCARD_CONFIRM_DISCONNECT), ap_id);
-			if (!sdcard_confirm(confp, msg)) {
-				rv = CFGA_SDCARD_NACK;
-				break;
-			}
-
-			rv = sdcard_rcm_offline(devpath, errstring, flags);
-			if (rv != CFGA_SDCARD_OK) {
-				break;
-			}
-
-			ret = devctl_ap_unconfigure(hdl, NULL);
-			if (ret != 0) {
-				(void) printf(
-				    "devctl_ap_unconfigure failed\n");
-				rv = CFGA_SDCARD_DEV_UNCONFIGURE;
-				if (errno == EBUSY)
-					rv = CFGA_SDCARD_BUSY;
-				sdcard_rcm_online(devpath, errstring);
-
-				/*
-				 * The current policy is that if unconfigure
-				 * failed, do not continue with disconnect.
-				 */
-				break;
-			} else {
-				(void) printf("%s\n",
-				    ERR_STR(CFGA_SDCARD_DEVICE_UNCONFIGURED));
-				sdcard_rcm_remove(devpath, errstring);
-			}
-		} else if (rstate == AP_RSTATE_CONNECTED ||
-		    rstate == AP_RSTATE_EMPTY) {
-			/*LINTED E_SEC_PRINTF_VAR_FMT*/
-			(void) snprintf(msg, sizeof (msg),
-			    ERR_STR(CFGA_SDCARD_CONFIRM_DISCONNECT), ap_id);
-
-			if (!sdcard_confirm(confp, msg)) {
-				rv = CFGA_SDCARD_NACK;
-				break;
-			}
-		}
-		ret = devctl_ap_disconnect(hdl, NULL);
-		if (ret != 0) {
-			rv = CFGA_SDCARD_IOCTL;
-			if (errno == EBUSY) {
-				rv = CFGA_SDCARD_BUSY;
-			}
-		}
-		break;
-
-	case CFGA_CMD_CONNECT:
-		if ((rv = slot_state(hdl, &rstate, &ostate)) != CFGA_SDCARD_OK)
-			goto bailout;
-
-		if (rstate == AP_RSTATE_CONNECTED) {
-			rv = CFGA_SDCARD_ALREADY_CONNECTED;
-			goto bailout;
-		}
-
-		/* Disallow dynamic AP name component */
-		if (GET_DYN(ap_id) != NULL) {
-			rv = CFGA_SDCARD_INVALID_DEVNAME;
-			goto bailout;
-		}
-
-		ret = devctl_ap_connect(hdl, NULL);
-		if (ret != 0) {
-			rv = CFGA_SDCARD_IOCTL;
-		} else {
-			rv = CFGA_SDCARD_OK;
-		}
-
-		break;
-
-	case CFGA_CMD_LOAD:
-	case CFGA_CMD_UNLOAD:
-		(void) cfga_help(msgp, options, flags);
-		rv = CFGA_SDCARD_OPNOTSUPP;
-		break;
-
-	case CFGA_CMD_NONE:
-	default:
-		(void) cfga_help(msgp, options, flags);
-		rv = CFGA_SDCARD_INTERNAL_ERROR;
-	}
-
-bailout:
-	cleanup_after_devctl_cmd(hdl);
-
-	return (sdcard_err_msg(errstring, rv, ap_id, errno));
-}
-
-/* cfgadm entry point */
-/*ARGSUSED*/
-cfga_err_t
-cfga_private_func(
-	const char *func,
-	const char *ap_id,
-	const char *options,
-	struct cfga_confirm *confp,
-	struct cfga_msg *msgp,
-	char **errstring,
-	cfga_flags_t flags)
-{
-	devctl_hdl_t		hdl = NULL;
-	cfga_sdcard_ret_t	rv;
-	char			*str_p;
-	char			msg[256];
-
-	if ((rv = verify_params(ap_id, NULL, errstring)) != CFGA_SDCARD_OK) {
-		(void) cfga_help(msgp, options, flags);
-		return (sdcard_err_msg(errstring, rv, ap_id, errno));
-	}
-
-	/*
-	 * All subcommands which can change state of device require
-	 * root privileges.
-	 */
-	if (geteuid() != 0) {
-		rv = CFGA_SDCARD_PRIV;
-		goto bailout;
-	}
-
-	if (func == NULL) {
-		rv = CFGA_SDCARD_OPTIONS;
-		goto bailout;
-	}
-
-	if ((rv = setup_for_devctl_cmd(ap_id, &hdl, 0)) != CFGA_SDCARD_OK) {
-		goto bailout;
-	}
-
-	/* We do not care here about dynamic AP name component */
-	if ((str_p = GET_DYN(ap_id)) != NULL) {
-		*str_p = '\0';
-	}
-
-	if (strcmp(func, RESET_SLOT) == 0) {
-		/*LINTED E_SEC_PRINTF_VAR_FMT*/
-		(void) snprintf(msg, sizeof (msg),
-		    ERR_STR(CFGA_SDCARD_CONFIRM_RESET), ap_id);
-
-		if (!sdcard_confirm(confp, msg)) {
-			rv = CFGA_SDCARD_NACK;
-			goto bailout;
-		}
-		if ((rv = sdcard_reset_slot(ap_id)) != CFGA_SDCARD_OK) {
-			goto bailout;
-		}
-
-		rv = CFGA_SDCARD_OK;
-	} else {
-
-		/* Unrecognized operation request */
-		rv = CFGA_SDCARD_HWOPNOTSUPP;
-	}
-
-bailout:
-	cleanup_after_devctl_cmd(hdl);
-
-	return (sdcard_err_msg(errstring, rv, ap_id, errno));
-
-}
-
-/* cfgadm entry point */
-/*ARGSUSED*/
-cfga_err_t
-cfga_test(
-	const char *ap_id,
-	const char *options,
-	struct cfga_msg *msgp,
-	char **errstring,
-	cfga_flags_t flags)
-{
-	/* Should call ioctl for self test - phase 2 */
-	return (CFGA_OPNOTSUPP);
-}
-
-
-struct chk_dev {
-	int c_isblk;
-	char *c_minor;
-};
-
-/*ARGSUSED*/
-static int
-chk_dev_fcn(di_node_t node, di_minor_t minor, void *arg)
-{
-	char	*mn;
-	struct chk_dev *chkp = (struct chk_dev *)arg;
-
-	mn = di_minor_name(minor);
-	if (mn == NULL)
-		return (DI_WALK_CONTINUE);
-
-	if (strcmp(mn, chkp->c_minor) != 0)
-		return (DI_WALK_CONTINUE);
-
-	chkp->c_isblk = di_minor_spectype(minor) == S_IFBLK ? 1 : 0;
-
-	return (DI_WALK_TERMINATE);
-}
-
-/*
- * Don't use devfs if stat() in /devices fails. Use libdevinfo instead.
- * Retired devices don't show up in devfs.
- *
- *	Returns:
- *		1 - minor exists and is of type BLK
- *		0 - minor does not exist or is not of type BLK.
- */
-static int
-is_devinfo_blk(char *minor_path)
-{
-	char	*minor_portion;
-	struct chk_dev chk_dev;
-	di_node_t node;
-	int	rv;
-
-	/*
-	 * prune minor path for di_init() - no /devices prefix and no minor name
-	 */
-	if (strncmp(minor_path, "/devices/", strlen("/devices/")) != 0)
-		return (0);
-
-	minor_portion = strrchr(minor_path, MINOR_SEP);
-	if (minor_portion == NULL)
-		return (0);
-
-	*minor_portion = 0;
-
-	node = di_init(minor_path + strlen("/devices"), DINFOMINOR);
-
-	*minor_portion = MINOR_SEP;
-
-	if (node == DI_NODE_NIL)
-		return (0);
-
-	chk_dev.c_isblk = 0;
-	chk_dev.c_minor = minor_portion + 1;
-
-	rv = di_walk_minor(node, NULL, 0, &chk_dev, chk_dev_fcn);
-
-	di_fini(node);
-
-	if (rv == 0 && chk_dev.c_isblk)
-		return (1);
-	else
-		return (0);
-}
-
-/*
- * The dynamic component buffer returned by this function has to be freed!
- */
-cfga_sdcard_ret_t
-sdcard_make_dyncomp(const char *ap_id, char **dyncomp)
-{
-	char	*cp = NULL;
-	int	l_errno;
-	char	devpath[MAXPATHLEN];
-	char	minor_path[MAXPATHLEN];
-	char	name_part[MAXNAMELEN];
-	char	*devlink = NULL;
-	char	*minor_portion = NULL;
-	int	deplen;
-	int	err;
-	DIR	*dp = NULL;
-	struct stat sb;
-	struct dirent *dep = NULL;
-	struct dirent *newdep = NULL;
-	char	*p;
-
-	assert(dyncomp != NULL);
-
-	/*
-	 * Get target node path
-	 */
-	if (sdcard_get_devicepath(ap_id, devpath) != CFGA_SDCARD_OK) {
-
-		(void) printf("cfga_list_ext: cannot locate target device\n");
-		return (CFGA_SDCARD_DYNAMIC_AP);
-
-	} else {
-
-		cp = strrchr(devpath, PATH_SEP);
-		assert(cp != NULL);
-
-		/*
-		 * If the child node is the sdcard node, then what we really
-		 * want is the grandchild.  But we know that the grandchild
-		 * will always be disk@0,0.
-		 */
-		if (strstr(cp, "/sdcard@") == cp) {
-			/* sdcard nodes have disk children, if any */
-			(void) strlcat(devpath, "/disk@0,0", sizeof (devpath));
-			cp = strrchr(cp, PATH_SEP);
-		}
-		*cp = 0;	/* terminate path for opendir() */
-
-		(void) strncpy(name_part, cp + 1, MAXNAMELEN);
-
-		/*
-		 * Using libdevinfo for this is overkill and kills
-		 * performance when many consumers are using libcfgadm
-		 * concurrently.
-		 */
-		if ((dp = opendir(devpath)) == NULL) {
-			goto bailout;
-		}
-
-		/*
-		 * deplen is large enough to fit the largest path-
-		 * struct dirent includes one byte (the terminator)
-		 * so we don't add 1 to the calculation here.
-		 */
-		deplen = pathconf(devpath, _PC_NAME_MAX);
-		deplen = ((deplen <= 0) ? MAXNAMELEN : deplen) +
-		    sizeof (struct dirent);
-		dep = (struct dirent *)malloc(deplen);
-		if (dep == NULL)
-			goto bailout;
-
-		while ((err = readdir_r(dp, dep, &newdep)) == 0 &&
-		    newdep != NULL) {
-
-			assert(newdep == dep);
-
-			if (strcmp(dep->d_name, ".") == 0 ||
-			    strcmp(dep->d_name, "..") == 0 ||
-			    (minor_portion = strchr(dep->d_name,
-			    MINOR_SEP)) == NULL)
-				continue;
-
-			*minor_portion = 0;
-			if (strcmp(dep->d_name, name_part) != 0)
-				continue;
-			*minor_portion = MINOR_SEP;
-
-			(void) snprintf(minor_path, MAXPATHLEN,
-			    "%s/%s", devpath, dep->d_name);
-
-			/*
-			 * If stat() fails, the device *may* be retired.
-			 * Check via libdevinfo if the device has a BLK minor.
-			 * We don't use libdevinfo all the time, since taking
-			 * a snapshot is slower than a stat().
-			 */
-			if (stat(minor_path, &sb) < 0) {
-				if (is_devinfo_blk(minor_path)) {
-					break;
-				} else {
-					continue;
-				}
-			}
-
-			if (S_ISBLK(sb.st_mode))
-				break;
-		}
-
-		(void) closedir(dp);
-		free(dep);
-
-		dp = NULL;
-		dep = NULL;
-
-		/*
-		 * If there was an error, or we didn't exit the loop
-		 * by finding a block or character device, bail out.
-		 */
-		if (err != 0 || newdep == NULL)
-			goto bailout;
-
-		/*
-		 * Look for links to the physical path in /dev/dsk,
-		 * since we ONLY looked for BLOCK devices above.
-		 */
-
-		(void) physpath_to_devlink("/dev/dsk",
-		    minor_path, &devlink, &l_errno);
-
-		/* postprocess and copy logical name here */
-		if (devlink != NULL) {
-			/*
-			 * For disks, remove partition/slice info
-			 */
-			if ((cp = strstr(devlink, "dsk/")) != NULL) {
-				/* cXtYdZ[(s[0..15])|(p[0..X])] */
-				if ((p = strchr(cp + 4, 'd')) != NULL) {
-					p++;	/* Skip the 'd' */
-					while (*p != 0 && isdigit(*p))
-						p++;
-					*p = 0;
-				}
-				*dyncomp = strdup(cp);
-			}
-
-			free(devlink);
-		}
-
-		return (CFGA_SDCARD_OK);
-	}
-
-bailout:
-	if (dp)
-		(void) closedir(dp);
-	if (dep)
-		free(dep);
-	return (CFGA_SDCARD_DYNAMIC_AP);
-}
-
-void
-sdcard_clean_string(char *s, int sz)
-{
-	int	len;
-	char	*p;
-
-	/* ensure null termination */
-	s[sz - 1] = '\0';
-	p = s;
-
-	/* strip leading white space */
-	while (*p == ' ') p++;
-	(void) memmove(s, p, strlen(p));
-
-	len = strlen(s) - 1;
-	/* trim trailing space */
-	while ((len >= 0) && (s[len] == ' ')) {
-		s[len] = '\0';
-		len--;
-	}
-
-	for (/* nop */; len >= 0; len--) {
-		char	c = s[len];
-		if (((c >= 'a') && (c <= 'z')) ||
-		    ((c >= 'A') && (c <= 'Z')) ||
-		    ((c >= '0') && (c <= '9')) ||
-		    (c == '_') || (c == '+') || (c == '-'))
-			continue;
-		s[len] = '_';
-	}
-}
-
-/* cfgadm entry point */
-/*ARGSUSED*/
-cfga_err_t
-cfga_list_ext(
-	const char *ap_id,
-	cfga_list_data_t **ap_id_list,
-	int *nlistp,
-	const char *options,
-	const char *listopts,
-	char **errstring,
-	cfga_flags_t flags)
-{
-	int			l_errno;
-	char			*ap_id_log = NULL;
-	devctl_hdl_t		devctl_hdl = NULL;
-	cfga_sdcard_ret_t	rv = CFGA_SDCARD_OK;
-	devctl_ap_state_t	devctl_ap_state;
-	char			*pdyn;
-
-
-	if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SDCARD_OK) {
-		(void) cfga_help(NULL, options, flags);
-		goto bailout;
-	}
-	/* We do not care here about dynamic AP name component */
-	if ((pdyn = GET_DYN(ap_id)) != NULL) {
-		*pdyn = '\0';
-	}
-
-	if (ap_id_list == NULL || nlistp == NULL) {
-		rv = CFGA_SDCARD_DATA_ERROR;
-		(void) cfga_help(NULL, options, flags);
-		goto bailout;
-	}
-
-	/* Get ap status */
-	if ((rv = setup_for_devctl_cmd(ap_id, &devctl_hdl, DC_RDONLY)) !=
-	    CFGA_SDCARD_OK) {
-		goto bailout;
-	}
-
-	/* will call dc_cmd to send IOCTL to kernel */
-	if (devctl_ap_getstate(devctl_hdl, NULL, &devctl_ap_state) == -1) {
-		cleanup_after_devctl_cmd(devctl_hdl);
-		rv = CFGA_SDCARD_IOCTL;
-		goto bailout;
-	}
-
-	cleanup_after_devctl_cmd(devctl_hdl);
-
-	/*
-	 * Create cfga_list_data_t struct.
-	 */
-	if ((*ap_id_list =
-	    (cfga_list_data_t *)malloc(sizeof (**ap_id_list))) == NULL) {
-		rv = CFGA_SDCARD_ALLOC_FAIL;
-		goto bailout;
-	}
-	*nlistp = 1;
-
-	/*
-	 * Rest of the code fills in the cfga_list_data_t struct.
-	 */
-
-	/* Get /dev/cfg path to corresponding to the physical ap_id */
-	/* Remember ap_id_log must be freed */
-	rv = physpath_to_devlink(CFGA_DEV_DIR, (char *)ap_id,
-	    &ap_id_log, &l_errno);
-
-	if (rv != 0) {
-		rv = CFGA_SDCARD_DEVLINK;
-		goto bailout;
-	}
-
-	/* Get logical ap_id corresponding to the physical */
-	if (ap_id_log == NULL || strstr(ap_id_log, CFGA_DEV_DIR) == NULL) {
-		rv = CFGA_SDCARD_DEVLINK;
-		goto bailout;
-	}
-
-	(void) strlcpy((*ap_id_list)->ap_log_id,
-	    /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR)+ 1,
-	    sizeof ((*ap_id_list)->ap_log_id));
-
-	free(ap_id_log);
-	ap_id_log = NULL;
-
-	(void) strlcpy((*ap_id_list)->ap_phys_id, ap_id,
-	    sizeof ((*ap_id_list)->ap_phys_id));
-
-	switch (devctl_ap_state.ap_rstate) {
-		case AP_RSTATE_EMPTY:
-			(*ap_id_list)->ap_r_state = CFGA_STAT_EMPTY;
-			break;
-
-		case AP_RSTATE_DISCONNECTED:
-			(*ap_id_list)->ap_r_state = CFGA_STAT_DISCONNECTED;
-			break;
-
-		case AP_RSTATE_CONNECTED:
-			(*ap_id_list)->ap_r_state = CFGA_STAT_CONNECTED;
-			break;
-
-		default:
-			rv = CFGA_SDCARD_STATE;
-			goto bailout;
-	}
-
-	switch (devctl_ap_state.ap_ostate) {
-		case AP_OSTATE_CONFIGURED:
-			(*ap_id_list)->ap_o_state = CFGA_STAT_CONFIGURED;
-			break;
-
-		case AP_OSTATE_UNCONFIGURED:
-			(*ap_id_list)->ap_o_state = CFGA_STAT_UNCONFIGURED;
-			break;
-
-		default:
-			rv = CFGA_SDCARD_STATE;
-			goto bailout;
-	}
-
-	switch (devctl_ap_state.ap_condition) {
-		case AP_COND_OK:
-			(*ap_id_list)->ap_cond = CFGA_COND_OK;
-			break;
-
-		case AP_COND_FAILING:
-			(*ap_id_list)->ap_cond = CFGA_COND_FAILING;
-			break;
-
-		case AP_COND_FAILED:
-			(*ap_id_list)->ap_cond = CFGA_COND_FAILED;
-			break;
-
-		case AP_COND_UNUSABLE:
-			(*ap_id_list)->ap_cond = CFGA_COND_UNUSABLE;
-			break;
-
-		case AP_COND_UNKNOWN:
-			(*ap_id_list)->ap_cond = CFGA_COND_UNKNOWN;
-			break;
-
-		default:
-			rv = CFGA_SDCARD_STATE;
-			goto bailout;
-	}
-
-	(*ap_id_list)->ap_class[0] = '\0';	/* Filled by libcfgadm */
-	(*ap_id_list)->ap_busy = devctl_ap_state.ap_in_transition;
-	(*ap_id_list)->ap_status_time = devctl_ap_state.ap_last_change;
-	(*ap_id_list)->ap_info[0] = NULL;
-
-	if ((*ap_id_list)->ap_r_state == CFGA_STAT_CONNECTED) {
-		sda_card_info_t		ci;
-		char			*ct;
-
-		/*
-		 * Fill in the 'Information' field for the -v option
-		 */
-		rv = do_control_ioctl(ap_id, SDA_CFGA_GET_CARD_INFO,
-		    &ci, sizeof (ci));
-		if (rv != CFGA_SDCARD_OK) {
-			goto bailout;
-		}
-
-		switch (ci.ci_type) {
-		case SDA_CT_MMC:
-		case SDA_CT_SDMEM:
-		case SDA_CT_SDHC:
-		case SDA_CT_SDCOMBO:
-			/* these are all memory cards */
-			sdcard_clean_string(ci.ci_pid, sizeof (ci.ci_pid));
-
-			/*
-			 * We don't display the mfg id, because we
-			 * have no reliable way to look it up.
-			 */
-			(void) snprintf((*ap_id_list)->ap_info,
-			    sizeof ((*ap_id_list)->ap_info),
-			    "Mod: %s Rev: %d.%d Date: %d/%d SN: %X",
-			    ci.ci_pid[0] ? ci.ci_pid : "?",
-			    ci.ci_major, ci.ci_minor,
-			    ci.ci_month, (int)ci.ci_year + 1900,
-			    ci.ci_serial);
-			break;
-		default:
-			/*
-			 * we don't know what this is really... need to
-			 * parse CIS later.
-			 */
-			(void) strlcpy((*ap_id_list)->ap_info, "",
-			    sizeof ((*ap_id_list)->ap_info));
-			break;
-		}
-
-		switch (ci.ci_type) {
-		case SDA_CT_UNKNOWN:
-			ct = "unknown";
-			break;
-		case SDA_CT_MMC:
-			ct = "mmc";
-			break;
-		case SDA_CT_SDMEM:
-			ct = "sdcard";
-			break;
-		case SDA_CT_SDHC:
-			ct = "sdhc";
-			break;
-		case SDA_CT_SDCOMBO:
-			ct = "sd-combo";
-			break;
-		case SDA_CT_SDIO:
-			ct = "sdio";
-			break;
-		}
-
-		(void) strlcpy((*ap_id_list)->ap_type, ct,
-		    sizeof ((*ap_id_list)->ap_type));
-
-		if ((*ap_id_list)->ap_o_state == CFGA_STAT_CONFIGURED) {
-
-			char *dyncomp = NULL;
-
-			/*
-			 * This is the case where we need to generate
-			 * a dynamic component of the ap_id, i.e. device.
-			 */
-			(void) sdcard_make_dyncomp(ap_id, &dyncomp);
-			if (dyncomp != NULL) {
-				(void) strcat((*ap_id_list)->ap_log_id,
-				    DYN_SEP);
-				(void) strlcat((*ap_id_list)->ap_log_id,
-				    dyncomp,
-				    sizeof ((*ap_id_list)->ap_log_id));
-				free(dyncomp);
-			}
-		}
-
-	} else {
-		(void) strlcpy((*ap_id_list)->ap_type, "sdcard-slot",
-		    sizeof ((*ap_id_list)->ap_type));
-	}
-
-	return (sdcard_err_msg(errstring, rv, ap_id, errno));
-
-bailout:
-	if (*ap_id_list != NULL) {
-		free(*ap_id_list);
-	}
-	if (ap_id_log != NULL) {
-		free(ap_id_log);
-	}
-
-	return (sdcard_err_msg(errstring, rv, ap_id, errno));
-}
-
-/*
- * This routine accepts a string and prints it using
- * the message print routine argument.
- */
-static void
-cfga_msg(struct cfga_msg *msgp, const char *str)
-{
-	int len;
-	char *q;
-
-	if (msgp == NULL || msgp->message_routine == NULL) {
-		(void) printf("cfga_msg: NULL msgp\n");
-		return;
-	}
-
-	if ((len = strlen(str)) == 0) {
-		(void) printf("cfga_msg: null str\n");
-		return;
-	}
-
-	if ((q = (char *)calloc(len + 1, 1)) == NULL) {
-		perror("cfga_msg");
-		return;
-	}
-
-	(void) strcpy(q, str);
-	(*msgp->message_routine)(msgp->appdata_ptr, q);
-
-	free(q);
-}
-
-/* cfgadm entry point */
-/*ARGSUSED*/
-cfga_err_t
-cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
-{
-	if (options != NULL) {
-		cfga_msg(msgp,
-		    dgettext(TEXT_DOMAIN, sdcard_help[HELP_UNKNOWN]));
-		cfga_msg(msgp, options);
-	}
-	cfga_msg(msgp, dgettext(TEXT_DOMAIN, sdcard_help[HELP_HEADER]));
-	cfga_msg(msgp, sdcard_help[HELP_CONFIG]);
-	cfga_msg(msgp, sdcard_help[HELP_RESET_SLOT]);
-
-	return (CFGA_OK);
-}
-
-
-/*
- * Ensure the ap_id passed is in the correct (physical ap_id) form:
- *     path/device:xx
- * where xx is a one or two-digit number.
- *
- * Note the library always calls the plugin with a physical ap_id.
- */
-static int
-verify_valid_apid(const char *ap_id)
-{
-	char	*l_ap_id;
-
-	if (ap_id == NULL)
-		return (-1);
-
-	l_ap_id = strrchr(ap_id, MINOR_SEP);
-	l_ap_id++;
-
-	if (strspn(l_ap_id, "0123456789") != strlen(l_ap_id)) {
-		/* Bad characters in the ap_id */
-		return (-1);
-	}
-
-	return (0);
-}
-
-
-
-/*
- * Verify the params passed in are valid.
- */
-static cfga_sdcard_ret_t
-verify_params(const char *ap_id, const char *options, char **errstring)
-{
-	char *pdyn, *lap_id;
-	int rv;
-
-	if (errstring != NULL) {
-		*errstring = NULL;
-	}
-
-	if (options != NULL) {
-		return (CFGA_SDCARD_OPTIONS);
-	}
-
-	/* Strip dynamic AP name component if it is present. */
-	lap_id = strdup(ap_id);
-	if (lap_id == NULL) {
-		return (CFGA_SDCARD_ALLOC_FAIL);
-	}
-	if ((pdyn = GET_DYN(lap_id)) != NULL) {
-		*pdyn = '\0';
-	}
-
-	if (verify_valid_apid(lap_id) != 0) {
-		rv = CFGA_SDCARD_AP;
-	} else {
-		rv = CFGA_SDCARD_OK;
-	}
-	free(lap_id);
-
-	return (rv);
-}
-
-/*
- * Pair of routines to set up for/clean up after a devctl_ap_* lib call.
- */
-static void
-cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl)
-{
-	if (devctl_hdl != NULL) {
-		devctl_release(devctl_hdl);
-	}
-}
-
-static cfga_sdcard_ret_t
-setup_for_devctl_cmd(const char *ap_id, devctl_hdl_t *devctl_hdl, uint_t oflag)
-{
-	char *lap_id, *pdyn;
-
-	lap_id = strdup(ap_id);
-	if (lap_id == NULL)
-		return (CFGA_SDCARD_ALLOC_FAIL);
-	if ((pdyn = GET_DYN(lap_id)) != NULL) {
-		*pdyn = '\0';
-	}
-
-	/* Get a devctl handle to pass to the devctl_ap_XXX functions */
-	if ((*devctl_hdl = devctl_ap_acquire(lap_id, oflag)) == NULL) {
-		(void) fprintf(stderr, "[libcfgadm:sdcard] "
-		    "setup_for_devctl_cmd: devctl_ap_acquire failed: %s\n",
-		    strerror(errno));
-		free(lap_id);
-		return (CFGA_SDCARD_DEVCTL);
-	}
-
-	free(lap_id);
-	return (CFGA_SDCARD_OK);
-}
-
-
-static cfga_sdcard_ret_t
-slot_state(devctl_hdl_t hdl, ap_rstate_t *rstate, ap_ostate_t *ostate)
-{
-	devctl_ap_state_t	devctl_ap_state;
-
-	if (devctl_ap_getstate(hdl, NULL, &devctl_ap_state) == -1) {
-		(void) printf("devctl_ap_getstate failed, errno: %d\n", errno);
-		return (CFGA_SDCARD_IOCTL);
-	}
-	*rstate = devctl_ap_state.ap_rstate;
-	*ostate =  devctl_ap_state.ap_ostate;
-	return (CFGA_SDCARD_OK);
-}
-
-/*
- * Given a subcommand to the DEVCTL_AP_CONTROL ioctl, rquest the size of
- * the data to be returned, allocate a buffer, then get the data.
- */
-cfga_sdcard_ret_t
-do_control_ioctl(const char *ap_id, int subcommand, void *data, size_t size)
-{
-	int			fd = -1;
-	cfga_sdcard_ret_t	rv = CFGA_SDCARD_OK;
-	struct sda_ap_control	apc;
-
-	if ((fd = open(ap_id, O_RDONLY)) == -1) {
-		(void) printf("do_control_ioctl: open: errno:%d\n", errno);
-		rv = CFGA_SDCARD_OPEN;
-		goto bailout;
-	}
-
-	apc.cmd = subcommand;
-	apc.data = data;
-	apc.size = size;
-
-	/* Execute IOCTL */
-	if (ioctl(fd, DEVCTL_AP_CONTROL, &apc) != 0) {
-		rv = CFGA_SDCARD_IOCTL;
-		goto bailout;
-	}
-
-	(void) close(fd);
-
-	return (rv);
-
-bailout:
-	if (fd != -1) {
-		(void) close(fd);
-	}
-
-	if ((rv != CFGA_SDCARD_OK) && (errno == EBUSY)) {
-		rv = CFGA_SDCARD_BUSY;
-	}
-
-	return (rv);
-}
-
-
-static int
-sdcard_confirm(struct cfga_confirm *confp, char *msg)
-{
-	int rval;
-
-	if (confp == NULL || confp->confirm == NULL) {
-		return (0);
-	}
-	rval = (*confp->confirm)(confp->appdata_ptr, msg);
-
-	return (rval);
-}
-
-
-cfga_sdcard_ret_t
-sdcard_get_devicepath(const char *ap_id, char *devpath)
-{
-	return (do_control_ioctl(ap_id, SDA_CFGA_GET_DEVICE_PATH,
-	    devpath, MAXPATHLEN));
-}
-
-cfga_sdcard_ret_t
-sdcard_reset_slot(const char *ap_id)
-{
-	return (do_control_ioctl(ap_id, SDA_CFGA_RESET_SLOT, NULL, 0));
-}
-
-static rcm_handle_t *rcm_handle = NULL;
-static mutex_t rcm_handle_lock = DEFAULTMUTEX;
-
-/*
- * sdcard_rcm_offline:
- *      Offline resource consumers.
- */
-cfga_sdcard_ret_t
-sdcard_rcm_offline(char *devpath, char **errstring, cfga_flags_t flags)
-{
-	int			rret;
-	uint_t			rflags;
-	rcm_info_t		*rinfo = NULL;
-	cfga_sdcard_ret_t	ret;
-
-	if ((ret = sdcard_rcm_init()) != CFGA_SDCARD_OK) {
-		return (ret);
-	}
-
-	/* Translate the cfgadm flags to RCM flags */
-	rflags = (flags & CFGA_FLAG_FORCE) ? RCM_FORCE : 0;
-
-	rret = rcm_request_offline(rcm_handle, devpath, rflags, &rinfo);
-	if (rret != RCM_SUCCESS) {
-		if (rinfo) {
-			sdcard_rcm_info_table(rinfo, errstring);
-			rcm_free_info(rinfo);
-			rinfo = NULL;
-		}
-
-		if (rret == RCM_FAILURE) {
-			sdcard_rcm_online(devpath, errstring);
-		}
-		ret = CFGA_SDCARD_RCM_OFFLINE;
-	}
-	return (ret);
-}
-
-
-/*
- * sdcard_rcm_online:
- *      Online resource consumers that were previously offlined.
- */
-void
-sdcard_rcm_online(char *devpath, char **errstring)
-{
-	rcm_info_t		*rinfo = NULL;
-
-	if (sdcard_rcm_init() != CFGA_SDCARD_OK) {
-		return;
-	}
-
-	if (rcm_notify_online(rcm_handle, devpath, 0, &rinfo) !=
-	    RCM_SUCCESS && (rinfo != NULL)) {
-		sdcard_rcm_info_table(rinfo, errstring);
-		rcm_free_info(rinfo);
-		rinfo = NULL;
-	}
-}
-
-/*
- * sdcard_rcm_remove:
- *      Remove resource consumers after their kernel removal.
- */
-void
-sdcard_rcm_remove(char *devpath, char **errstring)
-{
-	rcm_info_t		*rinfo = NULL;
-
-	if (sdcard_rcm_init() != CFGA_SDCARD_OK) {
-		return;
-	}
-
-	if (rcm_notify_remove(rcm_handle, devpath, 0, &rinfo) !=
-	    RCM_SUCCESS && (rinfo != NULL)) {
-
-		sdcard_rcm_info_table(rinfo, errstring);
-		rcm_free_info(rinfo);
-		rinfo = NULL;
-	}
-}
-
-
-/*
- * sdcard_rcm_init:
- * Contains common initialization code for entering a sdcard_rcm_xx() routine.
- */
-static cfga_sdcard_ret_t
-sdcard_rcm_init(void)
-{
-	/* Get a handle for the RCM operations */
-	(void) mutex_lock(&rcm_handle_lock);
-	if (rcm_handle == NULL) {
-		if (rcm_alloc_handle(NULL, RCM_NOPID, NULL, &rcm_handle) !=
-		    RCM_SUCCESS) {
-			(void) mutex_unlock(&rcm_handle_lock);
-
-			return (CFGA_SDCARD_RCM_HANDLE);
-		}
-	}
-	(void) mutex_unlock(&rcm_handle_lock);
-
-	return (CFGA_SDCARD_OK);
-}
-
-
-#define	MAX_FORMAT	80	/* for info table */
-
-/*
- * sdcard_rcm_info_table:
- * Takes an opaque rcm_info_t pointer and a character pointer,
- * and appends the rcm_info_t data in the form of a table to the
- * given character pointer.
- */
-static void
-sdcard_rcm_info_table(rcm_info_t *rinfo, char **table)
-{
-	int i;
-	size_t w;
-	size_t width = 0;
-	size_t w_rsrc = 0;
-	size_t w_info = 0;
-	size_t table_size = 0;
-	uint_t tuples = 0;
-	rcm_info_tuple_t *tuple = NULL;
-	char *rsrc;
-	char *info;
-	char *newtable;
-	static char format[MAX_FORMAT];
-	const char *infostr;
-
-	/* Protect against invalid arguments */
-	if (rinfo == NULL || table == NULL) {
-		return;
-	}
-
-	/* Set localized table header strings */
-	rsrc = dgettext(TEXT_DOMAIN, "Resource");
-	info = dgettext(TEXT_DOMAIN, "Information");
-
-
-	/* A first pass, to size up the RCM information */
-	while (tuple = rcm_info_next(rinfo, tuple)) {
-		if ((infostr = rcm_info_info(tuple)) != NULL) {
-			tuples++;
-			if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc)
-				w_rsrc = w;
-			if ((w = strlen(infostr)) > w_info)
-				w_info = w;
-		}
-	}
-
-	/* If nothing was sized up above, stop early */
-	if (tuples == 0) {
-		return;
-	}
-
-	/* Adjust column widths for column headings */
-	if ((w = strlen(rsrc)) > w_rsrc) {
-		w_rsrc = w;
-	} else if ((w_rsrc - w) % 2) {
-		w_rsrc++;
-	}
-
-	if ((w = strlen(info)) > w_info) {
-		w_info = w;
-	} else if ((w_info - w) % 2) {
-		w_info++;
-	}
-
-
-	/*
-	 * Compute the total line width of each line,
-	 * accounting for intercolumn spacing.
-	 */
-	width = w_info + w_rsrc + 4;
-
-	/* Allocate space for the table */
-	table_size = (2 + tuples) * (width + 1) + 2;
-	if (*table == NULL) {
-		/* zero fill for the strcat() call below */
-		*table = calloc(table_size, sizeof (char));
-		if (*table == NULL) {
-			return;
-		}
-	} else {
-		newtable = realloc(*table, strlen(*table) + table_size);
-		if (newtable == NULL) {
-			return;
-		} else {
-			*table = newtable;
-		}
-	}
-
-	/* Place a table header into the string */
-
-
-	/* The resource header */
-	(void) strcat(*table, "\n");
-	w = strlen(rsrc);
-
-	for (i = 0; i < ((w_rsrc - w) / 2); i++) {
-		(void) strcat(*table, " ");
-	}
-	(void) strcat(*table, rsrc);
-
-	for (i = 0; i < ((w_rsrc - w) / 2); i++) {
-		(void) strcat(*table, " ");
-	}
-
-	/* The information header */
-	(void) strcat(*table, "  ");
-	w = strlen(info);
-	for (i = 0; i < ((w_info - w) / 2); i++) {
-		(void) strcat(*table, " ");
-	}
-	(void) strcat(*table, info);
-
-	for (i = 0; i < ((w_info - w) / 2); i++) {
-		(void) strcat(*table, " ");
-	}
-
-	(void) strcat(*table, "\n");
-
-	/* Underline the headers */
-	for (i = 0; i < w_rsrc; i++) {
-		(void) strcat(*table, "-");
-	}
-
-	(void) strcat(*table, "  ");
-	for (i = 0; i < w_info; i++) {
-		(void) strcat(*table, "-");
-	}
-
-
-	(void) strcat(*table, "\n");
-
-	/* Construct the format string */
-	(void) snprintf(format, MAX_FORMAT, "%%-%ds  %%-%ds",
-	    (int)w_rsrc, (int)w_info);
-
-	/* Add the tuples to the table string */
-	tuple = NULL;
-	while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
-		if ((infostr = rcm_info_info(tuple)) != NULL) {
-			(void) sprintf(&((*table)[strlen(*table)]),
-			    format, rcm_info_rsrc(tuple), infostr);
-			(void) strcat(*table, "\n");
-		}
-	}
-}
--- a/usr/src/lib/cfgadm_plugins/sdcard/common/cfga_sdcard.h	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,138 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _CFGA_SDCARD_H
-#define	_CFGA_SDCARD_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdlib.h>
-#include <strings.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <libintl.h>
-#include <libdevice.h>
-#include <sys/varargs.h>
-
-#include <libdevinfo.h>
-#include <libdevice.h>
-#include <librcm.h>
-#include <synch.h>
-#include <thread.h>
-#include <assert.h>
-#include <sys/sdcard/sda_ioctl.h>
-
-#define	CFGA_PLUGIN_LIB
-#include <config_admin.h>
-
-/* Misc text strings */
-#define	CFGA_DEV_DIR			"/dev/cfg"
-#define	DYN_SEP				"::"
-#define	CFGA_DEVCTL_NODE  		":devctl"
-#define	MINOR_SEP 			':'
-#define	PATH_SEP 			'/'
-
-#define	RESET_SLOT		"sdcard_reset_slot"
-
-/* for confirm operation */
-#define	SDCARD_CONFIRM_1 \
-	"This operation will suspend activity on the SD card device\nContinue"
-#define	SDCARD_CONFIRM_2 \
-	"This operation will disrupt activity on the SD card device\nContinue"
-
-#define	GET_DYN(a)		(((a) != NULL) ? \
-				strstr((a), DYN_SEP) : (void *)0)
-
-
-/* Messages */
-
-typedef struct msgcvt {
-	int		intl;		/* Flag: if 1, internationalize */
-	cfga_err_t	cfga_err;	/* Error code libcfgadm understands */
-	const char	*msgstr;
-} msgcvt_t;
-
-#define	NO_CVT	0
-#define	CVT	1
-
-#define	MSG_TBL_SZ(table)	(sizeof ((table)) / sizeof (msgcvt_t))
-
-/* Messages */
-
-
-/* Error message ids (and indices into sdcard_error_msgs) */
-typedef enum {
-	CFGA_SDCARD_OK = 0,
-	CFGA_SDCARD_NACK,
-	CFGA_SDCARD_UNKNOWN,
-	CFGA_SDCARD_PRIV,
-	CFGA_SDCARD_DYNAMIC_AP,
-	CFGA_SDCARD_INTERNAL_ERROR,
-	CFGA_SDCARD_ALLOC_FAIL,
-	CFGA_SDCARD_IOCTL,
-	CFGA_SDCARD_DEVCTL,
-	CFGA_SDCARD_AP,
-	CFGA_SDCARD_BUSY,
-	CFGA_SDCARD_DEVLINK,
-	CFGA_SDCARD_INVALID_DEVNAME,
-	CFGA_SDCARD_DATA_ERROR,
-	CFGA_SDCARD_DEV_CONFIGURE,
-	CFGA_SDCARD_DEV_UNCONFIGURE,
-	CFGA_SDCARD_NOT_CONNECTED,
-	CFGA_SDCARD_DISCONNECTED,
-	CFGA_SDCARD_NOT_CONFIGURED,
-	CFGA_SDCARD_ALREADY_CONNECTED,
-	CFGA_SDCARD_ALREADY_CONFIGURED,
-	CFGA_SDCARD_DEVICE_UNCONFIGURED,
-	CFGA_SDCARD_OPNOTSUPP,
-	CFGA_SDCARD_HWOPNOTSUPP,
-	CFGA_SDCARD_OPTIONS,
-	CFGA_SDCARD_STATE,
-	CFGA_SDCARD_OPEN,
-	CFGA_SDCARD_RCM_HANDLE,
-	CFGA_SDCARD_RCM_OFFLINE,
-	CFGA_SDCARD_RCM_REMOVE,
-	CFGA_SDCARD_RCM_ONLINE,
-	CFGA_SDCARD_CONFIRM_RESET,
-	CFGA_SDCARD_CONFIRM_UNCONFIGURE,
-	CFGA_SDCARD_CONFIRM_DISCONNECT
-} cfga_sdcard_ret_t;
-
-/*
- * Given an error msg index, look up the associated string, and
- * convert it to the current locale if required.
- */
-#define	ERR_STR(msg_idx) \
-	(get_msg((msg_idx), sdcard_msgs, MSG_TBL_SZ(sdcard_msgs)))
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif	/* _CFGA_SDCARD_H */
--- a/usr/src/lib/cfgadm_plugins/sdcard/common/mapfile-vers	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-#
-# MAPFILE HEADER START
-#
-# WARNING:  STOP NOW.  DO NOT MODIFY THIS FILE.
-# Object versioning must comply with the rules detailed in
-#
-#	usr/src/lib/README.mapfiles
-#
-# You should not be making modifications here until you've read the most current
-# copy of that file. If you need help, contact a gatekeeper for guidance.
-#
-# MAPFILE HEADER END
-#
-
-SUNWprivate_1.1 {
-    global:
-	cfga_change_state;
-	cfga_help;
-	cfga_list_ext;
-	cfga_private_func;
-	cfga_test;
-	cfga_version;
-    local:
-	*;
-};
--- a/usr/src/lib/cfgadm_plugins/sdcard/i386/Makefile	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-include ../Makefile.com
-CFLAGS += -D_POSIX_PTHREAD_SEMANTICS
-LINTFLAGS += -D_POSIX_PTHREAD_SEMANTICS
-
-.KEEP_STATE:
-
-install: all $(ROOTLIBS) $(ROOTLINKS) 
--- a/usr/src/lib/cfgadm_plugins/sdcard/sdcard.xcl	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-# lib/cfgadm_plugins/sdcard/sdcard.xcl
-#
-msgid "/devices/"
-msgid "/devices"
-msgid "/"
-msgid "."
-msgid "C"
-msgid "\n"
-msgid "-"
-msgid "ap_id: "
-msgid " %s%s\n%s"
-msgid "%s/%s"
-msgid "%s\n"
-msgid "../"
-msgid ""
-msgid "cfga_change_state: get device path failed\n"
-msgid "cfga_change_state: get path failed\n"
-msgid "devctl_ap_unconfigure failed\n"
-#msgid "No valid option specified\n"
-msgid "cfga_list_ext: cannot locate target device\n"
-msgid "dsk/"
-msgid "/dev/dsk"
-msgid "/dsk/"
-msgid "/rdsk/"
-msgid "/dev/"
-msgid "/disk@0,0"
-msgid "/sdcard@"
-msgid "Mod: %s Rev: %d.%d Date: %d/%d SN: %X"
-msgid "::"
-msgid "cfga_msg"
-msgid "cfga_msg: NULL msgp\n"
-msgid "cfga_msg: null str\n"
-msgid "0123456789"
-msgid ".."
-msgid "[libcfgadm:sdcard] "
-      "setup_for_devctl_cmd: devctl_ap_acquire failed: %s\n"
-msgid "devctl_ap_getstate failed, errno: %d\n"
-msgid "do_control_ioctl: open: errno:%d\n"
-msgid "ioctl failed (size)"
-msgid " "
-msgid "  "
-msgid "%%-%ds  %%-%ds"
-msgid " cfgadm -c [configure|unconfigure|disconnect|connect] ap_id "
-      "[ap_id...]\n"
-msgid " cfgadm -x sdcard_reset_slot ap_id [ap_id...]\n"
--- a/usr/src/lib/cfgadm_plugins/sdcard/sparc/Makefile	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-include ../Makefile.com
-CFLAGS += -D_POSIX_PTHREAD_SEMANTICS
-LINTFLAGS += -D_POSIX_PTHREAD_SEMANTICS
-
-.KEEP_STATE:
-
-install: all $(ROOTLIBS) $(ROOTLINKS) 
--- a/usr/src/lib/cfgadm_plugins/sdcard/sparcv9/Makefile	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-include ../Makefile.com
-include ../../../Makefile.lib.64
-CFLAGS += -D_POSIX_PTHREAD_SEMANTICS
-LINTFLAGS += -D_POSIX_PTHREAD_SEMANTICS
-
-.KEEP_STATE:
-
-install: all $(ROOTLIBS64) $(ROOTLINKS64) 
--- a/usr/src/lib/libsmedia/library/common/l_defines.h	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/lib/libsmedia/library/common/l_defines.h	Mon May 17 21:17:01 2010 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,15 +19,12 @@
  * CDDL HEADER END
  */
 /*
- * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _L_DEFINES_H_
 #define	_L_DEFINES_H_
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -76,6 +72,7 @@
 #define	SM_PCMEM_VERSION_1 	1
 #define	SM_PLUGIN_VERSION	1
 #define	SM_PCATA_VERSION_1 	1
+#define	SM_BLKDEV_VERSION_1	1
 
 #ifdef __cplusplus
 }
--- a/usr/src/lib/libsmedia/library/inc/smedia.h	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/lib/libsmedia/library/inc/smedia.h	Mon May 17 21:17:01 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _SMEDIA_H_
@@ -62,6 +61,7 @@
 #define	IF_SCSI		0x0
 #define	IF_FLOPPY	0x1
 #define	IF_PCMCIA	0x2
+#define	IF_BLOCK	0x3
 
 
 typedef struct smmedium_property {
@@ -86,6 +86,7 @@
 #define	SM_SCSI_FLOPPY		0x10005 /* SCSI floppy device */
 #define	SM_PCMCIA_MEM		0x20006 /* PCMCIA memory card (Obsolete) */
 #define	SM_PCMCIA_ATA		0x20007 /* PCMCIA ata card */
+#define	SM_BLOCK		0x20008	/* Generic block device */
 #define	SM_NOT_PRESENT		0xFFFF
 
 
--- a/usr/src/lib/libsmedia/plugins/Makefile	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/lib/libsmedia/plugins/Makefile	Mon May 17 21:17:01 2010 -0700
@@ -19,13 +19,13 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 # lib/libsmedia/plugins/Makefile
 
 
 SUBDIRS = \
+	blkdev \
 	scsi \
 	floppy \
 	pcata
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmedia/plugins/blkdev/Makefile	Mon May 17 21:17:01 2010 -0700
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+#
+# lib/libsmedia/plugins/bd/Makefile
+
+include		../../../Makefile.lib
+include		Makefile.targ
+include		../Makefile.plugin
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmedia/plugins/blkdev/Makefile.targ	Mon May 17 21:17:01 2010 -0700
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+# lib/libsmedia/plugins/bd/Makefile.targ
+
+LIBRARY=	sm_blkdev.a
+VERS=		.1
+
+OBJECTS= b_generic.o 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmedia/plugins/blkdev/amd64/Makefile	Mon May 17 21:17:01 2010 -0700
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.targ
+include ../../../../Makefile.lib
+include ../../../../Makefile.targ
+include ../../Makefile.com
+include ../../../../Makefile.lib.64
+
+.KEEP_STATE:
+
+all:    $(LIBS) $(TXTS)
+
+install: all $(PLUGINDIR64) .WAIT $(PLUGINS64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmedia/plugins/blkdev/common/b_generic.c	Mon May 17 21:17:01 2010 -0700
@@ -0,0 +1,206 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * b_generic.c :
+ *      This file contains the functions for generic block devices
+ * 	for libsmedia.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <locale.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/dkio.h>
+#include <string.h>
+#include "../../../library/inc/smedia.h"
+#include "../../../library/inc/rmedia.h"
+#include "../../../library/common/l_defines.h"
+
+#define	PERROR(string)	my_perror(gettext(string))
+
+static void
+my_perror(char *err_string)
+{
+
+	int error_no;
+	if (errno == 0)
+		return;
+
+	error_no = errno;
+	(void) fprintf(stderr, gettext(err_string));
+	(void) fprintf(stderr, gettext(" : "));
+	errno = error_no;
+	perror("");
+}
+
+int32_t
+_m_version_no(void)
+{
+	return (SM_BLKDEV_VERSION_1);
+}
+
+int32_t
+_m_device_type(ushort_t ctype, ushort_t mtype)
+{
+	if (ctype == DKC_BLKDEV) {
+		if (mtype == 0)
+			return (0);
+	}
+	return (-1);
+}
+
+
+int32_t
+_m_get_media_info(rmedia_handle_t *handle, void *ip)
+{
+	smmedium_prop_t *mp = (smmedium_prop_t *)ip;
+	struct dk_geom		dkg;
+	struct dk_minfo		minfo;
+	enum dkio_state		state = DKIO_NONE;
+	int			ret_val;
+
+	if (handle == NULL) {
+		DPRINTF("Null Handle\n");
+		errno = EINVAL;
+		return (-1);
+	}
+	if (handle->sm_signature != (int32_t)LIBSMEDIA_SIGNATURE) {
+		DPRINTF2("Signature expected=0x%x, found=0x%x\n",
+		    LIBSMEDIA_SIGNATURE, handle->sm_signature);
+		errno = EINVAL;
+		return (-1);
+	}
+
+	if (ioctl(handle->sm_fd, DKIOCSTATE, &state) < 0) {
+		PERROR("DKIOCSTATE failed");
+		return (-1);
+	}
+
+	if (state != DKIO_INSERTED) {
+		DPRINTF("No media.\n");
+		mp->sm_media_type = SM_NOT_PRESENT;
+		mp->sm_version = SMMEDIA_PROP_V_1;
+		return (0);
+
+	}
+
+	ret_val = ioctl(handle->sm_fd, DKIOCGMEDIAINFO, &minfo);
+	if (ret_val < 0) {
+		DPRINTF("DKIOCGMEDIAINFO ioctl failed");
+		return (ret_val);
+	}
+	ret_val = ioctl(handle->sm_fd, DKIOCGGEOM, &dkg);
+	if (ret_val < 0) {
+		DPRINTF("DKIOCGGEOM ioctl failed");
+		return (ret_val);
+	}
+
+	mp->sm_media_type = SM_BLOCK;
+	mp->sm_blocksize = minfo.dki_lbsize;
+	mp->sm_capacity = minfo.dki_capacity;
+	mp->sm_pcyl = dkg.dkg_pcyl;
+	mp->sm_nhead = dkg.dkg_nhead;
+	mp->sm_nsect = dkg.dkg_nsect;
+	return (0);
+}
+
+
+
+/* ARGSUSED0 */
+
+int32_t
+_m_get_device_info(rmedia_handle_t *handle, void *ip)
+{
+	smdevice_info_t *mp = (smdevice_info_t *)ip;
+	char *vendor_name, *product_name, *fw_version;
+
+	if (handle == NULL) {
+		DPRINTF("Null Handle\n");
+		errno = EINVAL;
+		return (-1);
+	}
+	if (handle->sm_signature != (int32_t)LIBSMEDIA_SIGNATURE) {
+		DPRINTF2("Signature expected=0x%x, found=0x%x\n",
+		    LIBSMEDIA_SIGNATURE, handle->sm_signature);
+		errno = EINVAL;
+		return (-1);
+	}
+	vendor_name = (char *)malloc(1);
+	if (vendor_name == NULL) {
+	if (!errno)
+		errno = ENOMEM;
+		return (-1);
+	}
+	product_name = (char *)malloc(1);
+	if (product_name == NULL) {
+		free(vendor_name);
+		if (!errno)
+			errno = ENOMEM;
+		return (-1);
+	}
+
+	fw_version = (char *)malloc(1);
+	if (fw_version == NULL) {
+		free(vendor_name);
+		free(product_name);
+			if (!errno)
+		errno = ENOMEM;
+		return (-1);
+	}
+
+	/* Note: we could potentially offer more here */
+	vendor_name[0] = 0;
+	product_name[0] = 0;
+	fw_version[0] = 0;
+	mp->sm_interface_type = IF_BLOCK;
+	mp->sm_vendor_name = vendor_name;
+	mp->sm_product_name = product_name;
+	mp->sm_firmware_version = fw_version;
+	return (0);
+}
+
+int32_t
+_m_free_device_info(rmedia_handle_t *handle, void *ip)
+{
+	struct smdevice_info *dev_info = ip;
+
+	/* Check for valid handle */
+	if (handle == NULL) {
+		DPRINTF("Null Handle\n");
+		errno = EINVAL;
+		return (-1);
+	}
+	if (handle->sm_signature != LIBSMEDIA_SIGNATURE) {
+		DPRINTF("Invalid signature in handle.\n");
+		errno = EINVAL;
+		return (-1);
+	}
+
+	free(dev_info->sm_vendor_name);
+	free(dev_info->sm_product_name);
+	free(dev_info->sm_firmware_version);
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmedia/plugins/blkdev/common/mapfile-vers	Mon May 17 21:17:01 2010 -0700
@@ -0,0 +1,48 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING:  STOP NOW.  DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+#	usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+SUNWprivate_1.1 {
+    global:
+	_m_device_type;
+	_m_free_device_info;
+	_m_get_device_info;
+	_m_get_media_info;
+	_m_version_no;
+    local:
+	*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmedia/plugins/blkdev/i386/Makefile	Mon May 17 21:17:01 2010 -0700
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.targ
+include ../../../../Makefile.lib
+include ../../../../Makefile.targ
+include ../../Makefile.com
+
+.KEEP_STATE:
+
+all:    $(LIBS) $(TXTS)
+
+
+install: all $(PLUGINDIR) .WAIT $(PLUGINS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmedia/plugins/blkdev/sparc/Makefile	Mon May 17 21:17:01 2010 -0700
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.targ
+include ../../../../Makefile.lib
+include ../../../../Makefile.targ
+include ../../Makefile.com
+
+.KEEP_STATE:
+
+all:    $(LIBS) $(TXTS)
+
+install: all $(PLUGINDIR) .WAIT $(PLUGINS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmedia/plugins/blkdev/sparcv9/Makefile	Mon May 17 21:17:01 2010 -0700
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.targ
+include ../../../../Makefile.lib
+include ../../../../Makefile.targ
+include ../../Makefile.com
+include ../../../../Makefile.lib.64
+
+.KEEP_STATE:
+
+all:    $(LIBS) $(TXTS)
+
+install: all $(PLUGINDIR64) .WAIT $(PLUGINS64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkg/manifests/driver-storage-blkdev.mf	Mon May 17 21:17:01 2010 -0700
@@ -0,0 +1,45 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# This package will install successfully into any zone, global or
+# non-global.  The files, directories, links, and hardlinks, however,
+# will only be installed into the global zone.
+#
+<include hollow_zone_pkg>
+set name=pkg.fmri value=pkg:/driver/storage/blkdev@$(PKGVERS)
+set name=pkg.description value="Generic Block Driver"
+set name=pkg.summary value="Generic Block Driver"
+set name=info.classification value=org.opensolaris.category.2008:Drivers/Storage
+set name=variant.arch value=$(ARCH)
+set name=variant.opensolaris.zone value=global value=nonglobal
+dir path=kernel group=sys
+dir path=kernel/drv group=sys
+dir path=kernel/drv/$(ARCH64) group=sys
+driver name=blkdev perms="* 0640 root root"
+file path=kernel/drv/$(ARCH64)/blkdev group=sys
+$(i386_ONLY)file path=kernel/drv/blkdev group=sys
+license cr_Sun license=cr_Sun
+license lic_CDDL license=lic_CDDL
--- a/usr/src/pkg/manifests/driver-storage-sdcard.mf	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/pkg/manifests/driver-storage-sdcard.mf	Mon May 17 21:17:01 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 #
@@ -44,13 +43,10 @@
 $(i386_ONLY)dir path=kernel/drv/$(ARCH64) group=sys
 $(i386_ONLY)dir path=kernel/misc group=sys
 $(i386_ONLY)dir path=kernel/misc/$(ARCH64) group=sys
-$(i386_ONLY)driver name=sdcard perms="* 0644 root root"
 $(i386_ONLY)driver name=sdhost perms="* 0644 root root" \
     alias=pciclass,080500 \
     alias=pciclass,080501
-$(i386_ONLY)file path=kernel/drv/$(ARCH64)/sdcard group=sys
 $(i386_ONLY)file path=kernel/drv/$(ARCH64)/sdhost group=sys
-$(i386_ONLY)file path=kernel/drv/sdcard group=sys
 $(i386_ONLY)file path=kernel/drv/sdhost group=sys
 $(i386_ONLY)file path=kernel/misc/$(ARCH64)/sda group=sys mode=0755 \
     reboot-needed=true
--- a/usr/src/pkg/manifests/service-storage-removable-media.mf	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/pkg/manifests/service-storage-removable-media.mf	Mon May 17 21:17:01 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 set name=pkg.fmri value=pkg:/service/storage/removable-media@$(PKGVERS)
@@ -46,10 +45,12 @@
 file path=usr/lib/libsmedia.so.1
 file path=usr/lib/llib-lsmedia
 file path=usr/lib/llib-lsmedia.ln
+file path=usr/lib/smedia/$(ARCH64)/sm_blkdev.so.1 mode=0555
 file path=usr/lib/smedia/$(ARCH64)/sm_fd.so.1 mode=0555
 file path=usr/lib/smedia/$(ARCH64)/sm_pcata.so.1 mode=0555
 file path=usr/lib/smedia/$(ARCH64)/sm_scsi.so.1 mode=0555
 file path=usr/lib/smedia/rpc.smserverd mode=0555
+file path=usr/lib/smedia/sm_blkdev.so.1 mode=0555
 file path=usr/lib/smedia/sm_fd.so.1 mode=0555
 file path=usr/lib/smedia/sm_pcata.so.1 mode=0555
 file path=usr/lib/smedia/sm_scsi.so.1 mode=0555
--- a/usr/src/pkg/manifests/system-header.mf	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/pkg/manifests/system-header.mf	Mon May 17 21:17:01 2010 -0700
@@ -803,6 +803,7 @@
 file path=usr/include/sys/bitmap.h
 file path=usr/include/sys/bitset.h
 file path=usr/include/sys/bl.h
+file path=usr/include/sys/blkdev.h
 file path=usr/include/sys/bmc_intf.h
 file path=usr/include/sys/bofi.h
 file path=usr/include/sys/bofi_impl.h
--- a/usr/src/pkg/manifests/system-kernel.mf	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/pkg/manifests/system-kernel.mf	Mon May 17 21:17:01 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 #
@@ -632,7 +631,6 @@
 $(i386_ONLY)file path=kernel/misc/$(ARCH64)/agpmaster group=sys mode=0755 \
     reboot-needed=true
 file path=kernel/misc/$(ARCH64)/bignum group=sys mode=0755 reboot-needed=true
-file path=kernel/misc/$(ARCH64)/blk2scsa group=sys mode=0755 reboot-needed=true
 $(i386_ONLY)file path=kernel/misc/$(ARCH64)/bootdev group=sys mode=0755 \
     reboot-needed=true
 file path=kernel/misc/$(ARCH64)/busra group=sys mode=0755 reboot-needed=true
@@ -683,8 +681,6 @@
 $(i386_ONLY)file path=kernel/misc/agpmaster group=sys mode=0755 \
     reboot-needed=true
 $(i386_ONLY)file path=kernel/misc/bignum group=sys mode=0755 reboot-needed=true
-$(i386_ONLY)file path=kernel/misc/blk2scsa group=sys mode=0755 \
-    reboot-needed=true
 $(i386_ONLY)file path=kernel/misc/bootdev group=sys mode=0755 reboot-needed=true
 $(i386_ONLY)file path=kernel/misc/busra group=sys mode=0755 reboot-needed=true
 $(i386_ONLY)file path=kernel/misc/cardbus group=sys mode=0755 reboot-needed=true
--- a/usr/src/pkg/manifests/system-library.mf	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/pkg/manifests/system-library.mf	Mon May 17 21:17:01 2010 -0700
@@ -295,14 +295,12 @@
 file path=usr/lib/cfgadm/$(ARCH64)/pci.so.1
 $(i386_ONLY)file path=usr/lib/cfgadm/$(ARCH64)/sata.so.1
 file path=usr/lib/cfgadm/$(ARCH64)/scsi.so.1
-file path=usr/lib/cfgadm/$(ARCH64)/sdcard.so.1
 file path=usr/lib/cfgadm/$(ARCH64)/shp.so.1
 file path=usr/lib/cfgadm/$(ARCH64)/usb.so.1
 file path=usr/lib/cfgadm/ib.so.1
 file path=usr/lib/cfgadm/pci.so.1
 $(i386_ONLY)file path=usr/lib/cfgadm/sata.so.1
 file path=usr/lib/cfgadm/scsi.so.1
-file path=usr/lib/cfgadm/sdcard.so.1
 file path=usr/lib/cfgadm/shp.so.1
 file path=usr/lib/cfgadm/usb.so.1
 file path=usr/lib/extendedFILE.so.1
@@ -916,14 +914,12 @@
 link path=usr/lib/cfgadm/$(ARCH64)/pci.so target=./pci.so.1
 $(i386_ONLY)link path=usr/lib/cfgadm/$(ARCH64)/sata.so target=./sata.so.1
 link path=usr/lib/cfgadm/$(ARCH64)/scsi.so target=./scsi.so.1
-link path=usr/lib/cfgadm/$(ARCH64)/sdcard.so target=./sdcard.so.1
 link path=usr/lib/cfgadm/$(ARCH64)/shp.so target=./shp.so.1
 link path=usr/lib/cfgadm/$(ARCH64)/usb.so target=./usb.so.1
 link path=usr/lib/cfgadm/ib.so target=./ib.so.1
 link path=usr/lib/cfgadm/pci.so target=./pci.so.1
 $(i386_ONLY)link path=usr/lib/cfgadm/sata.so target=./sata.so.1
 link path=usr/lib/cfgadm/scsi.so target=./scsi.so.1
-link path=usr/lib/cfgadm/sdcard.so target=./sdcard.so.1
 link path=usr/lib/cfgadm/shp.so target=./shp.so.1
 link path=usr/lib/cfgadm/usb.so target=./usb.so.1
 link path=usr/lib/lib300.so target=./lib300.so.1
--- a/usr/src/tools/scripts/bfu.sh	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/tools/scripts/bfu.sh	Mon May 17 21:17:01 2010 -0700
@@ -8454,6 +8454,22 @@
 	rm -rf $usr/ucb/tek
 	rm -rf $usr/ucb/vplot
 
+	# Remove blk2scsa
+	rm -f $root/kernel/drv/blk2scsa
+	rm -f $root/kernel/drv/amd64/blk2scsa
+	rm -f $root/kernel/drv/sparcv9/blk2scsa
+
+	# Remove sdcard kernel module and cfgadm plugin - use blkdev now
+	rm -f $root/kernel/drv/sdcard
+	rm -f $root/kernel/drv/amd64/sdcard
+	rm -f $root/kernel/drv/sparcv9/sdcard
+	rm -f $usr/lib/cfgadm/sdcard.so.1
+	rm -f $usr/lib/cfgadm/sdcard.so
+	rm -f $usr/lib/cfgadm/amd64/sdcard.so.1
+	rm -f $usr/lib/cfgadm/amd64/sdcard.so
+	rm -f $usr/lib/cfgadm/sparcv9/sdcard.so.1
+	rm -f $usr/lib/cfgadm/sparcv9/sdcard.so	
+
 	#
 	# Remove legacy pcmcia bits
 	#
--- a/usr/src/uts/common/Makefile.files	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/common/Makefile.files	Mon May 17 21:17:01 2010 -0700
@@ -468,6 +468,8 @@
 
 AC97_OBJS += ac97.o ac97_ad.o ac97_alc.o ac97_cmi.o
 
+BLKDEV_OBJS += blkdev.o
+
 CARDBUS_OBJS += cardbus.o cardbus_hp.o cardbus_cfg.o
 
 CONSKBD_OBJS += conskbd.o
@@ -1939,9 +1941,7 @@
 #
 #	sdcard modules
 #
-SDA_OBJS =	sda_cmd.o sda_host.o sda_init.o sda_mem.o sda_mod.o \
-		sda_nexus.o sda_slot.o
-SDCARD_OBJS =	sdcard.o
+SDA_OBJS =	sda_cmd.o sda_host.o sda_init.o sda_mem.o sda_mod.o sda_slot.o
 SDHOST_OBJS =	sdhost.o
 
 #
--- a/usr/src/uts/common/Makefile.rules	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/common/Makefile.rules	Mon May 17 21:17:01 2010 -0700
@@ -646,6 +646,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/blkdev/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/bpf/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -1971,6 +1975,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/bge/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/blkdev/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/cardbus/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/blkdev/blkdev.c	Mon May 17 21:17:01 2010 -0700
@@ -0,0 +1,1634 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/ksynch.h>
+#include <sys/kmem.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+#include <sys/open.h>
+#include <sys/buf.h>
+#include <sys/uio.h>
+#include <sys/aio_req.h>
+#include <sys/cred.h>
+#include <sys/modctl.h>
+#include <sys/cmlb.h>
+#include <sys/conf.h>
+#include <sys/devops.h>
+#include <sys/list.h>
+#include <sys/sysmacros.h>
+#include <sys/dkio.h>
+#include <sys/vtoc.h>
+#include <sys/scsi/scsi.h>	/* for DTYPE_DIRECT */
+#include <sys/kstat.h>
+#include <sys/fs/dv_node.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/note.h>
+#include <sys/blkdev.h>
+
+#define	BD_MAXPART	64
+#define	BDINST(dev)	(getminor(dev) / BD_MAXPART)
+#define	BDPART(dev)	(getminor(dev) % BD_MAXPART)
+
+typedef struct bd bd_t;
+typedef struct bd_xfer_impl bd_xfer_impl_t;
+
+struct bd {
+	void		*d_private;
+	dev_info_t	*d_dip;
+	kmutex_t	d_ocmutex;
+	kmutex_t	d_iomutex;
+	kmutex_t	d_statemutex;
+	kcondvar_t	d_statecv;
+	enum dkio_state	d_state;
+	cmlb_handle_t	d_cmlbh;
+	unsigned	d_open_lyr[BD_MAXPART];	/* open count */
+	uint64_t	d_open_excl;	/* bit mask indexed by partition */
+	uint64_t	d_open_reg[OTYPCNT];		/* bit mask */
+
+	uint32_t	d_qsize;
+	uint32_t	d_qactive;
+	uint32_t	d_maxxfer;
+	uint32_t	d_blkshift;
+	uint64_t	d_numblks;
+	ddi_devid_t	d_devid;
+
+	kmem_cache_t	*d_cache;
+	list_t		d_runq;
+	list_t		d_waitq;
+	kstat_t		*d_ksp;
+	kstat_io_t	*d_kiop;
+
+	boolean_t	d_rdonly;
+	boolean_t	d_removable;
+	boolean_t	d_hotpluggable;
+	boolean_t	d_use_dma;
+
+	ddi_dma_attr_t	d_dma;
+	bd_ops_t	d_ops;
+	bd_handle_t	d_handle;
+};
+
+struct bd_handle {
+	bd_ops_t	h_ops;
+	ddi_dma_attr_t	*h_dma;
+	dev_info_t	*h_parent;
+	dev_info_t	*h_child;
+	void		*h_private;
+	bd_t		*h_bd;
+	char		*h_name;
+	char		h_addr[20];	/* enough for %X,%X */
+};
+
+struct bd_xfer_impl {
+	bd_xfer_t	i_public;
+	list_node_t	i_linkage;
+	bd_t		*i_bd;
+	buf_t		*i_bp;
+	uint_t		i_num_win;
+	uint_t		i_cur_win;
+	off_t		i_offset;
+	int		(*i_func)(void *, bd_xfer_t *);
+	uint32_t	i_blkshift;
+	size_t		i_len;
+	size_t		i_resid;
+};
+
+#define	i_dmah		i_public.x_dmah
+#define	i_dmac		i_public.x_dmac
+#define	i_ndmac		i_public.x_ndmac
+#define	i_kaddr		i_public.x_kaddr
+#define	i_nblks		i_public.x_nblks
+#define	i_blkno		i_public.x_blkno
+
+
+/*
+ * Private prototypes.
+ */
+
+static int bd_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int bd_attach(dev_info_t *, ddi_attach_cmd_t);
+static int bd_detach(dev_info_t *, ddi_detach_cmd_t);
+
+static int bd_open(dev_t *, int, int, cred_t *);
+static int bd_close(dev_t, int, int, cred_t *);
+static int bd_strategy(struct buf *);
+static int bd_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+static int bd_read(dev_t, struct uio *, cred_t *);
+static int bd_write(dev_t, struct uio *, cred_t *);
+static int bd_aread(dev_t, struct aio_req *, cred_t *);
+static int bd_awrite(dev_t, struct aio_req *, cred_t *);
+static int bd_prop_op(dev_t, dev_info_t *, ddi_prop_op_t, int, char *,
+    caddr_t, int *);
+
+static int bd_tg_rdwr(dev_info_t *, uchar_t, void *, diskaddr_t, size_t,
+    void *);
+static int bd_tg_getinfo(dev_info_t *, int, void *, void *);
+static int bd_xfer_ctor(void *, void *, int);
+static void bd_xfer_dtor(void *, void *);
+static void bd_sched(bd_t *);
+static void bd_submit(bd_t *, bd_xfer_impl_t *);
+static void bd_runq_exit(bd_xfer_impl_t *, int);
+static void bd_update_state(bd_t *);
+static int bd_check_state(bd_t *, enum dkio_state *);
+static int bd_flush_write_cache(bd_t *, struct dk_callback *);
+
+struct cmlb_tg_ops bd_tg_ops = {
+	TG_DK_OPS_VERSION_1,
+	bd_tg_rdwr,
+	bd_tg_getinfo,
+};
+
+static struct cb_ops bd_cb_ops = {
+	bd_open, 		/* open */
+	bd_close, 		/* close */
+	bd_strategy, 		/* strategy */
+	nodev, 			/* print */
+	nodev,			/* dump */
+	bd_read, 		/* read */
+	bd_write, 		/* write */
+	bd_ioctl, 		/* ioctl */
+	nodev, 			/* devmap */
+	nodev, 			/* mmap */
+	nodev, 			/* segmap */
+	nochpoll, 		/* poll */
+	bd_prop_op, 		/* cb_prop_op */
+	0, 			/* streamtab  */
+	D_64BIT | D_MP,		/* Driver comaptibility flag */
+	CB_REV,			/* cb_rev */
+	bd_aread,		/* async read */
+	bd_awrite		/* async write */
+};
+
+struct dev_ops bd_dev_ops = {
+	DEVO_REV, 		/* devo_rev, */
+	0, 			/* refcnt  */
+	bd_getinfo,		/* getinfo */
+	nulldev, 		/* identify */
+	nulldev, 		/* probe */
+	bd_attach, 		/* attach */
+	bd_detach,		/* detach */
+	nodev, 			/* reset */
+	&bd_cb_ops, 		/* driver operations */
+	NULL,			/* bus operations */
+	NULL,			/* power */
+	ddi_quiesce_not_needed,	/* quiesce */
+};
+
+static struct modldrv modldrv = {
+	&mod_driverops,
+	"Generic Block Device",
+	&bd_dev_ops,
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1, { &modldrv, NULL }
+};
+
+static void *bd_state;
+static krwlock_t bd_lock;
+
+int
+_init(void)
+{
+	int	rv;
+
+	rv = ddi_soft_state_init(&bd_state, sizeof (struct bd), 2);
+	if (rv != DDI_SUCCESS) {
+		return (rv);
+	}
+	rw_init(&bd_lock, NULL, RW_DRIVER, NULL);
+	rv = mod_install(&modlinkage);
+	if (rv != DDI_SUCCESS) {
+		rw_destroy(&bd_lock);
+		ddi_soft_state_fini(&bd_state);
+	}
+	return (rv);
+}
+
+int
+_fini(void)
+{
+	int	rv;
+
+	rv = mod_remove(&modlinkage);
+	if (rv == DDI_SUCCESS) {
+		rw_destroy(&bd_lock);
+		ddi_soft_state_fini(&bd_state);
+	}
+	return (rv);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+static int
+bd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
+{
+	bd_t	*bd;
+	minor_t	inst;
+
+	_NOTE(ARGUNUSED(dip));
+
+	inst = BDINST((dev_t)arg);
+
+	switch (cmd) {
+	case DDI_INFO_DEVT2DEVINFO:
+		bd = ddi_get_soft_state(bd_state, inst);
+		if (bd == NULL) {
+			return (DDI_FAILURE);
+		}
+		*resultp = (void *)bd->d_dip;
+		break;
+
+	case DDI_INFO_DEVT2INSTANCE:
+		*resultp = (void *)(intptr_t)inst;
+		break;
+
+	default:
+		return (DDI_FAILURE);
+	}
+	return (DDI_SUCCESS);
+}
+
+static int
+bd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	int		inst;
+	bd_handle_t	hdl;
+	bd_t		*bd;
+	bd_drive_t	drive;
+	int		rv;
+	char		name[16];
+	char		kcache[32];
+
+	switch (cmd) {
+	case DDI_ATTACH:
+		break;
+	case DDI_RESUME:
+		/* We don't do anything native for suspend/resume */
+		return (DDI_SUCCESS);
+	default:
+		return (DDI_FAILURE);
+	}
+
+	inst = ddi_get_instance(dip);
+	hdl = ddi_get_parent_data(dip);
+
+	(void) snprintf(name, sizeof (name), "%s%d",
+	    ddi_driver_name(dip), ddi_get_instance(dip));
+	(void) snprintf(kcache, sizeof (kcache), "%s_xfer", name);
+
+	if (hdl == NULL) {
+		cmn_err(CE_WARN, "%s: missing parent data!", name);
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_soft_state_zalloc(bd_state, inst) != DDI_SUCCESS) {
+		cmn_err(CE_WARN, "%s: unable to zalloc soft state!", name);
+		return (DDI_FAILURE);
+	}
+	bd = ddi_get_soft_state(bd_state, inst);
+
+	if (hdl->h_dma) {
+		bd->d_dma = *(hdl->h_dma);
+		bd->d_dma.dma_attr_granular =
+		    max(DEV_BSIZE, bd->d_dma.dma_attr_granular);
+		bd->d_use_dma = B_TRUE;
+
+		if (bd->d_maxxfer &&
+		    (bd->d_maxxfer != bd->d_dma.dma_attr_maxxfer)) {
+			cmn_err(CE_WARN,
+			    "%s: inconsistent maximum transfer size!",
+			    name);
+			/* We force it */
+			bd->d_maxxfer = bd->d_dma.dma_attr_maxxfer;
+		} else {
+			bd->d_maxxfer = bd->d_dma.dma_attr_maxxfer;
+		}
+	} else {
+		bd->d_use_dma = B_FALSE;
+		if (bd->d_maxxfer == 0) {
+			bd->d_maxxfer = 1024 * 1024;
+		}
+	}
+	bd->d_ops = hdl->h_ops;
+	bd->d_private = hdl->h_private;
+	bd->d_blkshift = 9;	/* 512 bytes, to start */
+
+	if (bd->d_maxxfer % DEV_BSIZE) {
+		cmn_err(CE_WARN, "%s: maximum transfer misaligned!", name);
+		bd->d_maxxfer &= ~(DEV_BSIZE - 1);
+	}
+	if (bd->d_maxxfer < DEV_BSIZE) {
+		cmn_err(CE_WARN, "%s: maximum transfer size too small!", name);
+		ddi_soft_state_free(bd_state, inst);
+		return (DDI_FAILURE);
+	}
+
+	bd->d_dip = dip;
+	bd->d_handle = hdl;
+	hdl->h_bd = bd;
+	ddi_set_driver_private(dip, bd);
+
+	mutex_init(&bd->d_iomutex, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&bd->d_ocmutex, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&bd->d_statemutex, NULL, MUTEX_DRIVER, NULL);
+	cv_init(&bd->d_statecv, NULL, CV_DRIVER, NULL);
+
+	list_create(&bd->d_waitq, sizeof (bd_xfer_impl_t),
+	    offsetof(struct bd_xfer_impl, i_linkage));
+	list_create(&bd->d_runq, sizeof (bd_xfer_impl_t),
+	    offsetof(struct bd_xfer_impl, i_linkage));
+
+	bd->d_cache = kmem_cache_create(kcache, sizeof (bd_xfer_impl_t), 8,
+	    bd_xfer_ctor, bd_xfer_dtor, NULL, bd, NULL, 0);
+
+	bd->d_ksp = kstat_create(ddi_driver_name(dip), inst, NULL, "disk",
+	    KSTAT_TYPE_IO, 1, KSTAT_FLAG_PERSISTENT);
+	if (bd->d_ksp != NULL) {
+		bd->d_ksp->ks_lock = &bd->d_iomutex;
+		kstat_install(bd->d_ksp);
+		bd->d_kiop = bd->d_ksp->ks_data;
+	} else {
+		/*
+		 * Even if we cannot create the kstat, we create a
+		 * scratch kstat.  The reason for this is to ensure
+		 * that we can update the kstat all of the time,
+		 * without adding an extra branch instruction.
+		 */
+		bd->d_kiop = kmem_zalloc(sizeof (kstat_io_t), KM_SLEEP);
+	}
+
+	cmlb_alloc_handle(&bd->d_cmlbh);
+
+	bd->d_state = DKIO_NONE;
+
+	bzero(&drive, sizeof (drive));
+	bd->d_ops.o_drive_info(bd->d_private, &drive);
+	bd->d_qsize = drive.d_qsize;
+	bd->d_maxxfer = drive.d_maxxfer;
+	bd->d_removable = drive.d_removable;
+	bd->d_hotpluggable = drive.d_hotpluggable;
+
+	rv = cmlb_attach(dip, &bd_tg_ops, DTYPE_DIRECT,
+	    bd->d_removable, bd->d_hotpluggable,
+	    drive.d_lun >= 0 ? DDI_NT_BLOCK_CHAN : DDI_NT_BLOCK,
+	    CMLB_FAKE_LABEL_ONE_PARTITION, bd->d_cmlbh, bd);
+	if (rv != 0) {
+		cmlb_free_handle(&bd->d_cmlbh);
+		kmem_cache_destroy(bd->d_cache);
+		mutex_destroy(&bd->d_iomutex);
+		mutex_destroy(&bd->d_ocmutex);
+		mutex_destroy(&bd->d_statemutex);
+		cv_destroy(&bd->d_statecv);
+		list_destroy(&bd->d_waitq);
+		list_destroy(&bd->d_runq);
+		if (bd->d_ksp != NULL) {
+			kstat_delete(bd->d_ksp);
+			bd->d_ksp = NULL;
+		} else {
+			kmem_free(bd->d_kiop, sizeof (kstat_io_t));
+		}
+		ddi_soft_state_free(bd_state, inst);
+		return (DDI_FAILURE);
+	}
+
+	if (bd->d_ops.o_devid_init != NULL) {
+		rv = bd->d_ops.o_devid_init(bd->d_private, dip, &bd->d_devid);
+		if (rv == DDI_SUCCESS) {
+			if (ddi_devid_register(dip, bd->d_devid) !=
+			    DDI_SUCCESS) {
+				cmn_err(CE_WARN,
+				    "%s: unable to register devid", name);
+			}
+		}
+	}
+
+	/*
+	 * Add a zero-length attribute to tell the world we support
+	 * kernel ioctls (for layered drivers).  Also set up properties
+	 * used by HAL to identify removable media.
+	 */
+	(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
+	    DDI_KERNEL_IOCTL, NULL, 0);
+	if (bd->d_removable) {
+		(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
+		    "removable-media", NULL, 0);
+	}
+	if (bd->d_hotpluggable) {
+		(void) ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
+		    "hotpluggable", NULL, 0);
+	}
+
+	ddi_report_dev(dip);
+
+	return (DDI_SUCCESS);
+}
+
+static int
+bd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	bd_t	*bd;
+
+	bd = ddi_get_driver_private(dip);
+
+	switch (cmd) {
+	case DDI_DETACH:
+		break;
+	case DDI_SUSPEND:
+		/* We don't suspend, but our parent does */
+		return (DDI_SUCCESS);
+	default:
+		return (DDI_FAILURE);
+	}
+	if (bd->d_ksp != NULL) {
+		kstat_delete(bd->d_ksp);
+		bd->d_ksp = NULL;
+	} else {
+		kmem_free(bd->d_kiop, sizeof (kstat_io_t));
+	}
+	cmlb_detach(bd->d_cmlbh, bd);
+	cmlb_free_handle(&bd->d_cmlbh);
+	if (bd->d_devid)
+		ddi_devid_free(bd->d_devid);
+	kmem_cache_destroy(bd->d_cache);
+	mutex_destroy(&bd->d_iomutex);
+	mutex_destroy(&bd->d_ocmutex);
+	mutex_destroy(&bd->d_statemutex);
+	cv_destroy(&bd->d_statecv);
+	list_destroy(&bd->d_waitq);
+	list_destroy(&bd->d_runq);
+	ddi_soft_state_free(bd_state, ddi_get_instance(dip));
+	return (DDI_SUCCESS);
+}
+
+static int
+bd_xfer_ctor(void *buf, void *arg, int kmflag)
+{
+	bd_xfer_impl_t	*xi;
+	bd_t		*bd = arg;
+	int		(*dcb)(caddr_t);
+
+	if (kmflag == KM_SLEEP) {
+		dcb = DDI_DMA_SLEEP;
+	} else {
+		dcb = DDI_DMA_DONTWAIT;
+	}
+
+	xi = buf;
+	bzero(xi, sizeof (*xi));
+	xi->i_bd = bd;
+
+	if (bd->d_use_dma) {
+		if (ddi_dma_alloc_handle(bd->d_dip, &bd->d_dma, dcb, NULL,
+		    &xi->i_dmah) != DDI_SUCCESS) {
+			return (-1);
+		}
+	}
+
+	return (0);
+}
+
+static void
+bd_xfer_dtor(void *buf, void *arg)
+{
+	bd_xfer_impl_t	*xi = buf;
+
+	_NOTE(ARGUNUSED(arg));
+
+	if (xi->i_dmah)
+		ddi_dma_free_handle(&xi->i_dmah);
+	xi->i_dmah = NULL;
+}
+
+static bd_xfer_impl_t *
+bd_xfer_alloc(bd_t *bd, struct buf *bp, int (*func)(void *, bd_xfer_t *),
+    int kmflag)
+{
+	bd_xfer_impl_t		*xi;
+	int			rv;
+	int			status;
+	unsigned		dir;
+	int			(*cb)(caddr_t);
+	size_t			len;
+	uint32_t		shift;
+
+	if (kmflag == KM_SLEEP) {
+		cb = DDI_DMA_SLEEP;
+	} else {
+		cb = DDI_DMA_DONTWAIT;
+	}
+
+	xi = kmem_cache_alloc(bd->d_cache, kmflag);
+	if (xi == NULL) {
+		bioerror(bp, ENOMEM);
+		return (NULL);
+	}
+
+	ASSERT(bp);
+	ASSERT(bp->b_bcount);
+
+	xi->i_bp = bp;
+	xi->i_func = func;
+	xi->i_blkno = bp->b_lblkno;
+
+	if (bp->b_bcount == 0) {
+		xi->i_len = 0;
+		xi->i_nblks = 0;
+		xi->i_kaddr = NULL;
+		xi->i_resid = 0;
+		xi->i_num_win = 0;
+		goto done;
+	}
+
+	if (bp->b_flags & B_READ) {
+		dir = DDI_DMA_READ;
+		xi->i_func = bd->d_ops.o_read;
+	} else {
+		dir = DDI_DMA_WRITE;
+		xi->i_func = bd->d_ops.o_write;
+	}
+
+	shift = bd->d_blkshift;
+	xi->i_blkshift = shift;
+
+	if (!bd->d_use_dma) {
+		bp_mapin(bp);
+		rv = 0;
+		xi->i_offset = 0;
+		xi->i_num_win =
+		    (bp->b_bcount + (bd->d_maxxfer - 1)) / bd->d_maxxfer;
+		xi->i_cur_win = 0;
+		xi->i_len = min(bp->b_bcount, bd->d_maxxfer);
+		xi->i_nblks = xi->i_len >> shift;
+		xi->i_kaddr = bp->b_un.b_addr;
+		xi->i_resid = bp->b_bcount;
+	} else {
+
+		/*
+		 * We have to use consistent DMA if the address is misaligned.
+		 */
+		if (((bp->b_flags & (B_PAGEIO | B_REMAPPED)) != B_PAGEIO) &&
+		    ((uintptr_t)bp->b_un.b_addr & 0x7)) {
+			dir |= DDI_DMA_CONSISTENT | DDI_DMA_PARTIAL;
+		} else {
+			dir |= DDI_DMA_STREAMING | DDI_DMA_PARTIAL;
+		}
+
+		status = ddi_dma_buf_bind_handle(xi->i_dmah, bp, dir, cb,
+		    NULL, &xi->i_dmac, &xi->i_ndmac);
+		switch (status) {
+		case DDI_DMA_MAPPED:
+			xi->i_num_win = 1;
+			xi->i_cur_win = 0;
+			xi->i_offset = 0;
+			xi->i_len = bp->b_bcount;
+			xi->i_nblks = xi->i_len >> shift;
+			xi->i_resid = bp->b_bcount;
+			rv = 0;
+			break;
+		case DDI_DMA_PARTIAL_MAP:
+			xi->i_cur_win = 0;
+
+			if ((ddi_dma_numwin(xi->i_dmah, &xi->i_num_win) !=
+			    DDI_SUCCESS) ||
+			    (ddi_dma_getwin(xi->i_dmah, 0, &xi->i_offset,
+			    &len, &xi->i_dmac, &xi->i_ndmac) !=
+			    DDI_SUCCESS) ||
+			    (P2PHASE(len, shift) != 0)) {
+				(void) ddi_dma_unbind_handle(xi->i_dmah);
+				rv = EFAULT;
+				goto done;
+			}
+			xi->i_len = len;
+			xi->i_nblks = xi->i_len >> shift;
+			xi->i_resid = bp->b_bcount;
+			rv = 0;
+			break;
+		case DDI_DMA_NORESOURCES:
+			rv = EAGAIN;
+			goto done;
+		case DDI_DMA_TOOBIG:
+			rv = EINVAL;
+			goto done;
+		case DDI_DMA_NOMAPPING:
+		case DDI_DMA_INUSE:
+		default:
+			rv = EFAULT;
+			goto done;
+		}
+	}
+
+done:
+	if (rv != 0) {
+		kmem_cache_free(bd->d_cache, xi);
+		bioerror(bp, rv);
+		return (NULL);
+	}
+
+	return (xi);
+}
+
+static void
+bd_xfer_free(bd_xfer_impl_t *xi)
+{
+	if (xi->i_dmah) {
+		(void) ddi_dma_unbind_handle(xi->i_dmah);
+	}
+	kmem_cache_free(xi->i_bd->d_cache, xi);
+}
+
+static int
+bd_open(dev_t *devp, int flag, int otyp, cred_t *credp)
+{
+	dev_t		dev = *devp;
+	bd_t		*bd;
+	minor_t		part;
+	minor_t		inst;
+	uint64_t	mask;
+	boolean_t	ndelay;
+	int		rv;
+	diskaddr_t	nblks;
+	diskaddr_t	lba;
+
+	_NOTE(ARGUNUSED(credp));
+
+	part = BDPART(dev);
+	inst = BDINST(dev);
+
+	if (otyp >= OTYPCNT)
+		return (EINVAL);
+
+	ndelay = (flag & (FNDELAY | FNONBLOCK)) ? B_TRUE : B_FALSE;
+
+	/*
+	 * Block any DR events from changing the set of registered
+	 * devices while we function.
+	 */
+	rw_enter(&bd_lock, RW_READER);
+	if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
+		rw_exit(&bd_lock);
+		return (ENXIO);
+	}
+
+	mutex_enter(&bd->d_ocmutex);
+
+	ASSERT(part < 64);
+	mask = (1U << part);
+
+	bd_update_state(bd);
+
+	if (cmlb_validate(bd->d_cmlbh, 0, bd) != 0) {
+
+		/* non-blocking opens are allowed to succeed */
+		if (!ndelay) {
+			rv = ENXIO;
+			goto done;
+		}
+	} else if (cmlb_partinfo(bd->d_cmlbh, part, &nblks, &lba,
+	    NULL, NULL, bd) == 0) {
+
+		/*
+		 * We read the partinfo, verify valid ranges.  If the
+		 * partition is invalid, and we aren't blocking or
+		 * doing a raw access, then fail. (Non-blocking and
+		 * raw accesses can still succeed to allow a disk with
+		 * bad partition data to opened by format and fdisk.)
+		 */
+		if ((!nblks) && ((!ndelay) || (otyp != OTYP_CHR))) {
+			rv = ENXIO;
+			goto done;
+		}
+	} else if (!ndelay) {
+		/*
+		 * cmlb_partinfo failed -- invalid partition or no
+		 * disk label.
+		 */
+		rv = ENXIO;
+		goto done;
+	}
+
+	if ((flag & FWRITE) && bd->d_rdonly) {
+		rv = EROFS;
+		goto done;
+	}
+
+	if ((bd->d_open_excl) & (mask)) {
+		rv = EBUSY;
+		goto done;
+	}
+	if (flag & FEXCL) {
+		if (bd->d_open_lyr[part]) {
+			rv = EBUSY;
+			goto done;
+		}
+		for (int i = 0; i < OTYP_LYR; i++) {
+			if (bd->d_open_reg[i] & mask) {
+				rv = EBUSY;
+				goto done;
+			}
+		}
+	}
+
+	if (otyp == OTYP_LYR) {
+		bd->d_open_lyr[part]++;
+	} else {
+		bd->d_open_reg[otyp] |= mask;
+	}
+	if (flag & FEXCL) {
+		bd->d_open_excl |= mask;
+	}
+
+	rv = 0;
+done:
+	mutex_exit(&bd->d_ocmutex);
+	rw_exit(&bd_lock);
+
+	return (rv);
+}
+
+static int
+bd_close(dev_t dev, int flag, int otyp, cred_t *credp)
+{
+	bd_t		*bd;
+	minor_t		inst;
+	minor_t		part;
+	uint64_t	mask;
+	boolean_t	last = B_TRUE;
+
+	_NOTE(ARGUNUSED(flag));
+	_NOTE(ARGUNUSED(credp));
+
+	part = BDPART(dev);
+	inst = BDINST(dev);
+
+	ASSERT(part < 64);
+	mask = (1U << part);
+
+	rw_enter(&bd_lock, RW_READER);
+
+	if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
+		rw_exit(&bd_lock);
+		return (ENXIO);
+	}
+
+	mutex_enter(&bd->d_ocmutex);
+	if (bd->d_open_excl & mask) {
+		bd->d_open_excl &= ~mask;
+	}
+	if (otyp == OTYP_LYR) {
+		bd->d_open_lyr[part]--;
+	} else {
+		bd->d_open_reg[otyp] &= ~mask;
+	}
+	for (int i = 0; i < 64; i++) {
+		if (bd->d_open_lyr[part]) {
+			last = B_FALSE;
+		}
+	}
+	for (int i = 0; last && (i < OTYP_LYR); i++) {
+		if (bd->d_open_reg[i]) {
+			last = B_FALSE;
+		}
+	}
+	mutex_exit(&bd->d_ocmutex);
+
+	if (last) {
+		cmlb_invalidate(bd->d_cmlbh, bd);
+	}
+	rw_exit(&bd_lock);
+
+	return (0);
+}
+
+static int
+bd_read(dev_t dev, struct uio *uio, cred_t *credp)
+{
+	_NOTE(ARGUNUSED(credp));
+	return (physio(bd_strategy, NULL, dev, B_READ, minphys, uio));
+}
+
+static int
+bd_write(dev_t dev, struct uio *uio, cred_t *credp)
+{
+	_NOTE(ARGUNUSED(credp));
+	return (physio(bd_strategy, NULL, dev, B_WRITE, minphys, uio));
+}
+
+static int
+bd_aread(dev_t dev, struct aio_req *aio, cred_t *credp)
+{
+	_NOTE(ARGUNUSED(credp));
+	return (aphysio(bd_strategy, anocancel, dev, B_READ, minphys, aio));
+}
+
+static int
+bd_awrite(dev_t dev, struct aio_req *aio, cred_t *credp)
+{
+	_NOTE(ARGUNUSED(credp));
+	return (aphysio(bd_strategy, anocancel, dev, B_WRITE, minphys, aio));
+}
+
+static int
+bd_strategy(struct buf *bp)
+{
+	minor_t		inst;
+	minor_t		part;
+	bd_t		*bd;
+	diskaddr_t	p_lba;
+	diskaddr_t	p_nblks;
+	diskaddr_t	b_nblks;
+	bd_xfer_impl_t	*xi;
+	uint32_t	shift;
+	int		(*func)(void *, bd_xfer_t *);
+
+	part = BDPART(bp->b_edev);
+	inst = BDINST(bp->b_edev);
+
+	ASSERT(bp);
+
+	bp->b_resid = bp->b_bcount;
+
+	if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
+		bioerror(bp, ENXIO);
+		biodone(bp);
+		return (0);
+	}
+
+	if (cmlb_partinfo(bd->d_cmlbh, part, &p_nblks, &p_lba,
+	    NULL, NULL, bd)) {
+		bioerror(bp, ENXIO);
+		biodone(bp);
+		return (0);
+	}
+
+	shift = bd->d_blkshift;
+
+	if ((P2PHASE(bp->b_bcount, (1U << shift)) != 0) ||
+	    (bp->b_lblkno > p_nblks)) {
+		bioerror(bp, ENXIO);
+		biodone(bp);
+		return (0);
+	}
+	b_nblks = bp->b_bcount >> shift;
+	if ((bp->b_lblkno == p_nblks) || (bp->b_bcount == 0)) {
+		biodone(bp);
+		return (0);
+	}
+
+	if ((b_nblks + bp->b_lblkno) > p_nblks) {
+		bp->b_resid = ((bp->b_lblkno + b_nblks - p_nblks) << shift);
+		bp->b_bcount -= bp->b_resid;
+	} else {
+		bp->b_resid = 0;
+	}
+	func = (bp->b_flags & B_READ) ? bd->d_ops.o_read : bd->d_ops.o_write;
+
+	xi = bd_xfer_alloc(bd, bp, func, KM_NOSLEEP);
+	if (xi == NULL) {
+		xi = bd_xfer_alloc(bd, bp, func, KM_PUSHPAGE);
+	}
+	if (xi == NULL) {
+		/* bd_request_alloc will have done bioerror */
+		biodone(bp);
+		return (0);
+	}
+	xi->i_blkno = bp->b_lblkno + p_lba;
+
+	bd_submit(bd, xi);
+
+	return (0);
+}
+
+static int
+bd_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp)
+{
+	minor_t		inst;
+	uint16_t	part;
+	bd_t		*bd;
+	void		*ptr = (void *)arg;
+	int		rv;
+
+	part = BDPART(dev);
+	inst = BDINST(dev);
+
+	if ((bd = ddi_get_soft_state(bd_state, inst)) == NULL) {
+		return (ENXIO);
+	}
+
+	rv = cmlb_ioctl(bd->d_cmlbh, dev, cmd, arg, flag, credp, rvalp, bd);
+	if (rv != ENOTTY)
+		return (rv);
+
+	switch (cmd) {
+	case DKIOCGMEDIAINFO: {
+		struct dk_minfo minfo;
+
+		/* make sure our state information is current */
+		bd_update_state(bd);
+		bzero(&minfo, sizeof (minfo));
+		minfo.dki_media_type = DK_FIXED_DISK;
+		minfo.dki_lbsize = (1U << bd->d_blkshift);
+		minfo.dki_capacity = bd->d_numblks;
+		if (ddi_copyout(&minfo, ptr, sizeof (minfo), flag))  {
+			return (EFAULT);
+		}
+		return (0);
+	}
+	case DKIOCINFO: {
+		struct dk_cinfo cinfo;
+		bzero(&cinfo, sizeof (cinfo));
+		cinfo.dki_ctype = DKC_BLKDEV;
+		cinfo.dki_cnum = ddi_get_instance(ddi_get_parent(bd->d_dip));
+		(void) snprintf(cinfo.dki_cname, sizeof (cinfo.dki_cname),
+		    "%s", ddi_driver_name(ddi_get_parent(bd->d_dip)));
+		(void) snprintf(cinfo.dki_dname, sizeof (cinfo.dki_dname),
+		    "%s", ddi_driver_name(bd->d_dip));
+		cinfo.dki_unit = inst;
+		cinfo.dki_flags = DKI_FMTVOL;
+		cinfo.dki_partition = part;
+		cinfo.dki_maxtransfer = bd->d_maxxfer / DEV_BSIZE;
+		cinfo.dki_addr = 0;
+		cinfo.dki_slave = 0;
+		cinfo.dki_space = 0;
+		cinfo.dki_prio = 0;
+		cinfo.dki_vec = 0;
+		if (ddi_copyout(&cinfo, ptr, sizeof (cinfo), flag))  {
+			return (EFAULT);
+		}
+		return (0);
+	}
+	case DKIOCREMOVABLE: {
+		int i;
+		i = bd->d_removable ? 1 : 0;
+		if (ddi_copyout(&i, ptr, sizeof (i), flag)) {
+			return (EFAULT);
+		}
+		return (0);
+	}
+	case DKIOCHOTPLUGGABLE: {
+		int i;
+		i = bd->d_hotpluggable ? 1 : 0;
+		if (ddi_copyout(&i, ptr, sizeof (i), flag)) {
+			return (EFAULT);
+		}
+		return (0);
+	}
+	case DKIOCREADONLY: {
+		int i;
+		i = bd->d_rdonly ? 1 : 0;
+		if (ddi_copyout(&i, ptr, sizeof (i), flag)) {
+			return (EFAULT);
+		}
+		return (0);
+	}
+	case DKIOCSTATE: {
+		enum dkio_state	state;
+		if (ddi_copyin(ptr, &state, sizeof (state), flag)) {
+			return (EFAULT);
+		}
+		if ((rv = bd_check_state(bd, &state)) != 0) {
+			return (rv);
+		}
+		if (ddi_copyout(&state, ptr, sizeof (state), flag)) {
+			return (EFAULT);
+		}
+		return (0);
+	}
+	case DKIOCFLUSHWRITECACHE: {
+		struct dk_callback *dkc;
+
+		dkc = flag & FKIOCTL ? (void *)arg : NULL;
+		rv = bd_flush_write_cache(bd, dkc);
+		return (rv);
+	}
+
+	default:
+		break;
+
+	}
+	return (ENOTTY);
+}
+
+static int
+bd_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
+    char *name, caddr_t valuep, int *lengthp)
+{
+	bd_t	*bd;
+
+	bd = ddi_get_soft_state(bd_state, ddi_get_instance(dip));
+	if (bd == NULL)
+		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
+		    name, valuep, lengthp));
+
+	return (cmlb_prop_op(bd->d_cmlbh, dev, dip, prop_op, mod_flags, name,
+	    valuep, lengthp, BDPART(dev), bd));
+}
+
+
+static int
+bd_tg_rdwr(dev_info_t *dip, uchar_t cmd, void *bufaddr, diskaddr_t start,
+    size_t length, void *tg_cookie)
+{
+	bd_t		*bd;
+	buf_t		*bp;
+	bd_xfer_impl_t	*xi;
+	int		rv;
+	int		(*func)(void *, bd_xfer_t *);
+
+	_NOTE(ARGUNUSED(dip));
+
+
+	bd = tg_cookie;
+	if (P2PHASE(length, (1U << bd->d_blkshift)) != 0) {
+		/* We can only transfer whole blocks at a time! */
+		return (EINVAL);
+	}
+
+	bp = getrbuf(KM_SLEEP);
+
+	switch (cmd) {
+	case TG_READ:
+		bp->b_flags = B_READ;
+		func = bd->d_ops.o_read;
+		break;
+	case TG_WRITE:
+		bp->b_flags = B_WRITE;
+		func = bd->d_ops.o_write;
+		break;
+	default:
+		freerbuf(bp);
+		return (EINVAL);
+	}
+
+	bp->b_un.b_addr = bufaddr;
+	bp->b_bcount = length;
+	xi = bd_xfer_alloc(bd, bp, func, KM_SLEEP);
+	if (xi == NULL) {
+		rv = geterror(bp);
+		freerbuf(bp);
+		return (rv);
+	}
+
+	xi->i_blkno = start;
+	bd_submit(bd, xi);
+	(void) biowait(bp);
+	rv = geterror(bp);
+	freerbuf(bp);
+
+	return (rv);
+}
+
+static int
+bd_tg_getinfo(dev_info_t *dip, int cmd, void *arg, void *tg_cookie)
+{
+	bd_t		*bd;
+
+	_NOTE(ARGUNUSED(dip));
+	bd = tg_cookie;
+
+	switch (cmd) {
+	case TG_GETPHYGEOM:
+	case TG_GETVIRTGEOM:
+		/*
+		 * We don't have any "geometry" as such, let cmlb
+		 * fabricate something.
+		 */
+		return (ENOTTY);
+
+	case TG_GETCAPACITY:
+		bd_update_state(bd);
+		*(diskaddr_t *)arg = bd->d_numblks;
+		return (0);
+
+	case TG_GETBLOCKSIZE:
+		*(uint32_t *)arg = (1U << bd->d_blkshift);
+		return (0);
+
+	case TG_GETATTR:
+		/*
+		 * It turns out that cmlb really doesn't do much for
+		 * non-writable media, but lets make the information
+		 * available for it in case it does more in the
+		 * future.  (The value is currently used for
+		 * triggering special behavior for CD-ROMs.)
+		 */
+		bd_update_state(bd);
+		((tg_attribute_t *)arg)->media_is_writable =
+		    bd->d_rdonly ? B_FALSE : B_TRUE;
+		return (0);
+
+	default:
+		return (EINVAL);
+	}
+}
+
+
+static void
+bd_sched(bd_t *bd)
+{
+	bd_xfer_impl_t	*xi;
+	struct buf	*bp;
+	int		rv;
+
+	ASSERT(mutex_owned(&bd->d_iomutex));
+
+	while ((bd->d_qactive < bd->d_qsize) &&
+	    ((xi = list_remove_head(&bd->d_waitq)) != NULL)) {
+		bd->d_qactive++;
+		kstat_waitq_to_runq(bd->d_kiop);
+		list_insert_tail(&bd->d_runq, xi);
+
+		/* Submit the job to driver */
+		rv = xi->i_func(bd->d_private, &xi->i_public);
+		if (rv != 0) {
+			bd->d_qactive--;
+			kstat_runq_exit(bd->d_kiop);
+			list_remove(&bd->d_runq, xi);
+
+			mutex_exit(&bd->d_iomutex);
+			bp = xi->i_bp;
+			bd_xfer_free(xi);
+			bioerror(bp, rv);
+			biodone(bp);
+			mutex_enter(&bd->d_iomutex);
+		}
+	}
+}
+
+static void
+bd_submit(bd_t *bd, bd_xfer_impl_t *xi)
+{
+	mutex_enter(&bd->d_iomutex);
+	list_insert_tail(&bd->d_waitq, xi);
+	kstat_waitq_enter(bd->d_kiop);
+	bd_sched(bd);
+	mutex_exit(&bd->d_iomutex);
+}
+
+static void
+bd_runq_exit(bd_xfer_impl_t *xi, int err)
+{
+	bd_t	*bd = xi->i_bd;
+	buf_t	*bp = xi->i_bp;
+
+	ASSERT(mutex_owned(&bd->d_iomutex));
+
+	bd->d_qactive--;
+	kstat_runq_exit(bd->d_kiop);
+	if (err == 0) {
+		if (bp->b_flags & B_READ) {
+			bd->d_kiop->reads++;
+			bd->d_kiop->nread += (bp->b_bcount - xi->i_resid);
+		} else {
+			bd->d_kiop->writes++;
+			bd->d_kiop->nwritten += (bp->b_bcount - xi->i_resid);
+		}
+	}
+	list_remove(&bd->d_runq, xi);
+	bd_sched(bd);
+}
+
+static void
+bd_update_state(bd_t *bd)
+{
+	enum	dkio_state	state;
+	bd_media_t		media;
+	boolean_t		docmlb = B_FALSE;
+
+	bzero(&media, sizeof (media));
+
+	mutex_enter(&bd->d_statemutex);
+	if (bd->d_ops.o_media_info(bd->d_private, &media) == 0) {
+		if ((1U << bd->d_blkshift) != media.m_blksize) {
+			if ((media.m_blksize < 512) ||
+			    (!ISP2(media.m_blksize)) ||
+			    (P2PHASE(bd->d_maxxfer, media.m_blksize))) {
+				cmn_err(CE_WARN,
+				    "%s%d: Invalid media block size (%d)",
+				    ddi_driver_name(bd->d_dip),
+				    ddi_get_instance(bd->d_dip),
+				    media.m_blksize);
+				/*
+				 * We can't use the media, treat it as
+				 * not present.
+				 */
+				state = DKIO_EJECTED;
+				bd->d_numblks = 0;
+			} else {
+				bd->d_blkshift = ddi_ffs(media.m_blksize) - 1;
+				bd->d_numblks = media.m_nblks;
+				bd->d_rdonly = media.m_readonly;
+				state = DKIO_INSERTED;
+			}
+
+			/* Device size changed */
+			docmlb = B_TRUE;
+
+		} else {
+			if (bd->d_numblks != media.m_nblks) {
+				/* Device size changed */
+				docmlb = B_TRUE;
+			}
+			bd->d_numblks = media.m_nblks;
+			bd->d_rdonly = media.m_readonly;
+			state = DKIO_INSERTED;
+		}
+
+	} else {
+		bd->d_numblks = 0;
+		state = DKIO_EJECTED;
+	}
+	if (state != bd->d_state) {
+		bd->d_state = state;
+		cv_broadcast(&bd->d_statecv);
+		docmlb = B_TRUE;
+	}
+	mutex_exit(&bd->d_statemutex);
+
+	if (docmlb) {
+		if (state == DKIO_INSERTED) {
+			(void) cmlb_validate(bd->d_cmlbh, 0, bd);
+		} else {
+			cmlb_invalidate(bd->d_cmlbh, bd);
+		}
+	}
+}
+
+static int
+bd_check_state(bd_t *bd, enum dkio_state *state)
+{
+	clock_t		when;
+
+	for (;;) {
+
+		bd_update_state(bd);
+
+		mutex_enter(&bd->d_statemutex);
+
+		if (bd->d_state != *state) {
+			*state = bd->d_state;
+			mutex_exit(&bd->d_statemutex);
+			break;
+		}
+
+		when = drv_usectohz(1000000);
+		if (cv_reltimedwait_sig(&bd->d_statecv, &bd->d_statemutex,
+		    when, TR_CLOCK_TICK) == 0) {
+			mutex_exit(&bd->d_statemutex);
+			return (EINTR);
+		}
+
+		mutex_exit(&bd->d_statemutex);
+	}
+
+	return (0);
+}
+
+static int
+bd_flush_write_cache_done(struct buf *bp)
+{
+	struct dk_callback *dc = (void *)bp->b_private;
+
+	(*dc->dkc_callback)(dc->dkc_cookie, geterror(bp));
+	kmem_free(dc, sizeof (*dc));
+	freerbuf(bp);
+	return (0);
+}
+
+static int
+bd_flush_write_cache(bd_t *bd, struct dk_callback *dkc)
+{
+	buf_t			*bp;
+	struct dk_callback	*dc;
+	bd_xfer_impl_t		*xi;
+	int			rv;
+
+	if (bd->d_ops.o_sync_cache == NULL) {
+		return (ENOTSUP);
+	}
+	if ((bp = getrbuf(KM_SLEEP)) == NULL) {
+		return (ENOMEM);
+	}
+	bp->b_resid = 0;
+	bp->b_bcount = 0;
+
+	xi = bd_xfer_alloc(bd, bp, bd->d_ops.o_sync_cache, KM_SLEEP);
+	if (xi == NULL) {
+		rv = geterror(bp);
+		freerbuf(bp);
+		return (rv);
+	}
+
+	if (dkc != NULL) {
+		/* Make a private copy of the callback structure */
+		dc = kmem_alloc(sizeof (*dc), KM_SLEEP);
+		*dc = *dkc;
+		bp->b_private = dc;
+		bp->b_iodone = bd_flush_write_cache_done;
+	}
+
+	bd_submit(bd, xi);
+	if (dkc == NULL) {
+		/* wait synchronously */
+		(void) biowait(bp);
+		rv = geterror(bp);
+		freerbuf(bp);
+	} else {
+		/* deferred via callback */
+		rv = 0;
+	}
+	return (rv);
+}
+
+/*
+ * Nexus support.
+ */
+int
+bd_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
+    void *arg, void *result)
+{
+	bd_handle_t	hdl;
+
+	switch (ctlop) {
+	case DDI_CTLOPS_REPORTDEV:
+		cmn_err(CE_CONT, "?Block device: %s@%s, %s%d\n",
+		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
+		    ddi_driver_name(rdip), ddi_get_instance(rdip));
+		return (DDI_SUCCESS);
+
+	case DDI_CTLOPS_INITCHILD:
+		hdl = ddi_get_parent_data((dev_info_t *)arg);
+		if (hdl == NULL) {
+			return (DDI_NOT_WELL_FORMED);
+		}
+		ddi_set_name_addr((dev_info_t *)arg, hdl->h_addr);
+		return (DDI_SUCCESS);
+
+	case DDI_CTLOPS_UNINITCHILD:
+		ddi_set_name_addr((dev_info_t *)arg, NULL);
+		ndi_prop_remove_all((dev_info_t *)arg);
+		return (DDI_SUCCESS);
+
+	default:
+		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
+	}
+}
+
+/*
+ * Functions for device drivers.
+ */
+bd_handle_t
+bd_alloc_handle(void *private, bd_ops_t *ops, ddi_dma_attr_t *dma, int kmflag)
+{
+	bd_handle_t	hdl;
+
+	hdl = kmem_zalloc(sizeof (*hdl), kmflag);
+	if (hdl != NULL) {
+		hdl->h_ops = *ops;
+		hdl->h_dma = dma;
+		hdl->h_private = private;
+	}
+
+	return (hdl);
+}
+
+void
+bd_free_handle(bd_handle_t hdl)
+{
+	kmem_free(hdl, sizeof (*hdl));
+}
+
+int
+bd_attach_handle(dev_info_t *dip, bd_handle_t hdl)
+{
+	dev_info_t	*child;
+	bd_drive_t	drive;
+
+	/* if drivers don't override this, make it assume none */
+	drive.d_lun = -1;
+	hdl->h_ops.o_drive_info(hdl->h_private, &drive);
+
+	hdl->h_parent = dip;
+	hdl->h_name = "blkdev";
+
+	if (drive.d_lun >= 0) {
+		(void) snprintf(hdl->h_addr, sizeof (hdl->h_addr), "%X,%X",
+		    drive.d_target, drive.d_lun);
+	} else {
+		(void) snprintf(hdl->h_addr, sizeof (hdl->h_addr), "%X",
+		    drive.d_target);
+	}
+	if (ndi_devi_alloc(dip, hdl->h_name, (pnode_t)DEVI_SID_NODEID,
+	    &child) != NDI_SUCCESS) {
+		cmn_err(CE_WARN, "%s%d: unable to allocate node %s@%s",
+		    ddi_driver_name(dip), ddi_get_instance(dip),
+		    "blkdev", hdl->h_addr);
+		return (DDI_FAILURE);
+	}
+
+	ddi_set_parent_data(child, hdl);
+	hdl->h_child = child;
+
+	if (ndi_devi_online(child, 0) == NDI_FAILURE) {
+		cmn_err(CE_WARN, "%s%d: failed bringing node %s@%s online",
+		    ddi_driver_name(dip), ddi_get_instance(dip),
+		    hdl->h_name, hdl->h_addr);
+		(void) ndi_devi_free(child);
+		return (DDI_FAILURE);
+	}
+
+	return (DDI_SUCCESS);
+}
+
+int
+bd_detach_handle(bd_handle_t hdl)
+{
+	int	circ;
+	int	rv;
+	char	*devnm;
+
+	if (hdl->h_child == NULL) {
+		return (DDI_SUCCESS);
+	}
+	ndi_devi_enter(hdl->h_parent, &circ);
+	if (i_ddi_node_state(hdl->h_child) < DS_INITIALIZED) {
+		rv = ddi_remove_child(hdl->h_child, 0);
+	} else {
+		devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
+		(void) ddi_deviname(hdl->h_child, devnm);
+		(void) devfs_clean(hdl->h_parent, devnm + 1, DV_CLEAN_FORCE);
+		rv = ndi_devi_unconfig_one(hdl->h_parent, devnm + 1, NULL,
+		    NDI_DEVI_REMOVE | NDI_UNCONFIG);
+		kmem_free(devnm, MAXNAMELEN + 1);
+	}
+	if (rv == 0) {
+		hdl->h_child = NULL;
+	}
+
+	ndi_devi_exit(hdl->h_parent, circ);
+	return (rv = NDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
+}
+
+void
+bd_xfer_done(bd_xfer_t *xfer, int err)
+{
+	bd_xfer_impl_t	*xi = (void *)xfer;
+	buf_t		*bp = xi->i_bp;
+	int		rv;
+	bd_t		*bd = xi->i_bd;
+	size_t		len;
+
+	mutex_enter(&bd->d_iomutex);
+	if (err != 0) {
+		bd_runq_exit(xi, err);
+		mutex_exit(&bd->d_iomutex);
+
+		bp->b_resid += xi->i_resid;
+		bd_xfer_free(xi);
+		bioerror(bp, err);
+		biodone(bp);
+		return;
+	}
+
+	xi->i_cur_win++;
+	xi->i_resid -= xi->i_len;
+
+	if (xi->i_resid == 0) {
+		/* Job completed succcessfully! */
+		bd_runq_exit(xi, 0);
+		mutex_exit(&bd->d_iomutex);
+
+		bd_xfer_free(xi);
+		biodone(bp);
+		return;
+	}
+
+	xi->i_blkno += xi->i_nblks;
+
+	if (bd->d_use_dma) {
+		/* More transfer still pending... advance to next DMA window. */
+		rv = ddi_dma_getwin(xi->i_dmah, xi->i_cur_win,
+		    &xi->i_offset, &len, &xi->i_dmac, &xi->i_ndmac);
+	} else {
+		/* Advance memory window. */
+		xi->i_kaddr += xi->i_len;
+		xi->i_offset += xi->i_len;
+		len = min(bp->b_bcount - xi->i_offset, bd->d_maxxfer);
+	}
+
+
+	if ((rv != DDI_SUCCESS) ||
+	    (P2PHASE(len, (1U << xi->i_blkshift) != 0))) {
+		bd_runq_exit(xi, EFAULT);
+		mutex_exit(&bd->d_iomutex);
+
+		bp->b_resid += xi->i_resid;
+		bd_xfer_free(xi);
+		bioerror(bp, EFAULT);
+		biodone(bp);
+		return;
+	}
+	xi->i_len = len;
+	xi->i_nblks = len >> xi->i_blkshift;
+
+	/* Submit next window to hardware. */
+	rv = xi->i_func(bd->d_private, &xi->i_public);
+	if (rv != 0) {
+		bd_runq_exit(xi, rv);
+		mutex_exit(&bd->d_iomutex);
+
+		bp->b_resid += xi->i_resid;
+		bd_xfer_free(xi);
+		bioerror(bp, rv);
+		biodone(bp);
+		return;
+	}
+
+	mutex_exit(&bd->d_iomutex);
+}
+
+void
+bd_state_change(bd_handle_t hdl)
+{
+	bd_t		*bd;
+
+	if ((bd = hdl->h_bd) != NULL) {
+		bd_update_state(bd);
+	}
+}
+
+void
+bd_mod_init(struct dev_ops *devops)
+{
+	static struct bus_ops bd_bus_ops = {
+		BUSO_REV,		/* busops_rev */
+		nullbusmap,		/* bus_map */
+		NULL,			/* bus_get_intrspec (OBSOLETE) */
+		NULL,			/* bus_add_intrspec (OBSOLETE) */
+		NULL,			/* bus_remove_intrspec (OBSOLETE) */
+		i_ddi_map_fault,	/* bus_map_fault */
+		ddi_dma_map,		/* bus_dma_map */
+		ddi_dma_allochdl,	/* bus_dma_allochdl */
+		ddi_dma_freehdl,	/* bus_dma_freehdl */
+		ddi_dma_bindhdl,	/* bus_dma_bindhdl */
+		ddi_dma_unbindhdl,	/* bus_dma_unbindhdl */
+		ddi_dma_flush,		/* bus_dma_flush */
+		ddi_dma_win,		/* bus_dma_win */
+		ddi_dma_mctl,		/* bus_dma_ctl */
+		bd_bus_ctl,		/* bus_ctl */
+		ddi_bus_prop_op,	/* bus_prop_op */
+		NULL,			/* bus_get_eventcookie */
+		NULL,			/* bus_add_eventcall */
+		NULL,			/* bus_remove_eventcall */
+		NULL,			/* bus_post_event */
+		NULL,			/* bus_intr_ctl (OBSOLETE) */
+		NULL,			/* bus_config */
+		NULL,			/* bus_unconfig */
+		NULL,			/* bus_fm_init */
+		NULL,			/* bus_fm_fini */
+		NULL,			/* bus_fm_access_enter */
+		NULL,			/* bus_fm_access_exit */
+		NULL,			/* bus_power */
+		NULL,			/* bus_intr_op */
+	};
+
+	devops->devo_bus_ops = &bd_bus_ops;
+
+	/*
+	 * NB: The device driver is free to supply its own
+	 * character entry device support.
+	 */
+}
+
+void
+bd_mod_fini(struct dev_ops *devops)
+{
+	devops->devo_bus_ops = NULL;
+}
--- a/usr/src/uts/common/io/scsi/adapters/blk2scsa/blk2scsa.c	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2005 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#include <sys/types.h>
-#include <sys/ksynch.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/note.h>
-#include <sys/scsi/scsi.h>
-#include <sys/scsi/adapters/blk2scsa.h>
-
-/*
- * We implement the following SCSI-2 commands on behalf of targets:
- *
- * SCMD_DOORLOCK
- * SCMD_FORMAT
- * SCMD_INQUIRY
- * SCMD_MODE_SENSE
- * SCMD_READ
- * SCMD_READ_G1
- * SCMD_READ_CAPACITY
- * SCMD_RELEASE
- * SCMD_REQUEST_SENSE
- * SCMD_RESERVE
- * SCMD_SDIAG
- * SCMD_START_STOP
- * SCMD_TEST_UNIT_READY
- * SCMD_WRITE
- * SCMD_WRITE_G1
- *
- * We really should, at some point in the future, investigate offering
- * more complete SCSI-3 commands, including the G4 and G5 variants of
- * READ and WRITE, MODE_SELECT, PERSISTENT_RESERVE_IN,
- * PERSISTENT_RESERVE_OUT, SYNCHRONIZE_CACHE, READ_MEDIAL_SERIAL,
- * REPORT_LUNS, etc.
- */
-
-typedef struct b2s_request_impl b2s_request_impl_t;
-
-struct b2s_request_impl {
-	b2s_request_t		ri_public;
-	struct scsi_pkt		*ri_pkt;
-	struct scsi_arq_status	*ri_sts;
-	buf_t			*ri_bp;
-
-	size_t			ri_resid;
-	b2s_nexus_t		*ri_nexus;
-	b2s_leaf_t		*ri_leaf;
-	void			(*ri_done)(struct b2s_request_impl *);
-};
-
-#define	ri_lun		ri_public.br_lun
-#define	ri_target	ri_public.br_target
-#define	ri_cmd		ri_public.br_cmd
-#define	ri_errno	ri_public.br_errno
-#define	ri_count	ri_public.br_count
-#define	ri_xfered	ri_public.br_xfered
-
-#define	ri_flags	ri_public.br_flags
-#define	ri_media	ri_public.br_media
-#define	ri_inquiry	ri_public.br_inquiry
-#define	ri_lba		ri_public.br_lba
-#define	ri_nblks	ri_public.br_nblks
-
-struct b2s_nexus {
-	dev_info_t		*n_dip;
-	struct scsi_hba_tran	*n_tran;
-	void			*n_private;
-	ddi_dma_attr_t		*n_dma;
-	boolean_t		(*n_request)(void *, b2s_request_t *);
-
-	kmutex_t		n_lock;
-	kcondvar_t		n_cv;
-	boolean_t		n_attached;
-	list_t			n_leaves;
-};
-#define	B2S_NEXUS_ATTACHED	(1U << 0)
-
-_NOTE(MUTEX_PROTECTS_DATA(b2s_nexus::n_lock, b2s_nexus::n_leaves))
-_NOTE(SCHEME_PROTECTS_DATA("stable data", b2s_nexus::n_dip))
-_NOTE(SCHEME_PROTECTS_DATA("stable data", b2s_nexus::n_private))
-_NOTE(SCHEME_PROTECTS_DATA("stable data", b2s_nexus::n_request))
-_NOTE(SCHEME_PROTECTS_DATA("stable data", b2s_nexus::n_dma))
-_NOTE(SCHEME_PROTECTS_DATA("stable data", b2s_nexus::n_tran))
-_NOTE(SCHEME_PROTECTS_DATA("client synchronized", b2s_nexus::n_attached))
-
-struct b2s_leaf {
-	b2s_nexus_t		*l_nexus;
-	uint_t			l_target;
-	uint_t			l_lun;
-	uint32_t		l_flags;
-	char			*l_uuid;
-	uint32_t		l_refcnt;
-	list_node_t		l_node;
-	struct scsi_inquiry	l_inq;
-	uint64_t		l_eui;
-};
-
-_NOTE(MUTEX_PROTECTS_DATA(b2s_nexus::n_lock, b2s_leaf::l_node))
-_NOTE(MUTEX_PROTECTS_DATA(b2s_nexus::n_lock, b2s_leaf::l_refcnt))
-_NOTE(MUTEX_PROTECTS_DATA(b2s_nexus::n_lock, b2s_leaf::l_uuid))
-_NOTE(MUTEX_PROTECTS_DATA(b2s_nexus::n_lock, b2s_leaf::l_lun))
-_NOTE(MUTEX_PROTECTS_DATA(b2s_nexus::n_lock, b2s_leaf::l_target))
-_NOTE(MUTEX_PROTECTS_DATA(b2s_nexus::n_lock, b2s_leaf::l_nexus))
-_NOTE(DATA_READABLE_WITHOUT_LOCK(b2s_leaf::l_uuid))
-_NOTE(DATA_READABLE_WITHOUT_LOCK(b2s_leaf::l_lun))
-_NOTE(DATA_READABLE_WITHOUT_LOCK(b2s_leaf::l_target))
-_NOTE(DATA_READABLE_WITHOUT_LOCK(b2s_leaf::l_nexus))
-
-_NOTE(SCHEME_PROTECTS_DATA("stable data", scsi_hba_tran))
-_NOTE(SCHEME_PROTECTS_DATA("unshared data", b2s_request_impl))
-_NOTE(SCHEME_PROTECTS_DATA("unique per packet", scsi_arq_status))
-_NOTE(SCHEME_PROTECTS_DATA("unique per packet", scsi_pkt))
-_NOTE(SCHEME_PROTECTS_DATA("unique per packet", scsi_inquiry))
-_NOTE(SCHEME_PROTECTS_DATA("client synchronized", b2s_leaf::l_flags))
-
-/*
- * This copies a string into a target buf, obeying the size limits
- * of the target.  It does not null terminate, ever.
- */
-#define	COPYSTR(src, dst)	bcopy(src, dst, min(strlen(src), sizeof (dst)))
-
-/*
- * Thank you SCSA, for making it a PITA to deal with a single byte
- * value by turning it into a bitfield!
- */
-#define	PUTSTAT(dst, val)	(*((uint8_t *)(void *)&dst) = val)
-
-struct b2s_error {
-	uint8_t			e_reason;	/* scsi CMD_xxx reason */
-	uint8_t			e_status;	/* scsi STATUS_xxx code */
-	uint8_t			e_skey;		/* sense key */
-	uint8_t			e_asc;		/* additional sense code */
-	uint8_t			e_ascq;		/* sense code qualifier */
-	uint8_t			e_sksv[3];	/* sense key specific-value */
-};
-
-static struct b2s_error b2s_errs[B2S_NERRS];
-
-static struct modlmisc modlmisc = {
-	&mod_miscops,
-	"SCSA Block Device Emulation",
-};
-
-static struct modlinkage modlinkage = {
-	MODREV_1, { &modlmisc, NULL }
-};
-
-/*
- * For layers that don't provide a DMA attribute, we offer a default
- * one.  Such devices probably just want to do mapin, all of the time,
- * but since SCSI doesn't give us a way to indicate that, we have to
- * provide a fake attribute.  Slightly wasteful, but PIO-only disk
- * devices are going to have some performance issues anyway.
- *
- * For such devices, we only want to commit to transferring 64K at a time,
- * and let the SCSA layer break it up for us.
- */
-static struct ddi_dma_attr b2s_default_dma_attr =  {
-	DMA_ATTR_V0,
-	0,			/* lo address */
-	0xffffffffffffffffULL,	/* high address */
-	0xffffU,		/* DMA counter max */
-	1,			/* alignment */
-	0x0c,			/* burst sizes */
-	1,			/* minimum transfer size */
-	0xffffU,		/* maximum transfer size */
-	0xffffU,		/* maximum segment size */
-	1,			/* scatter/gather list length */
-	1,			/* granularity */
-	0			/* DMA flags */
-};
-
-
-/*
- * Private prototypes.
- */
-
-static int b2s_tran_tgt_init(dev_info_t *, dev_info_t *,
-    scsi_hba_tran_t *, struct scsi_device *);
-static void b2s_tran_tgt_free(dev_info_t *, dev_info_t *,
-    scsi_hba_tran_t *, struct scsi_device *);
-static int b2s_tran_getcap(struct scsi_address *, char *, int);
-static int b2s_tran_setcap(struct scsi_address *, char *, int, int);
-static void b2s_tran_destroy_pkt(struct scsi_address *, struct scsi_pkt *);
-static struct scsi_pkt *b2s_tran_init_pkt(struct scsi_address *,
-    struct scsi_pkt *, struct buf *, int, int, int, int,
-    int (*)(caddr_t), caddr_t);
-static int b2s_tran_start(struct scsi_address *, struct scsi_pkt *);
-static int b2s_tran_abort(struct scsi_address *, struct scsi_pkt *);
-static int b2s_tran_reset(struct scsi_address *, int);
-static int b2s_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t, void *,
-    dev_info_t **);
-static b2s_leaf_t *b2s_hold_leaf(b2s_nexus_t *, uint_t, uint_t);
-static dev_info_t *b2s_find_node(b2s_nexus_t *, b2s_leaf_t *);
-static int b2s_create_node(b2s_nexus_t *, b2s_leaf_t *, dev_info_t **);
-static int b2s_update_props(dev_info_t *, b2s_leaf_t *, char **, int);
-static void b2s_inquiry_done(b2s_request_impl_t *);
-static int b2s_inquiry(b2s_leaf_t *);
-static void b2s_init_err_table(void);
-static int b2s_scmd_inq(b2s_request_impl_t *);
-static int b2s_scmd_tur(b2s_request_impl_t *);
-static int b2s_scmd_doorlock(b2s_request_impl_t *);
-static int b2s_scmd_format(b2s_request_impl_t *);
-static int b2s_scmd_readcap(b2s_request_impl_t *);
-static int b2s_scmd_rw(b2s_request_impl_t *);
-static int b2s_scmd_rqs(b2s_request_impl_t *);
-static int b2s_scmd_sdiag(b2s_request_impl_t *);
-static int b2s_scmd_start_stop(b2s_request_impl_t *);
-static int b2s_scmd_mode_sense(b2s_request_impl_t *);
-static int b2s_scmd_reserve_release(b2s_request_impl_t *);
-static void b2s_scmd_readcap_done(b2s_request_impl_t *);
-static void b2s_scmd_mode_sense_done(b2s_request_impl_t *);
-static void b2s_warn(b2s_leaf_t *, const char *, ...);
-
-int
-_init(void)
-{
-	int	rv;
-
-	b2s_init_err_table();
-	rv = mod_install(&modlinkage);
-	return (rv);
-}
-
-int
-_fini(void)
-{
-	int	rv;
-
-	rv = mod_remove(&modlinkage);
-	return (rv);
-}
-
-int
-_info(struct modinfo *modinfop)
-{
-	return (mod_info(&modlinkage, modinfop));
-}
-
-int
-b2s_mod_init(struct modlinkage *modlp)
-{
-	return (scsi_hba_init(modlp));
-}
-
-void
-b2s_mod_fini(struct modlinkage *modlp)
-{
-	scsi_hba_fini(modlp);
-}
-
-void
-b2s_init_err_table(void)
-{
-	int	i;
-
-	/* fill up most of them with defaults */
-	for (i = 0; i < B2S_NERRS; i++) {
-		b2s_errs[i].e_reason = CMD_CMPLT;
-		b2s_errs[i].e_status = STATUS_CHECK;
-		b2s_errs[i].e_skey = KEY_NO_SENSE;
-		b2s_errs[i].e_asc = 0;
-		b2s_errs[i].e_ascq = 0;
-		b2s_errs[i].e_sksv[0] = 0;
-		b2s_errs[i].e_sksv[1] = 0;
-		b2s_errs[i].e_sksv[2] = 0;
-	}
-
-	/* now flesh out real values */
-	b2s_errs[B2S_EOK].e_status = STATUS_GOOD;
-
-	b2s_errs[B2S_ENOTSUP].e_skey = KEY_ILLEGAL_REQUEST;
-	b2s_errs[B2S_ENOTSUP].e_asc = 0x20;
-
-	b2s_errs[B2S_EFORMATTING].e_skey = KEY_NOT_READY;
-	b2s_errs[B2S_EFORMATTING].e_asc = 0x04;
-	b2s_errs[B2S_EFORMATTING].e_ascq = 0x04;
-	b2s_errs[B2S_EFORMATTING].e_sksv[0] = 0x80;
-
-	b2s_errs[B2S_ENOMEDIA].e_skey = KEY_NOT_READY;
-	b2s_errs[B2S_ENOMEDIA].e_asc = 0x3A;
-
-	b2s_errs[B2S_EMEDIACHG].e_skey = KEY_UNIT_ATTENTION;
-	b2s_errs[B2S_EMEDIACHG].e_asc = 0x28;
-
-	b2s_errs[B2S_ESTOPPED].e_skey = KEY_NOT_READY;
-	b2s_errs[B2S_ESTOPPED].e_asc = 0x04;
-	b2s_errs[B2S_ESTOPPED].e_ascq = 0x02;
-
-	b2s_errs[B2S_EBLKADDR].e_skey = KEY_ILLEGAL_REQUEST;
-	b2s_errs[B2S_EBLKADDR].e_asc = 0x21;
-
-	b2s_errs[B2S_EIO].e_skey = KEY_HARDWARE_ERROR;
-	b2s_errs[B2S_EIO].e_asc = 0x08;
-	b2s_errs[B2S_EIO].e_ascq = 0x00;
-
-	b2s_errs[B2S_EHARDWARE].e_skey = KEY_HARDWARE_ERROR;
-	b2s_errs[B2S_EHARDWARE].e_asc = 0x44;
-
-	b2s_errs[B2S_ENODEV].e_reason = CMD_DEV_GONE;
-
-	b2s_errs[B2S_EMEDIA].e_skey = KEY_MEDIUM_ERROR;
-
-	b2s_errs[B2S_EDOORLOCK].e_skey = KEY_NOT_READY;
-	b2s_errs[B2S_EDOORLOCK].e_asc = 0x53;
-	b2s_errs[B2S_EDOORLOCK].e_ascq = 0x02;
-
-	b2s_errs[B2S_EWPROTECT].e_skey = KEY_DATA_PROTECT;
-	b2s_errs[B2S_EWPROTECT].e_asc = 0x27;
-
-	b2s_errs[B2S_ESTARTING].e_skey = KEY_NOT_READY;
-	b2s_errs[B2S_ESTARTING].e_asc = 0x04;
-	b2s_errs[B2S_ESTARTING].e_ascq = 0x01;
-
-	b2s_errs[B2S_ETIMEDOUT].e_skey = KEY_ABORTED_COMMAND;
-	b2s_errs[B2S_ETIMEDOUT].e_asc = 0x08;
-	b2s_errs[B2S_ETIMEDOUT].e_ascq = 0x01;
-
-	/*
-	 * This one, SYSTEM_RESOURCE_FAILURE, is not really legal for
-	 * DTYPE_DIRECT in SCSI-2, but sd doesn't care, and reporting
-	 * it this way may help diagnosis.  sd will retry it in any
-	 * case.
-	 */
-	b2s_errs[B2S_ENOMEM].e_skey = KEY_ABORTED_COMMAND;
-	b2s_errs[B2S_ENOMEM].e_asc = 0x55;
-
-	b2s_errs[B2S_ERESET].e_reason = CMD_RESET;
-
-	b2s_errs[B2S_EABORT].e_reason = CMD_ABORTED;
-
-	b2s_errs[B2S_ERSVD].e_status = STATUS_RESERVATION_CONFLICT;
-
-	b2s_errs[B2S_EINVAL].e_skey = KEY_ILLEGAL_REQUEST;
-	b2s_errs[B2S_EINVAL].e_asc = 0x24;
-
-	b2s_errs[B2S_EPARAM].e_skey = KEY_ILLEGAL_REQUEST;
-	b2s_errs[B2S_EPARAM].e_asc = 0x26;
-
-	b2s_errs[B2S_EBADMSG].e_reason = CMD_BADMSG;
-}
-
-/*
- * Locate the the leaf node for the given target/lun.  This must be
- * called with the nexus lock held.
- */
-b2s_leaf_t *
-b2s_get_leaf(b2s_nexus_t *n, uint_t target, uint_t lun)
-{
-	b2s_leaf_t *l;
-
-	ASSERT(mutex_owned(&n->n_lock));
-
-	l = list_head(&n->n_leaves);
-	while (l != NULL) {
-		ASSERT(l->l_nexus == n);
-		if ((l->l_target == target) && (l->l_lun == lun)) {
-			break;
-		}
-		l = list_next(&n->n_leaves, l);
-	}
-
-	return (l);
-}
-
-/*
- * Locate the the leaf node for the given target/lun, and hold it.  The
- * nexus lock must *NOT* be held.
- */
-b2s_leaf_t *
-b2s_hold_leaf(b2s_nexus_t *n, uint_t target, uint_t lun)
-{
-	b2s_leaf_t	*l;
-
-	mutex_enter(&n->n_lock);
-	l = b2s_get_leaf(n, target, lun);
-	if (l != NULL) {
-		l->l_refcnt++;
-	}
-	mutex_exit(&n->n_lock);
-	return (l);
-}
-
-/*
- * Drop the hold on the leaf.
- */
-void
-b2s_rele_leaf(b2s_leaf_t *l)
-{
-	b2s_nexus_t *n = l->l_nexus;
-	mutex_enter(&n->n_lock);
-	l->l_refcnt--;
-	if (l->l_refcnt == 0) {
-		list_remove(&n->n_leaves, l);
-		kmem_free(l->l_uuid, strlen(l->l_uuid) + 1);
-		kmem_free(l, sizeof (*l));
-	}
-	mutex_exit(&n->n_lock);
-}
-
-/*
- * This is used to walk the list of leaves safely, without requiring the
- * nexus lock to be held.  The returned leaf is held.  (If the passed in
- * lastl is not NULL, then it is released as well.)
- *
- * Pass NULL for lastl to start the walk.
- */
-b2s_leaf_t *
-b2s_next_leaf(b2s_nexus_t *n, b2s_leaf_t *lastl)
-{
-	b2s_leaf_t *l;
-
-	mutex_enter(&n->n_lock);
-	if (lastl == NULL) {
-		l = list_head(&n->n_leaves);
-	} else {
-		l = list_next(&n->n_leaves, lastl);
-	}
-	if (l != NULL) {
-		l->l_refcnt++;
-	}
-	mutex_exit(&n->n_lock);
-
-	if (lastl != NULL) {
-		b2s_rele_leaf(lastl);
-	}
-
-	return (l);
-}
-
-void
-b2s_request_mapin(b2s_request_t *req, caddr_t *addrp, size_t *lenp)
-{
-	b2s_request_impl_t	 *ri = (void *)req;
-	buf_t			*bp;
-
-	if (((bp = ri->ri_bp) != NULL) && (bp->b_bcount != 0)) {
-		*addrp = bp->b_un.b_addr;
-		*lenp = bp->b_bcount;
-	} else {
-		*addrp = 0;
-		*lenp = 0;
-	}
-}
-
-void
-b2s_request_dma(b2s_request_t *req, uint_t *ndmacp, ddi_dma_cookie_t **dmacsp)
-{
-	/*
-	 * Direct DMA support was removed; SCSA can't easily deal with
-	 * HBAs that have restrictions which would require partial DMA
-	 * to be used.
-	 */
-	_NOTE(ARGUNUSED(req));
-
-	*ndmacp = 0;
-	*dmacsp = NULL;
-}
-
-void
-b2s_request_done_pkt(b2s_request_impl_t *ri)
-{
-	struct scsi_pkt		*pkt;
-	uint8_t			status;
-	struct scsi_arq_status	*sts = ri->ri_sts;
-	b2s_err_t		err;
-
-	err = ri->ri_errno;
-
-	pkt = ri->ri_pkt;
-	pkt->pkt_resid = ri->ri_resid;
-
-	bzero(sts, sizeof (*sts));
-
-	/*
-	 * Make sure that the status is in range of our known errs.  If we
-	 * don't know it, then just cobble up a bogus one.
-	 */
-	if ((err < 0) || (err >= B2S_NERRS)) {
-		pkt->pkt_reason = CMD_TRAN_ERR;
-	} else {
-		pkt->pkt_reason = b2s_errs[err].e_reason;
-		status = b2s_errs[err].e_status;
-	}
-
-	if (pkt->pkt_reason == CMD_CMPLT) {
-
-		pkt->pkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
-		    STATE_SENT_CMD | STATE_GOT_STATUS;
-
-		PUTSTAT(sts->sts_status, status);
-
-		if (status == STATUS_CHECK) {
-			/*
-			 * Contingent allegiance.  We need to do the
-			 * ARQ thing.
-			 */
-			PUTSTAT(sts->sts_rqpkt_status, STATUS_GOOD);
-
-			sts->sts_rqpkt_reason = CMD_CMPLT;
-			sts->sts_rqpkt_resid = 0;
-			sts->sts_rqpkt_state = STATE_XFERRED_DATA |
-			    STATE_GOT_BUS | STATE_GOT_STATUS;
-
-			sts->sts_sensedata.es_valid = 1;
-			sts->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
-			sts->sts_sensedata.es_key = b2s_errs[err].e_skey;
-			sts->sts_sensedata.es_add_code = b2s_errs[err].e_asc;
-			sts->sts_sensedata.es_qual_code = b2s_errs[err].e_ascq;
-			bcopy(sts->sts_sensedata.es_skey_specific,
-			    b2s_errs[err].e_sksv, 3);
-			/*
-			 * Stash any residue information.
-			 */
-			sts->sts_sensedata.es_info_1 =
-			    (ri->ri_resid >> 24) & 0xff;
-			sts->sts_sensedata.es_info_2 =
-			    (ri->ri_resid >> 16) & 0xff;
-			sts->sts_sensedata.es_info_3 =
-			    (ri->ri_resid >> 8) & 0xff;
-			sts->sts_sensedata.es_info_4 =
-			    (ri->ri_resid) & 0xff;
-
-			pkt->pkt_state |= STATE_ARQ_DONE;
-		}
-
-	} else if (pkt->pkt_reason == CMD_ABORTED) {
-		pkt->pkt_statistics |= STAT_ABORTED;
-	} else if (pkt->pkt_reason == CMD_RESET) {
-		pkt->pkt_statistics |= STAT_DEV_RESET;
-	} else {
-		pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET |
-		    STATE_SENT_CMD;
-	}
-
-	/*
-	 * N.B.: Obviously not all commands actually have a SCSI
-	 * DATA-IN or DATA-OUT phase.  But it doesn't matter, since
-	 * sd.c only bothers to look at this flag for request sense
-	 * traffic, which is always correct within our emulation.
-	 *
-	 * We go ahead and set it on all good packets however, since
-	 * there may in the future be some additional checks to make
-	 * sure a data transfer occurred.  This seems safer (since
-	 * then sd should examine pkt_resid) rather than leaving it
-	 * off by default.
-	 */
-	if (ri->ri_errno == 0) {
-		pkt->pkt_state |= STATE_XFERRED_DATA;
-	}
-
-	/*
-	 * Finally, execute the callback (unless running POLLED)
-	 */
-	if ((pkt->pkt_flags & FLAG_NOINTR) == 0) {
-		scsi_hba_pkt_comp(pkt);
-	}
-
-}
-
-void
-b2s_request_done(b2s_request_t *req, b2s_err_t err, size_t resid)
-{
-	b2s_request_impl_t	*ri = (void *)req;
-
-	ri->ri_errno = err;
-	ri->ri_resid = (ssize_t)resid;
-
-	/*
-	 * Post process...  this is used for massaging results into
-	 * what SCSI wants.
-	 */
-	if (ri->ri_done != NULL)
-		ri->ri_done(ri);
-
-	/*
-	 * For SCSI packets, we have special completion handling.  For
-	 * internal requests, we just mark the request done so the caller
-	 * can free it.
-	 */
-	if (ri->ri_pkt == NULL) {
-		b2s_nexus_t	*n = ri->ri_nexus;
-
-		mutex_enter(&n->n_lock);
-		ri->ri_flags |= B2S_REQUEST_FLAG_DONE;
-		cv_broadcast(&n->n_cv);
-		mutex_exit(&n->n_lock);
-	} else {
-		b2s_request_done_pkt(ri);
-	}
-}
-
-int
-b2s_tran_tgt_init(dev_info_t *hbadip, dev_info_t *tgtdip,
-    scsi_hba_tran_t *tran, struct scsi_device *sd)
-{
-	uint_t		tgt, lun;
-	b2s_nexus_t	*n;
-	b2s_leaf_t	*l;
-
-	_NOTE(ARGUNUSED(hbadip));
-	_NOTE(ARGUNUSED(sd));
-
-	/*
-	 * Lookup the target and lun.
-	 */
-	tgt = (uint_t)ddi_prop_get_int(DDI_DEV_T_ANY, tgtdip,
-	    DDI_PROP_DONTPASS, "target", -1);
-
-	lun = (uint_t)ddi_prop_get_int(DDI_DEV_T_ANY, tgtdip,
-	    DDI_PROP_DONTPASS, "lun", -1);
-
-	n = tran->tran_hba_private;
-
-	/*
-	 * Hold the leaf node as long as the devinfo node is using it.
-	 */
-	l = b2s_hold_leaf(n, tgt, lun);
-	if (l == NULL) {
-		/*
-		 * Target node not found on bus.
-		 */
-		return (DDI_FAILURE);
-	}
-	tran->tran_tgt_private = l;
-
-	return (DDI_SUCCESS);
-}
-
-void
-b2s_tran_tgt_free(dev_info_t *hbadip, dev_info_t *tgtdip,
-    scsi_hba_tran_t *tran, struct scsi_device *sd)
-{
-	b2s_leaf_t	*l;
-
-	_NOTE(ARGUNUSED(hbadip));
-	_NOTE(ARGUNUSED(tgtdip));
-	_NOTE(ARGUNUSED(sd));
-
-	l = tran->tran_tgt_private;
-	ASSERT(l != NULL);
-	b2s_rele_leaf(l);
-}
-
-struct scsi_pkt *
-b2s_tran_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
-    struct buf *bp, int cmdlen, int statuslen, int tgtlen, int flags,
-    int (*cb)(caddr_t), caddr_t cbarg)
-{
-	dev_info_t		*dip;
-	scsi_hba_tran_t		*tran;
-	b2s_request_impl_t	*ri;
-
-	_NOTE(ARGUNUSED(cbarg));
-	_NOTE(ARGUNUSED(flags));
-
-	tran = ap->a_hba_tran;
-	dip = tran->tran_hba_dip;
-
-	/*
-	 * Unconditional mapin for now, so we will always have kernel
-	 * virtual addresses to work with.
-	 */
-	if (bp && (bp->b_bcount)) {
-		bp_mapin(bp);
-	}
-
-	if (pkt == NULL) {
-		/* we can only support these two kinds of callbacks */
-		cb = (cb == SLEEP_FUNC) ? SLEEP_FUNC : NULL_FUNC;
-		pkt = scsi_hba_pkt_alloc(dip, ap, cmdlen, statuslen,
-		    tgtlen, sizeof (b2s_request_impl_t), cb, NULL);
-		if (pkt == NULL)
-			return (NULL);
-
-		ri = pkt->pkt_ha_private;
-		ri->ri_pkt = pkt;
-		ri->ri_sts = (void *)pkt->pkt_scbp;
-		ri->ri_bp = bp;
-	}
-
-	return (pkt);
-}
-
-void
-b2s_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
-{
-	scsi_hba_pkt_free(ap, pkt);
-}
-
-int
-b2s_tran_getcap(struct scsi_address *ap, char *cap, int whom)
-{
-	int	capid;
-
-	_NOTE(ARGUNUSED(ap));
-	_NOTE(ARGUNUSED(whom));
-
-	capid = scsi_hba_lookup_capstr(cap);
-
-	switch (capid) {
-	case SCSI_CAP_ARQ:
-	case SCSI_CAP_UNTAGGED_QING:
-		return (1);
-	case SCSI_CAP_DMA_MAX:
-		return (65536);
-
-	default:
-		return (-1);
-	}
-}
-
-int
-b2s_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
-{
-	b2s_request_impl_t	*ri;
-	b2s_nexus_t		*n = ap->a_hba_tran->tran_hba_private;
-	b2s_leaf_t		*l = ap->a_hba_tran->tran_tgt_private;
-	int			err;
-
-	/*
-	 * We can only do the blind abort of all packets.  We have
-	 * no way to request an individual packet be aborted.
-	 */
-	if (pkt != NULL) {
-		return (B_FALSE);
-	}
-
-	ri = kmem_zalloc(sizeof (*ri), KM_NOSLEEP);
-	if (ri == NULL) {
-		return (B_FALSE);
-	}
-	ri->ri_cmd = B2S_CMD_ABORT;
-	ri->ri_target = l->l_target;
-	ri->ri_lun = l->l_lun;
-	ri->ri_flags = B2S_REQUEST_FLAG_HEAD;
-	ri->ri_leaf = l;
-	ri->ri_nexus = n;
-	/* leave all else null */
-
-	/*
-	 * Submit request to device driver.
-	 */
-	if (!n->n_request(n->n_private, &ri->ri_public)) {
-		/* this shouldn't happen, since we are just starting out */
-		b2s_warn(l, "Busy trying to abort");
-		kmem_free(ri, sizeof (*ri));
-		return (B_FALSE);
-	}
-
-	/*
-	 * Wait for command completion.
-	 */
-	mutex_enter(&n->n_lock);
-	while ((ri->ri_flags & B2S_REQUEST_FLAG_DONE) == 0)
-		cv_wait(&n->n_cv, &n->n_lock);
-	mutex_exit(&n->n_lock);
-
-	err = ri->ri_errno;
-	kmem_free(ri, sizeof (*ri));
-
-	if (err != 0) {
-		b2s_warn(l, "Failed during abort (error %d)", err);
-		return (B_FALSE);
-	}
-
-	return (B_TRUE);
-}
-
-int
-b2s_tran_reset(struct scsi_address *ap, int level)
-{
-	b2s_request_impl_t	*ri;
-	b2s_nexus_t		*n = ap->a_hba_tran->tran_hba_private;
-	b2s_leaf_t		*l = ap->a_hba_tran->tran_tgt_private;
-	int			err;
-
-	if (level == RESET_LUN) {
-		return (B_FALSE);
-	}
-
-	ri = kmem_zalloc(sizeof (*ri), KM_NOSLEEP);
-	if (ri == NULL) {
-		return (B_FALSE);
-	}
-	ri->ri_cmd = B2S_CMD_RESET;
-	ri->ri_target = l->l_target;
-	ri->ri_lun = l->l_lun;
-	ri->ri_flags = B2S_REQUEST_FLAG_HEAD;
-	ri->ri_leaf = l;
-	ri->ri_nexus = n;
-	/* leave all else null */
-
-	/*
-	 * Submit request to device driver.
-	 */
-	if (!n->n_request(n->n_private, &ri->ri_public)) {
-		/* this shouldn't happen, since we are just starting out */
-		b2s_warn(l, "Busy trying to reset");
-		kmem_free(ri, sizeof (*ri));
-		return (B_FALSE);
-	}
-
-	/*
-	 * Wait for command completion.
-	 */
-	mutex_enter(&n->n_lock);
-	while ((ri->ri_flags & B2S_REQUEST_FLAG_DONE) == 0)
-		cv_wait(&n->n_cv, &n->n_lock);
-	mutex_exit(&n->n_lock);
-
-	err = ri->ri_errno;
-	kmem_free(ri, sizeof (*ri));
-
-	if (err != 0) {
-		b2s_warn(l, "Failed during reset (error %d)", err);
-		return (B_FALSE);
-	}
-
-	return (B_TRUE);
-}
-
-int
-b2s_tran_setcap(struct scsi_address *ap, char *cap, int val, int whom)
-{
-	int	capid;
-
-	_NOTE(ARGUNUSED(ap));
-	_NOTE(ARGUNUSED(val));
-	_NOTE(ARGUNUSED(whom));
-
-	capid = scsi_hba_lookup_capstr(cap);
-
-	switch (capid) {
-	case SCSI_CAP_ARQ:
-		if (val == 0) {
-			return (0);
-		} else {
-			return (1);
-		}
-
-	default:
-		return (-1);
-	}
-}
-
-int
-b2s_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
-{
-	b2s_request_impl_t	*ri = pkt->pkt_ha_private;
-	b2s_nexus_t		*n = ap->a_hba_tran->tran_hba_private;
-	b2s_leaf_t		*l = ap->a_hba_tran->tran_tgt_private;
-
-	ri->ri_errno = B2S_EOK;
-	ri->ri_resid = 0;
-	bzero(&ri->ri_public.br_args, sizeof (ri->ri_public.br_args));
-	ri->ri_flags = 0;
-	ri->ri_done = NULL;
-
-	if ((n == NULL) || (l == NULL) ||
-	    ((l->l_flags & B2S_LEAF_DETACHED) != 0)) {
-		/*
-		 * Leaf is not on the bus!
-		 *
-		 * We should add support for inquiry when lun != 0,
-		 * even if when the lun does not exist, but lun 0 is
-		 * present.  But, it turns out this is not strictly
-		 * required by sd(7d).
-		 */
-		b2s_request_done(&ri->ri_public, B2S_ENODEV, 0);
-		return (TRAN_ACCEPT);
-	}
-
-	ri->ri_nexus = n;
-	ri->ri_leaf = l;
-	ri->ri_target = l->l_target;
-	ri->ri_lun = l->l_lun;
-
-	if (pkt->pkt_flags & FLAG_NOINTR)
-		ri->ri_flags |= B2S_REQUEST_FLAG_POLL;
-	if (pkt->pkt_flags & FLAG_HEAD)
-		ri->ri_flags |= B2S_REQUEST_FLAG_HEAD;
-
-	switch (pkt->pkt_cdbp[0]) {
-	case SCMD_DOORLOCK:
-		return (b2s_scmd_doorlock(ri));
-
-	case SCMD_FORMAT:
-		return (b2s_scmd_format(ri));
-
-	case SCMD_INQUIRY:
-		return (b2s_scmd_inq(ri));
-
-	case SCMD_REQUEST_SENSE:
-		return (b2s_scmd_rqs(ri));
-
-	case SCMD_SDIAG:
-		return (b2s_scmd_sdiag(ri));
-
-	case SCMD_TEST_UNIT_READY:
-		return (b2s_scmd_tur(ri));
-
-	case SCMD_READ_CAPACITY:
-		return (b2s_scmd_readcap(ri));
-
-	case SCMD_RELEASE:
-	case SCMD_RESERVE:
-		return (b2s_scmd_reserve_release(ri));
-
-	case SCMD_START_STOP:
-		return (b2s_scmd_start_stop(ri));
-
-	case SCMD_MODE_SENSE:
-		return (b2s_scmd_mode_sense(ri));
-
-	case SCMD_READ:
-	case SCMD_READ_G1:
-	case SCMD_WRITE:
-	case SCMD_WRITE_G1:
-		return (b2s_scmd_rw(ri));
-
-	default:
-		b2s_request_done(&ri->ri_public, B2S_ENOTSUP, 0);
-		return (TRAN_ACCEPT);
-	}
-}
-
-/*
- * Publish standard properties on a newly created devinfo node.
- */
-int
-b2s_update_props(dev_info_t *dip, b2s_leaf_t *l, char **compat, int ncompat)
-{
-	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip, "target", l->l_target) !=
-	    DDI_PROP_SUCCESS) {
-		return (DDI_FAILURE);
-	}
-	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip, "lun", l->l_lun) !=
-	    DDI_PROP_SUCCESS) {
-		return (DDI_FAILURE);
-	}
-	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip, "pm-capable", 1) !=
-	    DDI_PROP_SUCCESS) {
-		return (DDI_FAILURE);
-	}
-	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible",
-	    compat, ncompat) != DDI_PROP_SUCCESS) {
-		return (DDI_FAILURE);
-	}
-	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "unique-id",
-	    l->l_uuid) != DDI_PROP_SUCCESS) {
-		return (DDI_FAILURE);
-	}
-
-	if (l->l_flags & B2S_LEAF_HOTPLUGGABLE) {
-		if (ndi_prop_create_boolean(DDI_DEV_T_NONE, dip,
-		    "hotpluggable") != DDI_PROP_SUCCESS) {
-			return (DDI_FAILURE);
-		}
-	}
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * Find the devinfo node associated with the leaf, looking up by target and
- * lun.  (Alternatively in the future we could use a full address)
- *
- * This must be called with the tree lock held.
- */
-dev_info_t *
-b2s_find_node(b2s_nexus_t *n, b2s_leaf_t *l)
-{
-	dev_info_t	*dip;
-	int		tgt, lun;
-
-	dip = ddi_get_child(n->n_dip);
-	while (dip != NULL) {
-
-		tgt = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
-		    DDI_PROP_DONTPASS, "target", -1);
-
-		lun = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
-		    DDI_PROP_DONTPASS, "lun", -1);
-
-		/* is this the right target */
-		if ((lun == l->l_lun) && (tgt == l->l_target)) {
-			return (dip);
-		}
-
-		dip = ddi_get_next_sibling(dip);
-	}
-
-	return (NULL);
-
-}
-
-/*
- * Create and attach a devinfo node for the supplied nexus/leaf
- * combination.
- */
-int
-b2s_create_node(b2s_nexus_t *n, b2s_leaf_t *l, dev_info_t **dipp)
-{
-	dev_info_t	*dip;
-	char		*name;
-	char		**compat;
-	int		ncompat;
-	int		rv;
-
-	/*
-	 * If the node was already created, then we're done.
-	 */
-	if ((dip = b2s_find_node(n, l)) != NULL) {
-		if (dipp)
-			*dipp = dip;
-		return (DDI_SUCCESS);
-	}
-
-	ASSERT(l != NULL);
-
-	/*
-	 * Perform an inquiry to collect key information.
-	 */
-	if (b2s_inquiry(l) != DDI_SUCCESS) {
-		return (DDI_FAILURE);
-	}
-
-	scsi_hba_nodename_compatible_get(&l->l_inq, NULL, l->l_inq.inq_dtype,
-	    NULL, &name, &compat, &ncompat);
-
-	if (ndi_devi_alloc(n->n_dip, name, DEVI_SID_NODEID, &dip) !=
-	    NDI_SUCCESS) {
-		scsi_hba_nodename_compatible_free(name, compat);
-		b2s_warn(l, "Unable to create devinfo node");
-		return (DDI_FAILURE);
-	}
-
-	if (b2s_update_props(dip, l, compat, ncompat) != DDI_SUCCESS) {
-		scsi_hba_nodename_compatible_free(name, compat);
-		ndi_prop_remove_all(dip);
-		(void) ndi_devi_free(dip);
-		b2s_warn(l, "Unable to create properties");
-		return (DDI_FAILURE);
-	}
-	scsi_hba_nodename_compatible_free(name, compat);
-
-	if (dipp) {
-		/*
-		 * We were called by bus_config BUS_CONFIG_ONE,
-		 * and therefore must be done synchronously.
-		 */
-		rv = ndi_devi_online(dip, NDI_ONLINE_ATTACH);
-		if (rv == NDI_SUCCESS)
-			*dipp = dip;
-	} else {
-		/*
-		 * The rest of the time, asynchronous is easier and
-		 * safer (nexus could call us from interrupt context).
-		 */
-		rv = ndi_devi_online_async(dip,
-		    NDI_ONLINE_ATTACH | NDI_NOSLEEP);
-	}
-	if (rv != NDI_SUCCESS) {
-		b2s_warn(l, "Failed to online device");
-		ndi_prop_remove_all(dip);
-		(void) ndi_devi_free(dip);
-		return (DDI_FAILURE);
-	}
-
-	return (DDI_SUCCESS);
-}
-
-int
-b2s_bus_config(dev_info_t *ndip, uint_t flag, ddi_bus_config_op_t op,
-    void *arg, dev_info_t **ldip)
-{
-	long			val;
-	char			*ptr;
-	int			rv;
-	scsi_hba_tran_t		*tran;
-	b2s_leaf_t		*l;
-	b2s_nexus_t		*n;
-	int			circ;
-	uint_t			target, lun;
-
-	tran = ddi_get_driver_private(ndip);
-	n = tran->tran_hba_private;
-
-	ndi_devi_enter(ndip, &circ);
-
-	switch (op) {
-	case BUS_CONFIG_ONE:
-
-		/*
-		 * First parse out the target and lun from the
-		 * address.
-		 */
-		if ((ptr = strchr((char *)arg, '@')) == NULL) {
-			rv = NDI_FAILURE;
-			break;
-		}
-		ptr++;
-		if ((ddi_strtol(ptr, &ptr, 16, &val) != 0) ||
-		    (val < 0) || (*ptr != ',')) {
-			rv = NDI_FAILURE;
-			break;
-		}
-		ptr++;
-		target = (uint_t)val;
-		if ((ddi_strtol(ptr, &ptr, 16, &val) != 0) ||
-		    (val < 0) || (*ptr != 0)) {
-			rv = NDI_FAILURE;
-			break;
-		}
-		lun = (uint_t)val;
-
-		/*
-		 * Now lookup the leaf, and if we have it, attempt to create
-		 * the devinfo node for it.
-		 */
-		rv = NDI_SUCCESS;
-		if ((l = b2s_hold_leaf(n, target, lun)) != NULL) {
-			if (b2s_create_node(n, l, ldip) != DDI_SUCCESS) {
-				rv = NDI_FAILURE;
-			}
-			b2s_rele_leaf(l);
-			break;
-		}
-		break;
-
-	case BUS_CONFIG_DRIVER:
-	case BUS_CONFIG_ALL:
-
-		l = b2s_next_leaf(n, NULL);
-		while (l != NULL) {
-			(void) b2s_create_node(n, l, NULL);
-			l = b2s_next_leaf(n, l);
-		}
-
-		rv = NDI_SUCCESS;
-		break;
-
-	default:
-		rv = NDI_FAILURE;
-		break;
-	}
-
-	if (rv == NDI_SUCCESS) {
-		rv = ndi_busop_bus_config(ndip, flag, op, arg, ldip, 0);
-	}
-
-	ndi_devi_exit(ndip, circ);
-	return (rv);
-}
-
-void
-b2s_inquiry_done(b2s_request_impl_t *ri)
-{
-	struct scsi_inquiry	*inqp = &ri->ri_leaf->l_inq;
-
-	/*
-	 * The only post processing we have to do is to massage the
-	 * strings into the inquiry structure.
-	 */
-	COPYSTR(ri->ri_inquiry.inq_vendor, inqp->inq_vid);
-	COPYSTR(ri->ri_inquiry.inq_product, inqp->inq_pid);
-	COPYSTR(ri->ri_inquiry.inq_revision, inqp->inq_revision);
-	COPYSTR(ri->ri_inquiry.inq_serial, inqp->inq_serial);
-}
-
-int
-b2s_inquiry(b2s_leaf_t *l)
-{
-	b2s_nexus_t		*n;
-	b2s_request_impl_t	*ri;
-	struct scsi_inquiry	*inqp;
-	int			err;
-
-	inqp = &l->l_inq;
-	n = l->l_nexus;
-
-	/*
-	 * Set up basic structure, including space padding for ASCII strings.
-	 */
-	bzero(inqp, sizeof (*inqp));
-	(void) memset(inqp->inq_vid, ' ', sizeof (inqp->inq_vid));
-	(void) memset(inqp->inq_pid, ' ', sizeof (inqp->inq_pid));
-	(void) memset(inqp->inq_revision, ' ', sizeof (inqp->inq_revision));
-	(void) memset(inqp->inq_serial, ' ', sizeof (inqp->inq_serial));
-	inqp->inq_len = sizeof (*inqp) - 4;
-	inqp->inq_ansi = 2;
-	inqp->inq_rdf = RDF_SCSI2;
-	inqp->inq_dtype = DTYPE_DIRECT;
-	if (l->l_flags & B2S_LEAF_REMOVABLE)
-		inqp->inq_rmb = 1;
-
-	/*
-	 * To get product strings, we have to issue a query to the driver.
-	 */
-	ri = kmem_zalloc(sizeof (*ri), KM_NOSLEEP);
-	if (ri == NULL) {
-		return (DDI_FAILURE);
-	}
-	ri->ri_cmd = B2S_CMD_INQUIRY;
-	ri->ri_target = l->l_target;
-	ri->ri_lun = l->l_lun;
-	ri->ri_flags = B2S_REQUEST_FLAG_HEAD;
-	ri->ri_leaf = l;
-	ri->ri_nexus = n;
-	ri->ri_done = b2s_inquiry_done;
-	/* leave all else null */
-
-	/*
-	 * Submit inquiry request to device driver.
-	 */
-	if (!n->n_request(n->n_private, &ri->ri_public)) {
-		/* this shouldn't happen, since we are just starting out */
-		b2s_warn(l, "Busy trying to collect inquiry data");
-		kmem_free(ri, sizeof (*ri));
-		return (DDI_FAILURE);
-	}
-
-	/*
-	 * Wait for inquiry completion.
-	 */
-	mutex_enter(&n->n_lock);
-	while ((ri->ri_flags & B2S_REQUEST_FLAG_DONE) == 0)
-		cv_wait(&n->n_cv, &n->n_lock);
-	mutex_exit(&n->n_lock);
-
-	err = ri->ri_errno;
-	kmem_free(ri, sizeof (*ri));
-
-	if (err != 0) {
-		b2s_warn(l, "Failed during inquiry (error %d)", err);
-		return (DDI_FAILURE);
-	}
-
-	return (DDI_SUCCESS);
-}
-
-int
-b2s_scmd_inq(b2s_request_impl_t *ri)
-{
-	b2s_leaf_t		*l = ri->ri_leaf;
-	union scsi_cdb		*cdb = (void *)ri->ri_pkt->pkt_cdbp;
-	caddr_t			ptr;
-	size_t			resid, len;
-	uint8_t			hdr[4];
-	const uint8_t		*data;
-	uint8_t			page83[12];
-
-	/*
-	 * Suppport inquiry pages: 0 is the list itself, and 80 is the
-	 * unit serial number (in ASCII).
-	 */
-	const uint8_t		supp[3] = { 0, 0x80, 0x83 };
-
-	b2s_request_mapin(&ri->ri_public, &ptr, &len);
-
-	hdr[2] = 0;
-
-	/*
-	 * We don't support the EVP data bit, and hence neither a page code.
-	 * This corresponds to the entire G0 address field (which includes
-	 * a few reserved bits).
-	 */
-	switch (GETG0ADDR(cdb)) {
-	case 0x00000:		/* standard SCSI inquiry */
-		resid = min(sizeof (l->l_inq), GETG0COUNT(cdb));
-		len = min(resid, len);
-		bcopy(&l->l_inq, ptr, len);
-		ri->ri_resid = resid - len;
-		b2s_request_done(&ri->ri_public, B2S_EOK, 0);
-		return (TRAN_ACCEPT);
-
-	case 0x10000:		/* page 0 supported VPD pages */
-		data = supp;
-		hdr[0] = DTYPE_DIRECT;
-		hdr[1] = 0;	/* page code */
-		hdr[2] = 0;
-		hdr[3] = l->l_eui ? 3 : 2;	/* page length */
-		break;
-
-	case 0x18000:		/* page 80 unit serial number */
-		data = (uint8_t *)l->l_uuid;
-		hdr[0] = DTYPE_DIRECT;
-		hdr[1] = 0x80;	/* page code */
-		hdr[2] = 0;
-		hdr[3] = l->l_uuid ? strlen(l->l_uuid) : 0; 	/* page len */
-		break;
-
-	case 0x18300:		/* page 83 WWN */
-		if (l->l_eui == 0) {
-			b2s_request_done(&ri->ri_public, B2S_EINVAL, 0);
-			return (TRAN_ACCEPT);
-		}
-		data = page83;
-		hdr[0] = DTYPE_DIRECT;
-		hdr[1] = 0x83;	/* page code */
-		hdr[2] = 0;
-		hdr[3] = 12;	/* length, only 12 bytes */
-
-		/* lun designator */
-		page83[0] = 1;		/* binary */
-		page83[1] = 2;		/* lun association, eui-64 type */
-		page83[2] = 0;		/* reserved */
-		page83[3] = 8;		/* designator length */
-		SCSI_WRITE64(&page83[4], l->l_eui);
-
-		/* Note that we don't bother with port or target ids */
-		break;
-
-	default:
-		b2s_request_done(&ri->ri_public, B2S_EINVAL, 0);
-		return (TRAN_ACCEPT);
-	}
-
-	resid = min(hdr[3] + 4, GETG0COUNT(cdb));
-	len = min(resid, len);
-	ri->ri_resid = resid - len;
-
-	/* now copy the header */
-	len = min(resid, 4);
-	bcopy(hdr, ptr, len);
-	resid -= len;
-
-	/* now copy the actual page data */
-	bcopy(data, ptr + len, resid);
-
-	b2s_request_done(&ri->ri_public, B2S_EOK, 0);
-	return (TRAN_ACCEPT);
-}
-
-int
-b2s_scmd_rqs(b2s_request_impl_t *ri)
-{
-	union scsi_cdb	*cdb = (void *)ri->ri_pkt->pkt_cdbp;
-	size_t		len, resid;
-	caddr_t		ptr;
-	int		rv;
-
-	/* Like inquiry, the entire G0 address field must be zero. */
-	if (GETG0ADDR(cdb) != 0) {
-		rv = B2S_EINVAL;
-		len = 0;
-		resid = 0;
-	} else {
-		struct scsi_extended_sense es;
-
-		/*
-		 * We always use ARQ, unconditionally, so this command
-		 * can always return success.
-		 */
-		bzero(&es, sizeof (es));
-		es.es_valid = 1;
-		es.es_class = CLASS_EXTENDED_SENSE;
-		es.es_key = KEY_NO_SENSE;
-
-		resid = sizeof (es);
-
-		b2s_request_mapin(&ri->ri_public, &ptr, &len);
-
-		len = min(resid, len);
-		bcopy(&es, ptr, len);
-		resid -= len;
-
-		rv = B2S_EOK;
-	}
-	b2s_request_done(&ri->ri_public, rv, resid);
-	return (TRAN_ACCEPT);
-}
-
-int
-b2s_scmd_sdiag(b2s_request_impl_t *ri)
-{
-	union scsi_cdb	*cdb = (void *)ri->ri_pkt->pkt_cdbp;
-	int		rv;
-
-	/* we only support the SELFTEST bit */
-	if ((GETG0TAG(cdb) & 0x4) == 0) {
-		rv = B2S_EINVAL;
-	} else {
-		rv = B2S_EOK;
-	}
-	b2s_request_done(&ri->ri_public, rv, 0);
-	return (TRAN_ACCEPT);
-}
-
-int
-b2s_scmd_tur(b2s_request_impl_t *ri)
-{
-	b2s_nexus_t 	*n = ri->ri_nexus;
-
-	ri->ri_cmd = B2S_CMD_GETMEDIA;
-	if (!n->n_request(n->n_private, &ri->ri_public)) {
-		return (TRAN_BUSY);
-	}
-	return (TRAN_ACCEPT);
-}
-
-int
-b2s_scmd_doorlock(b2s_request_impl_t *ri)
-{
-	b2s_nexus_t	*n = ri->ri_nexus;
-	union scsi_cdb	*cdb = (void *)ri->ri_pkt->pkt_cdbp;
-
-	/*
-	 * Bit 0 of the count indicates the "Prevent" mode.  All other address
-	 * and count bits are reserved.
-	 */
-	if ((GETG0ADDR(cdb) != 0) || ((GETG0COUNT(cdb) & 0xFE) != 0)) {
-		b2s_request_done(&ri->ri_public, B2S_EINVAL, 0);
-		return (TRAN_ACCEPT);
-	}
-
-	ri->ri_cmd = (GETG0COUNT(cdb) != 0) ? B2S_CMD_LOCK : B2S_CMD_UNLOCK;
-	if (!n->n_request(n->n_private, &ri->ri_public)) {
-		return (TRAN_BUSY);
-	}
-	return (TRAN_ACCEPT);
-}
-
-int
-b2s_scmd_format(b2s_request_impl_t *ri)
-{
-	b2s_nexus_t	*n = ri->ri_nexus;
-	union scsi_cdb	*cdb = (void *)ri->ri_pkt->pkt_cdbp;
-	size_t		len;
-	caddr_t		ptr;
-
-	if (GETG0TAG(cdb) & 0x7) {
-		b2s_request_done(&ri->ri_public, B2S_EINVAL, 0);
-		return (TRAN_ACCEPT);
-	}
-
-	if (GETG0TAG(cdb) & FPB_DATA) {
-		/*
-		 * FmtData set.  A defect list is attached.
-		 *
-		 * This is an awful lot of work just to support a command
-		 * option we don't ever care about.  SCSI-2 says we have
-		 * to do it.
-		 *
-		 * The alternative would just be to ignore the defect list
-		 * and format options altogether.  That would be a lot easier.
-		 */
-
-		b2s_request_mapin(&ri->ri_public, &ptr, &len);
-
-		if (len < 4) {
-			b2s_request_done(&ri->ri_public, B2S_EBADMSG, 0);
-			return (TRAN_ACCEPT);
-		}
-
-		if ((ptr[0] != 0) || (ptr[2] != 0) || (ptr[3] != 0) ||
-		    ((ptr[1] & 0xF9) != 0)) {
-			b2s_request_done(&ri->ri_public, B2S_EPARAM, 0);
-			return (TRAN_ACCEPT);
-		}
-
-		if (ptr[1] & 0x2) {
-			ri->ri_flags |= B2S_REQUEST_FLAG_IMMED;
-		}
-
-	} else if (GETG0TAG(cdb) & FPB_CMPLT) {
-		/*
-		 * No defect list, so this bit (CmpLst) should have been zero!
-		 */
-		b2s_request_done(&ri->ri_public, B2S_EINVAL, 0);
-		return (TRAN_ACCEPT);
-	}
-
-	ri->ri_cmd = B2S_CMD_FORMAT;
-	if (!n->n_request(n->n_private, &ri->ri_public)) {
-		return (TRAN_BUSY);
-	}
-
-	return (TRAN_ACCEPT);
-}
-
-void
-b2s_scmd_readcap_done(b2s_request_impl_t *ri)
-{
-	uint32_t		lba;
-	union scsi_cdb		*cdb = (void *)ri->ri_pkt->pkt_cdbp;
-	struct scsi_capacity	cap;
-	caddr_t			ptr;
-	size_t			resid, len;
-
-	/*
-	 * Lower layer resid is meaningless here.
-	 */
-	if (ri->ri_errno != B2S_EOK) {
-		return;
-	}
-
-	lba = GETG1ADDR(cdb);
-
-	switch (GETG1COUNT(cdb)) {
-	case 0:	/* PMI == 0 */
-		if (lba != 0) {
-			ri->ri_errno = B2S_EINVAL;
-			return;
-		}
-		break;
-	case 1:	/* PMI == 1 */
-		if (lba >= ri->ri_media.media_nblks) {
-			ri->ri_errno = B2S_EBLKADDR;
-			return;
-		}
-		break;
-	default:
-		ri->ri_errno = B2S_EINVAL;
-		return;
-	}
-
-	/*
-	 * Note that the capacity is the LBA of the last block, not the
-	 * number of blocks.  A little surprising if you don't pay close
-	 * enough attention to the spec.
-	 */
-	SCSI_WRITE32(&cap.capacity, ri->ri_media.media_nblks - 1);
-	SCSI_WRITE32(&cap.lbasize, ri->ri_media.media_blksz);
-
-	b2s_request_mapin(&ri->ri_public, &ptr, &len);
-
-	if (len != 0) {
-		resid = sizeof (cap);
-		len = min(resid, len);
-		bcopy(&cap, ptr, len);
-		ri->ri_resid = resid - len;
-	}
-}
-
-int
-b2s_scmd_readcap(b2s_request_impl_t *ri)
-{
-	b2s_nexus_t	*n = ri->ri_nexus;
-	union scsi_cdb	*cdb = (void *)ri->ri_pkt->pkt_cdbp;
-
-	/*
-	 * No transfer by real target.
-	 */
-	ri->ri_done = b2s_scmd_readcap_done;
-
-	if ((GETG1TAG(cdb)) != 0) {
-		b2s_request_done(&ri->ri_public, B2S_EINVAL, 0);
-		return (TRAN_ACCEPT);
-	}
-
-	ri->ri_cmd = B2S_CMD_GETMEDIA;
-	if (!n->n_request(n->n_private, &ri->ri_public)) {
-		return (TRAN_BUSY);
-	}
-
-	return (TRAN_ACCEPT);
-}
-
-int
-b2s_scmd_reserve_release(b2s_request_impl_t *ri)
-{
-	union scsi_cdb	*cdb = (void *)ri->ri_pkt->pkt_cdbp;
-
-	/* we aren't checking fields we don't care about */
-	if ((GETG0TAG(cdb) & 0x1) != 0)  {
-		/* extent reservations not supported */
-		b2s_request_done(&ri->ri_public, B2S_EINVAL, 0);
-		return (TRAN_ACCEPT);
-	}
-
-	/*
-	 * We don't support multi-initiator access, so we always
-	 * return success.
-	 */
-
-	b2s_request_done(&ri->ri_public, B2S_EOK, 0);
-	return (TRAN_ACCEPT);
-}
-
-int
-b2s_scmd_start_stop(b2s_request_impl_t *ri)
-{
-	b2s_nexus_t	*n = ri->ri_nexus;
-	union scsi_cdb	*cdb = (void *)ri->ri_pkt->pkt_cdbp;
-	uint8_t		count;
-
-	switch (GETG0ADDR(cdb)) {
-	case 0:
-		break;
-	case 0x10000:	/* immed set */
-		ri->ri_flags |= B2S_REQUEST_FLAG_IMMED;
-		break;
-	default:
-		b2s_request_done(&ri->ri_public, B2S_EINVAL, 0);
-		return (TRAN_ACCEPT);
-	}
-	count = GETG0COUNT(cdb);
-	if (count > 3) {
-		b2s_request_done(&ri->ri_public, B2S_EINVAL, 0);
-		return (TRAN_ACCEPT);
-	}
-	if (count & 0x2)
-		ri->ri_flags |= B2S_REQUEST_FLAG_LOAD_EJECT;
-	if (count & 0x1) {
-		ri->ri_cmd = B2S_CMD_START;
-	} else {
-		ri->ri_cmd = B2S_CMD_STOP;
-	}
-
-	if (!n->n_request(n->n_private, &ri->ri_public)) {
-		return (TRAN_BUSY);
-	}
-	return (TRAN_ACCEPT);
-}
-
-void
-b2s_scmd_mode_sense_done(b2s_request_impl_t *ri)
-{
-	uchar_t			*cdb = ri->ri_pkt->pkt_cdbp;
-	uint8_t			pc, page, devspec;
-	caddr_t			ptr;
-	size_t			len, resid;
-	uint8_t			data[16];
-
-	if ((ri->ri_errno == 0) &&
-	    ((ri->ri_media.media_flags & B2S_MEDIA_FLAG_READ_ONLY) == 0))  {
-		devspec = 0;
-	} else {
-		/* this marks the media read-only */
-		devspec = 0x80;
-	}
-
-	pc = page = cdb[2];
-	pc &= 0xc0;
-	page &= 0x3f;
-
-	/* we do not support savable parameters, at all */
-	if ((pc & 0xc0) == 0x3) {
-		ri->ri_errno = B2S_ENOSAV;
-		ri->ri_resid = 0;
-		return;
-	}
-
-	b2s_request_mapin(&ri->ri_public, &ptr, &resid);
-
-	if ((page == 0x9) || (page == 0x3f)) {
-		/* Peripheral device page */
-
-		/* header */
-		data[0] = 9 + 3;	/* length following */
-		data[1] = 0;		/* medium type */
-		data[2] = devspec;	/* mostly r/w flag */
-		data[3] = 0;		/* block descriptor len */
-		len = min(4, resid);
-
-		bcopy(data, ptr, len);
-		resid -= len;
-		ptr += len;
-
-		/* page data - 9 bytes long */
-		bzero(data, 9);
-		data[0] = 0x9;		/* page code */
-		data[1] = 0x8;		/* following data */
-		len = min(resid, 9);
-		bcopy(data, ptr, len);
-		resid -= len;
-		ptr += len;
-	}
-
-	if ((page == 0xa) || (page == 0x3f)) {
-		/* Control mode page */
-
-		/* header */
-		data[0] = 8 + 3;	/* length following */
-		data[1] = 0;		/* medium type */
-		data[2] = devspec;	/* mostly r/w flag */
-		data[3] = 0;		/* block descriptor len */
-		len = min(4, resid);
-
-		bcopy(data, ptr, len);
-		resid -= len;
-		ptr += len;
-
-		/* page data - 9 bytes long */
-		bzero(data, 8);
-		data[0] = 0xa;		/* page code */
-		data[1] = 0x7;		/* following data */
-		len = min(resid, 9);
-		bcopy(data, ptr, len);
-		resid -= len;
-		ptr += len;
-	}
-
-	ri->ri_resid = 0;
-	ri->ri_errno = B2S_EOK;
-}
-
-int
-b2s_scmd_mode_sense(b2s_request_impl_t *ri)
-{
-	b2s_nexus_t	*n = ri->ri_nexus;
-
-	ri->ri_done = b2s_scmd_mode_sense_done;
-	ri->ri_cmd = B2S_CMD_GETMEDIA;
-	if (!n->n_request(n->n_private, &ri->ri_public)) {
-		return (TRAN_BUSY);
-	}
-	return (TRAN_ACCEPT);
-}
-
-int
-b2s_scmd_rw(b2s_request_impl_t *ri)
-{
-	b2s_nexus_t	*n = ri->ri_nexus;
-	uint32_t	lba;
-	uint32_t	nblks;
-	union scsi_cdb	*cdb = (void *)ri->ri_pkt->pkt_cdbp;
-
-	switch (GETGROUP(cdb)) {
-	case CDB_GROUPID_0:
-		nblks = GETG0COUNT(cdb);
-		nblks = nblks ? nblks : 256;
-		lba = GETG0ADDR(cdb);
-		break;
-	case CDB_GROUPID_1:
-		if (GETG1TAG(cdb)) {
-			/* we don't support relative addresses */
-			b2s_request_done(&ri->ri_public, B2S_EINVAL, 0);
-			return (TRAN_ACCEPT);
-		}
-		lba = GETG1ADDR(cdb);
-		nblks = GETG1COUNT(cdb);
-		break;
-	default:
-		b2s_request_done(&ri->ri_public, B2S_ENOTSUP, 0);
-		return (TRAN_ACCEPT);
-	}
-
-	if (nblks == 0) {
-		b2s_request_done(&ri->ri_public, 0, 0);
-		return (TRAN_ACCEPT);
-	}
-
-	ri->ri_nblks = nblks;
-	ri->ri_lba = lba;
-	ri->ri_flags |= B2S_REQUEST_FLAG_BLKS;
-	ri->ri_cmd = (GETCMD(cdb)) == SCMD_READ ?
-	    B2S_CMD_READ : B2S_CMD_WRITE;
-
-	if (!n->n_request(n->n_private, &ri->ri_public)) {
-		return (TRAN_BUSY);
-	}
-	return (TRAN_ACCEPT);
-}
-
-void
-b2s_warn(b2s_leaf_t *l, const char *fmt, ...)
-{
-	va_list		ap;
-	b2s_nexus_t	*n;
-	char		msg[256];
-
-	n = l->l_nexus;
-
-	(void) snprintf(msg, sizeof (msg), "%s%d target %d lun %d: %s",
-	    ddi_driver_name(n->n_dip), ddi_get_instance(n->n_dip),
-	    l->l_target, l->l_lun, fmt);
-
-	va_start(ap, fmt);
-	vcmn_err(CE_WARN, msg, ap);
-	va_end(ap);
-}
-
-b2s_nexus_t *
-b2s_alloc_nexus(b2s_nexus_info_t *info)
-{
-	b2s_nexus_t		*n;
-	struct scsi_hba_tran	*tran;
-
-	if (info->nexus_version != B2S_VERSION_0)
-		return (NULL);
-
-	n = kmem_zalloc(sizeof (*n), KM_SLEEP);
-	mutex_init(&n->n_lock, NULL, MUTEX_DRIVER, NULL);
-	cv_init(&n->n_cv, NULL, CV_DRIVER, NULL);
-	list_create(&n->n_leaves, sizeof (struct b2s_leaf),
-	    offsetof(struct b2s_leaf, l_node));
-
-	n->n_dip = info->nexus_dip;
-	n->n_private = info->nexus_private;
-	n->n_request = info->nexus_request;
-	if (info->nexus_dma_attr != NULL) {
-		n->n_dma = info->nexus_dma_attr;
-	} else {
-		n->n_dma = &b2s_default_dma_attr;
-	}
-
-	tran = scsi_hba_tran_alloc(n->n_dip, SCSI_HBA_CANSLEEP);
-	if (tran == NULL) {
-		list_destroy(&n->n_leaves);
-		mutex_destroy(&n->n_lock);
-		cv_destroy(&n->n_cv);
-		kmem_free(n, sizeof (*n));
-		return (NULL);
-	}
-	n->n_tran =  tran;
-
-	tran->tran_hba_dip =		n->n_dip;
-	tran->tran_hba_private =	n;
-	tran->tran_tgt_private =	NULL;
-	tran->tran_tgt_init =		b2s_tran_tgt_init;
-	tran->tran_tgt_free =		b2s_tran_tgt_free;
-	tran->tran_tgt_probe =		scsi_hba_probe;
-	tran->tran_tgt_free =		NULL;
-	tran->tran_start =		b2s_tran_start;
-	tran->tran_reset = 		b2s_tran_reset;
-	tran->tran_abort = 		b2s_tran_abort;
-	tran->tran_getcap = 		b2s_tran_getcap;
-	tran->tran_setcap = 		b2s_tran_setcap;
-	tran->tran_init_pkt =		b2s_tran_init_pkt;
-	tran->tran_destroy_pkt =	b2s_tran_destroy_pkt;
-	tran->tran_hba_len =		sizeof (b2s_request_impl_t);
-	tran->tran_bus_config =		b2s_bus_config;
-
-	return (n);
-}
-
-void
-b2s_free_nexus(b2s_nexus_t *n)
-{
-	b2s_leaf_t *l;
-
-	/*
-	 * Toss any registered leaves, if we haven't already done so.
-	 * At this point we don't care about upper layers, because the
-	 * DDI should not have allowed us to detach if there were busy
-	 * targets.
-	 */
-	while ((l = list_head(&n->n_leaves)) != NULL) {
-		list_remove(&n->n_leaves, l);
-		kmem_free(l, sizeof (struct b2s_leaf));
-	}
-	list_destroy(&n->n_leaves);
-	mutex_destroy(&n->n_lock);
-	cv_destroy(&n->n_cv);
-	kmem_free(n, sizeof (struct b2s_nexus));
-}
-
-int
-b2s_attach_nexus(b2s_nexus_t *n)
-{
-	int	rv;
-
-	rv = scsi_hba_attach_setup(n->n_dip, n->n_dma, n->n_tran,
-	    SCSI_HBA_TRAN_SCB | SCSI_HBA_TRAN_CDB | SCSI_HBA_TRAN_CLONE);
-	if (rv == 0) {
-		n->n_attached = B_TRUE;
-	}
-	return (rv);
-}
-
-int
-b2s_detach_nexus(b2s_nexus_t *n)
-{
-	int	rv;
-
-	if (n->n_attached) {
-		rv = scsi_hba_detach(n->n_dip);
-		if (rv == 0) {
-			n->n_attached = B_FALSE;
-		}
-	} else {
-		rv = 0;
-	}
-	return ((rv == 0) ? DDI_SUCCESS : DDI_FAILURE);
-}
-
-b2s_leaf_t *
-b2s_attach_leaf(b2s_nexus_t *n, b2s_leaf_info_t *info)
-{
-	b2s_leaf_t	*l;
-	uint_t		target	= info->leaf_target;
-	uint_t		lun	= info->leaf_lun;
-	const char	*uuid	= info->leaf_unique_id;
-	uint32_t	flags	= info->leaf_flags;
-	uint64_t	eui	= info->leaf_eui;
-
-	if (uuid == NULL) {
-		uuid = "";
-	}
-
-	mutex_enter(&n->n_lock);
-
-	/*
-	 * If the leaf already exists, it is a sign that the device
-	 * was kept around because it was still in use.  In that case,
-	 * we attempt to detect the situation where the node is the same
-	 * as the previous one, and reconnect it.
-	 */
-	if ((l = b2s_get_leaf(n, target, lun)) != NULL) {
-		if (strcmp(l->l_uuid, uuid) != 0) {
-			/*
-			 * Leaf already exists, but is not the same!  This
-			 * would be a good time to issue a warning.
-			 */
-			mutex_exit(&n->n_lock);
-			b2s_warn(l, "Target disconnected while still in use.");
-			b2s_warn(l, "Reconnect the previous target device.");
-			return (NULL);
-		}
-		l->l_flags &= ~B2S_LEAF_DETACHED;
-	} else {
-		if ((l = kmem_zalloc(sizeof (*l), KM_NOSLEEP)) == NULL) {
-			mutex_exit(&n->n_lock);
-			b2s_warn(l, "Unable to allocate target state.");
-			return (NULL);
-		}
-		l->l_nexus = n;
-		l->l_target = target;
-		l->l_lun = lun;
-		l->l_flags = flags;
-		l->l_eui = eui;
-
-		/* strdup would be nice here */
-		l->l_uuid = kmem_alloc(strlen(uuid) + 1, KM_NOSLEEP);
-		if (l->l_uuid == NULL) {
-			mutex_exit(&n->n_lock);
-			kmem_free(l, sizeof (*l));
-			b2s_warn(l, "Unable to allocate target UUID storage.");
-			return (NULL);
-		}
-		(void) strcpy(l->l_uuid, uuid);
-
-		list_insert_tail(&n->n_leaves, l);
-	}
-
-	/*
-	 * Make sure we hold it, so that it won't be freed out from
-	 * underneath us.
-	 */
-	l->l_refcnt++;
-	mutex_exit(&n->n_lock);
-
-	/*
-	 * If the HBA is currently attached, then we need to attach
-	 * the node right now.  This supports "hotplug".  Note that
-	 * if the node is a reinsert, then this should degenerate into
-	 * a NOP.
-	 */
-	if (n->n_attached) {
-		int	circ;
-		ndi_devi_enter(n->n_dip, &circ);
-		(void) b2s_create_node(n, l, NULL);
-		ndi_devi_exit(n->n_dip, circ);
-	}
-
-	return (l);
-}
-
-void
-b2s_detach_leaf(b2s_leaf_t *l)
-{
-	b2s_nexus_t	*n = l->l_nexus;
-	dev_info_t	*dip;
-	int		circ;
-
-	l->l_flags |= B2S_LEAF_DETACHED;
-
-	/*
-	 * Search for an appropriate child devinfo.
-	 */
-	ndi_devi_enter(n->n_dip, &circ);
-	dip = b2s_find_node(n, l);
-	if (dip != NULL) {
-		(void) ndi_devi_offline(dip, NDI_DEVI_REMOVE);
-	}
-	ndi_devi_exit(n->n_dip, circ);
-
-	b2s_rele_leaf(l);
-}
--- a/usr/src/uts/common/io/sdcard/adapters/sdhost/sdhost.c	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/common/io/sdcard/adapters/sdhost/sdhost.c	Mon May 17 21:17:01 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include "sdhost.h"
@@ -368,7 +367,7 @@
 	}
 
 	shp->sh_host = sda_host_alloc(dip, shp->sh_numslots, &sdhost_ops,
-	    &shp->sh_dmaattr);
+	    NULL);
 	if (shp->sh_host == NULL) {
 		cmn_err(CE_WARN, "Failed allocating SD host structure");
 		goto failed;
--- a/usr/src/uts/common/io/sdcard/impl/mapfile	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/common/io/sdcard/impl/mapfile	Mon May 17 21:17:01 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 #
@@ -55,10 +54,6 @@
 		sda_host_fault;
 		sda_host_log;
 
-		# project private interfaces used by sdcard
-		sda_mem_init;
-		sda_mem_fini;
-
 	local:
 		*;
 };
--- a/usr/src/uts/common/io/sdcard/impl/sda_cmd.c	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/common/io/sdcard/impl/sda_cmd.c	Mon May 17 21:17:01 2010 -0700
@@ -19,18 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
  * SD card common framework.  This module provides most of the common
  * functionality so that SecureDigital host adapters and client devices
  * (such as the sdcard driver) can share common code.
- *
- * NB that this file contains a fair bit of non-DDI compliant code.
- * But writing a nexus driver would be impossible to do with only DDI
- * compliant interfaces.
  */
 
 #include <sys/types.h>
@@ -74,7 +69,8 @@
 #define	c_resid		c_public.sc_resid
 #define	c_flags		c_public.sc_flags
 #define	c_ndmac		c_public.sc_ndmac
-#define	c_dmacs		c_public.sc_dmacs
+#define	c_dmah		c_public.sc_dmah
+#define	c_dmac		c_public.sc_dmac
 #define	c_kvaddr	c_public.sc_kvaddr
 
 /*
@@ -224,14 +220,21 @@
 		errno = SDA_ENODEV;
 	}
 	if (errno != SDA_EOK) {
-		sda_slot_exit(slot);
-		/* fail it synchronously */
-		sda_cmd_notify(cmdp, SDA_CMDF_DAT | SDA_CMDF_BUSY, errno);
-		return;
-	}
+		/*
+		 * We have to return failure conditions asynchronously.
+		 * What we do in this case is mark the command failed,
+		 * and move it to the abortlist so that the slot thread
+		 * will execute the failure notification asynchronously.
+		 *
+		 * NB: using 0 for flags ensures that we don't execute
+		 * the notification callback yet, we're just stashing
+		 * the errno.
+		 */
+		sda_cmd_notify(cmdp, 0, errno);
+		list_insert_tail(&slot->s_abortlist, cmdp);
 
-	/* Initialization commands go to the head of the class */
-	if (c->c_flags & SDA_CMDF_INIT) {
+	} else if (c->c_flags & SDA_CMDF_INIT) {
+		/* Initialization commands go to the head of the class */
 		list_insert_head(&slot->s_cmdlist, c);
 	} else {
 		list_insert_tail(&slot->s_cmdlist, c);
@@ -274,8 +277,10 @@
 	c->c_blksz = 0;
 
 	c->c_kvaddr = 0;
+	c->c_dmah = 0;
 	c->c_ndmac = 0;
-	c->c_dmacs = NULL;
+	c->c_dmah = NULL;
+	bzero(&c->c_dmac, sizeof (c->c_dmac));
 	c->c_flags = 0;
 
 	c->c_slot = slot;
@@ -309,7 +314,8 @@
 
 	c->c_kvaddr = 0;
 	c->c_ndmac = 0;
-	c->c_dmacs = NULL;
+	c->c_dmah = NULL;
+	bzero(&c->c_dmac, sizeof (c->c_dmac));
 	c->c_flags = 0;
 
 	c->c_slot = slot;
--- a/usr/src/uts/common/io/sdcard/impl/sda_host.c	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/common/io/sdcard/impl/sda_host.c	Mon May 17 21:17:01 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -37,78 +36,19 @@
 #include <sys/sdcard/sda_impl.h>
 
 /*
- * Static Variables.
- */
-
-static struct bus_ops sda_host_bus_ops = {
-	BUSO_REV,			/* busops_rev */
-	nullbusmap,			/* bus_map */
-	NULL,				/* bus_get_intrspec (OBSOLETE) */
-	NULL,				/* bus_add_intrspec (OBSOLETE) */
-	NULL,				/* bus_remove_intrspec (OBSOLETE) */
-	i_ddi_map_fault,		/* bus_map_fault */
-	ddi_dma_map,			/* bus_dma_map */
-	ddi_dma_allochdl,		/* bus_dma_allochdl */
-	ddi_dma_freehdl,		/* bus_dma_freehdl */
-	ddi_dma_bindhdl,		/* bus_dma_bindhdl */
-	ddi_dma_unbindhdl,		/* bus_dma_unbindhdl */
-	ddi_dma_flush,			/* bus_dma_flush */
-	ddi_dma_win,			/* bus_dma_win */
-	ddi_dma_mctl,			/* bus_dma_ctl */
-	sda_nexus_bus_ctl,		/* bus_ctl */
-	ddi_bus_prop_op,		/* bus_prop_op */
-	NULL,				/* bus_get_eventcookie */
-	NULL,				/* bus_add_eventcall */
-	NULL,				/* bus_remove_eventcall */
-	NULL,				/* bus_post_event */
-	NULL,				/* bus_intr_ctl (OBSOLETE) */
-	NULL, /* sda_nexus_bus_config, */		/* bus_config */
-	NULL, /* sda_nexus_bus_unconfig, */		/* bus_unconfig */
-	NULL,				/* bus_fm_init */
-	NULL,				/* bus_fm_fini */
-	NULL,				/* bus_fm_access_enter */
-	NULL,				/* bus_fm_access_exit */
-	NULL,				/* bus_power */
-	NULL,				/* bus_intr_op */
-};
-
-static struct cb_ops sda_host_cb_ops = {
-	sda_nexus_open,			/* cb_open */
-	sda_nexus_close,		/* cb_close */
-	nodev,				/* cb_strategy */
-	nodev,				/* cb_print */
-	nodev,				/* cb_dump */
-	nodev,				/* cb_read */
-	nodev,				/* cb_write */
-	sda_nexus_ioctl,		/* cb_ioctl */
-	nodev,				/* cb_devmap */
-	nodev,				/* cb_mmap */
-	nodev,				/* cb_segmap */
-	nochpoll,			/* cb_poll */
-	ddi_prop_op,			/* cb_prop_op */
-	NULL,				/* cb_str */
-	D_MP,				/* cb_flag */
-	CB_REV,				/* cb_rev */
-	nodev,				/* cb_aread */
-	nodev,				/* cb_awrite */
-};
-
-/*
  * Implementation.
  */
 
 void
 sda_host_init_ops(struct dev_ops *devops)
 {
-	devops->devo_getinfo = sda_nexus_getinfo;
-	devops->devo_cb_ops = &sda_host_cb_ops;
-	devops->devo_bus_ops = &sda_host_bus_ops;
+	bd_mod_init(devops);
 }
 
 void
 sda_host_fini_ops(struct dev_ops *devops)
 {
-	devops->devo_bus_ops = NULL;
+	bd_mod_fini(devops);
 }
 
 sda_host_t *
@@ -173,11 +113,6 @@
 		sda_host_detect(h, i);
 	}
 
-	/*
-	 * Register (create) nexus minor nodes.
-	 */
-	sda_nexus_register(h);
-
 	return (DDI_SUCCESS);
 }
 
@@ -185,11 +120,6 @@
 sda_host_detach(sda_host_t *h)
 {
 	/*
-	 * Unregister nexus minor nodes.
-	 */
-	sda_nexus_unregister(h);
-
-	/*
 	 * Detach slots.
 	 */
 	for (int i = 0; i < h->h_nslot; i++) {
--- a/usr/src/uts/common/io/sdcard/impl/sda_mem.c	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/common/io/sdcard/impl/sda_mem.c	Mon May 17 21:17:01 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -30,23 +29,16 @@
 #include <sys/types.h>
 #include <sys/note.h>
 #include <sys/conf.h>
-#include <sys/scsi/adapters/blk2scsa.h>
+#include <sys/blkdev.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
 #include <sys/sdcard/sda.h>
 #include <sys/sdcard/sda_impl.h>
 
-static int sda_mem_attach(dev_info_t *, ddi_attach_cmd_t);
-static int sda_mem_detach(dev_info_t *, ddi_detach_cmd_t);
-static int sda_mem_quiesce(dev_info_t *);
-static b2s_err_t sda_mem_b2s_errno(sda_err_t);
-static boolean_t sda_mem_b2s_request(void *, b2s_request_t *);
-static boolean_t sda_mem_b2s_rw(sda_slot_t *, b2s_request_t *);
-static void sda_mem_b2s_done(sda_cmd_t *);
+static int sda_mem_errno(sda_err_t);
+static int sda_mem_rw(sda_slot_t *, bd_xfer_t *, uint8_t, uint16_t);
+static void sda_mem_done(sda_cmd_t *);
 static void sda_mem_getstring(uint32_t *, char *, int, int);
-static int sda_mem_parse_cid_csd(sda_slot_t *, dev_info_t *);
-static int sda_mem_cmd(sda_slot_t *, uint8_t, uint32_t, uint8_t, uint32_t *);
-
 
 /*
  * To minimize complexity and reduce layering, we implement almost the
@@ -56,417 +48,160 @@
  */
 
 /*
- * SCSA layer supplies a cb_ops, but we don't want it, because we
- * don't want to expose a SCSI attachment point.  (Our parent handles
- * the attachment point, the SCSI one would be confusing.)  We have to
- * supply a stubbed out one, to prevent SCSA from trying to create minor
- * nodes on our behalf.
- *
- * Perhaps at some future point we might want to expose a separate set
- * of ioctls for these nodes, but for now we rely on our parent to do
- * all that work.
- */
-static struct cb_ops sda_mem_ops = {
-	nodev,			/* cb_open */
-	nodev,			/* cb_close */
-	nodev,			/* cb_strategy */
-	nodev,			/* cb_print */
-	nodev,			/* cb_dump */
-	nodev,			/* cb_read */
-	nodev,			/* cb_write */
-	nodev,			/* cb_ioctl */
-	nodev,			/* cb_devmap */
-	nodev,			/* cb_mmap */
-	nodev,			/* cb_segmap */
-	nochpoll,		/* cb_chpoll */
-	ddi_prop_op,		/* cb_prop_op */
-	NULL,			/* cb_stream */
-	D_MP			/* cb_flag */
-};
-
-/*
- * Here are the public functions.
- */
-void
-sda_mem_init(struct modlinkage *modlp)
-{
-	struct dev_ops *devo;
-
-	devo = ((struct modldrv *)(modlp->ml_linkage[0]))->drv_dev_ops;
-	devo->devo_attach = sda_mem_attach;
-	devo->devo_detach = sda_mem_detach;
-	devo->devo_quiesce = sda_mem_quiesce;
-
-	devo->devo_cb_ops = &sda_mem_ops;
-
-	/* it turns out that this can't ever really fail */
-	(void) b2s_mod_init(modlp);
-}
-
-void
-sda_mem_fini(struct modlinkage *modlp)
-{
-	b2s_mod_fini(modlp);
-}
-
-/*
  * Everything beyond this is private.
  */
 
 int
-sda_mem_cmd(sda_slot_t *slot, uint8_t cmd, uint32_t arg, uint8_t rtype,
-    uint32_t *resp)
+sda_mem_errno(sda_err_t errno)
 {
-	sda_cmd_t	*cmdp;
-	int		errno;
+	/* the hot path */
+	if (errno == SDA_EOK) {
+		return (0);
+	}
 
-	cmdp = sda_cmd_alloc(slot, cmd, arg, rtype, NULL, KM_SLEEP);
-	if (cmdp == NULL) {
+	switch (errno) {
+	case SDA_ENOMEM:
 		return (ENOMEM);
+	case SDA_ETIME:
+		return (ETIMEDOUT);
+	case SDA_EWPROTECT:
+		return (EROFS);
+	case SDA_ESUSPENDED:
+	case SDA_ENODEV:
+		return (ENODEV);
+	case SDA_EFAULT:
+	case SDA_ECRC7:
+	case SDA_EPROTO:
+	case SDA_ERESET:
+	case SDA_EIO:
+	case SDA_ERESID:
+	default:
+		return (EIO);
 	}
-	errno = sda_cmd_exec(slot, cmdp, resp);
-	sda_cmd_free(cmdp);
-
-	return (errno);
 }
 
-boolean_t
-sda_mem_b2s_rw(sda_slot_t *slot, b2s_request_t *reqp)
+void
+sda_mem_done(sda_cmd_t *cmdp)
+{
+	bd_xfer_t	*xfer = sda_cmd_data(cmdp);
+	int		errno = sda_cmd_errno(cmdp);
+
+	bd_xfer_done(xfer, sda_mem_errno(errno));
+	sda_cmd_free(cmdp);
+}
+
+int
+sda_mem_rw(sda_slot_t *slot, bd_xfer_t *xfer, uint8_t cmd, uint16_t flags)
 {
 	sda_cmd_t	*cmdp;
 	uint64_t	nblks;
 	uint64_t	blkno;
 	uint16_t	rblen;
-	int		rv;
-	uint8_t		index;
-	uint16_t	flags;
 
-	blkno = reqp->br_lba;
-	nblks = reqp->br_nblks;
+	blkno = xfer->x_blkno;
+	nblks = xfer->x_nblks;
 
-	switch (reqp->br_cmd) {
-	case B2S_CMD_READ:
-		if (nblks > 1) {
-			index = CMD_READ_MULTI;
-			flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_READ |
-			    SDA_CMDF_AUTO_CMD12;
-		} else {
-			index = CMD_READ_SINGLE;
-			flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_READ;
-		}
-		break;
-	case B2S_CMD_WRITE:
-		if (nblks > 1) {
-			index = CMD_WRITE_MULTI;
-			flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_WRITE |
-			    SDA_CMDF_AUTO_CMD12;
-		} else {
-			index = CMD_WRITE_SINGLE;
-			flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_WRITE;
-		}
-		break;
-	default:
-		ASSERT(0);
-		break;
+	ASSERT(nblks != 0);
+
+	if ((blkno + nblks) > slot->s_nblks) {
+		return (EINVAL);
 	}
 
-	cmdp = sda_cmd_alloc(slot, index, blkno << slot->s_bshift,
-	    R1, reqp, KM_NOSLEEP);
+	cmdp = sda_cmd_alloc(slot, cmd, blkno << slot->s_bshift,
+	    R1, xfer, KM_NOSLEEP);
 	if (cmdp == NULL) {
-		b2s_request_done(reqp, B2S_ENOMEM, 0);
-		return (B_TRUE);
+		return (ENOMEM);
 	}
 
 	if (slot->s_hostp->h_dma != NULL) {
-		b2s_request_dma(reqp, &cmdp->sc_ndmac, &cmdp->sc_dmacs);
+		cmdp->sc_dmah = xfer->x_dmah;
+		cmdp->sc_ndmac = xfer->x_ndmac;
+		cmdp->sc_dmac = xfer->x_dmac;
 		cmdp->sc_kvaddr = 0;
 	} else {
 		cmdp->sc_ndmac = 0;
-	}
-	if ((slot->s_caps & SLOT_CAP_NOPIO) == 0) {
-		size_t	maplen;
-		b2s_request_mapin(reqp, &cmdp->sc_kvaddr, &maplen);
-	}
-
-	if (nblks == 0) {
-		/*
-		 * This is not strictly a failure, but no work to do.
-		 * We have to do it late here because we don't want to
-		 * by pass the above media readiness checks.
-		 */
-		rv = B2S_EOK;
-		goto failed;
-	}
-	if (nblks > 0xffff) {
-		rv = B2S_EINVAL;
-		goto failed;
+		cmdp->sc_kvaddr = xfer->x_kaddr;
 	}
 
 	rblen = slot->s_blksz;
 
-	if ((blkno + nblks) > slot->s_nblks) {
-		rv = B2S_EBLKADDR;
-		goto failed;
-	}
-
-	cmdp->sc_rtype = R1;
+	/* other fields are set by sda_cmd_alloc */
 	cmdp->sc_blksz = rblen;
 	cmdp->sc_nblks = (uint16_t)nblks;
-	cmdp->sc_index = index;
 	cmdp->sc_flags = flags;
 
-	sda_cmd_submit(slot, cmdp, sda_mem_b2s_done);
-	return (B_TRUE);
-
-failed:
-	sda_cmd_free(cmdp);
-	b2s_request_done(reqp, rv, 0);
-	return (B_TRUE);
+	sda_cmd_submit(slot, cmdp, sda_mem_done);
+	return (0);
 }
 
-boolean_t
-sda_mem_b2s_format(sda_slot_t *slot, b2s_request_t *reqp)
+int
+sda_mem_bd_read(void *arg, bd_xfer_t *xfer)
 {
-	sda_cmd_t	*cmdp;
-	int		rv;
-
+	sda_slot_t	*slot = arg;
+	uint8_t		cmd;
+	uint16_t	flags;
 
-	rv = sda_mem_cmd(slot, CMD_ERASE_START, 0, R1, NULL);
-	if (rv != 0) {
-		b2s_request_done(reqp, sda_mem_b2s_errno(rv), 0);
-		return (B_TRUE);
-	}
-	rv = sda_mem_cmd(slot, CMD_ERASE_END, slot->s_nblks - 1, R1, NULL);
-	if (rv != 0) {
-		b2s_request_done(reqp, sda_mem_b2s_errno(rv), 0);
-		return (B_TRUE);
+	if (xfer->x_nblks > 1) {
+		cmd = CMD_READ_MULTI;
+		flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_READ |
+		    SDA_CMDF_AUTO_CMD12;
+	} else {
+		cmd = CMD_READ_SINGLE;
+		flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_READ;
 	}
 
-	cmdp = sda_cmd_alloc(slot, CMD_ERASE, 0, R1b, reqp, KM_NOSLEEP);
-	if (cmdp == NULL) {
-		b2s_request_done(reqp, B2S_ENOMEM, 0);
-		return (B_TRUE);
-	}
-	cmdp->sc_flags = SDA_CMDF_DAT | SDA_CMDF_MEM;
-
-	sda_cmd_submit(slot, cmdp, sda_mem_b2s_done);
-	return (B_TRUE);
+	return (sda_mem_rw(slot, xfer, cmd, flags));
 }
 
-b2s_err_t
-sda_mem_b2s_errno(sda_err_t errno)
+int
+sda_mem_bd_write(void *arg, bd_xfer_t *xfer)
 {
-	/* the hot path */
-	if (errno == SDA_EOK) {
-		return (B2S_EOK);
+	sda_slot_t	*slot = arg;
+	uint8_t		cmd;
+	uint16_t	flags;
+
+	if ((slot->s_flags & SLOTF_WRITABLE) == 0) {
+		return (EROFS);
+	}
+	if (xfer->x_nblks > 1) {
+		cmd = CMD_WRITE_MULTI;
+		flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_WRITE |
+		    SDA_CMDF_AUTO_CMD12;
+	} else {
+		cmd = CMD_WRITE_SINGLE;
+		flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_WRITE;
 	}
 
-	switch (errno) {
-	case SDA_ENOMEM:
-		return (B2S_ENOMEM);
-	case SDA_ETIME:
-		return (B2S_ETIMEDOUT);
-	case SDA_EWPROTECT:
-		return (B2S_EWPROTECT);
-	case SDA_ESUSPENDED:
-	case SDA_ENODEV:
-		return (B2S_ENOMEDIA);
-	case SDA_EFAULT:
-	case SDA_ECRC7:
-	case SDA_EPROTO:
-		return (B2S_EHARDWARE);
-	case SDA_ERESET:
-		return (B2S_ERESET);
-	case SDA_EIO:
-	case SDA_ERESID:
-	default:
-		return (B2S_EIO);
-	}
+	return (sda_mem_rw(slot, xfer, cmd, flags));
 }
 
 void
-sda_mem_b2s_done(sda_cmd_t *cmdp)
-{
-	b2s_request_t	*reqp = sda_cmd_data(cmdp);
-	int		errno = sda_cmd_errno(cmdp);
-
-	b2s_request_done(reqp, sda_mem_b2s_errno(errno), cmdp->sc_resid);
-	sda_cmd_free(cmdp);
-}
-
-boolean_t
-sda_mem_b2s_request(void *arg, b2s_request_t *reqp)
+sda_mem_bd_driveinfo(void *arg, bd_drive_t *drive)
 {
 	sda_slot_t	*slot = arg;
-	int		rv;
 
-	switch (reqp->br_cmd) {
-	case B2S_CMD_WRITE:
-		if ((slot->s_flags & SLOTF_WRITABLE) == 0) {
-			rv = B2S_EWPROTECT;
-		} else {
-			return (sda_mem_b2s_rw(slot, reqp));
-		}
-		break;
-
-	case B2S_CMD_READ:
-		return (sda_mem_b2s_rw(slot, reqp));
-
-	case B2S_CMD_INQUIRY:
-		reqp->br_inquiry.inq_vendor = "OSOL";
-		reqp->br_inquiry.inq_product =
-		    slot->s_flags & SLOTF_MMC ? "MultiMediaCard" :
-		    slot->s_flags & SLOTF_SDHC ? "SDHC Memory Card" :
-		    "SD Memory Card";
-		reqp->br_inquiry.inq_revision = "";
-		reqp->br_inquiry.inq_serial = "";
-		rv = B2S_EOK;
-		break;
-
-	case B2S_CMD_GETMEDIA:
-		if (!slot->s_ready) {
-			rv = B2S_ENODEV;
-		} else {
-			reqp->br_media.media_blksz = slot->s_blksz;
-			reqp->br_media.media_nblks = slot->s_nblks;
-			/* detect read-only cards */
-			if (slot->s_flags & SLOTF_WRITABLE) {
-				reqp->br_media.media_flags = 0;
-			} else {
-				reqp->br_media.media_flags =
-				    B2S_MEDIA_FLAG_READ_ONLY;
-			}
-			rv = B2S_EOK;
-		}
-		break;
-
-	case B2S_CMD_FORMAT:
-		return (sda_mem_b2s_format(slot, reqp));
-
-	case B2S_CMD_ABORT:
-		sda_slot_mem_reset(slot, SDA_EABORT);
-		rv = B2S_EOK;
-		break;
-
-	case B2S_CMD_RESET:
-		sda_slot_mem_reset(slot, SDA_ERESET);
-		rv = B2S_EOK;
-		break;
-
-	case B2S_CMD_START:
-	case B2S_CMD_STOP:
-	case B2S_CMD_SYNC:
-		rv = B2S_EOK;
-		break;
-
-	case B2S_CMD_LOCK:
-	case B2S_CMD_UNLOCK:
-	default:
-		rv = B2S_ENOTSUP;
-		break;
-	}
-
-	b2s_request_done(reqp, rv, 0);
-	return (B_TRUE);
+	drive->d_qsize = 4;	/* we queue up internally, 4 is enough */
+	drive->d_maxxfer = 65536;
+	drive->d_removable = B_TRUE;
+	drive->d_hotpluggable = B_FALSE;
+	drive->d_target = slot->s_slot_num;
 }
 
 int
-sda_mem_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+sda_mem_bd_mediainfo(void *arg, bd_media_t *media)
 {
-	sda_slot_t		*slot;
-	b2s_nexus_t		*nexus;
-	b2s_nexus_info_t	nexinfo;
-	b2s_leaf_info_t		leafinfo;
-
-	switch (cmd) {
-	case DDI_ATTACH:
-		if ((slot = ddi_get_parent_data(dip)) == NULL) {
-			return (DDI_FAILURE);
-		}
-
-		if (sda_mem_parse_cid_csd(slot, dip) != DDI_SUCCESS) {
-			return (DDI_FAILURE);
-		}
-
-		nexinfo.nexus_version = B2S_VERSION_0;
-		nexinfo.nexus_private = slot;
-		nexinfo.nexus_dip = dip;
-		nexinfo.nexus_dma_attr = slot->s_hostp->h_dma;
-		nexinfo.nexus_request = sda_mem_b2s_request;
-
-		nexus = b2s_alloc_nexus(&nexinfo);
-		if (nexus == NULL) {
-			return (DDI_FAILURE);
-		}
-
-		leafinfo.leaf_target = 0;
-		leafinfo.leaf_lun = 0;
-		leafinfo.leaf_flags =
-		    B2S_LEAF_REMOVABLE | B2S_LEAF_HOTPLUGGABLE;
-		leafinfo.leaf_unique_id = slot->s_uuid;
-		leafinfo.leaf_eui = 0;
-
-		slot->s_leaf = b2s_attach_leaf(nexus, &leafinfo);
-		if (slot->s_leaf == NULL) {
-			b2s_free_nexus(nexus);
-			return (DDI_FAILURE);
-		}
+	sda_slot_t	*slot = arg;
 
-		slot->s_nexus = nexus;
-		if (b2s_attach_nexus(nexus) != DDI_SUCCESS) {
-			slot->s_nexus = NULL;
-			b2s_free_nexus(nexus);
-			return (DDI_FAILURE);
-		}
-		slot->s_nexus = nexus;
-
-		return (DDI_SUCCESS);
-
-
-	case DDI_RESUME:
-		return (DDI_SUCCESS);
-
-	default:
-		return (DDI_FAILURE);
+	sda_slot_enter(slot);
+	if (!slot->s_ready) {
+		sda_slot_exit(slot);
+		return (ENXIO);
 	}
-}
-
-int
-sda_mem_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
-{
-	sda_slot_t	*slot;
-	b2s_nexus_t	*nexus;
-
-	switch (cmd) {
-	case DDI_DETACH:
-		if ((slot = ddi_get_parent_data(dip)) == NULL) {
-			return (DDI_FAILURE);
-		}
-		if ((nexus = slot->s_nexus) == NULL) {
-			/* nothing to do */
-			return (DDI_SUCCESS);
-		}
-		if (b2s_detach_nexus(nexus) != DDI_SUCCESS) {
-			return (DDI_FAILURE);
-		}
-		slot->s_nexus = NULL;
-		b2s_free_nexus(nexus);
-		return (DDI_SUCCESS);
-
-	case DDI_SUSPEND:
-		return (DDI_SUCCESS);
-
-	default:
-		return (DDI_FAILURE);
-	}
-}
-
-int
-sda_mem_quiesce(dev_info_t *dip)
-{
-	_NOTE(ARGUNUSED(dip));
-	/* no work to do */
-	return (DDI_SUCCESS);
+	media->m_nblks = slot->s_nblks;
+	media->m_blksize = slot->s_blksz;
+	media->m_readonly = slot->s_flags & SLOTF_WRITABLE ? B_FALSE : B_TRUE;
+	sda_slot_exit(slot);
+	return (0);
 }
 
 uint32_t
@@ -510,7 +245,7 @@
 }
 
 int
-sda_mem_parse_cid_csd(sda_slot_t *slot, dev_info_t *dip)
+sda_mem_parse_cid_csd(sda_slot_t *slot)
 {
 	uint32_t	*rcid;
 	uint32_t	*rcsd;
@@ -519,8 +254,6 @@
 	uint16_t	bshift;
 	uint32_t	cmult;
 	uint32_t	csize;
-	char		date[16];
-	char		*dtype;
 
 	rcid = slot->s_rcid;
 	rcsd = slot->s_rcsd;
@@ -531,7 +264,6 @@
 		switch (csdver) {
 		case 0:
 			csize = sda_mem_getbits(rcsd, 73, 12);
-			/* see comment above */
 			rblen = (1 << sda_mem_getbits(rcsd, 83, 4));
 			cmult = (4 << sda_mem_getbits(rcsd, 49, 3));
 			bshift = 9;
@@ -548,7 +280,6 @@
 			return (DDI_FAILURE);
 		}
 
-		dtype = slot->s_flags & SLOTF_SDHC ? "sdhc" : "sdcard";
 		slot->s_mfg = sda_mem_getbits(rcid, 127, 8);
 		sda_mem_getstring(rcid, slot->s_oem, 119, 2);
 		sda_mem_getstring(rcid, slot->s_prod, 103, 5);
@@ -565,8 +296,6 @@
 			return (DDI_FAILURE);
 		}
 
-		dtype = "mmc";
-
 		switch (sda_mem_getbits(rcsd, 125, 4)) {
 		case 0:	/* MMC 1.0 - 1.2 */
 		case 1:	/* MMC 1.4 */
@@ -633,33 +362,6 @@
 	    (slot->s_perm_wp != 0) || (slot->s_temp_wp != 0)) {
 		slot->s_flags &= ~SLOTF_WRITABLE;
 	}
-	(void) snprintf(date, sizeof (date), "%02d-%04d",
-	    slot->s_month, slot->s_year);
-
-#define	prop_set_int(name, val)		\
-	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, name, val)
-#define	prop_set_str(name, val)		\
-	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip, name, val)
-#define	prop_set_bool(name, val)	\
-	if (val) (void) ddi_prop_create(DDI_DEV_T_NONE, dip, 0, name, NULL, 0)
-
-	prop_set_str("device-type", dtype);
-	prop_set_int("mfg-id", slot->s_mfg);
-	prop_set_str("product-id", slot->s_prod);
-	prop_set_str("oem-id", slot->s_oem);
-	prop_set_str("mfg-date", date);
-
-	prop_set_int("block-size", slot->s_blksz);
-	prop_set_int("num-blocks", slot->s_nblks);
-	prop_set_int("max-freq", slot->s_maxclk);
-	prop_set_bool("dsr-implemented", slot->s_dsr);
-	prop_set_int("ccc", slot->s_ccc);
-	prop_set_bool("perm-wp", slot->s_perm_wp);
-	prop_set_bool("temp-wp", slot->s_temp_wp);
-
-#undef	prop_set_int
-#undef	prop_set_str
-#undef	prop_set_bool
 
 	return (DDI_SUCCESS);
 }
--- a/usr/src/uts/common/io/sdcard/impl/sda_mod.c	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/common/io/sdcard/impl/sda_mod.c	Mon May 17 21:17:01 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -53,11 +52,9 @@
 	int	rv;
 
 	sda_cmd_init();
-	sda_nexus_init();
 
 	if ((rv = mod_install(&modlinkage)) != 0) {
 		sda_cmd_fini();
-		sda_nexus_fini();
 	}
 
 	return (rv);
@@ -70,7 +67,6 @@
 
 	if ((rv = mod_remove(&modlinkage)) == 0) {
 		sda_cmd_fini();
-		sda_nexus_fini();
 	}
 	return (rv);
 }
--- a/usr/src/uts/common/io/sdcard/impl/sda_nexus.c	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,920 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * SD card nexus support.
- *
- * NB that this file contains a fair bit of non-DDI compliant code.
- * But writing a nexus driver would be impossible to do with only DDI
- * compliant interfaces.
- */
-
-#include <sys/types.h>
-#include <sys/modctl.h>
-#include <sys/list.h>
-#include <sys/mkdev.h>
-#include <sys/file.h>
-#include <sys/errno.h>
-#include <sys/open.h>
-#include <sys/cred.h>
-#include <sys/stat.h>
-#include <sys/conf.h>
-#include <sys/sysmacros.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/sunndi.h>
-#include <sys/sdcard/sda.h>
-#include <sys/sdcard/sda_ioctl.h>
-#include <sys/sdcard/sda_impl.h>
-#include <sys/fs/dv_node.h>
-
-/*
- * Local prototypes.
- */
-
-static sda_host_t *sda_nexus_lookup_dev(dev_t);
-static int sda_nexus_ap_ioctl(sda_host_t *, int, int, intptr_t);
-static int sda_nexus_ap_control(sda_host_t *, int, intptr_t, int);
-static int sda_nexus_ap_disconnect(sda_slot_t *);
-static int sda_nexus_ap_configure(sda_slot_t *);
-static int sda_nexus_ap_unconfigure(sda_slot_t *);
-static void sda_nexus_ap_getstate(sda_slot_t *, devctl_ap_state_t *);
-static void sda_nexus_reinsert(sda_slot_t *);
-static void sda_nexus_create(sda_slot_t *);
-
-/*
- * Static Variables.
- */
-
-static kmutex_t	sda_nexus_lock;
-static list_t	sda_nexus_list;
-
-/*
- * Minor number allocation.
- *
- * We have up to NBITSMINOR32 (18) bits available.
- *
- * For each instance, we need one minor number for each slot, and one
- * minor number for the devctl node.
- *
- * For simplicity's sake, we use the lower 8 bits for AP and DEVCTL nodes,
- * and the remaining 10 bits for the instance number.
- */
-#define	MINOR_DC		0xff
-#define	DEV_SLOT(dev)		(getminor(dev) & 0xff)
-#define	DEV_INST(dev)		(getminor(dev) >> 8)
-#define	MKMINOR_AP(inst, slot)	(((slot) & 0xff) | ((inst) << 8))
-#define	MKMINOR_DC(inst)	(((inst) << 8) | MINOR_DC)
-
-/*
- * Implementation.
- */
-
-void
-sda_nexus_init(void)
-{
-	list_create(&sda_nexus_list, sizeof (sda_host_t),
-	    offsetof(struct sda_host, h_node));
-	mutex_init(&sda_nexus_lock, NULL, MUTEX_DRIVER, NULL);
-}
-
-void
-sda_nexus_fini(void)
-{
-	list_destroy(&sda_nexus_list);
-	mutex_destroy(&sda_nexus_lock);
-}
-
-int
-sda_nexus_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop,
-    void *arg, void *result)
-{
-	switch (ctlop) {
-	case DDI_CTLOPS_REPORTDEV:
-	{
-		cmn_err(CE_CONT, "?SD-device: %s@%s, %s#%d\n",
-		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
-		    ddi_driver_name(rdip), ddi_get_instance(rdip));
-
-		return (DDI_SUCCESS);
-	}
-
-	case DDI_CTLOPS_INITCHILD:
-	{
-		dev_info_t	*child_dip = (dev_info_t *)arg;
-		dev_info_t	*ndip;
-		sda_slot_t	*slot;
-		char		addr[16];
-
-		if ((slot = ddi_get_parent_data(child_dip)) == NULL) {
-			sda_slot_err(NULL, "Parent data struct missing!");
-			return (DDI_NOT_WELL_FORMED);
-		}
-
-		/*
-		 * TODO: SDIO: We will need to use x,y addresses for
-		 * SDIO function numbers.  Memory cards will always
-		 * resid at address 0.  Probably this can be passed in
-		 * to this function using properties.
-		 */
-		(void) snprintf(addr, sizeof (addr), "%x", slot->s_slot_num);
-
-		/*
-		 * Prevent duplicate nodes.
-		 */
-		ndip = ndi_devi_find(dip, ddi_node_name(child_dip), addr);
-		if (ndip && (ndip != child_dip)) {
-			sda_slot_err(slot, "Duplicate device node found "
-			    "(%s@%s)", ddi_node_name(ndip), addr);
-		}
-
-		/*
-		 * Stash the address in the devinfo node.
-		 */
-		ddi_set_name_addr(child_dip, addr);
-
-		return (DDI_SUCCESS);
-	}
-
-	case DDI_CTLOPS_UNINITCHILD:
-	{
-		dev_info_t	*child_dip = (dev_info_t *)arg;
-
-		ddi_set_name_addr(child_dip, NULL);
-		ndi_prop_remove_all(child_dip);
-		return (DDI_SUCCESS);
-	}
-
-	case DDI_CTLOPS_SIDDEV:
-		/*
-		 * All SDA target devices are self-identifying.
-		 */
-		return (DDI_SUCCESS);
-
-	case DDI_CTLOPS_SLAVEONLY:
-		/*
-		 * We don't support DMA master for SDA targets.
-		 */
-		return (DDI_SUCCESS);
-
-	case DDI_CTLOPS_AFFINITY:
-		/*
-		 * NB: We may want to revisit this later, so that functions
-		 * on one card can see other functions on the same card.
-		 * Right now there is no need.
-		 */
-		return (DDI_FAILURE);
-
-	case DDI_CTLOPS_DMAPMAPC:
-	case DDI_CTLOPS_REPORTINT:
-	case DDI_CTLOPS_POKE:
-	case DDI_CTLOPS_PEEK:
-	case DDI_CTLOPS_NREGS:
-	case DDI_CTLOPS_REGSIZE:
-		/*
-		 * We don't support any of these (yet?).
-		 */
-		return (DDI_FAILURE);
-
-	default:
-		/*
-		 * Everything else goes to the parent nexus.
-		 */
-		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
-	}
-}
-
-void
-sda_nexus_register(sda_host_t *h)
-{
-	int	i;
-	int	inst;
-	char	name[16];
-
-	mutex_enter(&sda_nexus_lock);
-	list_insert_tail(&sda_nexus_list, h);
-	mutex_exit(&sda_nexus_lock);
-
-	/*
-	 * Now create minor nodes.  Note that failures to create these nodes
-	 * are mostly harmless, so we don't do much besides warn about it.
-	 * (It means cfgadm will be useless, but most folks aren't likely
-	 * to use cfgadm anyway.)
-	 */
-
-	inst = ddi_get_instance(h->h_dip);
-
-	/*
-	 * Create the devctl minor node.
-	 */
-	if (ddi_create_minor_node(h->h_dip, "devctl", S_IFCHR,
-	    MKMINOR_DC(inst), DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
-		sda_slot_err(NULL, "Unable to create devctl node");
-	}
-
-	for (i = 0; i < h->h_nslot; i++) {
-
-		sda_slot_t	*slot;
-
-		slot = &h->h_slots[i];
-		/*
-		 * Create the attachment point minor nodes.
-		 */
-		(void) snprintf(name, sizeof (name), "%d", i);
-		if (ddi_create_minor_node(h->h_dip, name, S_IFCHR,
-		    MKMINOR_AP(inst, i), DDI_NT_SDCARD_ATTACHMENT_POINT,
-		    0) != DDI_SUCCESS) {
-			sda_slot_err(slot,
-			    "Unable to create attachment point node");
-		}
-	}
-}
-
-void
-sda_nexus_unregister(sda_host_t *h)
-{
-	/*
-	 * Remove all minor nodes.
-	 */
-	ddi_remove_minor_node(h->h_dip, NULL);
-
-	mutex_enter(&sda_nexus_lock);
-	list_remove(&sda_nexus_list, h);
-	mutex_exit(&sda_nexus_lock);
-}
-
-sda_host_t *
-sda_nexus_lookup_dev(dev_t dev)
-{
-	major_t		maj;
-	int		inst;
-	sda_host_t	*h;
-
-	ASSERT(mutex_owned(&sda_nexus_lock));
-
-	maj = getmajor(dev);
-	inst = DEV_INST(dev);
-
-	h = list_head(&sda_nexus_list);
-	while (h != NULL) {
-		if ((ddi_driver_major(h->h_dip) == maj) &&
-		    (ddi_get_instance(h->h_dip) == inst)) {
-			break;
-		}
-		h = list_next(&sda_nexus_list, h);
-	}
-	return (h);
-}
-
-void
-sda_nexus_create(sda_slot_t *slot)
-{
-	dev_info_t	*pdip, *cdip;
-	int		rv;
-
-	pdip = slot->s_hostp->h_dip;
-
-	/*
-	 * SDIO: This whole function will need to be recrafted to
-	 * support non-memory children.  For SDIO, there could be
-	 * multiple functions, which get inserted or removed together.
-	 */
-
-	if (ndi_devi_alloc(pdip, "sdcard", DEVI_SID_NODEID, &cdip) !=
-	    NDI_SUCCESS) {
-		sda_slot_err(slot, "Failed allocating devinfo node");
-		return;
-	}
-
-	ddi_set_parent_data(cdip, slot);
-	slot->s_dip = NULL;
-
-	/*
-	 * Make sure the child node gets suspend/resume events.
-	 */
-	rv = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "pm-capable", 1);
-	if (rv != 0) {
-		sda_slot_err(slot, "Failed creating pm-capable property");
-		(void) ndi_devi_free(cdip);
-		return;
-	}
-
-	sda_slot_enter(slot);
-	slot->s_ready = B_TRUE;
-	sda_slot_exit(slot);
-
-	if (ndi_devi_online(cdip, NDI_ONLINE_ATTACH) != NDI_SUCCESS) {
-		sda_slot_err(slot, "Failed bringing node online");
-		(void) ndi_devi_free(cdip);
-	} else {
-		slot->s_dip = cdip;
-	}
-}
-
-void
-sda_nexus_reinsert(sda_slot_t *slot)
-{
-	dev_info_t	*cdip, *pdip;
-	int		circ;
-
-	pdip = slot->s_hostp->h_dip;
-
-	ndi_devi_enter(pdip, &circ);
-	sda_slot_enter(slot);
-	if ((cdip = slot->s_dip) !=  NULL) {
-		mutex_enter(&DEVI(cdip)->devi_lock);
-		DEVI_SET_DEVICE_REINSERTED(cdip);
-		mutex_exit(&DEVI(cdip)->devi_lock);
-	}
-	sda_slot_exit(slot);
-	slot->s_warn = B_FALSE;
-	slot->s_ready = B_TRUE;
-	ndi_devi_exit(pdip, circ);
-}
-
-void
-sda_nexus_insert(sda_slot_t *slot)
-{
-	char		uuid[40];
-	boolean_t	match;
-
-	if (slot->s_flags & SLOTF_MEMORY) {
-		(void) snprintf(uuid, sizeof (uuid), "%c%08X%08X%08X%08X",
-		    slot->s_flags & SLOTF_MMC ? 'M' : 'S',
-		    slot->s_rcid[0], slot->s_rcid[1],
-		    slot->s_rcid[2], slot->s_rcid[3]);
-	} else {
-		/*
-		 * SDIO: For SDIO, we can write the card's MANFID
-		 * tuple in CIS to the UUID.  Until we support SDIO,
-		 * we just suppress creating devinfo nodes.
-		 */
-		sda_slot_err(slot, "Non-memory target not supported");
-		uuid[0] = 0;
-	}
-
-	match = ((uuid[0] != 0) && (strcmp(slot->s_uuid, uuid) == 0));
-
-	if (slot->s_dip != NULL) {
-		if (!match) {
-			sda_slot_err(slot, "Card removed while still in use.");
-			sda_slot_err(slot, "Please reinsert previous card.");
-
-			sda_nexus_remove(slot);
-		} else {
-			sda_nexus_reinsert(slot);
-		}
-	} else {
-		/*
-		 * Remember the UUID.
-		 */
-		(void) strlcpy(slot->s_uuid, uuid, sizeof (slot->s_uuid));
-		/*
-		 * Create the children.
-		 */
-		if (uuid[0] != 0)
-			sda_nexus_create(slot);
-	}
-}
-
-void
-sda_nexus_remove(sda_slot_t *slot)
-{
-	sda_host_t	*h  = slot->s_hostp;
-	dev_info_t	*pdip = h->h_dip;
-	dev_info_t	*cdip;
-	int		circ;
-	boolean_t	reap = B_FALSE;
-
-	ndi_devi_enter(pdip, &circ);
-	if ((cdip = slot->s_dip) != NULL) {
-		reap = B_TRUE;
-
-		mutex_enter(&(DEVI(cdip))->devi_lock);
-		DEVI_SET_DEVICE_REMOVED(cdip);
-		mutex_exit(&(DEVI(cdip))->devi_lock);
-	}
-	ndi_devi_exit(pdip, circ);
-
-	if (reap) {
-		mutex_enter(&slot->s_evlock);
-		slot->s_reap = B_TRUE;
-		mutex_exit(&slot->s_evlock);
-		sda_slot_wakeup(slot);
-	}
-}
-
-void
-sda_nexus_reap(void *arg)
-{
-	sda_slot_t	*slot = arg;
-	dev_info_t	*pdip = slot->s_hostp->h_dip;
-	dev_info_t	*cdip;
-	int		circ;
-	char		*devnm;
-	int		rv;
-
-	devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
-
-	ndi_devi_enter(pdip, &circ);
-	sda_slot_enter(slot);
-
-	cdip = slot->s_dip;
-
-	if ((cdip != NULL) && DEVI_IS_DEVICE_REMOVED(cdip)) {
-
-		sda_slot_exit(slot);
-
-		if (i_ddi_node_state(cdip) < DS_INITIALIZED) {
-			rv = ddi_remove_child(cdip, 0);
-		} else {
-			(void) ddi_deviname(cdip, devnm);
-			(void) devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE);
-			rv = ndi_devi_unconfig_one(pdip, devnm + 1, NULL,
-			    NDI_DEVI_REMOVE | NDI_UNCONFIG);
-		}
-
-		if (rv != NDI_SUCCESS) {
-
-			mutex_enter(&slot->s_evlock);
-			slot->s_reap = B_TRUE;
-			mutex_exit(&slot->s_evlock);
-			ndi_devi_exit(pdip, circ);
-			return;
-		}
-		sda_slot_enter(slot);
-
-		if (slot->s_dip == cdip) {
-			slot->s_dip = NULL;
-		}
-	}
-	sda_slot_exit(slot);
-
-	mutex_enter(&slot->s_evlock);
-	/* woohoo, done reaping nodes */
-	slot->s_reap = B_FALSE;
-	mutex_exit(&slot->s_evlock);
-
-	ndi_devi_exit(pdip, circ);
-	kmem_free(devnm, MAXNAMELEN + 1);
-}
-
-/*ARGSUSED3*/
-int
-sda_nexus_open(dev_t *devp, int flags, int otyp, cred_t *credp)
-{
-	int		rv = 0;
-	sda_host_t	*h;
-
-	if (otyp != OTYP_CHR)
-		return (EINVAL);
-
-	mutex_enter(&sda_nexus_lock);
-	if ((h = sda_nexus_lookup_dev(*devp)) == NULL) {
-		mutex_exit(&sda_nexus_lock);
-		return (ENXIO);
-	}
-
-	if (flags & FEXCL) {
-		if ((h->h_flags & (HOST_SOPEN|HOST_XOPEN)) != 0) {
-			rv = EBUSY;
-		} else {
-			h->h_flags |= HOST_XOPEN;
-		}
-	} else {
-		if ((h->h_flags & HOST_XOPEN) != 0) {
-			rv = EBUSY;
-		} else {
-			h->h_flags |= HOST_SOPEN;
-		}
-	}
-	mutex_exit(&sda_nexus_lock);
-	return (rv);
-}
-
-/*ARGSUSED1*/
-int
-sda_nexus_close(dev_t dev, int flag, int otyp, cred_t *credp)
-{
-	sda_host_t	*h;
-
-	if (otyp != OTYP_CHR)
-		return (EINVAL);
-
-	mutex_enter(&sda_nexus_lock);
-	if ((h = sda_nexus_lookup_dev(dev)) == NULL) {
-		mutex_exit(&sda_nexus_lock);
-		return (ENXIO);
-	}
-	h->h_flags &= ~(HOST_XOPEN | HOST_SOPEN);
-	mutex_exit(&sda_nexus_lock);
-	return (0);
-}
-
-void
-sda_nexus_ap_getstate(sda_slot_t *slot, devctl_ap_state_t *ap_state)
-{
-	dev_info_t	*cdip;
-	dev_info_t	*pdip = slot->s_hostp->h_dip;
-	int		circ;
-
-	ndi_devi_enter(pdip, &circ);
-	sda_slot_enter(slot);
-
-	/*
-	 * Default state.
-	 */
-	ap_state->ap_rstate = AP_RSTATE_EMPTY;
-	ap_state->ap_condition = AP_COND_OK;
-	ap_state->ap_ostate = AP_OSTATE_UNCONFIGURED;
-
-	if (slot->s_inserted) {
-		ap_state->ap_rstate = AP_RSTATE_CONNECTED;
-	}
-
-	if ((cdip = slot->s_dip) != NULL) {
-		mutex_enter(&DEVI(cdip)->devi_lock);
-		if (DEVI_IS_DEVICE_REMOVED(cdip)) {
-			ap_state->ap_condition = AP_COND_UNUSABLE;
-		}
-		if (DEVI_IS_DEVICE_OFFLINE(cdip) ||
-		    DEVI_IS_DEVICE_DOWN(cdip)) {
-			ap_state->ap_ostate = AP_OSTATE_UNCONFIGURED;
-		} else {
-			ap_state->ap_ostate = AP_OSTATE_CONFIGURED;
-		}
-		mutex_exit(&DEVI(cdip)->devi_lock);
-	}
-
-	if (slot->s_failed) {
-		ap_state->ap_condition = AP_COND_FAILED;
-	}
-
-	ap_state->ap_last_change = slot->s_stamp;
-	ap_state->ap_in_transition = slot->s_intransit;
-
-	sda_slot_exit(slot);
-	ndi_devi_exit(pdip, circ);
-}
-
-int
-sda_nexus_ap_disconnect(sda_slot_t *slot)
-{
-	dev_info_t	*cdip;
-	dev_info_t	*pdip = slot->s_hostp->h_dip;
-	int		rv = 0;
-	int		circ;
-
-	/* if a child node exists, try to delete it */
-	ndi_devi_enter(pdip, &circ);
-
-	sda_slot_enter(slot);
-	if ((cdip = slot->s_dip) != NULL) {
-		if (ndi_devi_offline(cdip, NDI_DEVI_REMOVE) != NDI_SUCCESS) {
-			/* couldn't disconnect, why not? */
-			rv = EBUSY;
-			goto done;
-		}
-	}
-	slot->s_stamp = ddi_get_time();
-	slot->s_dip = NULL;
-done:
-	sda_slot_exit(slot);
-	ndi_devi_exit(pdip, circ);
-	return (rv);
-}
-
-int
-sda_nexus_ap_unconfigure(sda_slot_t *slot)
-{
-	dev_info_t	*cdip;
-	dev_info_t	*pdip = slot->s_hostp->h_dip;
-	int		rv = 0;
-	int		circ;
-
-	/* attempt to unconfigure the node */
-	ndi_devi_enter(pdip, &circ);
-	sda_slot_enter(slot);
-	if ((cdip = slot->s_dip) != NULL) {
-		if (ndi_devi_offline(cdip, NDI_UNCONFIG) != NDI_SUCCESS) {
-			/* failed to unconfigure the node (EBUSY?) */
-			rv = EIO;
-			goto done;
-		}
-	}
-	slot->s_stamp = ddi_get_time();
-	slot->s_dip = NULL;
-done:
-	sda_slot_exit(slot);
-	ndi_devi_exit(pdip, circ);
-	return (rv);
-}
-
-int
-sda_nexus_ap_configure(sda_slot_t *slot)
-{
-	dev_info_t	*cdip;
-
-	sda_slot_enter(slot);
-	if (slot->s_inserted == B_FALSE) {
-		/* device not present */
-		sda_slot_exit(slot);
-		return (ENXIO);
-	}
-
-	/* attempt to configure the node */
-	if ((cdip = slot->s_dip) == NULL) {
-		sda_slot_exit(slot);
-		/* node not there! */
-		return (ENXIO);
-	}
-	sda_slot_exit(slot);
-
-	slot->s_intransit = 1;
-
-	if (ndi_devi_online(cdip, NDI_CONFIG) != NDI_SUCCESS) {
-		/* failed to configure the node */
-		slot->s_intransit = 0;
-		return (EIO);
-	}
-	slot->s_intransit = 0;
-	slot->s_stamp = ddi_get_time();
-	return (0);
-}
-
-int
-sda_nexus_ap_ioctl(sda_host_t *h, int snum, int cmd, intptr_t arg)
-{
-	struct devctl_iocdata	*dcp = NULL;
-	devctl_ap_state_t	ap_state;
-	sda_slot_t		*slot;
-	int			rv = 0;
-
-	/*
-	 * In theory we could try to support this operation on the
-	 * DEVCTL minor, but then we would need a slot member in the
-	 * user nvlist.  For now its easiest to assume a 1:1 relation
-	 * between the AP minor node, and the slot number.
-	 */
-	if (snum >= h->h_nslot) {
-		return (ENXIO);
-	}
-	slot = &h->h_slots[snum];
-
-	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
-		return (EFAULT);
-
-	switch (cmd) {
-	case DEVCTL_AP_DISCONNECT:
-		rv = sda_nexus_ap_disconnect(slot);
-		break;
-
-	case DEVCTL_AP_UNCONFIGURE:
-		rv = sda_nexus_ap_unconfigure(slot);
-		break;
-
-	case DEVCTL_AP_CONFIGURE:
-		rv = sda_nexus_ap_configure(slot);
-		break;
-
-	case DEVCTL_AP_GETSTATE:
-		bzero(&ap_state, sizeof (ap_state));
-		sda_nexus_ap_getstate(slot, &ap_state);
-		if (ndi_dc_return_ap_state(&ap_state, dcp) != NDI_SUCCESS) {
-			rv = EFAULT;
-		}
-		break;
-	}
-
-	ndi_dc_freehdl(dcp);
-
-	return (rv);
-}
-
-int
-sda_nexus_ap_control(sda_host_t *h, int snum, intptr_t arg, int mode)
-{
-	struct sda_ap_control	apc;
-	struct sda_ap_control32	apc32;
-	sda_slot_t		*slot;
-	int			rv = 0;
-
-	if (snum >= h->h_nslot) {
-		return (ENXIO);
-	}
-	slot = &h->h_slots[snum];
-
-	switch (ddi_model_convert_from(mode & FMODELS)) {
-	case DDI_MODEL_ILP32:
-		if (ddi_copyin((void *)arg, &apc32, sizeof (apc32), mode) !=
-		    0) {
-			return (EFAULT);
-		}
-		apc.cmd = apc32.cmd;
-		apc.size = apc32.size;
-		apc.data = (caddr_t *)(intptr_t)apc32.data;
-		break;
-	case DDI_MODEL_NONE:
-		if (ddi_copyin((void *)arg, &apc, sizeof (apc), mode) != 0) {
-			return (EFAULT);
-		}
-		break;
-	}
-
-	switch (apc.cmd) {
-	case SDA_CFGA_GET_CARD_INFO: {
-		sda_card_info_t	ci;
-
-		bzero(&ci, sizeof (ci));
-		if (apc.size < sizeof (sda_card_info_t)) {
-			apc.size = sizeof (sda_card_info_t);
-			break;
-		}
-		sda_slot_enter(slot);
-		if (!slot->s_inserted) {
-			ci.ci_type = SDA_CT_UNKNOWN;
-		} else if (slot->s_flags & SLOTF_MMC) {
-			ci.ci_type = SDA_CT_MMC;
-		} else if (slot->s_flags & SLOTF_SDIO) {
-			if (slot->s_flags & SLOTF_MEMORY) {
-				ci.ci_type = SDA_CT_SDCOMBO;
-			} else {
-				ci.ci_type = SDA_CT_SDIO;
-			}
-		} else if (slot->s_flags & SLOTF_SDMEM) {
-			if (slot->s_flags & SLOTF_SDHC) {
-				ci.ci_type = SDA_CT_SDHC;
-			} else {
-				ci.ci_type = SDA_CT_SDMEM;
-			}
-		} else {
-			ci.ci_type = SDA_CT_UNKNOWN;
-		}
-
-		if (slot->s_flags & SLOTF_MEMORY) {
-			ci.ci_mfg = slot->s_mfg;
-			(void) strlcpy(ci.ci_oem,
-			    slot->s_oem, sizeof (ci.ci_oem));
-			(void) strlcpy(ci.ci_pid,
-			    slot->s_prod, sizeof (ci.ci_pid));
-			ci.ci_serial = slot->s_serial;
-			ci.ci_month = slot->s_month;
-			ci.ci_year = (slot->s_year - 1900) & 0xff;
-			ci.ci_major = slot->s_majver;
-			ci.ci_minor = slot->s_minver;
-		}
-
-		sda_slot_exit(slot);
-
-		if (ddi_copyout(&ci, apc.data, sizeof (ci), mode) != 0) {
-			return (EFAULT);
-		}
-
-		break;
-	}
-
-	case SDA_CFGA_GET_DEVICE_PATH:
-	{
-		char		path[MAXPATHLEN];
-		dev_info_t	*cdip;
-		int		slen;
-
-		sda_slot_enter(slot);
-		if ((cdip = slot->s_dip) == NULL) {
-			sda_slot_exit(slot);
-			return (ENOENT);
-		}
-		(void) strcpy(path, "/devices");
-		(void) ddi_pathname(cdip, path + strlen(path));
-		slen = strlen(path) + 1;
-		sda_slot_exit(slot);
-		if (apc.size < slen) {
-			apc.size = slen;
-			rv = ENOSPC;
-			break;
-		}
-		apc.size = slen;
-		if (ddi_copyout(path, apc.data, slen, mode) != 0) {
-			return (EFAULT);
-		}
-		break;
-	}
-
-	case SDA_CFGA_RESET_SLOT:
-	{
-		sda_slot_enter(slot);
-		slot->s_failed = B_FALSE;
-		sda_slot_exit(slot);
-		sda_slot_reset(slot);
-		sda_slot_detect(slot);
-		break;
-	}
-
-	default:
-		return (EINVAL);
-	}
-
-	switch (ddi_model_convert_from(mode & FMODELS)) {
-	case DDI_MODEL_ILP32:
-		apc32.cmd = apc.cmd;
-		apc32.size = (size32_t)apc.size;
-		apc32.data = (caddr32_t)(intptr_t)apc.data;
-		if (ddi_copyout(&apc32, (void *)arg, sizeof (apc32), mode) !=
-		    0) {
-			return (EFAULT);
-		}
-		break;
-	case DDI_MODEL_NONE:
-		if (ddi_copyout(&apc, (void *)arg, sizeof (apc), mode) != 0) {
-			return (EFAULT);
-		}
-		break;
-	}
-	return (rv);
-}
-
-/*ARGSUSED4*/
-int
-sda_nexus_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
-    int *rvp)
-{
-	sda_host_t	*h;
-
-	mutex_enter(&sda_nexus_lock);
-	h = sda_nexus_lookup_dev(dev);
-	mutex_exit(&sda_nexus_lock);
-
-	if (h == NULL)
-		return (ENXIO);
-
-	switch (cmd) {
-	case DEVCTL_DEVICE_GETSTATE:
-	case DEVCTL_DEVICE_ONLINE:
-	case DEVCTL_DEVICE_OFFLINE:
-	case DEVCTL_DEVICE_REMOVE:
-	case DEVCTL_BUS_GETSTATE:
-		return (ndi_devctl_ioctl(h->h_dip, cmd, arg, mode, 0));
-
-	case DEVCTL_AP_DISCONNECT:
-	case DEVCTL_AP_CONFIGURE:
-	case DEVCTL_AP_UNCONFIGURE:
-	case DEVCTL_AP_GETSTATE:
-		return (sda_nexus_ap_ioctl(h, DEV_SLOT(dev), cmd, arg));
-
-	case DEVCTL_AP_CONTROL:
-		return (sda_nexus_ap_control(h, DEV_SLOT(dev), arg, mode));
-
-	default:
-		return (ENOTSUP);
-	}
-}
-
-/*ARGSUSED*/
-int
-sda_nexus_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp)
-{
-	sda_host_t	*h;
-	int		rv;
-
-	rv = DDI_FAILURE;
-
-	switch (cmd) {
-	case DDI_INFO_DEVT2DEVINFO:
-		mutex_enter(&sda_nexus_lock);
-		h = sda_nexus_lookup_dev((dev_t)arg);
-		if (h != NULL) {
-			*resp = h->h_dip;
-			rv = DDI_SUCCESS;
-		}
-		mutex_exit(&sda_nexus_lock);
-		break;
-
-	case DDI_INFO_DEVT2INSTANCE:
-		*resp = (void *)(intptr_t)DEV_INST((dev_t)arg);
-		rv = DDI_SUCCESS;
-		break;
-	}
-	return (rv);
-}
--- a/usr/src/uts/common/io/sdcard/impl/sda_slot.c	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/common/io/sdcard/impl/sda_slot.c	Mon May 17 21:17:01 2010 -0700
@@ -19,26 +19,18 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
  * SD card slot support.
- *
- * NB that this file contains a fair bit of non-DDI compliant code.
- * But writing a nexus driver would be impossible to do with only DDI
- * compliant interfaces.
  */
 
 #include <sys/types.h>
-#include <sys/sysmacros.h>
-#include <sys/cpuvar.h>
 #include <sys/cmn_err.h>
 #include <sys/varargs.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
-#include <sys/sunndi.h>
 #include <sys/sdcard/sda_impl.h>
 
 
@@ -256,39 +248,31 @@
 		sda_slot_power_off(slot);
 		sda_slot_abort(slot, SDA_ENODEV);
 		sda_slot_exit(slot);
-		sda_nexus_remove(slot);
 
+	} else if ((slot->s_flags & SLOTF_MEMORY) == 0) {
+		/*
+		 * SDIO: For SDIO, we can write the card's
+		 * MANFID tuple in CIS to the UUID.  Until we
+		 * support SDIO, we just suppress creating
+		 * devinfo nodes.
+		 */
+		sda_slot_err(slot, "Non-memory target not supported");
 	} else {
-		sda_nexus_insert(slot);
+
+		sda_slot_enter(slot);
+		if (sda_mem_parse_cid_csd(slot) != DDI_SUCCESS) {
+			sda_slot_err(slot,
+			    "Unable to parse card identification");
+		} else {
+			slot->s_warn = B_FALSE;
+			slot->s_ready = B_TRUE;
+		}
+		sda_slot_exit(slot);
 	}
 
 	slot->s_stamp = ddi_get_time();
 	slot->s_intransit = 0;
-}
-
-void
-sda_slot_mem_reset(sda_slot_t *slot, sda_err_t errno)
-{
-	sda_cmd_t	*cmdp;
-
-	sda_slot_enter(slot);
-	cmdp = list_head(&slot->s_cmdlist);
-	while (cmdp != NULL) {
-		sda_cmd_t	*next;
-		next = list_next(&slot->s_cmdlist, cmdp);
-		if (cmdp->sc_flags & SDA_CMDF_MEM) {
-			list_remove(&slot->s_cmdlist, cmdp);
-			sda_cmd_notify(cmdp, 0, errno);
-			mutex_enter(&slot->s_evlock);
-			list_insert_tail(&slot->s_abortlist, cmdp);
-			mutex_exit(&slot->s_evlock);
-		}
-		cmdp = next;
-	}
-	sda_slot_exit(slot);
-
-	/* wake up to process the abort list */
-	sda_slot_wakeup(slot);
+	bd_state_change(slot->s_bdh);
 }
 
 void
@@ -300,14 +284,13 @@
 
 	if ((cmdp = slot->s_xfrp) != NULL) {
 		slot->s_xfrp = NULL;
-		sda_cmd_notify(cmdp, SDA_CMDF_BUSY | SDA_CMDF_DAT, errno);
+		sda_cmd_notify(cmdp, 0, errno);
+		list_insert_tail(&slot->s_abortlist, cmdp);
 	}
 	while ((cmdp = list_head(&slot->s_cmdlist)) != NULL) {
 		list_remove(&slot->s_cmdlist, cmdp);
 		sda_cmd_notify(cmdp, 0, errno);
-		mutex_enter(&slot->s_evlock);
 		list_insert_tail(&slot->s_abortlist, cmdp);
-		mutex_exit(&slot->s_evlock);
 	}
 
 	sda_slot_wakeup(slot);
@@ -421,9 +404,8 @@
 		 */
 		sda_slot_reset(slot);
 
-		sda_nexus_remove(slot);
-
 		slot->s_intransit = 0;
+		bd_state_change(slot->s_bdh);
 	}
 	sda_slot_exit(slot);
 
@@ -490,6 +472,17 @@
 	cv_destroy(&slot->s_evcv);
 }
 
+static bd_ops_t sda_bd_ops = {
+	BD_OPS_VERSION_0,
+	sda_mem_bd_driveinfo,
+	sda_mem_bd_mediainfo,
+	NULL,			/* devid_init */
+	NULL,			/* sync_cache */
+	sda_mem_bd_read,
+	sda_mem_bd_write,
+	NULL			/* dump */
+};
+
 void
 sda_slot_attach(sda_slot_t *slot)
 {
@@ -511,6 +504,9 @@
 	 * card initialization.
 	 */
 
+	slot->s_bdh = bd_alloc_handle(slot, &sda_bd_ops, h->h_dma, KM_SLEEP);
+	ASSERT(slot->s_bdh);
+
 	sda_slot_enter(slot);
 
 	(void) snprintf(name, sizeof (name), "slot_%d_hp_tq",
@@ -521,6 +517,8 @@
 		/* Generally, this failure should never occur */
 		sda_slot_err(slot, "Unable to create hotplug slot taskq");
 		sda_slot_exit(slot);
+		bd_free_handle(slot->s_bdh);
+		slot->s_bdh = NULL;
 		return;
 	}
 
@@ -533,6 +531,8 @@
 		/* Generally, this failure should never occur */
 		sda_slot_err(slot, "Unable to create main slot taskq");
 		sda_slot_exit(slot);
+		bd_free_handle(slot->s_bdh);
+		slot->s_bdh = NULL;
 		return;
 	}
 	(void) ddi_taskq_dispatch(slot->s_main_tq, sda_slot_thread, slot,
@@ -560,6 +560,8 @@
 	}
 
 	sda_slot_exit(slot);
+
+	(void) bd_attach_handle(h->h_dip, slot->s_bdh);
 }
 
 void
@@ -568,6 +570,8 @@
 	/*
 	 * Shut down the thread.
 	 */
+	(void) bd_detach_handle(slot->s_bdh);
+
 	mutex_enter(&slot->s_evlock);
 	slot->s_detach = B_TRUE;
 	cv_broadcast(&slot->s_evcv);
@@ -581,6 +585,8 @@
 		ddi_taskq_destroy(slot->s_main_tq);
 	if (slot->s_hp_tq)
 		ddi_taskq_destroy(slot->s_hp_tq);
+
+	bd_free_handle(slot->s_bdh);
 }
 
 void
@@ -681,15 +687,6 @@
 			continue;
 		}
 
-		if (slot->s_reap) {
-			/*
-			 * Do not sleep while holding the evlock.  If this
-			 * fails, we'll just try again the next cycle.
-			 */
-			(void) ddi_taskq_dispatch(slot->s_hp_tq,
-			    sda_nexus_reap, slot, DDI_NOSLEEP);
-		}
-
 		if ((slot->s_xfrp != NULL) && (gethrtime() > slot->s_xfrtmo)) {
 			/*
 			 * The device stalled processing the data request.
@@ -710,8 +707,7 @@
 
 			/*
 			 * We use a timed wait if we are waiting for a
-			 * data transfer to complete, or if we might
-			 * need to reap child nodes.  Otherwise we
+			 * data transfer to complete.  Otherwise we
 			 * avoid the timed wait to avoid waking CPU
 			 * (power savings.)
 			 */
@@ -731,16 +727,7 @@
 
 		slot->s_wake = B_FALSE;
 
-		/*
-		 * Possibly reap child nodes.
-		 */
-		if (slot->s_reap) {
-			slot->s_reap = B_FALSE;
-			mutex_exit(&slot->s_evlock);
-			sda_nexus_reap(slot);
-		} else {
-			mutex_exit(&slot->s_evlock);
-		}
+		mutex_exit(&slot->s_evlock);
 
 		/*
 		 * We're awake now, so look for work to do.  First
@@ -826,12 +813,6 @@
 		 */
 		if ((!slot->s_ready) && (cmdp->sc_flags & SDA_CMDF_MEM)) {
 			rv = SDA_ENODEV;
-			if (!slot->s_warn) {
-				sda_slot_err(slot,
-				    "Device removed while in use.  "
-				    "Please reinsert!");
-				slot->s_warn = B_TRUE;
-			}
 		} else {
 			rv = slot->s_ops.so_cmd(slot->s_prv, cmdp);
 		}
--- a/usr/src/uts/common/io/sdcard/targets/sdcard/sdcard.c	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * SD memory card target driver.  It relies on the SDA common
- * framework, and translates to SCSA.  That is to say, it emulates a
- * simple SCSI block device.
- *
- * The entire driver is a tiny shim for the SDA framework, because to
- * make life simplify and reduce layering overhead, we just use implementation
- * in the SDA framework.
- *
- * (We have to be a separate driver, unfortunately, because SDA nexus drivers
- * need to support SDIO and memory targets, and there can only be one bus_ops
- * per driver.)
- */
-
-#include <sys/types.h>
-#include <sys/modctl.h>
-#include <sys/conf.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-
-
-/* our entire API with SDA is miniscule */
-extern void sda_mem_init(struct modlinkage *);
-extern void sda_mem_fini(struct modlinkage *);
-
-static struct dev_ops sdcard_devops = {
-	DEVO_REV,
-	0,
-	NULL,
-	nulldev,
-	nulldev,
-	NULL,
-	NULL,
-	nodev,
-	NULL,	/* cb_ops */
-	NULL,	/* bus_ops */
-	NULL,	/* power */
-	NULL,	/* quiesce */
-};
-
-static struct modldrv modldrv = {
-	&mod_driverops,
-	"SD Memory Slot",
-	&sdcard_devops,
-};
-
-static struct modlinkage modlinkage = {
-	MODREV_1, { &modldrv, NULL }
-};
-
-int
-_init(void)
-{
-	int	rv;
-
-	sda_mem_init(&modlinkage);
-
-	if ((rv = mod_install(&modlinkage)) != 0) {
-		sda_mem_fini(&modlinkage);
-		return (rv);
-	}
-	return (rv);
-}
-
-int
-_fini(void)
-{
-	int	rv;
-
-	if ((rv = mod_remove(&modlinkage)) == 0) {
-		sda_mem_fini(&modlinkage);
-		return (rv);
-	}
-	return (rv);
-}
-
-int
-_info(struct modinfo *modinfop)
-{
-	return (mod_info(&modlinkage, modinfop));
-}
--- a/usr/src/uts/common/io/warlock/blk2scsa.wlcmd	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-root	b2s_mod_fini
-root	b2s_mod_init
-root	b2s_alloc_nexus
-root	b2s_attach_leaf
-root	b2s_attach_nexus
-root	b2s_detach_leaf
-root	b2s_detach_nexus
-root	b2s_free_nexus
-root	b2s_request_dma
-root	b2s_tran_tgt_free
-root	b2s_tran_tgt_init
-
-root	b2s_tran_setup_pkt
-root	b2s_tran_start
-root	b2s_tran_teardown_pkt
-root	b2s_tran_tgt_free
-root	b2s_tran_tgt_init
-
-add	bus_ops::bus_config		targets	b2s_bus_config
-
-add 	scsi_pkt::pkt_comp		targets \
-					b2s_tran_teardown_pkt \
-					b2s_tran_setup_pkt \
-					b2s_tran_abort \
-					b2s_tran_reset \
-					b2s_tran_getcap \
-					b2s_tran_setcap \
-					b2s_tran_start
-
-add	b2s_nexus::n_request		targets	b2s_request_dma
-
-add	bus_ops::bus_add_eventcall	targets	warlock_dummy
-add	bus_ops::bus_unconfig		targets	warlock_dummy
-add	bus_ops::bus_get_eventcookie	targets warlock_dummy
-add	bus_ops::bus_intr_ctl		targets	warlock_dummy
-add	bus_ops::bus_post_event		targets warlock_dummy
-add	bus_ops::bus_remove_eventcall	targets warlock_dummy
-
--- a/usr/src/uts/common/io/warlock/sdhost.wlcmd	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-root	sda_host_log
-root	sdhost_poll
-
-add sda_slot::s_ops.so_cmd	targets sdhost_cmd \
-					sdhost_halt
-add sda_slot::s_ops.so_getprop	targets sdhost_getprop
-add sda_slot::s_ops.so_reset	targets sdhost_reset
-add sda_slot::s_ops.so_setprop	targets sdhost_setprop
-
--- a/usr/src/uts/common/sys/Makefile	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/common/sys/Makefile	Mon May 17 21:17:01 2010 -0700
@@ -85,6 +85,7 @@
 	bitmap.h		\
 	bitset.h		\
 	bl.h			\
+	blkdev.h		\
 	bmc_intf.h		\
 	bofi.h			\
 	bofi_impl.h		\
@@ -935,8 +936,7 @@
 	sddef.h		\
 	smp.h
 
-SCSIADHDRS=		\
-	blk2scsa.h
+SCSIADHDRS=
 
 SCSICADHDRS=
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/blkdev.h	Mon May 17 21:17:01 2010 -0700
@@ -0,0 +1,155 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#ifndef	_SYS_BLKDEV_H
+#define	_SYS_BLKDEV_H
+
+#include <sys/types.h>
+#include <sys/ksynch.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This describes a fairly simple block device.  The idea here is that
+ * these things want to take advantage of the common labelling support,
+ * but do not need all the capabilities of SCSA.  So we make quite a few
+ * simplifications:
+ *
+ * 1) Device block size is fixed at 512 bytes.  (Devices with larger
+ *    block sizes can still operate, but will need to support some
+ *    form of read-modify-write, and will take a performance penalty.)
+ *
+ * 2) Non-rotating media.  We assume a simple linear layout.
+ *
+ * 3) Fixed queue depth, for each device.  The adapter driver reports
+ *    the queue depth at registration.  We don't have any form of
+ *    dynamic flow control.
+ *
+ * 4) Negligible power management support.  The framework does not support
+ *    fine grained power management.  If the adapter driver wants to use
+ *    such, it will need to manage power on its own.
+ *
+ * 5) Suspend/resume support managed by the adapter driver.  We don't
+ *    support suspend/resume directly.  The adapter device driver will
+ *    need to manage this on its own behalf.
+ *
+ * 6) No request priorities.  Transfers are assumed to execute in
+ *    roughly FIFO order.  The adapter driver may reorder them, but the
+ *    submitter has no control over that.
+ *
+ * 7) No request cancellation.  Once submitted, the job completes or
+ *    fails.  It cannot be canceled.
+ *
+ * 8) Limited support for removable media.  There is no support for
+ *    locking bay doors or mechanised media bays.  This could be
+ *    added, but at present the only such interesting devices are
+ *    covered by the SCSI disk driver.
+ */
+
+typedef struct bd_handle *bd_handle_t;
+typedef struct bd_xfer bd_xfer_t;
+typedef struct bd_drive bd_drive_t;
+typedef struct bd_media bd_media_t;
+typedef struct bd_ops bd_ops_t;
+
+
+struct bd_xfer {
+	/*
+	 * NB: If using DMA the br_ndmac will be non-zero.  Otherwise
+	 * the br_kaddr will be non-NULL.
+	 */
+	diskaddr_t		x_blkno;
+	size_t			x_nblks;
+	ddi_dma_handle_t	x_dmah;
+	ddi_dma_cookie_t	x_dmac;
+	unsigned		x_ndmac;
+	caddr_t			x_kaddr;
+};
+
+#define	BD_XFER_POLL		(1U << 0)	/* no interrupts (dump) */
+
+struct bd_drive {
+	uint32_t		d_qsize;
+	uint32_t		d_maxxfer;
+	boolean_t		d_removable;
+	boolean_t		d_hotpluggable;
+	int			d_target;
+	int			d_lun;
+};
+
+struct bd_media {
+	/*
+	 * NB: The block size must be a power of two not less than
+	 * DEV_BSIZE (512).  Other values of the block size will
+	 * simply not function and the media will be rejected.
+	 *
+	 * The block size must also divide evenly into the device's
+	 * d_maxxfer field.  If the maxxfer is a power of two larger
+	 * than the block size, then this will automatically be
+	 * satisfied.
+	 */
+	uint64_t		m_nblks;
+	uint32_t		m_blksize;
+	boolean_t		m_readonly;
+};
+
+#define	BD_INFO_FLAG_REMOVABLE		(1U << 0)
+#define	BD_INFO_FLAG_HOTPLUGGABLE	(1U << 1)
+#define	BD_INFO_FLAG_READ_ONLY		(1U << 2)
+
+struct bd_ops {
+	int	o_version;
+	void	(*o_drive_info)(void *, bd_drive_t *);
+	int	(*o_media_info)(void *, bd_media_t *);
+	int	(*o_devid_init)(void *, dev_info_t *, ddi_devid_t *);
+	int	(*o_sync_cache)(void *, bd_xfer_t *);
+	int	(*o_read)(void *, bd_xfer_t *);
+	int	(*o_write)(void *, bd_xfer_t *);
+	int	(*o_dump)(void *, bd_xfer_t *);
+};
+
+#define	BD_OPS_VERSION_0		0
+
+/*
+ * Note, one handler *per* address.  Drivers with multiple targets at
+ * different addresses must use separate handles.
+ */
+bd_handle_t	bd_alloc_handle(void *, bd_ops_t *, ddi_dma_attr_t *, int);
+void		bd_free_handle(bd_handle_t);
+int		bd_attach_handle(dev_info_t *, bd_handle_t);
+int		bd_detach_handle(bd_handle_t);
+void		bd_state_change(bd_handle_t);
+void		bd_xfer_done(bd_xfer_t *, int);
+void		bd_mod_init(struct dev_ops *);
+void		bd_mod_fini(struct dev_ops *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _SYS_BLKDEV_H */
--- a/usr/src/uts/common/sys/dkio.h	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/common/sys/dkio.h	Mon May 17 21:17:01 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1982, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _SYS_DKIO_H
@@ -85,6 +84,7 @@
 #define	DKC_PCMCIA_MEM	21	/* PCMCIA memory disk-like type (Obsolete) */
 #define	DKC_PCMCIA_ATA	22	/* PCMCIA AT Attached type */
 #define	DKC_VBD		23	/* virtual block device */
+#define	DKC_BLKDEV	24	/* generic block device (see blkdev(7d)) */
 
 /*
  * Sun reserves up through 1023
--- a/usr/src/uts/common/sys/scsi/adapters/blk2scsa.h	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,183 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef	_SYS_SCSI_ADAPTERS_BLK2SCSA_H
-#define	_SYS_SCSI_ADAPTERS_BLK2SCSA_H
-
-#include <sys/types.h>
-#include <sys/ksynch.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct b2s_nexus_info b2s_nexus_info_t;
-typedef struct b2s_leaf_info b2s_leaf_info_t;
-typedef struct b2s_media b2s_media_t;
-typedef struct b2s_inquiry b2s_inquiry_t;
-typedef struct b2s_request b2s_request_t;
-typedef struct b2s_nexus b2s_nexus_t;
-typedef struct b2s_leaf b2s_leaf_t;
-
-struct b2s_media {
-	uint64_t	media_blksz;
-	uint64_t	media_nblks;
-	uint64_t	media_flags;
-};
-#define	B2S_MEDIA_FLAG_READ_ONLY	(1U << 1)
-#define	B2S_MEDIA_FLAG_LOCKED		(1U << 2)
-
-
-struct b2s_inquiry {
-	const char	*inq_vendor;
-	const char	*inq_product;
-	const char	*inq_revision;
-	const char	*inq_serial;
-};
-
-struct b2s_nexus_info {
-	int		nexus_version;
-	dev_info_t	*nexus_dip;
-	void		*nexus_private;
-	ddi_dma_attr_t	*nexus_dma_attr;
-	boolean_t	(*nexus_request)(void *, b2s_request_t *);
-};
-
-struct b2s_leaf_info {
-	uint_t		leaf_target;
-	uint_t		leaf_lun;
-	uint32_t	leaf_flags;
-	const char	*leaf_unique_id;
-	uint64_t	leaf_eui;
-};
-
-#define	B2S_LEAF_REMOVABLE	(1U << 0)
-#define	B2S_LEAF_HOTPLUGGABLE	(1U << 1)
-/* these values reserved! */
-#define	B2S_LEAF_DETACHED	(1U << 16)
-
-typedef enum {
-	B2S_CMD_GETMEDIA = 0,	/* get content */
-	B2S_CMD_FORMAT = 1,	/* format media */
-	B2S_CMD_START = 2,	/* spin up */
-	B2S_CMD_STOP = 3,	/* spin down */
-	B2S_CMD_LOCK = 4,	/* lock media door */
-	B2S_CMD_UNLOCK = 5,	/* unlock media door */
-	B2S_CMD_READ = 6,	/* read blocks */
-	B2S_CMD_WRITE = 7,	/* write blocks */
-	B2S_CMD_SYNC = 8,	/* flush write cache */
-	B2S_CMD_INQUIRY = 9,	/* inquiry data */
-	B2S_CMD_RESET = 10,	/* reset of bus */
-	B2S_CMD_ABORT = 11,	/* abort inflight commands */
-} b2s_cmd_t;
-
-typedef enum {
-	B2S_EOK = 0,		/* success */
-	B2S_ENOTSUP = 1,	/* operation not sup */
-	B2S_EFORMATTING = 2,	/* busy formatting */
-	B2S_ENOMEDIA = 3,	/* media not mounted */
-	B2S_EMEDIACHG = 4,	/* media changed */
-	B2S_ESTOPPED = 5,	/* unit not started */
-	B2S_EBLKADDR = 6,	/* blkno invalid */
-	B2S_EIO = 7,		/* general failure */
-	B2S_EHARDWARE = 8,	/* hardware error */
-	B2S_ENODEV = 9,		/* hardware removed */
-	B2S_EMEDIA = 10,	/* media problem */
-	B2S_EDOORLOCK = 11,	/* door lock engaged */
-	B2S_EWPROTECT = 12,	/* write protected */
-	B2S_ESTARTING = 13,	/* unit spinning up */
-	B2S_ETIMEDOUT = 14,	/* request timed out */
-	B2S_ENOMEM = 15,	/* out of memory */
-	B2S_ERESET = 16,	/* reset aborted command */
-	B2S_EABORT = 17,	/* aborted command */
-
-	/* these are framework internal use only */
-	B2S_ERSVD = 18,		/* unit reserved */
-	B2S_EINVAL = 19,	/* invalid parameter */
-	B2S_EPARAM = 20,	/* bad parameter */
-	B2S_EBADMSG = 21,	/* malformed message */
-	B2S_ENOSAV = 22,	/* no saveable parms */
-
-	/* used internally for array sizing, must be last */
-	B2S_NERRS = 23
-} b2s_err_t;
-
-#define	B2S_REQUEST_FLAG_POLL		(1U << 0)	/* use polled io */
-#define	B2S_REQUEST_FLAG_HEAD		(1U << 1)
-#define	B2S_REQUEST_FLAG_DONE		(1U << 2)
-#define	B2S_REQUEST_FLAG_LOAD_EJECT	(1U << 3)	/* for start/stop */
-#define	B2S_REQUEST_FLAG_IMMED		(1U << 4)	/* get status immed */
-/* framework internal flags */
-#define	B2S_REQUEST_FLAG_BLKS		(1U << 16)	/* block-oriented */
-#define	B2S_REQUEST_FLAG_MAPIN		(1U << 17)	/* bp_mapin done */
-
-struct b2s_request {
-	b2s_cmd_t		br_cmd;
-	b2s_err_t		br_errno;
-	uint_t			br_target;
-	uint_t			br_lun;
-	uint32_t		br_flags;
-
-	/* note that this member should come last for future expansion */
-	union {
-		uint64_t	a_ints[6];
-		b2s_media_t	a_media;
-		b2s_inquiry_t	a_inquiry;
-	} br_args;
-};
-#define	br_lba			br_args.a_ints[0]
-#define	br_nblks		br_args.a_ints[1]
-#define	br_media		br_args.a_media
-#define	br_inquiry		br_args.a_inquiry
-
-
-int b2s_mod_init(struct modlinkage *);
-void b2s_mod_fini(struct modlinkage *);
-
-/* used as version to alloc_hba */
-#define	B2S_VERSION_0	0
-
-b2s_nexus_t *b2s_alloc_nexus(b2s_nexus_info_t *);
-void b2s_free_nexus(b2s_nexus_t *);
-int b2s_attach_nexus(b2s_nexus_t *);
-int b2s_detach_nexus(b2s_nexus_t *);
-
-b2s_leaf_t *b2s_attach_leaf(b2s_nexus_t *, b2s_leaf_info_t *);
-void b2s_detach_leaf(b2s_leaf_t *);
-
-/*
- * Address information.
- */
-void b2s_request_mapin(b2s_request_t *, caddr_t *, size_t *);
-void b2s_request_dma(b2s_request_t *, uint_t *, ddi_dma_cookie_t **);
-void b2s_request_done(b2s_request_t *, b2s_err_t, size_t);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif	/* _SYS_SCSI_ADAPTERS_BLK2SCSA_H */
--- a/usr/src/uts/common/sys/sdcard/sda.h	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/common/sys/sdcard/sda.h	Mon May 17 21:17:01 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_SYS_SDCARD_SDA_H
@@ -222,8 +221,9 @@
 
 	uint32_t		sc_resid;
 
+	ddi_dma_handle_t	sc_dmah;
 	uint_t			sc_ndmac;	/* # DMA cookies */
-	ddi_dma_cookie_t	*sc_dmacs;	/* actual DMA cookies */
+	ddi_dma_cookie_t	sc_dmac;	/* actual DMA cookies */
 	caddr_t			sc_kvaddr;	/* kernel virtual address */
 
 #define	SDA_CMDF_READ		0x0001		/* transfer direction */
@@ -236,8 +236,6 @@
 #define	SDA_CMDF_MEM		0x0800		/* memory target command */
 };
 
-_NOTE(SCHEME_PROTECTS_DATA("unshared request", sda_cmd))
-
 /*
  * The framework has two APIs.  The first API is for host controllers,
  * and is referred to as SDHOST.  The second API is for target devices,
--- a/usr/src/uts/common/sys/sdcard/sda_impl.h	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/common/sys/sdcard/sda_impl.h	Mon May 17 21:17:01 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_SYS_SDCARD_SDA_IMPL_H
@@ -29,6 +28,7 @@
 #include <sys/list.h>
 #include <sys/ksynch.h>
 #include <sys/note.h>
+#include <sys/blkdev.h>
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
 #include <sys/sdcard/sda.h>
@@ -153,24 +153,9 @@
 	uint8_t		s_perm_wp;	/* permanent write protect set? */
 	uint8_t		s_temp_wp;	/* temporary write protect set? */
 
-	char		s_uuid[40];	/* fabricated universal unique id */
-
-	struct b2s_nexus	*s_nexus;
-	struct b2s_leaf		*s_leaf;
+	bd_handle_t	s_bdh;		/* block dev handle */
 };
 
-_NOTE(MUTEX_PROTECTS_DATA(sda_slot::s_lock, sda_slot::s_circular))
-_NOTE(MUTEX_PROTECTS_DATA(sda_slot::s_evlock, sda_slot::s_wake))
-_NOTE(MUTEX_PROTECTS_DATA(sda_slot::s_evlock, sda_slot::s_detach))
-_NOTE(MUTEX_PROTECTS_DATA(sda_slot::s_evlock, sda_slot::s_detect))
-_NOTE(MUTEX_PROTECTS_DATA(sda_slot::s_evlock, sda_slot::s_suspend))
-_NOTE(MUTEX_PROTECTS_DATA(sda_slot::s_evlock, sda_slot::s_fault))
-_NOTE(MUTEX_PROTECTS_DATA(sda_slot::s_evlock, sda_slot::s_xfrdone))
-_NOTE(MUTEX_PROTECTS_DATA(sda_slot::s_evlock, sda_slot::s_errno))
-_NOTE(SCHEME_PROTECTS_DATA("slot_enter", sda_slot::s_warn))
-_NOTE(SCHEME_PROTECTS_DATA("slot_enter", sda_slot::s_xfrtmo))
-_NOTE(SCHEME_PROTECTS_DATA("slot_enter", sda_slot::s_xfrp))
-
 /*
  * Per host state.  One per devinfo node.  There could be multiple
  * slots per devinfo node.
@@ -189,10 +174,6 @@
 #define	HOST_SOPEN	(1U << 3)	/* shared open */
 };
 
-_NOTE(SCHEME_PROTECTS_DATA("stable data", sda_host::h_dip))
-_NOTE(SCHEME_PROTECTS_DATA("stable data", sda_host::h_nslot))
-_NOTE(SCHEME_PROTECTS_DATA("stable data", sda_host::h_dma))
-
 /*
  * Useful function-like macros.
  */
@@ -230,6 +211,11 @@
 void sda_mem_fini(struct modlinkage *);
 uint32_t sda_mem_maxclk(sda_slot_t *);
 uint32_t sda_mem_getbits(uint32_t *, int, int);
+int sda_mem_parse_cid_csd(sda_slot_t *);
+int sda_mem_bd_read(void *, bd_xfer_t *);
+int sda_mem_bd_write(void *, bd_xfer_t *);
+void sda_mem_bd_driveinfo(void *, bd_drive_t *);
+int sda_mem_bd_mediainfo(void *, bd_media_t *);
 
 
 /*
@@ -269,7 +255,6 @@
 void sda_slot_reset(sda_slot_t *);
 void sda_slot_shutdown(sda_slot_t *);
 void sda_slot_transfer(sda_slot_t *, sda_err_t);
-void sda_slot_mem_reset(sda_slot_t *, sda_err_t);
 void sda_slot_fault(sda_slot_t *, sda_fault_t);
 /*PRINTFLIKE2*/
 void sda_slot_err(sda_slot_t *, const char *, ...);
--- a/usr/src/uts/intel/Makefile.intel.shared	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/intel/Makefile.intel.shared	Mon May 17 21:17:01 2010 -0700
@@ -209,6 +209,7 @@
 DRV_KMODS	+= audiovia823x
 DRV_KMODS_32	+= audiovia97
 DRV_KMODS	+= bl 
+DRV_KMODS	+= blkdev
 DRV_KMODS	+= bge
 DRV_KMODS	+= bofi
 DRV_KMODS	+= bpf
@@ -315,7 +316,6 @@
 DRV_KMODS	+= rwn
 DRV_KMODS	+= sad
 DRV_KMODS	+= sd
-DRV_KMODS	+= sdcard
 DRV_KMODS	+= sdhost
 DRV_KMODS	+= sgen
 DRV_KMODS	+= si3124
@@ -573,7 +573,6 @@
 MISC_KMODS	+= acpica
 MISC_KMODS	+= agpmaster
 MISC_KMODS	+= bignum
-MISC_KMODS	+= blk2scsa
 MISC_KMODS	+= bootdev
 MISC_KMODS	+= busra
 MISC_KMODS	+= cmlb
--- a/usr/src/uts/intel/blk2scsa/Makefile	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-#
-# This makefile drives the production of the blk2scsa driver
-# intel architecture dependent
-#
-
-#
-#	Paths to the base of the uts directory trees
-#
-UTSBASE   = ../..
-
-#
-# Define the module and object file sets.
-#
-MODULE		= blk2scsa
-OBJECTS		= $(BLK2SCSA_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(BLK2SCSA_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_MISC_DIR)/$(MODULE)
-WARLOCK_OUT	= $(BLK2SCSA_OBJS:%.o=%.ll)
-WARLOCK_OK	= $(MODULE).ok
-WLCMD_DIR	= $(UTSBASE)/common/io/warlock
-
-#
-# Include common rules.
-#
-include $(UTSBASE)/intel/Makefile.intel
-
-#
-# Define targets.
-#
-ALL_TARGET	= $(BINARY)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
-
-#
-# Note dependancy on misc/scsi.
-#
-LDFLAGS += -dy -N"misc/scsi"
-
-#
-# Default build targets.
-#
-.KEEP_STATE:
-
-def:		$(DEF_DEPS)
-
-all:		$(ALL_DEPS)
-
-clean:		$(CLEAN_DEPS)
-
-clobber:	$(CLOBBER_DEPS)
-
-lint:		$(LINT_DEPS)
-
-modlintlib:	$(MODLINTLIB_DEPS)
-
-clean.lint:	$(CLEAN_LINT_DEPS)
-
-install:	$(INSTALL_DEPS)
-
-#
-# Include common targets.
-#
-include $(UTSBASE)/intel/Makefile.targ
-
-WLCC	=	wlcc
-TOUCH	=	touch
-WARLOCK	=	warlock
-
-warlock:	$(WARLOCK_OK)
-
-$(WARLOCK_OK):	$(WARLOCK_OUT) 
-	$(WARLOCK) -c $(WLCMD_DIR)/blk2scsa.wlcmd \
-		$(WARLOCK_OUT) \
-		-l ../warlock/scsi.ll -l ../warlock/ddi_dki_impl.ll
-	$(TOUCH) $@
-
-%.ll:	$(UTSBASE)/common/io/scsi/adapters/blk2scsa/%.c
-	$(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/blkdev/Makefile	Mon May 17 21:17:01 2010 -0700
@@ -0,0 +1,84 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# This makefile drives the production of the blkdev driver
+#
+
+#
+#	Paths to the base of the uts directory trees
+#
+UTSBASE   = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE		= blkdev
+OBJECTS		= $(BLKDEV_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(BLKDEV_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+# Define targets.
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+# Note dependancy on misc/scsi.
+#
+LDFLAGS += -dy -Nmisc/cmlb
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
--- a/usr/src/uts/intel/sda/Makefile	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/intel/sda/Makefile	Mon May 17 21:17:01 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 #
@@ -45,8 +44,6 @@
 OBJECTS		= $(SDA_OBJS:%=$(OBJS_DIR)/%)
 LINTS		= $(SDA_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_MISC_DIR)/$(MODULE)
-WARLOCK_OUT	= $(SDA_OBJS:%.o=%.ll)
-WARLOCK_OK	= $(MODULE).ok
 
 #
 #	Include common rules.
@@ -72,11 +69,11 @@
 CFLAGS += $(CCVERBOSE)
 
 #
-# dependency on blk2scsa module, scope limiting mapfile
+# dependency on blkdev module, scope limiting mapfile
 # Note that we have to allow CTFMERGE to use fuzzy matching
 #
 MAPFILE		= $(UTSBASE)/common/io/sdcard/impl/mapfile
-LDFLAGS		+= -dy -Nmisc/blk2scsa -B reduce -M $(MAPFILE)
+LDFLAGS		+= -dy -Ndrv/blkdev -B reduce -M $(MAPFILE)
 CTFMRGFLAGS	+= -f
 
 #
@@ -104,15 +101,3 @@
 #	Include common targets.
 #
 include $(UTSBASE)/intel/Makefile.targ
-
-WLCC		= wlcc
-TOUCH		= touch
-WARLOCK		= warlock
-
-warlock:	$(WARLOCK_OK)
-
-$(WARLOCK_OK):	$(WARLOCK_OUT)
-	$(TOUCH) $@
-
-%.ll:	$(UTSBASE)/common/io/sdcard/impl/%.c
-	$(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
--- a/usr/src/uts/intel/sdcard/Makefile	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-#
-# uts/intel/sdcard/Makefile
-#
-#	This makefile drives the production of the sdcard driver.
-#
-#	intel architecture dependent
-#
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= sdcard
-OBJECTS		= $(SDCARD_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(SDCARD_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/intel/Makefile.intel
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
-
-#
-#	Overrides.
-#
-DEBUG_FLGS	=
-DEBUG_DEFS	+= $(DEBUG_FLGS)
-
-#
-# lint pass one enforcement
-#  
-CFLAGS += $(CCVERBOSE)
-
-#
-# dependency on sda module
-#
-LDFLAGS += -dy -N misc/sda
-
-#
-#	Default build targets.
-#
-.KEEP_STATE:
-
-def:		$(DEF_DEPS)
-
-all:		$(ALL_DEPS)
-
-clean:		$(CLEAN_DEPS)
-
-clobber:	$(CLOBBER_DEPS)
-
-lint:		$(LINT_DEPS)
-
-modlintlib:	$(MODLINTLIB_DEPS)
-
-clean.lint:	$(CLEAN_LINT_DEPS)
-
-install:	$(INSTALL_DEPS)
-
-#
-#	Include common targets.
-#
-include $(UTSBASE)/intel/Makefile.targ
--- a/usr/src/uts/intel/sdhost/Makefile	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/intel/sdhost/Makefile	Mon May 17 21:17:01 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 #
@@ -45,9 +44,6 @@
 OBJECTS		= $(SDHOST_OBJS:%=$(OBJS_DIR)/%)
 LINTS		= $(SDHOST_OBJS:%.o=$(LINTS_DIR)/%.ln)
 ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-WARLOCK_OUT	= $(SDHOST_OBJS:%.o=%.ll)
-WARLOCK_OK	= $(MODULE).ok
-WLCMD_DIR	= $(UTSBASE)/common/io/warlock
 
 #
 #	Include common rules.
@@ -73,7 +69,7 @@
 CFLAGS += $(CCVERBOSE)
 
 #
-# dependency on scsi module
+# dependency on sda module
 #
 LDFLAGS += -dy -Nmisc/sda
 
@@ -102,26 +98,3 @@
 #	Include common targets.
 #
 include $(UTSBASE)/intel/Makefile.targ
-
-WARLOCK		= warlock
-WLCC		= wlcc
-TOUCH		= touch
-SDA_LLS		= $(SDA_OBJS:%.o= -l ../sda/%.ll)
-BLK2SCSA_LLS	= $(BLK2SCSA_OBJS:%.o= -l ../blk2scsa/%.ll)
-
-warlock:	$(WARLOCK_OK)
-
-blk2scsa.wl:
-	@cd ../blk2scsa; pwd; $(MAKE) warlock
-
-sda.wl:
-	@cd ../sda; pwd; $(MAKE) warlock
-
-$(WARLOCK_OK):	$(WARLOCK_OUT) $(WLCMD_DIR)/sdhost.wlcmd blk2scsa.wl sda.wl
-	$(WARLOCK) -c $(WLCMD_DIR)/sdhost.wlcmd $(WARLOCK_OUT) \
-		$(SDA_LLS) $(BLK2SCSA_LLS) \
-		-l ../warlock/ddi_dki_impl.ll
-	$(TOUCH) $@
-
-%.ll:	$(UTSBASE)/common/io/sdcard/adapters/sdhost/%.c
-	$(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
--- a/usr/src/uts/intel/warlock/Makefile	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/intel/warlock/Makefile	Mon May 17 21:17:01 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 # uts/intel/warlock/Makefile
 #
@@ -52,7 +51,7 @@
 #	lock_lint rules
 #
 all:	warlock warlock.1394 warlock.ecpp warlock.scsi \
-	warlock.usb warlock.ib warlock.sata warlock.sdcard warlock.wc
+	warlock.usb warlock.ib warlock.sata warlock.wc
 
 warlock: $(MODULE).ok 
 
@@ -88,7 +87,6 @@
 	@cd ../sd; $(MAKE) clean; $(MAKE) warlock
 	@cd ../ses; $(MAKE) clean; $(MAKE) warlock
 	@cd ../st; $(MAKE) clean; $(MAKE) warlock
-	@cd ../blk2scsa; $(MAKE) clean; $(MAKE) warlock
 $(CLOSED_BUILD)	@cd $(CLOSED)/uts/intel/glm; $(MAKE) clean; $(MAKE) warlock
 $(CLOSED_BUILD)	@cd $(CLOSED)/uts/intel/mpt; $(MAKE) clean; $(MAKE) warlock
 
@@ -120,9 +118,5 @@
 $(CLOSED_BUILD)	@cd $(CLOSED)/uts/intel/marvell88sx; \
 		$(MAKE) clean; $(MAKE) warlock
 
-warlock.sdcard:
-	@cd ../sda; $(MAKE) clean; $(MAKE) warlock
-	@cd ../sdhost; $(MAKE) clean; $(MAKE) warlock
-
 warlock.wc:
 	@cd ../wc; $(MAKE) clean; $(MAKE) warlock
--- a/usr/src/uts/sparc/Makefile.sparc.shared	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/sparc/Makefile.sparc.shared	Mon May 17 21:17:01 2010 -0700
@@ -201,7 +201,7 @@
 #
 #	Common Drivers (usually pseudo drivers) (/kernel/drv):
 #
-DRV_KMODS	+= aggr arp audio bl bofi clone cn conskbd consms cpuid
+DRV_KMODS	+= aggr arp audio bl blkdev bofi clone cn conskbd consms cpuid
 DRV_KMODS	+= crypto cryptoadm devinfo dump
 DRV_KMODS	+= dtrace fasttrap fbt lockstat profile sdt systrace dcpc
 DRV_KMODS	+= fssnap icmp icmp6 ip ip6 ipnet ipsecah
@@ -425,7 +425,6 @@
 MISC_KMODS	+= qlc_fw_2500
 MISC_KMODS	+= qlc_fw_6322
 MISC_KMODS	+= qlc_fw_8100
-MISC_KMODS	+= blk2scsa
 MISC_KMODS	+= spuni
 MISC_KMODS	+= hwa1480_fw uwba
 MISC_KMODS	+= mii
--- a/usr/src/uts/sparc/blk2scsa/Makefile	Tue May 18 11:19:39 2010 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-#
-# This makefile drives the production of the blk2scsa driver
-# sparc architecture dependent
-#
-
-#
-#	Paths to the base of the uts directory trees
-#
-UTSBASE   = ../..
-
-#
-# Define the module and object file sets.
-#
-MODULE		= blk2scsa
-OBJECTS		= $(BLK2SCSA_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(BLK2SCSA_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_MISC_DIR)/$(MODULE)
-WARLOCK_OUT	= $(BLK2SCSA_OBJS:%.o=%.ll)
-WARLOCK_OK	= $(MODULE).ok
-WLCMD_DIR	= $(UTSBASE)/common/io/warlock
-
-#
-# Include common rules.
-#
-include $(UTSBASE)/sparc/Makefile.sparc
-
-#
-# Define targets.
-#
-ALL_TARGET	= $(BINARY)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
-
-#
-# Note dependancy on misc/scsi.
-#
-LDFLAGS += -dy -N"misc/scsi"
-
-#
-# Default build targets.
-#
-.KEEP_STATE:
-
-def:		$(DEF_DEPS)
-
-all:		$(ALL_DEPS)
-
-clean:		$(CLEAN_DEPS)
-
-clobber:	$(CLOBBER_DEPS)
-
-lint:		$(LINT_DEPS)
-
-modlintlib:	$(MODLINTLIB_DEPS)
-
-clean.lint:	$(CLEAN_LINT_DEPS)
-
-install:	$(INSTALL_DEPS)
-
-#
-# Include common targets.
-#
-include $(UTSBASE)/sparc/Makefile.targ
-
-WLCC	=	wlcc
-TOUCH	=	touch
-WARLOCK	=	warlock
-
-warlock:	$(WARLOCK_OK)
-
-$(WARLOCK_OK):	$(WARLOCK_OUT)
-	$(WARLOCK) -c $(WLCMD_DIR)/blk2scsa.wlcmd \
-		$(WARLOCK_OUT) \
-		-l ../warlock/scsi.ll -l ../warlock/ddi_dki_impl.ll
-	$(TOUCH) $@
-
-%.ll:	$(UTSBASE)/common/io/scsi/adapters/blk2scsa/%.c
-	$(WLCC) $(CPPFLAGS) -DDEBUG -o $@ $<
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/blkdev/Makefile	Mon May 17 21:17:01 2010 -0700
@@ -0,0 +1,84 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# This makefile drives the production of the blkdev driver
+#
+
+#
+#	Paths to the base of the uts directory trees
+#
+UTSBASE   = ../..
+
+#
+# Define the module and object file sets.
+#
+MODULE		= blkdev
+OBJECTS		= $(BLKDEV_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(BLKDEV_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+
+#
+# Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+#
+# Define targets.
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+# Note dependancy on misc/scsi.
+#
+LDFLAGS += -dy -Nmisc/cmlb
+
+#
+# Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+# Include common targets.
+#
+include $(UTSBASE)/sparc/Makefile.targ
--- a/usr/src/uts/sparc/warlock/Makefile	Tue May 18 11:19:39 2010 +0800
+++ b/usr/src/uts/sparc/warlock/Makefile	Mon May 17 21:17:01 2010 -0700
@@ -18,8 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 #	sparc architecture dependent
 #
@@ -94,7 +93,6 @@
 	@cd ../ses; $(MAKE) clean; $(MAKE) warlock
 	@cd ../st; $(MAKE) clean; $(MAKE) warlock
 	@cd ../ssd; $(MAKE) clean; $(MAKE) warlock
-	@cd ../blk2scsa; $(MAKE) clean; $(MAKE) warlock
 $(CLOSED_BUILD)	@cd $(CLOSED)/uts/sparc/uata; $(MAKE) clean; $(MAKE) warlock
 $(CLOSED_BUILD)	@cd $(CLOSED)/uts/sparc/glm; $(MAKE) clean; $(MAKE) warlock
 $(CLOSED_BUILD)	@cd $(CLOSED)/uts/sparc/mpt; $(MAKE) clean; $(MAKE) warlock