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