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