1ef270ab1SKenneth D. Merry /*- 2ef270ab1SKenneth D. Merry * Copyright (c) 2017 Broadcom. All rights reserved. 3ef270ab1SKenneth D. Merry * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. 4ef270ab1SKenneth D. Merry * 5ef270ab1SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 6ef270ab1SKenneth D. Merry * modification, are permitted provided that the following conditions are met: 7ef270ab1SKenneth D. Merry * 8ef270ab1SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright notice, 9ef270ab1SKenneth D. Merry * this list of conditions and the following disclaimer. 10ef270ab1SKenneth D. Merry * 11ef270ab1SKenneth D. Merry * 2. Redistributions in binary form must reproduce the above copyright notice, 12ef270ab1SKenneth D. Merry * this list of conditions and the following disclaimer in the documentation 13ef270ab1SKenneth D. Merry * and/or other materials provided with the distribution. 14ef270ab1SKenneth D. Merry * 15ef270ab1SKenneth D. Merry * 3. Neither the name of the copyright holder nor the names of its contributors 16ef270ab1SKenneth D. Merry * may be used to endorse or promote products derived from this software 17ef270ab1SKenneth D. Merry * without specific prior written permission. 18ef270ab1SKenneth D. Merry * 19ef270ab1SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20ef270ab1SKenneth D. Merry * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21ef270ab1SKenneth D. Merry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22ef270ab1SKenneth D. Merry * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23ef270ab1SKenneth D. Merry * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24ef270ab1SKenneth D. Merry * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25ef270ab1SKenneth D. Merry * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26ef270ab1SKenneth D. Merry * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27ef270ab1SKenneth D. Merry * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28ef270ab1SKenneth D. Merry * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29ef270ab1SKenneth D. Merry * POSSIBILITY OF SUCH DAMAGE. 30ef270ab1SKenneth D. Merry * 31ef270ab1SKenneth D. Merry * $FreeBSD$ 32ef270ab1SKenneth D. Merry */ 33ef270ab1SKenneth D. Merry 34ef270ab1SKenneth D. Merry /** 35ef270ab1SKenneth D. Merry * @file 36ef270ab1SKenneth D. Merry * OCS driver remote node handler. This file contains code that is shared 37ef270ab1SKenneth D. Merry * between fabric (ocs_fabric.c) and device (ocs_device.c) nodes. 38ef270ab1SKenneth D. Merry */ 39ef270ab1SKenneth D. Merry 40ef270ab1SKenneth D. Merry /*! 41ef270ab1SKenneth D. Merry * @defgroup node_common Node common support 42ef270ab1SKenneth D. Merry * @defgroup node_alloc Node allocation 43ef270ab1SKenneth D. Merry */ 44ef270ab1SKenneth D. Merry 45ef270ab1SKenneth D. Merry #include "ocs.h" 46ef270ab1SKenneth D. Merry #include "ocs_els.h" 47ef270ab1SKenneth D. Merry #include "ocs_device.h" 48ef270ab1SKenneth D. Merry 49ef270ab1SKenneth D. Merry #define SCSI_IOFMT "[%04x][i:%0*x t:%0*x h:%04x]" 50ef270ab1SKenneth D. Merry #define SCSI_ITT_SIZE(ocs) ((ocs->ocs_xport == OCS_XPORT_FC) ? 4 : 8) 51ef270ab1SKenneth D. Merry 52ef270ab1SKenneth D. Merry #define SCSI_IOFMT_ARGS(io) io->instance_index, SCSI_ITT_SIZE(io->ocs), io->init_task_tag, SCSI_ITT_SIZE(io->ocs), io->tgt_task_tag, io->hw_tag 53ef270ab1SKenneth D. Merry 54ef270ab1SKenneth D. Merry #define scsi_io_printf(io, fmt, ...) ocs_log_debug(io->ocs, "[%s]" SCSI_IOFMT fmt, \ 55ef270ab1SKenneth D. Merry io->node->display_name, SCSI_IOFMT_ARGS(io), ##__VA_ARGS__) 56ef270ab1SKenneth D. Merry 57ef270ab1SKenneth D. Merry void ocs_mgmt_node_list(ocs_textbuf_t *textbuf, void *node); 58ef270ab1SKenneth D. Merry void ocs_mgmt_node_get_all(ocs_textbuf_t *textbuf, void *node); 59ef270ab1SKenneth D. Merry int ocs_mgmt_node_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *node); 60ef270ab1SKenneth D. Merry int ocs_mgmt_node_set(char *parent, char *name, char *value, void *node); 61ef270ab1SKenneth D. Merry int ocs_mgmt_node_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length, 62ef270ab1SKenneth D. Merry void *arg_out, uint32_t arg_out_length, void *node); 63ef270ab1SKenneth D. Merry static ocs_mgmt_functions_t node_mgmt_functions = { 64ef270ab1SKenneth D. Merry .get_list_handler = ocs_mgmt_node_list, 65ef270ab1SKenneth D. Merry .get_handler = ocs_mgmt_node_get, 66ef270ab1SKenneth D. Merry .get_all_handler = ocs_mgmt_node_get_all, 67ef270ab1SKenneth D. Merry .set_handler = ocs_mgmt_node_set, 68ef270ab1SKenneth D. Merry .exec_handler = ocs_mgmt_node_exec, 69ef270ab1SKenneth D. Merry }; 70ef270ab1SKenneth D. Merry 71ef270ab1SKenneth D. Merry 72ef270ab1SKenneth D. Merry /** 73ef270ab1SKenneth D. Merry * @ingroup node_common 74ef270ab1SKenneth D. Merry * @brief Device node state machine wait for all ELS's to 75ef270ab1SKenneth D. Merry * complete 76ef270ab1SKenneth D. Merry * 77ef270ab1SKenneth D. Merry * Abort all ELS's for given node. 78ef270ab1SKenneth D. Merry * 79ef270ab1SKenneth D. Merry * @param node node for which ELS's will be aborted 80ef270ab1SKenneth D. Merry */ 81ef270ab1SKenneth D. Merry 82ef270ab1SKenneth D. Merry void 83ef270ab1SKenneth D. Merry ocs_node_abort_all_els(ocs_node_t *node) 84ef270ab1SKenneth D. Merry { 85ef270ab1SKenneth D. Merry ocs_io_t *els; 86ef270ab1SKenneth D. Merry ocs_io_t *els_next; 87ef270ab1SKenneth D. Merry ocs_node_cb_t cbdata = {0}; 88ef270ab1SKenneth D. Merry 89ef270ab1SKenneth D. Merry ocs_node_hold_frames(node); 90ef270ab1SKenneth D. Merry ocs_lock(&node->active_ios_lock); 91ef270ab1SKenneth D. Merry ocs_list_foreach_safe(&node->els_io_active_list, els, els_next) { 92ef270ab1SKenneth D. Merry ocs_log_debug(node->ocs, "[%s] initiate ELS abort %s\n", node->display_name, els->display_name); 93ef270ab1SKenneth D. Merry ocs_unlock(&node->active_ios_lock); 94ef270ab1SKenneth D. Merry cbdata.els = els; 95ef270ab1SKenneth D. Merry ocs_els_post_event(els, OCS_EVT_ABORT_ELS, &cbdata); 96ef270ab1SKenneth D. Merry ocs_lock(&node->active_ios_lock); 97ef270ab1SKenneth D. Merry } 98ef270ab1SKenneth D. Merry ocs_unlock(&node->active_ios_lock); 99ef270ab1SKenneth D. Merry } 100ef270ab1SKenneth D. Merry 101ef270ab1SKenneth D. Merry /** 102ef270ab1SKenneth D. Merry * @ingroup node_common 103ef270ab1SKenneth D. Merry * @brief Handle remote node events from HW 104ef270ab1SKenneth D. Merry * 105ef270ab1SKenneth D. Merry * Handle remote node events from HW. Essentially the HW event is translated into 106ef270ab1SKenneth D. Merry * a node state machine event that is posted to the affected node. 107ef270ab1SKenneth D. Merry * 108ef270ab1SKenneth D. Merry * @param arg pointer to ocs 109ef270ab1SKenneth D. Merry * @param event HW event to proceoss 110ef270ab1SKenneth D. Merry * @param data application specific data (pointer to the affected node) 111ef270ab1SKenneth D. Merry * 112ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 113ef270ab1SKenneth D. Merry */ 114ef270ab1SKenneth D. Merry int32_t 115ef270ab1SKenneth D. Merry ocs_remote_node_cb(void *arg, ocs_hw_remote_node_event_e event, void *data) 116ef270ab1SKenneth D. Merry { 117ef270ab1SKenneth D. Merry ocs_t *ocs = arg; 118ef270ab1SKenneth D. Merry ocs_sm_event_t sm_event = OCS_EVT_LAST; 119ef270ab1SKenneth D. Merry ocs_remote_node_t *rnode = data; 120ef270ab1SKenneth D. Merry ocs_node_t *node = rnode->node; 121ef270ab1SKenneth D. Merry 122ef270ab1SKenneth D. Merry switch (event) { 123ef270ab1SKenneth D. Merry case OCS_HW_NODE_ATTACH_OK: 124ef270ab1SKenneth D. Merry sm_event = OCS_EVT_NODE_ATTACH_OK; 125ef270ab1SKenneth D. Merry break; 126ef270ab1SKenneth D. Merry 127ef270ab1SKenneth D. Merry case OCS_HW_NODE_ATTACH_FAIL: 128ef270ab1SKenneth D. Merry sm_event = OCS_EVT_NODE_ATTACH_FAIL; 129ef270ab1SKenneth D. Merry break; 130ef270ab1SKenneth D. Merry 131ef270ab1SKenneth D. Merry case OCS_HW_NODE_FREE_OK: 132ef270ab1SKenneth D. Merry sm_event = OCS_EVT_NODE_FREE_OK; 133ef270ab1SKenneth D. Merry break; 134ef270ab1SKenneth D. Merry 135ef270ab1SKenneth D. Merry case OCS_HW_NODE_FREE_FAIL: 136ef270ab1SKenneth D. Merry sm_event = OCS_EVT_NODE_FREE_FAIL; 137ef270ab1SKenneth D. Merry break; 138ef270ab1SKenneth D. Merry 139ef270ab1SKenneth D. Merry default: 140ef270ab1SKenneth D. Merry ocs_log_test(ocs, "unhandled event %#x\n", event); 141ef270ab1SKenneth D. Merry return -1; 142ef270ab1SKenneth D. Merry } 143ef270ab1SKenneth D. Merry 144ef270ab1SKenneth D. Merry /* If we're using HLM, forward the NODE_ATTACH_OK/FAIL event to all nodes in the node group */ 145ef270ab1SKenneth D. Merry if ((node->node_group != NULL) && 146ef270ab1SKenneth D. Merry ((sm_event == OCS_EVT_NODE_ATTACH_OK) || (sm_event == OCS_EVT_NODE_ATTACH_FAIL))) { 147ef270ab1SKenneth D. Merry ocs_node_t *n = NULL; 148ef270ab1SKenneth D. Merry uint8_t attach_ok = sm_event == OCS_EVT_NODE_ATTACH_OK; 149ef270ab1SKenneth D. Merry 150ef270ab1SKenneth D. Merry ocs_sport_lock(node->sport); 151ef270ab1SKenneth D. Merry { 152ef270ab1SKenneth D. Merry ocs_list_foreach(&node->sport->node_list, n) { 153ef270ab1SKenneth D. Merry if (node == n) { 154ef270ab1SKenneth D. Merry continue; 155ef270ab1SKenneth D. Merry } 156ef270ab1SKenneth D. Merry ocs_node_lock(n); 157ef270ab1SKenneth D. Merry if ((!n->rnode.attached) && (node->node_group == n->node_group)) { 158ef270ab1SKenneth D. Merry n->rnode.attached = attach_ok; 159ef270ab1SKenneth D. Merry node_printf(n, "rpi[%d] deferred HLM node attach %s posted\n", 160ef270ab1SKenneth D. Merry n->rnode.index, attach_ok ? "ok" : "fail"); 161ef270ab1SKenneth D. Merry ocs_node_post_event(n, sm_event, NULL); 162ef270ab1SKenneth D. Merry } 163ef270ab1SKenneth D. Merry ocs_node_unlock(n); 164ef270ab1SKenneth D. Merry } 165ef270ab1SKenneth D. Merry } 166ef270ab1SKenneth D. Merry 167ef270ab1SKenneth D. Merry ocs_sport_unlock(node->sport); 168ef270ab1SKenneth D. Merry } 169ef270ab1SKenneth D. Merry 170ef270ab1SKenneth D. Merry ocs_node_post_event(node, sm_event, NULL); 171ef270ab1SKenneth D. Merry 172ef270ab1SKenneth D. Merry return 0; 173ef270ab1SKenneth D. Merry } 174ef270ab1SKenneth D. Merry 175ef270ab1SKenneth D. Merry /** 176ef270ab1SKenneth D. Merry * @ingroup node_alloc 177ef270ab1SKenneth D. Merry * @brief Find an FC node structure given the FC port ID 178ef270ab1SKenneth D. Merry * 179ef270ab1SKenneth D. Merry * @param sport the SPORT to search 180ef270ab1SKenneth D. Merry * @param port_id FC port ID 181ef270ab1SKenneth D. Merry * 182ef270ab1SKenneth D. Merry * @return pointer to the object or NULL if not found 183ef270ab1SKenneth D. Merry */ 184ef270ab1SKenneth D. Merry ocs_node_t * 185ef270ab1SKenneth D. Merry ocs_node_find(ocs_sport_t *sport, uint32_t port_id) 186ef270ab1SKenneth D. Merry { 187ef270ab1SKenneth D. Merry ocs_node_t *node; 188ef270ab1SKenneth D. Merry 189ef270ab1SKenneth D. Merry ocs_assert(sport->lookup, NULL); 190ef270ab1SKenneth D. Merry ocs_sport_lock(sport); 191ef270ab1SKenneth D. Merry node = spv_get(sport->lookup, port_id); 192ef270ab1SKenneth D. Merry ocs_sport_unlock(sport); 193ef270ab1SKenneth D. Merry return node; 194ef270ab1SKenneth D. Merry } 195ef270ab1SKenneth D. Merry 196ef270ab1SKenneth D. Merry /** 197ef270ab1SKenneth D. Merry * @ingroup node_alloc 198ef270ab1SKenneth D. Merry * @brief Find an FC node structure given the WWPN 199ef270ab1SKenneth D. Merry * 200ef270ab1SKenneth D. Merry * @param sport the SPORT to search 201ef270ab1SKenneth D. Merry * @param wwpn the WWPN to search for (host endian) 202ef270ab1SKenneth D. Merry * 203ef270ab1SKenneth D. Merry * @return pointer to the object or NULL if not found 204ef270ab1SKenneth D. Merry */ 205ef270ab1SKenneth D. Merry ocs_node_t * 206ef270ab1SKenneth D. Merry ocs_node_find_wwpn(ocs_sport_t *sport, uint64_t wwpn) 207ef270ab1SKenneth D. Merry { 208*aeb665b5SEd Maste ocs_node_t *node = NULL; 209ef270ab1SKenneth D. Merry 210ef270ab1SKenneth D. Merry ocs_assert(sport, NULL); 211ef270ab1SKenneth D. Merry 212ef270ab1SKenneth D. Merry ocs_sport_lock(sport); 213ef270ab1SKenneth D. Merry ocs_list_foreach(&sport->node_list, node) { 214ef270ab1SKenneth D. Merry if (ocs_node_get_wwpn(node) == wwpn) { 215ef270ab1SKenneth D. Merry ocs_sport_unlock(sport); 216ef270ab1SKenneth D. Merry return node; 217ef270ab1SKenneth D. Merry } 218ef270ab1SKenneth D. Merry } 219ef270ab1SKenneth D. Merry ocs_sport_unlock(sport); 220ef270ab1SKenneth D. Merry return NULL; 221ef270ab1SKenneth D. Merry } 222ef270ab1SKenneth D. Merry 223ef270ab1SKenneth D. Merry /** 224ef270ab1SKenneth D. Merry * @ingroup node_alloc 225ef270ab1SKenneth D. Merry * @brief allocate node object pool 226ef270ab1SKenneth D. Merry * 227ef270ab1SKenneth D. Merry * A pool of ocs_node_t objects is allocated. 228ef270ab1SKenneth D. Merry * 229ef270ab1SKenneth D. Merry * @param ocs pointer to driver instance context 230ef270ab1SKenneth D. Merry * @param node_count count of nodes to allocate 231ef270ab1SKenneth D. Merry * 232ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 233ef270ab1SKenneth D. Merry */ 234ef270ab1SKenneth D. Merry 235ef270ab1SKenneth D. Merry int32_t 236ef270ab1SKenneth D. Merry ocs_node_create_pool(ocs_t *ocs, uint32_t node_count) 237ef270ab1SKenneth D. Merry { 238ef270ab1SKenneth D. Merry ocs_xport_t *xport = ocs->xport; 239ef270ab1SKenneth D. Merry uint32_t i; 240ef270ab1SKenneth D. Merry ocs_node_t *node; 241ef270ab1SKenneth D. Merry uint32_t max_sge; 242ef270ab1SKenneth D. Merry uint32_t num_sgl; 243ef270ab1SKenneth D. Merry uint64_t max_xfer_size; 244ef270ab1SKenneth D. Merry int32_t rc; 245ef270ab1SKenneth D. Merry 246ef270ab1SKenneth D. Merry xport->nodes_count = node_count; 247ef270ab1SKenneth D. Merry 248ef270ab1SKenneth D. Merry xport->nodes = ocs_malloc(ocs, node_count * sizeof(ocs_node_t *), OCS_M_ZERO | OCS_M_NOWAIT); 249ef270ab1SKenneth D. Merry if (xport->nodes == NULL) { 250ef270ab1SKenneth D. Merry ocs_log_err(ocs, "node ptrs allocation failed"); 251ef270ab1SKenneth D. Merry return -1; 252ef270ab1SKenneth D. Merry } 253ef270ab1SKenneth D. Merry 254ef270ab1SKenneth D. Merry if (0 == ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGE, &max_sge) && 255ef270ab1SKenneth D. Merry 0 == ocs_hw_get(&ocs->hw, OCS_HW_N_SGL, &num_sgl)) { 2564915e5c7SRam Kishore Vegesna max_xfer_size = (max_sge * (uint64_t)num_sgl); 257ef270ab1SKenneth D. Merry } else { 258ef270ab1SKenneth D. Merry max_xfer_size = 65536; 259ef270ab1SKenneth D. Merry } 260ef270ab1SKenneth D. Merry 261ef270ab1SKenneth D. Merry if (max_xfer_size > 65536) 262ef270ab1SKenneth D. Merry max_xfer_size = 65536; 263ef270ab1SKenneth D. Merry 264ef270ab1SKenneth D. Merry ocs_list_init(&xport->nodes_free_list, ocs_node_t, link); 265ef270ab1SKenneth D. Merry 266ef270ab1SKenneth D. Merry 267ef270ab1SKenneth D. Merry for (i = 0; i < node_count; i ++) { 268ef270ab1SKenneth D. Merry node = ocs_malloc(ocs, sizeof(ocs_node_t), OCS_M_ZERO | OCS_M_NOWAIT); 269ef270ab1SKenneth D. Merry if (node == NULL) { 270ef270ab1SKenneth D. Merry ocs_log_err(ocs, "node allocation failed"); 271ef270ab1SKenneth D. Merry goto error; 272ef270ab1SKenneth D. Merry } 273ef270ab1SKenneth D. Merry 274ef270ab1SKenneth D. Merry /* Assign any persistent field values */ 275ef270ab1SKenneth D. Merry node->instance_index = i; 276ef270ab1SKenneth D. Merry node->max_wr_xfer_size = max_xfer_size; 277ef270ab1SKenneth D. Merry node->rnode.indicator = UINT32_MAX; 278ef270ab1SKenneth D. Merry 279ef270ab1SKenneth D. Merry rc = ocs_dma_alloc(ocs, &node->sparm_dma_buf, 256, 16); 280ef270ab1SKenneth D. Merry if (rc) { 281ef270ab1SKenneth D. Merry ocs_free(ocs, node, sizeof(ocs_node_t)); 282ef270ab1SKenneth D. Merry ocs_log_err(ocs, "ocs_dma_alloc failed: %d\n", rc); 283ef270ab1SKenneth D. Merry goto error; 284ef270ab1SKenneth D. Merry } 285ef270ab1SKenneth D. Merry 286ef270ab1SKenneth D. Merry xport->nodes[i] = node; 287ef270ab1SKenneth D. Merry ocs_list_add_tail(&xport->nodes_free_list, node); 288ef270ab1SKenneth D. Merry } 289ef270ab1SKenneth D. Merry return 0; 290ef270ab1SKenneth D. Merry 291ef270ab1SKenneth D. Merry error: 292ef270ab1SKenneth D. Merry ocs_node_free_pool(ocs); 293ef270ab1SKenneth D. Merry return -1; 294ef270ab1SKenneth D. Merry } 295ef270ab1SKenneth D. Merry 296ef270ab1SKenneth D. Merry /** 297ef270ab1SKenneth D. Merry * @ingroup node_alloc 298ef270ab1SKenneth D. Merry * @brief free node object pool 299ef270ab1SKenneth D. Merry * 300ef270ab1SKenneth D. Merry * The pool of previously allocated node objects is freed 301ef270ab1SKenneth D. Merry * 302ef270ab1SKenneth D. Merry * @param ocs pointer to driver instance context 303ef270ab1SKenneth D. Merry * 304ef270ab1SKenneth D. Merry * @return none 305ef270ab1SKenneth D. Merry */ 306ef270ab1SKenneth D. Merry 307ef270ab1SKenneth D. Merry void 308ef270ab1SKenneth D. Merry ocs_node_free_pool(ocs_t *ocs) 309ef270ab1SKenneth D. Merry { 310ef270ab1SKenneth D. Merry ocs_xport_t *xport = ocs->xport; 311ef270ab1SKenneth D. Merry ocs_node_t *node; 312ef270ab1SKenneth D. Merry uint32_t i; 313ef270ab1SKenneth D. Merry 314ef270ab1SKenneth D. Merry if (!xport->nodes) 315ef270ab1SKenneth D. Merry return; 316ef270ab1SKenneth D. Merry 317ef270ab1SKenneth D. Merry ocs_device_lock(ocs); 318ef270ab1SKenneth D. Merry 319ef270ab1SKenneth D. Merry for (i = 0; i < xport->nodes_count; i ++) { 320ef270ab1SKenneth D. Merry node = xport->nodes[i]; 321ef270ab1SKenneth D. Merry if (node) { 322ef270ab1SKenneth D. Merry /* free sparam_dma_buf */ 323ef270ab1SKenneth D. Merry ocs_dma_free(ocs, &node->sparm_dma_buf); 324ef270ab1SKenneth D. Merry ocs_free(ocs, node, sizeof(ocs_node_t)); 325ef270ab1SKenneth D. Merry } 326ef270ab1SKenneth D. Merry xport->nodes[i] = NULL; 327ef270ab1SKenneth D. Merry } 328ef270ab1SKenneth D. Merry 329ef270ab1SKenneth D. Merry ocs_free(ocs, xport->nodes, (xport->nodes_count * sizeof(ocs_node_t *))); 330ef270ab1SKenneth D. Merry 331ef270ab1SKenneth D. Merry ocs_device_unlock(ocs); 332ef270ab1SKenneth D. Merry } 333ef270ab1SKenneth D. Merry 334ef270ab1SKenneth D. Merry /** 335ef270ab1SKenneth D. Merry * @ingroup node_alloc 336ef270ab1SKenneth D. Merry * @brief return pointer to node object given instance index 337ef270ab1SKenneth D. Merry * 338ef270ab1SKenneth D. Merry * A pointer to the node object given by an instance index is returned. 339ef270ab1SKenneth D. Merry * 340ef270ab1SKenneth D. Merry * @param ocs pointer to driver instance context 341ef270ab1SKenneth D. Merry * @param index instance index 342ef270ab1SKenneth D. Merry * 343ef270ab1SKenneth D. Merry * @return returns pointer to node object, or NULL 344ef270ab1SKenneth D. Merry */ 345ef270ab1SKenneth D. Merry 346ef270ab1SKenneth D. Merry ocs_node_t * 347ef270ab1SKenneth D. Merry ocs_node_get_instance(ocs_t *ocs, uint32_t index) 348ef270ab1SKenneth D. Merry { 349ef270ab1SKenneth D. Merry ocs_xport_t *xport = ocs->xport; 350ef270ab1SKenneth D. Merry ocs_node_t *node = NULL; 351ef270ab1SKenneth D. Merry 352ef270ab1SKenneth D. Merry if (index >= (xport->nodes_count)) { 353ef270ab1SKenneth D. Merry ocs_log_test(ocs, "invalid index: %d\n", index); 354ef270ab1SKenneth D. Merry return NULL; 355ef270ab1SKenneth D. Merry } 356ef270ab1SKenneth D. Merry node = xport->nodes[index]; 357ef270ab1SKenneth D. Merry return node->attached ? node : NULL; 358ef270ab1SKenneth D. Merry } 359ef270ab1SKenneth D. Merry 360ef270ab1SKenneth D. Merry /** 361ef270ab1SKenneth D. Merry * @ingroup node_alloc 362ef270ab1SKenneth D. Merry * @brief Allocate an fc node structure and add to node list 363ef270ab1SKenneth D. Merry * 364ef270ab1SKenneth D. Merry * @param sport pointer to the SPORT from which this node is allocated 365ef270ab1SKenneth D. Merry * @param port_id FC port ID of new node 366ef270ab1SKenneth D. Merry * @param init Port is an inititiator (sent a plogi) 367ef270ab1SKenneth D. Merry * @param targ Port is potentially a target 368ef270ab1SKenneth D. Merry * 369ef270ab1SKenneth D. Merry * @return pointer to the object or NULL if none available 370ef270ab1SKenneth D. Merry */ 371ef270ab1SKenneth D. Merry 372ef270ab1SKenneth D. Merry ocs_node_t * 373ef270ab1SKenneth D. Merry ocs_node_alloc(ocs_sport_t *sport, uint32_t port_id, uint8_t init, uint8_t targ) 374ef270ab1SKenneth D. Merry { 375ef270ab1SKenneth D. Merry int32_t rc; 376ef270ab1SKenneth D. Merry ocs_node_t *node = NULL; 377ef270ab1SKenneth D. Merry uint32_t instance_index; 378ef270ab1SKenneth D. Merry uint32_t max_wr_xfer_size; 379ef270ab1SKenneth D. Merry ocs_t *ocs = sport->ocs; 380ef270ab1SKenneth D. Merry ocs_xport_t *xport = ocs->xport; 381ef270ab1SKenneth D. Merry ocs_dma_t sparm_dma_buf; 382ef270ab1SKenneth D. Merry 383ef270ab1SKenneth D. Merry ocs_assert(sport, NULL); 384ef270ab1SKenneth D. Merry 385ef270ab1SKenneth D. Merry if (sport->shutting_down) { 386ef270ab1SKenneth D. Merry ocs_log_debug(ocs, "node allocation when shutting down %06x", port_id); 387ef270ab1SKenneth D. Merry return NULL; 388ef270ab1SKenneth D. Merry } 389ef270ab1SKenneth D. Merry 390ef270ab1SKenneth D. Merry ocs_device_lock(ocs); 391ef270ab1SKenneth D. Merry node = ocs_list_remove_head(&xport->nodes_free_list); 392ef270ab1SKenneth D. Merry ocs_device_unlock(ocs); 393ef270ab1SKenneth D. Merry if (node == NULL) { 394ef270ab1SKenneth D. Merry ocs_log_err(ocs, "node allocation failed %06x", port_id); 395ef270ab1SKenneth D. Merry return NULL; 396ef270ab1SKenneth D. Merry } 397ef270ab1SKenneth D. Merry 398ef270ab1SKenneth D. Merry /* Save persistent values across memset zero */ 399ef270ab1SKenneth D. Merry instance_index = node->instance_index; 400ef270ab1SKenneth D. Merry max_wr_xfer_size = node->max_wr_xfer_size; 401ef270ab1SKenneth D. Merry sparm_dma_buf = node->sparm_dma_buf; 402ef270ab1SKenneth D. Merry 403ef270ab1SKenneth D. Merry ocs_memset(node, 0, sizeof(*node)); 404ef270ab1SKenneth D. Merry node->instance_index = instance_index; 405ef270ab1SKenneth D. Merry node->max_wr_xfer_size = max_wr_xfer_size; 406ef270ab1SKenneth D. Merry node->sparm_dma_buf = sparm_dma_buf; 407ef270ab1SKenneth D. Merry node->rnode.indicator = UINT32_MAX; 408ef270ab1SKenneth D. Merry 409ef270ab1SKenneth D. Merry node->sport = sport; 410ef270ab1SKenneth D. Merry ocs_sport_lock(sport); 411ef270ab1SKenneth D. Merry 412ef270ab1SKenneth D. Merry node->ocs = ocs; 413ef270ab1SKenneth D. Merry node->init = init; 414ef270ab1SKenneth D. Merry node->targ = targ; 415ef270ab1SKenneth D. Merry 416ef270ab1SKenneth D. Merry rc = ocs_hw_node_alloc(&ocs->hw, &node->rnode, port_id, sport); 417ef270ab1SKenneth D. Merry if (rc) { 418ef270ab1SKenneth D. Merry ocs_log_err(ocs, "ocs_hw_node_alloc failed: %d\n", rc); 419ef270ab1SKenneth D. Merry ocs_sport_unlock(sport); 420ef270ab1SKenneth D. Merry 421ef270ab1SKenneth D. Merry /* Return back to pool. */ 422ef270ab1SKenneth D. Merry ocs_device_lock(ocs); 423ef270ab1SKenneth D. Merry ocs_list_add_tail(&xport->nodes_free_list, node); 424ef270ab1SKenneth D. Merry ocs_device_unlock(ocs); 425ef270ab1SKenneth D. Merry 426ef270ab1SKenneth D. Merry return NULL; 427ef270ab1SKenneth D. Merry } 428ef270ab1SKenneth D. Merry ocs_list_add_tail(&sport->node_list, node); 429ef270ab1SKenneth D. Merry 430ef270ab1SKenneth D. Merry ocs_node_lock_init(node); 431ef270ab1SKenneth D. Merry ocs_lock_init(ocs, &node->pend_frames_lock, "pend_frames_lock[%d]", node->instance_index); 432ef270ab1SKenneth D. Merry ocs_list_init(&node->pend_frames, ocs_hw_sequence_t, link); 433ef270ab1SKenneth D. Merry ocs_lock_init(ocs, &node->active_ios_lock, "active_ios[%d]", node->instance_index); 434ef270ab1SKenneth D. Merry ocs_list_init(&node->active_ios, ocs_io_t, link); 435ef270ab1SKenneth D. Merry ocs_list_init(&node->els_io_pend_list, ocs_io_t, link); 436ef270ab1SKenneth D. Merry ocs_list_init(&node->els_io_active_list, ocs_io_t, link); 437ef270ab1SKenneth D. Merry ocs_scsi_io_alloc_enable(node); 438ef270ab1SKenneth D. Merry 439ef270ab1SKenneth D. Merry /* zero the service parameters */ 440ef270ab1SKenneth D. Merry ocs_memset(node->sparm_dma_buf.virt, 0, node->sparm_dma_buf.size); 441ef270ab1SKenneth D. Merry 442ef270ab1SKenneth D. Merry node->rnode.node = node; 443ef270ab1SKenneth D. Merry node->sm.app = node; 444ef270ab1SKenneth D. Merry node->evtdepth = 0; 445ef270ab1SKenneth D. Merry 446ef270ab1SKenneth D. Merry ocs_node_update_display_name(node); 447ef270ab1SKenneth D. Merry 448ef270ab1SKenneth D. Merry spv_set(sport->lookup, port_id, node); 449ef270ab1SKenneth D. Merry ocs_sport_unlock(sport); 450ef270ab1SKenneth D. Merry node->mgmt_functions = &node_mgmt_functions; 451ef270ab1SKenneth D. Merry 452ef270ab1SKenneth D. Merry return node; 453ef270ab1SKenneth D. Merry } 454ef270ab1SKenneth D. Merry 455ef270ab1SKenneth D. Merry /** 456ef270ab1SKenneth D. Merry * @ingroup node_alloc 457ef270ab1SKenneth D. Merry * @brief free a node structure 458ef270ab1SKenneth D. Merry * 459ef270ab1SKenneth D. Merry * The node structure given by 'node' is free'd 460ef270ab1SKenneth D. Merry * 461ef270ab1SKenneth D. Merry * @param node the node to free 462ef270ab1SKenneth D. Merry * 463ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 464ef270ab1SKenneth D. Merry */ 465ef270ab1SKenneth D. Merry 466ef270ab1SKenneth D. Merry int32_t 467ef270ab1SKenneth D. Merry ocs_node_free(ocs_node_t *node) 468ef270ab1SKenneth D. Merry { 469ef270ab1SKenneth D. Merry ocs_sport_t *sport; 470ef270ab1SKenneth D. Merry ocs_t *ocs; 471ef270ab1SKenneth D. Merry ocs_xport_t *xport; 472ef270ab1SKenneth D. Merry ocs_hw_rtn_e rc = 0; 473ef270ab1SKenneth D. Merry ocs_node_t *ns = NULL; 474ef270ab1SKenneth D. Merry int post_all_free = FALSE; 475ef270ab1SKenneth D. Merry 476ef270ab1SKenneth D. Merry ocs_assert(node, -1); 477ef270ab1SKenneth D. Merry ocs_assert(node->sport, -1); 478ef270ab1SKenneth D. Merry ocs_assert(node->ocs, -1); 479ef270ab1SKenneth D. Merry sport = node->sport; 480ef270ab1SKenneth D. Merry ocs_assert(sport, -1); 481ef270ab1SKenneth D. Merry ocs = node->ocs; 482ef270ab1SKenneth D. Merry ocs_assert(ocs->xport, -1); 483ef270ab1SKenneth D. Merry xport = ocs->xport; 484ef270ab1SKenneth D. Merry 485ef270ab1SKenneth D. Merry node_printf(node, "Free'd\n"); 486ef270ab1SKenneth D. Merry 487ef270ab1SKenneth D. Merry if(node->refound) { 488ef270ab1SKenneth D. Merry /* 489ef270ab1SKenneth D. Merry * Save the name server node. We will send fake RSCN event at 490ef270ab1SKenneth D. Merry * the end to handle ignored RSCN event during node deletion 491ef270ab1SKenneth D. Merry */ 492ef270ab1SKenneth D. Merry ns = ocs_node_find(node->sport, FC_ADDR_NAMESERVER); 493ef270ab1SKenneth D. Merry } 494ef270ab1SKenneth D. Merry 495ef270ab1SKenneth D. Merry /* Remove from node list */ 496ef270ab1SKenneth D. Merry ocs_sport_lock(sport); 497ef270ab1SKenneth D. Merry ocs_list_remove(&sport->node_list, node); 498ef270ab1SKenneth D. Merry 499ef270ab1SKenneth D. Merry /* Free HW resources */ 500ef270ab1SKenneth D. Merry if (OCS_HW_RTN_IS_ERROR((rc = ocs_hw_node_free_resources(&ocs->hw, &node->rnode)))) { 501ef270ab1SKenneth D. Merry ocs_log_test(ocs, "ocs_hw_node_free failed: %d\n", rc); 502ef270ab1SKenneth D. Merry rc = -1; 503ef270ab1SKenneth D. Merry } 504ef270ab1SKenneth D. Merry 505ef270ab1SKenneth D. Merry /* if the gidpt_delay_timer is still running, then delete it */ 506ef270ab1SKenneth D. Merry if (ocs_timer_pending(&node->gidpt_delay_timer)) { 507ef270ab1SKenneth D. Merry ocs_del_timer(&node->gidpt_delay_timer); 508ef270ab1SKenneth D. Merry } 509ef270ab1SKenneth D. Merry 510ef270ab1SKenneth D. Merry if (node->fcp2device) { 511ef270ab1SKenneth D. Merry ocs_del_crn(node); 512ef270ab1SKenneth D. Merry } 513ef270ab1SKenneth D. Merry 514ef270ab1SKenneth D. Merry /* remove entry from sparse vector list */ 515ef270ab1SKenneth D. Merry if (sport->lookup == NULL) { 516ef270ab1SKenneth D. Merry ocs_log_test(node->ocs, "assertion failed: sport lookup is NULL\n"); 517ef270ab1SKenneth D. Merry ocs_sport_unlock(sport); 518ef270ab1SKenneth D. Merry return -1; 519ef270ab1SKenneth D. Merry } 520ef270ab1SKenneth D. Merry 521ef270ab1SKenneth D. Merry spv_set(sport->lookup, node->rnode.fc_id, NULL); 522ef270ab1SKenneth D. Merry 523ef270ab1SKenneth D. Merry /* 524ef270ab1SKenneth D. Merry * If the node_list is empty, then post a ALL_CHILD_NODES_FREE event to the sport, 525ef270ab1SKenneth D. Merry * after the lock is released. The sport may be free'd as a result of the event. 526ef270ab1SKenneth D. Merry */ 527ef270ab1SKenneth D. Merry if (ocs_list_empty(&sport->node_list)) { 528ef270ab1SKenneth D. Merry post_all_free = TRUE; 529ef270ab1SKenneth D. Merry } 530ef270ab1SKenneth D. Merry 531ef270ab1SKenneth D. Merry ocs_sport_unlock(sport); 532ef270ab1SKenneth D. Merry 533ef270ab1SKenneth D. Merry if (post_all_free) { 534ef270ab1SKenneth D. Merry ocs_sm_post_event(&sport->sm, OCS_EVT_ALL_CHILD_NODES_FREE, NULL); 535ef270ab1SKenneth D. Merry } 536ef270ab1SKenneth D. Merry 537ef270ab1SKenneth D. Merry node->sport = NULL; 538ef270ab1SKenneth D. Merry node->sm.current_state = NULL; 539ef270ab1SKenneth D. Merry 540ef270ab1SKenneth D. Merry ocs_node_lock_free(node); 541ef270ab1SKenneth D. Merry ocs_lock_free(&node->pend_frames_lock); 542ef270ab1SKenneth D. Merry ocs_lock_free(&node->active_ios_lock); 543ef270ab1SKenneth D. Merry 544ef270ab1SKenneth D. Merry /* return to free list */ 545ef270ab1SKenneth D. Merry ocs_device_lock(ocs); 546ef270ab1SKenneth D. Merry ocs_list_add_tail(&xport->nodes_free_list, node); 547ef270ab1SKenneth D. Merry ocs_device_unlock(ocs); 548ef270ab1SKenneth D. Merry 549ef270ab1SKenneth D. Merry if(ns != NULL) { 550ef270ab1SKenneth D. Merry /* sending fake RSCN event to name server node */ 551ef270ab1SKenneth D. Merry ocs_node_post_event(ns, OCS_EVT_RSCN_RCVD, NULL); 552ef270ab1SKenneth D. Merry } 553ef270ab1SKenneth D. Merry 554ef270ab1SKenneth D. Merry return rc; 555ef270ab1SKenneth D. Merry } 556ef270ab1SKenneth D. Merry 557ef270ab1SKenneth D. Merry /** 558ef270ab1SKenneth D. Merry * @brief free memory resources of a node object 559ef270ab1SKenneth D. Merry * 560ef270ab1SKenneth D. Merry * The node object's child objects are freed after which the 561ef270ab1SKenneth D. Merry * node object is freed. 562ef270ab1SKenneth D. Merry * 563ef270ab1SKenneth D. Merry * @param node pointer to a node object 564ef270ab1SKenneth D. Merry * 565ef270ab1SKenneth D. Merry * @return none 566ef270ab1SKenneth D. Merry */ 567ef270ab1SKenneth D. Merry 568ef270ab1SKenneth D. Merry void 569ef270ab1SKenneth D. Merry ocs_node_force_free(ocs_node_t *node) 570ef270ab1SKenneth D. Merry { 571ef270ab1SKenneth D. Merry ocs_io_t *io; 572ef270ab1SKenneth D. Merry ocs_io_t *next; 573ef270ab1SKenneth D. Merry ocs_io_t *els; 574ef270ab1SKenneth D. Merry ocs_io_t *els_next; 575ef270ab1SKenneth D. Merry 576ef270ab1SKenneth D. Merry /* shutdown sm processing */ 577ef270ab1SKenneth D. Merry ocs_sm_disable(&node->sm); 578ef270ab1SKenneth D. Merry ocs_strncpy(node->prev_state_name, node->current_state_name, sizeof(node->prev_state_name)); 579ef270ab1SKenneth D. Merry ocs_strncpy(node->current_state_name, "disabled", sizeof(node->current_state_name)); 580ef270ab1SKenneth D. Merry 581ef270ab1SKenneth D. Merry /* Let the backend cleanup if needed */ 582ef270ab1SKenneth D. Merry ocs_scsi_notify_node_force_free(node); 583ef270ab1SKenneth D. Merry 584ef270ab1SKenneth D. Merry ocs_lock(&node->active_ios_lock); 585ef270ab1SKenneth D. Merry ocs_list_foreach_safe(&node->active_ios, io, next) { 586ef270ab1SKenneth D. Merry ocs_list_remove(&io->node->active_ios, io); 587ef270ab1SKenneth D. Merry ocs_io_free(node->ocs, io); 588ef270ab1SKenneth D. Merry } 589ef270ab1SKenneth D. Merry ocs_unlock(&node->active_ios_lock); 590ef270ab1SKenneth D. Merry 591ef270ab1SKenneth D. Merry /* free all pending ELS IOs */ 592ef270ab1SKenneth D. Merry ocs_lock(&node->active_ios_lock); 593ef270ab1SKenneth D. Merry ocs_list_foreach_safe(&node->els_io_pend_list, els, els_next) { 594ef270ab1SKenneth D. Merry /* can't call ocs_els_io_free() because lock is held; cleanup manually */ 595ef270ab1SKenneth D. Merry ocs_list_remove(&node->els_io_pend_list, els); 596ef270ab1SKenneth D. Merry 597ef270ab1SKenneth D. Merry ocs_io_free(node->ocs, els); 598ef270ab1SKenneth D. Merry } 599ef270ab1SKenneth D. Merry ocs_unlock(&node->active_ios_lock); 600ef270ab1SKenneth D. Merry 601ef270ab1SKenneth D. Merry /* free all active ELS IOs */ 602ef270ab1SKenneth D. Merry ocs_lock(&node->active_ios_lock); 603ef270ab1SKenneth D. Merry ocs_list_foreach_safe(&node->els_io_active_list, els, els_next) { 604ef270ab1SKenneth D. Merry /* can't call ocs_els_io_free() because lock is held; cleanup manually */ 605ef270ab1SKenneth D. Merry ocs_list_remove(&node->els_io_active_list, els); 606ef270ab1SKenneth D. Merry 607ef270ab1SKenneth D. Merry ocs_io_free(node->ocs, els); 608ef270ab1SKenneth D. Merry } 609ef270ab1SKenneth D. Merry ocs_unlock(&node->active_ios_lock); 610ef270ab1SKenneth D. Merry 611ef270ab1SKenneth D. Merry /* manually purge pending frames (if any) */ 612ef270ab1SKenneth D. Merry ocs_node_purge_pending(node); 613ef270ab1SKenneth D. Merry 614ef270ab1SKenneth D. Merry ocs_node_free(node); 615ef270ab1SKenneth D. Merry } 616ef270ab1SKenneth D. Merry 617ef270ab1SKenneth D. Merry /** 618ef270ab1SKenneth D. Merry * @ingroup node_common 619ef270ab1SKenneth D. Merry * @brief Perform HW call to attach a remote node 620ef270ab1SKenneth D. Merry * 621ef270ab1SKenneth D. Merry * @param node pointer to node object 622ef270ab1SKenneth D. Merry * 623ef270ab1SKenneth D. Merry * @return 0 on success, non-zero otherwise 624ef270ab1SKenneth D. Merry */ 625ef270ab1SKenneth D. Merry int32_t 626ef270ab1SKenneth D. Merry ocs_node_attach(ocs_node_t *node) 627ef270ab1SKenneth D. Merry { 628ef270ab1SKenneth D. Merry int32_t rc = 0; 629ef270ab1SKenneth D. Merry ocs_sport_t *sport = node->sport; 630ef270ab1SKenneth D. Merry ocs_domain_t *domain = sport->domain; 631ef270ab1SKenneth D. Merry ocs_t *ocs = node->ocs; 632ef270ab1SKenneth D. Merry 633ef270ab1SKenneth D. Merry if (!domain->attached) { 634ef270ab1SKenneth D. Merry ocs_log_test(ocs, "Warning: ocs_node_attach with unattached domain\n"); 635ef270ab1SKenneth D. Merry return -1; 636ef270ab1SKenneth D. Merry } 637ef270ab1SKenneth D. Merry /* Update node->wwpn/wwnn */ 638ef270ab1SKenneth D. Merry 639ef270ab1SKenneth D. Merry ocs_node_build_eui_name(node->wwpn, sizeof(node->wwpn), ocs_node_get_wwpn(node)); 640ef270ab1SKenneth D. Merry ocs_node_build_eui_name(node->wwnn, sizeof(node->wwnn), ocs_node_get_wwnn(node)); 641ef270ab1SKenneth D. Merry 642ef270ab1SKenneth D. Merry if (ocs->enable_hlm) { 643ef270ab1SKenneth D. Merry ocs_node_group_init(node); 644ef270ab1SKenneth D. Merry } 645ef270ab1SKenneth D. Merry 646ef270ab1SKenneth D. Merry ocs_dma_copy_in(&node->sparm_dma_buf, node->service_params+4, sizeof(node->service_params)-4); 647ef270ab1SKenneth D. Merry 648ef270ab1SKenneth D. Merry /* take lock to protect node->rnode.attached */ 649ef270ab1SKenneth D. Merry ocs_node_lock(node); 650ef270ab1SKenneth D. Merry rc = ocs_hw_node_attach(&ocs->hw, &node->rnode, &node->sparm_dma_buf); 651ef270ab1SKenneth D. Merry if (OCS_HW_RTN_IS_ERROR(rc)) { 652ef270ab1SKenneth D. Merry ocs_log_test(ocs, "ocs_hw_node_attach failed: %d\n", rc); 653ef270ab1SKenneth D. Merry } 654ef270ab1SKenneth D. Merry ocs_node_unlock(node); 655ef270ab1SKenneth D. Merry 656ef270ab1SKenneth D. Merry return rc; 657ef270ab1SKenneth D. Merry } 658ef270ab1SKenneth D. Merry 659ef270ab1SKenneth D. Merry /** 660ef270ab1SKenneth D. Merry * @ingroup node_common 661ef270ab1SKenneth D. Merry * @brief Generate text for a node's fc_id 662ef270ab1SKenneth D. Merry * 663ef270ab1SKenneth D. Merry * The text for a nodes fc_id is generated, either as a well known name, or a 6 digit 664ef270ab1SKenneth D. Merry * hex value. 665ef270ab1SKenneth D. Merry * 666ef270ab1SKenneth D. Merry * @param fc_id fc_id 667ef270ab1SKenneth D. Merry * @param buffer text buffer 668ef270ab1SKenneth D. Merry * @param buffer_length text buffer length in bytes 669ef270ab1SKenneth D. Merry * 670ef270ab1SKenneth D. Merry * @return none 671ef270ab1SKenneth D. Merry */ 672ef270ab1SKenneth D. Merry 673ef270ab1SKenneth D. Merry void 674ef270ab1SKenneth D. Merry ocs_node_fcid_display(uint32_t fc_id, char *buffer, uint32_t buffer_length) 675ef270ab1SKenneth D. Merry { 676ef270ab1SKenneth D. Merry switch (fc_id) { 677ef270ab1SKenneth D. Merry case FC_ADDR_FABRIC: 678ef270ab1SKenneth D. Merry ocs_snprintf(buffer, buffer_length, "fabric"); 679ef270ab1SKenneth D. Merry break; 680ef270ab1SKenneth D. Merry case FC_ADDR_CONTROLLER: 681ef270ab1SKenneth D. Merry ocs_snprintf(buffer, buffer_length, "fabctl"); 682ef270ab1SKenneth D. Merry break; 683ef270ab1SKenneth D. Merry case FC_ADDR_NAMESERVER: 684ef270ab1SKenneth D. Merry ocs_snprintf(buffer, buffer_length, "nserve"); 685ef270ab1SKenneth D. Merry break; 686ef270ab1SKenneth D. Merry default: 687ef270ab1SKenneth D. Merry if (FC_ADDR_IS_DOMAIN_CTRL(fc_id)) { 688ef270ab1SKenneth D. Merry ocs_snprintf(buffer, buffer_length, "dctl%02x", 689ef270ab1SKenneth D. Merry FC_ADDR_GET_DOMAIN_CTRL(fc_id)); 690ef270ab1SKenneth D. Merry } else { 691ef270ab1SKenneth D. Merry ocs_snprintf(buffer, buffer_length, "%06x", fc_id); 692ef270ab1SKenneth D. Merry } 693ef270ab1SKenneth D. Merry break; 694ef270ab1SKenneth D. Merry } 695ef270ab1SKenneth D. Merry 696ef270ab1SKenneth D. Merry } 697ef270ab1SKenneth D. Merry 698ef270ab1SKenneth D. Merry /** 699ef270ab1SKenneth D. Merry * @brief update the node's display name 700ef270ab1SKenneth D. Merry * 701ef270ab1SKenneth D. Merry * The node's display name is updated, sometimes needed because the sport part 702ef270ab1SKenneth D. Merry * is updated after the node is allocated. 703ef270ab1SKenneth D. Merry * 704ef270ab1SKenneth D. Merry * @param node pointer to the node object 705ef270ab1SKenneth D. Merry * 706ef270ab1SKenneth D. Merry * @return none 707ef270ab1SKenneth D. Merry */ 708ef270ab1SKenneth D. Merry 709ef270ab1SKenneth D. Merry void 710ef270ab1SKenneth D. Merry ocs_node_update_display_name(ocs_node_t *node) 711ef270ab1SKenneth D. Merry { 712ef270ab1SKenneth D. Merry uint32_t port_id = node->rnode.fc_id; 713ef270ab1SKenneth D. Merry ocs_sport_t *sport = node->sport; 714ef270ab1SKenneth D. Merry char portid_display[16]; 715ef270ab1SKenneth D. Merry 716ef270ab1SKenneth D. Merry ocs_assert(sport); 717ef270ab1SKenneth D. Merry 718ef270ab1SKenneth D. Merry ocs_node_fcid_display(port_id, portid_display, sizeof(portid_display)); 719ef270ab1SKenneth D. Merry 720ef270ab1SKenneth D. Merry ocs_snprintf(node->display_name, sizeof(node->display_name), "%s.%s", sport->display_name, portid_display); 721ef270ab1SKenneth D. Merry } 722ef270ab1SKenneth D. Merry 723ef270ab1SKenneth D. Merry /** 724ef270ab1SKenneth D. Merry * @brief cleans up an XRI for the pending link services accept by aborting the 725ef270ab1SKenneth D. Merry * XRI if required. 726ef270ab1SKenneth D. Merry * 727ef270ab1SKenneth D. Merry * <h3 class="desc">Description</h3> 728ef270ab1SKenneth D. Merry * This function is called when the LS accept is not sent. 729ef270ab1SKenneth D. Merry * 730ef270ab1SKenneth D. Merry * @param node Node for which should be cleaned up 731ef270ab1SKenneth D. Merry */ 732ef270ab1SKenneth D. Merry 733ef270ab1SKenneth D. Merry void 734ef270ab1SKenneth D. Merry ocs_node_send_ls_io_cleanup(ocs_node_t *node) 735ef270ab1SKenneth D. Merry { 736ef270ab1SKenneth D. Merry ocs_t *ocs = node->ocs; 737ef270ab1SKenneth D. Merry 738ef270ab1SKenneth D. Merry if (node->send_ls_acc != OCS_NODE_SEND_LS_ACC_NONE) { 739ef270ab1SKenneth D. Merry ocs_assert(node->ls_acc_io); 740ef270ab1SKenneth D. Merry ocs_log_debug(ocs, "[%s] cleaning up LS_ACC oxid=0x%x\n", 741ef270ab1SKenneth D. Merry node->display_name, node->ls_acc_oxid); 742ef270ab1SKenneth D. Merry 743ef270ab1SKenneth D. Merry node->ls_acc_io->hio = NULL; 744ef270ab1SKenneth D. Merry ocs_els_io_free(node->ls_acc_io); 745ef270ab1SKenneth D. Merry node->send_ls_acc = OCS_NODE_SEND_LS_ACC_NONE; 746ef270ab1SKenneth D. Merry node->ls_acc_io = NULL; 747ef270ab1SKenneth D. Merry } 748ef270ab1SKenneth D. Merry } 749ef270ab1SKenneth D. Merry 750ef270ab1SKenneth D. Merry /** 751ef270ab1SKenneth D. Merry * @ingroup node_common 752ef270ab1SKenneth D. Merry * @brief state: shutdown a node 753ef270ab1SKenneth D. Merry * 754ef270ab1SKenneth D. Merry * A node is shutdown, 755ef270ab1SKenneth D. Merry * 756ef270ab1SKenneth D. Merry * @param ctx remote node sm context 757ef270ab1SKenneth D. Merry * @param evt event to process 758ef270ab1SKenneth D. Merry * @param arg per event optional argument 759ef270ab1SKenneth D. Merry * 760ef270ab1SKenneth D. Merry * @return returns NULL 761ef270ab1SKenneth D. Merry * 762ef270ab1SKenneth D. Merry * @note 763ef270ab1SKenneth D. Merry */ 764ef270ab1SKenneth D. Merry 765ef270ab1SKenneth D. Merry void * 766ef270ab1SKenneth D. Merry __ocs_node_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 767ef270ab1SKenneth D. Merry { 768ef270ab1SKenneth D. Merry int32_t rc; 769ef270ab1SKenneth D. Merry std_node_state_decl(); 770ef270ab1SKenneth D. Merry 771ef270ab1SKenneth D. Merry node_sm_trace(); 772ef270ab1SKenneth D. Merry 773ef270ab1SKenneth D. Merry switch(evt) { 774ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: { 775ef270ab1SKenneth D. Merry ocs_node_hold_frames(node); 776ef270ab1SKenneth D. Merry ocs_assert(ocs_node_active_ios_empty(node), NULL); 777ef270ab1SKenneth D. Merry ocs_assert(ocs_els_io_list_empty(node, &node->els_io_active_list), NULL); 778ef270ab1SKenneth D. Merry 779ef270ab1SKenneth D. Merry /* by default, we will be freeing node after we unwind */ 780ef270ab1SKenneth D. Merry node->req_free = 1; 781ef270ab1SKenneth D. Merry 782ef270ab1SKenneth D. Merry switch (node->shutdown_reason) { 783ef270ab1SKenneth D. Merry case OCS_NODE_SHUTDOWN_IMPLICIT_LOGO: 784ef270ab1SKenneth D. Merry /* sm: if shutdown reason is implicit logout / ocs_node_attach 785ef270ab1SKenneth D. Merry * Node shutdown b/c of PLOGI received when node already 786ef270ab1SKenneth D. Merry * logged in. We have PLOGI service parameters, so submit 787ef270ab1SKenneth D. Merry * node attach; we won't be freeing this node 788ef270ab1SKenneth D. Merry */ 789ef270ab1SKenneth D. Merry 790ef270ab1SKenneth D. Merry /* currently, only case for implicit logo is PLOGI recvd. Thus, 791ef270ab1SKenneth D. Merry * node's ELS IO pending list won't be empty (PLOGI will be on it) 792ef270ab1SKenneth D. Merry */ 793ef270ab1SKenneth D. Merry ocs_assert(node->send_ls_acc == OCS_NODE_SEND_LS_ACC_PLOGI, NULL); 794ef270ab1SKenneth D. Merry node_printf(node, "Shutdown reason: implicit logout, re-authenticate\n"); 795ef270ab1SKenneth D. Merry 796ef270ab1SKenneth D. Merry ocs_scsi_io_alloc_enable(node); 797ef270ab1SKenneth D. Merry 798ef270ab1SKenneth D. Merry /* Re-attach node with the same HW node resources */ 799ef270ab1SKenneth D. Merry node->req_free = 0; 800ef270ab1SKenneth D. Merry rc = ocs_node_attach(node); 801ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_d_wait_node_attach, NULL); 802ef270ab1SKenneth D. Merry if (rc == OCS_HW_RTN_SUCCESS_SYNC) { 803ef270ab1SKenneth D. Merry ocs_node_post_event(node, OCS_EVT_NODE_ATTACH_OK, NULL); 804ef270ab1SKenneth D. Merry } 805ef270ab1SKenneth D. Merry break; 806ef270ab1SKenneth D. Merry case OCS_NODE_SHUTDOWN_EXPLICIT_LOGO: { 807ef270ab1SKenneth D. Merry int8_t pend_frames_empty; 808ef270ab1SKenneth D. Merry 809ef270ab1SKenneth D. Merry /* cleanup any pending LS_ACC ELSs */ 810ef270ab1SKenneth D. Merry ocs_node_send_ls_io_cleanup(node); 811ef270ab1SKenneth D. Merry ocs_assert(ocs_els_io_list_empty(node, &node->els_io_pend_list), NULL); 812ef270ab1SKenneth D. Merry 813ef270ab1SKenneth D. Merry ocs_lock(&node->pend_frames_lock); 814ef270ab1SKenneth D. Merry pend_frames_empty = ocs_list_empty(&node->pend_frames); 815ef270ab1SKenneth D. Merry ocs_unlock(&node->pend_frames_lock); 816ef270ab1SKenneth D. Merry 817ef270ab1SKenneth D. Merry /* there are two scenarios where we want to keep this node alive: 818ef270ab1SKenneth D. Merry * 1. there are pending frames that need to be processed or 819ef270ab1SKenneth D. Merry * 2. we're an initiator and the remote node is a target and we 820ef270ab1SKenneth D. Merry * need to re-authenticate 821ef270ab1SKenneth D. Merry */ 822ef270ab1SKenneth D. Merry node_printf(node, "Shutdown: explicit logo pend=%d sport.ini=%d node.tgt=%d\n", 823ef270ab1SKenneth D. Merry !pend_frames_empty, node->sport->enable_ini, node->targ); 824ef270ab1SKenneth D. Merry 825ef270ab1SKenneth D. Merry if((!pend_frames_empty) || (node->sport->enable_ini && node->targ)) { 826ef270ab1SKenneth D. Merry uint8_t send_plogi = FALSE; 827ef270ab1SKenneth D. Merry if (node->sport->enable_ini && node->targ) { 828ef270ab1SKenneth D. Merry /* we're an initiator and node shutting down is a target; we'll 829ef270ab1SKenneth D. Merry * need to re-authenticate in initial state 830ef270ab1SKenneth D. Merry */ 831ef270ab1SKenneth D. Merry send_plogi = TRUE; 832ef270ab1SKenneth D. Merry } 833ef270ab1SKenneth D. Merry 834ef270ab1SKenneth D. Merry /* transition to __ocs_d_init (will retain HW node resources) */ 835ef270ab1SKenneth D. Merry ocs_scsi_io_alloc_enable(node); 836ef270ab1SKenneth D. Merry node->req_free = 0; 837ef270ab1SKenneth D. Merry 838ef270ab1SKenneth D. Merry /* either pending frames exist, or we're re-authenticating with PLOGI 839ef270ab1SKenneth D. Merry * (or both); in either case, return to initial state 840ef270ab1SKenneth D. Merry */ 841ef270ab1SKenneth D. Merry ocs_node_init_device(node, send_plogi); 842ef270ab1SKenneth D. Merry 843ef270ab1SKenneth D. Merry } 844ef270ab1SKenneth D. Merry /* else: let node shutdown occur */ 845ef270ab1SKenneth D. Merry break; 846ef270ab1SKenneth D. Merry } 847ef270ab1SKenneth D. Merry case OCS_NODE_SHUTDOWN_DEFAULT: 848ef270ab1SKenneth D. Merry default: 849ef270ab1SKenneth D. Merry /* shutdown due to link down, node going away (xport event) or 850ef270ab1SKenneth D. Merry * sport shutdown, purge pending and proceed to cleanup node 851ef270ab1SKenneth D. Merry */ 852ef270ab1SKenneth D. Merry 853ef270ab1SKenneth D. Merry /* cleanup any pending LS_ACC ELSs */ 854ef270ab1SKenneth D. Merry ocs_node_send_ls_io_cleanup(node); 855ef270ab1SKenneth D. Merry ocs_assert(ocs_els_io_list_empty(node, &node->els_io_pend_list), NULL); 856ef270ab1SKenneth D. Merry 857ef270ab1SKenneth D. Merry node_printf(node, "Shutdown reason: default, purge pending\n"); 858ef270ab1SKenneth D. Merry ocs_node_purge_pending(node); 859ef270ab1SKenneth D. Merry break; 860ef270ab1SKenneth D. Merry } 861ef270ab1SKenneth D. Merry 862ef270ab1SKenneth D. Merry break; 863ef270ab1SKenneth D. Merry } 864ef270ab1SKenneth D. Merry case OCS_EVT_EXIT: 865ef270ab1SKenneth D. Merry ocs_node_accept_frames(node); 866ef270ab1SKenneth D. Merry break; 867ef270ab1SKenneth D. Merry 868ef270ab1SKenneth D. Merry default: 869ef270ab1SKenneth D. Merry __ocs_node_common(__func__, ctx, evt, arg); 870ef270ab1SKenneth D. Merry return NULL; 871ef270ab1SKenneth D. Merry } 872ef270ab1SKenneth D. Merry 873ef270ab1SKenneth D. Merry return NULL; 874ef270ab1SKenneth D. Merry } 875ef270ab1SKenneth D. Merry 876ef270ab1SKenneth D. Merry /** 877ef270ab1SKenneth D. Merry * @ingroup common_node 878ef270ab1SKenneth D. Merry * @brief Checks to see if ELS's have been quiesced 879ef270ab1SKenneth D. Merry * 880ef270ab1SKenneth D. Merry * Check if ELS's have been quiesced. If so, transition to the 881ef270ab1SKenneth D. Merry * next state in the shutdown process. 882ef270ab1SKenneth D. Merry * 883ef270ab1SKenneth D. Merry * @param node Node for which ELS's are checked 884ef270ab1SKenneth D. Merry * 885ef270ab1SKenneth D. Merry * @return Returns 1 if ELS's have been quiesced, 0 otherwise. 886ef270ab1SKenneth D. Merry */ 887ef270ab1SKenneth D. Merry static int 888ef270ab1SKenneth D. Merry ocs_node_check_els_quiesced(ocs_node_t *node) 889ef270ab1SKenneth D. Merry { 890ef270ab1SKenneth D. Merry ocs_assert(node, -1); 891ef270ab1SKenneth D. Merry 892ef270ab1SKenneth D. Merry /* check to see if ELS requests, completions are quiesced */ 893ef270ab1SKenneth D. Merry if ((node->els_req_cnt == 0) && (node->els_cmpl_cnt == 0) && 894ef270ab1SKenneth D. Merry ocs_els_io_list_empty(node, &node->els_io_active_list)) { 895ef270ab1SKenneth D. Merry if (!node->attached) { 896ef270ab1SKenneth D. Merry /* hw node detach already completed, proceed */ 897ef270ab1SKenneth D. Merry node_printf(node, "HW node not attached\n"); 898ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_node_wait_ios_shutdown, NULL); 899ef270ab1SKenneth D. Merry } else { 900ef270ab1SKenneth D. Merry /* hw node detach hasn't completed, transition and wait */ 901ef270ab1SKenneth D. Merry node_printf(node, "HW node still attached\n"); 902ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_node_wait_node_free, NULL); 903ef270ab1SKenneth D. Merry } 904ef270ab1SKenneth D. Merry return 1; 905ef270ab1SKenneth D. Merry } 906ef270ab1SKenneth D. Merry return 0; 907ef270ab1SKenneth D. Merry } 908ef270ab1SKenneth D. Merry 909ef270ab1SKenneth D. Merry /** 910ef270ab1SKenneth D. Merry * @ingroup common_node 911ef270ab1SKenneth D. Merry * @brief Initiate node IO cleanup. 912ef270ab1SKenneth D. Merry * 913ef270ab1SKenneth D. Merry * Note: this function must be called with a non-attached node 914ef270ab1SKenneth D. Merry * or a node for which the node detach (ocs_hw_node_detach()) 915ef270ab1SKenneth D. Merry * has already been initiated. 916ef270ab1SKenneth D. Merry * 917ef270ab1SKenneth D. Merry * @param node Node for which shutdown is initiated 918ef270ab1SKenneth D. Merry * 919ef270ab1SKenneth D. Merry * @return Returns None. 920ef270ab1SKenneth D. Merry */ 921ef270ab1SKenneth D. Merry 922ef270ab1SKenneth D. Merry void 923ef270ab1SKenneth D. Merry ocs_node_initiate_cleanup(ocs_node_t *node) 924ef270ab1SKenneth D. Merry { 925ef270ab1SKenneth D. Merry ocs_io_t *els; 926ef270ab1SKenneth D. Merry ocs_io_t *els_next; 927ef270ab1SKenneth D. Merry ocs_t *ocs; 928ef270ab1SKenneth D. Merry ocs_assert(node); 929ef270ab1SKenneth D. Merry ocs = node->ocs; 930ef270ab1SKenneth D. Merry 931ef270ab1SKenneth D. Merry /* first cleanup ELS's that are pending (not yet active) */ 932ef270ab1SKenneth D. Merry ocs_lock(&node->active_ios_lock); 933ef270ab1SKenneth D. Merry ocs_list_foreach_safe(&node->els_io_pend_list, els, els_next) { 934ef270ab1SKenneth D. Merry 935ef270ab1SKenneth D. Merry /* skip the ELS IO for which a response will be sent after shutdown */ 936ef270ab1SKenneth D. Merry if ((node->send_ls_acc != OCS_NODE_SEND_LS_ACC_NONE) && 937ef270ab1SKenneth D. Merry (els == node->ls_acc_io)) { 938ef270ab1SKenneth D. Merry continue; 939ef270ab1SKenneth D. Merry } 940ef270ab1SKenneth D. Merry /* can't call ocs_els_io_free() because lock is held; cleanup manually */ 941ef270ab1SKenneth D. Merry node_printf(node, "Freeing pending els %s\n", els->display_name); 942ef270ab1SKenneth D. Merry ocs_list_remove(&node->els_io_pend_list, els); 943ef270ab1SKenneth D. Merry 944ef270ab1SKenneth D. Merry ocs_io_free(node->ocs, els); 945ef270ab1SKenneth D. Merry } 946ef270ab1SKenneth D. Merry ocs_unlock(&node->active_ios_lock); 947ef270ab1SKenneth D. Merry 948ef270ab1SKenneth D. Merry if (node->ls_acc_io && node->ls_acc_io->hio != NULL) { 949ef270ab1SKenneth D. Merry /* 950ef270ab1SKenneth D. Merry * if there's an IO that will result in an LS_ACC after 951ef270ab1SKenneth D. Merry * shutdown and its HW IO is non-NULL, it better be an 952ef270ab1SKenneth D. Merry * implicit logout in vanilla sequence coalescing. In this 953ef270ab1SKenneth D. Merry * case, force the LS_ACC to go out on another XRI (hio) 954ef270ab1SKenneth D. Merry * since the previous will have been aborted by the UNREG_RPI 955ef270ab1SKenneth D. Merry */ 956ef270ab1SKenneth D. Merry ocs_assert(node->shutdown_reason == OCS_NODE_SHUTDOWN_IMPLICIT_LOGO); 957ef270ab1SKenneth D. Merry ocs_assert(node->send_ls_acc == OCS_NODE_SEND_LS_ACC_PLOGI); 958ef270ab1SKenneth D. Merry node_printf(node, "invalidating ls_acc_io due to implicit logo\n"); 959ef270ab1SKenneth D. Merry 960ef270ab1SKenneth D. Merry /* No need to abort because the unreg_rpi takes care of it, just free */ 961ef270ab1SKenneth D. Merry ocs_hw_io_free(&ocs->hw, node->ls_acc_io->hio); 962ef270ab1SKenneth D. Merry 963ef270ab1SKenneth D. Merry /* NULL out hio to force the LS_ACC to grab a new XRI */ 964ef270ab1SKenneth D. Merry node->ls_acc_io->hio = NULL; 965ef270ab1SKenneth D. Merry } 966ef270ab1SKenneth D. Merry 967ef270ab1SKenneth D. Merry /* 968ef270ab1SKenneth D. Merry * if ELS's have already been quiesced, will move to next state 969ef270ab1SKenneth D. Merry * if ELS's have not been quiesced, abort them 970ef270ab1SKenneth D. Merry */ 971ef270ab1SKenneth D. Merry if (ocs_node_check_els_quiesced(node) == 0) { 972ef270ab1SKenneth D. Merry /* 973ef270ab1SKenneth D. Merry * Abort all ELS's since ELS's won't be aborted by HW 974ef270ab1SKenneth D. Merry * node free. 975ef270ab1SKenneth D. Merry */ 976ef270ab1SKenneth D. Merry ocs_node_abort_all_els(node); 977ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_node_wait_els_shutdown, NULL); 978ef270ab1SKenneth D. Merry } 979ef270ab1SKenneth D. Merry } 980ef270ab1SKenneth D. Merry 981ef270ab1SKenneth D. Merry /** 982ef270ab1SKenneth D. Merry * @ingroup node_common 983ef270ab1SKenneth D. Merry * @brief Node state machine: Wait for all ELSs to complete. 984ef270ab1SKenneth D. Merry * 985ef270ab1SKenneth D. Merry * <h3 class="desc">Description</h3> 986ef270ab1SKenneth D. Merry * State waits for all ELSs to complete after aborting all 987ef270ab1SKenneth D. Merry * outstanding . 988ef270ab1SKenneth D. Merry * 989ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 990ef270ab1SKenneth D. Merry * @param evt Event to process. 991ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 992ef270ab1SKenneth D. Merry * 993ef270ab1SKenneth D. Merry * @return Returns NULL. 994ef270ab1SKenneth D. Merry */ 995ef270ab1SKenneth D. Merry 996ef270ab1SKenneth D. Merry void * 997ef270ab1SKenneth D. Merry __ocs_node_wait_els_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 998ef270ab1SKenneth D. Merry { 999ef270ab1SKenneth D. Merry uint8_t check_quiesce = FALSE; 1000ef270ab1SKenneth D. Merry std_node_state_decl(); 1001ef270ab1SKenneth D. Merry 1002ef270ab1SKenneth D. Merry node_sm_trace(); 1003ef270ab1SKenneth D. Merry 1004ef270ab1SKenneth D. Merry switch(evt) { 1005ef270ab1SKenneth D. Merry 1006ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: { 1007ef270ab1SKenneth D. Merry ocs_node_hold_frames(node); 1008ef270ab1SKenneth D. Merry if (ocs_els_io_list_empty(node, &node->els_io_active_list)) { 1009ef270ab1SKenneth D. Merry node_printf(node, "All ELS IOs complete\n"); 1010ef270ab1SKenneth D. Merry check_quiesce = TRUE; 1011ef270ab1SKenneth D. Merry } 1012ef270ab1SKenneth D. Merry break; 1013ef270ab1SKenneth D. Merry } 1014ef270ab1SKenneth D. Merry case OCS_EVT_EXIT: 1015ef270ab1SKenneth D. Merry ocs_node_accept_frames(node); 1016ef270ab1SKenneth D. Merry break; 1017ef270ab1SKenneth D. Merry 1018ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_OK: 1019ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_FAIL: 1020ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_RJT: 1021ef270ab1SKenneth D. Merry case OCS_EVT_ELS_REQ_ABORTED: 1022ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 1023ef270ab1SKenneth D. Merry node->els_req_cnt--; 1024ef270ab1SKenneth D. Merry check_quiesce = TRUE; 1025ef270ab1SKenneth D. Merry break; 1026ef270ab1SKenneth D. Merry 1027ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_CMPL_OK: 1028ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_CMPL_FAIL: 1029ef270ab1SKenneth D. Merry ocs_assert(node->els_cmpl_cnt, NULL); 1030ef270ab1SKenneth D. Merry node->els_cmpl_cnt--; 1031ef270ab1SKenneth D. Merry check_quiesce = TRUE; 1032ef270ab1SKenneth D. Merry break; 1033ef270ab1SKenneth D. Merry 1034ef270ab1SKenneth D. Merry case OCS_EVT_ALL_CHILD_NODES_FREE: 1035ef270ab1SKenneth D. Merry /* all ELS IO's complete */ 1036ef270ab1SKenneth D. Merry node_printf(node, "All ELS IOs complete\n"); 1037ef270ab1SKenneth D. Merry ocs_assert(ocs_els_io_list_empty(node, &node->els_io_active_list), NULL); 1038ef270ab1SKenneth D. Merry check_quiesce = TRUE; 1039ef270ab1SKenneth D. Merry break; 1040ef270ab1SKenneth D. Merry 1041ef270ab1SKenneth D. Merry case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY: 1042ef270ab1SKenneth D. Merry break; 1043ef270ab1SKenneth D. Merry 1044ef270ab1SKenneth D. Merry case OCS_EVT_DOMAIN_ATTACH_OK: 1045ef270ab1SKenneth D. Merry /* don't care about domain_attach_ok */ 1046ef270ab1SKenneth D. Merry break; 1047ef270ab1SKenneth D. Merry 1048ef270ab1SKenneth D. Merry /* ignore shutdown events as we're already in shutdown path */ 1049ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN: 1050ef270ab1SKenneth D. Merry /* have default shutdown event take precedence */ 1051ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1052ef270ab1SKenneth D. Merry /* fall through */ 1053ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO: 1054ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO: 1055ef270ab1SKenneth D. Merry node_printf(node, "%s received\n", ocs_sm_event_name(evt)); 1056ef270ab1SKenneth D. Merry break; 1057ef270ab1SKenneth D. Merry 1058ef270ab1SKenneth D. Merry default: 1059ef270ab1SKenneth D. Merry __ocs_node_common(__func__, ctx, evt, arg); 1060ef270ab1SKenneth D. Merry return NULL; 1061ef270ab1SKenneth D. Merry } 1062ef270ab1SKenneth D. Merry 1063ef270ab1SKenneth D. Merry if (check_quiesce) { 1064ef270ab1SKenneth D. Merry ocs_node_check_els_quiesced(node); 1065ef270ab1SKenneth D. Merry } 1066ef270ab1SKenneth D. Merry return NULL; 1067ef270ab1SKenneth D. Merry } 1068ef270ab1SKenneth D. Merry 1069ef270ab1SKenneth D. Merry /** 1070ef270ab1SKenneth D. Merry * @ingroup node_command 1071ef270ab1SKenneth D. Merry * @brief Node state machine: Wait for a HW node free event to 1072ef270ab1SKenneth D. Merry * complete. 1073ef270ab1SKenneth D. Merry * 1074ef270ab1SKenneth D. Merry * <h3 class="desc">Description</h3> 1075ef270ab1SKenneth D. Merry * State waits for the node free event to be received from the HW. 1076ef270ab1SKenneth D. Merry * 1077ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 1078ef270ab1SKenneth D. Merry * @param evt Event to process. 1079ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 1080ef270ab1SKenneth D. Merry * 1081ef270ab1SKenneth D. Merry * @return Returns NULL. 1082ef270ab1SKenneth D. Merry */ 1083ef270ab1SKenneth D. Merry 1084ef270ab1SKenneth D. Merry void * 1085ef270ab1SKenneth D. Merry __ocs_node_wait_node_free(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1086ef270ab1SKenneth D. Merry { 1087ef270ab1SKenneth D. Merry std_node_state_decl(); 1088ef270ab1SKenneth D. Merry 1089ef270ab1SKenneth D. Merry node_sm_trace(); 1090ef270ab1SKenneth D. Merry 1091ef270ab1SKenneth D. Merry switch(evt) { 1092ef270ab1SKenneth D. Merry 1093ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 1094ef270ab1SKenneth D. Merry ocs_node_hold_frames(node); 1095ef270ab1SKenneth D. Merry break; 1096ef270ab1SKenneth D. Merry 1097ef270ab1SKenneth D. Merry case OCS_EVT_EXIT: 1098ef270ab1SKenneth D. Merry ocs_node_accept_frames(node); 1099ef270ab1SKenneth D. Merry break; 1100ef270ab1SKenneth D. Merry 1101ef270ab1SKenneth D. Merry case OCS_EVT_NODE_FREE_OK: 1102ef270ab1SKenneth D. Merry /* node is officially no longer attached */ 1103ef270ab1SKenneth D. Merry node->attached = FALSE; 1104ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_node_wait_ios_shutdown, NULL); 1105ef270ab1SKenneth D. Merry break; 1106ef270ab1SKenneth D. Merry 1107ef270ab1SKenneth D. Merry case OCS_EVT_ALL_CHILD_NODES_FREE: 1108ef270ab1SKenneth D. Merry case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY: 1109ef270ab1SKenneth D. Merry /* As IOs and ELS IO's complete we expect to get these events */ 1110ef270ab1SKenneth D. Merry break; 1111ef270ab1SKenneth D. Merry 1112ef270ab1SKenneth D. Merry case OCS_EVT_DOMAIN_ATTACH_OK: 1113ef270ab1SKenneth D. Merry /* don't care about domain_attach_ok */ 1114ef270ab1SKenneth D. Merry break; 1115ef270ab1SKenneth D. Merry 1116ef270ab1SKenneth D. Merry /* ignore shutdown events as we're already in shutdown path */ 1117ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN: 1118ef270ab1SKenneth D. Merry /* have default shutdown event take precedence */ 1119ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1120ef270ab1SKenneth D. Merry /* Fall through */ 1121ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO: 1122ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO: 1123ef270ab1SKenneth D. Merry node_printf(node, "%s received\n", ocs_sm_event_name(evt)); 1124ef270ab1SKenneth D. Merry break; 1125ef270ab1SKenneth D. Merry default: 1126ef270ab1SKenneth D. Merry __ocs_node_common(__func__, ctx, evt, arg); 1127ef270ab1SKenneth D. Merry return NULL; 1128ef270ab1SKenneth D. Merry } 1129ef270ab1SKenneth D. Merry 1130ef270ab1SKenneth D. Merry return NULL; 1131ef270ab1SKenneth D. Merry } 1132ef270ab1SKenneth D. Merry 1133ef270ab1SKenneth D. Merry /** 1134ef270ab1SKenneth D. Merry * @ingroup node_common 1135ef270ab1SKenneth D. Merry * @brief state: initiate node shutdown 1136ef270ab1SKenneth D. Merry * 1137ef270ab1SKenneth D. Merry * State is entered when a node receives a shutdown event, and it's waiting 1138ef270ab1SKenneth D. Merry * for all the active IOs and ELS IOs associated with the node to complete. 1139ef270ab1SKenneth D. Merry * 1140ef270ab1SKenneth D. Merry * @param ctx remote node sm context 1141ef270ab1SKenneth D. Merry * @param evt event to process 1142ef270ab1SKenneth D. Merry * @param arg per event optional argument 1143ef270ab1SKenneth D. Merry * 1144ef270ab1SKenneth D. Merry * @return returns NULL 1145ef270ab1SKenneth D. Merry */ 1146ef270ab1SKenneth D. Merry 1147ef270ab1SKenneth D. Merry void * 1148ef270ab1SKenneth D. Merry __ocs_node_wait_ios_shutdown(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1149ef270ab1SKenneth D. Merry { 1150ef270ab1SKenneth D. Merry ocs_io_t *io; 1151ef270ab1SKenneth D. Merry ocs_io_t *next; 1152ef270ab1SKenneth D. Merry std_node_state_decl(); 1153ef270ab1SKenneth D. Merry 1154ef270ab1SKenneth D. Merry node_sm_trace(); 1155ef270ab1SKenneth D. Merry 1156ef270ab1SKenneth D. Merry switch(evt) { 1157ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 1158ef270ab1SKenneth D. Merry ocs_node_hold_frames(node); 1159ef270ab1SKenneth D. Merry 1160ef270ab1SKenneth D. Merry /* first check to see if no ELS IOs are outstanding */ 1161ef270ab1SKenneth D. Merry if (ocs_els_io_list_empty(node, &node->els_io_active_list)) { 1162ef270ab1SKenneth D. Merry /* If there are any active IOS, Free them. */ 1163ef270ab1SKenneth D. Merry if (!ocs_node_active_ios_empty(node)) { 1164ef270ab1SKenneth D. Merry ocs_lock(&node->active_ios_lock); 1165ef270ab1SKenneth D. Merry ocs_list_foreach_safe(&node->active_ios, io, next) { 1166ef270ab1SKenneth D. Merry ocs_list_remove(&io->node->active_ios, io); 1167ef270ab1SKenneth D. Merry ocs_io_free(node->ocs, io); 1168ef270ab1SKenneth D. Merry } 1169ef270ab1SKenneth D. Merry ocs_unlock(&node->active_ios_lock); 1170ef270ab1SKenneth D. Merry } 1171ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_node_shutdown, NULL); 1172ef270ab1SKenneth D. Merry } 1173ef270ab1SKenneth D. Merry break; 1174ef270ab1SKenneth D. Merry 1175ef270ab1SKenneth D. Merry case OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY: 1176ef270ab1SKenneth D. Merry case OCS_EVT_ALL_CHILD_NODES_FREE: { 1177ef270ab1SKenneth D. Merry if (ocs_node_active_ios_empty(node) && 1178ef270ab1SKenneth D. Merry ocs_els_io_list_empty(node, &node->els_io_active_list)) { 1179ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_node_shutdown, NULL); 1180ef270ab1SKenneth D. Merry } 1181ef270ab1SKenneth D. Merry break; 1182ef270ab1SKenneth D. Merry } 1183ef270ab1SKenneth D. Merry 1184ef270ab1SKenneth D. Merry case OCS_EVT_EXIT: 1185ef270ab1SKenneth D. Merry ocs_node_accept_frames(node); 1186ef270ab1SKenneth D. Merry break; 1187ef270ab1SKenneth D. Merry 1188ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_FAIL: 1189ef270ab1SKenneth D. Merry /* Can happen as ELS IO IO's complete */ 1190ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 1191ef270ab1SKenneth D. Merry node->els_req_cnt--; 1192ef270ab1SKenneth D. Merry break; 1193ef270ab1SKenneth D. Merry 1194ef270ab1SKenneth D. Merry /* ignore shutdown events as we're already in shutdown path */ 1195ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN: 1196ef270ab1SKenneth D. Merry /* have default shutdown event take precedence */ 1197ef270ab1SKenneth D. Merry node->shutdown_reason = OCS_NODE_SHUTDOWN_DEFAULT; 1198ef270ab1SKenneth D. Merry /* fall through */ 1199ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN_EXPLICIT_LOGO: 1200ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN_IMPLICIT_LOGO: 1201ef270ab1SKenneth D. Merry ocs_log_debug(ocs, "[%s] %-20s\n", node->display_name, ocs_sm_event_name(evt)); 1202ef270ab1SKenneth D. Merry break; 1203ef270ab1SKenneth D. Merry case OCS_EVT_DOMAIN_ATTACH_OK: 1204ef270ab1SKenneth D. Merry /* don't care about domain_attach_ok */ 1205ef270ab1SKenneth D. Merry break; 1206ef270ab1SKenneth D. Merry default: 1207ef270ab1SKenneth D. Merry __ocs_node_common(__func__, ctx, evt, arg); 1208ef270ab1SKenneth D. Merry return NULL; 1209ef270ab1SKenneth D. Merry } 1210ef270ab1SKenneth D. Merry 1211ef270ab1SKenneth D. Merry return NULL; 1212ef270ab1SKenneth D. Merry } 1213ef270ab1SKenneth D. Merry 1214ef270ab1SKenneth D. Merry /** 1215ef270ab1SKenneth D. Merry * @ingroup node_common 1216ef270ab1SKenneth D. Merry * @brief state: common node event handler 1217ef270ab1SKenneth D. Merry * 1218ef270ab1SKenneth D. Merry * Handle common/shared node events 1219ef270ab1SKenneth D. Merry * 1220ef270ab1SKenneth D. Merry * @param funcname calling function's name 1221ef270ab1SKenneth D. Merry * @param ctx remote node sm context 1222ef270ab1SKenneth D. Merry * @param evt event to process 1223ef270ab1SKenneth D. Merry * @param arg per event optional argument 1224ef270ab1SKenneth D. Merry * 1225ef270ab1SKenneth D. Merry * @return returns NULL 1226ef270ab1SKenneth D. Merry */ 1227ef270ab1SKenneth D. Merry 1228ef270ab1SKenneth D. Merry void * 1229ef270ab1SKenneth D. Merry __ocs_node_common(const char *funcname, ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 1230ef270ab1SKenneth D. Merry { 1231ef270ab1SKenneth D. Merry ocs_node_t *node = NULL; 1232ef270ab1SKenneth D. Merry ocs_t *ocs = NULL; 1233ef270ab1SKenneth D. Merry ocs_node_cb_t *cbdata = arg; 1234ef270ab1SKenneth D. Merry ocs_assert(ctx, NULL); 1235ef270ab1SKenneth D. Merry ocs_assert(ctx->app, NULL); 1236ef270ab1SKenneth D. Merry node = ctx->app; 1237ef270ab1SKenneth D. Merry ocs_assert(node->ocs, NULL); 1238ef270ab1SKenneth D. Merry ocs = node->ocs; 1239ef270ab1SKenneth D. Merry 1240ef270ab1SKenneth D. Merry switch(evt) { 1241ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 1242ef270ab1SKenneth D. Merry case OCS_EVT_REENTER: 1243ef270ab1SKenneth D. Merry case OCS_EVT_EXIT: 1244ef270ab1SKenneth D. Merry case OCS_EVT_SPORT_TOPOLOGY_NOTIFY: 1245ef270ab1SKenneth D. Merry case OCS_EVT_NODE_MISSING: 1246ef270ab1SKenneth D. Merry case OCS_EVT_FCP_CMD_RCVD: 1247ef270ab1SKenneth D. Merry break; 1248ef270ab1SKenneth D. Merry 1249ef270ab1SKenneth D. Merry case OCS_EVT_NODE_REFOUND: 1250ef270ab1SKenneth D. Merry node->refound = 1; 1251ef270ab1SKenneth D. Merry break; 1252ef270ab1SKenneth D. Merry 1253ef270ab1SKenneth D. Merry /* node->attached must be set appropriately for all node attach/detach events */ 1254ef270ab1SKenneth D. Merry case OCS_EVT_NODE_ATTACH_OK: 1255ef270ab1SKenneth D. Merry node->attached = TRUE; 1256ef270ab1SKenneth D. Merry break; 1257ef270ab1SKenneth D. Merry 1258ef270ab1SKenneth D. Merry case OCS_EVT_NODE_FREE_OK: 1259ef270ab1SKenneth D. Merry case OCS_EVT_NODE_ATTACH_FAIL: 1260ef270ab1SKenneth D. Merry node->attached = FALSE; 1261ef270ab1SKenneth D. Merry break; 1262ef270ab1SKenneth D. Merry 1263ef270ab1SKenneth D. Merry /* handle any ELS completions that other states either didn't care about 1264ef270ab1SKenneth D. Merry * or forgot about 1265ef270ab1SKenneth D. Merry */ 1266ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_CMPL_OK: 1267ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_CMPL_FAIL: 1268ef270ab1SKenneth D. Merry ocs_assert(node->els_cmpl_cnt, NULL); 1269ef270ab1SKenneth D. Merry node->els_cmpl_cnt--; 1270ef270ab1SKenneth D. Merry break; 1271ef270ab1SKenneth D. Merry 1272ef270ab1SKenneth D. Merry /* handle any ELS request completions that other states either didn't care about 1273ef270ab1SKenneth D. Merry * or forgot about 1274ef270ab1SKenneth D. Merry */ 1275ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_OK: 1276ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_FAIL: 1277ef270ab1SKenneth D. Merry case OCS_EVT_SRRS_ELS_REQ_RJT: 1278ef270ab1SKenneth D. Merry case OCS_EVT_ELS_REQ_ABORTED: 1279ef270ab1SKenneth D. Merry ocs_assert(node->els_req_cnt, NULL); 1280ef270ab1SKenneth D. Merry node->els_req_cnt--; 1281ef270ab1SKenneth D. Merry break; 1282ef270ab1SKenneth D. Merry 1283ef270ab1SKenneth D. Merry case OCS_EVT_ELS_RCVD: { 1284ef270ab1SKenneth D. Merry fc_header_t *hdr = cbdata->header->dma.virt; 1285ef270ab1SKenneth D. Merry 1286ef270ab1SKenneth D. Merry /* Unsupported ELS was received, send LS_RJT, command not supported */ 1287ef270ab1SKenneth D. Merry ocs_log_debug(ocs, "[%s] (%s) ELS x%02x, LS_RJT not supported\n", 1288ef270ab1SKenneth D. Merry node->display_name, funcname, ((uint8_t*)cbdata->payload->dma.virt)[0]); 1289ef270ab1SKenneth D. Merry ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id), 1290ef270ab1SKenneth D. Merry FC_REASON_COMMAND_NOT_SUPPORTED, FC_EXPL_NO_ADDITIONAL, 0, 1291ef270ab1SKenneth D. Merry NULL, NULL); 1292ef270ab1SKenneth D. Merry break; 1293ef270ab1SKenneth D. Merry } 1294ef270ab1SKenneth D. Merry 1295ef270ab1SKenneth D. Merry case OCS_EVT_PLOGI_RCVD: 1296ef270ab1SKenneth D. Merry case OCS_EVT_FLOGI_RCVD: 1297ef270ab1SKenneth D. Merry case OCS_EVT_LOGO_RCVD: 1298ef270ab1SKenneth D. Merry case OCS_EVT_PRLI_RCVD: 1299ef270ab1SKenneth D. Merry case OCS_EVT_PRLO_RCVD: 1300ef270ab1SKenneth D. Merry case OCS_EVT_PDISC_RCVD: 1301ef270ab1SKenneth D. Merry case OCS_EVT_FDISC_RCVD: 1302ef270ab1SKenneth D. Merry case OCS_EVT_ADISC_RCVD: 1303ef270ab1SKenneth D. Merry case OCS_EVT_RSCN_RCVD: 1304ef270ab1SKenneth D. Merry case OCS_EVT_SCR_RCVD: { 1305ef270ab1SKenneth D. Merry fc_header_t *hdr = cbdata->header->dma.virt; 1306ef270ab1SKenneth D. Merry /* sm: / send ELS_RJT */ 1307ef270ab1SKenneth D. Merry ocs_log_debug(ocs, "[%s] (%s) %s sending ELS_RJT\n", 1308ef270ab1SKenneth D. Merry node->display_name, funcname, ocs_sm_event_name(evt)); 1309ef270ab1SKenneth D. Merry /* if we didn't catch this in a state, send generic LS_RJT */ 1310ef270ab1SKenneth D. Merry ocs_send_ls_rjt(cbdata->io, ocs_be16toh(hdr->ox_id), 1311ef270ab1SKenneth D. Merry FC_REASON_UNABLE_TO_PERFORM, FC_EXPL_NO_ADDITIONAL, 0, 1312ef270ab1SKenneth D. Merry NULL, NULL); 1313ef270ab1SKenneth D. Merry 1314ef270ab1SKenneth D. Merry break; 1315ef270ab1SKenneth D. Merry } 1316ef270ab1SKenneth D. Merry case OCS_EVT_GID_PT_RCVD: 1317ef270ab1SKenneth D. Merry case OCS_EVT_RFT_ID_RCVD: 1318ef270ab1SKenneth D. Merry case OCS_EVT_RFF_ID_RCVD: { 1319ef270ab1SKenneth D. Merry fc_header_t *hdr = cbdata->header->dma.virt; 1320ef270ab1SKenneth D. Merry ocs_log_debug(ocs, "[%s] (%s) %s sending CT_REJECT\n", 1321ef270ab1SKenneth D. Merry node->display_name, funcname, ocs_sm_event_name(evt)); 1322ef270ab1SKenneth D. Merry ocs_send_ct_rsp(cbdata->io, hdr->ox_id, cbdata->payload->dma.virt, FCCT_HDR_CMDRSP_REJECT, FCCT_COMMAND_NOT_SUPPORTED, 0); 1323ef270ab1SKenneth D. Merry break; 1324ef270ab1SKenneth D. Merry } 1325ef270ab1SKenneth D. Merry 1326ef270ab1SKenneth D. Merry case OCS_EVT_ABTS_RCVD: { 1327ef270ab1SKenneth D. Merry fc_header_t *hdr = cbdata->header->dma.virt; 1328ef270ab1SKenneth D. Merry ocs_log_debug(ocs, "[%s] (%s) %s sending BA_ACC\n", 1329ef270ab1SKenneth D. Merry node->display_name, funcname, ocs_sm_event_name(evt)); 1330ef270ab1SKenneth D. Merry 1331ef270ab1SKenneth D. Merry /* sm: send BA_ACC */ 1332ef270ab1SKenneth D. Merry ocs_bls_send_acc_hdr(cbdata->io, hdr); 1333ef270ab1SKenneth D. Merry break; 1334ef270ab1SKenneth D. Merry } 1335ef270ab1SKenneth D. Merry 1336ef270ab1SKenneth D. Merry default: 1337ef270ab1SKenneth D. Merry ocs_log_test(node->ocs, "[%s] %-20s %-20s not handled\n", node->display_name, funcname, 1338ef270ab1SKenneth D. Merry ocs_sm_event_name(evt)); 1339ef270ab1SKenneth D. Merry break; 1340ef270ab1SKenneth D. Merry } 1341ef270ab1SKenneth D. Merry return NULL; 1342ef270ab1SKenneth D. Merry } 1343ef270ab1SKenneth D. Merry 1344ef270ab1SKenneth D. Merry 1345ef270ab1SKenneth D. Merry /** 1346ef270ab1SKenneth D. Merry * @ingroup node_common 1347ef270ab1SKenneth D. Merry * @brief save node service parameters 1348ef270ab1SKenneth D. Merry * 1349ef270ab1SKenneth D. Merry * Service parameters are copyed into the node structure 1350ef270ab1SKenneth D. Merry * 1351ef270ab1SKenneth D. Merry * @param node pointer to node structure 1352ef270ab1SKenneth D. Merry * @param payload pointer to service parameters to save 1353ef270ab1SKenneth D. Merry * 1354ef270ab1SKenneth D. Merry * @return none 1355ef270ab1SKenneth D. Merry */ 1356ef270ab1SKenneth D. Merry 1357ef270ab1SKenneth D. Merry void 1358ef270ab1SKenneth D. Merry ocs_node_save_sparms(ocs_node_t *node, void *payload) 1359ef270ab1SKenneth D. Merry { 1360ef270ab1SKenneth D. Merry ocs_memcpy(node->service_params, payload, sizeof(node->service_params)); 1361ef270ab1SKenneth D. Merry } 1362ef270ab1SKenneth D. Merry 1363ef270ab1SKenneth D. Merry /** 1364ef270ab1SKenneth D. Merry * @ingroup node_common 1365ef270ab1SKenneth D. Merry * @brief Post event to node state machine context 1366ef270ab1SKenneth D. Merry * 1367ef270ab1SKenneth D. Merry * This is used by the node state machine code to post events to the nodes. Upon 1368ef270ab1SKenneth D. Merry * completion of the event posting, if the nesting depth is zero and we're not holding 1369ef270ab1SKenneth D. Merry * inbound frames, then the pending frames are processed. 1370ef270ab1SKenneth D. Merry * 1371ef270ab1SKenneth D. Merry * @param node pointer to node 1372ef270ab1SKenneth D. Merry * @param evt event to post 1373ef270ab1SKenneth D. Merry * @param arg event posting argument 1374ef270ab1SKenneth D. Merry * 1375ef270ab1SKenneth D. Merry * @return none 1376ef270ab1SKenneth D. Merry */ 1377ef270ab1SKenneth D. Merry 1378ef270ab1SKenneth D. Merry void 1379ef270ab1SKenneth D. Merry ocs_node_post_event(ocs_node_t *node, ocs_sm_event_t evt, void *arg) 1380ef270ab1SKenneth D. Merry { 1381ef270ab1SKenneth D. Merry int free_node = FALSE; 1382ef270ab1SKenneth D. Merry ocs_assert(node); 1383ef270ab1SKenneth D. Merry 1384ef270ab1SKenneth D. Merry ocs_node_lock(node); 1385ef270ab1SKenneth D. Merry node->evtdepth ++; 1386ef270ab1SKenneth D. Merry 1387ef270ab1SKenneth D. Merry ocs_sm_post_event(&node->sm, evt, arg); 1388ef270ab1SKenneth D. Merry 1389ef270ab1SKenneth D. Merry /* If our event call depth is one and we're not holding frames 1390ef270ab1SKenneth D. Merry * then we can dispatch any pending frames. We don't want to allow 1391ef270ab1SKenneth D. Merry * the ocs_process_node_pending() call to recurse. 1392ef270ab1SKenneth D. Merry */ 1393ef270ab1SKenneth D. Merry if (!node->hold_frames && (node->evtdepth == 1)) { 1394ef270ab1SKenneth D. Merry ocs_process_node_pending(node); 1395ef270ab1SKenneth D. Merry } 1396ef270ab1SKenneth D. Merry node->evtdepth --; 1397ef270ab1SKenneth D. Merry 1398ef270ab1SKenneth D. Merry /* Free the node object if so requested, and we're at an event 1399ef270ab1SKenneth D. Merry * call depth of zero 1400ef270ab1SKenneth D. Merry */ 1401ef270ab1SKenneth D. Merry if ((node->evtdepth == 0) && node->req_free) { 1402ef270ab1SKenneth D. Merry free_node = TRUE; 1403ef270ab1SKenneth D. Merry } 1404ef270ab1SKenneth D. Merry ocs_node_unlock(node); 1405ef270ab1SKenneth D. Merry 1406ef270ab1SKenneth D. Merry if (free_node) { 1407ef270ab1SKenneth D. Merry ocs_node_free(node); 1408ef270ab1SKenneth D. Merry } 1409ef270ab1SKenneth D. Merry 1410ef270ab1SKenneth D. Merry return; 1411ef270ab1SKenneth D. Merry } 1412ef270ab1SKenneth D. Merry 1413ef270ab1SKenneth D. Merry /** 1414ef270ab1SKenneth D. Merry * @ingroup node_common 1415ef270ab1SKenneth D. Merry * @brief transition state of a node 1416ef270ab1SKenneth D. Merry * 1417ef270ab1SKenneth D. Merry * The node's state is transitioned to the requested state. Entry/Exit 1418ef270ab1SKenneth D. Merry * events are posted as needed. 1419ef270ab1SKenneth D. Merry * 1420ef270ab1SKenneth D. Merry * @param node pointer to node 1421ef270ab1SKenneth D. Merry * @param state state to transition to 1422ef270ab1SKenneth D. Merry * @param data transition data 1423ef270ab1SKenneth D. Merry * 1424ef270ab1SKenneth D. Merry * @return none 1425ef270ab1SKenneth D. Merry */ 1426ef270ab1SKenneth D. Merry 1427ef270ab1SKenneth D. Merry void 1428ef270ab1SKenneth D. Merry ocs_node_transition(ocs_node_t *node, ocs_sm_function_t state, void *data) 1429ef270ab1SKenneth D. Merry { 1430ef270ab1SKenneth D. Merry ocs_sm_ctx_t *ctx = &node->sm; 1431ef270ab1SKenneth D. Merry 1432ef270ab1SKenneth D. Merry ocs_node_lock(node); 1433ef270ab1SKenneth D. Merry if (ctx->current_state == state) { 1434ef270ab1SKenneth D. Merry ocs_node_post_event(node, OCS_EVT_REENTER, data); 1435ef270ab1SKenneth D. Merry } else { 1436ef270ab1SKenneth D. Merry ocs_node_post_event(node, OCS_EVT_EXIT, data); 1437ef270ab1SKenneth D. Merry ctx->current_state = state; 1438ef270ab1SKenneth D. Merry ocs_node_post_event(node, OCS_EVT_ENTER, data); 1439ef270ab1SKenneth D. Merry } 1440ef270ab1SKenneth D. Merry ocs_node_unlock(node); 1441ef270ab1SKenneth D. Merry } 1442ef270ab1SKenneth D. Merry 1443ef270ab1SKenneth D. Merry /** 1444ef270ab1SKenneth D. Merry * @ingroup node_common 1445ef270ab1SKenneth D. Merry * @brief build EUI formatted WWN 1446ef270ab1SKenneth D. Merry * 1447ef270ab1SKenneth D. Merry * Build a WWN given the somewhat transport agnostic iScsi naming specification, for FC 1448ef270ab1SKenneth D. Merry * use the eui. format, an ascii string such as: "eui.10000000C9A19501" 1449ef270ab1SKenneth D. Merry * 1450ef270ab1SKenneth D. Merry * @param buffer buffer to place formatted name into 1451ef270ab1SKenneth D. Merry * @param buffer_len length in bytes of the buffer 1452ef270ab1SKenneth D. Merry * @param eui_name cpu endian 64 bit WWN value 1453ef270ab1SKenneth D. Merry * 1454ef270ab1SKenneth D. Merry * @return none 1455ef270ab1SKenneth D. Merry */ 1456ef270ab1SKenneth D. Merry 1457ef270ab1SKenneth D. Merry void 1458ef270ab1SKenneth D. Merry ocs_node_build_eui_name(char *buffer, uint32_t buffer_len, uint64_t eui_name) 1459ef270ab1SKenneth D. Merry { 1460ef270ab1SKenneth D. Merry ocs_memset(buffer, 0, buffer_len); 1461ef270ab1SKenneth D. Merry 1462ef270ab1SKenneth D. Merry ocs_snprintf(buffer, buffer_len, "eui.%016llx", (unsigned long long)eui_name); 1463ef270ab1SKenneth D. Merry } 1464ef270ab1SKenneth D. Merry 1465ef270ab1SKenneth D. Merry /** 1466ef270ab1SKenneth D. Merry * @ingroup node_common 1467ef270ab1SKenneth D. Merry * @brief return nodes' WWPN as a uint64_t 1468ef270ab1SKenneth D. Merry * 1469ef270ab1SKenneth D. Merry * The WWPN is computed from service parameters and returned as a uint64_t 1470ef270ab1SKenneth D. Merry * 1471ef270ab1SKenneth D. Merry * @param node pointer to node structure 1472ef270ab1SKenneth D. Merry * 1473ef270ab1SKenneth D. Merry * @return WWPN 1474ef270ab1SKenneth D. Merry * 1475ef270ab1SKenneth D. Merry */ 1476ef270ab1SKenneth D. Merry 1477ef270ab1SKenneth D. Merry uint64_t 1478ef270ab1SKenneth D. Merry ocs_node_get_wwpn(ocs_node_t *node) 1479ef270ab1SKenneth D. Merry { 1480ef270ab1SKenneth D. Merry fc_plogi_payload_t *sp = (fc_plogi_payload_t*) node->service_params; 1481ef270ab1SKenneth D. Merry 1482ef270ab1SKenneth D. Merry return (((uint64_t)ocs_be32toh(sp->port_name_hi) << 32ll) | (ocs_be32toh(sp->port_name_lo))); 1483ef270ab1SKenneth D. Merry } 1484ef270ab1SKenneth D. Merry 1485ef270ab1SKenneth D. Merry /** 1486ef270ab1SKenneth D. Merry * @ingroup node_common 1487ef270ab1SKenneth D. Merry * @brief return nodes' WWNN as a uint64_t 1488ef270ab1SKenneth D. Merry * 1489ef270ab1SKenneth D. Merry * The WWNN is computed from service parameters and returned as a uint64_t 1490ef270ab1SKenneth D. Merry * 1491ef270ab1SKenneth D. Merry * @param node pointer to node structure 1492ef270ab1SKenneth D. Merry * 1493ef270ab1SKenneth D. Merry * @return WWNN 1494ef270ab1SKenneth D. Merry * 1495ef270ab1SKenneth D. Merry */ 1496ef270ab1SKenneth D. Merry 1497ef270ab1SKenneth D. Merry uint64_t 1498ef270ab1SKenneth D. Merry ocs_node_get_wwnn(ocs_node_t *node) 1499ef270ab1SKenneth D. Merry { 1500ef270ab1SKenneth D. Merry fc_plogi_payload_t *sp = (fc_plogi_payload_t*) node->service_params; 1501ef270ab1SKenneth D. Merry 1502ef270ab1SKenneth D. Merry return (((uint64_t)ocs_be32toh(sp->node_name_hi) << 32ll) | (ocs_be32toh(sp->node_name_lo))); 1503ef270ab1SKenneth D. Merry } 1504ef270ab1SKenneth D. Merry 1505ef270ab1SKenneth D. Merry /** 1506ef270ab1SKenneth D. Merry * @brief Generate node ddump data 1507ef270ab1SKenneth D. Merry * 1508ef270ab1SKenneth D. Merry * Generates the node ddumpdata 1509ef270ab1SKenneth D. Merry * 1510ef270ab1SKenneth D. Merry * @param textbuf pointer to text buffer 1511ef270ab1SKenneth D. Merry * @param node pointer to node context 1512ef270ab1SKenneth D. Merry * 1513ef270ab1SKenneth D. Merry * @return Returns 0 on success, or a negative value on failure. 1514ef270ab1SKenneth D. Merry */ 1515ef270ab1SKenneth D. Merry 1516ef270ab1SKenneth D. Merry int 1517ef270ab1SKenneth D. Merry ocs_ddump_node(ocs_textbuf_t *textbuf, ocs_node_t *node) 1518ef270ab1SKenneth D. Merry { 1519ef270ab1SKenneth D. Merry ocs_io_t *io; 1520ef270ab1SKenneth D. Merry ocs_io_t *els; 1521ef270ab1SKenneth D. Merry int retval = 0; 1522ef270ab1SKenneth D. Merry 1523ef270ab1SKenneth D. Merry ocs_ddump_section(textbuf, "node", node->instance_index); 1524ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "display_name", "%s", node->display_name); 1525ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "current_state", "%s", node->current_state_name); 1526ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "prev_state", "%s", node->prev_state_name); 1527ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "current_evt", "%s", ocs_sm_event_name(node->current_evt)); 1528ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "prev_evt", "%s", ocs_sm_event_name(node->prev_evt)); 1529ef270ab1SKenneth D. Merry 1530ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "indicator", "%#x", node->rnode.indicator); 1531ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "fc_id", "%#06x", node->rnode.fc_id); 1532ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "attached", "%d", node->rnode.attached); 1533ef270ab1SKenneth D. Merry 1534ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "hold_frames", "%d", node->hold_frames); 1535ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "io_alloc_enabled", "%d", node->io_alloc_enabled); 1536ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "shutdown_reason", "%d", node->shutdown_reason); 1537ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "send_ls_acc", "%d", node->send_ls_acc); 1538ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "ls_acc_did", "%d", node->ls_acc_did); 1539ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "ls_acc_oxid", "%#04x", node->ls_acc_oxid); 1540ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "req_free", "%d", node->req_free); 1541ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "els_req_cnt", "%d", node->els_req_cnt); 1542ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "els_cmpl_cnt", "%d", node->els_cmpl_cnt); 1543ef270ab1SKenneth D. Merry 1544ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "targ", "%d", node->targ); 1545ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "init", "%d", node->init); 1546ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "wwnn", "%s", node->wwnn); 1547ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "wwpn", "%s", node->wwpn); 1548ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "login_state", "%d", (node->sm.current_state == __ocs_d_device_ready) ? 1 : 0); 1549ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "chained_io_count", "%d", node->chained_io_count); 1550ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "abort_cnt", "%d", node->abort_cnt); 1551ef270ab1SKenneth D. Merry 1552ef270ab1SKenneth D. Merry ocs_display_sparams(NULL, "node_sparams", 1, textbuf, node->service_params+4); 1553ef270ab1SKenneth D. Merry 1554ef270ab1SKenneth D. Merry ocs_lock(&node->pend_frames_lock); 1555ef270ab1SKenneth D. Merry if (!ocs_list_empty(&node->pend_frames)) { 1556ef270ab1SKenneth D. Merry ocs_hw_sequence_t *frame; 1557ef270ab1SKenneth D. Merry ocs_ddump_section(textbuf, "pending_frames", 0); 1558ef270ab1SKenneth D. Merry ocs_list_foreach(&node->pend_frames, frame) { 1559ef270ab1SKenneth D. Merry fc_header_t *hdr; 1560ef270ab1SKenneth D. Merry char buf[128]; 1561ef270ab1SKenneth D. Merry 1562ef270ab1SKenneth D. Merry hdr = frame->header->dma.virt; 1563ef270ab1SKenneth D. Merry ocs_snprintf(buf, sizeof(buf), "%02x/%04x/%04x len %zu", 1564ef270ab1SKenneth D. Merry hdr->r_ctl, ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id), 1565ef270ab1SKenneth D. Merry frame->payload->dma.len); 1566ef270ab1SKenneth D. Merry ocs_ddump_value(textbuf, "frame", "%s", buf); 1567ef270ab1SKenneth D. Merry } 1568ef270ab1SKenneth D. Merry ocs_ddump_endsection(textbuf, "pending_frames", 0); 1569ef270ab1SKenneth D. Merry } 1570ef270ab1SKenneth D. Merry ocs_unlock(&node->pend_frames_lock); 1571ef270ab1SKenneth D. Merry 1572ef270ab1SKenneth D. Merry ocs_scsi_ini_ddump(textbuf, OCS_SCSI_DDUMP_NODE, node); 1573ef270ab1SKenneth D. Merry ocs_scsi_tgt_ddump(textbuf, OCS_SCSI_DDUMP_NODE, node); 1574ef270ab1SKenneth D. Merry 1575ef270ab1SKenneth D. Merry ocs_lock(&node->active_ios_lock); 1576ef270ab1SKenneth D. Merry ocs_ddump_section(textbuf, "active_ios", 0); 1577ef270ab1SKenneth D. Merry ocs_list_foreach(&node->active_ios, io) { 1578ef270ab1SKenneth D. Merry ocs_ddump_io(textbuf, io); 1579ef270ab1SKenneth D. Merry } 1580ef270ab1SKenneth D. Merry ocs_ddump_endsection(textbuf, "active_ios", 0); 1581ef270ab1SKenneth D. Merry 1582ef270ab1SKenneth D. Merry ocs_ddump_section(textbuf, "els_io_pend_list", 0); 1583ef270ab1SKenneth D. Merry ocs_list_foreach(&node->els_io_pend_list, els) { 1584ef270ab1SKenneth D. Merry ocs_ddump_els(textbuf, els); 1585ef270ab1SKenneth D. Merry } 1586ef270ab1SKenneth D. Merry ocs_ddump_endsection(textbuf, "els_io_pend_list", 0); 1587ef270ab1SKenneth D. Merry 1588ef270ab1SKenneth D. Merry ocs_ddump_section(textbuf, "els_io_active_list", 0); 1589ef270ab1SKenneth D. Merry ocs_list_foreach(&node->els_io_active_list, els) { 1590ef270ab1SKenneth D. Merry ocs_ddump_els(textbuf, els); 1591ef270ab1SKenneth D. Merry } 1592ef270ab1SKenneth D. Merry ocs_ddump_endsection(textbuf, "els_io_active_list", 0); 1593ef270ab1SKenneth D. Merry ocs_unlock(&node->active_ios_lock); 1594ef270ab1SKenneth D. Merry 1595ef270ab1SKenneth D. Merry ocs_ddump_endsection(textbuf, "node", node->instance_index); 1596ef270ab1SKenneth D. Merry 1597ef270ab1SKenneth D. Merry return retval; 1598ef270ab1SKenneth D. Merry } 1599ef270ab1SKenneth D. Merry 1600ef270ab1SKenneth D. Merry /** 1601ef270ab1SKenneth D. Merry * @brief check ELS request completion 1602ef270ab1SKenneth D. Merry * 1603ef270ab1SKenneth D. Merry * Check ELS request completion event to make sure it's for the 1604ef270ab1SKenneth D. Merry * ELS request we expect. If not, invoke given common event 1605ef270ab1SKenneth D. Merry * handler and return an error. 1606ef270ab1SKenneth D. Merry * 1607ef270ab1SKenneth D. Merry * @param ctx state machine context 1608ef270ab1SKenneth D. Merry * @param evt ELS request event 1609ef270ab1SKenneth D. Merry * @param arg event argument 1610ef270ab1SKenneth D. Merry * @param cmd ELS command expected 1611ef270ab1SKenneth D. Merry * @param node_common_func common event handler to call if ELS 1612ef270ab1SKenneth D. Merry * doesn't match 1613ef270ab1SKenneth D. Merry * @param funcname function name that called this 1614ef270ab1SKenneth D. Merry * 1615ef270ab1SKenneth D. Merry * @return zero if ELS command matches, -1 otherwise 1616ef270ab1SKenneth D. Merry */ 1617ef270ab1SKenneth D. Merry int32_t 1618ef270ab1SKenneth D. Merry node_check_els_req(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg, uint8_t cmd, ocs_node_common_func_t node_common_func, const char *funcname) 1619ef270ab1SKenneth D. Merry { 1620ef270ab1SKenneth D. Merry ocs_node_t *node = NULL; 1621ef270ab1SKenneth D. Merry ocs_t *ocs = NULL; 1622ef270ab1SKenneth D. Merry ocs_node_cb_t *cbdata = arg; 1623ef270ab1SKenneth D. Merry fc_els_gen_t *els_gen = NULL; 1624ef270ab1SKenneth D. Merry ocs_assert(ctx, -1); 1625ef270ab1SKenneth D. Merry node = ctx->app; 1626ef270ab1SKenneth D. Merry ocs_assert(node, -1); 1627ef270ab1SKenneth D. Merry ocs = node->ocs; 1628ef270ab1SKenneth D. Merry ocs_assert(ocs, -1); 1629ef270ab1SKenneth D. Merry cbdata = arg; 1630ef270ab1SKenneth D. Merry ocs_assert(cbdata, -1); 1631ef270ab1SKenneth D. Merry ocs_assert(cbdata->els, -1); 1632ef270ab1SKenneth D. Merry els_gen = (fc_els_gen_t *)cbdata->els->els_req.virt; 1633ef270ab1SKenneth D. Merry ocs_assert(els_gen, -1); 1634ef270ab1SKenneth D. Merry 1635ef270ab1SKenneth D. Merry if ((cbdata->els->hio_type != OCS_HW_ELS_REQ) || (els_gen->command_code != cmd)) { 1636ef270ab1SKenneth D. Merry if (cbdata->els->hio_type != OCS_HW_ELS_REQ) { 1637ef270ab1SKenneth D. Merry ocs_log_debug(node->ocs, "[%s] %-20s expecting ELS cmd=x%x received type=%d\n", 1638ef270ab1SKenneth D. Merry node->display_name, funcname, cmd, cbdata->els->hio_type); 1639ef270ab1SKenneth D. Merry } else { 1640ef270ab1SKenneth D. Merry ocs_log_debug(node->ocs, "[%s] %-20s expecting ELS cmd=x%x received cmd=x%x\n", 1641ef270ab1SKenneth D. Merry node->display_name, funcname, cmd, els_gen->command_code); 1642ef270ab1SKenneth D. Merry } 1643ef270ab1SKenneth D. Merry /* send event to common handler */ 1644ef270ab1SKenneth D. Merry node_common_func(funcname, ctx, evt, arg); 1645ef270ab1SKenneth D. Merry return -1; 1646ef270ab1SKenneth D. Merry } 1647ef270ab1SKenneth D. Merry return 0; 1648ef270ab1SKenneth D. Merry } 1649ef270ab1SKenneth D. Merry 1650ef270ab1SKenneth D. Merry /** 1651ef270ab1SKenneth D. Merry * @brief check NS request completion 1652ef270ab1SKenneth D. Merry * 1653ef270ab1SKenneth D. Merry * Check ELS request completion event to make sure it's for the 1654ef270ab1SKenneth D. Merry * nameserver request we expect. If not, invoke given common 1655ef270ab1SKenneth D. Merry * event handler and return an error. 1656ef270ab1SKenneth D. Merry * 1657ef270ab1SKenneth D. Merry * @param ctx state machine context 1658ef270ab1SKenneth D. Merry * @param evt ELS request event 1659ef270ab1SKenneth D. Merry * @param arg event argument 1660ef270ab1SKenneth D. Merry * @param cmd nameserver command expected 1661ef270ab1SKenneth D. Merry * @param node_common_func common event handler to call if 1662ef270ab1SKenneth D. Merry * nameserver cmd doesn't match 1663ef270ab1SKenneth D. Merry * @param funcname function name that called this 1664ef270ab1SKenneth D. Merry * 1665ef270ab1SKenneth D. Merry * @return zero if NS command matches, -1 otherwise 1666ef270ab1SKenneth D. Merry */ 1667ef270ab1SKenneth D. Merry int32_t 1668ef270ab1SKenneth D. Merry node_check_ns_req(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg, uint32_t cmd, ocs_node_common_func_t node_common_func, const char *funcname) 1669ef270ab1SKenneth D. Merry { 1670ef270ab1SKenneth D. Merry ocs_node_t *node = NULL; 1671ef270ab1SKenneth D. Merry ocs_t *ocs = NULL; 1672ef270ab1SKenneth D. Merry ocs_node_cb_t *cbdata = arg; 1673ef270ab1SKenneth D. Merry fcct_iu_header_t *fcct = NULL; 1674ef270ab1SKenneth D. Merry ocs_assert(ctx, -1); 1675ef270ab1SKenneth D. Merry node = ctx->app; 1676ef270ab1SKenneth D. Merry ocs_assert(node, -1); 1677ef270ab1SKenneth D. Merry ocs = node->ocs; 1678ef270ab1SKenneth D. Merry ocs_assert(ocs, -1); 1679ef270ab1SKenneth D. Merry cbdata = arg; 1680ef270ab1SKenneth D. Merry ocs_assert(cbdata, -1); 1681ef270ab1SKenneth D. Merry ocs_assert(cbdata->els, -1); 1682ef270ab1SKenneth D. Merry fcct = (fcct_iu_header_t *)cbdata->els->els_req.virt; 1683ef270ab1SKenneth D. Merry ocs_assert(fcct, -1); 1684ef270ab1SKenneth D. Merry 1685ef270ab1SKenneth D. Merry if ((cbdata->els->hio_type != OCS_HW_FC_CT) || fcct->cmd_rsp_code != ocs_htobe16(cmd)) { 1686ef270ab1SKenneth D. Merry if (cbdata->els->hio_type != OCS_HW_FC_CT) { 1687ef270ab1SKenneth D. Merry ocs_log_debug(node->ocs, "[%s] %-20s expecting NS cmd=x%x received type=%d\n", 1688ef270ab1SKenneth D. Merry node->display_name, funcname, cmd, cbdata->els->hio_type); 1689ef270ab1SKenneth D. Merry } else { 1690ef270ab1SKenneth D. Merry ocs_log_debug(node->ocs, "[%s] %-20s expecting NS cmd=x%x received cmd=x%x\n", 1691ef270ab1SKenneth D. Merry node->display_name, funcname, cmd, fcct->cmd_rsp_code); 1692ef270ab1SKenneth D. Merry } 1693ef270ab1SKenneth D. Merry /* send event to common handler */ 1694ef270ab1SKenneth D. Merry node_common_func(funcname, ctx, evt, arg); 1695ef270ab1SKenneth D. Merry return -1; 1696ef270ab1SKenneth D. Merry } 1697ef270ab1SKenneth D. Merry return 0; 1698ef270ab1SKenneth D. Merry } 1699ef270ab1SKenneth D. Merry 1700ef270ab1SKenneth D. Merry 1701ef270ab1SKenneth D. Merry void 1702ef270ab1SKenneth D. Merry ocs_mgmt_node_list(ocs_textbuf_t *textbuf, void *object) 1703ef270ab1SKenneth D. Merry { 1704ef270ab1SKenneth D. Merry ocs_io_t *io; 1705ef270ab1SKenneth D. Merry ocs_node_t *node = (ocs_node_t *)object; 1706ef270ab1SKenneth D. Merry 1707ef270ab1SKenneth D. Merry ocs_mgmt_start_section(textbuf, "node", node->instance_index); 1708ef270ab1SKenneth D. Merry 1709ef270ab1SKenneth D. Merry /* Readonly values */ 1710ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "display_name"); 1711ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "indicator"); 1712ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "fc_id"); 1713ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "attached"); 1714ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "hold_frames"); 1715ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "shutting_down"); 1716ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "req_free"); 1717ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "ox_id"); 1718ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "ox_id_in_use"); 1719ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "abort_cnt"); 1720ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "targ"); 1721ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "init"); 1722ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "wwpn"); 1723ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "wwnn"); 1724ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "pend_frames"); 1725ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "chained_io_count"); 1726ef270ab1SKenneth D. Merry 1727ef270ab1SKenneth D. Merry /* Actions */ 1728ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_EX, "resume"); 1729ef270ab1SKenneth D. Merry 1730ef270ab1SKenneth D. Merry ocs_lock(&node->active_ios_lock); 1731ef270ab1SKenneth D. Merry ocs_list_foreach(&node->active_ios, io) { 1732ef270ab1SKenneth D. Merry if ((io->mgmt_functions) && (io->mgmt_functions->get_list_handler)) { 1733ef270ab1SKenneth D. Merry io->mgmt_functions->get_list_handler(textbuf, io); 1734ef270ab1SKenneth D. Merry } 1735ef270ab1SKenneth D. Merry } 1736ef270ab1SKenneth D. Merry ocs_unlock(&node->active_ios_lock); 1737ef270ab1SKenneth D. Merry 1738ef270ab1SKenneth D. Merry ocs_mgmt_end_section(textbuf, "node", node->instance_index); 1739ef270ab1SKenneth D. Merry } 1740ef270ab1SKenneth D. Merry 1741ef270ab1SKenneth D. Merry int 1742ef270ab1SKenneth D. Merry ocs_mgmt_node_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *object) 1743ef270ab1SKenneth D. Merry { 1744ef270ab1SKenneth D. Merry ocs_io_t *io; 1745ef270ab1SKenneth D. Merry ocs_node_t *node = (ocs_node_t *)object; 1746ef270ab1SKenneth D. Merry char qualifier[80]; 1747ef270ab1SKenneth D. Merry int retval = -1; 1748ef270ab1SKenneth D. Merry 1749ef270ab1SKenneth D. Merry ocs_mgmt_start_section(textbuf, "node", node->instance_index); 1750ef270ab1SKenneth D. Merry 1751ef270ab1SKenneth D. Merry ocs_snprintf(qualifier, sizeof(qualifier), "%s/node[%d]", parent, node->instance_index); 1752ef270ab1SKenneth D. Merry 1753ef270ab1SKenneth D. Merry /* If it doesn't start with my qualifier I don't know what to do with it */ 1754ef270ab1SKenneth D. Merry if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) { 1755ef270ab1SKenneth D. Merry char *unqualified_name = name + strlen(qualifier) +1; 1756ef270ab1SKenneth D. Merry 1757ef270ab1SKenneth D. Merry /* See if it's a value I can supply */ 1758ef270ab1SKenneth D. Merry if (ocs_strcmp(unqualified_name, "display_name") == 0) { 1759ef270ab1SKenneth D. Merry ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", node->display_name); 1760ef270ab1SKenneth D. Merry retval = 0; 1761ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "indicator") == 0) { 1762ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "indicator", "0x%x", node->rnode.indicator); 1763ef270ab1SKenneth D. Merry retval = 0; 1764ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "fc_id") == 0) { 1765ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fc_id", "0x%06x", node->rnode.fc_id); 1766ef270ab1SKenneth D. Merry retval = 0; 1767ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "attached") == 0) { 1768ef270ab1SKenneth D. Merry ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "attached", node->rnode.attached); 1769ef270ab1SKenneth D. Merry retval = 0; 1770ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "hold_frames") == 0) { 1771ef270ab1SKenneth D. Merry ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "hold_frames", node->hold_frames); 1772ef270ab1SKenneth D. Merry retval = 0; 1773ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "io_alloc_enabled") == 0) { 1774ef270ab1SKenneth D. Merry ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "io_alloc_enabled", node->io_alloc_enabled); 1775ef270ab1SKenneth D. Merry retval = 0; 1776ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "req_free") == 0) { 1777ef270ab1SKenneth D. Merry ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "req_free", node->req_free); 1778ef270ab1SKenneth D. Merry retval = 0; 1779ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "ls_acc_oxid") == 0) { 1780ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "ls_acc_oxid", "0x%#04x", node->ls_acc_oxid); 1781ef270ab1SKenneth D. Merry retval = 0; 1782ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "ls_acc_did") == 0) { 1783ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "ls_acc_did", "0x%#04x", node->ls_acc_did); 1784ef270ab1SKenneth D. Merry retval = 0; 1785ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "abort_cnt") == 0) { 1786ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "abort_cnt", "%d", node->abort_cnt); 1787ef270ab1SKenneth D. Merry retval = 0; 1788ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "targ") == 0) { 1789ef270ab1SKenneth D. Merry ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "targ", node->targ); 1790ef270ab1SKenneth D. Merry retval = 0; 1791ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "init") == 0) { 1792ef270ab1SKenneth D. Merry ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "init", node->init); 1793ef270ab1SKenneth D. Merry retval = 0; 1794ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "wwpn") == 0) { 1795ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwpn", "%s", node->wwpn); 1796ef270ab1SKenneth D. Merry retval = 0; 1797ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "wwnn") == 0) { 1798ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwnn", "%s", node->wwnn); 1799ef270ab1SKenneth D. Merry retval = 0; 1800ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "current_state") == 0) { 1801ef270ab1SKenneth D. Merry ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "current_state", node->current_state_name); 1802ef270ab1SKenneth D. Merry retval = 0; 1803ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "login_state") == 0) { 1804ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "login_state", "%d", (node->sm.current_state == __ocs_d_device_ready) ? 1 : 0); 1805ef270ab1SKenneth D. Merry retval = 0; 1806ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "pend_frames") == 0) { 1807ef270ab1SKenneth D. Merry ocs_hw_sequence_t *frame; 1808ef270ab1SKenneth D. Merry ocs_lock(&node->pend_frames_lock); 1809ef270ab1SKenneth D. Merry ocs_list_foreach(&node->pend_frames, frame) { 1810ef270ab1SKenneth D. Merry fc_header_t *hdr; 1811ef270ab1SKenneth D. Merry char buf[128]; 1812ef270ab1SKenneth D. Merry 1813ef270ab1SKenneth D. Merry hdr = frame->header->dma.virt; 1814ef270ab1SKenneth D. Merry ocs_snprintf(buf, sizeof(buf), "%02x/%04x/%04x len %zu", hdr->r_ctl, 1815ef270ab1SKenneth D. Merry ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id), 1816ef270ab1SKenneth D. Merry frame->payload->dma.len); 1817ef270ab1SKenneth D. Merry ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "pend_frames", buf); 1818ef270ab1SKenneth D. Merry } 1819ef270ab1SKenneth D. Merry ocs_unlock(&node->pend_frames_lock); 1820ef270ab1SKenneth D. Merry retval = 0; 1821ef270ab1SKenneth D. Merry } else if (ocs_strcmp(unqualified_name, "chained_io_count") == 0) { 1822ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "chained_io_count", "%d", node->chained_io_count); 1823ef270ab1SKenneth D. Merry retval = 0; 1824ef270ab1SKenneth D. Merry } else { 1825ef270ab1SKenneth D. Merry /* If I didn't know the value of this status pass the request to each of my children */ 1826ef270ab1SKenneth D. Merry ocs_lock(&node->active_ios_lock); 1827ef270ab1SKenneth D. Merry ocs_list_foreach(&node->active_ios, io) { 1828ef270ab1SKenneth D. Merry if ((io->mgmt_functions) && (io->mgmt_functions->get_handler)) { 1829ef270ab1SKenneth D. Merry retval = io->mgmt_functions->get_handler(textbuf, qualifier, name, io); 1830ef270ab1SKenneth D. Merry } 1831ef270ab1SKenneth D. Merry 1832ef270ab1SKenneth D. Merry if (retval == 0) { 1833ef270ab1SKenneth D. Merry break; 1834ef270ab1SKenneth D. Merry } 1835ef270ab1SKenneth D. Merry } 1836ef270ab1SKenneth D. Merry ocs_unlock(&node->active_ios_lock); 1837ef270ab1SKenneth D. Merry } 1838ef270ab1SKenneth D. Merry } 1839ef270ab1SKenneth D. Merry 1840ef270ab1SKenneth D. Merry ocs_mgmt_end_section(textbuf, "node", node->instance_index); 1841ef270ab1SKenneth D. Merry 1842ef270ab1SKenneth D. Merry return retval; 1843ef270ab1SKenneth D. Merry } 1844ef270ab1SKenneth D. Merry 1845ef270ab1SKenneth D. Merry void 1846ef270ab1SKenneth D. Merry ocs_mgmt_node_get_all(ocs_textbuf_t *textbuf, void *object) 1847ef270ab1SKenneth D. Merry { 1848ef270ab1SKenneth D. Merry ocs_io_t *io; 1849ef270ab1SKenneth D. Merry ocs_node_t *node = (ocs_node_t *)object; 1850ef270ab1SKenneth D. Merry ocs_hw_sequence_t *frame; 1851ef270ab1SKenneth D. Merry 1852ef270ab1SKenneth D. Merry ocs_mgmt_start_section(textbuf, "node", node->instance_index); 1853ef270ab1SKenneth D. Merry 1854ef270ab1SKenneth D. Merry ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", node->display_name); 1855ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "indicator", "0x%x", node->rnode.indicator); 1856ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fc_id", "0x%06x", node->rnode.fc_id); 1857ef270ab1SKenneth D. Merry ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "attached", node->rnode.attached); 1858ef270ab1SKenneth D. Merry ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "hold_frames", node->hold_frames); 1859ef270ab1SKenneth D. Merry ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "io_alloc_enabled", node->io_alloc_enabled); 1860ef270ab1SKenneth D. Merry ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "req_free", node->req_free); 1861ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "ls_acc_oxid", "0x%#04x", node->ls_acc_oxid); 1862ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "ls_acc_did", "0x%#04x", node->ls_acc_did); 1863ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "abort_cnt", "%d", node->abort_cnt); 1864ef270ab1SKenneth D. Merry ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "targ", node->targ); 1865ef270ab1SKenneth D. Merry ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "init", node->init); 1866ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwpn", "%s", node->wwpn); 1867ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwnn", "%s", node->wwnn); 1868ef270ab1SKenneth D. Merry 1869ef270ab1SKenneth D. Merry ocs_lock(&node->pend_frames_lock); 1870ef270ab1SKenneth D. Merry ocs_list_foreach(&node->pend_frames, frame) { 1871ef270ab1SKenneth D. Merry fc_header_t *hdr; 1872ef270ab1SKenneth D. Merry char buf[128]; 1873ef270ab1SKenneth D. Merry 1874ef270ab1SKenneth D. Merry hdr = frame->header->dma.virt; 1875ef270ab1SKenneth D. Merry ocs_snprintf(buf, sizeof(buf), "%02x/%04x/%04x len %zu", hdr->r_ctl, 1876ef270ab1SKenneth D. Merry ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id), 1877ef270ab1SKenneth D. Merry frame->payload->dma.len); 1878ef270ab1SKenneth D. Merry ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "pend_frames", buf); 1879ef270ab1SKenneth D. Merry } 1880ef270ab1SKenneth D. Merry ocs_unlock(&node->pend_frames_lock); 1881ef270ab1SKenneth D. Merry 1882ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "chained_io_count", "%d", node->chained_io_count); 1883ef270ab1SKenneth D. Merry ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_EX, "resume"); 1884ef270ab1SKenneth D. Merry ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "current_state", node->current_state_name); 1885ef270ab1SKenneth D. Merry ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "login_state", "%d", (node->sm.current_state == __ocs_d_device_ready) ? 1 : 0); 1886ef270ab1SKenneth D. Merry 1887ef270ab1SKenneth D. Merry ocs_lock(&node->active_ios_lock); 1888ef270ab1SKenneth D. Merry ocs_list_foreach(&node->active_ios, io) { 1889ef270ab1SKenneth D. Merry if ((io->mgmt_functions) && (io->mgmt_functions->get_all_handler)) { 1890ef270ab1SKenneth D. Merry io->mgmt_functions->get_all_handler(textbuf,io); 1891ef270ab1SKenneth D. Merry } 1892ef270ab1SKenneth D. Merry } 1893ef270ab1SKenneth D. Merry ocs_unlock(&node->active_ios_lock); 1894ef270ab1SKenneth D. Merry 1895ef270ab1SKenneth D. Merry ocs_mgmt_end_section(textbuf, "node", node->instance_index); 1896ef270ab1SKenneth D. Merry } 1897ef270ab1SKenneth D. Merry 1898ef270ab1SKenneth D. Merry int 1899ef270ab1SKenneth D. Merry ocs_mgmt_node_set(char *parent, char *name, char *value, void *object) 1900ef270ab1SKenneth D. Merry { 1901ef270ab1SKenneth D. Merry ocs_io_t *io; 1902ef270ab1SKenneth D. Merry ocs_node_t *node = (ocs_node_t *)object; 1903ef270ab1SKenneth D. Merry char qualifier[80]; 1904ef270ab1SKenneth D. Merry int retval = -1; 1905ef270ab1SKenneth D. Merry 1906ef270ab1SKenneth D. Merry ocs_snprintf(qualifier, sizeof(qualifier), "%s/node[%d]", parent, node->instance_index); 1907ef270ab1SKenneth D. Merry 1908ef270ab1SKenneth D. Merry /* If it doesn't start with my qualifier I don't know what to do with it */ 1909ef270ab1SKenneth D. Merry if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) { 1910ef270ab1SKenneth D. Merry 1911ef270ab1SKenneth D. Merry ocs_lock(&node->active_ios_lock); 1912ef270ab1SKenneth D. Merry ocs_list_foreach(&node->active_ios, io) { 1913ef270ab1SKenneth D. Merry if ((io->mgmt_functions) && (io->mgmt_functions->set_handler)) { 1914ef270ab1SKenneth D. Merry retval = io->mgmt_functions->set_handler(qualifier, name, value, io); 1915ef270ab1SKenneth D. Merry } 1916ef270ab1SKenneth D. Merry 1917ef270ab1SKenneth D. Merry if (retval == 0) { 1918ef270ab1SKenneth D. Merry break; 1919ef270ab1SKenneth D. Merry } 1920ef270ab1SKenneth D. Merry 1921ef270ab1SKenneth D. Merry } 1922ef270ab1SKenneth D. Merry ocs_unlock(&node->active_ios_lock); 1923ef270ab1SKenneth D. Merry 1924ef270ab1SKenneth D. Merry } 1925ef270ab1SKenneth D. Merry 1926ef270ab1SKenneth D. Merry return retval; 1927ef270ab1SKenneth D. Merry } 1928ef270ab1SKenneth D. Merry 1929ef270ab1SKenneth D. Merry int 1930ef270ab1SKenneth D. Merry ocs_mgmt_node_exec(char *parent, char *action, void *arg_in, uint32_t arg_in_length, 1931ef270ab1SKenneth D. Merry void *arg_out, uint32_t arg_out_length, void *object) 1932ef270ab1SKenneth D. Merry { 1933ef270ab1SKenneth D. Merry ocs_io_t *io; 1934ef270ab1SKenneth D. Merry ocs_node_t *node = (ocs_node_t *)object; 1935ef270ab1SKenneth D. Merry char qualifier[80]; 1936ef270ab1SKenneth D. Merry int retval = -1; 1937ef270ab1SKenneth D. Merry 1938ef270ab1SKenneth D. Merry ocs_snprintf(qualifier, sizeof(qualifier), "%s.node%d", parent, node->instance_index); 1939ef270ab1SKenneth D. Merry 1940ef270ab1SKenneth D. Merry /* If it doesn't start with my qualifier I don't know what to do with it */ 1941ef270ab1SKenneth D. Merry if (ocs_strncmp(action, qualifier, strlen(qualifier)) == 0) { 1942ef270ab1SKenneth D. Merry char *unqualified_name = action + strlen(qualifier) +1; 1943ef270ab1SKenneth D. Merry 1944ef270ab1SKenneth D. Merry if (ocs_strcmp(unqualified_name, "resume") == 0) { 1945ef270ab1SKenneth D. Merry ocs_node_post_event(node, OCS_EVT_RESUME, NULL); 1946ef270ab1SKenneth D. Merry } 1947ef270ab1SKenneth D. Merry 1948ef270ab1SKenneth D. Merry { 1949ef270ab1SKenneth D. Merry /* If I didn't know how to do this action pass the request to each of my children */ 1950ef270ab1SKenneth D. Merry ocs_lock(&node->active_ios_lock); 1951ef270ab1SKenneth D. Merry ocs_list_foreach(&node->active_ios, io) { 1952ef270ab1SKenneth D. Merry if ((io->mgmt_functions) && (io->mgmt_functions->exec_handler)) { 1953ef270ab1SKenneth D. Merry retval = io->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length, 1954ef270ab1SKenneth D. Merry arg_out, arg_out_length, io); 1955ef270ab1SKenneth D. Merry } 1956ef270ab1SKenneth D. Merry 1957ef270ab1SKenneth D. Merry if (retval == 0) { 1958ef270ab1SKenneth D. Merry break; 1959ef270ab1SKenneth D. Merry } 1960ef270ab1SKenneth D. Merry 1961ef270ab1SKenneth D. Merry } 1962ef270ab1SKenneth D. Merry ocs_unlock(&node->active_ios_lock); 1963ef270ab1SKenneth D. Merry } 1964ef270ab1SKenneth D. Merry } 1965ef270ab1SKenneth D. Merry 1966ef270ab1SKenneth D. Merry return retval; 1967ef270ab1SKenneth D. Merry } 1968ef270ab1SKenneth D. Merry 1969ef270ab1SKenneth D. Merry 1970ef270ab1SKenneth D. Merry 1971ef270ab1SKenneth D. Merry /** 1972ef270ab1SKenneth D. Merry * @brief Return TRUE if active ios list is empty 1973ef270ab1SKenneth D. Merry * 1974ef270ab1SKenneth D. Merry * Test if node->active_ios list is empty while holding the node->active_ios_lock. 1975ef270ab1SKenneth D. Merry * 1976ef270ab1SKenneth D. Merry * @param node pointer to node object 1977ef270ab1SKenneth D. Merry * 1978ef270ab1SKenneth D. Merry * @return TRUE if node active ios list is empty 1979ef270ab1SKenneth D. Merry */ 1980ef270ab1SKenneth D. Merry 1981ef270ab1SKenneth D. Merry int 1982ef270ab1SKenneth D. Merry ocs_node_active_ios_empty(ocs_node_t *node) 1983ef270ab1SKenneth D. Merry { 1984ef270ab1SKenneth D. Merry int empty; 1985ef270ab1SKenneth D. Merry 1986ef270ab1SKenneth D. Merry ocs_lock(&node->active_ios_lock); 1987ef270ab1SKenneth D. Merry empty = ocs_list_empty(&node->active_ios); 1988ef270ab1SKenneth D. Merry ocs_unlock(&node->active_ios_lock); 1989ef270ab1SKenneth D. Merry return empty; 1990ef270ab1SKenneth D. Merry } 1991ef270ab1SKenneth D. Merry 1992ef270ab1SKenneth D. Merry /** 1993ef270ab1SKenneth D. Merry * @brief Pause a node 1994ef270ab1SKenneth D. Merry * 1995ef270ab1SKenneth D. Merry * The node is placed in the __ocs_node_paused state after saving the state 1996ef270ab1SKenneth D. Merry * to return to 1997ef270ab1SKenneth D. Merry * 1998ef270ab1SKenneth D. Merry * @param node Pointer to node object 1999ef270ab1SKenneth D. Merry * @param state State to resume to 2000ef270ab1SKenneth D. Merry * 2001ef270ab1SKenneth D. Merry * @return none 2002ef270ab1SKenneth D. Merry */ 2003ef270ab1SKenneth D. Merry 2004ef270ab1SKenneth D. Merry void 2005ef270ab1SKenneth D. Merry ocs_node_pause(ocs_node_t *node, ocs_sm_function_t state) 2006ef270ab1SKenneth D. Merry { 2007ef270ab1SKenneth D. Merry node->nodedb_state = state; 2008ef270ab1SKenneth D. Merry ocs_node_transition(node, __ocs_node_paused, NULL); 2009ef270ab1SKenneth D. Merry } 2010ef270ab1SKenneth D. Merry 2011ef270ab1SKenneth D. Merry /** 2012ef270ab1SKenneth D. Merry * @brief Paused node state 2013ef270ab1SKenneth D. Merry * 2014ef270ab1SKenneth D. Merry * This state is entered when a state is "paused". When resumed, the node 2015ef270ab1SKenneth D. Merry * is transitioned to a previously saved state (node->ndoedb_state) 2016ef270ab1SKenneth D. Merry * 2017ef270ab1SKenneth D. Merry * @param ctx Remote node state machine context. 2018ef270ab1SKenneth D. Merry * @param evt Event to process. 2019ef270ab1SKenneth D. Merry * @param arg Per event optional argument. 2020ef270ab1SKenneth D. Merry * 2021ef270ab1SKenneth D. Merry * @return returns NULL 2022ef270ab1SKenneth D. Merry */ 2023ef270ab1SKenneth D. Merry 2024ef270ab1SKenneth D. Merry void * 2025ef270ab1SKenneth D. Merry __ocs_node_paused(ocs_sm_ctx_t *ctx, ocs_sm_event_t evt, void *arg) 2026ef270ab1SKenneth D. Merry { 2027ef270ab1SKenneth D. Merry std_node_state_decl(); 2028ef270ab1SKenneth D. Merry 2029ef270ab1SKenneth D. Merry node_sm_trace(); 2030ef270ab1SKenneth D. Merry 2031ef270ab1SKenneth D. Merry switch(evt) { 2032ef270ab1SKenneth D. Merry case OCS_EVT_ENTER: 2033ef270ab1SKenneth D. Merry node_printf(node, "Paused\n"); 2034ef270ab1SKenneth D. Merry break; 2035ef270ab1SKenneth D. Merry 2036ef270ab1SKenneth D. Merry case OCS_EVT_RESUME: { 2037ef270ab1SKenneth D. Merry ocs_sm_function_t pf = node->nodedb_state; 2038ef270ab1SKenneth D. Merry 2039ef270ab1SKenneth D. Merry node->nodedb_state = NULL; 2040ef270ab1SKenneth D. Merry ocs_node_transition(node, pf, NULL); 2041ef270ab1SKenneth D. Merry break; 2042ef270ab1SKenneth D. Merry } 2043ef270ab1SKenneth D. Merry 2044ef270ab1SKenneth D. Merry case OCS_EVT_DOMAIN_ATTACH_OK: 2045ef270ab1SKenneth D. Merry break; 2046ef270ab1SKenneth D. Merry 2047ef270ab1SKenneth D. Merry case OCS_EVT_SHUTDOWN: 2048ef270ab1SKenneth D. Merry node->req_free = 1; 2049ef270ab1SKenneth D. Merry break; 2050ef270ab1SKenneth D. Merry 2051ef270ab1SKenneth D. Merry default: 2052ef270ab1SKenneth D. Merry __ocs_node_common(__func__, ctx, evt, arg); 2053ef270ab1SKenneth D. Merry break; 2054ef270ab1SKenneth D. Merry } 2055ef270ab1SKenneth D. Merry return NULL; 2056ef270ab1SKenneth D. Merry } 2057ef270ab1SKenneth D. Merry 2058ef270ab1SKenneth D. Merry /** 2059ef270ab1SKenneth D. Merry * @brief Resume a paused state 2060ef270ab1SKenneth D. Merry * 2061ef270ab1SKenneth D. Merry * Posts a resume event to the paused node. 2062ef270ab1SKenneth D. Merry * 2063ef270ab1SKenneth D. Merry * @param node Pointer to node object 2064ef270ab1SKenneth D. Merry * 2065ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 2066ef270ab1SKenneth D. Merry */ 2067ef270ab1SKenneth D. Merry 2068ef270ab1SKenneth D. Merry int32_t 2069ef270ab1SKenneth D. Merry ocs_node_resume(ocs_node_t *node) 2070ef270ab1SKenneth D. Merry { 2071ef270ab1SKenneth D. Merry ocs_assert(node != NULL, -1); 2072ef270ab1SKenneth D. Merry 2073ef270ab1SKenneth D. Merry ocs_node_post_event(node, OCS_EVT_RESUME, NULL); 2074ef270ab1SKenneth D. Merry 2075ef270ab1SKenneth D. Merry return 0; 2076ef270ab1SKenneth D. Merry } 2077ef270ab1SKenneth D. Merry 2078ef270ab1SKenneth D. Merry /** 2079ef270ab1SKenneth D. Merry * @ingroup node_common 2080ef270ab1SKenneth D. Merry * @brief Dispatch a ELS frame. 2081ef270ab1SKenneth D. Merry * 2082ef270ab1SKenneth D. Merry * <h3 class="desc">Description</h3> 2083ef270ab1SKenneth D. Merry * An ELS frame is dispatched to the \c node state machine. 2084ef270ab1SKenneth D. Merry * RQ Pair mode: this function is always called with a NULL hw 2085ef270ab1SKenneth D. Merry * io. 2086ef270ab1SKenneth D. Merry * 2087ef270ab1SKenneth D. Merry * @param node Node that originated the frame. 2088ef270ab1SKenneth D. Merry * @param seq header/payload sequence buffers 2089ef270ab1SKenneth D. Merry * 2090ef270ab1SKenneth D. Merry * @return Returns 0 if frame processed and RX buffers cleaned 2091ef270ab1SKenneth D. Merry * up appropriately, -1 if frame not handled and RX buffers need 2092ef270ab1SKenneth D. Merry * to be returned. 2093ef270ab1SKenneth D. Merry */ 2094ef270ab1SKenneth D. Merry 2095ef270ab1SKenneth D. Merry int32_t 2096ef270ab1SKenneth D. Merry ocs_node_recv_els_frame(ocs_node_t *node, ocs_hw_sequence_t *seq) 2097ef270ab1SKenneth D. Merry { 2098ef270ab1SKenneth D. Merry struct { 2099ef270ab1SKenneth D. Merry uint32_t cmd; 2100ef270ab1SKenneth D. Merry ocs_sm_event_t evt; 2101ef270ab1SKenneth D. Merry uint32_t payload_size; 2102ef270ab1SKenneth D. Merry } els_cmd_list[] = { 2103ef270ab1SKenneth D. Merry {FC_ELS_CMD_PLOGI, OCS_EVT_PLOGI_RCVD, sizeof(fc_plogi_payload_t)}, 2104ef270ab1SKenneth D. Merry {FC_ELS_CMD_FLOGI, OCS_EVT_FLOGI_RCVD, sizeof(fc_plogi_payload_t)}, 2105ef270ab1SKenneth D. Merry {FC_ELS_CMD_LOGO, OCS_EVT_LOGO_RCVD, sizeof(fc_acc_payload_t)}, 2106ef270ab1SKenneth D. Merry {FC_ELS_CMD_RRQ, OCS_EVT_RRQ_RCVD, sizeof(fc_acc_payload_t)}, 2107ef270ab1SKenneth D. Merry {FC_ELS_CMD_PRLI, OCS_EVT_PRLI_RCVD, sizeof(fc_prli_payload_t)}, 2108ef270ab1SKenneth D. Merry {FC_ELS_CMD_PRLO, OCS_EVT_PRLO_RCVD, sizeof(fc_prlo_payload_t)}, 2109ef270ab1SKenneth D. Merry {FC_ELS_CMD_PDISC, OCS_EVT_PDISC_RCVD, MAX_ACC_REJECT_PAYLOAD}, 2110ef270ab1SKenneth D. Merry {FC_ELS_CMD_FDISC, OCS_EVT_FDISC_RCVD, MAX_ACC_REJECT_PAYLOAD}, 2111ef270ab1SKenneth D. Merry {FC_ELS_CMD_ADISC, OCS_EVT_ADISC_RCVD, sizeof(fc_adisc_payload_t)}, 2112ef270ab1SKenneth D. Merry {FC_ELS_CMD_RSCN, OCS_EVT_RSCN_RCVD, MAX_ACC_REJECT_PAYLOAD}, 2113ef270ab1SKenneth D. Merry {FC_ELS_CMD_SCR , OCS_EVT_SCR_RCVD, MAX_ACC_REJECT_PAYLOAD}, 2114ef270ab1SKenneth D. Merry }; 2115ef270ab1SKenneth D. Merry ocs_t *ocs = node->ocs; 2116ef270ab1SKenneth D. Merry ocs_node_cb_t cbdata; 2117ef270ab1SKenneth D. Merry fc_header_t *hdr = seq->header->dma.virt; 2118ef270ab1SKenneth D. Merry uint8_t *buf = seq->payload->dma.virt; 2119ef270ab1SKenneth D. Merry ocs_sm_event_t evt = OCS_EVT_ELS_RCVD; 2120ef270ab1SKenneth D. Merry uint32_t payload_size = MAX_ACC_REJECT_PAYLOAD; 2121ef270ab1SKenneth D. Merry uint32_t i; 2122ef270ab1SKenneth D. Merry 2123ef270ab1SKenneth D. Merry ocs_memset(&cbdata, 0, sizeof(cbdata)); 2124ef270ab1SKenneth D. Merry cbdata.header = seq->header; 2125ef270ab1SKenneth D. Merry cbdata.payload = seq->payload; 2126ef270ab1SKenneth D. Merry 2127ef270ab1SKenneth D. Merry /* find a matching event for the ELS command */ 2128ef270ab1SKenneth D. Merry for (i = 0; i < ARRAY_SIZE(els_cmd_list); i ++) { 2129ef270ab1SKenneth D. Merry if (els_cmd_list[i].cmd == buf[0]) { 2130ef270ab1SKenneth D. Merry evt = els_cmd_list[i].evt; 2131ef270ab1SKenneth D. Merry payload_size = els_cmd_list[i].payload_size; 2132ef270ab1SKenneth D. Merry break; 2133ef270ab1SKenneth D. Merry } 2134ef270ab1SKenneth D. Merry } 2135ef270ab1SKenneth D. Merry 2136ef270ab1SKenneth D. Merry switch(evt) { 2137ef270ab1SKenneth D. Merry case OCS_EVT_FLOGI_RCVD: 2138ef270ab1SKenneth D. Merry ocs_display_sparams(node->display_name, "flogi rcvd req", 0, NULL, ((uint8_t*)seq->payload->dma.virt)+4); 2139ef270ab1SKenneth D. Merry break; 2140ef270ab1SKenneth D. Merry case OCS_EVT_FDISC_RCVD: 2141ef270ab1SKenneth D. Merry ocs_display_sparams(node->display_name, "fdisc rcvd req", 0, NULL, ((uint8_t*)seq->payload->dma.virt)+4); 2142ef270ab1SKenneth D. Merry break; 2143ef270ab1SKenneth D. Merry case OCS_EVT_PLOGI_RCVD: 2144ef270ab1SKenneth D. Merry ocs_display_sparams(node->display_name, "plogi rcvd req", 0, NULL, ((uint8_t*)seq->payload->dma.virt)+4); 2145ef270ab1SKenneth D. Merry break; 2146ef270ab1SKenneth D. Merry default: 2147ef270ab1SKenneth D. Merry break; 2148ef270ab1SKenneth D. Merry } 2149ef270ab1SKenneth D. Merry 2150ef270ab1SKenneth D. Merry cbdata.io = ocs_els_io_alloc(node, payload_size, OCS_ELS_ROLE_RESPONDER); 2151ef270ab1SKenneth D. Merry 2152ef270ab1SKenneth D. Merry if (cbdata.io != NULL) { 2153ef270ab1SKenneth D. Merry cbdata.io->hw_priv = seq->hw_priv; 2154ef270ab1SKenneth D. Merry /* if we're here, sequence initiative has been transferred */ 2155ef270ab1SKenneth D. Merry cbdata.io->seq_init = 1; 2156ef270ab1SKenneth D. Merry 2157ef270ab1SKenneth D. Merry ocs_node_post_event(node, evt, &cbdata); 2158ef270ab1SKenneth D. Merry } else { 2159ef270ab1SKenneth D. Merry node_printf(node, "failure to allocate SCSI IO for ELS s_id %06x d_id %06x ox_id %04x rx_id %04x\n", 2160ef270ab1SKenneth D. Merry fc_be24toh(hdr->s_id), fc_be24toh(hdr->d_id), ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id)); 2161ef270ab1SKenneth D. Merry } 2162ef270ab1SKenneth D. Merry ocs_hw_sequence_free(&ocs->hw, seq); 2163ef270ab1SKenneth D. Merry return 0; 2164ef270ab1SKenneth D. Merry } 2165ef270ab1SKenneth D. Merry 2166ef270ab1SKenneth D. Merry /** 2167ef270ab1SKenneth D. Merry * @ingroup node_common 2168ef270ab1SKenneth D. Merry * @brief Dispatch a ABTS frame (RQ Pair/sequence coalescing). 2169ef270ab1SKenneth D. Merry * 2170ef270ab1SKenneth D. Merry * <h3 class="desc">Description</h3> 2171ef270ab1SKenneth D. Merry * An ABTS frame is dispatched to the node state machine. This 2172ef270ab1SKenneth D. Merry * function is used for both RQ Pair and sequence coalescing. 2173ef270ab1SKenneth D. Merry * 2174ef270ab1SKenneth D. Merry * @param node Node that originated the frame. 2175ef270ab1SKenneth D. Merry * @param seq Header/payload sequence buffers 2176ef270ab1SKenneth D. Merry * 2177ef270ab1SKenneth D. Merry * @return Returns 0 if frame processed and RX buffers cleaned 2178ef270ab1SKenneth D. Merry * up appropriately, -1 if frame not handled and RX buffers need 2179ef270ab1SKenneth D. Merry * to be returned. 2180ef270ab1SKenneth D. Merry */ 2181ef270ab1SKenneth D. Merry 2182ef270ab1SKenneth D. Merry int32_t 2183ef270ab1SKenneth D. Merry ocs_node_recv_abts_frame(ocs_node_t *node, ocs_hw_sequence_t *seq) 2184ef270ab1SKenneth D. Merry { 2185ef270ab1SKenneth D. Merry ocs_t *ocs = node->ocs; 2186ef270ab1SKenneth D. Merry ocs_xport_t *xport = ocs->xport; 2187ef270ab1SKenneth D. Merry fc_header_t *hdr = seq->header->dma.virt; 2188ef270ab1SKenneth D. Merry uint16_t ox_id = ocs_be16toh(hdr->ox_id); 2189ef270ab1SKenneth D. Merry uint16_t rx_id = ocs_be16toh(hdr->rx_id); 2190ef270ab1SKenneth D. Merry ocs_node_cb_t cbdata; 2191ef270ab1SKenneth D. Merry int32_t rc = 0; 2192ef270ab1SKenneth D. Merry 2193ef270ab1SKenneth D. Merry node->abort_cnt++; 2194ef270ab1SKenneth D. Merry 2195ef270ab1SKenneth D. Merry /* 2196ef270ab1SKenneth D. Merry * Check to see if the IO we want to abort is active, if it not active, 2197ef270ab1SKenneth D. Merry * then we can send the BA_ACC using the send frame option 2198ef270ab1SKenneth D. Merry */ 2199ef270ab1SKenneth D. Merry if (ocs_io_find_tgt_io(ocs, node, ox_id, rx_id) == NULL) { 2200ef270ab1SKenneth D. Merry uint32_t send_frame_capable; 2201ef270ab1SKenneth D. Merry 2202ef270ab1SKenneth D. Merry ocs_log_debug(ocs, "IO not found (ox_id %04x)\n", ox_id); 2203ef270ab1SKenneth D. Merry 2204ef270ab1SKenneth D. Merry /* If we have SEND_FRAME capability, then use it to send BA_ACC */ 2205ef270ab1SKenneth D. Merry rc = ocs_hw_get(&ocs->hw, OCS_HW_SEND_FRAME_CAPABLE, &send_frame_capable); 2206ef270ab1SKenneth D. Merry if ((rc == 0) && send_frame_capable) { 2207ef270ab1SKenneth D. Merry rc = ocs_sframe_send_bls_acc(node, seq); 2208ef270ab1SKenneth D. Merry if (rc) { 2209ef270ab1SKenneth D. Merry ocs_log_test(ocs, "ocs_bls_acc_send_frame failed\n"); 2210ef270ab1SKenneth D. Merry } 2211ef270ab1SKenneth D. Merry return rc; 2212ef270ab1SKenneth D. Merry } 2213ef270ab1SKenneth D. Merry /* continuing */ 2214ef270ab1SKenneth D. Merry } 2215ef270ab1SKenneth D. Merry 2216ef270ab1SKenneth D. Merry ocs_memset(&cbdata, 0, sizeof(cbdata)); 2217ef270ab1SKenneth D. Merry cbdata.header = seq->header; 2218ef270ab1SKenneth D. Merry cbdata.payload = seq->payload; 2219ef270ab1SKenneth D. Merry 2220ef270ab1SKenneth D. Merry cbdata.io = ocs_scsi_io_alloc(node, OCS_SCSI_IO_ROLE_RESPONDER); 2221ef270ab1SKenneth D. Merry if (cbdata.io != NULL) { 2222ef270ab1SKenneth D. Merry cbdata.io->hw_priv = seq->hw_priv; 2223ef270ab1SKenneth D. Merry /* If we got this far, SIT=1 */ 2224ef270ab1SKenneth D. Merry cbdata.io->seq_init = 1; 2225ef270ab1SKenneth D. Merry 2226ef270ab1SKenneth D. Merry /* fill out generic fields */ 2227ef270ab1SKenneth D. Merry cbdata.io->ocs = ocs; 2228ef270ab1SKenneth D. Merry cbdata.io->node = node; 2229ef270ab1SKenneth D. Merry cbdata.io->cmd_tgt = TRUE; 2230ef270ab1SKenneth D. Merry 2231ef270ab1SKenneth D. Merry ocs_node_post_event(node, OCS_EVT_ABTS_RCVD, &cbdata); 2232ef270ab1SKenneth D. Merry } else { 2233ef270ab1SKenneth D. Merry ocs_atomic_add_return(&xport->io_alloc_failed_count, 1); 2234ef270ab1SKenneth D. Merry node_printf(node, "SCSI IO allocation failed for ABTS received s_id %06x d_id %06x ox_id %04x rx_id %04x\n", 2235ef270ab1SKenneth D. Merry fc_be24toh(hdr->s_id), fc_be24toh(hdr->d_id), ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id)); 2236ef270ab1SKenneth D. Merry } 2237ef270ab1SKenneth D. Merry 2238ef270ab1SKenneth D. Merry /* ABTS processed, return RX buffer to the chip */ 2239ef270ab1SKenneth D. Merry ocs_hw_sequence_free(&ocs->hw, seq); 2240ef270ab1SKenneth D. Merry return 0; 2241ef270ab1SKenneth D. Merry } 2242ef270ab1SKenneth D. Merry 2243ef270ab1SKenneth D. Merry /** 2244ef270ab1SKenneth D. Merry * @ingroup node_common 2245ef270ab1SKenneth D. Merry * @brief Dispatch a CT frame. 2246ef270ab1SKenneth D. Merry * 2247ef270ab1SKenneth D. Merry * <h3 class="desc">Description</h3> 2248ef270ab1SKenneth D. Merry * A CT frame is dispatched to the \c node state machine. 2249ef270ab1SKenneth D. Merry * RQ Pair mode: this function is always called with a NULL hw 2250ef270ab1SKenneth D. Merry * io. 2251ef270ab1SKenneth D. Merry * 2252ef270ab1SKenneth D. Merry * @param node Node that originated the frame. 2253ef270ab1SKenneth D. Merry * @param seq header/payload sequence buffers 2254ef270ab1SKenneth D. Merry * 2255ef270ab1SKenneth D. Merry * @return Returns 0 if frame processed and RX buffers cleaned 2256ef270ab1SKenneth D. Merry * up appropriately, -1 if frame not handled and RX buffers need 2257ef270ab1SKenneth D. Merry * to be returned. 2258ef270ab1SKenneth D. Merry */ 2259ef270ab1SKenneth D. Merry 2260ef270ab1SKenneth D. Merry int32_t 2261ef270ab1SKenneth D. Merry ocs_node_recv_ct_frame(ocs_node_t *node, ocs_hw_sequence_t *seq) 2262ef270ab1SKenneth D. Merry { 2263ef270ab1SKenneth D. Merry ocs_t *ocs = node->ocs; 2264ef270ab1SKenneth D. Merry fc_header_t *hdr = seq->header->dma.virt; 2265ef270ab1SKenneth D. Merry fcct_iu_header_t *iu = seq->payload->dma.virt; 2266ef270ab1SKenneth D. Merry ocs_sm_event_t evt = OCS_EVT_ELS_RCVD; 2267ef270ab1SKenneth D. Merry uint32_t payload_size = MAX_ACC_REJECT_PAYLOAD; 2268ef270ab1SKenneth D. Merry uint16_t gscmd = ocs_be16toh(iu->cmd_rsp_code); 2269ef270ab1SKenneth D. Merry ocs_node_cb_t cbdata; 2270ef270ab1SKenneth D. Merry uint32_t i; 2271ef270ab1SKenneth D. Merry struct { 2272ef270ab1SKenneth D. Merry uint32_t cmd; 2273ef270ab1SKenneth D. Merry ocs_sm_event_t evt; 2274ef270ab1SKenneth D. Merry uint32_t payload_size; 2275ef270ab1SKenneth D. Merry } ct_cmd_list[] = { 2276ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_RFF_ID, OCS_EVT_RFF_ID_RCVD, 100}, 2277ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_RFT_ID, OCS_EVT_RFT_ID_RCVD, 100}, 2278ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_GNN_ID, OCS_EVT_GNN_ID_RCVD, 100}, 2279ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_GPN_ID, OCS_EVT_GPN_ID_RCVD, 100}, 2280ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_GFPN_ID, OCS_EVT_GFPN_ID_RCVD, 100}, 2281ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_GFF_ID, OCS_EVT_GFF_ID_RCVD, 100}, 2282ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_GID_FT, OCS_EVT_GID_FT_RCVD, 256}, 2283ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_GID_PT, OCS_EVT_GID_PT_RCVD, 256}, 2284ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_RPN_ID, OCS_EVT_RPN_ID_RCVD, 100}, 2285ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_RNN_ID, OCS_EVT_RNN_ID_RCVD, 100}, 2286ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_RCS_ID, OCS_EVT_RCS_ID_RCVD, 100}, 2287ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_RSNN_NN, OCS_EVT_RSNN_NN_RCVD, 100}, 2288ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_RSPN_ID, OCS_EVT_RSPN_ID_RCVD, 100}, 2289ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_RHBA, OCS_EVT_RHBA_RCVD, 100}, 2290ef270ab1SKenneth D. Merry {FC_GS_NAMESERVER_RPA, OCS_EVT_RPA_RCVD, 100}, 2291ef270ab1SKenneth D. Merry }; 2292ef270ab1SKenneth D. Merry 2293ef270ab1SKenneth D. Merry ocs_memset(&cbdata, 0, sizeof(cbdata)); 2294ef270ab1SKenneth D. Merry cbdata.header = seq->header; 2295ef270ab1SKenneth D. Merry cbdata.payload = seq->payload; 2296ef270ab1SKenneth D. Merry 2297ef270ab1SKenneth D. Merry /* find a matching event for the ELS/GS command */ 2298ef270ab1SKenneth D. Merry for (i = 0; i < ARRAY_SIZE(ct_cmd_list); i ++) { 2299ef270ab1SKenneth D. Merry if (ct_cmd_list[i].cmd == gscmd) { 2300ef270ab1SKenneth D. Merry evt = ct_cmd_list[i].evt; 2301ef270ab1SKenneth D. Merry payload_size = ct_cmd_list[i].payload_size; 2302ef270ab1SKenneth D. Merry break; 2303ef270ab1SKenneth D. Merry } 2304ef270ab1SKenneth D. Merry } 2305ef270ab1SKenneth D. Merry 2306ef270ab1SKenneth D. Merry /* Allocate an IO and send a reject */ 2307ef270ab1SKenneth D. Merry cbdata.io = ocs_els_io_alloc(node, payload_size, OCS_ELS_ROLE_RESPONDER); 2308ef270ab1SKenneth D. Merry if (cbdata.io == NULL) { 2309ef270ab1SKenneth D. Merry node_printf(node, "GS IO failed for s_id %06x d_id %06x ox_id %04x rx_id %04x\n", 2310ef270ab1SKenneth D. Merry fc_be24toh(hdr->s_id), fc_be24toh(hdr->d_id), 2311ef270ab1SKenneth D. Merry ocs_be16toh(hdr->ox_id), ocs_be16toh(hdr->rx_id)); 2312ef270ab1SKenneth D. Merry return -1; 2313ef270ab1SKenneth D. Merry } 2314ef270ab1SKenneth D. Merry cbdata.io->hw_priv = seq->hw_priv; 2315ef270ab1SKenneth D. Merry ocs_node_post_event(node, evt, &cbdata); 2316ef270ab1SKenneth D. Merry 2317ef270ab1SKenneth D. Merry ocs_hw_sequence_free(&ocs->hw, seq); 2318ef270ab1SKenneth D. Merry return 0; 2319ef270ab1SKenneth D. Merry } 2320ef270ab1SKenneth D. Merry 2321ef270ab1SKenneth D. Merry /** 2322ef270ab1SKenneth D. Merry * @ingroup node_common 2323ef270ab1SKenneth D. Merry * @brief Dispatch a FCP command frame when the node is not ready. 2324ef270ab1SKenneth D. Merry * 2325ef270ab1SKenneth D. Merry * <h3 class="desc">Description</h3> 2326ef270ab1SKenneth D. Merry * A frame is dispatched to the \c node state machine. 2327ef270ab1SKenneth D. Merry * 2328ef270ab1SKenneth D. Merry * @param node Node that originated the frame. 2329ef270ab1SKenneth D. Merry * @param seq header/payload sequence buffers 2330ef270ab1SKenneth D. Merry * 2331ef270ab1SKenneth D. Merry * @return Returns 0 if frame processed and RX buffers cleaned 2332ef270ab1SKenneth D. Merry * up appropriately, -1 if frame not handled. 2333ef270ab1SKenneth D. Merry */ 2334ef270ab1SKenneth D. Merry 2335ef270ab1SKenneth D. Merry int32_t 2336ef270ab1SKenneth D. Merry ocs_node_recv_fcp_cmd(ocs_node_t *node, ocs_hw_sequence_t *seq) 2337ef270ab1SKenneth D. Merry { 2338ef270ab1SKenneth D. Merry ocs_node_cb_t cbdata; 2339ef270ab1SKenneth D. Merry ocs_t *ocs = node->ocs; 2340ef270ab1SKenneth D. Merry 2341ef270ab1SKenneth D. Merry ocs_memset(&cbdata, 0, sizeof(cbdata)); 2342ef270ab1SKenneth D. Merry cbdata.header = seq->header; 2343ef270ab1SKenneth D. Merry cbdata.payload = seq->payload; 2344ef270ab1SKenneth D. Merry ocs_node_post_event(node, OCS_EVT_FCP_CMD_RCVD, &cbdata); 2345ef270ab1SKenneth D. Merry ocs_hw_sequence_free(&ocs->hw, seq); 2346ef270ab1SKenneth D. Merry return 0; 2347ef270ab1SKenneth D. Merry } 2348ef270ab1SKenneth D. Merry 2349ef270ab1SKenneth D. Merry /** 2350ef270ab1SKenneth D. Merry * @ingroup node_common 2351ef270ab1SKenneth D. Merry * @brief Stub handler for non-ABTS BLS frames 2352ef270ab1SKenneth D. Merry * 2353ef270ab1SKenneth D. Merry * <h3 class="desc">Description</h3> 2354ef270ab1SKenneth D. Merry * Log message and drop. Customer can plumb it to their back-end as needed 2355ef270ab1SKenneth D. Merry * 2356ef270ab1SKenneth D. Merry * @param node Node that originated the frame. 2357ef270ab1SKenneth D. Merry * @param seq header/payload sequence buffers 2358ef270ab1SKenneth D. Merry * 2359ef270ab1SKenneth D. Merry * @return Returns 0 2360ef270ab1SKenneth D. Merry */ 2361ef270ab1SKenneth D. Merry 2362ef270ab1SKenneth D. Merry int32_t 2363ef270ab1SKenneth D. Merry ocs_node_recv_bls_no_sit(ocs_node_t *node, ocs_hw_sequence_t *seq) 2364ef270ab1SKenneth D. Merry { 2365ef270ab1SKenneth D. Merry fc_header_t *hdr = seq->header->dma.virt; 2366ef270ab1SKenneth D. Merry 2367ef270ab1SKenneth D. Merry node_printf(node, "Dropping frame hdr = %08x %08x %08x %08x %08x %08x\n", 2368ef270ab1SKenneth D. Merry ocs_htobe32(((uint32_t *)hdr)[0]), 2369ef270ab1SKenneth D. Merry ocs_htobe32(((uint32_t *)hdr)[1]), 2370ef270ab1SKenneth D. Merry ocs_htobe32(((uint32_t *)hdr)[2]), 2371ef270ab1SKenneth D. Merry ocs_htobe32(((uint32_t *)hdr)[3]), 2372ef270ab1SKenneth D. Merry ocs_htobe32(((uint32_t *)hdr)[4]), 2373ef270ab1SKenneth D. Merry ocs_htobe32(((uint32_t *)hdr)[5])); 2374ef270ab1SKenneth D. Merry 2375ef270ab1SKenneth D. Merry return -1; 2376ef270ab1SKenneth D. Merry } 2377