1331766Sken/*-
2331766Sken * Copyright (c) 2017 Broadcom. All rights reserved.
3331766Sken * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4331766Sken *
5331766Sken * Redistribution and use in source and binary forms, with or without
6331766Sken * modification, are permitted provided that the following conditions are met:
7331766Sken *
8331766Sken * 1. Redistributions of source code must retain the above copyright notice,
9331766Sken *    this list of conditions and the following disclaimer.
10331766Sken *
11331766Sken * 2. Redistributions in binary form must reproduce the above copyright notice,
12331766Sken *    this list of conditions and the following disclaimer in the documentation
13331766Sken *    and/or other materials provided with the distribution.
14331766Sken *
15331766Sken * 3. Neither the name of the copyright holder nor the names of its contributors
16331766Sken *    may be used to endorse or promote products derived from this software
17331766Sken *    without specific prior written permission.
18331766Sken *
19331766Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20331766Sken * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21331766Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22331766Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23331766Sken * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24331766Sken * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25331766Sken * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26331766Sken * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27331766Sken * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28331766Sken * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29331766Sken * POSSIBILITY OF SUCH DAMAGE.
30331766Sken *
31331766Sken * $FreeBSD: stable/11/sys/dev/ocs_fc/ocs_mgmt.c 343371 2019-01-24 01:04:23Z markj $
32331766Sken */
33331766Sken
34331766Sken/**
35331766Sken * @file
36331766Sken * The ocs_mgmt top level functions for Fibre Channel.
37331766Sken */
38331766Sken
39331766Sken/**
40331766Sken * @defgroup mgmt Management Functions
41331766Sken */
42331766Sken
43331766Sken#include "ocs.h"
44331766Sken#include "ocs_mgmt.h"
45331766Sken#include "ocs_vpd.h"
46331766Sken
47331766Sken#define SFP_PAGE_SIZE 128
48331766Sken
49331766Sken/* Executables*/
50331766Sken
51331766Skenstatic int ocs_mgmt_firmware_write(ocs_t *ocs, char *, void *buf, uint32_t buf_len, void*, uint32_t);
52331766Skenstatic int ocs_mgmt_firmware_reset(ocs_t *ocs, char *, void *buf, uint32_t buf_len, void*, uint32_t);
53331766Skenstatic int ocs_mgmt_function_reset(ocs_t *ocs, char *, void *buf, uint32_t buf_len, void*, uint32_t);
54331766Sken
55331766Skenstatic void ocs_mgmt_fw_write_cb(int32_t status, uint32_t actual_write_length, uint32_t change_status, void *arg);
56331766Skenstatic int ocs_mgmt_force_assert(ocs_t *ocs, char *, void *buf, uint32_t buf_len, void*, uint32_t);
57331766Sken
58331766Sken#if defined(OCS_INCLUDE_RAMD)
59331766Skenstatic int32_t
60331766Skenocs_mgmt_read_phys(ocs_t *ocs, char *, void *, uint32_t , void *, uint32_t);
61331766Sken#endif
62331766Sken
63331766Sken
64331766Sken/* Getters */
65331766Sken
66331766Skenstatic void get_nodes_count(ocs_t *, char *, ocs_textbuf_t*);
67331766Skenstatic void get_desc(ocs_t *, char *, ocs_textbuf_t*);
68331766Skenstatic void get_fw_rev(ocs_t *, char *, ocs_textbuf_t*);
69331766Skenstatic void get_fw_rev2(ocs_t *, char *, ocs_textbuf_t*);
70331766Skenstatic void get_ipl(ocs_t *, char *, ocs_textbuf_t*);
71331766Skenstatic void get_wwnn(ocs_t *, char *, ocs_textbuf_t*);
72331766Skenstatic void get_wwpn(ocs_t *, char *, ocs_textbuf_t*);
73331766Skenstatic void get_fcid(ocs_t *, char *, ocs_textbuf_t *);
74331766Skenstatic void get_sn(ocs_t *, char *, ocs_textbuf_t*);
75331766Skenstatic void get_pn(ocs_t *, char *, ocs_textbuf_t*);
76331766Skenstatic void get_sli4_intf_reg(ocs_t *, char *, ocs_textbuf_t*);
77331766Skenstatic void get_phy_port_num(ocs_t *, char *, ocs_textbuf_t*);
78331766Skenstatic void get_asic_id(ocs_t *, char *, ocs_textbuf_t*);
79331766Skenstatic void get_pci_vendor(ocs_t *, char *, ocs_textbuf_t*);
80331766Skenstatic void get_pci_device(ocs_t *, char *, ocs_textbuf_t*);
81331766Skenstatic void get_pci_subsystem_vendor(ocs_t *, char *, ocs_textbuf_t*);
82331766Skenstatic void get_pci_subsystem_device(ocs_t *, char *, ocs_textbuf_t*);
83331766Skenstatic void get_businfo(ocs_t *, char *, ocs_textbuf_t*);
84331766Skenstatic void get_sfp_a0(ocs_t *, char *, ocs_textbuf_t*);
85331766Skenstatic void get_sfp_a2(ocs_t *, char *, ocs_textbuf_t*);
86331766Skenstatic void get_hw_rev1(ocs_t *, char *, ocs_textbuf_t*);
87331766Skenstatic void get_hw_rev2(ocs_t *, char *, ocs_textbuf_t*);
88331766Skenstatic void get_hw_rev3(ocs_t *, char *, ocs_textbuf_t*);
89331766Skenstatic void get_debug_mq_dump(ocs_t*, char*, ocs_textbuf_t*);
90331766Skenstatic void get_debug_cq_dump(ocs_t*, char*, ocs_textbuf_t*);
91331766Skenstatic void get_debug_wq_dump(ocs_t*, char*, ocs_textbuf_t*);
92331766Skenstatic void get_debug_eq_dump(ocs_t*, char*, ocs_textbuf_t*);
93331766Skenstatic void get_logmask(ocs_t*, char*, ocs_textbuf_t*);
94331766Skenstatic void get_current_speed(ocs_t*, char*, ocs_textbuf_t*);
95331766Skenstatic void get_current_topology(ocs_t*, char*, ocs_textbuf_t*);
96331766Skenstatic void get_current_link_state(ocs_t*, char*, ocs_textbuf_t*);
97331766Skenstatic void get_configured_speed(ocs_t*, char*, ocs_textbuf_t*);
98331766Skenstatic void get_configured_topology(ocs_t*, char*, ocs_textbuf_t*);
99331766Skenstatic void get_configured_link_state(ocs_t*, char*, ocs_textbuf_t*);
100331766Skenstatic void get_linkcfg(ocs_t*, char*, ocs_textbuf_t*);
101331766Skenstatic void get_req_wwnn(ocs_t*, char*, ocs_textbuf_t*);
102331766Skenstatic void get_req_wwpn(ocs_t*, char*, ocs_textbuf_t*);
103331766Skenstatic void get_nodedb_mask(ocs_t*, char*, ocs_textbuf_t*);
104331766Skenstatic void get_profile_list(ocs_t*, char*, ocs_textbuf_t*);
105331766Skenstatic void get_active_profile(ocs_t*, char*, ocs_textbuf_t*);
106331766Skenstatic void get_port_protocol(ocs_t*, char*, ocs_textbuf_t*);
107331766Skenstatic void get_driver_version(ocs_t*, char*, ocs_textbuf_t*);
108331766Skenstatic void get_chip_type(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf);
109331766Skenstatic void get_tgt_rscn_delay(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf);
110331766Skenstatic void get_tgt_rscn_period(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf);
111331766Skenstatic void get_inject_drop_cmd(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf);
112331766Skenstatic void get_inject_free_drop_cmd(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf);
113331766Skenstatic void get_inject_drop_data(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf);
114331766Skenstatic void get_inject_drop_resp(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf);
115331766Skenstatic void get_cmd_err_inject(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf);
116331766Skenstatic void get_cmd_delay_value(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf);
117331766Skenstatic void get_nv_wwpn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf);
118331766Skenstatic void get_nv_wwnn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf);
119331766Skenstatic void get_loglevel(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf);
120331766Skenstatic void get_node_abort_cnt(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf);
121331766Sken
122331766Sken/* Setters */
123331766Skenstatic int set_debug_mq_dump(ocs_t*, char*, char*);
124331766Skenstatic int set_debug_cq_dump(ocs_t*, char*, char*);
125331766Skenstatic int set_debug_wq_dump(ocs_t*, char*, char*);
126331766Skenstatic int set_debug_eq_dump(ocs_t*, char*, char*);
127331766Skenstatic int set_logmask(ocs_t*, char*, char*);
128331766Skenstatic int set_configured_link_state(ocs_t*, char*, char*);
129331766Skenstatic int set_linkcfg(ocs_t*, char*, char*);
130331766Skenstatic int set_nodedb_mask(ocs_t*, char*, char*);
131331766Skenstatic int set_port_protocol(ocs_t*, char*, char*);
132331766Skenstatic int set_active_profile(ocs_t*, char*, char*);
133331766Skenstatic int set_tgt_rscn_delay(ocs_t*, char*, char*);
134331766Skenstatic int set_tgt_rscn_period(ocs_t*, char*, char*);
135331766Skenstatic int set_inject_drop_cmd(ocs_t*, char*, char*);
136331766Skenstatic int set_inject_free_drop_cmd(ocs_t*, char*, char*);
137331766Skenstatic int set_inject_drop_data(ocs_t*, char*, char*);
138331766Skenstatic int set_inject_drop_resp(ocs_t*, char*, char*);
139331766Skenstatic int set_cmd_err_inject(ocs_t*, char*, char*);
140331766Skenstatic int set_cmd_delay_value(ocs_t*, char*, char*);
141331766Skenstatic int set_nv_wwn(ocs_t*, char*, char*);
142331766Skenstatic int set_loglevel(ocs_t*, char*, char*);
143331766Sken
144331766Skenstatic void ocs_mgmt_linkcfg_cb(int32_t status, uintptr_t value, void *arg);
145331766Sken#if defined(OCS_INCLUDE_RAMD)
146331766Skenstatic void* find_address_in_target(ocs_ramdisc_t **ramdisc_array, uint32_t ramdisc_count, uintptr_t target_addr);
147331766Sken#endif
148331766Sken
149331766Skenocs_mgmt_table_entry_t mgmt_table[] = {
150331766Sken		{"nodes_count", get_nodes_count, NULL, NULL},
151331766Sken		{"desc", get_desc, NULL, NULL},
152331766Sken		{"fw_rev", get_fw_rev, NULL, NULL},
153331766Sken		{"fw_rev2", get_fw_rev2, NULL, NULL},
154331766Sken		{"ipl", get_ipl, NULL, NULL},
155331766Sken		{"hw_rev1", get_hw_rev1, NULL, NULL},
156331766Sken		{"hw_rev2", get_hw_rev2, NULL, NULL},
157331766Sken		{"hw_rev3", get_hw_rev3, NULL, NULL},
158331766Sken		{"wwnn", get_wwnn, NULL, NULL},
159331766Sken		{"wwpn", get_wwpn, NULL, NULL},
160331766Sken		{"fc_id", get_fcid, NULL, NULL},
161331766Sken		{"sn", get_sn, NULL, NULL},
162331766Sken		{"pn", get_pn, NULL, NULL},
163331766Sken		{"sli4_intf_reg", get_sli4_intf_reg, NULL, NULL},
164331766Sken		{"phy_port_num", get_phy_port_num, NULL, NULL},
165331766Sken		{"asic_id_reg", get_asic_id, NULL, NULL},
166331766Sken		{"pci_vendor", get_pci_vendor, NULL, NULL},
167331766Sken		{"pci_device", get_pci_device, NULL, NULL},
168331766Sken		{"pci_subsystem_vendor", get_pci_subsystem_vendor, NULL, NULL},
169331766Sken		{"pci_subsystem_device", get_pci_subsystem_device, NULL, NULL},
170331766Sken		{"businfo", get_businfo, NULL, NULL},
171331766Sken		{"sfp_a0", get_sfp_a0, NULL, NULL},
172331766Sken		{"sfp_a2", get_sfp_a2, NULL, NULL},
173331766Sken		{"profile_list", get_profile_list, NULL, NULL},
174331766Sken		{"driver_version", get_driver_version, NULL, NULL},
175331766Sken		{"current_speed", get_current_speed, NULL, NULL},
176331766Sken		{"current_topology", get_current_topology, NULL, NULL},
177331766Sken		{"current_link_state", get_current_link_state, NULL, NULL},
178331766Sken		{"chip_type", get_chip_type, NULL, NULL},
179331766Sken		{"configured_speed", get_configured_speed, set_configured_speed, NULL},
180331766Sken		{"configured_topology", get_configured_topology, set_configured_topology, NULL},
181331766Sken		{"configured_link_state", get_configured_link_state, set_configured_link_state, NULL},
182331766Sken		{"debug_mq_dump", get_debug_mq_dump, set_debug_mq_dump, NULL},
183331766Sken		{"debug_cq_dump", get_debug_cq_dump, set_debug_cq_dump, NULL},
184331766Sken		{"debug_wq_dump", get_debug_wq_dump, set_debug_wq_dump, NULL},
185331766Sken		{"debug_eq_dump", get_debug_eq_dump, set_debug_eq_dump, NULL},
186331766Sken		{"logmask", get_logmask, set_logmask, NULL},
187331766Sken		{"loglevel", get_loglevel, set_loglevel, NULL},
188331766Sken		{"linkcfg", get_linkcfg, set_linkcfg, NULL},
189331766Sken		{"requested_wwnn", get_req_wwnn, set_req_wwnn, NULL},
190331766Sken		{"requested_wwpn", get_req_wwpn, set_req_wwpn, NULL},
191331766Sken		{"nodedb_mask", get_nodedb_mask, set_nodedb_mask, NULL},
192331766Sken		{"port_protocol", get_port_protocol, set_port_protocol, NULL},
193331766Sken		{"active_profile", get_active_profile, set_active_profile, NULL},
194331766Sken		{"firmware_write", NULL, NULL, ocs_mgmt_firmware_write},
195331766Sken		{"firmware_reset", NULL, NULL, ocs_mgmt_firmware_reset},
196331766Sken		{"function_reset", NULL, NULL, ocs_mgmt_function_reset},
197331766Sken#if defined(OCS_INCLUDE_RAMD)
198331766Sken		{"read_phys", NULL, NULL, ocs_mgmt_read_phys},
199331766Sken#endif
200331766Sken		{"force_assert", NULL, NULL, ocs_mgmt_force_assert},
201331766Sken
202331766Sken		{"tgt_rscn_delay", get_tgt_rscn_delay, set_tgt_rscn_delay, NULL},
203331766Sken		{"tgt_rscn_period", get_tgt_rscn_period, set_tgt_rscn_period, NULL},
204331766Sken		{"inject_drop_cmd", get_inject_drop_cmd, set_inject_drop_cmd, NULL},
205331766Sken		{"inject_free_drop_cmd", get_inject_free_drop_cmd, set_inject_free_drop_cmd, NULL},
206331766Sken		{"inject_drop_data", get_inject_drop_data, set_inject_drop_data, NULL},
207331766Sken		{"inject_drop_resp", get_inject_drop_resp, set_inject_drop_resp, NULL},
208331766Sken		{"cmd_err_inject", get_cmd_err_inject, set_cmd_err_inject, NULL},
209331766Sken		{"cmd_delay_value", get_cmd_delay_value, set_cmd_delay_value, NULL},
210331766Sken		{"nv_wwpn", get_nv_wwpn, NULL, NULL},
211331766Sken		{"nv_wwnn", get_nv_wwnn, NULL, NULL},
212331766Sken		{"nv_wwn", NULL, set_nv_wwn, NULL},
213331766Sken		{"node_abort_cnt", get_node_abort_cnt, NULL, NULL},
214331766Sken};
215331766Sken
216331766Sken/**
217331766Sken * @ingroup mgmt
218331766Sken * @brief Get a list of options supported by the driver.
219331766Sken *
220331766Sken * @par Description
221331766Sken * This is the top level "get list" handler for the driver. It
222331766Sken * performs the following:
223331766Sken *  - Adds entries to the textbuf for any actions supported by this level in the driver.
224331766Sken *  - Calls a back-end function to add any actions supported by the back-end.
225331766Sken *  - Calls a function on each child (domain) to recursively add supported actions.
226331766Sken *
227331766Sken * @param ocs Pointer to the ocs structure.
228331766Sken * @param textbuf Pointer to an ocs_textbuf, which is used to accumulate the results.
229331766Sken *
230331766Sken * @return Returns 0 on success, or a negative value on failure.
231331766Sken */
232331766Sken
233331766Skenvoid
234331766Skenocs_mgmt_get_list(ocs_t *ocs, ocs_textbuf_t *textbuf)
235331766Sken{
236331766Sken	ocs_domain_t *domain;
237331766Sken	uint32_t i;
238331766Sken	int access;
239331766Sken
240331766Sken	ocs_mgmt_start_unnumbered_section(textbuf, "ocs");
241331766Sken
242331766Sken	for (i=0;i<ARRAY_SIZE(mgmt_table);i++) {
243331766Sken		access = 0;
244331766Sken		if (mgmt_table[i].get_handler) {
245331766Sken			access |= MGMT_MODE_RD;
246331766Sken		}
247331766Sken		if (mgmt_table[i].set_handler) {
248331766Sken			access |= MGMT_MODE_WR;
249331766Sken		}
250331766Sken		if (mgmt_table[i].action_handler) {
251331766Sken			access |= MGMT_MODE_EX;
252331766Sken		}
253331766Sken		ocs_mgmt_emit_property_name(textbuf, access, mgmt_table[i].name);
254331766Sken	}
255331766Sken
256331766Sken	if ((ocs->mgmt_functions) && (ocs->mgmt_functions->get_list_handler)) {
257331766Sken		ocs->mgmt_functions->get_list_handler(textbuf, ocs);
258331766Sken	}
259331766Sken
260331766Sken	if ((ocs->tgt_mgmt_functions) && (ocs->tgt_mgmt_functions->get_list_handler)) {
261331766Sken		ocs->tgt_mgmt_functions->get_list_handler(textbuf, &(ocs->tgt_ocs));
262331766Sken	}
263331766Sken
264331766Sken	/* Have each of my children add their actions */
265331766Sken	if (ocs_device_lock_try(ocs) == TRUE) {
266331766Sken
267331766Sken		/* If we get here then we are holding the device lock */
268331766Sken		ocs_list_foreach(&ocs->domain_list, domain) {
269331766Sken			if ((domain->mgmt_functions) && (domain->mgmt_functions->get_list_handler)) {
270331766Sken				domain->mgmt_functions->get_list_handler(textbuf, domain);
271331766Sken			}
272331766Sken		}
273331766Sken		ocs_device_unlock(ocs);
274331766Sken	}
275331766Sken
276331766Sken	ocs_mgmt_end_unnumbered_section(textbuf, "ocs");
277331766Sken
278331766Sken}
279331766Sken
280331766Sken/**
281331766Sken * @ingroup mgmt
282331766Sken * @brief Return the value of a management item.
283331766Sken *
284331766Sken * @par Description
285331766Sken * This is the top level "get" handler for the driver. It
286331766Sken * performs the following:
287331766Sken *  - Checks that the qualifier portion of the name begins with my qualifier (ocs).
288331766Sken *  - If the remaining part of the name matches a parameter that is known at this level,
289331766Sken *    writes the value into textbuf.
290331766Sken *  - If the name is not known, sends the request to the back-ends to fulfill (if possible).
291331766Sken *  - If the request has not been fulfilled by the back-end,
292331766Sken *    passes the request to each of the children (domains) to
293331766Sken *    have them (recursively) try to respond.
294331766Sken *
295331766Sken *  In passing the request to other entities, the request is considered to be answered
296331766Sken *  when a response has been written into textbuf, indicated by textbuf->buffer_written
297331766Sken *  being non-zero.
298331766Sken *
299331766Sken * @param ocs Pointer to the ocs structure.
300331766Sken * @param name Name of the status item to be retrieved.
301331766Sken * @param textbuf Pointer to an ocs_textbuf, which is used to return the results.
302331766Sken *
303331766Sken * @return Returns 0 if the value was found and returned, or -1 if an error occurred.
304331766Sken */
305331766Sken
306331766Sken
307331766Skenint
308331766Skenocs_mgmt_get(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
309331766Sken{
310331766Sken	ocs_domain_t *domain;
311331766Sken	char qualifier[6];
312331766Sken	int retval = -1;
313331766Sken	uint32_t i;
314331766Sken
315331766Sken	ocs_mgmt_start_unnumbered_section(textbuf, "ocs");
316331766Sken
317331766Sken
318331766Sken	snprintf(qualifier, sizeof(qualifier), "/ocs");
319331766Sken
320331766Sken	/* See if the name starts with my qualifier.  If not then this request isn't for me */
321331766Sken	if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
322331766Sken		char *unqualified_name = name + strlen(qualifier) + 1;
323331766Sken
324331766Sken		for (i=0;i<ARRAY_SIZE(mgmt_table);i++) {
325331766Sken			if (ocs_strcmp(unqualified_name, mgmt_table[i].name) == 0) {
326331766Sken				if (mgmt_table[i].get_handler) {
327331766Sken					mgmt_table[i].get_handler(ocs, name, textbuf);
328331766Sken					ocs_mgmt_end_unnumbered_section(textbuf, "ocs");
329331766Sken					return 0;
330331766Sken				}
331331766Sken			}
332331766Sken		}
333331766Sken
334331766Sken		if ((ocs->mgmt_functions) && (ocs->mgmt_functions->get_handler)) {
335331766Sken			retval = ocs->mgmt_functions->get_handler(textbuf, qualifier, (char*)name, ocs);
336331766Sken		}
337331766Sken
338331766Sken		if (retval != 0) {
339331766Sken			if ((ocs->tgt_mgmt_functions) && (ocs->tgt_mgmt_functions->get_handler)) {
340331766Sken				retval = ocs->tgt_mgmt_functions->get_handler(textbuf, qualifier,
341331766Sken						(char*)name, &(ocs->tgt_ocs));
342331766Sken			}
343331766Sken		}
344331766Sken
345331766Sken		if (retval != 0) {
346331766Sken			/* The driver didn't handle it, pass it to each domain */
347331766Sken
348331766Sken			ocs_device_lock(ocs);
349331766Sken			ocs_list_foreach(&ocs->domain_list, domain) {
350331766Sken				if ((domain->mgmt_functions) && (domain->mgmt_functions->get_handler)) {
351331766Sken					retval = domain->mgmt_functions->get_handler(textbuf, qualifier, (char*)name, domain);
352331766Sken				}
353331766Sken
354331766Sken				if (retval ==  0) {
355331766Sken					break;
356331766Sken				}
357331766Sken
358331766Sken
359331766Sken			}
360331766Sken			ocs_device_unlock(ocs);
361331766Sken		}
362331766Sken
363331766Sken	}
364331766Sken
365331766Sken	ocs_mgmt_end_unnumbered_section(textbuf, "ocs");
366331766Sken
367331766Sken	return retval;
368331766Sken}
369331766Sken
370331766Sken
371331766Sken/**
372331766Sken * @ingroup mgmt
373331766Sken * @brief Set the value of a mgmt item.
374331766Sken *
375331766Sken * @par Description
376331766Sken * This is the top level "set" handler for the driver. It
377331766Sken * performs the following:
378331766Sken *  - Checks that the qualifier portion of the name begins with my qualifier (ocs).
379331766Sken *  - If the remaining part of the name matches a parameter that is known at this level,
380331766Sken *    calls the correct function to change the configuration.
381331766Sken *  - If the name is not known, sends the request to the back-ends to fulfill (if possible).
382331766Sken *  - If the request has not been fulfilled by the back-end, passes the request to each of the
383331766Sken *    children (domains) to have them (recursively) try to respond.
384331766Sken *
385331766Sken *  In passing the request to other entities, the request is considered to be handled
386331766Sken *  if the function returns 0.
387331766Sken *
388331766Sken * @param ocs Pointer to the ocs structure.
389331766Sken * @param name Name of the property to be changed.
390331766Sken * @param value Requested new value of the property.
391331766Sken *
392331766Sken * @return Returns 0 if the configuration value was updated, or -1 otherwise.
393331766Sken */
394331766Sken
395331766Skenint
396331766Skenocs_mgmt_set(ocs_t *ocs, char *name, char *value)
397331766Sken{
398331766Sken	ocs_domain_t *domain;
399331766Sken	int result = -1;
400331766Sken	char qualifier[80];
401331766Sken	uint32_t i;
402331766Sken
403331766Sken	snprintf(qualifier, sizeof(qualifier), "/ocs");
404331766Sken
405331766Sken	/* If it doesn't start with my qualifier I don't know what to do with it */
406331766Sken	if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
407331766Sken		char *unqualified_name = name + strlen(qualifier) +1;
408331766Sken
409331766Sken		/* See if it's a value I can set */
410331766Sken		for (i=0;i<ARRAY_SIZE(mgmt_table);i++) {
411331766Sken			if (ocs_strcmp(unqualified_name, mgmt_table[i].name) == 0) {
412331766Sken				if (mgmt_table[i].set_handler) {
413331766Sken					return mgmt_table[i].set_handler(ocs, name, value);
414331766Sken				}
415331766Sken			}
416331766Sken		}
417331766Sken
418331766Sken		if ((ocs->mgmt_functions) && (ocs->mgmt_functions->set_handler)) {
419331766Sken			result = ocs->mgmt_functions->set_handler(qualifier, name, (char *)value, ocs);
420331766Sken		}
421331766Sken
422331766Sken		if (result != 0) {
423331766Sken			if ((ocs->tgt_mgmt_functions) && (ocs->tgt_mgmt_functions->set_handler)) {
424331766Sken				result = ocs->tgt_mgmt_functions->set_handler(qualifier, name,
425331766Sken						(char *)value, &(ocs->tgt_ocs));
426331766Sken			}
427331766Sken		}
428331766Sken
429331766Sken		/* If I didn't know how to set this config value pass the request to each of my children */
430331766Sken		if (result != 0) {
431331766Sken			ocs_device_lock(ocs);
432331766Sken			ocs_list_foreach(&ocs->domain_list, domain) {
433331766Sken				if ((domain->mgmt_functions) && (domain->mgmt_functions->set_handler)) {
434331766Sken					result = domain->mgmt_functions->set_handler(qualifier, name, (char*)value, domain);
435331766Sken				}
436331766Sken				if (result == 0) {
437331766Sken					break;
438331766Sken				}
439331766Sken			}
440331766Sken			ocs_device_unlock(ocs);
441331766Sken		}
442331766Sken
443331766Sken
444331766Sken	}
445331766Sken
446331766Sken	return result;
447331766Sken}
448331766Sken
449331766Sken/**
450331766Sken * @ingroup mgmt
451331766Sken * @brief Perform a management action.
452331766Sken *
453331766Sken * @par Description
454331766Sken * This is the top level "exec" handler for the driver. It
455331766Sken * performs the following:
456331766Sken *  - Checks that the qualifier portion of the name begins with my qualifier (ocs).
457331766Sken *  - If the remaining part of the name matches an action that is known at this level,
458331766Sken *    calls the correct function to perform the action.
459331766Sken *  - If the name is not known, sends the request to the back-ends to fulfill (if possible).
460331766Sken *  - If the request has not been fulfilled by the back-end, passes the request to each of the
461331766Sken *    children (domains) to have them (recursively) try to respond.
462331766Sken *
463331766Sken *  In passing the request to other entities, the request is considered to be handled
464331766Sken *  if the function returns 0.
465331766Sken *
466331766Sken * @param ocs Pointer to the ocs structure.
467331766Sken * @param action Name of the action to be performed.
468331766Sken * @param arg_in Pointer to an argument being passed to the action.
469331766Sken * @param arg_in_length Length of the argument pointed to by @c arg_in.
470331766Sken * @param arg_out Pointer to an argument being passed to the action.
471331766Sken * @param arg_out_length Length of the argument pointed to by @c arg_out.
472331766Sken *
473331766Sken * @return Returns 0 if the action was completed, or -1 otherwise.
474331766Sken *
475331766Sken *
476331766Sken */
477331766Sken
478331766Skenint
479331766Skenocs_mgmt_exec(ocs_t *ocs, char *action, void *arg_in,
480331766Sken		uint32_t arg_in_length, void *arg_out, uint32_t arg_out_length)
481331766Sken{
482331766Sken	ocs_domain_t *domain;
483331766Sken	int result = -1;
484331766Sken	char qualifier[80];
485331766Sken	uint32_t i;
486331766Sken
487331766Sken	snprintf(qualifier, sizeof(qualifier), "/ocs");
488331766Sken
489331766Sken	/* If it doesn't start with my qualifier I don't know what to do with it */
490331766Sken	if (ocs_strncmp(action, qualifier, strlen(qualifier)) == 0) {
491331766Sken		char *unqualified_name = action + strlen(qualifier) +1;
492331766Sken
493331766Sken		/* See if it's an action I can perform */
494331766Sken		for (i=0;i<ARRAY_SIZE(mgmt_table); i++) {
495331766Sken			if (ocs_strcmp(unqualified_name, mgmt_table[i].name) == 0) {
496331766Sken				if (mgmt_table[i].action_handler) {
497331766Sken					return mgmt_table[i].action_handler(ocs, action, arg_in, arg_in_length,
498331766Sken							arg_out, arg_out_length);
499331766Sken				}
500331766Sken
501331766Sken			}
502331766Sken		}
503331766Sken
504331766Sken		if ((ocs->mgmt_functions) && (ocs->mgmt_functions->exec_handler)) {
505331766Sken			result = ocs->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length,
506331766Sken								   arg_out, arg_out_length, ocs);
507331766Sken		}
508331766Sken
509331766Sken		if (result != 0) {
510331766Sken			if ((ocs->tgt_mgmt_functions) && (ocs->tgt_mgmt_functions->exec_handler)) {
511331766Sken				result = ocs->tgt_mgmt_functions->exec_handler(qualifier, action,
512331766Sken						arg_in, arg_in_length, arg_out, arg_out_length,
513331766Sken						&(ocs->tgt_ocs));
514331766Sken			}
515331766Sken		}
516331766Sken
517331766Sken		/* If I didn't know how to do this action pass the request to each of my children */
518331766Sken		if (result != 0) {
519331766Sken			ocs_device_lock(ocs);
520331766Sken			ocs_list_foreach(&ocs->domain_list, domain) {
521331766Sken				if ((domain->mgmt_functions) && (domain->mgmt_functions->exec_handler)) {
522331766Sken					result = domain->mgmt_functions->exec_handler(qualifier, action, arg_in, arg_in_length, arg_out,
523331766Sken							arg_out_length, domain);
524331766Sken				}
525331766Sken				if (result == 0) {
526331766Sken					break;
527331766Sken				}
528331766Sken			}
529331766Sken			ocs_device_unlock(ocs);
530331766Sken		}
531331766Sken
532331766Sken	}
533331766Sken
534331766Sken	return result;
535331766Sken}
536331766Sken
537331766Skenvoid
538331766Skenocs_mgmt_get_all(ocs_t *ocs, ocs_textbuf_t *textbuf)
539331766Sken{
540331766Sken	ocs_domain_t *domain;
541331766Sken	uint32_t i;
542331766Sken
543331766Sken	ocs_mgmt_start_unnumbered_section(textbuf, "ocs");
544331766Sken
545331766Sken	for (i=0;i<ARRAY_SIZE(mgmt_table);i++) {
546331766Sken		if (mgmt_table[i].get_handler) {
547331766Sken			mgmt_table[i].get_handler(ocs, mgmt_table[i].name, textbuf);
548331766Sken		} else if (mgmt_table[i].action_handler) {
549331766Sken			/* No get_handler, but there's an action_handler. Just report
550331766Sken			   the name */
551331766Sken			ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_EX, mgmt_table[i].name);
552331766Sken		}
553331766Sken	}
554331766Sken
555331766Sken	if ((ocs->mgmt_functions) && (ocs->mgmt_functions->get_all_handler)) {
556331766Sken		ocs->mgmt_functions->get_all_handler(textbuf, ocs);
557331766Sken	}
558331766Sken
559331766Sken	if ((ocs->tgt_mgmt_functions) && (ocs->tgt_mgmt_functions->get_all_handler)) {
560331766Sken		ocs->tgt_mgmt_functions->get_all_handler(textbuf, &(ocs->tgt_ocs));
561331766Sken	}
562331766Sken
563331766Sken	ocs_device_lock(ocs);
564331766Sken	ocs_list_foreach(&ocs->domain_list, domain) {
565331766Sken		if ((domain->mgmt_functions) && (domain->mgmt_functions->get_all_handler)) {
566331766Sken			domain->mgmt_functions->get_all_handler(textbuf, domain);
567331766Sken		}
568331766Sken	}
569331766Sken	ocs_device_unlock(ocs);
570331766Sken
571331766Sken	ocs_mgmt_end_unnumbered_section(textbuf, "ocs");
572331766Sken}
573331766Sken
574331766Sken#if defined(OCS_INCLUDE_RAMD)
575331766Skenstatic int32_t
576331766Skenocs_mgmt_read_phys(ocs_t *ocs, char *name, void *arg_in, uint32_t arg_in_length, void *arg_out, uint32_t arg_out_length)
577331766Sken{
578331766Sken        uint32_t length;
579331766Sken        char addr_str[80];
580331766Sken        uintptr_t target_addr;
581331766Sken        void* vaddr = NULL;
582331766Sken        ocs_ramdisc_t **ramdisc_array;
583331766Sken        uint32_t ramdisc_count;
584331766Sken
585331766Sken
586331766Sken        if ((arg_in == NULL) ||
587331766Sken            (arg_in_length == 0) ||
588331766Sken            (arg_out == NULL) ||
589331766Sken            (arg_out_length == 0)) {
590331766Sken                return -1;
591331766Sken        }
592331766Sken
593331766Sken        if (arg_in_length > 80) {
594331766Sken                arg_in_length = 80;
595331766Sken        }
596331766Sken
597331766Sken        if (ocs_copy_from_user(addr_str, arg_in, arg_in_length)) {
598331766Sken                ocs_log_test(ocs, "Failed to copy addr from user\n");
599331766Sken                return -EFAULT;
600331766Sken        }
601331766Sken
602331766Sken        target_addr = (uintptr_t)ocs_strtoul(addr_str, NULL, 0);
603331766Sken        /* addr_str must be the physical address of a buffer that was reported
604331766Sken         * in an SGL.  Search ramdiscs looking for a segment that contains that
605331766Sken         * physical address
606331766Sken         */
607331766Sken
608331766Sken        if (ocs->tgt_ocs.use_global_ramd) {
609331766Sken                /* Only one target */
610331766Sken                ramdisc_count = ocs->tgt_ocs.rdisc_count;
611331766Sken                ramdisc_array = ocs->tgt_ocs.rdisc;
612331766Sken                vaddr = find_address_in_target(ramdisc_array, ramdisc_count, target_addr);
613331766Sken        } else {
614331766Sken                /* Multiple targets.  Each target is on a sport */
615331766Sken		uint32_t domain_idx;
616331766Sken
617331766Sken		for (domain_idx=0; domain_idx<ocs->domain_instance_count; domain_idx++) {
618331766Sken			ocs_domain_t *domain;
619331766Sken			uint32_t sport_idx;
620331766Sken
621331766Sken			domain = ocs_domain_get_instance(ocs, domain_idx);
622331766Sken			for (sport_idx=0; sport_idx < domain->sport_instance_count; sport_idx++) {
623331766Sken				ocs_sport_t *sport;
624331766Sken
625331766Sken				sport = ocs_sport_get_instance(domain, sport_idx);
626331766Sken				ramdisc_count = sport->tgt_sport.rdisc_count;
627331766Sken				ramdisc_array = sport->tgt_sport.rdisc;
628331766Sken				vaddr = find_address_in_target(ramdisc_array, ramdisc_count, target_addr);
629331766Sken
630331766Sken				if (vaddr != NULL) {
631331766Sken					break;
632331766Sken				}
633331766Sken			}
634331766Sken                }
635331766Sken        }
636331766Sken
637331766Sken
638331766Sken
639331766Sken
640331766Sken        length = arg_out_length;
641331766Sken
642331766Sken        if (vaddr != NULL) {
643331766Sken
644331766Sken                if (ocs_copy_to_user(arg_out, vaddr, length)) {
645331766Sken                        ocs_log_test(ocs, "Failed to copy buffer to user\n");
646331766Sken                        return -EFAULT;
647331766Sken                }
648331766Sken
649331766Sken                return 0;
650331766Sken        } else {
651331766Sken
652331766Sken                return -EFAULT;
653331766Sken	}
654331766Sken
655331766Sken}
656331766Sken
657331766Sken/*
658331766Sken * This function searches a target for a given physical address.
659331766Sken * The target is made up of a number of LUNs, each represented by
660331766Sken * a ocs_ramdisc_t.
661331766Sken */
662331766Skenstatic void* find_address_in_target(ocs_ramdisc_t **ramdisc_array, uint32_t ramdisc_count, uintptr_t target_addr)
663331766Sken{
664331766Sken	void *vaddr = NULL;
665331766Sken	uint32_t ramdisc_idx;
666331766Sken
667331766Sken	/* Check each ramdisc */
668331766Sken	for (ramdisc_idx=0; ramdisc_idx<ramdisc_count; ramdisc_idx++) {
669331766Sken		uint32_t segment_idx;
670331766Sken		ocs_ramdisc_t *rdisc;
671331766Sken		rdisc = ramdisc_array[ramdisc_idx];
672331766Sken		/* Check each segment in the ramdisc */
673331766Sken		for (segment_idx=0; segment_idx<rdisc->segment_count; segment_idx++) {
674331766Sken			ramdisc_segment_t *segment = rdisc->segments[segment_idx];
675331766Sken			uintptr_t segment_start;
676331766Sken			uintptr_t segment_end;
677331766Sken			uint32_t offset;
678331766Sken
679331766Sken			segment_start = segment->data_segment.phys;
680331766Sken			segment_end = segment->data_segment.phys + segment->data_segment.size - 1;
681331766Sken			if ((target_addr >= segment_start) && (target_addr <= segment_end)) {
682331766Sken				/* Found the target address */
683331766Sken				offset = target_addr - segment_start;
684331766Sken				vaddr = (uint32_t*)segment->data_segment.virt + offset;
685331766Sken			}
686331766Sken
687331766Sken			if (rdisc->dif_separate) {
688331766Sken				segment_start = segment->dif_segment.phys;
689331766Sken				segment_end = segment->data_segment.phys + segment->dif_segment.size - 1;
690331766Sken				if ((target_addr >= segment_start) && (target_addr <= segment_end)) {
691331766Sken					/* Found the target address */
692331766Sken					offset = target_addr - segment_start;
693331766Sken					vaddr = (uint32_t*)segment->dif_segment.virt + offset;
694331766Sken				}
695331766Sken			}
696331766Sken
697331766Sken			if (vaddr != NULL) {
698331766Sken				break;
699331766Sken			}
700331766Sken
701331766Sken		}
702331766Sken
703331766Sken		if (vaddr != NULL) {
704331766Sken			break;
705331766Sken		}
706331766Sken
707331766Sken
708331766Sken	}
709331766Sken
710331766Sken	return vaddr;
711331766Sken}
712331766Sken#endif
713331766Sken
714331766Sken
715331766Sken
716331766Skenstatic int32_t
717331766Skenocs_mgmt_firmware_reset(ocs_t *ocs, char *name, void *buf, uint32_t buf_len, void *arg_out, uint32_t arg_out_length)
718331766Sken{
719331766Sken	int rc = 0;
720331766Sken	int index = 0;
721331766Sken	uint8_t bus, dev, func;
722331766Sken	ocs_t *other_ocs;
723331766Sken
724331766Sken	ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
725331766Sken
726331766Sken	ocs_log_debug(ocs, "Resetting port\n");
727331766Sken	if (ocs_hw_reset(&ocs->hw, OCS_HW_RESET_FIRMWARE)) {
728331766Sken		ocs_log_test(ocs, "failed to reset port\n");
729331766Sken		rc = -1;
730331766Sken	} else {
731331766Sken		ocs_log_debug(ocs, "successfully reset port\n");
732331766Sken
733331766Sken		/* now reset all functions on the same device */
734331766Sken
735331766Sken		while ((other_ocs = ocs_get_instance(index++)) != NULL) {
736331766Sken			uint8_t other_bus, other_dev, other_func;
737331766Sken
738331766Sken			ocs_get_bus_dev_func(other_ocs, &other_bus, &other_dev, &other_func);
739331766Sken
740331766Sken			if ((bus == other_bus) && (dev == other_dev)) {
741331766Sken				if (other_ocs->hw.state !=
742331766Sken                                      OCS_HW_STATE_UNINITIALIZED) {
743331766Sken                                        other_ocs->hw.state =
744331766Sken                                                OCS_HW_STATE_QUEUES_ALLOCATED;
745331766Sken                                }
746331766Sken
747331766Sken				ocs_device_detach(other_ocs);
748331766Sken				if (ocs_device_attach(other_ocs)) {
749331766Sken					ocs_log_err(other_ocs,
750331766Sken						"device %d attach failed \n", index);
751331766Sken					rc = -1;
752331766Sken				}
753331766Sken			}
754331766Sken		}
755331766Sken	}
756331766Sken	return rc;
757331766Sken}
758331766Sken
759331766Skenstatic int32_t
760331766Skenocs_mgmt_function_reset(ocs_t *ocs, char *name, void *buf, uint32_t buf_len, void *arg_out, uint32_t arg_out_length)
761331766Sken{
762331766Sken	int32_t rc;
763331766Sken
764331766Sken	ocs_device_detach(ocs);
765331766Sken	rc = ocs_device_attach(ocs);
766331766Sken
767331766Sken	return rc;
768331766Sken}
769331766Sken
770331766Skenstatic int32_t
771331766Skenocs_mgmt_firmware_write(ocs_t *ocs, char *name, void *buf, uint32_t buf_len, void *arg_out, uint32_t arg_out_length)
772331766Sken{
773331766Sken	int rc = 0;
774331766Sken	uint32_t bytes_left;
775331766Sken	uint32_t xfer_size;
776331766Sken	uint32_t offset;
777331766Sken	uint8_t *userp;
778331766Sken	ocs_dma_t dma;
779331766Sken	int last = 0;
780331766Sken	ocs_mgmt_fw_write_result_t result;
781331766Sken	uint32_t change_status = 0;
782331766Sken        char status_str[80];
783331766Sken
784331766Sken	ocs_sem_init(&(result.semaphore), 0, "fw_write");
785331766Sken
786331766Sken	bytes_left = buf_len;
787331766Sken	offset = 0;
788331766Sken	userp = (uint8_t *)buf;
789331766Sken
790331766Sken	if (ocs_dma_alloc(ocs, &dma, FW_WRITE_BUFSIZE, 4096)) {
791331766Sken		ocs_log_err(ocs, "ocs_mgmt_firmware_write: malloc failed");
792331766Sken		return -ENOMEM;
793331766Sken	}
794331766Sken
795331766Sken	while (bytes_left > 0) {
796331766Sken
797331766Sken
798331766Sken		if (bytes_left > FW_WRITE_BUFSIZE) {
799331766Sken			xfer_size = FW_WRITE_BUFSIZE;
800331766Sken		} else {
801331766Sken			xfer_size = bytes_left;
802331766Sken		}
803331766Sken
804331766Sken		/* Copy xfer_size bytes from user space to kernel buffer */
805331766Sken		if (ocs_copy_from_user(dma.virt, userp, xfer_size)) {
806331766Sken			rc = -EFAULT;
807331766Sken			break;
808331766Sken		}
809331766Sken
810331766Sken		/* See if this is the last block */
811331766Sken		if (bytes_left == xfer_size) {
812331766Sken			last = 1;
813331766Sken		}
814331766Sken
815331766Sken		/* Send the HW command */
816331766Sken		ocs_hw_firmware_write(&ocs->hw, &dma, xfer_size, offset, last, ocs_mgmt_fw_write_cb, &result);
817331766Sken
818331766Sken		/* Wait for semaphore to be signaled when the command completes
819331766Sken		 * TODO:  Should there be a timeout on this?  If so, how long? */
820331766Sken		if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) {
821331766Sken			ocs_log_err(ocs, "ocs_sem_p failed\n");
822331766Sken			rc = -ENXIO;
823331766Sken			break;
824331766Sken		}
825331766Sken
826331766Sken		if (result.actual_xfer == 0) {
827331766Sken			ocs_log_test(ocs, "actual_write_length is %d\n", result.actual_xfer);
828331766Sken			rc = -EFAULT;
829331766Sken			break;
830331766Sken		}
831331766Sken
832331766Sken		/* Check status */
833331766Sken		if (result.status != 0) {
834331766Sken			ocs_log_test(ocs, "write returned status %d\n", result.status);
835331766Sken			rc = -EFAULT;
836331766Sken			break;
837331766Sken		}
838331766Sken
839331766Sken		if (last) {
840331766Sken			change_status = result.change_status;
841331766Sken		}
842331766Sken
843331766Sken		bytes_left -= result.actual_xfer;
844331766Sken		offset += result.actual_xfer;
845331766Sken		userp += result.actual_xfer;
846331766Sken
847331766Sken	}
848331766Sken
849331766Sken	/* Create string with status and copy to userland */
850331766Sken	if ((arg_out_length > 0) && (arg_out != NULL)) {
851331766Sken		if (arg_out_length > sizeof(status_str)) {
852331766Sken			arg_out_length = sizeof(status_str);
853331766Sken		}
854343371Smarkj		ocs_memset(status_str, 0, sizeof(status_str));
855331766Sken		ocs_snprintf(status_str, arg_out_length, "%d", change_status);
856331766Sken		if (ocs_copy_to_user(arg_out, status_str, arg_out_length)) {
857331766Sken			ocs_log_test(ocs, "copy to user failed for change_status\n");
858331766Sken		}
859331766Sken	}
860331766Sken
861331766Sken
862331766Sken	ocs_dma_free(ocs, &dma);
863331766Sken
864331766Sken	return rc;
865331766Sken}
866331766Sken
867331766Skenstatic void
868331766Skenocs_mgmt_fw_write_cb(int32_t status, uint32_t actual_write_length, uint32_t change_status, void *arg)
869331766Sken{
870331766Sken	ocs_mgmt_fw_write_result_t *result = arg;
871331766Sken
872331766Sken	result->status = status;
873331766Sken	result->actual_xfer = actual_write_length;
874331766Sken	result->change_status = change_status;
875331766Sken
876331766Sken	ocs_sem_v(&(result->semaphore));
877331766Sken}
878331766Sken
879331766Skentypedef struct ocs_mgmt_sfp_result {
880331766Sken	ocs_sem_t semaphore;
881331766Sken	ocs_lock_t cb_lock;
882331766Sken	int32_t running;
883331766Sken	int32_t status;
884331766Sken	uint32_t bytes_read;
885331766Sken	uint32_t page_data[32];
886331766Sken} ocs_mgmt_sfp_result_t;
887331766Sken
888331766Skenstatic void
889331766Skenocs_mgmt_sfp_cb(void *os, int32_t status, uint32_t bytes_read, uint32_t *data, void *arg)
890331766Sken{
891331766Sken	ocs_mgmt_sfp_result_t *result = arg;
892331766Sken	ocs_t *ocs = os;
893331766Sken
894331766Sken	ocs_lock(&(result->cb_lock));
895331766Sken	result->running++;
896331766Sken	if(result->running == 2) {
897331766Sken		/* get_sfp() has timed out */
898331766Sken		ocs_unlock(&(result->cb_lock));
899331766Sken		ocs_free(ocs, result, sizeof(ocs_mgmt_sfp_result_t));
900331766Sken		return;
901331766Sken	}
902331766Sken
903331766Sken	result->status = status;
904331766Sken	result->bytes_read = bytes_read;
905331766Sken	ocs_memcpy(&result->page_data, data, SFP_PAGE_SIZE);
906331766Sken
907331766Sken	ocs_sem_v(&(result->semaphore));
908331766Sken	ocs_unlock(&(result->cb_lock));
909331766Sken}
910331766Sken
911331766Skenstatic int32_t
912331766Skenocs_mgmt_get_sfp(ocs_t *ocs, uint16_t page, void *buf, uint32_t buf_len)
913331766Sken{
914331766Sken	int rc = 0;
915331766Sken	ocs_mgmt_sfp_result_t *result = ocs_malloc(ocs, sizeof(ocs_mgmt_sfp_result_t),  OCS_M_ZERO | OCS_M_NOWAIT);;
916331766Sken
917331766Sken	ocs_sem_init(&(result->semaphore), 0, "get_sfp");
918331766Sken	ocs_lock_init(ocs, &(result->cb_lock), "get_sfp");
919331766Sken
920331766Sken	/* Send the HW command */
921331766Sken	ocs_hw_get_sfp(&ocs->hw, page, ocs_mgmt_sfp_cb, result);
922331766Sken
923331766Sken	/* Wait for semaphore to be signaled when the command completes */
924331766Sken	if (ocs_sem_p(&(result->semaphore), 5 * 1000 * 1000) != 0) {
925331766Sken		/* Timed out, callback will free memory */
926331766Sken		ocs_lock(&(result->cb_lock));
927331766Sken		result->running++;
928331766Sken		if(result->running == 1) {
929331766Sken			ocs_log_err(ocs, "ocs_sem_p failed\n");
930331766Sken			ocs_unlock(&(result->cb_lock));
931331766Sken			return (-ENXIO);
932331766Sken		}
933331766Sken		/* sfp_cb() has already executed, proceed as normal */
934331766Sken		ocs_unlock(&(result->cb_lock));
935331766Sken	}
936331766Sken
937331766Sken	/* Check status */
938331766Sken	if (result->status != 0) {
939331766Sken		ocs_log_test(ocs, "read_transceiver_data returned status %d\n",
940331766Sken			     result->status);
941331766Sken		rc = -EFAULT;
942331766Sken	}
943331766Sken
944331766Sken	if (rc == 0) {
945331766Sken		rc = (result->bytes_read > buf_len ? buf_len : result->bytes_read);
946331766Sken		/* Copy the results back to the supplied buffer */
947331766Sken		ocs_memcpy(buf, result->page_data, rc);
948331766Sken	}
949331766Sken
950331766Sken	ocs_free(ocs, result, sizeof(ocs_mgmt_sfp_result_t));
951331766Sken	return rc;
952331766Sken}
953331766Sken
954331766Skenstatic int32_t
955331766Skenocs_mgmt_force_assert(ocs_t *ocs, char *name, void *buf, uint32_t buf_len, void *arg_out, uint32_t arg_out_length)
956331766Sken{
957331766Sken	ocs_assert(FALSE, 0);
958331766Sken}
959331766Sken
960331766Skenstatic void
961331766Skenget_nodes_count(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
962331766Sken{
963331766Sken	ocs_xport_t *xport = ocs->xport;
964331766Sken
965331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "nodes_count", "%d", xport->nodes_count);
966331766Sken}
967331766Sken
968331766Skenstatic void
969331766Skenget_driver_version(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
970331766Sken{
971331766Sken	ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "driver_version", ocs->driver_version);
972331766Sken}
973331766Sken
974331766Skenstatic void
975331766Skenget_desc(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
976331766Sken{
977331766Sken	ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "desc", ocs->desc);
978331766Sken}
979331766Sken
980331766Skenstatic void
981331766Skenget_fw_rev(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
982331766Sken{
983331766Sken	ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "fw_rev", ocs_hw_get_ptr(&ocs->hw, OCS_HW_FW_REV));
984331766Sken}
985331766Sken
986331766Skenstatic void
987331766Skenget_fw_rev2(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
988331766Sken{
989331766Sken	ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "fw_rev2", ocs_hw_get_ptr(&ocs->hw, OCS_HW_FW_REV2));
990331766Sken}
991331766Sken
992331766Skenstatic void
993331766Skenget_ipl(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
994331766Sken{
995331766Sken	ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "ipl", ocs_hw_get_ptr(&ocs->hw, OCS_HW_IPL));
996331766Sken}
997331766Sken
998331766Skenstatic void
999331766Skenget_hw_rev1(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1000331766Sken{
1001331766Sken	uint32_t value;
1002331766Sken
1003331766Sken	ocs_hw_get(&ocs->hw, OCS_HW_HW_REV1, &value);
1004331766Sken
1005331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_rev1", "%u", value);
1006331766Sken}
1007331766Sken
1008331766Skenstatic void
1009331766Skenget_hw_rev2(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1010331766Sken{
1011331766Sken	uint32_t value;
1012331766Sken
1013331766Sken	ocs_hw_get(&ocs->hw, OCS_HW_HW_REV2, &value);
1014331766Sken
1015331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_rev2", "%u", value);
1016331766Sken}
1017331766Sken
1018331766Skenstatic void
1019331766Skenget_hw_rev3(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1020331766Sken{
1021331766Sken	uint32_t value;
1022331766Sken	ocs_hw_get(&ocs->hw, OCS_HW_HW_REV3, &value);
1023331766Sken
1024331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_rev3", "%u", value);
1025331766Sken}
1026331766Sken
1027331766Skenstatic void
1028331766Skenget_wwnn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1029331766Sken{
1030331766Sken	uint64_t *wwnn;
1031331766Sken
1032331766Sken	wwnn = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_NODE);
1033331766Sken
1034331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwnn", "0x%llx", (unsigned long long)ocs_htobe64(*wwnn));
1035331766Sken}
1036331766Sken
1037331766Skenstatic void
1038331766Skenget_wwpn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1039331766Sken{
1040331766Sken	uint64_t *wwpn;
1041331766Sken
1042331766Sken	wwpn = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_PORT);
1043331766Sken
1044331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "wwpn", "0x%llx", (unsigned long long)ocs_htobe64(*wwpn));
1045331766Sken}
1046331766Sken
1047331766Skenstatic void
1048331766Skenget_fcid(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1049331766Sken{
1050331766Sken
1051331766Sken	if (ocs->domain && ocs->domain->attached) {
1052331766Sken		ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fc_id", "0x%06x",
1053331766Sken						ocs->domain->sport->fc_id);
1054331766Sken	} else {
1055331766Sken		ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "fc_id", "UNKNOWN");
1056331766Sken	}
1057331766Sken
1058331766Sken}
1059331766Sken
1060331766Skenstatic void
1061331766Skenget_sn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1062331766Sken{
1063331766Sken	uint8_t *pserial;
1064331766Sken	uint32_t len;
1065331766Sken	char sn_buf[256];
1066331766Sken
1067331766Sken	pserial = ocs_scsi_get_property_ptr(ocs, OCS_SCSI_SERIALNUMBER);
1068331766Sken	if (pserial) {
1069331766Sken		len = *pserial ++;
1070331766Sken		strncpy(sn_buf, (char*)pserial, len);
1071331766Sken		sn_buf[len] = '\0';
1072331766Sken		ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sn", sn_buf);
1073331766Sken	}
1074331766Sken}
1075331766Sken
1076331766Skenstatic void
1077331766Skenget_pn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1078331766Sken{
1079331766Sken	uint8_t *pserial;
1080331766Sken	uint32_t len;
1081331766Sken	char sn_buf[256];
1082331766Sken
1083331766Sken	pserial = ocs_scsi_get_property_ptr(ocs, OCS_SCSI_PARTNUMBER);
1084331766Sken	if (pserial) {
1085331766Sken		len = *pserial ++;
1086331766Sken		strncpy(sn_buf, (char*)pserial, len);
1087331766Sken		sn_buf[len] = '\0';
1088331766Sken		ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "pn", sn_buf);
1089331766Sken	} else {
1090331766Sken		ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "pn", ocs->model);
1091331766Sken	}
1092331766Sken}
1093331766Sken
1094331766Skenstatic void
1095331766Skenget_sli4_intf_reg(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1096331766Sken{
1097331766Sken
1098331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "sli4_intf_reg", "0x%04x",
1099331766Sken		ocs_config_read32(ocs, SLI4_INTF_REG));
1100331766Sken}
1101331766Sken
1102331766Skenstatic void
1103331766Skenget_phy_port_num(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1104331766Sken{
1105331766Sken	char *phy_port = NULL;
1106331766Sken
1107331766Sken	phy_port = ocs_scsi_get_property_ptr(ocs, OCS_SCSI_PORTNUM);
1108331766Sken	if (phy_port) {
1109331766Sken		ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "phy_port_num", phy_port);
1110331766Sken	} else {
1111331766Sken		ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "phy_port_num", "unknown");
1112331766Sken	}
1113331766Sken}
1114331766Skenstatic void
1115331766Skenget_asic_id(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1116331766Sken{
1117331766Sken
1118331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "asic_id_reg", "0x%04x",
1119331766Sken		ocs_config_read32(ocs, SLI4_ASIC_ID_REG));
1120331766Sken}
1121331766Sken
1122331766Skenstatic void
1123331766Skenget_chip_type(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1124331766Sken{
1125331766Sken	uint32_t family;
1126331766Sken	uint32_t asic_id;
1127331766Sken	uint32_t asic_gen_num;
1128331766Sken	uint32_t asic_rev_num;
1129331766Sken	uint32_t rev_id;
1130331766Sken	char result_buf[80];
1131331766Sken	char tmp_buf[80];
1132331766Sken
1133331766Sken	family = (ocs_config_read32(ocs, SLI4_INTF_REG) & 0x00000f00) >> 8;
1134331766Sken	asic_id = ocs_config_read32(ocs, SLI4_ASIC_ID_REG);
1135331766Sken	asic_rev_num = asic_id & 0xff;
1136331766Sken	asic_gen_num = (asic_id & 0xff00) >> 8;
1137331766Sken
1138331766Sken	rev_id = ocs_config_read32(ocs, SLI4_PCI_CLASS_REVISION) & 0xff;
1139331766Sken
1140331766Sken	switch(family) {
1141331766Sken	case 0x00:
1142331766Sken		/* BE2 */
1143331766Sken		ocs_strncpy(result_buf,  "BE2 A", sizeof(result_buf));
1144331766Sken		ocs_snprintf(tmp_buf, 2, "%d", rev_id);
1145331766Sken		strcat(result_buf, tmp_buf);
1146331766Sken		break;
1147331766Sken	case 0x01:
1148331766Sken		/* BE3 */
1149331766Sken		ocs_strncpy(result_buf, "BE3", sizeof(result_buf));
1150331766Sken		if (rev_id >= 0x10) {
1151331766Sken			strcat(result_buf, "-R");
1152331766Sken		}
1153331766Sken		ocs_snprintf(tmp_buf, 3, " %c", ((rev_id & 0xf0) >> 4) + 'A');
1154331766Sken		strcat(result_buf, tmp_buf);
1155331766Sken		ocs_snprintf(tmp_buf, 2, "%d", rev_id & 0x0f);
1156331766Sken		strcat(result_buf, tmp_buf);
1157331766Sken		break;
1158331766Sken	case 0x02:
1159331766Sken		/* Skyhawk A0 */
1160331766Sken		ocs_strncpy(result_buf, "Skyhawk A0", sizeof(result_buf));
1161331766Sken		break;
1162331766Sken	case 0x0a:
1163331766Sken		/* Lancer A0 */
1164331766Sken		ocs_strncpy(result_buf, "Lancer A", sizeof(result_buf));
1165331766Sken		ocs_snprintf(tmp_buf, 2, "%d", rev_id & 0x0f);
1166331766Sken		strcat(result_buf, tmp_buf);
1167331766Sken		break;
1168331766Sken	case 0x0b:
1169331766Sken		/* Lancer B0 or D0 */
1170331766Sken		ocs_strncpy(result_buf, "Lancer", sizeof(result_buf));
1171331766Sken		ocs_snprintf(tmp_buf, 3, " %c", ((rev_id & 0xf0) >> 4) + 'A');
1172331766Sken		strcat(result_buf, tmp_buf);
1173331766Sken		ocs_snprintf(tmp_buf, 2, "%d", rev_id & 0x0f);
1174331766Sken		strcat(result_buf, tmp_buf);
1175331766Sken		break;
1176331766Sken	case 0x0c:
1177331766Sken		ocs_strncpy(result_buf, "Lancer G6", sizeof(result_buf));
1178331766Sken		break;
1179331766Sken	case 0x0f:
1180331766Sken		/* Refer to ASIC_ID */
1181331766Sken		switch(asic_gen_num) {
1182331766Sken		case 0x00:
1183331766Sken			ocs_strncpy(result_buf, "BE2", sizeof(result_buf));
1184331766Sken			break;
1185331766Sken		case 0x03:
1186331766Sken			ocs_strncpy(result_buf, "BE3-R", sizeof(result_buf));
1187331766Sken			break;
1188331766Sken		case 0x04:
1189331766Sken			ocs_strncpy(result_buf, "Skyhawk-R", sizeof(result_buf));
1190331766Sken			break;
1191331766Sken		case 0x05:
1192331766Sken			ocs_strncpy(result_buf, "Corsair", sizeof(result_buf));
1193331766Sken			break;
1194331766Sken		case 0x0b:
1195331766Sken			ocs_strncpy(result_buf, "Lancer", sizeof(result_buf));
1196331766Sken			break;
1197331766Sken		case 0x0c:
1198331766Sken			ocs_strncpy(result_buf, "LancerG6", sizeof(result_buf));
1199331766Sken			break;
1200331766Sken		default:
1201331766Sken			ocs_strncpy(result_buf, "Unknown", sizeof(result_buf));
1202331766Sken		}
1203331766Sken		if (ocs_strcmp(result_buf, "Unknown") != 0) {
1204331766Sken			ocs_snprintf(tmp_buf, 3, " %c", ((asic_rev_num & 0xf0) >> 4) + 'A');
1205331766Sken			strcat(result_buf, tmp_buf);
1206331766Sken			ocs_snprintf(tmp_buf, 2, "%d", asic_rev_num & 0x0f);
1207331766Sken			strcat(result_buf, tmp_buf);
1208331766Sken		}
1209331766Sken		break;
1210331766Sken	default:
1211331766Sken		ocs_strncpy(result_buf, "Unknown", sizeof(result_buf));
1212331766Sken	}
1213331766Sken
1214331766Sken	ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "chip_type", result_buf);
1215331766Sken
1216331766Sken}
1217331766Sken
1218331766Skenstatic void
1219331766Skenget_pci_vendor(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1220331766Sken{
1221331766Sken
1222331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "pci_vendor", "0x%04x", ocs->pci_vendor);
1223331766Sken}
1224331766Sken
1225331766Skenstatic void
1226331766Skenget_pci_device(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1227331766Sken{
1228331766Sken
1229331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "pci_device", "0x%04x", ocs->pci_device);
1230331766Sken}
1231331766Sken
1232331766Skenstatic void
1233331766Skenget_pci_subsystem_vendor(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1234331766Sken{
1235331766Sken
1236331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "pci_subsystem_vendor", "0x%04x", ocs->pci_subsystem_vendor);
1237331766Sken}
1238331766Sken
1239331766Skenstatic void
1240331766Skenget_pci_subsystem_device(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1241331766Sken{
1242331766Sken
1243331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "pci_subsystem_device", "0x%04x", ocs->pci_subsystem_device);
1244331766Sken}
1245331766Sken
1246331766Skenstatic void
1247331766Skenget_tgt_rscn_delay(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1248331766Sken{
1249331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "tgt_rscn_delay", "%ld", (unsigned long)ocs->tgt_rscn_delay_msec / 1000);
1250331766Sken}
1251331766Sken
1252331766Skenstatic void
1253331766Skenget_tgt_rscn_period(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1254331766Sken{
1255331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "tgt_rscn_period", "%ld", (unsigned long)ocs->tgt_rscn_period_msec / 1000);
1256331766Sken}
1257331766Sken
1258331766Skenstatic void
1259331766Skenget_inject_drop_cmd(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1260331766Sken{
1261331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "inject_drop_cmd", "%d",
1262331766Sken			(ocs->err_injection == INJECT_DROP_CMD ? 1:0));
1263331766Sken}
1264331766Sken
1265331766Skenstatic void
1266331766Skenget_inject_free_drop_cmd(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1267331766Sken{
1268331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "inject_free_drop_cmd", "%d",
1269331766Sken			(ocs->err_injection == INJECT_FREE_DROPPED ? 1:0));
1270331766Sken}
1271331766Sken
1272331766Skenstatic void
1273331766Skenget_inject_drop_data(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1274331766Sken{
1275331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "inject_drop_data", "%d",
1276331766Sken			(ocs->err_injection == INJECT_DROP_DATA ? 1:0));
1277331766Sken}
1278331766Sken
1279331766Skenstatic void
1280331766Skenget_inject_drop_resp(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1281331766Sken{
1282331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "inject_drop_resp", "%d",
1283331766Sken			(ocs->err_injection == INJECT_DROP_RESP ? 1:0));
1284331766Sken}
1285331766Sken
1286331766Skenstatic void
1287331766Skenget_cmd_err_inject(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1288331766Sken{
1289331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "cmd_err_inject", "0x%02x", ocs->cmd_err_inject);
1290331766Sken}
1291331766Sken
1292331766Skenstatic void
1293331766Skenget_cmd_delay_value(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1294331766Sken{
1295331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "cmd_delay_value", "%ld", (unsigned long)ocs->delay_value_msec);
1296331766Sken}
1297331766Sken
1298331766Skenstatic void
1299331766Skenget_businfo(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1300331766Sken{
1301331766Sken	ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "businfo", ocs->businfo);
1302331766Sken}
1303331766Sken
1304331766Skenstatic void
1305331766Skenget_sfp_a0(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1306331766Sken{
1307331766Sken	uint8_t *page_data;
1308331766Sken	char *buf;
1309331766Sken	int i;
1310331766Sken	int32_t bytes_read;
1311331766Sken
1312331766Sken	page_data = ocs_malloc(ocs, SFP_PAGE_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
1313331766Sken	if (page_data == NULL) {
1314331766Sken		return;
1315331766Sken	}
1316331766Sken
1317331766Sken	buf = ocs_malloc(ocs, (SFP_PAGE_SIZE * 3) + 1, OCS_M_ZERO | OCS_M_NOWAIT);
1318331766Sken	if (buf == NULL) {
1319331766Sken		ocs_free(ocs, page_data, SFP_PAGE_SIZE);
1320331766Sken		return;
1321331766Sken	}
1322331766Sken
1323331766Sken	bytes_read = ocs_mgmt_get_sfp(ocs, 0xa0, page_data, SFP_PAGE_SIZE);
1324331766Sken
1325331766Sken	if (bytes_read <= 0) {
1326331766Sken		ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sfp_a0", "(unknown)");
1327331766Sken	} else {
1328331766Sken		char *d = buf;
1329331766Sken		uint8_t *s = page_data;
1330331766Sken		int buffer_remaining = (SFP_PAGE_SIZE * 3) + 1;
1331331766Sken		int bytes_added;
1332331766Sken
1333331766Sken		for (i = 0; i < bytes_read; i++) {
1334331766Sken			bytes_added = ocs_snprintf(d, buffer_remaining, "%02x ", *s);
1335331766Sken			++s;
1336331766Sken			d += bytes_added;
1337331766Sken			buffer_remaining -= bytes_added;
1338331766Sken		}
1339331766Sken		*d = '\0';
1340331766Sken		ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sfp_a0", buf);
1341331766Sken	}
1342331766Sken
1343331766Sken	ocs_free(ocs, page_data, SFP_PAGE_SIZE);
1344331766Sken	ocs_free(ocs, buf, (3 * SFP_PAGE_SIZE) + 1);
1345331766Sken}
1346331766Sken
1347331766Skenstatic void
1348331766Skenget_sfp_a2(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1349331766Sken{
1350331766Sken	uint8_t *page_data;
1351331766Sken	char *buf;
1352331766Sken	int i;
1353331766Sken	int32_t bytes_read;
1354331766Sken
1355331766Sken	page_data = ocs_malloc(ocs, SFP_PAGE_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
1356331766Sken	if (page_data == NULL) {
1357331766Sken		return;
1358331766Sken	}
1359331766Sken
1360331766Sken	buf = ocs_malloc(ocs, (SFP_PAGE_SIZE * 3) + 1, OCS_M_ZERO | OCS_M_NOWAIT);
1361331766Sken	if (buf == NULL) {
1362331766Sken		ocs_free(ocs, page_data, SFP_PAGE_SIZE);
1363331766Sken		return;
1364331766Sken	}
1365331766Sken
1366331766Sken	bytes_read = ocs_mgmt_get_sfp(ocs, 0xa2, page_data, SFP_PAGE_SIZE);
1367331766Sken
1368331766Sken	if (bytes_read <= 0) {
1369331766Sken		ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sfp_a2", "(unknown)");
1370331766Sken	} else {
1371331766Sken		char *d = buf;
1372331766Sken		uint8_t *s = page_data;
1373331766Sken		int buffer_remaining = (SFP_PAGE_SIZE * 3) + 1;
1374331766Sken		int bytes_added;
1375331766Sken
1376331766Sken		for (i=0; i < bytes_read; i++) {
1377331766Sken			bytes_added = ocs_snprintf(d, buffer_remaining, "%02x ", *s);
1378331766Sken			++s;
1379331766Sken			d += bytes_added;
1380331766Sken			buffer_remaining -= bytes_added;
1381331766Sken		}
1382331766Sken		*d = '\0';
1383331766Sken		ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "sfp_a2", buf);
1384331766Sken	}
1385331766Sken
1386331766Sken	ocs_free(ocs, page_data, SFP_PAGE_SIZE);
1387331766Sken	ocs_free(ocs, buf, (3 * SFP_PAGE_SIZE) + 1);
1388331766Sken}
1389331766Sken
1390331766Skenstatic void
1391331766Skenget_debug_mq_dump(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1392331766Sken{
1393331766Sken
1394331766Sken	ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RW, "debug_mq_dump",
1395331766Sken		ocs_debug_is_enabled(OCS_DEBUG_ENABLE_MQ_DUMP));
1396331766Sken}
1397331766Sken
1398331766Skenstatic void
1399331766Skenget_debug_cq_dump(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1400331766Sken{
1401331766Sken
1402331766Sken	ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RW, "debug_cq_dump",
1403331766Sken		ocs_debug_is_enabled(OCS_DEBUG_ENABLE_CQ_DUMP));
1404331766Sken}
1405331766Sken
1406331766Skenstatic void
1407331766Skenget_debug_wq_dump(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1408331766Sken{
1409331766Sken	ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RW, "debug_wq_dump",
1410331766Sken		ocs_debug_is_enabled(OCS_DEBUG_ENABLE_WQ_DUMP));
1411331766Sken}
1412331766Sken
1413331766Skenstatic void
1414331766Skenget_debug_eq_dump(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1415331766Sken{
1416331766Sken	ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RW, "debug_eq_dump",
1417331766Sken		ocs_debug_is_enabled(OCS_DEBUG_ENABLE_EQ_DUMP));
1418331766Sken}
1419331766Sken
1420331766Skenstatic void
1421331766Skenget_logmask(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1422331766Sken{
1423331766Sken
1424331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "logmask", "0x%02x", ocs->logmask);
1425331766Sken
1426331766Sken}
1427331766Sken
1428331766Skenstatic void
1429331766Skenget_loglevel(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1430331766Sken{
1431331766Sken
1432331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "loglevel", "%d", loglevel);
1433331766Sken
1434331766Sken}
1435331766Sken
1436331766Skenstatic void
1437331766Skenget_current_speed(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1438331766Sken{
1439331766Sken	uint32_t value;
1440331766Sken
1441331766Sken	ocs_hw_get(&(ocs->hw), OCS_HW_LINK_SPEED, &value);
1442331766Sken
1443331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "current_speed", "%d", value);
1444331766Sken}
1445331766Sken
1446331766Skenstatic void
1447331766Skenget_configured_speed(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1448331766Sken{
1449331766Sken	uint32_t value;
1450331766Sken
1451331766Sken	ocs_hw_get(&(ocs->hw), OCS_HW_LINK_CONFIG_SPEED, &value);
1452331766Sken	if (value == 0) {
1453331766Sken		ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "configured_speed", "auto");
1454331766Sken	} else {
1455331766Sken		ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "configured_speed", "%d", value);
1456331766Sken	}
1457331766Sken
1458331766Sken}
1459331766Sken
1460331766Skenstatic void
1461331766Skenget_current_topology(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1462331766Sken{
1463331766Sken	uint32_t value;
1464331766Sken
1465331766Sken	ocs_hw_get(&(ocs->hw), OCS_HW_TOPOLOGY, &value);
1466331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "current_topology", "%d", value);
1467331766Sken
1468331766Sken}
1469331766Sken
1470331766Skenstatic void
1471331766Skenget_configured_topology(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1472331766Sken{
1473331766Sken	uint32_t value;
1474331766Sken
1475331766Sken	ocs_hw_get(&(ocs->hw), OCS_HW_CONFIG_TOPOLOGY, &value);
1476331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "configured_topology", "%d", value);
1477331766Sken
1478331766Sken}
1479331766Sken
1480331766Skenstatic void
1481331766Skenget_current_link_state(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1482331766Sken{
1483331766Sken	ocs_xport_stats_t value;
1484331766Sken
1485331766Sken	if (ocs_xport_status(ocs->xport, OCS_XPORT_PORT_STATUS, &value) == 0) {
1486331766Sken		if (value.value == OCS_XPORT_PORT_ONLINE) {
1487331766Sken			ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "current_link_state", "online");
1488331766Sken		} else {
1489331766Sken			ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "current_link_state", "offline");
1490331766Sken		}
1491331766Sken	}
1492331766Sken}
1493331766Sken
1494331766Skenstatic void
1495331766Skenget_configured_link_state(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1496331766Sken{
1497331766Sken	ocs_xport_stats_t value;
1498331766Sken
1499331766Sken	if (ocs_xport_status(ocs->xport, OCS_XPORT_CONFIG_PORT_STATUS, &value) == 0) {
1500331766Sken		if (value.value == OCS_XPORT_PORT_ONLINE) {
1501331766Sken			ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "configured_link_state", "online");
1502331766Sken		} else {
1503331766Sken			ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "configured_link_state", "offline");
1504331766Sken		}
1505331766Sken	}
1506331766Sken}
1507331766Sken
1508331766Sken/**
1509331766Sken * @brief HW link config enum to mgmt string value mapping.
1510331766Sken *
1511331766Sken * This structure provides a mapping from the ocs_hw_linkcfg_e
1512331766Sken * enum (enum exposed for the OCS_HW_PORT_SET_LINK_CONFIG port
1513331766Sken * control) to the mgmt string that is passed in by the mgmt application
1514331766Sken * (elxsdkutil).
1515331766Sken */
1516331766Skentypedef struct ocs_mgmt_linkcfg_map_s {
1517331766Sken	ocs_hw_linkcfg_e linkcfg;
1518331766Sken	const char *mgmt_str;
1519331766Sken} ocs_mgmt_linkcfg_map_t;
1520331766Sken
1521331766Skenstatic ocs_mgmt_linkcfg_map_t mgmt_linkcfg_map[] = {
1522331766Sken	{OCS_HW_LINKCFG_4X10G, OCS_CONFIG_LINKCFG_4X10G},
1523331766Sken	{OCS_HW_LINKCFG_1X40G, OCS_CONFIG_LINKCFG_1X40G},
1524331766Sken	{OCS_HW_LINKCFG_2X16G, OCS_CONFIG_LINKCFG_2X16G},
1525331766Sken	{OCS_HW_LINKCFG_4X8G, OCS_CONFIG_LINKCFG_4X8G},
1526331766Sken	{OCS_HW_LINKCFG_4X1G, OCS_CONFIG_LINKCFG_4X1G},
1527331766Sken	{OCS_HW_LINKCFG_2X10G, OCS_CONFIG_LINKCFG_2X10G},
1528331766Sken	{OCS_HW_LINKCFG_2X10G_2X8G, OCS_CONFIG_LINKCFG_2X10G_2X8G}};
1529331766Sken
1530331766Sken/**
1531331766Sken * @brief Get the HW linkcfg enum from the mgmt config string.
1532331766Sken *
1533331766Sken * @param mgmt_str mgmt string value.
1534331766Sken *
1535331766Sken * @return Returns the HW linkcfg enum corresponding to clp_str.
1536331766Sken */
1537331766Skenstatic ocs_hw_linkcfg_e
1538331766Skenocs_hw_linkcfg_from_mgmt(const char *mgmt_str)
1539331766Sken{
1540331766Sken	uint32_t i;
1541331766Sken	for (i = 0; i < ARRAY_SIZE(mgmt_linkcfg_map); i++) {
1542331766Sken		if (ocs_strncmp(mgmt_linkcfg_map[i].mgmt_str,
1543331766Sken				mgmt_str, ocs_strlen(mgmt_str)) == 0) {
1544331766Sken			return mgmt_linkcfg_map[i].linkcfg;
1545331766Sken		}
1546331766Sken	}
1547331766Sken	return OCS_HW_LINKCFG_NA;
1548331766Sken}
1549331766Sken
1550331766Sken/**
1551331766Sken * @brief Get the mgmt string value from the HW linkcfg enum.
1552331766Sken *
1553331766Sken * @param linkcfg HW linkcfg enum.
1554331766Sken *
1555331766Sken * @return Returns the mgmt string value corresponding to the given HW linkcfg.
1556331766Sken */
1557331766Skenstatic const char *
1558331766Skenocs_mgmt_from_hw_linkcfg(ocs_hw_linkcfg_e linkcfg)
1559331766Sken{
1560331766Sken	uint32_t i;
1561331766Sken	for (i = 0; i < ARRAY_SIZE(mgmt_linkcfg_map); i++) {
1562331766Sken		if (mgmt_linkcfg_map[i].linkcfg == linkcfg) {
1563331766Sken			return mgmt_linkcfg_map[i].mgmt_str;
1564331766Sken		}
1565331766Sken	}
1566331766Sken	return OCS_CONFIG_LINKCFG_UNKNOWN;
1567331766Sken}
1568331766Sken
1569331766Sken/**
1570331766Sken * @brief Link configuration callback argument
1571331766Sken */
1572331766Skentypedef struct ocs_mgmt_linkcfg_arg_s {
1573331766Sken	ocs_sem_t semaphore;
1574331766Sken	int32_t status;
1575331766Sken	ocs_hw_linkcfg_e linkcfg;
1576331766Sken} ocs_mgmt_linkcfg_arg_t;
1577331766Sken
1578331766Sken/**
1579331766Sken * @brief Get linkcfg config value
1580331766Sken *
1581331766Sken * @param ocs Pointer to the ocs structure.
1582331766Sken * @param name Not used.
1583331766Sken * @param textbuf The textbuf to which the result is written.
1584331766Sken *
1585331766Sken * @return None.
1586331766Sken */
1587331766Skenstatic void
1588331766Skenget_linkcfg(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1589331766Sken{
1590331766Sken	const char *linkcfg_str = NULL;
1591331766Sken	uint32_t value;
1592331766Sken	ocs_hw_linkcfg_e linkcfg;
1593331766Sken	ocs_hw_get(&ocs->hw, OCS_HW_LINKCFG, &value);
1594331766Sken	linkcfg = (ocs_hw_linkcfg_e)value;
1595331766Sken	linkcfg_str = ocs_mgmt_from_hw_linkcfg(linkcfg);
1596331766Sken	ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "linkcfg", linkcfg_str);
1597331766Sken}
1598331766Sken
1599331766Sken/**
1600331766Sken * @brief Get requested WWNN config value
1601331766Sken *
1602331766Sken * @param ocs Pointer to the ocs structure.
1603331766Sken * @param name Not used.
1604331766Sken * @param textbuf The textbuf to which the result is written.
1605331766Sken *
1606331766Sken * @return None.
1607331766Sken */
1608331766Skenstatic void
1609331766Skenget_req_wwnn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1610331766Sken{
1611331766Sken	ocs_xport_t *xport = ocs->xport;
1612331766Sken
1613331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "requested_wwnn", "0x%llx", (unsigned long long)xport->req_wwnn);
1614331766Sken}
1615331766Sken
1616331766Sken/**
1617331766Sken * @brief Get requested WWPN config value
1618331766Sken *
1619331766Sken * @param ocs Pointer to the ocs structure.
1620331766Sken * @param name Not used.
1621331766Sken * @param textbuf The textbuf to which the result is written.
1622331766Sken *
1623331766Sken * @return None.
1624331766Sken */
1625331766Skenstatic void
1626331766Skenget_req_wwpn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1627331766Sken{
1628331766Sken	ocs_xport_t *xport = ocs->xport;
1629331766Sken
1630331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "requested_wwpn", "0x%llx", (unsigned long long)xport->req_wwpn);
1631331766Sken}
1632331766Sken
1633331766Sken/**
1634331766Sken * @brief Get requested nodedb_mask config value
1635331766Sken *
1636331766Sken * @param ocs Pointer to the ocs structure.
1637331766Sken * @param name Not used.
1638331766Sken * @param textbuf The textbuf to which the result is written.
1639331766Sken *
1640331766Sken * @return None.
1641331766Sken */
1642331766Skenstatic void
1643331766Skenget_nodedb_mask(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
1644331766Sken{
1645331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RW, "nodedb_mask", "0x%08x", ocs->nodedb_mask);
1646331766Sken}
1647331766Sken
1648331766Sken/**
1649331766Sken * @brief Set requested WWNN value.
1650331766Sken *
1651331766Sken * @param ocs Pointer to the ocs structure.
1652331766Sken * @param name Not used.
1653331766Sken * @param value Value to which the linkcfg is set.
1654331766Sken *
1655331766Sken * @return Returns 0 on success.
1656331766Sken */
1657331766Sken
1658331766Skenint
1659331766Skenset_req_wwnn(ocs_t *ocs, char *name, char *value)
1660331766Sken{
1661331766Sken	int rc;
1662331766Sken	uint64_t wwnn;
1663331766Sken
1664331766Sken	if (ocs_strcasecmp(value, "default") == 0) {
1665331766Sken		wwnn = 0;
1666331766Sken	}
1667331766Sken	else if (parse_wwn(value, &wwnn) != 0) {
1668331766Sken		ocs_log_test(ocs, "Invalid WWNN: %s\n", value);
1669331766Sken		return 1;
1670331766Sken	}
1671331766Sken
1672331766Sken	rc = ocs_xport_control(ocs->xport, OCS_XPORT_WWNN_SET, wwnn);
1673331766Sken
1674331766Sken	if(rc) {
1675331766Sken		ocs_log_test(ocs, "OCS_XPORT_WWNN_SET failed: %d\n", rc);
1676331766Sken		return rc;
1677331766Sken	}
1678331766Sken
1679331766Sken	rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE);
1680331766Sken	if (rc) {
1681331766Sken		ocs_log_test(ocs, "port offline failed : %d\n", rc);
1682331766Sken	}
1683331766Sken
1684331766Sken	rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE);
1685331766Sken	if (rc) {
1686331766Sken		ocs_log_test(ocs, "port online failed : %d\n", rc);
1687331766Sken	}
1688331766Sken
1689331766Sken	return rc;
1690331766Sken}
1691331766Sken
1692331766Sken/**
1693331766Sken * @brief Set requested WWNP value.
1694331766Sken *
1695331766Sken * @param ocs Pointer to the ocs structure.
1696331766Sken * @param name Not used.
1697331766Sken * @param value Value to which the linkcfg is set.
1698331766Sken *
1699331766Sken * @return Returns 0 on success.
1700331766Sken */
1701331766Sken
1702331766Skenint
1703331766Skenset_req_wwpn(ocs_t *ocs, char *name, char *value)
1704331766Sken{
1705331766Sken	int rc;
1706331766Sken	uint64_t wwpn;
1707331766Sken
1708331766Sken	if (ocs_strcasecmp(value, "default") == 0) {
1709331766Sken		wwpn = 0;
1710331766Sken	}
1711331766Sken	else if (parse_wwn(value, &wwpn) != 0) {
1712331766Sken		ocs_log_test(ocs, "Invalid WWPN: %s\n", value);
1713331766Sken		return 1;
1714331766Sken	}
1715331766Sken
1716331766Sken	rc = ocs_xport_control(ocs->xport, OCS_XPORT_WWPN_SET, wwpn);
1717331766Sken
1718331766Sken	if(rc) {
1719331766Sken		ocs_log_test(ocs, "OCS_XPORT_WWPN_SET failed: %d\n", rc);
1720331766Sken		return rc;
1721331766Sken	}
1722331766Sken
1723331766Sken	rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE);
1724331766Sken	if (rc) {
1725331766Sken		ocs_log_test(ocs, "port offline failed : %d\n", rc);
1726331766Sken	}
1727331766Sken
1728331766Sken	rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE);
1729331766Sken	if (rc) {
1730331766Sken		ocs_log_test(ocs, "port online failed : %d\n", rc);
1731331766Sken	}
1732331766Sken
1733331766Sken	return rc;
1734331766Sken}
1735331766Sken
1736331766Sken/**
1737331766Sken * @brief Set node debug mask value
1738331766Sken *
1739331766Sken * @param ocs Pointer to the ocs structure.
1740331766Sken * @param name Not used.
1741331766Sken * @param value Value to which the nodedb_mask is set.
1742331766Sken *
1743331766Sken * @return Returns 0 on success.
1744331766Sken */
1745331766Skenstatic int
1746331766Skenset_nodedb_mask(ocs_t *ocs, char *name, char *value)
1747331766Sken{
1748331766Sken	ocs->nodedb_mask = ocs_strtoul(value, 0, 0);
1749331766Sken	return 0;
1750331766Sken}
1751331766Sken
1752331766Sken/**
1753331766Sken * @brief Set linkcfg config value.
1754331766Sken *
1755331766Sken * @param ocs Pointer to the ocs structure.
1756331766Sken * @param name Not used.
1757331766Sken * @param value Value to which the linkcfg is set.
1758331766Sken *
1759331766Sken * @return Returns 0 on success.
1760331766Sken */
1761331766Skenstatic int
1762331766Skenset_linkcfg(ocs_t *ocs, char *name, char *value)
1763331766Sken{
1764331766Sken	ocs_hw_linkcfg_e linkcfg;
1765331766Sken	ocs_mgmt_linkcfg_arg_t cb_arg;
1766331766Sken	ocs_hw_rtn_e status;
1767331766Sken
1768331766Sken	ocs_sem_init(&cb_arg.semaphore, 0, "mgmt_linkcfg");
1769331766Sken
1770331766Sken	/* translate mgmt linkcfg string to HW linkcfg enum */
1771331766Sken	linkcfg = ocs_hw_linkcfg_from_mgmt(value);
1772331766Sken
1773331766Sken	/* set HW linkcfg */
1774331766Sken	status = ocs_hw_port_control(&ocs->hw, OCS_HW_PORT_SET_LINK_CONFIG,
1775331766Sken				      (uintptr_t)linkcfg, ocs_mgmt_linkcfg_cb, &cb_arg);
1776331766Sken	if (status) {
1777331766Sken		ocs_log_test(ocs, "ocs_hw_set_linkcfg failed\n");
1778331766Sken		return -1;
1779331766Sken	}
1780331766Sken
1781331766Sken	if (ocs_sem_p(&cb_arg.semaphore, OCS_SEM_FOREVER)) {
1782331766Sken		ocs_log_err(ocs, "ocs_sem_p failed\n");
1783331766Sken		return -1;
1784331766Sken	}
1785331766Sken
1786331766Sken	if (cb_arg.status) {
1787331766Sken		ocs_log_test(ocs, "failed to set linkcfg from HW status=%d\n",
1788331766Sken			     cb_arg.status);
1789331766Sken		return -1;
1790331766Sken	}
1791331766Sken
1792331766Sken	return 0;
1793331766Sken}
1794331766Sken
1795331766Sken/**
1796331766Sken * @brief Linkcfg callback
1797331766Sken *
1798331766Sken * @param status Result of the linkcfg get/set operation.
1799331766Sken * @param value Resulting linkcfg value.
1800331766Sken * @param arg Callback argument.
1801331766Sken *
1802331766Sken * @return None.
1803331766Sken */
1804331766Skenstatic void
1805331766Skenocs_mgmt_linkcfg_cb(int32_t status, uintptr_t value, void *arg)
1806331766Sken{
1807331766Sken	ocs_mgmt_linkcfg_arg_t *cb_arg = (ocs_mgmt_linkcfg_arg_t *)arg;
1808331766Sken	cb_arg->status = status;
1809331766Sken	cb_arg->linkcfg = (ocs_hw_linkcfg_e)value;
1810331766Sken	ocs_sem_v(&cb_arg->semaphore);
1811331766Sken}
1812331766Sken
1813331766Skenstatic int
1814331766Skenset_debug_mq_dump(ocs_t *ocs, char *name, char *value)
1815331766Sken{
1816331766Sken	int result;
1817331766Sken
1818331766Sken	if (ocs_strcasecmp(value, "false") == 0) {
1819331766Sken		ocs_debug_disable(OCS_DEBUG_ENABLE_MQ_DUMP);
1820331766Sken		result = 0;
1821331766Sken	} else if (ocs_strcasecmp(value, "true") == 0) {
1822331766Sken		ocs_debug_enable(OCS_DEBUG_ENABLE_MQ_DUMP);
1823331766Sken		result = 0;
1824331766Sken	} else {
1825331766Sken		result = -1;
1826331766Sken	}
1827331766Sken
1828331766Sken	return result;
1829331766Sken}
1830331766Sken
1831331766Skenstatic int
1832331766Skenset_debug_cq_dump(ocs_t *ocs, char *name, char *value)
1833331766Sken{
1834331766Sken	int result;
1835331766Sken
1836331766Sken	if (ocs_strcasecmp(value, "false") == 0) {
1837331766Sken		ocs_debug_disable(OCS_DEBUG_ENABLE_CQ_DUMP);
1838331766Sken		result = 0;
1839331766Sken	} else if (ocs_strcasecmp(value, "true") == 0) {
1840331766Sken		ocs_debug_enable(OCS_DEBUG_ENABLE_CQ_DUMP);
1841331766Sken		result = 0;
1842331766Sken	} else {
1843331766Sken		result = -1;
1844331766Sken	}
1845331766Sken
1846331766Sken	return result;
1847331766Sken}
1848331766Sken
1849331766Skenstatic int
1850331766Skenset_debug_wq_dump(ocs_t *ocs, char *name, char *value)
1851331766Sken{
1852331766Sken	int result;
1853331766Sken
1854331766Sken	if (ocs_strcasecmp(value, "false") == 0) {
1855331766Sken		ocs_debug_disable(OCS_DEBUG_ENABLE_WQ_DUMP);
1856331766Sken		result = 0;
1857331766Sken	} else if (ocs_strcasecmp(value, "true") == 0) {
1858331766Sken		ocs_debug_enable(OCS_DEBUG_ENABLE_WQ_DUMP);
1859331766Sken		result = 0;
1860331766Sken	} else {
1861331766Sken		result = -1;
1862331766Sken	}
1863331766Sken
1864331766Sken	return result;
1865331766Sken}
1866331766Sken
1867331766Skenstatic int
1868331766Skenset_debug_eq_dump(ocs_t *ocs, char *name, char *value)
1869331766Sken{
1870331766Sken	int result;
1871331766Sken
1872331766Sken	if (ocs_strcasecmp(value, "false") == 0) {
1873331766Sken		ocs_debug_disable(OCS_DEBUG_ENABLE_EQ_DUMP);
1874331766Sken		result = 0;
1875331766Sken	} else if (ocs_strcasecmp(value, "true") == 0) {
1876331766Sken		ocs_debug_enable(OCS_DEBUG_ENABLE_EQ_DUMP);
1877331766Sken		result = 0;
1878331766Sken	} else {
1879331766Sken		result = -1;
1880331766Sken	}
1881331766Sken
1882331766Sken	return result;
1883331766Sken}
1884331766Sken
1885331766Skenstatic int
1886331766Skenset_logmask(ocs_t *ocs, char *name, char *value)
1887331766Sken{
1888331766Sken
1889331766Sken	ocs->logmask = ocs_strtoul(value, NULL, 0);
1890331766Sken
1891331766Sken	return 0;
1892331766Sken}
1893331766Sken
1894331766Skenstatic int
1895331766Skenset_loglevel(ocs_t *ocs, char *name, char *value)
1896331766Sken{
1897331766Sken
1898331766Sken	loglevel = ocs_strtoul(value, NULL, 0);
1899331766Sken
1900331766Sken	return 0;
1901331766Sken}
1902331766Sken
1903331766Skenint
1904331766Skenset_configured_speed(ocs_t *ocs, char *name, char *value)
1905331766Sken{
1906331766Sken	int result = 0;
1907331766Sken	ocs_hw_rtn_e hw_rc;
1908331766Sken	int xport_rc;
1909331766Sken	uint32_t spd;
1910331766Sken
1911331766Sken	spd = ocs_strtoul(value, NULL, 0);
1912331766Sken
1913331766Sken	if ((spd != 0) && (spd != 2000) && (spd != 4000) &&
1914331766Sken		(spd != 8000) && (spd != 16000) && (spd != 32000)) {
1915331766Sken		ocs_log_test(ocs, "unsupported speed %d\n", spd);
1916331766Sken		return 1;
1917331766Sken	}
1918331766Sken
1919331766Sken	ocs_log_debug(ocs, "Taking port offline\n");
1920331766Sken	xport_rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE);
1921331766Sken	if (xport_rc != 0) {
1922331766Sken		ocs_log_test(ocs, "Port offline failed\n");
1923331766Sken		result = 1;
1924331766Sken	} else {
1925331766Sken		ocs_log_debug(ocs, "Setting port to speed %d\n", spd);
1926331766Sken		hw_rc = ocs_hw_set(&ocs->hw, OCS_HW_LINK_SPEED, spd);
1927331766Sken		if (hw_rc != OCS_HW_RTN_SUCCESS) {
1928331766Sken			ocs_log_test(ocs, "Speed set failed\n");
1929331766Sken			result = 1;
1930331766Sken		}
1931331766Sken
1932331766Sken		/* If we failed to set the speed we still want to try to bring
1933331766Sken		 * the port back online */
1934331766Sken
1935331766Sken		ocs_log_debug(ocs, "Bringing port online\n");
1936331766Sken		xport_rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE);
1937331766Sken		if (xport_rc != 0) {
1938331766Sken			result = 1;
1939331766Sken		}
1940331766Sken	}
1941331766Sken
1942331766Sken	return result;
1943331766Sken}
1944331766Sken
1945331766Skenint
1946331766Skenset_configured_topology(ocs_t *ocs, char *name, char *value)
1947331766Sken{
1948331766Sken	int result = 0;
1949331766Sken	ocs_hw_rtn_e hw_rc;
1950331766Sken	int xport_rc;
1951331766Sken	uint32_t topo;
1952331766Sken
1953331766Sken	topo = ocs_strtoul(value, NULL, 0);
1954331766Sken	if (topo >= OCS_HW_TOPOLOGY_NONE) {
1955331766Sken		return 1;
1956331766Sken	}
1957331766Sken
1958331766Sken	ocs_log_debug(ocs, "Taking port offline\n");
1959331766Sken	xport_rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE);
1960331766Sken	if (xport_rc != 0) {
1961331766Sken		ocs_log_test(ocs, "Port offline failed\n");
1962331766Sken		result = 1;
1963331766Sken	} else {
1964331766Sken		ocs_log_debug(ocs, "Setting port to topology %d\n", topo);
1965331766Sken		hw_rc = ocs_hw_set(&ocs->hw, OCS_HW_TOPOLOGY, topo);
1966331766Sken		if (hw_rc != OCS_HW_RTN_SUCCESS) {
1967331766Sken			ocs_log_test(ocs, "Topology set failed\n");
1968331766Sken			result = 1;
1969331766Sken		}
1970331766Sken
1971331766Sken		/* If we failed to set the topology we still want to try to bring
1972331766Sken		 * the port back online */
1973331766Sken
1974331766Sken		ocs_log_debug(ocs, "Bringing port online\n");
1975331766Sken		xport_rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE);
1976331766Sken		if (xport_rc != 0) {
1977331766Sken			result = 1;
1978331766Sken		}
1979331766Sken	}
1980331766Sken
1981331766Sken	return result;
1982331766Sken}
1983331766Sken
1984331766Skenstatic int
1985331766Skenset_configured_link_state(ocs_t *ocs, char *name, char *value)
1986331766Sken{
1987331766Sken	int result = 0;
1988331766Sken	int xport_rc;
1989331766Sken
1990331766Sken	if (ocs_strcasecmp(value, "offline") == 0) {
1991331766Sken		ocs_log_debug(ocs, "Setting port to %s\n", value);
1992331766Sken		xport_rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE);
1993331766Sken		if (xport_rc != 0) {
1994331766Sken			ocs_log_test(ocs, "Setting port to offline failed\n");
1995331766Sken			result = -1;
1996331766Sken		}
1997331766Sken	} else if (ocs_strcasecmp(value, "online") == 0) {
1998331766Sken		ocs_log_debug(ocs, "Setting port to %s\n", value);
1999331766Sken		xport_rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE);
2000331766Sken		if (xport_rc != 0) {
2001331766Sken			ocs_log_test(ocs, "Setting port to online failed\n");
2002331766Sken			result = -1;
2003331766Sken		}
2004331766Sken	} else {
2005331766Sken		ocs_log_test(ocs, "Unsupported link state \"%s\"\n", value);
2006331766Sken		result = -1;
2007331766Sken	}
2008331766Sken
2009331766Sken	return result;
2010331766Sken}
2011331766Sken
2012331766Skentypedef struct ocs_mgmt_get_port_protocol_result {
2013331766Sken	ocs_sem_t semaphore;
2014331766Sken	int32_t status;
2015331766Sken	ocs_hw_port_protocol_e port_protocol;
2016331766Sken} ocs_mgmt_get_port_protocol_result_t;
2017331766Sken
2018331766Sken
2019331766Skenstatic void
2020331766Skenocs_mgmt_get_port_protocol_cb(int32_t status,
2021331766Sken			      ocs_hw_port_protocol_e port_protocol,
2022331766Sken			      void    *arg)
2023331766Sken{
2024331766Sken	ocs_mgmt_get_port_protocol_result_t *result = arg;
2025331766Sken
2026331766Sken	result->status = status;
2027331766Sken	result->port_protocol = port_protocol;
2028331766Sken
2029331766Sken	ocs_sem_v(&(result->semaphore));
2030331766Sken}
2031331766Sken
2032331766Skenstatic void
2033331766Skenget_port_protocol(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
2034331766Sken{
2035331766Sken	ocs_mgmt_get_port_protocol_result_t result;
2036331766Sken	uint8_t bus;
2037331766Sken	uint8_t dev;
2038331766Sken	uint8_t func;
2039331766Sken
2040331766Sken	ocs_sem_init(&(result.semaphore), 0, "get_port_protocol");
2041331766Sken
2042331766Sken	ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
2043331766Sken
2044331766Sken	if(ocs_hw_get_port_protocol(&ocs->hw, func, ocs_mgmt_get_port_protocol_cb, &result) == OCS_HW_RTN_SUCCESS) {
2045331766Sken		if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) {
2046331766Sken			/* Undefined failure */
2047331766Sken			ocs_log_err(ocs, "ocs_sem_p failed\n");
2048331766Sken		}
2049331766Sken		if (result.status == 0) {
2050331766Sken			switch (result.port_protocol) {
2051331766Sken			case OCS_HW_PORT_PROTOCOL_ISCSI:
2052331766Sken				ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "port_protocol", "iSCSI");
2053331766Sken				break;
2054331766Sken			case OCS_HW_PORT_PROTOCOL_FCOE:
2055331766Sken				ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "port_protocol", "FCoE");
2056331766Sken				break;
2057331766Sken			case OCS_HW_PORT_PROTOCOL_FC:
2058331766Sken				ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "port_protocol", "FC");
2059331766Sken				break;
2060331766Sken			case OCS_HW_PORT_PROTOCOL_OTHER:
2061331766Sken				ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "port_protocol", "Other");
2062331766Sken				break;
2063331766Sken			}
2064331766Sken		} else {
2065331766Sken			ocs_log_test(ocs, "getting port profile status 0x%x\n", result.status);
2066331766Sken			ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "port_protocol", "Unknown");
2067331766Sken		}
2068331766Sken	}
2069331766Sken}
2070331766Sken
2071331766Skentypedef struct ocs_mgmt_set_port_protocol_result {
2072331766Sken	ocs_sem_t semaphore;
2073331766Sken	int32_t status;
2074331766Sken} ocs_mgmt_set_port_protocol_result_t;
2075331766Sken
2076331766Sken
2077331766Sken
2078331766Skenstatic void
2079331766Skenocs_mgmt_set_port_protocol_cb(int32_t status,
2080331766Sken			      void    *arg)
2081331766Sken{
2082331766Sken	ocs_mgmt_get_port_protocol_result_t *result = arg;
2083331766Sken
2084331766Sken	result->status = status;
2085331766Sken
2086331766Sken	ocs_sem_v(&(result->semaphore));
2087331766Sken}
2088331766Sken
2089331766Sken/**
2090331766Sken * @brief  Set port protocol
2091331766Sken * @par Description
2092331766Sken * This is a management action handler to set the current
2093331766Sken * port protocol.  Input value should be one of iSCSI,
2094331766Sken * FC, or FCoE.
2095331766Sken *
2096331766Sken * @param ocs Pointer to the ocs structure.
2097331766Sken * @param name Name of the action being performed.
2098331766Sken * @param value The value to be assigned
2099331766Sken *
2100331766Sken * @return Returns 0 on success, non-zero on failure.
2101331766Sken */
2102331766Skenstatic int32_t
2103331766Skenset_port_protocol(ocs_t *ocs, char *name, char *value)
2104331766Sken{
2105331766Sken	ocs_mgmt_set_port_protocol_result_t result;
2106331766Sken	int32_t rc = 0;
2107331766Sken	ocs_hw_port_protocol_e new_protocol;
2108331766Sken	uint8_t bus;
2109331766Sken	uint8_t dev;
2110331766Sken	uint8_t func;
2111331766Sken
2112331766Sken	ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
2113331766Sken
2114331766Sken	ocs_sem_init(&(result.semaphore), 0, "set_port_protocol");
2115331766Sken
2116331766Sken	if (ocs_strcasecmp(value, "iscsi") == 0) {
2117331766Sken		new_protocol = OCS_HW_PORT_PROTOCOL_ISCSI;
2118331766Sken	} else if (ocs_strcasecmp(value, "fc") == 0) {
2119331766Sken		new_protocol = OCS_HW_PORT_PROTOCOL_FC;
2120331766Sken	} else if (ocs_strcasecmp(value, "fcoe") == 0) {
2121331766Sken		new_protocol = OCS_HW_PORT_PROTOCOL_FCOE;
2122331766Sken	} else {
2123331766Sken		return -1;
2124331766Sken	}
2125331766Sken
2126331766Sken	rc = ocs_hw_set_port_protocol(&ocs->hw, new_protocol, func,
2127331766Sken				       ocs_mgmt_set_port_protocol_cb, &result);
2128331766Sken	if (rc == OCS_HW_RTN_SUCCESS) {
2129331766Sken		if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) {
2130331766Sken			/* Undefined failure */
2131331766Sken			ocs_log_err(ocs, "ocs_sem_p failed\n");
2132331766Sken			rc = -ENXIO;
2133331766Sken		}
2134331766Sken		if (result.status == 0) {
2135331766Sken			/* Success. */
2136331766Sken			rc = 0;
2137331766Sken		} else {
2138331766Sken			rc = -1;
2139331766Sken			ocs_log_test(ocs, "setting active profile status 0x%x\n",
2140331766Sken				     result.status);
2141331766Sken		}
2142331766Sken	}
2143331766Sken
2144331766Sken	return rc;
2145331766Sken}
2146331766Sken
2147331766Skentypedef struct ocs_mgmt_get_profile_list_result_s {
2148331766Sken	ocs_sem_t semaphore;
2149331766Sken	int32_t status;
2150331766Sken	ocs_hw_profile_list_t *list;
2151331766Sken} ocs_mgmt_get_profile_list_result_t;
2152331766Sken
2153331766Skenstatic void
2154331766Skenocs_mgmt_get_profile_list_cb(int32_t status, ocs_hw_profile_list_t *list, void *ul_arg)
2155331766Sken{
2156331766Sken	ocs_mgmt_get_profile_list_result_t *result = ul_arg;
2157331766Sken
2158331766Sken	result->status = status;
2159331766Sken	result->list = list;
2160331766Sken
2161331766Sken	ocs_sem_v(&(result->semaphore));
2162331766Sken}
2163331766Sken
2164331766Sken/**
2165331766Sken * @brief  Get list of profiles
2166331766Sken * @par Description
2167331766Sken * This is a management action handler to get the list of
2168331766Sken * profiles supported by the SLI port.  Although the spec says
2169331766Sken * that all SLI platforms support this, only Skyhawk actually
2170331766Sken * has a useful implementation.
2171331766Sken *
2172331766Sken * @param ocs Pointer to the ocs structure.
2173331766Sken * @param name Name of the action being performed.
2174331766Sken * @param textbuf Pointer to an ocs_textbuf, which is used to return the results.
2175331766Sken *
2176331766Sken * @return none
2177331766Sken */
2178331766Skenstatic void
2179331766Skenget_profile_list(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
2180331766Sken{
2181331766Sken	ocs_mgmt_get_profile_list_result_t result;
2182331766Sken
2183331766Sken	ocs_sem_init(&(result.semaphore), 0, "get_profile_list");
2184331766Sken
2185331766Sken	if(ocs_hw_get_profile_list(&ocs->hw, ocs_mgmt_get_profile_list_cb, &result) == OCS_HW_RTN_SUCCESS) {
2186331766Sken		if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) {
2187331766Sken			/* Undefined failure */
2188331766Sken			ocs_log_err(ocs, "ocs_sem_p failed\n");
2189331766Sken		}
2190331766Sken		if (result.status == 0) {
2191331766Sken			/* Success. */
2192331766Sken#define MAX_LINE_SIZE 520
2193331766Sken#define BUFFER_SIZE MAX_LINE_SIZE*40
2194331766Sken			char *result_buf;
2195331766Sken			char result_line[MAX_LINE_SIZE];
2196331766Sken			uint32_t bytes_left;
2197331766Sken			uint32_t i;
2198331766Sken
2199331766Sken			result_buf = ocs_malloc(ocs, BUFFER_SIZE, OCS_M_ZERO);
2200331766Sken			bytes_left = BUFFER_SIZE;
2201331766Sken
2202331766Sken			for (i=0; i<result.list->num_descriptors; i++) {
2203331766Sken				sprintf(result_line, "0x%02x:%s\n", result.list->descriptors[i].profile_id,
2204331766Sken					result.list->descriptors[i].profile_description);
2205331766Sken				if (strlen(result_line) < bytes_left) {
2206331766Sken					strcat(result_buf, result_line);
2207331766Sken					bytes_left -= strlen(result_line);
2208331766Sken				}
2209331766Sken			}
2210331766Sken
2211331766Sken
2212331766Sken			ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "profile_list", result_buf);
2213331766Sken
2214331766Sken			ocs_free(ocs, result_buf, BUFFER_SIZE);
2215331766Sken			ocs_free(ocs, result.list, sizeof(ocs_hw_profile_list_t));
2216331766Sken		} else {
2217331766Sken			ocs_log_test(ocs, "getting profile list status 0x%x\n", result.status);
2218331766Sken		}
2219331766Sken	}
2220331766Sken}
2221331766Sken
2222331766Skentypedef struct ocs_mgmt_get_active_profile_result {
2223331766Sken	ocs_sem_t semaphore;
2224331766Sken	int32_t status;
2225331766Sken	uint32_t active_profile_id;
2226331766Sken} ocs_mgmt_get_active_profile_result_t;
2227331766Sken
2228331766Skenstatic void
2229331766Skenocs_mgmt_get_active_profile_cb(int32_t status, uint32_t active_profile, void *ul_arg)
2230331766Sken{
2231331766Sken	ocs_mgmt_get_active_profile_result_t *result = ul_arg;
2232331766Sken
2233331766Sken	result->status = status;
2234331766Sken	result->active_profile_id = active_profile;
2235331766Sken
2236331766Sken	ocs_sem_v(&(result->semaphore));
2237331766Sken}
2238331766Sken
2239331766Sken#define MAX_PROFILE_LENGTH 5
2240331766Sken
2241331766Sken/**
2242331766Sken * @brief  Get active profile
2243331766Sken * @par Description
2244331766Sken * This is a management action handler to get the currently
2245331766Sken * active profile for an SLI port.  Although the spec says that
2246331766Sken * all SLI platforms support this, only Skyhawk actually has a
2247331766Sken * useful implementation.
2248331766Sken *
2249331766Sken * @param ocs Pointer to the ocs structure.
2250331766Sken * @param name Name of the action being performed.
2251331766Sken * @param textbuf Pointer to an ocs_textbuf, which is used to return the results.
2252331766Sken *
2253331766Sken * @return none
2254331766Sken */
2255331766Skenstatic void
2256331766Skenget_active_profile(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
2257331766Sken{
2258331766Sken	char result_string[MAX_PROFILE_LENGTH];
2259331766Sken	ocs_mgmt_get_active_profile_result_t result;
2260331766Sken
2261331766Sken	ocs_sem_init(&(result.semaphore), 0, "get_active_profile");
2262331766Sken
2263331766Sken	if(ocs_hw_get_active_profile(&ocs->hw, ocs_mgmt_get_active_profile_cb, &result) == OCS_HW_RTN_SUCCESS) {
2264331766Sken		if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) {
2265331766Sken			/* Undefined failure */
2266331766Sken			ocs_log_err(ocs, "ocs_sem_p failed\n");
2267331766Sken		}
2268331766Sken		if (result.status == 0) {
2269331766Sken			/* Success. */
2270331766Sken			sprintf(result_string, "0x%02x", result.active_profile_id);
2271331766Sken			ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "active_profile", result_string);
2272331766Sken		} else {
2273331766Sken			ocs_log_test(ocs, "getting active profile status 0x%x\n", result.status);
2274331766Sken		}
2275331766Sken	}
2276331766Sken}
2277331766Sken
2278331766Skentypedef struct ocs_mgmt_set_active_profile_result {
2279331766Sken	ocs_sem_t semaphore;
2280331766Sken	int32_t status;
2281331766Sken} ocs_mgmt_set_active_profile_result_t;
2282331766Sken
2283331766Sken
2284331766Skenstatic void
2285331766Skenocs_mgmt_set_active_profile_cb(int32_t status, void *ul_arg)
2286331766Sken{
2287331766Sken	ocs_mgmt_get_profile_list_result_t *result = ul_arg;
2288331766Sken
2289331766Sken	result->status = status;
2290331766Sken
2291331766Sken	ocs_sem_v(&(result->semaphore));
2292331766Sken}
2293331766Sken
2294331766Sken/**
2295331766Sken * @brief  Set active profile
2296331766Sken * @par Description
2297331766Sken * This is a management action handler to set the currently
2298331766Sken * active profile for an SLI port.  Although the spec says that
2299331766Sken * all SLI platforms support this, only Skyhawk actually has a
2300331766Sken * useful implementation.
2301331766Sken *
2302331766Sken * @param ocs Pointer to the ocs structure.
2303331766Sken * @param name Name of the action being performed.
2304331766Sken * @param value Requested new value of the property.
2305331766Sken *
2306331766Sken * @return Returns 0 on success, non-zero on failure.
2307331766Sken */
2308331766Skenstatic int32_t
2309331766Skenset_active_profile(ocs_t *ocs, char *name, char *value)
2310331766Sken{
2311331766Sken	ocs_mgmt_set_active_profile_result_t result;
2312331766Sken	int32_t rc = 0;
2313331766Sken	int32_t new_profile;
2314331766Sken
2315331766Sken	new_profile = ocs_strtoul(value, NULL, 0);
2316331766Sken
2317331766Sken	ocs_sem_init(&(result.semaphore), 0, "set_active_profile");
2318331766Sken
2319331766Sken	rc = ocs_hw_set_active_profile(&ocs->hw, ocs_mgmt_set_active_profile_cb, new_profile, &result);
2320331766Sken	if (rc == OCS_HW_RTN_SUCCESS) {
2321331766Sken		if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) {
2322331766Sken			/* Undefined failure */
2323331766Sken			ocs_log_err(ocs, "ocs_sem_p failed\n");
2324331766Sken			rc = -ENXIO;
2325331766Sken		}
2326331766Sken		if (result.status == 0) {
2327331766Sken			/* Success. */
2328331766Sken			rc = 0;
2329331766Sken		} else {
2330331766Sken			rc = -1;
2331331766Sken			ocs_log_test(ocs, "setting active profile status 0x%x\n", result.status);
2332331766Sken		}
2333331766Sken	}
2334331766Sken
2335331766Sken	return rc;
2336331766Sken}
2337331766Sken
2338331766Skentypedef struct ocs_mgmt_get_nvparms_result {
2339331766Sken	ocs_sem_t semaphore;
2340331766Sken	int32_t status;
2341331766Sken	uint8_t	wwpn[8];
2342331766Sken	uint8_t wwnn[8];
2343331766Sken	uint8_t hard_alpa;
2344331766Sken	uint32_t preferred_d_id;
2345331766Sken} ocs_mgmt_get_nvparms_result_t;
2346331766Sken
2347331766Skenstatic void
2348331766Skenocs_mgmt_get_nvparms_cb(int32_t status, uint8_t *wwpn, uint8_t *wwnn, uint8_t hard_alpa,
2349331766Sken		uint32_t preferred_d_id, void *ul_arg)
2350331766Sken{
2351331766Sken	ocs_mgmt_get_nvparms_result_t *result = ul_arg;
2352331766Sken
2353331766Sken	result->status = status;
2354331766Sken	ocs_memcpy(result->wwpn, wwpn, sizeof(result->wwpn));
2355331766Sken	ocs_memcpy(result->wwnn, wwnn, sizeof(result->wwnn));
2356331766Sken	result->hard_alpa = hard_alpa;
2357331766Sken	result->preferred_d_id = preferred_d_id;
2358331766Sken
2359331766Sken	ocs_sem_v(&(result->semaphore));
2360331766Sken}
2361331766Sken
2362331766Sken/**
2363331766Sken * @brief  Get wwpn
2364331766Sken * @par Description
2365331766Sken *
2366331766Sken *
2367331766Sken * @param ocs Pointer to the ocs structure.
2368331766Sken * @param name Name of the action being performed.
2369331766Sken * @param textbuf Pointer to an ocs_textbuf, which is used to return the results.
2370331766Sken *
2371331766Sken * @return none
2372331766Sken */
2373331766Skenstatic void
2374331766Skenget_nv_wwpn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
2375331766Sken{
2376331766Sken	char result_string[24];
2377334872Sram	ocs_mgmt_get_nvparms_result_t result;
2378331766Sken
2379331766Sken	ocs_sem_init(&(result.semaphore), 0, "get_nv_wwpn");
2380331766Sken
2381331766Sken	if(ocs_hw_get_nvparms(&ocs->hw, ocs_mgmt_get_nvparms_cb, &result) == OCS_HW_RTN_SUCCESS) {
2382331766Sken		if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) {
2383331766Sken			/* Undefined failure */
2384331766Sken			ocs_log_err(ocs, "ocs_sem_p failed\n");
2385331766Sken			return;
2386331766Sken		}
2387331766Sken		if (result.status == 0) {
2388331766Sken			/* Success.  Copy wwpn from result struct to result string */
2389331766Sken			sprintf(result_string, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
2390331766Sken					result.wwpn[0], result.wwpn[1], result.wwpn[2],
2391331766Sken					result.wwpn[3], result.wwpn[4], result.wwpn[5],
2392331766Sken					result.wwpn[6], result.wwpn[7]);
2393331766Sken			ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "nv_wwpn", result_string);
2394331766Sken		} else {
2395331766Sken			ocs_log_test(ocs, "getting wwpn status 0x%x\n", result.status);
2396331766Sken		}
2397331766Sken	}
2398331766Sken}
2399331766Sken
2400331766Sken/**
2401331766Sken * @brief  Get wwnn
2402331766Sken * @par Description
2403331766Sken *
2404331766Sken *
2405331766Sken * @param ocs Pointer to the ocs structure.
2406331766Sken * @param name Name of the action being performed.
2407331766Sken * @param textbuf Pointer to an ocs_textbuf, which is used to return the results.
2408331766Sken *
2409331766Sken * @return none
2410331766Sken */
2411331766Skenstatic void
2412331766Skenget_nv_wwnn(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
2413331766Sken{
2414331766Sken	char result_string[24];
2415334872Sram	ocs_mgmt_get_nvparms_result_t result;
2416331766Sken
2417331766Sken	ocs_sem_init(&(result.semaphore), 0, "get_nv_wwnn");
2418331766Sken
2419331766Sken	if(ocs_hw_get_nvparms(&ocs->hw, ocs_mgmt_get_nvparms_cb, &result) == OCS_HW_RTN_SUCCESS) {
2420331766Sken		if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) {
2421331766Sken			/* Undefined failure */
2422331766Sken			ocs_log_err(ocs, "ocs_sem_p failed\n");
2423331766Sken			return;
2424331766Sken		}
2425331766Sken		if (result.status == 0) {
2426331766Sken			/* Success. Copy wwnn from result struct to result string */
2427331766Sken			ocs_snprintf(result_string, sizeof(result_string), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
2428331766Sken					result.wwnn[0], result.wwnn[1], result.wwnn[2],
2429331766Sken					result.wwnn[3], result.wwnn[4], result.wwnn[5],
2430331766Sken					result.wwnn[6], result.wwnn[7]);
2431331766Sken			ocs_mgmt_emit_string(textbuf, MGMT_MODE_RW, "nv_wwnn", result_string);
2432331766Sken		} else {
2433331766Sken			ocs_log_test(ocs, "getting wwnn status 0x%x\n", result.status);
2434331766Sken		}
2435331766Sken	}
2436331766Sken}
2437331766Sken
2438331766Sken/**
2439331766Sken * @brief Get accumulated node abort counts
2440331766Sken * @par Description Get the sum of all nodes abort count.
2441331766Sken *
2442331766Sken * @param ocs Pointer to the ocs structure.
2443331766Sken * @param name Name of the action being performed.
2444331766Sken * @param textbuf Pointer to an ocs_textbuf, which is used to return the results.
2445331766Sken *
2446331766Sken * @return None.
2447331766Sken */
2448331766Skenstatic void
2449331766Skenget_node_abort_cnt(ocs_t *ocs, char *name, ocs_textbuf_t *textbuf)
2450331766Sken{
2451331766Sken	uint32_t abort_counts = 0;
2452331766Sken	ocs_domain_t *domain;
2453331766Sken	ocs_sport_t *sport;
2454331766Sken	ocs_node_t *node;
2455331766Sken
2456331766Sken	if (ocs_device_lock_try(ocs) != TRUE) {
2457331766Sken		/* Didn't get the lock */
2458331766Sken		return;
2459331766Sken	}
2460331766Sken
2461331766Sken		/* Here the Device lock is held */
2462331766Sken		ocs_list_foreach(&ocs->domain_list, domain) {
2463331766Sken			if (ocs_domain_lock_try(domain) != TRUE) {
2464331766Sken				/* Didn't get the lock */
2465331766Sken				ocs_device_unlock(ocs);
2466331766Sken				return;
2467331766Sken			}
2468331766Sken
2469331766Sken				/* Here the Domain lock is held */
2470331766Sken				ocs_list_foreach(&domain->sport_list, sport) {
2471331766Sken					if (ocs_sport_lock_try(sport) != TRUE) {
2472331766Sken						/* Didn't get the lock */
2473331766Sken						ocs_domain_unlock(domain);
2474331766Sken						ocs_device_unlock(ocs);
2475331766Sken						return;
2476331766Sken					}
2477331766Sken
2478331766Sken						/* Here the sport lock is held */
2479331766Sken						ocs_list_foreach(&sport->node_list, node) {
2480331766Sken							abort_counts += node->abort_cnt;
2481331766Sken						}
2482331766Sken
2483331766Sken					ocs_sport_unlock(sport);
2484331766Sken				}
2485331766Sken
2486331766Sken			ocs_domain_unlock(domain);
2487331766Sken		}
2488331766Sken
2489331766Sken	ocs_device_unlock(ocs);
2490331766Sken
2491331766Sken	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "node_abort_cnt", "%d" , abort_counts);
2492331766Sken}
2493331766Sken
2494331766Skentypedef struct ocs_mgmt_set_nvparms_result {
2495331766Sken	ocs_sem_t semaphore;
2496331766Sken	int32_t status;
2497331766Sken} ocs_mgmt_set_nvparms_result_t;
2498331766Sken
2499331766Sken
2500331766Skenstatic void
2501331766Skenocs_mgmt_set_nvparms_cb(int32_t status, void *ul_arg)
2502331766Sken{
2503331766Sken	ocs_mgmt_get_profile_list_result_t *result = ul_arg;
2504331766Sken
2505331766Sken	result->status = status;
2506331766Sken
2507331766Sken	ocs_sem_v(&(result->semaphore));
2508331766Sken}
2509331766Sken
2510331766Sken/**
2511331766Sken * @brief  Set wwn
2512331766Sken * @par Description Sets the Non-volatile worldwide names,
2513331766Sken * if provided.
2514331766Sken *
2515331766Sken * @param ocs Pointer to the ocs structure.
2516331766Sken * @param name Name of the action being performed.
2517331766Sken * @param wwn_p Requested new WWN values.
2518331766Sken *
2519331766Sken * @return Returns 0 on success, non-zero on failure.
2520331766Sken */
2521331766Skenstatic int32_t
2522331766Skenset_nv_wwn(ocs_t *ocs, char *name, char *wwn_p)
2523331766Sken{
2524331766Sken	ocs_mgmt_get_nvparms_result_t result;
2525331766Sken	uint8_t new_wwpn[8];
2526331766Sken	uint8_t new_wwnn[8];
2527331766Sken	char *wwpn_p = NULL;
2528331766Sken	char *wwnn_p = NULL;
2529331766Sken	int32_t rc = -1;
2530331766Sken	int wwpn;
2531331766Sken	int wwnn;
2532331766Sken	int i;
2533331766Sken
2534331766Sken	/* This is a read-modify-write operation, so first we have to read
2535331766Sken	 * the current values
2536331766Sken	 */
2537331766Sken	ocs_sem_init(&(result.semaphore), 0, "set_nv_wwn1");
2538331766Sken
2539331766Sken	rc = ocs_hw_get_nvparms(&ocs->hw, ocs_mgmt_get_nvparms_cb, &result);
2540331766Sken
2541331766Sken	if (rc == OCS_HW_RTN_SUCCESS) {
2542331766Sken		if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) {
2543331766Sken			/* Undefined failure */
2544331766Sken			ocs_log_err(ocs, "ocs_sem_p failed\n");
2545331766Sken			return -ENXIO;
2546331766Sken		}
2547331766Sken		if (result.status != 0) {
2548331766Sken			ocs_log_test(ocs, "getting nvparms status 0x%x\n", result.status);
2549331766Sken			return -1;
2550331766Sken		}
2551331766Sken	}
2552331766Sken
2553331766Sken	/* wwn_p contains wwpn_p@wwnn_p values */
2554331766Sken	if (wwn_p != NULL) {
2555331766Sken		wwpn_p = ocs_strsep(&wwn_p, "@");
2556331766Sken		wwnn_p = wwn_p;
2557331766Sken	}
2558331766Sken
2559331766Sken	wwpn = ocs_strcmp(wwpn_p, "NA");
2560331766Sken	wwnn = ocs_strcmp(wwnn_p, "NA");
2561331766Sken
2562331766Sken	/* Parse the new WWPN */
2563331766Sken	if ((wwpn_p != NULL) && (wwpn != 0)) {
2564331766Sken		if (ocs_sscanf(wwpn_p, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
2565331766Sken				&(new_wwpn[0]), &(new_wwpn[1]), &(new_wwpn[2]),
2566331766Sken				&(new_wwpn[3]), &(new_wwpn[4]), &(new_wwpn[5]),
2567331766Sken				&(new_wwpn[6]), &(new_wwpn[7])) != 8) {
2568331766Sken			ocs_log_test(ocs, "can't parse WWPN %s\n", wwpn_p);
2569331766Sken			return -1;
2570331766Sken		}
2571331766Sken	}
2572331766Sken
2573331766Sken	/* Parse the new WWNN */
2574331766Sken	if ((wwnn_p != NULL) && (wwnn != 0 )) {
2575331766Sken		if (ocs_sscanf(wwnn_p, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
2576331766Sken				&(new_wwnn[0]), &(new_wwnn[1]), &(new_wwnn[2]),
2577331766Sken				&(new_wwnn[3]), &(new_wwnn[4]), &(new_wwnn[5]),
2578331766Sken				&(new_wwnn[6]), &(new_wwnn[7])) != 8) {
2579331766Sken			ocs_log_test(ocs, "can't parse WWNN %s\n", wwnn_p);
2580331766Sken			return -1;
2581331766Sken		}
2582331766Sken	}
2583331766Sken
2584331766Sken	for (i = 0; i < 8; i++) {
2585331766Sken		/* Use active wwpn, if new one is not provided */
2586331766Sken		if (wwpn == 0) {
2587331766Sken			new_wwpn[i] = result.wwpn[i];
2588331766Sken		}
2589331766Sken
2590331766Sken		/* Use active wwnn, if new one is not provided */
2591331766Sken		if (wwnn == 0) {
2592331766Sken			new_wwnn[i] = result.wwnn[i];
2593331766Sken		}
2594331766Sken	}
2595331766Sken
2596331766Sken	/* Modify the nv_wwnn and nv_wwpn, then write it back */
2597331766Sken	ocs_sem_init(&(result.semaphore), 0, "set_nv_wwn2");
2598331766Sken
2599331766Sken	rc = ocs_hw_set_nvparms(&ocs->hw, ocs_mgmt_set_nvparms_cb, new_wwpn,
2600331766Sken				 new_wwnn, result.hard_alpa, result.preferred_d_id,
2601331766Sken				 &result);
2602331766Sken	if (rc == OCS_HW_RTN_SUCCESS) {
2603331766Sken		if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) {
2604331766Sken			/* Undefined failure */
2605331766Sken			ocs_log_err(ocs, "ocs_sem_p failed\n");
2606331766Sken			return -ENXIO;
2607331766Sken		}
2608331766Sken		if (result.status != 0) {
2609331766Sken			ocs_log_test(ocs, "setting wwn status 0x%x\n", result.status);
2610331766Sken			return -1;
2611331766Sken		}
2612331766Sken	}
2613331766Sken
2614331766Sken	return rc;
2615331766Sken}
2616331766Sken
2617331766Skenstatic int
2618331766Skenset_tgt_rscn_delay(ocs_t *ocs, char *name, char *value)
2619331766Sken{
2620331766Sken	ocs->tgt_rscn_delay_msec = ocs_strtoul(value, NULL, 0) * 1000;
2621331766Sken	ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value);
2622331766Sken	return 0;
2623331766Sken}
2624331766Sken
2625331766Skenstatic int
2626331766Skenset_tgt_rscn_period(ocs_t *ocs, char *name, char *value)
2627331766Sken{
2628331766Sken	ocs->tgt_rscn_period_msec = ocs_strtoul(value, NULL, 0) * 1000;
2629331766Sken	ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value);
2630331766Sken	return 0;
2631331766Sken}
2632331766Sken
2633331766Skenstatic int
2634331766Skenset_inject_drop_cmd(ocs_t *ocs, char *name, char *value)
2635331766Sken{
2636331766Sken	ocs->err_injection = (ocs_strtoul(value, NULL, 0) == 0 ? NO_ERR_INJECT : INJECT_DROP_CMD);
2637331766Sken	ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value);
2638331766Sken	return 0;
2639331766Sken}
2640331766Sken
2641331766Skenstatic int
2642331766Skenset_inject_free_drop_cmd(ocs_t *ocs, char *name, char *value)
2643331766Sken{
2644331766Sken	ocs->err_injection = (ocs_strtoul(value, NULL, 0) == 0 ? NO_ERR_INJECT : INJECT_FREE_DROPPED);
2645331766Sken	ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value);
2646331766Sken	return 0;
2647331766Sken}
2648331766Sken
2649331766Skenstatic int
2650331766Skenset_inject_drop_data(ocs_t *ocs, char *name, char *value)
2651331766Sken{
2652331766Sken	ocs->err_injection = (ocs_strtoul(value, NULL, 0) == 0 ? NO_ERR_INJECT : INJECT_DROP_DATA);
2653331766Sken	ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value);
2654331766Sken	return 0;
2655331766Sken}
2656331766Sken
2657331766Skenstatic int
2658331766Skenset_inject_drop_resp(ocs_t *ocs, char *name, char *value)
2659331766Sken{
2660331766Sken	ocs->err_injection = (ocs_strtoul(value, NULL, 0) == 0 ? NO_ERR_INJECT : INJECT_DROP_RESP);
2661331766Sken	ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value);
2662331766Sken	return 0;
2663331766Sken}
2664331766Sken
2665331766Skenstatic int
2666331766Skenset_cmd_err_inject(ocs_t *ocs, char *name, char *value)
2667331766Sken{
2668331766Sken	ocs->cmd_err_inject = ocs_strtoul(value, NULL, 0);
2669331766Sken	ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value);
2670331766Sken	return 0;
2671331766Sken}
2672331766Sken
2673331766Skenstatic int
2674331766Skenset_cmd_delay_value(ocs_t *ocs, char *name, char *value)
2675331766Sken{
2676331766Sken	ocs->delay_value_msec = ocs_strtoul(value, NULL, 0);
2677331766Sken	ocs->err_injection = (ocs->delay_value_msec == 0 ? NO_ERR_INJECT : INJECT_DELAY_CMD);
2678331766Sken	ocs_log_debug(ocs, "mgmt set: %s %s\n", name, value);
2679331766Sken	return 0;
2680331766Sken}
2681331766Sken
2682331766Sken/**
2683331766Sken * @brief parse a WWN from a string into a 64-bit value
2684331766Sken *
2685331766Sken * Given a pointer to a string, parse the string into a 64-bit
2686331766Sken * WWN value.  The format of the string must be xx:xx:xx:xx:xx:xx:xx:xx
2687331766Sken *
2688331766Sken * @param wwn_in pointer to the string to be parsed
2689331766Sken * @param wwn_out pointer to uint64_t in which to put the parsed result
2690331766Sken *
2691331766Sken * @return 0 if successful, non-zero if the WWN is malformed and couldn't be parsed
2692331766Sken */
2693331766Skenint
2694331766Skenparse_wwn(char *wwn_in, uint64_t *wwn_out)
2695331766Sken{
2696331766Sken	uint8_t byte0;
2697331766Sken	uint8_t byte1;
2698331766Sken	uint8_t byte2;
2699331766Sken	uint8_t byte3;
2700331766Sken	uint8_t byte4;
2701331766Sken	uint8_t byte5;
2702331766Sken	uint8_t byte6;
2703331766Sken	uint8_t byte7;
2704331766Sken	int rc;
2705331766Sken
2706331766Sken	rc = ocs_sscanf(wwn_in, "0x%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
2707331766Sken				&byte0, &byte1, &byte2, &byte3,
2708331766Sken				&byte4, &byte5, &byte6, &byte7);
2709331766Sken
2710331766Sken	if (rc == 8) {
2711331766Sken		*wwn_out = ((uint64_t)byte0 << 56) |
2712331766Sken				((uint64_t)byte1 << 48) |
2713331766Sken				((uint64_t)byte2 << 40) |
2714331766Sken				((uint64_t)byte3 << 32) |
2715331766Sken				((uint64_t)byte4 << 24) |
2716331766Sken				((uint64_t)byte5 << 16) |
2717331766Sken				((uint64_t)byte6 <<  8) |
2718331766Sken				((uint64_t)byte7);
2719331766Sken		return 0;
2720331766Sken
2721331766Sken	} else {
2722331766Sken		return 1;
2723331766Sken	}
2724331766Sken}
2725331766Sken
2726331766Sken
2727331766Sken
2728331766Skenstatic char *mode_string(int mode);
2729331766Sken
2730331766Sken
2731331766Sken/**
2732331766Sken * @ingroup mgmt
2733331766Sken * @brief Generate the beginning of a numbered section in a management XML document.
2734331766Sken *
2735331766Sken * @par Description
2736331766Sken * This function begins a section. The XML information is appended to
2737331766Sken * the textbuf. This form of the function is used for sections that might have
2738331766Sken * multiple instances, such as a node or a SLI Port (sport). The index number
2739331766Sken * is appended to the name.
2740331766Sken *
2741331766Sken * @param textbuf Pointer to the driver dump text buffer.
2742331766Sken * @param name Name of the section.
2743331766Sken * @param index Index number of this instance of the section.
2744331766Sken *
2745331766Sken * @return None.
2746331766Sken */
2747331766Sken
2748331766Skenextern void ocs_mgmt_start_section(ocs_textbuf_t *textbuf, const char *name, int index)
2749331766Sken{
2750331766Sken	ocs_textbuf_printf(textbuf, "<%s instance=\"%d\">\n", name, index);
2751331766Sken}
2752331766Sken
2753331766Sken/**
2754331766Sken * @ingroup mgmt
2755331766Sken * @brief Generate the beginning of an unnumbered section in a management XML document.
2756331766Sken *
2757331766Sken * @par Description
2758331766Sken * This function begins a section. The XML information is appended to
2759331766Sken * the textbuf. This form of the function is used for sections that have
2760331766Sken * a single instance only. Therefore, no index number is needed.
2761331766Sken *
2762331766Sken * @param textbuf Pointer to the driver dump text buffer.
2763331766Sken * @param name Name of the section.
2764331766Sken *
2765331766Sken * @return None.
2766331766Sken */
2767331766Sken
2768331766Skenextern void ocs_mgmt_start_unnumbered_section(ocs_textbuf_t *textbuf, const char *name)
2769331766Sken{
2770331766Sken	ocs_textbuf_printf(textbuf, "<%s>\n", name);
2771331766Sken}
2772331766Sken
2773331766Sken/**
2774331766Sken * @ingroup mgmt
2775331766Sken * @brief Generate the end of a section in a management XML document.
2776331766Sken *
2777331766Sken * @par Description
2778331766Sken * This function ends a section. The XML information is appended to
2779331766Sken * the textbuf.
2780331766Sken *
2781331766Sken * @param textbuf Pointer to the driver dump text buffer.
2782331766Sken * @param name Name of the section.
2783331766Sken *
2784331766Sken * @return None.
2785331766Sken */
2786331766Sken
2787331766Skenvoid ocs_mgmt_end_unnumbered_section(ocs_textbuf_t *textbuf, const char *name)
2788331766Sken{
2789331766Sken	ocs_textbuf_printf(textbuf, "</%s>\n", name);
2790331766Sken}
2791331766Sken
2792331766Sken/**
2793331766Sken * @ingroup mgmt
2794331766Sken * @brief Generate the indexed end of a section in a management XML document.
2795331766Sken *
2796331766Sken * @par Description
2797331766Sken * This function ends a section. The XML information is appended to
2798331766Sken * the textbuf.
2799331766Sken *
2800331766Sken * @param textbuf Pointer to the driver dump text buffer.
2801331766Sken * @param name Name of the section.
2802331766Sken * @param index Index number of this instance of the section.
2803331766Sken *
2804331766Sken * @return None.
2805331766Sken */
2806331766Sken
2807331766Skenvoid ocs_mgmt_end_section(ocs_textbuf_t *textbuf, const char *name, int index)
2808331766Sken{
2809331766Sken
2810331766Sken	ocs_textbuf_printf(textbuf, "</%s>\n", name);
2811331766Sken
2812331766Sken}
2813331766Sken
2814331766Sken/**
2815331766Sken * @ingroup mgmt
2816331766Sken * @brief Generate a property, with no value, in a management XML document.
2817331766Sken *
2818331766Sken * @par Description
2819331766Sken * This function generates a property name. The XML information is appended to
2820331766Sken * the textbuf. This form of the function is used by the list functions
2821331766Sken * when the property name only (and not the current value) is given.
2822331766Sken *
2823331766Sken * @param textbuf Pointer to the driver dump text buffer.
2824331766Sken * @param mode Defines whether the property is read(r)/write(w)/executable(x).
2825331766Sken * @param name Name of the property.
2826331766Sken *
2827331766Sken * @return None.
2828331766Sken */
2829331766Sken
2830331766Skenvoid ocs_mgmt_emit_property_name(ocs_textbuf_t *textbuf, int mode, const char *name)
2831331766Sken{
2832331766Sken	ocs_textbuf_printf(textbuf, "<%s mode=\"%s\"/>\n", name, mode_string(mode));
2833331766Sken}
2834331766Sken
2835331766Sken/**
2836331766Sken * @ingroup mgmt
2837331766Sken * @brief Generate a property with a string value in a management XML document.
2838331766Sken *
2839331766Sken * @par Description
2840331766Sken * This function generates a property name and a string value.
2841331766Sken * The XML information is appended to the textbuf.
2842331766Sken *
2843331766Sken * @param textbuf Pointer to the driver dump text buffer.
2844331766Sken * @param mode Defines whether the property is read(r)/write(w)/executable(x).
2845331766Sken * @param name Name of the property.
2846331766Sken * @param value Value of the property.
2847331766Sken *
2848331766Sken * @return None.
2849331766Sken */
2850331766Sken
2851331766Skenvoid ocs_mgmt_emit_string(ocs_textbuf_t *textbuf, int mode, const char *name, const char *value)
2852331766Sken{
2853331766Sken	ocs_textbuf_printf(textbuf, "<%s mode=\"%s\">%s</%s>\n", name, mode_string(mode), value, name);
2854331766Sken}
2855331766Sken
2856331766Sken/**
2857331766Sken * @ingroup mgmt
2858331766Sken * @brief Generate a property with an integer value in a management XML document.
2859331766Sken *
2860331766Sken * @par Description
2861331766Sken * This function generates a property name and an integer value.
2862331766Sken * The XML information is appended to the textbuf.
2863331766Sken *
2864331766Sken * @param textbuf Pointer to driver dump text buffer.
2865331766Sken * @param mode Defines whether the property is read(r)/write(w)/executable(x).
2866331766Sken * @param name Name of the property.
2867331766Sken * @param fmt A printf format for formatting the integer value.
2868331766Sken *
2869331766Sken * @return none
2870331766Sken */
2871331766Sken
2872331766Skenvoid ocs_mgmt_emit_int(ocs_textbuf_t *textbuf, int mode, const char *name, const char *fmt, ...)
2873331766Sken{
2874331766Sken	va_list ap;
2875331766Sken	char valuebuf[64];
2876331766Sken
2877331766Sken	va_start(ap, fmt);
2878331766Sken	ocs_vsnprintf(valuebuf, sizeof(valuebuf), fmt, ap);
2879331766Sken	va_end(ap);
2880331766Sken
2881331766Sken	ocs_textbuf_printf(textbuf, "<%s mode=\"%s\">%s</%s>\n", name, mode_string(mode), valuebuf, name);
2882331766Sken}
2883331766Sken
2884331766Sken/**
2885331766Sken * @ingroup mgmt
2886331766Sken * @brief Generate a property with a boolean value in a management XML document.
2887331766Sken *
2888331766Sken * @par Description
2889331766Sken * This function generates a property name and a boolean value.
2890331766Sken * The XML information is appended to the textbuf.
2891331766Sken *
2892331766Sken * @param textbuf Pointer to the driver dump text buffer.
2893331766Sken * @param mode Defines whether the property is read(r)/write(w)/executable(x).
2894331766Sken * @param name Name of the property.
2895331766Sken * @param value Boolean value to be added to the textbuf.
2896331766Sken *
2897331766Sken * @return None.
2898331766Sken */
2899331766Sken
2900331766Skenvoid ocs_mgmt_emit_boolean(ocs_textbuf_t *textbuf, int mode, const char *name, int value)
2901331766Sken{
2902331766Sken	char *valuebuf = value ? "true" : "false";
2903331766Sken
2904331766Sken	ocs_textbuf_printf(textbuf, "<%s mode=\"%s\">%s</%s>\n", name, mode_string(mode), valuebuf, name);
2905331766Sken}
2906331766Sken
2907331766Skenstatic char *mode_string(int mode)
2908331766Sken{
2909331766Sken	static char mode_str[4];
2910331766Sken
2911331766Sken	mode_str[0] = '\0';
2912331766Sken	if (mode & MGMT_MODE_RD) {
2913331766Sken		strcat(mode_str, "r");
2914331766Sken	}
2915331766Sken	if (mode & MGMT_MODE_WR) {
2916331766Sken		strcat(mode_str, "w");
2917331766Sken	}
2918331766Sken	if (mode & MGMT_MODE_EX) {
2919331766Sken		strcat(mode_str, "x");
2920331766Sken	}
2921331766Sken
2922331766Sken	return mode_str;
2923331766Sken
2924331766Sken}
2925