diff options
Diffstat (limited to 'usr/src')
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 } |