1 /*- 2 * Copyright (c) 2017 Broadcom. All rights reserved. 3 * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /** 33 * @file 34 * The ocs_mgmt top level functions for Fibre Channel. 35 */ 36 37 /** 38 * @defgroup mgmt Management Functions 39 */ 40 41 #include "ocs.h" 42 #include "ocs_mgmt.h" 43 #include "ocs_gendump.h" 44 #include "ocs_vpd.h" 45 46 #define SFP_PAGE_SIZE 128 47 48 /* Executables*/ 49 50 static int ocs_mgmt_firmware_write(ocs_t *ocs, char *, void *buf, uint32_t buf_len, void*, uint32_t); 51 static int ocs_mgmt_firmware_reset(ocs_t *ocs, char *, void *buf, uint32_t buf_len, void*, uint32_t); 52 static int ocs_mgmt_function_reset(ocs_t *ocs, char *, void *buf, uint32_t buf_len, void*, uint32_t); 53 54 static void ocs_mgmt_fw_write_cb(int32_t status, uint32_t actual_write_length, uint32_t change_status, void *arg); 55 static int ocs_mgmt_force_assert(ocs_t *ocs, char *, void *buf, uint32_t buf_len, void*, uint32_t); 56 57 /* Getters */ 58 59 static void get_nodes_count(ocs_t *, char *, ocs_textbuf_t*); 60 static void get_desc(ocs_t *, char *, ocs_textbuf_t*); 61 static void get_fw_rev(ocs_t *, char *, ocs_textbuf_t*); 62 static void get_fw_rev2(ocs_t *, char *, ocs_textbuf_t*); 63 static void get_ipl(ocs_t *, char *, ocs_textbuf_t*); 64 static void get_wwnn(ocs_t *, char *, ocs_textbuf_t*); 65 static void get_wwpn(ocs_t *, char *, ocs_textbuf_t*); 66 static void get_fcid(ocs_t *, char *, ocs_textbuf_t *); 67 static void get_sn(ocs_t *, char *, ocs_textbuf_t*); 68 static void get_pn(ocs_t *, char *, ocs_textbuf_t*); 69 static void get_sli4_intf_reg(ocs_t *, char *, ocs_textbuf_t*); 70 static void get_phy_port_num(ocs_t *, char *, ocs_textbuf_t*); 71 static void get_asic_id(ocs_t *, char *, ocs_textbuf_t*); 72 static void get_pci_vendor(ocs_t *, char *, ocs_textbuf_t*); 73 static void get_pci_device(ocs_t *, char *, ocs_textbuf_t*); 74 static void get_pci_subsystem_vendor(ocs_t *, char *, ocs_textbuf_t*); 75 static void get_pci_subsystem_device(ocs_t *, char *, ocs_textbuf_t*); 76 static void get_businfo(ocs_t *, char *, ocs_textbuf_t*); 77 static void get_sfp_a0(ocs_t *, char *, ocs_textbuf_t*); 78 static void get_sfp_a2(ocs_t *, char *, ocs_textbuf_t*); 79 static void get_hw_rev1(ocs_t *, char *, ocs_textbuf_t*); 80 static void get_hw_rev2(ocs_t *, char *, ocs_textbuf_t*); 81 static void get_hw_rev3(ocs_t *, char *, ocs_textbuf_t*); 82 static void get_debug_mq_dump(ocs_t*, char*, ocs_textbuf_t*); 83 static void get_debug_cq_dump(ocs_t*, char*, ocs_textbuf_t*); 84 static void get_debug_wq_dump(ocs_t*, char*, ocs_textbuf_t*); 85 static void get_debug_eq_dump(ocs_t*, char*, ocs_textbuf_t*); 86 static void get_logmask(ocs_t*, char*, ocs_textbuf_t*); 87 static void get_current_speed(ocs_t*, char*, ocs_textbuf_t*); 88 static void get_current_topology(ocs_t*, char*, ocs_textbuf_t*); 89 static void get_current_link_state(ocs_t*, char*, ocs_textbuf_t*); 90 static void get_configured_speed(ocs_t*, char*, ocs_textbuf_t*); 91 static void get_configured_topology(ocs_t*, char*, ocs_textbuf_t*); 92 static void get_configured_link_state(ocs_t*, char*, ocs_textbuf_t*); 93 static void get_linkcfg(ocs_t*, char*, ocs_textbuf_t*); 94 static void get_req_wwnn(ocs_t*, char*, ocs_textbuf_t*); 95 static void get_req_wwpn(ocs_t*, char*, ocs_textbuf_t*); 96 static void get_nodedb_mask(ocs_t*, char*, ocs_textbuf_t*); 97 static void get_profile_list(ocs_t*, char*, ocs_textbuf_t*); 98 static void get_active_profile(ocs_t*, char*, ocs_textbuf_t*); 99 static void get_port_protocol(ocs_t*, char*, ocs_textbuf_t*); 100 static void get_driver_version(ocs_t*, char*, ocs_textbuf_t*); 101 static void get_chip_type(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf); 102 static void get_tgt_rscn_delay(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf); 103 static void get_tgt_rscn_period(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf); 104 static void get_inject_drop_cmd(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf); 105 static void get_inject_free_drop_cmd(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf); 106 static void get_inject_drop_data(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf); 107 static void get_inject_drop_resp(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf); 108 static void get_cmd_err_inject(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf); 109 static void get_cmd_delay_value(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf); 110 static void get_nv_wwpn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf); 111 static void get_nv_wwnn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf); 112 static void get_loglevel(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf); 113 static void get_node_abort_cnt(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf); 114 115 /* Setters */ 116 static int set_debug_mq_dump(ocs_t*, char*, char*); 117 static int set_debug_cq_dump(ocs_t*, char*, char*); 118 static int set_debug_wq_dump(ocs_t*, char*, char*); 119 static int set_debug_eq_dump(ocs_t*, char*, char*); 120 static int set_logmask(ocs_t*, char*, char*); 121 static int set_configured_link_state(ocs_t*, char*, char*); 122 static int set_linkcfg(ocs_t*, char*, char*); 123 static int set_nodedb_mask(ocs_t*, char*, char*); 124 static int set_port_protocol(ocs_t*, char*, char*); 125 static int set_active_profile(ocs_t*, char*, char*); 126 static int set_tgt_rscn_delay(ocs_t*, char*, char*); 127 static int set_tgt_rscn_period(ocs_t*, char*, char*); 128 static int set_inject_drop_cmd(ocs_t*, char*, char*); 129 static int set_inject_free_drop_cmd(ocs_t*, char*, char*); 130 static int set_inject_drop_data(ocs_t*, char*, char*); 131 static int set_inject_drop_resp(ocs_t*, char*, char*); 132 static int set_cmd_err_inject(ocs_t*, char*, char*); 133 static int set_cmd_delay_value(ocs_t*, char*, char*); 134 static int set_nv_wwn(ocs_t*, char*, char*); 135 static int set_loglevel(ocs_t*, char*, char*); 136 137 static void ocs_mgmt_linkcfg_cb(int32_t status, uintptr_t value, void *arg); 138 139 ocs_mgmt_table_entry_t mgmt_table[] = { 140 {"nodes_count", get_nodes_count, NULL, NULL}, 141 {"desc", get_desc, NULL, NULL}, 142 {"fw_rev", get_fw_rev, NULL, NULL}, 143 {"fw_rev2", get_fw_rev2, NULL, NULL}, 144 {"ipl", get_ipl, NULL, NULL}, 145 {"hw_rev1", get_hw_rev1, NULL, NULL}, 146 {"hw_rev2", get_hw_rev2, NULL, NULL}, 147 {"hw_rev3", get_hw_rev3, NULL, NULL}, 148 {"wwnn", get_wwnn, NULL, NULL}, 149 {"wwpn", get_wwpn, NULL, NULL}, 150 {"fc_id", get_fcid, NULL, NULL}, 151 {"sn", get_sn, NULL, NULL}, 152 {"pn", get_pn, NULL, NULL}, 153 {"sli4_intf_reg", get_sli4_intf_reg, NULL, NULL}, 154 {"phy_port_num", get_phy_port_num, NULL, NULL}, 155 {"asic_id_reg", get_asic_id, NULL, NULL}, 156 {"pci_vendor", get_pci_vendor, NULL, NULL}, 157 {"pci_device", get_pci_device, NULL, NULL}, 158 {"pci_subsystem_vendor", get_pci_subsystem_vendor, NULL, NULL}, 159 {"pci_subsystem_device", get_pci_subsystem_device, NULL, NULL}, 160 {"businfo", get_businfo, NULL, NULL}, 161 {"sfp_a0", get_sfp_a0, NULL, NULL}, 162 {"sfp_a2", get_sfp_a2, NULL, NULL}, 163 {"profile_list", get_profile_list, NULL, NULL}, 164 {"driver_version", get_driver_version, NULL, NULL}, 165 {"current_speed", get_current_speed, NULL, NULL}, 166 {"current_topology", get_current_topology, NULL, NULL}, 167 {"current_link_state", get_current_link_state, NULL, NULL}, 168 {"chip_type", get_chip_type, NULL, NULL}, 169 {"configured_speed", get_configured_speed, set_configured_speed, NULL}, 170 {"configured_topology", get_configured_topology, set_configured_topology, NULL}, 171 {"configured_link_state", get_configured_link_state, set_configured_link_state, NULL}, 172 {"debug_mq_dump", get_debug_mq_dump, set_debug_mq_dump, NULL}, 173 {"debug_cq_dump", get_debug_cq_dump, set_debug_cq_dump, NULL}, 174 {"debug_wq_dump", get_debug_wq_dump, set_debug_wq_dump, NULL}, 175 {"debug_eq_dump", get_debug_eq_dump, set_debug_eq_dump, NULL}, 176 {"logmask", get_logmask, set_logmask, NULL}, 177 {"loglevel", get_loglevel, set_loglevel, NULL}, 178 {"linkcfg", get_linkcfg, set_linkcfg, NULL}, 179 {"requested_wwnn", get_req_wwnn, set_req_wwnn, NULL}, 180 {"requested_wwpn", get_req_wwpn, set_req_wwpn, NULL}, 181 {"nodedb_mask", get_nodedb_mask, set_nodedb_mask, NULL}, 182 {"port_protocol", get_port_protocol, set_port_protocol, NULL}, 183 {"active_profile", get_active_profile, set_active_profile, NULL}, 184 {"firmware_write", NULL, NULL, ocs_mgmt_firmware_write}, 185 {"firmware_reset", NULL, NULL, ocs_mgmt_firmware_reset}, 186 {"function_reset", NULL, NULL, ocs_mgmt_function_reset}, 187 {"force_assert", NULL, NULL, ocs_mgmt_force_assert}, 188 189 {"tgt_rscn_delay", get_tgt_rscn_delay, set_tgt_rscn_delay, NULL}, 190 {"tgt_rscn_period", get_tgt_rscn_period, set_tgt_rscn_period, NULL}, 191 {"inject_drop_cmd", get_inject_drop_cmd, set_inject_drop_cmd, NULL}, 192 {"inject_free_drop_cmd", get_inject_free_drop_cmd, set_inject_free_drop_cmd, NULL}, 193 {"inject_drop_data", get_inject_drop_data, set_inject_drop_data, NULL}, 194 {"inject_drop_resp", get_inject_drop_resp, set_inject_drop_resp, NULL}, 195 {"cmd_err_inject", get_cmd_err_inject, set_cmd_err_inject, NULL}, 196 {"cmd_delay_value", get_cmd_delay_value, set_cmd_delay_value, NULL}, 197 {"nv_wwpn", get_nv_wwpn, NULL, NULL}, 198 {"nv_wwnn", get_nv_wwnn, NULL, NULL}, 199 {"nv_wwn", NULL, set_nv_wwn, NULL}, 200 {"node_abort_cnt", get_node_abort_cnt, NULL, NULL}, 201 }; 202 203 /** 204 * @ingroup mgmt 205 * @brief Get a list of options supported by the driver. 206 * 207 * @par Description 208 * This is the top level "get list" handler for the driver. It 209 * performs the following: 210 * - Adds entries to the textbuf for any actions supported by this level in the driver. 211 * - Calls a back-end function to add any actions supported by the back-end. 212 * - Calls a function on each child (domain) to recursively add supported actions. 213 * 214 * @param ocs Pointer to the ocs structure. 215 * @param textbuf Pointer to an ocs_textbuf, which is used to accumulate the results. 216 * 217 * @return Returns 0 on success, or a negative value on failure. 218 */ 219 220 void 221 ocs_mgmt_get_list(ocs_t *ocs, ocs_textbuf_t *textbuf) 222 { 223 ocs_domain_t *domain; 224 uint32_t i; 225 int access; 226 227 ocs_mgmt_start_unnumbered_section(textbuf, "ocs"); 228 229 for (i=0;i<ARRAY_SIZE(mgmt_table);i++) { 230 access = 0; 231 if (mgmt_table[i].get_handler) { 232 access |= MGMT_MODE_RD; 233 } 234 if (mgmt_table[i].set_handler) { 235 access |= MGMT_MODE_WR; 236 } 237 if (mgmt_table[i].action_handler) { 238 access |= MGMT_MODE_EX; 239 } 240 ocs_mgmt_emit_property_name(textbuf, access, mgmt_table[i].name); 241 } 242 243 if ((ocs->mgmt_functions) && (ocs->mgmt_functions->get_list_handler)) { 244 ocs->mgmt_functions->get_list_handler(textbuf, ocs); 245 } 246 247 if ((ocs->tgt_mgmt_functions) && (ocs->tgt_mgmt_functions->get_list_handler)) { 248 ocs->tgt_mgmt_functions->get_list_handler(textbuf, &(ocs->tgt_ocs)); 249 } 250 251 /* Have each of my children add their actions */ 252 if (ocs_device_lock_try(ocs) == TRUE) { 253 /* If we get here then we are holding the device lock */ 254 ocs_list_foreach(&ocs->domain_list, domain) { 255 if ((domain->mgmt_functions) && (domain->mgmt_functions->get_list_handler)) { 256 domain->mgmt_functions->get_list_handler(textbuf, domain); 257 } 258 } 259 ocs_device_unlock(ocs); 260 } 261 262 ocs_mgmt_end_unnumbered_section(textbuf, "ocs"); 263 264 } 265 266 /** 267 * @ingroup mgmt 268 * @brief Return the value of a management item. 269 * 270 * @par Description 271 * This is the top level "get" handler for the driver. It 272 * performs the following: 273 * - Checks that the qualifier portion of the name begins with my qualifier (ocs). 274 * - If the remaining part of the name matches a parameter that is known at this level, 275 * writes the value into textbuf. 276 * - If the name is not known, sends the request to the back-ends to fulfill (if possible). 277 * - If the request has not been fulfilled by the back-end, 278 * passes the request to each of the children (domains) to 279 * have them (recursively) try to respond. 280 * 281 * In passing the request to other entities, the request is considered to be answered 282 * when a response has been written into textbuf, indicated by textbuf->buffer_written 283 * being non-zero. 284 * 285 * @param ocs Pointer to the ocs structure. 286 * @param name Name of the status item to be retrieved. 287 * @param textbuf Pointer to an ocs_textbuf, which is used to return the results. 288 * 289 * @return Returns 0 if the value was found and returned, or -1 if an error occurred. 290 */ 291 292 int 293 ocs_mgmt_get(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 294 { 295 ocs_domain_t *domain; 296 char qualifier[6]; 297 int retval = -1; 298 uint32_t i; 299 300 ocs_mgmt_start_unnumbered_section(textbuf, "ocs"); 301 302 snprintf(qualifier, sizeof(qualifier), "/ocs"); 303 304 /* See if the name starts with my qualifier. If not then this request isn't for me */ 305 if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) { 306 char *unqualified_name = name + strlen(qualifier) + 1; 307 308 for (i=0;i<ARRAY_SIZE(mgmt_table);i++) { 309 if (ocs_strcmp(unqualified_name, mgmt_table[i].name) == 0) { 310 if (mgmt_table[i].get_handler) { 311 mgmt_table[i].get_handler(ocs, name, textbuf); 312 ocs_mgmt_end_unnumbered_section(textbuf, "ocs"); 313 return 0; 314 } 315 } 316 } 317 318 if ((ocs->mgmt_functions) && (ocs->mgmt_functions->get_handler)) { 319 retval = ocs->mgmt_functions->get_handler(textbuf, qualifier, (char*)name, ocs); 320 } 321 322 if (retval != 0) { 323 if ((ocs->tgt_mgmt_functions) && (ocs->tgt_mgmt_functions->get_handler)) { 324 retval = ocs->tgt_mgmt_functions->get_handler(textbuf, qualifier, 325 (char*)name, &(ocs->tgt_ocs)); 326 } 327 } 328 329 if (retval != 0) { 330 /* The driver didn't handle it, pass it to each domain */ 331 332 ocs_device_lock(ocs); 333 ocs_list_foreach(&ocs->domain_list, domain) { 334 if ((domain->mgmt_functions) && (domain->mgmt_functions->get_handler)) { 335 retval = domain->mgmt_functions->get_handler(textbuf, qualifier, (char*)name, domain); 336 } 337 338 if (retval == 0) { 339 break; 340 } 341 } 342 ocs_device_unlock(ocs); 343 } 344 } 345 346 ocs_mgmt_end_unnumbered_section(textbuf, "ocs"); 347 348 return retval; 349 } 350 351 /** 352 * @ingroup mgmt 353 * @brief Set the value of a mgmt item. 354 * 355 * @par Description 356 * This is the top level "set" handler for the driver. It 357 * performs the following: 358 * - Checks that the qualifier portion of the name begins with my qualifier (ocs). 359 * - If the remaining part of the name matches a parameter that is known at this level, 360 * calls the correct function to change the configuration. 361 * - If the name is not known, sends the request to the back-ends to fulfill (if possible). 362 * - If the request has not been fulfilled by the back-end, passes the request to each of the 363 * children (domains) to have them (recursively) try to respond. 364 * 365 * In passing the request to other entities, the request is considered to be handled 366 * if the function returns 0. 367 * 368 * @param ocs Pointer to the ocs structure. 369 * @param name Name of the property to be changed. 370 * @param value Requested new value of the property. 371 * 372 * @return Returns 0 if the configuration value was updated, or -1 otherwise. 373 */ 374 375 int 376 ocs_mgmt_set(ocs_t *ocs, char *name, char *value) 377 { 378 ocs_domain_t *domain; 379 int result = -1; 380 char qualifier[80]; 381 uint32_t i; 382 383 snprintf(qualifier, sizeof(qualifier), "/ocs"); 384 385 /* If it doesn't start with my qualifier I don't know what to do with it */ 386 if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) { 387 char *unqualified_name = name + strlen(qualifier) +1; 388 389 /* See if it's a value I can set */ 390 for (i=0;i<ARRAY_SIZE(mgmt_table);i++) { 391 if (ocs_strcmp(unqualified_name, mgmt_table[i].name) == 0) { 392 if (mgmt_table[i].set_handler) { 393 return mgmt_table[i].set_handler(ocs, name, value); 394 } 395 } 396 } 397 398 if ((ocs->mgmt_functions) && (ocs->mgmt_functions->set_handler)) { 399 result = ocs->mgmt_functions->set_handler(qualifier, name, (char *)value, ocs); 400 } 401 402 if (result != 0) { 403 if ((ocs->tgt_mgmt_functions) && (ocs->tgt_mgmt_functions->set_handler)) { 404 result = ocs->tgt_mgmt_functions->set_handler(qualifier, name, 405 (char *)value, &(ocs->tgt_ocs)); 406 } 407 } 408 409 /* If I didn't know how to set this config value pass the request to each of my children */ 410 if (result != 0) { 411 ocs_device_lock(ocs); 412 ocs_list_foreach(&ocs->domain_list, domain) { 413 if ((domain->mgmt_functions) && (domain->mgmt_functions->set_handler)) { 414 result = domain->mgmt_functions->set_handler(qualifier, name, (char*)value, domain); 415 } 416 if (result == 0) { 417 break; 418 } 419 } 420 ocs_device_unlock(ocs); 421 } 422 } 423 424 return result; 425 } 426 427 /** 428 * @ingroup mgmt 429 * @brief Perform a management action. 430 * 431 * @par Description 432 * This is the top level "exec" handler for the driver. It 433 * performs the following: 434 * - Checks that the qualifier portion of the name begins with my qualifier (ocs). 435 * - If the remaining part of the name matches an action that is known at this level, 436 * calls the correct function to perform the action. 437 * - If the name is not known, sends the request to the back-ends to fulfill (if possible). 438 * - If the request has not been fulfilled by the back-end, passes the request to each of the 439 * children (domains) to have them (recursively) try to respond. 440 * 441 * In passing the request to other entities, the request is considered to be handled 442 * if the function returns 0. 443 * 444 * @param ocs Pointer to the ocs structure. 445 * @param action Name of the action to be performed. 446 * @param arg_in Pointer to an argument being passed to the action. 447 * @param arg_in_length Length of the argument pointed to by @c arg_in. 448 * @param arg_out Pointer to an argument being passed to the action. 449 * @param arg_out_length Length of the argument pointed to by @c arg_out. 450 * 451 * @return Returns 0 if the action was completed, or -1 otherwise. 452 * 453 * 454 */ 455 456 int 457 ocs_mgmt_exec(ocs_t *ocs, char *action, void *arg_in, 458 uint32_t arg_in_length, void *arg_out, uint32_t arg_out_length) 459 { 460 ocs_domain_t *domain; 461 int result = -1; 462 char qualifier[80]; 463 uint32_t i; 464 465 snprintf(qualifier, sizeof(qualifier), "/ocs"); 466 467 /* If it doesn't start with my qualifier I don't know what to do with it */ 468 if (ocs_strncmp(action, qualifier, strlen(qualifier)) == 0) { 469 char *unqualified_name = action + strlen(qualifier) +1; 470 471 /* See if it's an action I can perform */ 472 for (i=0;i<ARRAY_SIZE(mgmt_table); i++) { 473 if (ocs_strcmp(unqualified_name, mgmt_table[i].name) == 0) { 474 if (mgmt_table[i].action_handler) { 475 return mgmt_table[i].action_handler(ocs, action, arg_in, arg_in_length, 476 arg_out, arg_out_length); 477 } 478 } 479 } 480 481 /* See if it's a value I can supply */ 482 if (ocs_strcmp(unqualified_name, "driver/gendump") == 0) { 483 return ocs_gen_dump(ocs); 484 } 485 486 if (ocs_strcmp(unqualified_name, "driver/dump_to_host") == 0) { 487 return ocs_dump_to_host(ocs, arg_out, arg_out_length); 488 } 489 490 if ((ocs->mgmt_functions) && (ocs->mgmt_functions->exec_handler)) { 491 result = ocs->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length, 492 arg_out, arg_out_length, ocs); 493 } 494 495 if (result != 0) { 496 if ((ocs->tgt_mgmt_functions) && (ocs->tgt_mgmt_functions->exec_handler)) { 497 result = ocs->tgt_mgmt_functions->exec_handler(qualifier, action, 498 arg_in, arg_in_length, arg_out, arg_out_length, 499 &(ocs->tgt_ocs)); 500 } 501 } 502 503 /* If I didn't know how to do this action pass the request to each of my children */ 504 if (result != 0) { 505 ocs_device_lock(ocs); 506 ocs_list_foreach(&ocs->domain_list, domain) { 507 if ((domain->mgmt_functions) && (domain->mgmt_functions->exec_handler)) { 508 result = domain->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length, arg_out, 509 arg_out_length, domain); 510 } 511 if (result == 0) { 512 break; 513 } 514 } 515 ocs_device_unlock(ocs); 516 } 517 } 518 519 return result; 520 } 521 522 void 523 ocs_mgmt_get_all(ocs_t *ocs, ocs_textbuf_t *textbuf) 524 { 525 ocs_domain_t *domain; 526 uint32_t i; 527 528 ocs_mgmt_start_unnumbered_section(textbuf, "ocs"); 529 530 for (i=0;i<ARRAY_SIZE(mgmt_table);i++) { 531 if (mgmt_table[i].get_handler) { 532 mgmt_table[i].get_handler(ocs, mgmt_table[i].name, textbuf); 533 } else if (mgmt_table[i].action_handler) { 534 /* No get_handler, but there's an action_handler. Just report 535 the name */ 536 ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_EX, mgmt_table[i].name); 537 } 538 } 539 540 if ((ocs->mgmt_functions) && (ocs->mgmt_functions->get_all_handler)) { 541 ocs->mgmt_functions->get_all_handler(textbuf, ocs); 542 } 543 544 if ((ocs->tgt_mgmt_functions) && (ocs->tgt_mgmt_functions->get_all_handler)) { 545 ocs->tgt_mgmt_functions->get_all_handler(textbuf, &(ocs->tgt_ocs)); 546 } 547 548 ocs_device_lock(ocs); 549 ocs_list_foreach(&ocs->domain_list, domain) { 550 if ((domain->mgmt_functions) && (domain->mgmt_functions->get_all_handler)) { 551 domain->mgmt_functions->get_all_handler(textbuf, domain); 552 } 553 } 554 ocs_device_unlock(ocs); 555 556 ocs_mgmt_end_unnumbered_section(textbuf, "ocs"); 557 } 558 559 static int32_t 560 ocs_mgmt_firmware_reset(ocs_t *ocs, char *name, void *buf, uint32_t buf_len, void *arg_out, uint32_t arg_out_length) 561 { 562 int rc = 0; 563 int index = 0; 564 uint8_t bus, dev, func; 565 ocs_t *other_ocs; 566 567 ocs_get_bus_dev_func(ocs, &bus, &dev, &func); 568 569 ocs_log_debug(ocs, "Resetting port\n"); 570 if (ocs_hw_reset(&ocs->hw, OCS_HW_RESET_FIRMWARE)) { 571 ocs_log_test(ocs, "failed to reset port\n"); 572 rc = -1; 573 } else { 574 ocs_log_debug(ocs, "successfully reset port\n"); 575 576 /* now reset all functions on the same device */ 577 578 while ((other_ocs = ocs_get_instance(index++)) != NULL) { 579 uint8_t other_bus, other_dev, other_func; 580 581 ocs_get_bus_dev_func(other_ocs, &other_bus, &other_dev, &other_func); 582 583 if ((bus == other_bus) && (dev == other_dev)) { 584 if (other_ocs->hw.state != 585 OCS_HW_STATE_UNINITIALIZED) { 586 other_ocs->hw.state = 587 OCS_HW_STATE_QUEUES_ALLOCATED; 588 } 589 590 ocs_device_detach(other_ocs); 591 if (ocs_device_attach(other_ocs)) { 592 ocs_log_err(other_ocs, 593 "device %d attach failed \n", index); 594 rc = -1; 595 } 596 } 597 } 598 } 599 return rc; 600 } 601 602 static int32_t 603 ocs_mgmt_function_reset(ocs_t *ocs, char *name, void *buf, uint32_t buf_len, void *arg_out, uint32_t arg_out_length) 604 { 605 int32_t rc; 606 607 ocs_device_detach(ocs); 608 rc = ocs_device_attach(ocs); 609 610 return rc; 611 } 612 613 static int32_t 614 ocs_mgmt_firmware_write(ocs_t *ocs, char *name, void *buf, uint32_t buf_len, void *arg_out, uint32_t arg_out_length) 615 { 616 int rc = 0; 617 uint32_t bytes_left; 618 uint32_t xfer_size; 619 uint32_t offset; 620 uint8_t *userp; 621 ocs_dma_t dma; 622 int last = 0; 623 ocs_mgmt_fw_write_result_t result; 624 uint32_t change_status = 0; 625 char status_str[80]; 626 627 ocs_sem_init(&(result.semaphore), 0, "fw_write"); 628 629 bytes_left = buf_len; 630 offset = 0; 631 userp = (uint8_t *)buf; 632 633 if (ocs_dma_alloc(ocs, &dma, FW_WRITE_BUFSIZE, 4096)) { 634 ocs_log_err(ocs, "ocs_mgmt_firmware_write: malloc failed"); 635 return -ENOMEM; 636 } 637 638 while (bytes_left > 0) { 639 if (bytes_left > FW_WRITE_BUFSIZE) { 640 xfer_size = FW_WRITE_BUFSIZE; 641 } else { 642 xfer_size = bytes_left; 643 } 644 645 /* Copy xfer_size bytes from user space to kernel buffer */ 646 if (ocs_copy_from_user(dma.virt, userp, xfer_size)) { 647 rc = -EFAULT; 648 break; 649 } 650 651 /* See if this is the last block */ 652 if (bytes_left == xfer_size) { 653 last = 1; 654 } 655 656 /* Send the HW command */ 657 ocs_hw_firmware_write(&ocs->hw, &dma, xfer_size, offset, last, ocs_mgmt_fw_write_cb, &result); 658 659 /* Wait for semaphore to be signaled when the command completes 660 * TODO: Should there be a timeout on this? If so, how long? */ 661 if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) { 662 ocs_log_err(ocs, "ocs_sem_p failed\n"); 663 rc = -ENXIO; 664 break; 665 } 666 667 if (result.actual_xfer == 0) { 668 ocs_log_test(ocs, "actual_write_length is %d\n", result.actual_xfer); 669 rc = -EFAULT; 670 break; 671 } 672 673 /* Check status */ 674 if (result.status != 0) { 675 ocs_log_test(ocs, "write returned status %d\n", result.status); 676 rc = -EFAULT; 677 break; 678 } 679 680 if (last) { 681 change_status = result.change_status; 682 } 683 684 bytes_left -= result.actual_xfer; 685 offset += result.actual_xfer; 686 userp += result.actual_xfer; 687 } 688 689 /* Create string with status and copy to userland */ 690 if ((arg_out_length > 0) && (arg_out != NULL)) { 691 if (arg_out_length > sizeof(status_str)) { 692 arg_out_length = sizeof(status_str); 693 } 694 ocs_memset(status_str, 0, sizeof(status_str)); 695 ocs_snprintf(status_str, arg_out_length, "%d", change_status); 696 if (ocs_copy_to_user(arg_out, status_str, arg_out_length)) { 697 ocs_log_test(ocs, "copy to user failed for change_status\n"); 698 } 699 } 700 701 ocs_dma_free(ocs, &dma); 702 703 return rc; 704 } 705 706 static void 707 ocs_mgmt_fw_write_cb(int32_t status, uint32_t actual_write_length, uint32_t change_status, void *arg) 708 { 709 ocs_mgmt_fw_write_result_t *result = arg; 710 711 result->status = status; 712 result->actual_xfer = actual_write_length; 713 result->change_status = change_status; 714 715 ocs_sem_v(&(result->semaphore)); 716 } 717 718 typedef struct ocs_mgmt_sfp_result { 719 ocs_sem_t semaphore; 720 ocs_lock_t cb_lock; 721 int32_t running; 722 int32_t status; 723 uint32_t bytes_read; 724 uint32_t page_data[32]; 725 } ocs_mgmt_sfp_result_t; 726 727 static void 728 ocs_mgmt_sfp_cb(void *os, int32_t status, uint32_t bytes_read, uint32_t *data, void *arg) 729 { 730 ocs_mgmt_sfp_result_t *result = arg; 731 ocs_t *ocs = os; 732 733 ocs_lock(&(result->cb_lock)); 734 result->running++; 735 if(result->running == 2) { 736 /* get_sfp() has timed out */ 737 ocs_unlock(&(result->cb_lock)); 738 ocs_free(ocs, result, sizeof(ocs_mgmt_sfp_result_t)); 739 return; 740 } 741 742 result->status = status; 743 result->bytes_read = bytes_read; 744 ocs_memcpy(&result->page_data, data, SFP_PAGE_SIZE); 745 746 ocs_sem_v(&(result->semaphore)); 747 ocs_unlock(&(result->cb_lock)); 748 } 749 750 static int32_t 751 ocs_mgmt_get_sfp(ocs_t *ocs, uint16_t page, void *buf, uint32_t buf_len) 752 { 753 int rc = 0; 754 ocs_mgmt_sfp_result_t *result = ocs_malloc(ocs, sizeof(ocs_mgmt_sfp_result_t), OCS_M_ZERO | OCS_M_NOWAIT); 755 756 ocs_sem_init(&(result->semaphore), 0, "get_sfp"); 757 ocs_lock_init(ocs, &(result->cb_lock), "get_sfp"); 758 759 /* Send the HW command */ 760 ocs_hw_get_sfp(&ocs->hw, page, ocs_mgmt_sfp_cb, result); 761 762 /* Wait for semaphore to be signaled when the command completes */ 763 if (ocs_sem_p(&(result->semaphore), 5 * 1000 * 1000) != 0) { 764 /* Timed out, callback will free memory */ 765 ocs_lock(&(result->cb_lock)); 766 result->running++; 767 if(result->running == 1) { 768 ocs_log_err(ocs, "ocs_sem_p failed\n"); 769 ocs_unlock(&(result->cb_lock)); 770 return (-ENXIO); 771 } 772 /* sfp_cb() has already executed, proceed as normal */ 773 ocs_unlock(&(result->cb_lock)); 774 } 775 776 /* Check status */ 777 if (result->status != 0) { 778 ocs_log_test(ocs, "read_transceiver_data returned status %d\n", 779 result->status); 780 rc = -EFAULT; 781 } 782 783 if (rc == 0) { 784 rc = (result->bytes_read > buf_len ? buf_len : result->bytes_read); 785 /* Copy the results back to the supplied buffer */ 786 ocs_memcpy(buf, result->page_data, rc); 787 } 788 789 ocs_free(ocs, result, sizeof(ocs_mgmt_sfp_result_t)); 790 return rc; 791 } 792 793 static int32_t 794 ocs_mgmt_force_assert(ocs_t *ocs, char *name, void *buf, uint32_t buf_len, void *arg_out, uint32_t arg_out_length) 795 { 796 ocs_assert(FALSE, 0); 797 } 798 799 static void 800 get_nodes_count(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 801 { 802 ocs_xport_t *xport = ocs->xport; 803 804 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "nodes_count", "%d", xport->nodes_count); 805 } 806 807 static void 808 get_driver_version(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 809 { 810 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "driver_version", ocs->driver_version); 811 } 812 813 static void 814 get_desc(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 815 { 816 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "desc", ocs->desc); 817 } 818 819 static void 820 get_fw_rev(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 821 { 822 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "fw_rev", ocs_hw_get_ptr(&ocs->hw, OCS_HW_FW_REV)); 823 } 824 825 static void 826 get_fw_rev2(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 827 { 828 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "fw_rev2", ocs_hw_get_ptr(&ocs->hw, OCS_HW_FW_REV2)); 829 } 830 831 static void 832 get_ipl(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 833 { 834 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "ipl", ocs_hw_get_ptr(&ocs->hw, OCS_HW_IPL)); 835 } 836 837 static void 838 get_hw_rev1(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 839 { 840 uint32_t value; 841 842 ocs_hw_get(&ocs->hw, OCS_HW_HW_REV1, &value); 843 844 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_rev1", "%u", value); 845 } 846 847 static void 848 get_hw_rev2(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 849 { 850 uint32_t value; 851 852 ocs_hw_get(&ocs->hw, OCS_HW_HW_REV2, &value); 853 854 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_rev2", "%u", value); 855 } 856 857 static void 858 get_hw_rev3(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 859 { 860 uint32_t value; 861 ocs_hw_get(&ocs->hw, OCS_HW_HW_REV3, &value); 862 863 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_rev3", "%u", value); 864 } 865 866 static void 867 get_wwnn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 868 { 869 uint64_t *wwnn; 870 871 wwnn = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_NODE); 872 873 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwnn", "0x%llx", (unsigned long long)ocs_htobe64(*wwnn)); 874 } 875 876 static void 877 get_wwpn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 878 { 879 uint64_t *wwpn; 880 881 wwpn = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_PORT); 882 883 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwpn", "0x%llx", (unsigned long long)ocs_htobe64(*wwpn)); 884 } 885 886 static void 887 get_fcid(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 888 { 889 890 if (ocs->domain && ocs->domain->attached) { 891 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fc_id", "0x%06x", 892 ocs->domain->sport->fc_id); 893 } else { 894 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fc_id", "UNKNOWN"); 895 } 896 897 } 898 899 static void 900 get_sn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 901 { 902 uint8_t *pserial; 903 uint32_t len; 904 char sn_buf[256]; 905 906 pserial = ocs_scsi_get_property_ptr(ocs, OCS_SCSI_SERIALNUMBER); 907 if (pserial) { 908 len = *pserial ++; 909 strncpy(sn_buf, (char*)pserial, len); 910 sn_buf[len] = '\0'; 911 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sn", sn_buf); 912 } 913 } 914 915 static void 916 get_pn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 917 { 918 uint8_t *pserial; 919 uint32_t len; 920 char sn_buf[256]; 921 922 pserial = ocs_scsi_get_property_ptr(ocs, OCS_SCSI_PARTNUMBER); 923 if (pserial) { 924 len = *pserial ++; 925 strncpy(sn_buf, (char*)pserial, len); 926 sn_buf[len] = '\0'; 927 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "pn", sn_buf); 928 } else { 929 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "pn", ocs->model); 930 } 931 } 932 933 static void 934 get_sli4_intf_reg(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 935 { 936 937 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "sli4_intf_reg", "0x%04x", 938 ocs_config_read32(ocs, SLI4_INTF_REG)); 939 } 940 941 static void 942 get_phy_port_num(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 943 { 944 char *phy_port = NULL; 945 946 phy_port = ocs_scsi_get_property_ptr(ocs, OCS_SCSI_PORTNUM); 947 if (phy_port) { 948 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "phy_port_num", phy_port); 949 } else { 950 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "phy_port_num", "unknown"); 951 } 952 } 953 static void 954 get_asic_id(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 955 { 956 957 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "asic_id_reg", "0x%04x", 958 ocs_config_read32(ocs, SLI4_ASIC_ID_REG)); 959 } 960 961 static void 962 get_chip_type(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 963 { 964 uint32_t family; 965 uint32_t asic_id; 966 uint32_t asic_gen_num; 967 uint32_t asic_rev_num; 968 uint32_t rev_id; 969 char result_buf[80]; 970 char tmp_buf[80]; 971 972 family = (ocs_config_read32(ocs, SLI4_INTF_REG) & 0x00000f00) >> 8; 973 asic_id = ocs_config_read32(ocs, SLI4_ASIC_ID_REG); 974 asic_rev_num = asic_id & 0xff; 975 asic_gen_num = (asic_id & 0xff00) >> 8; 976 977 rev_id = ocs_config_read32(ocs, SLI4_PCI_CLASS_REVISION) & 0xff; 978 979 switch(family) { 980 case 0x00: 981 /* BE2 */ 982 ocs_strncpy(result_buf, "BE2 A", sizeof(result_buf)); 983 ocs_snprintf(tmp_buf, 2, "%d", rev_id); 984 strcat(result_buf, tmp_buf); 985 break; 986 case 0x01: 987 /* BE3 */ 988 ocs_strncpy(result_buf, "BE3", sizeof(result_buf)); 989 if (rev_id >= 0x10) { 990 strcat(result_buf, "-R"); 991 } 992 ocs_snprintf(tmp_buf, 3, " %c", ((rev_id & 0xf0) >> 4) + 'A'); 993 strcat(result_buf, tmp_buf); 994 ocs_snprintf(tmp_buf, 2, "%d", rev_id & 0x0f); 995 strcat(result_buf, tmp_buf); 996 break; 997 case 0x02: 998 /* Skyhawk A0 */ 999 ocs_strncpy(result_buf, "Skyhawk A0", sizeof(result_buf)); 1000 break; 1001 case 0x0a: 1002 /* Lancer A0 */ 1003 ocs_strncpy(result_buf, "Lancer A", sizeof(result_buf)); 1004 ocs_snprintf(tmp_buf, 2, "%d", rev_id & 0x0f); 1005 strcat(result_buf, tmp_buf); 1006 break; 1007 case 0x0b: 1008 /* Lancer B0 or D0 */ 1009 ocs_strncpy(result_buf, "Lancer", sizeof(result_buf)); 1010 ocs_snprintf(tmp_buf, 3, " %c", ((rev_id & 0xf0) >> 4) + 'A'); 1011 strcat(result_buf, tmp_buf); 1012 ocs_snprintf(tmp_buf, 2, "%d", rev_id & 0x0f); 1013 strcat(result_buf, tmp_buf); 1014 break; 1015 case 0x0c: 1016 ocs_strncpy(result_buf, "Lancer G6", sizeof(result_buf)); 1017 break; 1018 case 0x0f: 1019 /* Refer to ASIC_ID */ 1020 switch(asic_gen_num) { 1021 case 0x00: 1022 ocs_strncpy(result_buf, "BE2", sizeof(result_buf)); 1023 break; 1024 case 0x03: 1025 ocs_strncpy(result_buf, "BE3-R", sizeof(result_buf)); 1026 break; 1027 case 0x04: 1028 ocs_strncpy(result_buf, "Skyhawk-R", sizeof(result_buf)); 1029 break; 1030 case 0x05: 1031 ocs_strncpy(result_buf, "Corsair", sizeof(result_buf)); 1032 break; 1033 case 0x0b: 1034 ocs_strncpy(result_buf, "Lancer", sizeof(result_buf)); 1035 break; 1036 case 0x0c: 1037 ocs_strncpy(result_buf, "LancerG6", sizeof(result_buf)); 1038 break; 1039 default: 1040 ocs_strncpy(result_buf, "Unknown", sizeof(result_buf)); 1041 } 1042 if (ocs_strcmp(result_buf, "Unknown") != 0) { 1043 ocs_snprintf(tmp_buf, 3, " %c", ((asic_rev_num & 0xf0) >> 4) + 'A'); 1044 strcat(result_buf, tmp_buf); 1045 ocs_snprintf(tmp_buf, 2, "%d", asic_rev_num & 0x0f); 1046 strcat(result_buf, tmp_buf); 1047 } 1048 break; 1049 default: 1050 ocs_strncpy(result_buf, "Unknown", sizeof(result_buf)); 1051 } 1052 1053 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "chip_type", result_buf); 1054 1055 } 1056 1057 static void 1058 get_pci_vendor(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1059 { 1060 1061 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "pci_vendor", "0x%04x", ocs->pci_vendor); 1062 } 1063 1064 static void 1065 get_pci_device(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1066 { 1067 1068 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "pci_device", "0x%04x", ocs->pci_device); 1069 } 1070 1071 static void 1072 get_pci_subsystem_vendor(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1073 { 1074 1075 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "pci_subsystem_vendor", "0x%04x", ocs->pci_subsystem_vendor); 1076 } 1077 1078 static void 1079 get_pci_subsystem_device(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1080 { 1081 1082 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "pci_subsystem_device", "0x%04x", ocs->pci_subsystem_device); 1083 } 1084 1085 static void 1086 get_tgt_rscn_delay(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1087 { 1088 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "tgt_rscn_delay", "%ld", (unsigned long)ocs->tgt_rscn_delay_msec / 1000); 1089 } 1090 1091 static void 1092 get_tgt_rscn_period(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1093 { 1094 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "tgt_rscn_period", "%ld", (unsigned long)ocs->tgt_rscn_period_msec / 1000); 1095 } 1096 1097 static void 1098 get_inject_drop_cmd(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1099 { 1100 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "inject_drop_cmd", "%d", 1101 (ocs->err_injection == INJECT_DROP_CMD ? 1:0)); 1102 } 1103 1104 static void 1105 get_inject_free_drop_cmd(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1106 { 1107 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "inject_free_drop_cmd", "%d", 1108 (ocs->err_injection == INJECT_FREE_DROPPED ? 1:0)); 1109 } 1110 1111 static void 1112 get_inject_drop_data(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1113 { 1114 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "inject_drop_data", "%d", 1115 (ocs->err_injection == INJECT_DROP_DATA ? 1:0)); 1116 } 1117 1118 static void 1119 get_inject_drop_resp(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1120 { 1121 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "inject_drop_resp", "%d", 1122 (ocs->err_injection == INJECT_DROP_RESP ? 1:0)); 1123 } 1124 1125 static void 1126 get_cmd_err_inject(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1127 { 1128 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "cmd_err_inject", "0x%02x", ocs->cmd_err_inject); 1129 } 1130 1131 static void 1132 get_cmd_delay_value(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1133 { 1134 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "cmd_delay_value", "%ld", (unsigned long)ocs->delay_value_msec); 1135 } 1136 1137 static void 1138 get_businfo(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1139 { 1140 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "businfo", ocs->businfo); 1141 } 1142 1143 static void 1144 get_sfp_a0(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1145 { 1146 uint8_t *page_data; 1147 char *buf; 1148 int i; 1149 int32_t bytes_read; 1150 1151 page_data = ocs_malloc(ocs, SFP_PAGE_SIZE, OCS_M_ZERO | OCS_M_NOWAIT); 1152 if (page_data == NULL) { 1153 return; 1154 } 1155 1156 buf = ocs_malloc(ocs, (SFP_PAGE_SIZE * 3) + 1, OCS_M_ZERO | OCS_M_NOWAIT); 1157 if (buf == NULL) { 1158 ocs_free(ocs, page_data, SFP_PAGE_SIZE); 1159 return; 1160 } 1161 1162 bytes_read = ocs_mgmt_get_sfp(ocs, 0xa0, page_data, SFP_PAGE_SIZE); 1163 1164 if (bytes_read <= 0) { 1165 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sfp_a0", "(unknown)"); 1166 } else { 1167 char *d = buf; 1168 uint8_t *s = page_data; 1169 int buffer_remaining = (SFP_PAGE_SIZE * 3) + 1; 1170 int bytes_added; 1171 1172 for (i = 0; i < bytes_read; i++) { 1173 bytes_added = ocs_snprintf(d, buffer_remaining, "%02x ", *s); 1174 ++s; 1175 d += bytes_added; 1176 buffer_remaining -= bytes_added; 1177 } 1178 *d = '\0'; 1179 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sfp_a0", buf); 1180 } 1181 1182 ocs_free(ocs, page_data, SFP_PAGE_SIZE); 1183 ocs_free(ocs, buf, (3 * SFP_PAGE_SIZE) + 1); 1184 } 1185 1186 static void 1187 get_sfp_a2(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1188 { 1189 uint8_t *page_data; 1190 char *buf; 1191 int i; 1192 int32_t bytes_read; 1193 1194 page_data = ocs_malloc(ocs, SFP_PAGE_SIZE, OCS_M_ZERO | OCS_M_NOWAIT); 1195 if (page_data == NULL) { 1196 return; 1197 } 1198 1199 buf = ocs_malloc(ocs, (SFP_PAGE_SIZE * 3) + 1, OCS_M_ZERO | OCS_M_NOWAIT); 1200 if (buf == NULL) { 1201 ocs_free(ocs, page_data, SFP_PAGE_SIZE); 1202 return; 1203 } 1204 1205 bytes_read = ocs_mgmt_get_sfp(ocs, 0xa2, page_data, SFP_PAGE_SIZE); 1206 1207 if (bytes_read <= 0) { 1208 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sfp_a2", "(unknown)"); 1209 } else { 1210 char *d = buf; 1211 uint8_t *s = page_data; 1212 int buffer_remaining = (SFP_PAGE_SIZE * 3) + 1; 1213 int bytes_added; 1214 1215 for (i=0; i < bytes_read; i++) { 1216 bytes_added = ocs_snprintf(d, buffer_remaining, "%02x ", *s); 1217 ++s; 1218 d += bytes_added; 1219 buffer_remaining -= bytes_added; 1220 } 1221 *d = '\0'; 1222 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sfp_a2", buf); 1223 } 1224 1225 ocs_free(ocs, page_data, SFP_PAGE_SIZE); 1226 ocs_free(ocs, buf, (3 * SFP_PAGE_SIZE) + 1); 1227 } 1228 1229 static void 1230 get_debug_mq_dump(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1231 { 1232 1233 ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RW, "debug_mq_dump", 1234 ocs_debug_is_enabled(OCS_DEBUG_ENABLE_MQ_DUMP)); 1235 } 1236 1237 static void 1238 get_debug_cq_dump(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1239 { 1240 1241 ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RW, "debug_cq_dump", 1242 ocs_debug_is_enabled(OCS_DEBUG_ENABLE_CQ_DUMP)); 1243 } 1244 1245 static void 1246 get_debug_wq_dump(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1247 { 1248 ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RW, "debug_wq_dump", 1249 ocs_debug_is_enabled(OCS_DEBUG_ENABLE_WQ_DUMP)); 1250 } 1251 1252 static void 1253 get_debug_eq_dump(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1254 { 1255 ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RW, "debug_eq_dump", 1256 ocs_debug_is_enabled(OCS_DEBUG_ENABLE_EQ_DUMP)); 1257 } 1258 1259 static void 1260 get_logmask(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1261 { 1262 1263 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "logmask", "0x%02x", ocs->logmask); 1264 1265 } 1266 1267 static void 1268 get_loglevel(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1269 { 1270 1271 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "loglevel", "%d", loglevel); 1272 1273 } 1274 1275 static void 1276 get_current_speed(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1277 { 1278 uint32_t value; 1279 1280 ocs_hw_get(&(ocs->hw), OCS_HW_LINK_SPEED, &value); 1281 1282 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "current_speed", "%d", value); 1283 } 1284 1285 static void 1286 get_configured_speed(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1287 { 1288 uint32_t value; 1289 1290 ocs_hw_get(&(ocs->hw), OCS_HW_LINK_CONFIG_SPEED, &value); 1291 if (value == 0) { 1292 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "configured_speed", "auto"); 1293 } else { 1294 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "configured_speed", "%d", value); 1295 } 1296 1297 } 1298 1299 static void 1300 get_current_topology(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1301 { 1302 uint32_t value; 1303 1304 ocs_hw_get(&(ocs->hw), OCS_HW_TOPOLOGY, &value); 1305 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "current_topology", "%d", value); 1306 1307 } 1308 1309 static void 1310 get_configured_topology(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1311 { 1312 uint32_t value; 1313 1314 ocs_hw_get(&(ocs->hw), OCS_HW_CONFIG_TOPOLOGY, &value); 1315 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "configured_topology", "%d", value); 1316 1317 } 1318 1319 static void 1320 get_current_link_state(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1321 { 1322 ocs_xport_stats_t value; 1323 1324 if (ocs_xport_status(ocs->xport, OCS_XPORT_PORT_STATUS, &value) == 0) { 1325 if (value.value == OCS_XPORT_PORT_ONLINE) { 1326 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "current_link_state", "online"); 1327 } else { 1328 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "current_link_state", "offline"); 1329 } 1330 } 1331 } 1332 1333 static void 1334 get_configured_link_state(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1335 { 1336 ocs_xport_stats_t value; 1337 1338 if (ocs_xport_status(ocs->xport, OCS_XPORT_CONFIG_PORT_STATUS, &value) == 0) { 1339 if (value.value == OCS_XPORT_PORT_ONLINE) { 1340 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "configured_link_state", "online"); 1341 } else { 1342 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "configured_link_state", "offline"); 1343 } 1344 } 1345 } 1346 1347 /** 1348 * @brief HW link config enum to mgmt string value mapping. 1349 * 1350 * This structure provides a mapping from the ocs_hw_linkcfg_e 1351 * enum (enum exposed for the OCS_HW_PORT_SET_LINK_CONFIG port 1352 * control) to the mgmt string that is passed in by the mgmt application 1353 * (elxsdkutil). 1354 */ 1355 typedef struct ocs_mgmt_linkcfg_map_s { 1356 ocs_hw_linkcfg_e linkcfg; 1357 const char *mgmt_str; 1358 } ocs_mgmt_linkcfg_map_t; 1359 1360 static ocs_mgmt_linkcfg_map_t mgmt_linkcfg_map[] = { 1361 {OCS_HW_LINKCFG_4X10G, OCS_CONFIG_LINKCFG_4X10G}, 1362 {OCS_HW_LINKCFG_1X40G, OCS_CONFIG_LINKCFG_1X40G}, 1363 {OCS_HW_LINKCFG_2X16G, OCS_CONFIG_LINKCFG_2X16G}, 1364 {OCS_HW_LINKCFG_4X8G, OCS_CONFIG_LINKCFG_4X8G}, 1365 {OCS_HW_LINKCFG_4X1G, OCS_CONFIG_LINKCFG_4X1G}, 1366 {OCS_HW_LINKCFG_2X10G, OCS_CONFIG_LINKCFG_2X10G}, 1367 {OCS_HW_LINKCFG_2X10G_2X8G, OCS_CONFIG_LINKCFG_2X10G_2X8G}}; 1368 1369 /** 1370 * @brief Get the HW linkcfg enum from the mgmt config string. 1371 * 1372 * @param mgmt_str mgmt string value. 1373 * 1374 * @return Returns the HW linkcfg enum corresponding to clp_str. 1375 */ 1376 static ocs_hw_linkcfg_e 1377 ocs_hw_linkcfg_from_mgmt(const char *mgmt_str) 1378 { 1379 uint32_t i; 1380 for (i = 0; i < ARRAY_SIZE(mgmt_linkcfg_map); i++) { 1381 if (ocs_strncmp(mgmt_linkcfg_map[i].mgmt_str, 1382 mgmt_str, ocs_strlen(mgmt_str)) == 0) { 1383 return mgmt_linkcfg_map[i].linkcfg; 1384 } 1385 } 1386 return OCS_HW_LINKCFG_NA; 1387 } 1388 1389 /** 1390 * @brief Get the mgmt string value from the HW linkcfg enum. 1391 * 1392 * @param linkcfg HW linkcfg enum. 1393 * 1394 * @return Returns the mgmt string value corresponding to the given HW linkcfg. 1395 */ 1396 static const char * 1397 ocs_mgmt_from_hw_linkcfg(ocs_hw_linkcfg_e linkcfg) 1398 { 1399 uint32_t i; 1400 for (i = 0; i < ARRAY_SIZE(mgmt_linkcfg_map); i++) { 1401 if (mgmt_linkcfg_map[i].linkcfg == linkcfg) { 1402 return mgmt_linkcfg_map[i].mgmt_str; 1403 } 1404 } 1405 return OCS_CONFIG_LINKCFG_UNKNOWN; 1406 } 1407 1408 /** 1409 * @brief Link configuration callback argument 1410 */ 1411 typedef struct ocs_mgmt_linkcfg_arg_s { 1412 ocs_sem_t semaphore; 1413 int32_t status; 1414 ocs_hw_linkcfg_e linkcfg; 1415 } ocs_mgmt_linkcfg_arg_t; 1416 1417 /** 1418 * @brief Get linkcfg config value 1419 * 1420 * @param ocs Pointer to the ocs structure. 1421 * @param name Not used. 1422 * @param textbuf The textbuf to which the result is written. 1423 * 1424 * @return None. 1425 */ 1426 static void 1427 get_linkcfg(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1428 { 1429 const char *linkcfg_str = NULL; 1430 uint32_t value; 1431 ocs_hw_linkcfg_e linkcfg; 1432 ocs_hw_get(&ocs->hw, OCS_HW_LINKCFG, &value); 1433 linkcfg = (ocs_hw_linkcfg_e)value; 1434 linkcfg_str = ocs_mgmt_from_hw_linkcfg(linkcfg); 1435 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "linkcfg", linkcfg_str); 1436 } 1437 1438 /** 1439 * @brief Get requested WWNN config value 1440 * 1441 * @param ocs Pointer to the ocs structure. 1442 * @param name Not used. 1443 * @param textbuf The textbuf to which the result is written. 1444 * 1445 * @return None. 1446 */ 1447 static void 1448 get_req_wwnn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1449 { 1450 ocs_xport_t *xport = ocs->xport; 1451 1452 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "requested_wwnn", "0x%llx", (unsigned long long)xport->req_wwnn); 1453 } 1454 1455 /** 1456 * @brief Get requested WWPN config value 1457 * 1458 * @param ocs Pointer to the ocs structure. 1459 * @param name Not used. 1460 * @param textbuf The textbuf to which the result is written. 1461 * 1462 * @return None. 1463 */ 1464 static void 1465 get_req_wwpn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1466 { 1467 ocs_xport_t *xport = ocs->xport; 1468 1469 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "requested_wwpn", "0x%llx", (unsigned long long)xport->req_wwpn); 1470 } 1471 1472 /** 1473 * @brief Get requested nodedb_mask config value 1474 * 1475 * @param ocs Pointer to the ocs structure. 1476 * @param name Not used. 1477 * @param textbuf The textbuf to which the result is written. 1478 * 1479 * @return None. 1480 */ 1481 static void 1482 get_nodedb_mask(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1483 { 1484 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "nodedb_mask", "0x%08x", ocs->nodedb_mask); 1485 } 1486 1487 /** 1488 * @brief Set requested WWNN value. 1489 * 1490 * @param ocs Pointer to the ocs structure. 1491 * @param name Not used. 1492 * @param value Value to which the linkcfg is set. 1493 * 1494 * @return Returns 0 on success. 1495 */ 1496 1497 int 1498 set_req_wwnn(ocs_t *ocs, char *name, char *value) 1499 { 1500 int rc; 1501 uint64_t wwnn; 1502 1503 if (ocs_strcasecmp(value, "default") == 0) { 1504 wwnn = 0; 1505 } 1506 else if (parse_wwn(value, &wwnn) != 0) { 1507 ocs_log_test(ocs, "Invalid WWNN: %s\n", value); 1508 return 1; 1509 } 1510 1511 rc = ocs_xport_control(ocs->xport, OCS_XPORT_WWNN_SET, wwnn); 1512 1513 if(rc) { 1514 ocs_log_test(ocs, "OCS_XPORT_WWNN_SET failed: %d\n", rc); 1515 return rc; 1516 } 1517 1518 rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE); 1519 if (rc) { 1520 ocs_log_test(ocs, "port offline failed : %d\n", rc); 1521 } 1522 1523 rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE); 1524 if (rc) { 1525 ocs_log_test(ocs, "port online failed : %d\n", rc); 1526 } 1527 1528 return rc; 1529 } 1530 1531 /** 1532 * @brief Set requested WWNP value. 1533 * 1534 * @param ocs Pointer to the ocs structure. 1535 * @param name Not used. 1536 * @param value Value to which the linkcfg is set. 1537 * 1538 * @return Returns 0 on success. 1539 */ 1540 1541 int 1542 set_req_wwpn(ocs_t *ocs, char *name, char *value) 1543 { 1544 int rc; 1545 uint64_t wwpn; 1546 1547 if (ocs_strcasecmp(value, "default") == 0) { 1548 wwpn = 0; 1549 } 1550 else if (parse_wwn(value, &wwpn) != 0) { 1551 ocs_log_test(ocs, "Invalid WWPN: %s\n", value); 1552 return 1; 1553 } 1554 1555 rc = ocs_xport_control(ocs->xport, OCS_XPORT_WWPN_SET, wwpn); 1556 1557 if(rc) { 1558 ocs_log_test(ocs, "OCS_XPORT_WWPN_SET failed: %d\n", rc); 1559 return rc; 1560 } 1561 1562 rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE); 1563 if (rc) { 1564 ocs_log_test(ocs, "port offline failed : %d\n", rc); 1565 } 1566 1567 rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE); 1568 if (rc) { 1569 ocs_log_test(ocs, "port online failed : %d\n", rc); 1570 } 1571 1572 return rc; 1573 } 1574 1575 /** 1576 * @brief Set node debug mask value 1577 * 1578 * @param ocs Pointer to the ocs structure. 1579 * @param name Not used. 1580 * @param value Value to which the nodedb_mask is set. 1581 * 1582 * @return Returns 0 on success. 1583 */ 1584 static int 1585 set_nodedb_mask(ocs_t *ocs, char *name, char *value) 1586 { 1587 ocs->nodedb_mask = ocs_strtoul(value, 0, 0); 1588 return 0; 1589 } 1590 1591 /** 1592 * @brief Set linkcfg config value. 1593 * 1594 * @param ocs Pointer to the ocs structure. 1595 * @param name Not used. 1596 * @param value Value to which the linkcfg is set. 1597 * 1598 * @return Returns 0 on success. 1599 */ 1600 static int 1601 set_linkcfg(ocs_t *ocs, char *name, char *value) 1602 { 1603 ocs_hw_linkcfg_e linkcfg; 1604 ocs_mgmt_linkcfg_arg_t cb_arg; 1605 ocs_hw_rtn_e status; 1606 1607 ocs_sem_init(&cb_arg.semaphore, 0, "mgmt_linkcfg"); 1608 1609 /* translate mgmt linkcfg string to HW linkcfg enum */ 1610 linkcfg = ocs_hw_linkcfg_from_mgmt(value); 1611 1612 /* set HW linkcfg */ 1613 status = ocs_hw_port_control(&ocs->hw, OCS_HW_PORT_SET_LINK_CONFIG, 1614 (uintptr_t)linkcfg, ocs_mgmt_linkcfg_cb, &cb_arg); 1615 if (status) { 1616 ocs_log_test(ocs, "ocs_hw_set_linkcfg failed\n"); 1617 return -1; 1618 } 1619 1620 if (ocs_sem_p(&cb_arg.semaphore, OCS_SEM_FOREVER)) { 1621 ocs_log_err(ocs, "ocs_sem_p failed\n"); 1622 return -1; 1623 } 1624 1625 if (cb_arg.status) { 1626 ocs_log_test(ocs, "failed to set linkcfg from HW status=%d\n", 1627 cb_arg.status); 1628 return -1; 1629 } 1630 1631 return 0; 1632 } 1633 1634 /** 1635 * @brief Linkcfg callback 1636 * 1637 * @param status Result of the linkcfg get/set operation. 1638 * @param value Resulting linkcfg value. 1639 * @param arg Callback argument. 1640 * 1641 * @return None. 1642 */ 1643 static void 1644 ocs_mgmt_linkcfg_cb(int32_t status, uintptr_t value, void *arg) 1645 { 1646 ocs_mgmt_linkcfg_arg_t *cb_arg = (ocs_mgmt_linkcfg_arg_t *)arg; 1647 cb_arg->status = status; 1648 cb_arg->linkcfg = (ocs_hw_linkcfg_e)value; 1649 ocs_sem_v(&cb_arg->semaphore); 1650 } 1651 1652 static int 1653 set_debug_mq_dump(ocs_t *ocs, char *name, char *value) 1654 { 1655 int result; 1656 1657 if (ocs_strcasecmp(value, "false") == 0) { 1658 ocs_debug_disable(OCS_DEBUG_ENABLE_MQ_DUMP); 1659 result = 0; 1660 } else if (ocs_strcasecmp(value, "true") == 0) { 1661 ocs_debug_enable(OCS_DEBUG_ENABLE_MQ_DUMP); 1662 result = 0; 1663 } else { 1664 result = -1; 1665 } 1666 1667 return result; 1668 } 1669 1670 static int 1671 set_debug_cq_dump(ocs_t *ocs, char *name, char *value) 1672 { 1673 int result; 1674 1675 if (ocs_strcasecmp(value, "false") == 0) { 1676 ocs_debug_disable(OCS_DEBUG_ENABLE_CQ_DUMP); 1677 result = 0; 1678 } else if (ocs_strcasecmp(value, "true") == 0) { 1679 ocs_debug_enable(OCS_DEBUG_ENABLE_CQ_DUMP); 1680 result = 0; 1681 } else { 1682 result = -1; 1683 } 1684 1685 return result; 1686 } 1687 1688 static int 1689 set_debug_wq_dump(ocs_t *ocs, char *name, char *value) 1690 { 1691 int result; 1692 1693 if (ocs_strcasecmp(value, "false") == 0) { 1694 ocs_debug_disable(OCS_DEBUG_ENABLE_WQ_DUMP); 1695 result = 0; 1696 } else if (ocs_strcasecmp(value, "true") == 0) { 1697 ocs_debug_enable(OCS_DEBUG_ENABLE_WQ_DUMP); 1698 result = 0; 1699 } else { 1700 result = -1; 1701 } 1702 1703 return result; 1704 } 1705 1706 static int 1707 set_debug_eq_dump(ocs_t *ocs, char *name, char *value) 1708 { 1709 int result; 1710 1711 if (ocs_strcasecmp(value, "false") == 0) { 1712 ocs_debug_disable(OCS_DEBUG_ENABLE_EQ_DUMP); 1713 result = 0; 1714 } else if (ocs_strcasecmp(value, "true") == 0) { 1715 ocs_debug_enable(OCS_DEBUG_ENABLE_EQ_DUMP); 1716 result = 0; 1717 } else { 1718 result = -1; 1719 } 1720 1721 return result; 1722 } 1723 1724 static int 1725 set_logmask(ocs_t *ocs, char *name, char *value) 1726 { 1727 1728 ocs->logmask = ocs_strtoul(value, NULL, 0); 1729 1730 return 0; 1731 } 1732 1733 static int 1734 set_loglevel(ocs_t *ocs, char *name, char *value) 1735 { 1736 1737 loglevel = ocs_strtoul(value, NULL, 0); 1738 1739 return 0; 1740 } 1741 1742 int 1743 set_configured_speed(ocs_t *ocs, char *name, char *value) 1744 { 1745 int result = 0; 1746 ocs_hw_rtn_e hw_rc; 1747 int xport_rc; 1748 uint32_t spd; 1749 1750 spd = ocs_strtoul(value, NULL, 0); 1751 1752 if ((spd != 0) && (spd != 2000) && (spd != 4000) && 1753 (spd != 8000) && (spd != 16000) && (spd != 32000)) { 1754 ocs_log_test(ocs, "unsupported speed %d\n", spd); 1755 return 1; 1756 } 1757 1758 ocs_log_debug(ocs, "Taking port offline\n"); 1759 xport_rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE); 1760 if (xport_rc != 0) { 1761 ocs_log_test(ocs, "Port offline failed\n"); 1762 result = 1; 1763 } else { 1764 ocs_log_debug(ocs, "Setting port to speed %d\n", spd); 1765 hw_rc = ocs_hw_set(&ocs->hw, OCS_HW_LINK_SPEED, spd); 1766 if (hw_rc != OCS_HW_RTN_SUCCESS) { 1767 ocs_log_test(ocs, "Speed set failed\n"); 1768 result = 1; 1769 } 1770 1771 /* If we failed to set the speed we still want to try to bring 1772 * the port back online */ 1773 1774 ocs_log_debug(ocs, "Bringing port online\n"); 1775 xport_rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE); 1776 if (xport_rc != 0) { 1777 result = 1; 1778 } 1779 } 1780 1781 return result; 1782 } 1783 1784 int 1785 set_configured_topology(ocs_t *ocs, char *name, char *value) 1786 { 1787 int result = 0; 1788 ocs_hw_rtn_e hw_rc; 1789 int xport_rc; 1790 uint32_t topo; 1791 1792 topo = ocs_strtoul(value, NULL, 0); 1793 if (topo >= OCS_HW_TOPOLOGY_NONE) { 1794 return 1; 1795 } 1796 1797 ocs_log_debug(ocs, "Taking port offline\n"); 1798 xport_rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE); 1799 if (xport_rc != 0) { 1800 ocs_log_test(ocs, "Port offline failed\n"); 1801 result = 1; 1802 } else { 1803 ocs_log_debug(ocs, "Setting port to topology %d\n", topo); 1804 hw_rc = ocs_hw_set(&ocs->hw, OCS_HW_TOPOLOGY, topo); 1805 if (hw_rc != OCS_HW_RTN_SUCCESS) { 1806 ocs_log_test(ocs, "Topology set failed\n"); 1807 result = 1; 1808 } else { 1809 // Set the persistent topology before port is online 1810 hw_rc = ocs_hw_set_persistent_topology(&ocs->hw, topo, OCS_CMD_NOWAIT); 1811 if (hw_rc != OCS_HW_RTN_SUCCESS) 1812 ocs_log_err(ocs, "Set persistent topology feature failed: %d\n", hw_rc); 1813 } 1814 1815 /* If we failed to set the topology we still want to try to bring 1816 * the port back online */ 1817 1818 ocs_log_debug(ocs, "Bringing port online\n"); 1819 xport_rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE); 1820 if (xport_rc != 0) { 1821 result = 1; 1822 } 1823 } 1824 1825 return result; 1826 } 1827 1828 static int 1829 set_configured_link_state(ocs_t *ocs, char *name, char *value) 1830 { 1831 int result = 0; 1832 int xport_rc; 1833 1834 if (ocs_strcasecmp(value, "offline") == 0) { 1835 ocs_log_debug(ocs, "Setting port to %s\n", value); 1836 xport_rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE); 1837 if (xport_rc != 0) { 1838 ocs_log_test(ocs, "Setting port to offline failed\n"); 1839 result = -1; 1840 } 1841 } else if (ocs_strcasecmp(value, "online") == 0) { 1842 ocs_log_debug(ocs, "Setting port to %s\n", value); 1843 xport_rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE); 1844 if (xport_rc != 0) { 1845 ocs_log_test(ocs, "Setting port to online failed\n"); 1846 result = -1; 1847 } 1848 } else { 1849 ocs_log_test(ocs, "Unsupported link state \"%s\"\n", value); 1850 result = -1; 1851 } 1852 1853 return result; 1854 } 1855 1856 typedef struct ocs_mgmt_get_port_protocol_result { 1857 ocs_sem_t semaphore; 1858 int32_t status; 1859 ocs_hw_port_protocol_e port_protocol; 1860 } ocs_mgmt_get_port_protocol_result_t; 1861 1862 static void 1863 ocs_mgmt_get_port_protocol_cb(int32_t status, 1864 ocs_hw_port_protocol_e port_protocol, 1865 void *arg) 1866 { 1867 ocs_mgmt_get_port_protocol_result_t *result = arg; 1868 1869 result->status = status; 1870 result->port_protocol = port_protocol; 1871 1872 ocs_sem_v(&(result->semaphore)); 1873 } 1874 1875 static void 1876 get_port_protocol(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 1877 { 1878 ocs_mgmt_get_port_protocol_result_t result; 1879 uint8_t bus; 1880 uint8_t dev; 1881 uint8_t func; 1882 1883 ocs_sem_init(&(result.semaphore), 0, "get_port_protocol"); 1884 1885 ocs_get_bus_dev_func(ocs, &bus, &dev, &func); 1886 1887 if(ocs_hw_get_port_protocol(&ocs->hw, func, ocs_mgmt_get_port_protocol_cb, &result) == OCS_HW_RTN_SUCCESS) { 1888 if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) { 1889 /* Undefined failure */ 1890 ocs_log_err(ocs, "ocs_sem_p failed\n"); 1891 } 1892 if (result.status == 0) { 1893 switch (result.port_protocol) { 1894 case OCS_HW_PORT_PROTOCOL_ISCSI: 1895 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "port_protocol", "iSCSI"); 1896 break; 1897 case OCS_HW_PORT_PROTOCOL_FCOE: 1898 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "port_protocol", "FCoE"); 1899 break; 1900 case OCS_HW_PORT_PROTOCOL_FC: 1901 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "port_protocol", "FC"); 1902 break; 1903 case OCS_HW_PORT_PROTOCOL_OTHER: 1904 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "port_protocol", "Other"); 1905 break; 1906 } 1907 } else { 1908 ocs_log_test(ocs, "getting port profile status 0x%x\n", result.status); 1909 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "port_protocol", "Unknown"); 1910 } 1911 } 1912 } 1913 1914 typedef struct ocs_mgmt_set_port_protocol_result { 1915 ocs_sem_t semaphore; 1916 int32_t status; 1917 } ocs_mgmt_set_port_protocol_result_t; 1918 1919 static void 1920 ocs_mgmt_set_port_protocol_cb(int32_t status, 1921 void *arg) 1922 { 1923 ocs_mgmt_get_port_protocol_result_t *result = arg; 1924 1925 result->status = status; 1926 1927 ocs_sem_v(&(result->semaphore)); 1928 } 1929 1930 /** 1931 * @brief Set port protocol 1932 * @par Description 1933 * This is a management action handler to set the current 1934 * port protocol. Input value should be one of iSCSI, 1935 * FC, or FCoE. 1936 * 1937 * @param ocs Pointer to the ocs structure. 1938 * @param name Name of the action being performed. 1939 * @param value The value to be assigned 1940 * 1941 * @return Returns 0 on success, non-zero on failure. 1942 */ 1943 static int32_t 1944 set_port_protocol(ocs_t *ocs, char *name, char *value) 1945 { 1946 ocs_mgmt_set_port_protocol_result_t result; 1947 int32_t rc = 0; 1948 ocs_hw_port_protocol_e new_protocol; 1949 uint8_t bus; 1950 uint8_t dev; 1951 uint8_t func; 1952 1953 ocs_get_bus_dev_func(ocs, &bus, &dev, &func); 1954 1955 ocs_sem_init(&(result.semaphore), 0, "set_port_protocol"); 1956 1957 if (ocs_strcasecmp(value, "iscsi") == 0) { 1958 new_protocol = OCS_HW_PORT_PROTOCOL_ISCSI; 1959 } else if (ocs_strcasecmp(value, "fc") == 0) { 1960 new_protocol = OCS_HW_PORT_PROTOCOL_FC; 1961 } else if (ocs_strcasecmp(value, "fcoe") == 0) { 1962 new_protocol = OCS_HW_PORT_PROTOCOL_FCOE; 1963 } else { 1964 return -1; 1965 } 1966 1967 rc = ocs_hw_set_port_protocol(&ocs->hw, new_protocol, func, 1968 ocs_mgmt_set_port_protocol_cb, &result); 1969 if (rc == OCS_HW_RTN_SUCCESS) { 1970 if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) { 1971 /* Undefined failure */ 1972 ocs_log_err(ocs, "ocs_sem_p failed\n"); 1973 return -ENXIO; 1974 } 1975 if (result.status == 0) { 1976 /* Success. */ 1977 rc = 0; 1978 } else { 1979 rc = -1; 1980 ocs_log_test(ocs, "setting active profile status 0x%x\n", 1981 result.status); 1982 } 1983 } 1984 1985 return rc; 1986 } 1987 1988 typedef struct ocs_mgmt_get_profile_list_result_s { 1989 ocs_sem_t semaphore; 1990 int32_t status; 1991 ocs_hw_profile_list_t *list; 1992 } ocs_mgmt_get_profile_list_result_t; 1993 1994 static void 1995 ocs_mgmt_get_profile_list_cb(int32_t status, ocs_hw_profile_list_t *list, void *ul_arg) 1996 { 1997 ocs_mgmt_get_profile_list_result_t *result = ul_arg; 1998 1999 result->status = status; 2000 result->list = list; 2001 2002 ocs_sem_v(&(result->semaphore)); 2003 } 2004 2005 /** 2006 * @brief Get list of profiles 2007 * @par Description 2008 * This is a management action handler to get the list of 2009 * profiles supported by the SLI port. Although the spec says 2010 * that all SLI platforms support this, only Skyhawk actually 2011 * has a useful implementation. 2012 * 2013 * @param ocs Pointer to the ocs structure. 2014 * @param name Name of the action being performed. 2015 * @param textbuf Pointer to an ocs_textbuf, which is used to return the results. 2016 * 2017 * @return none 2018 */ 2019 static void 2020 get_profile_list(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 2021 { 2022 ocs_mgmt_get_profile_list_result_t result; 2023 2024 ocs_sem_init(&(result.semaphore), 0, "get_profile_list"); 2025 2026 if(ocs_hw_get_profile_list(&ocs->hw, ocs_mgmt_get_profile_list_cb, &result) == OCS_HW_RTN_SUCCESS) { 2027 if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) { 2028 /* Undefined failure */ 2029 ocs_log_err(ocs, "ocs_sem_p failed\n"); 2030 } 2031 if (result.status == 0) { 2032 /* Success. */ 2033 #define MAX_LINE_SIZE 520 2034 #define BUFFER_SIZE MAX_LINE_SIZE*40 2035 char *result_buf; 2036 char result_line[MAX_LINE_SIZE]; 2037 uint32_t bytes_left; 2038 uint32_t i; 2039 2040 result_buf = ocs_malloc(ocs, BUFFER_SIZE, OCS_M_ZERO); 2041 bytes_left = BUFFER_SIZE; 2042 2043 for (i=0; i<result.list->num_descriptors; i++) { 2044 sprintf(result_line, "0x%02x:%s\n", result.list->descriptors[i].profile_id, 2045 result.list->descriptors[i].profile_description); 2046 if (strlen(result_line) < bytes_left) { 2047 strcat(result_buf, result_line); 2048 bytes_left -= strlen(result_line); 2049 } 2050 } 2051 2052 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "profile_list", result_buf); 2053 2054 ocs_free(ocs, result_buf, BUFFER_SIZE); 2055 ocs_free(ocs, result.list, sizeof(ocs_hw_profile_list_t)); 2056 } else { 2057 ocs_log_test(ocs, "getting profile list status 0x%x\n", result.status); 2058 } 2059 } 2060 } 2061 2062 typedef struct ocs_mgmt_get_active_profile_result { 2063 ocs_sem_t semaphore; 2064 int32_t status; 2065 uint32_t active_profile_id; 2066 } ocs_mgmt_get_active_profile_result_t; 2067 2068 static void 2069 ocs_mgmt_get_active_profile_cb(int32_t status, uint32_t active_profile, void *ul_arg) 2070 { 2071 ocs_mgmt_get_active_profile_result_t *result = ul_arg; 2072 2073 result->status = status; 2074 result->active_profile_id = active_profile; 2075 2076 ocs_sem_v(&(result->semaphore)); 2077 } 2078 2079 #define MAX_PROFILE_LENGTH 5 2080 2081 /** 2082 * @brief Get active profile 2083 * @par Description 2084 * This is a management action handler to get the currently 2085 * active profile for an SLI port. Although the spec says that 2086 * all SLI platforms support this, only Skyhawk actually has a 2087 * useful implementation. 2088 * 2089 * @param ocs Pointer to the ocs structure. 2090 * @param name Name of the action being performed. 2091 * @param textbuf Pointer to an ocs_textbuf, which is used to return the results. 2092 * 2093 * @return none 2094 */ 2095 static void 2096 get_active_profile(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 2097 { 2098 char result_string[MAX_PROFILE_LENGTH]; 2099 ocs_mgmt_get_active_profile_result_t result; 2100 2101 ocs_sem_init(&(result.semaphore), 0, "get_active_profile"); 2102 2103 if(ocs_hw_get_active_profile(&ocs->hw, ocs_mgmt_get_active_profile_cb, &result) == OCS_HW_RTN_SUCCESS) { 2104 if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) { 2105 /* Undefined failure */ 2106 ocs_log_err(ocs, "ocs_sem_p failed\n"); 2107 } 2108 if (result.status == 0) { 2109 /* Success. */ 2110 sprintf(result_string, "0x%02x", result.active_profile_id); 2111 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "active_profile", result_string); 2112 } else { 2113 ocs_log_test(ocs, "getting active profile status 0x%x\n", result.status); 2114 } 2115 } 2116 } 2117 2118 typedef struct ocs_mgmt_set_active_profile_result { 2119 ocs_sem_t semaphore; 2120 int32_t status; 2121 } ocs_mgmt_set_active_profile_result_t; 2122 2123 static void 2124 ocs_mgmt_set_active_profile_cb(int32_t status, void *ul_arg) 2125 { 2126 ocs_mgmt_get_profile_list_result_t *result = ul_arg; 2127 2128 result->status = status; 2129 2130 ocs_sem_v(&(result->semaphore)); 2131 } 2132 2133 /** 2134 * @brief Set active profile 2135 * @par Description 2136 * This is a management action handler to set the currently 2137 * active profile for an SLI port. Although the spec says that 2138 * all SLI platforms support this, only Skyhawk actually has a 2139 * useful implementation. 2140 * 2141 * @param ocs Pointer to the ocs structure. 2142 * @param name Name of the action being performed. 2143 * @param value Requested new value of the property. 2144 * 2145 * @return Returns 0 on success, non-zero on failure. 2146 */ 2147 static int32_t 2148 set_active_profile(ocs_t *ocs, char *name, char *value) 2149 { 2150 ocs_mgmt_set_active_profile_result_t result; 2151 int32_t rc = 0; 2152 int32_t new_profile; 2153 2154 new_profile = ocs_strtoul(value, NULL, 0); 2155 2156 ocs_sem_init(&(result.semaphore), 0, "set_active_profile"); 2157 2158 rc = ocs_hw_set_active_profile(&ocs->hw, ocs_mgmt_set_active_profile_cb, new_profile, &result); 2159 if (rc == OCS_HW_RTN_SUCCESS) { 2160 if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) { 2161 /* Undefined failure */ 2162 ocs_log_err(ocs, "ocs_sem_p failed\n"); 2163 return -ENXIO; 2164 } 2165 if (result.status == 0) { 2166 /* Success. */ 2167 rc = 0; 2168 } else { 2169 rc = -1; 2170 ocs_log_test(ocs, "setting active profile status 0x%x\n", result.status); 2171 } 2172 } 2173 2174 return rc; 2175 } 2176 2177 typedef struct ocs_mgmt_get_nvparms_result { 2178 ocs_sem_t semaphore; 2179 int32_t status; 2180 uint8_t wwpn[8]; 2181 uint8_t wwnn[8]; 2182 uint8_t hard_alpa; 2183 uint32_t preferred_d_id; 2184 } ocs_mgmt_get_nvparms_result_t; 2185 2186 static void 2187 ocs_mgmt_get_nvparms_cb(int32_t status, uint8_t *wwpn, uint8_t *wwnn, uint8_t hard_alpa, 2188 uint32_t preferred_d_id, void *ul_arg) 2189 { 2190 ocs_mgmt_get_nvparms_result_t *result = ul_arg; 2191 2192 result->status = status; 2193 ocs_memcpy(result->wwpn, wwpn, sizeof(result->wwpn)); 2194 ocs_memcpy(result->wwnn, wwnn, sizeof(result->wwnn)); 2195 result->hard_alpa = hard_alpa; 2196 result->preferred_d_id = preferred_d_id; 2197 2198 ocs_sem_v(&(result->semaphore)); 2199 } 2200 2201 /** 2202 * @brief Get wwpn 2203 * @par Description 2204 * 2205 * 2206 * @param ocs Pointer to the ocs structure. 2207 * @param name Name of the action being performed. 2208 * @param textbuf Pointer to an ocs_textbuf, which is used to return the results. 2209 * 2210 * @return none 2211 */ 2212 static void 2213 get_nv_wwpn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 2214 { 2215 char result_string[24]; 2216 ocs_mgmt_get_nvparms_result_t result; 2217 2218 ocs_sem_init(&(result.semaphore), 0, "get_nv_wwpn"); 2219 2220 if(ocs_hw_get_nvparms(&ocs->hw, ocs_mgmt_get_nvparms_cb, &result) == OCS_HW_RTN_SUCCESS) { 2221 if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) { 2222 /* Undefined failure */ 2223 ocs_log_err(ocs, "ocs_sem_p failed\n"); 2224 return; 2225 } 2226 if (result.status == 0) { 2227 /* Success. Copy wwpn from result struct to result string */ 2228 sprintf(result_string, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", 2229 result.wwpn[0], result.wwpn[1], result.wwpn[2], 2230 result.wwpn[3], result.wwpn[4], result.wwpn[5], 2231 result.wwpn[6], result.wwpn[7]); 2232 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "nv_wwpn", result_string); 2233 } else { 2234 ocs_log_test(ocs, "getting wwpn status 0x%x\n", result.status); 2235 } 2236 } 2237 } 2238 2239 /** 2240 * @brief Get wwnn 2241 * @par Description 2242 * 2243 * 2244 * @param ocs Pointer to the ocs structure. 2245 * @param name Name of the action being performed. 2246 * @param textbuf Pointer to an ocs_textbuf, which is used to return the results. 2247 * 2248 * @return none 2249 */ 2250 static void 2251 get_nv_wwnn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 2252 { 2253 char result_string[24]; 2254 ocs_mgmt_get_nvparms_result_t result; 2255 2256 ocs_sem_init(&(result.semaphore), 0, "get_nv_wwnn"); 2257 2258 if(ocs_hw_get_nvparms(&ocs->hw, ocs_mgmt_get_nvparms_cb, &result) == OCS_HW_RTN_SUCCESS) { 2259 if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) { 2260 /* Undefined failure */ 2261 ocs_log_err(ocs, "ocs_sem_p failed\n"); 2262 return; 2263 } 2264 if (result.status == 0) { 2265 /* Success. Copy wwnn from result struct to result string */ 2266 ocs_snprintf(result_string, sizeof(result_string), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", 2267 result.wwnn[0], result.wwnn[1], result.wwnn[2], 2268 result.wwnn[3], result.wwnn[4], result.wwnn[5], 2269 result.wwnn[6], result.wwnn[7]); 2270 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "nv_wwnn", result_string); 2271 } else { 2272 ocs_log_test(ocs, "getting wwnn status 0x%x\n", result.status); 2273 } 2274 } 2275 } 2276 2277 /** 2278 * @brief Get accumulated node abort counts 2279 * @par Description Get the sum of all nodes abort count. 2280 * 2281 * @param ocs Pointer to the ocs structure. 2282 * @param name Name of the action being performed. 2283 * @param textbuf Pointer to an ocs_textbuf, which is used to return the results. 2284 * 2285 * @return None. 2286 */ 2287 static void 2288 get_node_abort_cnt(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf) 2289 { 2290 uint32_t abort_counts = 0; 2291 ocs_domain_t *domain; 2292 ocs_sport_t *sport; 2293 ocs_node_t *node; 2294 2295 if (ocs_device_lock_try(ocs) != TRUE) { 2296 /* Didn't get the lock */ 2297 return; 2298 } 2299 2300 /* Here the Device lock is held */ 2301 ocs_list_foreach(&ocs->domain_list, domain) { 2302 if (ocs_domain_lock_try(domain) != TRUE) { 2303 /* Didn't get the lock */ 2304 ocs_device_unlock(ocs); 2305 return; 2306 } 2307 2308 /* Here the Domain lock is held */ 2309 ocs_list_foreach(&domain->sport_list, sport) { 2310 if (ocs_sport_lock_try(sport) != TRUE) { 2311 /* Didn't get the lock */ 2312 ocs_domain_unlock(domain); 2313 ocs_device_unlock(ocs); 2314 return; 2315 } 2316 2317 /* Here the sport lock is held */ 2318 ocs_list_foreach(&sport->node_list, node) { 2319 abort_counts += node->abort_cnt; 2320 } 2321 2322 ocs_sport_unlock(sport); 2323 } 2324 2325 ocs_domain_unlock(domain); 2326 } 2327 2328 ocs_device_unlock(ocs); 2329 2330 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "node_abort_cnt", "%d" , abort_counts); 2331 } 2332 2333 typedef struct ocs_mgmt_set_nvparms_result { 2334 ocs_sem_t semaphore; 2335 int32_t status; 2336 } ocs_mgmt_set_nvparms_result_t; 2337 2338 static void 2339 ocs_mgmt_set_nvparms_cb(int32_t status, void *ul_arg) 2340 { 2341 ocs_mgmt_get_profile_list_result_t *result = ul_arg; 2342 2343 result->status = status; 2344 2345 ocs_sem_v(&(result->semaphore)); 2346 } 2347 2348 /** 2349 * @brief Set wwn 2350 * @par Description Sets the Non-volatile worldwide names, 2351 * if provided. 2352 * 2353 * @param ocs Pointer to the ocs structure. 2354 * @param name Name of the action being performed. 2355 * @param wwn_p Requested new WWN values. 2356 * 2357 * @return Returns 0 on success, non-zero on failure. 2358 */ 2359 static int32_t 2360 set_nv_wwn(ocs_t *ocs, char *name, char *wwn_p) 2361 { 2362 ocs_mgmt_get_nvparms_result_t result; 2363 uint8_t new_wwpn[8]; 2364 uint8_t new_wwnn[8]; 2365 char *wwpn_p = NULL; 2366 char *wwnn_p = NULL; 2367 int32_t rc = -1; 2368 int wwpn = 0; 2369 int wwnn = 0; 2370 int i; 2371 2372 /* This is a read-modify-write operation, so first we have to read 2373 * the current values 2374 */ 2375 ocs_sem_init(&(result.semaphore), 0, "set_nv_wwn1"); 2376 2377 rc = ocs_hw_get_nvparms(&ocs->hw, ocs_mgmt_get_nvparms_cb, &result); 2378 2379 if (rc == OCS_HW_RTN_SUCCESS) { 2380 if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) { 2381 /* Undefined failure */ 2382 ocs_log_err(ocs, "ocs_sem_p failed\n"); 2383 return -ENXIO; 2384 } 2385 if (result.status != 0) { 2386 ocs_log_test(ocs, "getting nvparms status 0x%x\n", result.status); 2387 return -1; 2388 } 2389 } 2390 2391 /* wwn_p contains wwpn_p@wwnn_p values */ 2392 if (wwn_p != NULL) { 2393 wwpn_p = ocs_strsep(&wwn_p, "@"); 2394 wwnn_p = wwn_p; 2395 } 2396 2397 if (wwpn_p != NULL) { 2398 wwpn = ocs_strcmp(wwpn_p, "NA"); 2399 } 2400 2401 if (wwnn_p != NULL) { 2402 wwnn = ocs_strcmp(wwnn_p, "NA"); 2403 } 2404 2405 /* Parse the new WWPN */ 2406 if ((wwpn_p != NULL) && (wwpn != 0)) { 2407 if (ocs_sscanf(wwpn_p, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", 2408 &(new_wwpn[0]), &(new_wwpn[1]), &(new_wwpn[2]), 2409 &(new_wwpn[3]), &(new_wwpn[4]), &(new_wwpn[5]), 2410 &(new_wwpn[6]), &(new_wwpn[7])) != 8) { 2411 ocs_log_test(ocs, "can't parse WWPN %s\n", wwpn_p); 2412 return -1; 2413 } 2414 } 2415 2416 /* Parse the new WWNN */ 2417 if ((wwnn_p != NULL) && (wwnn != 0 )) { 2418 if (ocs_sscanf(wwnn_p, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", 2419 &(new_wwnn[0]), &(new_wwnn[1]), &(new_wwnn[2]), 2420 &(new_wwnn[3]), &(new_wwnn[4]), &(new_wwnn[5]), 2421 &(new_wwnn[6]), &(new_wwnn[7])) != 8) { 2422 ocs_log_test(ocs, "can't parse WWNN %s\n", wwnn_p); 2423 return -1; 2424 } 2425 } 2426 2427 for (i = 0; i < 8; i++) { 2428 /* Use active wwpn, if new one is not provided */ 2429 if (wwpn == 0) { 2430 new_wwpn[i] = result.wwpn[i]; 2431 } 2432 2433 /* Use active wwnn, if new one is not provided */ 2434 if (wwnn == 0) { 2435 new_wwnn[i] = result.wwnn[i]; 2436 } 2437 } 2438 2439 /* Modify the nv_wwnn and nv_wwpn, then write it back */ 2440 ocs_sem_init(&(result.semaphore), 0, "set_nv_wwn2"); 2441 2442 rc = ocs_hw_set_nvparms(&ocs->hw, ocs_mgmt_set_nvparms_cb, new_wwpn, 2443 new_wwnn, result.hard_alpa, result.preferred_d_id, 2444 &result); 2445 if (rc == OCS_HW_RTN_SUCCESS) { 2446 if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) { 2447 /* Undefined failure */ 2448 ocs_log_err(ocs, "ocs_sem_p failed\n"); 2449 return -ENXIO; 2450 } 2451 if (result.status != 0) { 2452 ocs_log_test(ocs, "setting wwn status 0x%x\n", result.status); 2453 return -1; 2454 } 2455 } 2456 2457 return rc; 2458 } 2459 2460 static int 2461 set_tgt_rscn_delay(ocs_t *ocs, char *name, char *value) 2462 { 2463 ocs->tgt_rscn_delay_msec = ocs_strtoul(value, NULL, 0) * 1000; 2464 ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value); 2465 return 0; 2466 } 2467 2468 static int 2469 set_tgt_rscn_period(ocs_t *ocs, char *name, char *value) 2470 { 2471 ocs->tgt_rscn_period_msec = ocs_strtoul(value, NULL, 0) * 1000; 2472 ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value); 2473 return 0; 2474 } 2475 2476 static int 2477 set_inject_drop_cmd(ocs_t *ocs, char *name, char *value) 2478 { 2479 ocs->err_injection = (ocs_strtoul(value, NULL, 0) == 0 ? NO_ERR_INJECT : INJECT_DROP_CMD); 2480 ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value); 2481 return 0; 2482 } 2483 2484 static int 2485 set_inject_free_drop_cmd(ocs_t *ocs, char *name, char *value) 2486 { 2487 ocs->err_injection = (ocs_strtoul(value, NULL, 0) == 0 ? NO_ERR_INJECT : INJECT_FREE_DROPPED); 2488 ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value); 2489 return 0; 2490 } 2491 2492 static int 2493 set_inject_drop_data(ocs_t *ocs, char *name, char *value) 2494 { 2495 ocs->err_injection = (ocs_strtoul(value, NULL, 0) == 0 ? NO_ERR_INJECT : INJECT_DROP_DATA); 2496 ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value); 2497 return 0; 2498 } 2499 2500 static int 2501 set_inject_drop_resp(ocs_t *ocs, char *name, char *value) 2502 { 2503 ocs->err_injection = (ocs_strtoul(value, NULL, 0) == 0 ? NO_ERR_INJECT : INJECT_DROP_RESP); 2504 ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value); 2505 return 0; 2506 } 2507 2508 static int 2509 set_cmd_err_inject(ocs_t *ocs, char *name, char *value) 2510 { 2511 ocs->cmd_err_inject = ocs_strtoul(value, NULL, 0); 2512 ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value); 2513 return 0; 2514 } 2515 2516 static int 2517 set_cmd_delay_value(ocs_t *ocs, char *name, char *value) 2518 { 2519 ocs->delay_value_msec = ocs_strtoul(value, NULL, 0); 2520 ocs->err_injection = (ocs->delay_value_msec == 0 ? NO_ERR_INJECT : INJECT_DELAY_CMD); 2521 ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value); 2522 return 0; 2523 } 2524 2525 /** 2526 * @brief parse a WWN from a string into a 64-bit value 2527 * 2528 * Given a pointer to a string, parse the string into a 64-bit 2529 * WWN value. The format of the string must be xx:xx:xx:xx:xx:xx:xx:xx 2530 * 2531 * @param wwn_in pointer to the string to be parsed 2532 * @param wwn_out pointer to uint64_t in which to put the parsed result 2533 * 2534 * @return 0 if successful, non-zero if the WWN is malformed and couldn't be parsed 2535 */ 2536 int 2537 parse_wwn(char *wwn_in, uint64_t *wwn_out) 2538 { 2539 uint8_t byte0; 2540 uint8_t byte1; 2541 uint8_t byte2; 2542 uint8_t byte3; 2543 uint8_t byte4; 2544 uint8_t byte5; 2545 uint8_t byte6; 2546 uint8_t byte7; 2547 int rc; 2548 2549 rc = ocs_sscanf(wwn_in, "0x%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", 2550 &byte0, &byte1, &byte2, &byte3, 2551 &byte4, &byte5, &byte6, &byte7); 2552 2553 if (rc == 8) { 2554 *wwn_out = ((uint64_t)byte0 << 56) | 2555 ((uint64_t)byte1 << 48) | 2556 ((uint64_t)byte2 << 40) | 2557 ((uint64_t)byte3 << 32) | 2558 ((uint64_t)byte4 << 24) | 2559 ((uint64_t)byte5 << 16) | 2560 ((uint64_t)byte6 << 8) | 2561 ((uint64_t)byte7); 2562 return 0; 2563 2564 } else { 2565 return 1; 2566 } 2567 } 2568 2569 static char *mode_string(int mode); 2570 2571 /** 2572 * @ingroup mgmt 2573 * @brief Generate the beginning of a numbered section in a management XML document. 2574 * 2575 * @par Description 2576 * This function begins a section. The XML information is appended to 2577 * the textbuf. This form of the function is used for sections that might have 2578 * multiple instances, such as a node or a SLI Port (sport). The index number 2579 * is appended to the name. 2580 * 2581 * @param textbuf Pointer to the driver dump text buffer. 2582 * @param name Name of the section. 2583 * @param index Index number of this instance of the section. 2584 * 2585 * @return None. 2586 */ 2587 2588 extern void ocs_mgmt_start_section(ocs_textbuf_t *textbuf, const char *name, int index) 2589 { 2590 ocs_textbuf_printf(textbuf, "<%s instance=\"%d\">\n", name, index); 2591 } 2592 2593 /** 2594 * @ingroup mgmt 2595 * @brief Generate the beginning of an unnumbered section in a management XML document. 2596 * 2597 * @par Description 2598 * This function begins a section. The XML information is appended to 2599 * the textbuf. This form of the function is used for sections that have 2600 * a single instance only. Therefore, no index number is needed. 2601 * 2602 * @param textbuf Pointer to the driver dump text buffer. 2603 * @param name Name of the section. 2604 * 2605 * @return None. 2606 */ 2607 2608 extern void ocs_mgmt_start_unnumbered_section(ocs_textbuf_t *textbuf, const char *name) 2609 { 2610 ocs_textbuf_printf(textbuf, "<%s>\n", name); 2611 } 2612 2613 /** 2614 * @ingroup mgmt 2615 * @brief Generate the end of a section in a management XML document. 2616 * 2617 * @par Description 2618 * This function ends a section. The XML information is appended to 2619 * the textbuf. 2620 * 2621 * @param textbuf Pointer to the driver dump text buffer. 2622 * @param name Name of the section. 2623 * 2624 * @return None. 2625 */ 2626 2627 void ocs_mgmt_end_unnumbered_section(ocs_textbuf_t *textbuf, const char *name) 2628 { 2629 ocs_textbuf_printf(textbuf, "</%s>\n", name); 2630 } 2631 2632 /** 2633 * @ingroup mgmt 2634 * @brief Generate the indexed end of a section in a management XML document. 2635 * 2636 * @par Description 2637 * This function ends a section. The XML information is appended to 2638 * the textbuf. 2639 * 2640 * @param textbuf Pointer to the driver dump text buffer. 2641 * @param name Name of the section. 2642 * @param index Index number of this instance of the section. 2643 * 2644 * @return None. 2645 */ 2646 2647 void ocs_mgmt_end_section(ocs_textbuf_t *textbuf, const char *name, int index) 2648 { 2649 2650 ocs_textbuf_printf(textbuf, "</%s>\n", name); 2651 2652 } 2653 2654 /** 2655 * @ingroup mgmt 2656 * @brief Generate a property, with no value, in a management XML document. 2657 * 2658 * @par Description 2659 * This function generates a property name. The XML information is appended to 2660 * the textbuf. This form of the function is used by the list functions 2661 * when the property name only (and not the current value) is given. 2662 * 2663 * @param textbuf Pointer to the driver dump text buffer. 2664 * @param mode Defines whether the property is read(r)/write(w)/executable(x). 2665 * @param name Name of the property. 2666 * 2667 * @return None. 2668 */ 2669 2670 void ocs_mgmt_emit_property_name(ocs_textbuf_t *textbuf, int mode, const char *name) 2671 { 2672 ocs_textbuf_printf(textbuf, "<%s mode=\"%s\"/>\n", name, mode_string(mode)); 2673 } 2674 2675 /** 2676 * @ingroup mgmt 2677 * @brief Generate a property with a string value in a management XML document. 2678 * 2679 * @par Description 2680 * This function generates a property name and a string value. 2681 * The XML information is appended to the textbuf. 2682 * 2683 * @param textbuf Pointer to the driver dump text buffer. 2684 * @param mode Defines whether the property is read(r)/write(w)/executable(x). 2685 * @param name Name of the property. 2686 * @param value Value of the property. 2687 * 2688 * @return None. 2689 */ 2690 2691 void ocs_mgmt_emit_string(ocs_textbuf_t *textbuf, int mode, const char *name, const char *value) 2692 { 2693 ocs_textbuf_printf(textbuf, "<%s mode=\"%s\">%s</%s>\n", name, mode_string(mode), value, name); 2694 } 2695 2696 /** 2697 * @ingroup mgmt 2698 * @brief Generate a property with an integer value in a management XML document. 2699 * 2700 * @par Description 2701 * This function generates a property name and an integer value. 2702 * The XML information is appended to the textbuf. 2703 * 2704 * @param textbuf Pointer to driver dump text buffer. 2705 * @param mode Defines whether the property is read(r)/write(w)/executable(x). 2706 * @param name Name of the property. 2707 * @param fmt A printf format for formatting the integer value. 2708 * 2709 * @return none 2710 */ 2711 2712 void ocs_mgmt_emit_int(ocs_textbuf_t *textbuf, int mode, const char *name, const char *fmt, ...) 2713 { 2714 va_list ap; 2715 char valuebuf[64]; 2716 2717 va_start(ap, fmt); 2718 ocs_vsnprintf(valuebuf, sizeof(valuebuf), fmt, ap); 2719 va_end(ap); 2720 2721 ocs_textbuf_printf(textbuf, "<%s mode=\"%s\">%s</%s>\n", name, mode_string(mode), valuebuf, name); 2722 } 2723 2724 /** 2725 * @ingroup mgmt 2726 * @brief Generate a property with a boolean value in a management XML document. 2727 * 2728 * @par Description 2729 * This function generates a property name and a boolean value. 2730 * The XML information is appended to the textbuf. 2731 * 2732 * @param textbuf Pointer to the driver dump text buffer. 2733 * @param mode Defines whether the property is read(r)/write(w)/executable(x). 2734 * @param name Name of the property. 2735 * @param value Boolean value to be added to the textbuf. 2736 * 2737 * @return None. 2738 */ 2739 2740 void ocs_mgmt_emit_boolean(ocs_textbuf_t *textbuf, int mode, const char *name, int value) 2741 { 2742 char *valuebuf = value ? "true" : "false"; 2743 2744 ocs_textbuf_printf(textbuf, "<%s mode=\"%s\">%s</%s>\n", name, mode_string(mode), valuebuf, name); 2745 } 2746 2747 static char *mode_string(int mode) 2748 { 2749 static char mode_str[4]; 2750 2751 mode_str[0] = '\0'; 2752 if (mode & MGMT_MODE_RD) { 2753 strcat(mode_str, "r"); 2754 } 2755 if (mode & MGMT_MODE_WR) { 2756 strcat(mode_str, "w"); 2757 } 2758 if (mode & MGMT_MODE_EX) { 2759 strcat(mode_str, "x"); 2760 } 2761 2762 return mode_str; 2763 2764 } 2765