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