#include "ocs.h"
#include "ocs_fabric.h"
#include "ocs_device.h"
#define domain_sm_trace(domain) \
do { \
if (OCS_LOG_ENABLE_DOMAIN_SM_TRACE(domain->ocs)) \
ocs_log_info(domain->ocs, "[domain] %-20s %-20s\n", __func__, ocs_sm_event_name(evt)); \
} while (0)
#define domain_trace(domain, fmt, ...) \
do { \
if (OCS_LOG_ENABLE_DOMAIN_SM_TRACE(domain ? domain->ocs : NULL)) \
ocs_log_info(domain ? domain->ocs : NULL, fmt, ##__VA_ARGS__); \
} while (0)
#define domain_printf(domain, fmt, ...) \
do { \
ocs_log_info(domain ? domain->ocs : NULL, fmt, ##__VA_ARGS__); \
} while (0)
void ocs_mgmt_domain_list(ocs_textbuf_t *textbuf, void *domain);
void ocs_mgmt_domain_get_all(ocs_textbuf_t *textbuf, void *domain);
int ocs_mgmt_domain_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *domain);
int ocs_mgmt_domain_set(char *parent, char *name, char *value, void *domain);
int ocs_mgmt_domain_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
void *arg_out, uint32_t arg_out_length, void *domain);
static ocs_mgmt_functions_t domain_mgmt_functions = {
.get_list_handler = ocs_mgmt_domain_list,
.get_handler = ocs_mgmt_domain_get,
.get_all_handler = ocs_mgmt_domain_get_all,
.set_handler = ocs_mgmt_domain_set,
.exec_handler = ocs_mgmt_domain_exec,
};
int32_t
ocs_domain_cb(void *arg, ocs_hw_domain_event_e event, void *data)
{
ocs_t *ocs = arg;
ocs_domain_t *domain = NULL;
int32_t rc = 0;
ocs_assert(data, -1);
if (event != OCS_HW_DOMAIN_FOUND) {
domain = data;
}
switch (event) {
case OCS_HW_DOMAIN_FOUND: {
uint64_t fcf_wwn = 0;
ocs_domain_record_t *drec = data;
ocs_assert(drec, -1);
fcf_wwn = ocs_be64toh(*((uint64_t*)drec->wwn));
domain = ocs_domain_find(ocs, fcf_wwn);
if (domain == NULL) {
domain = ocs_domain_alloc(ocs, fcf_wwn);
if (domain == NULL) {
ocs_log_err(ocs, "ocs_domain_alloc() failed\n");
rc = -1;
break;
}
ocs_sm_transition(&domain->drvsm, __ocs_domain_init, NULL);
}
ocs_domain_post_event(domain, OCS_EVT_DOMAIN_FOUND, drec);
break;
}
case OCS_HW_DOMAIN_LOST:
domain_trace(domain, "OCS_HW_DOMAIN_LOST:\n");
ocs_domain_hold_frames(domain);
ocs_domain_post_event(domain, OCS_EVT_DOMAIN_LOST, NULL);
break;
case OCS_HW_DOMAIN_ALLOC_OK: {
domain_trace(domain, "OCS_HW_DOMAIN_ALLOC_OK:\n");
domain->instance_index = 0;
ocs_domain_post_event(domain, OCS_EVT_DOMAIN_ALLOC_OK, NULL);
break;
}
case OCS_HW_DOMAIN_ALLOC_FAIL:
domain_trace(domain, "OCS_HW_DOMAIN_ALLOC_FAIL:\n");
ocs_domain_post_event(domain, OCS_EVT_DOMAIN_ALLOC_FAIL, NULL);
break;
case OCS_HW_DOMAIN_ATTACH_OK:
domain_trace(domain, "OCS_HW_DOMAIN_ATTACH_OK:\n");
ocs_domain_post_event(domain, OCS_EVT_DOMAIN_ATTACH_OK, NULL);
break;
case OCS_HW_DOMAIN_ATTACH_FAIL:
domain_trace(domain, "OCS_HW_DOMAIN_ATTACH_FAIL:\n");
ocs_domain_post_event(domain, OCS_EVT_DOMAIN_ATTACH_FAIL, NULL);
break;
case OCS_HW_DOMAIN_FREE_OK:
domain_trace(domain, "OCS_HW_DOMAIN_FREE_OK:\n");
ocs_domain_post_event(domain, OCS_EVT_DOMAIN_FREE_OK, NULL);
break;
case OCS_HW_DOMAIN_FREE_FAIL:
domain_trace(domain, "OCS_HW_DOMAIN_FREE_FAIL:\n");
ocs_domain_post_event(domain, OCS_EVT_DOMAIN_FREE_FAIL, NULL);
break;
default:
ocs_log_warn(ocs, "unsupported event %#x\n", event);
}
return rc;
}
ocs_domain_t *
ocs_domain_find(ocs_t *ocs, uint64_t fcf_wwn)
{
ocs_domain_t *domain = NULL;
ocs_device_lock(ocs);
ocs_list_foreach(&ocs->domain_list, domain) {
if (fcf_wwn == domain->fcf_wwn) {
break;
}
}
ocs_device_unlock(ocs);
return domain;
}
ocs_domain_t *
ocs_domain_alloc(ocs_t *ocs, uint64_t fcf_wwn)
{
ocs_domain_t *domain;
ocs_assert(ocs, NULL);
domain = ocs_malloc(ocs, sizeof(*domain), OCS_M_NOWAIT | OCS_M_ZERO);
if (domain) {
domain->ocs = ocs;
domain->instance_index = ocs->domain_instance_count++;
domain->drvsm.app = domain;
ocs_domain_lock_init(domain);
ocs_lock_init(ocs, &domain->lookup_lock, "Domain lookup[%d]", domain->instance_index);
domain->lookup = spv_new(ocs);
if (domain->lookup == NULL) {
ocs_log_err(ocs, "spv_new() failed\n");
ocs_free(ocs, domain, sizeof(*domain));
return NULL;
}
ocs_list_init(&domain->sport_list, ocs_sport_t, link);
domain->fcf_wwn = fcf_wwn;
ocs_log_debug(ocs, "Domain allocated: wwn %016" PRIX64 "\n", domain->fcf_wwn);
domain->femul_enable = (ocs->ctrlmask & OCS_CTRLMASK_ENABLE_FABRIC_EMULATION) != 0;
ocs_device_lock(ocs);
if (ocs_list_empty(&ocs->domain_list)) {
ocs->domain = domain;
}
ocs_list_add_tail(&ocs->domain_list, domain);
ocs_device_unlock(ocs);
domain->mgmt_functions = &domain_mgmt_functions;
} else {
ocs_log_err(ocs, "domain allocation failed\n");
}
return domain;
}
void
ocs_domain_free(ocs_domain_t *domain)
{
ocs_t *ocs;
ocs_assert(domain);
ocs_assert(domain->ocs);
ocs_domain_hold_frames(domain);
ocs = domain->ocs;
ocs_log_debug(ocs, "Domain free: wwn %016" PRIX64 "\n", domain->fcf_wwn);
spv_del(domain->lookup);
domain->lookup = NULL;
ocs_device_lock(ocs);
ocs_list_remove(&ocs->domain_list, domain);
if (domain == ocs->domain) {
ocs->domain = ocs_list_get_head(&ocs->domain_list);
if (ocs->domain) {
ocs_log_debug(ocs, "setting new domain, old=%p new=%p\n",
domain, ocs->domain);
}
}
if (ocs_list_empty(&ocs->domain_list) && ocs->domain_list_empty_cb ) {
(*ocs->domain_list_empty_cb)(ocs, ocs->domain_list_empty_cb_arg);
}
ocs_device_unlock(ocs);
ocs_lock_free(&domain->lookup_lock);
ocs_free(ocs, domain, sizeof(*domain));
}
void
ocs_domain_force_free(ocs_domain_t *domain)
{
ocs_sport_t *sport;
ocs_sport_t *next;
ocs_sm_disable(&domain->drvsm);
ocs_scsi_notify_domain_force_free(domain);
ocs_domain_lock(domain);
ocs_list_foreach_safe(&domain->sport_list, sport, next) {
ocs_sport_force_free(sport);
}
ocs_domain_unlock(domain);
ocs_hw_domain_force_free(&domain->ocs->hw, domain);
ocs_domain_free(domain);
}
void
ocs_register_domain_list_empty_cb(ocs_t *ocs, void (*callback)(ocs_t *ocs, void *arg), void *arg)
{
ocs_device_lock(ocs);
ocs->domain_list_empty_cb = callback;
ocs->domain_list_empty_cb_arg = arg;
if (ocs_list_empty(&ocs->domain_list) && callback) {
(*callback)(ocs, arg);
}
ocs_device_unlock(ocs);
}
ocs_domain_t *
ocs_domain_get_instance(ocs_t *ocs, uint32_t index)
{
ocs_domain_t *domain = NULL;
if (index >= OCS_MAX_DOMAINS) {
ocs_log_err(ocs, "invalid index: %d\n", index);
return NULL;
}
ocs_device_lock(ocs);
ocs_list_foreach(&ocs->domain_list, domain) {
if (domain->instance_index == index) {
break;
}
}
ocs_device_unlock(ocs);
return domain;
}
static void *
__ocs_domain_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
{
ocs_domain_t *domain = ctx->app;
switch(evt) {
case OCS_EVT_ENTER:
case OCS_EVT_REENTER:
case OCS_EVT_EXIT:
case OCS_EVT_ALL_CHILD_NODES_FREE:
break;
default:
ocs_log_warn(domain->ocs, "%-20s %-20s not handled\n", funcname, ocs_sm_event_name(evt));
break;
}
return NULL;
}
static void *
__ocs_domain_common_shutdown(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
{
ocs_domain_t *domain = ctx->app;
switch(evt) {
case OCS_EVT_ENTER:
case OCS_EVT_REENTER:
case OCS_EVT_EXIT:
break;
case OCS_EVT_DOMAIN_FOUND:
ocs_assert(arg, NULL);
ocs_memcpy(&domain->pending_drec, arg, sizeof(domain->pending_drec));
domain->domain_found_pending = TRUE;
break;
case OCS_EVT_DOMAIN_LOST:
domain->domain_found_pending = FALSE;
break;
default:
ocs_log_warn(domain->ocs, "%-20s %-20s not handled\n", funcname, ocs_sm_event_name(evt));
break;
}
return NULL;
}
#define std_domain_state_decl(...) \
ocs_domain_t *domain = NULL; \
ocs_t *ocs = NULL; \
\
ocs_assert(ctx, NULL); \
ocs_assert(ctx->app, NULL); \
domain = ctx->app; \
ocs_assert(domain->ocs, NULL); \
ocs = domain->ocs; \
ocs_assert(ocs->xport, NULL);
void *
__ocs_domain_init(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
{
std_domain_state_decl();
domain_sm_trace(domain);
switch(evt) {
case OCS_EVT_ENTER:
domain->attached = 0;
break;
case OCS_EVT_DOMAIN_FOUND: {
int32_t vlan = 0;
uint32_t i;
ocs_domain_record_t *drec = arg;
ocs_sport_t *sport;
uint64_t my_wwnn = ocs->xport->req_wwnn;
uint64_t my_wwpn = ocs->xport->req_wwpn;
uint64_t be_wwpn;
if ((my_wwpn == 0) || (my_wwnn == 0)) {
ocs_log_debug(ocs, "using default hardware WWN configuration \n");
my_wwpn = ocs_get_wwn(&ocs->hw, OCS_HW_WWN_PORT);
my_wwnn = ocs_get_wwn(&ocs->hw, OCS_HW_WWN_NODE);
}
ocs_log_debug(ocs, "Creating base sport using WWPN %016" PRIx64 " WWNN %016" PRIx64 "\n",
my_wwpn, my_wwnn);
sport = ocs_sport_alloc(domain, my_wwpn, my_wwnn, UINT32_MAX, ocs->enable_ini, ocs->enable_tgt);
if (sport == NULL) {
ocs_log_err(ocs, "ocs_sport_alloc() failed\n");
break;
}
ocs_sm_transition(&sport->sm, __ocs_sport_allocated, NULL);
if (drec->is_ethernet) {
vlan = ocs_bitmap_search((void *)drec->map.vlan, TRUE, 512 * 8);
if (vlan < 0) {
ocs_log_err(ocs, "no VLAN id available (FCF=%d)\n",
drec->index);
break;
}
}
be_wwpn = ocs_htobe64(sport->wwpn);
if (ocs_hw_port_alloc(&ocs->hw, sport, NULL, (uint8_t *)&be_wwpn)) {
ocs_log_err(ocs, "Can't allocate port\n");
ocs_sport_free(sport);
break;
}
domain->is_loop = drec->is_loop;
domain->is_fc = drec->is_fc;
domain->is_nlport = drec->map.loop[1] == 0x00;
if (domain->is_loop) {
ocs_log_debug(ocs, "%s fc_id=%#x speed=%d\n",
drec->is_loop ? (domain->is_nlport ? "public-loop" : "loop") : "other",
drec->fc_id, drec->speed);
sport->fc_id = drec->fc_id;
sport->topology = OCS_SPORT_TOPOLOGY_LOOP;
ocs_snprintf(sport->display_name, sizeof(sport->display_name), "s%06x", drec->fc_id);
if (ocs->enable_ini) {
uint32_t count = drec->map.loop[0];
ocs_log_debug(ocs, "%d position map entries\n", count);
for (i = 1; i <= count; i++) {
if (drec->map.loop[i] != drec->fc_id) {
ocs_node_t *node;
ocs_log_debug(ocs, "%#x -> %#x\n",
drec->fc_id, drec->map.loop[i]);
node = ocs_node_alloc(sport, drec->map.loop[i], FALSE, TRUE);
if (node == NULL) {
ocs_log_err(ocs, "ocs_node_alloc() failed\n");
break;
}
ocs_node_transition(node, __ocs_d_wait_loop, NULL);
}
}
}
}
if (ocs_hw_domain_alloc(&ocs->hw, domain, drec->index, vlan)) {
ocs_log_err(ocs, "Failed to initiate HW domain allocation\n");
break;
}
ocs_sm_transition(ctx, __ocs_domain_wait_alloc, arg);
break;
}
default:
__ocs_domain_common(__func__, ctx, evt, arg);
return NULL;
}
return NULL;
}
void *
__ocs_domain_wait_alloc(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
{
ocs_sport_t *sport;
std_domain_state_decl();
domain_sm_trace(domain);
switch(evt) {
case OCS_EVT_DOMAIN_ALLOC_OK: {
char prop_buf[32];
uint64_t wwn_bump = 0;
fc_plogi_payload_t *sp;
if (ocs_get_property("wwn_bump", prop_buf, sizeof(prop_buf)) == 0) {
wwn_bump = ocs_strtoull(prop_buf, 0, 0);
}
sport = domain->sport;
ocs_assert(sport, NULL);
sp = (fc_plogi_payload_t*) sport->service_params;
ocs_memcpy(domain->service_params + 4, domain->dma.virt, sizeof(fc_plogi_payload_t) - 4);
ocs_memcpy(sport->service_params + 4, domain->dma.virt, sizeof(fc_plogi_payload_t) - 4);
if (domain->femul_enable) {
ocs_memcpy(domain->flogi_service_params + 4, domain->service_params + 4, sizeof(fc_plogi_payload_t) - 4);
}
sp->port_name_hi = ocs_htobe32((uint32_t) (sport->wwpn >> 32ll));
sp->port_name_lo = ocs_htobe32((uint32_t) sport->wwpn);
sp->node_name_hi = ocs_htobe32((uint32_t) (sport->wwnn >> 32ll));
sp->node_name_lo = ocs_htobe32((uint32_t) sport->wwnn);
if (wwn_bump) {
sp->port_name_lo = ocs_htobe32(ocs_be32toh(sp->port_name_lo) ^ ((uint32_t)(wwn_bump)));
sp->port_name_hi = ocs_htobe32(ocs_be32toh(sp->port_name_hi) ^ ((uint32_t)(wwn_bump >> 32)));
sp->node_name_lo = ocs_htobe32(ocs_be32toh(sp->node_name_lo) ^ ((uint32_t)(wwn_bump)));
sp->node_name_hi = ocs_htobe32(ocs_be32toh(sp->node_name_hi) ^ ((uint32_t)(wwn_bump >> 32)));
ocs_log_info(ocs, "Overriding WWN\n");
}
if (domain->is_loop && !domain->is_nlport) {
ocs_sm_transition(ctx, __ocs_domain_allocated, NULL);
__ocs_domain_attach_internal(domain, sport->fc_id);
break;
} else {
ocs_node_t *node;
node = ocs_node_find(sport, FC_ADDR_FABRIC);
if (node) {
ocs_log_err(ocs, "Hmmmm ... Fabric Controller node already exists\n");
break;
}
node = ocs_node_alloc(sport, FC_ADDR_FABRIC, FALSE, FALSE);
if (!node) {
ocs_log_err(ocs, "Error: ocs_node_alloc() failed\n");
} else {
if (ocs->nodedb_mask & OCS_NODEDB_PAUSE_FABRIC_LOGIN) {
ocs_node_pause(node, __ocs_fabric_init);
} else {
ocs_node_transition(node, __ocs_fabric_init, NULL);
}
}
domain->req_accept_frames = 1;
}
ocs_sm_transition(ctx, __ocs_domain_allocated, NULL);
break;
}
case OCS_EVT_DOMAIN_ALLOC_FAIL:
ocs_log_err(ocs, "%s recv'd waiting for DOMAIN_ALLOC_OK; shutting down domain\n",
ocs_sm_event_name(evt));
domain->req_domain_free = 1;
break;
case OCS_EVT_DOMAIN_FOUND:
ocs_assert(evt, NULL);
break;
case OCS_EVT_DOMAIN_LOST:
ocs_log_debug(ocs, "%s received while waiting for ocs_hw_domain_alloc() to complete\n", ocs_sm_event_name(evt));
ocs_sm_transition(ctx, __ocs_domain_wait_domain_lost, NULL);
break;
default:
__ocs_domain_common(__func__, ctx, evt, arg);
return NULL;
}
return NULL;
}
void *
__ocs_domain_allocated(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
{
int32_t rc = 0;
std_domain_state_decl();
domain_sm_trace(domain);
switch(evt) {
case OCS_EVT_DOMAIN_REQ_ATTACH: {
uint32_t fc_id;
ocs_assert(arg, NULL);
fc_id = *((uint32_t*)arg);
ocs_log_debug(ocs, "Requesting hw domain attach fc_id x%x\n", fc_id);
ocs_lock(&domain->lookup_lock);
spv_set(domain->lookup, fc_id, domain->sport);
ocs_unlock(&domain->lookup_lock);
ocs_node_fcid_display(fc_id, domain->sport->display_name, sizeof(domain->sport->display_name));
rc = ocs_hw_domain_attach(&ocs->hw, domain, fc_id);
if (rc) {
ocs_log_err(ocs, "ocs_hw_domain_attach failed: %d\n", rc);
return NULL;
}
ocs_sm_transition(ctx, __ocs_domain_wait_attach, NULL);
break;
}
case OCS_EVT_DOMAIN_FOUND:
ocs_assert(evt, NULL);
break;
case OCS_EVT_DOMAIN_LOST: {
int32_t rc;
ocs_log_debug(ocs, "%s received while waiting for OCS_EVT_DOMAIN_REQ_ATTACH\n",
ocs_sm_event_name(evt));
ocs_domain_lock(domain);
if (!ocs_list_empty(&domain->sport_list)) {
ocs_sport_t *sport = NULL;
ocs_sport_t *sport_next = NULL;
ocs_sm_transition(ctx, __ocs_domain_wait_sports_free, NULL);
ocs_list_foreach_safe(&domain->sport_list, sport, sport_next) {
ocs_sm_post_event(&sport->sm, OCS_EVT_SHUTDOWN, NULL);
}
ocs_domain_unlock(domain);
} else {
ocs_domain_unlock(domain);
ocs_sm_transition(ctx, __ocs_domain_wait_shutdown, NULL);
rc = ocs_hw_domain_free(&ocs->hw, domain);
if (rc) {
ocs_log_err(ocs, "ocs_hw_domain_free() failed: %d\n", rc);
}
}
break;
}
default:
__ocs_domain_common(__func__, ctx, evt, arg);
return NULL;
}
return NULL;
}
void *
__ocs_domain_wait_attach(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
{
std_domain_state_decl();
domain_sm_trace(domain);
switch(evt) {
case OCS_EVT_DOMAIN_ATTACH_OK: {
ocs_node_t *node = NULL;
ocs_node_t *next_node = NULL;
ocs_sport_t *sport;
ocs_sport_t *next_sport;
domain->attached = 1;
if (ocs->enable_tgt)
ocs_scsi_tgt_new_domain(domain);
if (ocs->enable_ini)
ocs_scsi_ini_new_domain(domain);
ocs_sm_transition(ctx, __ocs_domain_ready, NULL);
domain->req_accept_frames = 1;
domain->domain_notify_pend = 1;
ocs_domain_lock(domain);
ocs_list_foreach_safe(&domain->sport_list, sport, next_sport) {
ocs_sport_lock(sport);
ocs_list_foreach_safe(&sport->node_list, node, next_node) {
ocs_node_post_event(node, OCS_EVT_DOMAIN_ATTACH_OK, NULL);
}
ocs_sport_unlock(sport);
}
ocs_domain_unlock(domain);
domain->domain_notify_pend = 0;
break;
}
case OCS_EVT_DOMAIN_ATTACH_FAIL:
ocs_log_debug(ocs, "%s received while waiting for hw attach to complete\n", ocs_sm_event_name(evt));
break;
case OCS_EVT_DOMAIN_FOUND:
ocs_assert(evt, NULL);
break;
case OCS_EVT_DOMAIN_LOST:
ocs_sm_transition(ctx, __ocs_domain_wait_domain_lost, NULL);
break;
case OCS_EVT_DOMAIN_REQ_ATTACH:
break;
default:
__ocs_domain_common(__func__, ctx, evt, arg);
return NULL;
}
return NULL;
}
void *
__ocs_domain_ready(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
{
std_domain_state_decl();
domain_sm_trace(domain);
switch(evt) {
case OCS_EVT_ENTER: {
if (ocs_vport_start(domain)) {
ocs_log_debug(domain->ocs, "ocs_vport_start() did not start all vports\n");
}
break;
}
case OCS_EVT_DOMAIN_LOST: {
int32_t rc;
ocs_domain_lock(domain);
if (!ocs_list_empty(&domain->sport_list)) {
ocs_sport_t *sport = NULL;
ocs_sport_t *sport_next = NULL;
ocs_sm_transition(ctx, __ocs_domain_wait_sports_free, NULL);
ocs_list_foreach_safe(&domain->sport_list, sport, sport_next) {
ocs_sm_post_event(&sport->sm, OCS_EVT_SHUTDOWN, NULL);
}
ocs_domain_unlock(domain);
} else {
ocs_domain_unlock(domain);
ocs_sm_transition(ctx, __ocs_domain_wait_shutdown, NULL);
rc = ocs_hw_domain_free(&ocs->hw, domain);
if (rc) {
ocs_log_err(ocs, "ocs_hw_domain_free() failed: %d\n", rc);
}
}
break;
}
case OCS_EVT_DOMAIN_FOUND:
ocs_assert(evt, NULL);
break;
case OCS_EVT_DOMAIN_REQ_ATTACH: {
uint32_t fc_id;
ocs_assert(arg, NULL);
fc_id = *((uint32_t*)arg);
ocs_assert(domain->attached, NULL);
ocs_assert(domain->sport->fc_id == fc_id, NULL);
break;
}
default:
__ocs_domain_common(__func__, ctx, evt, arg);
return NULL;
}
return NULL;
}
void *
__ocs_domain_wait_sports_free(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
{
std_domain_state_decl();
domain_sm_trace(domain);
switch(evt) {
case OCS_EVT_ALL_CHILD_NODES_FREE: {
int32_t rc;
ocs_sm_transition(ctx, __ocs_domain_wait_shutdown, NULL);
rc = ocs_hw_domain_free(&ocs->hw, domain);
if (rc) {
ocs_log_err(ocs, "ocs_hw_domain_free() failed: %d\n", rc);
}
break;
}
default:
__ocs_domain_common_shutdown(__func__, ctx, evt, arg);
return NULL;
}
return NULL;
}
void *
__ocs_domain_wait_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
{
std_domain_state_decl();
domain_sm_trace(domain);
switch(evt) {
case OCS_EVT_DOMAIN_FREE_OK: {
if (ocs->enable_ini)
ocs_scsi_ini_del_domain(domain);
if (ocs->enable_tgt)
ocs_scsi_tgt_del_domain(domain);
if (domain->domain_found_pending) {
uint64_t fcf_wwn = domain->fcf_wwn;
ocs_domain_record_t drec = domain->pending_drec;
ocs_log_debug(ocs, "Reallocating domain\n");
domain->req_domain_free = 1;
domain = ocs_domain_alloc(ocs, fcf_wwn);
if (domain == NULL) {
ocs_log_err(ocs, "ocs_domain_alloc() failed\n");
return NULL;
}
ocs_sm_transition(&domain->drvsm, __ocs_domain_init, NULL);
ocs_sm_post_event(&domain->drvsm, OCS_EVT_DOMAIN_FOUND, &drec);
} else {
domain->req_domain_free = 1;
}
break;
}
default:
__ocs_domain_common_shutdown(__func__, ctx, evt, arg);
return NULL;
}
return NULL;
}
void *
__ocs_domain_wait_domain_lost(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg)
{
std_domain_state_decl();
domain_sm_trace(domain);
switch(evt) {
case OCS_EVT_DOMAIN_ALLOC_OK:
case OCS_EVT_DOMAIN_ATTACH_OK: {
int32_t rc;
ocs_domain_lock(domain);
if (!ocs_list_empty(&domain->sport_list)) {
ocs_sport_t *sport = NULL;
ocs_sport_t *sport_next = NULL;
ocs_sm_transition(ctx, __ocs_domain_wait_sports_free, NULL);
ocs_list_foreach_safe(&domain->sport_list, sport, sport_next) {
ocs_sm_post_event(&sport->sm, OCS_EVT_SHUTDOWN, NULL);
}
ocs_domain_unlock(domain);
} else {
ocs_domain_unlock(domain);
ocs_sm_transition(ctx, __ocs_domain_wait_shutdown, NULL);
rc = ocs_hw_domain_free(&ocs->hw, domain);
if (rc) {
ocs_log_err(ocs, "ocs_hw_domain_free() failed: %d\n", rc);
}
}
break;
}
case OCS_EVT_DOMAIN_ALLOC_FAIL:
case OCS_EVT_DOMAIN_ATTACH_FAIL:
ocs_log_err(ocs, "[domain] %-20s: failed\n", ocs_sm_event_name(evt));
break;
default:
__ocs_domain_common_shutdown(__func__, ctx, evt, arg);
return NULL;
}
return NULL;
}
void
ocs_domain_save_sparms(ocs_domain_t *domain, void *payload)
{
ocs_memcpy(domain->flogi_service_params, payload, sizeof (fc_plogi_payload_t));
}
void
__ocs_domain_attach_internal(ocs_domain_t *domain, uint32_t s_id)
{
ocs_memcpy(domain->dma.virt, ((uint8_t*)domain->flogi_service_params)+4, sizeof (fc_plogi_payload_t) - 4);
(void)ocs_sm_post_event(&domain->drvsm, OCS_EVT_DOMAIN_REQ_ATTACH, &s_id);
}
void
ocs_domain_attach(ocs_domain_t *domain, uint32_t s_id)
{
__ocs_domain_attach_internal(domain, s_id);
}
int
ocs_domain_post_event(ocs_domain_t *domain, ocs_sm_event_t event, void *arg)
{
int rc;
int accept_frames;
int req_domain_free;
rc = ocs_sm_post_event(&domain->drvsm, event, arg);
req_domain_free = domain->req_domain_free;
domain->req_domain_free = 0;
accept_frames = domain->req_accept_frames;
domain->req_accept_frames = 0;
if (accept_frames) {
ocs_domain_accept_frames(domain);
}
if (req_domain_free) {
ocs_domain_free(domain);
}
return rc;
}
uint64_t
ocs_get_wwn(ocs_hw_t *hw, ocs_hw_property_e prop)
{
uint8_t *p = ocs_hw_get_ptr(hw, prop);
uint64_t value = 0;
if (p) {
uint32_t i;
for (i = 0; i < sizeof(value); i++) {
value = (value << 8) | p[i];
}
}
return value;
}
int
ocs_ddump_domain(ocs_textbuf_t *textbuf, ocs_domain_t *domain)
{
ocs_sport_t *sport;
int retval = 0;
ocs_ddump_section(textbuf, "domain", domain->instance_index);
ocs_ddump_value(textbuf, "display_name", "%s", domain->display_name);
ocs_ddump_value(textbuf, "fcf", "%#x", domain->fcf);
ocs_ddump_value(textbuf, "fcf_indicator", "%#x", domain->fcf_indicator);
ocs_ddump_value(textbuf, "vlan_id", "%#x", domain->vlan_id);
ocs_ddump_value(textbuf, "indicator", "%#x", domain->indicator);
ocs_ddump_value(textbuf, "attached", "%d", domain->attached);
ocs_ddump_value(textbuf, "is_loop", "%d", domain->is_loop);
ocs_ddump_value(textbuf, "is_nlport", "%d", domain->is_nlport);
ocs_scsi_ini_ddump(textbuf, OCS_SCSI_DDUMP_DOMAIN, domain);
ocs_scsi_tgt_ddump(textbuf, OCS_SCSI_DDUMP_DOMAIN, domain);
ocs_display_sparams(NULL, "domain_sparms", 1, textbuf, domain->dma.virt);
if (ocs_domain_lock_try(domain) != TRUE) {
return -1;
}
ocs_list_foreach(&domain->sport_list, sport) {
retval = ocs_ddump_sport(textbuf, sport);
if (retval != 0) {
break;
}
}
#if defined(ENABLE_FABRIC_EMULATION)
ocs_ddump_ns(textbuf, domain->ocs_ns);
#endif
ocs_domain_unlock(domain);
ocs_ddump_endsection(textbuf, "domain", domain->instance_index);
return retval;
}
void
ocs_mgmt_domain_list(ocs_textbuf_t *textbuf, void *object)
{
ocs_sport_t *sport;
ocs_domain_t *domain = (ocs_domain_t *)object;
ocs_mgmt_start_section(textbuf, "domain", domain->instance_index);
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "fcf");
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "fcf_indicator");
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "vlan_id");
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "indicator");
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "attached");
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "is_loop");
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "display_name");
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "num_sports");
#if defined(ENABLE_FABRIC_EMULATION)
ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RW, "femul_enable");
#endif
if (ocs_domain_lock_try(domain) == TRUE) {
ocs_list_foreach(&domain->sport_list, sport) {
if ((sport->mgmt_functions) && (sport->mgmt_functions->get_list_handler)) {
sport->mgmt_functions->get_list_handler(textbuf, sport);
}
}
ocs_domain_unlock(domain);
}
ocs_mgmt_end_section(textbuf, "domain", domain->instance_index);
}
int
ocs_mgmt_domain_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *object)
{
ocs_sport_t *sport;
ocs_domain_t *domain = (ocs_domain_t *)object;
char qualifier[80];
int retval = -1;
ocs_mgmt_start_section(textbuf, "domain", domain->instance_index);
snprintf(qualifier, sizeof(qualifier), "%s/domain[%d]", parent, domain->instance_index);
if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
char *unqualified_name = name + strlen(qualifier) +1;
if (ocs_strcmp(unqualified_name, "display_name") == 0) {
ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", domain->display_name);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "fcf") == 0) {
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fcf", "%#x", domain->fcf);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "fcf_indicator") == 0) {
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fcf_indicator", "%#x", domain->fcf_indicator);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "vlan_id") == 0) {
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "vlan_id", "%#x", domain->vlan_id);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "indicator") == 0) {
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "indicator", "%#x", domain->indicator);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "attached") == 0) {
ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "attached", domain->attached);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "is_loop") == 0) {
ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_loop", domain->is_loop);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "is_nlport") == 0) {
ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_nlport", domain->is_nlport);
retval = 0;
} else if (ocs_strcmp(unqualified_name, "display_name") == 0) {
ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", domain->display_name);
retval = 0;
#if defined(ENABLE_FABRIC_EMULATION)
} else if (ocs_strcmp(unqualified_name, "femul_enable") == 0) {
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "femul_enable", "%d", domain->femul_enable);
retval = 0;
#endif
} else if (ocs_strcmp(unqualified_name, "num_sports") == 0) {
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "num_sports", "%d", domain->sport_instance_count);
retval = 0;
} else {
ocs_domain_lock(domain);
ocs_list_foreach(&domain->sport_list, sport) {
if ((sport->mgmt_functions) && (sport->mgmt_functions->get_handler)) {
retval = sport->mgmt_functions->get_handler(textbuf, qualifier, name, sport);
}
if (retval == 0) {
break;
}
}
ocs_domain_unlock(domain);
}
}
ocs_mgmt_end_section(textbuf, "domain", domain->instance_index);
return retval;
}
void
ocs_mgmt_domain_get_all(ocs_textbuf_t *textbuf, void *object)
{
ocs_sport_t *sport;
ocs_domain_t *domain = (ocs_domain_t *)object;
ocs_mgmt_start_section(textbuf, "domain", domain->instance_index);
ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", domain->display_name);
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fcf", "%#x", domain->fcf);
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fcf_indicator", "%#x", domain->fcf_indicator);
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "vlan_id", "%#x", domain->vlan_id);
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "indicator", "%#x", domain->indicator);
ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "attached", domain->attached);
ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_loop", domain->is_loop);
ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "is_nlport", domain->is_nlport);
#if defined(ENABLE_FABRIC_EMULATION)
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "femul_enable", "%d", domain->femul_enable);
#endif
ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "num_sports", "%d", domain->sport_instance_count);
ocs_domain_lock(domain);
ocs_list_foreach(&domain->sport_list, sport) {
if ((sport->mgmt_functions) && (sport->mgmt_functions->get_all_handler)) {
sport->mgmt_functions->get_all_handler(textbuf, sport);
}
}
ocs_domain_unlock(domain);
ocs_mgmt_end_unnumbered_section(textbuf, "domain");
}
int
ocs_mgmt_domain_set(char *parent, char *name, char *value, void *object)
{
ocs_sport_t *sport;
ocs_domain_t *domain = (ocs_domain_t *)object;
char qualifier[80];
int retval = -1;
snprintf(qualifier, sizeof(qualifier), "%s/domain[%d]", parent, domain->instance_index);
if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
{
ocs_domain_lock(domain);
ocs_list_foreach(&domain->sport_list, sport) {
if ((sport->mgmt_functions) && (sport->mgmt_functions->set_handler)) {
retval = sport->mgmt_functions->set_handler(qualifier, name, value, sport);
}
if (retval == 0) {
break;
}
}
ocs_domain_unlock(domain);
}
}
return retval;
}
int
ocs_mgmt_domain_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length,
void *arg_out, uint32_t arg_out_length, void *object)
{
ocs_sport_t *sport;
ocs_domain_t *domain = (ocs_domain_t *)object;
char qualifier[80];
int retval = -1;
snprintf(qualifier, sizeof(qualifier), "%s.domain%d", parent, domain->instance_index);
if (ocs_strncmp(action, qualifier, strlen(qualifier)) == 0) {
{
ocs_domain_lock(domain);
ocs_list_foreach(&domain->sport_list, sport) {
if ((sport->mgmt_functions) && (sport->mgmt_functions->exec_handler)) {
retval = sport->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length, arg_out, arg_out_length, sport);
}
if (retval == 0) {
break;
}
}
ocs_domain_unlock(domain);
}
}
return retval;
}