2 * Copyright (c) 2017 Broadcom. All rights reserved.
3 * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
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.
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.
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.
36 * The ocs_mgmt top level functions for Fibre Channel.
40 * @defgroup mgmt Management Functions
47 #define SFP_PAGE_SIZE 128
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);
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);
58 #if defined(OCS_INCLUDE_RAMD)
60 ocs_mgmt_read_phys(ocs_t *ocs, char *, void *, uint32_t , void *, uint32_t);
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);
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*);
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);
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},
199 {"force_assert", NULL, NULL, ocs_mgmt_force_assert},
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},
217 * @brief Get a list of options supported by the driver.
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.
226 * @param ocs Pointer to the ocs structure.
227 * @param textbuf Pointer to an ocs_textbuf, which is used to accumulate the results.
229 * @return Returns 0 on success, or a negative value on failure.
233 ocs_mgmt_get_list(ocs_t *ocs, ocs_textbuf_t *textbuf)
235 ocs_domain_t *domain;
239 ocs_mgmt_start_unnumbered_section(textbuf, "ocs");
241 for (i=0;i<ARRAY_SIZE(mgmt_table);i++) {
243 if (mgmt_table[i].get_handler) {
244 access |= MGMT_MODE_RD;
246 if (mgmt_table[i].set_handler) {
247 access |= MGMT_MODE_WR;
249 if (mgmt_table[i].action_handler) {
250 access |= MGMT_MODE_EX;
252 ocs_mgmt_emit_property_name(textbuf, access, mgmt_table[i].name);
255 if ((ocs->mgmt_functions) && (ocs->mgmt_functions->get_list_handler)) {
256 ocs->mgmt_functions->get_list_handler(textbuf, ocs);
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));
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);
271 ocs_device_unlock(ocs);
274 ocs_mgmt_end_unnumbered_section(textbuf, "ocs");
280 * @brief Return the value of a management item.
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.
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
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.
301 * @return Returns 0 if the value was found and returned, or -1 if an error occurred.
305 ocs_mgmt_get(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
307 ocs_domain_t *domain;
312 ocs_mgmt_start_unnumbered_section(textbuf, "ocs");
314 snprintf(qualifier, sizeof(qualifier), "/ocs");
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;
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");
330 if ((ocs->mgmt_functions) && (ocs->mgmt_functions->get_handler)) {
331 retval = ocs->mgmt_functions->get_handler(textbuf, qualifier, (char*)name, ocs);
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));
342 /* The driver didn't handle it, pass it to each domain */
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);
354 ocs_device_unlock(ocs);
358 ocs_mgmt_end_unnumbered_section(textbuf, "ocs");
365 * @brief Set the value of a mgmt item.
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.
377 * In passing the request to other entities, the request is considered to be handled
378 * if the function returns 0.
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.
384 * @return Returns 0 if the configuration value was updated, or -1 otherwise.
388 ocs_mgmt_set(ocs_t *ocs, char *name, char *value)
390 ocs_domain_t *domain;
395 snprintf(qualifier, sizeof(qualifier), "/ocs");
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;
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);
410 if ((ocs->mgmt_functions) && (ocs->mgmt_functions->set_handler)) {
411 result = ocs->mgmt_functions->set_handler(qualifier, name, (char *)value, ocs);
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));
421 /* If I didn't know how to set this config value pass the request to each of my children */
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);
432 ocs_device_unlock(ocs);
441 * @brief Perform a management action.
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.
453 * In passing the request to other entities, the request is considered to be handled
454 * if the function returns 0.
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.
463 * @return Returns 0 if the action was completed, or -1 otherwise.
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)
472 ocs_domain_t *domain;
477 snprintf(qualifier, sizeof(qualifier), "/ocs");
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;
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);
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);
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,
506 /* If I didn't know how to do this action pass the request to each of my children */
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);
518 ocs_device_unlock(ocs);
526 ocs_mgmt_get_all(ocs_t *ocs, ocs_textbuf_t *textbuf)
528 ocs_domain_t *domain;
531 ocs_mgmt_start_unnumbered_section(textbuf, "ocs");
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
539 ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_EX, mgmt_table[i].name);
543 if ((ocs->mgmt_functions) && (ocs->mgmt_functions->get_all_handler)) {
544 ocs->mgmt_functions->get_all_handler(textbuf, ocs);
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));
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);
557 ocs_device_unlock(ocs);
559 ocs_mgmt_end_unnumbered_section(textbuf, "ocs");
562 #if defined(OCS_INCLUDE_RAMD)
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)
568 uintptr_t target_addr;
570 ocs_ramdisc_t **ramdisc_array;
571 uint32_t ramdisc_count;
573 if ((arg_in == NULL) ||
574 (arg_in_length == 0) ||
576 (arg_out_length == 0)) {
580 if (arg_in_length > 80) {
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");
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
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);
601 /* Multiple targets. Each target is on a sport */
604 for (domain_idx=0; domain_idx<ocs->domain_instance_count; domain_idx++) {
605 ocs_domain_t *domain;
608 domain = ocs_domain_get_instance(ocs, domain_idx);
609 for (sport_idx=0; sport_idx < domain->sport_instance_count; sport_idx++) {
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);
624 length = arg_out_length;
627 if (ocs_copy_to_user(arg_out, vaddr, length)) {
628 ocs_log_test(ocs, "Failed to copy buffer to user\n");
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
644 static void* find_address_in_target(ocs_ramdisc_t **ramdisc_array, uint32_t ramdisc_count, uintptr_t target_addr)
647 uint32_t ramdisc_idx;
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;
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;
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;
694 ocs_mgmt_firmware_reset(ocs_t *ocs, char *name, void *buf, uint32_t buf_len, void *arg_out, uint32_t arg_out_length)
698 uint8_t bus, dev, func;
701 ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
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");
708 ocs_log_debug(ocs, "successfully reset port\n");
710 /* now reset all functions on the same device */
712 while ((other_ocs = ocs_get_instance(index++)) != NULL) {
713 uint8_t other_bus, other_dev, other_func;
715 ocs_get_bus_dev_func(other_ocs, &other_bus, &other_dev, &other_func);
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;
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);
737 ocs_mgmt_function_reset(ocs_t *ocs, char *name, void *buf, uint32_t buf_len, void *arg_out, uint32_t arg_out_length)
741 ocs_device_detach(ocs);
742 rc = ocs_device_attach(ocs);
748 ocs_mgmt_firmware_write(ocs_t *ocs, char *name, void *buf, uint32_t buf_len, void *arg_out, uint32_t arg_out_length)
757 ocs_mgmt_fw_write_result_t result;
758 uint32_t change_status = 0;
761 ocs_sem_init(&(result.semaphore), 0, "fw_write");
763 bytes_left = buf_len;
765 userp = (uint8_t *)buf;
767 if (ocs_dma_alloc(ocs, &dma, FW_WRITE_BUFSIZE, 4096)) {
768 ocs_log_err(ocs, "ocs_mgmt_firmware_write: malloc failed");
772 while (bytes_left > 0) {
773 if (bytes_left > FW_WRITE_BUFSIZE) {
774 xfer_size = FW_WRITE_BUFSIZE;
776 xfer_size = bytes_left;
779 /* Copy xfer_size bytes from user space to kernel buffer */
780 if (ocs_copy_from_user(dma.virt, userp, xfer_size)) {
785 /* See if this is the last block */
786 if (bytes_left == xfer_size) {
790 /* Send the HW command */
791 ocs_hw_firmware_write(&ocs->hw, &dma, xfer_size, offset, last, ocs_mgmt_fw_write_cb, &result);
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");
801 if (result.actual_xfer == 0) {
802 ocs_log_test(ocs, "actual_write_length is %d\n", result.actual_xfer);
808 if (result.status != 0) {
809 ocs_log_test(ocs, "write returned status %d\n", result.status);
815 change_status = result.change_status;
818 bytes_left -= result.actual_xfer;
819 offset += result.actual_xfer;
820 userp += result.actual_xfer;
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);
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");
835 ocs_dma_free(ocs, &dma);
841 ocs_mgmt_fw_write_cb(int32_t status, uint32_t actual_write_length, uint32_t change_status, void *arg)
843 ocs_mgmt_fw_write_result_t *result = arg;
845 result->status = status;
846 result->actual_xfer = actual_write_length;
847 result->change_status = change_status;
849 ocs_sem_v(&(result->semaphore));
852 typedef struct ocs_mgmt_sfp_result {
858 uint32_t page_data[32];
859 } ocs_mgmt_sfp_result_t;
862 ocs_mgmt_sfp_cb(void *os, int32_t status, uint32_t bytes_read, uint32_t *data, void *arg)
864 ocs_mgmt_sfp_result_t *result = arg;
867 ocs_lock(&(result->cb_lock));
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));
876 result->status = status;
877 result->bytes_read = bytes_read;
878 ocs_memcpy(&result->page_data, data, SFP_PAGE_SIZE);
880 ocs_sem_v(&(result->semaphore));
881 ocs_unlock(&(result->cb_lock));
885 ocs_mgmt_get_sfp(ocs_t *ocs, uint16_t page, void *buf, uint32_t buf_len)
888 ocs_mgmt_sfp_result_t *result = ocs_malloc(ocs, sizeof(ocs_mgmt_sfp_result_t), OCS_M_ZERO | OCS_M_NOWAIT);
890 ocs_sem_init(&(result->semaphore), 0, "get_sfp");
891 ocs_lock_init(ocs, &(result->cb_lock), "get_sfp");
893 /* Send the HW command */
894 ocs_hw_get_sfp(&ocs->hw, page, ocs_mgmt_sfp_cb, result);
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));
901 if(result->running == 1) {
902 ocs_log_err(ocs, "ocs_sem_p failed\n");
903 ocs_unlock(&(result->cb_lock));
906 /* sfp_cb() has already executed, proceed as normal */
907 ocs_unlock(&(result->cb_lock));
911 if (result->status != 0) {
912 ocs_log_test(ocs, "read_transceiver_data returned status %d\n",
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);
923 ocs_free(ocs, result, sizeof(ocs_mgmt_sfp_result_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)
930 ocs_assert(FALSE, 0);
934 get_nodes_count(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
936 ocs_xport_t *xport = ocs->xport;
938 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "nodes_count", "%d", xport->nodes_count);
942 get_driver_version(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
944 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "driver_version", ocs->driver_version);
948 get_desc(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
950 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "desc", ocs->desc);
954 get_fw_rev(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
956 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "fw_rev", ocs_hw_get_ptr(&ocs->hw, OCS_HW_FW_REV));
960 get_fw_rev2(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
962 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "fw_rev2", ocs_hw_get_ptr(&ocs->hw, OCS_HW_FW_REV2));
966 get_ipl(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
968 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "ipl", ocs_hw_get_ptr(&ocs->hw, OCS_HW_IPL));
972 get_hw_rev1(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
976 ocs_hw_get(&ocs->hw, OCS_HW_HW_REV1, &value);
978 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_rev1", "%u", value);
982 get_hw_rev2(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
986 ocs_hw_get(&ocs->hw, OCS_HW_HW_REV2, &value);
988 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_rev2", "%u", value);
992 get_hw_rev3(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
995 ocs_hw_get(&ocs->hw, OCS_HW_HW_REV3, &value);
997 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_rev3", "%u", value);
1001 get_wwnn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1005 wwnn = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_NODE);
1007 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwnn", "0x%llx", (unsigned long long)ocs_htobe64(*wwnn));
1011 get_wwpn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1015 wwpn = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_PORT);
1017 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwpn", "0x%llx", (unsigned long long)ocs_htobe64(*wwpn));
1021 get_fcid(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
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);
1028 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fc_id", "UNKNOWN");
1034 get_sn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1040 pserial = ocs_scsi_get_property_ptr(ocs, OCS_SCSI_SERIALNUMBER);
1043 strncpy(sn_buf, (char*)pserial, len);
1045 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sn", sn_buf);
1050 get_pn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1056 pserial = ocs_scsi_get_property_ptr(ocs, OCS_SCSI_PARTNUMBER);
1059 strncpy(sn_buf, (char*)pserial, len);
1061 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "pn", sn_buf);
1063 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "pn", ocs->model);
1068 get_sli4_intf_reg(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1071 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "sli4_intf_reg", "0x%04x",
1072 ocs_config_read32(ocs, SLI4_INTF_REG));
1076 get_phy_port_num(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1078 char *phy_port = NULL;
1080 phy_port = ocs_scsi_get_property_ptr(ocs, OCS_SCSI_PORTNUM);
1082 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "phy_port_num", phy_port);
1084 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "phy_port_num", "unknown");
1088 get_asic_id(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1091 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "asic_id_reg", "0x%04x",
1092 ocs_config_read32(ocs, SLI4_ASIC_ID_REG));
1096 get_chip_type(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1100 uint32_t asic_gen_num;
1101 uint32_t asic_rev_num;
1103 char result_buf[80];
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;
1111 rev_id = ocs_config_read32(ocs, SLI4_PCI_CLASS_REVISION) & 0xff;
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);
1122 ocs_strncpy(result_buf, "BE3", sizeof(result_buf));
1123 if (rev_id >= 0x10) {
1124 strcat(result_buf, "-R");
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);
1133 ocs_strncpy(result_buf, "Skyhawk A0", sizeof(result_buf));
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);
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);
1150 ocs_strncpy(result_buf, "Lancer G6", sizeof(result_buf));
1153 /* Refer to ASIC_ID */
1154 switch(asic_gen_num) {
1156 ocs_strncpy(result_buf, "BE2", sizeof(result_buf));
1159 ocs_strncpy(result_buf, "BE3-R", sizeof(result_buf));
1162 ocs_strncpy(result_buf, "Skyhawk-R", sizeof(result_buf));
1165 ocs_strncpy(result_buf, "Corsair", sizeof(result_buf));
1168 ocs_strncpy(result_buf, "Lancer", sizeof(result_buf));
1171 ocs_strncpy(result_buf, "LancerG6", sizeof(result_buf));
1174 ocs_strncpy(result_buf, "Unknown", sizeof(result_buf));
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);
1184 ocs_strncpy(result_buf, "Unknown", sizeof(result_buf));
1187 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "chip_type", result_buf);
1192 get_pci_vendor(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1195 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "pci_vendor", "0x%04x", ocs->pci_vendor);
1199 get_pci_device(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1202 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "pci_device", "0x%04x", ocs->pci_device);
1206 get_pci_subsystem_vendor(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1209 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "pci_subsystem_vendor", "0x%04x", ocs->pci_subsystem_vendor);
1213 get_pci_subsystem_device(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1216 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "pci_subsystem_device", "0x%04x", ocs->pci_subsystem_device);
1220 get_tgt_rscn_delay(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1222 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "tgt_rscn_delay", "%ld", (unsigned long)ocs->tgt_rscn_delay_msec / 1000);
1226 get_tgt_rscn_period(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1228 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "tgt_rscn_period", "%ld", (unsigned long)ocs->tgt_rscn_period_msec / 1000);
1232 get_inject_drop_cmd(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1234 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "inject_drop_cmd", "%d",
1235 (ocs->err_injection == INJECT_DROP_CMD ? 1:0));
1239 get_inject_free_drop_cmd(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1241 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "inject_free_drop_cmd", "%d",
1242 (ocs->err_injection == INJECT_FREE_DROPPED ? 1:0));
1246 get_inject_drop_data(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1248 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "inject_drop_data", "%d",
1249 (ocs->err_injection == INJECT_DROP_DATA ? 1:0));
1253 get_inject_drop_resp(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1255 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "inject_drop_resp", "%d",
1256 (ocs->err_injection == INJECT_DROP_RESP ? 1:0));
1260 get_cmd_err_inject(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1262 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "cmd_err_inject", "0x%02x", ocs->cmd_err_inject);
1266 get_cmd_delay_value(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1268 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "cmd_delay_value", "%ld", (unsigned long)ocs->delay_value_msec);
1272 get_businfo(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1274 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "businfo", ocs->businfo);
1278 get_sfp_a0(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1285 page_data = ocs_malloc(ocs, SFP_PAGE_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
1286 if (page_data == NULL) {
1290 buf = ocs_malloc(ocs, (SFP_PAGE_SIZE * 3) + 1, OCS_M_ZERO | OCS_M_NOWAIT);
1292 ocs_free(ocs, page_data, SFP_PAGE_SIZE);
1296 bytes_read = ocs_mgmt_get_sfp(ocs, 0xa0, page_data, SFP_PAGE_SIZE);
1298 if (bytes_read <= 0) {
1299 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sfp_a0", "(unknown)");
1302 uint8_t *s = page_data;
1303 int buffer_remaining = (SFP_PAGE_SIZE * 3) + 1;
1306 for (i = 0; i < bytes_read; i++) {
1307 bytes_added = ocs_snprintf(d, buffer_remaining, "%02x ", *s);
1310 buffer_remaining -= bytes_added;
1313 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sfp_a0", buf);
1316 ocs_free(ocs, page_data, SFP_PAGE_SIZE);
1317 ocs_free(ocs, buf, (3 * SFP_PAGE_SIZE) + 1);
1321 get_sfp_a2(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1328 page_data = ocs_malloc(ocs, SFP_PAGE_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
1329 if (page_data == NULL) {
1333 buf = ocs_malloc(ocs, (SFP_PAGE_SIZE * 3) + 1, OCS_M_ZERO | OCS_M_NOWAIT);
1335 ocs_free(ocs, page_data, SFP_PAGE_SIZE);
1339 bytes_read = ocs_mgmt_get_sfp(ocs, 0xa2, page_data, SFP_PAGE_SIZE);
1341 if (bytes_read <= 0) {
1342 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sfp_a2", "(unknown)");
1345 uint8_t *s = page_data;
1346 int buffer_remaining = (SFP_PAGE_SIZE * 3) + 1;
1349 for (i=0; i < bytes_read; i++) {
1350 bytes_added = ocs_snprintf(d, buffer_remaining, "%02x ", *s);
1353 buffer_remaining -= bytes_added;
1356 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sfp_a2", buf);
1359 ocs_free(ocs, page_data, SFP_PAGE_SIZE);
1360 ocs_free(ocs, buf, (3 * SFP_PAGE_SIZE) + 1);
1364 get_debug_mq_dump(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1367 ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RW, "debug_mq_dump",
1368 ocs_debug_is_enabled(OCS_DEBUG_ENABLE_MQ_DUMP));
1372 get_debug_cq_dump(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1375 ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RW, "debug_cq_dump",
1376 ocs_debug_is_enabled(OCS_DEBUG_ENABLE_CQ_DUMP));
1380 get_debug_wq_dump(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1382 ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RW, "debug_wq_dump",
1383 ocs_debug_is_enabled(OCS_DEBUG_ENABLE_WQ_DUMP));
1387 get_debug_eq_dump(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1389 ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RW, "debug_eq_dump",
1390 ocs_debug_is_enabled(OCS_DEBUG_ENABLE_EQ_DUMP));
1394 get_logmask(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1397 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "logmask", "0x%02x", ocs->logmask);
1402 get_loglevel(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1405 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "loglevel", "%d", loglevel);
1410 get_current_speed(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1414 ocs_hw_get(&(ocs->hw), OCS_HW_LINK_SPEED, &value);
1416 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "current_speed", "%d", value);
1420 get_configured_speed(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1424 ocs_hw_get(&(ocs->hw), OCS_HW_LINK_CONFIG_SPEED, &value);
1426 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "configured_speed", "auto");
1428 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "configured_speed", "%d", value);
1434 get_current_topology(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1438 ocs_hw_get(&(ocs->hw), OCS_HW_TOPOLOGY, &value);
1439 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "current_topology", "%d", value);
1444 get_configured_topology(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1448 ocs_hw_get(&(ocs->hw), OCS_HW_CONFIG_TOPOLOGY, &value);
1449 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "configured_topology", "%d", value);
1454 get_current_link_state(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1456 ocs_xport_stats_t value;
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");
1462 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "current_link_state", "offline");
1468 get_configured_link_state(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1470 ocs_xport_stats_t value;
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");
1476 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "configured_link_state", "offline");
1482 * @brief HW link config enum to mgmt string value mapping.
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
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;
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}};
1504 * @brief Get the HW linkcfg enum from the mgmt config string.
1506 * @param mgmt_str mgmt string value.
1508 * @return Returns the HW linkcfg enum corresponding to clp_str.
1510 static ocs_hw_linkcfg_e
1511 ocs_hw_linkcfg_from_mgmt(const char *mgmt_str)
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;
1520 return OCS_HW_LINKCFG_NA;
1524 * @brief Get the mgmt string value from the HW linkcfg enum.
1526 * @param linkcfg HW linkcfg enum.
1528 * @return Returns the mgmt string value corresponding to the given HW linkcfg.
1531 ocs_mgmt_from_hw_linkcfg(ocs_hw_linkcfg_e linkcfg)
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;
1539 return OCS_CONFIG_LINKCFG_UNKNOWN;
1543 * @brief Link configuration callback argument
1545 typedef struct ocs_mgmt_linkcfg_arg_s {
1546 ocs_sem_t semaphore;
1548 ocs_hw_linkcfg_e linkcfg;
1549 } ocs_mgmt_linkcfg_arg_t;
1552 * @brief Get linkcfg config value
1554 * @param ocs Pointer to the ocs structure.
1555 * @param name Not used.
1556 * @param textbuf The textbuf to which the result is written.
1561 get_linkcfg(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1563 const char *linkcfg_str = NULL;
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);
1573 * @brief Get requested WWNN config value
1575 * @param ocs Pointer to the ocs structure.
1576 * @param name Not used.
1577 * @param textbuf The textbuf to which the result is written.
1582 get_req_wwnn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1584 ocs_xport_t *xport = ocs->xport;
1586 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "requested_wwnn", "0x%llx", (unsigned long long)xport->req_wwnn);
1590 * @brief Get requested WWPN config value
1592 * @param ocs Pointer to the ocs structure.
1593 * @param name Not used.
1594 * @param textbuf The textbuf to which the result is written.
1599 get_req_wwpn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1601 ocs_xport_t *xport = ocs->xport;
1603 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "requested_wwpn", "0x%llx", (unsigned long long)xport->req_wwpn);
1607 * @brief Get requested nodedb_mask config value
1609 * @param ocs Pointer to the ocs structure.
1610 * @param name Not used.
1611 * @param textbuf The textbuf to which the result is written.
1616 get_nodedb_mask(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1618 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "nodedb_mask", "0x%08x", ocs->nodedb_mask);
1622 * @brief Set requested WWNN value.
1624 * @param ocs Pointer to the ocs structure.
1625 * @param name Not used.
1626 * @param value Value to which the linkcfg is set.
1628 * @return Returns 0 on success.
1632 set_req_wwnn(ocs_t *ocs, char *name, char *value)
1637 if (ocs_strcasecmp(value, "default") == 0) {
1640 else if (parse_wwn(value, &wwnn) != 0) {
1641 ocs_log_test(ocs, "Invalid WWNN: %s\n", value);
1645 rc = ocs_xport_control(ocs->xport, OCS_XPORT_WWNN_SET, wwnn);
1648 ocs_log_test(ocs, "OCS_XPORT_WWNN_SET failed: %d\n", rc);
1652 rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE);
1654 ocs_log_test(ocs, "port offline failed : %d\n", rc);
1657 rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE);
1659 ocs_log_test(ocs, "port online failed : %d\n", rc);
1666 * @brief Set requested WWNP value.
1668 * @param ocs Pointer to the ocs structure.
1669 * @param name Not used.
1670 * @param value Value to which the linkcfg is set.
1672 * @return Returns 0 on success.
1676 set_req_wwpn(ocs_t *ocs, char *name, char *value)
1681 if (ocs_strcasecmp(value, "default") == 0) {
1684 else if (parse_wwn(value, &wwpn) != 0) {
1685 ocs_log_test(ocs, "Invalid WWPN: %s\n", value);
1689 rc = ocs_xport_control(ocs->xport, OCS_XPORT_WWPN_SET, wwpn);
1692 ocs_log_test(ocs, "OCS_XPORT_WWPN_SET failed: %d\n", rc);
1696 rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE);
1698 ocs_log_test(ocs, "port offline failed : %d\n", rc);
1701 rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE);
1703 ocs_log_test(ocs, "port online failed : %d\n", rc);
1710 * @brief Set node debug mask value
1712 * @param ocs Pointer to the ocs structure.
1713 * @param name Not used.
1714 * @param value Value to which the nodedb_mask is set.
1716 * @return Returns 0 on success.
1719 set_nodedb_mask(ocs_t *ocs, char *name, char *value)
1721 ocs->nodedb_mask = ocs_strtoul(value, 0, 0);
1726 * @brief Set linkcfg config value.
1728 * @param ocs Pointer to the ocs structure.
1729 * @param name Not used.
1730 * @param value Value to which the linkcfg is set.
1732 * @return Returns 0 on success.
1735 set_linkcfg(ocs_t *ocs, char *name, char *value)
1737 ocs_hw_linkcfg_e linkcfg;
1738 ocs_mgmt_linkcfg_arg_t cb_arg;
1739 ocs_hw_rtn_e status;
1741 ocs_sem_init(&cb_arg.semaphore, 0, "mgmt_linkcfg");
1743 /* translate mgmt linkcfg string to HW linkcfg enum */
1744 linkcfg = ocs_hw_linkcfg_from_mgmt(value);
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);
1750 ocs_log_test(ocs, "ocs_hw_set_linkcfg failed\n");
1754 if (ocs_sem_p(&cb_arg.semaphore, OCS_SEM_FOREVER)) {
1755 ocs_log_err(ocs, "ocs_sem_p failed\n");
1759 if (cb_arg.status) {
1760 ocs_log_test(ocs, "failed to set linkcfg from HW status=%d\n",
1769 * @brief Linkcfg callback
1771 * @param status Result of the linkcfg get/set operation.
1772 * @param value Resulting linkcfg value.
1773 * @param arg Callback argument.
1778 ocs_mgmt_linkcfg_cb(int32_t status, uintptr_t value, void *arg)
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);
1787 set_debug_mq_dump(ocs_t *ocs, char *name, char *value)
1791 if (ocs_strcasecmp(value, "false") == 0) {
1792 ocs_debug_disable(OCS_DEBUG_ENABLE_MQ_DUMP);
1794 } else if (ocs_strcasecmp(value, "true") == 0) {
1795 ocs_debug_enable(OCS_DEBUG_ENABLE_MQ_DUMP);
1805 set_debug_cq_dump(ocs_t *ocs, char *name, char *value)
1809 if (ocs_strcasecmp(value, "false") == 0) {
1810 ocs_debug_disable(OCS_DEBUG_ENABLE_CQ_DUMP);
1812 } else if (ocs_strcasecmp(value, "true") == 0) {
1813 ocs_debug_enable(OCS_DEBUG_ENABLE_CQ_DUMP);
1823 set_debug_wq_dump(ocs_t *ocs, char *name, char *value)
1827 if (ocs_strcasecmp(value, "false") == 0) {
1828 ocs_debug_disable(OCS_DEBUG_ENABLE_WQ_DUMP);
1830 } else if (ocs_strcasecmp(value, "true") == 0) {
1831 ocs_debug_enable(OCS_DEBUG_ENABLE_WQ_DUMP);
1841 set_debug_eq_dump(ocs_t *ocs, char *name, char *value)
1845 if (ocs_strcasecmp(value, "false") == 0) {
1846 ocs_debug_disable(OCS_DEBUG_ENABLE_EQ_DUMP);
1848 } else if (ocs_strcasecmp(value, "true") == 0) {
1849 ocs_debug_enable(OCS_DEBUG_ENABLE_EQ_DUMP);
1859 set_logmask(ocs_t *ocs, char *name, char *value)
1862 ocs->logmask = ocs_strtoul(value, NULL, 0);
1868 set_loglevel(ocs_t *ocs, char *name, char *value)
1871 loglevel = ocs_strtoul(value, NULL, 0);
1877 set_configured_speed(ocs_t *ocs, char *name, char *value)
1884 spd = ocs_strtoul(value, NULL, 0);
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);
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");
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");
1905 /* If we failed to set the speed we still want to try to bring
1906 * the port back online */
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) {
1919 set_configured_topology(ocs_t *ocs, char *name, char *value)
1926 topo = ocs_strtoul(value, NULL, 0);
1927 if (topo >= OCS_HW_TOPOLOGY_NONE) {
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");
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");
1944 /* If we failed to set the topology we still want to try to bring
1945 * the port back online */
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) {
1958 set_configured_link_state(ocs_t *ocs, char *name, char *value)
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");
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");
1978 ocs_log_test(ocs, "Unsupported link state \"%s\"\n", value);
1985 typedef struct ocs_mgmt_get_port_protocol_result {
1986 ocs_sem_t semaphore;
1988 ocs_hw_port_protocol_e port_protocol;
1989 } ocs_mgmt_get_port_protocol_result_t;
1992 ocs_mgmt_get_port_protocol_cb(int32_t status,
1993 ocs_hw_port_protocol_e port_protocol,
1996 ocs_mgmt_get_port_protocol_result_t *result = arg;
1998 result->status = status;
1999 result->port_protocol = port_protocol;
2001 ocs_sem_v(&(result->semaphore));
2005 get_port_protocol(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
2007 ocs_mgmt_get_port_protocol_result_t result;
2012 ocs_sem_init(&(result.semaphore), 0, "get_port_protocol");
2014 ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
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");
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");
2026 case OCS_HW_PORT_PROTOCOL_FCOE:
2027 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "port_protocol", "FCoE");
2029 case OCS_HW_PORT_PROTOCOL_FC:
2030 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "port_protocol", "FC");
2032 case OCS_HW_PORT_PROTOCOL_OTHER:
2033 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "port_protocol", "Other");
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");
2043 typedef struct ocs_mgmt_set_port_protocol_result {
2044 ocs_sem_t semaphore;
2046 } ocs_mgmt_set_port_protocol_result_t;
2049 ocs_mgmt_set_port_protocol_cb(int32_t status,
2052 ocs_mgmt_get_port_protocol_result_t *result = arg;
2054 result->status = status;
2056 ocs_sem_v(&(result->semaphore));
2060 * @brief Set port protocol
2062 * This is a management action handler to set the current
2063 * port protocol. Input value should be one of iSCSI,
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
2070 * @return Returns 0 on success, non-zero on failure.
2073 set_port_protocol(ocs_t *ocs, char *name, char *value)
2075 ocs_mgmt_set_port_protocol_result_t result;
2077 ocs_hw_port_protocol_e new_protocol;
2082 ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
2084 ocs_sem_init(&(result.semaphore), 0, "set_port_protocol");
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;
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");
2104 if (result.status == 0) {
2109 ocs_log_test(ocs, "setting active profile status 0x%x\n",
2117 typedef struct ocs_mgmt_get_profile_list_result_s {
2118 ocs_sem_t semaphore;
2120 ocs_hw_profile_list_t *list;
2121 } ocs_mgmt_get_profile_list_result_t;
2124 ocs_mgmt_get_profile_list_cb(int32_t status, ocs_hw_profile_list_t *list, void *ul_arg)
2126 ocs_mgmt_get_profile_list_result_t *result = ul_arg;
2128 result->status = status;
2129 result->list = list;
2131 ocs_sem_v(&(result->semaphore));
2135 * @brief Get list of profiles
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.
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.
2149 get_profile_list(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
2151 ocs_mgmt_get_profile_list_result_t result;
2153 ocs_sem_init(&(result.semaphore), 0, "get_profile_list");
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");
2160 if (result.status == 0) {
2162 #define MAX_LINE_SIZE 520
2163 #define BUFFER_SIZE MAX_LINE_SIZE*40
2165 char result_line[MAX_LINE_SIZE];
2166 uint32_t bytes_left;
2169 result_buf = ocs_malloc(ocs, BUFFER_SIZE, OCS_M_ZERO);
2170 bytes_left = BUFFER_SIZE;
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);
2181 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "profile_list", result_buf);
2183 ocs_free(ocs, result_buf, BUFFER_SIZE);
2184 ocs_free(ocs, result.list, sizeof(ocs_hw_profile_list_t));
2186 ocs_log_test(ocs, "getting profile list status 0x%x\n", result.status);
2191 typedef struct ocs_mgmt_get_active_profile_result {
2192 ocs_sem_t semaphore;
2194 uint32_t active_profile_id;
2195 } ocs_mgmt_get_active_profile_result_t;
2198 ocs_mgmt_get_active_profile_cb(int32_t status, uint32_t active_profile, void *ul_arg)
2200 ocs_mgmt_get_active_profile_result_t *result = ul_arg;
2202 result->status = status;
2203 result->active_profile_id = active_profile;
2205 ocs_sem_v(&(result->semaphore));
2208 #define MAX_PROFILE_LENGTH 5
2211 * @brief Get active profile
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.
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.
2225 get_active_profile(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
2227 char result_string[MAX_PROFILE_LENGTH];
2228 ocs_mgmt_get_active_profile_result_t result;
2230 ocs_sem_init(&(result.semaphore), 0, "get_active_profile");
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");
2237 if (result.status == 0) {
2239 sprintf(result_string, "0x%02x", result.active_profile_id);
2240 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "active_profile", result_string);
2242 ocs_log_test(ocs, "getting active profile status 0x%x\n", result.status);
2247 typedef struct ocs_mgmt_set_active_profile_result {
2248 ocs_sem_t semaphore;
2250 } ocs_mgmt_set_active_profile_result_t;
2253 ocs_mgmt_set_active_profile_cb(int32_t status, void *ul_arg)
2255 ocs_mgmt_get_profile_list_result_t *result = ul_arg;
2257 result->status = status;
2259 ocs_sem_v(&(result->semaphore));
2263 * @brief Set active profile
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.
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.
2274 * @return Returns 0 on success, non-zero on failure.
2277 set_active_profile(ocs_t *ocs, char *name, char *value)
2279 ocs_mgmt_set_active_profile_result_t result;
2281 int32_t new_profile;
2283 new_profile = ocs_strtoul(value, NULL, 0);
2285 ocs_sem_init(&(result.semaphore), 0, "set_active_profile");
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");
2294 if (result.status == 0) {
2299 ocs_log_test(ocs, "setting active profile status 0x%x\n", result.status);
2306 typedef struct ocs_mgmt_get_nvparms_result {
2307 ocs_sem_t semaphore;
2312 uint32_t preferred_d_id;
2313 } ocs_mgmt_get_nvparms_result_t;
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)
2319 ocs_mgmt_get_nvparms_result_t *result = ul_arg;
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;
2327 ocs_sem_v(&(result->semaphore));
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.
2342 get_nv_wwpn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
2344 char result_string[24];
2345 ocs_mgmt_get_nvparms_result_t result;
2347 ocs_sem_init(&(result.semaphore), 0, "get_nv_wwpn");
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");
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);
2363 ocs_log_test(ocs, "getting wwpn status 0x%x\n", result.status);
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.
2380 get_nv_wwnn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
2382 char result_string[24];
2383 ocs_mgmt_get_nvparms_result_t result;
2385 ocs_sem_init(&(result.semaphore), 0, "get_nv_wwnn");
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");
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);
2401 ocs_log_test(ocs, "getting wwnn status 0x%x\n", result.status);
2407 * @brief Get accumulated node abort counts
2408 * @par Description Get the sum of all nodes abort count.
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.
2417 get_node_abort_cnt(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
2419 uint32_t abort_counts = 0;
2420 ocs_domain_t *domain;
2424 if (ocs_device_lock_try(ocs) != TRUE) {
2425 /* Didn't get the lock */
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);
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);
2446 /* Here the sport lock is held */
2447 ocs_list_foreach(&sport->node_list, node) {
2448 abort_counts += node->abort_cnt;
2451 ocs_sport_unlock(sport);
2454 ocs_domain_unlock(domain);
2457 ocs_device_unlock(ocs);
2459 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "node_abort_cnt", "%d" , abort_counts);
2462 typedef struct ocs_mgmt_set_nvparms_result {
2463 ocs_sem_t semaphore;
2465 } ocs_mgmt_set_nvparms_result_t;
2468 ocs_mgmt_set_nvparms_cb(int32_t status, void *ul_arg)
2470 ocs_mgmt_get_profile_list_result_t *result = ul_arg;
2472 result->status = status;
2474 ocs_sem_v(&(result->semaphore));
2479 * @par Description Sets the Non-volatile worldwide names,
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.
2486 * @return Returns 0 on success, non-zero on failure.
2489 set_nv_wwn(ocs_t *ocs, char *name, char *wwn_p)
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;
2501 /* This is a read-modify-write operation, so first we have to read
2502 * the current values
2504 ocs_sem_init(&(result.semaphore), 0, "set_nv_wwn1");
2506 rc = ocs_hw_get_nvparms(&ocs->hw, ocs_mgmt_get_nvparms_cb, &result);
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");
2514 if (result.status != 0) {
2515 ocs_log_test(ocs, "getting nvparms status 0x%x\n", result.status);
2520 /* wwn_p contains wwpn_p@wwnn_p values */
2521 if (wwn_p != NULL) {
2522 wwpn_p = ocs_strsep(&wwn_p, "@");
2526 if (wwpn_p != NULL) {
2527 wwpn = ocs_strcmp(wwpn_p, "NA");
2530 if (wwnn_p != NULL) {
2531 wwnn = ocs_strcmp(wwnn_p, "NA");
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);
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);
2556 for (i = 0; i < 8; i++) {
2557 /* Use active wwpn, if new one is not provided */
2559 new_wwpn[i] = result.wwpn[i];
2562 /* Use active wwnn, if new one is not provided */
2564 new_wwnn[i] = result.wwnn[i];
2568 /* Modify the nv_wwnn and nv_wwpn, then write it back */
2569 ocs_sem_init(&(result.semaphore), 0, "set_nv_wwn2");
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,
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");
2580 if (result.status != 0) {
2581 ocs_log_test(ocs, "setting wwn status 0x%x\n", result.status);
2590 set_tgt_rscn_delay(ocs_t *ocs, char *name, char *value)
2592 ocs->tgt_rscn_delay_msec = ocs_strtoul(value, NULL, 0) * 1000;
2593 ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value);
2598 set_tgt_rscn_period(ocs_t *ocs, char *name, char *value)
2600 ocs->tgt_rscn_period_msec = ocs_strtoul(value, NULL, 0) * 1000;
2601 ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value);
2606 set_inject_drop_cmd(ocs_t *ocs, char *name, char *value)
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);
2614 set_inject_free_drop_cmd(ocs_t *ocs, char *name, char *value)
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);
2622 set_inject_drop_data(ocs_t *ocs, char *name, char *value)
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);
2630 set_inject_drop_resp(ocs_t *ocs, char *name, char *value)
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);
2638 set_cmd_err_inject(ocs_t *ocs, char *name, char *value)
2640 ocs->cmd_err_inject = ocs_strtoul(value, NULL, 0);
2641 ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value);
2646 set_cmd_delay_value(ocs_t *ocs, char *name, char *value)
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);
2655 * @brief parse a WWN from a string into a 64-bit value
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
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
2663 * @return 0 if successful, non-zero if the WWN is malformed and couldn't be parsed
2666 parse_wwn(char *wwn_in, uint64_t *wwn_out)
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);
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) |
2698 static char *mode_string(int mode);
2702 * @brief Generate the beginning of a numbered section in a management XML document.
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.
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.
2717 extern void ocs_mgmt_start_section(ocs_textbuf_t *textbuf, const char *name, int index)
2719 ocs_textbuf_printf(textbuf, "<%s instance=\"%d\">\n", name, index);
2724 * @brief Generate the beginning of an unnumbered section in a management XML document.
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.
2731 * @param textbuf Pointer to the driver dump text buffer.
2732 * @param name Name of the section.
2737 extern void ocs_mgmt_start_unnumbered_section(ocs_textbuf_t *textbuf, const char *name)
2739 ocs_textbuf_printf(textbuf, "<%s>\n", name);
2744 * @brief Generate the end of a section in a management XML document.
2747 * This function ends a section. The XML information is appended to
2750 * @param textbuf Pointer to the driver dump text buffer.
2751 * @param name Name of the section.
2756 void ocs_mgmt_end_unnumbered_section(ocs_textbuf_t *textbuf, const char *name)
2758 ocs_textbuf_printf(textbuf, "</%s>\n", name);
2763 * @brief Generate the indexed end of a section in a management XML document.
2766 * This function ends a section. The XML information is appended to
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.
2776 void ocs_mgmt_end_section(ocs_textbuf_t *textbuf, const char *name, int index)
2779 ocs_textbuf_printf(textbuf, "</%s>\n", name);
2785 * @brief Generate a property, with no value, in a management XML document.
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.
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.
2799 void ocs_mgmt_emit_property_name(ocs_textbuf_t *textbuf, int mode, const char *name)
2801 ocs_textbuf_printf(textbuf, "<%s mode=\"%s\"/>\n", name, mode_string(mode));
2806 * @brief Generate a property with a string value in a management XML document.
2809 * This function generates a property name and a string value.
2810 * The XML information is appended to the textbuf.
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.
2820 void ocs_mgmt_emit_string(ocs_textbuf_t *textbuf, int mode, const char *name, const char *value)
2822 ocs_textbuf_printf(textbuf, "<%s mode=\"%s\">%s</%s>\n", name, mode_string(mode), value, name);
2827 * @brief Generate a property with an integer value in a management XML document.
2830 * This function generates a property name and an integer value.
2831 * The XML information is appended to the textbuf.
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.
2841 void ocs_mgmt_emit_int(ocs_textbuf_t *textbuf, int mode, const char *name, const char *fmt, ...)
2847 ocs_vsnprintf(valuebuf, sizeof(valuebuf), fmt, ap);
2850 ocs_textbuf_printf(textbuf, "<%s mode=\"%s\">%s</%s>\n", name, mode_string(mode), valuebuf, name);
2855 * @brief Generate a property with a boolean value in a management XML document.
2858 * This function generates a property name and a boolean value.
2859 * The XML information is appended to the textbuf.
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.
2869 void ocs_mgmt_emit_boolean(ocs_textbuf_t *textbuf, int mode, const char *name, int value)
2871 char *valuebuf = value ? "true" : "false";
2873 ocs_textbuf_printf(textbuf, "<%s mode=\"%s\">%s</%s>\n", name, mode_string(mode), valuebuf, name);
2876 static char *mode_string(int mode)
2878 static char mode_str[4];
2881 if (mode & MGMT_MODE_RD) {
2882 strcat(mode_str, "r");
2884 if (mode & MGMT_MODE_WR) {
2885 strcat(mode_str, "w");
2887 if (mode & MGMT_MODE_EX) {
2888 strcat(mode_str, "x");