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