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