6795089 COMSTAR sbd lun provider should support PGR
authortim szeto <Tim.Szeto@Sun.COM>
Fri, 08 May 2009 16:22:42 -0600
changeset 9585 bf09620212ab
parent 9584 5536d6df764d
child 9586 bd5e99a50121
6795089 COMSTAR sbd lun provider should support PGR 6808269 Add interfaces for support of create/delete/modify logical unit 6824910 Allow persistence of configuration data to be optional 6794362 Add support for the SCSI direct-access block device Caching mode page 6749644 stmf/sbd getinfo(9E) entry point needs to be fixed PSARC 2009/251 libstmf/stmfadm enhancements for COMSTAR
usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c
usr/src/cmd/sbdadm/Makefile
usr/src/cmd/sbdadm/sbdadm.c
usr/src/cmd/stmfadm/stmfadm.c
usr/src/common/cmdparse/cmdparse.c
usr/src/common/cmdparse/cmdparse.h
usr/src/lib/libstmf/Makefile.com
usr/src/lib/libstmf/common/libstmf.h
usr/src/lib/libstmf/common/libstmf_impl.h
usr/src/lib/libstmf/common/mapfile-vers
usr/src/lib/libstmf/common/stmf.c
usr/src/lib/libstmf/common/store.c
usr/src/lib/libstmf/common/store.h
usr/src/uts/common/Makefile.files
usr/src/uts/common/io/comstar/lu/stmf_sbd/filedisk.c
usr/src/uts/common/io/comstar/lu/stmf_sbd/memdisk.c
usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c
usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_impl.h
usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_pgr.c
usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c
usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h
usr/src/uts/common/io/comstar/port/fct/fct.c
usr/src/uts/common/io/comstar/stmf/stmf.c
usr/src/uts/common/io/comstar/stmf/stmf_impl.h
usr/src/uts/common/sys/scsi/generic/persist.h
usr/src/uts/common/sys/stmf.h
usr/src/uts/common/sys/stmf_defines.h
usr/src/uts/common/sys/stmf_ioctl.h
usr/src/uts/common/sys/stmf_sbd_ioctl.h
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c	Fri May 08 16:22:42 2009 -0600
@@ -674,6 +674,7 @@
 	int			i = 0, max_buf_rsrv, hsize;
 	spc_pr_rsrv_t		*rsrv;
 	scsi_prin_full_status_t	*buf = (scsi_prin_full_status_t *)bp;
+	iscsi_transport_id_t	*tptid;
 
 	hsize = sizeof (buf->PRgeneration) + sizeof (buf->add_len);
 	max_buf_rsrv = ((int)alloc_len - hsize) /
@@ -694,15 +695,15 @@
 			buf->full_desc[i].type = rsrv->r_type;
 			SCSI_WRITE16(buf->full_desc[i].rel_tgt_port_id, 0);
 			SCSI_WRITE32(buf->full_desc[i].add_len,
-			    sizeof (scsi_transport_id_t));
+			    sizeof (iscsi_transport_id_t));
 			buf->full_desc[i].trans_id.protocol_id =
 			    iSCSI_PROTOCOL_ID;
 			buf->full_desc[i].trans_id.format_code =
 			    WW_UID_DEVICE_NAME;
-			SCSI_WRITE16(buf->full_desc[i].trans_id.add_len, 0);
-			(void) sprintf(buf->full_desc[i].trans_id.iscsi_name,
-			    "");
-
+			tptid = (iscsi_transport_id_t *)
+			    &(buf->full_desc[i].trans_id);
+			SCSI_WRITE16(tptid->add_len, 0);
+			(void) sprintf(tptid->iscsi_name, "");
 			i++;
 		}
 		else
--- a/usr/src/cmd/sbdadm/Makefile	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/cmd/sbdadm/Makefile	Fri May 08 16:22:42 2009 -0600
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -41,7 +41,7 @@
 POFILES = $(LOCAL_OBJS:%.o=%.po)
  
 CPPFLAGS += -I. -I$(COMMONBASE)/cmdparse
-LDLIBS += -lstmf -lnvpair
+LDLIBS += -lstmf
 LINTFLAGS += -xerroff=E_BAD_PTR_CAST_ALIGN
 
 .KEEP_STATE:
--- a/usr/src/cmd/sbdadm/sbdadm.c	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/cmd/sbdadm/sbdadm.c	Fri May 08 16:22:42 2009 -0600
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #include <stdlib.h>
@@ -36,49 +36,36 @@
 #include <strings.h>
 #include <ctype.h>
 #include <libnvpair.h>
+#include <locale.h>
 
 #include <cmdparse.h>
 #include <sys/stmf_defines.h>
 #include <libstmf.h>
 #include <sys/stmf_sbd_ioctl.h>
 
-#define	BIG_BUF_SIZE	512
 #define	MAX_LU_LIST	8192
 #define	LU_LIST_MAX_RETRIES 3
+#define	GUID_INPUT  32
 
-uint8_t big_buf[BIG_BUF_SIZE];
+#define	VERSION_STRING_MAJOR	    "1"
+#define	VERSION_STRING_MINOR	    "0"
+#define	VERSION_STRING_MAX_LEN	    10
 
+
+char *cmdName;
+
+static char *getExecBasename(char *);
 int delete_lu(int argc, char *argv[], cmdOptions_t *options,
     void *callData);
 int create_lu(int argc, char *argv[], cmdOptions_t *options, void *callData);
-int import_lu(int argc, char *argv[], cmdOptions_t *options, void *callData);
 int list_lus(int argc, char *argv[], cmdOptions_t *options, void *callData);
 int modify_lu(int argc, char *argv[], cmdOptions_t *options, void *callData);
-static int persist_lu_register(char *, char *);
-int print_lu_attr(uint64_t handle, char **s);
+int import_lu(int argc, char *argv[], cmdOptions_t *options, void *callData);
+static int callModify(char *, stmfGuid *, uint32_t, const char *, const char *);
+int print_lu_attr(stmfGuid *);
 void print_guid(uint8_t *g, FILE *f);
 void print_attr_header();
 
-char	*rlc_ret[] = {	"", "Metadata creation failed",
-	"LU is not initialized",
-	"File is already loaded",
-	"GUID in the file is already registered",
-	"Registration with framework failed",
-	"Deregistration with stmf failed",
-	"Unable to lookup file",
-	"Incorrect file type to export as LU. Only regular \n"
-	    "files and raw storage devices (disks/volumes) can be exported "
-	    "as LUs",
-	"Unable to open file",
-	"Unable to get file attributes",
-	"File size has to be at least 1M",
-	"File size is not a multiple of blocksize",
-	"LU size is out of range",
-	"LU size is not supported by underlying Filesystem"
-};
-
-char sbdadm_ver[] = "sbdadm version 1.0";
-
 optionTbl_t options[] = {
 	{ "disk-size", required_argument, 's',
 			"Size with <none>/k/m/g/t/p/e modifier" },
@@ -103,590 +90,445 @@
 	{ NULL, 0, 0, NULL, 0, NULL}
 };
 
-int sbd_fd;
-
+/*ARGSUSED*/
 int
-main(int argc, char *argv[])
-{
-	int ret, func_ret;
-	synTables_t sbdt = { sbdadm_ver, options, subCommands };
-
-	sbd_fd = open("/devices/pseudo/stmf_sbd@0:admin", O_RDONLY);
-	if (sbd_fd < 0) {
-		if (errno == EPERM) {
-			(void) fprintf(stderr, "Not enough permissions to open "
-			    "device\n");
-		} else {
-			(void) fprintf(stderr,
-			    "Unable to open device. Is the driver "
-			    "attached ?\n");
-		}
-		exit(1);
-	}
-	ret = cmdParse(argc, argv, sbdt, NULL, &func_ret);
-
-	if (ret)
-		return (ret);
-	return (func_ret);
-}
-
-/*
- * Supports upto 8 Exabytes.
- *
- * Returns zero upon success and the size in sizep.
- * returns 2 if the string format is invalid.
- * returns 1 if the specified size is out of range.
- */
-int
-str_to_size(char *str, uint64_t *sizep)
+create_lu(int argc, char *operands[], cmdOptions_t *options, void *callData)
 {
-	uint64_t cur_size, m;
-	uint64_t new_cur_size;
-	int i;
-	char c;
+	luResource hdl = NULL;
+	int ret = 0;
+	stmfGuid createdGuid;
+
+	ret = stmfCreateLuResource(STMF_DISK, &hdl);
 
-	m = 1;
-	cur_size = 0;
+	if (ret != STMF_STATUS_SUCCESS) {
+		(void) fprintf(stderr, "%s: %s\n",
+		    cmdName, gettext("Failure to create lu resource\n"));
+		return (1);
+	}
 
-	for (i = 0; str[i] != NULL; i++) {
-		if (m != 1) {
-			/* We should have been done after the modifier */
-			return (2);
-		}
-		c = str[i];
-		if (isdigit(c)) {
-			new_cur_size = (cur_size * 10) +
-			    (((uint64_t)c) - '0');
-			if (new_cur_size < cur_size) {
-				/* Overflow */
+	for (; options->optval; options++) {
+		switch (options->optval) {
+			case 's':
+				ret = stmfSetLuProp(hdl, STMF_LU_PROP_SIZE,
+				    options->optarg);
+				if (ret != STMF_STATUS_SUCCESS) {
+					(void) fprintf(stderr, "%s: %c: %s\n",
+					    cmdName, options->optval,
+					    gettext("size param invalid"));
+					(void) stmfFreeLuResource(hdl);
+					return (1);
+				}
+				break;
+			default:
+				(void) fprintf(stderr, "%s: %c: %s\n",
+				    cmdName, options->optval,
+				    gettext("unknown option"));
 				return (1);
-			}
-			cur_size = new_cur_size;
-			continue;
-		}
-		if (cur_size == 0) {
-			/* Direct format modifier ?? */
-			return (2);
-		}
-		c = toupper(c);
-		if (c == 'K') {
-			m = 1024;
-		} else if (c == 'M') {
-			m = 1024 * 1024;
-		} else if (c == 'G') {
-			m = 1024 * 1024 * 1024;
-		} else if (c == 'T') {
-			m = 1024ll * 1024 * 1024 * 1024;
-		} else if (c == 'P') {
-			m = 1024ll * 1024 * 1024 * 1024 * 1024;
-		} else if (c == 'E') {
-			m = 1024ll * 1024 * 1024 * 1024 * 1024 * 1024;
-		} else {
-			return (2);
 		}
 	}
 
-	while (m > 1) {
-		if (cur_size & 0x8000000000000000ull) {
-			/* Overflow */
-			return (1);
-		}
-		cur_size <<= 1;
-		m >>= 1;
-	}
+	ret = stmfSetLuProp(hdl, STMF_LU_PROP_FILENAME, operands[0]);
 
-	if (cur_size > 0x8000000000000000ull) {
-		/* We cannot allow more than 8 Exabytes */
+	if (ret != STMF_STATUS_SUCCESS) {
+		(void) fprintf(stderr, "%s: %s\n",
+		    cmdName, gettext("could not set filename"));
 		return (1);
 	}
 
-	*sizep = cur_size;
-
-	return (0);
-}
-
-static int
-persist_lu_register(char *guid, char *filename)
-{
-	int ret = 0;
-	nvlist_t *nvl = NULL;
-	uint64_t setToken;
-	boolean_t		retryGetProviderData;
-
-	do {
-		retryGetProviderData = B_FALSE;
-		ret = stmfGetProviderDataProt("sbd", &nvl,
-		    STMF_LU_PROVIDER_TYPE, &setToken);
-		if (ret != STMF_STATUS_SUCCESS) {
-			if (ret == STMF_ERROR_NOT_FOUND) {
-				(void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
-			} else {
-				(void) fprintf(stderr,
-				    "could not access persistent store\n");
-				ret = 1;
-				goto out;
-			}
-		}
+	ret = stmfCreateLu(hdl, &createdGuid);
+	switch (ret) {
+		case STMF_STATUS_SUCCESS:
+			break;
+		case STMF_ERROR_BUSY:
+		case STMF_ERROR_LU_BUSY:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("resource busy"));
+			ret++;
+			break;
+		case STMF_ERROR_PERM:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("permission denied"));
+			ret++;
+			break;
+		case STMF_ERROR_FILE_IN_USE:
+			(void) fprintf(stderr, "%s: filename %s: %s\n", cmdName,
+			    operands[0], gettext("in use"));
+			ret++;
+			break;
+		case STMF_ERROR_INVALID_BLKSIZE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("invalid block size"));
+			ret++;
+			break;
+		case STMF_ERROR_GUID_IN_USE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("guid in use"));
+			ret++;
+			break;
+		case STMF_ERROR_META_FILE_NAME:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("meta file error"));
+			ret++;
+			break;
+		case STMF_ERROR_DATA_FILE_NAME:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("data file error"));
+			ret++;
+			break;
+		case STMF_ERROR_SIZE_OUT_OF_RANGE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("invalid size"));
+			ret++;
+			break;
+		case STMF_ERROR_META_CREATION:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("could not create meta file"));
+			ret++;
+			break;
+		default:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("unknown error"));
+			ret++;
+			break;
+	}
 
-		ret = nvlist_add_string(nvl, guid, filename);
-		if (ret != 0) {
-			(void) fprintf(stderr,
-			    "could not add data to nvlist\n");
-			ret = 1;
-			goto out;
-		}
+	if (ret != STMF_STATUS_SUCCESS) {
+		goto done;
+	}
 
-		ret = stmfSetProviderDataProt("sbd", nvl, STMF_LU_PROVIDER_TYPE,
-		    &setToken);
-		if (ret != STMF_STATUS_SUCCESS) {
-			if (ret == STMF_ERROR_BUSY) {
-				(void) fprintf(stderr,
-				    "stmf framework resource busy\n");
-			} else if (ret == STMF_ERROR_PROV_DATA_STALE) {
-				nvlist_free(nvl);
-				nvl = NULL;
-				retryGetProviderData = B_TRUE;
-				continue;
-			} else {
-				(void) fprintf(stderr,
-				    "unable to set persistent store data\n");
-			}
-			ret = 1;
-			goto out;
-		}
-	} while (retryGetProviderData);
-out:
-	nvlist_free(nvl);
+	(void) printf("Created the following LU:\n");
+	print_attr_header();
+	ret = print_lu_attr(&createdGuid);
+
+done:
+	(void) stmfFreeLuResource(hdl);
 	return (ret);
 }
 
 /*ARGSUSED*/
 int
-create_lu(int argc, char *argv[], cmdOptions_t *options, void *callData)
+import_lu(int argc, char *operands[], cmdOptions_t *options, void *callData)
 {
-	register_lu_cmd_t *rlc;
-	uint32_t fl;
-	int ret = 0, err;
-	uint64_t size;
-	char guidAsciiBuf[33];
+	int ret = 0;
+	stmfGuid createdGuid;
 
-	/* Check whether this file path is absolute path */
-	if (argv[argc - 1][0] != '/') {
-		(void) fprintf(stderr, "File name should be an absolute path"
-		    " i.e. it should start with a /\n");
-		return (1);
+	ret = stmfImportLu(STMF_DISK, operands[0], &createdGuid);
+	switch (ret) {
+		case STMF_STATUS_SUCCESS:
+			break;
+		case STMF_ERROR_BUSY:
+		case STMF_ERROR_LU_BUSY:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("resource busy"));
+			ret++;
+			break;
+		case STMF_ERROR_PERM:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("permission denied"));
+			ret++;
+			break;
+		case STMF_ERROR_FILE_IN_USE:
+			(void) fprintf(stderr, "%s: filename %s: %s\n", cmdName,
+			    operands[0], gettext("in use"));
+			ret++;
+			break;
+		case STMF_ERROR_GUID_IN_USE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("guid in use"));
+			ret++;
+			break;
+		case STMF_ERROR_META_FILE_NAME:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("meta file error"));
+			ret++;
+			break;
+		case STMF_ERROR_DATA_FILE_NAME:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("data file error"));
+			ret++;
+			break;
+		case STMF_ERROR_SIZE_OUT_OF_RANGE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("invalid size"));
+			ret++;
+			break;
+		case STMF_ERROR_META_CREATION:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("could not create meta file"));
+			ret++;
+			break;
+		default:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("unknown error"));
+			ret++;
+			break;
 	}
 
-	fl = strlen(argv[argc - 1]) + 1;
-	rlc = (register_lu_cmd_t *)malloc(sizeof (register_lu_cmd_t) + fl - 8);
-	if (rlc == NULL) {
-		(void) fprintf(stderr, "Unable to allocate memory\n");
-		return (1);
-	}
-	bzero(rlc, sizeof (register_lu_cmd_t));
-	rlc->total_struct_size = sizeof (register_lu_cmd_t) + fl - 8;
-
-	rlc->flags = RLC_LU_TYPE_FILEDISK | RLC_CREATE_LU | RLC_REGISTER_LU;
-	for (; options->optval; options++) {
-		if (options->optval == 's') {
-			err = str_to_size(options->optarg, &size);
-			if (err == 1) {
-				(void) fprintf(stderr,
-				    "Size out of range: maximum"
-				    " supported size is 9223372036854710272"
-				    " (8 Exabytes - 64 Kilobytes)\n");
-				ret = 1;
-				goto create_lu_done;
-			} else if (err == 2) {
-				(void) fprintf(stderr,
-				    "Invalid size specified\n");
-				ret = 1;
-				goto create_lu_done;
-			}
-			rlc->lu_size = size;
-		}
-	}
-	(void) strcpy(rlc->name, argv[argc-1]);
-	if ((ioctl(sbd_fd, SBD_REGISTER_LU, rlc) < 0) ||
-	    (rlc->return_code != 0) || (rlc->op_ret != STMF_SUCCESS)) {
-		if (rlc->return_code && (rlc->return_code < RLC_RET_MAX_VAL)) {
-			(void) fprintf(stderr, "LU Create failed : %s.\n",
-			    rlc_ret[rlc->return_code]);
-			if (rlc->return_code ==
-			    RLC_RET_SIZE_NOT_SUPPORTED_BY_FS) {
-				(void) fprintf(stderr, "Maximum LU size on "
-				    "the underlying filesystem can be %llu "
-				    "bytes.\n",
-				    ((((uint64_t)1) << rlc->filesize_nbits)
-				    - 1 - 64 * 1024) & 0xfffffffffffffe00ull);
-			}
-			if (rlc->return_code ==
-			    RLC_RET_GUID_ALREADY_REGISTERED) {
-				(void) fprintf(stderr, "Registered GUID is ");
-				print_guid(rlc->guid, stderr);
-				(void) fprintf(stderr, "\n");
-			}
-		} else {
-			(void) fprintf(stderr, "LU Create failed(%llx) : %s.\n",
-			    rlc->op_ret, strerror(errno));
-		}
-		ret = 1;
-	} else {
-		if (rlc->flags & RLC_REGISTER_LU) {
-			(void) printf("\nCreated the following LU:\n");
-			print_attr_header();
-			(void) print_lu_attr(rlc->lu_handle, NULL);
-			(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
-			    "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
-			    "%02x%02x%02x%02x%02x%02x",
-			    rlc->guid[0], rlc->guid[1], rlc->guid[2],
-			    rlc->guid[3], rlc->guid[4], rlc->guid[5],
-			    rlc->guid[6], rlc->guid[7], rlc->guid[8],
-			    rlc->guid[9], rlc->guid[10], rlc->guid[11],
-			    rlc->guid[12], rlc->guid[13], rlc->guid[14],
-			    rlc->guid[15]);
-
-			ret = persist_lu_register(guidAsciiBuf, argv[argc - 1]);
-		}
+	if (ret != STMF_STATUS_SUCCESS) {
+		goto done;
 	}
 
-create_lu_done:;
-	free(rlc);
+	(void) printf("Imported the following LU:\n");
+	print_attr_header();
+	ret = print_lu_attr(&createdGuid);
+
+done:
 	return (ret);
 }
 
 /*ARGSUSED*/
 int
-import_lu(int argc, char *argv[], cmdOptions_t *options, void *callData)
+delete_lu(int operandLen, char *operands[], cmdOptions_t *options,
+    void *callData)
 {
-	register_lu_cmd_t *rlc;
-	uint32_t fl;
+	int i, j;
 	int ret = 0;
-	char guidAsciiBuf[33];
-
-	/* Check whether this file path is absolute path */
-	if (argv[argc - 1][0] != '/') {
-		(void) fprintf(stderr, "File name should be an absolute path"
-		    " i.e. it should start with a /\n");
-		return (1);
-	}
-
-	fl = strlen(argv[argc - 1]) + 1;
-	rlc = (register_lu_cmd_t *)malloc(sizeof (register_lu_cmd_t) + fl - 8);
-	if (rlc == NULL) {
-		(void) fprintf(stderr, "Unable to allocate memory\n");
-		return (1);
-	}
-	bzero(rlc, sizeof (register_lu_cmd_t));
-	rlc->total_struct_size = sizeof (register_lu_cmd_t) + fl - 8;
+	int stmfRet;
+	unsigned int inGuid[sizeof (stmfGuid)];
+	stmfGuid delGuid;
+	boolean_t keepViews = B_FALSE;
+	boolean_t viewEntriesRemoved = B_FALSE;
+	boolean_t noLunFound = B_FALSE;
+	boolean_t views = B_FALSE;
+	char sGuid[GUID_INPUT + 1];
+	stmfViewEntryList *viewEntryList = NULL;
 
-	rlc->flags = RLC_LU_TYPE_FILEDISK | RLC_REGISTER_LU;
-	(void) strcpy(rlc->name, argv[argc-1]);
-	if ((ioctl(sbd_fd, SBD_REGISTER_LU, rlc) < 0) ||
-	    (rlc->return_code != 0) || (rlc->op_ret != STMF_SUCCESS)) {
-		if (rlc->return_code && (rlc->return_code < RLC_RET_MAX_VAL)) {
-			(void) fprintf(stderr, "LU import failed : %s.\n",
-			    rlc_ret[rlc->return_code]);
-			if (rlc->return_code ==
-			    RLC_RET_SIZE_NOT_SUPPORTED_BY_FS) {
-				(void) fprintf(stderr, "Maximum LU size on "
-				    "the underlying filesystem can be %llu "
-				    "bytes.\n",
-				    ((((uint64_t)1) << rlc->filesize_nbits)
-				    - 1 - 64 * 1024) & 0xfffffffffffffe00ull);
-			}
-			if (rlc->return_code ==
-			    RLC_RET_GUID_ALREADY_REGISTERED) {
-				(void) fprintf(stderr, "Registered GUID is ");
-				print_guid(rlc->guid, stderr);
-				(void) fprintf(stderr, "\n");
-			}
-		} else {
-			(void) fprintf(stderr, "LU import failed(%llx) : %s.\n",
-			    rlc->op_ret, strerror(errno));
-		}
-		ret = 1;
-	} else {
-		if (rlc->flags & RLC_REGISTER_LU) {
-			(void) printf("\nImported the following LU:\n");
-			print_attr_header();
-			(void) print_lu_attr(rlc->lu_handle, NULL);
-			(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
-			    "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
-			    "%02x%02x%02x%02x%02x%02x",
-			    rlc->guid[0], rlc->guid[1], rlc->guid[2],
-			    rlc->guid[3], rlc->guid[4], rlc->guid[5],
-			    rlc->guid[6], rlc->guid[7], rlc->guid[8],
-			    rlc->guid[9], rlc->guid[10], rlc->guid[11],
-			    rlc->guid[12], rlc->guid[13], rlc->guid[14],
-			    rlc->guid[15]);
-
-			ret = persist_lu_register(guidAsciiBuf, argv[argc - 1]);
+	for (; options->optval; options++) {
+		switch (options->optval) {
+			/* Keep views for logical unit */
+			case 'k':
+				keepViews = B_TRUE;
+				break;
+			default:
+				(void) fprintf(stderr, "%s: %c: %s\n",
+				    cmdName, options->optval,
+				    gettext("unknown option"));
+				return (1);
 		}
 	}
 
-import_lu_done:;
-	free(rlc);
+
+	for (i = 0; i < operandLen; i++) {
+		for (j = 0; j < GUID_INPUT; j++) {
+			if (!isxdigit(operands[i][j])) {
+				break;
+			}
+			sGuid[j] = tolower(operands[i][j]);
+		}
+		if (j != GUID_INPUT) {
+			(void) fprintf(stderr, "%s: %s: %s%d%s\n",
+			    cmdName, operands[i], gettext("must be "),
+			    GUID_INPUT,
+			    gettext(" hexadecimal digits long"));
+			ret++;
+			continue;
+		}
+
+		sGuid[j] = 0;
+
+		(void) sscanf(sGuid,
+		    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
+		    &inGuid[0], &inGuid[1], &inGuid[2], &inGuid[3],
+		    &inGuid[4], &inGuid[5], &inGuid[6], &inGuid[7],
+		    &inGuid[8], &inGuid[9], &inGuid[10], &inGuid[11],
+		    &inGuid[12], &inGuid[13], &inGuid[14], &inGuid[15]);
+
+		for (j = 0; j < sizeof (stmfGuid); j++) {
+			delGuid.guid[j] = inGuid[j];
+		}
+
+		stmfRet = stmfDeleteLu(&delGuid);
+		switch (stmfRet) {
+			case STMF_STATUS_SUCCESS:
+				break;
+			case STMF_ERROR_NOT_FOUND:
+				noLunFound = B_TRUE;
+				break;
+			case STMF_ERROR_BUSY:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("resource busy"));
+				ret++;
+				break;
+			case STMF_ERROR_PERM:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("permission denied"));
+				ret++;
+				break;
+			default:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("unknown error"));
+				ret++;
+				break;
+		}
+
+		if (!keepViews) {
+			stmfRet = stmfGetViewEntryList(&delGuid,
+			    &viewEntryList);
+			if (stmfRet == STMF_STATUS_SUCCESS) {
+				for (j = 0; j < viewEntryList->cnt; j++) {
+					(void) stmfRemoveViewEntry(&delGuid,
+					    viewEntryList->ve[j].veIndex);
+				}
+				viewEntriesRemoved = B_TRUE;
+				stmfFreeMemory(viewEntryList);
+			} else if (stmfRet != STMF_ERROR_NOT_FOUND) {
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("unable to remove view entries\n"));
+				ret++;
+			} /* No view entries to remove */
+		}
+		if (keepViews) {
+			stmfRet = stmfGetViewEntryList(&delGuid,
+			    &viewEntryList);
+			if (stmfRet == STMF_STATUS_SUCCESS) {
+				views = B_TRUE;
+				stmfFreeMemory(viewEntryList);
+			}
+		}
+
+		if ((!viewEntriesRemoved && noLunFound && !views) ||
+		    (!views && keepViews && noLunFound)) {
+			(void) fprintf(stderr, "%s: %s: %s\n",
+			    cmdName, sGuid,
+			    gettext("not found"));
+			ret++;
+		}
+		noLunFound = viewEntriesRemoved = views = B_FALSE;
+	}
 	return (ret);
 }
 
 /*ARGSUSED*/
 int
-delete_lu(int argc, char *argv[], cmdOptions_t *options, void *callData)
+modify_lu(int operandLen, char *operands[], cmdOptions_t *options,
+    void *callData)
 {
-	deregister_lu_cmd_t	drlc;
-	int			ret = 0, i;
-	char			chstr[3], *pend = NULL;
-	uint32_t		ch, off = 0;
-	int			exists = 0;
-	char			guidAsciiBuf[33];
-	nvlist_t		*nvl = NULL;
+	stmfGuid inGuid;
+	unsigned int guid[sizeof (stmfGuid)];
+	int ret = 0;
+	int i;
+	char *fname = NULL;
+	char sGuid[GUID_INPUT + 1];
+	boolean_t fnameUsed = B_FALSE;
+
+	if (operands[0][0] == '/') {
+		fnameUsed = B_TRUE;
+		fname = operands[0];
+	}
 
-	int			stmf_ret;
-	int			keep_view = 0;
-	uint64_t		setToken;
-	stmfGuid		inGuid;
-	stmfViewEntryList	*viewEntryList;
-	boolean_t		retryGetProviderData;
+	/* check input length */
+	if (!fnameUsed && strlen(operands[0]) != GUID_INPUT) {
+		(void) fprintf(stderr, "%s: %s: %s%d%s\n", cmdName, operands[0],
+		    gettext("must be "), GUID_INPUT,
+		    gettext(" hexadecimal digits"));
+		return (1);
+	}
 
-	for (; options->optval; options++) {
-		switch (options->optval) {
-		case 'k':
-			keep_view = 1;
-			break;
+	if (!fnameUsed) {
+		/* convert to lower case for scan */
+		for (i = 0; i < 32; i++)
+			sGuid[i] = tolower(operands[0][i]);
+		sGuid[i] = 0;
+		(void) sscanf(sGuid,
+		    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
+		    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
+		    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10],
+		    &guid[11], &guid[12], &guid[13], &guid[14], &guid[15]);
+
+		for (i = 0; i < sizeof (stmfGuid); i++) {
+			inGuid.guid[i] = guid[i];
 		}
 	}
 
-	if (strlen(argv[argc - 1]) != 32) {
-		(void) fprintf(stderr, "GUID must be 32 characters\n");
-		ret = 1;
-		goto delete_lu_done;
-	}
-
-	for (i = 0; i < 32; i++) {
-		guidAsciiBuf[i] = tolower(argv[argc - 1][i]);
-	}
-
-	guidAsciiBuf[i] = 0;
-
-	do {
-		retryGetProviderData = B_FALSE;
-		stmf_ret = stmfGetProviderDataProt("sbd", &nvl,
-		    STMF_LU_PROVIDER_TYPE, &setToken);
-		if (stmf_ret != STMF_STATUS_SUCCESS) {
-			(void) fprintf(stderr,
-			    "Could not access persistent store\n");
-			ret = 1;
-			goto delete_lu_done;
-		}
-		ret = nvlist_remove(nvl, guidAsciiBuf, DATA_TYPE_STRING);
-		if (ret == 0) {
-			exists = 1;
-			stmf_ret = stmfSetProviderDataProt("sbd", nvl,
-			    STMF_LU_PROVIDER_TYPE, &setToken);
-			if (stmf_ret != STMF_STATUS_SUCCESS) {
-				if (stmf_ret == STMF_ERROR_BUSY) {
-					(void) fprintf(stderr,
-					    "stmf framework resource busy\n");
-				} else if (stmf_ret ==
-				    STMF_ERROR_PROV_DATA_STALE) {
-					/*
-					 * update failed, try again
-					 */
-					nvlist_free(nvl);
-					nvl = NULL;
-					retryGetProviderData = B_TRUE;
-					continue;
-				} else {
-					(void) fprintf(stderr,
-					    "unable to set persistent store "
-					    "data\n");
+	for (; options->optval; options++) {
+		switch (options->optval) {
+			case 's':
+				if (callModify(fname, &inGuid,
+				    STMF_LU_PROP_SIZE, options->optarg,
+				    "size") != 0) {
+					return (1);
 				}
-				ret = 1;
-				goto delete_lu_done;
-			}
-		}
-	} while (retryGetProviderData);
-
-	bzero(&drlc, sizeof (drlc));
-	drlc.total_struct_size = sizeof (drlc);
-	drlc.flags = RLC_DEREGISTER_LU;
-
-	chstr[2] = 0;
-	i = 0;
-	while ((off + 2) <= strlen(argv[argc - 1])) {
-		bcopy(argv[argc -1] + off, chstr, 2);
-		off += 2;
-
-		if (!isxdigit(chstr[0]) || !isxdigit(chstr[1])) {
-			(void) fprintf(stderr, "Invalid LU GUID specified.\n");
-			ret = 1;
-			goto delete_lu_done;
-		}
-		errno = 0;
-		ch = strtoul(chstr, &pend, 16);
-		if (errno != 0) {
-			(void) fprintf(stderr, "Invalid LU GUID specified.\n");
-			ret = 1;
-			goto delete_lu_done;
-		}
-		drlc.guid[i++] = ch;
-
-	}
-
-	if (ioctl(sbd_fd, SBD_DEREGISTER_LU, &drlc) < 0) {
-		if (errno != ENODEV) {
-			(void) fprintf(stderr,
-			    "Request to delete LU failed: %s\n",
-			    strerror(errno));
-			ret = 1;
-			goto delete_lu_done;
-		}
-	} else if (drlc.return_code != 0) {
-		(void) fprintf(stderr, "LU deregister failed: ret_code-%x",
-		    drlc.return_code);
-		ret = 1;
-		goto delete_lu_done;
-	} else {
-		exists = 1;
-	}
-
-	if (!keep_view) {
-		for (i = 0; i < 16; i++)
-			inGuid.guid[i] = drlc.guid[i];
-
-		if ((stmf_ret = stmfGetViewEntryList(&inGuid,
-		    &viewEntryList)) == STMF_STATUS_SUCCESS) {
-			for (i = 0; i < viewEntryList->cnt; i++) {
-				(void) stmfRemoveViewEntry(&inGuid,
-				    viewEntryList->ve[i].veIndex);
-			}
-		} else if (stmf_ret != STMF_ERROR_NOT_FOUND) {
-			(void) fprintf(stderr,
-			    "unable to remove view entries\n");
-			ret = 1;
+				break;
+			default:
+				(void) fprintf(stderr, "%s: %c: %s\n",
+				    cmdName, options->optval,
+				    gettext("unknown option"));
+				return (1);
 		}
 	}
-
-	if (!exists) {
-		(void) fprintf(stderr, "GUID not found.\n");
-		ret = 1;
-		goto delete_lu_done;
-	}
-
-delete_lu_done:;
 	return (ret);
 }
 
-/*ARGSUSED*/
-int
-modify_lu(int argc, char *argv[], cmdOptions_t *options, void *callData)
+static int
+callModify(char *fname, stmfGuid *luGuid, uint32_t prop, const char *propVal,
+    const char *propString)
 {
-	modify_lu_cmd_t *mlc;
-	uint32_t fl = 0, struct_size;
-	int ret = 0, err;
-	int i = 0;
-	uint64_t size;
-	int is_filename = 0;
-	char chstr[3], *pend = NULL;
-	uint32_t ch;
-	uint32_t off = 0;
+	int ret = 0;
+	int stmfRet = 0;
 
-	if (argv[argc - 1][0] == '/') {
-		is_filename = 1;
-		fl = strlen(argv[argc - 1]) + 1;
-		struct_size = sizeof (modify_lu_cmd_t) + fl - 8;
-	} else {
-		struct_size = sizeof (modify_lu_cmd_t);
-	}
-	mlc = (modify_lu_cmd_t *)malloc(struct_size);
-	if (mlc == NULL) {
-		(void) fprintf(stderr, "Unable to allocate memory\n");
-		return (1);
-	}
-	bzero(mlc, sizeof (modify_lu_cmd_t));
-	mlc->total_struct_size = struct_size;
-
-	mlc->flags = RLC_LU_TYPE_FILEDISK | RLC_CREATE_LU;
-	for (; options->optval; options++) {
-		if (options->optval == 's') {
-			err = str_to_size(options->optarg, &size);
-			if (err == 1) {
-				(void) fprintf(stderr,
-				    "Size out of range: maximum"
-				    " supported size is 9223372036854775808"
-				    " (8 Exabytes)\n");
-				ret = 1;
-				goto modify_lu_done;
-			} else if (err == 2) {
-				(void) fprintf(stderr,
-				    "Invalid size specified\n");
-				ret = 1;
-				goto modify_lu_done;
-			}
-			mlc->lu_size = size;
-		}
-	}
-	if (is_filename) {
-		(void) strcpy(mlc->name, argv[argc-1]);
-		(void) memset(mlc->guid, 0, 16);
+	if (!fname) {
+		stmfRet = stmfModifyLu(luGuid, prop, propVal);
 	} else {
-		if (strlen(argv[argc - 1]) != 32) {
-			(void) fprintf(stderr,
-			    "Invalid device identifier or filename"
-			    " specified.\nIf it is a filename, it should be an"
-			    " absolute path i.e. it should start with a /\n");
-			goto modify_lu_done;
-		}
-		chstr[2] = 0;
-		i = 0;
-		while ((off + 2) <= strlen(argv[argc - 1])) {
-			bcopy(argv[argc -1] + off, chstr, 2);
-			off += 2;
-
-			ch = strtoul(chstr, &pend, 16);
-			if (errno != 0) {
-				(void) fprintf(stderr,
-				    "Invalid device identifier or"
-				    " filename specified.\nIf it is a"
-				    " filename, it should be an absolute path"
-				    " i.e. it should start with a /\n");
-				ret = 1;
-				goto modify_lu_done;
-			}
-			mlc->guid[i++] = ch;
-
-		}
-		mlc->name[0] = '\0';
+		stmfRet = stmfModifyLuByFname(STMF_DISK, fname, prop,
+		    propVal);
 	}
-	if ((ioctl(sbd_fd, SBD_MODIFY_LU, mlc) < 0) ||
-	    (mlc->return_code != 0) || (mlc->op_ret |= STMF_SUCCESS)) {
-		if (mlc->return_code && (mlc->return_code < RLC_RET_MAX_VAL)) {
-			(void) fprintf(stderr, "LU modify failed : %s.\n",
-			    rlc_ret[mlc->return_code]);
-			if (mlc->return_code ==
-			    RLC_RET_SIZE_NOT_SUPPORTED_BY_FS) {
-				(void) fprintf(stderr, "Maximum LU size on "
-				    "the underlying filesystem can be %llu "
-				    "bytes.\n",
-				    ((((uint64_t)1) << mlc->filesize_nbits)
-				    - 1) & 0xfffffffffffffe00ull);
-			} else if (mlc->return_code ==
-			    RLC_RET_LU_NOT_INITIALIZED) {
-				(void) fprintf(stderr, "Use 'sbdadm lu-create' "
-				    "to initialize the LU.\n");
-			}
-		} else {
-			(void) fprintf(stderr, "LU modify failed(%llx) : %s.\n",
-			    mlc->op_ret, strerror(errno));
-		}
-		ret = 1;
-	} else {
-		(void) printf("LU modified Successfully.\n");
+	switch (stmfRet) {
+		case STMF_STATUS_SUCCESS:
+			break;
+		case STMF_ERROR_BUSY:
+		case STMF_ERROR_LU_BUSY:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("resource busy"));
+			ret++;
+			break;
+		case STMF_ERROR_PERM:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("permission denied"));
+			ret++;
+			break;
+		case STMF_ERROR_INVALID_BLKSIZE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("invalid block size"));
+			ret++;
+			break;
+		case STMF_ERROR_GUID_IN_USE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("guid in use"));
+			ret++;
+			break;
+		case STMF_ERROR_META_FILE_NAME:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("meta file error"));
+			ret++;
+			break;
+		case STMF_ERROR_DATA_FILE_NAME:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("data file error"));
+			ret++;
+			break;
+		case STMF_ERROR_FILE_SIZE_INVALID:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("file size invalid"));
+			ret++;
+			break;
+		case STMF_ERROR_SIZE_OUT_OF_RANGE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("invalid size"));
+			ret++;
+			break;
+		case STMF_ERROR_META_CREATION:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("could not create meta file"));
+			ret++;
+			break;
+		default:
+			(void) fprintf(stderr, "%s: %s: %s: %d\n", cmdName,
+			    gettext("could not set property"), propString,
+			    stmfRet);
+			ret++;
+			break;
 	}
 
-modify_lu_done:;
-	free(mlc);
 	return (ret);
 }
 
@@ -695,88 +537,71 @@
 int
 list_lus(int argc, char *argv[], cmdOptions_t *options, void *callData)
 {
-	sbd_lu_list_t *sll;
-	uint32_t i;
-	ssize_t list_size;
-	int retry_count = 0;
-	uint32_t lu_count_in = MAX_LU_LIST;
-	int ret;
-	nvlist_t *nvl = NULL;
-	nvpair_t *np;
-	char *s;
+	int stmfRet;
+	stmfGuidList *luList;
+	stmfLogicalUnitProperties luProps;
+	int sbdLuCnt = 0;
+	int i;
 
-	ret = stmfGetProviderDataProt("sbd", &nvl, STMF_LU_PROVIDER_TYPE,
-	    NULL);
-	if (ret != STMF_STATUS_SUCCESS) {
-		if (ret == STMF_ERROR_NOT_FOUND) {
-			(void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
-		} else {
-			(void) fprintf(stderr,
-			    "Could not access persistent store\n");
-			return (1);
+	if ((stmfRet = stmfGetLogicalUnitList(&luList))
+	    != STMF_STATUS_SUCCESS) {
+		switch (stmfRet) {
+			case STMF_ERROR_SERVICE_NOT_FOUND:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("STMF service not found"));
+				break;
+			case STMF_ERROR_BUSY:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("resource busy"));
+				break;
+			case STMF_ERROR_PERM:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("permission denied"));
+				break;
+			case STMF_ERROR_SERVICE_DATA_VERSION:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("STMF service version incorrect"));
+				break;
+			default:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("list failed"));
+				break;
 		}
-	}
-
-retry_get_lu_list:
-	list_size = (lu_count_in * 8) + sizeof (sbd_lu_list_t) - 8;
-	sll = (sbd_lu_list_t *)calloc(1, list_size);
-	if (sll == NULL) {
-		(void) fprintf(stderr, "Memory allocation failure\n");
-		nvlist_free(nvl);
 		return (1);
 	}
 
-	sll->total_struct_size = list_size;
-
-	sll->count_in = lu_count_in;
-	if (ioctl(sbd_fd, SBD_GET_LU_LIST, sll) < 0) {
-		(void) fprintf(stderr, "Unable to get LU list : %s\n",
-		    strerror(errno));
-		free(sll);
-		nvlist_free(nvl);
-		return (1);
-	}
-	if (sll->count_out > sll->count_in) {
-		lu_count_in = sll->count_out;
-		free(sll);
-		if (retry_count < LU_LIST_MAX_RETRIES) {
-			retry_count++;
-			goto retry_get_lu_list;
-		} else {
-			(void) fprintf(stderr, "Unable to get LU list after %d"
-			    " retries\n", retry_count);
-			nvlist_free(nvl);
+	for (i = 0; i < luList->cnt; i++) {
+		stmfRet = stmfGetLogicalUnitProperties(&luList->guid[i],
+		    &luProps);
+		if (stmfRet != STMF_STATUS_SUCCESS) {
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("list failed"));
 			return (1);
 		}
+		if (strcmp(luProps.providerName, "sbd") == 0) {
+			sbdLuCnt++;
+		}
 	}
 
-	(void) printf("\nFound %d LU(s)\n", sll->count_out);
-	if (sll->count_out == 0)
-		goto over_print_attr;
 
+	if (sbdLuCnt == 0)
+		return (0);
+
+	(void) printf("\nFound %d LU(s)\n", sbdLuCnt);
 	print_attr_header();
-	for (i = 0; i < sll->count_out; i++) {
-		if (!print_lu_attr(sll->handles[i], &s))
-			continue;
-		if (nvlist_remove(nvl, s, DATA_TYPE_STRING) != 0) {
-			(void) fprintf(stderr,
-			    "Error: GUID %s does not exist in "
-			    "persistent store\n", s);
+
+	for (i = 0; i < luList->cnt; i++) {
+		stmfRet = stmfGetLogicalUnitProperties(&luList->guid[i],
+		    &luProps);
+		if (stmfRet != STMF_STATUS_SUCCESS) {
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("list failed"));
+			return (1);
+		}
+		if (strcmp(luProps.providerName, "sbd") == 0) {
+			(void) print_lu_attr(&luList->guid[i]);
 		}
 	}
-over_print_attr:
-	free(sll);
-	np = NULL;
-	while ((np = nvlist_next_nvpair(nvl, np)) != NULL) {
-		if (nvpair_type(np) != DATA_TYPE_STRING)
-			continue;
-		if (nvpair_value_string(np, &s) != 0)
-			continue;
-
-		(void) fprintf(stderr, "%s   <Failed to load>    %s\n",
-		    nvpair_name(np), s);
-	}
-	nvlist_free(nvl);
 	return (0);
 }
 
@@ -801,47 +626,121 @@
 }
 
 int
-print_lu_attr(uint64_t handle, char **s)
+print_lu_attr(stmfGuid *guid)
 {
-	sbd_lu_attr_t *sla;
-
-	sla = (sbd_lu_attr_t *)big_buf;
-
-	bzero(sla, BIG_BUF_SIZE);
+	luResource hdl = NULL;
+	int stmfRet = 0;
+	int ret = 0;
+	char propVal[MAXPATHLEN];
+	size_t propValSize = sizeof (propVal);
 
-	sla->lu_handle = handle;
-	sla->total_struct_size = BIG_BUF_SIZE;
-	sla->max_name_length = BIG_BUF_SIZE - sizeof (*sla) + 7;
+	if ((stmfRet = stmfGetLuResource(guid, &hdl)) != STMF_STATUS_SUCCESS) {
+		switch (stmfRet) {
+			case STMF_ERROR_BUSY:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("resource busy"));
+				break;
+			case STMF_ERROR_PERM:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("permission denied"));
+				break;
+			case STMF_ERROR_NOT_FOUND:
+				/* No error here */
+				return (0);
+				break;
+			default:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("get extended properties failed"));
+				break;
+		}
+		return (1);
+	}
 
-	if (ioctl(sbd_fd, SBD_GET_LU_ATTR, sla) < 0) {
-		(void) fprintf(stderr, "Request to get LU attr failed: %s\n",
-		    strerror(errno));
-		return (0);
+	print_guid((uint8_t *)guid, stdout);
+
+	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_SIZE, propVal,
+	    &propValSize);
+	if (stmfRet == STMF_STATUS_SUCCESS) {
+		(void) printf("  %-19s  ", propVal);
+	} else if (stmfRet == STMF_ERROR_NO_PROP) {
+		(void) printf("not set\n");
+	} else {
+		(void) printf("<error retrieving property>");
+		ret++;
+	}
+
+	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_FILENAME, propVal,
+	    &propValSize);
+	if (stmfRet == STMF_STATUS_SUCCESS) {
+		(void) printf("%s\n", propVal);
+	} else if (stmfRet == STMF_ERROR_NO_PROP) {
+		(void) printf("not set\n");
+	} else {
+		(void) printf("<error retrieving property>");
+		ret++;
 	}
 
-	print_guid(sla->guid, stdout);
+
+	(void) stmfFreeLuResource(hdl);
+	return (ret);
+}
 
-	if (sla->data_size > 9999999999999ull)
-		(void) printf("  %-19llu  ", sla->data_size);
-	else
-		(void) printf("      %-13llu    ", sla->data_size);
+/*
+ * input:
+ *  execFullName - exec name of program (argv[0])
+ *
+ *  copied from usr/src/cmd/zoneadm/zoneadm.c in OS/Net
+ *  (changed name to lowerCamelCase to keep consistent with this file)
+ *
+ * Returns:
+ *  command name portion of execFullName
+ */
+static char *
+getExecBasename(char *execFullname)
+{
+	char *lastSlash, *execBasename;
 
-	if (sla->flags & RLC_LU_TYPE_MEMDISK) {
-		(void) printf("<RAM : %llu bytes>\n", sla->total_size);
-	} else {
-		(void) printf("%s\n", sla->name);
+	/* guard against '/' at end of command invocation */
+	for (;;) {
+		lastSlash = strrchr(execFullname, '/');
+		if (lastSlash == NULL) {
+			execBasename = execFullname;
+			break;
+		} else {
+			execBasename = lastSlash + 1;
+			if (*execBasename == '\0') {
+				*lastSlash = '\0';
+				continue;
+			}
+			break;
+		}
 	}
-	if (s != NULL) {
-		(void) snprintf((char *)big_buf, sizeof (big_buf),
-		    "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
-		    "%02x%02x%02x%02x%02x%02x",
-		    sla->guid[0], sla->guid[1], sla->guid[2],
-		    sla->guid[3], sla->guid[4], sla->guid[5],
-		    sla->guid[6], sla->guid[7], sla->guid[8],
-		    sla->guid[9], sla->guid[10], sla->guid[11],
-		    sla->guid[12], sla->guid[13], sla->guid[14],
-		    sla->guid[15]);
-		*s = (char *)big_buf;
+	return (execBasename);
+}
+int
+main(int argc, char *argv[])
+{
+	synTables_t synTables;
+	char versionString[VERSION_STRING_MAX_LEN];
+	int ret;
+	int funcRet;
+	void *subcommandArgs = NULL;
+
+	(void) setlocale(LC_ALL, "");
+	(void) textdomain(TEXT_DOMAIN);
+	/* set global command name */
+	cmdName = getExecBasename(argv[0]);
+
+	(void) snprintf(versionString, VERSION_STRING_MAX_LEN, "%s.%s",
+	    VERSION_STRING_MAJOR, VERSION_STRING_MINOR);
+	synTables.versionString = versionString;
+	synTables.longOptionTbl = options;
+	synTables.subCommandPropsTbl = subCommands;
+
+	ret = cmdParse(argc, argv, synTables, subcommandArgs, &funcRet);
+	if (ret != 0) {
+		return (ret);
 	}
-	return (1);
-}
+
+	return (funcRet);
+} /* end main */
--- a/usr/src/cmd/stmfadm/stmfadm.c	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/cmd/stmfadm/stmfadm.c	Fri May 08 16:22:42 2009 -0600
@@ -46,6 +46,10 @@
 static int addTargetGroupMemberFunc(int, char **, cmdOptions_t *, void *);
 static int addViewFunc(int, char **, cmdOptions_t *, void *);
 static int createHostGroupFunc(int, char **, cmdOptions_t *, void *);
+static int createLuFunc(int, char **, cmdOptions_t *, void *);
+static int modifyLuFunc(int, char **, cmdOptions_t *, void *);
+static int importLuFunc(int, char **, cmdOptions_t *, void *);
+static int deleteLuFunc(int, char **, cmdOptions_t *, void *);
 static int createTargetGroupFunc(int, char **, cmdOptions_t *, void *);
 static int deleteHostGroupFunc(int, char **, cmdOptions_t *, void *);
 static int deleteTargetGroupFunc(int, char **, cmdOptions_t *, void *);
@@ -63,6 +67,7 @@
 static int onlineOfflineLu(char *, int);
 static int removeHostGroupMemberFunc(int, char **, cmdOptions_t *, void *);
 static int removeTargetGroupMemberFunc(int, char **, cmdOptions_t *, void *);
+static int callModify(char *, stmfGuid *, uint32_t, const char *, const char *);
 static int removeViewFunc(int, char **, cmdOptions_t *, void *);
 static char *getExecBasename(char *);
 static int parseDevid(char *input, stmfDevid *devid);
@@ -71,9 +76,12 @@
 static int checkHexUpper(char *);
 static int checkIscsiName(wchar_t *);
 static void printLuProps(stmfLogicalUnitProperties *luProps);
+static int printExtLuProps(stmfGuid *guid);
 static void printGuid(stmfGuid *guid, FILE *printWhere);
 static void printTargetProps(stmfTargetProperties *);
 static void printSessionProps(stmfSessionList *);
+static int setLuPropFromInput(luResource, char *);
+static int convertCharToPropId(char *, uint32_t *);
 
 
 
@@ -107,21 +115,68 @@
 #define	SNS_WWN_16		    16
 #define	SNS_IQN_223		    223
 
+/* LU Property strings */
+#define	GUID			    "GUID"
+#define	ALIAS			    "ALIAS"
+#define	VID			    "VID"
+#define	PID			    "PID"
+#define	META_FILE		    "META"
+#define	WRITE_PROTECT		    "WP"
+#define	WRITEBACK_CACHE_DISABLE	    "WCD"
+#define	COMPANY_ID		    "OUI"
+#define	BLOCK_SIZE		    "BLK"
+#define	SERIAL_NUMBER		    "SERIAL"
+
+#define	MODIFY_HELP "\n"\
+"Description: Modify properties of a logical unit. \n" \
+"Valid properties for -p, --lu-prop are: \n" \
+"     alias - alias for logical unit (up to 255 chars)\n" \
+"     wcd   - write cache disabled (true, false)\n" \
+"     wp    - write protect (true, false)\n\n" \
+"-f alters the meaning of the operand to be a file name\n" \
+"rather than a LU name. This allows for modification\n" \
+"of a logical unit that is not yet imported into stmf\n"
+
+#define	CREATE_HELP "\n"\
+"Description: Create a logical unit. \n" \
+"Valid properties for -p, --lu-prop are: \n" \
+"     alias - alias for logical unit (up to 255 chars)\n" \
+"     blk   - block size in bytes in 2^n\n" \
+"     guid  - 32 ascii hex characters in NAA format \n" \
+"     meta  - separate meta data file name\n" \
+"     oui   - organizational unique identifier\n" \
+"             6 ascii hex characters of valid format\n" \
+"     pid   - product identifier (up to 16 chars)\n" \
+"     serial- serial number (up to 252 chars)\n" \
+"     vid   - vendor identifier (up to 8 chars)\n" \
+"     wp    - write protect (true, false)\n" \
+"     wcd   - write cache disabled (true, false)\n"
+#define	ADD_VIEW_HELP "\n"\
+"Description: Add a view entry to a logical unit. \n" \
+"A view entry is comprised of three elements; the \n" \
+"logical unit number, the target group name and the\n" \
+"host group name. These three elements combine together\n" \
+"to form a view for a given COMSTAR logical unit.\n" \
+"This view is realized by a client, a SCSI initiator,\n" \
+"via a REPORT LUNS command. \n"
+
+
+
 /* tables set up based on cmdparse instructions */
 
 /* add new options here */
 optionTbl_t longOptions[] = {
 	{"all", no_arg, 'a', NULL},
 	{"group-name", required_arg, 'g', "group-name"},
-	{"secure-data", no_arg, 's', NULL},
+	{"keep-views", no_arg, 'k', NULL},
 	{"lu-name", required_arg, 'l', "LU-Name"},
 	{"lun", required_arg, 'n', "logical-unit-number"},
-	{"verbose", no_arg, 'v', NULL},
+	{"lu-prop", required_arg, 'p', "logical-unit-property=value"},
+	{"file", no_arg, 'f', "filename"},
+	{"size", required_arg, 's', "size K/M/G/T/P"},
 	{"target-group", required_arg, 't', "group-name"},
 	{"host-group", required_arg, 'h', "group-name"},
-	{"size", required_arg, 's', "size (k/M/G)"},
-	{"force", no_arg, 'r', NULL},
-	{"new", no_arg, 'n', NULL},
+	{"verbose", no_arg, 'v', NULL},
 	{NULL, 0, 0, 0}
 };
 
@@ -130,45 +185,53 @@
  */
 subCommandProps_t subcommands[] = {
 	{"add-hg-member", addHostGroupMemberFunc, "g", "g", NULL,
-		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER},
+		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
 	{"add-tg-member", addTargetGroupMemberFunc, "g", "g", NULL,
-		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER},
+		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
 	{"add-view", addViewFunc, "nth", NULL, NULL,
-		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU},
+		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, ADD_VIEW_HELP},
 	{"create-hg", createHostGroupFunc, NULL, NULL, NULL,
-		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME},
+		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
 	{"create-tg", createTargetGroupFunc, NULL, NULL, NULL,
-		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME},
+		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
+	{"create-lu", createLuFunc, "ps", NULL, NULL, OPERAND_MANDATORY_SINGLE,
+		"lu file", CREATE_HELP},
 	{"delete-hg", deleteHostGroupFunc, NULL, NULL, NULL,
-		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME},
+		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
+	{"modify-lu", modifyLuFunc, "psf", NULL, NULL, OPERAND_MANDATORY_SINGLE,
+		OPERANDSTRING_LU, MODIFY_HELP},
+	{"delete-lu", deleteLuFunc, "k", NULL, NULL,
+		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_LU, NULL},
 	{"delete-tg", deleteTargetGroupFunc, NULL, NULL, NULL,
-		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME},
+		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_GROUP_NAME, NULL},
+	{"import-lu", importLuFunc, NULL, NULL, NULL,
+		OPERAND_MANDATORY_SINGLE, "file name", NULL},
 	{"list-hg", listHostGroupFunc, "v", NULL, NULL,
-		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_GROUP_NAME},
+		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_GROUP_NAME, NULL},
 	{"list-lu", listLuFunc, "v", NULL, NULL, OPERAND_OPTIONAL_MULTIPLE,
-		OPERANDSTRING_LU},
+		OPERANDSTRING_LU, NULL},
 	{"list-state", listStateFunc, NULL, NULL, NULL, OPERAND_NONE, NULL},
 	{"list-target", listTargetFunc, "v", NULL, NULL,
-		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_TARGET},
+		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_TARGET, NULL},
 	{"list-tg", listTargetGroupFunc, "v", NULL, NULL,
-		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_GROUP_NAME},
+		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_GROUP_NAME, NULL},
 	{"list-view", listViewFunc, "l", "l", NULL,
-		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_VIEW_ENTRY},
+		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_VIEW_ENTRY, NULL},
 	{"online-lu", onlineLuFunc, NULL, NULL, NULL,
-		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU},
+		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, NULL},
 	{"offline-lu", offlineLuFunc, NULL, NULL, NULL,
-		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU},
+		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_LU, NULL},
 	{"online-target", onlineTargetFunc, NULL, NULL, NULL,
-		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_TARGET},
+		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_TARGET, NULL},
 	{"offline-target", offlineTargetFunc, NULL, NULL, NULL,
-		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_TARGET},
+		OPERAND_MANDATORY_SINGLE, OPERANDSTRING_TARGET, NULL},
 	{"remove-hg-member", removeHostGroupMemberFunc, "g", "g", NULL,
-		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER},
+		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
 	{"remove-tg-member", removeTargetGroupMemberFunc, "g", "g", NULL,
-		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER},
+		OPERAND_MANDATORY_MULTIPLE, OPERANDSTRING_GROUP_MEMBER, NULL},
 	{"remove-view", removeViewFunc, "la", "l", NULL,
-		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_VIEW_ENTRY},
-	{NULL, 0, NULL, NULL, 0, NULL, 0, NULL}
+		OPERAND_OPTIONAL_MULTIPLE, OPERANDSTRING_VIEW_ENTRY, NULL},
+	{NULL, 0, NULL, NULL, 0, NULL, 0, NULL, NULL}
 };
 
 /* globals */
@@ -718,6 +781,630 @@
 }
 
 /*
+ * createLuFunc
+ *
+ * Create a logical unit
+ *
+ */
+/*ARGSUSED*/
+static int
+createLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
+    void *args)
+{
+	luResource hdl = NULL;
+	int ret = 0;
+	int stmfRet = 0;
+	char guidAsciiBuf[33];
+	stmfGuid createdGuid;
+
+	stmfRet = stmfCreateLuResource(STMF_DISK, &hdl);
+
+	if (stmfRet != STMF_STATUS_SUCCESS) {
+		(void) fprintf(stderr, "%s: %s\n",
+		    cmdName, gettext("Failure to create lu resource\n"));
+		return (1);
+	}
+
+	for (; options->optval; options++) {
+		switch (options->optval) {
+			case 'p':
+				ret = setLuPropFromInput(hdl, options->optarg);
+				if (ret != 0) {
+					(void) stmfFreeLuResource(hdl);
+					return (1);
+				}
+				break;
+			case 's':
+				stmfRet = stmfSetLuProp(hdl, STMF_LU_PROP_SIZE,
+				    options->optarg);
+				if (stmfRet != STMF_STATUS_SUCCESS) {
+					(void) fprintf(stderr, "%s: %c: %s\n",
+					    cmdName, options->optval,
+					    gettext("size param invalid"));
+					(void) stmfFreeLuResource(hdl);
+					return (1);
+				}
+				break;
+			default:
+				(void) fprintf(stderr, "%s: %c: %s\n",
+				    cmdName, options->optval,
+				    gettext("unknown option"));
+				return (1);
+		}
+	}
+
+	stmfRet = stmfSetLuProp(hdl, STMF_LU_PROP_FILENAME, operands[0]);
+
+	if (stmfRet != STMF_STATUS_SUCCESS) {
+		(void) fprintf(stderr, "%s: %s\n",
+		    cmdName, gettext("could not set filename"));
+		return (1);
+	}
+
+	stmfRet = stmfCreateLu(hdl, &createdGuid);
+	switch (stmfRet) {
+		case STMF_STATUS_SUCCESS:
+			break;
+		case STMF_ERROR_BUSY:
+		case STMF_ERROR_LU_BUSY:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("resource busy"));
+			ret++;
+			break;
+		case STMF_ERROR_PERM:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("permission denied"));
+			ret++;
+			break;
+		case STMF_ERROR_FILE_IN_USE:
+			(void) fprintf(stderr, "%s: filename %s: %s\n", cmdName,
+			    operands[0], gettext("in use"));
+			ret++;
+			break;
+		case STMF_ERROR_INVALID_BLKSIZE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("invalid block size"));
+			ret++;
+			break;
+		case STMF_ERROR_GUID_IN_USE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("guid in use"));
+			ret++;
+			break;
+		case STMF_ERROR_META_FILE_NAME:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("meta file error"));
+			ret++;
+			break;
+		case STMF_ERROR_DATA_FILE_NAME:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("data file error"));
+			ret++;
+			break;
+		case STMF_ERROR_FILE_SIZE_INVALID:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("file size invalid"));
+			ret++;
+			break;
+		case STMF_ERROR_SIZE_OUT_OF_RANGE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("invalid size"));
+			ret++;
+			break;
+		case STMF_ERROR_META_CREATION:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("could not create meta file"));
+			ret++;
+			break;
+		case STMF_ERROR_WRITE_CACHE_SET:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("could not set write cache"));
+			ret++;
+			break;
+		default:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("unknown error"));
+			ret++;
+			break;
+	}
+
+	if (ret != 0) {
+		goto done;
+	}
+
+	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
+	    "%02X%02X%02X%02X%02X%02X",
+	    createdGuid.guid[0], createdGuid.guid[1], createdGuid.guid[2],
+	    createdGuid.guid[3], createdGuid.guid[4], createdGuid.guid[5],
+	    createdGuid.guid[6], createdGuid.guid[7], createdGuid.guid[8],
+	    createdGuid.guid[9], createdGuid.guid[10], createdGuid.guid[11],
+	    createdGuid.guid[12], createdGuid.guid[13], createdGuid.guid[14],
+	    createdGuid.guid[15]);
+	(void) printf("Logical unit created: %s\n", guidAsciiBuf);
+
+done:
+	(void) stmfFreeLuResource(hdl);
+	return (ret);
+}
+
+/*
+ * createLuFunc
+ *
+ * Create a logical unit
+ *
+ */
+/*ARGSUSED*/
+static int
+modifyLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
+    void *args)
+{
+	stmfGuid inGuid;
+	unsigned int guid[sizeof (stmfGuid)];
+	int ret = 0;
+	int i;
+	char *fname = NULL;
+	char *lasts = NULL;
+	char sGuid[GUID_INPUT + 1];
+	char *prop = NULL;
+	char *propVal = NULL;
+	boolean_t fnameUsed = B_FALSE;
+	uint32_t propId;
+	cmdOptions_t *optionStart = options;
+
+
+	for (; options->optval; options++) {
+		switch (options->optval) {
+			case 'f':
+				fnameUsed = B_TRUE;
+				fname = operands[0];
+				break;
+		}
+	}
+	options = optionStart;
+
+	/* check input length */
+	if (!fnameUsed && strlen(operands[0]) != GUID_INPUT) {
+		(void) fprintf(stderr, "%s: %s: %s%d%s\n", cmdName, operands[0],
+		    gettext("must be "), GUID_INPUT,
+		    gettext(" hexadecimal digits"));
+		return (1);
+	}
+
+	if (!fnameUsed) {
+		/* convert to lower case for scan */
+		for (i = 0; i < 32; i++)
+			sGuid[i] = tolower(operands[0][i]);
+		sGuid[i] = 0;
+		(void) sscanf(sGuid,
+		    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
+		    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4], &guid[5],
+		    &guid[6], &guid[7], &guid[8], &guid[9], &guid[10],
+		    &guid[11], &guid[12], &guid[13], &guid[14], &guid[15]);
+
+		for (i = 0; i < sizeof (stmfGuid); i++) {
+			inGuid.guid[i] = guid[i];
+		}
+	}
+
+	for (; options->optval; options++) {
+		switch (options->optval) {
+			case 'p':
+				prop = strtok_r(options->optarg, "=", &lasts);
+				if ((propVal = strtok_r(NULL, "=", &lasts))
+				    == NULL) {
+					(void) fprintf(stderr, "%s: %s: %s\n",
+					    cmdName, options->optarg,
+					gettext("invalid property specifier"
+					    "- prop=val\n"));
+					return (1);
+				}
+				ret = convertCharToPropId(prop, &propId);
+				if (ret != 0) {
+					(void) fprintf(stderr, "%s: %s: %s\n",
+					    cmdName,
+					gettext("invalid property specified"),
+					    prop);
+					return (1);
+				}
+				if (callModify(fname, &inGuid, propId, propVal,
+				    prop) != 0) {
+					return (1);
+				}
+				break;
+			case 's':
+				if (callModify(fname, &inGuid,
+				    STMF_LU_PROP_SIZE, options->optarg,
+				    "size") != 0) {
+					return (1);
+				}
+				break;
+			case 'f':
+				break;
+			default:
+				(void) fprintf(stderr, "%s: %c: %s\n",
+				    cmdName, options->optval,
+				    gettext("unknown option"));
+				return (1);
+		}
+	}
+	return (ret);
+}
+
+static int
+callModify(char *fname, stmfGuid *luGuid, uint32_t prop, const char *propVal,
+    const char *propString)
+{
+	int ret = 0;
+	int stmfRet = 0;
+
+	if (!fname) {
+		stmfRet = stmfModifyLu(luGuid, prop, propVal);
+	} else {
+		stmfRet = stmfModifyLuByFname(STMF_DISK, fname, prop,
+		    propVal);
+	}
+	switch (stmfRet) {
+		case STMF_STATUS_SUCCESS:
+			break;
+		case STMF_ERROR_BUSY:
+		case STMF_ERROR_LU_BUSY:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("resource busy"));
+			ret++;
+			break;
+		case STMF_ERROR_PERM:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("permission denied"));
+			ret++;
+			break;
+		case STMF_ERROR_INVALID_BLKSIZE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("invalid block size"));
+			ret++;
+			break;
+		case STMF_ERROR_GUID_IN_USE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("guid in use"));
+			ret++;
+			break;
+		case STMF_ERROR_META_FILE_NAME:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("meta file error"));
+			ret++;
+			break;
+		case STMF_ERROR_DATA_FILE_NAME:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("data file error"));
+			ret++;
+			break;
+		case STMF_ERROR_FILE_SIZE_INVALID:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("file size invalid"));
+			ret++;
+			break;
+		case STMF_ERROR_SIZE_OUT_OF_RANGE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("invalid size"));
+			ret++;
+			break;
+		case STMF_ERROR_META_CREATION:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("could not create meta file"));
+			ret++;
+			break;
+		case STMF_ERROR_INVALID_PROP:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("invalid property for modify"));
+			ret++;
+			break;
+		case STMF_ERROR_WRITE_CACHE_SET:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("could not set write cache"));
+			ret++;
+			break;
+		default:
+			(void) fprintf(stderr, "%s: %s: %s: %d\n", cmdName,
+			    gettext("could not set property"), propString,
+			    stmfRet);
+			ret++;
+			break;
+	}
+
+	return (ret);
+}
+
+
+/*
+ * importLuFunc
+ *
+ * Create a logical unit
+ *
+ */
+/*ARGSUSED*/
+static int
+importLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
+    void *args)
+{
+	int stmfRet = 0;
+	int ret = 0;
+	char guidAsciiBuf[33];
+	stmfGuid createdGuid;
+
+	stmfRet = stmfImportLu(STMF_DISK, operands[0], &createdGuid);
+	switch (stmfRet) {
+		case STMF_STATUS_SUCCESS:
+			break;
+		case STMF_ERROR_BUSY:
+		case STMF_ERROR_LU_BUSY:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("resource busy"));
+			ret++;
+			break;
+		case STMF_ERROR_PERM:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("permission denied"));
+			ret++;
+			break;
+		case STMF_ERROR_FILE_IN_USE:
+			(void) fprintf(stderr, "%s: filename %s: %s\n", cmdName,
+			    operands[0], gettext("in use"));
+			ret++;
+			break;
+		case STMF_ERROR_GUID_IN_USE:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("guid in use"));
+			ret++;
+			break;
+		case STMF_ERROR_META_FILE_NAME:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("meta file error"));
+			ret++;
+			break;
+		case STMF_ERROR_DATA_FILE_NAME:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("data file error"));
+			ret++;
+			break;
+		case STMF_ERROR_META_CREATION:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("could not create meta file"));
+			ret++;
+			break;
+		case STMF_ERROR_WRITE_CACHE_SET:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("could not set write cache"));
+			ret++;
+			break;
+		default:
+			(void) fprintf(stderr, "%s: %s\n", cmdName,
+			    gettext("unknown error"));
+			ret++;
+			break;
+	}
+
+	if (ret != STMF_STATUS_SUCCESS) {
+		goto done;
+	}
+
+	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+	    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
+	    "%02X%02X%02X%02X%02X%02X",
+	    createdGuid.guid[0], createdGuid.guid[1], createdGuid.guid[2],
+	    createdGuid.guid[3], createdGuid.guid[4], createdGuid.guid[5],
+	    createdGuid.guid[6], createdGuid.guid[7], createdGuid.guid[8],
+	    createdGuid.guid[9], createdGuid.guid[10], createdGuid.guid[11],
+	    createdGuid.guid[12], createdGuid.guid[13], createdGuid.guid[14],
+	    createdGuid.guid[15]);
+	(void) printf("Logical unit imported: %s\n", guidAsciiBuf);
+
+done:
+	return (ret);
+}
+
+static int
+setLuPropFromInput(luResource hdl, char *optarg)
+{
+	char *prop = NULL;
+	char *propVal = NULL;
+	char *lasts = NULL;
+	uint32_t propId;
+	int ret = 0;
+
+	prop = strtok_r(optarg, "=", &lasts);
+	if ((propVal = strtok_r(NULL, "=", &lasts)) == NULL) {
+		(void) fprintf(stderr, "%s: %s: %s\n",
+		    cmdName, optarg,
+		    gettext("invalid property specifier - prop=val\n"));
+		return (1);
+	}
+
+	ret = convertCharToPropId(prop, &propId);
+	if (ret != 0) {
+		(void) fprintf(stderr, "%s: %s: %s\n",
+		    cmdName, gettext("invalid property specified"), prop);
+		return (1);
+	}
+
+	ret = stmfSetLuProp(hdl, propId, propVal);
+	if (ret != STMF_STATUS_SUCCESS) {
+		(void) fprintf(stderr, "%s: %s %s: ",
+		    cmdName, gettext("unable to set"), prop);
+		switch (ret) {
+			case STMF_ERROR_INVALID_PROPSIZE:
+				(void) fprintf(stderr, "invalid length\n");
+				break;
+			case STMF_ERROR_INVALID_ARG:
+				(void) fprintf(stderr, "bad format\n");
+				break;
+			default:
+				(void) fprintf(stderr, "\n");
+				break;
+		}
+		return (1);
+	}
+
+	return (0);
+}
+
+static int
+convertCharToPropId(char *prop, uint32_t *propId)
+{
+	if (strcasecmp(prop, GUID) == 0) {
+		*propId = STMF_LU_PROP_GUID;
+	} else if (strcasecmp(prop, ALIAS) == 0) {
+		*propId = STMF_LU_PROP_ALIAS;
+	} else if (strcasecmp(prop, VID) == 0) {
+		*propId = STMF_LU_PROP_VID;
+	} else if (strcasecmp(prop, PID) == 0) {
+		*propId = STMF_LU_PROP_PID;
+	} else if (strcasecmp(prop, WRITE_PROTECT) == 0) {
+		*propId = STMF_LU_PROP_WRITE_PROTECT;
+	} else if (strcasecmp(prop, WRITEBACK_CACHE_DISABLE) == 0) {
+		*propId = STMF_LU_PROP_WRITE_CACHE_DISABLE;
+	} else if (strcasecmp(prop, BLOCK_SIZE) == 0) {
+		*propId = STMF_LU_PROP_BLOCK_SIZE;
+	} else if (strcasecmp(prop, SERIAL_NUMBER) == 0) {
+		*propId = STMF_LU_PROP_SERIAL_NUM;
+	} else if (strcasecmp(prop, COMPANY_ID) == 0) {
+		*propId = STMF_LU_PROP_COMPANY_ID;
+	} else if (strcasecmp(prop, META_FILE) == 0) {
+		*propId = STMF_LU_PROP_META_FILENAME;
+	} else {
+		return (1);
+	}
+	return (0);
+}
+
+/*
+ * deleteLuFunc
+ *
+ * Delete a logical unit
+ *
+ */
+/*ARGSUSED*/
+static int
+deleteLuFunc(int operandLen, char *operands[], cmdOptions_t *options,
+    void *args)
+{
+	int i, j;
+	int ret = 0;
+	int stmfRet;
+	unsigned int inGuid[sizeof (stmfGuid)];
+	stmfGuid delGuid;
+	boolean_t keepViews = B_FALSE;
+	boolean_t viewEntriesRemoved = B_FALSE;
+	boolean_t noLunFound = B_FALSE;
+	boolean_t views = B_FALSE;
+	char sGuid[GUID_INPUT + 1];
+	stmfViewEntryList *viewEntryList = NULL;
+
+	for (; options->optval; options++) {
+		switch (options->optval) {
+			/* Keep views for logical unit */
+			case 'k':
+				keepViews = B_TRUE;
+				break;
+			default:
+				(void) fprintf(stderr, "%s: %c: %s\n",
+				    cmdName, options->optval,
+				    gettext("unknown option"));
+				return (1);
+		}
+	}
+
+
+	for (i = 0; i < operandLen; i++) {
+		for (j = 0; j < GUID_INPUT; j++) {
+			if (!isxdigit(operands[i][j])) {
+				break;
+			}
+			sGuid[j] = tolower(operands[i][j]);
+		}
+		if (j != GUID_INPUT) {
+			(void) fprintf(stderr, "%s: %s: %s%d%s\n",
+			    cmdName, operands[i], gettext("must be "),
+			    GUID_INPUT,
+			    gettext(" hexadecimal digits long"));
+			continue;
+		}
+
+		sGuid[j] = 0;
+
+		(void) sscanf(sGuid,
+		    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
+		    &inGuid[0], &inGuid[1], &inGuid[2], &inGuid[3],
+		    &inGuid[4], &inGuid[5], &inGuid[6], &inGuid[7],
+		    &inGuid[8], &inGuid[9], &inGuid[10], &inGuid[11],
+		    &inGuid[12], &inGuid[13], &inGuid[14], &inGuid[15]);
+
+		for (j = 0; j < sizeof (stmfGuid); j++) {
+			delGuid.guid[j] = inGuid[j];
+		}
+
+		stmfRet = stmfDeleteLu(&delGuid);
+		switch (stmfRet) {
+			case STMF_STATUS_SUCCESS:
+				break;
+			case STMF_ERROR_NOT_FOUND:
+				noLunFound = B_TRUE;
+				break;
+			case STMF_ERROR_BUSY:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("resource busy"));
+				ret++;
+				break;
+			case STMF_ERROR_PERM:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("permission denied"));
+				ret++;
+				break;
+			default:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("unknown error"));
+				ret++;
+				break;
+		}
+
+		if (!keepViews) {
+			stmfRet = stmfGetViewEntryList(&delGuid,
+			    &viewEntryList);
+			if (stmfRet == STMF_STATUS_SUCCESS) {
+				for (j = 0; j < viewEntryList->cnt; j++) {
+					(void) stmfRemoveViewEntry(&delGuid,
+					    viewEntryList->ve[j].veIndex);
+				}
+				viewEntriesRemoved = B_TRUE;
+				stmfFreeMemory(viewEntryList);
+			} else if (stmfRet != STMF_ERROR_NOT_FOUND) {
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("unable to remove view entries\n"));
+				ret++;
+			} /* No view entries to remove */
+		}
+		if (keepViews) {
+			stmfRet = stmfGetViewEntryList(&delGuid,
+			    &viewEntryList);
+			if (stmfRet == STMF_STATUS_SUCCESS) {
+				views = B_TRUE;
+				stmfFreeMemory(viewEntryList);
+			}
+		}
+
+		if ((!viewEntriesRemoved && noLunFound && !views) ||
+		    (!views && keepViews && noLunFound)) {
+			(void) fprintf(stderr, "%s: %s: %s\n",
+			    cmdName, sGuid,
+			    gettext("not found"));
+			ret++;
+		}
+		noLunFound = viewEntriesRemoved = views = B_FALSE;
+	}
+	return (ret);
+}
+
+
+/*
  * createTargetGroupFunc
  *
  * Create a target group
@@ -1235,6 +1922,7 @@
 				    cmdName, operands[i], gettext("must be "),
 				    GUID_INPUT,
 				    gettext(" hexadecimal digits long"));
+				invalidInput = B_FALSE;
 				continue;
 			}
 
@@ -1296,6 +1984,8 @@
 						(void) printf("unknown");
 					}
 					(void) printf("\n");
+					ret = printExtLuProps(
+					    &(luList->guid[j]));
 				}
 				if (found && operandEntered) {
 					break;
@@ -1322,6 +2012,154 @@
 	}
 }
 
+static int
+printExtLuProps(stmfGuid *guid)
+{
+	int stmfRet;
+	luResource hdl = NULL;
+	int ret = 0;
+	char propVal[MAXNAMELEN];
+	size_t propValSize = sizeof (propVal);
+
+	if ((stmfRet = stmfGetLuResource(guid, &hdl))
+	    != STMF_STATUS_SUCCESS) {
+		switch (stmfRet) {
+			case STMF_ERROR_BUSY:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("resource busy"));
+				break;
+			case STMF_ERROR_PERM:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("permission denied"));
+				break;
+			case STMF_ERROR_NOT_FOUND:
+				/* No error here */
+				return (0);
+				break;
+			default:
+				(void) fprintf(stderr, "%s: %s\n", cmdName,
+				    gettext("get extended properties failed"));
+				break;
+		}
+		return (1);
+	}
+
+	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_FILENAME, propVal,
+	    &propValSize);
+	(void) printf(PROPS_FORMAT, "Data File");
+	if (stmfRet == STMF_STATUS_SUCCESS) {
+		(void) printf("%s\n", propVal);
+	} else if (stmfRet == STMF_ERROR_NO_PROP) {
+		(void) printf("not set\n");
+	} else {
+		(void) printf("<error retrieving property>\n");
+		ret++;
+	}
+
+	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_META_FILENAME, propVal,
+	    &propValSize);
+	(void) printf(PROPS_FORMAT, "Meta File");
+	if (stmfRet == STMF_STATUS_SUCCESS) {
+		(void) printf("%s\n", propVal);
+	} else if (stmfRet == STMF_ERROR_NO_PROP) {
+		(void) printf("not set\n");
+	} else {
+		(void) printf("<error retrieving property>\n");
+		ret++;
+	}
+
+	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_SIZE, propVal,
+	    &propValSize);
+	(void) printf(PROPS_FORMAT, "Size");
+	if (stmfRet == STMF_STATUS_SUCCESS) {
+		(void) printf("%s\n", propVal);
+	} else if (stmfRet == STMF_ERROR_NO_PROP) {
+		(void) printf("not set\n");
+	} else {
+		(void) printf("<error retrieving property>\n");
+		ret++;
+	}
+
+	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_BLOCK_SIZE, propVal,
+	    &propValSize);
+	(void) printf(PROPS_FORMAT, "Block Size");
+	if (stmfRet == STMF_STATUS_SUCCESS) {
+		(void) printf("%s\n", propVal);
+	} else if (stmfRet == STMF_ERROR_NO_PROP) {
+		(void) printf("not set\n");
+	} else {
+		(void) printf("<error retrieving property>\n");
+		ret++;
+	}
+
+	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_VID, propVal,
+	    &propValSize);
+	(void) printf(PROPS_FORMAT, "Vendor ID");
+	if (stmfRet == STMF_STATUS_SUCCESS) {
+		(void) printf("%s\n", propVal);
+	} else if (stmfRet == STMF_ERROR_NO_PROP) {
+		(void) printf("not set\n");
+	} else {
+		(void) printf("<error retrieving property>\n");
+		ret++;
+	}
+
+	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_PID, propVal,
+	    &propValSize);
+	(void) printf(PROPS_FORMAT, "Product ID");
+	if (stmfRet == STMF_STATUS_SUCCESS) {
+		(void) printf("%s\n", propVal);
+	} else if (stmfRet == STMF_ERROR_NO_PROP) {
+		(void) printf("not set\n");
+	} else {
+		(void) printf("<error retrieving property>\n");
+		ret++;
+	}
+
+	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_SERIAL_NUM, propVal,
+	    &propValSize);
+	(void) printf(PROPS_FORMAT, "Serial Num");
+	if (stmfRet == STMF_STATUS_SUCCESS) {
+		(void) printf("%s\n", propVal);
+	} else if (stmfRet == STMF_ERROR_NO_PROP) {
+		(void) printf("not set\n");
+	} else {
+		(void) printf("<error retrieving property>\n");
+		ret++;
+	}
+
+	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_WRITE_PROTECT, propVal,
+	    &propValSize);
+	(void) printf(PROPS_FORMAT, "Write Protect");
+	if (stmfRet == STMF_STATUS_SUCCESS) {
+		(void) printf("%s\n",
+		    strcasecmp(propVal, "true") ? "Disabled" : "Enabled");
+	} else if (stmfRet == STMF_ERROR_NO_PROP) {
+		(void) printf("not set\n");
+	} else {
+		(void) printf("<error retrieving property>\n");
+		ret++;
+	}
+
+	stmfRet = stmfGetLuProp(hdl, STMF_LU_PROP_WRITE_CACHE_DISABLE, propVal,
+	    &propValSize);
+	(void) printf(PROPS_FORMAT, "Writeback Cache");
+	if (stmfRet == STMF_STATUS_SUCCESS) {
+		(void) printf("%s\n",
+		    strcasecmp(propVal, "true") ? "Enabled" : "Disabled");
+	} else if (stmfRet == STMF_ERROR_NO_PROP) {
+		(void) printf("not set\n");
+	} else {
+		(void) printf("<error retrieving property>\n");
+		ret++;
+	}
+
+
+	(void) stmfFreeLuResource(hdl);
+	return (ret);
+
+}
+
 
 /*
  * printLuProps
@@ -1479,8 +2317,8 @@
 			    gettext("STMF service version incorrect"));
 			break;
 		default:
-			(void) fprintf(stderr, "%s: %s\n", cmdName,
-			    gettext("unknown error"));
+			(void) fprintf(stderr, "%s: %s: %d\n", cmdName,
+			    gettext("unknown error"), ret);
 			break;
 	}
 	return (ret);
--- a/usr/src/common/cmdparse/cmdparse.c	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/common/cmdparse/cmdparse.c	Fri May 08 16:22:42 2009 -0600
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -250,6 +250,9 @@
 		}
 	}
 	(void) fprintf(stdout, "\n");
+	if (subcommand->helpText) {
+		(void) printf("%s\n", subcommand->helpText);
+	}
 }
 
 /*
--- a/usr/src/common/cmdparse/cmdparse.h	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/common/cmdparse/cmdparse.h	Fri May 08 16:22:42 2009 -0600
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -126,7 +126,8 @@
 	char *exclusive;
 	int operand;
 	char *operandDefinition;
-	uint8_t reserved[64];
+	char *helpText;
+	uint8_t reserved[60];
 } subCommandProps_t;
 
 
--- a/usr/src/lib/libstmf/Makefile.com	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/lib/libstmf/Makefile.com	Fri May 08 16:22:42 2009 -0600
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -38,7 +38,7 @@
 
 C99MODE=	-xc99=%all
 C99LMODE=	-Xc99=%all
-LDLIBS +=	-lc -lnvpair -lscf
+LDLIBS +=	-lc -lnvpair -lscf -lm
 CPPFLAGS +=	$(INCS) -D_REENTRANT
 
 $(LINTLIB) := SRCS=	$(SRCDIR)/$(LINTSRC)
--- a/usr/src/lib/libstmf/common/libstmf.h	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/lib/libstmf/common/libstmf.h	Fri May 08 16:22:42 2009 -0600
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -80,18 +80,63 @@
 #define	STMF_ERROR_INVALID_HG		(STMF_STATUS_ERROR | 0x11)
 #define	STMF_ERROR_INVALID_TG		(STMF_STATUS_ERROR | 0x12)
 #define	STMF_ERROR_PROV_DATA_STALE	(STMF_STATUS_ERROR | 0x13)
+#define	STMF_ERROR_NO_PROP		(STMF_STATUS_ERROR | 0x14)
+#define	STMF_ERROR_NO_PROP_VAL		(STMF_STATUS_ERROR | 0x15)
+#define	STMF_ERROR_MISSING_PROP_VAL	(STMF_STATUS_ERROR | 0x16)
+#define	STMF_ERROR_INVALID_BLOCKSIZE	(STMF_STATUS_ERROR | 0x17)
+#define	STMF_ERROR_FILE_ALREADY		(STMF_STATUS_ERROR | 0x18)
+#define	STMF_ERROR_INVALID_PROPSIZE	(STMF_STATUS_ERROR | 0x19)
+#define	STMF_ERROR_INVALID_PROP		(STMF_STATUS_ERROR | 0x20)
+#define	STMF_ERROR_PERSIST_TYPE		(STMF_STATUS_ERROR | 0x21)
+
+/* Failures for stmfCreateLu */
+#define	STMF_ERROR_FILE_IN_USE		(STMF_STATUS_ERROR | 0x100)
+#define	STMF_ERROR_INVALID_BLKSIZE	(STMF_STATUS_ERROR | 0x101)
+#define	STMF_ERROR_GUID_IN_USE		(STMF_STATUS_ERROR | 0x102)
+#define	STMF_ERROR_META_FILE_NAME	(STMF_STATUS_ERROR | 0x103)
+#define	STMF_ERROR_DATA_FILE_NAME	(STMF_STATUS_ERROR | 0x104)
+#define	STMF_ERROR_SIZE_OUT_OF_RANGE	(STMF_STATUS_ERROR | 0x105)
+#define	STMF_ERROR_LU_BUSY		(STMF_STATUS_ERROR | 0x106)
+#define	STMF_ERROR_META_CREATION	(STMF_STATUS_ERROR | 0x107)
+#define	STMF_ERROR_FILE_SIZE_INVALID	(STMF_STATUS_ERROR | 0x108)
+#define	STMF_ERROR_WRITE_CACHE_SET	(STMF_STATUS_ERROR | 0x109)
 
 /* Initiator Name Types */
 #define	STMF_FC_PORT_WWN	    1
 #define	STMF_ISCSI_NAME		    2
 
-/* protected data flag for provider store */
-#define	STMF_PROTECTED_DATA	0x0001
 
 /* provider types */
 #define	STMF_LU_PROVIDER_TYPE	1
 #define	STMF_PORT_PROVIDER_TYPE	2
 
+/* LU Resource types */
+#define	STMF_DISK   0
+
+/* Persistence methods */
+#define	STMF_PERSIST_SMF	1
+#define	STMF_PERSIST_NONE	2
+
+/*
+ * LU Disk Properties
+ */
+
+enum {
+	STMF_LU_PROP_ALIAS = 1,
+	STMF_LU_PROP_BLOCK_SIZE,
+	STMF_LU_PROP_COMPANY_ID,
+	STMF_LU_PROP_FILENAME,
+	STMF_LU_PROP_GUID,
+	STMF_LU_PROP_META_FILENAME,
+	STMF_LU_PROP_NEW,
+	STMF_LU_PROP_SIZE,
+	STMF_LU_PROP_WRITE_PROTECT,
+	STMF_LU_PROP_WRITE_CACHE_DISABLE,
+	STMF_LU_PROP_VID,
+	STMF_LU_PROP_PID,
+	STMF_LU_PROP_SERIAL_NUM
+};
+
 
 /* devid code set and name types */
 #define	EUI_64_TYPE	2
@@ -224,6 +269,8 @@
 	stmfGuid    luid;
 } stmfLogicalUnitProperties;
 
+typedef void * luResource;
+
 typedef struct _stmfLogicalUnitProviderProperties
 {
 	char	    providerName[MAXPATHLEN];
@@ -247,11 +294,15 @@
 int stmfAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry);
 int stmfClearProviderData(char *providerName, int providerType);
 int stmfCreateHostGroup(stmfGroupName *hostGroupName);
+int stmfCreateLu(luResource hdl, stmfGuid *luGuid);
+int stmfCreateLuResource(uint16_t dType, luResource *hdl);
 int stmfCreateTargetGroup(stmfGroupName *targetGroupName);
 int stmfDeleteHostGroup(stmfGroupName *hostGroupName);
+int stmfDeleteLu(stmfGuid *luGuid);
 int stmfDeleteTargetGroup(stmfGroupName *targetGroupName);
 int stmfDevidFromIscsiName(char *iscsiName, stmfDevid *devid);
 int stmfDevidFromWwn(uchar_t wwn[8], stmfDevid *devid);
+int stmfFreeLuResource(luResource hdl);
 void stmfFreeMemory(void *);
 int stmfGetHostGroupList(stmfGroupList **initiatorGroupList);
 int stmfGetHostGroupMembers(stmfGroupName *hostGroupName,
@@ -265,6 +316,10 @@
 int stmfGetLogicalUnitProviderList(stmfProviderList **logicalUnitProviderList);
 int stmfGetLogicalUnitProviderProperties(stmfProviderName *providerName,
     stmfLogicalUnitProviderProperties *providerProperties);
+int stmfGetLuProp(luResource hdl, uint32_t propType, char *prop,
+    size_t *propLen);
+int stmfGetLuResource(stmfGuid *luGuid, luResource *hdl);
+int stmfGetPersistMethod(uint8_t *persistType, boolean_t serviceState);
 int stmfGetProviderData(char *providerName, nvlist_t **nvl, int providerType);
 int stmfGetProviderDataProt(char *providerName, nvlist_t **nvl,
     int providerType, uint64_t *setToken);
@@ -277,7 +332,11 @@
 int stmfGetTargetProperties(stmfDevid *target,
     stmfTargetProperties *targetProps);
 int stmfGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList);
+int stmfImportLu(uint16_t dType, char *fname, stmfGuid *luGuid);
 int stmfLoadConfig(void);
+int stmfModifyLu(stmfGuid *luGuid, uint32_t prop, const char *propVal);
+int stmfModifyLuByFname(uint16_t dType, const char *fname, uint32_t prop,
+    const char *propVal);
 int stmfOffline(void);
 int stmfOfflineTarget(stmfDevid *devid);
 int stmfOfflineLogicalUnit(stmfGuid *logicalUnit);
@@ -289,6 +348,8 @@
 int stmfRemoveFromTargetGroup(stmfGroupName *targetGroupName,
     stmfDevid *targetName);
 int stmfRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex);
+int stmfSetLuProp(luResource hdl, uint32_t propType, const char *propVal);
+int stmfSetPersistMethod(uint8_t persistType, boolean_t serviceSet);
 int stmfSetProviderData(char *providerName, nvlist_t *nvl, int providerType);
 int stmfSetProviderDataProt(char *providerName, nvlist_t *nvl,
     int providerType, uint64_t *setToken);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libstmf/common/libstmf_impl.h	Fri May 08 16:22:42 2009 -0600
@@ -0,0 +1,75 @@
+/*
+ * 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	_LIBSTMF_IMPL_H
+#define	_LIBSTMF_IMPL_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <libstmf.h>
+
+typedef struct _luResourceImpl {
+	uint16_t type;
+	void *resource;
+} luResourceImpl;
+
+
+typedef struct _diskResource {
+	boolean_t   luDataFileNameValid;
+	char	    luDataFileName[MAXPATHLEN];
+	boolean_t   luMetaFileNameValid;
+	char	    luMetaFileName[MAXPATHLEN];
+	boolean_t   luSizeValid;
+	uint64_t    luSize;
+	boolean_t   blkSizeValid;
+	uint16_t    blkSize;
+	boolean_t   luGuidValid;
+	uint8_t	    luGuid[16];
+	boolean_t   serialNumValid;
+	char	    serialNum[253];
+	boolean_t   companyIdValid;
+	uint32_t    companyId;
+	boolean_t   luAliasValid;
+	char	    luAlias[256];
+	boolean_t   vidValid;
+	char	    vid[8];
+	boolean_t   pidValid;
+	char	    pid[16];
+	boolean_t   revValid;
+	char	    rev[4];
+	boolean_t   writeProtectEnableValid;
+	boolean_t   writeProtectEnable;
+	boolean_t   writebackCacheDisableValid;
+	boolean_t   writebackCacheDisable;
+} diskResource;
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _LIBSTMF_IMPL_H */
--- a/usr/src/lib/libstmf/common/mapfile-vers	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/lib/libstmf/common/mapfile-vers	Fri May 08 16:22:42 2009 -0600
@@ -42,26 +42,36 @@
 	    stmfAddViewEntry;
 	    stmfClearProviderData;
 	    stmfCreateHostGroup;
+	    stmfCreateLu;
+	    stmfCreateLuResource;
 	    stmfCreateTargetGroup;
 	    stmfDeleteHostGroup;
+	    stmfDeleteLu;
 	    stmfDeleteTargetGroup;
 	    stmfDevidFromIscsiName;
 	    stmfDevidFromWwn;
+	    stmfFreeLuResource;
 	    stmfFreeMemory;
 	    stmfGetHostGroupList;
 	    stmfGetHostGroupMembers;
+	    stmfGetLuProp;
+	    stmfGetLuResource;
 	    stmfGetTargetGroupList;
 	    stmfGetTargetGroupMembers;
 	    stmfGetTargetList;
 	    stmfGetTargetProperties;
 	    stmfGetLogicalUnitList;
 	    stmfGetLogicalUnitProperties;
+	    stmfGetPersistMethod;
 	    stmfGetProviderData;
 	    stmfGetProviderDataList;
 	    stmfGetProviderDataProt;
 	    stmfGetSessionList;
 	    stmfGetState;
 	    stmfGetViewEntryList;
+	    stmfImportLu;
+	    stmfModifyLu;
+	    stmfModifyLuByFname;
 	    stmfOfflineTarget;
 	    stmfOfflineLogicalUnit;
 	    stmfOnlineTarget;
@@ -69,8 +79,10 @@
 	    stmfRemoveFromHostGroup;
 	    stmfRemoveFromTargetGroup;
 	    stmfRemoveViewEntry;
+	    stmfSetPersistMethod;
 	    stmfSetProviderData;
 	    stmfSetProviderDataProt;
+	    stmfSetLuProp;
 	local:
 		*;
 };
--- a/usr/src/lib/libstmf/common/stmf.c	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/lib/libstmf/common/stmf.c	Fri May 08 16:22:42 2009 -0600
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -43,31 +43,58 @@
 #include <inttypes.h>
 #include <store.h>
 #include <locale.h>
+#include <math.h>
+#include <libstmf_impl.h>
 #include <sys/stmf_ioctl.h>
+#include <sys/stmf_sbd_ioctl.h>
 
 #define	STMF_PATH    "/devices/pseudo/stmf@0:admin"
+#define	SBD_PATH    "/devices/pseudo/stmf_sbd@0:admin"
 
 #define	EUI "eui."
 #define	WWN "wwn."
 #define	IQN "iqn."
-#define	WWN_ASCII_SIZE 16
+#define	LU_ASCII_GUID_SIZE 32
+#define	LU_GUID_SIZE 16
+#define	OUI_ASCII_SIZE 6
+#define	OUI_SIZE 3
 #define	IDENT_LENGTH_BYTE 3
 
-#define	MAX_LU		2<<16 - 1
-#define	MAX_TARGET_PORT	1024
-#define	MAX_PROVIDER	1024
-#define	MAX_GROUP	1024
-#define	MAX_SESSION	1024
+/* various initial allocation values */
+#define	ALLOC_LU		8192
+#define	ALLOC_TARGET_PORT	2048
+#define	ALLOC_PROVIDER		64
+#define	ALLOC_GROUP		2048
+#define	ALLOC_SESSION		2048
+#define	ALLOC_VE		256
+#define	ALLOC_PP_DATA_SIZE	128*1024
+#define	ALLOC_GRP_MEMBER	256
+
 #define	MAX_ISCSI_NAME	223
+#define	MAX_SERIAL_SIZE 252 + 1
+#define	MAX_LU_ALIAS_SIZE 256
+#define	MAX_SBD_PROPS	MAXPATHLEN + MAX_SERIAL_SIZE + MAX_LU_ALIAS_SIZE
 
 #define	OPEN_STMF 0
 #define	OPEN_EXCL_STMF O_EXCL
 
+#define	OPEN_SBD 0
+#define	OPEN_EXCL_SBD O_EXCL
+
 #define	LOGICAL_UNIT_TYPE 0
 #define	TARGET_TYPE 1
 #define	STMF_SERVICE_TYPE 2
 
+#define	HOST_GROUP   1
+#define	TARGET_GROUP 2
+
+/* set default persistence here */
+#define	STMF_DEFAULT_PERSIST	STMF_PERSIST_SMF
+
+#define	MAX_PROVIDER_RETRY 30
+
 static int openStmf(int, int *fd);
+static int openSbd(int, int *fd);
 static int groupIoctl(int fd, int cmd, stmfGroupName *);
 static int loadStore(int fd);
 static int initializeConfig();
@@ -78,7 +105,36 @@
 static int loadTargetGroups(int fd, stmfGroupList *);
 static int getStmfState(stmf_state_desc_t *);
 static int setStmfState(int fd, stmf_state_desc_t *, int);
-static int setProviderData(int fd, char *, nvlist_t *, int);
+static int setProviderData(int fd, char *, nvlist_t *, int, uint64_t *);
+static int createDiskResource(luResourceImpl *);
+static int createDiskLu(diskResource *, stmfGuid *);
+static int deleteDiskLu(stmfGuid *luGuid);
+static int getDiskProp(luResourceImpl *, uint32_t, char *, size_t *);
+static int getDiskAllProps(stmfGuid *luGuid, luResource *hdl);
+static int loadDiskPropsFromDriver(luResourceImpl *, sbd_lu_props_t *);
+static int removeGuidFromDiskStore(stmfGuid *);
+static int addGuidToDiskStore(stmfGuid *, char *);
+static int persistDiskGuid(stmfGuid *, char *, boolean_t);
+static int setDiskProp(luResourceImpl *, uint32_t, const char *);
+static int checkHexUpper(char *);
+static int strToShift(const char *);
+static int niceStrToNum(const char *, uint64_t *);
+static void diskError(uint32_t, int *);
+static int importDiskLu(char *fname, stmfGuid *);
+static int modifyDiskLu(diskResource *, stmfGuid *, const char *);
+static int modifyDiskLuProp(stmfGuid *, const char *, uint32_t, const char *);
+static int validateModifyDiskProp(uint32_t);
+static uint8_t iGetPersistMethod();
+static int groupListIoctl(stmfGroupList **, int);
+static int iLoadGroupFromPs(stmfGroupList **, int);
+static int groupMemberListIoctl(stmfGroupName *, stmfGroupProperties **, int);
+static int getProviderData(char *, nvlist_t **, int, uint64_t *);
+static int viewEntryCompare(const void *, const void *);
+
+static pthread_mutex_t persistenceTypeLock = PTHREAD_MUTEX_INITIALIZER;
+static int iPersistType = 0;
+/* when B_TRUE, no need to access SMF anymore. Just use iPersistType */
+static boolean_t iLibSetPersist = B_FALSE;
 
 /*
  * Open for stmf module
@@ -96,6 +152,8 @@
 	} else {
 		if (errno == EBUSY) {
 			ret = STMF_ERROR_BUSY;
+		} else if (errno == EACCES) {
+			ret = STMF_ERROR_PERM;
 		} else {
 			ret = STMF_STATUS_ERROR;
 		}
@@ -107,6 +165,34 @@
 }
 
 /*
+ * Open for sbd module
+ *
+ * flag - open flag (OPEN_STMF, OPEN_EXCL_STMF)
+ * fd - pointer to integer. On success, contains the stmf file descriptor
+ */
+static int
+openSbd(int flag, int *fd)
+{
+	int ret = STMF_STATUS_ERROR;
+
+	if ((*fd = open(SBD_PATH, O_NDELAY | O_RDONLY | flag)) != -1) {
+		ret = STMF_STATUS_SUCCESS;
+	} else {
+		if (errno == EBUSY) {
+			ret = STMF_ERROR_BUSY;
+		} else if (errno == EACCES) {
+			ret = STMF_ERROR_PERM;
+		} else {
+			ret = STMF_STATUS_ERROR;
+		}
+		syslog(LOG_DEBUG, "openSbd:open failure:%s:errno(%d)",
+		    SBD_PATH, errno);
+	}
+
+	return (ret);
+}
+
+/*
  * initializeConfig
  *
  * This routine should be called before any ioctl requiring initialization
@@ -187,6 +273,7 @@
 	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
 	if (ioctlRet != 0) {
 		switch (errno) {
+			case EPERM:
 			case EACCES:
 				ret = STMF_ERROR_PERM;
 				break;
@@ -219,7 +306,7 @@
 }
 
 /*
- * groupIoctl
+ * groupMemberIoctl
  *
  * Purpose: issue ioctl for add/remove member on group
  *
@@ -257,6 +344,7 @@
 			case EBUSY:
 				ret = STMF_ERROR_BUSY;
 				break;
+			case EPERM:
 			case EACCES:
 				ret = STMF_ERROR_PERM;
 				break;
@@ -292,6 +380,22 @@
 }
 
 /*
+ * qsort function
+ * sort on veIndex
+ */
+static int
+viewEntryCompare(const void *p1, const void *p2)
+{
+
+	stmfViewEntry *v1 = (stmfViewEntry *)p1, *v2 = (stmfViewEntry *)p2;
+	if (v1->veIndex > v2->veIndex)
+		return (1);
+	if (v1->veIndex < v2->veIndex)
+		return (-1);
+	return (0);
+}
+
+/*
  * guidCompare
  *
  * qsort function
@@ -351,6 +455,10 @@
 		goto done;
 	}
 
+	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+		goto done;
+	}
+
 	ret = psAddHostGroupMember((char *)hostGroupName,
 	    (char *)hostName->ident);
 	switch (ret) {
@@ -432,6 +540,10 @@
 		goto done;
 	}
 
+	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+		goto done;
+	}
+
 	ret = psAddTargetGroupMember((char *)targetGroupName,
 	    (char *)targetName->ident);
 	switch (ret) {
@@ -526,6 +638,9 @@
 			case EBUSY:
 				ret = STMF_ERROR_BUSY;
 				break;
+			case EPERM:
+				ret = STMF_ERROR_PERM;
+				break;
 			case EACCES:
 				switch (stmfIoctl.stmf_error) {
 					case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
@@ -651,6 +766,10 @@
 		goto done;
 	}
 
+	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+		goto done;
+	}
+
 	/*
 	 * If the add to driver was successful, add it to the persistent
 	 * store.
@@ -760,6 +879,7 @@
 			case EBUSY:
 				ret = STMF_ERROR_BUSY;
 				break;
+			case EPERM:
 			case EACCES:
 				ret = STMF_ERROR_PERM;
 				break;
@@ -775,6 +895,10 @@
 		}
 	}
 
+	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+		goto done;
+	}
+
 	ret = psClearProviderData(providerName, providerType);
 	switch (ret) {
 		case STMF_PS_SUCCESS:
@@ -846,6 +970,10 @@
 		goto done;
 	}
 
+	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+		goto done;
+	}
+
 	ret = psCreateHostGroup((char *)hostGroupName);
 	switch (ret) {
 		case STMF_PS_SUCCESS:
@@ -877,6 +1005,1641 @@
 }
 
 /*
+ * stmfCreateLu
+ *
+ * Purpose: Create a logical unit
+ *
+ * hdl - handle to logical unit resource created via stmfCreateLuResource
+ *
+ * luGuid - If non-NULL, on success, contains the guid of the created logical
+ *	    unit
+ */
+int
+stmfCreateLu(luResource hdl, stmfGuid *luGuid)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	luResourceImpl *luPropsHdl = hdl;
+
+	if (hdl == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	if (luPropsHdl->type == STMF_DISK) {
+		ret = createDiskLu((diskResource *)luPropsHdl->resource,
+		    luGuid);
+	} else {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	return (ret);
+}
+
+/*
+ * stmfCreateLuResource
+ *
+ * Purpose: Create resource handle for a logical unit
+ *
+ * dType - Type of logical unit resource to create
+ *	   Can be: STMF_DISK
+ *
+ * hdl - pointer to luResource
+ */
+int
+stmfCreateLuResource(uint16_t dType, luResource *hdl)
+{
+	int ret = STMF_STATUS_SUCCESS;
+
+	if (dType != STMF_DISK || hdl == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	*hdl = calloc(1, sizeof (luResourceImpl));
+	if (*hdl == NULL) {
+		return (STMF_ERROR_NOMEM);
+	}
+
+	ret = createDiskResource((luResourceImpl *)*hdl);
+	if (ret != STMF_STATUS_SUCCESS) {
+		free(*hdl);
+		return (ret);
+	}
+
+	return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * Creates a disk logical unit
+ *
+ * disk - pointer to diskResource structure that represents the properties
+ *        for the disk logical unit to be created.
+ */
+static int
+createDiskLu(diskResource *disk, stmfGuid *createdGuid)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	int dataFileNameLen = 0;
+	int metaFileNameLen = 0;
+	int serialNumLen = 0;
+	int luAliasLen = 0;
+	int sluBufSize = 0;
+	int bufOffset = 0;
+	int fd = 0;
+	int ioctlRet;
+	int savedErrno;
+	stmfGuid guid;
+	stmf_iocdata_t sbdIoctl = {0};
+
+	sbd_create_and_reg_lu_t *sbdLu = NULL;
+
+	/*
+	 * Open control node for sbd
+	 */
+	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+		return (ret);
+
+	/* data file name must be specified */
+	if (disk->luDataFileNameValid) {
+		dataFileNameLen = strlen(disk->luDataFileName);
+	} else {
+		(void) close(fd);
+		return (STMF_ERROR_MISSING_PROP_VAL);
+	}
+
+	sluBufSize += dataFileNameLen + 1;
+
+	if (disk->luMetaFileNameValid) {
+		metaFileNameLen = strlen(disk->luMetaFileName);
+		sluBufSize += metaFileNameLen + 1;
+	}
+
+	serialNumLen = strlen(disk->serialNum);
+	sluBufSize += serialNumLen;
+
+	if (disk->luAliasValid) {
+		luAliasLen = strlen(disk->luAlias);
+		sluBufSize += luAliasLen + 1;
+	}
+
+	/*
+	 * 8 is the size of the buffer set aside for
+	 * concatenation of variable length fields
+	 */
+	sbdLu = (sbd_create_and_reg_lu_t *)calloc(1,
+	    sizeof (sbd_create_and_reg_lu_t) + sluBufSize - 8);
+	if (sbdLu == NULL) {
+		return (STMF_ERROR_NOMEM);
+	}
+
+	sbdLu->slu_struct_size = sizeof (sbd_create_and_reg_lu_t) +
+	    sluBufSize - 8;
+
+	if (metaFileNameLen) {
+		sbdLu->slu_meta_fname_valid = 1;
+		sbdLu->slu_meta_fname_off = bufOffset;
+		bcopy(disk->luMetaFileName, &(sbdLu->slu_buf[bufOffset]),
+		    metaFileNameLen + 1);
+		bufOffset += metaFileNameLen + 1;
+	}
+
+	bcopy(disk->luDataFileName, &(sbdLu->slu_buf[bufOffset]),
+	    dataFileNameLen + 1);
+	sbdLu->slu_data_fname_off = bufOffset;
+	bufOffset += dataFileNameLen + 1;
+
+	/* currently, serial # is not passed null terminated to the driver */
+	if (disk->serialNumValid) {
+		sbdLu->slu_serial_valid = 1;
+		sbdLu->slu_serial_off = bufOffset;
+		sbdLu->slu_serial_size = serialNumLen;
+		bcopy(disk->serialNum, &(sbdLu->slu_buf[bufOffset]),
+		    serialNumLen);
+		bufOffset += serialNumLen;
+	}
+
+	if (disk->luAliasValid) {
+		sbdLu->slu_alias_valid = 1;
+		sbdLu->slu_alias_off = bufOffset;
+		bcopy(disk->luAlias, &(sbdLu->slu_buf[bufOffset]),
+		    luAliasLen + 1);
+		bufOffset += luAliasLen + 1;
+	}
+
+	if (disk->luSizeValid) {
+		sbdLu->slu_lu_size_valid = 1;
+		sbdLu->slu_lu_size = disk->luSize;
+	}
+
+	if (disk->luGuidValid) {
+		sbdLu->slu_guid_valid = 1;
+		bcopy(disk->luGuid, sbdLu->slu_guid, sizeof (disk->luGuid));
+	}
+
+	if (disk->vidValid) {
+		sbdLu->slu_vid_valid = 1;
+		bcopy(disk->vid, sbdLu->slu_vid, sizeof (disk->vid));
+	}
+
+	if (disk->pidValid) {
+		sbdLu->slu_pid_valid = 1;
+		bcopy(disk->pid, sbdLu->slu_pid, sizeof (disk->pid));
+	}
+
+	if (disk->revValid) {
+		sbdLu->slu_rev_valid = 1;
+		bcopy(disk->rev, sbdLu->slu_rev, sizeof (disk->rev));
+	}
+
+	if (disk->companyIdValid) {
+		sbdLu->slu_company_id_valid = 1;
+		sbdLu->slu_company_id = disk->companyId;
+	}
+
+	if (disk->blkSizeValid) {
+		sbdLu->slu_blksize_valid = 1;
+		sbdLu->slu_blksize = disk->blkSize;
+	}
+
+	if (disk->writeProtectEnableValid) {
+		if (disk->writeProtectEnable) {
+			sbdLu->slu_write_protected = 1;
+		}
+	}
+
+	if (disk->writebackCacheDisableValid) {
+		sbdLu->slu_writeback_cache_disable_valid = 1;
+		if (disk->writebackCacheDisable) {
+			sbdLu->slu_writeback_cache_disable = 1;
+		}
+	}
+
+	sbdIoctl.stmf_version = STMF_VERSION_1;
+	sbdIoctl.stmf_ibuf_size = sbdLu->slu_struct_size;
+	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
+	sbdIoctl.stmf_obuf_size = sbdLu->slu_struct_size;
+	sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdLu;
+
+	ioctlRet = ioctl(fd, SBD_IOCTL_CREATE_AND_REGISTER_LU, &sbdIoctl);
+	if (ioctlRet != 0) {
+		savedErrno = errno;
+		switch (savedErrno) {
+			case EBUSY:
+				ret = STMF_ERROR_BUSY;
+				break;
+			case EPERM:
+			case EACCES:
+				ret = STMF_ERROR_PERM;
+				break;
+			default:
+				diskError(sbdIoctl.stmf_error, &ret);
+				if (ret == STMF_STATUS_ERROR) {
+					syslog(LOG_DEBUG,
+					"createDiskLu:ioctl "
+					"error(%d) (%d) (%d)", ioctlRet,
+					    sbdIoctl.stmf_error, savedErrno);
+				}
+				break;
+		}
+	}
+
+	if (ret != STMF_STATUS_SUCCESS) {
+		goto done;
+	}
+
+	/*
+	 * on success, copy the resulting guid into the caller's guid if not
+	 * NULL
+	 */
+	if (createdGuid) {
+		bcopy(sbdLu->slu_guid, createdGuid->guid,
+		    sizeof (sbdLu->slu_guid));
+	}
+
+	bcopy(sbdLu->slu_guid, guid.guid, sizeof (sbdLu->slu_guid));
+	if (disk->luMetaFileNameValid) {
+		ret = addGuidToDiskStore(&guid, disk->luMetaFileName);
+	} else {
+		ret = addGuidToDiskStore(&guid, disk->luDataFileName);
+	}
+done:
+	free(sbdLu);
+	(void) close(fd);
+	return (ret);
+}
+
+
+/*
+ * stmfImportLu
+ *
+ * Purpose: Import a previously created logical unit
+ *
+ * dType - Type of logical unit
+ *         Can be: STMF_DISK
+ *
+ * luGuid - If non-NULL, on success, contains the guid of the imported logical
+ *	    unit
+ *
+ * fname - A file name where the metadata resides
+ *
+ */
+int
+stmfImportLu(uint16_t dType, char *fname, stmfGuid *luGuid)
+{
+	int ret = STMF_STATUS_SUCCESS;
+
+	if (dType == STMF_DISK) {
+		ret = importDiskLu(fname, luGuid);
+	} else {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	return (ret);
+}
+
+/*
+ * importDiskLu
+ *
+ * filename - filename to import
+ * createdGuid - if not NULL, on success contains the imported guid
+ *
+ */
+static int
+importDiskLu(char *fname, stmfGuid *createdGuid)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	int fd = 0;
+	int ioctlRet;
+	int savedErrno;
+	int metaFileNameLen;
+	stmfGuid iGuid;
+	int iluBufSize = 0;
+	sbd_import_lu_t *sbdLu = NULL;
+	stmf_iocdata_t sbdIoctl = {0};
+
+	if (fname == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	/*
+	 * Open control node for sbd
+	 */
+	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+		return (ret);
+
+	metaFileNameLen = strlen(fname);
+	iluBufSize += metaFileNameLen + 1;
+
+	/*
+	 * 8 is the size of the buffer set aside for
+	 * concatenation of variable length fields
+	 */
+	sbdLu = (sbd_import_lu_t *)calloc(1,
+	    sizeof (sbd_import_lu_t) + iluBufSize - 8);
+	if (sbdLu == NULL) {
+		(void) close(fd);
+		return (STMF_ERROR_NOMEM);
+	}
+
+	/*
+	 * Accept either a data file or meta data file.
+	 * sbd will do the right thing here either way.
+	 * i.e. if it's a data file, it assumes that the
+	 * meta data is shared with the data.
+	 */
+	(void) strncpy(sbdLu->ilu_meta_fname, fname, metaFileNameLen);
+
+	sbdLu->ilu_struct_size = sizeof (sbd_import_lu_t) + iluBufSize - 8;
+
+	sbdIoctl.stmf_version = STMF_VERSION_1;
+	sbdIoctl.stmf_ibuf_size = sbdLu->ilu_struct_size;
+	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
+	sbdIoctl.stmf_obuf_size = sbdLu->ilu_struct_size;
+	sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdLu;
+
+	ioctlRet = ioctl(fd, SBD_IOCTL_IMPORT_LU, &sbdIoctl);
+	if (ioctlRet != 0) {
+		savedErrno = errno;
+		switch (savedErrno) {
+			case EBUSY:
+				ret = STMF_ERROR_BUSY;
+				break;
+			case EPERM:
+			case EACCES:
+				ret = STMF_ERROR_PERM;
+				break;
+			default:
+				diskError(sbdIoctl.stmf_error, &ret);
+				if (ret == STMF_STATUS_ERROR) {
+					syslog(LOG_DEBUG,
+					"importDiskLu:ioctl "
+					"error(%d) (%d) (%d)", ioctlRet,
+					    sbdIoctl.stmf_error, savedErrno);
+				}
+				break;
+		}
+	}
+
+	if (ret != STMF_STATUS_SUCCESS) {
+		goto done;
+	}
+
+	/*
+	 * on success, copy the resulting guid into the caller's guid if not
+	 * NULL and add it to the persistent store for sbd
+	 */
+	if (createdGuid) {
+		bcopy(sbdLu->ilu_ret_guid, createdGuid->guid,
+		    sizeof (sbdLu->ilu_ret_guid));
+		ret = addGuidToDiskStore(createdGuid, fname);
+	} else {
+		bcopy(sbdLu->ilu_ret_guid, iGuid.guid,
+		    sizeof (sbdLu->ilu_ret_guid));
+		ret = addGuidToDiskStore(&iGuid, fname);
+	}
+done:
+	free(sbdLu);
+	(void) close(fd);
+	return (ret);
+}
+
+/*
+ * diskError
+ *
+ * Purpose: Translate sbd driver error
+ */
+static void
+diskError(uint32_t stmfError, int *ret)
+{
+	switch (stmfError) {
+		case SBD_RET_META_CREATION_FAILED:
+		case SBD_RET_ZFS_META_CREATE_FAILED:
+			*ret = STMF_ERROR_META_CREATION;
+			break;
+		case SBD_RET_INVALID_BLKSIZE:
+			*ret = STMF_ERROR_INVALID_BLKSIZE;
+			break;
+		case SBD_RET_FILE_ALREADY_REGISTERED:
+			*ret = STMF_ERROR_FILE_IN_USE;
+			break;
+		case SBD_RET_GUID_ALREADY_REGISTERED:
+			*ret = STMF_ERROR_GUID_IN_USE;
+			break;
+		case SBD_RET_META_PATH_NOT_ABSOLUTE:
+		case SBD_RET_META_FILE_LOOKUP_FAILED:
+		case SBD_RET_META_FILE_OPEN_FAILED:
+		case SBD_RET_META_FILE_GETATTR_FAILED:
+		case SBD_RET_NO_META:
+			*ret = STMF_ERROR_META_FILE_NAME;
+			break;
+		case SBD_RET_DATA_PATH_NOT_ABSOLUTE:
+		case SBD_RET_DATA_FILE_LOOKUP_FAILED:
+		case SBD_RET_DATA_FILE_OPEN_FAILED:
+		case SBD_RET_DATA_FILE_GETATTR_FAILED:
+			*ret = STMF_ERROR_DATA_FILE_NAME;
+			break;
+		case SBD_RET_FILE_SIZE_ERROR:
+			*ret = STMF_ERROR_FILE_SIZE_INVALID;
+			break;
+		case SBD_RET_SIZE_OUT_OF_RANGE:
+			*ret = STMF_ERROR_SIZE_OUT_OF_RANGE;
+			break;
+		case SBD_RET_LU_BUSY:
+			*ret = STMF_ERROR_LU_BUSY;
+			break;
+		case SBD_RET_WRITE_CACHE_SET_FAILED:
+			*ret = STMF_ERROR_WRITE_CACHE_SET;
+			break;
+		default:
+			*ret = STMF_STATUS_ERROR;
+			break;
+	}
+}
+
+/*
+ * Creates a logical unit resource of type STMF_DISK.
+ *
+ * No defaults should be set here as all defaults are derived from the
+ * driver's default settings.
+ */
+static int
+createDiskResource(luResourceImpl *hdl)
+{
+	hdl->type = STMF_DISK;
+
+	hdl->resource = calloc(1, sizeof (diskResource));
+	if (hdl->resource == NULL) {
+		return (STMF_ERROR_NOMEM);
+	}
+
+	return (STMF_STATUS_SUCCESS);
+}
+
+/*
+ * stmfDeleteLu
+ *
+ * Purpose: Delete a logical unit
+ *
+ * hdl - handle to logical unit resource created via stmfCreateLuResource
+ *
+ * luGuid - If non-NULL, on success, contains the guid of the created logical
+ *	    unit
+ */
+int
+stmfDeleteLu(stmfGuid *luGuid)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	stmfLogicalUnitProperties luProps;
+
+	if (luGuid == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	/* Check logical unit provider name to call correct dtype function */
+	if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
+	    != STMF_STATUS_SUCCESS) {
+		return (ret);
+	} else {
+		if (strcmp(luProps.providerName, "sbd") == 0) {
+			ret = deleteDiskLu(luGuid);
+		} else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
+			return (STMF_ERROR_NOT_FOUND);
+		} else {
+			return (STMF_ERROR_INVALID_ARG);
+		}
+	}
+
+	return (ret);
+}
+
+static int
+deleteDiskLu(stmfGuid *luGuid)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	int fd;
+	int savedErrno;
+	int ioctlRet;
+	sbd_delete_lu_t deleteLu = {0};
+
+	stmf_iocdata_t sbdIoctl = {0};
+
+	/*
+	 * Open control node for sbd
+	 */
+	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+		return (ret);
+
+	ret = removeGuidFromDiskStore(luGuid);
+	if (ret != STMF_STATUS_SUCCESS) {
+		goto done;
+	}
+
+	bcopy(luGuid, deleteLu.dlu_guid, sizeof (deleteLu.dlu_guid));
+	deleteLu.dlu_by_guid = 1;
+
+	sbdIoctl.stmf_version = STMF_VERSION_1;
+	sbdIoctl.stmf_ibuf_size = sizeof (deleteLu);
+	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)&deleteLu;
+	ioctlRet = ioctl(fd, SBD_IOCTL_DELETE_LU, &sbdIoctl);
+	if (ioctlRet != 0) {
+		savedErrno = errno;
+		switch (savedErrno) {
+			case EBUSY:
+				ret = STMF_ERROR_BUSY;
+				break;
+			case EPERM:
+			case EACCES:
+				ret = STMF_ERROR_PERM;
+				break;
+			case ENOENT:
+				ret = STMF_ERROR_NOT_FOUND;
+				break;
+			default:
+				syslog(LOG_DEBUG,
+				    "deleteDiskLu:ioctl error(%d) (%d) (%d)",
+				    ioctlRet, sbdIoctl.stmf_error, savedErrno);
+				ret = STMF_STATUS_ERROR;
+				break;
+		}
+	}
+
+done:
+	(void) close(fd);
+	return (ret);
+}
+
+/*
+ * stmfModifyLu
+ *
+ * Purpose: Modify properties of a logical unit
+ *
+ * luGuid - guid of registered logical unit
+ * prop - property to modify
+ * propVal - property value to set
+ *
+ */
+int
+stmfModifyLu(stmfGuid *luGuid, uint32_t prop, const char *propVal)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	stmfLogicalUnitProperties luProps;
+
+	if (luGuid == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	/* Check logical unit provider name to call correct dtype function */
+	if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
+	    != STMF_STATUS_SUCCESS) {
+		return (ret);
+	} else {
+		if (strcmp(luProps.providerName, "sbd") == 0) {
+			ret = modifyDiskLuProp(luGuid, NULL, prop, propVal);
+		} else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
+			return (STMF_ERROR_NOT_FOUND);
+		} else {
+			return (STMF_ERROR_INVALID_ARG);
+		}
+	}
+
+	return (ret);
+}
+
+/*
+ * stmfModifyLuByFname
+ *
+ * Purpose: Modify a device by filename. Device does not need to be registered.
+ *
+ * dType - type of device to modify
+ *         STMF_DISK
+ *
+ * fname - filename or meta filename
+ * prop - valid property identifier
+ * propVal - property value
+ *
+ */
+int
+stmfModifyLuByFname(uint16_t dType, const char *fname, uint32_t prop,
+    const char *propVal)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	if (fname == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	if (dType == STMF_DISK) {
+		ret = modifyDiskLuProp(NULL, fname, prop, propVal);
+	} else {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	return (ret);
+}
+
+static int
+modifyDiskLuProp(stmfGuid *luGuid, const char *fname, uint32_t prop,
+    const char *propVal)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	luResource hdl = NULL;
+	luResourceImpl *luPropsHdl;
+
+	ret = stmfCreateLuResource(STMF_DISK, &hdl);
+	if (ret != STMF_STATUS_SUCCESS) {
+		return (ret);
+	}
+	ret = validateModifyDiskProp(prop);
+	if (ret != STMF_STATUS_SUCCESS) {
+		(void) stmfFreeLuResource(hdl);
+		return (STMF_ERROR_INVALID_PROP);
+	}
+	ret = stmfSetLuProp(hdl, prop, propVal);
+	if (ret != STMF_STATUS_SUCCESS) {
+		(void) stmfFreeLuResource(hdl);
+		return (ret);
+	}
+	luPropsHdl = hdl;
+	ret = modifyDiskLu((diskResource *)luPropsHdl->resource, luGuid, fname);
+	(void) stmfFreeLuResource(hdl);
+	return (ret);
+}
+
+static int
+validateModifyDiskProp(uint32_t prop)
+{
+	switch (prop) {
+		case STMF_LU_PROP_ALIAS:
+		case STMF_LU_PROP_SIZE:
+		case STMF_LU_PROP_WRITE_PROTECT:
+		case STMF_LU_PROP_WRITE_CACHE_DISABLE:
+			return (STMF_STATUS_SUCCESS);
+			break;
+		default:
+			return (STMF_STATUS_ERROR);
+			break;
+	}
+}
+
+static int
+modifyDiskLu(diskResource *disk, stmfGuid *luGuid, const char *fname)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	int luAliasLen = 0;
+	int mluBufSize = 0;
+	int bufOffset = 0;
+	int fd = 0;
+	int ioctlRet;
+	int savedErrno;
+	int fnameSize = 0;
+	stmf_iocdata_t sbdIoctl = {0};
+
+	sbd_modify_lu_t *sbdLu = NULL;
+
+	if (luGuid == NULL && fname == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	if (fname) {
+		fnameSize = strlen(fname) + 1;
+		mluBufSize += fnameSize;
+	}
+
+	/*
+	 * Open control node for sbd
+	 */
+	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+		return (ret);
+
+	if (disk->luAliasValid) {
+		luAliasLen = strlen(disk->luAlias);
+		mluBufSize += luAliasLen + 1;
+	}
+
+	/*
+	 * 8 is the size of the buffer set aside for
+	 * concatenation of variable length fields
+	 */
+	sbdLu = (sbd_modify_lu_t *)calloc(1,
+	    sizeof (sbd_modify_lu_t) + mluBufSize - 8 + fnameSize);
+	if (sbdLu == NULL) {
+		(void) close(fd);
+		return (STMF_ERROR_NOMEM);
+	}
+
+	sbdLu->mlu_struct_size = sizeof (sbd_modify_lu_t) +
+	    mluBufSize - 8 + fnameSize;
+
+	if (disk->luAliasValid) {
+		sbdLu->mlu_alias_valid = 1;
+		sbdLu->mlu_alias_off = bufOffset;
+		bcopy(disk->luAlias, &(sbdLu->mlu_buf[bufOffset]),
+		    luAliasLen + 1);
+		bufOffset += luAliasLen + 1;
+	}
+
+	if (disk->luSizeValid) {
+		sbdLu->mlu_lu_size_valid = 1;
+		sbdLu->mlu_lu_size = disk->luSize;
+	}
+
+	if (disk->writeProtectEnableValid) {
+		sbdLu->mlu_write_protected_valid = 1;
+		if (disk->writeProtectEnable) {
+			sbdLu->mlu_write_protected = 1;
+		}
+	}
+
+	if (disk->writebackCacheDisableValid) {
+		sbdLu->mlu_writeback_cache_disable_valid = 1;
+		if (disk->writebackCacheDisable) {
+			sbdLu->mlu_writeback_cache_disable = 1;
+		}
+	}
+
+	if (luGuid) {
+		bcopy(luGuid, sbdLu->mlu_input_guid, sizeof (stmfGuid));
+		sbdLu->mlu_by_guid = 1;
+	} else {
+		sbdLu->mlu_fname_off = bufOffset;
+		bcopy(fname, &(sbdLu->mlu_buf[bufOffset]), fnameSize + 1);
+		sbdLu->mlu_by_fname = 1;
+	}
+
+	sbdIoctl.stmf_version = STMF_VERSION_1;
+	sbdIoctl.stmf_ibuf_size = sbdLu->mlu_struct_size;
+	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdLu;
+
+	ioctlRet = ioctl(fd, SBD_IOCTL_MODIFY_LU, &sbdIoctl);
+	if (ioctlRet != 0) {
+		savedErrno = errno;
+		switch (savedErrno) {
+			case EBUSY:
+				ret = STMF_ERROR_BUSY;
+				break;
+			case EPERM:
+			case EACCES:
+				ret = STMF_ERROR_PERM;
+				break;
+			default:
+				diskError(sbdIoctl.stmf_error, &ret);
+				if (ret == STMF_STATUS_ERROR) {
+					syslog(LOG_DEBUG,
+					"modifyDiskLu:ioctl "
+					"error(%d) (%d) (%d)", ioctlRet,
+					    sbdIoctl.stmf_error, savedErrno);
+				}
+				break;
+		}
+	}
+
+	if (ret != STMF_STATUS_SUCCESS) {
+		goto done;
+	}
+
+done:
+	free(sbdLu);
+	(void) close(fd);
+	return (ret);
+}
+
+/*
+ * removeGuidFromDiskStore
+ *
+ * Purpose: delete a logical unit from the sbd provider data
+ */
+static int
+removeGuidFromDiskStore(stmfGuid *guid)
+{
+	return (persistDiskGuid(guid, NULL, B_FALSE));
+}
+
+
+/*
+ * addGuidToDiskStore
+ *
+ * Purpose: add a logical unit to the sbd provider data
+ */
+static int
+addGuidToDiskStore(stmfGuid *guid, char *filename)
+{
+	return (persistDiskGuid(guid, filename, B_TRUE));
+}
+
+
+/*
+ * persistDiskGuid
+ *
+ * Purpose: Persist or unpersist a guid for the sbd provider data
+ *
+ */
+static int
+persistDiskGuid(stmfGuid *guid, char *filename, boolean_t persist)
+{
+	char	    guidAsciiBuf[LU_ASCII_GUID_SIZE + 1] = {0};
+	nvlist_t    *nvl = NULL;
+
+	uint64_t    setToken;
+	boolean_t   retryGetProviderData = B_FALSE;
+	boolean_t   newData = B_FALSE;
+	int	    ret = STMF_STATUS_SUCCESS;
+	int	    retryCnt = 0;
+	int	    stmfRet;
+
+	/* if we're persisting a guid, there must be a filename */
+	if (persist && !filename) {
+		return (1);
+	}
+
+	/* guid is stored in lowercase ascii hex */
+	(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
+	    "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+	    "%02x%02x%02x%02x%02x%02x",
+	    guid->guid[0], guid->guid[1], guid->guid[2], guid->guid[3],
+	    guid->guid[4], guid->guid[5], guid->guid[6], guid->guid[7],
+	    guid->guid[8], guid->guid[9], guid->guid[10], guid->guid[11],
+	    guid->guid[12], guid->guid[13], guid->guid[14], guid->guid[15]);
+
+
+	do {
+		retryGetProviderData = B_FALSE;
+		stmfRet = stmfGetProviderDataProt("sbd", &nvl,
+		    STMF_LU_PROVIDER_TYPE, &setToken);
+		if (stmfRet != STMF_STATUS_SUCCESS) {
+			if (persist && stmfRet == STMF_ERROR_NOT_FOUND) {
+				ret = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
+				if (ret != 0) {
+					syslog(LOG_DEBUG,
+					    "unpersistGuid:nvlist_alloc(%d)",
+					    ret);
+					ret = STMF_STATUS_ERROR;
+					goto done;
+				}
+				newData = B_TRUE;
+			} else {
+				ret = stmfRet;
+				goto done;
+			}
+		}
+		if (persist) {
+			ret = nvlist_add_string(nvl, guidAsciiBuf, filename);
+		} else {
+			ret = nvlist_remove(nvl, guidAsciiBuf,
+			    DATA_TYPE_STRING);
+			if (ret == ENOENT) {
+				ret = 0;
+			}
+		}
+		if (ret == 0) {
+			if (newData) {
+				stmfRet = stmfSetProviderDataProt("sbd", nvl,
+				    STMF_LU_PROVIDER_TYPE, NULL);
+			} else {
+				stmfRet = stmfSetProviderDataProt("sbd", nvl,
+				    STMF_LU_PROVIDER_TYPE, &setToken);
+			}
+			if (stmfRet != STMF_STATUS_SUCCESS) {
+				if (stmfRet == STMF_ERROR_BUSY) {
+					/* get/set failed, try again */
+					retryGetProviderData = B_TRUE;
+					if (retryCnt++ > MAX_PROVIDER_RETRY) {
+						ret = stmfRet;
+						break;
+					}
+					continue;
+				} else if (stmfRet ==
+				    STMF_ERROR_PROV_DATA_STALE) {
+					/* update failed, try again */
+					nvlist_free(nvl);
+					nvl = NULL;
+					retryGetProviderData = B_TRUE;
+					if (retryCnt++ > MAX_PROVIDER_RETRY) {
+						ret = stmfRet;
+						break;
+					}
+					continue;
+				} else {
+					syslog(LOG_DEBUG,
+					    "unpersistGuid:error(%x)", stmfRet);
+					ret = stmfRet;
+				}
+				break;
+			}
+		} else {
+			syslog(LOG_DEBUG,
+			    "unpersistGuid:error nvlist_add/remove(%d)",
+			    ret);
+			ret = STMF_STATUS_ERROR;
+		}
+	} while (retryGetProviderData);
+
+done:
+	nvlist_free(nvl);
+	return (ret);
+}
+
+
+/*
+ * stmfGetLuProp
+ *
+ * Purpose: Get current value for a resource property
+ *
+ * hdl - luResource from a previous call to stmfCreateLuResource
+ *
+ * resourceProp - a valid resource property type
+ *
+ * propVal - void pointer to a pointer of the value to be retrieved
+ */
+int
+stmfGetLuProp(luResource hdl, uint32_t prop, char *propVal, size_t *propLen)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	luResourceImpl *luPropsHdl = hdl;
+	if (hdl == NULL || propLen == NULL || propVal == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	if (luPropsHdl->type == STMF_DISK) {
+		ret = getDiskProp(luPropsHdl, prop, propVal, propLen);
+	} else {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	return (ret);
+}
+
+/*
+ * stmfGetLuResource
+ *
+ * Purpose: Get a logical unit resource handle for a given logical unit.
+ *
+ * hdl - pointer to luResource
+ */
+int
+stmfGetLuResource(stmfGuid *luGuid, luResource *hdl)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	stmfLogicalUnitProperties luProps;
+
+
+	/* Check logical unit provider name to call correct dtype function */
+	if ((ret = stmfGetLogicalUnitProperties(luGuid, &luProps))
+	    != STMF_STATUS_SUCCESS) {
+		return (ret);
+	} else {
+		if (strcmp(luProps.providerName, "sbd") == 0) {
+			ret = getDiskAllProps(luGuid, hdl);
+		} else if (luProps.status == STMF_LOGICAL_UNIT_UNREGISTERED) {
+			return (STMF_ERROR_NOT_FOUND);
+		} else {
+			return (STMF_ERROR_INVALID_ARG);
+		}
+	}
+
+	return (ret);
+}
+
+/*
+ * getDiskAllProps
+ *
+ * Purpose: load all disk properties from sbd driver
+ *
+ * luGuid - guid of disk device for which properties are to be retrieved
+ * hdl - allocated luResource into which properties are to be copied
+ *
+ */
+static int
+getDiskAllProps(stmfGuid *luGuid, luResource *hdl)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	int fd;
+	sbd_lu_props_t *sbdProps;
+	int ioctlRet;
+	int savedErrno;
+	int sbdPropsSize = sizeof (*sbdProps) + MAX_SBD_PROPS;
+	stmf_iocdata_t sbdIoctl = {0};
+
+	/*
+	 * Open control node for sbd
+	 */
+	if ((ret = openSbd(OPEN_SBD, &fd)) != STMF_STATUS_SUCCESS)
+		return (ret);
+
+
+	*hdl = calloc(1, sizeof (luResourceImpl));
+	if (*hdl == NULL) {
+		(void) close(fd);
+		return (STMF_ERROR_NOMEM);
+	}
+
+	sbdProps = calloc(1, sbdPropsSize);
+	if (sbdProps == NULL) {
+		free(*hdl);
+		(void) close(fd);
+		return (STMF_ERROR_NOMEM);
+	}
+
+	ret = createDiskResource((luResourceImpl *)*hdl);
+	if (ret != STMF_STATUS_SUCCESS) {
+		free(*hdl);
+		(void) close(fd);
+		return (ret);
+	}
+
+	sbdProps->slp_input_guid = 1;
+	bcopy(luGuid, sbdProps->slp_guid, sizeof (sbdProps->slp_guid));
+
+	sbdIoctl.stmf_version = STMF_VERSION_1;
+	sbdIoctl.stmf_ibuf_size = sbdPropsSize;
+	sbdIoctl.stmf_ibuf = (uint64_t)(unsigned long)sbdProps;
+	sbdIoctl.stmf_obuf_size = sbdPropsSize;
+	sbdIoctl.stmf_obuf = (uint64_t)(unsigned long)sbdProps;
+	ioctlRet = ioctl(fd, SBD_IOCTL_GET_LU_PROPS, &sbdIoctl);
+	if (ioctlRet != 0) {
+		savedErrno = errno;
+		switch (savedErrno) {
+			case EBUSY:
+				ret = STMF_ERROR_BUSY;
+				break;
+			case EPERM:
+			case EACCES:
+				ret = STMF_ERROR_PERM;
+				break;
+			case ENOENT:
+				ret = STMF_ERROR_NOT_FOUND;
+				break;
+			default:
+				syslog(LOG_DEBUG,
+				    "getDiskAllProps:ioctl error(%d) (%d) (%d)",
+				    ioctlRet, sbdIoctl.stmf_error, savedErrno);
+				ret = STMF_STATUS_ERROR;
+				break;
+		}
+	}
+
+	if (ret == STMF_STATUS_SUCCESS) {
+		ret = loadDiskPropsFromDriver((luResourceImpl *)*hdl, sbdProps);
+	}
+
+	(void) close(fd);
+	return (ret);
+}
+
+/*
+ * loadDiskPropsFromDriver
+ *
+ * Purpose: Retrieve all disk type properties from sbd driver
+ *
+ * hdl - Allocated luResourceImpl
+ * sbdProps - sbd_lu_props_t structure returned from sbd driver
+ *
+ */
+static int
+loadDiskPropsFromDriver(luResourceImpl *hdl, sbd_lu_props_t *sbdProps)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	diskResource *diskLu = hdl->resource;
+	/* copy guid */
+	diskLu->luGuidValid = B_TRUE;
+	bcopy(sbdProps->slp_guid, diskLu->luGuid, sizeof (sbdProps->slp_guid));
+
+	if (sbdProps->slp_separate_meta && sbdProps->slp_meta_fname_valid) {
+		diskLu->luMetaFileNameValid = B_TRUE;
+		if (strlcpy(diskLu->luMetaFileName,
+		    (char *)&(sbdProps->slp_buf[sbdProps->slp_meta_fname_off]),
+		    sizeof (diskLu->luMetaFileName)) >=
+		    sizeof (diskLu->luMetaFileName)) {
+			return (STMF_STATUS_ERROR);
+		}
+	}
+
+	if (sbdProps->slp_data_fname_valid) {
+		diskLu->luDataFileNameValid = B_TRUE;
+		if (strlcpy(diskLu->luDataFileName,
+		    (char *)&(sbdProps->slp_buf[sbdProps->slp_data_fname_off]),
+		    sizeof (diskLu->luDataFileName)) >=
+		    sizeof (diskLu->luDataFileName)) {
+			return (STMF_STATUS_ERROR);
+		}
+	}
+
+	if (sbdProps->slp_serial_valid) {
+		diskLu->serialNumValid = B_TRUE;
+		bcopy(&(sbdProps->slp_buf[sbdProps->slp_serial_off]),
+		    diskLu->serialNum, sbdProps->slp_serial_size);
+	}
+
+	if (sbdProps->slp_alias_valid) {
+		diskLu->luAliasValid = B_TRUE;
+		if (strlcpy(diskLu->luAlias,
+		    (char *)&(sbdProps->slp_buf[sbdProps->slp_alias_off]),
+		    sizeof (diskLu->luAlias)) >=
+		    sizeof (diskLu->luAlias)) {
+			return (STMF_STATUS_ERROR);
+		}
+	} else { /* set alias to data filename if not set */
+		if (sbdProps->slp_data_fname_valid) {
+			diskLu->luAliasValid = B_TRUE;
+			if (strlcpy(diskLu->luAlias,
+			    (char *)&(sbdProps->slp_buf[
+			    sbdProps->slp_data_fname_off]),
+			    sizeof (diskLu->luAlias)) >=
+			    sizeof (diskLu->luAlias)) {
+				return (STMF_STATUS_ERROR);
+			}
+		}
+	}
+
+	diskLu->vidValid = B_TRUE;
+	bcopy(sbdProps->slp_vid, diskLu->vid, sizeof (diskLu->vid));
+
+	diskLu->pidValid = B_TRUE;
+	bcopy(sbdProps->slp_pid, diskLu->pid, sizeof (diskLu->pid));
+
+	diskLu->revValid = B_TRUE;
+	bcopy(sbdProps->slp_rev, diskLu->rev, sizeof (diskLu->rev));
+
+	diskLu->writeProtectEnableValid = B_TRUE;
+	if (sbdProps->slp_write_protected) {
+		diskLu->writeProtectEnable = B_TRUE;
+	}
+
+	diskLu->writebackCacheDisableValid = B_TRUE;
+	if (sbdProps->slp_writeback_cache_disable_cur) {
+		diskLu->writebackCacheDisable = B_TRUE;
+	}
+
+	diskLu->blkSizeValid = B_TRUE;
+	diskLu->blkSize = sbdProps->slp_blksize;
+
+	diskLu->luSizeValid = B_TRUE;
+	diskLu->luSize = sbdProps->slp_lu_size;
+
+	return (ret);
+}
+
+
+/*
+ * stmfSetLuProp
+ *
+ * Purpose: set a property on an luResource
+ *
+ * hdl - allocated luResource
+ * prop - property identifier
+ * propVal - property value to be set
+ */
+int
+stmfSetLuProp(luResource hdl, uint32_t prop, const char *propVal)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	luResourceImpl *luPropsHdl = hdl;
+	if (hdl == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	if (luPropsHdl->type == STMF_DISK) {
+		ret = setDiskProp(luPropsHdl, prop, propVal);
+	} else {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	return (ret);
+}
+
+/*
+ * getDiskProp
+ *
+ * Purpose: retrieve a given property from a logical unit resource of type disk
+ *
+ * hdl - allocated luResourceImpl
+ * prop - property identifier
+ * propVal - pointer to character to contain the retrieved property value
+ * propLen - On input this is the length of propVal. On failure, it contains the
+ *           number of bytes required for propVal
+ */
+static int
+getDiskProp(luResourceImpl *hdl, uint32_t prop, char *propVal, size_t *propLen)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	diskResource *diskLu = hdl->resource;
+	size_t reqLen;
+
+	switch (prop) {
+		case STMF_LU_PROP_BLOCK_SIZE:
+			if (diskLu->blkSizeValid == B_FALSE) {
+				return (STMF_ERROR_NO_PROP);
+			}
+			reqLen = snprintf(propVal, *propLen, "%llu",
+			    (u_longlong_t)diskLu->blkSize);
+			if (reqLen >= *propLen) {
+				*propLen = reqLen + 1;
+				return (STMF_ERROR_INVALID_ARG);
+			}
+			break;
+		case STMF_LU_PROP_FILENAME:
+			if (diskLu->luDataFileNameValid == B_FALSE) {
+				return (STMF_ERROR_NO_PROP);
+			}
+			if ((reqLen = strlcpy(propVal, diskLu->luDataFileName,
+			    *propLen)) >= *propLen) {
+				*propLen = reqLen + 1;
+				return (STMF_ERROR_INVALID_ARG);
+			}
+			break;
+		case STMF_LU_PROP_META_FILENAME:
+			if (diskLu->luMetaFileNameValid == B_FALSE) {
+				return (STMF_ERROR_NO_PROP);
+			}
+			if ((reqLen = strlcpy(propVal, diskLu->luMetaFileName,
+			    *propLen)) >= *propLen) {
+				*propLen = reqLen + 1;
+				return (STMF_ERROR_INVALID_ARG);
+			}
+			break;
+		case STMF_LU_PROP_GUID:
+			if (diskLu->luGuidValid == B_FALSE) {
+				return (STMF_ERROR_NO_PROP);
+			}
+			reqLen = snprintf(propVal, *propLen,
+			    "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X"
+			    "%02X%02X%02X%02X",
+			    diskLu->luGuid[0], diskLu->luGuid[1],
+			    diskLu->luGuid[2], diskLu->luGuid[3],
+			    diskLu->luGuid[4], diskLu->luGuid[5],
+			    diskLu->luGuid[6], diskLu->luGuid[7],
+			    diskLu->luGuid[8], diskLu->luGuid[9],
+			    diskLu->luGuid[10], diskLu->luGuid[11],
+			    diskLu->luGuid[12], diskLu->luGuid[13],
+			    diskLu->luGuid[14], diskLu->luGuid[15]);
+			if (reqLen >= *propLen) {
+				*propLen = reqLen + 1;
+				return (STMF_ERROR_INVALID_ARG);
+			}
+			break;
+		case STMF_LU_PROP_SERIAL_NUM:
+			if (diskLu->serialNumValid == B_FALSE) {
+				return (STMF_ERROR_NO_PROP);
+			}
+			if ((reqLen = strlcpy(propVal, diskLu->serialNum,
+			    *propLen)) >= *propLen) {
+				*propLen = reqLen + 1;
+				return (STMF_ERROR_INVALID_ARG);
+			}
+			break;
+		case STMF_LU_PROP_SIZE:
+			if (diskLu->luSizeValid == B_FALSE) {
+				return (STMF_ERROR_NO_PROP);
+			}
+			(void) snprintf(propVal, *propLen, "%llu",
+			    (u_longlong_t)diskLu->luSize);
+			break;
+		case STMF_LU_PROP_ALIAS:
+			if (diskLu->luAliasValid == B_FALSE) {
+				return (STMF_ERROR_NO_PROP);
+			}
+			if ((reqLen = strlcpy(propVal, diskLu->luAlias,
+			    *propLen)) >= *propLen) {
+				*propLen = reqLen + 1;
+				return (STMF_ERROR_INVALID_ARG);
+			}
+			break;
+		case STMF_LU_PROP_VID:
+			if (diskLu->vidValid == B_FALSE) {
+				return (STMF_ERROR_NO_PROP);
+			}
+			if (*propLen <= sizeof (diskLu->vid)) {
+				return (STMF_ERROR_INVALID_ARG);
+			}
+			bcopy(diskLu->vid, propVal, sizeof (diskLu->vid));
+			propVal[sizeof (diskLu->vid)] = 0;
+			break;
+		case STMF_LU_PROP_PID:
+			if (diskLu->pidValid == B_FALSE) {
+				return (STMF_ERROR_NO_PROP);
+			}
+			if (*propLen <= sizeof (diskLu->pid)) {
+				return (STMF_ERROR_INVALID_ARG);
+			}
+			bcopy(diskLu->pid, propVal, sizeof (diskLu->pid));
+			propVal[sizeof (diskLu->pid)] = 0;
+			break;
+		case STMF_LU_PROP_WRITE_PROTECT:
+			if (diskLu->writeProtectEnableValid == B_FALSE) {
+				return (STMF_ERROR_NO_PROP);
+			}
+			if (diskLu->writeProtectEnable) {
+				if ((reqLen = strlcpy(propVal, "true",
+				    *propLen)) >= *propLen) {
+					*propLen = reqLen + 1;
+					return (STMF_ERROR_INVALID_ARG);
+				}
+			} else {
+				if ((reqLen = strlcpy(propVal, "false",
+				    *propLen)) >= *propLen) {
+					*propLen = reqLen + 1;
+					return (STMF_ERROR_INVALID_ARG);
+				}
+			}
+			break;
+		case STMF_LU_PROP_WRITE_CACHE_DISABLE:
+			if (diskLu->writebackCacheDisableValid == B_FALSE) {
+				return (STMF_ERROR_NO_PROP);
+			}
+			if (diskLu->writebackCacheDisable) {
+				if ((reqLen = strlcpy(propVal, "true",
+				    *propLen)) >= *propLen) {
+					*propLen = reqLen + 1;
+					return (STMF_ERROR_INVALID_ARG);
+				}
+			} else {
+				if ((reqLen = strlcpy(propVal, "false",
+				    *propLen)) >= *propLen) {
+					*propLen = reqLen + 1;
+					return (STMF_ERROR_INVALID_ARG);
+				}
+			}
+			break;
+		default:
+			ret = STMF_ERROR_NO_PROP;
+			break;
+	}
+
+	return (ret);
+}
+
+/*
+ * setDiskProp
+ *
+ * Purpose: set properties for resource of type disk
+ *
+ * hdl - allocated luResourceImpl
+ * resourceProp - valid resource identifier
+ * propVal - valid resource value
+ */
+static int
+setDiskProp(luResourceImpl *hdl, uint32_t resourceProp, const char *propVal)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	int i;
+	diskResource *diskLu = hdl->resource;
+	unsigned long long numericProp = 0;
+	char guidProp[LU_ASCII_GUID_SIZE + 1];
+	char ouiProp[OUI_ASCII_SIZE + 1];
+	unsigned int oui[OUI_SIZE];
+	unsigned int guid[LU_GUID_SIZE];
+	int propSize;
+
+
+	if (propVal == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	switch (resourceProp) {
+		case STMF_LU_PROP_ALIAS:
+			if (strlcpy(diskLu->luAlias, propVal,
+			    sizeof (diskLu->luAlias)) >=
+			    sizeof (diskLu->luAlias)) {
+				return (STMF_ERROR_INVALID_PROPSIZE);
+			}
+			diskLu->luAliasValid = B_TRUE;
+			break;
+		case STMF_LU_PROP_BLOCK_SIZE:
+			(void) sscanf(propVal, "%llu", &numericProp);
+			if (numericProp > UINT16_MAX) {
+				return (STMF_ERROR_INVALID_PROPSIZE);
+			}
+			diskLu->blkSize = numericProp;
+			diskLu->blkSizeValid = B_TRUE;
+			break;
+		case STMF_LU_PROP_COMPANY_ID:
+			if ((strlcpy(ouiProp, propVal, sizeof (ouiProp))) >=
+			    sizeof (ouiProp)) {
+				return (STMF_ERROR_INVALID_ARG);
+			}
+			if (checkHexUpper(ouiProp) != 0) {
+				return (STMF_ERROR_INVALID_ARG);
+			}
+			(void) sscanf(ouiProp, "%2X%2X%2X",
+			    &oui[0], &oui[1], &oui[2]);
+
+			diskLu->companyId = 0;
+			diskLu->companyId += oui[0] << 16;
+			diskLu->companyId += oui[1] << 8;
+			diskLu->companyId += oui[2];
+			diskLu->companyIdValid = B_TRUE;
+			break;
+		case STMF_LU_PROP_GUID:
+			if (strlen(propVal) != LU_ASCII_GUID_SIZE) {
+				return (STMF_ERROR_INVALID_PROPSIZE);
+			}
+
+			if ((strlcpy(guidProp, propVal, sizeof (guidProp))) >=
+			    sizeof (guidProp)) {
+				return (STMF_ERROR_INVALID_ARG);
+			}
+
+			if (checkHexUpper(guidProp) != 0) {
+				return (STMF_ERROR_INVALID_ARG);
+			}
+
+			(void) sscanf(guidProp,
+			    "%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X%2X",
+			    &guid[0], &guid[1], &guid[2], &guid[3], &guid[4],
+			    &guid[5], &guid[6], &guid[7], &guid[8], &guid[9],
+			    &guid[10], &guid[11], &guid[12], &guid[13],
+			    &guid[14], &guid[15]);
+			for (i = 0; i < sizeof (diskLu->luGuid); i++) {
+				diskLu->luGuid[i] = guid[i];
+			}
+			diskLu->luGuidValid = B_TRUE;
+			break;
+		case STMF_LU_PROP_FILENAME:
+			if ((strlcpy(diskLu->luDataFileName, propVal,
+			    sizeof (diskLu->luDataFileName))) >=
+			    sizeof (diskLu->luDataFileName)) {
+				return (STMF_ERROR_INVALID_PROPSIZE);
+			}
+			diskLu->luDataFileNameValid = B_TRUE;
+			break;
+		case STMF_LU_PROP_META_FILENAME:
+			if ((strlcpy(diskLu->luMetaFileName, propVal,
+			    sizeof (diskLu->luMetaFileName))) >=
+			    sizeof (diskLu->luMetaFileName)) {
+				return (STMF_ERROR_INVALID_PROPSIZE);
+			}
+			diskLu->luMetaFileNameValid = B_TRUE;
+			break;
+		case STMF_LU_PROP_PID:
+			if ((propSize = strlen(propVal)) >
+			    sizeof (diskLu->pid)) {
+				return (STMF_ERROR_INVALID_PROPSIZE);
+			}
+			(void) strncpy(diskLu->pid, propVal, propSize);
+			diskLu->pidValid = B_TRUE;
+			break;
+		case STMF_LU_PROP_SERIAL_NUM:
+			if ((propSize = strlen(propVal)) >
+			    (sizeof (diskLu->serialNum) - 1)) {
+				return (STMF_ERROR_INVALID_PROPSIZE);
+			}
+			(void) strncpy(diskLu->serialNum, propVal, propSize);
+			diskLu->serialNumValid = B_TRUE;
+			break;
+		case STMF_LU_PROP_SIZE:
+			if ((niceStrToNum(propVal, &diskLu->luSize) != 0)) {
+				return (STMF_ERROR_INVALID_ARG);
+			}
+			diskLu->luSizeValid = B_TRUE;
+			break;
+		case STMF_LU_PROP_VID:
+			if ((propSize = strlen(propVal)) >
+			    sizeof (diskLu->vid)) {
+				return (STMF_ERROR_INVALID_PROPSIZE);
+			}
+			(void) strncpy(diskLu->vid, propVal, propSize);
+			diskLu->vidValid = B_TRUE;
+			break;
+		case STMF_LU_PROP_WRITE_PROTECT:
+			if (strcasecmp(propVal, "TRUE") == 0) {
+				diskLu->writeProtectEnable = B_TRUE;
+			} else if (strcasecmp(propVal, "FALSE") == 0) {
+				diskLu->writeProtectEnable = B_FALSE;
+			} else {
+				return (STMF_ERROR_INVALID_ARG);
+			}
+			diskLu->writeProtectEnableValid = B_TRUE;
+			break;
+		case STMF_LU_PROP_WRITE_CACHE_DISABLE:
+			if (strcasecmp(propVal, "TRUE") == 0) {
+				diskLu->writebackCacheDisable = B_TRUE;
+			} else if (strcasecmp(propVal, "FALSE") == 0) {
+				diskLu->writebackCacheDisable = B_FALSE;
+			} else {
+				return (STMF_ERROR_INVALID_ARG);
+			}
+			diskLu->writebackCacheDisableValid = B_TRUE;
+			break;
+		default:
+			ret = STMF_ERROR_NO_PROP;
+			break;
+	}
+	return (ret);
+}
+
+static int
+checkHexUpper(char *buf)
+{
+	int i;
+
+	for (i = 0; i < strlen(buf); i++) {
+		if (isxdigit(buf[i])) {
+			buf[i] = toupper(buf[i]);
+			continue;
+		}
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * Given a numeric suffix, convert the value into a number of bits that the
+ * resulting value must be shifted.
+ * Code lifted from libzfs_util.c
+ */
+static int
+strToShift(const char *buf)
+{
+	const char *ends = "BKMGTPE";
+	int i;
+
+	if (buf[0] == '\0')
+		return (0);
+
+	for (i = 0; i < strlen(ends); i++) {
+		if (toupper(buf[0]) == ends[i])
+			return (10*i);
+	}
+
+	return (-1);
+}
+
+int
+stmfFreeLuResource(luResource hdl)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	if (hdl == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	luResourceImpl *hdlImpl = hdl;
+	free(hdlImpl->resource);
+	free(hdlImpl);
+	return (ret);
+}
+
+/*
+ * Convert a string of the form '100G' into a real number. Used when setting
+ * the size of a logical unit.
+ * Code lifted from libzfs_util.c
+ */
+static int
+niceStrToNum(const char *value, uint64_t *num)
+{
+	char *end;
+	int shift;
+
+	*num = 0;
+
+	/* Check to see if this looks like a number.  */
+	if ((value[0] < '0' || value[0] > '9') && value[0] != '.') {
+		return (-1);
+	}
+
+	/* Rely on stroull() to process the numeric portion.  */
+	errno = 0;
+	*num = strtoull(value, &end, 10);
+
+	/*
+	 * Check for ERANGE, which indicates that the value is too large to fit
+	 * in a 64-bit value.
+	 */
+	if (errno == ERANGE) {
+		return (-1);
+	}
+
+	/*
+	 * If we have a decimal value, then do the computation with floating
+	 * point arithmetic.  Otherwise, use standard arithmetic.
+	 */
+	if (*end == '.') {
+		double fval = strtod(value, &end);
+
+		if ((shift = strToShift(end)) == -1) {
+			return (-1);
+		}
+
+		fval *= pow(2, shift);
+
+		if (fval > UINT64_MAX) {
+			return (-1);
+		}
+
+		*num = (uint64_t)fval;
+	} else {
+		if ((shift = strToShift(end)) == -1) {
+			return (-1);
+		}
+
+		/* Check for overflow */
+		if (shift >= 64 || (*num << shift) >> shift != *num) {
+			return (-1);
+		}
+
+		*num <<= shift;
+	}
+
+	return (0);
+}
+
+/*
  * stmfCreateTargetGroup
  *
  * Purpose: Create a local port group
@@ -920,6 +2683,10 @@
 		goto done;
 	}
 
+	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+		goto done;
+	}
+
 	/*
 	 * If the add to the driver was successful, add it to the persistent
 	 * store.
@@ -996,6 +2763,10 @@
 		goto done;
 	}
 
+	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+		goto done;
+	}
+
 	/*
 	 * If the remove from the driver was successful, remove it from the
 	 * persistent store.
@@ -1072,6 +2843,10 @@
 		goto done;
 	}
 
+	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+		goto done;
+	}
+
 	/*
 	 * If the remove from the driver was successful, remove it from the
 	 * persistent store.
@@ -1183,23 +2958,306 @@
 }
 
 /*
- * stmfGetHostGroupList
- *
- * Purpose: Retrieves the list of initiator group oids
+ * get host group, target group list from stmf
  *
- * hostGroupList - pointer to pointer to hostGroupList structure
- *                 on success, this contains the host group list.
+ * groupType - HOST_GROUP, TARGET_GROUP
  */
-int
-stmfGetHostGroupList(stmfGroupList **hostGroupList)
+static int
+groupListIoctl(stmfGroupList **groupList, int groupType)
+{
+	int ret;
+	int fd;
+	int ioctlRet;
+	int i;
+	int cmd;
+	stmf_iocdata_t stmfIoctl;
+	/* framework group list */
+	stmf_group_name_t *iGroupList = NULL;
+	uint32_t groupListSize;
+
+	if (groupList == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	if (groupType == HOST_GROUP) {
+		cmd = STMF_IOCTL_GET_HG_LIST;
+	} else if (groupType == TARGET_GROUP) {
+		cmd = STMF_IOCTL_GET_TG_LIST;
+	} else {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	/* call init */
+	ret = initializeConfig();
+	if (ret != STMF_STATUS_SUCCESS) {
+		return (ret);
+	}
+
+	/*
+	 * Open control node for stmf
+	 */
+	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+		return (ret);
+
+	/*
+	 * Allocate ioctl input buffer
+	 */
+	groupListSize = ALLOC_GROUP;
+	groupListSize = groupListSize * (sizeof (stmf_group_name_t));
+	iGroupList = (stmf_group_name_t *)calloc(1, groupListSize);
+	if (iGroupList == NULL) {
+		ret = STMF_ERROR_NOMEM;
+		goto done;
+	}
+
+	bzero(&stmfIoctl, sizeof (stmfIoctl));
+	/*
+	 * Issue ioctl to get the group list
+	 */
+	stmfIoctl.stmf_version = STMF_VERSION_1;
+	stmfIoctl.stmf_obuf_size = groupListSize;
+	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupList;
+	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+	if (ioctlRet != 0) {
+		switch (errno) {
+			case EBUSY:
+				ret = STMF_ERROR_BUSY;
+				break;
+			case EPERM:
+			case EACCES:
+				ret = STMF_ERROR_PERM;
+				break;
+			default:
+				syslog(LOG_DEBUG,
+				    "groupListIoctl:ioctl errno(%d)",
+				    errno);
+				ret = STMF_STATUS_ERROR;
+				break;
+		}
+		goto done;
+	}
+	/*
+	 * Check whether input buffer was large enough
+	 */
+	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_GROUP) {
+		groupListSize = stmfIoctl.stmf_obuf_max_nentries *
+		    sizeof (stmf_group_name_t);
+		iGroupList = realloc(iGroupList, groupListSize);
+		if (iGroupList == NULL) {
+			ret = STMF_ERROR_NOMEM;
+			goto done;
+		}
+		stmfIoctl.stmf_obuf_size = groupListSize;
+		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupList;
+		ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+		if (ioctlRet != 0) {
+			switch (errno) {
+				case EBUSY:
+					ret = STMF_ERROR_BUSY;
+					break;
+				case EPERM:
+				case EACCES:
+					ret = STMF_ERROR_PERM;
+					break;
+				default:
+					syslog(LOG_DEBUG,
+					    "groupListIoctl:ioctl errno(%d)",
+					    errno);
+					ret = STMF_STATUS_ERROR;
+					break;
+			}
+			goto done;
+		}
+	}
+
+	/* allocate and copy to caller's buffer */
+	*groupList = (stmfGroupList *)calloc(1, sizeof (stmfGroupList) *
+	    stmfIoctl.stmf_obuf_nentries);
+	if (*groupList == NULL) {
+		ret = STMF_ERROR_NOMEM;
+		goto done;
+	}
+	(*groupList)->cnt = stmfIoctl.stmf_obuf_nentries;
+	for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
+		bcopy(iGroupList->name, (*groupList)->name[i],
+		    sizeof (stmfGroupName));
+		iGroupList++;
+	}
+
+done:
+	free(iGroupList);
+	(void) close(fd);
+	return (ret);
+}
+
+/*
+ * get host group members, target group members from stmf
+ *
+ * groupProps - allocated on success
+ *
+ * groupType - HOST_GROUP, TARGET_GROUP
+ */
+static int
+groupMemberListIoctl(stmfGroupName *groupName, stmfGroupProperties **groupProps,
+    int groupType)
 {
 	int ret;
-
-	if (hostGroupList == NULL) {
+	int fd;
+	int ioctlRet;
+	int i;
+	int cmd;
+	stmf_iocdata_t stmfIoctl;
+	/* framework group list */
+	stmf_group_name_t iGroupName;
+	stmf_ge_ident_t *iGroupMembers;
+	uint32_t groupListSize;
+
+	if (groupName == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	if (groupType == HOST_GROUP) {
+		cmd = STMF_IOCTL_GET_HG_ENTRIES;
+	} else if (groupType == TARGET_GROUP) {
+		cmd = STMF_IOCTL_GET_TG_ENTRIES;
+	} else {
 		return (STMF_ERROR_INVALID_ARG);
 	}
 
-	ret = psGetHostGroupList(hostGroupList);
+	/* call init */
+	ret = initializeConfig();
+	if (ret != STMF_STATUS_SUCCESS) {
+		return (ret);
+	}
+
+	/*
+	 * Open control node for stmf
+	 */
+	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+		return (ret);
+
+	bzero(&iGroupName, sizeof (iGroupName));
+
+	bcopy(groupName, &iGroupName.name, strlen((char *)groupName));
+
+	iGroupName.name_size = strlen((char *)groupName);
+
+	/*
+	 * Allocate ioctl input buffer
+	 */
+	groupListSize = ALLOC_GRP_MEMBER;
+	groupListSize = groupListSize * (sizeof (stmf_ge_ident_t));
+	iGroupMembers = (stmf_ge_ident_t *)calloc(1, groupListSize);
+	if (iGroupMembers == NULL) {
+		ret = STMF_ERROR_NOMEM;
+		goto done;
+	}
+
+	bzero(&stmfIoctl, sizeof (stmfIoctl));
+	/*
+	 * Issue ioctl to get the group list
+	 */
+	stmfIoctl.stmf_version = STMF_VERSION_1;
+	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
+	stmfIoctl.stmf_ibuf_size = sizeof (stmf_group_name_t);
+	stmfIoctl.stmf_obuf_size = groupListSize;
+	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupMembers;
+	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+	if (ioctlRet != 0) {
+		switch (errno) {
+			case EBUSY:
+				ret = STMF_ERROR_BUSY;
+				break;
+			case EPERM:
+			case EACCES:
+				ret = STMF_ERROR_PERM;
+				break;
+			default:
+				syslog(LOG_DEBUG,
+				    "groupListIoctl:ioctl errno(%d)",
+				    errno);
+				ret = STMF_STATUS_ERROR;
+				break;
+		}
+		goto done;
+	}
+	/*
+	 * Check whether input buffer was large enough
+	 */
+	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_GRP_MEMBER) {
+		groupListSize = stmfIoctl.stmf_obuf_max_nentries *
+		    sizeof (stmf_ge_ident_t);
+		iGroupMembers = realloc(iGroupMembers, groupListSize);
+		if (iGroupMembers == NULL) {
+			ret = STMF_ERROR_NOMEM;
+			goto done;
+		}
+		stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&iGroupName;
+		stmfIoctl.stmf_ibuf_size = sizeof (stmf_group_name_t);
+		stmfIoctl.stmf_obuf_size = groupListSize;
+		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)iGroupMembers;
+		ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+		if (ioctlRet != 0) {
+			switch (errno) {
+				case EBUSY:
+					ret = STMF_ERROR_BUSY;
+					break;
+				case EPERM:
+				case EACCES:
+					ret = STMF_ERROR_PERM;
+					break;
+				default:
+					syslog(LOG_DEBUG,
+					    "groupListIoctl:ioctl errno(%d)",
+					    errno);
+					ret = STMF_STATUS_ERROR;
+					break;
+			}
+			goto done;
+		}
+	}
+
+	/* allocate and copy to caller's buffer */
+	*groupProps = (stmfGroupProperties *)calloc(1,
+	    sizeof (stmfGroupProperties) * stmfIoctl.stmf_obuf_nentries);
+	if (*groupProps == NULL) {
+		ret = STMF_ERROR_NOMEM;
+		goto done;
+	}
+	(*groupProps)->cnt = stmfIoctl.stmf_obuf_nentries;
+	for (i = 0; i < stmfIoctl.stmf_obuf_nentries; i++) {
+		(*groupProps)->name[i].identLength =
+		    iGroupMembers->ident_size;
+		bcopy(iGroupMembers->ident, (*groupProps)->name[i].ident,
+		    iGroupMembers->ident_size);
+		iGroupMembers++;
+	}
+
+done:
+	free(iGroupMembers);
+	(void) close(fd);
+	return (ret);
+}
+
+/*
+ * Purpose: access persistent config data for host groups and target groups
+ */
+static int
+iLoadGroupFromPs(stmfGroupList **groupList, int type)
+{
+	int ret;
+
+	if (groupList == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	if (type == HOST_GROUP) {
+		ret = psGetHostGroupList(groupList);
+	} else if (type == TARGET_GROUP) {
+		ret = psGetTargetGroupList(groupList);
+	} else {
+		return (STMF_ERROR_INVALID_ARG);
+	}
 	switch (ret) {
 		case STMF_PS_SUCCESS:
 			ret = STMF_STATUS_SUCCESS;
@@ -1228,25 +3286,47 @@
 }
 
 /*
- * stmfGetHostGroupMembers
- *
- * Purpose: Retrieves the group properties for a host group
+ * stmfGetHostGroupList
  *
- * groupName - name of group for which to retrieve host group members.
- * groupProp - pointer to pointer to stmfGroupProperties structure
- *             on success, this contains the list of group members.
+ * Purpose: Retrieves the list of initiator group oids
+ *
+ * hostGroupList - pointer to pointer to hostGroupList structure
+ *                 on success, this contains the host group list.
  */
 int
-stmfGetHostGroupMembers(stmfGroupName *groupName,
-    stmfGroupProperties **groupProp)
+stmfGetHostGroupList(stmfGroupList **hostGroupList)
+{
+	int ret = STMF_STATUS_ERROR;
+
+	if (hostGroupList == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	ret = groupListIoctl(hostGroupList, HOST_GROUP);
+	return (ret);
+}
+
+
+/*
+ * Purpose: access persistent config data for host groups and target groups
+ */
+static int
+iLoadGroupMembersFromPs(stmfGroupName *groupName,
+    stmfGroupProperties **groupProp, int type)
 {
 	int ret;
 
-	if (groupName == NULL || groupProp == NULL) {
+	if (groupName == NULL) {
 		return (STMF_ERROR_INVALID_ARG);
 	}
 
-	ret = psGetHostGroupMemberList((char *)groupName, groupProp);
+	if (type == HOST_GROUP) {
+		ret = psGetHostGroupMemberList((char *)groupName, groupProp);
+	} else if (type == TARGET_GROUP) {
+		ret = psGetTargetGroupMemberList((char *)groupName, groupProp);
+	} else {
+		return (STMF_ERROR_INVALID_ARG);
+	}
 	switch (ret) {
 		case STMF_PS_SUCCESS:
 			ret = STMF_STATUS_SUCCESS;
@@ -1265,8 +3345,8 @@
 			break;
 		default:
 			syslog(LOG_DEBUG,
-			    "stmfGetHostGroupMembers:psGetHostGroupMembers"
-			    ":error(%d)", ret);
+			    "iLoadGroupMembersFromPs:psGetHostGroupList:"
+			    "error(%d)", ret);
 			ret = STMF_STATUS_ERROR;
 			break;
 	}
@@ -1275,6 +3355,30 @@
 }
 
 /*
+ * stmfGetHostGroupMembers
+ *
+ * Purpose: Retrieves the group properties for a host group
+ *
+ * groupName - name of group for which to retrieve host group members.
+ * groupProp - pointer to pointer to stmfGroupProperties structure
+ *             on success, this contains the list of group members.
+ */
+int
+stmfGetHostGroupMembers(stmfGroupName *groupName,
+    stmfGroupProperties **groupProp)
+{
+	int ret;
+
+	if (groupName == NULL || groupProp == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	ret = groupMemberListIoctl(groupName, groupProp, HOST_GROUP);
+
+	return (ret);
+}
+
+/*
  * stmfGetProviderData
  *
  * Purpose: Get provider data list
@@ -1315,44 +3419,16 @@
 	if (providerName == NULL || nvl == NULL) {
 		return (STMF_ERROR_INVALID_ARG);
 	}
-
 	if (providerType != STMF_LU_PROVIDER_TYPE &&
 	    providerType != STMF_PORT_PROVIDER_TYPE) {
 		return (STMF_ERROR_INVALID_ARG);
 	}
-
 	/* call init */
 	ret = initializeConfig();
 	if (ret != STMF_STATUS_SUCCESS) {
 		return (ret);
 	}
-
-	ret = psGetProviderData(providerName, nvl, providerType, setToken);
-	switch (ret) {
-		case STMF_PS_SUCCESS:
-			ret = STMF_STATUS_SUCCESS;
-			break;
-		case STMF_PS_ERROR_BUSY:
-			ret = STMF_ERROR_BUSY;
-			break;
-		case STMF_PS_ERROR_NOT_FOUND:
-			ret = STMF_ERROR_NOT_FOUND;
-			break;
-		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
-			ret = STMF_ERROR_SERVICE_NOT_FOUND;
-			break;
-		case STMF_PS_ERROR_VERSION_MISMATCH:
-			ret = STMF_ERROR_SERVICE_DATA_VERSION;
-			break;
-		default:
-			syslog(LOG_DEBUG,
-			    "stmfGetProviderData:psGetProviderData:error(%d)",
-			    ret);
-			ret = STMF_STATUS_ERROR;
-			break;
-	}
-
-	return (ret);
+	return (getProviderData(providerName, nvl, providerType, setToken));
 }
 
 /*
@@ -1435,7 +3511,7 @@
 	/*
 	 * Allocate ioctl input buffer
 	 */
-	fSessionListSize = MAX_SESSION;
+	fSessionListSize = ALLOC_SESSION;
 	fSessionListSize = fSessionListSize * (sizeof (slist_scsi_session_t));
 	fSessionList = (slist_scsi_session_t *)calloc(1, fSessionListSize);
 	if (fSessionList == NULL) {
@@ -1461,6 +3537,7 @@
 			case EBUSY:
 				ret = STMF_ERROR_BUSY;
 				break;
+			case EPERM:
 			case EACCES:
 				ret = STMF_ERROR_PERM;
 				break;
@@ -1476,7 +3553,7 @@
 	/*
 	 * Check whether input buffer was large enough
 	 */
-	if (stmfIoctl.stmf_obuf_max_nentries > MAX_SESSION) {
+	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_SESSION) {
 		fSessionListSize = stmfIoctl.stmf_obuf_max_nentries *
 		    sizeof (slist_scsi_session_t);
 		fSessionList = realloc(fSessionList, fSessionListSize);
@@ -1491,6 +3568,7 @@
 				case EBUSY:
 					ret = STMF_ERROR_BUSY;
 					break;
+				case EPERM:
 				case EACCES:
 					ret = STMF_ERROR_PERM;
 					break;
@@ -1556,31 +3634,7 @@
 		return (STMF_ERROR_INVALID_ARG);
 	}
 
-	ret = psGetTargetGroupList(targetGroupList);
-	switch (ret) {
-		case STMF_PS_SUCCESS:
-			ret = STMF_STATUS_SUCCESS;
-			break;
-		case STMF_PS_ERROR_NOT_FOUND:
-			ret = STMF_ERROR_NOT_FOUND;
-			break;
-		case STMF_PS_ERROR_BUSY:
-			ret = STMF_ERROR_BUSY;
-			break;
-		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
-			ret = STMF_ERROR_SERVICE_NOT_FOUND;
-			break;
-		case STMF_PS_ERROR_VERSION_MISMATCH:
-			ret = STMF_ERROR_SERVICE_DATA_VERSION;
-			break;
-		default:
-			syslog(LOG_DEBUG,
-			    "stmfGetTargetGroupList:psGetTargetGroupList:"
-			    "error(%d)", ret);
-			ret = STMF_STATUS_ERROR;
-			break;
-	}
-
+	ret = groupListIoctl(targetGroupList, TARGET_GROUP);
 	return (ret);
 }
 
@@ -1603,30 +3657,7 @@
 		return (STMF_ERROR_INVALID_ARG);
 	}
 
-	ret = psGetTargetGroupMemberList((char *)groupName, groupProp);
-	switch (ret) {
-		case STMF_PS_SUCCESS:
-			ret = STMF_STATUS_SUCCESS;
-			break;
-		case STMF_PS_ERROR_NOT_FOUND:
-			ret = STMF_ERROR_NOT_FOUND;
-			break;
-		case STMF_PS_ERROR_BUSY:
-			ret = STMF_ERROR_BUSY;
-			break;
-		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
-			ret = STMF_ERROR_SERVICE_NOT_FOUND;
-			break;
-		case STMF_PS_ERROR_VERSION_MISMATCH:
-			ret = STMF_ERROR_SERVICE_DATA_VERSION;
-			break;
-		default:
-			syslog(LOG_DEBUG,
-			    "stmfGetTargetGroupMembers:psGetTargetGroupMembers:"
-			    "error(%d)", ret);
-			ret = STMF_STATUS_ERROR;
-			break;
-	}
+	ret = groupMemberListIoctl(groupName, groupProp, TARGET_GROUP);
 
 	return (ret);
 }
@@ -1648,7 +3679,7 @@
 	int i;
 	stmf_iocdata_t stmfIoctl;
 	/* framework target port list */
-	slist_target_port_t *fTargetList, *fTargetListP;
+	slist_target_port_t *fTargetList, *fTargetListP = NULL;
 	uint32_t fTargetListSize;
 
 	if (targetList == NULL) {
@@ -1670,10 +3701,11 @@
 	/*
 	 * Allocate ioctl input buffer
 	 */
-	fTargetListSize = MAX_TARGET_PORT * sizeof (slist_target_port_t);
+	fTargetListSize = ALLOC_TARGET_PORT * sizeof (slist_target_port_t);
 	fTargetListP = fTargetList =
 	    (slist_target_port_t *)calloc(1, fTargetListSize);
 	if (fTargetList == NULL) {
+		ret = STMF_ERROR_NOMEM;
 		goto done;
 	}
 
@@ -1690,6 +3722,7 @@
 			case EBUSY:
 				ret = STMF_ERROR_BUSY;
 				break;
+			case EPERM:
 			case EACCES:
 				ret = STMF_ERROR_PERM;
 				break;
@@ -1704,13 +3737,14 @@
 	/*
 	 * Check whether input buffer was large enough
 	 */
-	if (stmfIoctl.stmf_obuf_max_nentries > MAX_TARGET_PORT) {
+	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_TARGET_PORT) {
 		fTargetListSize = stmfIoctl.stmf_obuf_max_nentries *
 		    sizeof (slist_target_port_t);
 		fTargetListP = fTargetList =
 		    realloc(fTargetList, fTargetListSize);
 		if (fTargetList == NULL) {
-			return (STMF_ERROR_NOMEM);
+			ret = STMF_ERROR_NOMEM;
+			goto done;
 		}
 		stmfIoctl.stmf_obuf_size = fTargetListSize;
 		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fTargetList;
@@ -1721,6 +3755,7 @@
 				case EBUSY:
 					ret = STMF_ERROR_BUSY;
 					break;
+				case EPERM:
 				case EACCES:
 					ret = STMF_ERROR_PERM;
 					break;
@@ -1738,6 +3773,10 @@
 	*targetList = (stmfDevidList *)calloc(1,
 	    stmfIoctl.stmf_obuf_max_nentries * sizeof (stmfDevid) +
 	    sizeof (stmfDevidList));
+	if (*targetList == NULL) {
+		ret = STMF_ERROR_NOMEM;
+		goto done;
+	}
 
 	(*targetList)->cnt = stmfIoctl.stmf_obuf_max_nentries;
 	for (i = 0; i < stmfIoctl.stmf_obuf_max_nentries; i++, fTargetList++) {
@@ -1809,6 +3848,7 @@
 			case EBUSY:
 				ret = STMF_ERROR_BUSY;
 				break;
+			case EPERM:
 			case EACCES:
 				ret = STMF_ERROR_PERM;
 				break;
@@ -1859,16 +3899,11 @@
 	int fd;
 	int ioctlRet;
 	int cmd = STMF_IOCTL_LU_LIST;
-	int i, k;
+	int i;
 	stmf_iocdata_t stmfIoctl;
-	/* framework lu list */
 	slist_lu_t *fLuList;
-	/* persistent store lu list */
-	stmfGuidList *sLuList = NULL;
-	int finalListSize = 0;
-	int newAllocSize;
 	uint32_t fLuListSize;
-	uint32_t endList;
+	uint32_t listCnt;
 
 	if (luList == NULL) {
 		return (STMF_ERROR_INVALID_ARG);
@@ -1889,11 +3924,12 @@
 	/*
 	 * Allocate ioctl input buffer
 	 */
-	fLuListSize = MAX_LU;
+	fLuListSize = ALLOC_LU;
 	fLuListSize = fLuListSize * (sizeof (slist_lu_t));
 	fLuList = (slist_lu_t *)calloc(1, fLuListSize);
 	if (fLuList == NULL) {
-		return (STMF_ERROR_NOMEM);
+		ret = STMF_ERROR_NOMEM;
+		goto done;
 	}
 
 	bzero(&stmfIoctl, sizeof (stmfIoctl));
@@ -1909,6 +3945,7 @@
 			case EBUSY:
 				ret = STMF_ERROR_BUSY;
 				break;
+			case EPERM:
 			case EACCES:
 				ret = STMF_ERROR_PERM;
 				break;
@@ -1924,12 +3961,14 @@
 	/*
 	 * Check whether input buffer was large enough
 	 */
-	if (stmfIoctl.stmf_obuf_max_nentries > MAX_LU) {
+	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_LU) {
 		fLuListSize = stmfIoctl.stmf_obuf_max_nentries *
 		    sizeof (slist_lu_t);
-		fLuList = realloc(fLuList, fLuListSize);
+		free(fLuList);
+		fLuList = (slist_lu_t *)calloc(1, fLuListSize);
 		if (fLuList == NULL) {
-			return (STMF_ERROR_NOMEM);
+			ret = STMF_ERROR_NOMEM;
+			goto done;
 		}
 		stmfIoctl.stmf_obuf_size = fLuListSize;
 		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fLuList;
@@ -1939,6 +3978,7 @@
 				case EBUSY:
 					ret = STMF_ERROR_BUSY;
 					break;
+				case EPERM:
 				case EACCES:
 					ret = STMF_ERROR_PERM;
 					break;
@@ -1953,99 +3993,35 @@
 		}
 	}
 
-	ret = psGetLogicalUnitList(&sLuList);
-	switch (ret) {
-		case STMF_PS_SUCCESS:
-			ret = STMF_STATUS_SUCCESS;
-			break;
-		case STMF_PS_ERROR_BUSY:
-			ret = STMF_ERROR_BUSY;
-			break;
-		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
-			ret = STMF_ERROR_SERVICE_NOT_FOUND;
-			break;
-		case STMF_PS_ERROR_VERSION_MISMATCH:
-			ret = STMF_ERROR_SERVICE_DATA_VERSION;
-			break;
-		default:
-			syslog(LOG_DEBUG,
-			    "stmfGetLogicalUnitList:psGetLogicalUnitList"
-			    ":error(%d)", ret);
-			ret = STMF_STATUS_ERROR;
-			break;
-	}
 	if (ret != STMF_STATUS_SUCCESS) {
 		goto done;
 	}
 
-	/*
-	 * 2 lists must be merged
-	 * reallocate the store list to add the list from the
-	 * framework
-	 */
-	newAllocSize = sLuList->cnt * sizeof (stmfGuid) + sizeof (stmfGuidList)
-	    + stmfIoctl.stmf_obuf_nentries * sizeof (stmfGuid);
-
-	sLuList = realloc(sLuList, newAllocSize);
-	if (sLuList == NULL) {
-		ret = STMF_ERROR_NOMEM;
-		goto done;
-	}
-
-	/*
-	 * add list from ioctl. Start from end of list retrieved from store.
-	 */
-	endList = sLuList->cnt + stmfIoctl.stmf_obuf_nentries;
-	for (k = 0, i = sLuList->cnt; i < endList; i++, k++) {
-		bcopy(&fLuList[k].lu_guid, sLuList->guid[i].guid,
-		    sizeof (stmfGuid));
-	}
-	sLuList->cnt = endList;
-
-	/*
-	 * sort the list for merging
-	 */
-	qsort((void *)&(sLuList->guid[0]), sLuList->cnt,
-	    sizeof (stmfGuid), guidCompare);
-
-	/*
-	 * get final list count
-	 */
-	for (i = 0; i < sLuList->cnt; i++) {
-		if ((i + 1) <= sLuList->cnt) {
-			if (bcmp(sLuList->guid[i].guid, sLuList->guid[i+1].guid,
-			    sizeof (stmfGuid)) == 0) {
-				continue;
-			}
-		}
-		finalListSize++;
-	}
+	listCnt = stmfIoctl.stmf_obuf_nentries;
 
 	/*
 	 * allocate caller's buffer with the final size
 	 */
 	*luList = (stmfGuidList *)calloc(1, sizeof (stmfGuidList) +
-	    finalListSize * sizeof (stmfGuid));
+	    listCnt * sizeof (stmfGuid));
 	if (*luList == NULL) {
 		ret = STMF_ERROR_NOMEM;
 		goto done;
 	}
 
+	(*luList)->cnt = listCnt;
+
+	/* copy to caller's buffer */
+	for (i = 0; i < listCnt; i++) {
+		bcopy(&fLuList[i].lu_guid, (*luList)->guid[i].guid,
+		    sizeof (stmfGuid));
+	}
+
 	/*
-	 * copy guids to caller's buffer
+	 * sort the list. This gives a consistent view across gets
 	 */
-	for (k = 0, i = 0; i < sLuList->cnt; i++) {
-		if ((i + 1) <= sLuList->cnt) {
-			if (bcmp(sLuList->guid[i].guid, sLuList->guid[i+1].guid,
-			    sizeof (stmfGuid)) == 0) {
-				continue;
-			}
-		}
-		bcopy(&(sLuList->guid[i].guid), (*luList)->guid[k++].guid,
-		    sizeof (stmfGuid));
-	}
-
-	(*luList)->cnt = finalListSize;
+	qsort((void *)&((*luList)->guid[0]), (*luList)->cnt,
+	    sizeof (stmfGuid), guidCompare);
 
 done:
 	(void) close(fd);
@@ -2053,7 +4029,6 @@
 	 * free internal buffers
 	 */
 	free(fLuList);
-	free(sLuList);
 	return (ret);
 }
 
@@ -2078,8 +4053,8 @@
 	stmf_iocdata_t stmfIoctl;
 	sioc_lu_props_t fLuProps;
 
-	if (luProps == NULL || luProps == NULL) {
-		ret = STMF_ERROR_INVALID_ARG;
+	if (lu == NULL || luProps == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
 	}
 
 	bzero(luProps, sizeof (stmfLogicalUnitProperties));
@@ -2111,6 +4086,7 @@
 			case EBUSY:
 				ret = STMF_ERROR_BUSY;
 				break;
+			case EPERM:
 			case EACCES:
 				ret = STMF_ERROR_PERM;
 				break;
@@ -2234,38 +4210,167 @@
 stmfGetViewEntryList(stmfGuid *lu, stmfViewEntryList **viewEntryList)
 {
 	int ret;
+	int fd;
+	int ioctlRet;
+	int cmd = STMF_IOCTL_LU_VE_LIST;
+	int i;
+	stmf_iocdata_t stmfIoctl;
+	stmf_view_op_entry_t *fVeList;
+	uint32_t fVeListSize;
+	uint32_t listCnt;
 
 	if (lu == NULL || viewEntryList == NULL) {
 		return (STMF_ERROR_INVALID_ARG);
 	}
 
-	ret = psGetViewEntryList(lu, viewEntryList);
-	switch (ret) {
-		case STMF_PS_SUCCESS:
-			ret = STMF_STATUS_SUCCESS;
-			break;
-		case STMF_PS_ERROR_NOT_FOUND:
-			ret = STMF_ERROR_NOT_FOUND;
-			break;
-		case STMF_PS_ERROR_BUSY:
-			ret = STMF_ERROR_BUSY;
-			break;
-		case STMF_PS_ERROR_SERVICE_NOT_FOUND:
-			ret = STMF_ERROR_SERVICE_NOT_FOUND;
-			break;
-		case STMF_PS_ERROR_VERSION_MISMATCH:
-			ret = STMF_ERROR_SERVICE_DATA_VERSION;
-			break;
-		default:
-			syslog(LOG_DEBUG,
-			    "stmfGetViewEntryList:error(%d)", ret);
-			ret = STMF_STATUS_ERROR;
-			break;
-	}
-
+	/* call init */
+	ret = initializeConfig();
+	if (ret != STMF_STATUS_SUCCESS) {
+		return (ret);
+	}
+
+	/*
+	 * Open control node for stmf
+	 */
+	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+		return (ret);
+
+	/*
+	 * Allocate ioctl input buffer
+	 */
+	fVeListSize = ALLOC_VE;
+	fVeListSize = fVeListSize * (sizeof (stmf_view_op_entry_t));
+	fVeList = (stmf_view_op_entry_t *)calloc(1, fVeListSize);
+	if (fVeList == NULL) {
+		ret = STMF_ERROR_NOMEM;
+		goto done;
+	}
+
+	bzero(&stmfIoctl, sizeof (stmfIoctl));
+	/*
+	 * Issue ioctl to get the LU list
+	 */
+	stmfIoctl.stmf_version = STMF_VERSION_1;
+	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)lu;
+	stmfIoctl.stmf_ibuf_size = sizeof (stmfGuid);
+	stmfIoctl.stmf_obuf_size = fVeListSize;
+	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fVeList;
+	ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+	if (ioctlRet != 0) {
+		switch (errno) {
+			case EBUSY:
+				ret = STMF_ERROR_BUSY;
+				break;
+			case EPERM:
+			case EACCES:
+				ret = STMF_ERROR_PERM;
+				break;
+			default:
+				syslog(LOG_DEBUG,
+				    "stmfGetViewEntryList:ioctl errno(%d)",
+				    errno);
+				ret = STMF_STATUS_ERROR;
+				break;
+		}
+		goto done;
+	}
+	/*
+	 * Check whether input buffer was large enough
+	 */
+	if (stmfIoctl.stmf_obuf_max_nentries > ALLOC_VE) {
+		bzero(&stmfIoctl, sizeof (stmfIoctl));
+		fVeListSize = stmfIoctl.stmf_obuf_max_nentries *
+		    sizeof (stmf_view_op_entry_t);
+		free(fVeList);
+		fVeList = (stmf_view_op_entry_t *)calloc(1, fVeListSize);
+		if (fVeList == NULL) {
+			return (STMF_ERROR_NOMEM);
+		}
+		stmfIoctl.stmf_obuf_size = fVeListSize;
+		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)fVeList;
+		ioctlRet = ioctl(fd, cmd, &stmfIoctl);
+		if (ioctlRet != 0) {
+			switch (errno) {
+				case EBUSY:
+					ret = STMF_ERROR_BUSY;
+					break;
+				case EPERM:
+				case EACCES:
+					ret = STMF_ERROR_PERM;
+					break;
+				default:
+					syslog(LOG_DEBUG,
+					    "stmfGetLogicalUnitList:"
+					    "ioctl errno(%d)", errno);
+					ret = STMF_STATUS_ERROR;
+					break;
+			}
+			goto done;
+		}
+	}
+
+	if (ret != STMF_STATUS_SUCCESS) {
+		goto done;
+	}
+
+	if (stmfIoctl.stmf_obuf_nentries == 0) {
+		ret = STMF_ERROR_NOT_FOUND;
+		goto done;
+	}
+
+	listCnt = stmfIoctl.stmf_obuf_nentries;
+
+	/*
+	 * allocate caller's buffer with the final size
+	 */
+	*viewEntryList = (stmfViewEntryList *)calloc(1,
+	    sizeof (stmfViewEntryList) + listCnt * sizeof (stmfViewEntry));
+	if (*viewEntryList == NULL) {
+		ret = STMF_ERROR_NOMEM;
+		goto done;
+	}
+
+	(*viewEntryList)->cnt = listCnt;
+
+	/* copy to caller's buffer */
+	for (i = 0; i < listCnt; i++) {
+		(*viewEntryList)->ve[i].veIndexValid = B_TRUE;
+		(*viewEntryList)->ve[i].veIndex = fVeList[i].ve_ndx;
+		if (fVeList[i].ve_all_hosts == 1) {
+			(*viewEntryList)->ve[i].allHosts = B_TRUE;
+		} else {
+			bcopy(fVeList[i].ve_host_group.name,
+			    (*viewEntryList)->ve[i].hostGroup,
+			    fVeList[i].ve_host_group.name_size);
+		}
+		if (fVeList[i].ve_all_targets == 1) {
+			(*viewEntryList)->ve[i].allTargets = B_TRUE;
+		} else {
+			bcopy(fVeList[i].ve_target_group.name,
+			    (*viewEntryList)->ve[i].targetGroup,
+			    fVeList[i].ve_target_group.name_size);
+		}
+		bcopy(fVeList[i].ve_lu_nbr, (*viewEntryList)->ve[i].luNbr,
+		    sizeof ((*viewEntryList)->ve[i].luNbr));
+		(*viewEntryList)->ve[i].luNbrValid = B_TRUE;
+	}
+
+	/*
+	 * sort the list. This gives a consistent view across gets
+	 */
+	qsort((void *)&((*viewEntryList)->ve[0]), (*viewEntryList)->cnt,
+	    sizeof (stmfViewEntry), viewEntryCompare);
+
+done:
+	(void) close(fd);
+	/*
+	 * free internal buffers
+	 */
+	free(fVeList);
 	return (ret);
 }
 
+
 /*
  * loadHostGroups
  *
@@ -2286,8 +4391,8 @@
 		    &(groupList->name[i]))) != STMF_STATUS_SUCCESS) {
 			goto out;
 		}
-		ret = stmfGetHostGroupMembers(&(groupList->name[i]),
-		    &groupProps);
+		ret = iLoadGroupMembersFromPs(&(groupList->name[i]),
+		    &groupProps, HOST_GROUP);
 		for (j = 0; j < groupProps->cnt; j++) {
 			if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_HG_ENTRY,
 			    &(groupList->name[i]), &(groupProps->name[j])))
@@ -2323,8 +4428,8 @@
 		    &(groupList->name[i]))) != STMF_STATUS_SUCCESS) {
 			goto out;
 		}
-		ret = stmfGetTargetGroupMembers(&(groupList->name[i]),
-		    &groupProps);
+		ret = iLoadGroupMembersFromPs(&(groupList->name[i]),
+		    &groupProps, TARGET_GROUP);
 		for (j = 0; j < groupProps->cnt; j++) {
 			if ((ret = groupMemberIoctl(fd, STMF_IOCTL_ADD_TG_ENTRY,
 			    &(groupList->name[i]), &(groupProps->name[j])))
@@ -2366,7 +4471,7 @@
 
 
 	/* load host groups */
-	ret = stmfGetHostGroupList(&groupList);
+	ret = iLoadGroupFromPs(&groupList, HOST_GROUP);
 	if (ret != STMF_STATUS_SUCCESS) {
 		return (ret);
 	}
@@ -2379,7 +4484,7 @@
 	groupList = NULL;
 
 	/* load target groups */
-	ret = stmfGetTargetGroupList(&groupList);
+	ret = iLoadGroupFromPs(&groupList, TARGET_GROUP);
 	if (ret != STMF_STATUS_SUCCESS) {
 		goto out;
 	}
@@ -2512,7 +4617,7 @@
 
 		/* call setProviderData */
 		ret = setProviderData(fd, providerList->provider[i].name, nvl,
-		    providerType);
+		    providerType, NULL);
 		switch (ret) {
 			case STMF_PS_SUCCESS:
 				ret = STMF_STATUS_SUCCESS;
@@ -2565,11 +4670,25 @@
 int
 stmfLoadConfig(void)
 {
-	int ret;
+	int ret = STMF_STATUS_SUCCESS;
 	int fd;
 	stmf_state_desc_t stmfStateSet;
 	stmfState state;
 
+	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+		stmfStateSet.state = STMF_STATE_OFFLINE;
+		stmfStateSet.config_state = STMF_CONFIG_INIT;
+		if ((ret = openStmf(OPEN_EXCL_STMF, &fd))
+		    != STMF_STATUS_SUCCESS) {
+			return (ret);
+		}
+		ret = setStmfState(fd, &stmfStateSet, STMF_SERVICE_TYPE);
+		if (ret != STMF_STATUS_SUCCESS) {
+			goto done;
+		}
+		stmfStateSet.config_state = STMF_CONFIG_INIT_DONE;
+		goto done;
+	}
 
 	/* Check to ensure service exists */
 	if (psCheckService() != STMF_STATUS_SUCCESS) {
@@ -2617,6 +4736,7 @@
 	return (ret);
 }
 
+
 /*
  * getStmfState
  *
@@ -2715,6 +4835,7 @@
 			case EBUSY:
 				ret = STMF_ERROR_BUSY;
 				break;
+			case EPERM:
 			case EACCES:
 				ret = STMF_ERROR_PERM;
 				break;
@@ -2975,6 +5096,10 @@
 		goto done;
 	}
 
+	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+		goto done;
+	}
+
 	ret = psRemoveHostGroupMember((char *)hostGroupName,
 	    (char *)hostName->ident);
 	switch (ret) {
@@ -3046,6 +5171,10 @@
 		goto done;
 	}
 
+	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+		goto done;
+	}
+
 	ret = psRemoveTargetGroupMember((char *)targetGroupName,
 	    (char *)targetName->ident);
 	switch (ret) {
@@ -3132,6 +5261,9 @@
 			case EBUSY:
 				ret = STMF_ERROR_BUSY;
 				break;
+			case EPERM:
+				ret = STMF_ERROR_PERM;
+				break;
 			case EACCES:
 				switch (stmfIoctl.stmf_error) {
 					case STMF_IOCERR_UPDATE_NEED_CFG_INIT:
@@ -3156,6 +5288,10 @@
 		goto done;
 	}
 
+	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+		goto done;
+	}
+
 	ret = psRemoveViewEntry(lu, viewEntryIndex);
 	switch (ret) {
 		case STMF_PS_SUCCESS:
@@ -3245,7 +5381,7 @@
 	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
 		return (ret);
 
-	ret = setProviderData(fd, providerName, nvl, providerType);
+	ret = setProviderData(fd, providerName, nvl, providerType, setToken);
 
 	(void) close(fd);
 
@@ -3253,8 +5389,12 @@
 		goto done;
 	}
 
+	if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+		goto done;
+	}
+
 	/* setting driver provider data successful. Now persist it */
-	ret = psSetProviderData(providerName, nvl, providerType, setToken);
+	ret = psSetProviderData(providerName, nvl, providerType, NULL);
 	switch (ret) {
 		case STMF_PS_SUCCESS:
 			ret = STMF_STATUS_SUCCESS;
@@ -3287,21 +5427,161 @@
 }
 
 /*
+ * getProviderData
+ *
+ * Purpose: set the provider data from stmf
+ *
+ * providerName - unique name of provider
+ * nvl - nvlist to load/retrieve
+ * providerType - logical unit or port provider
+ * setToken - returned stale data token
+ */
+int
+getProviderData(char *providerName, nvlist_t **nvl, int providerType,
+    uint64_t *setToken)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	int fd;
+	int ioctlRet;
+	size_t nvlistSize = ALLOC_PP_DATA_SIZE;
+	int retryCnt = 0;
+	int retryCntMax = MAX_PROVIDER_RETRY;
+	stmf_ppioctl_data_t ppi = {0}, *ppi_out = NULL;
+	boolean_t retry = B_TRUE;
+	stmf_iocdata_t stmfIoctl;
+
+	if (providerName == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+
+	/*
+	 * Open control node for stmf
+	 */
+	if ((ret = openStmf(OPEN_STMF, &fd)) != STMF_STATUS_SUCCESS)
+		return (ret);
+
+	/* set provider name and provider type */
+	if (strlcpy(ppi.ppi_name, providerName,
+	    sizeof (ppi.ppi_name)) >=
+	    sizeof (ppi.ppi_name)) {
+		ret = STMF_ERROR_INVALID_ARG;
+		goto done;
+	}
+	switch (providerType) {
+		case STMF_LU_PROVIDER_TYPE:
+			ppi.ppi_lu_provider = 1;
+			break;
+		case STMF_PORT_PROVIDER_TYPE:
+			ppi.ppi_port_provider = 1;
+			break;
+		default:
+			ret = STMF_ERROR_INVALID_ARG;
+			goto done;
+	}
+
+	do {
+		/* allocate memory for ioctl */
+		ppi_out = (stmf_ppioctl_data_t *)calloc(1, nvlistSize +
+		    sizeof (stmf_ppioctl_data_t));
+		if (ppi_out == NULL) {
+			ret = STMF_ERROR_NOMEM;
+			goto done;
+
+		}
+
+		/* set the size of the ioctl data to allocated buffer */
+		ppi.ppi_data_size = nvlistSize;
+
+		bzero(&stmfIoctl, sizeof (stmfIoctl));
+
+		stmfIoctl.stmf_version = STMF_VERSION_1;
+		stmfIoctl.stmf_ibuf_size = sizeof (stmf_ppioctl_data_t);
+		stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)&ppi;
+		stmfIoctl.stmf_obuf_size = sizeof (stmf_ppioctl_data_t) +
+		    nvlistSize;
+		stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)ppi_out;
+		ioctlRet = ioctl(fd, STMF_IOCTL_GET_PP_DATA, &stmfIoctl);
+		if (ioctlRet != 0) {
+			switch (errno) {
+				case EBUSY:
+					ret = STMF_ERROR_BUSY;
+					break;
+				case EPERM:
+				case EACCES:
+					ret = STMF_ERROR_PERM;
+					break;
+				case EINVAL:
+					if (stmfIoctl.stmf_error ==
+					    STMF_IOCERR_INSUFFICIENT_BUF) {
+						nvlistSize =
+						    ppi_out->ppi_data_size;
+						free(ppi_out);
+						ppi_out = NULL;
+						if (retryCnt++ > retryCntMax) {
+							retry = B_FALSE;
+							ret = STMF_ERROR_BUSY;
+						} else {
+							ret =
+							    STMF_STATUS_SUCCESS;
+						}
+					} else {
+						syslog(LOG_DEBUG,
+						    "getProviderData:ioctl"
+						    "unable to retrieve "
+						    "nvlist");
+						ret = STMF_STATUS_ERROR;
+					}
+					break;
+				case ENOENT:
+					ret = STMF_ERROR_NOT_FOUND;
+					break;
+				default:
+					syslog(LOG_DEBUG,
+					    "getProviderData:ioctl errno(%d)",
+					    errno);
+					ret = STMF_STATUS_ERROR;
+					break;
+			}
+			if (ret != STMF_STATUS_SUCCESS)
+				goto done;
+		}
+	} while (retry && stmfIoctl.stmf_error == STMF_IOCERR_INSUFFICIENT_BUF);
+
+	if ((ret = nvlist_unpack((char *)ppi_out->ppi_data,
+	    ppi_out->ppi_data_size, nvl, 0)) != 0) {
+		ret = STMF_STATUS_ERROR;
+		goto done;
+	}
+
+	/* caller has asked for new token */
+	if (setToken) {
+		*setToken = ppi_out->ppi_token;
+	}
+done:
+	free(ppi_out);
+	(void) close(fd);
+	return (ret);
+}
+
+/*
  * setProviderData
  *
- * Purpose: set the provider data
+ * Purpose: set the provider data in stmf
  *
  * providerName - unique name of provider
  * nvl - nvlist to set
  * providerType - logical unit or port provider
+ * setToken - stale data token to check if not NULL
  */
 static int
-setProviderData(int fd, char *providerName, nvlist_t *nvl, int providerType)
+setProviderData(int fd, char *providerName, nvlist_t *nvl, int providerType,
+    uint64_t *setToken)
 {
 	int ret = STMF_STATUS_SUCCESS;
 	int ioctlRet;
 	size_t nvlistEncodedSize;
 	stmf_ppioctl_data_t *ppi = NULL;
+	uint64_t outToken;
 	char *allocatedNvBuffer;
 	stmf_iocdata_t stmfIoctl;
 
@@ -3321,6 +5601,11 @@
 		return (STMF_ERROR_NOMEM);
 	}
 
+	if (setToken) {
+		ppi->ppi_token_valid = 1;
+		ppi->ppi_token = *setToken;
+	}
+
 	allocatedNvBuffer = (char *)&ppi->ppi_data;
 	if (nvlist_pack(nvl, &allocatedNvBuffer, &nvlistEncodedSize,
 	    NV_ENCODE_XDR, 0) != 0) {
@@ -3353,15 +5638,26 @@
 	stmfIoctl.stmf_ibuf_size = nvlistEncodedSize +
 	    sizeof (stmf_ppioctl_data_t) - 8;
 	stmfIoctl.stmf_ibuf = (uint64_t)(unsigned long)ppi;
+	stmfIoctl.stmf_obuf_size = sizeof (uint64_t);
+	stmfIoctl.stmf_obuf = (uint64_t)(unsigned long)&outToken;
 	ioctlRet = ioctl(fd, STMF_IOCTL_LOAD_PP_DATA, &stmfIoctl);
 	if (ioctlRet != 0) {
 		switch (errno) {
 			case EBUSY:
 				ret = STMF_ERROR_BUSY;
 				break;
+			case EPERM:
 			case EACCES:
 				ret = STMF_ERROR_PERM;
 				break;
+			case EINVAL:
+				if (stmfIoctl.stmf_error ==
+				    STMF_IOCERR_PPD_UPDATED) {
+					ret = STMF_ERROR_PROV_DATA_STALE;
+				} else {
+					ret = STMF_STATUS_ERROR;
+				}
+				break;
 			default:
 				syslog(LOG_DEBUG,
 				    "setProviderData:ioctl errno(%d)", errno);
@@ -3372,7 +5668,99 @@
 			goto done;
 	}
 
+	/* caller has asked for new token */
+	if (setToken) {
+		*setToken = outToken;
+	}
 done:
 	free(ppi);
 	return (ret);
 }
+
+/*
+ * set the persistence method in the library only or library and service
+ */
+int
+stmfSetPersistMethod(uint8_t persistType, boolean_t serviceSet)
+{
+	int ret = STMF_STATUS_SUCCESS;
+	int oldPersist;
+
+	(void) pthread_mutex_lock(&persistenceTypeLock);
+	oldPersist = iPersistType;
+	if (persistType == STMF_PERSIST_NONE ||
+	    persistType == STMF_PERSIST_SMF) {
+		iLibSetPersist = B_TRUE;
+		iPersistType = persistType;
+	} else {
+		(void) pthread_mutex_unlock(&persistenceTypeLock);
+		return (STMF_ERROR_INVALID_ARG);
+	}
+	/* Is this for this library open or in SMF */
+	if (serviceSet == B_TRUE) {
+		ret = psSetServicePersist(persistType);
+		if (ret != STMF_PS_SUCCESS) {
+			ret = STMF_ERROR_PERSIST_TYPE;
+			/* Set to old value */
+			iPersistType = oldPersist;
+		}
+	}
+	(void) pthread_mutex_unlock(&persistenceTypeLock);
+
+	return (ret);
+}
+
+/*
+ * Only returns internal state for persist. If unset, goes to ps. If that
+ * fails, returns default setting
+ */
+static uint8_t
+iGetPersistMethod()
+{
+
+	uint8_t persistType = 0;
+
+	(void) pthread_mutex_lock(&persistenceTypeLock);
+	if (iLibSetPersist) {
+		persistType = iPersistType;
+	} else {
+		int ret;
+		ret = psGetServicePersist(&persistType);
+		if (ret != STMF_PS_SUCCESS) {
+			/* set to default */
+			persistType = STMF_DEFAULT_PERSIST;
+		}
+	}
+	(void) pthread_mutex_unlock(&persistenceTypeLock);
+	return (persistType);
+}
+
+/*
+ * Returns either library state or persistent config state depending on
+ * serviceState
+ */
+int
+stmfGetPersistMethod(uint8_t *persistType, boolean_t serviceState)
+{
+	int ret = STMF_STATUS_SUCCESS;
+
+	if (persistType == NULL) {
+		return (STMF_ERROR_INVALID_ARG);
+	}
+	if (serviceState) {
+		ret = psGetServicePersist(persistType);
+		if (ret != STMF_PS_SUCCESS) {
+			ret = STMF_ERROR_PERSIST_TYPE;
+		}
+	} else {
+		(void) pthread_mutex_lock(&persistenceTypeLock);
+		if (iLibSetPersist) {
+			*persistType = iPersistType;
+		} else {
+			*persistType = STMF_DEFAULT_PERSIST;
+		}
+		(void) pthread_mutex_unlock(&persistenceTypeLock);
+	}
+
+	return (ret);
+}
--- a/usr/src/lib/libstmf/common/store.c	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/lib/libstmf/common/store.c	Fri May 08 16:22:42 2009 -0600
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -153,6 +153,8 @@
 static int iPsGetViewEntry(char *, stmfViewEntry *);
 static int iPsGetActualGroupName(char *, char *, char *);
 static int iPsGetServiceVersion(uint64_t *, scf_handle_t *, scf_service_t *);
+static int iPsGetSetPersistType(uint8_t *, scf_handle_t *, scf_service_t *,
+    int);
 static int viewEntryCompare(const void *, const void *);
 static int holdSignal(sigset_t *);
 static int releaseSignal(sigset_t *);
@@ -175,6 +177,15 @@
 #define	STMF_SMF_VERSION    1
 
 /*
+ * Note: Do not change these property names and size values.
+ * They represent fields in the persistent config and once modified
+ * will have a nasty side effect of invalidating the existing store.
+ * If you do need to change them, you'll need to use the versioning above
+ * to retain backward compatiblity with the previous configuration schema.
+ */
+
+/* BEGIN STORE PROPERTY DEFINITIONS */
+/*
  * Property Group Names and prefixes
  */
 #define	STMF_HOST_GROUPS	"host_groups"
@@ -190,6 +201,7 @@
 #define	STMF_GROUP_PREFIX	"group_name"
 #define	STMF_MEMBER_LIST_SUFFIX	"member_list"
 #define	STMF_VERSION_NAME	"version_name"
+#define	STMF_PERSIST_TYPE	"persist_method"
 
 /*
  * Property names for view entry
@@ -207,17 +219,14 @@
 #define	STMF_PROVIDER_DATA_PROP_TYPE "provider_type"
 #define	STMF_PROVIDER_DATA_PROP_SET_COUNT "provider_data_set_cnt"
 #define	STMF_PROVIDER_DATA_PROP_COUNT "provider_data_cnt"
-/*
- * This is the data chunk size. The current value limit for scf is 4096.
- * This is defined by REP_PROTOCOL_VALUE_LEN in
- * OS/Net: usr/src/common/svc/repcache_protocol.h
- *
- * Larger data property size = better performance
- */
-#define	STMF_PROVIDER_DATA_PROP_SIZE 4000
+
 
 #define	STMF_SMF_READ_ATTR	"solaris.smf.read.stmf"
 
+#define	STMF_PS_PERSIST_NONE	"none"
+#define	STMF_PS_PERSIST_SMF	"smf"
+#define	STMF_PROVIDER_DATA_PROP_SIZE 4000
+/* END STORE PROPERTY DEFINITIONS */
 
 /* service name */
 #define	STMF_SERVICE	"system/stmf"
@@ -231,6 +240,8 @@
 #define	GROUP_MAX UINT64_MAX
 #define	ADD 0
 #define	REMOVE 1
+#define	GET 0
+#define	SET 1
 
 /*
  * sigHandler
@@ -1963,6 +1974,255 @@
 	return (ret);
 }
 
+int
+psGetServicePersist(uint8_t *persistType)
+{
+	scf_handle_t	*handle = NULL;
+	scf_service_t	*svc = NULL;
+	int ret;
+
+
+	ret = iPsInit(&handle, &svc);
+	if (ret != STMF_PS_SUCCESS) {
+		return (STMF_PS_ERROR);
+	}
+
+	ret = iPsGetSetPersistType(persistType, handle, svc, GET);
+
+	/*
+	 * Free resources
+	 */
+	if (handle != NULL) {
+		scf_handle_destroy(handle);
+	}
+	if (svc != NULL) {
+		scf_service_destroy(svc);
+	}
+	return (ret);
+}
+
+int
+psSetServicePersist(uint8_t persistType)
+{
+	scf_handle_t	*handle = NULL;
+	scf_service_t	*svc = NULL;
+	int ret;
+
+
+	ret = iPsInit(&handle, &svc);
+	if (ret != STMF_PS_SUCCESS) {
+		return (STMF_PS_ERROR);
+	}
+
+	ret = iPsGetSetPersistType(&persistType, handle, svc, SET);
+
+	/*
+	 * Free resources
+	 */
+	if (handle != NULL) {
+		scf_handle_destroy(handle);
+	}
+	if (svc != NULL) {
+		scf_service_destroy(svc);
+	}
+	return (ret);
+}
+
+static int
+iPsGetSetPersistType(uint8_t *persistType, scf_handle_t *handle,
+scf_service_t *svc, int getSet)
+{
+	scf_propertygroup_t	*pg = NULL;
+	scf_property_t	*prop = NULL;
+	scf_value_t	*value = NULL;
+	scf_transaction_t *tran = NULL;
+	scf_transaction_entry_t *entry = NULL;
+	char iPersistTypeGet[MAXNAMELEN] = {0};
+	char *iPersistType;
+	int ret = STMF_PS_SUCCESS;
+	int commitRet;
+
+	if (((pg = scf_pg_create(handle)) == NULL) ||
+	    ((prop = scf_property_create(handle)) == NULL) ||
+	    ((entry = scf_entry_create(handle)) == NULL) ||
+	    ((tran = scf_transaction_create(handle)) == NULL) ||
+	    ((value = scf_value_create(handle)) == NULL)) {
+		syslog(LOG_ERR, "scf alloc resource failed - %s",
+		    scf_strerror(scf_error()));
+		ret = STMF_PS_ERROR;
+		goto out;
+	}
+
+	if (getSet == GET) {
+		/* set to default */
+		*persistType = STMF_PERSIST_SMF;
+		iPersistType = STMF_PS_PERSIST_SMF;
+	}
+
+	if (getSet == SET) {
+		if (*persistType == STMF_PERSIST_SMF) {
+			iPersistType = STMF_PS_PERSIST_SMF;
+		} else if (*persistType == STMF_PERSIST_NONE) {
+			iPersistType = STMF_PS_PERSIST_NONE;
+		} else {
+			ret = STMF_PS_ERROR;
+			goto out;
+		}
+	}
+
+	/*
+	 * get stmf data property group
+	 */
+	if (scf_service_get_pg(svc, STMF_DATA_GROUP, pg) == -1) {
+		if (scf_error() == SCF_ERROR_NOT_FOUND) {
+			ret = STMF_PS_ERROR_NOT_FOUND;
+		} else {
+			syslog(LOG_ERR, "get pg failed - %s",
+			    scf_strerror(scf_error()));
+			ret = STMF_PS_ERROR;
+		}
+		goto out;
+	}
+
+	/* find persistence property */
+	/*
+	 * Get the persistence property
+	 */
+	if (scf_pg_get_property(pg, STMF_PERSIST_TYPE, prop) == -1) {
+		if (scf_error() == SCF_ERROR_NOT_FOUND) {
+			ret = STMF_PS_ERROR_NOT_FOUND;
+		} else {
+			syslog(LOG_ERR, "get property failed - %s",
+			    scf_strerror(scf_error()));
+			ret = STMF_PS_ERROR;
+			goto out;
+		}
+	}
+
+	/* no persist property found */
+	if (ret == STMF_PS_ERROR_NOT_FOUND || getSet == SET) {
+		/*
+		 * If we have no persistType property, go ahead
+		 * and create it with the user specified value or
+		 * the default value.
+		 */
+		/*
+		 * Begin the transaction
+		 */
+		if (scf_transaction_start(tran, pg) == -1) {
+			syslog(LOG_ERR, "start transaction failed - %s",
+			    scf_strerror(scf_error()));
+			ret = STMF_PS_ERROR;
+			goto out;
+		}
+
+		/* is this a SET or GET w/error? */
+		if (ret) {
+			if (scf_transaction_property_new(tran, entry,
+			    STMF_PERSIST_TYPE, SCF_TYPE_ASTRING) == -1) {
+				syslog(LOG_ERR,
+				    "transaction property new failed - %s",
+				    scf_strerror(scf_error()));
+				ret = STMF_PS_ERROR;
+				goto out;
+			}
+		} else {
+			if (scf_transaction_property_change(tran, entry,
+			    STMF_PERSIST_TYPE, SCF_TYPE_ASTRING) == -1) {
+				syslog(LOG_ERR,
+				    "transaction property change failed - %s",
+				    scf_strerror(scf_error()));
+				ret = STMF_PS_ERROR;
+				goto out;
+			}
+		}
+
+		/*
+		 * set the persist type
+		 */
+		if (scf_value_set_astring(value, iPersistType) == -1) {
+			syslog(LOG_ERR, "set value failed - %s",
+			    scf_strerror(scf_error()));
+			ret = STMF_PS_ERROR;
+			goto out;
+		}
+
+		/*
+		 * add the value to the transaction
+		 */
+		if (scf_entry_add_value(entry, value) == -1) {
+			syslog(LOG_ERR, "add value failed - %s",
+			    scf_strerror(scf_error()));
+			ret = STMF_PS_ERROR;
+			goto out;
+		}
+		if ((commitRet = scf_transaction_commit(tran)) != 1) {
+			syslog(LOG_ERR, "transaction commit failed - %s",
+			    scf_strerror(scf_error()));
+			if (commitRet == 0) {
+				ret = STMF_PS_ERROR_BUSY;
+			} else {
+				ret = STMF_PS_ERROR;
+			}
+			goto out;
+		}
+		/* reset return value */
+		ret = STMF_PS_SUCCESS;
+	} else if (getSet == GET) {
+		/* get the persist property */
+		if (scf_property_get_value(prop, value) == -1) {
+			syslog(LOG_ERR, "get property value failed - %s",
+			    scf_strerror(scf_error()));
+			ret = STMF_PS_ERROR;
+			goto out;
+		}
+
+		/*
+		 * Get the value of the persist property
+		 */
+		if (scf_value_get_astring(value, iPersistTypeGet, MAXNAMELEN)
+		    == -1) {
+			syslog(LOG_ERR, "get count value failed - %s",
+			    scf_strerror(scf_error()));
+			ret = STMF_PS_ERROR;
+			goto out;
+		}
+	}
+
+	if (getSet == GET) {
+		if (strcmp(iPersistTypeGet, STMF_PS_PERSIST_NONE) == 0) {
+			*persistType = STMF_PERSIST_NONE;
+		} else if (strcmp(iPersistTypeGet, STMF_PS_PERSIST_SMF) == 0) {
+			*persistType = STMF_PERSIST_SMF;
+		} else {
+			ret = STMF_PS_ERROR;
+			goto out;
+		}
+	}
+out:
+	/*
+	 * Free resources.
+	 * handle and svc should not be free'd here. They're
+	 * free'd elsewhere
+	 */
+	if (pg != NULL) {
+		scf_pg_destroy(pg);
+	}
+	if (prop != NULL) {
+		scf_property_destroy(prop);
+	}
+	if (entry != NULL) {
+		scf_entry_destroy(entry);
+	}
+	if (tran != NULL) {
+		scf_transaction_destroy(tran);
+	}
+	if (value != NULL) {
+		scf_value_destroy(value);
+	}
+	return (ret);
+}
+
 /*
  * Initialize scf stmf service access
  * handle - returned handle
@@ -2054,6 +2314,7 @@
 	return (ret);
 }
 
+
 /*
  * called by iPsInit only
  * iPsGetServiceVersion
--- a/usr/src/lib/libstmf/common/store.h	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/lib/libstmf/common/store.h	Fri May 08 16:22:42 2009 -0600
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #ifndef	_STORE_H
@@ -73,6 +73,8 @@
     uint64_t *setHandle);
 int psGetProviderDataList(stmfProviderList **providerList);
 int psClearProviderData(char *providerName, int providerType);
+int psSetServicePersist(uint8_t persistType);
+int psGetServicePersist(uint8_t *persistType);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/uts/common/Makefile.files	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/uts/common/Makefile.files	Fri May 08 16:22:42 2009 -0600
@@ -889,7 +889,7 @@
 
 STMF_OBJS += lun_map.o stmf.o
 
-STMF_SBD_OBJS += filedisk.o memdisk.o sbd.o sbd_scsi.o
+STMF_SBD_OBJS += sbd.o sbd_scsi.o sbd_pgr.o
 
 SYSMSG_OBJS +=	sysmsg.o
 
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/filedisk.c	Fri May 08 13:31:23 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,569 +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/sysmacros.h>
-#include <sys/cmn_err.h>
-#include <sys/uio.h>
-#include <sys/kmem.h>
-#include <sys/cred.h>
-#include <sys/mman.h>
-#include <sys/errno.h>
-#include <sys/aio_req.h>
-#include <sys/stat.h>
-#include <sys/file.h>
-#include <sys/modctl.h>
-#include <sys/conf.h>
-#include <sys/debug.h>
-#include <sys/vnode.h>
-#include <sys/lofi.h>
-#include <sys/fcntl.h>
-#include <sys/pathname.h>
-#include <sys/filio.h>
-#include <sys/fdio.h>
-#include <sys/open.h>
-#include <sys/disp.h>
-#include <vm/seg_map.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/time.h>
-#include <sys/modctl.h>
-#include <sys/scsi/scsi.h>
-#include <sys/scsi/impl/scsi_reset_notify.h>
-#include <sys/byteorder.h>
-#include <sys/atomic.h>
-#include <sys/sdt.h>
-
-#include <stmf.h>
-#include <lpif.h>
-#include <stmf_sbd.h>
-#include <stmf_sbd_ioctl.h>
-#include <sbd_impl.h>
-
-typedef struct sbd_filedisk {
-	uint32_t	sfd_flags;
-	uint64_t	sfd_lun_size;
-	uint64_t	sfd_cur_store_size;
-	struct vnode	*sfd_vp;
-	char		sfd_filename[1];
-} sbd_filedisk_t;
-
-#define	META_DATA_SIZE	0x10000	/* 64 * 1024 */
-/*
- * sfd_flags
- */
-#define	SFD_OPENED		0x0001
-
-stmf_status_t filedisk_online(sbd_store_t *sst);
-stmf_status_t filedisk_offline(sbd_store_t *sst);
-stmf_status_t filedisk_deregister_lu(sbd_store_t *sst);
-
-stmf_status_t
-filedisk_data_read(struct sbd_store *sst, uint64_t offset, uint64_t size,
-						uint8_t *buf)
-{
-	sbd_filedisk_t *sfd = (sbd_filedisk_t *)sst->sst_store_private;
-	int ret;
-	ssize_t resid;
-
-	if (((offset + size) > sfd->sfd_lun_size) ||
-	    ((sfd->sfd_flags & SFD_OPENED) == 0)) {
-		return (STMF_FAILURE);
-	}
-
-	if ((offset + size) > sfd->sfd_cur_store_size) {
-		uint64_t store_end;
-
-		if (offset >= sfd->sfd_cur_store_size) {
-			bzero(buf, size);
-			return (STMF_SUCCESS);
-		}
-		store_end = sfd->sfd_cur_store_size - offset;
-		bzero(buf + store_end, size - store_end);
-		size = store_end;
-	}
-
-	DTRACE_PROBE4(backing__store__read__start, sbd_store_t *, sst,
-	    uint8_t *, buf, uint64_t, size, uint64_t, offset);
-
-	ret = vn_rdwr(UIO_READ, sfd->sfd_vp, (caddr_t)buf, (ssize_t)size,
-	    (offset_t)offset, UIO_SYSSPACE, 0,
-	    RLIM64_INFINITY, CRED(), &resid);
-
-	DTRACE_PROBE5(backing__store__read__end, sbd_store_t *, sst,
-	    uint8_t *, buf, uint64_t, size, uint64_t, offset,
-	    int, ret);
-
-	if (ret || resid) {
-		stmf_trace(0, "UIO_READ failed, ret %d, resid %d", ret, resid);
-		return (STMF_FAILURE);
-	}
-
-	return (STMF_SUCCESS);
-}
-
-stmf_status_t
-filedisk_data_write(struct sbd_store *sst, uint64_t offset, uint64_t size,
-						uint8_t *buf)
-{
-	sbd_filedisk_t *sfd = (sbd_filedisk_t *)sst->sst_store_private;
-	int ret;
-	ssize_t resid;
-
-	if (((offset + size) > sfd->sfd_lun_size) ||
-	    ((sfd->sfd_flags & SFD_OPENED) == 0)) {
-		return (STMF_FAILURE);
-	}
-
-
-	DTRACE_PROBE4(backing__store__write__start, sbd_store_t *, sst,
-	    uint8_t *, buf, uint64_t, size, uint64_t, offset);
-
-	ret = vn_rdwr(UIO_WRITE, sfd->sfd_vp, (caddr_t)buf,
-	    (ssize_t)size, (offset_t)offset, UIO_SYSSPACE, 0,
-	    RLIM64_INFINITY, CRED(), &resid);
-
-	DTRACE_PROBE5(backing__store__write__end, sbd_store_t *, sst,
-	    uint8_t *, buf, uint64_t, size, uint64_t, offset,
-	    int, ret);
-
-	if (ret || resid) {
-		stmf_trace(0, "UIO_WRITE failed, ret %d, resid %d", ret, resid);
-		return (STMF_FAILURE);
-	} else if ((offset + size) > sfd->sfd_cur_store_size) {
-		uint64_t old_size, new_size;
-
-		do {
-			old_size = sfd->sfd_cur_store_size;
-			if ((offset + size) <= old_size)
-				break;
-			new_size = offset + size;
-		} while (atomic_cas_64(&sfd->sfd_cur_store_size, old_size,
-		    new_size) != old_size);
-	}
-
-	return (STMF_SUCCESS);
-}
-
-stmf_status_t
-filedisk_data_flush(struct sbd_store *sst)
-{
-	sbd_filedisk_t	*sfd = (sbd_filedisk_t *)sst->sst_store_private;
-	int		rval;
-
-	rval = VOP_FSYNC(sfd->sfd_vp, FSYNC, kcred, NULL);
-
-	if (rval != 0) {
-		stmf_trace(0, "filedisk_data_flush: VOP_FSYNC failed");
-		return (STMF_FAILURE);
-	}
-
-	return (STMF_SUCCESS);
-}
-
-/*
- * Registers a logical unit. Optionally creates it as well.
- */
-stmf_status_t
-filedisk_register_lu(register_lu_cmd_t *rlc)
-{
-	sbd_filedisk_t *sfd;
-	sbd_store_t *sst;
-	sbd_lu_t *slu;
-	sst_init_data_t sid;
-	stmf_status_t ret;
-	struct vnode *vp;
-	vattr_t vattr;
-	enum vtype vt;
-	int flag, error;
-	long nbits;
-	uint64_t supported_size;
-	uint64_t file_size;
-
-	error = lookupname(rlc->name, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp);
-	if (error) {
-		rlc->return_code = RLC_RET_FILE_LOOKUP_FAILED;
-		return (SBD_FILEIO_FAILURE | error);
-	}
-	vt = vp->v_type;
-	VN_RELE(vp);
-	if ((vt != VREG) && (vt != VCHR) && (vt != VBLK)) {
-		rlc->return_code = RLC_RET_WRONG_FILE_TYPE;
-		return (SBD_FAILURE);
-	}
-
-	/* Check if this file is already registered */
-	for (slu = sbd_lu_list; slu; slu = slu->sl_next) {
-		sst = slu->sl_sst;
-		sfd = (sbd_filedisk_t *)sst->sst_store_private;
-		if (strcmp(sfd->sfd_filename, rlc->name) == 0) {
-			rlc->return_code = RLC_RET_FILE_ALREADY_REGISTERED;
-			return (STMF_ALREADY);
-		}
-	}
-
-	flag = FREAD | FWRITE | FOFFMAX | FEXCL;
-	error = vn_open(rlc->name, UIO_SYSSPACE, flag, 0, &vp, 0, 0);
-	if (error) {
-		rlc->return_code = RLC_RET_FILE_OPEN_FAILED;
-		return (SBD_FILEIO_FAILURE | error);
-	}
-
-	vattr.va_mask = AT_SIZE;
-	error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL);
-	if (error) {
-		rlc->return_code = RLC_RET_FILE_GETATTR_FAILED;
-		ret = SBD_FILEIO_FAILURE | error;
-		goto closeout;
-	}
-
-	if ((vt != VREG) && (vattr.va_size == 0)) {
-		/*
-		 * Its a zero byte block or char device. This cannot be
-		 * a raw disk.
-		 */
-		rlc->return_code = RLC_RET_WRONG_FILE_TYPE;
-		ret = SBD_FAILURE;
-		goto closeout;
-	}
-
-	if (VOP_PATHCONF(vp, _PC_FILESIZEBITS, (ulong_t *)&nbits, CRED(),
-	    NULL) != 0) {
-		nbits = 0;
-	}
-
-	if (rlc->lu_size) {
-		file_size = rlc->lu_size + META_DATA_SIZE;
-		if ((nbits > 0) && (nbits < 64)) {
-			/*
-			 * The expression below is correct only if nbits is
-			 * positive and less than 64.
-			 */
-			supported_size = (((uint64_t)1) << nbits) - 1;
-			if (file_size > supported_size) {
-				rlc->return_code =
-				    RLC_RET_SIZE_NOT_SUPPORTED_BY_FS;
-				rlc->filesize_nbits = (uint32_t)nbits;
-				ret = SBD_FAILURE;
-				goto closeout;
-			}
-		}
-	} else {
-		file_size = vattr.va_size;
-		rlc->lu_size = (file_size > META_DATA_SIZE)?
-		    (file_size - META_DATA_SIZE):0;
-	}
-	if (rlc->flags & RLC_CREATE_LU) {
-		if (rlc->lu_size < (1024 * 1024)) {
-			rlc->return_code = RLC_RET_FILE_SIZE_ERROR;
-			ret = SBD_FAILURE;
-			goto closeout;
-		}
-		if (rlc->lu_size % DEV_BSIZE) {
-			rlc->return_code = RLC_RET_FILE_ALIGN_ERROR;
-			ret = SBD_FAILURE;
-			goto closeout;
-		}
-	}
-
-	sst = sbd_sst_alloc(sizeof (sbd_filedisk_t) + strlen(rlc->name), 0);
-	sfd = (sbd_filedisk_t *)sst->sst_store_private;
-	(void) strcpy(sfd->sfd_filename, rlc->name);
-	/*
-	 * If we are only registering LU, then we should use the size
-	 * get from the meta data as the lun_size, but for now, we have to
-	 * temporarily set it to the file size to avoid read failure when
-	 * reading meta data
-	 */
-	sfd->sfd_lun_size = file_size;
-	if (sfd->sfd_lun_size < META_DATA_SIZE)
-		/*
-		 * with aligned read/write, now we have to set this larger to
-		 * avoid read failure with old style LU
-		 */
-		sfd->sfd_lun_size = META_DATA_SIZE;
-	sfd->sfd_cur_store_size = vattr.va_size;
-	sfd->sfd_vp = vp;
-	sfd->sfd_flags = SFD_OPENED;
-
-	sst->sst_online = filedisk_online;
-	sst->sst_offline = filedisk_offline;
-	sst->sst_deregister_lu = filedisk_deregister_lu;
-	sst->sst_data_read = filedisk_data_read;
-	sst->sst_data_write = filedisk_data_write;
-	sst->sst_data_flush = filedisk_data_flush;
-	sst->sst_alias = sfd->sfd_filename;
-
-	if (rlc->flags & RLC_CREATE_LU) {
-		sid.sst_store_size = sfd->sfd_lun_size;
-		sid.sst_store_meta_data_size = 0;	/* XXX */
-		sid.sst_flags = 0;
-		sid.sst_blocksize = 512;
-
-		if ((ret = sbd_create_meta(sst, &sid)) != STMF_SUCCESS) {
-			rlc->return_code = RLC_RET_META_CREATION_FAILED;
-			sbd_sst_free(sst);
-			goto closeout;
-		}
-		bcopy(sid.sst_guid, rlc->guid, 16);
-	}
-
-	if (rlc->flags & RLC_REGISTER_LU) {
-		if ((ret = sbd_register_sst(sst, &sid)) != STMF_SUCCESS) {
-			bcopy(sid.sst_guid, rlc->guid, 16);
-			if (ret == STMF_ALREADY) {
-				rlc->return_code =
-				    RLC_RET_GUID_ALREADY_REGISTERED;
-			} else if (ret == STMF_INVALID_ARG) {
-				rlc->return_code = RLC_RET_LU_NOT_INITIALIZED;
-			} else {
-				rlc->return_code = RLC_RET_REGISTER_SST_FAILED;
-			}
-			sbd_sst_free(sst);
-			goto closeout;
-		}
-		sfd->sfd_lun_size = sid.sst_store_size;
-		bcopy(sid.sst_guid, rlc->guid, 16);
-		if ((nbits > 0) && (nbits < 64)) {
-			/*
-			 * The expression below is correct only if nbits is
-			 * positive and less than 64.
-			 */
-			supported_size = (((uint64_t)1) << nbits) - 1;
-			if (sfd->sfd_lun_size > supported_size) {
-				(void) sbd_deregister_sst(sst);
-				sbd_sst_free(sst);
-				rlc->return_code =
-				    RLC_RET_SIZE_NOT_SUPPORTED_BY_FS;
-				rlc->filesize_nbits = (uint32_t)nbits;
-				ret = SBD_FAILURE;
-				goto closeout;
-			}
-		}
-	} else {
-		sbd_sst_free(sst);
-		goto closeout;
-	}
-
-	rlc->lu_handle = (uint64_t)(unsigned long)sst->sst_sbd_private;
-
-	return (STMF_SUCCESS);
-
-closeout:;
-	(void) VOP_CLOSE(vp, flag, 1, 0, CRED(), NULL);
-	VN_RELE(vp);
-	return (ret);
-}
-
-stmf_status_t
-filedisk_modify_lu(sbd_store_t *sst, modify_lu_cmd_t *mlc)
-{
-	sbd_filedisk_t *sfd;
-	sst_init_data_t sid;
-	stmf_status_t ret = STMF_SUCCESS;
-	int lun_registered = 1;
-	struct vnode *vp;
-	vattr_t	vattr;
-	int flag, error;
-	uint64_t lun_old_size;
-	uint64_t file_size;
-	long nbits;
-
-	if (mlc->lu_size < (1024 * 1024)) {
-		mlc->return_code = RLC_RET_FILE_SIZE_ERROR;
-		return (SBD_FAILURE);
-	}
-	if (mlc->lu_size % DEV_BSIZE) {
-		mlc->return_code = RLC_RET_FILE_ALIGN_ERROR;
-		return (SBD_FAILURE);
-	}
-
-	if (sst) {
-		sfd = (sbd_filedisk_t *)sst->sst_store_private;
-		ASSERT(sfd->sfd_flags & SFD_OPENED);
-	} else {
-		/*
-		 * This LUN is not registered, we don't check the file type here
-		 * because meta data should have been created for this file,
-		 * or else, sbd_modify_meta will fail when read the meta data.
-		 */
-		lun_registered = 0;
-
-		flag = FREAD | FWRITE | FOFFMAX | FEXCL;
-		error = vn_open(mlc->name, UIO_SYSSPACE, flag, 0, &vp, 0, 0);
-		if (error) {
-			mlc->return_code = RLC_RET_FILE_OPEN_FAILED;
-			return (SBD_FILEIO_FAILURE | error);
-		}
-
-		vattr.va_mask = AT_SIZE;
-		error = VOP_GETATTR(vp, &vattr, 0, CRED(), NULL);
-		if (error) {
-			mlc->return_code = RLC_RET_FILE_GETATTR_FAILED;
-			ret = SBD_FILEIO_FAILURE | error;
-			goto closeout;
-		}
-
-		sst = sbd_sst_alloc(
-		    sizeof (sbd_filedisk_t) + strlen(mlc->name), 0);
-		sfd = (sbd_filedisk_t *)sst->sst_store_private;
-		(void) strcpy(sfd->sfd_filename, mlc->name);
-		sfd->sfd_vp = vp;
-		sfd->sfd_flags = SFD_OPENED;
-		/* set this, or else read meta data will fail */
-		sfd->sfd_cur_store_size = vattr.va_size;
-		sst->sst_data_read = filedisk_data_read;
-		sst->sst_data_write = filedisk_data_write;
-		sst->sst_alias = sfd->sfd_filename;
-	}
-
-	file_size = mlc->lu_size + META_DATA_SIZE;
-	if ((VOP_PATHCONF(sfd->sfd_vp, _PC_FILESIZEBITS, (ulong_t *)&nbits,
-	    CRED(), NULL) == 0) && (nbits > 0) && (nbits < 64)) {
-		uint64_t supported_size;
-
-		supported_size = (((uint64_t)1) << nbits) - 1;
-		if (file_size > supported_size) {
-			mlc->return_code =
-			    RLC_RET_SIZE_NOT_SUPPORTED_BY_FS;
-			mlc->filesize_nbits = (uint32_t)nbits;
-			ret = SBD_FAILURE;
-			goto closeout;
-		}
-	}
-
-	lun_old_size = sfd->sfd_lun_size;
-	sfd->sfd_lun_size = file_size;
-	sid.sst_store_size = file_size;
-	sid.sst_store_meta_data_size = 0;
-	sid.sst_flags = 0;
-	sid.sst_blocksize = 512;
-
-	ret = sbd_modify_meta(sst, &sid);
-	bcopy(sid.sst_guid, mlc->guid, 16);
-	if (ret != STMF_SUCCESS) {
-		/* if fail, just restore the old size */
-		sfd->sfd_lun_size = lun_old_size;
-		if (ret == STMF_INVALID_ARG) {
-			mlc->return_code = RLC_RET_LU_NOT_INITIALIZED;
-		}
-	}
-closeout:
-	if (lun_registered == 0) {
-		if (sst)
-			sbd_sst_free(sst);
-		(void) VOP_CLOSE(vp, flag, 1, 0, CRED(), NULL);
-		VN_RELE(vp);
-	}
-	return (ret);
-}
-
-void
-filedisk_fillout_attr(struct sbd_store *sst, struct sbd_lu_attr *sla)
-{
-	sbd_filedisk_t *sfd = (sbd_filedisk_t *)sst->sst_store_private;
-
-	if (sst->sst_data_read != filedisk_data_read)
-		return;
-
-	sla->flags = RLC_LU_TYPE_FILEDISK;
-	if (sla->max_name_length < 2)
-		return;
-	(void) strncpy(sla->name, sfd->sfd_filename, sla->max_name_length-1);
-	sla->name[sla->max_name_length-2] = 0;
-}
-
-/*
- * Ideally file should be opened when the lu is onlined but the metadata
- * access is needed even if lu is not yet onlined. Until we implement better
- * metadata handling routines i.e. allow metadata access even if lu is not
- * online, we will open the file during lu register itself.
- */
-/* ARGSUSED */
-stmf_status_t
-filedisk_online(sbd_store_t *sst)
-{
-#if 0
-	sbd_filedisk_t *sfd;
-	int flag, error;
-
-	sfd = (sbd_filedisk_t *)sst->sst_store_private;
-	ASSERT((sfd->sfd_flags & SFD_OPENED) == 0);
-	error = lookupname(sfd->sfd_filename, UIO_SYSSPACE, FOLLOW,
-	    NULLVPP, &sfd->sfd_vp);
-	if (error) {
-		return (SBD_FILEIO_FAILURE | error);
-	}
-	VN_RELE(sfd->sfd_vp);
-
-	flag = FREAD | FWRITE | FOFFMAX | FEXCL;
-	error = vn_open(sfd->sfd_filename, UIO_SYSSPACE, flag, 0,
-	    &sfd->sfd_vp, 0, 0);
-	if (error) {
-		return (SBD_FILEIO_FAILURE | error);
-	}
-	sfd->sfd_flags = SFD_OPENED;
-#endif
-
-	return (STMF_SUCCESS);
-}
-
-/* ARGSUSED */
-stmf_status_t
-filedisk_offline(sbd_store_t *sst)
-{
-#if 0
-	sbd_filedisk_t *sfd;
-	int flag;
-
-	sfd = (sbd_filedisk_t *)sst->sst_store_private;
-	ASSERT(sfd->sfd_flags & SFD_OPENED);
-	flag = FREAD | FWRITE | FOFFMAX | FEXCL;
-	(void) VOP_CLOSE(sfd->sfd_vp, flag, 1, 0, CRED());
-	VN_RELE(sfd->sfd_vp);
-
-	sfd->sfd_flags &= ~SFD_OPENED;
-#endif
-	return (STMF_SUCCESS);
-}
-
-stmf_status_t
-filedisk_deregister_lu(sbd_store_t *sst)
-{
-	stmf_status_t ret;
-	sbd_filedisk_t *sfd = (sbd_filedisk_t *)sst->sst_store_private;
-
-	if ((ret = sbd_deregister_sst(sst)) != STMF_SUCCESS)
-		return (ret);
-	if (sfd->sfd_flags & SFD_OPENED) {
-		int flag = FREAD | FWRITE | FOFFMAX | FEXCL;
-		sfd->sfd_flags &= ~SFD_OPENED;
-		(void) VOP_CLOSE(sfd->sfd_vp, flag, 1, 0, CRED(), NULL);
-		VN_RELE(sfd->sfd_vp);
-	}
-	sbd_sst_free(sst);
-
-	return (STMF_SUCCESS);
-}
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/memdisk.c	Fri May 08 13:31:23 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,175 +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/conf.h>
-#include <sys/file.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/modctl.h>
-#include <sys/scsi/scsi.h>
-#include <sys/scsi/impl/scsi_reset_notify.h>
-#include <sys/disp.h>
-#include <sys/byteorder.h>
-#include <sys/atomic.h>
-
-#include <stmf.h>
-#include <lpif.h>
-#include <stmf_sbd.h>
-#include <stmf_sbd_ioctl.h>
-
-stmf_status_t memdisk_online(sbd_store_t *sst);
-stmf_status_t memdisk_offline(sbd_store_t *sst);
-stmf_status_t memdisk_deregister_lu(sbd_store_t *sst);
-
-typedef struct sbd_memdisk {
-	uint64_t	smd_size;
-	uint8_t		*smd_buf;
-} sbd_memdisk_t;
-
-stmf_status_t
-memdisk_data_read(struct sbd_store *sst, uint64_t offset, uint64_t size,
-						uint8_t *buf)
-{
-	sbd_memdisk_t *smd = (sbd_memdisk_t *)sst->sst_store_private;
-
-	if ((offset + size) > smd->smd_size) {
-		return (STMF_FAILURE);
-	}
-
-	bcopy(&smd->smd_buf[offset], buf, (size_t)size);
-	return (STMF_SUCCESS);
-}
-
-stmf_status_t
-memdisk_data_write(struct sbd_store *sst, uint64_t offset, uint64_t size,
-						uint8_t *buf)
-{
-	sbd_memdisk_t *smd = (sbd_memdisk_t *)sst->sst_store_private;
-
-	if ((offset + size) > smd->smd_size) {
-		return (STMF_FAILURE);
-	}
-
-	bcopy(buf, &smd->smd_buf[offset], (size_t)size);
-	return (STMF_SUCCESS);
-}
-
-/* ARGSUSED */
-stmf_status_t
-memdisk_data_flush(struct sbd_store *sst)
-{
-	return (STMF_SUCCESS);
-}
-
-/*
- * Creates and registers a LU
- */
-stmf_status_t
-memdisk_register_lu(register_lu_cmd_t *rlc)
-{
-	sbd_memdisk_t *smd;
-	sbd_store_t *sst;
-	sst_init_data_t sid;
-	stmf_status_t ret;
-
-	if (((rlc->lu_size < MEMDISK_MIN_SIZE) ||
-	    (rlc->lu_size > MEMDISK_MAX_SIZE)) &&
-	    ((rlc->flags & RLC_FORCE_OP) == 0)) {
-		rlc->return_code = RLC_RET_SIZE_OUT_OF_RANGE;
-		return (STMF_INVALID_ARG);
-	}
-	sst = sbd_sst_alloc(sizeof (sbd_memdisk_t), 0);
-	smd = (sbd_memdisk_t *)sst->sst_store_private;
-	smd->smd_size = rlc->lu_size;
-	smd->smd_buf = kmem_zalloc((size_t)smd->smd_size, KM_SLEEP);
-
-	sst->sst_online = memdisk_online;
-	sst->sst_offline = memdisk_offline;
-	sst->sst_deregister_lu = memdisk_deregister_lu;
-	sst->sst_data_read = memdisk_data_read;
-	sst->sst_data_write = memdisk_data_write;
-	sst->sst_data_flush = memdisk_data_flush;
-
-	sid.sst_store_size = smd->smd_size;
-	sid.sst_store_meta_data_size = 0;
-	sid.sst_flags = SST_NOT_PERSISTENT;
-	sid.sst_blocksize = 512;
-
-	if ((ret = sbd_create_meta(sst, &sid)) != STMF_SUCCESS) {
-		rlc->return_code = RLC_RET_META_CREATION_FAILED;
-		kmem_free(smd->smd_buf, (size_t)smd->smd_size);
-		sbd_sst_free(sst);
-		return (ret);
-	}
-
-	if ((ret = sbd_register_sst(sst, &sid)) != STMF_SUCCESS) {
-		rlc->return_code = RLC_RET_REGISTER_SST_FAILED;
-		kmem_free(smd->smd_buf, (size_t)smd->smd_size);
-		sbd_sst_free(sst);
-		return (ret);
-	}
-
-	rlc->lu_handle = (uint64_t)(unsigned long)sst->sst_sbd_private;
-
-	return (STMF_SUCCESS);
-}
-
-void
-memdisk_fillout_attr(struct sbd_store *sst, struct sbd_lu_attr *sla)
-{
-	if (sst->sst_data_read != memdisk_data_read)
-		return;
-
-	sla->flags = RLC_LU_TYPE_MEMDISK;
-}
-
-/* ARGSUSED */
-stmf_status_t
-memdisk_online(sbd_store_t *sst)
-{
-	return (STMF_SUCCESS);
-}
-
-/* ARGSUSED */
-stmf_status_t
-memdisk_offline(sbd_store_t *sst)
-{
-	return (STMF_SUCCESS);
-}
-
-stmf_status_t
-memdisk_deregister_lu(sbd_store_t *sst)
-{
-	stmf_status_t ret;
-	sbd_memdisk_t *smd;
-
-	if ((ret = sbd_deregister_sst(sst)) != STMF_SUCCESS)
-		return (ret);
-	smd = (sbd_memdisk_t *)sst->sst_store_private;
-	kmem_free(smd->smd_buf, smd->smd_size);
-	sbd_sst_free(sst);
-
-	return (STMF_SUCCESS);
-}
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c	Fri May 08 16:22:42 2009 -0600
@@ -32,8 +32,12 @@
 #include <sys/scsi/impl/scsi_reset_notify.h>
 #include <sys/disp.h>
 #include <sys/byteorder.h>
+#include <sys/pathname.h>
 #include <sys/atomic.h>
 #include <sys/nvpair.h>
+#include <sys/fs/zfs.h>
+#include <sys/sdt.h>
+#include <sys/dkio.h>
 
 #include <stmf.h>
 #include <lpif.h>
@@ -42,30 +46,47 @@
 #include <sbd_impl.h>
 #include <stmf_sbd_ioctl.h>
 
+
+extern sbd_status_t sbd_pgr_meta_write(sbd_lu_t *sl);
+extern sbd_status_t sbd_pgr_meta_load(sbd_lu_t *sl);
+
+static int sbd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
+    void **result);
 static int sbd_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
 static int sbd_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
-static int sbd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
-	void **result);
 static int sbd_open(dev_t *devp, int flag, int otype, cred_t *credp);
 static int sbd_close(dev_t dev, int flag, int otype, cred_t *credp);
 static int stmf_sbd_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
-	cred_t *credp, int *rval);
+    cred_t *credp, int *rval);
 void sbd_lp_cb(stmf_lu_provider_t *lp, int cmd, void *arg, uint32_t flags);
-uint8_t sbd_calc_sum(uint8_t *buf, int size);
-void sbd_swap_meta_start(sbd_meta_start_t *sm);
-void sbd_swap_section_hdr(sm_section_hdr_t *h, uint8_t data_order);
-void sbd_swap_sli_fields(sbd_lu_info_t *sli, uint8_t data_order);
-int sbd_migrate_meta_from_v0_to_v1(sbd_store_t *sst);
-
-extern struct mod_ops mod_driverops;
+int sbd_create_register_lu(sbd_create_and_reg_lu_t *slu, int struct_sz,
+    uint32_t *err_ret);
+int sbd_import_lu(sbd_import_lu_t *ilu, int struct_sz, uint32_t *err_ret,
+    int no_register, sbd_lu_t **slr);
+int sbd_delete_lu(sbd_delete_lu_t *dlu, int struct_sz, uint32_t *err_ret);
+int sbd_modify_lu(sbd_modify_lu_t *mlu, int struct_sz, uint32_t *err_ret);
+int sbd_get_lu_props(sbd_lu_props_t *islp, uint32_t islp_sz,
+    sbd_lu_props_t *oslp, uint32_t oslp_sz, uint32_t *err_ret);
+char *sbd_get_zvol_name(sbd_lu_t *sl);
+sbd_status_t sbd_create_zfs_meta_object(sbd_lu_t *sl);
+sbd_status_t sbd_open_zfs_meta(sbd_lu_t *sl);
+void sbd_close_zfs_meta(sbd_lu_t *sl);
+sbd_status_t sbd_read_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz,
+    uint64_t off);
+sbd_status_t sbd_write_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz,
+    uint64_t off);
+int sbd_is_zvol(char *path, vnode_t *vp);
+int sbd_is_sbd_zvol(char *path, vnode_t *vp);
 
 static stmf_lu_provider_t *sbd_lp;
-static dev_info_t *sbd_dip;
-static kmutex_t sbd_lock;
-sbd_lu_t	*sbd_lu_list = NULL;
-static int sbd_lu_count = 0;
+static sbd_lu_t		*sbd_lu_list = NULL;
+static kmutex_t		sbd_lock;
+static dev_info_t	*sbd_dip;
+static uint32_t		sbd_lu_count = 0;
+char sbd_vendor_id[]	= "SUN     ";
+char sbd_product_id[]	= "COMSTAR         ";
+char sbd_revision[]	= "1.0 ";
 static char sbd_name[] = "sbd";
-static uint64_t	sbd_meta_offset	= 4096; /* offset to skip label */
 
 static struct cb_ops sbd_cb_ops = {
 	sbd_open,			/* open */
@@ -164,14 +185,16 @@
 		}
 		mutex_exit(&sbd_lock);
 
+#if 0
 		/* ok start deregistering them */
 		while (sbd_lu_list) {
 			sbd_store_t *sst = sbd_lu_list->sl_sst;
 			if (sst->sst_deregister_lu(sst) != STMF_SUCCESS)
 				return (EBUSY);
 		}
+#endif
+		return (EBUSY);
 	}
-	ASSERT(sbd_lu_count == 0);
 	if (stmf_deregister_lu_provider(sbd_lp) != STMF_SUCCESS)
 		return (EBUSY);
 	ret = mod_remove(&modlinkage);
@@ -199,7 +222,7 @@
 		*result = sbd_dip;
 		break;
 	case DDI_INFO_DEVT2INSTANCE:
-		*result = (void *)(uintptr_t)ddi_get_instance(dip);
+		*result = (void *)(uintptr_t)ddi_get_instance(sbd_dip);
 		break;
 	default:
 		return (DDI_FAILURE);
@@ -254,255 +277,127 @@
 	return (0);
 }
 
-/*
- * The ioctl code will be re written once the lun mapping and masking
- * has been implemented and ioctl definitions have been cleanned up.
- */
-void *
-sbd_ioctl_read_struct(intptr_t data, int mode)
-{
-	void *ptr;
-	uint32_t s;
-
-	if (ddi_copyin((void *)data, &s, 4, mode))
-		return (NULL);
-	ptr = kmem_alloc(s, KM_SLEEP);
-	if (ddi_copyin((void *)data, ptr, s, mode))
-		return (NULL);
-	return (ptr);
-}
-
-int
-sbd_ioctl_write_struct(intptr_t data, int mode, void *ptr)
-{
-	int *s = (int *)ptr;
-	int ret = 0;
-
-	if (ddi_copyout(ptr, (void *)data, *s, mode)) {
-		ret = EFAULT;
-	}
-
-	kmem_free(ptr, *s);
-	return (ret);
-}
-
 /* ARGSUSED */
 static int
 stmf_sbd_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
 	cred_t *credp, int *rval)
 {
-	register_lu_cmd_t	*rlc;
-	deregister_lu_cmd_t	*drlc;
-	sbd_lu_list_t		*sll;
-	sbd_lu_attr_t		*sla;
-	sbd_lu_t		*slul;
-	void			*p;
-	int			ret = 0;
-	int			ret1;
-	int			cnt;
-	int			max_times, idx;
-	stmf_state_change_info_t ssi;
+	stmf_iocdata_t		*iocd;
+	void			*ibuf	= NULL;
+	void			*obuf	= NULL;
+	sbd_lu_t		*nsl;
+	int			i;
+	int			ret;
 
 	if (drv_priv(credp) != 0) {
 		return (EPERM);
 	}
 
-	ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
-	ssi.st_additional_info = NULL;
-	if ((cmd != SBD_REGISTER_LU) && (cmd != SBD_GET_LU_ATTR) &&
-	    (cmd != SBD_GET_LU_LIST) && (cmd != SBD_DEREGISTER_LU) &&
-	    (cmd != SBD_MODIFY_LU)) {
-		return (EINVAL);
-	}
-	if ((p = sbd_ioctl_read_struct(data, mode)) == NULL)
-		return (EFAULT);
+	ret = stmf_copyin_iocdata(data, mode, &iocd, &ibuf, &obuf);
+	if (ret)
+		return (ret);
+	iocd->stmf_error = 0;
 
 	switch (cmd) {
-	case SBD_REGISTER_LU:
-		rlc = (register_lu_cmd_t *)p;
-		((char *)p)[rlc->total_struct_size - 1] = 0;
-		if (rlc->flags & RLC_LU_TYPE_MEMDISK) {
-			if ((rlc->op_ret = memdisk_register_lu(rlc)) !=
-			    STMF_SUCCESS) {
-				ret = EIO;
-			}
-		} else if (rlc->flags & RLC_LU_TYPE_FILEDISK) {
-			if ((rlc->op_ret = filedisk_register_lu(rlc)) !=
-			    STMF_SUCCESS) {
-				ret = EIO;
-			}
-		} else {
+	case SBD_IOCTL_CREATE_AND_REGISTER_LU:
+		if (iocd->stmf_ibuf_size <
+		    (sizeof (sbd_create_and_reg_lu_t) - 8)) {
+			ret = EFAULT;
+			break;
+		}
+		if ((iocd->stmf_obuf_size == 0) ||
+		    (iocd->stmf_obuf_size > iocd->stmf_ibuf_size)) {
 			ret = EINVAL;
 			break;
 		}
+		ret = sbd_create_register_lu((sbd_create_and_reg_lu_t *)
+		    ibuf, iocd->stmf_ibuf_size, &iocd->stmf_error);
+		bcopy(ibuf, obuf, iocd->stmf_obuf_size);
 		break;
-	case SBD_MODIFY_LU: {
-		modify_lu_cmd_t *mlc = (modify_lu_cmd_t *)p;
-		sbd_lu_t *slu;
-		sbd_store_t *sst = NULL;
-		if ((mlc->flags & RLC_LU_TYPE_FILEDISK) == 0) {
+	case SBD_IOCTL_IMPORT_LU:
+		if (iocd->stmf_ibuf_size <
+		    (sizeof (sbd_import_lu_t) - 8)) {
+			ret = EFAULT;
+			break;
+		}
+		if ((iocd->stmf_obuf_size == 0) ||
+		    (iocd->stmf_obuf_size > iocd->stmf_ibuf_size)) {
+			ret = EINVAL;
+			break;
+		}
+		ret = sbd_import_lu((sbd_import_lu_t *)ibuf,
+		    iocd->stmf_ibuf_size, &iocd->stmf_error, 0, NULL);
+		bcopy(ibuf, obuf, iocd->stmf_obuf_size);
+		break;
+	case SBD_IOCTL_DELETE_LU:
+		if (iocd->stmf_ibuf_size < (sizeof (sbd_delete_lu_t) - 8)) {
+			ret = EFAULT;
+			break;
+		}
+		if (iocd->stmf_obuf_size) {
 			ret = EINVAL;
 			break;
 		}
-		if (mlc->name[0] != '\0') {
-			mutex_enter(&sbd_lock);
-			for (slu = sbd_lu_list; slu != NULL;
-			    slu = slu->sl_next) {
-				if (strcmp(slu->sl_sst->sst_alias,
-				    mlc->name) == 0)
-					break;
-			}
-			mutex_exit(&sbd_lock);
-			if (slu == NULL) {
-				/* not registered */
-				sst = NULL;
-			} else {
-				sst = slu->sl_sst;
-			}
-		} else {
-			mutex_enter(&sbd_lock);
-			for (slu = sbd_lu_list; slu != NULL;
-			    slu = slu->sl_next) {
-				if (bcmp(slu->sl_lu->lu_id->ident,
-				    mlc->guid, 16) == 0)
-					break;
-			}
-			mutex_exit(&sbd_lock);
-			if (slu == NULL) {
-				/* not registered, this is not allowed */
-				ret = ENODEV;
-				break;
-			}
-			sst = slu->sl_sst;
-		}
-
-		mlc->op_ret = filedisk_modify_lu(sst, mlc);
-		if (mlc->op_ret != STMF_SUCCESS) {
-			ret = EIO;
-		}
-		}
+		ret = sbd_delete_lu((sbd_delete_lu_t *)ibuf,
+		    iocd->stmf_ibuf_size, &iocd->stmf_error);
 		break;
-
-	case SBD_DEREGISTER_LU:
-		drlc = (deregister_lu_cmd_t *)p;
-
-		mutex_enter(&sbd_lock);
-		for (slul = sbd_lu_list; slul != NULL; slul = slul->sl_next) {
-			ret1 = bcmp(drlc->guid, slul->sl_lu->lu_id->ident, 16);
-			if (ret1 == 0) {
-				break;
-			}
-		}
-
-		if (slul == NULL) {
-			mutex_exit(&sbd_lock);
-
-			stmf_trace(0, "sbd_ioctl: can't find specified LU");
-			ret = ENODEV;
+	case SBD_IOCTL_MODIFY_LU:
+		if (iocd->stmf_ibuf_size < (sizeof (sbd_modify_lu_t) - 8)) {
+			ret = EFAULT;
 			break;
 		}
-
-		if ((slul->sl_state == STMF_STATE_OFFLINE) &&
-		    !slul->sl_state_not_acked) {
-			mutex_exit(&sbd_lock);
-
-			goto do_lu_dereg;
-		}
-
-		if (slul->sl_state != STMF_STATE_ONLINE) {
-			mutex_exit(&sbd_lock);
-
-			ret = EBUSY;
+		if (iocd->stmf_obuf_size) {
+			ret = EINVAL;
 			break;
 		}
-		mutex_exit(&sbd_lock);
-
-		ssi.st_additional_info = "DEREGLU offline LU now";
-		(void) stmf_ctl(STMF_CMD_LU_OFFLINE, slul->sl_lu, &ssi);
-		max_times = 50;
-
-		mutex_enter(&sbd_lock);
-		for (idx = 0; idx < max_times; idx++) {
-			if ((slul->sl_state == STMF_STATE_OFFLINE) &&
-			    !slul->sl_state_not_acked) {
-				break;
-			}
-			mutex_exit(&sbd_lock);
-
-			delay(drv_usectohz(100000));
-
-			mutex_enter(&sbd_lock);
+		ret = sbd_modify_lu((sbd_modify_lu_t *)ibuf,
+		    iocd->stmf_ibuf_size, &iocd->stmf_error);
+		break;
+	case SBD_IOCTL_GET_LU_PROPS:
+		if (iocd->stmf_ibuf_size < (sizeof (sbd_lu_props_t) - 8)) {
+			ret = EFAULT;
+			break;
 		}
-		mutex_exit(&sbd_lock);
-
-		if (idx == max_times) {
-			stmf_trace(0, "sbd_ioctl: LU-%p can't go off", slul);
-			ret = ETIMEDOUT;
-		} else {
-do_lu_dereg:
-			if (slul->sl_sst->sst_deregister_lu(slul->sl_sst) !=
-			    STMF_SUCCESS) {
-				stmf_trace(0, "sbd_ioctl: sst_degregister_lu "
-				    "sst-%p failed", slul->sl_sst);
-				ret = ENOTSUP;
-			}
-		}
-		break;
-
-	case SBD_GET_LU_LIST:
-		sll = (sbd_lu_list_t *)p;
-		cnt = sll->total_struct_size - sizeof (sbd_lu_list_t);
-		if (cnt < 0) {
+		if (iocd->stmf_obuf_size < sizeof (sbd_lu_props_t)) {
 			ret = EINVAL;
 			break;
 		}
-		cnt = (cnt >> 3) + 1;
-		if (sll->count_in > cnt) {
-			ret = EFAULT;
-			break;
-		}
+		ret = sbd_get_lu_props((sbd_lu_props_t *)ibuf,
+		    iocd->stmf_ibuf_size, (sbd_lu_props_t *)obuf,
+		    iocd->stmf_obuf_size, &iocd->stmf_error);
+		break;
+	case SBD_IOCTL_GET_LU_LIST:
 		mutex_enter(&sbd_lock);
-		sll->count_out = 0;
-		for (slul = sbd_lu_list; slul != NULL; slul = slul->sl_next) {
-			if (sll->count_out < sll->count_in) {
-				sll->handles[sll->count_out] =
-				    (uint64_t)(unsigned long)slul;
-			}
-			sll->count_out++;
+		iocd->stmf_obuf_max_nentries = sbd_lu_count;
+		iocd->stmf_obuf_nentries = min((iocd->stmf_obuf_size >> 4),
+		    sbd_lu_count);
+		for (nsl = sbd_lu_list, i = 0; nsl &&
+		    (i < iocd->stmf_obuf_nentries); i++, nsl = nsl->sl_next) {
+			bcopy(nsl->sl_device_id + 4,
+			    &(((uint8_t *)obuf)[i << 4]), 16);
 		}
 		mutex_exit(&sbd_lock);
+		ret = 0;
+		iocd->stmf_error = 0;
 		break;
-	case SBD_GET_LU_ATTR:
-		sla = (sbd_lu_attr_t *)p;
-		if (sla->total_struct_size <
-		    (sizeof (sbd_lu_attr_t) + sla->max_name_length - 7)) {
-			ret = EFAULT;
-			break;
-		}
-		mutex_enter(&sbd_lock);
-		for (slul = sbd_lu_list; slul != NULL; slul = slul->sl_next) {
-			if (sla->lu_handle == (uint64_t)(unsigned long)slul)
-				break;
-		}
-		if (slul != NULL) {
-			filedisk_fillout_attr(slul->sl_sst, sla);
-			memdisk_fillout_attr(slul->sl_sst, sla);
-			sla->total_size = slul->sl_sli->sli_total_store_size;
-			sla->data_size = slul->sl_sli->sli_lu_data_size;
-			bcopy(slul->sl_lu->lu_id->ident, sla->guid, 16);
-		} else {
-			ret = EINVAL;
-		}
-		mutex_exit(&sbd_lock);
-		break;
-
 	default:
-		return (ENOTTY);
+		ret = ENOTTY;
 	}
 
-	ret1 = sbd_ioctl_write_struct(data, mode, p);
-	if (!ret)
-		ret = ret1;
+	if (ret == 0) {
+		ret = stmf_copyout_iocdata(data, mode, iocd, obuf);
+	} else if (iocd->stmf_error) {
+		(void) stmf_copyout_iocdata(data, mode, iocd, obuf);
+	}
+	if (obuf) {
+		kmem_free(obuf, iocd->stmf_obuf_size);
+		obuf = NULL;
+	}
+	if (ibuf) {
+		kmem_free(ibuf, iocd->stmf_ibuf_size);
+		ibuf = NULL;
+	}
+	kmem_free(iocd, sizeof (stmf_iocdata_t));
 	return (ret);
 }
 
@@ -510,11 +405,13 @@
 void
 sbd_lp_cb(stmf_lu_provider_t *lp, int cmd, void *arg, uint32_t flags)
 {
-	nvpair_t *np;
-	register_lu_cmd_t *rlc = NULL;
-	char *s;
-	int rlc_size = 0;
-	int sn;
+	nvpair_t	*np;
+	char		*s;
+	sbd_import_lu_t *ilu;
+	uint32_t	ilu_sz;
+	uint32_t	struct_sz;
+	uint32_t	err_ret;
+	int		iret;
 
 	if ((cmd != STMF_PROVIDER_DATA_UPDATED) || (arg == NULL)) {
 		return;
@@ -525,6 +422,8 @@
 	}
 
 	np = NULL;
+	ilu_sz = 1024;
+	ilu = (sbd_import_lu_t *)kmem_zalloc(ilu_sz, KM_SLEEP);
 	while ((np = nvlist_next_nvpair((nvlist_t *)arg, np)) != NULL) {
 		if (nvpair_type(np) != DATA_TYPE_STRING) {
 			continue;
@@ -532,133 +431,241 @@
 		if (nvpair_value_string(np, &s) != 0) {
 			continue;
 		}
-		sn = sizeof (register_lu_cmd_t) - 8 + strlen(s) + 1;
-		if (sn > rlc_size) {
-			if (rlc_size) {
-				kmem_free(rlc, rlc_size);
-			}
-			rlc_size = sn + 32; /* Make it a little bigger */
-			rlc = (register_lu_cmd_t *)kmem_zalloc(rlc_size,
-			    KM_SLEEP);
+		struct_sz = max(8, strlen(s) + 1);
+		struct_sz += sizeof (sbd_import_lu_t) - 8;
+		if (struct_sz > ilu_sz) {
+			kmem_free(ilu, ilu_sz);
+			ilu_sz = struct_sz + 32;
+			ilu = (sbd_import_lu_t *)kmem_zalloc(ilu_sz, KM_SLEEP);
 		}
-		bzero(rlc, rlc_size);
-		rlc->total_struct_size = rlc_size;
-		rlc->flags = RLC_LU_TYPE_FILEDISK | RLC_REGISTER_LU;
-		(void) strcpy(rlc->name, s);
-		(void) filedisk_register_lu(rlc);
+		ilu->ilu_struct_size = struct_sz;
+		(void) strcpy(ilu->ilu_meta_fname, s);
+		iret = sbd_import_lu(ilu, struct_sz, &err_ret, 0, NULL);
+		if (iret) {
+			stmf_trace(0, "sbd_lp_cb: import_lu failed, ret = %d, "
+			    "err_ret = %d", iret, err_ret);
+		} else {
+			stmf_trace(0, "Imported the LU %s", nvpair_name(np));
+		}
 	}
 
-	if (rlc) {
-		kmem_free(rlc, rlc_size);
+	if (ilu) {
+		kmem_free(ilu, ilu_sz);
+		ilu = NULL;
 	}
 }
 
-/* ARGSUSED */
-sbd_store_t *
-sbd_sst_alloc(uint32_t additional_size, uint32_t flags)
+sbd_status_t
+sbd_link_lu(sbd_lu_t *sl)
 {
-	uint32_t total_as;
-	sbd_store_t *sst;
-	stmf_lu_t *lu;
-	sbd_lu_t *slu;
+	sbd_lu_t *nsl;
 
-	total_as = GET_STRUCT_SIZE(sbd_store_t) + GET_STRUCT_SIZE(sbd_lu_t) +
-	    ((additional_size + 7) & ~7);
+	mutex_enter(&sbd_lock);
+	mutex_enter(&sl->sl_lock);
+	ASSERT(sl->sl_trans_op != SL_OP_NONE);
 
-	lu = (stmf_lu_t *)stmf_alloc(STMF_STRUCT_STMF_LU, total_as, 0);
-	if (lu == NULL)
-		return (NULL);
-	sst = (sbd_store_t *)lu->lu_provider_private;
-	sst->sst_sbd_private = GET_BYTE_OFFSET(sst,
-	    GET_STRUCT_SIZE(sbd_store_t));
-	sst->sst_store_private = GET_BYTE_OFFSET(sst->sst_sbd_private,
-	    GET_STRUCT_SIZE(sbd_lu_t));
-	slu = (sbd_lu_t *)sst->sst_sbd_private;
-	slu->sl_sst = sst;
-	slu->sl_lu = lu;
-	slu->sl_total_allocation_size = total_as;
-	mutex_init(&slu->sl_it_list_lock, NULL, MUTEX_DRIVER, NULL);
-
-	return (sst);
+	if (sl->sl_flags & SL_LINKED) {
+		mutex_exit(&sbd_lock);
+		mutex_exit(&sl->sl_lock);
+		return (SBD_ALREADY);
+	}
+	for (nsl = sbd_lu_list; nsl; nsl = nsl->sl_next) {
+		if (strcmp(nsl->sl_name, sl->sl_name) == 0)
+			break;
+	}
+	if (nsl) {
+		mutex_exit(&sbd_lock);
+		mutex_exit(&sl->sl_lock);
+		return (SBD_ALREADY);
+	}
+	sl->sl_next = sbd_lu_list;
+	sbd_lu_list = sl;
+	sl->sl_flags |= SL_LINKED;
+	mutex_exit(&sbd_lock);
+	mutex_exit(&sl->sl_lock);
+	return (SBD_SUCCESS);
 }
 
 void
-sbd_sst_free(sbd_store_t *sst)
+sbd_unlink_lu(sbd_lu_t *sl)
+{
+	sbd_lu_t **ppnsl;
+
+	mutex_enter(&sbd_lock);
+	mutex_enter(&sl->sl_lock);
+	ASSERT(sl->sl_trans_op != SL_OP_NONE);
+
+	ASSERT(sl->sl_flags & SL_LINKED);
+	for (ppnsl = &sbd_lu_list; *ppnsl; ppnsl = &((*ppnsl)->sl_next)) {
+		if (*ppnsl == sl)
+			break;
+	}
+	ASSERT(*ppnsl);
+	*ppnsl = (*ppnsl)->sl_next;
+	sl->sl_flags &= ~SL_LINKED;
+	mutex_exit(&sbd_lock);
+	mutex_exit(&sl->sl_lock);
+}
+
+sbd_status_t
+sbd_find_and_lock_lu(uint8_t *guid, uint8_t *meta_name, uint8_t op,
+    sbd_lu_t **ppsl)
 {
-	sbd_lu_t *slu = (sbd_lu_t *)sst->sst_sbd_private;
+	sbd_lu_t *sl;
+	int found = 0;
+	sbd_status_t sret;
 
-	mutex_destroy(&slu->sl_it_list_lock);
-	stmf_free(slu->sl_lu);
+	mutex_enter(&sbd_lock);
+	for (sl = sbd_lu_list; sl; sl = sl->sl_next) {
+		if (guid) {
+			found = bcmp(sl->sl_device_id + 4, guid, 16) == 0;
+		} else {
+			found = strcmp(sl->sl_name, (char *)meta_name) == 0;
+		}
+		if (found)
+			break;
+	}
+	if (!found) {
+		mutex_exit(&sbd_lock);
+		return (SBD_NOT_FOUND);
+	}
+	mutex_enter(&sl->sl_lock);
+	if (sl->sl_trans_op == SL_OP_NONE) {
+		sl->sl_trans_op = op;
+		*ppsl = sl;
+		sret = SBD_SUCCESS;
+	} else {
+		sret = SBD_BUSY;
+	}
+	mutex_exit(&sl->sl_lock);
+	mutex_exit(&sbd_lock);
+	return (sret);
 }
 
-#define	DATA_ALIGNMENT		0xfffffffffffff000
-#define	DATA_BLOCK_SIZE		4 * 1024
-
-stmf_status_t
-sbd_aligned_meta_write(struct sbd_store *sst, uint64_t offset,
-    uint64_t size, uint8_t *buf)
+sbd_status_t
+sbd_read_meta(sbd_lu_t *sl, uint64_t offset, uint64_t size, uint8_t *buf)
 {
-	uint64_t starting_off = offset & DATA_ALIGNMENT;
-	uint64_t off_from_starting = offset & (~DATA_ALIGNMENT);
-	uint64_t ending_off =
-	    (offset + size + DATA_BLOCK_SIZE) & DATA_ALIGNMENT;
-	uint64_t op_size = ending_off - starting_off;
-	uint8_t *op_buf = (uint8_t *)kmem_zalloc(op_size, KM_SLEEP);
-	stmf_status_t ret;
+	uint64_t	meta_align;
+	uint64_t	starting_off;
+	uint64_t	data_off;
+	uint64_t	ending_off;
+	uint64_t	io_size;
+	uint8_t		*io_buf;
+	vnode_t		*vp;
+	sbd_status_t	ret;
+	ssize_t		resid;
+	int		vret;
 
-	/* we should read first to avoid overwrite other data */
-	if (sst->sst_meta_read) {
-		ret = sst->sst_meta_read(sst, starting_off,
-		    op_size, (uint8_t *)op_buf);
+	ASSERT(sl->sl_flags & SL_META_OPENED);
+	if (sl->sl_flags & SL_SHARED_META) {
+		meta_align = (((uint64_t)1) << sl->sl_data_blocksize_shift) - 1;
+		vp = sl->sl_data_vp;
+		ASSERT(vp);
 	} else {
-		ret = sst->sst_data_read(sst, starting_off,
-		    op_size, (uint8_t *)op_buf);
+		meta_align = (((uint64_t)1) << sl->sl_meta_blocksize_shift) - 1;
+		if ((sl->sl_flags & SL_ZFS_META) == 0) {
+			vp = sl->sl_meta_vp;
+			ASSERT(vp);
+		}
 	}
-	if (ret != STMF_SUCCESS)
-		goto aligned_write_ret;
-
-	bcopy(buf, op_buf + off_from_starting, size);
+	starting_off = offset & ~(meta_align);
+	data_off = offset & meta_align;
+	ending_off = (offset + size + meta_align) & (~meta_align);
+	if (ending_off > sl->sl_meta_size_used) {
+		bzero(buf, size);
+		if (starting_off >= sl->sl_meta_size_used) {
+			return (SBD_SUCCESS);
+		}
+		ending_off = (sl->sl_meta_size_used + meta_align) &
+		    (~meta_align);
+		if (size > (ending_off - (starting_off + data_off))) {
+			size = ending_off - (starting_off + data_off);
+		}
+	}
+	io_size = ending_off - starting_off;
+	io_buf = (uint8_t *)kmem_zalloc(io_size, KM_SLEEP);
+	ASSERT((starting_off + io_size) <= sl->sl_total_meta_size);
 
-	if (sst->sst_meta_write) {
-		ret = sst->sst_meta_write(sst, starting_off,
-		    op_size, (uint8_t *)op_buf);
+	if (sl->sl_flags & SL_ZFS_META) {
+		if ((ret = sbd_read_zfs_meta(sl, io_buf, io_size,
+		    starting_off)) != SBD_SUCCESS) {
+			goto sbd_read_meta_failure;
+		}
 	} else {
-		ret = sst->sst_data_write(sst, starting_off,
-		    op_size, (uint8_t *)op_buf);
+		vret = vn_rdwr(UIO_READ, vp, (caddr_t)io_buf, (ssize_t)io_size,
+		    (offset_t)starting_off, UIO_SYSSPACE, FRSYNC,
+		    RLIM64_INFINITY, CRED(), &resid);
+
+		if (vret || resid) {
+			ret = SBD_FILEIO_FAILURE | vret;
+			goto sbd_read_meta_failure;
+		}
 	}
 
-aligned_write_ret:
-	if (op_buf)
-		kmem_free(op_buf, op_size);
+	bcopy(io_buf + data_off, buf, size);
+	ret = SBD_SUCCESS;
+
+sbd_read_meta_failure:
+	kmem_free(io_buf, io_size);
 	return (ret);
 }
 
-stmf_status_t
-sbd_aligned_meta_read(struct sbd_store *sst, uint64_t offset,
-    uint64_t size, uint8_t *buf)
+sbd_status_t
+sbd_write_meta(sbd_lu_t *sl, uint64_t offset, uint64_t size, uint8_t *buf)
 {
-	uint64_t starting_off = offset & DATA_ALIGNMENT;
-	uint64_t off_from_starting = offset & (~DATA_ALIGNMENT);
-	uint64_t ending_off =
-	    (offset + size + DATA_BLOCK_SIZE) & DATA_ALIGNMENT;
-	uint64_t op_size = ending_off - starting_off;
-	uint8_t *op_buf = (uint8_t *)kmem_zalloc(op_size, KM_SLEEP);
-	stmf_status_t ret;
+	uint64_t	meta_align;
+	uint64_t	starting_off;
+	uint64_t	data_off;
+	uint64_t	ending_off;
+	uint64_t	io_size;
+	uint8_t		*io_buf;
+	vnode_t		*vp;
+	sbd_status_t	ret;
+	ssize_t		resid;
+	int		vret;
 
-	if (sst->sst_meta_read) {
-		ret = sst->sst_meta_read(sst, starting_off,
-		    op_size, (uint8_t *)op_buf);
+	ASSERT(sl->sl_flags & SL_META_OPENED);
+	if (sl->sl_flags & SL_SHARED_META) {
+		meta_align = (((uint64_t)1) << sl->sl_data_blocksize_shift) - 1;
+		vp = sl->sl_data_vp;
+		ASSERT(vp);
 	} else {
-		ret = sst->sst_data_read(sst, starting_off,
-		    op_size, (uint8_t *)op_buf);
+		meta_align = (((uint64_t)1) << sl->sl_meta_blocksize_shift) - 1;
+		if ((sl->sl_flags & SL_ZFS_META) == 0) {
+			vp = sl->sl_meta_vp;
+			ASSERT(vp);
+		}
+	}
+	starting_off = offset & ~(meta_align);
+	data_off = offset & meta_align;
+	ending_off = (offset + size + meta_align) & (~meta_align);
+	io_size = ending_off - starting_off;
+	io_buf = (uint8_t *)kmem_zalloc(io_size, KM_SLEEP);
+	ret = sbd_read_meta(sl, starting_off, io_size, io_buf);
+	if (ret != SBD_SUCCESS) {
+		goto sbd_write_meta_failure;
 	}
-	if (ret != STMF_SUCCESS)
-		goto aligned_read_ret;
-	bcopy(op_buf + off_from_starting, buf, size);
+	bcopy(buf, io_buf + data_off, size);
+	if (sl->sl_flags & SL_ZFS_META) {
+		if ((ret = sbd_write_zfs_meta(sl, io_buf, io_size,
+		    starting_off)) != SBD_SUCCESS) {
+			goto sbd_write_meta_failure;
+		}
+	} else {
+		vret = vn_rdwr(UIO_WRITE, vp, (caddr_t)io_buf, (ssize_t)io_size,
+		    (offset_t)starting_off, UIO_SYSSPACE, FDSYNC,
+		    RLIM64_INFINITY, CRED(), &resid);
 
-aligned_read_ret:
-	if (op_buf)
-		kmem_free(op_buf, op_size);
+		if (vret || resid) {
+			ret = SBD_FILEIO_FAILURE | vret;
+			goto sbd_write_meta_failure;
+		}
+	}
+
+	ret = SBD_SUCCESS;
+
+sbd_write_meta_failure:
+	kmem_free(io_buf, io_size);
 	return (ret);
 }
 
@@ -673,9 +680,36 @@
 	return (s);
 }
 
+uint8_t
+sbd_calc_section_sum(sm_section_hdr_t *sm, uint32_t sz)
+{
+	uint8_t s, o;
+
+	o = sm->sms_chksum;
+	sm->sms_chksum = 0;
+	s = sbd_calc_sum((uint8_t *)sm, sz);
+	sm->sms_chksum = o;
+
+	return (s);
+}
+
+uint32_t
+sbd_strlen(char *str, uint32_t maxlen)
+{
+	uint32_t i;
+
+	for (i = 0; i < maxlen; i++) {
+		if (str[i] == 0)
+			return (i);
+	}
+	return (i);
+}
+
 void
 sbd_swap_meta_start(sbd_meta_start_t *sm)
 {
+	if (sm->sm_magic == SBD_MAGIC)
+		return;
 	sm->sm_magic		= BSWAP_64(sm->sm_magic);
 	sm->sm_meta_size	= BSWAP_64(sm->sm_meta_size);
 	sm->sm_meta_size_used	= BSWAP_64(sm->sm_meta_size_used);
@@ -685,394 +719,446 @@
 }
 
 void
-sbd_swap_section_hdr(sm_section_hdr_t *h, uint8_t data_order)
+sbd_swap_section_hdr(sm_section_hdr_t *sm)
 {
-	h->sms_offset		= BSWAP_64(h->sms_offset);
-	h->sms_size		= BSWAP_32(h->sms_size);
-	h->sms_id		= BSWAP_16(h->sms_id);
-	h->sms_data_order	= data_order;
+	if (sm->sms_data_order == SMS_DATA_ORDER)
+		return;
+	sm->sms_offset		= BSWAP_64(sm->sms_offset);
+	sm->sms_size		= BSWAP_32(sm->sms_size);
+	sm->sms_id		= BSWAP_16(sm->sms_id);
+	sm->sms_chksum		+= SMS_DATA_ORDER - sm->sms_data_order;
+	sm->sms_data_order	= SMS_DATA_ORDER;
+}
+
+void
+sbd_swap_lu_info_1_0(sbd_lu_info_1_0_t *sli)
+{
+	sbd_swap_section_hdr(&sli->sli_sms_header);
+	if (sli->sli_data_order == SMS_DATA_ORDER)
+		return;
+	sli->sli_sms_header.sms_chksum	+= SMS_DATA_ORDER - sli->sli_data_order;
+	sli->sli_data_order		= SMS_DATA_ORDER;
+	sli->sli_total_store_size	= BSWAP_64(sli->sli_total_store_size);
+	sli->sli_total_meta_size	= BSWAP_64(sli->sli_total_meta_size);
+	sli->sli_lu_data_offset		= BSWAP_64(sli->sli_lu_data_offset);
+	sli->sli_lu_data_size		= BSWAP_64(sli->sli_lu_data_size);
+	sli->sli_flags			= BSWAP_32(sli->sli_flags);
+	sli->sli_blocksize		= BSWAP_16(sli->sli_blocksize);
 }
 
 void
-sbd_swap_sli_fields(sbd_lu_info_t *sli, uint8_t data_order)
-{
-	sli->sli_total_store_size = BSWAP_64(sli->sli_total_store_size);
-	sli->sli_total_meta_size = BSWAP_64(sli->sli_total_meta_size);
-	sli->sli_lu_data_offset = BSWAP_64(sli->sli_lu_data_offset);
-	sli->sli_lu_data_size = BSWAP_64(sli->sli_lu_data_size);
-	sli->sli_flags = BSWAP_32(sli->sli_flags);
-	sli->sli_blocksize = BSWAP_16(sli->sli_blocksize);
-	sli->sli_data_order = data_order;
-}
-
-/*
- * will not modify sms.
- */
-uint64_t
-sbd_find_section_offset(sbd_store_t *sst, sm_section_hdr_t *sms)
+sbd_swap_lu_info_1_1(sbd_lu_info_1_1_t *sli)
 {
-	stmf_status_t ret;
-	sbd_lu_t *slu = (sbd_lu_t *)sst->sst_sbd_private;
-	uint64_t ssize;
-	uint64_t meta_end;
-	sm_section_hdr_t smsh;
-
-	if (slu->sl_sm.sm_magic != SBD_MAGIC) {
-		cmn_err(CE_PANIC, "sbd_find section called without reading the"
-		    " header first.");
-	}
-
-	ssize = slu->sl_meta_offset + sizeof (sbd_meta_start_t);
-	meta_end = slu->sl_sm.sm_meta_size_used;
-	while (ssize < meta_end) {
-		ret = sbd_aligned_meta_read(sst, ssize,
-		    sizeof (sm_section_hdr_t), (uint8_t *)&smsh);
-		if (ret != STMF_SUCCESS)
-			return (0);
-		if (smsh.sms_data_order != sms->sms_data_order) {
-			sbd_swap_section_hdr(&smsh, sms->sms_data_order);
-		}
-		if (smsh.sms_id == sms->sms_id)
-			return (smsh.sms_offset);
-		ssize += smsh.sms_size;
-	}
-
-	return (0);
+	sbd_swap_section_hdr(&sli->sli_sms_header);
+	if (sli->sli_data_order == SMS_DATA_ORDER)
+		return;
+	sli->sli_sms_header.sms_chksum	+= SMS_DATA_ORDER - sli->sli_data_order;
+	sli->sli_data_order		= SMS_DATA_ORDER;
+	sli->sli_flags			= BSWAP_32(sli->sli_flags);
+	sli->sli_lu_size		= BSWAP_64(sli->sli_lu_size);
+	sli->sli_meta_fname_offset	= BSWAP_16(sli->sli_meta_fname_offset);
+	sli->sli_data_fname_offset	= BSWAP_16(sli->sli_data_fname_offset);
+	sli->sli_serial_offset		= BSWAP_16(sli->sli_serial_offset);
+	sli->sli_alias_offset		= BSWAP_16(sli->sli_alias_offset);
 }
 
-stmf_status_t
-sbd_read_section(sbd_store_t *sst, sm_section_hdr_t *sms)
+sbd_status_t
+sbd_load_section_hdr(sbd_lu_t *sl, sm_section_hdr_t *sms)
 {
-	stmf_status_t			ret;
-	uint32_t			sz;
-	uint8_t				osum, nsum;
-
-	if (sms->sms_offset == 0) {
-		sms->sms_offset = sbd_find_section_offset(sst, sms);
-		if (sms->sms_offset == 0)
-			return (STMF_FAILURE);
-	}
-	sz = sms->sms_size;
-
-	ret = sbd_aligned_meta_read(sst, sms->sms_offset,
-	    sms->sms_size, (uint8_t *)sms);
-	if (ret != STMF_SUCCESS)
-		return (ret);
-
-	osum = sms->sms_chksum;
-	sms->sms_chksum = 0;
-	nsum = sbd_calc_sum((uint8_t *)sms, sz);
-	sms->sms_chksum = osum;
-	if (osum != nsum) {
-		return (STMF_FAILURE);
-	}
-	if (sms->sms_data_order != SMS_DATA_ORDER) {
-		/* Adjust byte order of the header */
-		sbd_swap_section_hdr(sms, SMS_DATA_ORDER);
-	}
+	sm_section_hdr_t h;
+	uint64_t st;
+	sbd_status_t ret;
 
-	return (STMF_SUCCESS);
-}
-
-stmf_status_t
-sbd_write_section(sbd_store_t *sst, sm_section_hdr_t *sms)
-{
-	stmf_status_t		ret;
-	sbd_lu_t		*slu = (sbd_lu_t *)sst->sst_sbd_private;
-	sbd_lu_info_t		*sli = slu->sl_sli;
-
-	if (sms->sms_offset == 0) {
-		sms->sms_offset = sbd_find_section_offset(sst, sms);
-		if (sms->sms_offset == 0) {
-			if (sli->sli_total_meta_size <
-			    (slu->sl_sm.sm_meta_size_used + sms->sms_size)) {
-				return (STMF_FAILURE);
-			}
-			sms->sms_offset = slu->sl_sm.sm_meta_size_used;
-			slu->sl_sm.sm_meta_size_used += sms->sms_size;
-			slu->sl_sm.sm_chksum = 0;
-			slu->sl_sm.sm_chksum = sbd_calc_sum((uint8_t *)
-			    &slu->sl_sm, sizeof (sbd_meta_start_t));
-			ret = sbd_aligned_meta_write(sst, slu->sl_meta_offset,
-			    sizeof (sbd_meta_start_t), (uint8_t *)&slu->sl_sm);
-			if (ret != STMF_SUCCESS) {
-				slu->sl_sm.sm_meta_size_used -= sms->sms_size;
-				slu->sl_sm.sm_chksum = 0;
-				slu->sl_sm.sm_chksum = sbd_calc_sum((uint8_t *)
-				    &slu->sl_sm, sizeof (sbd_meta_start_t));
-				return (STMF_FAILURE);
-			}
+	for (st = SBD_META_OFFSET + sizeof (sbd_meta_start_t);
+	    st < sl->sl_meta_size_used; st += h.sms_size) {
+		if ((ret = sbd_read_meta(sl, st, sizeof (sm_section_hdr_t),
+		    (uint8_t *)&h)) != SBD_SUCCESS) {
+			return (ret);
+		}
+		if (h.sms_data_order != SMS_DATA_ORDER) {
+			sbd_swap_section_hdr(&h);
+		}
+		if ((h.sms_data_order != SMS_DATA_ORDER) ||
+		    (h.sms_offset != st) || (h.sms_size < sizeof (h)) ||
+		    ((st + h.sms_size) > sl->sl_meta_size_used)) {
+			return (SBD_META_CORRUPTED);
+		}
+		if (h.sms_id == sms->sms_id) {
+			bcopy(&h, sms, sizeof (h));
+			return (SBD_SUCCESS);
 		}
 	}
 
-	sms->sms_chksum = 0;
-	sms->sms_chksum = sbd_calc_sum((uint8_t *)sms, sms->sms_size);
-	ret = sbd_aligned_meta_write(sst, sms->sms_offset,
-	    sms->sms_size, (uint8_t *)sms);
+	return (SBD_NOT_FOUND);
+}
+
+sbd_status_t
+sbd_load_meta_start(sbd_lu_t *sl)
+{
+	sbd_meta_start_t *sm;
+	sbd_status_t ret;
+
+	/* Fake meta params initially */
+	sl->sl_total_meta_size = (uint64_t)-1;
+	sl->sl_meta_size_used = SBD_META_OFFSET + sizeof (sbd_meta_start_t);
+
+	sm = kmem_zalloc(sizeof (*sm), KM_SLEEP);
+	ret = sbd_read_meta(sl, SBD_META_OFFSET, sizeof (*sm), (uint8_t *)sm);
+	if (ret != SBD_SUCCESS) {
+		goto load_meta_start_failed;
+	}
+
+	if (sm->sm_magic != SBD_MAGIC) {
+		sbd_swap_meta_start(sm);
+	}
+
+	if ((sm->sm_magic != SBD_MAGIC) || (sbd_calc_sum((uint8_t *)sm,
+	    sizeof (*sm) - 1) != sm->sm_chksum)) {
+		ret = SBD_META_CORRUPTED;
+		goto load_meta_start_failed;
+	}
+
+	if (sm->sm_ver_major != SBD_VER_MAJOR) {
+		ret = SBD_NOT_SUPPORTED;
+		goto load_meta_start_failed;
+	}
+
+	sl->sl_total_meta_size = sm->sm_meta_size;
+	sl->sl_meta_size_used = sm->sm_meta_size_used;
+	ret = SBD_SUCCESS;
+
+load_meta_start_failed:
+	kmem_free(sm, sizeof (*sm));
+	return (ret);
+}
+
+sbd_status_t
+sbd_write_meta_start(sbd_lu_t *sl, uint64_t meta_size, uint64_t meta_size_used)
+{
+	sbd_meta_start_t *sm;
+	sbd_status_t ret;
+
+	sm = (sbd_meta_start_t *)kmem_zalloc(sizeof (sbd_meta_start_t),
+	    KM_SLEEP);
+
+	sm->sm_magic = SBD_MAGIC;
+	sm->sm_meta_size = meta_size;
+	sm->sm_meta_size_used = meta_size_used;
+	sm->sm_ver_major = SBD_VER_MAJOR;
+	sm->sm_ver_minor = SBD_VER_MINOR;
+	sm->sm_ver_subminor = SBD_VER_SUBMINOR;
+	sm->sm_chksum = sbd_calc_sum((uint8_t *)sm, sizeof (*sm) - 1);
+
+	ret = sbd_write_meta(sl, SBD_META_OFFSET, sizeof (*sm), (uint8_t *)sm);
+	kmem_free(sm, sizeof (*sm));
 
 	return (ret);
 }
 
-stmf_status_t
-sbd_create_meta(sbd_store_t *sst, sst_init_data_t *sst_idata)
+sbd_status_t
+sbd_read_meta_section(sbd_lu_t *sl, sm_section_hdr_t **ppsms, uint16_t sms_id)
 {
-	sbd_lu_t	*slu = (sbd_lu_t *)sst->sst_sbd_private;
-	sbd_lu_info_t	*sli;
-	sm_section_hdr_t *h;
-	stmf_status_t	ret;
-	uint64_t	meta_size;
-	uint64_t	lu_data_offset;
-	uint64_t	lu_data_size;
-	uint16_t	b;
+	sbd_status_t ret;
+	sm_section_hdr_t sms;
+	int alloced = 0;
 
-	/* Blocksize should be a non-zero power of 2 */
-	b = sst_idata->sst_blocksize;
-	if ((b < 2) || ((b & (b - 1)) != 0)) {
-		return (STMF_INVALID_ARG);
-	}
-
-	/* Store size should be nonzero multiple of blocksize */
-	if ((sst_idata->sst_store_size == 0) ||
-	    ((sst_idata->sst_store_size % b) != 0)) {
-		return (STMF_INVALID_ARG);
+	if (((*ppsms) == NULL) || ((*ppsms)->sms_offset == 0)) {
+		bzero(&sms, sizeof (sm_section_hdr_t));
+		sms.sms_id = sms_id;
+		if ((ret = sbd_load_section_hdr(sl, &sms)) != SBD_SUCCESS) {
+			return (ret);
+		} else {
+			if ((*ppsms) == NULL) {
+				*ppsms = (sm_section_hdr_t *)kmem_zalloc(
+				    sms.sms_size, KM_SLEEP);
+				alloced = 1;
+			}
+			bcopy(&sms, *ppsms, sizeof (sm_section_hdr_t));
+		}
 	}
 
-	/*
-	 * Total metadata size is size of metadata headers + size of
-	 * sbd_lu_info_t + any space needed by the store implementation
-	 * itself. We should also keep enough space for future expansions.
-	 * Also metadat size should be rounded off to blocksize.
-	 */
-	/*
-	 * meta_size = sizeof (sbd_meta_start_t ) + sizeof (sbd_lu_info_t) +
-	 *		sst_idata->sst_store_meta_data_size;
-	 */
-	/*
-	 * for now keep a static 64K for metasize. This should be enough to
-	 * store metadata as well as any persistent reservations and keys.
-	 */
-	meta_size = 64 * 1024;
-	meta_size = (meta_size + (uint64_t)(b - 1));
-	meta_size /= (uint64_t)b;
-	meta_size *= (uint64_t)b;
-
-	/*
-	 * If metadata is not separate from user data then store size
-	 * should be large enough to hold metadata. Also effective data
-	 * size should be adjusted.
-	 */
-	if (sst->sst_meta_write == NULL) {
-		if (meta_size >= sst_idata->sst_store_size)
-			return (STMF_INVALID_ARG);
-		lu_data_offset = meta_size;
-		lu_data_size = sst_idata->sst_store_size - meta_size;
+	ret = sbd_read_meta(sl, (*ppsms)->sms_offset, (*ppsms)->sms_size,
+	    (uint8_t *)(*ppsms));
+	if (ret == SBD_SUCCESS) {
+		uint8_t s;
+		if ((*ppsms)->sms_data_order != SMS_DATA_ORDER)
+			sbd_swap_section_hdr(*ppsms);
+		if ((*ppsms)->sms_id != SMS_ID_UNUSED) {
+			s = sbd_calc_section_sum(*ppsms, (*ppsms)->sms_size);
+			if (s != (*ppsms)->sms_chksum)
+				ret = SBD_META_CORRUPTED;
+		}
 	}
 
-	/* Initialize the header and write it */
-	bzero(&slu->sl_sm, sizeof (sbd_meta_start_t));
-	slu->sl_sm.sm_magic = SBD_MAGIC;
-	slu->sl_sm.sm_meta_size = meta_size;
-	/*
-	 * Note that we already included the size for sli even though
-	 * it is going to be written in next step.
-	 */
-	slu->sl_sm.sm_meta_size_used = sbd_meta_offset +
-	    sizeof (sbd_meta_start_t) + sizeof (sbd_lu_info_t);
-	slu->sl_sm.sm_ver_major = 1;
-	slu->sl_sm.sm_chksum = sbd_calc_sum((uint8_t *)&slu->sl_sm,
-	    sizeof (sbd_meta_start_t));
-
-	ret = sbd_aligned_meta_write(sst, sbd_meta_offset,
-	    sizeof (sbd_meta_start_t), (uint8_t *)&slu->sl_sm);
-	if (ret != STMF_SUCCESS)
-		return (ret);
-
-	slu->sl_meta_offset = sbd_meta_offset;
-	slu->sl_sli = (sbd_lu_info_t *)kmem_zalloc(sizeof (sbd_lu_info_t),
-	    KM_SLEEP);
-	sli = slu->sl_sli;
-	h = &sli->sli_sms_header;
-	h->sms_offset = sbd_meta_offset + sizeof (sbd_meta_start_t);
-	h->sms_size = sizeof (sbd_lu_info_t);
-	h->sms_id = SMS_ID_LU_INFO;
-	h->sms_data_order = SMS_DATA_ORDER;
-	sli->sli_total_store_size = sst_idata->sst_store_size;
-	sli->sli_total_meta_size = meta_size;
-	sli->sli_lu_data_offset = lu_data_offset;
-	sli->sli_lu_data_size = lu_data_size;
-	sli->sli_blocksize = sst_idata->sst_blocksize;
-	sli->sli_data_order = SMS_DATA_ORDER;
-	sli->sli_lu_devid[3] = 16;
-	ret = stmf_scsilib_uniq_lu_id(COMPANY_ID_SUN, (scsi_devid_desc_t *)
-	    &sli->sli_lu_devid[0]);
-
-	if (ret == STMF_SUCCESS) {
-		bcopy(&sli->sli_lu_devid[4], sst_idata->sst_guid, 16);
-		ret = sbd_write_section(sst, (sm_section_hdr_t *)slu->sl_sli);
-		if (ret != STMF_SUCCESS)
-			cmn_err(CE_NOTE, "write section failed");
-	} else {
-		cmn_err(CE_NOTE, "scsilib failed %llx",
-		    (unsigned long long)ret);
-	}
-
-	kmem_free(slu->sl_sli, sizeof (sbd_lu_info_t));
-	slu->sl_sli = NULL;
-
+	if ((ret != SBD_SUCCESS) && alloced)
+		kmem_free(*ppsms, sms.sms_size);
 	return (ret);
 }
 
-/*
- * Used to modify the total store size in meta for a LUN, We only
- * check sst_idata->sst_store_size here.
- * For LUN not registered, we will read meta data first
- */
-stmf_status_t
-sbd_modify_meta(sbd_store_t *sst, sst_init_data_t *sst_idata)
+sbd_status_t
+sbd_write_meta_section(sbd_lu_t *sl, sm_section_hdr_t *sms)
 {
-	sbd_lu_t	*slu = (sbd_lu_t *)sst->sst_sbd_private;
-	sbd_lu_info_t	*sli;
-	stmf_status_t	ret;
-	/* uint64_t	meta_size; */
-	uint64_t	lu_data_size;
-	sbd_it_data_t	*sid = NULL;
-	uint64_t	meta_offset;
+	sm_section_hdr_t t;
+	uint64_t off, s;
+	uint64_t unused_start;
+	sbd_status_t ret;
+	uint8_t *cb;
+	int update_meta_start = 0;
 
-
-	if (sst->sst_meta_write == NULL) {
-		if (slu->sl_sm.sm_meta_size >= sst_idata->sst_store_size)
-			return (STMF_INVALID_ARG);
-		lu_data_size = sst_idata->sst_store_size -
-		    slu->sl_sm.sm_meta_size;
+write_meta_section_again:
+	if (sms->sms_offset) {
+		/* Verify that size has not changed */
+		ret = sbd_read_meta(sl, sms->sms_offset, sizeof (t),
+		    (uint8_t *)&t);
+		if (ret != SBD_SUCCESS)
+			return (ret);
+		if (t.sms_data_order != SMS_DATA_ORDER) {
+			sbd_swap_section_hdr(&t);
+		}
+		if (t.sms_id != sms->sms_id) {
+			return (SBD_INVALID_ARG);
+		}
+		if (t.sms_size == sms->sms_size) {
+			return (sbd_write_meta(sl, sms->sms_offset,
+			    sms->sms_size, (uint8_t *)sms));
+		}
+		t.sms_id = SMS_ID_UNUSED;
+		/*
+		 * For unused sections we only use chksum of the header. for
+		 * all other sections, the chksum is for the entire section.
+		 */
+		t.sms_chksum = sbd_calc_section_sum(&t, sizeof (t));
+		ret = sbd_write_meta(sl, t.sms_offset, sizeof (t),
+		    (uint8_t *)&t);
+		if (ret != SBD_SUCCESS)
+			return (ret);
+		sms->sms_offset = 0;
+	} else {
+		t.sms_id = sms->sms_id;
+		t.sms_data_order = SMS_DATA_ORDER;
+		ret = sbd_load_section_hdr(sl, &t);
+		if (ret == SBD_SUCCESS) {
+			sms->sms_offset = t.sms_offset;
+			sms->sms_chksum =
+			    sbd_calc_section_sum(sms, sms->sms_size);
+			goto write_meta_section_again;
+		} else if (ret != SBD_NOT_FOUND) {
+			return (ret);
+		}
 	}
 
 	/*
-	 * use a copy here in order not to change anything if
-	 * sbd_write_section() failed
+	 * At this point we know that section does not already exist.
+	 * find space large enough to hold the section or grow meta if
+	 * possible.
 	 */
-	sli = (sbd_lu_info_t *)kmem_zalloc(sizeof (sbd_lu_info_t), KM_SLEEP);
-	if (slu->sl_sli)
-		bcopy(slu->sl_sli, sli, sizeof (sbd_lu_info_t));
-	else { /* not registered, have to read meta data */
-		meta_offset = sbd_meta_offset;
-read_meta_header:
-		ret = sbd_aligned_meta_read(sst, meta_offset,
-		    sizeof (sbd_meta_start_t), (uint8_t *)&slu->sl_sm);
-		if (ret != STMF_SUCCESS) {
-			goto exit_modify_lu;
+	unused_start = 0;
+	s = 0;
+	for (off = SBD_META_OFFSET + sizeof (sbd_meta_start_t);
+	    off < sl->sl_meta_size_used; off += t.sms_size) {
+		ret = sbd_read_meta(sl, off, sizeof (t), (uint8_t *)&t);
+		if (ret != SBD_SUCCESS)
+			return (ret);
+		if (t.sms_data_order != SMS_DATA_ORDER)
+			sbd_swap_section_hdr(&t);
+		if (t.sms_size == 0)
+			return (SBD_META_CORRUPTED);
+		if (t.sms_id == SMS_ID_UNUSED) {
+			if (unused_start == 0)
+				unused_start = off;
+			s = t.sms_size - unused_start + off;
+			if ((s == sms->sms_size) || (s >= (sms->sms_size +
+			    sizeof (t)))) {
+				break;
+			} else {
+				s = 0;
+			}
+		} else {
+			unused_start = 0;
 		}
-		if (slu->sl_sm.sm_magic != SBD_MAGIC) {
-			if (BSWAP_64(slu->sl_sm.sm_magic) != SBD_MAGIC) {
-				if (!sbd_migrate_meta_from_v0_to_v1(sst)) {
-					ret = STMF_INVALID_ARG;
-					goto exit_modify_lu;
-				}
-				goto read_meta_header;
-			}
-			sbd_swap_meta_start(&slu->sl_sm);
-		}
-		slu->sl_meta_offset = meta_offset;
+	}
 
-		sli->sli_sms_header.sms_size = sizeof (sbd_lu_info_t);
-		sli->sli_sms_header.sms_id = SMS_ID_LU_INFO;
-		sli->sli_sms_header.sms_data_order = SMS_DATA_ORDER;
-
-		ret = sbd_read_section(sst, (sm_section_hdr_t *)sli);
-
-		if (ret != STMF_SUCCESS)
-			goto exit_modify_lu;
-		if (sli->sli_data_order != SMS_DATA_ORDER) {
-			sbd_swap_sli_fields(sli, SMS_DATA_ORDER);
+	off = (unused_start == 0) ? sl->sl_meta_size_used : unused_start;
+	if (s == 0) {
+		s = sl->sl_total_meta_size - off;
+		/* Lets see if we can expand the metadata */
+		if (s >= sms->sms_size || !(sl->sl_flags & SL_SHARED_META)) {
+			s = sms->sms_size;
+			update_meta_start = 1;
+		} else {
+			s = 0;
 		}
 	}
 
-	sli->sli_total_store_size = sst_idata->sst_store_size;
-	sli->sli_lu_data_size = lu_data_size;
-	bcopy(&sli->sli_lu_devid[4], sst_idata->sst_guid, 16);
+	if (s == 0)
+		return (SBD_ALLOC_FAILURE);
 
-	ret = sbd_write_section(sst, (sm_section_hdr_t *)sli);
-	if (ret != STMF_SUCCESS)
-		cmn_err(CE_NOTE, "write section failed");
-	else if (slu->sl_sli) {
-		/* for registered LU */
-		slu->sl_sli->sli_total_store_size = sli->sli_total_store_size;
-		slu->sl_sli->sli_lu_data_size = sli->sli_lu_data_size;
-		mutex_enter(&slu->sl_it_list_lock);
-		for (sid = slu->sl_it_list; sid; sid = sid->sbd_it_next) {
-			sid->sbd_it_ua_conditions |= SBD_UA_CAPACITY_CHANGED;
+	sms->sms_offset = off;
+	sms->sms_chksum = sbd_calc_section_sum(sms, sms->sms_size);
+	/*
+	 * Since we may have to write more than one section (current +
+	 * any unused), use a combined buffer.
+	 */
+	cb = kmem_zalloc(s, KM_SLEEP);
+	bcopy(sms, cb, sms->sms_size);
+	if (s > sms->sms_size) {
+		t.sms_offset = off + sms->sms_size;
+		t.sms_size = s - sms->sms_size;
+		t.sms_id = SMS_ID_UNUSED;
+		t.sms_data_order = SMS_DATA_ORDER;
+		t.sms_chksum = sbd_calc_section_sum(&t, sizeof (t));
+		bcopy(&t, cb + sms->sms_size, sizeof (t));
+	}
+	ret = sbd_write_meta(sl, off, s, cb);
+	kmem_free(cb, s);
+	if (ret != SBD_SUCCESS)
+		return (ret);
+
+	if (update_meta_start) {
+		uint64_t old_sz_used = sl->sl_meta_size_used; /* save a copy */
+		sl->sl_meta_size_used = off + s;
+		s = sl->sl_total_meta_size; /* save a copy */
+		if (sl->sl_total_meta_size < sl->sl_meta_size_used) {
+			uint64_t meta_align =
+			    (((uint64_t)1) << sl->sl_meta_blocksize_shift) - 1;
+			sl->sl_total_meta_size = (sl->sl_meta_size_used +
+			    meta_align) & (~meta_align);
 		}
-		mutex_exit(&slu->sl_it_list_lock);
+		ret = sbd_write_meta_start(sl, sl->sl_total_meta_size,
+		    sl->sl_meta_size_used);
+		if (ret != SBD_SUCCESS) {
+			sl->sl_meta_size_used = old_sz_used;
+			sl->sl_total_meta_size = s;
+		}
 	}
-exit_modify_lu:
-	kmem_free(sli, sizeof (sbd_lu_info_t));
-
 	return (ret);
 }
 
-/*
- * Added sst_idata here because with dynamic LUN, we can only get the
- * LUN size from meta data if we are registering LUN
- */
-stmf_status_t
-sbd_register_sst(sbd_store_t *sst, sst_init_data_t *sst_idata)
+sbd_status_t
+sbd_delete_meta_section(sbd_lu_t *sl, sm_section_hdr_t *sms, uint16_t sms_id)
 {
-	sbd_lu_t	*slu = (sbd_lu_t *)sst->sst_sbd_private;
-	sbd_lu_info_t	*sli;
-	stmf_lu_t	*lu;
-	stmf_status_t	ret;
-	uint16_t	b;
-	uint64_t	meta_offset = sbd_meta_offset;
+	/* Delete sms, if sms is NULL, search by sms_id */
+
+	sm_section_hdr_t hdr;
+	sbd_status_t ret;
+
+	if (sms == NULL) {
+		sms = &hdr;
+		sms->sms_data_order = SMS_DATA_ORDER;
+		sms->sms_id = sms_id;
+		ret = sbd_load_section_hdr(sl, sms);
+		if (ret != SBD_SUCCESS) {
+			return (ret);
+		}
+	}
+	sms->sms_id = SMS_ID_UNUSED;
+	return (sbd_write_meta(sl, sms->sms_offset,
+	    sizeof (sm_section_hdr_t), (uint8_t *)sms));
+}
 
-	if (slu->sl_sli) {
-		cmn_err(CE_PANIC, "sbd_register_sst called with active data "
-		    " from an existing store");
+sbd_status_t
+sbd_write_lu_info(sbd_lu_t *sl)
+{
+	sbd_lu_info_1_1_t *sli;
+	int s;
+	uint8_t *p;
+	char *zvol_name = NULL;
+	sbd_status_t ret;
+
+	mutex_enter(&sl->sl_lock);
+
+	s = sl->sl_serial_no_size;
+	if ((sl->sl_flags & (SL_SHARED_META | SL_ZFS_META)) == 0) {
+		if (sl->sl_data_filename) {
+			s += strlen(sl->sl_data_filename) + 1;
+		}
+	}
+	if (sl->sl_flags & SL_ZFS_META) {
+		zvol_name = sbd_get_zvol_name(sl);
+		s += strlen(zvol_name) + 1;
+	}
+	if (sl->sl_alias) {
+		s += strlen(sl->sl_alias) + 1;
 	}
-read_meta_header:
-	ret = sbd_aligned_meta_read(sst, meta_offset,
-	    sizeof (sbd_meta_start_t), (uint8_t *)&slu->sl_sm);
-	if (ret != STMF_SUCCESS) {
-		return (ret);
+	sli = (sbd_lu_info_1_1_t *)kmem_zalloc(sizeof (*sli) + s, KM_SLEEP);
+	p = sli->sli_buf;
+	if ((sl->sl_flags & (SL_SHARED_META | SL_ZFS_META)) == 0) {
+		sli->sli_flags |= SLI_SEPARATE_META;
+		(void) strcpy((char *)p, sl->sl_data_filename);
+		sli->sli_data_fname_offset =
+		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
+		sli->sli_flags |= SLI_DATA_FNAME_VALID;
+		p += strlen(sl->sl_data_filename) + 1;
+	}
+	if (sl->sl_flags & SL_ZFS_META) {
+		(void) strcpy((char *)p, zvol_name);
+		sli->sli_meta_fname_offset =
+		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
+		sli->sli_flags |= SLI_META_FNAME_VALID | SLI_ZFS_META;
+		p += strlen(zvol_name) + 1;
+		kmem_free(zvol_name, strlen(zvol_name) + 1);
+		zvol_name = NULL;
+	}
+	if (sl->sl_alias) {
+		(void) strcpy((char *)p, sl->sl_alias);
+		sli->sli_alias_offset =
+		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
+		sli->sli_flags |= SLI_ALIAS_VALID;
+		p += strlen(sl->sl_alias) + 1;
+	}
+	if (sl->sl_flags & SL_WRITE_PROTECTED) {
+		sli->sli_flags |= SLI_WRITE_PROTECTED;
 	}
-	if (slu->sl_sm.sm_magic != SBD_MAGIC) {
-		if (BSWAP_64(slu->sl_sm.sm_magic) != SBD_MAGIC) {
-			if (!sbd_migrate_meta_from_v0_to_v1(sst))
-				return (STMF_INVALID_ARG);
-			goto read_meta_header;
-		}
-		sbd_swap_meta_start(&slu->sl_sm);
-		ret = sbd_aligned_meta_write(sst, meta_offset,
-		    sizeof (sbd_meta_start_t), (uint8_t *)&slu->sl_sm);
-		if (ret != STMF_SUCCESS)
-			return (ret);
+	if (sl->sl_flags & SL_SAVED_WRITE_CACHE_DISABLE) {
+		sli->sli_flags |= SLI_WRITEBACK_CACHE_DISABLE;
+	}
+	if (sl->sl_flags & SL_VID_VALID) {
+		bcopy(sl->sl_vendor_id, sli->sli_vid, 8);
+		sli->sli_flags |= SLI_VID_VALID;
+	}
+	if (sl->sl_flags & SL_PID_VALID) {
+		bcopy(sl->sl_product_id, sli->sli_pid, 16);
+		sli->sli_flags |= SLI_PID_VALID;
+	}
+	if (sl->sl_flags & SL_REV_VALID) {
+		bcopy(sl->sl_revision, sli->sli_rev, 4);
+		sli->sli_flags |= SLI_REV_VALID;
 	}
-	slu->sl_meta_offset = meta_offset;
+	if (sl->sl_serial_no_size) {
+		bcopy(sl->sl_serial_no, p, sl->sl_serial_no_size);
+		sli->sli_serial_size = sl->sl_serial_no_size;
+		sli->sli_serial_offset =
+		    (uintptr_t)p - (uintptr_t)sli->sli_buf;
+		sli->sli_flags |= SLI_SERIAL_VALID;
+		p += sli->sli_serial_size;
+	}
+	sli->sli_lu_size = sl->sl_lu_size;
+	sli->sli_data_blocksize_shift = sl->sl_data_blocksize_shift;
+	sli->sli_data_order = SMS_DATA_ORDER;
+	bcopy(sl->sl_device_id, sli->sli_device_id, 20);
 
-	sli = (sbd_lu_info_t *)kmem_zalloc(sizeof (sbd_lu_info_t), KM_SLEEP);
-	slu->sl_sli = sli;
-	sli->sli_sms_header.sms_size = sizeof (sbd_lu_info_t);
-	sli->sli_sms_header.sms_id = SMS_ID_LU_INFO;
+	sli->sli_sms_header.sms_size = sizeof (*sli) + s;
+	sli->sli_sms_header.sms_id = SMS_ID_LU_INFO_1_1;
 	sli->sli_sms_header.sms_data_order = SMS_DATA_ORDER;
 
-	ret = sbd_read_section(sst, (sm_section_hdr_t *)sli);
+	mutex_exit(&sl->sl_lock);
+	ret = sbd_write_meta_section(sl, (sm_section_hdr_t *)sli);
+	kmem_free(sli, sizeof (*sli) + s);
+	return (ret);
+}
 
-	if (ret != STMF_SUCCESS) {
-		goto exit_store_online;
-	}
+int
+sbd_populate_and_register_lu(sbd_lu_t *sl, uint32_t *err_ret)
+{
+	stmf_lu_t *lu = sl->sl_lu;
+	stmf_status_t ret;
 
-	if (sli->sli_data_order != SMS_DATA_ORDER) {
-		sbd_swap_sli_fields(sli, SMS_DATA_ORDER);
+	lu->lu_id = (scsi_devid_desc_t *)sl->sl_device_id;
+	if (sl->sl_alias) {
+		lu->lu_alias = sl->sl_alias;
+	} else {
+		lu->lu_alias = sl->sl_name;
 	}
-	bcopy(&sli->sli_lu_devid[4], sst_idata->sst_guid, 16);
-	b = sli->sli_blocksize;
-
-	/* Calculate shift factor to convert LBA to a linear offset */
-	for (slu->sl_shift_count = 0; b != 1; slu->sl_shift_count++)
-		b >>= 1;
-
-	/* Initialize LU and register it */
-	lu = slu->sl_lu;
-	lu->lu_id = (scsi_devid_desc_t *)&sli->sli_lu_devid[0];
-	lu->lu_alias = sst->sst_alias;
 	lu->lu_lp = sbd_lp;
 	lu->lu_task_alloc = sbd_task_alloc;
 	lu->lu_new_task = sbd_new_task;
@@ -1082,160 +1168,1534 @@
 	lu->lu_abort = sbd_abort;
 	lu->lu_ctl = sbd_ctl;
 	lu->lu_info = sbd_info;
-	slu->sl_state = STMF_STATE_OFFLINE;
+	sl->sl_state = STMF_STATE_OFFLINE;
 
 	if ((ret = stmf_register_lu(lu)) != STMF_SUCCESS) {
 		stmf_trace(0, "Failed to register with framework, ret=%llx",
 		    ret);
-		goto exit_store_online;
+		if (ret == STMF_ALREADY) {
+			*err_ret = SBD_RET_GUID_ALREADY_REGISTERED;
+		}
+		return (EIO);
 	}
 
-	mutex_enter(&sbd_lock);
-	slu->sl_next = sbd_lu_list;
-	sbd_lu_list = slu;
-	sbd_lu_count++;
-	mutex_exit(&sbd_lock);
+	*err_ret = 0;
+	return (0);
+}
+
+int
+sbd_open_data_file(sbd_lu_t *sl, uint32_t *err_ret, int lu_size_valid,
+    int vp_valid, int keep_open)
+{
+	int ret;
+	int flag;
+	ulong_t	nbits;
+	uint64_t supported_size;
+	vattr_t vattr;
+	enum vtype vt;
 
-	if (sst_idata) {
-		sst_idata->sst_store_size = sli->sli_total_store_size;
-		sst_idata->sst_blocksize = sli->sli_blocksize;
+	mutex_enter(&sl->sl_lock);
+	if (vp_valid) {
+		goto odf_over_open;
+	}
+	if (sl->sl_data_filename[0] != '/') {
+		*err_ret = SBD_RET_DATA_PATH_NOT_ABSOLUTE;
+		mutex_exit(&sl->sl_lock);
+		return (EINVAL);
+	}
+	if ((ret = lookupname(sl->sl_data_filename, UIO_SYSSPACE, FOLLOW,
+	    NULLVPP, &sl->sl_data_vp)) != 0) {
+		*err_ret = SBD_RET_DATA_FILE_LOOKUP_FAILED;
+		mutex_exit(&sl->sl_lock);
+		return (ret);
+	}
+	sl->sl_data_vtype = vt = sl->sl_data_vp->v_type;
+	VN_RELE(sl->sl_data_vp);
+	if ((vt != VREG) && (vt != VCHR) && (vt != VBLK)) {
+		*err_ret = SBD_RET_WRONG_DATA_FILE_TYPE;
+		mutex_exit(&sl->sl_lock);
+		return (EINVAL);
+	}
+	if (sl->sl_flags & SL_WRITE_PROTECTED) {
+		flag = FREAD | FOFFMAX;
+	} else {
+		flag = FREAD | FWRITE | FOFFMAX | FEXCL;
+	}
+	if ((ret = vn_open(sl->sl_data_filename, UIO_SYSSPACE, flag, 0,
+	    &sl->sl_data_vp, 0, 0)) != 0) {
+		*err_ret = SBD_RET_DATA_FILE_OPEN_FAILED;
+		mutex_exit(&sl->sl_lock);
+		return (ret);
+	}
+odf_over_open:
+	vattr.va_mask = AT_SIZE;
+	if ((ret = VOP_GETATTR(sl->sl_data_vp, &vattr, 0, CRED(), NULL)) != 0) {
+		*err_ret = SBD_RET_DATA_FILE_GETATTR_FAILED;
+		goto odf_close_data_and_exit;
+	}
+	if ((vt != VREG) && (vattr.va_size == 0)) {
+		/*
+		 * Its a zero byte block or char device. This cannot be
+		 * a raw disk.
+		 */
+		*err_ret = SBD_RET_WRONG_DATA_FILE_TYPE;
+		ret = EINVAL;
+		goto odf_close_data_and_exit;
 	}
+	/* sl_data_readable size includes any metadata. */
+	sl->sl_data_readable_size = vattr.va_size;
+	if (VOP_PATHCONF(sl->sl_data_vp, _PC_FILESIZEBITS, &nbits,
+	    CRED(), NULL) != 0) {
+		nbits = 0;
+	}
+	/* nbits cannot be greater than 64 */
+	sl->sl_data_fs_nbits = (uint8_t)nbits;
+	if (lu_size_valid) {
+		sl->sl_total_data_size = sl->sl_lu_size;
+		if (sl->sl_flags & SL_SHARED_META) {
+			sl->sl_total_data_size += SHARED_META_DATA_SIZE;
+		}
+		if ((nbits > 0) && (nbits < 64)) {
+			/*
+			 * The expression below is correct only if nbits is
+			 * positive and less than 64.
+			 */
+			supported_size = (((uint64_t)1) << nbits) - 1;
+			if (sl->sl_total_data_size > supported_size) {
+				*err_ret = SBD_RET_SIZE_NOT_SUPPORTED_BY_FS;
+				ret = EINVAL;
+				goto odf_close_data_and_exit;
+			}
+		}
+	} else {
+		sl->sl_total_data_size = vattr.va_size;
+		if (sl->sl_flags & SL_SHARED_META) {
+			if (vattr.va_size > SHARED_META_DATA_SIZE) {
+				sl->sl_lu_size = vattr.va_size -
+				    SHARED_META_DATA_SIZE;
+			} else {
+				*err_ret = SBD_RET_FILE_SIZE_ERROR;
+				ret = EINVAL;
+				goto odf_close_data_and_exit;
+			}
+		} else {
+			sl->sl_lu_size = vattr.va_size;
+		}
+	}
+	if (sl->sl_lu_size < SBD_MIN_LU_SIZE) {
+		*err_ret = SBD_RET_FILE_SIZE_ERROR;
+		ret = EINVAL;
+		goto odf_close_data_and_exit;
+	}
+	if (sl->sl_lu_size &
+	    ((((uint64_t)1) << sl->sl_data_blocksize_shift) - 1)) {
+		*err_ret = SBD_RET_FILE_ALIGN_ERROR;
+		ret = EINVAL;
+		goto odf_close_data_and_exit;
+	}
+	sl->sl_flags |= SL_MEDIA_LOADED;
+	mutex_exit(&sl->sl_lock);
+	return (0);
 
-	return (STMF_SUCCESS);
-exit_store_online:;
-	kmem_free(slu->sl_sli, sizeof (sbd_lu_info_t));
-	slu->sl_sli = NULL;
+odf_close_data_and_exit:
+	if (!keep_open) {
+		(void) VOP_CLOSE(sl->sl_data_vp, flag, 1, 0, CRED(), NULL);
+		VN_RELE(sl->sl_data_vp);
+	}
+	mutex_exit(&sl->sl_lock);
+	return (ret);
+}
+
+int
+sbd_close_delete_lu(sbd_lu_t *sl, int ret)
+{
+	int flag;
+
+	if (((sl->sl_flags & SL_SHARED_META) == 0) &&
+	    (sl->sl_flags & SL_META_OPENED)) {
+		if (sl->sl_flags & SL_ZFS_META) {
+			sbd_close_zfs_meta(sl);
+		} else {
+			flag = FREAD | FWRITE | FOFFMAX | FEXCL;
+			(void) VOP_CLOSE(sl->sl_meta_vp, flag, 1, 0,
+			    CRED(), NULL);
+			VN_RELE(sl->sl_meta_vp);
+		}
+		sl->sl_flags &= ~SL_META_OPENED;
+	}
+	if (sl->sl_flags & SL_MEDIA_LOADED) {
+		if (sl->sl_flags & SL_WRITE_PROTECTED) {
+			flag = FREAD | FOFFMAX;
+		} else {
+			flag = FREAD | FWRITE | FOFFMAX | FEXCL;
+		}
+		(void) VOP_CLOSE(sl->sl_data_vp, flag, 1, 0, CRED(), NULL);
+		VN_RELE(sl->sl_data_vp);
+		sl->sl_flags &= ~SL_MEDIA_LOADED;
+		if (sl->sl_flags & SL_SHARED_META) {
+			sl->sl_flags &= ~SL_META_OPENED;
+		}
+	}
+	if (sl->sl_flags & SL_LINKED)
+		sbd_unlink_lu(sl);
+	mutex_destroy(&sl->sl_lock);
+	rw_destroy(&sl->sl_pgr->pgr_lock);
+	if (sl->sl_serial_no_alloc_size) {
+		kmem_free(sl->sl_serial_no, sl->sl_serial_no_alloc_size);
+	}
+	if (sl->sl_data_fname_alloc_size) {
+		kmem_free(sl->sl_data_filename, sl->sl_data_fname_alloc_size);
+	}
+	if (sl->sl_alias_alloc_size) {
+		kmem_free(sl->sl_alias, sl->sl_alias_alloc_size);
+	}
+	stmf_free(sl->sl_lu);
 	return (ret);
 }
 
-stmf_status_t
-sbd_deregister_sst(sbd_store_t *sst)
+int
+sbd_create_register_lu(sbd_create_and_reg_lu_t *slu, int struct_sz,
+    uint32_t *err_ret)
 {
-	sbd_lu_t	*slu = (sbd_lu_t *)sst->sst_sbd_private;
-	sbd_lu_t	**ppslu;
+	char *namebuf;
+	sbd_lu_t *sl;
+	stmf_lu_t *lu;
+	sbd_status_t sret;
+	char *p;
+	int sz;
+	int alloc_sz;
+	int ret = EIO;
+	int flag;
+	int wcd = 0;
+	enum vtype vt;
+
+	sz = struct_sz - sizeof (sbd_create_and_reg_lu_t) + 8 + 1;
+
+	*err_ret = 0;
+
+	/* Lets validate various offsets */
+	if (((slu->slu_meta_fname_valid) &&
+	    (slu->slu_meta_fname_off >= sz)) ||
+	    (slu->slu_data_fname_off >= sz) ||
+	    ((slu->slu_alias_valid) &&
+	    (slu->slu_alias_off >= sz)) ||
+	    ((slu->slu_serial_valid) &&
+	    ((slu->slu_serial_off + slu->slu_serial_size) >= sz))) {
+		return (EINVAL);
+	}
+
+	namebuf = kmem_zalloc(sz, KM_SLEEP);
+	bcopy(slu->slu_buf, namebuf, sz - 1);
+	namebuf[sz - 1] = 0;
+
+	alloc_sz = sizeof (sbd_lu_t) + sizeof (sbd_pgr_t);
+	if (slu->slu_meta_fname_valid) {
+		alloc_sz += strlen(namebuf + slu->slu_meta_fname_off) + 1;
+	}
+	alloc_sz += strlen(namebuf + slu->slu_data_fname_off) + 1;
+	if (slu->slu_alias_valid) {
+		alloc_sz += strlen(namebuf + slu->slu_alias_off) + 1;
+	}
+	if (slu->slu_serial_valid) {
+		alloc_sz += slu->slu_serial_size;
+	}
+
+	lu = (stmf_lu_t *)stmf_alloc(STMF_STRUCT_STMF_LU, alloc_sz, 0);
+	if (lu == NULL) {
+		kmem_free(namebuf, sz);
+		return (ENOMEM);
+	}
+	sl = (sbd_lu_t *)lu->lu_provider_private;
+	bzero(sl, alloc_sz);
+	sl->sl_lu = lu;
+	sl->sl_alloc_size = alloc_sz;
+	sl->sl_pgr = (sbd_pgr_t *)(sl + 1);
+	rw_init(&sl->sl_pgr->pgr_lock, NULL, RW_DRIVER, NULL);
+	mutex_init(&sl->sl_lock, NULL, MUTEX_DRIVER, NULL);
+	p = ((char *)sl) + sizeof (sbd_lu_t) + sizeof (sbd_pgr_t);
+	sl->sl_data_filename = p;
+	(void) strcpy(sl->sl_data_filename, namebuf + slu->slu_data_fname_off);
+	p += strlen(sl->sl_data_filename) + 1;
+	if (slu->slu_meta_fname_valid) {
+		sl->sl_alias = sl->sl_name = sl->sl_meta_filename = p;
+		(void) strcpy(sl->sl_meta_filename, namebuf +
+		    slu->slu_meta_fname_off);
+		p += strlen(sl->sl_meta_filename) + 1;
+	} else {
+		sl->sl_alias = sl->sl_name = sl->sl_data_filename;
+		if (sbd_is_zvol(sl->sl_data_filename, NULL)) {
+			sl->sl_flags |= SL_ZFS_META;
+		} else {
+			sl->sl_flags |= SL_SHARED_META;
+			sl->sl_data_offset = SHARED_META_DATA_SIZE;
+			sl->sl_total_meta_size = SHARED_META_DATA_SIZE;
+			sl->sl_meta_size_used = 0;
+		}
+	}
+	if (slu->slu_alias_valid) {
+		sl->sl_alias = p;
+		(void) strcpy(p, namebuf + slu->slu_alias_off);
+		p += strlen(sl->sl_alias) + 1;
+	}
+	if (slu->slu_serial_valid) {
+		sl->sl_serial_no = (uint8_t *)p;
+		bcopy(namebuf + slu->slu_serial_off, sl->sl_serial_no,
+		    slu->slu_serial_size);
+		sl->sl_serial_no_size = slu->slu_serial_size;
+		p += slu->slu_serial_size;
+	}
+	kmem_free(namebuf, sz);
+	if (slu->slu_vid_valid) {
+		bcopy(slu->slu_vid, sl->sl_vendor_id, 8);
+		sl->sl_flags |= SL_VID_VALID;
+	}
+	if (slu->slu_pid_valid) {
+		bcopy(slu->slu_pid, sl->sl_product_id, 16);
+		sl->sl_flags |= SL_PID_VALID;
+	}
+	if (slu->slu_rev_valid) {
+		bcopy(slu->slu_rev, sl->sl_revision, 4);
+		sl->sl_flags |= SL_REV_VALID;
+	}
+	if (slu->slu_write_protected) {
+		sl->sl_flags |= SL_WRITE_PROTECTED;
+	}
+	if (slu->slu_writeback_cache_disable) {
+		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE |
+		    SL_SAVED_WRITE_CACHE_DISABLE;
+	}
+
+	if (slu->slu_blksize_valid) {
+		if ((slu->slu_blksize & (slu->slu_blksize - 1)) ||
+		    (slu->slu_blksize > (32 * 1024)) ||
+		    (slu->slu_blksize == 0)) {
+			*err_ret = SBD_RET_INVALID_BLKSIZE;
+			ret = EINVAL;
+			goto scm_err_out;
+		}
+		while ((1 << sl->sl_data_blocksize_shift) != slu->slu_blksize) {
+			sl->sl_data_blocksize_shift++;
+		}
+	} else {
+		sl->sl_data_blocksize_shift = 9;	/* 512 by default */
+		slu->slu_blksize = 512;
+	}
+
+	/* Now lets start creating meta */
+	sl->sl_trans_op = SL_OP_CREATE_REGISTER_LU;
+	if (sbd_link_lu(sl) != SBD_SUCCESS) {
+		*err_ret = SBD_RET_FILE_ALREADY_REGISTERED;
+		ret = EALREADY;
+		goto scm_err_out;
+	}
 
-	if (slu->sl_state != STMF_STATE_OFFLINE)
-		return (STMF_BUSY);
+	/* 1st focus on the data store */
+	if (slu->slu_lu_size_valid) {
+		sl->sl_lu_size = slu->slu_lu_size;
+	}
+	ret = sbd_open_data_file(sl, err_ret, slu->slu_lu_size_valid, 0, 0);
+	slu->slu_ret_filesize_nbits = sl->sl_data_fs_nbits;
+	slu->slu_lu_size = sl->sl_lu_size;
+	if (ret) {
+		goto scm_err_out;
+	}
+
+	/*
+	 * set write cache disable on the device
+	 * if it fails, we'll support it using sync/flush
+	 */
+	if (slu->slu_writeback_cache_disable) {
+		(void) sbd_wcd_set(1, sl);
+		wcd = 1;
+	/*
+	 * Attempt to set it to enable, if that fails and it was explicitly set
+	 * return an error, otherwise get the current setting and use that
+	 */
+	} else {
+		sret = sbd_wcd_set(0, sl);
+		if (slu->slu_writeback_cache_disable_valid &&
+		    sret != SBD_SUCCESS) {
+			*err_ret = SBD_RET_WRITE_CACHE_SET_FAILED;
+			ret = EFAULT;
+			goto scm_err_out;
+		}
+		if (sret != SBD_SUCCESS) {
+			sbd_wcd_get(&wcd, sl);
+		}
+	}
+
+	if (wcd) {
+		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE |
+		    SL_SAVED_WRITE_CACHE_DISABLE;
+	}
+
+	if (sl->sl_flags & SL_SHARED_META) {
+		goto over_meta_open;
+	}
+	if (sl->sl_flags & SL_ZFS_META) {
+		if (sbd_create_zfs_meta_object(sl) != SBD_SUCCESS) {
+			*err_ret = SBD_RET_ZFS_META_CREATE_FAILED;
+			ret = EIO;
+			goto scm_err_out;
+		}
+		sl->sl_meta_blocksize_shift = 0;
+		goto over_meta_create;
+	}
+	if ((ret = lookupname(sl->sl_meta_filename, UIO_SYSSPACE, FOLLOW,
+	    NULLVPP, &sl->sl_meta_vp)) != 0) {
+		*err_ret = SBD_RET_META_FILE_LOOKUP_FAILED;
+		goto scm_err_out;
+	}
+	sl->sl_meta_vtype = vt = sl->sl_meta_vp->v_type;
+	VN_RELE(sl->sl_meta_vp);
+	if ((vt != VREG) && (vt != VCHR) && (vt != VBLK)) {
+		*err_ret = SBD_RET_WRONG_META_FILE_TYPE;
+		ret = EINVAL;
+		goto scm_err_out;
+	}
+	if (vt == VREG) {
+		sl->sl_meta_blocksize_shift = 0;
+	} else {
+		sl->sl_meta_blocksize_shift = 9;
+	}
+	flag = FREAD | FWRITE | FOFFMAX | FEXCL;
+	if ((ret = vn_open(sl->sl_meta_filename, UIO_SYSSPACE, flag, 0,
+	    &sl->sl_meta_vp, 0, 0)) != 0) {
+		*err_ret = SBD_RET_META_FILE_OPEN_FAILED;
+		goto scm_err_out;
+	}
+over_meta_create:
+	sl->sl_total_meta_size = SBD_META_OFFSET + sizeof (sbd_meta_start_t);
+	sl->sl_total_meta_size +=
+	    (((uint64_t)1) << sl->sl_meta_blocksize_shift) - 1;
+	sl->sl_total_meta_size &=
+	    ~((((uint64_t)1) << sl->sl_meta_blocksize_shift) - 1);
+	sl->sl_meta_size_used = 0;
+over_meta_open:
+	sl->sl_flags |= SL_META_OPENED;
+
+	sl->sl_device_id[3] = 16;
+	if (slu->slu_guid_valid) {
+		sl->sl_device_id[0] = 0xf1;
+		sl->sl_device_id[1] = 3;
+		sl->sl_device_id[2] = 0;
+		bcopy(slu->slu_guid, sl->sl_device_id + 4, 16);
+	} else {
+		if (!slu->slu_company_id_valid)
+			slu->slu_company_id = COMPANY_ID_SUN;
+		if (stmf_scsilib_uniq_lu_id(slu->slu_company_id,
+		    (scsi_devid_desc_t *)&sl->sl_device_id[0]) !=
+		    STMF_SUCCESS) {
+			*err_ret = SBD_RET_META_CREATION_FAILED;
+			ret = EIO;
+			goto scm_err_out;
+		}
+		bcopy(sl->sl_device_id + 4, slu->slu_guid, 16);
+	}
+
+	/* Lets create the meta now */
+	if (sbd_write_meta_start(sl, sl->sl_total_meta_size,
+	    sizeof (sbd_meta_start_t)) != SBD_SUCCESS) {
+		*err_ret = SBD_RET_META_CREATION_FAILED;
+		ret = EIO;
+		goto scm_err_out;
+	}
+	sl->sl_meta_size_used = SBD_META_OFFSET + sizeof (sbd_meta_start_t);
+
+	if (sbd_write_lu_info(sl) != SBD_SUCCESS) {
+		*err_ret = SBD_RET_META_CREATION_FAILED;
+		ret = EIO;
+		goto scm_err_out;
+	}
+
+	if (sbd_pgr_meta_write(sl) != SBD_SUCCESS) {
+		*err_ret = SBD_RET_META_CREATION_FAILED;
+		ret = EIO;
+		goto scm_err_out;
+	}
+
+	ret = sbd_populate_and_register_lu(sl, err_ret);
+	if (ret) {
+		goto scm_err_out;
+	}
+
+	sl->sl_trans_op = SL_OP_NONE;
+	atomic_add_32(&sbd_lu_count, 1);
+	return (0);
+
+scm_err_out:
+	return (sbd_close_delete_lu(sl, ret));
+}
+
+int
+sbd_load_sli_1_0(sbd_lu_t *sl, uint32_t *err_ret)
+{
+	sbd_lu_info_1_0_t *sli = NULL;
+	sbd_status_t sret;
+
+	sret = sbd_read_meta_section(sl, (sm_section_hdr_t **)&sli,
+	    SMS_ID_LU_INFO_1_0);
 
-	if (stmf_deregister_lu(slu->sl_lu) != STMF_SUCCESS)
-		return (STMF_BUSY);
+	if (sret != SBD_SUCCESS) {
+		*err_ret = SBD_RET_NO_META;
+		return (EIO);
+	}
+	if (sli->sli_data_order != SMS_DATA_ORDER) {
+		sbd_swap_lu_info_1_0(sli);
+		if (sli->sli_data_order != SMS_DATA_ORDER) {
+			kmem_free(sli, sli->sli_sms_header.sms_size);
+			*err_ret = SBD_RET_NO_META;
+			return (EIO);
+		}
+	}
+
+	sl->sl_flags |= SL_SHARED_META;
+	sl->sl_data_blocksize_shift = 9;
+	sl->sl_data_offset = SHARED_META_DATA_SIZE;
+	sl->sl_lu_size = sli->sli_total_store_size - SHARED_META_DATA_SIZE;
+	sl->sl_total_data_size = SHARED_META_DATA_SIZE + sl->sl_lu_size;
+	bcopy(sli->sli_lu_devid, sl->sl_device_id, 20);
+
+	kmem_free(sli, sli->sli_sms_header.sms_size);
+	return (0);
+}
+
+int
+sbd_import_lu(sbd_import_lu_t *ilu, int struct_sz, uint32_t *err_ret,
+    int no_register, sbd_lu_t **slr)
+{
+	stmf_lu_t *lu;
+	sbd_lu_t *sl;
+	sbd_lu_info_1_1_t *sli = NULL;
+	int asz;
+	int ret = 0;
+	int flag;
+	int wcd = 0;
+	int data_opened;
+	uint16_t sli_buf_sz;
+	uint8_t *sli_buf_copy = NULL;
+	enum vtype vt;
+	sbd_status_t sret;
+
+	if (no_register && slr == NULL) {
+		return (EINVAL);
+	}
+	ilu->ilu_meta_fname[struct_sz - sizeof (*ilu) + 8 - 1] = 0;
+	asz = strlen(ilu->ilu_meta_fname) + 1;
+
+	lu = (stmf_lu_t *)stmf_alloc(STMF_STRUCT_STMF_LU,
+	    sizeof (sbd_lu_t) + sizeof (sbd_pgr_t) + asz, 0);
+	if (lu == NULL) {
+		return (ENOMEM);
+	}
+	sl = (sbd_lu_t *)lu->lu_provider_private;
+	bzero(sl, sizeof (*sl));
+	sl->sl_lu = lu;
+	sl->sl_pgr = (sbd_pgr_t *)(sl + 1);
+	sl->sl_meta_filename = ((char *)sl) + sizeof (*sl) + sizeof (sbd_pgr_t);
+	(void) strcpy(sl->sl_meta_filename, ilu->ilu_meta_fname);
+	sl->sl_name = sl->sl_meta_filename;
+	rw_init(&sl->sl_pgr->pgr_lock, NULL, RW_DRIVER, NULL);
+	mutex_init(&sl->sl_lock, NULL, MUTEX_DRIVER, NULL);
+	sl->sl_trans_op = SL_OP_IMPORT_LU;
+	/* we're only loading the metadata */
+	if (!no_register) {
+		if (sbd_link_lu(sl) != SBD_SUCCESS) {
+			*err_ret = SBD_RET_FILE_ALREADY_REGISTERED;
+			ret = EALREADY;
+			goto sim_err_out;
+		}
+	}
+	if ((ret = lookupname(sl->sl_meta_filename, UIO_SYSSPACE, FOLLOW,
+	    NULLVPP, &sl->sl_meta_vp)) != 0) {
+		*err_ret = SBD_RET_META_FILE_LOOKUP_FAILED;
+		goto sim_err_out;
+	}
+	if (sbd_is_sbd_zvol(sl->sl_meta_filename, sl->sl_meta_vp)) {
+		sl->sl_flags |= SL_ZFS_META;
+		sl->sl_data_filename = sl->sl_meta_filename;
+	}
+	sl->sl_meta_vtype = vt = sl->sl_meta_vp->v_type;
+	VN_RELE(sl->sl_meta_vp);
+	if ((vt != VREG) && (vt != VCHR) && (vt != VBLK)) {
+		*err_ret = SBD_RET_WRONG_META_FILE_TYPE;
+		ret = EINVAL;
+		goto sim_err_out;
+	}
+	if (sl->sl_flags & SL_ZFS_META) {
+		if (sbd_open_zfs_meta(sl) != SBD_SUCCESS) {
+			ret = EIO;
+			*err_ret = SBD_RET_META_FILE_OPEN_FAILED;
+			goto sim_err_out;
+		}
+	} else {
+		/* metadata is always writable */
+		flag = FREAD | FWRITE | FOFFMAX | FEXCL;
+		if ((ret = vn_open(sl->sl_meta_filename, UIO_SYSSPACE, flag, 0,
+		    &sl->sl_meta_vp, 0, 0)) != 0) {
+			*err_ret = SBD_RET_META_FILE_OPEN_FAILED;
+			goto sim_err_out;
+		}
+	}
+	if ((sl->sl_flags & SL_ZFS_META) || (vt == VREG)) {
+		sl->sl_meta_blocksize_shift = 0;
+	} else {
+		sl->sl_meta_blocksize_shift = 9;
+	}
+	sl->sl_flags |= SL_META_OPENED;
+
+	sret = sbd_load_meta_start(sl);
+	if (sret != SBD_SUCCESS) {
+		if (sret == SBD_META_CORRUPTED) {
+			*err_ret = SBD_RET_NO_META;
+		} else if (sret == SBD_NOT_SUPPORTED) {
+			*err_ret = SBD_RET_VERSION_NOT_SUPPORTED;
+		} else {
+			*err_ret = SBD_RET_NO_META;
+		}
+		ret = EINVAL;
+		goto sim_err_out;
+	}
 
-	mutex_enter(&sbd_lock);
-	for (ppslu = &sbd_lu_list; (*ppslu) != NULL;
-	    ppslu = &((*ppslu)->sl_next)) {
-		if ((*ppslu) == slu) {
-			*ppslu = (*ppslu)->sl_next;
-			sbd_lu_count--;
-			break;
+	/* Now lets see if we can read the most recent LU info */
+	sret = sbd_read_meta_section(sl, (sm_section_hdr_t **)&sli,
+	    SMS_ID_LU_INFO_1_1);
+	if ((sret == SBD_NOT_FOUND) && ((sl->sl_flags & SL_ZFS_META) == 0)) {
+		ret = sbd_load_sli_1_0(sl, err_ret);
+		if (ret)
+			goto sim_err_out;
+		goto sim_sli_loaded;
+	}
+	if (sret != SBD_SUCCESS) {
+		*err_ret = SBD_RET_NO_META;
+		ret = EIO;
+		goto sim_err_out;
+	}
+	/* load sli 1.1 */
+	if (sli->sli_data_order != SMS_DATA_ORDER) {
+		sbd_swap_lu_info_1_1(sli);
+		if (sli->sli_data_order != SMS_DATA_ORDER) {
+			*err_ret = SBD_RET_NO_META;
+			ret = EIO;
+			goto sim_err_out;
+		}
+	}
+
+	sli_buf_sz = sli->sli_sms_header.sms_size -
+	    sizeof (sbd_lu_info_1_1_t) + 8;
+	sli_buf_copy = kmem_alloc(sli_buf_sz + 1, KM_SLEEP);
+	bcopy(sli->sli_buf, sli_buf_copy, sli_buf_sz);
+	sli_buf_copy[sli_buf_sz] = 0;
+
+	/* Make sure all the offsets are within limits */
+	if (((sli->sli_flags & SLI_META_FNAME_VALID) &&
+	    (sli->sli_meta_fname_offset > sli_buf_sz)) ||
+	    ((sli->sli_flags & SLI_DATA_FNAME_VALID) &&
+	    (sli->sli_data_fname_offset > sli_buf_sz)) ||
+	    ((sli->sli_flags & SLI_SERIAL_VALID) &&
+	    ((sli->sli_serial_offset + sli->sli_serial_size) > sli_buf_sz)) ||
+	    ((sli->sli_flags & SLI_ALIAS_VALID) &&
+	    (sli->sli_alias_offset > sli_buf_sz))) {
+		*err_ret = SBD_RET_NO_META;
+		ret = EIO;
+		goto sim_err_out;
+	}
+
+	if (sl->sl_flags & SL_ZFS_META) {
+		/* Verify that its the right zfs node and not some clone */
+		int same_zvol;
+		char *zvol_name = sbd_get_zvol_name(sl);
+
+		if ((sli->sli_flags & (SLI_ZFS_META |
+		    SLI_META_FNAME_VALID)) == 0) {
+			*err_ret = SBD_RET_NO_META;
+			ret = EIO;
+			goto sim_err_out;
+		}
+		zvol_name = sbd_get_zvol_name(sl);
+		if (strcmp(zvol_name, (char *)sli_buf_copy +
+		    sli->sli_meta_fname_offset) != 0)
+			same_zvol = 0;
+		else
+			same_zvol = 1;
+		kmem_free(zvol_name, strlen(zvol_name) + 1);
+		if (!same_zvol) {
+			*err_ret = SBD_ZVOL_META_NAME_MISMATCH;
+			ret = EINVAL;
+			goto sim_err_out;
+		}
+	}
+	sl->sl_lu_size = sli->sli_lu_size;
+	sl->sl_data_blocksize_shift = sli->sli_data_blocksize_shift;
+	bcopy(sli->sli_device_id, sl->sl_device_id, 20);
+	if (sli->sli_flags & SLI_SERIAL_VALID) {
+		sl->sl_serial_no_size = sl->sl_serial_no_alloc_size =
+		    sli->sli_serial_size;
+		sl->sl_serial_no = kmem_zalloc(sli->sli_serial_size, KM_SLEEP);
+		bcopy(sli_buf_copy + sli->sli_serial_offset, sl->sl_serial_no,
+		    sl->sl_serial_no_size);
+	}
+	if (sli->sli_flags & SLI_SEPARATE_META) {
+		sl->sl_total_data_size = sl->sl_lu_size;
+		if (sli->sli_flags & SLI_DATA_FNAME_VALID) {
+			sl->sl_data_fname_alloc_size = strlen((char *)
+			    sli_buf_copy + sli->sli_data_fname_offset) + 1;
+			sl->sl_data_filename = kmem_zalloc(
+			    sl->sl_data_fname_alloc_size, KM_SLEEP);
+			(void) strcpy(sl->sl_data_filename,
+			    (char *)sli_buf_copy + sli->sli_data_fname_offset);
+		}
+	} else {
+		if (sl->sl_flags & SL_ZFS_META) {
+			sl->sl_total_data_size = sl->sl_lu_size;
+			sl->sl_data_offset = 0;
+		} else {
+			sl->sl_total_data_size =
+			    sl->sl_lu_size + SHARED_META_DATA_SIZE;
+			sl->sl_data_offset = SHARED_META_DATA_SIZE;
+			sl->sl_flags |= SL_SHARED_META;
+		}
+	}
+	if (sli->sli_flags & SLI_ALIAS_VALID) {
+		sl->sl_alias_alloc_size = strlen((char *)sli_buf_copy +
+		    sli->sli_alias_offset) + 1;
+		sl->sl_alias = kmem_alloc(sl->sl_alias_alloc_size, KM_SLEEP);
+		(void) strcpy(sl->sl_alias, (char *)sli_buf_copy +
+		    sli->sli_alias_offset);
+	}
+	if (sli->sli_flags & SLI_WRITE_PROTECTED) {
+		sl->sl_flags |= SL_WRITE_PROTECTED;
+	}
+	if (sli->sli_flags & SLI_VID_VALID) {
+		sl->sl_flags |= SL_VID_VALID;
+		bcopy(sli->sli_vid, sl->sl_vendor_id, 8);
+	}
+	if (sli->sli_flags & SLI_PID_VALID) {
+		sl->sl_flags |= SL_PID_VALID;
+		bcopy(sli->sli_pid, sl->sl_product_id, 16);
+	}
+	if (sli->sli_flags & SLI_REV_VALID) {
+		sl->sl_flags |= SL_REV_VALID;
+		bcopy(sli->sli_rev, sl->sl_revision, 4);
+	}
+	if (sli->sli_flags & SLI_WRITEBACK_CACHE_DISABLE) {
+		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE;
+	}
+sim_sli_loaded:
+	if ((sl->sl_flags & SL_SHARED_META) == 0) {
+		data_opened = 0;
+	} else {
+		data_opened = 1;
+		sl->sl_data_filename = sl->sl_meta_filename;
+		sl->sl_data_vp = sl->sl_meta_vp;
+		sl->sl_data_vtype = sl->sl_meta_vtype;
+	}
+
+	sret = sbd_pgr_meta_load(sl);
+	if (sret != SBD_SUCCESS) {
+		*err_ret = SBD_RET_NO_META;
+		ret = EIO;
+		goto sim_err_out;
+	}
+
+	ret = sbd_open_data_file(sl, err_ret, 1, data_opened, 0);
+	if (ret)
+		goto sim_err_out;
+
+	/*
+	 * set write cache disable on the device
+	 * Note: this shouldn't fail on import unless the cache capabilities
+	 * of the device changed. If that happened, modify will need to
+	 * be used to set the cache flag appropriately after import is done.
+	 */
+	if (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) {
+		(void) sbd_wcd_set(1, sl);
+		wcd = 1;
+	/*
+	 * if not explicitly set, attempt to set it to enable, if that fails
+	 * get the current setting and use that
+	 */
+	} else {
+		sret = sbd_wcd_set(0, sl);
+		if (sret != SBD_SUCCESS) {
+			sbd_wcd_get(&wcd, sl);
 		}
 	}
-	mutex_exit(&sbd_lock);
-	if (slu->sl_sli) {
-		kmem_free(slu->sl_sli, sizeof (sbd_lu_info_t));
-		slu->sl_sli = NULL;
+
+	if (wcd) {
+		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE |
+		    SL_SAVED_WRITE_CACHE_DISABLE;
+	}
+
+	/* we're only loading the metadata */
+	if (!no_register) {
+		ret = sbd_populate_and_register_lu(sl, err_ret);
+		if (ret)
+			goto sim_err_out;
+		atomic_add_32(&sbd_lu_count, 1);
+	}
+
+	bcopy(sl->sl_device_id + 4, ilu->ilu_ret_guid, 16);
+	sl->sl_trans_op = SL_OP_NONE;
+	if (sli) {
+		kmem_free(sli, sli->sli_sms_header.sms_size);
+		sli = NULL;
+	}
+	if (sli_buf_copy) {
+		kmem_free(sli_buf_copy, sli_buf_sz + 1);
+		sli_buf_copy = NULL;
+	}
+	if (no_register) {
+		*slr = sl;
+	}
+	return (0);
+
+sim_err_out:
+	if (sli) {
+		kmem_free(sli, sli->sli_sms_header.sms_size);
+		sli = NULL;
+	}
+	if (sli_buf_copy) {
+		kmem_free(sli_buf_copy, sli_buf_sz + 1);
+		sli_buf_copy = NULL;
+	}
+	return (sbd_close_delete_lu(sl, ret));
+}
+
+int
+sbd_modify_lu(sbd_modify_lu_t *mlu, int struct_sz, uint32_t *err_ret)
+{
+	sbd_lu_t *sl = NULL;
+	int alias_sz;
+	int ret = 0;
+	sbd_it_data_t *it;
+	sbd_status_t sret;
+	uint64_t old_size;
+	int modify_unregistered = 0;
+	int ua = 0;
+	sbd_import_lu_t *ilu;
+	stmf_lu_t *lu;
+	uint32_t ilu_sz;
+	uint32_t sz;
+
+	sz = struct_sz - sizeof (*mlu) + 8 + 1;
+
+	/* if there is data in the buf, null terminate it */
+	if (struct_sz > sizeof (*mlu)) {
+		mlu->mlu_buf[struct_sz - sizeof (*mlu) + 8 - 1] = 0;
+	}
+
+	*err_ret = 0;
+
+	/* Lets validate offsets */
+	if (((mlu->mlu_alias_valid) &&
+	    (mlu->mlu_alias_off >= sz)) ||
+	    (mlu->mlu_by_fname) &&
+	    (mlu->mlu_fname_off >= sz)) {
+		return (EINVAL);
+	}
+
+	/*
+	 * We'll look for the device but if we don't find it registered,
+	 * we'll still try to modify the unregistered device.
+	 */
+	if (mlu->mlu_by_guid) {
+		sret = sbd_find_and_lock_lu(mlu->mlu_input_guid, NULL,
+		    SL_OP_MODIFY_LU, &sl);
+	} else if (mlu->mlu_by_fname) {
+		sret = sbd_find_and_lock_lu(NULL,
+		    (uint8_t *)&(mlu->mlu_buf[mlu->mlu_fname_off]),
+		    SL_OP_MODIFY_LU, &sl);
+	} else {
+		return (EINVAL);
+	}
+
+
+	if (sret != SBD_SUCCESS) {
+		if (sret == SBD_BUSY) {
+			*err_ret = SBD_RET_LU_BUSY;
+			return (EBUSY);
+		} else if (sret != SBD_NOT_FOUND) {
+			return (EIO);
+		} else if (!mlu->mlu_by_fname) {
+			return (EINVAL);
+		}
+		/* Okay, try to import the device */
+		struct_sz = max(8, strlen(&(mlu->mlu_buf[mlu->mlu_fname_off]))
+		    + 1);
+		struct_sz += sizeof (sbd_import_lu_t) - 8;
+		ilu_sz = struct_sz;
+		ilu = (sbd_import_lu_t *)kmem_zalloc(ilu_sz, KM_SLEEP);
+		ilu->ilu_struct_size = struct_sz;
+		(void) strcpy(ilu->ilu_meta_fname,
+		    &(mlu->mlu_buf[mlu->mlu_fname_off]));
+		ret = sbd_import_lu(ilu, struct_sz, err_ret, 1, &sl);
+		kmem_free(ilu, ilu_sz);
+		if (ret != SBD_SUCCESS) {
+			return (ENOENT);
+		}
+		modify_unregistered = 1;
+	}
+
+	/* check for write cache change */
+	if (mlu->mlu_writeback_cache_disable_valid) {
+		/* set wce on device */
+		sret = sbd_wcd_set(mlu->mlu_writeback_cache_disable, sl);
+		if (!mlu->mlu_writeback_cache_disable && sret != SBD_SUCCESS) {
+			*err_ret = SBD_RET_WRITE_CACHE_SET_FAILED;
+			ret = EFAULT;
+			goto smm_err_out;
+		}
+		mutex_enter(&sl->sl_lock);
+		if (!mlu->mlu_writeback_cache_disable) {
+			if (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) {
+				ua = 1;
+				sl->sl_flags &= ~SL_WRITEBACK_CACHE_DISABLE;
+				sl->sl_flags &= ~SL_SAVED_WRITE_CACHE_DISABLE;
+			}
+		} else {
+			if ((sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) == 0) {
+				ua = 1;
+				sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE;
+				sl->sl_flags |= SL_SAVED_WRITE_CACHE_DISABLE;
+			}
+		}
+		for (it = sl->sl_it_list; ua && it != NULL;
+		    it = it->sbd_it_next) {
+			it->sbd_it_ua_conditions |=
+			    SBD_UA_MODE_PARAMETERS_CHANGED;
+		}
+		mutex_exit(&sl->sl_lock);
+	}
+	ua = 0;
+
+	if (mlu->mlu_alias_valid) {
+		alias_sz = strlen((char *)mlu->mlu_buf +
+		    mlu->mlu_alias_off) + 1;
+		/*
+		 * Use the allocated buffer or alloc a new one.
+		 * Don't copy into sl_alias if sl_alias_alloc_size is 0
+		 * otherwise or you'll be writing over the data/metadata
+		 * filename.
+		 */
+		mutex_enter(&sl->sl_lock);
+		if (sl->sl_alias_alloc_size > 0 &&
+		    sl->sl_alias_alloc_size < alias_sz) {
+			kmem_free(sl->sl_alias,
+			    sl->sl_alias_alloc_size);
+			sl->sl_alias_alloc_size = 0;
+		}
+		if (sl->sl_alias_alloc_size == 0) {
+			sl->sl_alias = kmem_alloc(alias_sz, KM_SLEEP);
+			sl->sl_alias_alloc_size = alias_sz;
+		}
+		(void) strcpy(sl->sl_alias, (char *)mlu->mlu_buf +
+		    mlu->mlu_alias_off);
+		lu = sl->sl_lu;
+		lu->lu_alias = sl->sl_alias;
+		mutex_exit(&sl->sl_lock);
+	}
+
+
+	if (mlu->mlu_write_protected_valid) {
+		mutex_enter(&sl->sl_lock);
+		if (mlu->mlu_write_protected) {
+			if ((sl->sl_flags & SL_WRITE_PROTECTED) == 0) {
+				ua = 1;
+				sl->sl_flags |= SL_WRITE_PROTECTED;
+			}
+		} else {
+			if (sl->sl_flags & SL_WRITE_PROTECTED) {
+				ua = 1;
+				sl->sl_flags &= ~SL_WRITE_PROTECTED;
+			}
+		}
+		for (it = sl->sl_it_list; ua && it != NULL;
+		    it = it->sbd_it_next) {
+			it->sbd_it_ua_conditions |=
+			    SBD_UA_MODE_PARAMETERS_CHANGED;
+		}
+		mutex_exit(&sl->sl_lock);
+	}
+
+	if (mlu->mlu_lu_size_valid) {
+		/*
+		 * validate lu size and set
+		 * For open file only (registered lu)
+		 */
+		mutex_enter(&sl->sl_lock);
+		old_size = sl->sl_lu_size;
+		sl->sl_lu_size = mlu->mlu_lu_size;
+		mutex_exit(&sl->sl_lock);
+		ret = sbd_open_data_file(sl, err_ret, 1, 1, 1);
+		if (ret) {
+			mutex_enter(&sl->sl_lock);
+			sl->sl_lu_size = old_size;
+			mutex_exit(&sl->sl_lock);
+			goto smm_err_out;
+		}
+		if (old_size != mlu->mlu_lu_size) {
+			mutex_enter(&sl->sl_lock);
+			for (it = sl->sl_it_list; it != NULL;
+			    it = it->sbd_it_next) {
+				it->sbd_it_ua_conditions |=
+				    SBD_UA_CAPACITY_CHANGED;
+			}
+			mutex_exit(&sl->sl_lock);
+		}
+	}
+
+	if (sbd_write_lu_info(sl) != SBD_SUCCESS) {
+		*err_ret = SBD_RET_META_CREATION_FAILED;
+		ret = EIO;
+	}
+
+smm_err_out:
+	if (modify_unregistered) {
+		(void) sbd_close_delete_lu(sl, 0);
+	} else {
+		sl->sl_trans_op = SL_OP_NONE;
+	}
+	return (ret);
+}
+
+/* ARGSUSED */
+int
+sbd_delete_locked_lu(sbd_lu_t *sl, uint32_t *err_ret,
+    stmf_state_change_info_t *ssi)
+{
+	int i;
+
+	if ((sl->sl_state == STMF_STATE_OFFLINE) &&
+	    !sl->sl_state_not_acked) {
+		goto sdl_do_dereg;
+	}
+
+	if ((sl->sl_state != STMF_STATE_ONLINE) ||
+	    sl->sl_state_not_acked) {
+		return (EBUSY);
+	}
+	if (stmf_ctl(STMF_CMD_LU_OFFLINE, sl->sl_lu, ssi) != STMF_SUCCESS) {
+		return (EBUSY);
+	}
+
+	for (i = 0; i < 500; i++) {
+		if (sl->sl_state == STMF_STATE_OFFLINE)
+			break;
+		delay(drv_usectohz(10000));
+	}
+
+	if ((sl->sl_state == STMF_STATE_OFFLINE) &&
+	    !sl->sl_state_not_acked) {
+		goto sdl_do_dereg;
+	}
+
+	return (EBUSY);
+sdl_do_dereg:;
+	if (stmf_deregister_lu(sl->sl_lu) != STMF_SUCCESS)
+		return (EBUSY);
+	atomic_add_32(&sbd_lu_count, -1);
+
+	return (sbd_close_delete_lu(sl, 0));
+}
+
+int
+sbd_delete_lu(sbd_delete_lu_t *dlu, int struct_sz, uint32_t *err_ret)
+{
+	sbd_lu_t *sl;
+	sbd_status_t sret;
+	stmf_state_change_info_t ssi;
+	int ret;
+
+	if (dlu->dlu_by_meta_name) {
+		((char *)dlu)[struct_sz - 1] = 0;
+		sret = sbd_find_and_lock_lu(NULL, dlu->dlu_meta_name,
+		    SL_OP_DELETE_LU, &sl);
+	} else {
+		sret = sbd_find_and_lock_lu(dlu->dlu_guid, NULL,
+		    SL_OP_DELETE_LU, &sl);
+	}
+	if (sret != SBD_SUCCESS) {
+		if (sret == SBD_BUSY) {
+			*err_ret = SBD_RET_LU_BUSY;
+			return (EBUSY);
+		} else if (sret == SBD_NOT_FOUND) {
+			*err_ret = SBD_RET_NOT_FOUND;
+			return (ENOENT);
+		}
+		return (EIO);
+	}
+
+	ssi.st_rflags = STMF_RFLAG_USER_REQUEST;
+	ssi.st_additional_info = "sbd_delete_lu call (ioctl)";
+	ret = sbd_delete_locked_lu(sl, err_ret, &ssi);
+
+	if (ret) {
+		/* Once its locked, no need to grab mutex again */
+		sl->sl_trans_op = SL_OP_NONE;
+	}
+	return (ret);
+}
+
+sbd_status_t
+sbd_data_read(sbd_lu_t *sl, uint64_t offset, uint64_t size, uint8_t *buf)
+{
+	int ret;
+	long resid;
+
+	if ((offset + size) > sl->sl_lu_size) {
+		return (SBD_IO_PAST_EOF);
+	}
+
+	offset += sl->sl_data_offset;
+
+	if ((offset + size) > sl->sl_data_readable_size) {
+		uint64_t store_end;
+		if (offset > sl->sl_data_readable_size) {
+			bzero(buf, size);
+			return (SBD_SUCCESS);
+		}
+		store_end = sl->sl_data_readable_size - offset;
+		bzero(buf + store_end, size - store_end);
+		size = store_end;
+	}
+
+	DTRACE_PROBE4(backing__store__read__start, sbd_lu_t *, sl,
+	    uint8_t *, buf, uint64_t, size, uint64_t, offset);
+
+	ret = vn_rdwr(UIO_READ, sl->sl_data_vp, (caddr_t)buf, (ssize_t)size,
+	    (offset_t)offset, UIO_SYSSPACE, 0, RLIM64_INFINITY, CRED(),
+	    &resid);
+
+	DTRACE_PROBE5(backing__store__read__end, sbd_lu_t *, sl,
+	    uint8_t *, buf, uint64_t, size, uint64_t, offset,
+	    int, ret);
+
+over_sl_data_read:
+	if (ret || resid) {
+		stmf_trace(0, "UIO_READ failed, ret = %d, resid = %d", ret,
+		    resid);
+		return (SBD_FAILURE);
+	}
+
+	return (SBD_SUCCESS);
+}
+
+sbd_status_t
+sbd_data_write(sbd_lu_t *sl, uint64_t offset, uint64_t size, uint8_t *buf)
+{
+	int ret;
+	long resid;
+	sbd_status_t sret = SBD_SUCCESS;
+	int ioflag;
+
+	if ((offset + size) > sl->sl_lu_size) {
+		return (SBD_IO_PAST_EOF);
 	}
-	return (STMF_SUCCESS);
+
+	offset += sl->sl_data_offset;
+
+	if ((sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) &&
+	    (sl->sl_flags & SL_FLUSH_ON_DISABLED_WRITECACHE)) {
+		ioflag = FSYNC;
+	} else {
+		ioflag = 0;
+	}
+
+	DTRACE_PROBE4(backing__store__write__start, sbd_lu_t *, sl,
+	    uint8_t *, buf, uint64_t, size, uint64_t, offset);
+
+	ret = vn_rdwr(UIO_WRITE, sl->sl_data_vp, (caddr_t)buf, (ssize_t)size,
+	    (offset_t)offset, UIO_SYSSPACE, ioflag, RLIM64_INFINITY, CRED(),
+	    &resid);
+
+	DTRACE_PROBE5(backing__store__write__end, sbd_lu_t *, sl,
+	    uint8_t *, buf, uint64_t, size, uint64_t, offset,
+	    int, ret);
+
+	if ((ret == 0) && (resid == 0) &&
+	    (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) &&
+	    (sl->sl_flags & SL_FLUSH_ON_DISABLED_WRITECACHE)) {
+		sret = sbd_flush_data_cache(sl, 1);
+	}
+over_sl_data_write:
+
+	if ((ret || resid) || (sret != SBD_SUCCESS)) {
+		return (SBD_FAILURE);
+	} else if ((offset + size) > sl->sl_data_readable_size) {
+		uint64_t old_size, new_size;
+
+		do {
+			old_size = sl->sl_data_readable_size;
+			if ((offset + size) <= old_size)
+				break;
+			new_size = offset + size;
+		} while (atomic_cas_64(&sl->sl_data_readable_size, old_size,
+		    new_size) != old_size);
+	}
+
+	return (SBD_SUCCESS);
+}
+
+int
+sbd_get_lu_props(sbd_lu_props_t *islp, uint32_t islp_sz,
+    sbd_lu_props_t *oslp, uint32_t oslp_sz, uint32_t *err_ret)
+{
+	sbd_status_t sret;
+	sbd_lu_t *sl = NULL;
+	uint32_t sz;
+	uint16_t off;
+
+	if (islp->slp_input_guid) {
+		sret = sbd_find_and_lock_lu(islp->slp_guid, NULL,
+		    SL_OP_LU_PROPS, &sl);
+	} else {
+		((char *)islp)[islp_sz - 1] = 0;
+		sret = sbd_find_and_lock_lu(NULL, islp->slp_buf,
+		    SL_OP_LU_PROPS, &sl);
+	}
+	if (sret != SBD_SUCCESS) {
+		if (sret == SBD_BUSY) {
+			*err_ret = SBD_RET_LU_BUSY;
+			return (EBUSY);
+		} else if (sret == SBD_NOT_FOUND) {
+			*err_ret = SBD_RET_NOT_FOUND;
+			return (ENOENT);
+		}
+		return (EIO);
+	}
+
+	sz = strlen(sl->sl_name) + 1;
+	if ((sl->sl_flags & (SL_ZFS_META | SL_SHARED_META)) == 0) {
+		if (sl->sl_data_filename) {
+			sz += strlen(sl->sl_data_filename) + 1;
+		}
+	}
+	sz += sl->sl_serial_no_size;
+	if (sl->sl_alias) {
+		sz += strlen(sl->sl_alias) + 1;
+	}
+
+	bzero(oslp, sizeof (*oslp) - 8);
+	oslp->slp_buf_size_needed = sz;
+
+	if (sz > (oslp_sz - sizeof (*oslp) + 8)) {
+		sl->sl_trans_op = SL_OP_NONE;
+		*err_ret = SBD_RET_INSUFFICIENT_BUF_SPACE;
+		return (ENOMEM);
+	}
+
+	off = 0;
+	(void) strcpy((char *)oslp->slp_buf, sl->sl_name);
+	oslp->slp_meta_fname_off = off;
+	off += strlen(sl->sl_name) + 1;
+	if ((sl->sl_flags & (SL_ZFS_META | SL_SHARED_META)) == 0) {
+		oslp->slp_meta_fname_valid = 1;
+		oslp->slp_separate_meta = 1;
+		if (sl->sl_data_filename) {
+			oslp->slp_data_fname_valid = 1;
+			oslp->slp_data_fname_off = off;
+			(void) strcpy((char *)&oslp->slp_buf[off],
+			    sl->sl_data_filename);
+			off += strlen(sl->sl_data_filename) + 1;
+		}
+	} else {
+		oslp->slp_data_fname_valid = 1;
+		oslp->slp_data_fname_off = oslp->slp_meta_fname_off;
+		if (sl->sl_flags & SL_ZFS_META) {
+			oslp->slp_zfs_meta = 1;
+		}
+	}
+	if (sl->sl_alias) {
+		oslp->slp_alias_valid = 1;
+		oslp->slp_alias_off = off;
+		(void) strcpy((char *)&oslp->slp_buf[off], sl->sl_alias);
+		off += strlen(sl->sl_alias) + 1;
+	}
+	if (sl->sl_serial_no_size) {
+		oslp->slp_serial_off = off;
+		bcopy(sl->sl_serial_no, &oslp->slp_buf[off],
+		    sl->sl_serial_no_size);
+		oslp->slp_serial_size = sl->sl_serial_no_size;
+		oslp->slp_serial_valid = 1;
+		off += sl->sl_serial_no_size;
+	}
+
+	oslp->slp_lu_size = sl->sl_lu_size;
+	oslp->slp_blksize = ((uint16_t)1) << sl->sl_data_blocksize_shift;
+
+	if (sl->sl_flags & SL_VID_VALID) {
+		oslp->slp_lu_vid = 1;
+		bcopy(sl->sl_vendor_id, oslp->slp_vid, 8);
+	} else {
+		bcopy(sbd_vendor_id, oslp->slp_vid, 8);
+	}
+	if (sl->sl_flags & SL_PID_VALID) {
+		oslp->slp_lu_pid = 1;
+		bcopy(sl->sl_product_id, oslp->slp_pid, 16);
+	} else {
+		bcopy(sbd_product_id, oslp->slp_pid, 16);
+	}
+	if (sl->sl_flags & SL_REV_VALID) {
+		oslp->slp_lu_rev = 1;
+		bcopy(sl->sl_revision, oslp->slp_rev, 4);
+	} else {
+		bcopy(sbd_revision, oslp->slp_rev, 4);
+	}
+	bcopy(sl->sl_device_id + 4, oslp->slp_guid, 16);
+
+	if (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE)
+		oslp->slp_writeback_cache_disable_cur = 1;
+	if (sl->sl_flags & SL_SAVED_WRITE_CACHE_DISABLE)
+		oslp->slp_writeback_cache_disable_saved = 1;
+	if (sl->sl_flags & SL_WRITE_PROTECTED)
+		oslp->slp_write_protected = 1;
+
+	sl->sl_trans_op = SL_OP_NONE;
+
+	return (0);
+}
+
+int
+sbd_path_to_zfs_meta(char *src, char *dst)
+{
+	if (strncmp(src, "/dev/zvol", 9) != 0)
+		return (0);
+
+	src += 14;
+	if (*src == '/')
+		src++;
+	(void) strcpy(dst, "/var/tmp/");
+	(void) strcat(dst, src);
+	*(strrchr(dst, '/')) = '_';
+	(void) strcat(dst, ".mat");
+
+	return (1);
+}
+
+char *
+sbd_get_zvol_name(sbd_lu_t *sl)
+{
+	char *src;
+	char *p;
+
+	if (sl->sl_data_filename)
+		src = sl->sl_data_filename;
+	else
+		src = sl->sl_meta_filename;
+	/* There has to be a better way */
+	if (strncmp(src, "/dev/zvol", 9) != 0) {
+		ASSERT(0);
+	}
+	src += 14;
+	if (*src == '/')
+		src++;
+	p = (char *)kmem_alloc(strlen(src) + 1, KM_SLEEP);
+	(void) strcpy(p, src);
+	return (p);
+}
+
+sbd_status_t
+sbd_create_zfs_meta_object(sbd_lu_t *sl)
+{
+	int flag;
+	int ret;
+	char zmt[40];
+
+	ASSERT(sl->sl_zfs_meta_vp == NULL);
+	ASSERT(sl->sl_data_filename);
+	if (!sbd_path_to_zfs_meta(sl->sl_data_filename, zmt)) {
+		stmf_trace(0, "--- sbd_path_to_zfs_meta failed for %s", zmt);
+		return (SBD_FAILURE);
+	}
+
+	flag = FREAD | FWRITE | FOFFMAX | FEXCL | FCREAT | FTRUNC;
+	if ((ret = vn_open(zmt, UIO_SYSSPACE, flag, 0600, &sl->sl_zfs_meta_vp,
+	    CRCREAT, 0)) != 0) {
+		stmf_trace(0, "--- vn_open failed for create, ret = %d", ret);
+		return (SBD_FAILURE);
+	}
+	return (SBD_SUCCESS);
+}
+
+sbd_status_t
+sbd_open_zfs_meta(sbd_lu_t *sl)
+{
+	int flag;
+	char zmt[40];
+
+	ASSERT(sl->sl_zfs_meta_vp == NULL);
+	ASSERT(sl->sl_data_filename);
+	if (!sbd_path_to_zfs_meta(sl->sl_data_filename, zmt)) {
+		return (SBD_FAILURE);
+	}
+
+	flag = FREAD | FWRITE | FOFFMAX | FEXCL;
+	if (vn_open(zmt, UIO_SYSSPACE, flag, 0,
+	    &sl->sl_zfs_meta_vp, 0, 0) != 0) {
+		return (SBD_FAILURE);
+	}
+	return (SBD_SUCCESS);
+}
+
+void
+sbd_close_zfs_meta(sbd_lu_t *sl)
+{
+	int flag;
+
+	flag = FREAD | FWRITE | FOFFMAX | FEXCL;
+	(void) VOP_CLOSE(sl->sl_zfs_meta_vp, flag, 1, 0, CRED(), NULL);
+	VN_RELE(sl->sl_zfs_meta_vp);
+	sl->sl_zfs_meta_vp = NULL;
+}
+
+sbd_status_t
+sbd_read_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz, uint64_t off)
+{
+	int ret;
+	long resid;
+
+	ASSERT(sl->sl_zfs_meta_vp);
+	ret = vn_rdwr(UIO_READ, sl->sl_zfs_meta_vp, (caddr_t)buf, (ssize_t)sz,
+	    (offset_t)off, UIO_SYSSPACE, FSYNC, RLIM64_INFINITY, CRED(),
+	    &resid);
+	if (ret || resid) {
+		return (SBD_FAILURE);
+	}
+	return (SBD_SUCCESS);
+}
+
+sbd_status_t
+sbd_write_zfs_meta(sbd_lu_t *sl, uint8_t *buf, uint64_t sz, uint64_t off)
+{
+	int ret;
+	long resid;
+
+	ASSERT(sl->sl_zfs_meta_vp);
+	ret = vn_rdwr(UIO_WRITE, sl->sl_zfs_meta_vp, (caddr_t)buf, (ssize_t)sz,
+	    (offset_t)off, UIO_SYSSPACE, FSYNC, RLIM64_INFINITY, CRED(),
+	    &resid);
+	if (ret || resid) {
+		return (SBD_FAILURE);
+	}
+	return (SBD_SUCCESS);
+}
+
+/* zvol metadata code to still be implemented */
+int
+/* LINTED E_FUNC_ARG_UNUSED */
+sbd_is_zvol(char *path, vnode_t *vp)
+{
+	return (0);
+#if 0
+	int is_zfs = 0;
+	vnode_t *zvp;
+	vattr_t vattr;
+
+	if (vp != NULL) {
+		zvp = vp;
+		goto over_zvp_open;
+	}
+	if (lookupname(path, UIO_SYSSPACE, FOLLOW, NULLVPP, &zvp) != 0) {
+		return (0);
+	}
+over_zvp_open:
+	vattr.va_mask = AT_RDEV;
+	if (VOP_GETATTR(zvp, &vattr, 0, kcred, NULL) == 0) {
+		is_zfs = (getmajor(vattr.va_rdev) ==
+		    ddi_name_to_major(ZFS_DRIVER)) ? 1 : 0;
+	}
+	if (vp == NULL) {
+		VN_RELE(zvp);
+	}
+
+	return (is_zfs);
+#endif
+}
+
+/*
+ * set write cache disable
+ * wcd - 1 = disable, 0 = enable
+ */
+sbd_status_t
+sbd_wcd_set(int wcd, sbd_lu_t *sl)
+{
+	/* translate to wce bit */
+	int wce = wcd ? 0 : 1;
+	int ret;
+	sbd_status_t sret = SBD_SUCCESS;
+
+	mutex_enter(&sl->sl_lock);
+	sl->sl_flags &= ~SL_WRITEBACK_CACHE_SET_UNSUPPORTED;
+
+	if (sl->sl_data_vp->v_type == VREG) {
+		sl->sl_flags |= SL_FLUSH_ON_DISABLED_WRITECACHE;
+		goto done;
+	}
+
+	ret = VOP_IOCTL(sl->sl_data_vp, DKIOCSETWCE, (intptr_t)&wce, FKIOCTL,
+	    kcred, NULL, NULL);
+	if (ret == 0) {
+		sl->sl_flags &= ~SL_WRITEBACK_CACHE_SET_UNSUPPORTED;
+		sl->sl_flags &= ~SL_FLUSH_ON_DISABLED_WRITECACHE;
+	} else {
+		sl->sl_flags |= SL_WRITEBACK_CACHE_SET_UNSUPPORTED;
+		sl->sl_flags |= SL_FLUSH_ON_DISABLED_WRITECACHE;
+		sret = SBD_FAILURE;
+		goto done;
+	}
+
+done:
+	mutex_exit(&sl->sl_lock);
+	return (sret);
+}
+
+/*
+ * get write cache disable
+ * wcd - 1 = disable, 0 = enable
+ */
+void
+sbd_wcd_get(int *wcd, sbd_lu_t *sl)
+{
+	int wce;
+	int ret;
+
+	if (sl->sl_data_vp->v_type == VREG) {
+		*wcd = 0;
+		return;
+	}
+
+	ret = VOP_IOCTL(sl->sl_data_vp, DKIOCGETWCE, (intptr_t)&wce, FKIOCTL,
+	    kcred, NULL, NULL);
+	/* if write cache get failed, assume disabled */
+	if (ret) {
+		*wcd = 1;
+	} else {
+		/* translate to wcd bit */
+		*wcd = wce ? 0 : 1;
+	}
 }
 
 
 /*
- * Version 0 format of metadata was never integrated into solaris. It
- * was the format used by early opensolaris release until feb. 2008.
- * Subsequent opensolaris releases used version 1 and thats what
- * was integrated into solaris as well. At some point V0 stuff should be
- * completely removed.
+ * check for a zvol with sbd metadata object.
  */
 int
-sbd_is_meta_v0(sbd_store_t *sst, uint64_t *meta_size, uint64_t *meta_offset)
+sbd_is_sbd_zvol(char *path, vnode_t *vp)
 {
-	sbd_v0_meta_start_t m;
+	char zmt[40];
+	vnode_t *zvp;
 
-	*meta_offset = 4096;
-v0_check:;
-	if (sbd_aligned_meta_read(sst, *meta_offset, 16, (uint8_t *)&m) !=
-	    STMF_SUCCESS) {
+	if (!sbd_is_zvol(path, vp)) {
+		return (0);
+	}
+	if (!sbd_path_to_zfs_meta(path, zmt)) {
 		return (0);
 	}
 
-	if (m.sm_magic != SBD_V0_MAGIC) {
-		m.sm_magic = BSWAP_64(m.sm_magic);
-		if (m.sm_magic != SBD_V0_MAGIC) {
-			if (*meta_offset == 4096) {
-				*meta_offset = 0;
-				goto v0_check;
-			}
-			return (0);
-		}
-		m.sm_meta_size = BSWAP_64(m.sm_meta_size);
+	if (lookupname(zmt, UIO_SYSSPACE, FOLLOW, NULLVPP, &zvp) != 0) {
+		return (0);
 	}
-
-	*meta_size = m.sm_meta_size;
-
+	VN_RELE(zvp);
 	return (1);
 }
-
-int
-sbd_migrate_meta_from_v0_to_v1(sbd_store_t *sst)
-{
-	uint64_t v0_meta_size;
-	uint64_t v0_meta_offset;
-	sbd_v0_lu_info_t *v0sli;
-	sbd_lu_info_t *sli;
-	sbd_meta_start_t *sm;
-	sm_section_hdr_t *h;
-	int ret = 0;
-
-	if (!sbd_is_meta_v0(sst, &v0_meta_size, &v0_meta_offset))
-		return (0);
-
-	v0sli = kmem_zalloc(sizeof (*v0sli), KM_SLEEP);
-	sm = kmem_zalloc(sizeof (*sm) + sizeof (*sli), KM_SLEEP);
-	sli = (sbd_lu_info_t *)(((uint8_t *)sm) + sizeof (*sm));
-	if (sbd_aligned_meta_read(sst, v0_meta_offset + 16, sizeof (*v0sli),
-	    (uint8_t *)v0sli) != STMF_SUCCESS) {
-		goto mv0v1_exit;
-	}
-	sm->sm_magic = SBD_MAGIC;
-	sm->sm_meta_size = v0_meta_size;
-	sm->sm_meta_size_used = sbd_meta_offset + sizeof (*sm) + sizeof (*sli);
-	sm->sm_ver_major = 1;
-	sm->sm_chksum = sbd_calc_sum((uint8_t *)sm, sizeof (sbd_meta_start_t));
-
-	h = &sli->sli_sms_header;
-	h->sms_offset = sbd_meta_offset + sizeof (*sm);
-	h->sms_size = sizeof (*sli);
-	h->sms_id = SMS_ID_LU_INFO;
-	h->sms_data_order = SMS_DATA_ORDER;
-	if (v0sli->sli_sms_header.sms_payload_data_order == SMS_DATA_ORDER) {
-		sli->sli_total_store_size = v0sli->sli_total_store_size;
-		sli->sli_total_meta_size = v0sli->sli_total_meta_size;
-		sli->sli_lu_data_offset = v0sli->sli_lu_data_offset;
-		sli->sli_lu_data_size = v0sli->sli_lu_data_size;
-	} else {
-		sli->sli_total_store_size =
-		    BSWAP_64(v0sli->sli_total_store_size);
-		sli->sli_total_meta_size =
-		    BSWAP_64(v0sli->sli_total_meta_size);
-		sli->sli_lu_data_offset =
-		    BSWAP_64(v0sli->sli_lu_data_offset);
-		sli->sli_lu_data_size =
-		    BSWAP_64(v0sli->sli_lu_data_size);
-	}
-	/* sli_flags were not used in v0 */
-	sli->sli_blocksize = 512;
-	sli->sli_data_order = SMS_DATA_ORDER;
-	bcopy(v0sli->sli_lu_devid, sli->sli_lu_devid, 20);
-	h->sms_chksum = sbd_calc_sum((uint8_t *)h, h->sms_size);
-
-	if (sbd_aligned_meta_write(sst, sbd_meta_offset,
-	    sizeof (*sm) + sizeof (*sli), (uint8_t *)sm) != STMF_SUCCESS) {
-		goto mv0v1_exit;
-	}
-
-	ret = 1;
-mv0v1_exit:
-	kmem_free(v0sli, sizeof (*v0sli));
-	kmem_free(sm, sizeof (*sm) + sizeof (*sli));
-
-	return (ret);
-}
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_impl.h	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_impl.h	Fri May 08 16:22:42 2009 -0600
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -47,6 +47,13 @@
 #define	SMS_DATA_ORDER	SMS_LITTLE_ENDIAN
 #endif
 
+/* Test if one of the BitOrder definitions exists */
+#ifdef _BIT_FIELDS_LTOH
+#elif defined(_BIT_FIELDS_HTOL)
+#else
+#error  One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
+#endif
+
 #define	SBD_V0_MAGIC	0x53554e4d4943524f
 #define	SBD_MAGIC	0x53554e5342444c55
 
@@ -80,18 +87,79 @@
 	uint32_t	rsvd3;		/* 8 byte align */
 } sm_v0_section_hdr_t;
 
-typedef struct sm_section_hdr {
-	uint64_t	sms_offset;	/* Offset of this section */
-	uint32_t	sms_size;	/* Includes the header and padding */
-	uint16_t	sms_id;		/* Section identifier */
-	uint8_t		sms_data_order; /* 0x00 or 0xff */
-	uint8_t		sms_chksum;
-} sm_section_hdr_t;
+/*
+ * sbd_it_flags
+ */
+#define	SBD_IT_HAS_SCSI2_RESERVATION	0x0001
+#define	SBD_IT_PGR_REGISTERED		0x0002
+#define	SBD_IT_PGR_EXCLUSIVE_RSV_HOLDER	0x0004
+#define	SBD_IT_PGR_CHECK_FLAG		0x0008
+
+/*
+ * PGR flags
+ */
+#define	SBD_PGR_APTPL			0x01
+#define	SBD_PGR_RSVD_ONE		0x02
+#define	SBD_PGR_RSVD_ALL_REGISTRANTS	0x04
+#define	SBD_PGR_ALL_KEYS_HAS_IT		0x08
+
+#define	SBD_PGR_RSVD(pgr)	(((pgr)->pgr_flags) & (SBD_PGR_RSVD_ONE | \
+					SBD_PGR_RSVD_ALL_REGISTRANTS))
+#define	SBD_PGR_RSVD_NONE(pgr)	(!(SBD_PGR_RSVD(pgr)))
 
 /*
- * sbd meta section identifiers
+ * PGR key flags
  */
-#define	SMS_ID_LU_INFO	0
+#define	SBD_PGR_KEY_ALL_TG_PT		0x01
+
+typedef struct sbd_pgr_key_info {
+	uint64_t	pgr_key;
+	uint16_t	pgr_key_lpt_len;
+	uint16_t	pgr_key_rpt_len;
+	uint8_t		pgr_key_flags;
+	uint8_t		pgr_key_it[1];	/* devid_desc of initiator will be */
+					/* followed by devid_desc of target */
+} sbd_pgr_key_info_t;
+
+typedef struct sbd_pgr_info {
+	sm_section_hdr_t	pgr_sms_header;
+	uint32_t		pgr_rsvholder_indx;
+	uint32_t		pgr_numkeys;
+	uint8_t			pgr_flags;
+	uint8_t			pgr_data_order;
+#ifdef _BIT_FIELDS_LTOH
+	uint8_t			pgr_rsv_type:4,
+				pgr_rsv_scope:4;
+#else
+	uint8_t			pgr_rsv_scope:4,
+				pgr_rsv_type:4;
+#endif
+	uint8_t			rsvd[5];	/* 8 byte boundary */
+
+} sbd_pgr_info_t;
+
+typedef struct sbd_pgr_key {
+	uint64_t		pgr_key;
+	uint16_t		pgr_key_lpt_len;
+	uint16_t		pgr_key_rpt_len;
+	uint8_t			pgr_key_flags;
+	struct scsi_devid_desc	*pgr_key_lpt_id;
+	struct scsi_devid_desc	*pgr_key_rpt_id;
+	struct sbd_it_data	*pgr_key_it;
+	struct sbd_pgr_key	*pgr_key_next;
+	struct sbd_pgr_key	*pgr_key_prev;
+} sbd_pgr_key_t;
+
+typedef struct sbd_pgr {
+	sbd_pgr_key_t		*pgr_keylist;
+	sbd_pgr_key_t		*pgr_rsvholder;
+	uint32_t		pgr_PRgeneration; /* PGR PRgeneration value */
+	uint8_t			pgr_flags;	/* PGR flags (eg: APTPL)  */
+	uint8_t			pgr_rsv_type:4,
+				pgr_rsv_scope:4;
+	krwlock_t		pgr_lock; /* Lock order pgr_lock, sl_lock */
+} sbd_pgr_t;
+
 
 typedef struct sbd_v0_lu_info {
 	sm_v0_section_hdr_t	sli_sms_header;
@@ -122,26 +190,6 @@
 	uint32_t		rsvd2;
 } sbd_lu_info_t;
 
-typedef struct sbd_lu {
-	sbd_store_t			*sl_sst;
-	uint32_t			sl_total_allocation_size;
-	uint8_t				sl_shift_count;
-	uint8_t				sl_state:7,
-					sl_state_not_acked:1;
-	uint8_t				sl_flags;
-	kmutex_t			sl_it_list_lock;
-	struct sbd_it_data		*sl_it_list;
-	uint64_t			sl_rs_owner_session_id;
-	stmf_lu_t			*sl_lu;
-	struct sbd_lu			*sl_next; /* for int. tracking */
-
-	sbd_meta_start_t		sl_sm;
-	sbd_lu_info_t			*sl_sli;
-	uint64_t			sl_meta_offset;
-} sbd_lu_t;
-
-extern sbd_lu_t *sbd_lu_list;
-
 /*
  * sl_flags
  */
@@ -171,6 +219,7 @@
 #define	SBD_CMD_SCSI_WRITE	0x02
 #define	SBD_CMD_SMALL_READ	0x03
 #define	SBD_CMD_SMALL_WRITE	0x04
+#define	SBD_CMD_SCSI_PR_OUT	0x05
 
 typedef struct sbd_it_data {
 	struct sbd_it_data	*sbd_it_next;
@@ -178,6 +227,7 @@
 	uint8_t			sbd_it_lun[8];
 	uint8_t			sbd_it_ua_conditions;
 	uint8_t			sbd_it_flags;
+	sbd_pgr_key_t		*pgr_key_ptr;
 } sbd_it_data_t;
 
 /*
@@ -185,11 +235,15 @@
  */
 #define	SBD_UA_POR			0x01
 #define	SBD_UA_CAPACITY_CHANGED		0x02
+#define	SBD_UA_MODE_PARAMETERS_CHANGED	0x04
+#define	SBD_UA_REGISTRATIONS_PREEMPTED	0x10
+#define	SBD_UA_RESERVATIONS_PREEMPTED	0x20
+#define	SBD_UA_RESERVATIONS_RELEASED	0x40
 
 /*
  * sbd_it_flags
  */
-#define	SBD_IT_HAS_SCSI2_RESERVATION		0x0001
+#define	SBD_IT_HAS_SCSI2_RESERVATION	0x0001
 
 stmf_status_t sbd_task_alloc(struct scsi_task *task);
 void sbd_new_task(struct scsi_task *task, struct stmf_data_buf *initial_dbuf);
@@ -202,14 +256,6 @@
 stmf_status_t sbd_info(uint32_t cmd, stmf_lu_t *lu, void *arg,
 				uint8_t *buf, uint32_t *bufsizep);
 
-stmf_status_t memdisk_register_lu(struct register_lu_cmd *rlc);
-stmf_status_t memdisk_deregister_lu(sbd_store_t *sst);
-stmf_status_t filedisk_register_lu(struct register_lu_cmd *rlc);
-stmf_status_t filedisk_deregister_lu(sbd_store_t *sst);
-stmf_status_t filedisk_modify_lu(sbd_store_t *sst, struct modify_lu_cmd *mlc);
-void filedisk_fillout_attr(struct sbd_store *sst, struct sbd_lu_attr *sla);
-void memdisk_fillout_attr(struct sbd_store *sst, struct sbd_lu_attr *sla);
-
 #ifdef	__cplusplus
 }
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_pgr.c	Fri May 08 16:22:42 2009 -0600
@@ -0,0 +1,1905 @@
+/*
+ * 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/atomic.h>
+#include <sys/conf.h>
+#include <sys/byteorder.h>
+#include <sys/scsi/scsi_types.h>
+#include <sys/scsi/generic/persist.h>
+
+#include <lpif.h>
+#include <stmf.h>
+#include <stmf_ioctl.h>
+#include <stmf_sbd.h>
+#include <sbd_impl.h>
+#include <portif.h>
+#include <stmf_sbd_ioctl.h>
+
+#define	MAX_PGR_PARAM_LIST_LENGTH	(256 * 1024)
+
+int  sbd_pgr_reservation_conflict(scsi_task_t *);
+void sbd_pgr_initialize_it(scsi_task_t *);
+void sbd_handle_pgr_in_cmd(scsi_task_t *, stmf_data_buf_t *);
+void sbd_handle_pgr_out_cmd(scsi_task_t *, stmf_data_buf_t *);
+void sbd_handle_pgr_out_data(scsi_task_t *, stmf_data_buf_t *);
+void sbd_pgr_keylist_dealloc(sbd_lu_t *);
+uint32_t sbd_get_tptid_length_for_devid(scsi_devid_desc_t *);
+uint32_t sbd_devid_desc_to_tptid(scsi_devid_desc_t *, scsi_transport_id_t *);
+scsi_devid_desc_t *sbd_tptid_to_devid_desc(scsi_transport_id_t *, uint32_t *);
+char *sbd_get_devid_string(sbd_lu_t *);
+
+sbd_status_t sbd_pgr_meta_load(sbd_lu_t *);
+sbd_status_t sbd_pgr_meta_write(sbd_lu_t *);
+static void sbd_swap_pgr_info(sbd_pgr_info_t *);
+static void sbd_swap_pgrkey_info(sbd_pgr_key_info_t *);
+static void sbd_pgr_key_free(sbd_pgr_key_t *);
+static void sbd_pgr_remove_key(sbd_lu_t *, sbd_pgr_key_t *);
+static uint32_t sbd_pgr_remove_keys(sbd_lu_t *, sbd_it_data_t *,
+	sbd_pgr_key_t *, uint64_t, boolean_t);
+static boolean_t sbd_pgr_key_compare(sbd_pgr_key_t *, scsi_devid_desc_t *,
+	scsi_devid_desc_t *rpt);
+static sbd_pgr_key_t *sbd_pgr_key_alloc(scsi_devid_desc_t *,
+	scsi_devid_desc_t *, int8_t, int8_t);
+
+static void sbd_pgr_set_pgr_check_flag(sbd_lu_t *, boolean_t);
+static void sbd_pgr_set_ua_conditions(sbd_lu_t *, sbd_it_data_t *, uint8_t);
+static void sbd_pgr_in_read_keys(scsi_task_t *, stmf_data_buf_t *);
+static void sbd_pgr_in_report_capabilities(scsi_task_t *, stmf_data_buf_t *);
+static void sbd_pgr_in_read_reservation(scsi_task_t *, stmf_data_buf_t *);
+static void sbd_pgr_in_read_full_status(scsi_task_t *, stmf_data_buf_t *);
+static void sbd_pgr_out_register(scsi_task_t *, stmf_data_buf_t *);
+static void sbd_pgr_out_reserve(scsi_task_t *);
+static void sbd_pgr_out_release(scsi_task_t *);
+static void sbd_pgr_out_clear(scsi_task_t *);
+static void sbd_pgr_out_preempt(scsi_task_t *, stmf_data_buf_t *);
+static void sbd_pgr_out_register_and_move(scsi_task_t *, stmf_data_buf_t *);
+
+static sbd_pgr_key_t *sbd_pgr_do_register(sbd_lu_t *, sbd_it_data_t *,
+	scsi_devid_desc_t *, scsi_devid_desc_t *, uint8_t, uint64_t);
+static void sbd_pgr_do_unregister(sbd_lu_t *, sbd_it_data_t *, sbd_pgr_key_t *);
+static void sbd_pgr_do_release(sbd_lu_t *, sbd_it_data_t *, uint8_t);
+static void sbd_pgr_do_reserve(sbd_pgr_t *, sbd_pgr_key_t *, sbd_it_data_t *it,
+	stmf_scsi_session_t *, scsi_cdb_prout_t *);
+
+extern sbd_status_t sbd_write_meta_section(sbd_lu_t *, sm_section_hdr_t *);
+extern sbd_status_t sbd_read_meta_section(sbd_lu_t *, sm_section_hdr_t **,
+	uint16_t);
+extern void sbd_swap_section_hdr(sm_section_hdr_t *);
+extern void sbd_handle_short_write_transfers(scsi_task_t *task,
+	stmf_data_buf_t *dbuf, uint32_t cdb_xfer_size);
+extern void sbd_handle_short_read_transfers(scsi_task_t *task,
+	stmf_data_buf_t *dbuf, uint8_t *p, uint32_t cdb_xfer_size,
+	uint32_t cmd_xfer_size);
+extern uint16_t stmf_scsilib_get_lport_rtid(scsi_devid_desc_t *devid);
+extern scsi_devid_desc_t *stmf_scsilib_get_devid_desc(uint16_t rtpid);
+
+/*
+ *
+ *
+ *   +-----------+
+ *   |           |sl_it_list
+ *   |           |---------------------------------------+
+ *   |           |                                       |
+ *   |  sbd_lu_t |                                       |
+ *   |           |                                       |
+ *   |           |                                       |
+ *   |           |                                       |
+ *   +-----+-----+                                       V
+ *         |                                          +-------+
+ *         V                                          |       |
+ *   +-----------+ pgr_key_list               +------>|       |
+ *   |           |------------+  +-->(NULL)   | +- ---|sbd_it |
+ *   |           |            |  |            | |     | _data |
+ *   | sbd_pgr_t |            V  |            | |     |       |
+ *   |           |          +-------+         | |     +-------+
+ *   |           |---+      |       |         | |         |
+ *   |           |   |      |sbd_pgr|---------+ |         v
+ *   +-----------+   |      | _key_t|<----------+     +-------+
+ *                   |      |       |                 |       |
+ *                   |      |       |                 |       |
+ *                   |      +-------+        +--------|       |
+ *                   |         |^            |        |       |
+ *                   |         ||            |        |       |
+ *                   |         v|            |        +-------+
+ *                   |      +-------+        |            |
+ *                   |      |       |        |            v
+ *                   |      |ALL_TG_|<-------+        +-------+
+ *                   |      |PT = 1 |<---------+      |       |
+ *                   |      |       |---+      |      |       |
+ *                   |      |       |   |      +------|       |
+ *          (pgr_rsvholder  +-------+   V             |       |
+ *             pgr_flags&      |^     (NUll)          |       |
+ *              RSVD_ONE)      ||                     +-------+
+ *                   |         v|                         |
+ *                   |      +-------+                     v
+ *                   |      |       |                 +-------+
+ *                   |      |  not  |                 |       |
+ *                   |      |claimed|---+             |       |
+ *                   |      |       |   |        +----| unreg |
+ *                   |      |       |   V        |    |       |
+ *                   |      +-------+ (NUll)     V    |       |
+ *                   |         |^              (NUll) +-------+
+ *                   |         ||                         |
+ *                   |         v|                         v
+ *                   |      +-------+                 +-------+
+ *                   |      |       |                 |       |
+ *                   |      |reserv-|<----------------|       |
+ *                   +----->|  ation|---------------->|       |
+ *                          |holder |                 |       |
+ *                          |key    |                 |       |
+ *                          +-------+                 +-------+
+ *                              |^                        |
+ *                              ||                        v
+ *                              v|                    +-------+
+ *                           +-------+                |       |
+ *                           |       |                |       |
+ *                           |  not  |---+       +----| unreg |
+ *                           |claimed|   |       |    |       |
+ *                           |       |   V       V    |       |
+ *                           |       | (NUll)  (NUll) +-------+
+ *                           +-------+                    |
+ *                              |                         v
+ *                              v                      (NULL)
+ *                           (NULL)
+ *
+ *
+ */
+
+#define	PGR_CONFLICT_FREE_CMDS(cdb)	( \
+	/* ----------------------- */                                      \
+	/* SPC-3 (rev 23) Table 31 */                                      \
+	/* ----------------------- */                                      \
+	((cdb[0]) == SCMD_INQUIRY)					|| \
+	((cdb[0]) == SCMD_LOG_SENSE_G1)					|| \
+	((cdb[0]) == SCMD_PERSISTENT_RESERVE_IN)			|| \
+	((cdb[0]) == SCMD_REPORT_LUNS)					|| \
+	((cdb[0]) == SCMD_REQUEST_SENSE)				|| \
+	((cdb[0]) == SCMD_TEST_UNIT_READY)				|| \
+	/* PREVENT ALLOW MEDIUM REMOVAL with prevent == 0 */               \
+	((((cdb[0]) == SCMD_DOORLOCK) && (((cdb[4]) & 0x3) == 0)))	|| \
+	/* SERVICE ACTION IN with READ MEDIA SERIAL NUMBER (0x01) */       \
+	(((cdb[0]) == SCMD_SVC_ACTION_IN_G5) && (                          \
+	    ((cdb[1]) & 0x1F) == 0x01))					|| \
+	/* MAINTENANCE IN with service actions REPORT ALIASES (0x0Bh) */   \
+	/* REPORT DEVICE IDENTIFIER (0x05)  REPORT PRIORITY (0x0Eh) */     \
+	/* REPORT TARGET PORT GROUPS (0x0A) REPORT TIMESTAMP (0x0F) */     \
+	(((cdb[0]) == SCMD_MAINTENANCE_IN) && (                            \
+	    (((cdb[1]) & 0x1F) == 0x0B) ||                                 \
+	    (((cdb[1]) & 0x1F) == 0x05) ||                                 \
+	    (((cdb[1]) & 0x1F) == 0x0E) ||                                 \
+	    (((cdb[1]) & 0x1F) == 0x0A) ||                                 \
+	    (((cdb[1]) & 0x1F) == 0x0F)))				|| \
+	/* REGISTER and REGISTER_AND_IGNORE_EXISTING_KEY */                \
+	/* actions for PERSISTENT RESERVE OUT command */                   \
+	(((cdb[0]) == SCMD_PERSISTENT_RESERVE_OUT) && (                    \
+	    (((cdb[1]) & 0x1F) == PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY) || \
+	    (((cdb[1]) & 0x1F) == PR_OUT_REGISTER))) 			|| \
+	/* ----------------------- */                                      \
+	/* SBC-3 (rev 17) Table 3  */                                      \
+	/* ----------------------- */                                      \
+	/* READ CAPACITY(10) */                                            \
+	((cdb[0]) == SCMD_READ_CAPACITY)				|| \
+	/* READ CAPACITY(16) */                                            \
+	(((cdb[0]) == SCMD_SVC_ACTION_IN_G4) && (                          \
+	    ((cdb[1]) & 0x1F) == 0x10))					|| \
+	/* START STOP UNIT with START bit 0 and POWER CONDITION 0  */      \
+	(((cdb[0]) == SCMD_START_STOP) && (                                \
+	    (((cdb[4]) & 0xF0) == 0) && (((cdb[4]) & 0x01) == 0))))
+/* End of PGR_CONFLICT_FREE_CMDS */
+
+/* Commands allowed for registered IT nexues but not reservation holder */
+#define	PGR_REGISTERED_POSSIBLE_CMDS(cdb)	( \
+	(((cdb[0]) == SCMD_PERSISTENT_RESERVE_OUT) && (                \
+	    (((cdb[1]) & 0x1F) == PR_OUT_RELEASE)		||     \
+	    (((cdb[1]) & 0x1F) == PR_OUT_CLEAR)			||     \
+	    (((cdb[1]) & 0x1F) == PR_OUT_PREEMPT)		||     \
+	    (((cdb[1]) & 0x1F) == PR_OUT_PREEMPT_ABORT))))
+
+/* List of commands allowed when WR_EX type reservation held */
+#define	PGR_READ_POSSIBLE_CMDS(c)	(  \
+	((c) == SCMD_READ)		|| \
+	((c) == SCMD_READ_G1)		|| \
+	((c) == SCMD_READ_G4)		|| \
+	((c) == SCMD_READ_G5)		|| \
+	/* READ FETCH (10) (16) */         \
+	((c) == SCMD_READ_POSITION)	|| \
+	((c) == 0x90)			|| \
+	/* READ DEFECT DATA */             \
+	((c) == SCMD_READ_DEFECT_LIST)	|| \
+	((c) == 0xB7)			|| \
+	/* VERIFY (10) (16) (12) */        \
+	((c) == SCMD_VERIFY)		|| \
+	((c) == SCMD_VERIFY_G4)		|| \
+	((c) == SCMD_VERIFY_G5)		|| \
+	/* XDREAD (10) */                  \
+	((c) == 0x52))
+
+#define	PGR_RESERVATION_HOLDER(pgr, key, it)	( \
+	((pgr)->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS) || ( \
+	    ((pgr)->pgr_rsvholder) && ((pgr)->pgr_rsvholder == (key)) && \
+	    ((key)->pgr_key_it) && ((key)->pgr_key_it == (it))))
+
+#define	PGR_SET_FLAG(flg, val)		(atomic_or_8(&(flg), (val)))
+#define	PGR_CLEAR_FLAG(flg, val)	(atomic_and_8(&(flg), ~(val)))
+#define	PGR_CLEAR_RSV_FLAG(flg)		(atomic_and_8(&(flg), \
+	(~(SBD_PGR_RSVD_ALL_REGISTRANTS | SBD_PGR_RSVD_ONE))))
+
+#define	PGR_VALID_SCOPE(scope)	((scope) == PR_LU_SCOPE)
+#define	PGR_VALID_TYPE(type)	( \
+				((type) == PGR_TYPE_WR_EX)	|| \
+				((type) == PGR_TYPE_EX_AC)	|| \
+				((type) == PGR_TYPE_WR_EX_RO)	|| \
+				((type) == PGR_TYPE_EX_AC_RO)	|| \
+				((type) == PGR_TYPE_WR_EX_AR)	|| \
+				((type) == PGR_TYPE_EX_AC_AR))
+
+#define	ALIGNED_TO_WORD_BOUNDARY(i)	(((i) + 7) & ~7)
+
+static void
+sbd_swap_pgr_info(sbd_pgr_info_t *spi)
+{
+	sbd_swap_section_hdr(&spi->pgr_sms_header);
+	if (spi->pgr_data_order == SMS_DATA_ORDER)
+		return;
+	spi->pgr_sms_header.sms_chksum += SMS_DATA_ORDER - spi->pgr_data_order;
+	spi->pgr_rsvholder_indx		= BSWAP_32(spi->pgr_rsvholder_indx);
+	spi->pgr_numkeys		= BSWAP_32(spi->pgr_numkeys);
+}
+
+static void
+sbd_swap_pgrkey_info(sbd_pgr_key_info_t *key)
+{
+	key->pgr_key			= BSWAP_64(key->pgr_key);
+	key->pgr_key_lpt_len		= BSWAP_16(key->pgr_key_lpt_len);
+	key->pgr_key_rpt_len		= BSWAP_16(key->pgr_key_rpt_len);
+}
+
+sbd_status_t
+sbd_pgr_meta_load(sbd_lu_t *slu)
+{
+	sbd_pgr_t		*pgr = slu->sl_pgr;
+	sbd_pgr_info_t		*spi = NULL;
+	sbd_pgr_key_t		*key, *last_key = NULL;
+	sbd_pgr_key_info_t	*spi_key;
+	sbd_status_t		ret = SBD_SUCCESS;
+	scsi_devid_desc_t	*lpt, *rpt;
+	uint8_t			*ptr, *keyoffset,  *endoffset;
+	uint32_t		i, sz;
+
+	ret = sbd_read_meta_section(slu, (sm_section_hdr_t **)&spi,
+	    SMS_ID_PGR_INFO);
+	if (ret != SBD_SUCCESS) {
+		/* No PGR section found, means volume made before PGR support */
+		if (ret == SBD_NOT_FOUND) {
+			/* So just create a default PGR section */
+			ret = sbd_pgr_meta_write(slu);
+		}
+		return (ret);
+	}
+	if (spi->pgr_data_order != SMS_DATA_ORDER) {
+		sbd_swap_pgr_info(spi);
+	}
+
+	pgr->pgr_flags = spi->pgr_flags;
+	if (pgr->pgr_flags & SBD_PGR_APTPL) {
+		pgr->pgr_rsv_type = spi->pgr_rsv_type;
+		pgr->pgr_rsv_scope = spi->pgr_rsv_scope;
+	} else {
+		PGR_CLEAR_RSV_FLAG(pgr->pgr_flags);
+	}
+	PGR_CLEAR_FLAG(slu->sl_pgr->pgr_flags, SBD_PGR_ALL_KEYS_HAS_IT);
+
+	endoffset	= (uint8_t *)spi;
+	endoffset	+= spi->pgr_sms_header.sms_size;
+	keyoffset	= (uint8_t *)(spi + 1);
+	for (i = 1; i <= spi->pgr_numkeys; i++) {
+
+		spi_key = (sbd_pgr_key_info_t *)keyoffset;
+		if (spi->pgr_data_order != SMS_DATA_ORDER) {
+			sbd_swap_pgrkey_info(spi_key);
+		}
+
+		/* Calculate the size and next offset */
+		sz = ALIGNED_TO_WORD_BOUNDARY(sizeof (sbd_pgr_key_info_t) - 1 +
+		    spi_key->pgr_key_lpt_len + spi_key->pgr_key_rpt_len);
+		keyoffset += sz;
+
+		/* Validate the key fields */
+		if (spi_key->pgr_key_rpt_len == 0 || endoffset < keyoffset ||
+		    (spi_key->pgr_key_lpt_len == 0 &&
+		    !(spi_key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT))) {
+			char *lun_name = sbd_get_devid_string(slu);
+			sbd_pgr_keylist_dealloc(slu);
+			kmem_free(spi, spi->pgr_sms_header.sms_size);
+			cmn_err(CE_WARN, "sbd_pgr_meta_load: Failed to load "
+			    "PGR meta data for lun %s.", lun_name);
+			kmem_free(lun_name, strlen(lun_name) + 1);
+			return (SBD_META_CORRUPTED);
+		}
+
+		lpt = (scsi_devid_desc_t *)spi_key->pgr_key_it;
+		ptr = (uint8_t *)spi_key->pgr_key_it + spi_key->pgr_key_lpt_len;
+		rpt = (scsi_devid_desc_t *)ptr;
+		key = sbd_pgr_key_alloc(lpt, rpt, spi_key->pgr_key_lpt_len,
+		    spi_key->pgr_key_rpt_len);
+
+		key->pgr_key		= spi_key->pgr_key;
+		key->pgr_key_flags	= spi_key->pgr_key_flags;
+		key->pgr_key_prev	= last_key;
+
+		if (last_key) {
+			last_key->pgr_key_next = key;
+		} else {
+			pgr->pgr_keylist = key;
+		}
+		last_key = key;
+
+		if ((pgr->pgr_flags & SBD_PGR_RSVD_ONE) &&
+		    (i == spi->pgr_rsvholder_indx)) {
+			pgr->pgr_rsvholder = key;
+		}
+	}
+
+	kmem_free(spi, spi->pgr_sms_header.sms_size);
+	return (ret);
+}
+
+sbd_status_t
+sbd_pgr_meta_write(sbd_lu_t *slu)
+{
+	sbd_pgr_key_t		*key;
+	sbd_pgr_info_t		*spi;
+	sbd_pgr_key_info_t	*spi_key;
+	sbd_pgr_t		*pgr = slu->sl_pgr;
+	sbd_status_t		ret = SBD_SUCCESS;
+	uint32_t		sz, totalsz;
+
+	/* Calculate total pgr meta section size needed */
+	sz = sizeof (sbd_pgr_info_t);
+	if (pgr->pgr_flags & SBD_PGR_APTPL) {
+		key = pgr->pgr_keylist;
+		while (key != NULL) {
+			sz = ALIGNED_TO_WORD_BOUNDARY(sz +
+			    sizeof (sbd_pgr_key_info_t) - 1 +
+			    key->pgr_key_lpt_len + key->pgr_key_rpt_len);
+			key = key->pgr_key_next;
+		}
+	}
+	totalsz = sz;
+
+	spi = (sbd_pgr_info_t *)kmem_zalloc(totalsz, KM_SLEEP);
+	spi->pgr_flags		= pgr->pgr_flags;
+	spi->pgr_rsv_type	= pgr->pgr_rsv_type;
+	spi->pgr_rsv_scope	= pgr->pgr_rsv_scope;
+	spi->pgr_data_order	= SMS_DATA_ORDER;
+	spi->pgr_numkeys	= 0;
+
+	spi->pgr_sms_header.sms_size = totalsz;
+	spi->pgr_sms_header.sms_id = SMS_ID_PGR_INFO;
+	spi->pgr_sms_header.sms_data_order = SMS_DATA_ORDER;
+
+	if (pgr->pgr_flags & SBD_PGR_APTPL) {
+		uint8_t *ptr;
+		key = pgr->pgr_keylist;
+		sz = sizeof (sbd_pgr_info_t);
+		while (key != NULL) {
+			spi_key = (sbd_pgr_key_info_t *)((uint8_t *)spi + sz);
+			spi_key->pgr_key = key->pgr_key;
+			spi_key->pgr_key_lpt_len = key->pgr_key_lpt_len;
+			spi_key->pgr_key_rpt_len = key->pgr_key_rpt_len;
+			ptr = spi_key->pgr_key_it;
+			bcopy(key->pgr_key_lpt_id, ptr, key->pgr_key_lpt_len);
+			ptr += key->pgr_key_lpt_len;
+			bcopy(key->pgr_key_rpt_id, ptr, key->pgr_key_rpt_len);
+
+			spi->pgr_numkeys++;
+			if (key == pgr->pgr_rsvholder) {
+				spi->pgr_rsvholder_indx = spi->pgr_numkeys;
+			}
+
+			sz = ALIGNED_TO_WORD_BOUNDARY(sz +
+			    sizeof (sbd_pgr_key_info_t) - 1 +
+			    key->pgr_key_lpt_len + key->pgr_key_rpt_len);
+			key = key->pgr_key_next;
+		}
+	}
+
+	ret = sbd_write_meta_section(slu, (sm_section_hdr_t *)spi);
+	kmem_free(spi, totalsz);
+	if (ret != SBD_SUCCESS) {
+		sbd_pgr_key_t	*tmp_list;
+		tmp_list = pgr->pgr_keylist;
+		pgr->pgr_keylist = NULL;
+		if (sbd_pgr_meta_load(slu) != SBD_SUCCESS) {
+			char *lun_name = sbd_get_devid_string(slu);
+			cmn_err(CE_WARN, "sbd_pgr_meta_write: Failed to revert "
+			    "back to existing PGR state after meta write "
+			    "failure, may cause PGR inconsistancy for lun %s.",
+			    lun_name);
+			kmem_free(lun_name, strlen(lun_name) + 1);
+			pgr->pgr_keylist = tmp_list;
+		} else {
+			key = pgr->pgr_keylist;
+			pgr->pgr_keylist = tmp_list;
+			sbd_pgr_set_pgr_check_flag(slu, B_TRUE);
+			sbd_pgr_keylist_dealloc(slu);
+			pgr->pgr_keylist = key;
+		}
+
+	}
+	return (ret);
+}
+
+static sbd_pgr_key_t *
+sbd_pgr_key_alloc(scsi_devid_desc_t *lptid, scsi_devid_desc_t *rptid,
+					int8_t lpt_len, int8_t rpt_len)
+{
+	sbd_pgr_key_t *key;
+
+	key = (sbd_pgr_key_t *)kmem_zalloc(sizeof (sbd_pgr_key_t), KM_SLEEP);
+
+	if (lpt_len >= sizeof (scsi_devid_desc_t)) {
+		ASSERT(lptid);
+		key->pgr_key_lpt_len = lpt_len;
+		key->pgr_key_lpt_id  = (scsi_devid_desc_t *)kmem_zalloc(
+		    lpt_len, KM_SLEEP);
+		bcopy(lptid, key->pgr_key_lpt_id, lpt_len);
+	}
+
+	if (rpt_len >= sizeof (scsi_devid_desc_t)) {
+		ASSERT(rptid);
+		key->pgr_key_rpt_len = rpt_len;
+		key->pgr_key_rpt_id  = (scsi_devid_desc_t *)kmem_zalloc(
+		    rpt_len, KM_SLEEP);
+		bcopy(rptid, key->pgr_key_rpt_id, rpt_len);
+	}
+
+	return (key);
+}
+
+static void
+sbd_pgr_key_free(sbd_pgr_key_t *key)
+{
+	if (key->pgr_key_lpt_id) {
+		kmem_free(key->pgr_key_lpt_id, key->pgr_key_lpt_len);
+	}
+	if (key->pgr_key_rpt_id) {
+		kmem_free(key->pgr_key_rpt_id, key->pgr_key_rpt_len);
+	}
+	kmem_free(key, sizeof (sbd_pgr_key_t));
+}
+
+void
+sbd_pgr_keylist_dealloc(sbd_lu_t *slu)
+{
+	sbd_pgr_t	*pgr  = slu->sl_pgr;
+	sbd_it_data_t	*it;
+	sbd_pgr_key_t	*key;
+
+	mutex_enter(&slu->sl_lock);
+	for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
+		it->pgr_key_ptr = NULL;
+	}
+	mutex_exit(&slu->sl_lock);
+
+	while (pgr->pgr_keylist != NULL) {
+		key = pgr->pgr_keylist;
+		pgr->pgr_keylist = key->pgr_key_next;
+		sbd_pgr_key_free(key);
+	}
+}
+
+static void
+sbd_pgr_remove_key(sbd_lu_t *slu, sbd_pgr_key_t *key)
+{
+	sbd_pgr_t *pgr  = slu->sl_pgr;
+	sbd_it_data_t *it;
+
+	ASSERT(key);
+
+	mutex_enter(&slu->sl_lock);
+	if (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) {
+		for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
+			if (it->pgr_key_ptr == key)
+				it->pgr_key_ptr = NULL;
+		}
+	} else {
+		if (key->pgr_key_it) {
+			key->pgr_key_it->pgr_key_ptr = NULL;
+		}
+	}
+	mutex_exit(&slu->sl_lock);
+
+	if (key->pgr_key_next) {
+		key->pgr_key_next->pgr_key_prev = key->pgr_key_prev;
+	}
+	if (key->pgr_key_prev) {
+		key->pgr_key_prev->pgr_key_next = key->pgr_key_next;
+	} else {
+		pgr->pgr_keylist =  key->pgr_key_next;
+	}
+
+	sbd_pgr_key_free(key);
+}
+
+/*
+ * Remove keys depends on boolean variable "match"
+ * match = B_TRUE  ==>	Remove all keys which matches the given svc_key,
+ *			except for IT equal to given "my_it".
+ * match = B_FALSE ==>	Remove all keys which does not matches the svc_key,
+ *			except for IT equal to given "my_it"
+ */
+static uint32_t
+sbd_pgr_remove_keys(sbd_lu_t *slu, sbd_it_data_t *my_it, sbd_pgr_key_t *my_key,
+				uint64_t svc_key, boolean_t match)
+{
+	sbd_pgr_t	*pgr  = slu->sl_pgr;
+	sbd_it_data_t	*it;
+	sbd_pgr_key_t	*nextkey, *key = pgr->pgr_keylist;
+	uint32_t	count = 0;
+
+	while (key) {
+
+		nextkey = key->pgr_key_next;
+		if (match == B_TRUE && key->pgr_key == svc_key ||
+		    match == B_FALSE && key->pgr_key != svc_key) {
+			/*
+			 * If the key is registered by current IT keep it,
+			 * but just remove pgr pointers from other ITs
+			 */
+			if (key == my_key) {
+				mutex_enter(&slu->sl_lock);
+				for (it = slu->sl_it_list; it != NULL;
+				    it = it->sbd_it_next) {
+					if (it->pgr_key_ptr == key &&
+					    it != my_it)
+						it->pgr_key_ptr = NULL;
+				}
+				mutex_exit(&slu->sl_lock);
+			} else {
+				sbd_pgr_remove_key(slu, key);
+			}
+			count++;
+		}
+		key = nextkey;
+	}
+	return (count);
+}
+
+static void
+sbd_pgr_set_ua_conditions(sbd_lu_t *slu, sbd_it_data_t *my_it, uint8_t ua)
+{
+	sbd_it_data_t *it;
+
+	mutex_enter(&slu->sl_lock);
+	for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
+		if (it == my_it)
+			continue;
+		it->sbd_it_ua_conditions |= ua;
+	}
+	mutex_exit(&slu->sl_lock);
+}
+
+/*
+ * Set the SBD_IT_PGR_CHECK_FLAG  depends on variable "registered". See Below.
+ *
+ *   If
+ *     registered is B_TRUE  => Set PGR_CHECK_FLAG on all registered IT nexus
+ *     registered is B_FALSE => Set PGR_CHECK_FLAG on all unregistered IT nexus
+ */
+static void
+sbd_pgr_set_pgr_check_flag(sbd_lu_t *slu, boolean_t registered)
+{
+	sbd_it_data_t *it;
+
+	PGR_CLEAR_FLAG(slu->sl_pgr->pgr_flags, SBD_PGR_ALL_KEYS_HAS_IT);
+	mutex_enter(&slu->sl_lock);
+	for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
+		if (it->pgr_key_ptr) {
+			if (registered == B_TRUE)  {
+				it->sbd_it_flags |=  SBD_IT_PGR_CHECK_FLAG;
+			}
+		} else {
+			if (registered == B_FALSE)
+				it->sbd_it_flags |=  SBD_IT_PGR_CHECK_FLAG;
+		}
+	}
+	mutex_exit(&slu->sl_lock);
+}
+
+static boolean_t
+sbd_pgr_key_compare(sbd_pgr_key_t *key, scsi_devid_desc_t *lpt,
+					scsi_devid_desc_t *rpt)
+{
+	scsi_devid_desc_t *id;
+
+	id = key->pgr_key_rpt_id;
+	if ((rpt->ident_length != id->ident_length) ||
+	    (memcmp(id->ident, rpt->ident, id->ident_length) != 0)) {
+			return (B_FALSE);
+	}
+
+	/*
+	 * You can skip target port name comparison if ALL_TG_PT flag
+	 * is set for this key;
+	 */
+	if (!(key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) && lpt) {
+		id = key->pgr_key_lpt_id;
+		if ((lpt->ident_length != id->ident_length) ||
+		    (memcmp(id->ident, lpt->ident, id->ident_length) != 0)) {
+				return (B_FALSE);
+		}
+	}
+	return (B_TRUE);
+}
+
+
+sbd_pgr_key_t *
+sbd_pgr_key_registered(sbd_pgr_t *pgr, scsi_devid_desc_t *lpt,
+					scsi_devid_desc_t *rpt)
+{
+	sbd_pgr_key_t *key;
+
+	for (key = pgr->pgr_keylist; key != NULL; key = key->pgr_key_next) {
+		if (sbd_pgr_key_compare(key, lpt, rpt) == B_TRUE) {
+			return (key);
+		}
+	}
+	return (NULL);
+}
+
+void
+sbd_pgr_initialize_it(scsi_task_t *task)
+{
+	sbd_lu_t *slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	stmf_scsi_session_t *ses = task->task_session;
+	sbd_it_data_t *it = slu->sl_it_list;
+	sbd_pgr_t		*pgr = slu->sl_pgr;
+	sbd_pgr_key_t		*key;
+	scsi_devid_desc_t	*lpt, *rpt, *id;
+
+	if (pgr->pgr_flags & SBD_PGR_ALL_KEYS_HAS_IT)
+		return;
+	rpt = ses->ss_rport_id;
+	lpt = ses->ss_lport->lport_id;
+
+	rw_enter(&pgr->pgr_lock, RW_WRITER);
+	PGR_SET_FLAG(pgr->pgr_flags,  SBD_PGR_ALL_KEYS_HAS_IT);
+	for (key = pgr->pgr_keylist; key != NULL; key = key->pgr_key_next) {
+
+		if ((!(key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT)) &&
+		    key->pgr_key_it != NULL)
+			continue;
+		/*
+		 * SBD_PGR_ALL_KEYS_HAS_IT is set only if no single key
+		 * in the list has SBD_PGR_KEY_ALL_TG_PT flag set and
+		 * pgr_key_it all keys points to some IT
+		 */
+		PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_ALL_KEYS_HAS_IT);
+
+		/* Check if key matches with given lpt rpt combination */
+		if (sbd_pgr_key_compare(key, lpt, rpt) == B_FALSE)
+			continue;
+
+		/* IT nexus devid information matches with this key */
+		if (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) {
+			/*
+			 * If ALL_TG_PT is set, pgr_key_it will point to NULL,
+			 * unless pgr->pgr_rsvholder pointing to this key.
+			 * In that case, pgr_key_it should point to the IT
+			 * which initiated that reservation.
+			 */
+			if (pgr->pgr_rsvholder == key) {
+				id = key->pgr_key_lpt_id;
+				if (lpt->ident_length == id->ident_length) {
+					if (memcmp(id->ident, lpt->ident,
+					    id->ident_length) == 0)
+						key->pgr_key_it = it;
+				}
+			}
+
+		} else {
+			key->pgr_key_it = it;
+		}
+
+		mutex_enter(&slu->sl_lock);
+		it->pgr_key_ptr = key;
+		mutex_exit(&slu->sl_lock);
+		rw_exit(&pgr->pgr_lock);
+		return;
+	}
+	rw_exit(&pgr->pgr_lock);
+}
+
+/*
+ * Check for any PGR Reservation conflict. return 0 if access allowed
+ */
+int
+sbd_pgr_reservation_conflict(scsi_task_t *task)
+{
+	sbd_lu_t	*slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	sbd_pgr_t	*pgr = slu->sl_pgr;
+	sbd_it_data_t	*it  = (sbd_it_data_t *)task->task_lu_itl_handle;
+
+	/* If Registered */
+	if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS && it->pgr_key_ptr)
+			return (0);
+
+	/* If you are registered */
+	if (pgr->pgr_flags & SBD_PGR_RSVD_ONE) {
+		rw_enter(&pgr->pgr_lock, RW_READER);
+
+		/*
+		 * Note: it->pgr_key_ptr is protected by sl_lock. Also,
+		 *    it is expected to change its value only with pgr_lock
+		 *    held. Hence we are safe to read its value without
+		 *    grabbing sl_lock. But make sure that the value used is
+		 *    not from registers by using "volatile" keyword.
+		 *    Since this funtion is in performance path, we may want
+		 *    to avoid grabbing sl_lock.
+		 */
+		if ((volatile sbd_pgr_key_t *)it->pgr_key_ptr) {
+			/* If you are the reservation holder */
+			if (pgr->pgr_rsvholder == it->pgr_key_ptr &&
+			    it->pgr_key_ptr->pgr_key_it == it) {
+				rw_exit(&pgr->pgr_lock);
+				return (0);
+			}
+
+			/* If reserve type is not EX_AC */
+			if (pgr->pgr_rsv_type != PGR_TYPE_EX_AC) {
+				/* If reserve type is WR_EX allow read */
+				if (pgr->pgr_rsv_type == PGR_TYPE_WR_EX) {
+					if (PGR_READ_POSSIBLE_CMDS(
+					    task->task_cdb[0])) {
+						rw_exit(&pgr->pgr_lock);
+						return (0);
+					}
+				/* For all other reserve types allow access */
+				} else {
+					rw_exit(&pgr->pgr_lock);
+					return (0);
+				}
+			}
+
+			/* If registered, allow these commands */
+			if (PGR_REGISTERED_POSSIBLE_CMDS(task->task_cdb)) {
+				rw_exit(&pgr->pgr_lock);
+				return (0);
+			}
+		}
+		rw_exit(&pgr->pgr_lock);
+	}
+
+	/* For any case, allow these commands */
+	if (PGR_CONFLICT_FREE_CMDS(task->task_cdb)) {
+		return (0);
+	}
+
+	/* Give read access if reservation type WR_EX for registrants */
+	if (pgr->pgr_rsv_type == PGR_TYPE_WR_EX_RO ||
+	    pgr->pgr_rsv_type == PGR_TYPE_WR_EX_AR) {
+		if (PGR_READ_POSSIBLE_CMDS(task->task_cdb[0]))
+			return (0);
+	}
+
+	/* If  you reached here, No access for you */
+	return (1);
+}
+
+void
+sbd_handle_pgr_in_cmd(scsi_task_t *task, stmf_data_buf_t *initial_dbuf)
+{
+
+	sbd_lu_t	*slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	sbd_pgr_t	*pgr = slu->sl_pgr;
+	scsi_cdb_prin_t *pr_in;
+
+	ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN);
+
+	pr_in = (scsi_cdb_prin_t *)task->task_cdb;
+
+	rw_enter(&pgr->pgr_lock, RW_READER);
+	switch (pr_in->action) {
+	case PR_IN_READ_KEYS:
+		sbd_pgr_in_read_keys(task, initial_dbuf);
+		break;
+	case PR_IN_READ_RESERVATION:
+		sbd_pgr_in_read_reservation(task, initial_dbuf);
+		break;
+	case PR_IN_REPORT_CAPABILITIES:
+		sbd_pgr_in_report_capabilities(task, initial_dbuf);
+		break;
+	case PR_IN_READ_FULL_STATUS:
+		sbd_pgr_in_read_full_status(task, initial_dbuf);
+		break;
+	default :
+		stmf_scsilib_send_status(task, STATUS_CHECK,
+		    STMF_SAA_INVALID_FIELD_IN_CDB);
+		break;
+	}
+	rw_exit(&pgr->pgr_lock);
+}
+
+void
+sbd_handle_pgr_out_cmd(scsi_task_t *task, stmf_data_buf_t *initial_dbuf)
+{
+
+	scsi_cdb_prout_t *pr_out = (scsi_cdb_prout_t *)task->task_cdb;
+	uint32_t param_len;
+
+	ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_OUT);
+
+	switch (pr_out->action) {
+		case PR_OUT_REGISTER:
+		case PR_OUT_RESERVE:
+		case PR_OUT_RELEASE:
+		case PR_OUT_CLEAR:
+		case PR_OUT_PREEMPT:
+		case PR_OUT_PREEMPT_ABORT:
+		case PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY:
+		case PR_OUT_REGISTER_MOVE:
+			param_len = READ_SCSI32(pr_out->param_len, uint32_t);
+			if (param_len < MAX_PGR_PARAM_LIST_LENGTH &&
+			    param_len > 0) {
+				sbd_handle_short_write_transfers(task,
+				    initial_dbuf, param_len);
+			} else {
+				stmf_scsilib_send_status(task, STATUS_CHECK,
+				    STMF_SAA_PARAM_LIST_LENGTH_ERROR);
+			}
+			break;
+		default :
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INVALID_FIELD_IN_CDB);
+			break;
+	}
+}
+
+void
+sbd_handle_pgr_out_data(scsi_task_t *task, stmf_data_buf_t *dbuf)
+{
+	sbd_lu_t	*slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	scsi_cdb_prout_t	*pr_out	= (scsi_cdb_prout_t *)task->task_cdb;
+	sbd_it_data_t		*it	= task->task_lu_itl_handle;
+	sbd_pgr_t		*pgr	= slu->sl_pgr;
+	sbd_pgr_key_t		*key;
+	scsi_prout_plist_t	*plist;
+	uint64_t		rsv_key;
+	uint8_t			*buf, buflen;
+
+	ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_OUT);
+
+	if (dbuf == NULL || dbuf->db_data_size < 24) {
+		stmf_scsilib_send_status(task, STATUS_CHECK,
+		    STMF_SAA_PARAM_LIST_LENGTH_ERROR);
+		return;
+	}
+
+	buf = dbuf->db_sglist[0].seg_addr;
+	buflen = dbuf->db_data_size;
+	plist = (scsi_prout_plist_t *)buf;
+
+	/* SPC3 - 6.12.1 */
+	if (pr_out->action != PR_OUT_REGISTER_MOVE && buflen != 24) {
+		if ((pr_out->action !=
+		    PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY &&
+		    pr_out->action != PR_OUT_REGISTER) ||
+		    plist->spec_i_pt == 0) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_PARAM_LIST_LENGTH_ERROR);
+			return;
+		}
+	}
+
+	/*
+	 * Common Reservation Conflict Checks
+	 *
+	 * It is okey to handle REGISTER_MOVE with same plist here,
+	 * because we are only accessing reservation key feild.
+	 */
+	rw_enter(&pgr->pgr_lock, RW_WRITER);
+
+	/*
+	 * Currently it is not mandatory to have volatile keyword here,
+	 * because, it->pgr_key_ptr is not accessed yet. But still
+	 * keeping it to safe gaurd against any possible future changes.
+	 */
+	key = (sbd_pgr_key_t *)((volatile sbd_pgr_key_t *)it->pgr_key_ptr);
+	if (pr_out->action != PR_OUT_REGISTER &&
+	    pr_out->action != PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY) {
+		/* if IT is not yet registered send conflict status */
+		if (key == NULL) {
+			if (pr_out->action == PR_OUT_REGISTER_MOVE &&
+			    SBD_PGR_RSVD_NONE(pgr)) {
+				stmf_scsilib_send_status(task, STATUS_CHECK,
+				    STMF_SAA_INVALID_FIELD_IN_CDB);
+
+			} else {
+				stmf_scsilib_send_status(task,
+				    STATUS_RESERVATION_CONFLICT, 0);
+			}
+			rw_exit(&pgr->pgr_lock);
+			return;
+		}
+
+		/* Given reservation key should matches with registered key */
+		rsv_key = READ_SCSI64(plist->reservation_key, uint64_t);
+		if (key->pgr_key != rsv_key) {
+			stmf_scsilib_send_status(task,
+			    STATUS_RESERVATION_CONFLICT, 0);
+			rw_exit(&pgr->pgr_lock);
+			return;
+		}
+	}
+
+	switch (pr_out->action) {
+	case PR_OUT_REGISTER:
+	case PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY:
+		sbd_pgr_out_register(task, dbuf);
+		break;
+	case PR_OUT_REGISTER_MOVE:
+		sbd_pgr_out_register_and_move(task, dbuf);
+		break;
+	case PR_OUT_RESERVE:
+		sbd_pgr_out_reserve(task);
+		break;
+	case PR_OUT_RELEASE:
+		sbd_pgr_out_release(task);
+		break;
+	case PR_OUT_CLEAR:
+		sbd_pgr_out_clear(task);
+		break;
+	case PR_OUT_PREEMPT:
+	case PR_OUT_PREEMPT_ABORT:
+		sbd_pgr_out_preempt(task, dbuf);
+		break;
+	default :
+		stmf_scsilib_send_status(task, STATUS_CHECK,
+		    STMF_SAA_INVALID_FIELD_IN_CDB);
+		break;
+	}
+	rw_exit(&pgr->pgr_lock);
+}
+
+static void
+sbd_pgr_in_read_keys(scsi_task_t *task, stmf_data_buf_t *initial_dbuf)
+{
+	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	sbd_pgr_t	*pgr   =  slu->sl_pgr;
+	sbd_pgr_key_t	*key;
+	scsi_prin_readrsrv_t *buf;
+	uint32_t buf_size, cdb_len, numkeys = 0;
+	uint64_t *reg_key;
+
+	ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN);
+
+	cdb_len = READ_SCSI16(&task->task_cdb[7], uint16_t);
+	for (key = pgr->pgr_keylist; key != NULL; key = key->pgr_key_next)
+		++numkeys;
+	buf_size = 8 + numkeys * 8; /* minimum 8 bytes */
+	buf = kmem_zalloc(buf_size, KM_SLEEP);
+	SCSI_WRITE32(buf->PRgeneration, pgr->pgr_PRgeneration);
+	SCSI_WRITE32(buf->add_len, numkeys * 8);
+
+	reg_key = (uint64_t *)&buf->key_list;
+	for (key = pgr->pgr_keylist; key != NULL; key = key->pgr_key_next) {
+		SCSI_WRITE64(reg_key, key->pgr_key);
+		reg_key++;
+	}
+	sbd_handle_short_read_transfers(task, initial_dbuf, (uint8_t *)buf,
+	    cdb_len, buf_size);
+	kmem_free(buf, buf_size);
+}
+
+static void
+sbd_pgr_in_read_reservation(scsi_task_t *task, stmf_data_buf_t *initial_dbuf)
+{
+	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	sbd_pgr_t	*pgr   =  slu->sl_pgr;
+	scsi_prin_readrsrv_t *buf;
+	uint32_t cdb_len, buf_len, buf_size = 24;
+
+	ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN);
+
+	cdb_len = READ_SCSI16(&task->task_cdb[7], uint16_t);
+	buf = kmem_zalloc(buf_size, KM_SLEEP); /* fixed size cdb, 24 bytes */
+	SCSI_WRITE32(buf->PRgeneration, pgr->pgr_PRgeneration);
+
+	if (SBD_PGR_RSVD_NONE(pgr)) {
+		SCSI_WRITE32(buf->add_len, 0);
+		buf_len = 8;
+	} else {
+		if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS) {
+			SCSI_WRITE64(
+			    buf->key_list.res_key_list[0].reservation_key, 0);
+		} else {
+			SCSI_WRITE64(
+			    buf->key_list.res_key_list[0].reservation_key,
+			    pgr->pgr_rsvholder->pgr_key);
+		}
+		buf->key_list.res_key_list[0].type = pgr->pgr_rsv_type;
+		buf->key_list.res_key_list[0].scope = pgr->pgr_rsv_scope;
+		SCSI_WRITE32(buf->add_len, 16);
+		buf_len = 24;
+	}
+
+	sbd_handle_short_read_transfers(task, initial_dbuf, (uint8_t *)buf,
+	    cdb_len, buf_len);
+	kmem_free(buf, buf_size);
+}
+
+static void
+sbd_pgr_in_report_capabilities(scsi_task_t *task,
+				stmf_data_buf_t *initial_dbuf)
+{
+	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	sbd_pgr_t	*pgr   =  slu->sl_pgr;
+	scsi_prin_rpt_cap_t buf;
+	uint32_t cdb_len;
+
+	ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN);
+	ASSERT(pgr != NULL);
+
+	buf.ptpl_c		= 1;   /* Persist Through Power Loss C */
+	buf.atp_c		= 1;   /* All Target Ports Capable */
+	buf.sip_c		= 1;   /* Specify Initiator Ports Capable */
+	buf.crh			= 0;   /* Supports Reserve/Release exception */
+	buf.tmv			= 1;   /* Type Mask Valid */
+	buf.pr_type.wr_ex	= 1;   /* Write Exclusve */
+	buf.pr_type.ex_ac	= 1;   /* Exclusive Access */
+	buf.pr_type.wr_ex_ro	= 1;   /* Write Exclusive Registrants Only */
+	buf.pr_type.ex_ac_ro	= 1;   /* Exclusive Access Registrants Only */
+	buf.pr_type.wr_ex_ar	= 1;   /* Write Exclusive All Registrants */
+	buf.pr_type.ex_ac_ar	= 1;   /* Exclusive Access All Registrants */
+
+	/* Persist Though Power Loss Active */
+	buf.ptpl_a = pgr->pgr_flags & SBD_PGR_APTPL;
+	SCSI_WRITE16(&buf.length, 8);
+	cdb_len = READ_SCSI16(&task->task_cdb[7], uint16_t);
+	sbd_handle_short_read_transfers(task, initial_dbuf, (uint8_t *)&buf,
+	    cdb_len, 8);
+}
+
+static void
+sbd_pgr_in_read_full_status(scsi_task_t *task,
+				stmf_data_buf_t *initial_dbuf)
+{
+	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	sbd_pgr_t	*pgr   = slu->sl_pgr;
+	sbd_pgr_key_t	*key;
+	scsi_prin_status_t 	*sts;
+	scsi_prin_full_status_t	*buf;
+	uint32_t 		i, buf_size, cdb_len, tptid_len;
+	uint8_t			*offset;
+
+	ASSERT(task->task_cdb[0] == SCMD_PERSISTENT_RESERVE_IN);
+	ASSERT(pgr != NULL);
+
+	cdb_len = READ_SCSI16(&task->task_cdb[7], uint16_t);
+
+	buf_size = 8; /* PRgeneration and additional length fields */
+	for (key = pgr->pgr_keylist; key != NULL; key = key->pgr_key_next) {
+		tptid_len = sbd_get_tptid_length_for_devid(key->pgr_key_rpt_id);
+		buf_size  = buf_size + 24 + tptid_len;
+	}
+
+	buf = kmem_zalloc(buf_size, KM_SLEEP);
+	SCSI_WRITE32(buf->PRgeneration, pgr->pgr_PRgeneration);
+	SCSI_WRITE32(buf->add_len, buf_size - 8);
+
+	offset	= (uint8_t *)&buf->full_desc[0];
+	key	= pgr->pgr_keylist;
+	i	= 0;
+	while (key) {
+		sts = (scsi_prin_status_t *)offset;
+		SCSI_WRITE64(sts->reservation_key, key->pgr_key);
+		if ((pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS) ||
+		    (pgr->pgr_rsvholder && pgr->pgr_rsvholder == key)) {
+				sts->r_holder	= 1;
+				sts->type 	= pgr->pgr_rsv_type;
+				sts->scope	= pgr->pgr_rsv_scope;
+		}
+
+		if (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) {
+			sts->all_tg_pt = 1;
+		} else {
+			SCSI_WRITE16(sts->rel_tgt_port_id,
+			    stmf_scsilib_get_lport_rtid(key->pgr_key_lpt_id));
+		}
+		tptid_len = sbd_devid_desc_to_tptid(key->pgr_key_rpt_id,
+		    &sts->trans_id);
+		SCSI_WRITE32(sts->add_len, tptid_len);
+		offset = offset + tptid_len + 24;
+		key = key->pgr_key_next;
+		++i;
+	}
+
+	sbd_handle_short_read_transfers(task, initial_dbuf, (uint8_t *)buf,
+	    cdb_len, buf_size);
+	kmem_free(buf, buf_size);
+}
+
+static void
+sbd_pgr_out_register(scsi_task_t *task, stmf_data_buf_t *dbuf)
+{
+	sbd_lu_t	*slu = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	sbd_pgr_t		*pgr	= slu->sl_pgr;
+	stmf_scsi_session_t	*ses	= task->task_session;
+	sbd_it_data_t		*it	= task->task_lu_itl_handle;
+	sbd_pgr_key_t		*key	= it->pgr_key_ptr;
+	scsi_cdb_prout_t	*pr_out	= (scsi_cdb_prout_t *)task->task_cdb;
+	scsi_prout_plist_t	*plist;
+	uint8_t			*buf, buflen;
+	uint64_t		rsv_key, svc_key;
+
+	buf = dbuf->db_sglist[0].seg_addr;
+	plist = (scsi_prout_plist_t *)buf;
+	buflen = dbuf->db_data_size;
+	rsv_key = READ_SCSI64(plist->reservation_key, uint64_t);
+	svc_key = READ_SCSI64(plist->service_key, uint64_t);
+
+	/* Handling already registered IT session */
+	if (key) {
+
+		if (pr_out->action == PR_OUT_REGISTER &&
+		    key->pgr_key != rsv_key) {
+			stmf_scsilib_send_status(task,
+			    STATUS_RESERVATION_CONFLICT, 0);
+			return;
+		}
+		if (plist->spec_i_pt) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INVALID_FIELD_IN_CDB);
+			return;
+		}
+
+		if (plist->all_tg_pt !=
+		    (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT)) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INVALID_FIELD_IN_CDB);
+			return;
+		}
+
+		if (svc_key == 0) {
+			sbd_pgr_do_unregister(slu, it, key);
+		} else {
+			key->pgr_key = svc_key;
+		}
+
+		goto sbd_pgr_reg_done;
+	}
+
+	/* Handling unregistered IT session */
+	if (pr_out->action == PR_OUT_REGISTER && rsv_key != 0) {
+		stmf_scsilib_send_status(task, STATUS_RESERVATION_CONFLICT, 0);
+		return;
+	}
+
+	if (svc_key == 0) {
+		/* Do we need to consider aptpl here? I don't think so */
+		pgr->pgr_PRgeneration++;
+		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+		return;
+	}
+
+	if (plist->spec_i_pt) {
+		uint8_t *tpd, *tpdmax;
+		uint32_t tpdlen, max_tpdnum, tpdnum, i, adnlen = 0;
+		scsi_devid_desc_t **newdevids;
+		scsi_devid_desc_t *rpt, *lpt = ses->ss_lport->lport_id;
+
+		if (pr_out->action == PR_OUT_REGISTER_AND_IGNORE_EXISTING_KEY) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INVALID_FIELD_IN_CDB);
+			return;
+		}
+
+		if (plist->all_tg_pt)
+			lpt = NULL;
+
+		/* Validate the given length */
+		if (buflen >= sizeof (scsi_prout_plist_t) - 1 + 4)
+			adnlen = READ_SCSI32(plist->apd, uint32_t);
+		if (adnlen < sizeof (scsi_transport_id_t) + 4 ||
+		    buflen < sizeof (scsi_prout_plist_t) - 1 + adnlen) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_PARAM_LIST_LENGTH_ERROR);
+			return;
+		}
+		tpdmax = plist->apd + adnlen;
+		tpdlen = adnlen - 4;
+		max_tpdnum = tpdlen / sizeof (scsi_transport_id_t);
+		newdevids = kmem_zalloc(sizeof (scsi_devid_desc_t **),
+		    KM_SLEEP);
+		*newdevids  = kmem_zalloc(sizeof (scsi_devid_desc_t *) *
+		    max_tpdnum, KM_SLEEP);
+		tpdnum = 0;
+		/* Check the validity of given TransportIDs */
+		while (tpdlen != 0) {
+			tpd = tpdmax - tpdlen;
+			rpt = sbd_tptid_to_devid_desc((scsi_transport_id_t *)
+			    tpd, &tpdlen);
+			if (rpt == NULL)
+				break;
+			/* make sure that there is no duplicates */
+			for (i = 0; i < tpdnum; i++) {
+				if (rpt->ident_length ==
+				    newdevids[i]->ident_length &&
+				    (memcmp(rpt->ident, newdevids[i]->ident,
+				    rpt->ident_length) == 0)) {
+					break;
+				}
+			}
+			newdevids[tpdnum] = rpt;
+			tpdnum++;
+			if (i < tpdnum - 1)
+				break;
+			/* Check if the given IT nexus is already registered */
+			if (sbd_pgr_key_registered(pgr, lpt, rpt))
+				break;
+		}
+
+		for (i = 0; i < tpdnum; i++) {
+			rpt = newdevids[i];
+			if (tpdlen == 0) {
+				(void) sbd_pgr_do_register(slu, NULL,
+				    ses->ss_lport->lport_id, rpt,
+				    plist->all_tg_pt, svc_key);
+			}
+			kmem_free(rpt, sizeof (scsi_devid_desc_t) - 1 +
+			    rpt->ident_length);
+		}
+		kmem_free(*newdevids,
+		    sizeof (scsi_devid_desc_t *) * max_tpdnum);
+		kmem_free(newdevids, sizeof (scsi_devid_desc_t **));
+		if (tpdlen != 0) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INVALID_FIELD_IN_CDB);
+			return;
+		}
+	}
+
+	(void) sbd_pgr_do_register(slu, it, ses->ss_lport->lport_id,
+	    ses->ss_rport_id, plist->all_tg_pt, svc_key);
+
+sbd_pgr_reg_done:
+
+	if (pgr->pgr_flags & SBD_PGR_APTPL || plist->aptpl) {
+		if (plist->aptpl)
+			PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
+		else
+			PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
+
+		if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INSUFFICIENT_REG_RESOURCES);
+			return;
+		}
+	}
+
+	pgr->pgr_PRgeneration++;
+	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+}
+
+static sbd_pgr_key_t *
+sbd_pgr_do_register(sbd_lu_t *slu, sbd_it_data_t *it, scsi_devid_desc_t *lpt,
+		scsi_devid_desc_t *rpt,	uint8_t all_tg_pt, uint64_t svc_key)
+{
+	sbd_pgr_t		*pgr = slu->sl_pgr;
+	sbd_pgr_key_t		*key;
+	uint16_t		lpt_len, rpt_len;
+
+	lpt_len	= sizeof (scsi_devid_desc_t) - 1 + lpt->ident_length;
+	rpt_len	= sizeof (scsi_devid_desc_t) - 1 + rpt->ident_length;
+
+	key = sbd_pgr_key_alloc(lpt, rpt, lpt_len, rpt_len);
+	key->pgr_key = svc_key;
+
+	if (all_tg_pt) {
+		key->pgr_key_flags |= SBD_PGR_KEY_ALL_TG_PT;
+		/* set PGR_CHECK flag for all unregistered IT nexus */
+		sbd_pgr_set_pgr_check_flag(slu, B_FALSE);
+	} else {
+		key->pgr_key_it = it;
+	}
+
+	if (it) {
+		mutex_enter(&slu->sl_lock);
+		it->pgr_key_ptr = key;
+		mutex_exit(&slu->sl_lock);
+	}
+
+	key->pgr_key_next = pgr->pgr_keylist;
+	if (pgr->pgr_keylist) {
+		pgr->pgr_keylist->pgr_key_prev = key;
+	}
+	pgr->pgr_keylist = key;
+
+	return (key);
+}
+
+static void
+sbd_pgr_do_unregister(sbd_lu_t *slu, sbd_it_data_t *it, sbd_pgr_key_t *key)
+{
+	if (slu->sl_pgr->pgr_rsvholder == key) {
+		sbd_pgr_do_release(slu, it, SBD_UA_RESERVATIONS_RELEASED);
+	}
+
+	sbd_pgr_remove_key(slu, key);
+	if (slu->sl_pgr->pgr_keylist == NULL) {
+		PGR_CLEAR_RSV_FLAG(slu->sl_pgr->pgr_flags);
+	}
+}
+
+static void
+sbd_pgr_out_reserve(scsi_task_t *task)
+{
+	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	stmf_scsi_session_t	*ses	= task->task_session;
+	scsi_cdb_prout_t	*pr_out	= (scsi_cdb_prout_t *)task->task_cdb;
+	sbd_it_data_t		*it	= task->task_lu_itl_handle;
+	sbd_pgr_t		*pgr	= slu->sl_pgr;
+	sbd_pgr_key_t		*key	= it->pgr_key_ptr;
+
+	ASSERT(key);
+
+	if (!(PGR_VALID_SCOPE(pr_out->scope) && PGR_VALID_TYPE(pr_out->type))) {
+		stmf_scsilib_send_status(task, STATUS_CHECK,
+		    STMF_SAA_INVALID_FIELD_IN_CDB);
+		return;
+	}
+
+	if (SBD_PGR_RSVD(pgr)) {
+		if (PGR_RESERVATION_HOLDER(pgr, key, it)) {
+			if (pgr->pgr_rsv_type != pr_out->type ||
+			    pgr->pgr_rsv_scope != pr_out->scope) {
+				stmf_scsilib_send_status(task,
+				    STATUS_RESERVATION_CONFLICT, 0);
+				return;
+			}
+		} else {
+			stmf_scsilib_send_status(task,
+			    STATUS_RESERVATION_CONFLICT, 0);
+			return;
+
+		}
+	/* In case there is no reservation exist */
+	} else {
+		sbd_pgr_do_reserve(pgr, key, it, ses, pr_out);
+		if (pgr->pgr_flags & SBD_PGR_APTPL) {
+			if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
+				stmf_scsilib_send_status(task, STATUS_CHECK,
+				    STMF_SAA_INSUFFICIENT_REG_RESOURCES);
+				return;
+			}
+		}
+	}
+
+	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+}
+
+static void
+sbd_pgr_do_reserve(sbd_pgr_t *pgr, sbd_pgr_key_t *key, sbd_it_data_t *it,
+			stmf_scsi_session_t *ses, scsi_cdb_prout_t *pr_out)
+{
+	scsi_devid_desc_t	*lpt;
+	uint16_t		lpt_len;
+
+	pgr->pgr_rsv_type = pr_out->type;
+	pgr->pgr_rsv_scope = pr_out->scope;
+	if (pr_out->type == PGR_TYPE_WR_EX_AR ||
+	    pr_out->type == PGR_TYPE_EX_AC_AR) {
+		PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_RSVD_ALL_REGISTRANTS);
+	} else {
+		if (key->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) {
+			lpt = key->pgr_key_lpt_id;
+			lpt_len = key->pgr_key_lpt_len;
+			if (lpt_len > 0 && lpt != NULL) {
+				kmem_free(lpt, lpt_len);
+			}
+			lpt = ses->ss_lport->lport_id;
+			lpt_len = sizeof (scsi_devid_desc_t) - 1 +
+			    lpt->ident_length;
+			key->pgr_key_lpt_len = lpt_len;
+			key->pgr_key_lpt_id = (scsi_devid_desc_t *)
+			    kmem_zalloc(lpt_len, KM_SLEEP);
+			bcopy(lpt, key->pgr_key_lpt_id, lpt_len);
+			key->pgr_key_it = it;
+		}
+
+		PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_RSVD_ONE);
+		pgr->pgr_rsvholder = key;
+	}
+}
+
+static void
+sbd_pgr_out_release(scsi_task_t *task)
+{
+	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	scsi_cdb_prout_t	*pr_out	= (scsi_cdb_prout_t *)task->task_cdb;
+	sbd_it_data_t		*it	= task->task_lu_itl_handle;
+	sbd_pgr_t		*pgr	= slu->sl_pgr;
+	sbd_pgr_key_t		*key	= it->pgr_key_ptr;
+
+	ASSERT(key);
+
+	if (SBD_PGR_RSVD(pgr)) {
+		if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS ||
+		    pgr->pgr_rsvholder == key) {
+			if (pgr->pgr_rsv_type != pr_out->type ||
+			    pgr->pgr_rsv_scope != pr_out->scope) {
+				stmf_scsilib_send_status(task, STATUS_CHECK,
+				    STMF_SAA_INVALID_RELEASE_OF_PR);
+				return;
+			}
+			sbd_pgr_do_release(slu, it,
+			    SBD_UA_RESERVATIONS_RELEASED);
+		}
+	}
+	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+}
+
+static void
+sbd_pgr_do_release(sbd_lu_t *slu, sbd_it_data_t *it, uint8_t ua_condition)
+{
+
+	sbd_pgr_t *pgr    =  slu->sl_pgr;
+
+	/* Reset pgr_flags */
+	PGR_CLEAR_RSV_FLAG(pgr->pgr_flags);
+	pgr->pgr_rsvholder = NULL;
+
+	/* set unit attention condition if necessary */
+	if (pgr->pgr_rsv_type != PGR_TYPE_WR_EX &&
+	    pgr->pgr_rsv_type != PGR_TYPE_EX_AC) {
+		sbd_pgr_set_ua_conditions(slu, it, ua_condition);
+	}
+	pgr->pgr_rsv_type = 0;
+}
+
+static void
+sbd_pgr_out_clear(scsi_task_t *task)
+{
+	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	sbd_it_data_t		*it	= task->task_lu_itl_handle;
+	sbd_pgr_t		*pgr	= slu->sl_pgr;
+
+	ASSERT(it->pgr_key_ptr);
+
+	PGR_CLEAR_RSV_FLAG(pgr->pgr_flags);
+	pgr->pgr_rsvholder = NULL;
+	pgr->pgr_rsv_type = 0;
+	mutex_enter(&slu->sl_lock);
+	/* Remove all pointers from IT to pgr keys */
+	for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
+		it->pgr_key_ptr = NULL;
+	}
+	mutex_exit(&slu->sl_lock);
+	sbd_pgr_keylist_dealloc(slu);
+	sbd_pgr_set_ua_conditions(slu, it, SBD_UA_RESERVATIONS_PREEMPTED);
+	if (pgr->pgr_flags & SBD_PGR_APTPL) {
+		if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INSUFFICIENT_REG_RESOURCES);
+			return;
+		}
+	}
+	pgr->pgr_PRgeneration++;
+	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+}
+
+static void
+sbd_pgr_out_preempt(scsi_task_t *task, stmf_data_buf_t *dbuf)
+{
+	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	stmf_scsi_session_t	*ses	= task->task_session;
+	scsi_cdb_prout_t	*pr_out	= (scsi_cdb_prout_t *)task->task_cdb;
+	sbd_it_data_t		*it	= task->task_lu_itl_handle;
+	sbd_pgr_t		*pgr	= slu->sl_pgr;
+	sbd_pgr_key_t		*key	= it->pgr_key_ptr;
+	scsi_prout_plist_t	*plist;
+	uint8_t			*buf, change_rsv = 0;
+	uint64_t		svc_key;
+
+	ASSERT(key);
+
+	buf = dbuf->db_sglist[0].seg_addr;
+	plist = (scsi_prout_plist_t *)buf;
+	svc_key = READ_SCSI64(plist->service_key, uint64_t);
+
+	if (SBD_PGR_RSVD_NONE(pgr)) {
+		if (svc_key == 0 ||
+		    sbd_pgr_remove_keys(slu, it, key, svc_key, B_TRUE) == 0) {
+			stmf_scsilib_send_status(task,
+			    STATUS_RESERVATION_CONFLICT, 0);
+			return;
+		}
+
+	} else if (pgr->pgr_flags & SBD_PGR_RSVD_ONE) {
+		if (svc_key == 0) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INVALID_FIELD_IN_CDB);
+			return;
+		}
+
+		/* Validity check of scope and type */
+		if (pgr->pgr_rsvholder->pgr_key == svc_key) {
+			if (!(PGR_VALID_SCOPE(pr_out->scope) &&
+			    PGR_VALID_TYPE(pr_out->type))) {
+				stmf_scsilib_send_status(task, STATUS_CHECK,
+				    STMF_SAA_INVALID_FIELD_IN_CDB);
+				return;
+			}
+		}
+
+		if (pgr->pgr_rsvholder != key &&
+		    pgr->pgr_rsvholder->pgr_key == svc_key) {
+			sbd_pgr_do_release(slu, it,
+			    SBD_UA_REGISTRATIONS_PREEMPTED);
+			change_rsv = 1;
+		}
+
+		if (pgr->pgr_rsvholder == key &&
+		    pgr->pgr_rsvholder->pgr_key == svc_key) {
+			if (pr_out->scope != pgr->pgr_rsv_scope ||
+			    pr_out->type != pgr->pgr_rsv_type) {
+				sbd_pgr_do_release(slu, it,
+				    SBD_UA_REGISTRATIONS_PREEMPTED);
+				change_rsv = 1;
+			}
+		} else {
+			/*
+			 * Remove matched keys in all cases, except when the
+			 * current IT nexus holds the reservation and the given
+			 * svc_key matches with registered key.
+			 * Note that, if the reservation is held by another
+			 * IT nexus, and svc_key matches registered key for
+			 * that IT nexus, sbd_pgr_remove_key() is not expected
+			 * return 0. Hence, returning check condition after
+			 * releasing the reservation does not arise.
+			 */
+			if (sbd_pgr_remove_keys(slu, it, key, svc_key, B_TRUE)
+			    == 0) {
+				stmf_scsilib_send_status(task,
+				    STATUS_RESERVATION_CONFLICT, 0);
+				return;
+			}
+		}
+
+		if (change_rsv) {
+			sbd_pgr_do_reserve(pgr, key, it, ses, pr_out);
+		}
+
+	} else if (pgr->pgr_flags & SBD_PGR_RSVD_ALL_REGISTRANTS) {
+		if (svc_key == 0) {
+			if (!(PGR_VALID_SCOPE(pr_out->scope) &&
+			    PGR_VALID_TYPE(pr_out->type))) {
+				stmf_scsilib_send_status(task, STATUS_CHECK,
+				    STMF_SAA_INVALID_FIELD_IN_CDB);
+				return;
+			}
+			sbd_pgr_do_release(slu, it,
+			    SBD_UA_REGISTRATIONS_PREEMPTED);
+			(void) sbd_pgr_remove_keys(slu, it, key, 0, B_FALSE);
+			sbd_pgr_do_reserve(pgr, key, it, ses, pr_out);
+		} else {
+			if (sbd_pgr_remove_keys(slu, it, key, svc_key, B_TRUE)
+			    == 0) {
+				stmf_scsilib_send_status(task,
+				    STATUS_RESERVATION_CONFLICT, 0);
+				return;
+			}
+		}
+	}
+
+	if (pgr->pgr_flags & SBD_PGR_APTPL) {
+		if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INSUFFICIENT_REG_RESOURCES);
+			return;
+		}
+	}
+
+	pgr->pgr_PRgeneration++;
+
+	if (pr_out->action == PR_OUT_PREEMPT_ABORT) {
+		/*
+		 * XXX iscsi port provider doesn't like this idea
+		 * Need to implement abort differently
+		 *
+		 * task->task_mgmt_function = TM_ABORT_TASK_SET;
+		 * stmf_scsilib_handle_task_mgmt(task);
+		 */
+		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+	} else {
+		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+	}
+}
+
+static void
+sbd_pgr_out_register_and_move(scsi_task_t *task, stmf_data_buf_t *dbuf)
+{
+	sbd_lu_t	*slu   = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	sbd_it_data_t		*it	= task->task_lu_itl_handle;
+	sbd_pgr_t		*pgr	= slu->sl_pgr;
+	sbd_pgr_key_t		*key	= it->pgr_key_ptr;
+	scsi_devid_desc_t	*lpt, *rpt;
+	sbd_pgr_key_t		*newkey;
+	scsi_prout_reg_move_plist_t *plist;
+	uint8_t			*buf, lpt_len;
+	uint32_t		tpd_len;
+	uint64_t		svc_key;
+
+	/*
+	 * Check whether the key holds the reservation or current reservation
+	 * is of type all registrants.
+	 */
+	if (pgr->pgr_rsvholder != key) {
+		stmf_scsilib_send_status(task, STATUS_RESERVATION_CONFLICT, 0);
+		return;
+	}
+
+	buf = dbuf->db_sglist[0].seg_addr;
+	plist = (scsi_prout_reg_move_plist_t *)buf;
+	svc_key = READ_SCSI64(plist->service_key, uint64_t);
+	if (svc_key == 0) {
+		stmf_scsilib_send_status(task, STATUS_CHECK,
+		    STMF_SAA_INVALID_FIELD_IN_CDB);
+		return;
+	}
+
+	lpt = stmf_scsilib_get_devid_desc(READ_SCSI16(plist->rel_tgt_port_id,
+	    uint16_t));
+	if (lpt == NULL) {
+		stmf_scsilib_send_status(task, STATUS_CHECK,
+		    STMF_SAA_INVALID_FIELD_IN_CDB);
+		return;
+	}
+
+	tpd_len = READ_SCSI32(plist->tptid_len, uint32_t);
+	rpt = sbd_tptid_to_devid_desc((scsi_transport_id_t *)plist->tptid,
+	    &tpd_len);
+	if (rpt == NULL) {
+		stmf_scsilib_send_status(task, STATUS_CHECK,
+		    STMF_SAA_INVALID_FIELD_IN_PARAM_LIST);
+		return;
+	} else if (rpt->ident_length == key->pgr_key_rpt_id->ident_length &&
+	    (memcmp(rpt->ident, key->pgr_key_rpt_id->ident, rpt->ident_length)
+	    == 0)) {
+		kmem_free(rpt, sizeof (rpt) - 1 + rpt->ident_length);
+		kmem_free(lpt, sizeof (lpt) - 1 + lpt->ident_length);
+		stmf_scsilib_send_status(task, STATUS_CHECK,
+		    STMF_SAA_INVALID_FIELD_IN_PARAM_LIST);
+		return;
+	}
+
+	newkey = sbd_pgr_key_registered(pgr, lpt, rpt);
+	if (newkey) {
+		/* Set the pgr_key, irrespective of what it currently holds */
+		newkey->pgr_key = svc_key;
+
+		/* all_tg_pt is set for found key, copy lpt info to the key */
+		if (newkey->pgr_key_flags & SBD_PGR_KEY_ALL_TG_PT) {
+			if (newkey->pgr_key_lpt_id &&
+			    newkey->pgr_key_lpt_len > 0) {
+				kmem_free(newkey->pgr_key_lpt_id,
+				    newkey->pgr_key_lpt_len);
+			}
+			lpt_len = sizeof (scsi_devid_desc_t) - 1 +
+			    lpt->ident_length;
+			newkey->pgr_key_lpt_len = lpt_len;
+			newkey->pgr_key_lpt_id = (scsi_devid_desc_t *)
+			    kmem_zalloc(lpt_len, KM_SLEEP);
+			bcopy(lpt, newkey->pgr_key_lpt_id, lpt_len);
+		}
+	} else  {
+		newkey = sbd_pgr_do_register(slu, NULL, lpt, rpt, 0, svc_key);
+	}
+
+	kmem_free(rpt, sizeof (scsi_devid_desc_t) - 1 + rpt->ident_length);
+	kmem_free(lpt, sizeof (scsi_devid_desc_t) - 1 + lpt->ident_length);
+
+	/* Now reserve the key corresponding to the specified IT nexus */
+	pgr->pgr_rsvholder = newkey;
+
+	if (plist->unreg) {
+		sbd_pgr_do_unregister(slu, it, key);
+	}
+
+	/* Since we do not have IT nexus information, set PGR_CHEK flag */
+	sbd_pgr_set_pgr_check_flag(slu, B_TRUE);
+
+	/* Write to disk if currenty aptpl is set or given task is setting it */
+	if (pgr->pgr_flags & SBD_PGR_APTPL || plist->aptpl) {
+		if (plist->aptpl)
+			PGR_SET_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
+		else
+			PGR_CLEAR_FLAG(pgr->pgr_flags, SBD_PGR_APTPL);
+
+		if (sbd_pgr_meta_write(slu) != SBD_SUCCESS) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INSUFFICIENT_REG_RESOURCES);
+			return;
+		}
+	}
+
+	pgr->pgr_PRgeneration++;
+	stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+}
+
+void
+sbd_pgr_remove_it_handle(sbd_lu_t *sl, sbd_it_data_t *my_it) {
+	sbd_it_data_t *it;
+
+	rw_enter(&sl->sl_pgr->pgr_lock, RW_WRITER);
+	mutex_enter(&sl->sl_lock);
+	for (it = sl->sl_it_list; it != NULL; it = it->sbd_it_next) {
+		if (it == my_it) {
+			if (it->pgr_key_ptr) {
+				sbd_pgr_key_t *key = it->pgr_key_ptr;
+				if (key->pgr_key_it == it) {
+					key->pgr_key_it = NULL;
+					sl->sl_pgr->pgr_flags &=
+					    ~SBD_PGR_ALL_KEYS_HAS_IT;
+				}
+			}
+			break;
+		}
+	}
+	mutex_exit(&sl->sl_lock);
+	rw_exit(&sl->sl_pgr->pgr_lock);
+
+}
+
+scsi_devid_desc_t *
+sbd_tptid_to_devid_desc(scsi_transport_id_t *tptid, uint32_t *tptid_len)
+{
+
+	scsi_devid_desc_t *devid = NULL;
+	uint16_t ident_len,  sz;
+
+	struct scsi_fc_transport_id	*fcid;
+	struct iscsi_transport_id	*iscsiid;
+
+	switch (tptid->protocol_id) {
+
+	case PROTOCOL_FIBRE_CHANNEL:
+
+		if (*tptid_len < 24 || tptid->format_code != 0) {
+			return (NULL);
+		}
+		*tptid_len -= 24;
+		ident_len = 8;
+		fcid	= (scsi_fc_transport_id_t *)tptid;
+		sz	= sizeof (scsi_devid_desc_t) - 1 + ident_len;
+		devid	= (scsi_devid_desc_t *)kmem_zalloc(sz, KM_SLEEP);
+		(void) memcpy(devid->ident, fcid->port_name, ident_len);
+		/* LINTED E_ASSIGN_NARROW_CONV */
+		devid->ident_length	= ident_len;
+		devid->protocol_id	= tptid->protocol_id;
+		devid->code_set		= CODE_SET_BINARY;
+		return (devid);
+
+	case PROTOCOL_iSCSI:
+
+		if (tptid->format_code != 0 && tptid->format_code != 1) {
+			return (NULL);
+		}
+		iscsiid 	= (iscsi_transport_id_t *)tptid;
+		ident_len 	= READ_SCSI16(iscsiid->add_len, uint16_t);
+		if (*tptid_len < sizeof (iscsi_transport_id_t) + ident_len) {
+			return (NULL);
+		}
+		*tptid_len -= (sizeof (iscsi_transport_id_t) + ident_len);
+		sz	= sizeof (scsi_devid_desc_t) - 1 + ident_len;
+		devid	= (scsi_devid_desc_t *)kmem_zalloc(sz, KM_SLEEP);
+		(void) memcpy(devid->ident, iscsiid->iscsi_name, ident_len);
+		/* LINTED E_ASSIGN_NARROW_CONV */
+		devid->ident_length	= ident_len;
+		devid->protocol_id	= tptid->protocol_id;
+		devid->code_set		= CODE_SET_ASCII;
+		return (devid);
+
+	default:
+		cmn_err(CE_NOTE, "sbd_tptid_to_devid_desc: received unknown"
+		    "protocol id 0x%x", tptid->protocol_id);
+		return (NULL);
+	}
+}
+
+/*
+ * Changes devid_desc to corresponding TransportID format
+ * Returns : Total length used by TransportID
+ * Note    :- No buffer lenghth checking
+ */
+uint32_t
+sbd_devid_desc_to_tptid(scsi_devid_desc_t *devid, scsi_transport_id_t *tptid)
+{
+	struct scsi_fc_transport_id	*fcid;
+	struct iscsi_transport_id	*iscsiid;
+	uint32_t ident_len,  sz = 0;
+
+	switch (devid->protocol_id) {
+	case PROTOCOL_FIBRE_CHANNEL:
+		fcid = (scsi_fc_transport_id_t *)tptid;
+		ident_len = 8;
+		tptid->format_code = 0;
+		tptid->protocol_id = devid->protocol_id;
+		(void) memcpy(fcid->port_name, devid->ident, ident_len);
+		sz = 24;
+		break;
+
+	case PROTOCOL_iSCSI:
+		iscsiid = (iscsi_transport_id_t *)tptid;
+		ident_len = devid->ident_length;
+		tptid->format_code = 0;
+		tptid->protocol_id = devid->protocol_id;
+		SCSI_WRITE16(iscsiid->add_len, ident_len);
+		(void) memcpy(iscsiid->iscsi_name, devid->ident, ident_len);
+		sz = ALIGNED_TO_WORD_BOUNDARY(4 + ident_len);
+		break;
+
+	default :
+		cmn_err(CE_NOTE, "sbd_devid_desc_to_tptid: received unknown"
+		    "protocol id 0x%x", devid->protocol_id);
+		break;
+	}
+
+	return (sz);
+}
+
+uint32_t
+sbd_get_tptid_length_for_devid(scsi_devid_desc_t *devid)
+{
+	uint32_t sz = 0;
+	switch (devid->protocol_id) {
+	case PROTOCOL_FIBRE_CHANNEL:
+		sz = 24;
+		break;
+	case PROTOCOL_iSCSI:
+		sz = 4 + devid->ident_length;
+		break;
+	}
+	sz = ALIGNED_TO_WORD_BOUNDARY(sz);
+	sz = (sz > 0 && sz < 24) ? 24 : sz;
+
+	return (sz);
+}
+
+char *
+sbd_get_devid_string(sbd_lu_t *sl)
+{
+	char *str = (char *)kmem_zalloc(33, KM_SLEEP);
+	(void) snprintf(str, 33,
+	    "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+	    sl->sl_device_id[4], sl->sl_device_id[5], sl->sl_device_id[6],
+	    sl->sl_device_id[7], sl->sl_device_id[8], sl->sl_device_id[9],
+	    sl->sl_device_id[10], sl->sl_device_id[11], sl->sl_device_id[12],
+	    sl->sl_device_id[13], sl->sl_device_id[14], sl->sl_device_id[15],
+	    sl->sl_device_id[16], sl->sl_device_id[17], sl->sl_device_id[18],
+	    sl->sl_device_id[19]);
+	return (str);
+}
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c	Fri May 08 16:22:42 2009 -0600
@@ -35,20 +35,76 @@
 #include <sys/byteorder.h>
 #include <sys/atomic.h>
 #include <sys/sdt.h>
+#include <sys/dkio.h>
 
 #include <stmf.h>
 #include <lpif.h>
 #include <portif.h>
 #include <stmf_ioctl.h>
 #include <stmf_sbd.h>
+#include <stmf_sbd_ioctl.h>
 #include <sbd_impl.h>
 
+#define	SCSI2_CONFLICT_FREE_CMDS(cdb)	( \
+	/* ----------------------- */                                      \
+	/* Refer Both		   */                                      \
+	/* SPC-2 (rev 20) Table 10 */                                      \
+	/* SPC-3 (rev 23) Table 31 */                                      \
+	/* ----------------------- */                                      \
+	((cdb[0]) == SCMD_INQUIRY)					|| \
+	((cdb[0]) == SCMD_LOG_SENSE_G1)					|| \
+	((cdb[0]) == SCMD_RELEASE)					|| \
+	((cdb[0]) == SCMD_RELEASE_G1)					|| \
+	((cdb[0]) == SCMD_REPORT_LUNS)					|| \
+	((cdb[0]) == SCMD_REQUEST_SENSE)				|| \
+	/* PREVENT ALLOW MEDIUM REMOVAL with prevent == 0 */               \
+	((((cdb[0]) == SCMD_DOORLOCK) && (((cdb[4]) & 0x3) == 0)))	|| \
+	/* SERVICE ACTION IN with READ MEDIA SERIAL NUMBER (0x01) */       \
+	(((cdb[0]) == SCMD_SVC_ACTION_IN_G5) && (                          \
+	    ((cdb[1]) & 0x1F) == 0x01))					|| \
+	/* MAINTENANCE IN with service actions REPORT ALIASES (0x0Bh) */   \
+	/* REPORT DEVICE IDENTIFIER (0x05)  REPORT PRIORITY (0x0Eh) */     \
+	/* REPORT TARGET PORT GROUPS (0x0A) REPORT TIMESTAMP (0x0F) */     \
+	(((cdb[0]) == SCMD_MAINTENANCE_IN) && (                            \
+	    (((cdb[1]) & 0x1F) == 0x0B) ||                                 \
+	    (((cdb[1]) & 0x1F) == 0x05) ||                                 \
+	    (((cdb[1]) & 0x1F) == 0x0E) ||                                 \
+	    (((cdb[1]) & 0x1F) == 0x0A) ||                                 \
+	    (((cdb[1]) & 0x1F) == 0x0F)))				|| \
+	/* ----------------------- */                                      \
+	/* SBC-3 (rev 17) Table 3  */                                      \
+	/* ----------------------- */                                      \
+	/* READ CAPACITY(10) */                                            \
+	((cdb[0]) == SCMD_READ_CAPACITY)				|| \
+	/* READ CAPACITY(16) */                                            \
+	(((cdb[0]) == SCMD_SVC_ACTION_IN_G4) && (                          \
+	    ((cdb[1]) & 0x1F) == 0x10))					|| \
+	/* START STOP UNIT with START bit 0 and POWER CONDITION 0  */      \
+	(((cdb[0]) == SCMD_START_STOP) && (                                \
+	    (((cdb[4]) & 0xF0) == 0) && (((cdb[4]) & 0x01) == 0))))
+/* End of SCSI2_CONFLICT_FREE_CMDS */
+
 stmf_status_t sbd_lu_reset_state(stmf_lu_t *lu);
 static void sbd_handle_sync_cache(struct scsi_task *task,
     struct stmf_data_buf *initial_dbuf);
 void sbd_handle_read_xfer_completion(struct scsi_task *task,
     sbd_cmd_t *scmd, struct stmf_data_buf *dbuf);
+void sbd_handle_short_write_xfer_completion(scsi_task_t *task,
+    stmf_data_buf_t *dbuf);
+void sbd_handle_short_write_transfers(scsi_task_t *task,
+    stmf_data_buf_t *dbuf, uint32_t cdb_xfer_size);
+static void sbd_handle_sync_cache(struct scsi_task *task,
+    struct stmf_data_buf *initial_dbuf);
+void sbd_handle_mode_select_xfer(scsi_task_t *task, uint8_t *buf,
+    uint32_t buflen);
+void sbd_handle_mode_select(scsi_task_t *task, stmf_data_buf_t *dbuf);
 
+extern void sbd_pgr_initialize_it(scsi_task_t *);
+extern int sbd_pgr_reservation_conflict(scsi_task_t *);
+extern void sbd_pgr_remove_it_handle(sbd_lu_t *, sbd_it_data_t *);
+extern void sbd_handle_pgr_in_cmd(scsi_task_t *, stmf_data_buf_t *);
+extern void sbd_handle_pgr_out_cmd(scsi_task_t *, stmf_data_buf_t *);
+extern void sbd_handle_pgr_out_data(scsi_task_t *, stmf_data_buf_t *);
 /*
  * IMPORTANT NOTE:
  * =================
@@ -62,8 +118,7 @@
 sbd_do_read_xfer(struct scsi_task *task, sbd_cmd_t *scmd,
 					struct stmf_data_buf *dbuf)
 {
-	sbd_store_t *sst = (sbd_store_t *)task->task_lu->lu_provider_private;
-	sbd_lu_t *slu = (sbd_lu_t *)sst->sst_sbd_private;
+	sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private;
 	uint64_t laddr;
 	uint32_t len, buflen, iolen;
 	int ndx;
@@ -75,15 +130,15 @@
 	    task->task_max_nbufs;
 
 	len = scmd->len > dbuf->db_buf_size ? dbuf->db_buf_size : scmd->len;
-	laddr = scmd->addr + scmd->current_ro + slu->sl_sli->sli_lu_data_offset;
+	laddr = scmd->addr + scmd->current_ro;
 
 	for (buflen = 0, ndx = 0; (buflen < len) &&
 	    (ndx < dbuf->db_sglist_length); ndx++) {
 		iolen = min(len - buflen, dbuf->db_sglist[ndx].seg_length);
 		if (iolen == 0)
 			break;
-		if (sst->sst_data_read(sst, laddr, (uint64_t)iolen,
-		    dbuf->db_sglist[ndx].seg_addr) != STMF_SUCCESS) {
+		if (sbd_data_read(sl, laddr, (uint64_t)iolen,
+		    dbuf->db_sglist[0].seg_addr) != STMF_SUCCESS) {
 			scmd->flags |= SBD_SCSI_CMD_XFER_FAIL;
 			/* Do not need to do xfer anymore, just complete it */
 			dbuf->db_data_size = 0;
@@ -176,8 +231,7 @@
 	uint64_t lba, laddr;
 	uint32_t len;
 	uint8_t op = task->task_cdb[0];
-	sbd_store_t *sst = (sbd_store_t *)task->task_lu->lu_provider_private;
-	sbd_lu_t *slu = (sbd_lu_t *)sst->sst_sbd_private;
+	sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private;
 	sbd_cmd_t *scmd;
 	stmf_data_buf_t *dbuf;
 	int fast_path;
@@ -204,10 +258,10 @@
 		return;
 	}
 
-	laddr = lba << slu->sl_shift_count;
-	len <<= slu->sl_shift_count;
+	laddr = lba << sl->sl_data_blocksize_shift;
+	len <<= sl->sl_data_blocksize_shift;
 
-	if ((laddr + (uint64_t)len) > slu->sl_sli->sli_lu_data_size) {
+	if ((laddr + (uint64_t)len) > sl->sl_lu_size) {
 		stmf_scsilib_send_status(task, STATUS_CHECK,
 		    STMF_SAA_LBA_OUT_OF_RANGE);
 		return;
@@ -251,8 +305,7 @@
 
 	if ((dbuf->db_buf_size >= len) && fast_path &&
 	    (dbuf->db_sglist_length == 1)) {
-		if (sst->sst_data_read(sst,
-		    laddr + slu->sl_sli->sli_lu_data_offset, (uint64_t)len,
+		if (sbd_data_read(sl, laddr, (uint64_t)len,
 		    dbuf->db_sglist[0].seg_addr) == STMF_SUCCESS) {
 			dbuf->db_relative_offset = 0;
 			dbuf->db_data_size = len;
@@ -324,8 +377,7 @@
 sbd_handle_write_xfer_completion(struct scsi_task *task, sbd_cmd_t *scmd,
     struct stmf_data_buf *dbuf, uint8_t dbuf_reusable)
 {
-	sbd_store_t *sst = (sbd_store_t *)task->task_lu->lu_provider_private;
-	sbd_lu_t *slu = (sbd_lu_t *)sst->sst_sbd_private;
+	sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private;
 	uint64_t laddr;
 	uint32_t buflen, iolen;
 	int ndx;
@@ -340,8 +392,7 @@
 		goto WRITE_XFER_DONE;
 	}
 
-	laddr = scmd->addr + dbuf->db_relative_offset +
-	    slu->sl_sli->sli_lu_data_offset;
+	laddr = scmd->addr + dbuf->db_relative_offset;
 
 	for (buflen = 0, ndx = 0; (buflen < dbuf->db_data_size) &&
 	    (ndx < dbuf->db_sglist_length); ndx++) {
@@ -349,8 +400,8 @@
 		    dbuf->db_sglist[ndx].seg_length);
 		if (iolen == 0)
 			break;
-		if (sst->sst_data_write(sst, laddr, (uint64_t)iolen,
-		    dbuf->db_sglist[ndx].seg_addr) != STMF_SUCCESS) {
+		if (sbd_data_write(sl, laddr, (uint64_t)iolen,
+		    dbuf->db_sglist[0].seg_addr) != STMF_SUCCESS) {
 			scmd->flags |= SBD_SCSI_CMD_XFER_FAIL;
 			break;
 		}
@@ -402,11 +453,15 @@
 	uint64_t lba, laddr;
 	uint32_t len;
 	uint8_t op = task->task_cdb[0], do_immediate_data = 0;
-	sbd_store_t *sst = (sbd_store_t *)task->task_lu->lu_provider_private;
-	sbd_lu_t *slu = (sbd_lu_t *)sst->sst_sbd_private;
+	sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private;
 	sbd_cmd_t *scmd;
 	stmf_data_buf_t *dbuf;
 
+	if (sl->sl_flags & SL_WRITE_PROTECTED) {
+		stmf_scsilib_send_status(task, STATUS_CHECK,
+		    STMF_SAA_WRITE_PROTECTED);
+		return;
+	}
 	if (op == SCMD_WRITE) {
 		lba = READ_SCSI21(&task->task_cdb[1], uint64_t);
 		len = (uint32_t)task->task_cdb[4];
@@ -429,10 +484,10 @@
 		return;
 	}
 
-	laddr = lba << slu->sl_shift_count;
-	len <<= slu->sl_shift_count;
+	laddr = lba << sl->sl_data_blocksize_shift;
+	len <<= sl->sl_data_blocksize_shift;
 
-	if ((laddr + (uint64_t)len) > slu->sl_sli->sli_lu_data_size) {
+	if ((laddr + (uint64_t)len) > sl->sl_lu_size) {
 		stmf_scsilib_send_status(task, STATUS_CHECK,
 		    STMF_SAA_LBA_OUT_OF_RANGE);
 		return;
@@ -584,18 +639,111 @@
 }
 
 void
+sbd_handle_short_write_transfers(scsi_task_t *task,
+    stmf_data_buf_t *dbuf, uint32_t cdb_xfer_size)
+{
+	sbd_cmd_t *scmd;
+
+	task->task_cmd_xfer_length = cdb_xfer_size;
+	if (task->task_additional_flags & TASK_AF_NO_EXPECTED_XFER_LENGTH) {
+		task->task_expected_xfer_length = cdb_xfer_size;
+	} else {
+		cdb_xfer_size = min(cdb_xfer_size,
+		    task->task_expected_xfer_length);
+	}
+
+	if (cdb_xfer_size == 0) {
+		stmf_scsilib_send_status(task, STATUS_CHECK,
+		    STMF_SAA_INVALID_FIELD_IN_CDB);
+		return;
+	}
+	if (task->task_lu_private == NULL) {
+		task->task_lu_private = kmem_zalloc(sizeof (sbd_cmd_t),
+		    KM_SLEEP);
+	} else {
+		bzero(task->task_lu_private, sizeof (sbd_cmd_t));
+	}
+	scmd = (sbd_cmd_t *)task->task_lu_private;
+	scmd->cmd_type = SBD_CMD_SMALL_WRITE;
+	scmd->flags = SBD_SCSI_CMD_ACTIVE;
+	scmd->len = cdb_xfer_size;
+	if (dbuf == NULL) {
+		uint32_t minsize = cdb_xfer_size;
+
+		dbuf = stmf_alloc_dbuf(task, cdb_xfer_size, &minsize, 0);
+		if (dbuf == NULL) {
+			stmf_abort(STMF_QUEUE_TASK_ABORT, task,
+			    STMF_ALLOC_FAILURE, NULL);
+			return;
+		}
+		dbuf->db_data_size = cdb_xfer_size;
+		dbuf->db_relative_offset = 0;
+		dbuf->db_flags = DB_DIRECTION_FROM_RPORT;
+		stmf_xfer_data(task, dbuf, 0);
+	} else {
+		if (dbuf->db_data_size < cdb_xfer_size) {
+			stmf_abort(STMF_QUEUE_TASK_ABORT, task,
+			    STMF_ABORTED, NULL);
+			return;
+		}
+		dbuf->db_data_size = cdb_xfer_size;
+		sbd_handle_short_write_xfer_completion(task, dbuf);
+	}
+}
+
+void
+sbd_handle_short_write_xfer_completion(scsi_task_t *task,
+    stmf_data_buf_t *dbuf)
+{
+	sbd_cmd_t *scmd;
+
+	/*
+	 * For now lets assume we will get only one sglist element
+	 * for short writes. If that ever changes, we should allocate
+	 * a local buffer and copy all the sg elements to one linear space.
+	 */
+	if ((dbuf->db_xfer_status != STMF_SUCCESS) ||
+	    (dbuf->db_sglist_length > 1)) {
+		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
+		    dbuf->db_xfer_status, NULL);
+		return;
+	}
+
+	task->task_nbytes_transferred = dbuf->db_data_size;
+	scmd = (sbd_cmd_t *)task->task_lu_private;
+	scmd->flags &= ~SBD_SCSI_CMD_ACTIVE;
+
+	/* Lets find out who to call */
+	switch (task->task_cdb[0]) {
+	case SCMD_MODE_SELECT:
+	case SCMD_MODE_SELECT_G1:
+		sbd_handle_mode_select_xfer(task,
+		    dbuf->db_sglist[0].seg_addr, dbuf->db_data_size);
+		break;
+	case SCMD_PERSISTENT_RESERVE_OUT:
+		sbd_handle_pgr_out_data(task, dbuf);
+		break;
+	default:
+		/* This should never happen */
+		stmf_abort(STMF_QUEUE_TASK_ABORT, task,
+		    STMF_ABORTED, NULL);
+	}
+}
+
+void
 sbd_handle_read_capacity(struct scsi_task *task,
     struct stmf_data_buf *initial_dbuf)
 {
-	sbd_store_t *sst = (sbd_store_t *)task->task_lu->lu_provider_private;
-	sbd_lu_t *slu = (sbd_lu_t *)sst->sst_sbd_private;
-	sbd_lu_info_t *sli = slu->sl_sli;
+	sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private;
 	uint32_t cdb_len;
 	uint8_t p[32];
 	uint64_t s;
+	uint16_t blksize;
 
-	s = sli->sli_lu_data_size >> slu->sl_shift_count;
+	s = sl->sl_lu_size >> sl->sl_data_blocksize_shift;
 	s--;
+	blksize = ((uint16_t)1) << sl->sl_data_blocksize_shift;
+
 	switch (task->task_cdb[0]) {
 	case SCMD_READ_CAPACITY:
 		if (s & 0xffffffff00000000ull) {
@@ -607,10 +755,10 @@
 			p[3] = s & 0xff;
 		}
 		p[4] = 0; p[5] = 0;
-		p[6] = (sli->sli_blocksize >> 8) & 0xff;
-		p[7] = sli->sli_blocksize & 0xff;
+		p[6] = (blksize >> 8) & 0xff;
+		p[7] = blksize & 0xff;
 		sbd_handle_short_read_transfers(task, initial_dbuf, p, 8, 8);
-		return;
+		break;
 
 	case SCMD_SVC_ACTION_IN_G4:
 		cdb_len = READ_SCSI32(&task->task_cdb[10], uint32_t);
@@ -623,154 +771,316 @@
 		p[5] = (s >> 16) & 0xff;
 		p[6] = (s >> 8) & 0xff;
 		p[7] = s & 0xff;
-		p[10] = (sli->sli_blocksize >> 8) & 0xff;
-		p[11] = sli->sli_blocksize & 0xff;
+		p[10] = (blksize >> 8) & 0xff;
+		p[11] = blksize & 0xff;
 		sbd_handle_short_read_transfers(task, initial_dbuf, p,
 		    cdb_len, 32);
-		return;
+		break;
 	}
 }
 
-static uint8_t sbd_p3[] =
-	{3, 0x16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 2, 0, 0, 0,
-	    0, 0, 0, 0, 0x80, 0, 0, 0};
-static uint8_t sbd_p4[] =
-	{4, 0x16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	    0, 0, 0, 0, 0x15, 0x18, 0, 0};
-static uint8_t sbd_pa[] = {0xa, 0xa, 0, 0x10, 0, 0, 0, 0, 0, 0, 0, 0};
-static uint8_t sbd_bd[] = {0, 0, 0, 0, 0, 0, 0x02, 0};
+void
+sbd_calc_geometry(uint64_t s, uint16_t blksize, uint8_t *nsectors,
+    uint8_t *nheads, uint32_t *ncyl)
+{
+	if (s < (4ull * 1024ull * 1024ull * 1024ull)) {
+		*nsectors = 32;
+		*nheads = 8;
+	} else {
+		*nsectors = 254;
+		*nheads = 254;
+	}
+	*ncyl = s / ((uint64_t)blksize * (uint64_t)(*nsectors) *
+	    (uint64_t)(*nheads));
+}
 
 void
 sbd_handle_mode_sense(struct scsi_task *task,
-    struct stmf_data_buf *initial_dbuf)
+    struct stmf_data_buf *initial_dbuf, uint8_t *buf)
 {
-	sbd_store_t *sst = (sbd_store_t *)task->task_lu->lu_provider_private;
-	sbd_lu_t *slu = (sbd_lu_t *)sst->sst_sbd_private;
-	sbd_lu_info_t *sli = slu->sl_sli;
-	uint32_t cmd_size, hdrsize, xfer_size, ncyl;
-	uint8_t payload_buf[8 + 8 + 24 + 24 + 12];
-	uint8_t *payload, *p;
-	uint8_t ctrl, page;
-	uint16_t ps;
-	uint64_t s = sli->sli_lu_data_size;
-	uint8_t dbd;
-
-	p = &task->task_cdb[0];
-	page = p[2] & 0x3F;
-	ctrl = (p[2] >> 6) & 3;
-	dbd = p[1] & 0x08;
-
-	hdrsize = (p[0] == SCMD_MODE_SENSE) ? 4 : 8;
-
-	cmd_size = (p[0] == SCMD_MODE_SENSE) ? p[4] :
-	    READ_SCSI16(&p[7], uint32_t);
+	sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	uint32_t cmd_size, n;
+	uint8_t *cdb;
+	uint32_t ncyl;
+	uint8_t nsectors, nheads;
+	uint8_t page, ctrl, header_size, pc_valid;
+	uint16_t nbytes;
+	uint8_t *p;
+	uint64_t s = sl->sl_lu_size;
+	uint32_t dev_spec_param_offset;
 
-	switch (page) {
-	case 0x03:
-		ps = hdrsize + sizeof (sbd_p3);
-		break;
-	case 0x04:
-		ps = hdrsize + sizeof (sbd_p4);
-		break;
-	case 0x0A:
-		ps = hdrsize + sizeof (sbd_pa);
-		break;
-	case MODEPAGE_ALLPAGES:
-		ps = hdrsize + sizeof (sbd_p3) + sizeof (sbd_p4)
-		    + sizeof (sbd_pa);
+	p = buf;	/* buf is assumed to be zeroed out and large enough */
+	n = 0;
+	cdb = &task->task_cdb[0];
+	page = cdb[2] & 0x3F;
+	ctrl = (cdb[2] >> 6) & 3;
+	cmd_size = (cdb[0] == SCMD_MODE_SENSE) ? cdb[4] :
+	    READ_SCSI16(&cdb[7], uint32_t);
 
-		/*
-		 * If the buffer is big enough, include the block
-		 * descriptor; otherwise, leave it out.
-		 */
-		if (cmd_size < ps) {
-			dbd = 1;
-		}
+	if (cdb[0] == SCMD_MODE_SENSE) {
+		header_size = 4;
+		dev_spec_param_offset = 2;
+	} else {
+		header_size = 8;
+		dev_spec_param_offset = 3;
+	}
 
-		if (dbd == 0) {
-			ps += 8;
-		}
-
-		break;
-	default:
+	/* Now validate the command */
+	if ((cdb[2] == 0) || (page == MODEPAGE_ALLPAGES) || (page == 0x08) ||
+	    (page == 0x0A) || (page == 0x03) || (page == 0x04)) {
+		pc_valid = 1;
+	} else {
+		pc_valid = 0;
+	}
+	if ((cmd_size < header_size) || (pc_valid == 0)) {
 		stmf_scsilib_send_status(task, STATUS_CHECK,
 		    STMF_SAA_INVALID_FIELD_IN_CDB);
 		return;
 	}
 
-	xfer_size = min(cmd_size, ps);
+	/* We will update the length in the mode header at the end */
+
+	/* Block dev device specific param in mode param header has wp bit */
+	if (sl->sl_flags & SL_WRITE_PROTECTED) {
+		p[n + dev_spec_param_offset] = BIT_7;
+	}
+	n += header_size;
+	/* We are not going to return any block descriptor */
+
+	nbytes = ((uint16_t)1) << sl->sl_data_blocksize_shift;
+	sbd_calc_geometry(s, nbytes, &nsectors, &nheads, &ncyl);
+
+	if ((page == 0x03) || (page == MODEPAGE_ALLPAGES)) {
+		p[n] = 0x03;
+		p[n+1] = 0x16;
+		if (ctrl != 1) {
+			p[n + 11] = nsectors;
+			p[n + 12] = nbytes >> 8;
+			p[n + 13] = nbytes & 0xff;
+			p[n + 20] = 0x80;
+		}
+		n += 24;
+	}
+	if ((page == 0x04) || (page == MODEPAGE_ALLPAGES)) {
+		p[n] = 0x04;
+		p[n + 1] = 0x16;
+		if (ctrl != 1) {
+			p[n + 2] = ncyl >> 16;
+			p[n + 3] = ncyl >> 8;
+			p[n + 4] = ncyl & 0xff;
+			p[n + 5] = nheads;
+			p[n + 20] = 0x15;
+			p[n + 21] = 0x18;
+		}
+		n += 24;
+	}
+	if ((page == MODEPAGE_CACHING) || (page == MODEPAGE_ALLPAGES)) {
+		struct mode_caching *mode_caching_page;
+
+		mode_caching_page = (struct mode_caching *)&p[n];
+
+		mode_caching_page->mode_page.code = MODEPAGE_CACHING;
+		mode_caching_page->mode_page.ps = 1; /* A saveable page */
+		mode_caching_page->mode_page.length = 0x12;
+
+		switch (ctrl) {
+		case (0):
+			/* Current */
+			if ((sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) == 0) {
+				mode_caching_page->wce = 1;
+			}
+			break;
+
+		case (1):
+			/* Changeable */
+			if ((sl->sl_flags &
+			    SL_WRITEBACK_CACHE_SET_UNSUPPORTED) == 0) {
+				mode_caching_page->wce = 1;
+			}
+			break;
 
-	if ((xfer_size < hdrsize) || (ctrl == 1) ||
-	    (((task->task_additional_flags &
-	    TASK_AF_NO_EXPECTED_XFER_LENGTH) == 0) &&
-	    (xfer_size > task->task_expected_xfer_length))) {
+		default:
+			if ((sl->sl_flags &
+			    SL_SAVED_WRITE_CACHE_DISABLE) == 0) {
+				mode_caching_page->wce = 1;
+			}
+			break;
+		}
+		n += (sizeof (struct mode_page) +
+		    mode_caching_page->mode_page.length);
+	}
+	if ((page == MODEPAGE_CTRL_MODE) || (page == MODEPAGE_ALLPAGES)) {
+		struct mode_control_scsi3 *mode_control_page;
+
+		mode_control_page = (struct mode_control_scsi3 *)&p[n];
+
+		mode_control_page->mode_page.code = MODEPAGE_CTRL_MODE;
+		mode_control_page->mode_page.length =
+		    PAGELENGTH_MODE_CONTROL_SCSI3;
+		if (ctrl != 1) {
+			/* If not looking for changeable values, report this. */
+			mode_control_page->que_mod = CTRL_QMOD_UNRESTRICT;
+		}
+		n += (sizeof (struct mode_page) +
+		    mode_control_page->mode_page.length);
+	}
+
+	if (cdb[0] == SCMD_MODE_SENSE) {
+		if (n > 255) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INVALID_FIELD_IN_CDB);
+			return;
+		}
+		/*
+		 * Mode parameter header length doesn't include the number
+		 * of bytes in the length field, so adjust the count.
+		 * Byte count minus header length field size.
+		 */
+		buf[0] = (n - 1) & 0xff;
+	} else {
+		/* Byte count minus header length field size. */
+		buf[1] = (n - 2) & 0xff;
+		buf[0] = ((n - 2) >> 8) & 0xff;
+	}
+
+	sbd_handle_short_read_transfers(task, initial_dbuf, buf,
+	    cmd_size, n);
+}
+
+void
+sbd_handle_mode_select(scsi_task_t *task, stmf_data_buf_t *dbuf)
+{
+	uint32_t cmd_xfer_len;
+
+	if (task->task_cdb[0] == SCMD_MODE_SELECT) {
+		cmd_xfer_len = (uint32_t)task->task_cdb[4];
+	} else {
+		cmd_xfer_len = READ_SCSI16(&task->task_cdb[7], uint32_t);
+	}
+
+	if ((task->task_cdb[1] & 0xFE) != 0x10) {
 		stmf_scsilib_send_status(task, STATUS_CHECK,
 		    STMF_SAA_INVALID_FIELD_IN_CDB);
 		return;
 	}
 
-	bzero(payload_buf, xfer_size);
+	if (cmd_xfer_len == 0) {
+		/* zero byte mode selects are allowed */
+		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+		return;
+	}
+
+	sbd_handle_short_write_transfers(task, dbuf, cmd_xfer_len);
+}
+
+void
+sbd_handle_mode_select_xfer(scsi_task_t *task, uint8_t *buf, uint32_t buflen)
+{
+	sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	sbd_it_data_t *it;
+	int hdr_len, bd_len;
+	sbd_status_t sret;
+	int i;
+
+	if (task->task_cdb[0] == SCMD_MODE_SELECT) {
+		hdr_len = 4;
+	} else {
+		hdr_len = 8;
+	}
 
-	if (p[0] == SCMD_MODE_SENSE) {
-		payload_buf[0] = ps - 1;
-	} else {
-		ps -= 2;
-		*((uint16_t *)payload_buf) = BE_16(ps);
+	if (buflen < hdr_len)
+		goto mode_sel_param_len_err;
+
+	bd_len = hdr_len == 4 ? buf[3] : READ_SCSI16(&buf[6], int);
+
+	if (buflen < (hdr_len + bd_len + 2))
+		goto mode_sel_param_len_err;
+
+	buf += hdr_len + bd_len;
+	buflen -= hdr_len + bd_len;
+
+	if ((buf[0] != 8) || (buflen != ((uint32_t)buf[1] + 2))) {
+		goto mode_sel_param_len_err;
+	}
+
+	if (buf[2] & 0xFB) {
+		goto mode_sel_param_field_err;
+	}
+
+	for (i = 3; i < (buf[1] + 2); i++) {
+		if (buf[i]) {
+			goto mode_sel_param_field_err;
+		}
 	}
 
-	payload = payload_buf + hdrsize;
-
-	switch (page) {
-	case 0x03:
-		bcopy(sbd_p3, payload, sizeof (sbd_p3));
-		break;
+	sret = SBD_SUCCESS;
 
-	case 0x0A:
-		bcopy(sbd_pa, payload, sizeof (sbd_pa));
-		break;
-
-	case MODEPAGE_ALLPAGES:
-		if (dbd == 0) {
-			payload_buf[3] = sizeof (sbd_bd);
-			bcopy(sbd_bd, payload, sizeof (sbd_bd));
-			payload += sizeof (sbd_bd);
-		}
+	/* All good. Lets handle the write cache change, if any */
+	if (buf[2] & BIT_2) {
+		sret = sbd_wcd_set(0, sl);
+	} else {
+		sret = sbd_wcd_set(1, sl);
+	}
 
-		bcopy(sbd_p3, payload, sizeof (sbd_p3));
-		payload += sizeof (sbd_p3);
-		bcopy(sbd_pa, payload, sizeof (sbd_pa));
-		payload += sizeof (sbd_pa);
-		/* FALLTHROUGH */
-
-	case 0x04:
-		bcopy(sbd_p4, payload, sizeof (sbd_p4));
+	if (sret != SBD_SUCCESS) {
+		stmf_scsilib_send_status(task, STATUS_CHECK,
+		    STMF_SAA_WRITE_ERROR);
+		return;
+	}
 
-		if (s > 1024 * 1024 * 1024) {
-			payload[5] = 16;
-		} else {
-			payload[5] = 2;
-		}
-		ncyl = (uint32_t)((s/(((uint64_t)payload[5]) * 32 * 512)) + 1);
-		payload[4] = (uchar_t)ncyl;
-		payload[3] = (uchar_t)(ncyl >> 8);
-		payload[2] = (uchar_t)(ncyl >> 16);
-		break;
-
+	/* set on the device passed, now set the flags */
+	mutex_enter(&sl->sl_lock);
+	if (buf[2] & BIT_2) {
+		sl->sl_flags &= ~SL_WRITEBACK_CACHE_DISABLE;
+	} else {
+		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE;
 	}
 
-	sbd_handle_short_read_transfers(task, initial_dbuf, payload_buf,
-	    cmd_size, xfer_size);
+	for (it = sl->sl_it_list; it != NULL; it = it->sbd_it_next) {
+		if (it == task->task_lu_itl_handle)
+			continue;
+		it->sbd_it_ua_conditions |= SBD_UA_MODE_PARAMETERS_CHANGED;
+	}
+
+	if (task->task_cdb[1] & 1) {
+		if (buf[2] & BIT_2) {
+			sl->sl_flags &= ~SL_SAVED_WRITE_CACHE_DISABLE;
+		} else {
+			sl->sl_flags |= SL_SAVED_WRITE_CACHE_DISABLE;
+		}
+		mutex_exit(&sl->sl_lock);
+		sret = sbd_write_lu_info(sl);
+	} else {
+		mutex_exit(&sl->sl_lock);
+	}
+	if (sret == SBD_SUCCESS) {
+		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+	} else {
+		stmf_scsilib_send_status(task, STATUS_CHECK,
+		    STMF_SAA_WRITE_ERROR);
+	}
+	return;
+
+mode_sel_param_len_err:
+	stmf_scsilib_send_status(task, STATUS_CHECK,
+	    STMF_SAA_PARAM_LIST_LENGTH_ERROR);
+	return;
+mode_sel_param_field_err:
+	stmf_scsilib_send_status(task, STATUS_CHECK,
+	    STMF_SAA_INVALID_FIELD_IN_PARAM_LIST);
 }
 
-
 void
 sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf,
 			uint8_t *p, int bsize)
 {
-	uint8_t		*cdbp = (uint8_t *)&task->task_cdb[0];
-	uint32_t	 cmd_size;
-	uint8_t		 page_length;
+	sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private;
+	uint8_t *cdbp = (uint8_t *)&task->task_cdb[0];
+	uint32_t cmd_size;
+	uint8_t page_length;
+	uint8_t byte0;
 
+	byte0 = DTYPE_DIRECT;
 	/*
 	 * Basic protocol checks.
 	 */
@@ -808,19 +1118,32 @@
 		page_length = 31;
 		bzero(inq, page_length + 5);
 
-		inq->inq_dtype = 0;
+		inq->inq_dtype = DTYPE_DIRECT;
 		inq->inq_ansi = 5;	/* SPC-3 */
 		inq->inq_hisup = 1;
 		inq->inq_rdf = 2;	/* Response data format for SPC-3 */
 		inq->inq_len = page_length;
 
 		inq->inq_tpgs = 1;
-
 		inq->inq_cmdque = 1;
 
-		(void) strncpy((char *)inq->inq_vid, "SUN     ", 8);
-		(void) strncpy((char *)inq->inq_pid, "COMSTAR         ", 16);
-		(void) strncpy((char *)inq->inq_revision, "1.0 ", 4);
+		if (sl->sl_flags & SL_VID_VALID) {
+			bcopy(sl->sl_vendor_id, inq->inq_vid, 8);
+		} else {
+			bcopy(sbd_vendor_id, inq->inq_vid, 8);
+		}
+
+		if (sl->sl_flags & SL_PID_VALID) {
+			bcopy(sl->sl_product_id, inq->inq_pid, 16);
+		} else {
+			bcopy(sbd_product_id, inq->inq_pid, 16);
+		}
+
+		if (sl->sl_flags & SL_REV_VALID) {
+			bcopy(sl->sl_revision, inq->inq_revision, 4);
+		} else {
+			bcopy(sbd_revision, inq->inq_revision, 4);
+		}
 
 		sbd_handle_short_read_transfers(task, initial_dbuf, p, cmd_size,
 		    min(cmd_size, page_length + 5));
@@ -834,21 +1157,34 @@
 
 	switch (cdbp[2]) {
 	case 0x00:
-		page_length = 3;
+		page_length = 4;
 
 		bzero(p, page_length + 4);
 
-		p[0] = 0;
-		p[3] = page_length;	/* we support 3 pages, 0, 0x83, 0x86 */
-		p[5] = 0x83;
-		p[6] = 0x86;
+		p[0] = byte0;
+		p[3] = page_length;
+		p[5] = 0x80;
+		p[6] = 0x83;
+		p[7] = 0x86;
+
+		break;
 
+	case 0x80:
+		if (sl->sl_serial_no_size) {
+			page_length = sl->sl_serial_no_size;
+			bcopy(sl->sl_serial_no, p + 4, sl->sl_serial_no_size);
+		} else {
+			bcopy("    ", p + 4, 4);
+		}
+		p[0] = byte0;
+		p[1] = 0x80;
+		p[3] = page_length;
 		break;
 
 	case 0x83:
 
 		page_length = stmf_scsilib_prepare_vpd_page83(task, p,
-		    bsize, 0, STMF_VPD_LU_ID|STMF_VPD_TARGET_ID|
+		    bsize, byte0, STMF_VPD_LU_ID|STMF_VPD_TARGET_ID|
 		    STMF_VPD_TP_GROUP|STMF_VPD_RELATIVE_TP_ID) - 4;
 		break;
 
@@ -857,7 +1193,7 @@
 
 		bzero(p, page_length + 4);
 
-		p[0] = 0;
+		p[0] = byte0;
 		p[1] = 0x86;		/* Page 86 response */
 		p[3] = page_length;
 
@@ -894,42 +1230,43 @@
 }
 
 void
-sbd_remove_it_handle(sbd_lu_t *slu, sbd_it_data_t *it)
+sbd_remove_it_handle(sbd_lu_t *sl, sbd_it_data_t *it)
 {
 	sbd_it_data_t **ppit;
 
-	mutex_enter(&slu->sl_it_list_lock);
-	for (ppit = &slu->sl_it_list; *ppit != NULL;
+	sbd_pgr_remove_it_handle(sl, it);
+	mutex_enter(&sl->sl_lock);
+	for (ppit = &sl->sl_it_list; *ppit != NULL;
 	    ppit = &((*ppit)->sbd_it_next)) {
 		if ((*ppit) == it) {
 			*ppit = it->sbd_it_next;
 			break;
 		}
 	}
-	mutex_exit(&slu->sl_it_list_lock);
+	mutex_exit(&sl->sl_lock);
 
-	DTRACE_PROBE2(itl__nexus__end, stmf_lu_t *, slu->sl_lu,
+	DTRACE_PROBE2(itl__nexus__end, stmf_lu_t *, sl->sl_lu,
 	    sbd_it_data_t *, it);
 
 	kmem_free(it, sizeof (*it));
 }
 
 void
-sbd_check_and_clear_scsi2_reservation(sbd_lu_t *slu, sbd_it_data_t *it)
+sbd_check_and_clear_scsi2_reservation(sbd_lu_t *sl, sbd_it_data_t *it)
 {
-	mutex_enter(&slu->sl_it_list_lock);
-	if ((slu->sl_flags & SBD_LU_HAS_SCSI2_RESERVATION) == 0) {
+	mutex_enter(&sl->sl_lock);
+	if ((sl->sl_flags & SL_LU_HAS_SCSI2_RESERVATION) == 0) {
 		/* If we dont have any reservations, just get out. */
-		mutex_exit(&slu->sl_it_list_lock);
+		mutex_exit(&sl->sl_lock);
 		return;
 	}
 
 	if (it == NULL) {
 		/* Find the I_T nexus which is holding the reservation. */
-		for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
+		for (it = sl->sl_it_list; it != NULL; it = it->sbd_it_next) {
 			if (it->sbd_it_flags & SBD_IT_HAS_SCSI2_RESERVATION) {
 				ASSERT(it->sbd_it_session_id ==
-				    slu->sl_rs_owner_session_id);
+				    sl->sl_rs_owner_session_id);
 				break;
 			}
 		}
@@ -941,74 +1278,63 @@
 		 * called "check_and_clear".
 		 */
 		if ((it->sbd_it_flags & SBD_IT_HAS_SCSI2_RESERVATION) == 0) {
-			mutex_exit(&slu->sl_it_list_lock);
+			mutex_exit(&sl->sl_lock);
 			return;
 		}
 	}
 	it->sbd_it_flags &= ~SBD_IT_HAS_SCSI2_RESERVATION;
-	slu->sl_flags &= ~SBD_IT_HAS_SCSI2_RESERVATION;
-	mutex_exit(&slu->sl_it_list_lock);
+	sl->sl_flags &= ~SL_LU_HAS_SCSI2_RESERVATION;
+	mutex_exit(&sl->sl_lock);
 }
 
-/*
- * returns non-zero, if this command can be allowed to run even if the
- * lu has been reserved by another initiator.
- */
-int
-sbd_reserve_allow(scsi_task_t *task)
-{
-	uint8_t cdb0 = task->task_cdb[0];
-	uint8_t cdb1 = task->task_cdb[1];
 
-	if ((cdb0 == SCMD_INQUIRY) || (cdb0 == SCMD_READ_CAPACITY) ||
-	    ((cdb0 == SCMD_SVC_ACTION_IN_G4) &&
-	    (cdb1 == SSVC_ACTION_READ_CAPACITY_G4))) {
-		return (1);
-	}
-	return (0);
-}
 
 void
 sbd_new_task(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
 {
-	sbd_store_t *sst = (sbd_store_t *)task->task_lu->lu_provider_private;
-	sbd_lu_t *slu = (sbd_lu_t *)sst->sst_sbd_private;
+	sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private;
 	sbd_it_data_t *it;
 	uint8_t cdb0, cdb1;
 
 	if ((it = task->task_lu_itl_handle) == NULL) {
-		mutex_enter(&slu->sl_it_list_lock);
-		for (it = slu->sl_it_list; it != NULL; it = it->sbd_it_next) {
+		mutex_enter(&sl->sl_lock);
+		for (it = sl->sl_it_list; it != NULL; it = it->sbd_it_next) {
 			if (it->sbd_it_session_id ==
 			    task->task_session->ss_session_id) {
-				mutex_exit(&slu->sl_it_list_lock);
+				mutex_exit(&sl->sl_lock);
 				stmf_scsilib_send_status(task, STATUS_BUSY, 0);
 				return;
 			}
 		}
 		it = (sbd_it_data_t *)kmem_zalloc(sizeof (*it), KM_NOSLEEP);
 		if (it == NULL) {
-			mutex_exit(&slu->sl_it_list_lock);
+			mutex_exit(&sl->sl_lock);
 			stmf_scsilib_send_status(task, STATUS_BUSY, 0);
 			return;
 		}
 		it->sbd_it_session_id = task->task_session->ss_session_id;
 		bcopy(task->task_lun_no, it->sbd_it_lun, 8);
-		it->sbd_it_next = slu->sl_it_list;
-		slu->sl_it_list = it;
-		mutex_exit(&slu->sl_it_list_lock);
+		it->sbd_it_next = sl->sl_it_list;
+		sl->sl_it_list = it;
+		mutex_exit(&sl->sl_lock);
 
 		DTRACE_PROBE1(itl__nexus__start, scsi_task *, task);
 
+		sbd_pgr_initialize_it(task);
 		if (stmf_register_itl_handle(task->task_lu, task->task_lun_no,
 		    task->task_session, it->sbd_it_session_id, it)
 		    != STMF_SUCCESS) {
-			sbd_remove_it_handle(slu, it);
+			sbd_remove_it_handle(sl, it);
 			stmf_scsilib_send_status(task, STATUS_BUSY, 0);
 			return;
 		}
 		task->task_lu_itl_handle = it;
 		it->sbd_it_ua_conditions = SBD_UA_POR;
+	} else if (it->sbd_it_flags & SBD_IT_PGR_CHECK_FLAG) {
+		sbd_pgr_initialize_it(task);
+		mutex_enter(&sl->sl_lock);
+		it->sbd_it_flags &= ~SBD_IT_PGR_CHECK_FLAG;
+		mutex_exit(&sl->sl_lock);
 	}
 
 	if (task->task_mgmt_function) {
@@ -1016,23 +1342,44 @@
 		return;
 	}
 
-	if ((slu->sl_flags & SBD_LU_HAS_SCSI2_RESERVATION) &&
+	/* Checking ua conditions as per SAM3R14 5.3.2 specified order */
+	if ((it->sbd_it_ua_conditions) && (task->task_cdb[0] != SCMD_INQUIRY)) {
+		uint32_t saa = 0;
+
+		mutex_enter(&sl->sl_lock);
+		if (it->sbd_it_ua_conditions & SBD_UA_POR) {
+			it->sbd_it_ua_conditions &= ~SBD_UA_POR;
+			saa = STMF_SAA_POR;
+		}
+		mutex_exit(&sl->sl_lock);
+		if (saa) {
+			stmf_scsilib_send_status(task, STATUS_CHECK, saa);
+			return;
+		}
+	}
+
+	/* Reservation conflict checks */
+	if (SBD_PGR_RSVD(sl->sl_pgr)) {
+		if (sbd_pgr_reservation_conflict(task)) {
+			stmf_scsilib_send_status(task,
+			    STATUS_RESERVATION_CONFLICT, 0);
+			return;
+		}
+	} else if ((sl->sl_flags & SL_LU_HAS_SCSI2_RESERVATION) &&
 	    ((it->sbd_it_flags & SBD_IT_HAS_SCSI2_RESERVATION) == 0)) {
-		if (!sbd_reserve_allow(task)) {
+		if (!(SCSI2_CONFLICT_FREE_CMDS(task->task_cdb))) {
 			stmf_scsilib_send_status(task,
 			    STATUS_RESERVATION_CONFLICT, 0);
 			return;
 		}
 	}
 
+	/* Rest of the ua conndition checks */
 	if ((it->sbd_it_ua_conditions) && (task->task_cdb[0] != SCMD_INQUIRY)) {
 		uint32_t saa = 0;
 
-		mutex_enter(&slu->sl_it_list_lock);
-		if (it->sbd_it_ua_conditions & SBD_UA_POR) {
-			it->sbd_it_ua_conditions &= ~SBD_UA_POR;
-			saa = STMF_SAA_POR;
-		} else if (it->sbd_it_ua_conditions & SBD_UA_CAPACITY_CHANGED) {
+		mutex_enter(&sl->sl_lock);
+		if (it->sbd_it_ua_conditions & SBD_UA_CAPACITY_CHANGED) {
 			it->sbd_it_ua_conditions &= ~SBD_UA_CAPACITY_CHANGED;
 			if ((task->task_cdb[0] == SCMD_READ_CAPACITY) ||
 			    ((task->task_cdb[0] == SCMD_SVC_ACTION_IN_G4) &&
@@ -1042,18 +1389,22 @@
 			} else {
 				saa = STMF_SAA_CAPACITY_DATA_HAS_CHANGED;
 			}
+		} else if (it->sbd_it_ua_conditions &
+		    SBD_UA_MODE_PARAMETERS_CHANGED) {
+			it->sbd_it_ua_conditions &=
+			    ~SBD_UA_MODE_PARAMETERS_CHANGED;
+			saa = STMF_SAA_MODE_PARAMETERS_CHANGED;
 		} else {
 			it->sbd_it_ua_conditions = 0;
 			saa = 0;
 		}
-		mutex_exit(&slu->sl_it_list_lock);
+		mutex_exit(&sl->sl_lock);
 		if (saa) {
 			stmf_scsilib_send_status(task, STATUS_CHECK, saa);
 			return;
 		}
 	}
 
-
 	cdb0 = task->task_cdb[0] & 0x1F;
 
 	if ((cdb0 == SCMD_READ) || (cdb0 == SCMD_WRITE)) {
@@ -1072,6 +1423,130 @@
 	cdb0 = task->task_cdb[0];
 	cdb1 = task->task_cdb[1];
 
+	if (cdb0 == SCMD_INQUIRY) {		/* Inquiry */
+		uint8_t *p;
+
+		p = (uint8_t *)kmem_zalloc(512, KM_SLEEP);
+		sbd_handle_inquiry(task, initial_dbuf, p, 512);
+		kmem_free(p, 512);
+		return;
+	}
+
+	if (cdb0  == SCMD_PERSISTENT_RESERVE_OUT) {
+		sbd_handle_pgr_out_cmd(task, initial_dbuf);
+		return;
+	}
+
+	if (cdb0  == SCMD_PERSISTENT_RESERVE_IN) {
+		sbd_handle_pgr_in_cmd(task, initial_dbuf);
+		return;
+	}
+
+	if (cdb0 == SCMD_RELEASE) {
+		if (cdb1) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INVALID_FIELD_IN_CDB);
+			return;
+		}
+
+		mutex_enter(&sl->sl_lock);
+		if (sl->sl_flags & SL_LU_HAS_SCSI2_RESERVATION) {
+			/* If not owner don't release it, just return good */
+			if (it->sbd_it_session_id !=
+			    sl->sl_rs_owner_session_id) {
+				mutex_exit(&sl->sl_lock);
+				stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+				return;
+			}
+		}
+		sl->sl_flags &= ~SL_LU_HAS_SCSI2_RESERVATION;
+		it->sbd_it_flags &= ~SBD_IT_HAS_SCSI2_RESERVATION;
+		mutex_exit(&sl->sl_lock);
+		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+		return;
+	}
+
+	if (cdb0 == SCMD_RESERVE) {
+		if (cdb1) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INVALID_FIELD_IN_CDB);
+			return;
+		}
+
+		mutex_enter(&sl->sl_lock);
+		if (sl->sl_flags & SL_LU_HAS_SCSI2_RESERVATION) {
+			/* If not owner, return conflict status */
+			if (it->sbd_it_session_id !=
+			    sl->sl_rs_owner_session_id) {
+				mutex_exit(&sl->sl_lock);
+				stmf_scsilib_send_status(task,
+				    STATUS_RESERVATION_CONFLICT, 0);
+				return;
+			}
+		}
+		sl->sl_flags |= SL_LU_HAS_SCSI2_RESERVATION;
+		it->sbd_it_flags |= SBD_IT_HAS_SCSI2_RESERVATION;
+		sl->sl_rs_owner_session_id = it->sbd_it_session_id;
+		mutex_exit(&sl->sl_lock);
+		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+		return;
+	}
+
+	if (cdb0 == SCMD_REQUEST_SENSE) {
+		/*
+		 * LU provider needs to store unretrieved sense data
+		 * (e.g. after power-on/reset).  For now, we'll just
+		 * return good status with no sense.
+		 */
+
+		if ((cdb1 & ~1) || task->task_cdb[2] || task->task_cdb[3] ||
+		    task->task_cdb[5]) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INVALID_FIELD_IN_CDB);
+		} else {
+			stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+		}
+
+		return;
+	}
+
+	/* Report Target Port Groups */
+	if ((cdb0 == SCMD_MAINTENANCE_IN) &&
+	    ((cdb1 & 0x1F) == 0x0A)) {
+		stmf_scsilib_handle_report_tpgs(task, initial_dbuf);
+		return;
+	}
+
+	if (cdb0 == SCMD_START_STOP) {			/* Start stop */
+		task->task_cmd_xfer_length = 0;
+		if (task->task_cdb[4] & 0xFC) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INVALID_FIELD_IN_CDB);
+			return;
+		}
+		if (task->task_cdb[4] & 2) {
+			stmf_scsilib_send_status(task, STATUS_CHECK,
+			    STMF_SAA_INVALID_FIELD_IN_CDB);
+		} else {
+			stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+		}
+		return;
+
+	}
+
+	if ((cdb0 == SCMD_MODE_SENSE) || (cdb0 == SCMD_MODE_SENSE_G1)) {
+		uint8_t *p;
+		p = kmem_zalloc(512, KM_SLEEP);
+		sbd_handle_mode_sense(task, initial_dbuf, p);
+		kmem_free(p, 512);
+		return;
+	}
+
+	if ((cdb0 == SCMD_MODE_SELECT) || (cdb0 == SCMD_MODE_SELECT_G1)) {
+		sbd_handle_mode_select(task, initial_dbuf);
+		return;
+	}
+
 	if (cdb0 == SCMD_TEST_UNIT_READY) {	/* Test unit ready */
 		task->task_cmd_xfer_length = 0;
 		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
@@ -1083,15 +1558,6 @@
 		return;
 	}
 
-	if (cdb0 == SCMD_INQUIRY) {		/* Inquiry */
-		uint8_t *p;
-
-		p = (uint8_t *)kmem_zalloc(512, KM_SLEEP);
-		sbd_handle_inquiry(task, initial_dbuf, p, 512);
-		kmem_free(p, 512);
-		return;
-	}
-
 	if (cdb0 == SCMD_SVC_ACTION_IN_G4) { 	/* Read Capacity or read long */
 		if (cdb1 == SSVC_ACTION_READ_CAPACITY_G4) {
 			sbd_handle_read_capacity(task, initial_dbuf);
@@ -1113,42 +1579,6 @@
 	 * }
 	 */
 
-	if (cdb0 == SCMD_START_STOP) {			/* Start stop */
-		/* XXX Implement power management */
-		task->task_cmd_xfer_length = 0;
-		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
-		return;
-	}
-#if 0
-	/* XXX Remove #if 0 above */
-	if ((cdb0 == SCMD_MODE_SELECT) || (cdb0 == SCMD_MODE_SELECT_G1)) {
-		sbd_handle_mode_select(task, initial_dbuf);
-		return;
-	}
-#endif
-	if ((cdb0 == SCMD_MODE_SENSE) || (cdb0 == SCMD_MODE_SENSE_G1)) {
-		sbd_handle_mode_sense(task, initial_dbuf);
-		return;
-	}
-
-	if (cdb0 == SCMD_REQUEST_SENSE) {
-		/*
-		 * LU provider needs to store unretrieved sense data
-		 * (e.g. after power-on/reset).  For now, we'll just
-		 * return good status with no sense.
-		 */
-
-		if ((cdb1 & ~1) || task->task_cdb[2] || task->task_cdb[3] ||
-		    task->task_cdb[5]) {
-			stmf_scsilib_send_status(task, STATUS_CHECK,
-			    STMF_SAA_INVALID_FIELD_IN_CDB);
-		} else {
-			stmf_scsilib_send_status(task, STATUS_GOOD, 0);
-		}
-
-		return;
-	}
-
 	if (cdb0 == SCMD_VERIFY) {
 		/*
 		 * Something more likely needs to be done here.
@@ -1158,57 +1588,12 @@
 		return;
 	}
 
-	if ((cdb0 == SCMD_RESERVE) || (cdb0 == SCMD_RELEASE)) {
-		if (cdb1) {
-			stmf_scsilib_send_status(task, STATUS_CHECK,
-			    STMF_SAA_INVALID_FIELD_IN_CDB);
-			return;
-		}
-		mutex_enter(&slu->sl_it_list_lock);
-		if (slu->sl_flags & SBD_LU_HAS_SCSI2_RESERVATION) {
-			if (it->sbd_it_session_id !=
-			    slu->sl_rs_owner_session_id) {
-				/*
-				 * This can only happen if things were in
-				 * flux.
-				 */
-				mutex_exit(&slu->sl_it_list_lock);
-				stmf_scsilib_send_status(task,
-				    STATUS_RESERVATION_CONFLICT, 0);
-				return;
-			}
-		}
-	}
-
-	if (cdb0 == SCMD_RELEASE) {
-		slu->sl_flags &= ~SBD_LU_HAS_SCSI2_RESERVATION;
-		it->sbd_it_flags &= ~SBD_IT_HAS_SCSI2_RESERVATION;
-		mutex_exit(&slu->sl_it_list_lock);
-		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
-		return;
-	}
-	if (cdb0 == SCMD_RESERVE) {
-		slu->sl_flags |= SBD_LU_HAS_SCSI2_RESERVATION;
-		it->sbd_it_flags |= SBD_IT_HAS_SCSI2_RESERVATION;
-		slu->sl_rs_owner_session_id = it->sbd_it_session_id;
-		mutex_exit(&slu->sl_it_list_lock);
-		stmf_scsilib_send_status(task, STATUS_GOOD, 0);
-		return;
-	}
-
 	if (cdb0 == SCMD_SYNCHRONIZE_CACHE ||
 	    cdb0 == SCMD_SYNCHRONIZE_CACHE_G4) {
 		sbd_handle_sync_cache(task, initial_dbuf);
 		return;
 	}
 
-	/* Report Target Port Groups */
-	if ((cdb0 == SCMD_MAINTENANCE_IN) &&
-	    ((cdb1 & 0x1F) == 0x0A)) {
-		stmf_scsilib_handle_report_tpgs(task, initial_dbuf);
-		return;
-	}
-
 	stmf_scsilib_send_status(task, STATUS_CHECK, STMF_SAA_INVALID_OPCODE);
 }
 
@@ -1221,14 +1606,26 @@
 	if ((scmd == NULL) || ((scmd->flags & SBD_SCSI_CMD_ACTIVE) == 0))
 		return;
 
-	if (scmd->cmd_type == SBD_CMD_SCSI_READ) {
+	switch (scmd->cmd_type) {
+	case (SBD_CMD_SCSI_READ):
 		sbd_handle_read_xfer_completion(task, scmd, dbuf);
-	} else if (scmd->cmd_type == SBD_CMD_SCSI_WRITE) {
+		break;
+
+	case (SBD_CMD_SCSI_WRITE):
 		sbd_handle_write_xfer_completion(task, scmd, dbuf, 1);
-	} else if (scmd->cmd_type == SBD_CMD_SMALL_READ) {
+		break;
+
+	case (SBD_CMD_SMALL_READ):
 		sbd_handle_short_read_xfer_completion(task, scmd, dbuf);
-	} else {
+		break;
+
+	case (SBD_CMD_SMALL_WRITE):
+		sbd_handle_short_write_xfer_completion(task, dbuf);
+		break;
+
+	default:
 		cmn_err(CE_PANIC, "Unknown cmd type, task = %p", (void *)task);
+		break;
 	}
 }
 
@@ -1265,8 +1662,7 @@
 stmf_status_t
 sbd_abort(struct stmf_lu *lu, int abort_cmd, void *arg, uint32_t flags)
 {
-	sbd_store_t *sst = (sbd_store_t *)lu->lu_provider_private;
-	sbd_lu_t *slu = (sbd_lu_t *)sst->sst_sbd_private;
+	sbd_lu_t *sl = (sbd_lu_t *)lu->lu_provider_private;
 	scsi_task_t *task;
 
 	if (abort_cmd == STMF_LU_RESET_STATE) {
@@ -1274,9 +1670,8 @@
 	}
 
 	if (abort_cmd == STMF_LU_ITL_HANDLE_REMOVED) {
-		sbd_check_and_clear_scsi2_reservation(slu,
-		    (sbd_it_data_t *)arg);
-		sbd_remove_it_handle(slu, (sbd_it_data_t *)arg);
+		sbd_check_and_clear_scsi2_reservation(sl, (sbd_it_data_t *)arg);
+		sbd_remove_it_handle(sl, (sbd_it_data_t *)arg);
 		return (STMF_SUCCESS);
 	}
 
@@ -1298,8 +1693,7 @@
 void
 sbd_ctl(struct stmf_lu *lu, int cmd, void *arg)
 {
-	sbd_store_t *sst = (sbd_store_t *)lu->lu_provider_private;
-	sbd_lu_t *slu = (sbd_lu_t *)sst->sst_sbd_private;
+	sbd_lu_t *sl = (sbd_lu_t *)lu->lu_provider_private;
 	stmf_change_status_t st;
 
 	ASSERT((cmd == STMF_CMD_LU_ONLINE) ||
@@ -1312,39 +1706,27 @@
 
 	switch (cmd) {
 	case STMF_CMD_LU_ONLINE:
-		if (slu->sl_state == STMF_STATE_ONLINE)
+		if (sl->sl_state == STMF_STATE_ONLINE)
 			st.st_completion_status = STMF_ALREADY;
-		else if (slu->sl_state != STMF_STATE_OFFLINE)
+		else if (sl->sl_state != STMF_STATE_OFFLINE)
 			st.st_completion_status = STMF_FAILURE;
 		if (st.st_completion_status == STMF_SUCCESS) {
-			slu->sl_state = STMF_STATE_ONLINING;
-			slu->sl_state_not_acked = 1;
-			st.st_completion_status = sst->sst_online(sst);
-			if (st.st_completion_status != STMF_SUCCESS) {
-				slu->sl_state = STMF_STATE_OFFLINE;
-				slu->sl_state_not_acked = 0;
-			} else {
-				slu->sl_state = STMF_STATE_ONLINE;
-			}
+			sl->sl_state = STMF_STATE_ONLINE;
+			sl->sl_state_not_acked = 1;
 		}
 		(void) stmf_ctl(STMF_CMD_LU_ONLINE_COMPLETE, lu, &st);
 		break;
 
 	case STMF_CMD_LU_OFFLINE:
-		if (slu->sl_state == STMF_STATE_OFFLINE)
+		if (sl->sl_state == STMF_STATE_OFFLINE)
 			st.st_completion_status = STMF_ALREADY;
-		else if (slu->sl_state != STMF_STATE_ONLINE)
+		else if (sl->sl_state != STMF_STATE_ONLINE)
 			st.st_completion_status = STMF_FAILURE;
 		if (st.st_completion_status == STMF_SUCCESS) {
-			slu->sl_state = STMF_STATE_OFFLINING;
-			slu->sl_state_not_acked = 1;
-			st.st_completion_status = sst->sst_offline(sst);
-			if (st.st_completion_status != STMF_SUCCESS) {
-				slu->sl_state = STMF_STATE_ONLINE;
-				slu->sl_state_not_acked = 0;
-			} else {
-				slu->sl_state = STMF_STATE_OFFLINE;
-			}
+			sl->sl_flags &= ~(SL_MEDIUM_REMOVAL_PREVENTED |
+			    SL_LU_HAS_SCSI2_RESERVATION);
+			sl->sl_state = STMF_STATE_OFFLINE;
+			sl->sl_state_not_acked = 1;
 		}
 		(void) stmf_ctl(STMF_CMD_LU_OFFLINE_COMPLETE, lu, &st);
 		break;
@@ -1352,7 +1734,7 @@
 	case STMF_ACK_LU_ONLINE_COMPLETE:
 		/* Fallthrough */
 	case STMF_ACK_LU_OFFLINE_COMPLETE:
-		slu->sl_state_not_acked = 0;
+		sl->sl_state_not_acked = 0;
 		break;
 
 	}
@@ -1361,7 +1743,7 @@
 /* ARGSUSED */
 stmf_status_t
 sbd_info(uint32_t cmd, stmf_lu_t *lu, void *arg, uint8_t *buf,
-						uint32_t *bufsizep)
+    uint32_t *bufsizep)
 {
 	return (STMF_NOT_SUPPORTED);
 }
@@ -1369,29 +1751,67 @@
 stmf_status_t
 sbd_lu_reset_state(stmf_lu_t *lu)
 {
-	sbd_store_t *sst = (sbd_store_t *)lu->lu_provider_private;
-	sbd_lu_t *slu = (sbd_lu_t *)sst->sst_sbd_private;
+	sbd_lu_t *sl = (sbd_lu_t *)lu->lu_provider_private;
 
-	sbd_check_and_clear_scsi2_reservation(slu, NULL);
+	mutex_enter(&sl->sl_lock);
+	if (sl->sl_flags & SL_SAVED_WRITE_CACHE_DISABLE) {
+		sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE;
+		mutex_exit(&sl->sl_lock);
+		(void) sbd_wcd_set(1, sl);
+	} else {
+		sl->sl_flags &= ~SL_WRITEBACK_CACHE_DISABLE;
+		mutex_exit(&sl->sl_lock);
+		(void) sbd_wcd_set(0, sl);
+	}
+	sbd_check_and_clear_scsi2_reservation(sl, NULL);
 	if (stmf_deregister_all_lu_itl_handles(lu) != STMF_SUCCESS) {
 		return (STMF_FAILURE);
 	}
 	return (STMF_SUCCESS);
 }
 
+sbd_status_t
+sbd_flush_data_cache(sbd_lu_t *sl, int fsync_done)
+{
+	int r = 0;
+	int ret;
+
+	if (fsync_done)
+		goto over_fsync;
+	if ((sl->sl_data_vtype == VREG) || (sl->sl_data_vtype == VBLK)) {
+		if (VOP_FSYNC(sl->sl_data_vp, FSYNC, kcred, NULL))
+			return (SBD_FAILURE);
+	}
+over_fsync:
+	if (((sl->sl_data_vtype == VCHR) || (sl->sl_data_vtype == VBLK)) &&
+	    ((sl->sl_flags & SL_NO_DATA_DKIOFLUSH) == 0)) {
+		ret = VOP_IOCTL(sl->sl_data_vp, DKIOCFLUSHWRITECACHE, NULL,
+		    FKIOCTL, kcred, &r, NULL);
+		if ((ret == ENOTTY) || (ret == ENOTSUP)) {
+			mutex_enter(&sl->sl_lock);
+			sl->sl_flags |= SL_NO_DATA_DKIOFLUSH;
+			mutex_exit(&sl->sl_lock);
+		} else if (ret != 0) {
+			return (SBD_FAILURE);
+		}
+	}
+
+	return (SBD_SUCCESS);
+}
+
 /* ARGSUSED */
 static void
 sbd_handle_sync_cache(struct scsi_task *task,
     struct stmf_data_buf *initial_dbuf)
 {
-	sbd_store_t	*sst =
-	    (sbd_store_t *)task->task_lu->lu_provider_private;
-	sbd_lu_t	*slu = (sbd_lu_t *)sst->sst_sbd_private;
+	sbd_lu_t *sl = (sbd_lu_t *)task->task_lu->lu_provider_private;
 	uint64_t	lba, laddr;
+	sbd_status_t	sret;
 	uint32_t	len;
 	int		is_g4 = 0;
 	int		immed;
 
+	task->task_cmd_xfer_length = 0;
 	/*
 	 * Determine if this is a 10 or 16 byte CDB
 	 */
@@ -1441,16 +1861,17 @@
 		len = READ_SCSI16(&task->task_cdb[7], uint32_t);
 	}
 
-	laddr = lba << slu->sl_shift_count;
-	len <<= slu->sl_shift_count;
+	laddr = lba << sl->sl_data_blocksize_shift;
+	len <<= sl->sl_data_blocksize_shift;
 
-	if ((laddr + (uint64_t)len) > slu->sl_sli->sli_lu_data_size) {
+	if ((laddr + (uint64_t)len) > sl->sl_lu_size) {
 		stmf_scsilib_send_status(task, STATUS_CHECK,
 		    STMF_SAA_LBA_OUT_OF_RANGE);
 		return;
 	}
 
-	if (sst->sst_data_flush(sst) != STMF_SUCCESS) {
+	sret = sbd_flush_data_cache(sl, 0);
+	if (sret != SBD_SUCCESS) {
 		stmf_scsilib_send_status(task, STATUS_CHECK,
 		    STMF_SAA_WRITE_ERROR);
 		return;
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h	Fri May 08 16:22:42 2009 -0600
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -30,64 +30,251 @@
 extern "C" {
 #endif
 
+typedef	stmf_status_t	sbd_status_t;
+extern char sbd_vendor_id[];
+extern char sbd_product_id[];
+extern char sbd_revision[];
+/*
+ * Error codes
+ */
+#define	SBD_SUCCESS		STMF_SUCCESS
 #define	SBD_FAILURE		STMF_LU_FAILURE
-#define	SBD_FILEIO_FAILURE	(SBD_FAILURE | STMF_FSC(1))
+
+#define	SBD_ALREADY		(SBD_FAILURE | STMF_FSC(1))
+#define	SBD_NOT_SUPPORTED	(SBD_FAILURE | STMF_FSC(2))
+#define	SBD_META_CORRUPTED	(SBD_FAILURE | STMF_FSC(3))
+#define	SBD_INVALID_ARG		(SBD_FAILURE | STMF_FSC(4))
+#define	SBD_NOT_FOUND		(SBD_FAILURE | STMF_FSC(5))
+#define	SBD_ALLOC_FAILURE	(SBD_FAILURE | STMF_FSC(6))
+#define	SBD_FILEIO_FAILURE	(SBD_FAILURE | STMF_FSC(7))
+#define	SBD_IO_PAST_EOF		(SBD_FAILURE | STMF_FSC(8))
+#define	SBD_BUSY		(SBD_FAILURE | STMF_FSC(9))
+
+#define	SHARED_META_DATA_SIZE	65536
+#define	SBD_META_OFFSET		4096
+#define	SBD_MIN_LU_SIZE		(1024 * 1024)
+
+/*
+ * sms endianess
+ */
+#define	SMS_BIG_ENDIAN			0x00
+#define	SMS_LITTLE_ENDIAN		0xFF
+
+#ifdef	_BIG_ENDIAN
+#define	SMS_DATA_ORDER	SMS_BIG_ENDIAN
+#else
+#define	SMS_DATA_ORDER	SMS_LITTLE_ENDIAN
+#endif
+
+#define	SBD_MAGIC	0x53554e5342444c55
+
+#define	SBD_VER_MAJOR		1
+#define	SBD_VER_MINOR		1
+#define	SBD_VER_SUBMINOR	0
+
+#if 0
+typedef struct sbd_meta_start {
+	uint64_t		sm_magic;
+	uint64_t		sm_meta_size;
+	uint64_t		sm_meta_size_used;
+	uint64_t		sm_rsvd1;	/* Defaults to zero */
+	uint64_t		sm_rsvd2;
+	uint16_t		sm_ver_major;
+	uint16_t		sm_ver_minor;
+	uint16_t		sm_ver_subminor;
+	uint8_t			sm_flags;
+	uint8_t			sm_chksum;
+} sbd_meta_start_t;
+#endif
+
+typedef struct sm_section_hdr {
+	uint64_t	sms_offset;	/* Offset of this section */
+	uint32_t	sms_size;	/* Includes the header and padding */
+	uint16_t	sms_id;		/* Section identifier */
+	uint8_t		sms_data_order; /* 0x00 or 0xff */
+	uint8_t		sms_chksum;
+} sm_section_hdr_t;
 
 /*
- * if the function pointers to write metadata are NULL, then sbd assumes that
- * metadata and LU data share the same store. In that case sbd sets aside
- * some space for metadata and adjusts the LU size reported to initiators
- * accordingly.
+ * sbd meta section identifiers
  */
-typedef	struct sbd_store {
-	void		*sst_sbd_private;
-	void		*sst_store_private;
-	char		*sst_alias;
+#define	SMS_ID_LU_INFO_1_0	0
+#define	SMS_ID_LU_INFO_1_1	1
+#define	SMS_ID_PGR_INFO		2
+#define	SMS_ID_UNUSED		0x1000
 
-	stmf_status_t	(*sst_online)(struct sbd_store *sst);
-	stmf_status_t	(*sst_offline)(struct sbd_store *sst);
-	stmf_status_t	(*sst_deregister_lu)(struct sbd_store *sst);
+typedef struct sbd_lu_info_1_0 {
+	sm_section_hdr_t	sli_sms_header;
+	uint64_t		sli_total_store_size;
+	uint64_t		sli_total_meta_size;
+	uint64_t		sli_lu_data_offset;
+	uint64_t		sli_lu_data_size;
+	uint32_t		sli_flags;
+	uint16_t		sli_blocksize;
+	uint8_t			sli_data_order;
+	uint8_t			rsvd1;
+	uint8_t			sli_lu_devid[20];
+	uint32_t		rsvd2;
+} sbd_lu_info_1_0_t;
 
-	stmf_status_t	(*sst_data_read)(struct sbd_store *sst,
-				uint64_t offset, uint64_t size, uint8_t *buf);
-	stmf_status_t	(*sst_data_write)(struct sbd_store *sst,
-				uint64_t offset, uint64_t size, uint8_t *buf);
-	stmf_status_t	(*sst_data_flush)(struct sbd_store *sst);
+typedef struct sbd_lu_info_1_1 {
+	sm_section_hdr_t	sli_sms_header;
+	uint32_t		sli_flags;
+	char			sli_rev[4];
+	char			sli_vid[8];
+	char			sli_pid[16];
+	uint64_t		sli_lu_size;	/* Read capacity size */
+
+	/*
+	 * Essetially zfs volume name for zvols to verify that the
+	 * metadata is coming in from the correct zvol and not from a
+	 * clone. Has no meaning in any other case.
+	 */
+	uint16_t		sli_meta_fname_offset;
 
-	stmf_status_t	(*sst_meta_read)(struct sbd_store *sst,
-				uint64_t offset, uint64_t size, uint8_t *buf);
-	stmf_status_t	(*sst_meta_write)(struct sbd_store *sst,
-				uint64_t offset, uint64_t size, uint8_t *buf);
-} sbd_store_t;
-
-typedef struct sst_init_data {
-	uint64_t	sst_store_size;		/* Total size of the store */
+	/*
+	 * Data filename or the media filename when the metadata is in
+	 * a separate file. Its not needed if the metadata is shared
+	 * with data as the user supplied name is the data filename.
+	 */
+	uint64_t		sli_data_fname_offset;
+	uint64_t		sli_serial_offset;
+	uint64_t		sli_alias_offset;
+	uint8_t			sli_data_blocksize_shift;
+	uint8_t			sli_data_order;
+	uint8_t			sli_serial_size;
+	uint8_t			sli_rsvd1;
+	uint8_t			sli_device_id[20];
+	uint8_t			sli_rsvd2[256];
 
 	/*
-	 * This is the metadat for the store implementation itself
-	 * that needs to be persisted.
+	 * In case there is no separate meta, sli_meta_fname_offset wont
+	 * be valid. The same is true for zfs based metadata. The data_fname
+	 * is the zvol.
 	 */
-	uint64_t	sst_store_meta_data_size;
-
-	/* This is returned to the caller */
-	uint8_t		sst_guid[16];
-
-	uint32_t	sst_flags;
-	uint16_t	sst_blocksize;		/* To expose to initiators */
-} sst_init_data_t;
+	uint8_t			sli_buf[8];
+} sbd_lu_info_1_1_t;
 
 /*
- * sst_flags.
+ * sli flags
  */
-#define	SST_NOT_PERSISTENT	0x0001
-#define	SST_READONLY_DATA	0x0002
+#define	SLI_SEPARATE_META			0x0001
+#define	SLI_WRITE_PROTECTED			0x0002
+#define	SLI_VID_VALID				0x0004
+#define	SLI_PID_VALID				0x0008
+#define	SLI_REV_VALID				0x0010
+#define	SLI_META_FNAME_VALID			0x0020
+#define	SLI_DATA_FNAME_VALID			0x0040
+#define	SLI_SERIAL_VALID			0x0080
+#define	SLI_ALIAS_VALID				0x0100
+#define	SLI_WRITEBACK_CACHE_DISABLE		0x0200
+#define	SLI_ZFS_META				0x0400
+
+struct sbd_it_data;
+
+typedef struct sbd_lu {
+	struct sbd_lu	*sl_next;
+	stmf_lu_t	*sl_lu;
+	uint32_t	sl_alloc_size;
+
+	/* Current LU state */
+	kmutex_t	sl_lock;
+	uint32_t	sl_flags;
+	uint8_t		sl_trans_op;
+	uint8_t		sl_state:7,
+			sl_state_not_acked:1;
+
+	char		*sl_name;		/* refers to meta or data */
+
+	/* Metadata */
+	char		*sl_alias;
+	char		*sl_meta_filename;	/* If applicable */
+	vnode_t		*sl_meta_vp;
+	vtype_t		sl_meta_vtype;
+	uint8_t		sl_device_id[20];	/* 4(hdr) + 16(GUID) */
+	uint8_t		sl_meta_blocksize_shift; /* Left shift multiplier */
+	uint8_t		sl_data_blocksize_shift;
+	uint8_t		sl_data_fs_nbits;
+	uint8_t		sl_serial_no_size;
+	uint64_t	sl_total_meta_size;
+	uint64_t	sl_meta_size_used;
+	uint8_t		*sl_serial_no;		/* optional */
+	char		sl_vendor_id[8];
+	char		sl_product_id[16];
+	char		sl_revision[4];
+	uint32_t	sl_data_fname_alloc_size; /* for an explicit alloc */
+	uint32_t	sl_alias_alloc_size;
+	uint8_t		sl_serial_no_alloc_size;
+
+	/* zfs metadata */
+	vnode_t		*sl_zfs_meta_vp;
 
-sbd_store_t *sbd_sst_alloc(uint32_t additional_size, uint32_t flags);
-void sbd_sst_free(sbd_store_t *sst);
-stmf_status_t sbd_create_meta(sbd_store_t *sst, sst_init_data_t *sst_idata);
-stmf_status_t sbd_modify_meta(sbd_store_t *sst, sst_init_data_t *sst_idata);
-stmf_status_t sbd_register_sst(sbd_store_t *sst, sst_init_data_t *sst_idata);
-stmf_status_t sbd_deregister_sst(sbd_store_t *sst);
+	/* Backing store */
+	char		*sl_data_filename;
+	vnode_t		*sl_data_vp;
+	vtype_t		sl_data_vtype;
+	uint64_t	sl_total_data_size;
+	uint64_t	sl_data_readable_size;	/* read() fails after this */
+	uint64_t	sl_data_offset;		/* After the metadata,if any */
+	uint64_t	sl_lu_size;		/* READ CAPACITY size */
+
+	struct sbd_it_data	*sl_it_list;
+	struct sbd_pgr		*sl_pgr;
+	uint64_t	sl_rs_owner_session_id;
+} sbd_lu_t;
+
+/*
+ * sl_flags
+ */
+#define	SL_LINKED			    0x00001
+#define	SL_META_OPENED			    0x00002
+#define	SL_REGISTERED			    0x00004
+#define	SL_META_NEEDS_FLUSH		    0x00008
+#define	SL_DATA_NEEDS_FLUSH		    0x00010
+#define	SL_VID_VALID			    0x00020
+#define	SL_PID_VALID			    0x00040
+#define	SL_REV_VALID			    0x00080
+#define	SL_WRITE_PROTECTED		    0x00100
+#define	SL_MEDIA_LOADED			    0x00200
+#define	SL_LU_HAS_SCSI2_RESERVATION	    0x00400
+#define	SL_WRITEBACK_CACHE_DISABLE	    0x00800
+#define	SL_SAVED_WRITE_CACHE_DISABLE	    0x01000
+#define	SL_MEDIUM_REMOVAL_PREVENTED	    0x02000
+#define	SL_NO_DATA_DKIOFLUSH		    0x04000
+#define	SL_SHARED_META			    0x08000
+#define	SL_ZFS_META			    0x10000
+#define	SL_WRITEBACK_CACHE_SET_UNSUPPORTED  0x20000
+#define	SL_FLUSH_ON_DISABLED_WRITECACHE	    0x40000
+
+/*
+ * sl_trans_op. LU is undergoing some transition and this field
+ * tells what kind of transition that is.
+ */
+#define	SL_OP_NONE				0
+#define	SL_OP_CREATE_REGISTER_LU		1
+#define	SL_OP_IMPORT_LU				2
+#define	SL_OP_DELETE_LU				3
+#define	SL_OP_MODIFY_LU				4
+#define	SL_OP_LU_PROPS				5
+
+sbd_status_t sbd_data_read(sbd_lu_t *sl, uint64_t offset, uint64_t size,
+    uint8_t *buf);
+sbd_status_t sbd_data_write(sbd_lu_t *sl, uint64_t offset, uint64_t size,
+    uint8_t *buf);
+stmf_status_t sbd_task_alloc(struct scsi_task *task);
+void sbd_new_task(struct scsi_task *task, struct stmf_data_buf *initial_dbuf);
+void sbd_dbuf_xfer_done(struct scsi_task *task, struct stmf_data_buf *dbuf);
+void sbd_send_status_done(struct scsi_task *task);
+void sbd_task_free(struct scsi_task *task);
+stmf_status_t sbd_abort(struct stmf_lu *lu, int abort_cmd, void *arg,
+    uint32_t flags);
+void sbd_ctl(struct stmf_lu *lu, int cmd, void *arg);
+stmf_status_t sbd_info(uint32_t cmd, stmf_lu_t *lu, void *arg, uint8_t *buf,
+    uint32_t *bufsizep);
+sbd_status_t sbd_write_lu_info(sbd_lu_t *sl);
+sbd_status_t sbd_flush_data_cache(sbd_lu_t *sl, int fsync_done);
+sbd_status_t sbd_wcd_set(int wcd, sbd_lu_t *sl);
+void sbd_wcd_get(int *wcd, sbd_lu_t *sl);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/uts/common/io/comstar/port/fct/fct.c	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/uts/common/io/comstar/port/fct/fct.c	Fri May 08 16:22:42 2009 -0600
@@ -152,7 +152,7 @@
 		*result = fct_dip;
 		break;
 	case DDI_INFO_DEVT2INSTANCE:
-		*result = (void *)(uintptr_t)ddi_get_instance(dip);
+		*result = (void *)(uintptr_t)ddi_get_instance(fct_dip);
 		break;
 	default:
 		return (DDI_FAILURE);
@@ -1699,6 +1699,7 @@
 		for (p = &irp->irp_els_list; *p != NULL;
 		    p = &((*p)->icmd_next))
 			;
+		}
 		*p = icmd;
 		atomic_or_32(&icmd->icmd_flags, ICMD_IN_IRP_QUEUE);
 	}
@@ -2853,6 +2854,7 @@
 	for (ppicmd = &(iport->iport_abort_queue); *ppicmd != NULL;
 	    ppicmd = &((*ppicmd)->icmd_next))
 		;
+	}
 	*ppicmd = icmd;
 }
 
--- a/usr/src/uts/common/io/comstar/stmf/stmf.c	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/uts/common/io/comstar/stmf/stmf.c	Fri May 08 16:22:42 2009 -0600
@@ -73,8 +73,11 @@
 void stmf_handle_lun_reset(scsi_task_t *task);
 void stmf_handle_target_reset(scsi_task_t *task);
 void stmf_xd_to_dbuf(stmf_data_buf_t *dbuf);
-int stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi);
+int stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token,
+    uint32_t *err_ret);
 int stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi);
+int stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out,
+    uint32_t *err_ret);
 void stmf_delete_ppd(stmf_pp_data_t *ppd);
 void stmf_delete_all_ppds();
 void stmf_trace_clear();
@@ -282,7 +285,8 @@
 		*result = stmf_state.stmf_dip;
 		break;
 	case DDI_INFO_DEVT2INSTANCE:
-		*result = (void *)(uintptr_t)ddi_get_instance(dip);
+		*result =
+		    (void *)(uintptr_t)ddi_get_instance(stmf_state.stmf_dip);
 		break;
 	default:
 		return (DDI_FAILURE);
@@ -433,8 +437,9 @@
 	slist_scsi_session_t *iss_list;
 	sioc_lu_props_t *lup;
 	sioc_target_port_props_t *lportp;
-	stmf_ppioctl_data_t *ppi;
-	uint8_t *p_id;
+	stmf_ppioctl_data_t *ppi, *ppi_out = NULL;
+	uint64_t *ppi_token = NULL;
+	uint8_t *p_id, *id;
 	stmf_state_desc_t *std;
 	stmf_status_t ctl_ret;
 	stmf_state_change_info_t ssi;
@@ -445,11 +450,9 @@
 	stmf_group_name_t *grpname;
 	stmf_view_op_entry_t *ve;
 	stmf_id_type_t idtype;
-#if 0
 	stmf_id_data_t *id_entry;
 	stmf_id_list_t	*id_list;
 	stmf_view_entry_t *view_entry;
-#endif
 	uint32_t	veid;
 
 	if ((cmd & 0xff000000) != STMF_IOCTL) {
@@ -467,6 +470,36 @@
 
 	switch (cmd) {
 	case STMF_IOCTL_LU_LIST:
+		/* retrieves both registered/unregistered */
+		mutex_enter(&stmf_state.stmf_lock);
+		id_list = &stmf_state.stmf_luid_list;
+		n = min(id_list->id_count,
+		    (iocd->stmf_obuf_size)/sizeof (slist_lu_t));
+		iocd->stmf_obuf_max_nentries = id_list->id_count;
+		luid_list = (slist_lu_t *)obuf;
+		id_entry = id_list->idl_head;
+		for (i = 0; i < n; i++) {
+			bcopy(id_entry->id_data, luid_list[i].lu_guid, 16);
+			id_entry = id_entry->id_next;
+		}
+
+		n = iocd->stmf_obuf_size/sizeof (slist_lu_t);
+		for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) {
+			id = (uint8_t *)ilu->ilu_lu->lu_id;
+			if (stmf_lookup_id(id_list, 16, id + 4) == NULL) {
+				iocd->stmf_obuf_max_nentries++;
+				if (i < n) {
+					bcopy(id + 4, luid_list[i].lu_guid,
+					    sizeof (slist_lu_t));
+					i++;
+				}
+			}
+		}
+		iocd->stmf_obuf_nentries = i;
+		mutex_exit(&stmf_state.stmf_lock);
+		break;
+
+	case STMF_IOCTL_REG_LU_LIST:
 		mutex_enter(&stmf_state.stmf_lock);
 		iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlus;
 		n = min(stmf_state.stmf_nlus,
@@ -483,6 +516,22 @@
 		mutex_exit(&stmf_state.stmf_lock);
 		break;
 
+	case STMF_IOCTL_VE_LU_LIST:
+		mutex_enter(&stmf_state.stmf_lock);
+		id_list = &stmf_state.stmf_luid_list;
+		n = min(id_list->id_count,
+		    (iocd->stmf_obuf_size)/sizeof (slist_lu_t));
+		iocd->stmf_obuf_max_nentries = id_list->id_count;
+		iocd->stmf_obuf_nentries = n;
+		luid_list = (slist_lu_t *)obuf;
+		id_entry = id_list->idl_head;
+		for (i = 0; i < n; i++) {
+			bcopy(id_entry->id_data, luid_list[i].lu_guid, 16);
+			id_entry = id_entry->id_next;
+		}
+		mutex_exit(&stmf_state.stmf_lock);
+		break;
+
 	case STMF_IOCTL_TARGET_PORT_LIST:
 		mutex_enter(&stmf_state.stmf_lock);
 		iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlports;
@@ -928,7 +977,6 @@
 		    &iocd->stmf_error);
 		mutex_exit(&stmf_state.stmf_lock);
 		break;
-#if 0
 	case STMF_IOCTL_GET_HG_LIST:
 		id_list = &stmf_state.stmf_hg_list;
 		/* FALLTHROUGH */
@@ -943,9 +991,17 @@
 		id_entry = id_list->idl_head;
 		grpname = (stmf_group_name_t *)obuf;
 		for (i = 0; i < n; i++) {
-			grpname[i].name_size = id_entry->id_data_size;
-			bcopy(id_entry->id_data, grpname[i].name,
+			if (id_entry->id_data[0] == '*') {
+				if (iocd->stmf_obuf_nentries > 0) {
+					iocd->stmf_obuf_nentries--;
+				}
+				id_entry = id_entry->id_next;
+				continue;
+			}
+			grpname->name_size = id_entry->id_data_size;
+			bcopy(id_entry->id_data, grpname->name,
 			    id_entry->id_data_size);
+			grpname++;
 			id_entry = id_entry->id_next;
 		}
 		mutex_exit(&stmf_state.stmf_lock);
@@ -978,50 +1034,114 @@
 			id_entry = id_list->idl_head;
 			grp_entry = (stmf_ge_ident_t *)obuf;
 			for (i = 0; i < n; i++) {
-				bcopy(id_entry->id_data, grp_entry,
+				bcopy(id_entry->id_data, grp_entry->ident,
 				    id_entry->id_data_size);
+				grp_entry->ident_size = id_entry->id_data_size;
 				id_entry = id_entry->id_next;
+				grp_entry++;
 			}
 		}
 		mutex_exit(&stmf_state.stmf_lock);
 		break;
+
 	case STMF_IOCTL_GET_VE_LIST:
 		n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t);
 		mutex_enter(&stmf_state.stmf_lock);
-		id_entry = stmf_state.stmf_luid_list.idl_head;
 		ve = (stmf_view_op_entry_t *)obuf;
-		while (id_entry) {
-			view_entry =
-			    (stmf_view_entry_t *)id_entry->id_impl_specific;
-			for (; view_entry; view_entry = view_entry->ve_next) {
+		for (id_entry = stmf_state.stmf_luid_list.idl_head;
+		    id_entry; id_entry = id_entry->id_next) {
+			for (view_entry = (stmf_view_entry_t *)
+			    id_entry->id_impl_specific; view_entry;
+			    view_entry = view_entry->ve_next) {
+				iocd->stmf_obuf_max_nentries++;
+				if (iocd->stmf_obuf_nentries >= n)
+					continue;
 				ve->ve_ndx_valid = 1;
 				ve->ve_ndx = view_entry->ve_id;
 				ve->ve_lu_number_valid = 1;
 				bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8);
 				bcopy(view_entry->ve_luid->id_data, ve->ve_guid,
 				    view_entry->ve_luid->id_data_size);
-				if (view_entry->ve_hg->id_data[0] == '*')
+				if (view_entry->ve_hg->id_data[0] == '*') {
 					ve->ve_all_hosts = 1;
-				else
+				} else {
 					bcopy(view_entry->ve_hg->id_data,
 					    ve->ve_host_group.name,
 					    view_entry->ve_hg->id_data_size);
-				if (view_entry->ve_tg->id_data[0] == '*')
+					ve->ve_host_group.name_size =
+					    view_entry->ve_hg->id_data_size;
+				}
+
+				if (view_entry->ve_tg->id_data[0] == '*') {
 					ve->ve_all_targets = 1;
-				else
+				} else {
 					bcopy(view_entry->ve_tg->id_data,
 					    ve->ve_target_group.name,
 					    view_entry->ve_tg->id_data_size);
+					ve->ve_target_group.name_size =
+					    view_entry->ve_tg->id_data_size;
+				}
+				ve++;
 				iocd->stmf_obuf_nentries++;
-				if (iocd->stmf_obuf_nentries >= n)
-					break;
 			}
-			if (iocd->stmf_obuf_nentries >= n)
-				break;
 		}
 		mutex_exit(&stmf_state.stmf_lock);
 		break;
-#endif
+
+	case STMF_IOCTL_LU_VE_LIST:
+		p_id = (uint8_t *)ibuf;
+		if ((iocd->stmf_ibuf_size != 16) ||
+		    (iocd->stmf_obuf_size < sizeof (stmf_view_op_entry_t))) {
+			ret = EINVAL;
+			break;
+		}
+
+		n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t);
+		mutex_enter(&stmf_state.stmf_lock);
+		ve = (stmf_view_op_entry_t *)obuf;
+		for (id_entry = stmf_state.stmf_luid_list.idl_head;
+		    id_entry; id_entry = id_entry->id_next) {
+			if (bcmp(id_entry->id_data, p_id, 16) != 0)
+				continue;
+			for (view_entry = (stmf_view_entry_t *)
+			    id_entry->id_impl_specific; view_entry;
+			    view_entry = view_entry->ve_next) {
+				iocd->stmf_obuf_max_nentries++;
+				if (iocd->stmf_obuf_nentries >= n)
+					continue;
+				ve->ve_ndx_valid = 1;
+				ve->ve_ndx = view_entry->ve_id;
+				ve->ve_lu_number_valid = 1;
+				bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8);
+				bcopy(view_entry->ve_luid->id_data, ve->ve_guid,
+				    view_entry->ve_luid->id_data_size);
+				if (view_entry->ve_hg->id_data[0] == '*') {
+					ve->ve_all_hosts = 1;
+				} else {
+					bcopy(view_entry->ve_hg->id_data,
+					    ve->ve_host_group.name,
+					    view_entry->ve_hg->id_data_size);
+					ve->ve_host_group.name_size =
+					    view_entry->ve_hg->id_data_size;
+				}
+
+				if (view_entry->ve_tg->id_data[0] == '*') {
+					ve->ve_all_targets = 1;
+				} else {
+					bcopy(view_entry->ve_tg->id_data,
+					    ve->ve_target_group.name,
+					    view_entry->ve_tg->id_data_size);
+					ve->ve_target_group.name_size =
+					    view_entry->ve_tg->id_data_size;
+				}
+				ve++;
+				iocd->stmf_obuf_nentries++;
+			}
+			break;
+		}
+		mutex_exit(&stmf_state.stmf_lock);
+		break;
+
 	case STMF_IOCTL_LOAD_PP_DATA:
 		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
 			ret = EACCES;
@@ -1034,7 +1154,35 @@
 			ret = EINVAL;
 			break;
 		}
-		ret = stmf_load_ppd_ioctl(ppi);
+		/* returned token */
+		ppi_token = (uint64_t *)obuf;
+		if ((ppi_token == NULL) ||
+		    (iocd->stmf_obuf_size < sizeof (uint64_t))) {
+			ret = EINVAL;
+			break;
+		}
+		ret = stmf_load_ppd_ioctl(ppi, ppi_token, &iocd->stmf_error);
+		break;
+
+	case STMF_IOCTL_GET_PP_DATA:
+		if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
+			ret = EACCES;
+			iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT;
+			break;
+		}
+		ppi = (stmf_ppioctl_data_t *)ibuf;
+		if (ppi == NULL ||
+		    (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) {
+			ret = EINVAL;
+			break;
+		}
+		ppi_out = (stmf_ppioctl_data_t *)obuf;
+		if ((ppi_out == NULL) ||
+		    (iocd->stmf_obuf_size < sizeof (stmf_ppioctl_data_t))) {
+			ret = EINVAL;
+			break;
+		}
+		ret = stmf_get_ppd_ioctl(ppi, ppi_out, &iocd->stmf_error);
 		break;
 
 	case STMF_IOCTL_CLEAR_PP_DATA:
@@ -1565,7 +1713,8 @@
 }
 
 int
-stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi)
+stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token,
+    uint32_t *err_ret)
 {
 	stmf_i_port_provider_t		*ipp;
 	stmf_i_lu_provider_t		*ilp;
@@ -1574,6 +1723,8 @@
 	int				s;
 	int				ret;
 
+	*err_ret = 0;
+
 	if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
 		return (EINVAL);
 	}
@@ -1638,6 +1789,19 @@
 		stmf_state.stmf_ppdlist = ppd;
 	}
 
+	/*
+	 * User is requesting that the token be checked.
+	 * If there was another set after the user's get
+	 * it's an error
+	 */
+	if (ppi->ppi_token_valid) {
+		if (ppi->ppi_token != ppd->ppd_token) {
+			*err_ret = STMF_IOCERR_PPD_UPDATED;
+			mutex_exit(&stmf_state.stmf_lock);
+			return (EINVAL);
+		}
+	}
+
 	if ((ret = nvlist_unpack((char *)ppi->ppi_data,
 	    (size_t)ppi->ppi_data_size, &nv, KM_NOSLEEP)) != 0) {
 		mutex_exit(&stmf_state.stmf_lock);
@@ -1649,6 +1813,13 @@
 		nvlist_free(ppd->ppd_nv);
 	ppd->ppd_nv = nv;
 
+	/* set the token for writes */
+	ppd->ppd_token++;
+	/* return token to caller */
+	if (ppi_token) {
+		*ppi_token = ppd->ppd_token;
+	}
+
 	/* If there is a provider registered, do the notifications */
 	if (ppd->ppd_provider) {
 		uint32_t cb_flags = 0;
@@ -1750,6 +1921,59 @@
 	return (ret);
 }
 
+int
+stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out,
+    uint32_t *err_ret)
+{
+	stmf_pp_data_t *ppd;
+	size_t req_size;
+	int ret = ENOENT;
+	char *bufp = (char *)ppi_out->ppi_data;
+
+	if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
+		return (EINVAL);
+	}
+
+	mutex_enter(&stmf_state.stmf_lock);
+
+	for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) {
+		if (ppi->ppi_lu_provider) {
+			if (!ppd->ppd_lu_provider)
+				continue;
+		} else if (ppi->ppi_port_provider) {
+			if (!ppd->ppd_port_provider)
+				continue;
+		}
+		if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0)
+			break;
+	}
+
+	if (ppd && ppd->ppd_nv) {
+		ppi_out->ppi_token = ppd->ppd_token;
+		if ((ret = nvlist_size(ppd->ppd_nv, &req_size,
+		    NV_ENCODE_XDR)) != 0) {
+			goto done;
+		}
+		ppi_out->ppi_data_size = req_size;
+		if (req_size > ppi->ppi_data_size) {
+			*err_ret = STMF_IOCERR_INSUFFICIENT_BUF;
+			ret = EINVAL;
+			goto done;
+		}
+
+		if ((ret = nvlist_pack(ppd->ppd_nv, &bufp, &req_size,
+		    NV_ENCODE_XDR, 0)) != 0) {
+			goto done;
+		}
+		ret = 0;
+	}
+
+done:
+	mutex_exit(&stmf_state.stmf_lock);
+
+	return (ret);
+}
+
 void
 stmf_delete_all_ppds()
 {
@@ -4092,6 +4316,53 @@
 	return (xd);
 }
 
+struct scsi_devid_desc *
+stmf_scsilib_get_devid_desc(uint16_t rtpid)
+{
+	scsi_devid_desc_t *devid = NULL;
+	stmf_i_local_port_t *ilport;
+
+	mutex_enter(&stmf_state.stmf_lock);
+
+	for (ilport = stmf_state.stmf_ilportlist; ilport;
+	    ilport = ilport->ilport_next) {
+		if (ilport->ilport_rtpid == rtpid) {
+			scsi_devid_desc_t *id = ilport->ilport_lport->lport_id;
+			uint32_t id_sz = sizeof (scsi_devid_desc_t) - 1 +
+			    id->ident_length;
+			devid = (scsi_devid_desc_t *)kmem_zalloc(id_sz,
+			    KM_NOSLEEP);
+			if (devid != NULL) {
+				bcopy(id, devid, id_sz);
+			}
+			break;
+		}
+	}
+
+	mutex_exit(&stmf_state.stmf_lock);
+	return (devid);
+}
+
+uint16_t
+stmf_scsilib_get_lport_rtid(struct scsi_devid_desc *devid)
+{
+	stmf_i_local_port_t	*ilport;
+	scsi_devid_desc_t	*id;
+	uint16_t		rtpid = 0;
+
+	mutex_enter(&stmf_state.stmf_lock);
+	for (ilport = stmf_state.stmf_ilportlist; ilport;
+	    ilport = ilport->ilport_next) {
+		id = ilport->ilport_lport->lport_id;
+		if ((devid->ident_length == id->ident_length) &&
+		    (memcmp(devid->ident, id->ident, id->ident_length) == 0)) {
+			rtpid = ilport->ilport_rtpid;
+			break;
+		}
+	}
+	mutex_exit(&stmf_state.stmf_lock);
+	return (rtpid);
+}
 
 static uint16_t stmf_lu_id_gen_number = 0;
 
@@ -4121,7 +4392,6 @@
 	p[7] = (company_id << 4) & 0xf0;
 	if (!localetheraddr((struct ether_addr *)NULL, &mac)) {
 		int hid = BE_32((int)zone_get_hostid(NULL));
-
 		e[0] = (hid >> 24) & 0xff;
 		e[1] = (hid >> 16) & 0xff;
 		e[2] = (hid >> 8) & 0xff;
--- a/usr/src/uts/common/io/comstar/stmf/stmf_impl.h	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/uts/common/io/comstar/stmf/stmf_impl.h	Fri May 08 16:22:42 2009 -0600
@@ -262,6 +262,7 @@
 				ppd_port_provider:1,
 				ppd_rsvd:30;
 	uint32_t		ppd_alloc_size;
+	uint64_t		ppd_token;
 	char			ppd_name[8];
 } stmf_pp_data_t;
 
--- a/usr/src/uts/common/sys/scsi/generic/persist.h	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/uts/common/sys/scsi/generic/persist.h	Fri May 08 16:22:42 2009 -0600
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_SYS_SCSI_GENERIC_PERSIST_H
 #define	_SYS_SCSI_GENERIC_PERSIST_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -152,19 +150,42 @@
 } scsi_prin_rpt_cap_t;
 
 /*
+ * Refer SPC-3, Revision 23
+ * Section 7.5.4 TransportID identifiers
+ */
+typedef struct scsi_transport_id {
+	uint8_t			protocol_id : 4,
+				resbits : 2,
+				format_code : 2;
+	uint8_t			protocol_data[1];
+} scsi_transport_id_t;
+
+typedef struct scsi_fc_transport_id {
+	uint8_t			protocol_id : 4,
+				resbits : 2,
+				format_code : 2;
+	uint8_t			rsvbytes1[7];
+	uint8_t			port_name[8];
+	uint8_t			rsvbytes2[8];
+} scsi_fc_transport_id_t;
+
+typedef struct iscsi_transport_id {
+	uint8_t			protocol_id : 4,
+				resbits : 2,
+				format_code : 2;
+	uint8_t			rsvbyte1;
+	uint8_t			add_len[2];
+	char			iscsi_name[1];
+} iscsi_transport_id_t;
+
+/*
  * Information obtained from:
  *	SPC-3, Revision 23
  *	Section 6.11.5 PERSISTENCE RESERVE IN
  * 	Table 110/111 - parameter data for READ FULL STATUS
  *	Table 281 - TransportId format
  */
-typedef struct scsi_transport_id {
-	uint8_t			protocol_id : 4,
-				resbits : 2,
-				format_code : 2;
-	uint8_t			add_len[2];
-	char			iscsi_name[1];
-} scsi_transport_id_t;
+
 typedef struct scsi_prin_status_t {
 	uint8_t			reservation_key[8];
 	uint8_t			resbytes1[4];
@@ -221,6 +242,24 @@
 	uint8_t			apd[1];
 } scsi_prout_plist_t;
 
+/*
+ * Information obtained from:
+ *	SPC-3, Revision 23
+ *	Section 6.12.4 PERSISTENCE RESERVE OUT command with REGISTER AND MOVE
+ *	Table 117 - REGISTER and MOVE service action  parameter list
+ */
+typedef struct scsi_prout_reg_move_plist {
+	uint8_t			reservation_key[8];
+	uint8_t			service_key[8];
+	uint8_t			resbytes1;
+	uint8_t			aptpl : 1,
+				unreg : 1,
+				resbits1 : 6;
+	uint8_t			rel_tgt_port_id[2];
+	uint8_t			tptid_len[4];
+	uint8_t			tptid[1];
+} scsi_prout_reg_move_plist_t;
+
 #elif defined(_BIT_FIELDS_HTOL)
 /*
  * Information obtained from:
@@ -294,19 +333,42 @@
 } scsi_prin_rpt_cap_t;
 
 /*
+ * Refer SPC-3, Revision 23
+ * Section 7.5.4 TransportID identifiers
+ */
+typedef struct scsi_transport_id {
+	uint8_t			format_code : 2,
+				resbits : 2,
+				protocol_id : 4;
+	uint8_t			protocol_data[1];
+} scsi_transport_id_t;
+
+typedef struct scsi_fc_transport_id {
+	uint8_t			format_code : 2,
+				resbits : 2,
+				protocol_id : 4;
+	uint8_t			rsvbytes1[7];
+	uint8_t			port_name[8];
+	uint8_t			rsvbytes2[8];
+} scsi_fc_transport_id_t;
+
+typedef struct iscsi_transport_id {
+	uint8_t			format_code : 2,
+				resbits : 2,
+				protocol_id : 4;
+	uint8_t			rsvbyte1;
+	uint8_t			add_len[2];
+	char			iscsi_name[1];
+} iscsi_transport_id_t;
+
+/*
  * Information obtained from:
  *	SPC-3, Revision 23
  *	Section 6.11.5 PERSISTENCE RESERVE IN
  * 	Table 110/111 - parameter data for READ FULL STATUS
  *	Table 281 - TransportId format
  */
-typedef struct scsi_transport_id {
-	uint8_t			format_code : 2,
-				resbits : 2,
-				protocol_id : 4;
-	uint8_t			add_len[2];
-	char			iscsi_name[1];
-} scsi_transport_id_t;
+
 typedef struct scsi_prin_status_t {
 	uint8_t			reservation_key[8];
 	uint8_t			resbytes1[4];
@@ -363,6 +425,24 @@
 	uint8_t			apd[1];
 } scsi_prout_plist_t;
 
+/*
+ * Information obtained from:
+ *	SPC-3, Revision 23
+ *	Section 6.12.4 PERSISTENCE RESERVE OUT command with REGISTER AND MOVE
+ *	Table 117 - REGISTER and MOVE service action  parameter list
+ */
+typedef struct scsi_prout_reg_move_plist {
+	uint8_t			reservation_key[8];
+	uint8_t			service_key[8];
+	uint8_t			resbytes1;
+	uint8_t			resbits1 : 6,
+				unreg    : 1,
+				aptpl    : 1;
+	uint8_t			rel_tgt_port_id[2];
+	uint8_t			tptid_len[4];
+	uint8_t			tptid[1];
+} scsi_prout_reg_move_plist_t;
+
 #else
 #error	One of _BIT_FIELDS_LTOH or _BIT_FIELDS_HTOL must be defined
 #endif	/* _BIT_FIELDS_LTOH */
--- a/usr/src/uts/common/sys/stmf.h	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/uts/common/sys/stmf.h	Fri May 08 16:22:42 2009 -0600
@@ -374,6 +374,8 @@
 void stmf_scsilib_send_status(scsi_task_t *task, uint8_t st, uint32_t saa);
 uint32_t stmf_scsilib_prepare_vpd_page83(scsi_task_t *task, uint8_t *page,
 		uint32_t page_len, uint8_t byte0, uint32_t vpd_mask);
+uint16_t stmf_scsilib_get_lport_rtid(struct scsi_devid_desc *devid);
+struct scsi_devid_desc *stmf_scsilib_get_devid_desc(uint16_t rtpid);
 void stmf_scsilib_handle_report_tpgs(scsi_task_t *task, stmf_data_buf_t *dbuf);
 void stmf_scsilib_handle_task_mgmt(scsi_task_t *task);
 
--- a/usr/src/uts/common/sys/stmf_defines.h	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/uts/common/sys/stmf_defines.h	Fri May 08 16:22:42 2009 -0600
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #ifndef	_STMF_DEFINES_H
@@ -107,17 +107,25 @@
 /*
  * Common key, asc, ascq for stmf_scsilib_send_status
  */
+#define	STMF_SAA_MEDIUM_NOT_PRESENT		0X023A00
 #define	STMF_SAA_WRITE_ERROR			0x030C00
 #define	STMF_SAA_READ_ERROR			0x031100
+#define	STMF_SAA_OPERATION_IN_PROGRESS		0x050016
+#define	STMF_SAA_INVALID_FIELD_IN_CMD_IU	0x050E03
+#define	STMF_SAA_PARAM_LIST_LENGTH_ERROR	0x051A00
 #define	STMF_SAA_INVALID_OPCODE			0x052000
 #define	STMF_SAA_INVALID_LU			0x052009
 #define	STMF_SAA_LBA_OUT_OF_RANGE		0x052100
 #define	STMF_SAA_INVALID_FIELD_IN_CDB		0x052400
-#define	STMF_SAA_INVALID_FIELD_IN_CMD_IU	0x050E03
-#define	STMF_SAA_REPORT_LUN_DATA_HAS_CHANGED	0x063F0E
-#define	STMF_SAA_OPERATION_IN_PROGRESS		0x050016
+#define	STMF_SAA_INVALID_FIELD_IN_PARAM_LIST	0x052600
+#define	STMF_SAA_INVALID_RELEASE_OF_PR		0x052604
+#define	STMF_SAA_MEDIUM_REMOVAL_PREVENTED	0x055302
+#define	STMF_SAA_INSUFFICIENT_REG_RESOURCES	0x055504
 #define	STMF_SAA_POR				0x062900
 #define	STMF_SAA_CAPACITY_DATA_HAS_CHANGED	0x062A09
+#define	STMF_SAA_MODE_PARAMETERS_CHANGED	0x062A01
+#define	STMF_SAA_REPORT_LUN_DATA_HAS_CHANGED	0x063F0E
+#define	STMF_SAA_WRITE_PROTECTED		0X072700
 
 struct stmf_lu_provider;
 struct stmf_lu;
--- a/usr/src/uts/common/sys/stmf_ioctl.h	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/uts/common/sys/stmf_ioctl.h	Fri May 08 16:22:42 2009 -0600
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 #ifndef	_STMF_IOCTL_H
@@ -51,19 +51,21 @@
 #define	STMF_IOCTL_REMOVE_TG_ENTRY		(STMF_IOCTL | 17)
 #define	STMF_IOCTL_ADD_VIEW_ENTRY		(STMF_IOCTL | 18)
 #define	STMF_IOCTL_REMOVE_VIEW_ENTRY		(STMF_IOCTL | 19)
-#if 0
 #define	STMF_IOCTL_GET_HG_LIST			(STMF_IOCTL | 20)
 #define	STMF_IOCTL_GET_TG_LIST			(STMF_IOCTL | 21)
 #define	STMF_IOCTL_GET_HG_ENTRIES		(STMF_IOCTL | 22)
 #define	STMF_IOCTL_GET_TG_ENTRIES		(STMF_IOCTL | 23)
 #define	STMF_IOCTL_GET_VE_LIST			(STMF_IOCTL | 24)
-#endif
 #define	STMF_IOCTL_LOAD_PP_DATA			(STMF_IOCTL | 25)
 #define	STMF_IOCTL_CLEAR_PP_DATA		(STMF_IOCTL | 26)
-#define	STMF_IOCTL_CLEAR_TRACE			(STMF_IOCTL | 27)
-#define	STMF_IOCTL_ADD_TRACE			(STMF_IOCTL | 28)
-#define	STMF_IOCTL_GET_TRACE_POSITION		(STMF_IOCTL | 29)
-#define	STMF_IOCTL_GET_TRACE			(STMF_IOCTL | 30)
+#define	STMF_IOCTL_GET_PP_DATA			(STMF_IOCTL | 27)
+#define	STMF_IOCTL_CLEAR_TRACE			(STMF_IOCTL | 28)
+#define	STMF_IOCTL_ADD_TRACE			(STMF_IOCTL | 29)
+#define	STMF_IOCTL_GET_TRACE_POSITION		(STMF_IOCTL | 30)
+#define	STMF_IOCTL_GET_TRACE			(STMF_IOCTL | 31)
+#define	STMF_IOCTL_REG_LU_LIST			(STMF_IOCTL | 32)
+#define	STMF_IOCTL_VE_LU_LIST			(STMF_IOCTL | 33)
+#define	STMF_IOCTL_LU_VE_LIST			(STMF_IOCTL | 34)
 
 typedef	struct stmf_iocdata {
 	uint32_t	stmf_version;
@@ -133,7 +135,7 @@
 	uint8_t		config_state;	/* N/A for LU/LPORTs */
 } stmf_state_desc_t;
 
-/* Error definitions for group/view entry ioctls */
+/* Error definitions for group/view entry/provider dataioctls */
 #define	STMF_IOCERR_NONE			0
 #define	STMF_IOCERR_HG_EXISTS			1
 #define	STMF_IOCERR_INVALID_HG			2
@@ -152,6 +154,9 @@
 #define	STMF_IOCERR_INVALID_VIEW_ENTRY		15
 #define	STMF_IOCERR_INVALID_VE_ID		16
 #define	STMF_IOCERR_UPDATE_NEED_CFG_INIT	17
+#define	STMF_IOCERR_PPD_UPDATED			18
+#define	STMF_IOCERR_INSUFFICIENT_BUF		19
+
 
 typedef struct stmf_group_name {
 	uint16_t	name_size;	/* in bytes */
@@ -163,9 +168,11 @@
 /*
  * struct used to operate (add/remove entry) on a group.
  */
-#if 0
-typedef uint8_t	stmf_ge_ident_t[260];
-#endif
+
+typedef struct stmf_ge_ident {
+	uint16_t    ident_size;
+	uint8_t	    ident[256];
+} stmf_ge_ident_t;
 
 typedef struct stmf_group_op_data {
 	stmf_group_name_t	group;
@@ -189,7 +196,9 @@
 	char		ppi_name[255];	/* Provider name including \0 */
 	uint8_t		ppi_port_provider:1,
 			ppi_lu_provider:1,
-			ppt_rsvd:6;
+			ppi_token_valid:1,
+			ppt_rsvd:5;
+	uint64_t	ppi_token;
 	uint64_t	ppi_data_size;
 	uint8_t		ppi_data[8];
 } stmf_ppioctl_data_t;
--- a/usr/src/uts/common/sys/stmf_sbd_ioctl.h	Fri May 08 13:31:23 2009 -0700
+++ b/usr/src/uts/common/sys/stmf_sbd_ioctl.h	Fri May 08 16:22:42 2009 -0600
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -30,98 +30,150 @@
 extern "C" {
 #endif
 
-#define	MEMDISK_MIN_SIZE	(1024 * 1024)
-#define	MEMDISK_MAX_SIZE	(1024 * 1024 * 1024)
-
 /*
- * ioctl cmds
+ * error codes from sbd.
  */
-#define	SBD_IOCTL_CMD		(((uint32_t)'S') << 24)
-
-#define	SBD_REGISTER_LU		(SBD_IOCTL_CMD | 0x01)
-#define	SBD_GET_LU_ATTR		(SBD_IOCTL_CMD | 0x02)
-#define	SBD_GET_LU_LIST		(SBD_IOCTL_CMD | 0x03)
-#define	SBD_DEREGISTER_LU	(SBD_IOCTL_CMD | 0x04)
-#define	SBD_MODIFY_LU		(SBD_IOCTL_CMD | 0x05)
+typedef enum sbd_ret {
+	SBD_RET_META_CREATION_FAILED = 0x01,
+	SBD_RET_INVALID_BLKSIZE,
+	SBD_RET_REQUIRES_SEPARATE_META,
+	SBD_RET_FILE_ALREADY_REGISTERED,
+	SBD_RET_GUID_ALREADY_REGISTERED,
+	SBD_RET_DATA_PATH_NOT_ABSOLUTE,
+	SBD_RET_META_PATH_NOT_ABSOLUTE,
+	SBD_RET_META_FILE_LOOKUP_FAILED,
+	SBD_RET_ZFS_META_CREATE_FAILED,
+	SBD_ZVOL_META_NAME_MISMATCH,
+	SBD_RET_DATA_FILE_LOOKUP_FAILED,
+	SBD_RET_WRONG_META_FILE_TYPE,
+	SBD_RET_WRONG_DATA_FILE_TYPE,
+	SBD_RET_DATA_FILE_OPEN_FAILED,
+	SBD_RET_META_FILE_OPEN_FAILED,
+	SBD_RET_DATA_FILE_GETATTR_FAILED,
+	SBD_RET_META_FILE_GETATTR_FAILED,
+	SBD_RET_FILE_SIZE_ERROR,
+	SBD_RET_FILE_ALIGN_ERROR,
+	SBD_RET_SIZE_OUT_OF_RANGE,
+	SBD_RET_SIZE_NOT_SUPPORTED_BY_FS,
+	SBD_RET_NO_META,
+	SBD_RET_VERSION_NOT_SUPPORTED,
+	SBD_RET_LU_BUSY,
+	SBD_RET_NOT_FOUND,
+	SBD_RET_INSUFFICIENT_BUF_SPACE,
+	SBD_RET_WRITE_CACHE_SET_FAILED,
 
-typedef enum rlc_flags {
-	RLC_LU_TYPE_MEMDISK = 0x01,
-	RLC_LU_TYPE_FILEDISK = 0x02,
-	RLC_CREATE_LU = 0x04,		/* Initialize metadata */
-	RLC_REGISTER_LU = 0x10,
-	RLC_DEREGISTER_LU = 0x20,
-	RLC_FORCE_OP = 0x40
-} rlc_flags_t;
+	SBD_RET_MAX_VAL
+} sbd_ret_t;
+
+#define	SBD_IOCTL_DEF(n)	((((int)0x5B) << 16) | (n))
+#define	SBD_IOCTL_CREATE_AND_REGISTER_LU		SBD_IOCTL_DEF(1)
+#define	SBD_IOCTL_IMPORT_LU				SBD_IOCTL_DEF(2)
+#define	SBD_IOCTL_DELETE_LU				SBD_IOCTL_DEF(3)
+#define	SBD_IOCTL_MODIFY_LU				SBD_IOCTL_DEF(4)
+#define	SBD_IOCTL_GET_LU_PROPS				SBD_IOCTL_DEF(5)
+#define	SBD_IOCTL_GET_LU_LIST				SBD_IOCTL_DEF(6)
 
-typedef enum rlc_ret {
-	RLC_RET_META_CREATION_FAILED = 0x01,
-	RLC_RET_LU_NOT_INITIALIZED,
-	RLC_RET_FILE_ALREADY_REGISTERED,
-	RLC_RET_GUID_ALREADY_REGISTERED,
-	RLC_RET_REGISTER_SST_FAILED,
-	RLC_RET_DEREGISTER_SST_FAILED,
-	RLC_RET_FILE_LOOKUP_FAILED,
-	RLC_RET_WRONG_FILE_TYPE,
-	RLC_RET_FILE_OPEN_FAILED,
-	RLC_RET_FILE_GETATTR_FAILED,
-	RLC_RET_FILE_SIZE_ERROR,
-	RLC_RET_FILE_ALIGN_ERROR,
-	RLC_RET_SIZE_OUT_OF_RANGE,
-	RLC_RET_SIZE_NOT_SUPPORTED_BY_FS,
-
-	RLC_RET_MAX_VAL
-} rlc_ret_t;
+typedef struct sbd_create_and_reg_lu {
+	uint32_t	slu_struct_size;
+	uint16_t	slu_meta_fname_valid:1,
+			slu_lu_size_valid:1,
+			slu_blksize_valid:1,
+			slu_vid_valid:1,
+			slu_pid_valid:1,
+			slu_rev_valid:1,
+			slu_serial_valid:1,
+			slu_alias_valid:1,
+			slu_guid_valid:1,
+			slu_company_id_valid:1,
+			slu_writeback_cache_disable_valid:1,
+			slu_writeback_cache_disable:1,
+			slu_write_protected:1;
 
-typedef struct register_lu_cmd {
-	uint32_t	total_struct_size;
-	rlc_flags_t	flags;
-	uint64_t	lu_size;	/* For memdisk only */
-	rlc_ret_t	return_code;
-	uint32_t	filesize_nbits;
-	stmf_status_t	op_ret;
-	uint64_t	lu_handle;
-	uint8_t		guid[16];	/* For reporting back duplicate GUID */
-	char		name[8];
-} register_lu_cmd_t;
+	uint16_t	slu_meta_fname_off;
+	uint64_t	slu_lu_size;
+	uint16_t	slu_data_fname_off;
+	uint16_t	slu_serial_off;
+	uint8_t		slu_serial_size;
+	uint8_t		slu_ret_filesize_nbits;
+	uint16_t	slu_blksize;
+	uint32_t	slu_company_id;
+	uint16_t	slu_alias_off;
+	uint8_t		slu_rsvd2;
+	uint8_t		slu_rsvd;
+	uint32_t	slu_rsvd1;
+	char		slu_rev[4];
+	char		slu_vid[8];
+	char		slu_pid[16];
+	uint8_t		slu_guid[16];
+	char		slu_buf[8];	/* likely more than 8 */
+} sbd_create_and_reg_lu_t;
 
-typedef struct deregister_lu_cmd {
-	uint32_t	total_struct_size;
-	rlc_flags_t	flags;
-	rlc_ret_t	return_code;
-	uint32_t	rsvd;
-	uint8_t		guid[16];
-} deregister_lu_cmd_t;
+typedef struct sbd_import_lu {
+	uint32_t	ilu_struct_size;
+	uint32_t	ilu_rsvd;
+	uint8_t		ilu_ret_guid[16];
+	char		ilu_meta_fname[8]; /* Can be more than 8 */
+} sbd_import_lu_t;
 
-typedef struct modify_lu_cmd {
-	uint32_t	total_struct_size;
-	rlc_flags_t	flags;
-	uint64_t	lu_size;
-	rlc_ret_t	return_code;
-	uint32_t	filesize_nbits;
-	stmf_status_t	op_ret;
-	uint8_t		guid[16];
-	char		name[8];
-} modify_lu_cmd_t;
+typedef struct sbd_modify_lu {
+	uint32_t	mlu_struct_size;
+	uint32_t	mlu_lu_size_valid:1,
+			mlu_serial_valid:1,
+			mlu_alias_valid:1,
+			mlu_writeback_cache_disable_valid:1,
+			mlu_writeback_cache_disable:1,
+			mlu_write_protected_valid:1,
+			mlu_write_protected:1,
+			mlu_by_guid:1,
+			mlu_by_fname:1;
+	uint64_t	mlu_lu_size;
+	uint16_t	mlu_alias_off;
+	uint16_t	mlu_serial_off;
+	uint16_t	mlu_serial_size;
+	uint16_t	mlu_fname_off;
+	uint8_t		mlu_input_guid[16];
+	char		mlu_buf[8]; /* can be more than 8 */
+} sbd_modify_lu_t;
+
+typedef struct sbd_delete_lu {
+	uint32_t	dlu_struct_size;
+	uint16_t	dlu_by_guid:1,
+			dlu_by_meta_name:1;
+	uint16_t	dlu_rsvd;
+	uint8_t		dlu_guid[16];
+	uint8_t		dlu_meta_name[8];
+} sbd_delete_lu_t;
 
-typedef struct sbd_lu_attr {
-	uint32_t	total_struct_size;
-	rlc_flags_t	flags;	/* to find out the type */
-	int		max_name_length;
-	uint32_t	rsvd;
-	uint64_t	lu_handle;
-	uint64_t	total_size;
-	uint64_t	data_size;
-	uint8_t		guid[16];
-	char		name[8];
-} sbd_lu_attr_t;
+typedef struct sbd_lu_props {
+	uint32_t	slp_input_guid:1,	/* GUID or meta filename */
+			slp_separate_meta:1,
+			slp_meta_fname_valid:1,
+			slp_data_fname_valid:1,
+			slp_zfs_meta:1,
+			slp_alias_valid:1,
+			slp_lu_vid:1,
+			slp_lu_pid:1,
+			slp_lu_rev:1,
+			slp_serial_valid:1,
+			slp_writeback_cache_disable_cur:1,
+			slp_writeback_cache_disable_saved:1,
+			slp_write_protected:1;
 
-typedef struct sbd_lu_list {
-	uint32_t	total_struct_size;
-	uint32_t	count_in;
-	uint32_t	count_out;
-	uint32_t	rsvd;
-	uint64_t	handles[1];
-} sbd_lu_list_t;
+	uint16_t	slp_meta_fname_off;
+	uint16_t	slp_data_fname_off;
+	uint64_t	slp_lu_size;
+	uint16_t	slp_serial_off;
+	uint16_t	slp_blksize;
+	uint16_t	slp_alias_off;
+	uint32_t	slp_buf_size_needed;	/* Upon return */
+	uint16_t	slp_serial_size;
+	uint16_t	slp_rsvd;
+	char		slp_rev[4];
+	char		slp_vid[8];
+	char		slp_pid[16];
+	uint8_t		slp_guid[16];
+	uint8_t		slp_buf[8];	/* likely more than 8 */
+} sbd_lu_props_t;
 
 #ifdef	__cplusplus
 }