summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c11
-rw-r--r--usr/src/cmd/sbdadm/Makefile4
-rw-r--r--usr/src/cmd/sbdadm/sbdadm.c1179
-rw-r--r--usr/src/cmd/stmfadm/stmfadm.c892
-rw-r--r--usr/src/common/cmdparse/cmdparse.c5
-rw-r--r--usr/src/common/cmdparse/cmdparse.h5
-rw-r--r--usr/src/lib/libstmf/Makefile.com4
-rw-r--r--usr/src/lib/libstmf/common/libstmf.h67
-rw-r--r--usr/src/lib/libstmf/common/libstmf_impl.h75
-rw-r--r--usr/src/lib/libstmf/common/mapfile-vers12
-rw-r--r--usr/src/lib/libstmf/common/stmf.c2862
-rw-r--r--usr/src/lib/libstmf/common/store.c279
-rw-r--r--usr/src/lib/libstmf/common/store.h4
-rw-r--r--usr/src/uts/common/Makefile.files2
-rw-r--r--usr/src/uts/common/io/comstar/lu/stmf_sbd/filedisk.c569
-rw-r--r--usr/src/uts/common/io/comstar/lu/stmf_sbd/memdisk.c175
-rw-r--r--usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c2962
-rw-r--r--usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_impl.h124
-rw-r--r--usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_pgr.c1905
-rw-r--r--usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c1059
-rw-r--r--usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h281
-rw-r--r--usr/src/uts/common/io/comstar/port/fct/fct.c4
-rw-r--r--usr/src/uts/common/io/comstar/stmf/stmf.c322
-rw-r--r--usr/src/uts/common/io/comstar/stmf/stmf_impl.h1
-rw-r--r--usr/src/uts/common/sys/scsi/generic/persist.h110
-rw-r--r--usr/src/uts/common/sys/stmf.h2
-rw-r--r--usr/src/uts/common/sys/stmf_defines.h16
-rw-r--r--usr/src/uts/common/sys/stmf_ioctl.h33
-rw-r--r--usr/src/uts/common/sys/stmf_sbd_ioctl.h216
29 files changed, 10210 insertions, 2970 deletions
diff --git a/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c b/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c
index fa58f7f65c..11252da19a 100644
--- a/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c
+++ b/usr/src/cmd/iscsi/iscsitgtd/t10_spc_pr.c
@@ -674,6 +674,7 @@ spc_pr_in_fullstat(
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 @@ spc_pr_in_fullstat(
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
diff --git a/usr/src/cmd/sbdadm/Makefile b/usr/src/cmd/sbdadm/Makefile
index ff11610b64..9c4479d06e 100644
--- a/usr/src/cmd/sbdadm/Makefile
+++ b/usr/src/cmd/sbdadm/Makefile
@@ -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 @@ POFILE = sbdadm_all.po
POFILES = $(LOCAL_OBJS:%.o=%.po)
CPPFLAGS += -I. -I$(COMMONBASE)/cmdparse
-LDLIBS += -lstmf -lnvpair
+LDLIBS += -lstmf
LINTFLAGS += -xerroff=E_BAD_PTR_CAST_ALIGN
.KEEP_STATE:
diff --git a/usr/src/cmd/sbdadm/sbdadm.c b/usr/src/cmd/sbdadm/sbdadm.c
index 1481e44833..41229169e9 100644
--- a/usr/src/cmd/sbdadm/sbdadm.c
+++ b/usr/src/cmd/sbdadm/sbdadm.c
@@ -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 @@ subCommandProps_t subCommands[] = {
{ NULL, 0, 0, NULL, 0, NULL}
};
-int sbd_fd;
-
+/*ARGSUSED*/
int
-main(int argc, char *argv[])
+create_lu(int argc, char *operands[], cmdOptions_t *options, void *callData)
{
- 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);
-}
+ luResource hdl = NULL;
+ int ret = 0;
+ stmfGuid createdGuid;
-/*
- * 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)
-{
- uint64_t cur_size, m;
- uint64_t new_cur_size;
- int i;
- char c;
+ 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 = nvlist_add_string(nvl, guid, filename);
- if (ret != 0) {
- (void) fprintf(stderr,
- "could not add data to nvlist\n");
- ret = 1;
- goto out;
- }
-
- 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);
- return (ret);
-}
-
-/*ARGSUSED*/
-int
-create_lu(int argc, char *argv[], cmdOptions_t *options, void *callData)
-{
- register_lu_cmd_t *rlc;
- uint32_t fl;
- int ret = 0, err;
- uint64_t size;
- 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);
+ 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;
}
- 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);
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
}
- 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]);
- }
- }
+ (void) printf("Created the following LU:\n");
+ print_attr_header();
+ ret = print_lu_attr(&createdGuid);
-create_lu_done:;
- free(rlc);
+done:
+ (void) stmfFreeLuResource(hdl);
return (ret);
}
/*ARGSUSED*/
int
-import_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;
- char guidAsciiBuf[33];
+ 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_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]);
- }
+ if (ret != STMF_STATUS_SUCCESS) {
+ goto done;
}
-import_lu_done:;
- free(rlc);
+ (void) printf("Imported the following LU:\n");
+ print_attr_header();
+ ret = print_lu_attr(&createdGuid);
+
+done:
return (ret);
}
/*ARGSUSED*/
int
-delete_lu(int argc, char *argv[], cmdOptions_t *options, void *callData)
+delete_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;
-
- int stmf_ret;
- int keep_view = 0;
- uint64_t setToken;
- stmfGuid inGuid;
- stmfViewEntryList *viewEntryList;
- boolean_t retryGetProviderData;
+ 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) {
- case 'k':
- keep_view = 1;
- break;
+ /* 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);
}
}
- 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");
- }
- ret = 1;
- goto delete_lu_done;
+ 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]);
}
- } 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;
+ 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;
}
- drlc.guid[i++] = ch;
- }
+ sGuid[j] = 0;
- 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;
+ (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];
}
- } 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];
+ 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 ((stmf_ret = stmfGetViewEntryList(&inGuid,
- &viewEntryList)) == STMF_STATUS_SUCCESS) {
- for (i = 0; i < viewEntryList->cnt; i++) {
- (void) stmfRemoveViewEntry(&inGuid,
- viewEntryList->ve[i].veIndex);
+ 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);
}
- } else if (stmf_ret != STMF_ERROR_NOT_FOUND) {
- (void) fprintf(stderr,
- "unable to remove view entries\n");
- ret = 1;
}
- }
- if (!exists) {
- (void) fprintf(stderr, "GUID not found.\n");
- ret = 1;
- goto delete_lu_done;
+ 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;
}
-
-delete_lu_done:;
return (ret);
}
/*ARGSUSED*/
int
-modify_lu(int argc, char *argv[], cmdOptions_t *options, void *callData)
+modify_lu(int operandLen, char *operands[], cmdOptions_t *options,
+ void *callData)
{
- 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;
-
- 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);
+ 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];
}
- mlc = (modify_lu_cmd_t *)malloc(struct_size);
- if (mlc == NULL) {
- (void) fprintf(stderr, "Unable to allocate memory\n");
+
+ /* 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);
}
- 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 (!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 (is_filename) {
- (void) strcpy(mlc->name, argv[argc-1]);
- (void) memset(mlc->guid, 0, 16);
- } 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;
+ for (; options->optval; options++) {
+ switch (options->optval) {
+ case 's':
+ if (callModify(fname, &inGuid,
+ STMF_LU_PROP_SIZE, options->optarg,
+ "size") != 0) {
+ return (1);
+ }
+ break;
+ default:
+ (void) fprintf(stderr, "%s: %c: %s\n",
+ cmdName, options->optval,
+ gettext("unknown option"));
+ return (1);
}
- mlc->name[0] = '\0';
}
- 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;
+ 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 {
- (void) printf("LU modified Successfully.\n");
+ 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;
+ 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 @@ modify_lu_done:;
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);
- }
- }
-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);
+ 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]);
+ }
}
- nvlist_free(nvl);
return (0);
}
@@ -801,47 +626,121 @@ print_guid(uint8_t *g, FILE *f)
}
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;
+ luResource hdl = NULL;
+ int stmfRet = 0;
+ int ret = 0;
+ char propVal[MAXPATHLEN];
+ 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);
+ }
- bzero(sla, BIG_BUF_SIZE);
+ print_guid((uint8_t *)guid, stdout);
- sla->lu_handle = handle;
- sla->total_struct_size = BIG_BUF_SIZE;
- sla->max_name_length = BIG_BUF_SIZE - sizeof (*sla) + 7;
+ 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++;
+ }
- 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);
+ 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);
- if (sla->data_size > 9999999999999ull)
- (void) printf(" %-19llu ", sla->data_size);
- else
- (void) printf(" %-13llu ", sla->data_size);
+ (void) stmfFreeLuResource(hdl);
+ return (ret);
+}
- if (sla->flags & RLC_LU_TYPE_MEMDISK) {
- (void) printf("<RAM : %llu bytes>\n", sla->total_size);
- } else {
- (void) printf("%s\n", sla->name);
- }
- 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;
+/*
+ * 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;
+
+ /* 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;
+ }
}
- return (1);
+ 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 (funcRet);
+} /* end main */
diff --git a/usr/src/cmd/stmfadm/stmfadm.c b/usr/src/cmd/stmfadm/stmfadm.c
index 7be85c5796..d4d1fcd99d 100644
--- a/usr/src/cmd/stmfadm/stmfadm.c
+++ b/usr/src/cmd/stmfadm/stmfadm.c
@@ -46,6 +46,10 @@ static int addHostGroupMemberFunc(int, char **, cmdOptions_t *, void *);
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 onlineOfflineTarget(char *, int);
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 checkScsiNameString(wchar_t *, stmfDevid *);
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 @@ static void printSessionProps(stmfSessionList *);
#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 @@ optionTbl_t longOptions[] = {
*/
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 @@ createHostGroupFunc(int operandLen, char *operands[],
}
/*
+ * 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 @@ listLuFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args)
cmdName, operands[i], gettext("must be "),
GUID_INPUT,
gettext(" hexadecimal digits long"));
+ invalidInput = B_FALSE;
continue;
}
@@ -1296,6 +1984,8 @@ listLuFunc(int operandLen, char *operands[], cmdOptions_t *options, void *args)
(void) printf("unknown");
}
(void) printf("\n");
+ ret = printExtLuProps(
+ &(luList->guid[j]));
}
if (found && operandEntered) {
break;
@@ -1322,6 +2012,154 @@ printGuid(stmfGuid *guid, FILE *stream)
}
}
+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 @@ getStmfState(stmfState *state)
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);
diff --git a/usr/src/common/cmdparse/cmdparse.c b/usr/src/common/cmdparse/cmdparse.c
index b67d6b352b..a773311033 100644
--- a/usr/src/common/cmdparse/cmdparse.c
+++ b/usr/src/common/cmdparse/cmdparse.c
@@ -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 @@ subUsage(uint_t usageType, subCommandProps_t *subcommand)
}
}
(void) fprintf(stdout, "\n");
+ if (subcommand->helpText) {
+ (void) printf("%s\n", subcommand->helpText);
+ }
}
/*
diff --git a/usr/src/common/cmdparse/cmdparse.h b/usr/src/common/cmdparse/cmdparse.h
index fd42affc4a..63554a16a1 100644
--- a/usr/src/common/cmdparse/cmdparse.h
+++ b/usr/src/common/cmdparse/cmdparse.h
@@ -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 @@ typedef struct _subCommandProps {
char *exclusive;
int operand;
char *operandDefinition;
- uint8_t reserved[64];
+ char *helpText;
+ uint8_t reserved[60];
} subCommandProps_t;
diff --git a/usr/src/lib/libstmf/Makefile.com b/usr/src/lib/libstmf/Makefile.com
index 627df92056..35c04ac4a2 100644
--- a/usr/src/lib/libstmf/Makefile.com
+++ b/usr/src/lib/libstmf/Makefile.com
@@ -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 @@ INCS += -I$(SRCDIR)
C99MODE= -xc99=%all
C99LMODE= -Xc99=%all
-LDLIBS += -lc -lnvpair -lscf
+LDLIBS += -lc -lnvpair -lscf -lm
CPPFLAGS += $(INCS) -D_REENTRANT
$(LINTLIB) := SRCS= $(SRCDIR)/$(LINTSRC)
diff --git a/usr/src/lib/libstmf/common/libstmf.h b/usr/src/lib/libstmf/common/libstmf.h
index 99d27a705b..72d9d8381a 100644
--- a/usr/src/lib/libstmf/common/libstmf.h
+++ b/usr/src/lib/libstmf/common/libstmf.h
@@ -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 @@ extern "C" {
#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 @@ typedef struct _stmfLogicalUnitProperties
stmfGuid luid;
} stmfLogicalUnitProperties;
+typedef void * luResource;
+
typedef struct _stmfLogicalUnitProviderProperties
{
char providerName[MAXPATHLEN];
@@ -247,11 +294,15 @@ int stmfAddToTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName);
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 stmfGetLogicalUnitProperties(stmfGuid *logicalUnit,
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 stmfGetTargetList(stmfDevidList **targetList);
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 stmfRemoveFromHostGroup(stmfGroupName *hostGroupName,
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);
diff --git a/usr/src/lib/libstmf/common/libstmf_impl.h b/usr/src/lib/libstmf/common/libstmf_impl.h
new file mode 100644
index 0000000000..cd32c932e4
--- /dev/null
+++ b/usr/src/lib/libstmf/common/libstmf_impl.h
@@ -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 */
diff --git a/usr/src/lib/libstmf/common/mapfile-vers b/usr/src/lib/libstmf/common/mapfile-vers
index e0f847853b..7be0e8ba5d 100644
--- a/usr/src/lib/libstmf/common/mapfile-vers
+++ b/usr/src/lib/libstmf/common/mapfile-vers
@@ -42,26 +42,36 @@ SUNW_1.1 {
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 @@ SUNW_1.1 {
stmfRemoveFromHostGroup;
stmfRemoveFromTargetGroup;
stmfRemoveViewEntry;
+ stmfSetPersistMethod;
stmfSetProviderData;
stmfSetProviderDataProt;
+ stmfSetLuProp;
local:
*;
};
diff --git a/usr/src/lib/libstmf/common/stmf.c b/usr/src/lib/libstmf/common/stmf.c
index af9da8255d..12799e47ab 100644
--- a/usr/src/lib/libstmf/common/stmf.c
+++ b/usr/src/lib/libstmf/common/stmf.c
@@ -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 loadHostGroups(int fd, stmfGroupList *);
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 @@ openStmf(int flag, int *fd)
} 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 @@ openStmf(int flag, int *fd)
}
/*
+ * 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 @@ groupIoctl(int fd, int cmd, stmfGroupName *groupName)
ioctlRet = ioctl(fd, cmd, &stmfIoctl);
if (ioctlRet != 0) {
switch (errno) {
+ case EPERM:
case EACCES:
ret = STMF_ERROR_PERM;
break;
@@ -219,7 +306,7 @@ done:
}
/*
- * groupIoctl
+ * groupMemberIoctl
*
* Purpose: issue ioctl for add/remove member on group
*
@@ -257,6 +344,7 @@ groupMemberIoctl(int fd, int cmd, stmfGroupName *groupName, stmfDevid *devid)
case EBUSY:
ret = STMF_ERROR_BUSY;
break;
+ case EPERM:
case EACCES:
ret = STMF_ERROR_PERM;
break;
@@ -292,6 +380,22 @@ done:
}
/*
+ * 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 @@ stmfAddToHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName)
goto done;
}
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
ret = psAddHostGroupMember((char *)hostGroupName,
(char *)hostName->ident);
switch (ret) {
@@ -432,6 +540,10 @@ stmfAddToTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName)
goto done;
}
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
ret = psAddTargetGroupMember((char *)targetGroupName,
(char *)targetName->ident);
switch (ret) {
@@ -526,6 +638,9 @@ addViewEntryIoctl(int fd, stmfGuid *lu, stmfViewEntry *viewEntry)
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 @@ stmfAddViewEntry(stmfGuid *lu, stmfViewEntry *viewEntry)
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 @@ stmfClearProviderData(char *providerName, int providerType)
case EBUSY:
ret = STMF_ERROR_BUSY;
break;
+ case EPERM:
case EACCES:
ret = STMF_ERROR_PERM;
break;
@@ -775,6 +895,10 @@ stmfClearProviderData(char *providerName, int providerType)
}
}
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
ret = psClearProviderData(providerName, providerType);
switch (ret) {
case STMF_PS_SUCCESS:
@@ -846,6 +970,10 @@ stmfCreateHostGroup(stmfGroupName *hostGroupName)
goto done;
}
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
ret = psCreateHostGroup((char *)hostGroupName);
switch (ret) {
case STMF_PS_SUCCESS:
@@ -877,6 +1005,1641 @@ done:
}
/*
+ * 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 @@ stmfCreateTargetGroup(stmfGroupName *targetGroupName)
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 @@ stmfDeleteHostGroup(stmfGroupName *hostGroupName)
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 @@ stmfDeleteTargetGroup(stmfGroupName *targetGroupName)
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 @@ stmfFreeMemory(void *memory)
}
/*
- * stmfGetHostGroupList
+ * get host group, target group list from stmf
*
- * Purpose: Retrieves the list of initiator group oids
+ * groupType - HOST_GROUP, TARGET_GROUP
+ */
+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
*
- * hostGroupList - pointer to pointer to hostGroupList structure
- * on success, this contains the host group list.
+ * groupProps - allocated on success
+ *
+ * groupType - HOST_GROUP, TARGET_GROUP
*/
-int
-stmfGetHostGroupList(stmfGroupList **hostGroupList)
+static int
+groupMemberListIoctl(stmfGroupName *groupName, stmfGroupProperties **groupProps,
+ int groupType)
{
int ret;
+ 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 (hostGroupList == NULL) {
+ 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 @@ stmfGetHostGroupList(stmfGroupList **hostGroupList)
}
/*
- * stmfGetHostGroupMembers
+ * stmfGetHostGroupList
*
- * Purpose: Retrieves the group properties for a host group
+ * Purpose: Retrieves the list of initiator group oids
*
- * 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.
+ * 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 @@ stmfGetHostGroupMembers(stmfGroupName *groupName,
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(stmfGroupName *groupName,
}
/*
+ * 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 @@ stmfGetProviderDataProt(char *providerName, nvlist_t **nvl, int providerType,
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 @@ stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList)
/*
* 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 @@ stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList)
case EBUSY:
ret = STMF_ERROR_BUSY;
break;
+ case EPERM:
case EACCES:
ret = STMF_ERROR_PERM;
break;
@@ -1476,7 +3553,7 @@ stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList)
/*
* 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 @@ stmfGetSessionList(stmfDevid *devid, stmfSessionList **sessionList)
case EBUSY:
ret = STMF_ERROR_BUSY;
break;
+ case EPERM:
case EACCES:
ret = STMF_ERROR_PERM;
break;
@@ -1556,31 +3634,7 @@ stmfGetTargetGroupList(stmfGroupList **targetGroupList)
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 @@ stmfGetTargetGroupMembers(stmfGroupName *groupName,
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 @@ stmfGetTargetList(stmfDevidList **targetList)
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 @@ stmfGetTargetList(stmfDevidList **targetList)
/*
* 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 @@ stmfGetTargetList(stmfDevidList **targetList)
case EBUSY:
ret = STMF_ERROR_BUSY;
break;
+ case EPERM:
case EACCES:
ret = STMF_ERROR_PERM;
break;
@@ -1704,13 +3737,14 @@ stmfGetTargetList(stmfDevidList **targetList)
/*
* 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 @@ stmfGetTargetList(stmfDevidList **targetList)
case EBUSY:
ret = STMF_ERROR_BUSY;
break;
+ case EPERM:
case EACCES:
ret = STMF_ERROR_PERM;
break;
@@ -1738,6 +3773,10 @@ stmfGetTargetList(stmfDevidList **targetList)
*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 @@ stmfGetTargetProperties(stmfDevid *devid, stmfTargetProperties *targetProps)
case EBUSY:
ret = STMF_ERROR_BUSY;
break;
+ case EPERM:
case EACCES:
ret = STMF_ERROR_PERM;
break;
@@ -1859,16 +3899,11 @@ stmfGetLogicalUnitList(stmfGuidList **luList)
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 @@ stmfGetLogicalUnitList(stmfGuidList **luList)
/*
* 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 @@ stmfGetLogicalUnitList(stmfGuidList **luList)
case EBUSY:
ret = STMF_ERROR_BUSY;
break;
+ case EPERM:
case EACCES:
ret = STMF_ERROR_PERM;
break;
@@ -1924,12 +3961,14 @@ stmfGetLogicalUnitList(stmfGuidList **luList)
/*
* 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 @@ stmfGetLogicalUnitList(stmfGuidList **luList)
case EBUSY:
ret = STMF_ERROR_BUSY;
break;
+ case EPERM:
case EACCES:
ret = STMF_ERROR_PERM;
break;
@@ -1953,99 +3993,35 @@ stmfGetLogicalUnitList(stmfGuidList **luList)
}
}
- 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;
}
- /*
- * copy guids to caller's buffer
- */
- 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,
+ (*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));
}
- (*luList)->cnt = finalListSize;
+ /*
+ * sort the list. This gives a consistent view across gets
+ */
+ qsort((void *)&((*luList)->guid[0]), (*luList)->cnt,
+ sizeof (stmfGuid), guidCompare);
done:
(void) close(fd);
@@ -2053,7 +4029,6 @@ done:
* free internal buffers
*/
free(fLuList);
- free(sLuList);
return (ret);
}
@@ -2078,8 +4053,8 @@ stmfGetLogicalUnitProperties(stmfGuid *lu, stmfLogicalUnitProperties *luProps)
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 @@ stmfGetLogicalUnitProperties(stmfGuid *lu, stmfLogicalUnitProperties *luProps)
case EBUSY:
ret = STMF_ERROR_BUSY;
break;
+ case EPERM:
case EACCES:
ret = STMF_ERROR_PERM;
break;
@@ -2234,38 +4210,167 @@ int
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 @@ loadHostGroups(int fd, stmfGroupList *groupList)
&(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 @@ loadTargetGroups(int fd, stmfGroupList *groupList)
&(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 @@ loadStore(int fd)
/* load host groups */
- ret = stmfGetHostGroupList(&groupList);
+ ret = iLoadGroupFromPs(&groupList, HOST_GROUP);
if (ret != STMF_STATUS_SUCCESS) {
return (ret);
}
@@ -2379,7 +4484,7 @@ loadStore(int fd)
groupList = NULL;
/* load target groups */
- ret = stmfGetTargetGroupList(&groupList);
+ ret = iLoadGroupFromPs(&groupList, TARGET_GROUP);
if (ret != STMF_STATUS_SUCCESS) {
goto out;
}
@@ -2512,7 +4617,7 @@ loadStore(int fd)
/* 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 @@ out:
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 @@ done:
return (ret);
}
+
/*
* getStmfState
*
@@ -2715,6 +4835,7 @@ setStmfState(int fd, stmf_state_desc_t *stmfState, int objectType)
case EBUSY:
ret = STMF_ERROR_BUSY;
break;
+ case EPERM:
case EACCES:
ret = STMF_ERROR_PERM;
break;
@@ -2975,6 +5096,10 @@ stmfRemoveFromHostGroup(stmfGroupName *hostGroupName, stmfDevid *hostName)
goto done;
}
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
ret = psRemoveHostGroupMember((char *)hostGroupName,
(char *)hostName->ident);
switch (ret) {
@@ -3046,6 +5171,10 @@ stmfRemoveFromTargetGroup(stmfGroupName *targetGroupName, stmfDevid *targetName)
goto done;
}
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
ret = psRemoveTargetGroupMember((char *)targetGroupName,
(char *)targetName->ident);
switch (ret) {
@@ -3132,6 +5261,9 @@ stmfRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex)
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 @@ stmfRemoveViewEntry(stmfGuid *lu, uint32_t viewEntryIndex)
goto done;
}
+ if (iGetPersistMethod() == STMF_PERSIST_NONE) {
+ goto done;
+ }
+
ret = psRemoveViewEntry(lu, viewEntryIndex);
switch (ret) {
case STMF_PS_SUCCESS:
@@ -3245,7 +5381,7 @@ stmfSetProviderDataProt(char *providerName, nvlist_t *nvl, int providerType,
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 @@ stmfSetProviderDataProt(char *providerName, nvlist_t *nvl, int providerType,
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 @@ done:
}
/*
+ * 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 @@ setProviderData(int fd, char *providerName, nvlist_t *nvl, int providerType)
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 @@ setProviderData(int fd, char *providerName, nvlist_t *nvl, int providerType)
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 @@ setProviderData(int fd, char *providerName, nvlist_t *nvl, int providerType)
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);
+}
diff --git a/usr/src/lib/libstmf/common/store.c b/usr/src/lib/libstmf/common/store.c
index 9e20376233..d9332c9977 100644
--- a/usr/src/lib/libstmf/common/store.c
+++ b/usr/src/lib/libstmf/common/store.c
@@ -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 iPsAddRemoveLuViewEntry(char *, char *, int);
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 @@ boolean_t actionSet = B_FALSE;
#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 @@ boolean_t actionSet = B_FALSE;
#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 @@ boolean_t actionSet = B_FALSE;
#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 @@ boolean_t actionSet = B_FALSE;
#define GROUP_MAX UINT64_MAX
#define ADD 0
#define REMOVE 1
+#define GET 0
+#define SET 1
/*
* sigHandler
@@ -1963,6 +1974,255 @@ out:
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 @@ err:
return (ret);
}
+
/*
* called by iPsInit only
* iPsGetServiceVersion
diff --git a/usr/src/lib/libstmf/common/store.h b/usr/src/lib/libstmf/common/store.h
index 2f19963755..01105a8e75 100644
--- a/usr/src/lib/libstmf/common/store.h
+++ b/usr/src/lib/libstmf/common/store.h
@@ -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 @@ int psGetProviderData(char *providerName, nvlist_t **nvl, int providerType,
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
}
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 80a462a002..053d7af9ff 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -889,7 +889,7 @@ ISCSIT_OBJS += $(ISCSIT_SHARED_OBJS) \
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
diff --git a/usr/src/uts/common/io/comstar/lu/stmf_sbd/filedisk.c b/usr/src/uts/common/io/comstar/lu/stmf_sbd/filedisk.c
deleted file mode 100644
index cf23131e84..0000000000
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/filedisk.c
+++ /dev/null
@@ -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);
-}
diff --git a/usr/src/uts/common/io/comstar/lu/stmf_sbd/memdisk.c b/usr/src/uts/common/io/comstar/lu/stmf_sbd/memdisk.c
deleted file mode 100644
index 6ff1104d2e..0000000000
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/memdisk.c
+++ /dev/null
@@ -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);
-}
diff --git a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c
index 25a24bd515..1875ee3e97 100644
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd.c
@@ -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 @@ _fini(void)
}
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 @@ sbd_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
*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 @@ sbd_close(dev_t dev, int flag, int otype, cred_t *credp)
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 {
- ret = EINVAL;
+ case SBD_IOCTL_CREATE_AND_REGISTER_LU:
+ if (iocd->stmf_ibuf_size <
+ (sizeof (sbd_create_and_reg_lu_t) - 8)) {
+ ret = EFAULT;
break;
}
- 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) {
+ if ((iocd->stmf_obuf_size == 0) ||
+ (iocd->stmf_obuf_size > iocd->stmf_ibuf_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_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_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_IMPORT_LU:
+ if (iocd->stmf_ibuf_size <
+ (sizeof (sbd_import_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 == 0) ||
+ (iocd->stmf_obuf_size > iocd->stmf_ibuf_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);
- }
- 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;
- }
- }
+ 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_GET_LU_LIST:
- sll = (sbd_lu_list_t *)p;
- cnt = sll->total_struct_size - sizeof (sbd_lu_list_t);
- if (cnt < 0) {
+ 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;
}
- cnt = (cnt >> 3) + 1;
- if (sll->count_in > cnt) {
+ ret = sbd_delete_lu((sbd_delete_lu_t *)ibuf,
+ iocd->stmf_ibuf_size, &iocd->stmf_error);
+ break;
+ case SBD_IOCTL_MODIFY_LU:
+ if (iocd->stmf_ibuf_size < (sizeof (sbd_modify_lu_t) - 8)) {
ret = EFAULT;
break;
}
- 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++;
+ if (iocd->stmf_obuf_size) {
+ ret = EINVAL;
+ break;
}
- mutex_exit(&sbd_lock);
+ ret = sbd_modify_lu((sbd_modify_lu_t *)ibuf,
+ iocd->stmf_ibuf_size, &iocd->stmf_error);
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)) {
+ case SBD_IOCTL_GET_LU_PROPS:
+ if (iocd->stmf_ibuf_size < (sizeof (sbd_lu_props_t) - 8)) {
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 {
+ if (iocd->stmf_obuf_size < sizeof (sbd_lu_props_t)) {
ret = EINVAL;
+ 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);
+ 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;
-
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 @@ do_lu_dereg:
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 @@ sbd_lp_cb(stmf_lu_provider_t *lp, int cmd, void *arg, uint32_t flags)
}
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 @@ sbd_lp_cb(stmf_lu_provider_t *lp, int cmd, void *arg, uint32_t flags)
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);
+ }
+ 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));
}
- 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);
}
- 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;
-
- total_as = GET_STRUCT_SIZE(sbd_store_t) + GET_STRUCT_SIZE(sbd_lu_t) +
- ((additional_size + 7) & ~7);
-
- 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);
+ sbd_lu_t *nsl;
+
+ mutex_enter(&sbd_lock);
+ mutex_enter(&sl->sl_lock);
+ ASSERT(sl->sl_trans_op != SL_OP_NONE);
+
+ 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 *slu = (sbd_lu_t *)sst->sst_sbd_private;
+ sbd_lu_t **ppnsl;
- mutex_destroy(&slu->sl_it_list_lock);
- stmf_free(slu->sl_lu);
-}
+ mutex_enter(&sbd_lock);
+ mutex_enter(&sl->sl_lock);
+ ASSERT(sl->sl_trans_op != SL_OP_NONE);
-#define DATA_ALIGNMENT 0xfffffffffffff000
-#define DATA_BLOCK_SIZE 4 * 1024
+ 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);
+}
-stmf_status_t
-sbd_aligned_meta_write(struct sbd_store *sst, uint64_t offset,
- uint64_t size, uint8_t *buf)
+sbd_status_t
+sbd_find_and_lock_lu(uint8_t *guid, uint8_t *meta_name, uint8_t op,
+ sbd_lu_t **ppsl)
{
- 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;
+ sbd_lu_t *sl;
+ int found = 0;
+ sbd_status_t sret;
- /* 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);
+ 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 {
- ret = sst->sst_data_read(sst, starting_off,
- op_size, (uint8_t *)op_buf);
+ sret = SBD_BUSY;
}
- if (ret != STMF_SUCCESS)
- goto aligned_write_ret;
-
- bcopy(buf, op_buf + off_from_starting, size);
+ mutex_exit(&sl->sl_lock);
+ mutex_exit(&sbd_lock);
+ return (sret);
+}
- if (sst->sst_meta_write) {
- ret = sst->sst_meta_write(sst, starting_off,
- op_size, (uint8_t *)op_buf);
+sbd_status_t
+sbd_read_meta(sbd_lu_t *sl, uint64_t offset, uint64_t size, uint8_t *buf)
+{
+ 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;
+
+ 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_write(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);
+ 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 (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 {
+ 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;
+ }
+ }
+
+ bcopy(io_buf + data_off, buf, size);
+ ret = SBD_SUCCESS;
-aligned_write_ret:
- if (op_buf)
- kmem_free(op_buf, op_size);
+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;
-
- if (sst->sst_meta_read) {
- ret = sst->sst_meta_read(sst, starting_off,
- op_size, (uint8_t *)op_buf);
+ 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;
+
+ 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 {
+ 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;
+ }
+ 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 {
- ret = sst->sst_data_read(sst, starting_off,
- op_size, (uint8_t *)op_buf);
+ 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);
+
+ if (vret || resid) {
+ ret = SBD_FILEIO_FAILURE | vret;
+ goto sbd_write_meta_failure;
+ }
}
- if (ret != STMF_SUCCESS)
- goto aligned_read_ret;
- bcopy(op_buf + off_from_starting, buf, size);
-aligned_read_ret:
- if (op_buf)
- kmem_free(op_buf, op_size);
+ ret = SBD_SUCCESS;
+
+sbd_write_meta_failure:
+ kmem_free(io_buf, io_size);
return (ret);
}
@@ -673,9 +680,36 @@ sbd_calc_sum(uint8_t *buf, int size)
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,557 +719,1983 @@ sbd_swap_meta_start(sbd_meta_start_t *sm)
}
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_sli_fields(sbd_lu_info_t *sli, uint8_t data_order)
+sbd_swap_lu_info_1_0(sbd_lu_info_1_0_t *sli)
{
- 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;
+ 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);
}
-/*
- * will not modify sms.
- */
-uint64_t
-sbd_find_section_offset(sbd_store_t *sst, sm_section_hdr_t *sms)
+void
+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;
+ 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);
+}
- if (slu->sl_sm.sm_magic != SBD_MAGIC) {
- cmn_err(CE_PANIC, "sbd_find section called without reading the"
- " header first.");
+sbd_status_t
+sbd_load_section_hdr(sbd_lu_t *sl, sm_section_hdr_t *sms)
+{
+ sm_section_hdr_t h;
+ uint64_t st;
+ sbd_status_t ret;
+
+ 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);
+ }
}
- 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);
+ 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);
+}
+
+sbd_status_t
+sbd_read_meta_section(sbd_lu_t *sl, sm_section_hdr_t **ppsms, uint16_t sms_id)
+{
+ sbd_status_t ret;
+ sm_section_hdr_t sms;
+ int alloced = 0;
+
+ 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));
}
- if (smsh.sms_id == sms->sms_id)
- return (smsh.sms_offset);
- ssize += smsh.sms_size;
}
- return (0);
+ 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;
+ }
+ }
+
+ if ((ret != SBD_SUCCESS) && alloced)
+ kmem_free(*ppsms, sms.sms_size);
+ return (ret);
}
-stmf_status_t
-sbd_read_section(sbd_store_t *sst, sm_section_hdr_t *sms)
+sbd_status_t
+sbd_write_meta_section(sbd_lu_t *sl, sm_section_hdr_t *sms)
{
- stmf_status_t ret;
- uint32_t sz;
- uint8_t osum, nsum;
+ 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;
+
+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);
+ }
+ }
- if (sms->sms_offset == 0) {
- sms->sms_offset = sbd_find_section_offset(sst, sms);
- if (sms->sms_offset == 0)
- return (STMF_FAILURE);
+ /*
+ * At this point we know that section does not already exist.
+ * find space large enough to hold the section or grow meta if
+ * possible.
+ */
+ 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;
+ }
+ }
+
+ 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;
+ }
}
- sz = sms->sms_size;
- ret = sbd_aligned_meta_read(sst, sms->sms_offset,
- sms->sms_size, (uint8_t *)sms);
- if (ret != STMF_SUCCESS)
+ if (s == 0)
+ return (SBD_ALLOC_FAILURE);
+
+ 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);
- 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 (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);
+ }
+ 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;
+ }
+ }
+ return (ret);
+}
+
+sbd_status_t
+sbd_delete_meta_section(sbd_lu_t *sl, sm_section_hdr_t *sms, uint16_t sms_id)
+{
+ /* 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));
+}
+
+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 (sms->sms_data_order != SMS_DATA_ORDER) {
- /* Adjust byte order of the header */
- sbd_swap_section_hdr(sms, SMS_DATA_ORDER);
+ if (sl->sl_alias) {
+ s += strlen(sl->sl_alias) + 1;
}
+ 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 (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;
+ }
+ 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);
- return (STMF_SUCCESS);
+ 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;
+
+ mutex_exit(&sl->sl_lock);
+ ret = sbd_write_meta_section(sl, (sm_section_hdr_t *)sli);
+ kmem_free(sli, sizeof (*sli) + s);
+ return (ret);
+}
+
+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;
+
+ 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;
+ }
+ lu->lu_lp = sbd_lp;
+ lu->lu_task_alloc = sbd_task_alloc;
+ lu->lu_new_task = sbd_new_task;
+ lu->lu_dbuf_xfer_done = sbd_dbuf_xfer_done;
+ lu->lu_send_status_done = sbd_send_status_done;
+ lu->lu_task_free = sbd_task_free;
+ lu->lu_abort = sbd_abort;
+ lu->lu_ctl = sbd_ctl;
+ lu->lu_info = sbd_info;
+ 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);
+ if (ret == STMF_ALREADY) {
+ *err_ret = SBD_RET_GUID_ALREADY_REGISTERED;
+ }
+ return (EIO);
+ }
+
+ *err_ret = 0;
+ return (0);
}
-stmf_status_t
-sbd_write_section(sbd_store_t *sst, sm_section_hdr_t *sms)
+int
+sbd_open_data_file(sbd_lu_t *sl, uint32_t *err_ret, int lu_size_valid,
+ int vp_valid, int keep_open)
{
- 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);
+ int ret;
+ int flag;
+ ulong_t nbits;
+ uint64_t supported_size;
+ vattr_t vattr;
+ enum vtype vt;
+
+ 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;
}
- 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);
+ }
+ } 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);
+
+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);
+}
- 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);
+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_create_meta(sbd_store_t *sst, sst_init_data_t *sst_idata)
+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_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;
+ 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;
+ }
- /* 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);
+ /* 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;
}
- /* 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);
+ /* 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;
}
/*
- * 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.
+ * 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;
/*
- * meta_size = sizeof (sbd_meta_start_t ) + sizeof (sbd_lu_info_t) +
- * sst_idata->sst_store_meta_data_size;
+ * 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 (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;
+ }
+
+ /* 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;
+
/*
- * for now keep a static 64K for metasize. This should be enough to
- * store metadata as well as any persistent reservations and keys.
+ * 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.
*/
- meta_size = 64 * 1024;
- meta_size = (meta_size + (uint64_t)(b - 1));
- meta_size /= (uint64_t)b;
- meta_size *= (uint64_t)b;
-
+ if (sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) {
+ (void) sbd_wcd_set(1, sl);
+ wcd = 1;
/*
- * 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 not explicitly set, attempt to set it to enable, if that fails
+ * get the current setting and use that
*/
- 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;
+ } else {
+ sret = sbd_wcd_set(0, sl);
+ if (sret != SBD_SUCCESS) {
+ sbd_wcd_get(&wcd, sl);
+ }
}
- /* 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);
+ if (wcd) {
+ sl->sl_flags |= SL_WRITEBACK_CACHE_DISABLE |
+ SL_SAVED_WRITE_CACHE_DISABLE;
+ }
- 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);
+ /* 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);
}
- kmem_free(slu->sl_sli, sizeof (sbd_lu_info_t));
- slu->sl_sli = NULL;
+ 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);
- return (ret);
+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));
}
-/*
- * 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)
+int
+sbd_modify_lu(sbd_modify_lu_t *mlu, int struct_sz, uint32_t *err_ret)
{
- 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;
+ 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 (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;
+ /* 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);
}
/*
- * use a copy here in order not to change anything if
- * sbd_write_section() failed
+ * We'll look for the device but if we don't find it registered,
+ * we'll still try to modify the unregistered device.
*/
- 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;
- }
- 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;
+ 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;
}
- sbd_swap_meta_start(&slu->sl_sm);
}
- slu->sl_meta_offset = meta_offset;
+ 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);
+ }
- 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 (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 (ret != STMF_SUCCESS)
- goto exit_modify_lu;
- if (sli->sli_data_order != SMS_DATA_ORDER) {
- sbd_swap_sli_fields(sli, SMS_DATA_ORDER);
+ 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);
}
}
- 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 (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;
- 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;
+ 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);
}
- mutex_exit(&slu->sl_it_list_lock);
+ return (EIO);
}
-exit_modify_lu:
- kmem_free(sli, sizeof (sbd_lu_info_t));
+ 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);
}
-/*
- * 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_data_read(sbd_lu_t *sl, uint64_t offset, uint64_t size, uint8_t *buf)
{
- 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;
-
- if (slu->sl_sli) {
- cmn_err(CE_PANIC, "sbd_register_sst called with active data "
- " from an existing store");
- }
-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);
+ int ret;
+ long resid;
+
+ if ((offset + size) > sl->sl_lu_size) {
+ return (SBD_IO_PAST_EOF);
}
- 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;
+
+ 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);
}
- 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);
+ store_end = sl->sl_data_readable_size - offset;
+ bzero(buf + store_end, size - store_end);
+ size = store_end;
}
- slu->sl_meta_offset = meta_offset;
- 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_data_order = SMS_DATA_ORDER;
+ 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);
- ret = sbd_read_section(sst, (sm_section_hdr_t *)sli);
+ DTRACE_PROBE5(backing__store__read__end, sbd_lu_t *, sl,
+ uint8_t *, buf, uint64_t, size, uint64_t, offset,
+ int, ret);
- if (ret != STMF_SUCCESS) {
- goto exit_store_online;
+over_sl_data_read:
+ if (ret || resid) {
+ stmf_trace(0, "UIO_READ failed, ret = %d, resid = %d", ret,
+ resid);
+ return (SBD_FAILURE);
}
- if (sli->sli_data_order != SMS_DATA_ORDER) {
- sbd_swap_sli_fields(sli, SMS_DATA_ORDER);
+ 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);
}
- 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;
+ offset += sl->sl_data_offset;
- /* 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;
- lu->lu_dbuf_xfer_done = sbd_dbuf_xfer_done;
- lu->lu_send_status_done = sbd_send_status_done;
- lu->lu_task_free = sbd_task_free;
- lu->lu_abort = sbd_abort;
- lu->lu_ctl = sbd_ctl;
- lu->lu_info = sbd_info;
- slu->sl_state = STMF_STATE_OFFLINE;
+ if ((sl->sl_flags & SL_WRITEBACK_CACHE_DISABLE) &&
+ (sl->sl_flags & SL_FLUSH_ON_DISABLED_WRITECACHE)) {
+ ioflag = FSYNC;
+ } else {
+ ioflag = 0;
+ }
- if ((ret = stmf_register_lu(lu)) != STMF_SUCCESS) {
- stmf_trace(0, "Failed to register with framework, ret=%llx",
- ret);
- goto exit_store_online;
+ 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:
- mutex_enter(&sbd_lock);
- slu->sl_next = sbd_lu_list;
- sbd_lu_list = slu;
- sbd_lu_count++;
- mutex_exit(&sbd_lock);
+ if ((ret || resid) || (sret != SBD_SUCCESS)) {
+ return (SBD_FAILURE);
+ } else if ((offset + size) > sl->sl_data_readable_size) {
+ uint64_t old_size, new_size;
- if (sst_idata) {
- sst_idata->sst_store_size = sli->sli_total_store_size;
- sst_idata->sst_blocksize = sli->sli_blocksize;
+ 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 (STMF_SUCCESS);
-exit_store_online:;
- kmem_free(slu->sl_sli, sizeof (sbd_lu_info_t));
- slu->sl_sli = NULL;
- return (ret);
+ return (SBD_SUCCESS);
}
-stmf_status_t
-sbd_deregister_sst(sbd_store_t *sst)
+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_lu_t *slu = (sbd_lu_t *)sst->sst_sbd_private;
- sbd_lu_t **ppslu;
+ 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);
+ }
- if (slu->sl_state != STMF_STATE_OFFLINE)
- return (STMF_BUSY);
+ 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;
+ }
- if (stmf_deregister_lu(slu->sl_lu) != STMF_SUCCESS)
- return (STMF_BUSY);
+ bzero(oslp, sizeof (*oslp) - 8);
+ oslp->slp_buf_size_needed = sz;
- 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;
+ 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;
}
}
- mutex_exit(&sbd_lock);
- if (slu->sl_sli) {
- kmem_free(slu->sl_sli, sizeof (sbd_lu_info_t));
- slu->sl_sli = NULL;
+ 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;
}
- return (STMF_SUCCESS);
-}
+ 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);
+}
-/*
- * 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.
- */
int
-sbd_is_meta_v0(sbd_store_t *sst, uint64_t *meta_size, uint64_t *meta_offset)
+sbd_path_to_zfs_meta(char *src, char *dst)
{
- sbd_v0_meta_start_t m;
-
- *meta_offset = 4096;
-v0_check:;
- if (sbd_aligned_meta_read(sst, *meta_offset, 16, (uint8_t *)&m) !=
- STMF_SUCCESS) {
+ 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);
+}
- 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);
+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);
}
- *meta_size = m.sm_meta_size;
+ 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);
+}
- return (1);
+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);
}
-int
-sbd_migrate_meta_from_v0_to_v1(sbd_store_t *sst)
+void
+sbd_close_zfs_meta(sbd_lu_t *sl)
{
- 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;
+ 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);
+}
- if (!sbd_is_meta_v0(sst, &v0_meta_size, &v0_meta_offset))
+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;
- 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;
+ if (sl->sl_data_vp->v_type == VREG) {
+ sl->sl_flags |= SL_FLUSH_ON_DISABLED_WRITECACHE;
+ goto done;
}
- 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;
+
+ 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 {
- 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);
+ 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 (sbd_aligned_meta_write(sst, sbd_meta_offset,
- sizeof (*sm) + sizeof (*sli), (uint8_t *)sm) != STMF_SUCCESS) {
- goto mv0v1_exit;
+ if (sl->sl_data_vp->v_type == VREG) {
+ *wcd = 0;
+ return;
}
- ret = 1;
-mv0v1_exit:
- kmem_free(v0sli, sizeof (*v0sli));
- kmem_free(sm, sizeof (*sm) + sizeof (*sli));
+ 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;
+ }
+}
- return (ret);
+
+/*
+ * check for a zvol with sbd metadata object.
+ */
+int
+sbd_is_sbd_zvol(char *path, vnode_t *vp)
+{
+ char zmt[40];
+ vnode_t *zvp;
+
+ if (!sbd_is_zvol(path, vp)) {
+ return (0);
+ }
+ if (!sbd_path_to_zfs_meta(path, zmt)) {
+ return (0);
+ }
+
+ if (lookupname(zmt, UIO_SYSSPACE, FOLLOW, NULLVPP, &zvp) != 0) {
+ return (0);
+ }
+ VN_RELE(zvp);
+ return (1);
}
diff --git a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_impl.h b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_impl.h
index 7c7be6afcf..a9f5c9089d 100644
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_impl.h
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_impl.h
@@ -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 @@ struct sbd_it_data;
#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 @@ typedef struct sm_v0_section_hdr {
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 @@ typedef struct sbd_lu_info {
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 @@ typedef struct sbd_cmd {
#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 @@ typedef struct sbd_it_data {
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 @@ typedef struct sbd_it_data {
*/
#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 @@ 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);
-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
diff --git a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_pgr.c b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_pgr.c
new file mode 100644
index 0000000000..b9d484f95f
--- /dev/null
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_pgr.c
@@ -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);
+}
diff --git a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c
index 462fdc8c52..e62d398e11 100644
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/sbd_scsi.c
@@ -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 @@ void
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 @@ sbd_do_read_xfer(struct scsi_task *task, sbd_cmd_t *scmd,
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 @@ sbd_handle_read(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
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 @@ sbd_handle_read(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
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 @@ sbd_handle_read(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
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 @@ void
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 @@ sbd_handle_write_xfer_completion(struct scsi_task *task, sbd_cmd_t *scmd,
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 @@ sbd_handle_write_xfer_completion(struct scsi_task *task, sbd_cmd_t *scmd,
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 @@ sbd_handle_write(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
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 @@ sbd_handle_write(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
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 @@ sbd_handle_short_read_xfer_completion(struct scsi_task *task, sbd_cmd_t *scmd,
}
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 @@ sbd_handle_read_capacity(struct scsi_task *task,
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 @@ sbd_handle_read_capacity(struct scsi_task *task,
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);
-
- 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);
+ 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;
+
+ 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 (cdb[0] == SCMD_MODE_SENSE) {
+ header_size = 4;
+ dev_spec_param_offset = 2;
+ } else {
+ header_size = 8;
+ dev_spec_param_offset = 3;
+ }
- /*
- * If the buffer is big enough, include the block
- * descriptor; otherwise, leave it out.
- */
- if (cmd_size < ps) {
- dbd = 1;
+ /* 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;
+ }
+
+ /* 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;
+
+ 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;
- if (dbd == 0) {
- ps += 8;
+ 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);
+ }
- break;
- default:
- stmf_scsilib_send_status(task, STATUS_CHECK,
- STMF_SAA_INVALID_FIELD_IN_CDB);
- return;
+ 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;
}
- xfer_size = min(cmd_size, ps);
+ 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 ((xfer_size < hdrsize) || (ctrl == 1) ||
- (((task->task_additional_flags &
- TASK_AF_NO_EXPECTED_XFER_LENGTH) == 0) &&
- (xfer_size > task->task_expected_xfer_length))) {
+ 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;
+ }
- if (p[0] == SCMD_MODE_SENSE) {
- payload_buf[0] = ps - 1;
+ 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 {
- ps -= 2;
- *((uint16_t *)payload_buf) = BE_16(ps);
+ hdr_len = 8;
}
- payload = payload_buf + hdrsize;
+ if (buflen < hdr_len)
+ goto mode_sel_param_len_err;
- switch (page) {
- case 0x03:
- bcopy(sbd_p3, payload, sizeof (sbd_p3));
- break;
+ bd_len = hdr_len == 4 ? buf[3] : READ_SCSI16(&buf[6], int);
- case 0x0A:
- bcopy(sbd_pa, payload, sizeof (sbd_pa));
- break;
+ 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;
+ }
- case MODEPAGE_ALLPAGES:
- if (dbd == 0) {
- payload_buf[3] = sizeof (sbd_bd);
- bcopy(sbd_bd, payload, sizeof (sbd_bd));
- payload += sizeof (sbd_bd);
+ 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;
}
+ }
+
+ sret = SBD_SUCCESS;
+
+ /* 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);
+ }
+
+ if (sret != SBD_SUCCESS) {
+ stmf_scsilib_send_status(task, STATUS_CHECK,
+ STMF_SAA_WRITE_ERROR);
+ return;
+ }
- bcopy(sbd_p3, payload, sizeof (sbd_p3));
- payload += sizeof (sbd_p3);
- bcopy(sbd_pa, payload, sizeof (sbd_pa));
- payload += sizeof (sbd_pa);
- /* FALLTHROUGH */
+ /* 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;
+ }
- case 0x04:
- bcopy(sbd_p4, payload, sizeof (sbd_p4));
+ 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 (s > 1024 * 1024 * 1024) {
- payload[5] = 16;
+ if (task->task_cdb[1] & 1) {
+ if (buf[2] & BIT_2) {
+ sl->sl_flags &= ~SL_SAVED_WRITE_CACHE_DISABLE;
} else {
- payload[5] = 2;
+ sl->sl_flags |= SL_SAVED_WRITE_CACHE_DISABLE;
}
- 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;
-
+ 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;
- sbd_handle_short_read_transfers(task, initial_dbuf, payload_buf,
- cmd_size, xfer_size);
+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 @@ sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf,
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 @@ sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf,
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 @@ sbd_handle_inquiry(struct scsi_task *task, struct stmf_data_buf *initial_dbuf,
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 @@ sbd_task_alloc(struct scsi_task *task)
}
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 @@ sbd_check_and_clear_scsi2_reservation(sbd_lu_t *slu, sbd_it_data_t *it)
* 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 @@ sbd_new_task(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
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 @@ sbd_new_task(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
} 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,17 +1423,6 @@ sbd_new_task(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
cdb0 = task->task_cdb[0];
cdb1 = task->task_cdb[1];
- if (cdb0 == SCMD_TEST_UNIT_READY) { /* Test unit ready */
- task->task_cmd_xfer_length = 0;
- stmf_scsilib_send_status(task, STATUS_GOOD, 0);
- return;
- }
-
- if (cdb0 == SCMD_READ_CAPACITY) { /* Read Capacity */
- sbd_handle_read_capacity(task, initial_dbuf);
- return;
- }
-
if (cdb0 == SCMD_INQUIRY) { /* Inquiry */
uint8_t *p;
@@ -1092,42 +1432,63 @@ sbd_new_task(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
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);
- return;
- /*
- * } else if (cdb1 == SSVC_ACTION_READ_LONG_G4) {
- * sbd_handle_read(task, initial_dbuf);
- * return;
- */
- }
+ if (cdb0 == SCMD_PERSISTENT_RESERVE_OUT) {
+ sbd_handle_pgr_out_cmd(task, initial_dbuf);
+ return;
}
- /*
- * if (cdb0 == SCMD_SVC_ACTION_OUT_G4) {
- * if (cdb1 == SSVC_ACTION_WRITE_LONG_G4) {
- * sbd_handle_write(task, initial_dbuf);
- * return;
- * }
- * }
- */
-
- 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);
+ if (cdb0 == SCMD_PERSISTENT_RESERVE_IN) {
+ sbd_handle_pgr_in_cmd(task, initial_dbuf);
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);
+
+ 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;
}
-#endif
- if ((cdb0 == SCMD_MODE_SENSE) || (cdb0 == SCMD_MODE_SENSE_G1)) {
- sbd_handle_mode_sense(task, initial_dbuf);
+
+ 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;
}
@@ -1149,49 +1510,80 @@ sbd_new_task(struct scsi_task *task, struct stmf_data_buf *initial_dbuf)
return;
}
- if (cdb0 == SCMD_VERIFY) {
- /*
- * Something more likely needs to be done here.
- */
- task->task_cmd_xfer_length = 0;
- stmf_scsilib_send_status(task, STATUS_GOOD, 0);
+ /* Report Target Port Groups */
+ if ((cdb0 == SCMD_MAINTENANCE_IN) &&
+ ((cdb1 & 0x1F) == 0x0A)) {
+ stmf_scsilib_handle_report_tpgs(task, initial_dbuf);
return;
}
- if ((cdb0 == SCMD_RESERVE) || (cdb0 == SCMD_RELEASE)) {
- if (cdb1) {
+ 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;
}
- 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 (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_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);
+ 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);
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);
+
+ if (cdb0 == SCMD_READ_CAPACITY) { /* Read Capacity */
+ sbd_handle_read_capacity(task, initial_dbuf);
+ 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);
+ return;
+ /*
+ * } else if (cdb1 == SSVC_ACTION_READ_LONG_G4) {
+ * sbd_handle_read(task, initial_dbuf);
+ * return;
+ */
+ }
+ }
+
+ /*
+ * if (cdb0 == SCMD_SVC_ACTION_OUT_G4) {
+ * if (cdb1 == SSVC_ACTION_WRITE_LONG_G4) {
+ * sbd_handle_write(task, initial_dbuf);
+ * return;
+ * }
+ * }
+ */
+
+ if (cdb0 == SCMD_VERIFY) {
+ /*
+ * Something more likely needs to be done here.
+ */
+ task->task_cmd_xfer_length = 0;
stmf_scsilib_send_status(task, STATUS_GOOD, 0);
return;
}
@@ -1202,13 +1594,6 @@ sbd_new_task(struct scsi_task *task, struct stmf_data_buf *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 @@ sbd_dbuf_xfer_done(struct scsi_task *task, struct stmf_data_buf *dbuf)
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 @@ sbd_task_free(struct scsi_task *task)
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 @@ sbd_abort(struct stmf_lu *lu, int abort_cmd, void *arg, uint32_t flags)
}
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 @@ 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)
{
- 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 @@ sbd_ctl(struct stmf_lu *lu, int cmd, void *arg)
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 @@ sbd_ctl(struct stmf_lu *lu, int cmd, void *arg)
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 @@ sbd_ctl(struct stmf_lu *lu, int cmd, void *arg)
/* 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 @@ sbd_info(uint32_t cmd, stmf_lu_t *lu, void *arg, uint8_t *buf,
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 @@ sbd_handle_sync_cache(struct scsi_task *task,
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;
diff --git a/usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h b/usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h
index 344fe4a105..392a597d31 100644
--- a/usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h
+++ b/usr/src/uts/common/io/comstar/lu/stmf_sbd/stmf_sbd.h
@@ -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;
-
- 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);
-
- 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);
-
- 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 */
+#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
+
+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;
+
+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 */
/*
- * This is the metadat for the store implementation itself
- * that needs to be persisted.
+ * 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.
*/
- uint64_t sst_store_meta_data_size;
+ uint16_t sli_meta_fname_offset;
- /* This is returned to the caller */
- uint8_t sst_guid[16];
+ /*
+ * 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];
- uint32_t sst_flags;
- uint16_t sst_blocksize; /* To expose to initiators */
-} sst_init_data_t;
+ /*
+ * 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.
+ */
+ 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
-
-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);
+#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;
+
+ /* 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
}
diff --git a/usr/src/uts/common/io/comstar/port/fct/fct.c b/usr/src/uts/common/io/comstar/port/fct/fct.c
index 67a10b31cd..4d27a76b1c 100644
--- a/usr/src/uts/common/io/comstar/port/fct/fct.c
+++ b/usr/src/uts/common/io/comstar/port/fct/fct.c
@@ -152,7 +152,7 @@ fct_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
*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 @@ fct_post_to_discovery_queue(fct_i_local_port_t *iport,
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 @@ fct_q_for_termination_lock_held(fct_i_local_port_t *iport, fct_i_cmd_t *icmd,
for (ppicmd = &(iport->iport_abort_queue); *ppicmd != NULL;
ppicmd = &((*ppicmd)->icmd_next))
;
+ }
*ppicmd = icmd;
}
diff --git a/usr/src/uts/common/io/comstar/stmf/stmf.c b/usr/src/uts/common/io/comstar/stmf/stmf.c
index d416098e6c..f21444f3ee 100644
--- a/usr/src/uts/common/io/comstar/stmf/stmf.c
+++ b/usr/src/uts/common/io/comstar/stmf/stmf.c
@@ -73,8 +73,11 @@ void stmf_target_reset_poll(struct scsi_task *task);
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 @@ stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
*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 @@ stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
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_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
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 @@ stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
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 @@ stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
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 @@ stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
&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 @@ stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
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 @@ stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
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++;
+ }
+ }
+ mutex_exit(&stmf_state.stmf_lock);
+ break;
+
+ 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)
- break;
+ 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++;
}
- if (iocd->stmf_obuf_nentries >= n)
- break;
+ break;
}
mutex_exit(&stmf_state.stmf_lock);
break;
-#endif
+
case STMF_IOCTL_LOAD_PP_DATA:
if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) {
ret = EACCES;
@@ -1034,7 +1154,35 @@ stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
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 @@ stmf_deregister_port_provider(stmf_port_provider_t *pp)
}
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 @@ stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi)
int s;
int ret;
+ *err_ret = 0;
+
if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) {
return (EINVAL);
}
@@ -1638,6 +1789,19 @@ stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi)
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 @@ stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi)
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 @@ stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi)
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 @@ stmf_prepare_tpgs_data()
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 @@ stmf_scsilib_uniq_lu_id(uint32_t company_id, scsi_devid_desc_t *lu_id)
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;
diff --git a/usr/src/uts/common/io/comstar/stmf/stmf_impl.h b/usr/src/uts/common/io/comstar/stmf/stmf_impl.h
index 9cc2d01c6d..2947f5c4f8 100644
--- a/usr/src/uts/common/io/comstar/stmf/stmf_impl.h
+++ b/usr/src/uts/common/io/comstar/stmf/stmf_impl.h
@@ -262,6 +262,7 @@ typedef struct stmf_pp_data {
ppd_port_provider:1,
ppd_rsvd:30;
uint32_t ppd_alloc_size;
+ uint64_t ppd_token;
char ppd_name[8];
} stmf_pp_data_t;
diff --git a/usr/src/uts/common/sys/scsi/generic/persist.h b/usr/src/uts/common/sys/scsi/generic/persist.h
index 3c3a2cd964..b5d62dd451 100644
--- a/usr/src/uts/common/sys/scsi/generic/persist.h
+++ b/usr/src/uts/common/sys/scsi/generic/persist.h
@@ -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 @@ typedef struct scsi_prin_rpt_cap {
} scsi_prin_rpt_cap_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
+ * 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];
-} scsi_transport_id_t;
+} 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_prin_status_t {
uint8_t reservation_key[8];
uint8_t resbytes1[4];
@@ -221,6 +242,24 @@ typedef struct scsi_prout_plist {
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 @@ typedef struct scsi_prin_rpt_cap {
} scsi_prin_rpt_cap_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
+ * 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];
-} scsi_transport_id_t;
+} 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_prin_status_t {
uint8_t reservation_key[8];
uint8_t resbytes1[4];
@@ -363,6 +425,24 @@ typedef struct scsi_prout_plist {
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 */
diff --git a/usr/src/uts/common/sys/stmf.h b/usr/src/uts/common/sys/stmf.h
index 1159cc13b1..199409fd16 100644
--- a/usr/src/uts/common/sys/stmf.h
+++ b/usr/src/uts/common/sys/stmf.h
@@ -374,6 +374,8 @@ stmf_status_t stmf_scsilib_uniq_lu_id(uint32_t company_id,
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);
diff --git a/usr/src/uts/common/sys/stmf_defines.h b/usr/src/uts/common/sys/stmf_defines.h
index 0adbf326e4..75d404ffec 100644
--- a/usr/src/uts/common/sys/stmf_defines.h
+++ b/usr/src/uts/common/sys/stmf_defines.h
@@ -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 @@ typedef uint64_t stmf_status_t;
/*
* 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;
diff --git a/usr/src/uts/common/sys/stmf_ioctl.h b/usr/src/uts/common/sys/stmf_ioctl.h
index 2ae8597a2e..727cb6ff5a 100644
--- a/usr/src/uts/common/sys/stmf_ioctl.h
+++ b/usr/src/uts/common/sys/stmf_ioctl.h
@@ -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 @@ extern "C" {
#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 @@ typedef struct stmf_state_desc {
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 @@ typedef struct stmf_state_desc {
#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 @@ typedef struct stmf_group_name {
/*
* 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 @@ typedef struct stmf_ppioctl_data {
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;
diff --git a/usr/src/uts/common/sys/stmf_sbd_ioctl.h b/usr/src/uts/common/sys/stmf_sbd_ioctl.h
index ce086262d8..214994502b 100644
--- a/usr/src/uts/common/sys/stmf_sbd_ioctl.h
+++ b/usr/src/uts/common/sys/stmf_sbd_ioctl.h
@@ -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)
+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,
-#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)
+ SBD_RET_MAX_VAL
+} sbd_ret_t;
-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;
+#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,
+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;
- RLC_RET_MAX_VAL
-} rlc_ret_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 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;
+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 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_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 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_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
}