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