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