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