]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ocs_fc/ocs_ioctl.c
Fix downgrading of TOE TLS sockets to plain TOE.
[FreeBSD/FreeBSD.git] / sys / dev / ocs_fc / ocs_ioctl.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 #include "ocs.h"
35 #include "ocs_utils.h"
36
37 #include <sys/conf.h>
38 #include <sys/sysctl.h>
39 #include <sys/ioccom.h>
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/linker.h>
43 #include <sys/firmware.h>
44
45 static d_open_t         ocs_open;
46 static d_close_t        ocs_close;
47 static d_ioctl_t        ocs_ioctl;
48
49 static struct cdevsw ocs_cdevsw = {
50         .d_version =    D_VERSION,
51         .d_open =       ocs_open,
52         .d_close =      ocs_close,
53         .d_ioctl =      ocs_ioctl,
54         .d_name =       "ocs_fc"
55 };
56
57 int
58 ocs_firmware_write(ocs_t *ocs, const uint8_t *buf, size_t buf_len, uint8_t *change_status);
59
60 static int
61 ocs_open(struct cdev *cdev, int flags, int fmt, struct thread *td)
62 {
63 #if 0
64         struct ocs_softc *ocs = cdev->si_drv1;
65
66         device_printf(ocs->dev, "%s\n", __func__);
67 #endif
68         return 0;
69 }
70
71 static int
72 ocs_close(struct cdev *cdev, int flag, int fmt, struct thread *td)
73 {
74 #if 0
75         struct ocs_softc *ocs = cdev->si_drv1;
76
77         device_printf(ocs->dev, "%s\n", __func__);
78 #endif
79         return 0;
80 }
81
82 static int32_t
83 __ocs_ioctl_mbox_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
84 {
85         struct ocs_softc *ocs = arg;
86
87         /* wait for the ioctl to sleep before calling wakeup */
88         mtx_lock(&ocs->dbg_lock);
89
90         mtx_unlock(&ocs->dbg_lock);
91
92         wakeup(arg);
93
94         return 0;
95 }
96
97 static int
98 ocs_process_sli_config (ocs_t *ocs, ocs_ioctl_elxu_mbox_t *mcmd, ocs_dma_t *dma){
99         sli4_cmd_sli_config_t *sli_config = (sli4_cmd_sli_config_t *)mcmd->payload;
100
101         if (sli_config->emb) {
102                 sli4_req_hdr_t  *req = (sli4_req_hdr_t *)sli_config->payload.embed;
103
104                 switch (req->opcode) {
105                 case SLI4_OPC_COMMON_READ_OBJECT:
106                         if (mcmd->out_bytes) {
107                                 sli4_req_common_read_object_t *rdobj =
108                                         (sli4_req_common_read_object_t *)sli_config->payload.embed;
109
110                                 if (ocs_dma_alloc(ocs, dma, mcmd->out_bytes, 4096)) {
111                                         device_printf(ocs->dev, "%s: COMMON_READ_OBJECT - %lld allocation failed\n",
112                                                         __func__, (unsigned long long)mcmd->out_bytes);
113                                         return ENXIO;
114                                 }
115
116                                 memset(dma->virt, 0, mcmd->out_bytes);
117
118                                 rdobj->host_buffer_descriptor[0].bde_type = SLI4_BDE_TYPE_BDE_64;
119                                 rdobj->host_buffer_descriptor[0].buffer_length = mcmd->out_bytes;
120                                 rdobj->host_buffer_descriptor[0].u.data.buffer_address_low = ocs_addr32_lo(dma->phys);
121                                 rdobj->host_buffer_descriptor[0].u.data.buffer_address_high = ocs_addr32_hi(dma->phys);
122                         }
123                         break;
124                 case SLI4_OPC_COMMON_WRITE_OBJECT:
125                 {
126                         sli4_req_common_write_object_t *wrobj =
127                                 (sli4_req_common_write_object_t *)sli_config->payload.embed;
128
129                         if (ocs_dma_alloc(ocs, dma, wrobj->desired_write_length, 4096)) {
130                                 device_printf(ocs->dev, "%s: COMMON_WRITE_OBJECT - %d allocation failed\n",
131                                                 __func__, wrobj->desired_write_length);
132                                 return ENXIO;
133                         }
134                         /* setup the descriptor */
135                         wrobj->host_buffer_descriptor[0].bde_type = SLI4_BDE_TYPE_BDE_64;
136                         wrobj->host_buffer_descriptor[0].buffer_length = wrobj->desired_write_length;
137                         wrobj->host_buffer_descriptor[0].u.data.buffer_address_low = ocs_addr32_lo(dma->phys);
138                         wrobj->host_buffer_descriptor[0].u.data.buffer_address_high = ocs_addr32_hi(dma->phys);
139
140                         /* copy the data into the DMA buffer */
141                         copyin((void *)(uintptr_t)mcmd->in_addr, dma->virt, mcmd->in_bytes);
142                 }
143                         break;
144                 case SLI4_OPC_COMMON_DELETE_OBJECT:
145                         break;
146                 case SLI4_OPC_COMMON_READ_OBJECT_LIST:
147                         if (mcmd->out_bytes) {
148                                 sli4_req_common_read_object_list_t *rdobj =
149                                         (sli4_req_common_read_object_list_t *)sli_config->payload.embed;
150
151                                 if (ocs_dma_alloc(ocs, dma, mcmd->out_bytes, 4096)) {
152                                         device_printf(ocs->dev, "%s: COMMON_READ_OBJECT_LIST - %lld allocation failed\n",
153                                                         __func__,(unsigned long long) mcmd->out_bytes);
154                                         return ENXIO;
155                                 }
156
157                                 memset(dma->virt, 0, mcmd->out_bytes);
158
159                                 rdobj->host_buffer_descriptor[0].bde_type = SLI4_BDE_TYPE_BDE_64;
160                                 rdobj->host_buffer_descriptor[0].buffer_length = mcmd->out_bytes;
161                                 rdobj->host_buffer_descriptor[0].u.data.buffer_address_low = ocs_addr32_lo(dma->phys);
162                                 rdobj->host_buffer_descriptor[0].u.data.buffer_address_high = ocs_addr32_hi(dma->phys);
163                         }
164                         break;
165                 case SLI4_OPC_COMMON_READ_TRANSCEIVER_DATA:
166                         break;
167                 default:
168                         device_printf(ocs->dev, "%s: in=%p (%lld) out=%p (%lld)\n", __func__,
169                                         (void *)(uintptr_t)mcmd->in_addr, (unsigned long long)mcmd->in_bytes,
170                                         (void *)(uintptr_t)mcmd->out_addr, (unsigned long long)mcmd->out_bytes);
171                         device_printf(ocs->dev, "%s: unknown (opc=%#x)\n", __func__,
172                                         req->opcode);
173                         hexdump(mcmd, mcmd->size, NULL, 0);
174                         break;
175                 }
176         } else {
177                 uint32_t max_bytes = max(mcmd->in_bytes, mcmd->out_bytes);
178                 if (ocs_dma_alloc(ocs, dma, max_bytes, 4096)) {
179                         device_printf(ocs->dev, "%s: non-embedded - %u allocation failed\n",
180                                         __func__, max_bytes);
181                         return ENXIO;
182                 }
183
184                 copyin((void *)(uintptr_t)mcmd->in_addr, dma->virt, mcmd->in_bytes);
185
186                 sli_config->payload.mem.address_low  = ocs_addr32_lo(dma->phys);
187                 sli_config->payload.mem.address_high = ocs_addr32_hi(dma->phys);
188                 sli_config->payload.mem.length       = max_bytes;
189         }
190
191         return 0;
192 }
193
194 static int
195 ocs_process_mbx_ioctl(ocs_t *ocs, ocs_ioctl_elxu_mbox_t *mcmd)
196 {
197         ocs_dma_t       dma = { 0 };
198
199         if ((ELXU_BSD_MAGIC != mcmd->magic) ||
200                         (sizeof(ocs_ioctl_elxu_mbox_t) != mcmd->size)) {
201                 device_printf(ocs->dev, "%s: malformed command m=%08x s=%08x\n",
202                                 __func__, mcmd->magic, mcmd->size);
203                 return EINVAL;
204         }
205
206         switch(((sli4_mbox_command_header_t *)mcmd->payload)->command) {
207         case SLI4_MBOX_COMMAND_SLI_CONFIG:
208                 if (ENXIO == ocs_process_sli_config(ocs, mcmd, &dma))
209                         return ENXIO;
210                 break;
211
212         case SLI4_MBOX_COMMAND_READ_REV:
213         case SLI4_MBOX_COMMAND_READ_STATUS:
214         case SLI4_MBOX_COMMAND_READ_LNK_STAT:
215                 break;
216
217         default:
218                 device_printf(ocs->dev, "command %d\n",((sli4_mbox_command_header_t *)mcmd->payload)->command);
219                 device_printf(ocs->dev, "%s, command not support\n", __func__);
220                 goto no_support;
221                 break;
222         }
223
224         /*
225          * The dbg_lock usage here insures the command completion code
226          * (__ocs_ioctl_mbox_cb), which calls wakeup(), does not run until
227          * after first calling msleep()
228          *
229          *  1. ioctl grabs dbg_lock
230          *  2. ioctl issues command
231          *       if the command completes before msleep(), the
232          *       command completion code (__ocs_ioctl_mbox_cb) will spin
233          *       on dbg_lock before calling wakeup()
234          *  3. ioctl calls msleep which releases dbg_lock before sleeping
235          *     and reacquires it before waking
236          *  4. command completion handler acquires the dbg_lock, immediately
237          *     releases it, and calls wakeup
238          *  5. msleep returns, re-acquiring the lock
239          *  6. ioctl code releases the lock
240          */
241         mtx_lock(&ocs->dbg_lock);
242         if (ocs_hw_command(&ocs->hw, mcmd->payload, OCS_CMD_NOWAIT,
243                         __ocs_ioctl_mbox_cb, ocs)) {
244                 device_printf(ocs->dev, "%s: command- %x failed\n", __func__,
245                         ((sli4_mbox_command_header_t *)mcmd->payload)->command);
246         }
247         msleep(ocs, &ocs->dbg_lock, 0, "ocsmbx", 0);
248         mtx_unlock(&ocs->dbg_lock);
249
250         if( SLI4_MBOX_COMMAND_SLI_CONFIG == ((sli4_mbox_command_header_t *)mcmd->payload)->command
251                         && mcmd->out_bytes && dma.virt) {
252                 copyout(dma.virt, (void *)(uintptr_t)mcmd->out_addr, mcmd->out_bytes);
253         }
254
255 no_support:
256         ocs_dma_free(ocs, &dma);
257
258         return 0;
259 }
260
261 /**
262  * @brief perform requested Elx CoreDump helper function
263  *
264  * The Elx CoreDump facility used for BE3 diagnostics uses the OCS_IOCTL_CMD_ECD_HELPER
265  * ioctl function to execute requested "help" functions
266  *
267  * @param ocs pointer to ocs structure
268  * @param req pointer to helper function request
269  *
270  * @return returns 0 for success, a negative error code value for failure.
271  */
272
273 static int
274 ocs_process_ecd_helper (ocs_t *ocs, ocs_ioctl_ecd_helper_t *req)
275 {
276         int32_t rc = 0;
277         uint8_t v8;
278         uint16_t v16;
279         uint32_t v32;
280
281         /* Check the BAR read/write commands for valid bar */
282         switch(req->cmd) {
283         case OCS_ECD_HELPER_BAR_READ8:
284         case OCS_ECD_HELPER_BAR_READ16:
285         case OCS_ECD_HELPER_BAR_READ32:
286         case OCS_ECD_HELPER_BAR_WRITE8:
287         case OCS_ECD_HELPER_BAR_WRITE16:
288         case OCS_ECD_HELPER_BAR_WRITE32:
289                 if (req->bar >= PCI_MAX_BAR) {
290                         device_printf(ocs->dev, "Error: bar %d out of range\n", req->bar);
291                         return -EFAULT;
292                 }
293                 if (ocs->reg[req->bar].res == NULL) {
294                         device_printf(ocs->dev, "Error: bar %d not defined\n", req->bar);
295                         return -EFAULT;
296                 }
297                 break;
298         default:
299                 break;
300         }
301
302         switch(req->cmd) {
303         case OCS_ECD_HELPER_CFG_READ8:
304                 v8 = ocs_config_read8(ocs, req->offset);
305                 req->data = v8;
306                 break;
307         case OCS_ECD_HELPER_CFG_READ16:
308                 v16 = ocs_config_read16(ocs, req->offset);
309                 req->data = v16;
310                 break;
311         case OCS_ECD_HELPER_CFG_READ32:
312                 v32 = ocs_config_read32(ocs, req->offset);
313                 req->data = v32;
314                 break;
315         case OCS_ECD_HELPER_CFG_WRITE8:
316                 ocs_config_write8(ocs, req->offset, req->data);
317                 break;
318         case OCS_ECD_HELPER_CFG_WRITE16:
319                 ocs_config_write16(ocs, req->offset, req->data);
320                 break;
321         case OCS_ECD_HELPER_CFG_WRITE32:
322                 ocs_config_write32(ocs, req->offset, req->data);
323                 break;
324         case OCS_ECD_HELPER_BAR_READ8:
325                 req->data = ocs_reg_read8(ocs, req->bar, req->offset);
326                 break;
327         case OCS_ECD_HELPER_BAR_READ16:
328                 req->data = ocs_reg_read16(ocs, req->bar, req->offset);
329                 break;
330         case OCS_ECD_HELPER_BAR_READ32:
331                 req->data = ocs_reg_read32(ocs, req->bar, req->offset);
332                 break;
333         case OCS_ECD_HELPER_BAR_WRITE8:
334                 ocs_reg_write8(ocs, req->bar, req->offset, req->data);
335                 break;
336         case OCS_ECD_HELPER_BAR_WRITE16:
337                 ocs_reg_write16(ocs, req->bar, req->offset, req->data);
338                 break;
339         case OCS_ECD_HELPER_BAR_WRITE32:
340                 ocs_reg_write32(ocs, req->bar, req->offset, req->data);
341                 break;
342         default:
343                 device_printf(ocs->dev, "Invalid helper command=%d\n", req->cmd);
344                 break;
345         }
346
347         return rc;
348 }
349
350 static int
351 ocs_ioctl(struct cdev *cdev, u_long cmd, caddr_t addr, int flag, struct thread *td)
352 {
353         int status = 0;
354         struct ocs_softc *ocs = cdev->si_drv1;
355         device_t dev = ocs->dev;
356
357         switch (cmd) {
358         case OCS_IOCTL_CMD_ELXU_MBOX: {
359                 /* "copyin" done by kernel; thus, just dereference addr */
360                 ocs_ioctl_elxu_mbox_t *mcmd = (void *)addr;
361                 status = ocs_process_mbx_ioctl(ocs, mcmd);
362                 break;
363         }
364         case OCS_IOCTL_CMD_ECD_HELPER: {
365                 /* "copyin" done by kernel; thus, just dereference addr */
366                 ocs_ioctl_ecd_helper_t *req = (void *)addr;
367                 status = ocs_process_ecd_helper(ocs, req);
368                 break;
369         }
370
371         case OCS_IOCTL_CMD_VPORT: {
372                 int32_t rc = 0;
373                 ocs_ioctl_vport_t *req = (ocs_ioctl_vport_t*) addr;
374                 ocs_domain_t *domain;
375
376                 domain = ocs_domain_get_instance(ocs, req->domain_index);
377                 if (domain == NULL) {
378                         device_printf(ocs->dev, "domain [%d] nod found\n",
379                                                         req->domain_index);
380                         return -EFAULT;
381                 }
382
383                 if (req->req_create) {
384                         rc = ocs_sport_vport_new(domain, req->wwpn, req->wwnn, 
385                                                 UINT32_MAX, req->enable_ini,
386                                         req->enable_tgt, NULL, NULL, TRUE);
387                 } else {
388                         rc = ocs_sport_vport_del(ocs, domain, req->wwpn, req->wwnn);
389                 }
390
391                 return rc;
392         }
393
394         case OCS_IOCTL_CMD_GET_DDUMP: {
395                 ocs_ioctl_ddump_t *req = (ocs_ioctl_ddump_t*) addr;
396                 ocs_textbuf_t textbuf;
397                 int x;
398
399                 /* Build a text buffer */
400                 if (ocs_textbuf_alloc(ocs, &textbuf, req->user_buffer_len)) {
401                         device_printf(ocs->dev, "Error: ocs_textbuf_alloc failed\n");
402                         return -EFAULT;
403                 }
404
405                 switch (req->args.action) {
406                 case OCS_IOCTL_DDUMP_GET:
407                 case OCS_IOCTL_DDUMP_GET_SAVED: {
408                         uint32_t remaining;
409                         uint32_t written;
410                         uint32_t idx;
411                         int32_t n;
412                         ocs_textbuf_t *ptbuf = NULL;
413                         uint32_t flags = 0;
414
415                         if (req->args.action == OCS_IOCTL_DDUMP_GET_SAVED) {
416                                 if (ocs_textbuf_initialized(&ocs->ddump_saved)) {
417                                         ptbuf = &ocs->ddump_saved;
418                                 }
419                         } else {
420                                 if (ocs_textbuf_alloc(ocs, &textbuf, req->user_buffer_len)) {
421                                         ocs_log_err(ocs, "Error: ocs_textbuf_alloc failed\n");
422                                         return -EFAULT;
423                                 }
424
425                                 /* translate IOCTL ddump flags to ddump flags */
426                                 if (req->args.flags & OCS_IOCTL_DDUMP_FLAGS_WQES) {
427                                         flags |= OCS_DDUMP_FLAGS_WQES;
428                                 }
429                                 if (req->args.flags & OCS_IOCTL_DDUMP_FLAGS_CQES) {
430                                         flags |= OCS_DDUMP_FLAGS_CQES;
431                                 }
432                                 if (req->args.flags & OCS_IOCTL_DDUMP_FLAGS_MQES) {
433                                         flags |= OCS_DDUMP_FLAGS_MQES;
434                                 }
435                                 if (req->args.flags & OCS_IOCTL_DDUMP_FLAGS_RQES) {
436                                         flags |= OCS_DDUMP_FLAGS_RQES;
437                                 }
438                                 if (req->args.flags & OCS_IOCTL_DDUMP_FLAGS_EQES) {
439                                         flags |= OCS_DDUMP_FLAGS_EQES;
440                                 }
441
442                                 /* Try 3 times to get the dump */
443                                 for(x=0; x<3; x++) {
444                                         if (ocs_ddump(ocs, &textbuf, flags, req->args.q_entries) != 0) {
445                                                 ocs_textbuf_reset(&textbuf);
446                                         } else {
447                                                 /* Success */
448                                                 x = 0;
449                                                 break;
450                                         }
451                                 }
452                                 if (x != 0 ) {
453                                         /* Retries failed */
454                                         ocs_log_test(ocs, "ocs_ddump failed\n");
455                                 } else {
456                                         ptbuf = &textbuf;
457                                 }
458                         }
459                         written = 0;
460                         if (ptbuf != NULL) {
461                                 /* Process each textbuf segment */
462                                 remaining = req->user_buffer_len;
463                                 for (idx = 0; remaining; idx++) {
464                                         n = ocs_textbuf_ext_get_written(ptbuf, idx);
465                                         if (n < 0) {
466                                                 break;
467                                         }
468                                         if ((uint32_t)n >= remaining) {
469                                                 n = (int32_t)remaining;
470                                         }
471                                         if (ocs_copy_to_user(req->user_buffer + written,
472                                                 ocs_textbuf_ext_get_buffer(ptbuf, idx), n)) {
473                                                 ocs_log_test(ocs, "Error: (%d) ocs_copy_to_user failed\n", __LINE__);
474                                         }
475                                         written += n;
476                                         remaining -= (uint32_t)n;
477                                 }
478                         }
479                         req->bytes_written = written;
480                         if (ptbuf == &textbuf) {
481                                 ocs_textbuf_free(ocs, &textbuf);
482                         }
483
484                         break;
485                 }
486                 case OCS_IOCTL_DDUMP_CLR_SAVED:
487                         ocs_clear_saved_ddump(ocs);
488                         break;
489                 default:
490                         ocs_log_err(ocs, "Error: ocs_textbuf_alloc failed\n");
491                         break;
492                 }
493                 break;
494         }
495         case OCS_IOCTL_CMD_DRIVER_INFO: {
496                 ocs_ioctl_driver_info_t *req = (ocs_ioctl_driver_info_t*)addr;
497
498                 ocs_memset(req, 0, sizeof(*req));
499
500                 req->pci_vendor = ocs->pci_vendor;
501                 req->pci_device = ocs->pci_device;
502                 ocs_strncpy(req->businfo, ocs->businfo, sizeof(req->businfo));
503
504                 req->sli_intf = ocs_config_read32(ocs, SLI4_INTF_REG);
505                 ocs_strncpy(req->desc, device_get_desc(dev), sizeof(req->desc));
506                 ocs_strncpy(req->fw_rev, ocs->fwrev, sizeof(req->fw_rev));
507                 if (ocs->domain && ocs->domain->sport) {
508                         *((uint64_t*)req->hw_addr.fc.wwnn) = ocs_htobe64(ocs->domain->sport->wwnn);
509                         *((uint64_t*)req->hw_addr.fc.wwpn) = ocs_htobe64(ocs->domain->sport->wwpn);
510                 }
511                 ocs_strncpy(req->serialnum, ocs->serialnum, sizeof(req->serialnum));
512                 break;
513         }
514
515         case OCS_IOCTL_CMD_MGMT_LIST: {
516                 ocs_ioctl_mgmt_buffer_t* req = (ocs_ioctl_mgmt_buffer_t *)addr;
517                 ocs_textbuf_t textbuf;
518
519                 /* Build a text buffer */
520                 if (ocs_textbuf_alloc(ocs, &textbuf, req->user_buffer_len)) {
521                         ocs_log_err(ocs, "Error: ocs_textbuf_alloc failed\n");
522                         return -EFAULT;
523                 }
524
525                 ocs_mgmt_get_list(ocs, &textbuf);
526
527                 if (ocs_textbuf_get_written(&textbuf)) {
528                         if (ocs_copy_to_user(req->user_buffer,
529                                 ocs_textbuf_get_buffer(&textbuf), 
530                                 ocs_textbuf_get_written(&textbuf))) {
531                                 ocs_log_test(ocs, "Error: (%d) ocs_copy_to_user failed\n", __LINE__);
532                         }
533                 }
534                 req->bytes_written = ocs_textbuf_get_written(&textbuf);
535
536                 ocs_textbuf_free(ocs, &textbuf);
537
538                 break;
539         }
540
541         case OCS_IOCTL_CMD_MGMT_GET_ALL: {
542                 ocs_ioctl_mgmt_buffer_t* req = (ocs_ioctl_mgmt_buffer_t *)addr;
543                 ocs_textbuf_t textbuf;
544                 int32_t n;
545                 uint32_t idx;
546                 uint32_t copied = 0;
547
548                 /* Build a text buffer */
549                 if (ocs_textbuf_alloc(ocs, &textbuf, req->user_buffer_len)) {
550                         ocs_log_err(ocs, "Error: ocs_textbuf_alloc failed\n");
551                         return -EFAULT;
552                 }
553
554                 ocs_mgmt_get_all(ocs, &textbuf);
555
556                 for (idx = 0; (n = ocs_textbuf_ext_get_written(&textbuf, idx)) > 0; idx++) {
557                         if(ocs_copy_to_user(req->user_buffer + copied, 
558                                         ocs_textbuf_ext_get_buffer(&textbuf, idx),
559                                         ocs_textbuf_ext_get_written(&textbuf, idx))) {
560                                         ocs_log_err(ocs, "Error: ocs_textbuf_alloc failed\n");
561                         }
562                         copied += n;
563                 }
564                 req->bytes_written = copied;
565
566                 ocs_textbuf_free(ocs, &textbuf);
567
568                 break;
569         }
570
571         case OCS_IOCTL_CMD_MGMT_GET: {
572                 ocs_ioctl_cmd_get_t* req = (ocs_ioctl_cmd_get_t*)addr;
573                 ocs_textbuf_t textbuf;
574                 char name[OCS_MGMT_MAX_NAME];
575
576                 /* Copy the name value in from user space */
577                 if (ocs_copy_from_user(name, req->name, OCS_MGMT_MAX_NAME)) {
578                         ocs_log_test(ocs, "ocs_copy_from_user failed\n");
579                         ocs_ioctl_free(ocs, req, sizeof(ocs_ioctl_cmd_get_t));
580                         return -EFAULT;
581                 }
582
583                 /* Build a text buffer */
584                 if (ocs_textbuf_alloc(ocs, &textbuf, req->value_length)) {
585                         ocs_log_err(ocs, "Error: ocs_textbuf_alloc failed\n");
586                         return -EFAULT;
587                 }
588
589                 ocs_mgmt_get(ocs, name, &textbuf);
590
591                 if (ocs_textbuf_get_written(&textbuf)) {
592                         if (ocs_copy_to_user(req->value, 
593                                 ocs_textbuf_get_buffer(&textbuf), 
594                                 ocs_textbuf_get_written(&textbuf))) {
595                                 ocs_log_test(ocs, "Error: (%d) ocs_copy_to_user failed\n", __LINE__);
596                 }
597                 }
598                 req->value_length = ocs_textbuf_get_written(&textbuf);
599
600                 ocs_textbuf_free(ocs, &textbuf);
601
602                 break;
603         }
604
605         case OCS_IOCTL_CMD_MGMT_SET: {
606                 char name[OCS_MGMT_MAX_NAME];
607                 char value[OCS_MGMT_MAX_VALUE];
608                 ocs_ioctl_cmd_set_t* req = (ocs_ioctl_cmd_set_t*)addr;
609                 
610                 // Copy the name  in from user space
611                 if (ocs_copy_from_user(name, req->name, OCS_MGMT_MAX_NAME)) {
612                         ocs_log_test(ocs, "Error: copy from user failed\n");
613                         ocs_ioctl_free(ocs, req, sizeof(*req));
614                         return -EFAULT;
615                 }
616
617                 // Copy the  value in from user space
618                 if (ocs_copy_from_user(value, req->value, OCS_MGMT_MAX_VALUE)) {
619                         ocs_log_test(ocs, "Error: copy from user failed\n");
620                         ocs_ioctl_free(ocs, req, sizeof(*req));
621                         return -EFAULT;
622                 }
623
624                 req->result = ocs_mgmt_set(ocs, req->name, req->value);
625
626                 break;
627         }
628
629         case OCS_IOCTL_CMD_MGMT_EXEC: {
630                 ocs_ioctl_action_t* req = (ocs_ioctl_action_t*) addr;
631                 char action_name[OCS_MGMT_MAX_NAME];
632
633                 if (ocs_copy_from_user(action_name, req->name, sizeof(action_name))) {
634                         ocs_log_test(ocs, "Error: copy req.name from user failed\n");
635                         ocs_ioctl_free(ocs, req, sizeof(*req));
636                         return -EFAULT;
637                 }
638
639                 req->result = ocs_mgmt_exec(ocs, action_name, req->arg_in, req->arg_in_length,
640                                 req->arg_out, req->arg_out_length);
641
642                 break;
643         }
644
645         default:
646                 ocs_log_test(ocs, "Error: unknown cmd %#lx\n", cmd);
647                 status = -ENOTTY;
648                 break;
649         }
650         return status;
651 }
652
653 static void
654 ocs_fw_write_cb(int32_t status, uint32_t actual_write_length, 
655                                         uint32_t change_status, void *arg)
656 {
657         ocs_mgmt_fw_write_result_t *result = arg;
658
659         result->status = status;
660         result->actual_xfer = actual_write_length;
661         result->change_status = change_status;
662
663         ocs_sem_v(&(result->semaphore));
664 }
665
666 int
667 ocs_firmware_write(ocs_t *ocs, const uint8_t *buf, size_t buf_len, 
668                                                 uint8_t *change_status)
669 {
670         int rc = 0;
671         uint32_t bytes_left;
672         uint32_t xfer_size;
673         uint32_t offset;
674         ocs_dma_t dma;
675         int last = 0;
676         ocs_mgmt_fw_write_result_t result;
677
678         ocs_sem_init(&(result.semaphore), 0, "fw_write");
679
680         bytes_left = buf_len;
681         offset = 0;
682
683         if (ocs_dma_alloc(ocs, &dma, FW_WRITE_BUFSIZE, 4096)) {
684                 ocs_log_err(ocs, "ocs_firmware_write: malloc failed\n");
685                 return -ENOMEM;
686         }
687
688         while (bytes_left > 0) {
689                 if (bytes_left > FW_WRITE_BUFSIZE) {
690                         xfer_size = FW_WRITE_BUFSIZE;
691                 } else {
692                         xfer_size = bytes_left;
693                 }
694
695                 ocs_memcpy(dma.virt, buf + offset, xfer_size);
696
697                 if (bytes_left == xfer_size) {
698                         last = 1;
699                 }
700
701                 ocs_hw_firmware_write(&ocs->hw, &dma, xfer_size, offset, 
702                                                 last, ocs_fw_write_cb, &result);
703
704                 if (ocs_sem_p(&(result.semaphore), OCS_SEM_FOREVER) != 0) {
705                         rc = -ENXIO;
706                         break;
707                 }
708
709                 if (result.actual_xfer == 0 || result.status != 0) {
710                         rc = -EFAULT;
711                         break;
712                 }
713
714                 if (last) {
715                         *change_status = result.change_status;
716                 }
717
718                 bytes_left -= result.actual_xfer;
719                 offset += result.actual_xfer;
720         }
721
722         ocs_dma_free(ocs, &dma);
723         return rc;
724 }
725
726 static int
727 ocs_sys_fwupgrade(SYSCTL_HANDLER_ARGS)
728 {
729         char file_name[256] = {0};
730         char fw_change_status;
731         uint32_t rc = 1;
732         ocs_t *ocs  = (ocs_t *)arg1;
733         const struct firmware *fw;
734         const struct ocs_hw_grp_hdr *fw_image;
735
736         rc = sysctl_handle_string(oidp, file_name, sizeof(file_name), req);
737         if (rc || !req->newptr)
738                 return rc;
739
740         fw = firmware_get(file_name);
741         if (fw == NULL) {
742                 device_printf(ocs->dev, "Unable to get Firmware. "
743                         "Make sure %s is copied to /boot/modules\n", file_name);
744                 return ENOENT;
745         }
746
747         fw_image = (const struct ocs_hw_grp_hdr *)fw->data;
748
749         /* Check if firmware provided is compatible with this particular
750          * Adapter of not*/
751         if ((ocs_be32toh(fw_image->magic_number) != OCS_HW_OBJECT_G5) &&
752                 (ocs_be32toh(fw_image->magic_number) != OCS_HW_OBJECT_G6)) {
753                 device_printf(ocs->dev,
754                         "Invalid FW image found Magic: 0x%x Size: %zu \n",
755                         ocs_be32toh(fw_image->magic_number), fw->datasize);
756                 rc = -1;
757                 goto exit;
758         }
759
760         if (!strncmp(ocs->fw_version, fw_image->revision, 
761                                         strnlen(fw_image->revision, 16))) {
762                 device_printf(ocs->dev, "No update req. "
763                                 "Firmware is already up to date. \n");
764                 rc = 0;
765                 goto exit;
766         }
767
768         device_printf(ocs->dev, "Upgrading Firmware from %s to %s \n", 
769                                 ocs->fw_version, fw_image->revision);
770
771         rc = ocs_firmware_write(ocs, fw->data, fw->datasize, &fw_change_status);
772         if (rc) {
773                 ocs_log_err(ocs, "Firmware update failed with status = %d\n", rc);
774         } else {
775                 ocs_log_info(ocs, "Firmware updated successfully\n");
776                 switch (fw_change_status) {
777                         case 0x00:
778                                 device_printf(ocs->dev, 
779                                 "No reset needed, new firmware is active.\n");
780                                 break;
781                         case 0x01:
782                                 device_printf(ocs->dev,
783                                 "A physical device reset (host reboot) is "
784                                 "needed to activate the new firmware\n");
785                                 break;
786                         case 0x02:
787                         case 0x03:
788                                 device_printf(ocs->dev,
789                                 "firmware is resetting to activate the new "
790                                 "firmware, Host reboot is needed \n");
791                                 break;
792                         default:
793                                 ocs_log_warn(ocs,
794                                         "Unexected value change_status: %d\n",
795                                         fw_change_status);
796                                 break;
797                 }
798         }
799
800 exit:
801         /* Release Firmware*/
802         firmware_put(fw, FIRMWARE_UNLOAD);
803
804         return rc;
805
806 }
807
808 static int
809 ocs_sysctl_wwnn(SYSCTL_HANDLER_ARGS)
810 {
811         uint32_t rc = 1;
812         ocs_t *ocs = oidp->oid_arg1;
813         char old[64];
814         char new[64];
815         uint64_t *wwnn = NULL;
816         ocs_xport_t *xport = ocs->xport;
817
818         if (xport->req_wwnn) {
819                 wwnn = &xport->req_wwnn;
820                 memset(old, 0, sizeof(old));
821                 snprintf(old, sizeof(old), "0x%llx" , (unsigned long long) *wwnn);
822
823         } else {
824                 wwnn = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_NODE);
825
826                 memset(old, 0, sizeof(old));
827                 snprintf(old, sizeof(old), "0x%llx" , (unsigned long long) ocs_htobe64(*wwnn));
828         }
829
830         /*Read wwnn*/
831         if (!req->newptr) {
832                 return (sysctl_handle_string(oidp, old, sizeof(old), req));
833         }
834
835         /*Configure port wwn*/
836         rc = sysctl_handle_string(oidp, new, sizeof(new), req);
837         if (rc)
838                 return (rc);
839
840         if (strncmp(old, new, strlen(old)) == 0) {
841                 return 0;
842         }
843
844         return (set_req_wwnn(ocs, NULL, new));
845 }
846
847 static int
848 ocs_sysctl_wwpn(SYSCTL_HANDLER_ARGS)
849 {
850         uint32_t rc = 1;
851         ocs_t *ocs = oidp->oid_arg1;
852         char old[64];
853         char new[64];
854         uint64_t *wwpn = NULL;
855         ocs_xport_t *xport = ocs->xport;
856
857         if (xport->req_wwpn) {
858                 wwpn = &xport->req_wwpn;
859                 memset(old, 0, sizeof(old));
860                 snprintf(old, sizeof(old), "0x%llx",(unsigned long long) *wwpn);
861         } else {
862                 wwpn = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_PORT);
863                 memset(old, 0, sizeof(old));
864                 snprintf(old, sizeof(old), "0x%llx",(unsigned long long) ocs_htobe64(*wwpn));
865         }
866
867         /*Read wwpn*/
868         if (!req->newptr) {
869                 return (sysctl_handle_string(oidp, old, sizeof(old), req));
870         }
871
872         /*Configure port wwn*/
873         rc = sysctl_handle_string(oidp, new, sizeof(new), req);
874         if (rc)
875                 return (rc);
876
877         if (strncmp(old, new, strlen(old)) == 0) {
878                 return 0;
879         }
880
881         return (set_req_wwpn(ocs, NULL, new));
882 }
883
884 static int
885 ocs_sysctl_current_topology(SYSCTL_HANDLER_ARGS)
886 {
887         ocs_t *ocs = oidp->oid_arg1;
888         uint32_t value;
889
890         ocs_hw_get(&ocs->hw, OCS_HW_TOPOLOGY, &value);
891
892         return (sysctl_handle_int(oidp, &value, 0, req));
893 }
894
895 static int
896 ocs_sysctl_current_speed(SYSCTL_HANDLER_ARGS)
897 {
898         ocs_t *ocs = oidp->oid_arg1;
899         uint32_t value;
900
901         ocs_hw_get(&ocs->hw, OCS_HW_LINK_SPEED, &value);
902
903         return (sysctl_handle_int(oidp, &value, 0, req));
904 }
905
906 static int
907 ocs_sysctl_config_topology(SYSCTL_HANDLER_ARGS)
908 {
909         uint32_t rc = 1;
910         ocs_t *ocs = oidp->oid_arg1;
911         uint32_t old_value;
912         uint32_t new_value;
913         char buf[64];
914
915         ocs_hw_get(&ocs->hw, OCS_HW_CONFIG_TOPOLOGY, &old_value);
916
917         /*Read topo*/
918         if (!req->newptr) {
919                 return (sysctl_handle_int(oidp, &old_value, 0, req));
920         }
921
922         /*Configure port wwn*/
923         rc = sysctl_handle_int(oidp, &new_value, 0, req);
924         if (rc)
925                 return (rc);
926
927         if (new_value == old_value) {
928                 return 0;
929         }
930
931         snprintf(buf, sizeof(buf), "%d",new_value);
932         rc = set_configured_topology(ocs, NULL, buf);
933         return rc;
934 }
935
936 static int
937 ocs_sysctl_config_speed(SYSCTL_HANDLER_ARGS)
938 {
939         uint32_t rc = 1;
940         ocs_t *ocs = oidp->oid_arg1;
941         uint32_t old_value;
942         uint32_t new_value;
943         char buf[64];
944
945         ocs_hw_get(&ocs->hw, OCS_HW_LINK_CONFIG_SPEED, &old_value);
946
947         /*Read topo*/
948         if (!req->newptr) {
949                 return (sysctl_handle_int(oidp, &old_value, 0, req));
950         }
951
952         /*Configure port wwn*/
953         rc = sysctl_handle_int(oidp, &new_value, 0, req);
954         if (rc)
955                 return (rc);
956
957         if (new_value == old_value) {
958                 return 0;
959         }
960
961         snprintf(buf, sizeof(buf), "%d",new_value);
962         rc = set_configured_speed(ocs, NULL,buf);
963         return rc;
964 }
965
966 static int
967 ocs_sysctl_fcid(SYSCTL_HANDLER_ARGS)
968 {
969         ocs_t *ocs = oidp->oid_arg1;
970         char buf[64];
971
972         memset(buf, 0, sizeof(buf));
973         if (ocs->domain && ocs->domain->attached) {
974                 snprintf(buf, sizeof(buf), "0x%06x", 
975                         ocs->domain->sport->fc_id);
976         }
977
978         return (sysctl_handle_string(oidp, buf, sizeof(buf), req));
979 }
980
981 static int
982 ocs_sysctl_port_state(SYSCTL_HANDLER_ARGS)
983 {
984
985         char new[256] = {0};
986         uint32_t rc = 1;
987         ocs_xport_stats_t old;
988         ocs_t *ocs  = (ocs_t *)arg1;
989
990         ocs_xport_status(ocs->xport, OCS_XPORT_CONFIG_PORT_STATUS, &old);
991
992         /*Read port state */
993         if (!req->newptr) {
994                 snprintf(new, sizeof(new), "%s",
995                         (old.value == OCS_XPORT_PORT_OFFLINE) ?
996                                          "offline" : "online"); 
997                 return (sysctl_handle_string(oidp, new, sizeof(new), req));
998         }
999
1000         /*Configure port state*/
1001         rc = sysctl_handle_string(oidp, new, sizeof(new), req);
1002         if (rc)
1003                 return (rc);
1004
1005         if (ocs_strcasecmp(new, "offline") == 0) {
1006                 if (old.value == OCS_XPORT_PORT_OFFLINE) {
1007                         return (0);
1008                 }
1009                 ocs_log_debug(ocs, "Setting port to %s\n", new);
1010                 rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_OFFLINE);
1011                 if (rc != 0) {
1012                         ocs_log_err(ocs, "Setting port to offline failed\n");
1013                 }
1014         } else if (ocs_strcasecmp(new, "online") == 0) {
1015                 if (old.value == OCS_XPORT_PORT_ONLINE) {
1016                         return (0);
1017                 }
1018                 ocs_log_debug(ocs, "Setting port to %s\n", new);
1019                 rc = ocs_xport_control(ocs->xport, OCS_XPORT_PORT_ONLINE);
1020                 if (rc != 0) {
1021                         ocs_log_err(ocs, "Setting port to online failed\n");
1022                 }
1023         } else {
1024                 ocs_log_err(ocs, "Unsupported link state %s\n", new);
1025                 rc = 1;
1026         }
1027
1028         return (rc);    
1029
1030 }
1031
1032 static int
1033 ocs_sysctl_vport_wwpn(SYSCTL_HANDLER_ARGS)
1034 {
1035         ocs_fcport *fcp = oidp->oid_arg1;
1036         char str_wwpn[64];
1037
1038         memset(str_wwpn, 0, sizeof(str_wwpn));
1039         snprintf(str_wwpn, sizeof(str_wwpn), "0x%llx", (unsigned long long)fcp->vport->wwpn);
1040
1041         return (sysctl_handle_string(oidp, str_wwpn, sizeof(str_wwpn), req));
1042 }
1043
1044 static int
1045 ocs_sysctl_vport_wwnn(SYSCTL_HANDLER_ARGS)
1046 {
1047         ocs_fcport *fcp = oidp->oid_arg1;
1048         char str_wwnn[64];
1049
1050         memset(str_wwnn, 0, sizeof(str_wwnn));
1051         snprintf(str_wwnn, sizeof(str_wwnn), "0x%llx", (unsigned long long)fcp->vport->wwnn);
1052
1053         return (sysctl_handle_string(oidp, str_wwnn, sizeof(str_wwnn), req));
1054 }
1055
1056 /**
1057  * @brief Initialize sysctl
1058  *
1059  * Initialize sysctl so elxsdkutil can query device information.
1060  *
1061  * @param ocs pointer to ocs
1062  * @return void
1063  */
1064 static void
1065 ocs_sysctl_init(ocs_t *ocs)
1066 {
1067         struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(ocs->dev);
1068         struct sysctl_oid *tree = device_get_sysctl_tree(ocs->dev);
1069         struct sysctl_oid *vtree; 
1070         const char *str = NULL;
1071         char name[16];
1072         uint32_t rev, if_type, family, i;
1073         ocs_fcport *fcp = NULL;
1074
1075         SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1076                         "devid", CTLFLAG_RD, NULL,
1077                         pci_get_devid(ocs->dev), "Device ID");
1078
1079         memset(ocs->modeldesc, 0, sizeof(ocs->modeldesc));
1080         if (0 == pci_get_vpd_ident(ocs->dev, &str)) {
1081                 snprintf(ocs->modeldesc, sizeof(ocs->modeldesc), "%s", str);
1082         }
1083         SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1084                         "modeldesc", CTLFLAG_RD,
1085                         ocs->modeldesc,
1086                         0, "Model Description");
1087
1088         memset(ocs->serialnum, 0, sizeof(ocs->serialnum));
1089         if (0 == pci_get_vpd_readonly(ocs->dev, "SN", &str)) {
1090                 snprintf(ocs->serialnum, sizeof(ocs->serialnum), "%s", str);
1091         }
1092         SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1093                         "sn", CTLFLAG_RD,
1094                         ocs->serialnum,
1095                         0, "Serial Number");
1096
1097         ocs_hw_get(&ocs->hw, OCS_HW_SLI_REV, &rev);
1098         ocs_hw_get(&ocs->hw, OCS_HW_IF_TYPE, &if_type);
1099         ocs_hw_get(&ocs->hw, OCS_HW_SLI_FAMILY, &family);
1100
1101         memset(ocs->fwrev, 0, sizeof(ocs->fwrev));
1102         snprintf(ocs->fwrev, sizeof(ocs->fwrev), "%s, sli-%d:%d:%x",
1103                         (char *)ocs_hw_get_ptr(&ocs->hw, OCS_HW_FW_REV),
1104                         rev, if_type, family);
1105         SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1106                         "fwrev", CTLFLAG_RD,
1107                         ocs->fwrev,
1108                         0, "Firmware Revision");
1109
1110         memset(ocs->sli_intf, 0, sizeof(ocs->sli_intf));
1111         snprintf(ocs->sli_intf, sizeof(ocs->sli_intf), "%08x",
1112                  ocs_config_read32(ocs, SLI4_INTF_REG));
1113         SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1114                           "sli_intf", CTLFLAG_RD,
1115                           ocs->sli_intf,
1116                           0, "SLI Interface");
1117
1118         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "fw_upgrade",
1119             CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT, (void *)ocs, 0,
1120             ocs_sys_fwupgrade, "A", "Firmware grp file");
1121
1122         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1123             "wwnn", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
1124             ocs, 0, ocs_sysctl_wwnn, "A",
1125             "World Wide Node Name, wwnn should be in the format 0x<XXXXXXXXXXXXXXXX>");
1126
1127         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1128             "wwpn", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
1129             ocs, 0, ocs_sysctl_wwpn, "A",
1130             "World Wide Port Name, wwpn should be in the format 0x<XXXXXXXXXXXXXXXX>");
1131
1132         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1133             "current_topology", CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
1134             ocs, 0, ocs_sysctl_current_topology, "IU",
1135             "Current Topology, 1-NPort; 2-Loop; 3-None");
1136
1137         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1138             "current_speed", CTLTYPE_UINT | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
1139             ocs, 0, ocs_sysctl_current_speed, "IU",
1140             "Current Speed");
1141
1142         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1143             "configured_topology", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
1144             ocs, 0, ocs_sysctl_config_topology, "IU",
1145             "Configured Topology, 0-Auto; 1-NPort; 2-Loop");
1146
1147         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1148             "configured_speed", CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
1149             ocs, 0, ocs_sysctl_config_speed, "IU",
1150             "Configured Speed, 0-Auto, 2000, 4000, 8000, 16000, 32000");
1151
1152         SYSCTL_ADD_STRING(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1153                         "businfo", CTLFLAG_RD,
1154                         ocs->businfo,
1155                         0, "Bus Info");
1156
1157         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1158             "fcid", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
1159             ocs, 0, ocs_sysctl_fcid, "A", "Port FC ID");
1160
1161         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
1162             "port_state", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
1163             ocs, 0, ocs_sysctl_port_state, "A", "configured port state");
1164
1165         for (i  = 0; i < ocs->num_vports; i++) {
1166                 fcp = FCPORT(ocs, i+1);
1167
1168                 memset(name, 0, sizeof(name));
1169                 snprintf(name, sizeof(name), "vport%d", i);
1170                 vtree = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(tree),
1171                     OID_AUTO, name, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
1172                     "Virtual port");
1173
1174                 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(vtree), OID_AUTO,
1175                     "wwnn", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
1176                     fcp, 0, ocs_sysctl_vport_wwnn, "A",
1177                     "World Wide Node Name");
1178
1179                 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(vtree), OID_AUTO,
1180                     "wwpn", CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
1181                     fcp, 0, ocs_sysctl_vport_wwpn, "A", "World Wide Port Name");
1182         }
1183
1184 }
1185
1186 /**
1187  * @brief Initialize the debug module
1188  *
1189  * Parse device hints (similar to Linux module parameters) here. To use,
1190  * run the command
1191  *    kenv hint.ocs.U.P=V
1192  * from the command line replacing U with the unit # (0,1,...),
1193  * P with the parameter name (debug_mask), and V with the value
1194  */
1195 void
1196 ocs_debug_attach(void *os)
1197 {
1198         struct ocs_softc *ocs = os;
1199         int error = 0;
1200         char *resname = NULL;
1201         int32_t unit = INT32_MAX;
1202         uint32_t ocs_debug_mask = 0;
1203
1204         resname = "debug_mask";
1205         if (0 == (error = resource_int_value(device_get_name(ocs->dev), device_get_unit(ocs->dev),
1206                                 resname, &ocs_debug_mask))) {
1207                 device_printf(ocs->dev, "setting %s to %010x\n", resname, ocs_debug_mask);
1208                 ocs_debug_enable(ocs_debug_mask);
1209         }
1210
1211         unit = device_get_unit(ocs->dev);
1212         ocs->cdev = make_dev(&ocs_cdevsw, unit, UID_ROOT, GID_OPERATOR, 0640,
1213                         "ocs%d", unit);
1214         if (ocs->cdev) {
1215                 ocs->cdev->si_drv1 = ocs;
1216         }
1217
1218         /* initialize sysctl interface */
1219         ocs_sysctl_init(ocs);
1220         mtx_init(&ocs->dbg_lock, "ocs_dbg_lock", NULL, MTX_DEF);
1221 }
1222
1223 /**
1224  * @brief Free the debug module
1225  */
1226 void
1227 ocs_debug_detach(void *os)
1228 {
1229         struct ocs_softc *ocs = os;
1230
1231         mtx_destroy(&ocs->dbg_lock);
1232
1233         if (ocs->cdev) {
1234                 ocs->cdev->si_drv1 = NULL;
1235                 destroy_dev(ocs->cdev);
1236         }
1237 }