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