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