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