diff options
Diffstat (limited to 'usr/src/cmd/isns/isnsd/dd.c')
| -rw-r--r-- | usr/src/cmd/isns/isnsd/dd.c | 1855 |
1 files changed, 1855 insertions, 0 deletions
diff --git a/usr/src/cmd/isns/isnsd/dd.c b/usr/src/cmd/isns/isnsd/dd.c new file mode 100644 index 0000000000..039ca4b77a --- /dev/null +++ b/usr/src/cmd/isns/isnsd/dd.c @@ -0,0 +1,1855 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "isns_server.h" +#include "isns_msgq.h" +#include "isns_htab.h" +#include "isns_dd.h" +#include "isns_cache.h" +#include "isns_obj.h" +#include "isns_pdu.h" +#include "isns_dseng.h" +#include "isns_scn.h" +#include "isns_utils.h" + +/* + * extern global variables + */ +extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE]; + +extern msg_queue_t *sys_q; +extern msg_queue_t *scn_q; + +extern int cache_flag; + +/* + * extern functions. + */ + +/* + * global variables + */ + +/* + * local variables + */ + +/* + * local functions. + */ +static matrix_t *new_matrix(uint32_t, uint32_t); + +static int +cb_update_ds_attr( + void *p1, + void *p2 +) +{ + int ec = 0; + + isns_obj_t *obj = (isns_obj_t *)p1; + lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; + uint32_t tag = lcp->id[1]; + uint32_t which; + isns_attr_t *attr; + + uint32_t len; + uchar_t *name; + lookup_ctrl_t lc; + uint32_t uid; + + switch (tag) { + case ISNS_DD_NAME_ATTR_ID: + which = ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID); + break; + case ISNS_DD_FEATURES_ATTR_ID: + which = ATTR_INDEX_DD(ISNS_DD_FEATURES_ATTR_ID); + break; + case ISNS_DD_SET_NAME_ATTR_ID: + which = ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID); + break; + case ISNS_DD_SET_STATUS_ATTR_ID: + which = ATTR_INDEX_DDS(ISNS_DD_SET_STATUS_ATTR_ID); + break; + default: + ASSERT(0); + break; + } + + attr = &obj->attrs[which]; + + switch (tag) { + case ISNS_DD_NAME_ATTR_ID: + case ISNS_DD_SET_NAME_ATTR_ID: + len = lcp->data[1].ui; + name = lcp->data[2].ptr; + lc.type = lcp->type; + lc.curr_uid = 0; + lc.id[0] = which; + lc.op[0] = OP_STRING; + lc.data[0].ptr = name; + lc.op[1] = 0; + /* check if the name is in use */ + uid = is_obj_there(&lc); + if (uid != 0) { + if (uid != get_obj_uid(obj)) { + ec = ERR_NAME_IN_USE; + } + return (ec); + } + if (len > attr->len) { + uchar_t *tmp = (uchar_t *)malloc(len); + if (tmp != NULL) { + free(attr->value.ptr); + attr->value.ptr = tmp; + } else { + /* memory exhausted */ + return (ISNS_RSP_INTERNAL_ERROR); + } + } + (void) strcpy((char *)attr->value.ptr, (char *)name); + attr->len = len; + break; + case ISNS_DD_FEATURES_ATTR_ID: + case ISNS_DD_SET_STATUS_ATTR_ID: + if (attr->tag != tag || + attr->value.ui != lcp->data[1].ui) { + attr->tag = tag; + attr->len = 4; + attr->value.ui = lcp->data[1].ui; + } else { + return (ec); + } + break; + } + + /* cache has been updated, set the flag */ + SET_CACHE_UPDATED(); + + /* update data store */ + if (sys_q != NULL) { + ec = write_data(DATA_UPDATE, obj); + } + + return (ec); +} + +static isns_obj_t * +make_member_node( + const uint32_t uid, + isns_attr_t *attr1 +) +{ + isns_obj_t *obj = NULL; + isns_attr_t *attr; + isns_attr_t tmp; + + switch (attr1->tag) { + case ISNS_DD_ISCSI_NAME_ATTR_ID: + obj = obj_calloc(OBJ_ISCSI); + attr = &obj->attrs[ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID)]; + tmp.tag = ISNS_ISCSI_NAME_ATTR_ID; + tmp.len = attr1->len; + tmp.value.ptr = attr1->value.ptr; + if (assign_attr(attr, &tmp) != 0) { + free_object(obj); + obj = NULL; + } else if (uid != 0) { + (void) set_obj_uid(obj, uid); + } + break; + default: + ASSERT(0); + break; + } + + return (obj); +} + +static isns_obj_t * +make_member_dd( + const uint32_t uid +) +{ + isns_obj_t *obj = NULL; + isns_attr_t name = { 0 }; + + obj = obj_calloc(OBJ_DD); + if (obj != NULL) { + (void) set_obj_uid(obj, uid); + name.tag = ISNS_DD_NAME_ATTR_ID; + if (assign_attr( + &obj->attrs[ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID)], + &name) != 0) { + free_object(obj); + obj = NULL; + } + } + + return (obj); +} + +static int +get_member_info( + isns_obj_t *assoc, + uint32_t *m_type, + uint32_t *m_id, + int flag +) +{ + int ec = 0; + lookup_ctrl_t lc = { 0 }; + + isns_obj_t *obj; + isns_attr_t *attr1, *attr2; + uint32_t tmp_id = 0; + int i = 0; + + *m_type = 0; + *m_id = 0; + + attr1 = &assoc->attrs[ATTR_INDEX_ASSOC_ISCSI( + ISNS_DD_ISCSI_INDEX_ATTR_ID)]; + attr2 = &assoc->attrs[ATTR_INDEX_ASSOC_ISCSI( + ISNS_DD_ISCSI_NAME_ATTR_ID)]; + + lc.type = OBJ_ISCSI; + if (attr1->tag != 0 && attr1->value.ui != 0) { + *m_id = attr1->value.ui; + lc.id[i] = UID_ATTR_INDEX[OBJ_ISCSI]; + lc.op[i] = OP_INTEGER; + lc.data[i].ui = *m_id; + i ++; + } + if (attr2->tag != 0) { + lc.id[i] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID); + lc.op[i] = OP_STRING; + lc.data[i].ptr = attr2->value.ptr; + i ++; + } else if (scn_q != NULL || sys_q != NULL) { + lc.id[i] = ISNS_ISCSI_NAME_ATTR_ID; + } + + /* a member id or member name is required */ + if (i == 0) { + if (flag != 0) { + /* add member */ + return (ISNS_RSP_INVALID_REGIS); + } else { + /* remove member (isnsp msg request only) */ + return (0); + } + } + + ec = cache_lookup(&lc, &tmp_id, cb_clone_attrs); + + if (ec == 0 && tmp_id == 0) { + if (flag != 0) { + /* add member */ + if (attr1->tag == 0 || sys_q == NULL) { + /* object does not exist, create one */ + obj = make_member_node(*m_id, attr2); + if (obj == NULL) { + ec = ISNS_RSP_INTERNAL_ERROR; + } else { + ec = register_assoc(obj, &tmp_id); + if (ec != 0) { + free_object(obj); + } + } + } else { + /* don't create it if uid is specified */ + ec = ISNS_RSP_NO_SUCH_ENTRY; + } + } else { + /* remove member */ + ec = ERR_NO_SUCH_ASSOCIATION; + } + } + + if (attr1->tag == 0) { + attr1->tag = ISNS_DD_ISCSI_INDEX_ATTR_ID; + attr1->len = 4; + attr1->value.ui = tmp_id; + } else if (attr2->tag == 0) { + attr2->tag = ISNS_DD_ISCSI_NAME_ATTR_ID; + attr2->len = strlen((char *)lc.data[1].ptr); + attr2->len += 4 - (attr2->len % 4); + attr2->value.ptr = lc.data[1].ptr; + } + + *m_type = OBJ_ISCSI; + *m_id = tmp_id; + + return (ec); +} + +static int +get_dds_member_info( + uint32_t m_id +) +{ + int ec = 0; + lookup_ctrl_t lc; + + isns_obj_t *obj; + uint32_t tmp_id; + + if (m_id != 0) { + SET_UID_LCP(&lc, OBJ_DD, m_id); + } else { + return (ISNS_RSP_INVALID_REGIS); + } + + tmp_id = is_obj_there(&lc); + + if (tmp_id == 0) { + /* object does not exist, create one */ + obj = make_member_dd(m_id); + if (obj != NULL) { + ec = register_object(obj, NULL, NULL); + } else { + /* no memory */ + ec = ISNS_RSP_INTERNAL_ERROR; + } + } + + return (ec); +} + +static int +update_matrix( + matrix_t *matrix, + const uchar_t op, + const uint32_t puid, + const uint32_t m_id, + int ddd_flag +) +{ + int ec = 0; + + uint32_t new_x = 0, new_y = 0; + matrix_t *tmp_matrix; + + uint32_t i, j, k = 0; + uint32_t x_info; + bmp_t *bmp, *tmp_bmp; + + uint32_t primary = GET_PRIMARY(m_id); + uint32_t second = GET_SECOND(m_id); + + if (primary >= matrix->x) { + if (op == '-') { + ec = ERR_NO_SUCH_ASSOCIATION; + goto update_matrix_done; + } + /* enlarge the matrix on x axis */ + if (primary >= matrix->x * 2) { + new_x = primary + 1; + } else { + new_x = matrix->x * 2; + } + } + + i = 0; + while (i < matrix->y) { + bmp = MATRIX_X_UNIT(matrix, i); + x_info = MATRIX_X_INFO(bmp); + if (x_info == puid) { + break; + } else if (x_info == 0 && k == 0) { + /* the first available slot */ + k = i; + } + i ++; + } + if (i == matrix->y) { + if (op == '-') { + ec = ERR_NO_SUCH_ASSOCIATION; + goto update_matrix_done; + } else if (k == 0) { + new_y = matrix->y * 2; + } else { + i = k; + } + } + + /* + * enlarge the matrix. + */ + if (new_x != 0 || new_y != 0) { + if (new_x == 0) { + new_x = matrix->x; + } + if (new_y == 0) { + new_y = matrix->y; + } + tmp_matrix = new_matrix(new_x, new_y); + if (tmp_matrix != NULL) { + j = 0; + while (j < matrix->y) { + bmp = MATRIX_X_UNIT(matrix, j); + x_info = MATRIX_X_INFO(bmp); + if (x_info != 0) { + tmp_bmp = MATRIX_X_UNIT(tmp_matrix, j); + (void) memcpy((void *)tmp_bmp, + (void *)bmp, SIZEOF_X_UNIT(matrix)); + } + j ++; + } + free(matrix->m); + matrix->x = tmp_matrix->x; + matrix->y = tmp_matrix->y; + matrix->m = tmp_matrix->m; + free(tmp_matrix); + } else { + ec = ISNS_RSP_INTERNAL_ERROR; + goto update_matrix_done; + } + } + + bmp = MATRIX_X_UNIT(matrix, i); + + MATRIX_X_INFO(bmp) = puid; + if (op == '+') { + if (TEST_MEMBERSHIP(bmp, primary, second) == 0) { + SET_MEMBERSHIP(bmp, primary, second); + SET_CACHE_UPDATED(); + if (ddd_flag != 0) { + bmp = MATRIX_X_UNIT(matrix, 0); + ASSERT(MATRIX_X_INFO(bmp) == + ISNS_DEFAULT_DD_ID); + CLEAR_MEMBERSHIP(bmp, primary, second); + } + } else { + ec = ERR_ALREADY_ASSOCIATED; + } + } else if (op == '-') { + if (TEST_MEMBERSHIP(bmp, primary, second) != 0) { + CLEAR_MEMBERSHIP(bmp, primary, second); + SET_CACHE_UPDATED(); + if (ddd_flag != 0) { + i = 1; + while (i < matrix->y) { + bmp = MATRIX_X_UNIT(matrix, i); + x_info = MATRIX_X_INFO(bmp); + if (x_info != 0 && + TEST_MEMBERSHIP(bmp, + primary, second) != 0) { + break; + } + i ++; + } + if (i == matrix->y) { + bmp = MATRIX_X_UNIT(matrix, 0); + ASSERT(MATRIX_X_INFO(bmp) == + ISNS_DEFAULT_DD_ID); + SET_MEMBERSHIP(bmp, primary, second); + } + } + } else { + ec = ERR_NO_SUCH_ASSOCIATION; + } + } + +update_matrix_done: + return (ec); +} + +/*ARGSUSED*/ +static int +update_dd_matrix( + const uchar_t op, + const uint32_t dd_id, + const uint32_t m_type, + const uint32_t m_id +) +{ + matrix_t *matrix; + + ASSERT(m_type == OBJ_ISCSI); + + matrix = cache_get_matrix(OBJ_DD); + + return (update_matrix(matrix, op, dd_id, m_id, 1)); +} + +static int +update_dds_matrix( + const uchar_t op, + const uint32_t dds_id, + const uint32_t m_id +) +{ + matrix_t *dds_matrix = cache_get_matrix(OBJ_DDS); + + return (update_matrix(dds_matrix, op, dds_id, m_id, 0)); +} + +static int +clear_matrix( + matrix_t *matrix, + const uint32_t uid, + bmp_t **p, + uint32_t *n, + int ddd_flag +) +{ + int ec = 0; + bmp_t *bmp; + uint32_t x_info; + int i, j; + + uint32_t primary; + uint32_t second; + + if (p != NULL) { + *p = NULL; + *n = 0; + } + + i = 0; + while (i < matrix->y) { + bmp = MATRIX_X_UNIT(matrix, i); + x_info = MATRIX_X_INFO(bmp); + if (x_info == uid) { + if (p != NULL) { + /* dup it for caller */ + *n = matrix->x; + *p = (bmp_t *)malloc(*n * sizeof (bmp_t)); + if (*p != NULL) { + (void) memcpy(*p, &bmp[MATRIX_X_HEADER], + *n * sizeof (bmp_t)); + } else { + ec = ISNS_RSP_INTERNAL_ERROR; + } + } + /* clean it */ + (void) memset(bmp, 0, SIZEOF_X_UNIT(matrix)); + break; + } + i ++; + } + + if (ddd_flag != 0 && p != NULL) { + bmp = MATRIX_X_UNIT(matrix, 0); + ASSERT(MATRIX_X_INFO(bmp) == ISNS_DEFAULT_DD_ID); + /* Test the membership for each node which is a */ + /* member in the dd that is being deleted. */ + FOR_EACH_MEMBER(*p, *n, i, { + j = get_dd_id(i, 0); + if (j == 0) { + /* put it to the default dd */ + primary = GET_PRIMARY(i); + second = GET_SECOND(i); + SET_MEMBERSHIP(bmp, primary, second); + } + }); + } + + return (ec); +} + +static int +get_matrix( + matrix_t *matrix, + const uint32_t uid, + bmp_t **p, + uint32_t *n +) +{ + int ec = 0; + bmp_t *bmp; + uint32_t x_info; + int i; + + *n = 0; + *p = NULL; + + i = 0; + while (i < matrix->y) { + bmp = MATRIX_X_UNIT(matrix, i); + x_info = MATRIX_X_INFO(bmp); + if (x_info == uid) { + /* dup it for caller */ + *n = matrix->x; + *p = (bmp_t *)malloc(*n * sizeof (bmp_t)); + if (*p != NULL) { + (void) memcpy(*p, &bmp[MATRIX_X_HEADER], + *n * sizeof (bmp_t)); + } else { + *n = 0; + ec = ISNS_RSP_INTERNAL_ERROR; + } + break; + } + i ++; + } + + return (ec); +} + +static int +clear_dd_matrix( + const uint32_t dd_id, + bmp_t **p, + uint32_t *n +) +{ + matrix_t *matrix = cache_get_matrix(OBJ_DD); + + return (clear_matrix(matrix, dd_id, p, n, 1)); +} + +static int +clear_dds_matrix( + const uint32_t dds_id +) +{ + matrix_t *matrix = cache_get_matrix(OBJ_DDS); + + return (clear_matrix(matrix, dds_id, NULL, NULL, 0)); +} + +int +get_dd_matrix( + const uint32_t dd_id, + bmp_t **p, + uint32_t *n +) +{ + matrix_t *matrix = cache_get_matrix(OBJ_DD); + + return (get_matrix(matrix, dd_id, p, n)); +} + +int +get_dds_matrix( + const uint32_t dds_id, + bmp_t **p, + uint32_t *n +) +{ + matrix_t *matrix = cache_get_matrix(OBJ_DDS); + + return (get_matrix(matrix, dds_id, p, n)); +} + +/*ARGSUSED*/ +static int +cb_get_dds_status( + void *p1, + void *p2 +) +{ + isns_obj_t *obj = (isns_obj_t *)p1; + + isns_attr_t *attr = &obj->attrs[ + ATTR_INDEX_DDS(ISNS_DD_SET_STATUS_ATTR_ID)]; + + return (DDS_ENABLED(attr->value.ui) ? 1 : 0); +} + +static int +get_dds_status( + uint32_t dds_id +) +{ + lookup_ctrl_t lc; + + if (dds_id == 0) { + return (0); + } + + SET_UID_LCP(&lc, OBJ_DDS, dds_id); + + return (cache_lookup(&lc, NULL, cb_get_dds_status)); +} + +int +is_dd_active( + uint32_t dd_id +) +{ + int active = 0; + + matrix_t *dds_matrix; + uint32_t primary; + uint32_t second; + uint32_t x_info; + bmp_t *bmp; + int i; + + if (dd_id == 0) { + return (active); + } + + dds_matrix = cache_get_matrix(OBJ_DDS); + primary = GET_PRIMARY(dd_id); + second = GET_SECOND(dd_id); + + if (primary < dds_matrix->x) { + i = 0; + while (i < dds_matrix->y) { + bmp = MATRIX_X_UNIT(dds_matrix, i); + x_info = MATRIX_X_INFO(bmp); + if (x_info != 0 && + TEST_MEMBERSHIP(bmp, primary, second) != 0) { + if (get_dds_status(x_info) != 0) { + active = 1; + break; + } + } + i ++; + } + } + + return (active); +} + +int +get_scope( + uchar_t *node_name, + bmp_t **p, + uint32_t *n +) +{ + int ec = 0; + + lookup_ctrl_t lc; + uint32_t uid; + + matrix_t *dd_matrix; + uint32_t primary; + uint32_t second; + uint32_t x_info; + bmp_t *bmp; + int i, j; + + bmp_t *tmp_p; + uint32_t tmp_n; + + bmp_t *short_p; + uint32_t short_n; + + /* clear it */ + *p = NULL; + *n = 0; + + /* get the source object uid */ + lc.curr_uid = 0; + lc.type = OBJ_ISCSI; + lc.id[0] = ATTR_INDEX_ISCSI(ISNS_ISCSI_NAME_ATTR_ID); + lc.op[0] = OP_STRING; + lc.data[0].ptr = node_name; + lc.op[1] = 0; + + uid = is_obj_there(&lc); + + /* no such object */ + if (uid == 0) { + return (ec); + } + + dd_matrix = cache_get_matrix(OBJ_DD); + primary = GET_PRIMARY(uid); + second = GET_SECOND(uid); + + if (primary < dd_matrix->x) { + i = 0; + while (i < dd_matrix->y) { + bmp = MATRIX_X_UNIT(dd_matrix, i); + x_info = MATRIX_X_INFO(bmp); + if (ec == 0 && x_info != 0 && + TEST_MEMBERSHIP(bmp, primary, second) != 0) { + if (is_dd_active(x_info) != 0 && + (ec = get_dd_matrix(x_info, + &tmp_p, &tmp_n)) == 0) { + if (*p == NULL) { + *p = tmp_p; + *n = tmp_n; + } else { + if (*n >= tmp_n) { + short_p = tmp_p; + short_n = tmp_n; + } else { + short_p = *p; + short_n = *n; + *p = tmp_p; + *n = tmp_n; + } + j = 0; + while (j < short_n) { + (*p)[j] |= short_p[j]; + j ++; + } + free(short_p); + } + } + } + i ++; + } + } + + primary ++; + if (ec == 0 && *p == NULL) { + *p = (bmp_t *)calloc(primary, sizeof (bmp_t)); + if (*p != NULL) { + *n = primary; + } else { + *n = 0; + ec = ISNS_RSP_INTERNAL_ERROR; + } + } + + if (*p != NULL) { + (*p)[primary - 1] |= (1 << second); + } + + return (ec); +} + +int +cb_clone_attrs( + void *p1, + void *p2 +) +{ + int ec = 0; + + isns_obj_t *obj = (isns_obj_t *)p1; + lookup_ctrl_t *lcp = (lookup_ctrl_t *)p2; + + isns_attr_t *attr; + + int i = 1; + + while (i < MAX_LOOKUP_CTRL && + lcp->op[i] != 0) { + i ++; + } + + while (ec == 0 && + i < MAX_LOOKUP_CTRL && + lcp->id[i] != 0) { + switch (lcp->id[i]) { + case ISNS_ISCSI_NAME_ATTR_ID: + attr = &obj->attrs[ATTR_INDEX_ISCSI( + ISNS_ISCSI_NAME_ATTR_ID)]; + lcp->data[i].ptr = (uchar_t *)malloc(attr->len); + if (lcp->data[i].ptr != NULL) { + (void) strcpy((char *)lcp->data[i].ptr, + (char *)attr->value.ptr); + } else { + /* memory exhausted */ + ec = ISNS_RSP_INTERNAL_ERROR; + } + break; + case ISNS_ISCSI_NODE_TYPE_ATTR_ID: + attr = &obj->attrs[ATTR_INDEX_ISCSI( + ISNS_ISCSI_NODE_TYPE_ATTR_ID)]; + lcp->data[i].ui = attr->value.ui; + break; + case ISNS_PG_ISCSI_NAME_ATTR_ID: + attr = &obj->attrs[ATTR_INDEX_PG( + ISNS_PG_ISCSI_NAME_ATTR_ID)]; + lcp->data[i].ptr = (uchar_t *)malloc(attr->len); + if (lcp->data[i].ptr != NULL) { + (void) strcpy((char *)lcp->data[i].ptr, + (char *)attr->value.ptr); + } else { + /* memory exhausted */ + ec = ISNS_RSP_INTERNAL_ERROR; + } + break; + case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: + attr = &obj->attrs[ATTR_INDEX_PG( + ISNS_PG_PORTAL_IP_ADDR_ATTR_ID)]; + lcp->data[i].ip = (in6_addr_t *)malloc(attr->len); + if (lcp->data[i].ip != NULL) { + (void) memcpy(lcp->data[i].ip, + attr->value.ip, attr->len); + } else { + /* memory exhausted */ + ec = ISNS_RSP_INTERNAL_ERROR; + } + break; + case ISNS_PG_PORTAL_PORT_ATTR_ID: + attr = &obj->attrs[ATTR_INDEX_PG( + ISNS_PG_PORTAL_PORT_ATTR_ID)]; + lcp->data[i].ui = attr->value.ui; + break; + case ISNS_PORTAL_IP_ADDR_ATTR_ID: + attr = &obj->attrs[ATTR_INDEX_PORTAL( + ISNS_PORTAL_IP_ADDR_ATTR_ID)]; + lcp->data[i].ip = (in6_addr_t *)malloc(attr->len); + if (lcp->data[i].ip != NULL) { + (void) memcpy(lcp->data[i].ip, + attr->value.ip, attr->len); + } else { + /* memory exhausted */ + ec = ISNS_RSP_INTERNAL_ERROR; + } + break; + case ISNS_PORTAL_PORT_ATTR_ID: + case ISNS_ESI_PORT_ATTR_ID: + attr = &obj->attrs[ATTR_INDEX_PORTAL(lcp->id[i])]; + if (attr->tag != 0 && attr->value.ui != 0) { + lcp->data[i].ui = attr->value.ui; + } else { + lcp->data[i].ui = 0; + } + break; + default: + ASSERT(0); + lcp->data[i].ui = 0; + break; + } + i ++; + } + + return (ec); +} + +static matrix_t * +new_matrix( + uint32_t x, + uint32_t y +) +{ + matrix_t *matrix; + + matrix = (matrix_t *)malloc(sizeof (matrix_t)); + if (matrix != NULL) { + matrix->x = x; + matrix->y = y; + matrix->m = (bmp_t *)calloc(y, SIZEOF_X_UNIT(matrix)); + if (matrix->m == NULL) { + free(matrix); + matrix = NULL; + } + } + + return (matrix); +} + +int +dd_matrix_init( + struct cache *c +) +{ + matrix_t *x; + bmp_t *bmp; + uint32_t primary; + uint32_t second; + + /* + * allocate an array of pointer for dd and dd-set matrix. + */ + c->x = (matrix_t **)calloc(2, sizeof (matrix_t *)); + if (c->x == NULL) { + return (1); + } + + /* + * create dd matrix. + */ + x = new_matrix(8, 64); + if (x != NULL) { + x->c = c; + c->x[0] = x; + } else { + return (1); + } + + /* + * Mark the first array on the y axis for Default DD. + */ + bmp = MATRIX_X_UNIT(x, 0); + MATRIX_X_INFO(bmp) = ISNS_DEFAULT_DD_ID; + + /* + * create dd set matrix. + */ + x = new_matrix(2, 16); + if (x != NULL) { + x->c = c; + c->x[1] = x; + } else { + return (1); + } + + /* + * Mark the first array on the y axis for Default DD-set. + */ + bmp = MATRIX_X_UNIT(x, 0); + MATRIX_X_INFO(bmp) = ISNS_DEFAULT_DD_SET_ID; + + /* + * Add Default DD as a member of Default DD-set. + */ + primary = GET_PRIMARY(ISNS_DEFAULT_DD_ID); + second = GET_SECOND(ISNS_DEFAULT_DD_ID); + SET_MEMBERSHIP(bmp, primary, second); + + return (0); +} + +static uint32_t +get_ds_id( + matrix_t *matrix, + uint32_t m_id, + uint32_t curr_id +) +{ + bmp_t *bmp; + uint32_t primary = GET_PRIMARY(m_id); + uint32_t second = GET_SECOND(m_id); + uint32_t dd_id = 0; + uint32_t uid; + int i = 0; + + if (matrix->x > primary) { + while (i < matrix->y) { + bmp = MATRIX_X_UNIT(matrix, i); + uid = MATRIX_X_INFO(bmp); + if (uid > curr_id && + TEST_MEMBERSHIP(bmp, primary, second) != 0) { + if (dd_id == 0 || uid < dd_id) { + dd_id = uid; + } + } + i ++; + } + } + + return (dd_id); +} + +uint32_t +get_common_dd( + uint32_t m_id1, + uint32_t m_id2, + uint32_t curr_id +) +{ + matrix_t *matrix; + + bmp_t *bmp; + uint32_t primary1 = GET_PRIMARY(m_id1); + uint32_t second1 = GET_SECOND(m_id1); + uint32_t primary2 = GET_PRIMARY(m_id2); + uint32_t second2 = GET_SECOND(m_id2); + uint32_t dd_id = 0; + int i = 0; + + matrix = cache_get_matrix(OBJ_DD); + + if (matrix->x > primary1 && matrix->x > primary2) { + while (i < matrix->y) { + bmp = MATRIX_X_UNIT(matrix, i); + if (MATRIX_X_INFO(bmp) > curr_id && + TEST_MEMBERSHIP(bmp, primary1, second1) != 0 && + TEST_MEMBERSHIP(bmp, primary2, second2) != 0) { + dd_id = MATRIX_X_INFO(bmp); + break; + } + i ++; + } + } + + return (dd_id); +} + +uint32_t +get_dd_id( + uint32_t m_id, + uint32_t curr_id +) +{ + matrix_t *matrix = cache_get_matrix(OBJ_DD); + + return (get_ds_id(matrix, m_id, curr_id)); +} + +uint32_t +get_dds_id( + uint32_t m_id, + uint32_t curr_id +) +{ + matrix_t *matrix = cache_get_matrix(OBJ_DDS); + + return (get_ds_id(matrix, m_id, curr_id)); +} + +static int +create_ds_object( + isns_type_t type, + isns_obj_t **ds_p, + isns_attr_t *name_attr, + isns_attr_t *uid_attr, + isns_attr_t *status_attr +) +{ + int ec = 0; + + isns_obj_t *obj; + int id1, id2, id3; + + if (type == OBJ_DD) { + id1 = ATTR_INDEX_DD(ISNS_DD_NAME_ATTR_ID); + id2 = ATTR_INDEX_DD(ISNS_DD_ID_ATTR_ID); + id3 = ATTR_INDEX_DD(ISNS_DD_FEATURES_ATTR_ID); + } else { + ASSERT(type == OBJ_DDS); + id1 = ATTR_INDEX_DDS(ISNS_DD_SET_NAME_ATTR_ID); + id2 = ATTR_INDEX_DDS(ISNS_DD_SET_ID_ATTR_ID); + id3 = ATTR_INDEX_DDS(ISNS_DD_SET_STATUS_ATTR_ID); + } + + obj = obj_calloc(type); + if (obj != NULL && + (name_attr != NULL && name_attr->tag != 0 && + assign_attr(&obj->attrs[id1], name_attr) == 0) && + (uid_attr == NULL || uid_attr->value.ui == 0 || + assign_attr(&obj->attrs[id2], uid_attr) == 0) && + (status_attr == NULL || status_attr->value.ui == 0 || + assign_attr(&obj->attrs[id3], status_attr) == 0)) { + *ds_p = obj; + } else { + /* no memory */ + free_object(obj); + ec = ISNS_RSP_INTERNAL_ERROR; + } + + return (ec); +} + +int +create_dd_object( + isns_tlv_t *op, + uint16_t op_len, + isns_obj_t **dd_p +) +{ + int ec = 0; + uint8_t *value; + isns_attr_t name = { 0 }; + isns_attr_t dd_id = { 0 }, features = { 0 }; + + name.tag = ISNS_DD_NAME_ATTR_ID; + + while (op_len > 8 && ec == 0) { + value = &op->attr_value[0]; + switch (op->attr_id) { + case ISNS_DD_ID_ATTR_ID: + if (op->attr_len == 4) { + dd_id.tag = ISNS_DD_ID_ATTR_ID; + dd_id.len = 4; + dd_id.value.ui = ntohl(*(uint32_t *)value); + } else if (op->attr_len != 0) { + ec = ISNS_RSP_MSG_FORMAT_ERROR; + } + break; + case ISNS_DD_NAME_ATTR_ID: + if (op->attr_len > 0 && + op->attr_len <= 256) { + name.len = op->attr_len; + name.value.ptr = (uchar_t *)value; + } else if (op->attr_len != 0) { + ec = ISNS_RSP_MSG_FORMAT_ERROR; + } + break; + case ISNS_DD_ISCSI_INDEX_ATTR_ID: + case ISNS_DD_ISCSI_NAME_ATTR_ID: + break; + case ISNS_DD_FC_PORT_NAME_ATTR_ID: + case ISNS_DD_PORTAL_INDEX_ATTR_ID: + case ISNS_DD_PORTAL_IP_ADDR_ATTR_ID: + case ISNS_DD_PORTAL_PORT_ATTR_ID: + ec = ISNS_RSP_REGIS_NOT_SUPPORTED; + break; + case ISNS_DD_FEATURES_ATTR_ID: + if (op->attr_len == 4) { + features.tag = ISNS_DD_FEATURES_ATTR_ID; + features.len = op->attr_len; + features.value.ui = ntohl(*(uint32_t *)value); + } else if (op->attr_len != 0) { + ec = ISNS_RSP_MSG_FORMAT_ERROR; + } + break; + default: + ec = ISNS_RSP_INVALID_REGIS; + break; + } + NEXT_TLV(op, op_len); + } + + if (ec == 0) { + ec = create_ds_object(OBJ_DD, dd_p, + &name, &dd_id, &features); + } + + return (ec); +} + +int +create_dds_object( + isns_tlv_t *op, + uint16_t op_len, + isns_obj_t **dds_p +) +{ + int ec = 0; + uint8_t *value; + isns_attr_t name = { 0 }; + isns_attr_t dds_id = { 0 }, code = { 0 }; + + name.tag = ISNS_DD_SET_NAME_ATTR_ID; + + while (op_len > 8 && ec == 0) { + value = &op->attr_value[0]; + switch (op->attr_id) { + case ISNS_DD_SET_ID_ATTR_ID: + if (op->attr_len == 4) { + dds_id.tag = ISNS_DD_ID_ATTR_ID; + dds_id.len = 4; + dds_id.value.ui = ntohl(*(uint32_t *)value); + } else if (op->attr_len != 0) { + ec = ISNS_RSP_MSG_FORMAT_ERROR; + } + break; + case ISNS_DD_SET_NAME_ATTR_ID: + if (op->attr_len > 0 && + op->attr_len <= 256) { + name.len = op->attr_len; + name.value.ptr = (uchar_t *)value; + } else if (op->attr_len != 0) { + ec = ISNS_RSP_MSG_FORMAT_ERROR; + } + break; + case ISNS_DD_SET_STATUS_ATTR_ID: + if (op->attr_len == 4) { + code.tag = ISNS_DD_SET_STATUS_ATTR_ID; + code.len = op->attr_len; + code.value.ui = ntohl(*(uint32_t *)value); + } else if (op->attr_len != 0) { + ec = ISNS_RSP_MSG_FORMAT_ERROR; + } + break; + case ISNS_DD_ID_ATTR_ID: + break; + default: + ec = ISNS_RSP_INVALID_REGIS; + break; + } + NEXT_TLV(op, op_len); + } + + if (ec == 0) { + ec = create_ds_object(OBJ_DDS, dds_p, + &name, &dds_id, &code); + } + + return (ec); +} + +int +adm_create_dd( + isns_obj_t **dd_p, + uchar_t *name, + uint32_t uid, + uint32_t features +) +{ + uint32_t len; + isns_attr_t name_attr = { 0 }; + isns_attr_t uid_attr = { 0 }; + isns_attr_t features_attr = { 0 }; + + name_attr.tag = ISNS_DD_NAME_ATTR_ID; + if (name != NULL) { + /* need to include the null terminator */ + /* and be on 4 bytes aligned */ + len = strlen((char *)name) + 1; + len += 4 - (len % 4); + name_attr.len = len; + name_attr.value.ptr = name; + } + + uid_attr.tag = ISNS_DD_ID_ATTR_ID; + uid_attr.len = 4; + uid_attr.value.ui = uid; + + features_attr.tag = ISNS_DD_FEATURES_ATTR_ID; + features_attr.len = 4; + features_attr.value.ui = features; + + return (create_ds_object(OBJ_DD, dd_p, + &name_attr, &uid_attr, &features_attr)); +} + +int +adm_create_dds( + isns_obj_t **dds_p, + uchar_t *name, + uint32_t uid, + uint32_t code +) +{ + uint32_t len; + isns_attr_t name_attr = { 0 }; + isns_attr_t uid_attr = { 0 }; + isns_attr_t code_attr = { 0 }; + + name_attr.tag = ISNS_DD_SET_NAME_ATTR_ID; + if (name != NULL) { + /* need to include the null terminator */ + /* and be on 4 bytes aligned */ + len = strlen((char *)name) + 1; + len += 4 - (len % 4); + name_attr.len = len; + name_attr.value.ptr = name; + } + + uid_attr.tag = ISNS_DD_SET_ID_ATTR_ID; + uid_attr.len = 4; + uid_attr.value.ui = uid; + + code_attr.tag = ISNS_DD_SET_STATUS_ATTR_ID; + code_attr.len = 4; + code_attr.value.ui = code; + + return (create_ds_object(OBJ_DDS, dds_p, + &name_attr, &uid_attr, &code_attr)); +} + +static int +update_ds_name( + isns_type_t type, + uint32_t uid, + uint32_t tag, + uint32_t len, + uchar_t *name +) +{ + int ec = 0; + + lookup_ctrl_t lc; + + SET_UID_LCP(&lc, type, uid); + + lc.id[1] = tag; + lc.data[1].ui = len; + lc.data[2].ptr = name; + + ec = cache_rekey(&lc, &uid, cb_update_ds_attr); + if (uid == 0) { + ec = ISNS_RSP_INVALID_REGIS; + } + + return (ec); +} + +int +update_dd_name( + uint32_t uid, + uint32_t len, + uchar_t *name +) +{ + /* + * We do now allow changing the default DD and DD-set name. + */ + if (uid == ISNS_DEFAULT_DD_ID) { + return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); + } + + return (update_ds_name(OBJ_DD, uid, ISNS_DD_NAME_ATTR_ID, len, name)); +} + +int +update_dds_name( + uint32_t uid, + uint32_t len, + uchar_t *name +) +{ + /* + * We do now allow changing the default DD and DD-set name. + */ + if (uid == ISNS_DEFAULT_DD_ID) { + return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); + } + + return (update_ds_name(OBJ_DDS, uid, + ISNS_DD_SET_NAME_ATTR_ID, len, name)); +} + +static int +update_ds_uint32( + isns_type_t type, + uint32_t uid, + uint32_t tag, + uint32_t value +) +{ + int ec = 0; + + lookup_ctrl_t lc; + + SET_UID_LCP(&lc, type, uid); + + lc.id[1] = tag; + lc.data[1].ui = value; + + ec = cache_lookup(&lc, &uid, cb_update_ds_attr); + if (uid == 0) { + ec = ISNS_RSP_INVALID_REGIS; + } + + return (ec); +} + +int +update_dd_features( + uint32_t uid, + uint32_t features +) +{ + return (update_ds_uint32(OBJ_DD, uid, + ISNS_DD_FEATURES_ATTR_ID, features)); +} + +int +update_dds_status( + uint32_t uid, + uint32_t enabled +) +{ + return (update_ds_uint32(OBJ_DDS, uid, + ISNS_DD_SET_STATUS_ATTR_ID, enabled)); +} + +int +add_dd_member( + isns_obj_t *assoc +) +{ + int ec = 0; + + uint32_t dd_id; + uint32_t m_id, m_type; + + dd_id = get_parent_uid(assoc); + /* + * We do now allow placing any node to the default DD explicitly. + */ + if (dd_id == ISNS_DEFAULT_DD_ID) { + return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); + } + + ec = get_member_info(assoc, &m_type, &m_id, 1); + if (ec == 0) { + ec = update_dd_matrix( + '+', /* add member */ + dd_id, + m_type, + m_id); + } + + if (ec == 0) { + if (sys_q != NULL) { + /* add the membership to data store */ + ec = write_data(DATA_ADD, assoc); + } + + /* trigger a management scn */ + if (ec == 0 && scn_q != NULL) { + (void) make_scn(ISNS_MEMBER_ADDED, assoc); + } + } + + return (ec); +} + +int +add_dds_member( + isns_obj_t *assoc +) +{ + int ec = 0; + + uint32_t m_id = assoc->attrs[ATTR_INDEX_ASSOC_DD( + ISNS_DD_ID_ATTR_ID)].value.ui; + uint32_t dds_id; + + dds_id = get_parent_uid(assoc); + /* + * We do now allow changing the membership of the default DD + * and DD-set. + */ + if (dds_id == ISNS_DEFAULT_DD_SET_ID || + m_id == ISNS_DEFAULT_DD_ID) { + return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); + } + + ec = get_dds_member_info(m_id); + if (ec == 0) { + ec = update_dds_matrix( + '+', /* add member */ + dds_id, + m_id); + } + + if (ec == 0) { + if (sys_q != NULL) { + /* add the membership to data store */ + ec = write_data(DATA_ADD, assoc); + } + + /* trigger a management scn */ + if (ec == 0 && scn_q != NULL) { + (void) make_scn(ISNS_MEMBER_ADDED, assoc); + } + } + + return (ec); +} + +int +remove_dd_member( + isns_obj_t *assoc +) +{ + int ec = 0; + + uint32_t dd_id; + uint32_t m_type; + uint32_t m_id; + + lookup_ctrl_t lc; + + dd_id = get_parent_uid(assoc); + /* + * We do now allow removing the member from default DD explicitly. + */ + if (dd_id == ISNS_DEFAULT_DD_ID) { + return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); + } + + ec = get_member_info(assoc, &m_type, &m_id, 0); + if (ec == 0) { + ec = update_dd_matrix( + '-', /* remove member */ + dd_id, + m_type, + m_id); + if (ec == 0) { + /* update data store */ + if (sys_q != NULL) { + /* remove it from data store */ + ec = write_data( + DATA_DELETE_ASSOC, assoc); + } + + /* trigger a management scn */ + if (ec == 0 && scn_q != NULL) { + (void) make_scn(ISNS_MEMBER_REMOVED, assoc); + } + + /* remove it from object container if */ + /* it is not a registered object */ + if (ec == 0) { + SET_UID_LCP(&lc, m_type, m_id); + ec = dereg_assoc(&lc); + } + } + } + + return (ec); +} + +int +remove_dds_member( + uint32_t dds_id, + uint32_t m_id +) +{ + int ec = 0; + + isns_obj_t *clone; + + /* + * We do now allow removing the member from default DD-set. + */ + if (dds_id == ISNS_DEFAULT_DD_SET_ID) { + return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); + } + + if (m_id != 0) { + ec = update_dds_matrix( + '-', /* remove member */ + dds_id, + m_id); + if (ec == 0) { + clone = obj_calloc(OBJ_ASSOC_DD); + if (clone != NULL) { + (void) set_obj_uid((void *)clone, m_id); + (void) set_parent_obj(clone, dds_id); + } + /* update data store */ + if (sys_q != NULL) { + if (clone != NULL) { + /* remove it from data store */ + ec = write_data( + DATA_DELETE_ASSOC, clone); + } else { + ec = ISNS_RSP_INTERNAL_ERROR; + } + } + + /* trigger a management scn */ + if (ec == 0 && + scn_q != NULL && + clone != NULL) { + (void) make_scn(ISNS_MEMBER_REMOVED, clone); + } + free_object(clone); + } + } + + return (ec); +} + +static int +remove_member_wildchar( + matrix_t *matrix, + uint32_t m_id +) +{ + int ec = 0; + + bmp_t *bmp; + uint32_t x_info; + int i; + + uint32_t primary = GET_PRIMARY(m_id); + uint32_t second = GET_SECOND(m_id); + + isns_obj_t *clone; + + if (primary >= matrix->x) { + return (ec); + } + + i = 0; + while (ec == 0 && i < matrix->y) { + bmp = MATRIX_X_UNIT(matrix, i); + x_info = MATRIX_X_INFO(bmp); + if (x_info != 0 && + TEST_MEMBERSHIP(bmp, primary, second) != 0) { + /* clean the membership */ + CLEAR_MEMBERSHIP(bmp, primary, second); + /* update data store */ + if (sys_q != NULL) { + clone = obj_calloc(OBJ_ASSOC_DD); + if (clone != NULL) { + (void) set_obj_uid((void *)clone, m_id); + (void) set_parent_obj(clone, x_info); + /* remove it from data store */ + ec = write_data( + DATA_DELETE_ASSOC, clone); + free_object(clone); + } else { + ec = ISNS_RSP_INTERNAL_ERROR; + } + } + } + i ++; + } + + return (ec); +} + +int +remove_dd_object( + uint32_t dd_id +) +{ + matrix_t *dds_matrix; + + bmp_t *p; + uint32_t n; + int ec; + + lookup_ctrl_t lc; + uint32_t uid; + + /* + * We do now allow removing the default DD. + */ + if (dd_id == ISNS_DEFAULT_DD_ID) { + return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); + } + + SET_UID_LCP(&lc, OBJ_DD, dd_id); + + /* de-register the object at first */ + ec = dereg_object(&lc, 0); + + /* clear it from all of dd-set */ + dds_matrix = cache_get_matrix(OBJ_DDS); + (void) remove_member_wildchar(dds_matrix, dd_id); + + /* clear its member bitmap */ + (void) clear_dd_matrix(dd_id, &p, &n); + + /* deregister the member nodes which are not-registered node */ + /* and have no longer membership in other DD(s). */ + if (p != NULL) { + SET_UID_LCP(&lc, OBJ_ISCSI, 0); + FOR_EACH_MEMBER(p, n, uid, { + lc.data[0].ui = uid; + (void) dereg_assoc(&lc); + }); + free(p); + } + + return (ec); +} + +int +remove_dds_object( + uint32_t dds_id +) +{ + int ec; + + lookup_ctrl_t lc; + + /* + * We do now allow removing the default DD-set. + */ + if (dds_id == ISNS_DEFAULT_DD_SET_ID) { + return (ISNS_RSP_OPTION_NOT_UNDERSTOOD); + } + + (void) clear_dds_matrix(dds_id); + + SET_UID_LCP(&lc, OBJ_DDS, dds_id); + + ec = dereg_object(&lc, 0); + + return (ec); +} + +int +update_ddd( + void *p, + const uchar_t op +) +{ + isns_obj_t *obj; + uint32_t uid; + + matrix_t *matrix; + + obj = (isns_obj_t *)p; + if (obj->type != OBJ_ISCSI) { + return (0); + } + + matrix = cache_get_matrix(OBJ_DD); + uid = get_obj_uid(obj); + + return (update_matrix(matrix, op, ISNS_DEFAULT_DD_ID, uid, 0)); +} + +int +verify_ddd( +) +{ + int ec = 0; + + lookup_ctrl_t lc; + isns_obj_t *obj; + + uchar_t *name; + uint32_t uid; + uint32_t features; + uint32_t code; + + /* Ensure the Default DD is registered. */ + uid = ISNS_DEFAULT_DD_ID; + + SET_UID_LCP(&lc, OBJ_DD, uid); + + (void) cache_lock_write(); + + if (is_obj_there(&lc) == 0) { + name = (uchar_t *)DEFAULT_DD_NAME; + features = DEFAULT_DD_FEATURES; + ec = adm_create_dd(&obj, name, uid, features); + if (ec == 0) { + ec = register_object(obj, NULL, NULL); + if (ec != 0) { + free_object(obj); + goto verify_done; + } + } else { + goto verify_done; + } + } + + /* Ensure the Default DD-set is registered. */ + uid = ISNS_DEFAULT_DD_SET_ID; + + SET_UID_LCP(&lc, OBJ_DDS, uid); + + if (is_obj_there(&lc) == 0) { + name = (uchar_t *)DEFAULT_DD_SET_NAME; + code = DEFAULT_DD_SET_STATUS; + ec = adm_create_dds(&obj, name, uid, code); + if (ec == 0) { + ec = register_object(obj, NULL, NULL); + if (ec != 0) { + free_object(obj); + } + } + } + +verify_done: + + ec = cache_unlock_sync(ec); + + return (ec); +} |
