/* * 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 #include #include #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); }