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