4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
30 * The following notice accompanied the original version of this file:
34 * Copyright(c) 2007 Intel Corporation. All rights reserved.
35 * All rights reserved.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
41 * * Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * * Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in
45 * the documentation and/or other materials provided with the
47 * * Neither the name of Intel Corporation nor the names of its
48 * contributors may be used to endorse or promote products derived
49 * from this software without specific prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
52 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
53 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
54 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
55 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
56 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
57 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
61 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65 * Common FCoE interface interacts with MAC and FCoE clients, managing
66 * FCoE ports, doing MAC address discovery/managment, and FC frame
67 * encapsulation/decapsulation
76 #include <sys/sunddi.h>
77 #include <sys/sunndi.h>
78 #include <sys/byteorder.h>
79 #include <sys/atomic.h>
80 #include <sys/sysmacros.h>
81 #include <sys/cmn_err.h>
82 #include <sys/crc32.h>
83 #include <sys/strsubr.h>
85 #include <sys/mac_client.h>
90 #include <sys/fcoe/fcoeio.h>
91 #include <sys/fcoe/fcoe_common.h>
94 * Driver's own header files
101 * Function forward declaration
103 static int fcoe_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
);
104 static int fcoe_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
);
105 static int fcoe_bus_ctl(dev_info_t
*fca_dip
, dev_info_t
*rip
,
106 ddi_ctl_enum_t op
, void *arg
, void *result
);
107 static int fcoe_open(dev_t
*devp
, int flag
, int otype
, cred_t
*credp
);
108 static int fcoe_close(dev_t dev
, int flag
, int otype
, cred_t
*credp
);
109 static int fcoe_ioctl(dev_t dev
, int cmd
, intptr_t data
, int mode
,
110 cred_t
*credp
, int *rval
);
111 static int fcoe_copyin_iocdata(intptr_t data
, int mode
, fcoeio_t
**fcoeio
,
112 void **ibuf
, void **abuf
, void **obuf
);
113 static int fcoe_copyout_iocdata(intptr_t data
, int mode
, fcoeio_t
*fcoeio
,
115 static int fcoe_iocmd(fcoe_soft_state_t
*ss
, intptr_t data
, int mode
);
116 static int fcoe_attach_init(fcoe_soft_state_t
*this_ss
);
117 static int fcoe_detach_uninit(fcoe_soft_state_t
*this_ss
);
118 static int fcoe_initchild(dev_info_t
*fcoe_dip
, dev_info_t
*client_dip
);
119 static int fcoe_uninitchild(dev_info_t
*fcoe_dip
, dev_info_t
*client_dip
);
120 static void fcoe_init_wwn_from_mac(uint8_t *wwn
, uint8_t *mac
,
121 int is_pwwn
, uint8_t idx
);
122 static fcoe_mac_t
*fcoe_create_mac_by_id(datalink_id_t linkid
);
123 static int fcoe_cmp_wwn(fcoe_mac_t
*checkedmac
);
124 static void fcoe_watchdog(void *arg
);
125 static void fcoe_worker_init();
126 static int fcoe_worker_fini();
127 static void fcoe_worker_frame();
128 static int fcoe_get_port_list(fcoe_port_instance_t
*ports
, int count
);
129 static boolean_t
fcoe_mac_existed(fcoe_mac_t
*pmac
);
132 * Driver identificaton stuff
134 static struct cb_ops fcoe_cb_ops
= {
149 D_MP
| D_NEW
| D_HOTPLUG
,
155 static struct bus_ops fcoe_busops
= {
157 nullbusmap
, /* bus_map */
158 NULL
, /* bus_get_intrspec */
159 NULL
, /* bus_add_intrspec */
160 NULL
, /* bus_remove_intrspec */
161 i_ddi_map_fault
, /* bus_map_fault */
162 NULL
, /* bus_dma_map */
163 ddi_dma_allochdl
, /* bus_dma_allochdl */
164 ddi_dma_freehdl
, /* bus_dma_freehdl */
165 ddi_dma_bindhdl
, /* bus_dma_bindhdl */
166 ddi_dma_unbindhdl
, /* bus_unbindhdl */
167 ddi_dma_flush
, /* bus_dma_flush */
168 ddi_dma_win
, /* bus_dma_win */
169 ddi_dma_mctl
, /* bus_dma_ctl */
170 fcoe_bus_ctl
, /* bus_ctl */
171 ddi_bus_prop_op
, /* bus_prop_op */
172 NULL
, /* bus_get_eventcookie */
173 NULL
, /* bus_add_eventcall */
174 NULL
, /* bus_remove_event */
175 NULL
, /* bus_post_event */
176 NULL
, /* bus_intr_ctl */
177 NULL
, /* bus_config */
178 NULL
, /* bus_unconfig */
179 NULL
, /* bus_fm_init */
180 NULL
, /* bus_fm_fini */
181 NULL
, /* bus_fm_access_enter */
182 NULL
, /* bus_fm_access_exit */
183 NULL
, /* bus_power */
187 static struct dev_ops fcoe_ops
= {
199 ddi_quiesce_not_needed
202 #define FCOE_VERSION "20091123-1.02"
203 #define FCOE_NAME "FCoE Transport v" FCOE_VERSION
204 #define TASKQ_NAME_LEN 32
206 static struct modldrv modldrv
= {
212 static struct modlinkage modlinkage
= {
213 MODREV_1
, &modldrv
, NULL
217 * TRACE for all FCoE related modules
219 static kmutex_t fcoe_trace_buf_lock
;
220 static int fcoe_trace_buf_curndx
= 0;
221 static int fcoe_trace_on
= 1;
222 static caddr_t fcoe_trace_buf
= NULL
;
223 static clock_t fcoe_trace_start
= 0;
224 static caddr_t ftb
= NULL
;
225 static int fcoe_trace_buf_size
= (1 * 1024 * 1024);
228 * Driver's global variables
230 const fcoe_ver_e fcoe_ver_now
= FCOE_VER_NOW
;
231 static void *fcoe_state
= NULL
;
232 fcoe_soft_state_t
*fcoe_global_ss
= NULL
;
233 int fcoe_use_ext_log
= 1;
235 static ddi_taskq_t
*fcoe_worker_taskq
;
236 static fcoe_worker_t
*fcoe_workers
;
237 static uint32_t fcoe_nworkers_running
;
239 const char *fcoe_workers_num
= "workers-number";
240 volatile int fcoe_nworkers
;
243 * Common loadable module entry points _init, _fini, _info
251 ret
= ddi_soft_state_init(&fcoe_state
, sizeof (fcoe_soft_state_t
), 0);
253 ret
= mod_install(&modlinkage
);
255 ddi_soft_state_fini(&fcoe_state
);
257 fcoe_trace_start
= ddi_get_lbolt();
258 ftb
= kmem_zalloc(fcoe_trace_buf_size
,
260 fcoe_trace_buf
= ftb
;
261 mutex_init(&fcoe_trace_buf_lock
, NULL
, MUTEX_DRIVER
, 0);
265 FCOE_LOG("fcoe", "exit _init with %x", ret
);
275 ret
= mod_remove(&modlinkage
);
277 ddi_soft_state_fini(&fcoe_state
);
280 FCOE_LOG("fcoe", "exit _fini with %x", ret
);
282 kmem_free(fcoe_trace_buf
, fcoe_trace_buf_size
);
283 mutex_destroy(&fcoe_trace_buf_lock
);
290 _info(struct modinfo
*modinfop
)
292 return (mod_info(&modlinkage
, modinfop
));
296 * Autoconfiguration entry points: attach, detach, getinfo
300 fcoe_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
302 int ret
= DDI_FAILURE
;
305 fcoe_soft_state_t
*ss
;
307 instance
= ddi_get_instance(dip
);
310 ret
= ddi_soft_state_zalloc(fcoe_state
, instance
);
311 if (ret
== DDI_FAILURE
) {
312 FCOE_LOG(0, "soft_state_zalloc-%x/%x", ret
, instance
);
316 ss
= ddi_get_soft_state(fcoe_state
, instance
);
319 ASSERT(fcoe_global_ss
== NULL
);
321 fcoe_ret
= fcoe_attach_init(ss
);
322 if (fcoe_ret
== FCOE_SUCCESS
) {
326 FCOE_LOG("fcoe", "fcoe_attach_init end with-%x", fcoe_ret
);
334 FCOE_LOG("fcoe", "unsupported attach cmd-%x", cmd
);
342 fcoe_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
344 int ret
= DDI_FAILURE
;
347 fcoe_soft_state_t
*ss
;
349 instance
= ddi_get_instance(dip
);
350 ss
= ddi_get_soft_state(fcoe_state
, instance
);
355 ASSERT(fcoe_global_ss
!= NULL
);
356 ASSERT(dip
== fcoe_global_ss
->ss_dip
);
359 fcoe_ret
= fcoe_detach_uninit(ss
);
360 if (fcoe_ret
== FCOE_SUCCESS
) {
362 fcoe_global_ss
= NULL
;
372 FCOE_LOG(0, "unsupported detach cmd-%x", cmd
);
380 * FCA driver's intercepted bus control operations.
383 fcoe_bus_ctl(dev_info_t
*fcoe_dip
, dev_info_t
*rip
,
384 ddi_ctl_enum_t op
, void *clientarg
, void *result
)
388 case DDI_CTLOPS_REPORTDEV
:
389 case DDI_CTLOPS_IOMIN
:
393 case DDI_CTLOPS_INITCHILD
:
394 ret
= fcoe_initchild(fcoe_dip
, (dev_info_t
*)clientarg
);
397 case DDI_CTLOPS_UNINITCHILD
:
398 ret
= fcoe_uninitchild(fcoe_dip
, (dev_info_t
*)clientarg
);
402 ret
= ddi_ctlops(fcoe_dip
, rip
, op
, clientarg
, result
);
410 * We need specify the dev address for client driver's instance, or we
411 * can't online client driver's instance.
415 fcoe_initchild(dev_info_t
*fcoe_dip
, dev_info_t
*client_dip
)
417 char client_addr
[FCOE_STR_LEN
];
420 rval
= ddi_prop_get_int(DDI_DEV_T_ANY
, client_dip
,
421 DDI_PROP_DONTPASS
| DDI_PROP_NOTPROM
, "mac_id", -1);
423 FCOE_LOG(__FUNCTION__
, "no mac_id property: %p", client_dip
);
424 return (DDI_FAILURE
);
427 bzero(client_addr
, FCOE_STR_LEN
);
428 (void) sprintf((char *)client_addr
, "%x,0", rval
);
429 ddi_set_name_addr(client_dip
, client_addr
);
430 return (DDI_SUCCESS
);
435 fcoe_uninitchild(dev_info_t
*fcoe_dip
, dev_info_t
*client_dip
)
437 ddi_set_name_addr(client_dip
, NULL
);
438 return (DDI_SUCCESS
);
442 * Device access entry points
445 fcoe_open(dev_t
*devp
, int flag
, int otype
, cred_t
*credp
)
448 fcoe_soft_state_t
*ss
;
450 if (otype
!= OTYP_CHR
) {
455 * Since this is for debugging only, only allow root to issue ioctl now
457 if (drv_priv(credp
) != 0) {
461 instance
= (int)getminor(*devp
);
462 ss
= ddi_get_soft_state(fcoe_state
, instance
);
467 mutex_enter(&ss
->ss_ioctl_mutex
);
468 if (ss
->ss_ioctl_flags
& FCOE_IOCTL_FLAG_EXCL
) {
470 * It is already open for exclusive access.
471 * So shut the door on this caller.
473 mutex_exit(&ss
->ss_ioctl_mutex
);
478 if (ss
->ss_ioctl_flags
& FCOE_IOCTL_FLAG_OPEN
) {
480 * Exclusive operation not possible
481 * as it is already opened
483 mutex_exit(&ss
->ss_ioctl_mutex
);
486 ss
->ss_ioctl_flags
|= FCOE_IOCTL_FLAG_EXCL
;
489 ss
->ss_ioctl_flags
|= FCOE_IOCTL_FLAG_OPEN
;
490 mutex_exit(&ss
->ss_ioctl_mutex
);
497 fcoe_close(dev_t dev
, int flag
, int otype
, cred_t
*credp
)
500 fcoe_soft_state_t
*ss
;
502 if (otype
!= OTYP_CHR
) {
506 instance
= (int)getminor(dev
);
507 ss
= ddi_get_soft_state(fcoe_state
, instance
);
512 mutex_enter(&ss
->ss_ioctl_mutex
);
513 if ((ss
->ss_ioctl_flags
& FCOE_IOCTL_FLAG_OPEN
) == 0) {
514 mutex_exit(&ss
->ss_ioctl_mutex
);
518 ss
->ss_ioctl_flags
&= ~FCOE_IOCTL_FLAG_MASK
;
519 mutex_exit(&ss
->ss_ioctl_mutex
);
526 fcoe_ioctl(dev_t dev
, int cmd
, intptr_t data
, int mode
,
527 cred_t
*credp
, int *rval
)
529 fcoe_soft_state_t
*ss
;
532 if (drv_priv(credp
) != 0) {
536 ss
= ddi_get_soft_state(fcoe_state
, (int32_t)getminor(dev
));
541 mutex_enter(&ss
->ss_ioctl_mutex
);
542 if ((ss
->ss_ioctl_flags
& FCOE_IOCTL_FLAG_OPEN
) == 0) {
543 mutex_exit(&ss
->ss_ioctl_mutex
);
546 mutex_exit(&ss
->ss_ioctl_mutex
);
550 ret
= fcoe_iocmd(ss
, data
, mode
);
553 FCOE_LOG(0, "fcoe_ioctl: ioctl-0x%02X", cmd
);
562 fcoe_copyin_iocdata(intptr_t data
, int mode
, fcoeio_t
**fcoeio
,
563 void **ibuf
, void **abuf
, void **obuf
)
570 *fcoeio
= kmem_zalloc(sizeof (fcoeio_t
), KM_SLEEP
);
571 if (ddi_copyin((void *)data
, *fcoeio
, sizeof (fcoeio_t
), mode
) != 0) {
573 goto copyin_iocdata_fail
;
576 if ((*fcoeio
)->fcoeio_ilen
> FCOEIO_MAX_BUF_LEN
||
577 (*fcoeio
)->fcoeio_alen
> FCOEIO_MAX_BUF_LEN
||
578 (*fcoeio
)->fcoeio_olen
> FCOEIO_MAX_BUF_LEN
) {
580 goto copyin_iocdata_fail
;
583 if ((*fcoeio
)->fcoeio_ilen
) {
584 *ibuf
= kmem_zalloc((*fcoeio
)->fcoeio_ilen
, KM_SLEEP
);
585 if (ddi_copyin((void *)(unsigned long)(*fcoeio
)->fcoeio_ibuf
,
586 *ibuf
, (*fcoeio
)->fcoeio_ilen
, mode
) != 0) {
588 goto copyin_iocdata_fail
;
592 if ((*fcoeio
)->fcoeio_alen
) {
593 *abuf
= kmem_zalloc((*fcoeio
)->fcoeio_alen
, KM_SLEEP
);
594 if (ddi_copyin((void *)(unsigned long)(*fcoeio
)->fcoeio_abuf
,
595 *abuf
, (*fcoeio
)->fcoeio_alen
, mode
) != 0) {
597 goto copyin_iocdata_fail
;
601 if ((*fcoeio
)->fcoeio_olen
) {
602 *obuf
= kmem_zalloc((*fcoeio
)->fcoeio_olen
, KM_SLEEP
);
608 kmem_free(*abuf
, (*fcoeio
)->fcoeio_alen
);
613 kmem_free(*ibuf
, (*fcoeio
)->fcoeio_ilen
);
617 kmem_free(*fcoeio
, sizeof (fcoeio_t
));
622 fcoe_copyout_iocdata(intptr_t data
, int mode
, fcoeio_t
*fcoeio
, void *obuf
)
624 if (fcoeio
->fcoeio_olen
) {
625 if (ddi_copyout(obuf
,
626 (void *)(unsigned long)fcoeio
->fcoeio_obuf
,
627 fcoeio
->fcoeio_olen
, mode
) != 0) {
632 if (ddi_copyout(fcoeio
, (void *)data
, sizeof (fcoeio_t
), mode
) != 0) {
639 fcoe_iocmd(fcoe_soft_state_t
*ss
, intptr_t data
, int mode
)
642 fcoe_mac_t
*fcoe_mac
;
648 ret
= fcoe_copyin_iocdata(data
, mode
, &fcoeio
, &ibuf
, &abuf
, &obuf
);
650 goto fcoeiocmd_release_buf
;
654 * If an exclusive open was demanded during open, ensure that
655 * only one thread can execute an ioctl at a time
657 mutex_enter(&ss
->ss_ioctl_mutex
);
658 if (ss
->ss_ioctl_flags
& FCOE_IOCTL_FLAG_EXCL
) {
659 if (ss
->ss_ioctl_flags
& FCOE_IOCTL_FLAG_EXCL_BUSY
) {
660 mutex_exit(&ss
->ss_ioctl_mutex
);
661 fcoeio
->fcoeio_status
= FCOEIOE_BUSY
;
663 goto fcoeiocmd_release_buf
;
665 ss
->ss_ioctl_flags
|= FCOE_IOCTL_FLAG_EXCL_BUSY
;
667 mutex_exit(&ss
->ss_ioctl_mutex
);
669 fcoeio
->fcoeio_status
= 0;
671 switch (fcoeio
->fcoeio_cmd
) {
672 case FCOEIO_CREATE_FCOE_PORT
: {
673 fcoeio_create_port_param_t
*param
=
674 (fcoeio_create_port_param_t
*)ibuf
;
678 if (fcoeio
->fcoeio_ilen
!=
679 sizeof (fcoeio_create_port_param_t
) ||
680 fcoeio
->fcoeio_xfer
!= FCOEIO_XFER_WRITE
) {
681 fcoeio
->fcoeio_status
= FCOEIOE_INVAL_ARG
;
686 mutex_enter(&ss
->ss_ioctl_mutex
);
687 fcoe_mac
= fcoe_create_mac_by_id(param
->fcp_mac_linkid
);
688 if (fcoe_mac
== NULL
) {
689 mutex_exit(&ss
->ss_ioctl_mutex
);
690 fcoeio
->fcoeio_status
= FCOEIOE_CREATE_MAC
;
695 if (fcoe_mac
->fm_flags
& FCOE_MAC_FLAG_ENABLED
) {
696 mutex_exit(&ss
->ss_ioctl_mutex
);
697 fcoeio
->fcoeio_status
= FCOEIOE_ALREADY
;
701 ret
= fcoe_open_mac(fcoe_mac
, param
->fcp_force_promisc
,
702 &fcoeio
->fcoeio_status
);
704 fcoe_destroy_mac(fcoe_mac
);
705 mutex_exit(&ss
->ss_ioctl_mutex
);
706 if (fcoeio
->fcoeio_status
== 0) {
707 fcoeio
->fcoeio_status
=
713 fcoe_mac
->fm_flags
|= FCOE_MAC_FLAG_ENABLED
;
718 * Provide PWWN and NWWN based on mac address
720 eport
= &fcoe_mac
->fm_eport
;
721 if (!param
->fcp_pwwn_provided
) {
722 fcoe_init_wwn_from_mac(eport
->eport_portwwn
,
723 fcoe_mac
->fm_current_addr
, 1, 0);
725 (void) memcpy(eport
->eport_portwwn
, param
->fcp_pwwn
, 8);
728 if (!param
->fcp_nwwn_provided
) {
729 fcoe_init_wwn_from_mac(eport
->eport_nodewwn
,
730 fcoe_mac
->fm_current_addr
, 0, 0);
732 (void) memcpy(eport
->eport_nodewwn
, param
->fcp_nwwn
, 8);
735 cmpwwn
= fcoe_cmp_wwn(fcoe_mac
);
739 fcoeio
->fcoeio_status
= FCOEIOE_PWWN_CONFLICTED
;
740 } else if (cmpwwn
== -1) {
741 fcoeio
->fcoeio_status
= FCOEIOE_NWWN_CONFLICTED
;
743 (void) fcoe_close_mac(fcoe_mac
);
744 fcoe_destroy_mac(fcoe_mac
);
745 mutex_exit(&ss
->ss_ioctl_mutex
);
751 ret
= fcoe_create_port(ss
->ss_dip
,
753 (param
->fcp_port_type
== FCOE_CLIENT_TARGET
));
755 if (fcoe_mac_existed(fcoe_mac
) == B_TRUE
) {
756 (void) fcoe_close_mac(fcoe_mac
);
757 fcoe_destroy_mac(fcoe_mac
);
759 fcoeio
->fcoeio_status
= FCOEIOE_CREATE_PORT
;
763 mutex_exit(&ss
->ss_ioctl_mutex
);
768 case FCOEIO_DELETE_FCOE_PORT
: {
769 fcoeio_delete_port_param_t
*del_port_param
=
770 (fcoeio_delete_port_param_t
*)ibuf
;
771 uint64_t *is_target
= (uint64_t *)obuf
;
773 if (fcoeio
->fcoeio_ilen
< sizeof (fcoeio_delete_port_param_t
) ||
774 fcoeio
->fcoeio_olen
!= sizeof (uint64_t) ||
775 fcoeio
->fcoeio_xfer
!= FCOEIO_XFER_RW
) {
776 fcoeio
->fcoeio_status
= FCOEIOE_INVAL_ARG
;
781 mutex_enter(&ss
->ss_ioctl_mutex
);
782 ret
= fcoe_delete_port(ss
->ss_dip
, fcoeio
,
783 del_port_param
->fdp_mac_linkid
, is_target
);
784 mutex_exit(&ss
->ss_ioctl_mutex
);
785 FCOE_LOG("fcoe", "fcoe_delete_port %x return: %d",
786 del_port_param
->fdp_mac_linkid
, ret
);
790 case FCOEIO_GET_FCOE_PORT_LIST
: {
791 fcoe_port_list_t
*list
= (fcoe_port_list_t
*)obuf
;
794 if (fcoeio
->fcoeio_xfer
!= FCOEIO_XFER_READ
||
795 fcoeio
->fcoeio_olen
< sizeof (fcoe_port_list_t
)) {
796 fcoeio
->fcoeio_status
= FCOEIOE_INVAL_ARG
;
800 mutex_enter(&ss
->ss_ioctl_mutex
);
802 list
->numPorts
= 1 + (fcoeio
->fcoeio_olen
-
803 sizeof (fcoe_port_list_t
))/sizeof (fcoe_port_instance_t
);
805 count
= fcoe_get_port_list(list
->ports
, list
->numPorts
);
807 if (count
> list
->numPorts
) {
808 fcoeio
->fcoeio_status
= FCOEIOE_MORE_DATA
;
811 list
->numPorts
= count
;
812 mutex_exit(&ss
->ss_ioctl_mutex
);
822 FCOE_LOG("fcoe", "fcoe_ioctl %x returned %d, fcoeio_status = %d",
823 fcoeio
->fcoeio_cmd
, ret
, fcoeio
->fcoeio_status
);
825 fcoeiocmd_release_buf
:
827 ret
= fcoe_copyout_iocdata(data
, mode
, fcoeio
, obuf
);
828 } else if (fcoeio
->fcoeio_status
) {
829 (void) fcoe_copyout_iocdata(data
, mode
, fcoeio
, obuf
);
833 kmem_free(obuf
, fcoeio
->fcoeio_olen
);
837 kmem_free(abuf
, fcoeio
->fcoeio_alen
);
842 kmem_free(ibuf
, fcoeio
->fcoeio_ilen
);
845 kmem_free(fcoeio
, sizeof (fcoeio_t
));
851 * Finish final initialization
854 fcoe_attach_init(fcoe_soft_state_t
*ss
)
856 char taskq_name
[TASKQ_NAME_LEN
];
858 if (ddi_create_minor_node(ss
->ss_dip
, "admin", S_IFCHR
,
859 ddi_get_instance(ss
->ss_dip
), DDI_PSEUDO
, 0) != DDI_SUCCESS
) {
860 FCOE_LOG("FCOE", "ddi_create_minor_node failed");
861 return (FCOE_FAILURE
);
865 * watchdog responsible for release frame and dispatch events
867 (void) snprintf(taskq_name
, sizeof (taskq_name
), "fcoe_mac");
868 taskq_name
[TASKQ_NAME_LEN
- 1] = 0;
869 if ((ss
->ss_watchdog_taskq
= ddi_taskq_create(NULL
,
870 taskq_name
, 2, TASKQ_DEFAULTPRI
, 0)) == NULL
) {
871 return (FCOE_FAILURE
);
874 ss
->ss_ioctl_flags
= 0;
875 mutex_init(&ss
->ss_ioctl_mutex
, NULL
, MUTEX_DRIVER
, NULL
);
876 list_create(&ss
->ss_mac_list
, sizeof (fcoe_mac_t
),
877 offsetof(fcoe_mac_t
, fm_ss_node
));
878 list_create(&ss
->ss_pfrm_list
, sizeof (fcoe_i_frame_t
),
879 offsetof(fcoe_i_frame_t
, fmi_pending_node
));
881 mutex_init(&ss
->ss_watch_mutex
, 0, MUTEX_DRIVER
, 0);
882 cv_init(&ss
->ss_watch_cv
, NULL
, CV_DRIVER
, NULL
);
883 ss
->ss_flags
&= ~SS_FLAG_TERMINATE_WATCHDOG
;
884 (void) ddi_taskq_dispatch(ss
->ss_watchdog_taskq
,
885 fcoe_watchdog
, ss
, DDI_SLEEP
);
886 while ((ss
->ss_flags
& SS_FLAG_WATCHDOG_RUNNING
) == 0) {
889 fcoe_nworkers
= ddi_prop_get_int(DDI_DEV_T_ANY
, ss
->ss_dip
,
890 DDI_PROP_NOTPROM
| DDI_PROP_DONTPASS
, (char *)fcoe_workers_num
, 4);
891 if (fcoe_nworkers
< 1) {
896 ddi_report_dev(ss
->ss_dip
);
897 return (FCOE_SUCCESS
);
901 * Finish final uninitialization
904 fcoe_detach_uninit(fcoe_soft_state_t
*ss
)
907 if (!list_is_empty(&ss
->ss_mac_list
)) {
908 FCOE_LOG("fcoe", "ss_mac_list is not empty when detach");
909 return (FCOE_FAILURE
);
912 if ((ret
= fcoe_worker_fini()) != FCOE_SUCCESS
) {
919 if (ss
->ss_flags
& SS_FLAG_WATCHDOG_RUNNING
) {
920 mutex_enter(&ss
->ss_watch_mutex
);
921 ss
->ss_flags
|= SS_FLAG_TERMINATE_WATCHDOG
;
922 cv_broadcast(&ss
->ss_watch_cv
);
923 mutex_exit(&ss
->ss_watch_mutex
);
924 while (ss
->ss_flags
& SS_FLAG_WATCHDOG_RUNNING
) {
929 ddi_taskq_destroy(ss
->ss_watchdog_taskq
);
930 mutex_destroy(&ss
->ss_watch_mutex
);
931 cv_destroy(&ss
->ss_watch_cv
);
933 ddi_remove_minor_node(ss
->ss_dip
, NULL
);
934 mutex_destroy(&ss
->ss_ioctl_mutex
);
935 list_destroy(&ss
->ss_mac_list
);
937 return (FCOE_SUCCESS
);
941 * Return mac instance if it exist, or else return NULL.
944 fcoe_lookup_mac_by_id(datalink_id_t linkid
)
946 fcoe_mac_t
*mac
= NULL
;
948 ASSERT(MUTEX_HELD(&fcoe_global_ss
->ss_ioctl_mutex
));
949 for (mac
= list_head(&fcoe_global_ss
->ss_mac_list
); mac
;
950 mac
= list_next(&fcoe_global_ss
->ss_mac_list
, mac
)) {
951 if (linkid
!= mac
->fm_linkid
) {
960 * Return B_TRUE if mac exists, or else return B_FALSE
963 fcoe_mac_existed(fcoe_mac_t
*pmac
)
965 fcoe_mac_t
*mac
= NULL
;
967 ASSERT(MUTEX_HELD(&fcoe_global_ss
->ss_ioctl_mutex
));
968 for (mac
= list_head(&fcoe_global_ss
->ss_mac_list
); mac
;
969 mac
= list_next(&fcoe_global_ss
->ss_mac_list
, mac
)) {
978 * port wwn will start with 20:..., node wwn will start with 10:...
981 fcoe_init_wwn_from_mac(uint8_t *wwn
, uint8_t *mac
, int is_pwwn
, uint8_t idx
)
985 wwn
[0] = (is_pwwn
+ 1) << 4;
987 bcopy(mac
, wwn
+ 2, ETHERADDRL
);
991 * Return fcoe_mac if it exists, otherwise create a new one
994 fcoe_create_mac_by_id(datalink_id_t linkid
)
996 fcoe_mac_t
*mac
= NULL
;
997 ASSERT(MUTEX_HELD(&fcoe_global_ss
->ss_ioctl_mutex
));
999 mac
= fcoe_lookup_mac_by_id(linkid
);
1001 FCOE_LOG("fcoe", "fcoe_create_mac_by_id found one mac %d",
1006 mac
= kmem_zalloc(sizeof (fcoe_mac_t
), KM_SLEEP
);
1007 mac
->fm_linkid
= linkid
;
1009 mac
->fm_ss
= fcoe_global_ss
;
1010 list_insert_tail(&mac
->fm_ss
->ss_mac_list
, mac
);
1011 FCOE_LOG("fcoe", "fcoe_create_mac_by_id created one mac %d", linkid
);
1016 fcoe_destroy_mac(fcoe_mac_t
*mac
)
1018 ASSERT(mac
!= NULL
);
1019 list_remove(&mac
->fm_ss
->ss_mac_list
, mac
);
1020 kmem_free(mac
, sizeof (fcoe_mac_t
));
1025 * ethernet header + vlan header (optional) + FCoE header +
1026 * FC frame + FCoE tailer
1030 fcoe_get_mblk(fcoe_mac_t
*mac
, uint32_t raw_frame_size
)
1036 * FCFH_SIZE + PADDING_SIZE
1038 ASSERT(raw_frame_size
>= 60);
1039 while ((mp
= allocb((size_t)raw_frame_size
, 0)) == NULL
) {
1040 if ((err
= strwaitbuf((size_t)raw_frame_size
, BPRI_LO
)) != 0) {
1041 FCOE_LOG("fcoe_get_mblk", "strwaitbuf return %d", err
);
1045 mp
->b_wptr
= mp
->b_rptr
+ raw_frame_size
;
1048 * We should always zero FC frame header
1050 bzero(mp
->b_rptr
+ PADDING_HEADER_SIZE
,
1051 sizeof (fcoe_fc_frame_header_t
));
1056 fcoe_watchdog(void *arg
)
1058 fcoe_soft_state_t
*ss
= (fcoe_soft_state_t
*)arg
;
1059 fcoe_i_frame_t
*fmi
;
1060 fcoe_mac_t
*mac
= NULL
;
1062 FCOE_LOG("fcoe", "fcoe_soft_state is %p", ss
);
1064 mutex_enter(&ss
->ss_watch_mutex
);
1065 ss
->ss_flags
|= SS_FLAG_WATCHDOG_RUNNING
;
1066 while ((ss
->ss_flags
& SS_FLAG_TERMINATE_WATCHDOG
) == 0) {
1067 while (fmi
= (fcoe_i_frame_t
*)list_head(&ss
->ss_pfrm_list
)) {
1068 list_remove(&ss
->ss_pfrm_list
, fmi
);
1069 mutex_exit(&ss
->ss_watch_mutex
);
1071 mac
= EPORT2MAC(fmi
->fmi_frame
->frm_eport
);
1072 mac
->fm_client
.ect_release_sol_frame(fmi
->fmi_frame
);
1074 mutex_enter(&ss
->ss_watch_mutex
);
1078 ss
->ss_flags
|= SS_FLAG_DOG_WAITING
;
1079 (void) cv_wait(&ss
->ss_watch_cv
, &ss
->ss_watch_mutex
);
1080 ss
->ss_flags
&= ~SS_FLAG_DOG_WAITING
;
1083 ss
->ss_flags
&= ~SS_FLAG_WATCHDOG_RUNNING
;
1084 mutex_exit(&ss
->ss_watch_mutex
);
1092 fcoe_nworkers_running
= 0;
1093 fcoe_worker_taskq
= ddi_taskq_create(0, "FCOE_WORKER_TASKQ",
1094 fcoe_nworkers
, TASKQ_DEFAULTPRI
, 0);
1095 fcoe_workers
= (fcoe_worker_t
*)kmem_zalloc(sizeof (fcoe_worker_t
) *
1096 fcoe_nworkers
, KM_SLEEP
);
1097 for (i
= 0; i
< fcoe_nworkers
; i
++) {
1098 fcoe_worker_t
*w
= &fcoe_workers
[i
];
1099 mutex_init(&w
->worker_lock
, NULL
, MUTEX_DRIVER
, NULL
);
1100 cv_init(&w
->worker_cv
, NULL
, CV_DRIVER
, NULL
);
1101 w
->worker_flags
&= ~FCOE_WORKER_TERMINATE
;
1102 list_create(&w
->worker_frm_list
, sizeof (fcoe_i_frame_t
),
1103 offsetof(fcoe_i_frame_t
, fmi_pending_node
));
1104 (void) ddi_taskq_dispatch(fcoe_worker_taskq
, fcoe_worker_frame
,
1107 while (fcoe_nworkers_running
!= fcoe_nworkers
) {
1117 for (i
= 0; i
< fcoe_nworkers
; i
++) {
1118 fcoe_worker_t
*w
= &fcoe_workers
[i
];
1119 mutex_enter(&w
->worker_lock
);
1120 if (w
->worker_flags
& FCOE_WORKER_STARTED
) {
1121 w
->worker_flags
|= FCOE_WORKER_TERMINATE
;
1122 cv_signal(&w
->worker_cv
);
1124 mutex_exit(&w
->worker_lock
);
1127 while (fcoe_nworkers_running
!= 0) {
1128 delay(drv_usectohz(10000));
1131 ddi_taskq_destroy(fcoe_worker_taskq
);
1132 kmem_free(fcoe_workers
, sizeof (fcoe_worker_t
) * fcoe_nworkers
);
1133 fcoe_workers
= NULL
;
1134 return (FCOE_SUCCESS
);
1138 fcoe_crc_verify(fcoe_frame_t
*frm
)
1141 uint8_t *crc_array
= FRM2FMI(frm
)->fmi_fft
->fft_crc
;
1142 uint32_t crc_from_frame
= ~(crc_array
[0] | (crc_array
[1] << 8) |
1143 (crc_array
[2] << 16) | (crc_array
[3] << 24));
1144 CRC32(crc
, frm
->frm_fc_frame
, frm
->frm_fc_frame_size
, -1U, crc32_table
);
1145 return (crc
== crc_from_frame
? FCOE_SUCCESS
: FCOE_FAILURE
);
1149 fcoe_worker_frame(void *arg
)
1151 fcoe_worker_t
*w
= (fcoe_worker_t
*)arg
;
1152 fcoe_i_frame_t
*fmi
;
1155 atomic_inc_32(&fcoe_nworkers_running
);
1156 mutex_enter(&w
->worker_lock
);
1157 w
->worker_flags
|= FCOE_WORKER_STARTED
| FCOE_WORKER_ACTIVE
;
1158 while ((w
->worker_flags
& FCOE_WORKER_TERMINATE
) == 0) {
1160 * loop through the frames
1162 while (fmi
= list_head(&w
->worker_frm_list
)) {
1163 list_remove(&w
->worker_frm_list
, fmi
);
1164 mutex_exit(&w
->worker_lock
);
1168 ret
= fcoe_crc_verify(fmi
->fmi_frame
);
1169 if (ret
== FCOE_SUCCESS
) {
1170 fmi
->fmi_mac
->fm_client
.ect_rx_frame(
1173 fcoe_release_frame(fmi
->fmi_frame
);
1175 mutex_enter(&w
->worker_lock
);
1178 w
->worker_flags
&= ~FCOE_WORKER_ACTIVE
;
1179 cv_wait(&w
->worker_cv
, &w
->worker_lock
);
1180 w
->worker_flags
|= FCOE_WORKER_ACTIVE
;
1182 w
->worker_flags
&= ~(FCOE_WORKER_STARTED
| FCOE_WORKER_ACTIVE
);
1183 mutex_exit(&w
->worker_lock
);
1184 atomic_dec_32(&fcoe_nworkers_running
);
1185 list_destroy(&w
->worker_frm_list
);
1189 fcoe_post_frame(fcoe_frame_t
*frm
)
1192 uint16_t oxid
= FRM_OXID(frm
);
1194 w
= &fcoe_workers
[oxid
% fcoe_nworkers_running
];
1195 mutex_enter(&w
->worker_lock
);
1196 list_insert_tail(&w
->worker_frm_list
, frm
->frm_fcoe_private
);
1198 if ((w
->worker_flags
& FCOE_WORKER_ACTIVE
) == 0) {
1199 cv_signal(&w
->worker_cv
);
1201 mutex_exit(&w
->worker_lock
);
1205 * The max length of every LOG is 158
1208 fcoe_trace(caddr_t ident
, const char *fmt
, ...)
1216 if (fcoe_trace_on
== 0) {
1220 curclock
= ddi_get_lbolt();
1221 usec
= (curclock
- fcoe_trace_start
) * usec_per_tick
;
1222 len
= snprintf(tbuf
, 158, "%lu.%03lus 0t%lu %s ", (usec
/
1223 (1000 * 1000)), ((usec
% (1000 * 1000)) / 1000),
1224 curclock
, (ident
? ident
: "unknown"));
1225 va_start(args
, fmt
);
1226 len
+= vsnprintf(tbuf
+ len
, 158 - len
, fmt
, args
);
1235 mutex_enter(&fcoe_trace_buf_lock
);
1236 bcopy(tbuf
, &fcoe_trace_buf
[fcoe_trace_buf_curndx
], len
+1);
1237 fcoe_trace_buf_curndx
+= len
;
1238 if (fcoe_trace_buf_curndx
> (fcoe_trace_buf_size
- 320)) {
1239 fcoe_trace_buf_curndx
= 0;
1241 mutex_exit(&fcoe_trace_buf_lock
);
1245 * Check whether the pwwn or nwwn already exist or not
1247 * 1: PWWN conflicted
1248 * -1: NWWN conflicted
1252 fcoe_cmp_wwn(fcoe_mac_t
*checkedmac
)
1255 uint8_t *nwwn
, *pwwn
, *cnwwn
, *cpwwn
;
1257 cnwwn
= checkedmac
->fm_eport
.eport_nodewwn
;
1258 cpwwn
= checkedmac
->fm_eport
.eport_portwwn
;
1259 ASSERT(MUTEX_HELD(&fcoe_global_ss
->ss_ioctl_mutex
));
1261 for (mac
= list_head(&fcoe_global_ss
->ss_mac_list
); mac
;
1262 mac
= list_next(&fcoe_global_ss
->ss_mac_list
, mac
)) {
1263 if (mac
== checkedmac
) {
1266 nwwn
= mac
->fm_eport
.eport_nodewwn
;
1267 pwwn
= mac
->fm_eport
.eport_portwwn
;
1269 if (memcmp(nwwn
, cnwwn
, 8) == 0) {
1273 if (memcmp(pwwn
, cpwwn
, 8) == 0) {
1281 fcoe_get_port_list(fcoe_port_instance_t
*ports
, int count
)
1283 fcoe_mac_t
*mac
= NULL
;
1286 ASSERT(ports
!= NULL
);
1287 ASSERT(MUTEX_HELD(&fcoe_global_ss
->ss_ioctl_mutex
));
1289 for (mac
= list_head(&fcoe_global_ss
->ss_mac_list
); mac
;
1290 mac
= list_next(&fcoe_global_ss
->ss_mac_list
, mac
)) {
1292 bcopy(mac
->fm_eport
.eport_portwwn
,
1293 ports
[i
].fpi_pwwn
, 8);
1294 ports
[i
].fpi_mac_linkid
= mac
->fm_linkid
;
1295 bcopy(mac
->fm_current_addr
,
1296 ports
[i
].fpi_mac_current_addr
, ETHERADDRL
);
1297 bcopy(mac
->fm_primary_addr
,
1298 ports
[i
].fpi_mac_factory_addr
, ETHERADDRL
);
1299 ports
[i
].fpi_port_type
=
1300 EPORT_CLT_TYPE(&mac
->fm_eport
);
1301 ports
[i
].fpi_mtu_size
=
1302 mac
->fm_eport
.eport_mtu
;
1303 ports
[i
].fpi_mac_promisc
=
1304 mac
->fm_promisc_handle
!= NULL
? 1 : 0;