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