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