xref: /illumos-gate/usr/src/uts/common/io/fcoe/fcoe.c (revision 07d06da5)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * The following notice accompanied the original version of this file:
28  *
29  * BSD LICENSE
30  *
31  * Copyright(c) 2007 Intel Corporation. All rights reserved.
32  * All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions
36  * are met:
37  *
38  *   * Redistributions of source code must retain the above copyright
39  *     notice, this list of conditions and the following disclaimer.
40  *   * Redistributions in binary form must reproduce the above copyright
41  *     notice, this list of conditions and the following disclaimer in
42  *     the documentation and/or other materials provided with the
43  *     distribution.
44  *   * Neither the name of Intel Corporation nor the names of its
45  *     contributors may be used to endorse or promote products derived
46  *     from this software without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
49  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
50  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
51  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
52  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
53  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
54  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
55  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
56  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
57  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
58  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59  */
60 
61 /*
62  * Common FCoE interface interacts with MAC and FCoE clients, managing
63  * FCoE ports, doing MAC address discovery/managment, and FC frame
64  * encapsulation/decapsulation
65  */
66 
67 #include <sys/stat.h>
68 #include <sys/conf.h>
69 #include <sys/file.h>
70 #include <sys/cred.h>
71 
72 #include <sys/ddi.h>
73 #include <sys/sunddi.h>
74 #include <sys/sunndi.h>
75 #include <sys/byteorder.h>
76 #include <sys/atomic.h>
77 #include <sys/sysmacros.h>
78 #include <sys/cmn_err.h>
79 #include <sys/crc32.h>
80 #include <sys/strsubr.h>
81 
82 #include <sys/mac_client.h>
83 
84 /*
85  * FCoE header files
86  */
87 #include <sys/fcoe/fcoeio.h>
88 #include <sys/fcoe/fcoe_common.h>
89 
90 /*
91  * Driver's own header files
92  */
93 #include <fcoe.h>
94 #include <fcoe_fc.h>
95 #include <fcoe_eth.h>
96 
97 /*
98  * Function forward declaration
99  */
100 static int fcoe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
101 static int fcoe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
102 static int fcoe_bus_ctl(dev_info_t *fca_dip, dev_info_t *rip,
103     ddi_ctl_enum_t op, void *arg, void *result);
104 static int fcoe_open(dev_t *devp, int flag, int otype, cred_t *credp);
105 static int fcoe_close(dev_t dev, int flag, int otype, cred_t *credp);
106 static int fcoe_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
107     cred_t *credp, int *rval);
108 static int fcoe_copyin_iocdata(intptr_t data, int mode, fcoeio_t **fcoeio,
109     void **ibuf, void **abuf, void **obuf);
110 static int fcoe_copyout_iocdata(intptr_t data, int mode, fcoeio_t *fcoeio,
111     void *obuf);
112 static int fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode);
113 static int fcoe_attach_init(fcoe_soft_state_t *this_ss);
114 static int fcoe_detach_uninit(fcoe_soft_state_t *this_ss);
115 static int fcoe_initchild(dev_info_t *fcoe_dip, dev_info_t *client_dip);
116 static int fcoe_uninitchild(dev_info_t *fcoe_dip, dev_info_t *client_dip);
117 static void fcoe_init_wwn_from_mac(uint8_t *wwn, uint8_t *mac,
118     int is_pwwn, uint8_t idx);
119 static fcoe_mac_t *fcoe_create_mac_by_id(datalink_id_t linkid);
120 static int fcoe_cmp_wwn(fcoe_mac_t *checkedmac);
121 static void fcoe_watchdog(void *arg);
122 static void fcoe_worker_init();
123 static int fcoe_worker_fini();
124 static void fcoe_worker_frame();
125 static int fcoe_get_port_list(fcoe_port_instance_t *ports, int count);
126 static boolean_t fcoe_mac_existed(fcoe_mac_t *pmac);
127 
128 /*
129  * Driver identificaton stuff
130  */
131 static struct cb_ops fcoe_cb_ops = {
132 	fcoe_open,
133 	fcoe_close,
134 	nodev,
135 	nodev,
136 	nodev,
137 	nodev,
138 	nodev,
139 	fcoe_ioctl,
140 	nodev,
141 	nodev,
142 	nodev,
143 	nochpoll,
144 	ddi_prop_op,
145 	0,
146 	D_MP | D_NEW | D_HOTPLUG,
147 	CB_REV,
148 	nodev,
149 	nodev
150 };
151 
152 static struct bus_ops fcoe_busops = {
153 	BUSO_REV,
154 	nullbusmap,			/* bus_map */
155 	NULL,				/* bus_get_intrspec */
156 	NULL,				/* bus_add_intrspec */
157 	NULL,				/* bus_remove_intrspec */
158 	i_ddi_map_fault,		/* bus_map_fault */
159 	ddi_dma_map,			/* bus_dma_map */
160 	ddi_dma_allochdl,		/* bus_dma_allochdl */
161 	ddi_dma_freehdl,		/* bus_dma_freehdl */
162 	ddi_dma_bindhdl,		/* bus_dma_bindhdl */
163 	ddi_dma_unbindhdl,		/* bus_unbindhdl */
164 	ddi_dma_flush,			/* bus_dma_flush */
165 	ddi_dma_win,			/* bus_dma_win */
166 	ddi_dma_mctl,			/* bus_dma_ctl */
167 	fcoe_bus_ctl,			/* bus_ctl */
168 	ddi_bus_prop_op,		/* bus_prop_op */
169 	NULL,				/* bus_get_eventcookie */
170 	NULL,				/* bus_add_eventcall */
171 	NULL,				/* bus_remove_event */
172 	NULL,				/* bus_post_event */
173 	NULL,				/* bus_intr_ctl */
174 	NULL,				/* bus_config */
175 	NULL,				/* bus_unconfig */
176 	NULL,				/* bus_fm_init */
177 	NULL,				/* bus_fm_fini */
178 	NULL,				/* bus_fm_access_enter */
179 	NULL,				/* bus_fm_access_exit */
180 	NULL,				/* bus_power */
181 	NULL
182 };
183 
184 static struct dev_ops fcoe_ops = {
185 	DEVO_REV,
186 	0,
187 	nodev,
188 	nulldev,
189 	nulldev,
190 	fcoe_attach,
191 	fcoe_detach,
192 	nodev,
193 	&fcoe_cb_ops,
194 	&fcoe_busops,
195 	ddi_power,
196 	ddi_quiesce_not_needed
197 };
198 
199 #define	FCOE_VERSION	"20091123-1.02"
200 #define	FCOE_NAME	"FCoE Transport v" FCOE_VERSION
201 #define	TASKQ_NAME_LEN	32
202 
203 static struct modldrv modldrv = {
204 	&mod_driverops,
205 	FCOE_NAME,
206 	&fcoe_ops,
207 };
208 
209 static struct modlinkage modlinkage = {
210 	MODREV_1, &modldrv, NULL
211 };
212 
213 /*
214  * TRACE for all FCoE related modules
215  */
216 static kmutex_t fcoe_trace_buf_lock;
217 static int	fcoe_trace_buf_curndx	= 0;
218 static int	fcoe_trace_on		= 1;
219 static caddr_t	fcoe_trace_buf		= NULL;
220 static clock_t	fcoe_trace_start	= 0;
221 static caddr_t	ftb			= NULL;
222 static int	fcoe_trace_buf_size	= (1 * 1024 * 1024);
223 
224 /*
225  * Driver's global variables
226  */
227 const fcoe_ver_e	 fcoe_ver_now	  = FCOE_VER_NOW;
228 static void		*fcoe_state	  = NULL;
229 fcoe_soft_state_t	*fcoe_global_ss	  = NULL;
230 int			 fcoe_use_ext_log = 1;
231 
232 static ddi_taskq_t	*fcoe_worker_taskq;
233 static fcoe_worker_t	*fcoe_workers;
234 static uint32_t		fcoe_nworkers_running;
235 
236 const char		*fcoe_workers_num = "workers-number";
237 volatile int		fcoe_nworkers;
238 
239 /*
240  * Common loadable module entry points _init, _fini, _info
241  */
242 
243 int
244 _init(void)
245 {
246 	int ret;
247 
248 	ret = ddi_soft_state_init(&fcoe_state, sizeof (fcoe_soft_state_t), 0);
249 	if (ret == 0) {
250 		ret = mod_install(&modlinkage);
251 		if (ret != 0) {
252 			ddi_soft_state_fini(&fcoe_state);
253 		} else {
254 			fcoe_trace_start = ddi_get_lbolt();
255 			ftb = kmem_zalloc(fcoe_trace_buf_size,
256 			    KM_SLEEP);
257 			fcoe_trace_buf = ftb;
258 			mutex_init(&fcoe_trace_buf_lock, NULL, MUTEX_DRIVER, 0);
259 		}
260 	}
261 
262 	FCOE_LOG("fcoe", "exit _init with %x", ret);
263 
264 	return (ret);
265 }
266 
267 int
268 _fini(void)
269 {
270 	int ret;
271 
272 	ret = mod_remove(&modlinkage);
273 	if (ret == 0) {
274 		ddi_soft_state_fini(&fcoe_state);
275 	}
276 
277 	FCOE_LOG("fcoe", "exit _fini with %x", ret);
278 	if (ret == 0) {
279 		kmem_free(fcoe_trace_buf, fcoe_trace_buf_size);
280 		mutex_destroy(&fcoe_trace_buf_lock);
281 	}
282 
283 	return (ret);
284 }
285 
286 int
287 _info(struct modinfo *modinfop)
288 {
289 	return (mod_info(&modlinkage, modinfop));
290 }
291 
292 /*
293  * Autoconfiguration entry points: attach, detach, getinfo
294  */
295 
296 static int
297 fcoe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
298 {
299 	int			 ret = DDI_FAILURE;
300 	int			 fcoe_ret;
301 	int			 instance;
302 	fcoe_soft_state_t	*ss;
303 
304 	instance = ddi_get_instance(dip);
305 	switch (cmd) {
306 	case DDI_ATTACH:
307 		ret = ddi_soft_state_zalloc(fcoe_state, instance);
308 		if (ret == DDI_FAILURE) {
309 			FCOE_LOG(0, "soft_state_zalloc-%x/%x", ret, instance);
310 			return (ret);
311 		}
312 
313 		ss = ddi_get_soft_state(fcoe_state, instance);
314 		ss->ss_dip = dip;
315 
316 		ASSERT(fcoe_global_ss == NULL);
317 		fcoe_global_ss = ss;
318 		fcoe_ret = fcoe_attach_init(ss);
319 		if (fcoe_ret == FCOE_SUCCESS) {
320 			ret = DDI_SUCCESS;
321 		}
322 
323 		FCOE_LOG("fcoe", "fcoe_attach_init end with-%x", fcoe_ret);
324 		break;
325 
326 	case DDI_RESUME:
327 		ret = DDI_SUCCESS;
328 		break;
329 
330 	default:
331 		FCOE_LOG("fcoe", "unsupported attach cmd-%x", cmd);
332 		break;
333 	}
334 
335 	return (ret);
336 }
337 
338 static int
339 fcoe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
340 {
341 	int			 ret = DDI_FAILURE;
342 	int			 fcoe_ret;
343 	int			 instance;
344 	fcoe_soft_state_t	*ss;
345 
346 	instance = ddi_get_instance(dip);
347 	ss = ddi_get_soft_state(fcoe_state, instance);
348 	if (ss == NULL) {
349 		return (ret);
350 	}
351 
352 	ASSERT(fcoe_global_ss != NULL);
353 	ASSERT(dip == fcoe_global_ss->ss_dip);
354 	switch (cmd) {
355 	case DDI_DETACH:
356 		fcoe_ret = fcoe_detach_uninit(ss);
357 		if (fcoe_ret == FCOE_SUCCESS) {
358 			ret = DDI_SUCCESS;
359 			fcoe_global_ss = NULL;
360 		}
361 
362 		break;
363 
364 	case DDI_SUSPEND:
365 		ret = DDI_SUCCESS;
366 		break;
367 
368 	default:
369 		FCOE_LOG(0, "unsupported detach cmd-%x", cmd);
370 		break;
371 	}
372 
373 	return (ret);
374 }
375 
376 /*
377  * FCA driver's intercepted bus control operations.
378  */
379 static int
380 fcoe_bus_ctl(dev_info_t *fcoe_dip, dev_info_t *rip,
381     ddi_ctl_enum_t op, void *clientarg, void *result)
382 {
383 	int ret;
384 	switch (op) {
385 	case DDI_CTLOPS_REPORTDEV:
386 	case DDI_CTLOPS_IOMIN:
387 		ret = DDI_SUCCESS;
388 		break;
389 
390 	case DDI_CTLOPS_INITCHILD:
391 		ret = fcoe_initchild(fcoe_dip, (dev_info_t *)clientarg);
392 		break;
393 
394 	case DDI_CTLOPS_UNINITCHILD:
395 		ret = fcoe_uninitchild(fcoe_dip, (dev_info_t *)clientarg);
396 		break;
397 
398 	default:
399 		ret = ddi_ctlops(fcoe_dip, rip, op, clientarg, result);
400 		break;
401 	}
402 
403 	return (ret);
404 }
405 
406 /*
407  * We need specify the dev address for client driver's instance, or we
408  * can't online client driver's instance.
409  */
410 /* ARGSUSED */
411 static int
412 fcoe_initchild(dev_info_t *fcoe_dip, dev_info_t *client_dip)
413 {
414 	char	client_addr[FCOE_STR_LEN];
415 	int	rval;
416 
417 	rval = ddi_prop_get_int(DDI_DEV_T_ANY, client_dip,
418 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1);
419 	if (rval == -1) {
420 		FCOE_LOG(__FUNCTION__, "no mac_id property: %p", client_dip);
421 		return (DDI_FAILURE);
422 	}
423 
424 	bzero(client_addr, FCOE_STR_LEN);
425 	(void) sprintf((char *)client_addr, "%x,0", rval);
426 	ddi_set_name_addr(client_dip, client_addr);
427 	return (DDI_SUCCESS);
428 }
429 
430 /* ARGSUSED */
431 static int
432 fcoe_uninitchild(dev_info_t *fcoe_dip, dev_info_t *client_dip)
433 {
434 	ddi_set_name_addr(client_dip, NULL);
435 	return (DDI_SUCCESS);
436 }
437 
438 /*
439  * Device access entry points
440  */
441 static int
442 fcoe_open(dev_t *devp, int flag, int otype, cred_t *credp)
443 {
444 	int			 instance;
445 	fcoe_soft_state_t	*ss;
446 
447 	if (otype != OTYP_CHR) {
448 		return (EINVAL);
449 	}
450 
451 	/*
452 	 * Since this is for debugging only, only allow root to issue ioctl now
453 	 */
454 	if (drv_priv(credp) != 0) {
455 		return (EPERM);
456 	}
457 
458 	instance = (int)getminor(*devp);
459 	ss = ddi_get_soft_state(fcoe_state, instance);
460 	if (ss == NULL) {
461 		return (ENXIO);
462 	}
463 
464 	mutex_enter(&ss->ss_ioctl_mutex);
465 	if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL) {
466 		/*
467 		 * It is already open for exclusive access.
468 		 * So shut the door on this caller.
469 		 */
470 		mutex_exit(&ss->ss_ioctl_mutex);
471 		return (EBUSY);
472 	}
473 
474 	if (flag & FEXCL) {
475 		if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) {
476 			/*
477 			 * Exclusive operation not possible
478 			 * as it is already opened
479 			 */
480 			mutex_exit(&ss->ss_ioctl_mutex);
481 			return (EBUSY);
482 		}
483 		ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_EXCL;
484 	}
485 
486 	ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_OPEN;
487 	mutex_exit(&ss->ss_ioctl_mutex);
488 
489 	return (0);
490 }
491 
492 /* ARGSUSED */
493 static int
494 fcoe_close(dev_t dev, int flag, int otype, cred_t *credp)
495 {
496 	int			 instance;
497 	fcoe_soft_state_t	*ss;
498 
499 	if (otype != OTYP_CHR) {
500 		return (EINVAL);
501 	}
502 
503 	instance = (int)getminor(dev);
504 	ss = ddi_get_soft_state(fcoe_state, instance);
505 	if (ss == NULL) {
506 		return (ENXIO);
507 	}
508 
509 	mutex_enter(&ss->ss_ioctl_mutex);
510 	if ((ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) == 0) {
511 		mutex_exit(&ss->ss_ioctl_mutex);
512 		return (ENODEV);
513 	}
514 
515 	ss->ss_ioctl_flags &= ~FCOE_IOCTL_FLAG_MASK;
516 	mutex_exit(&ss->ss_ioctl_mutex);
517 
518 	return (0);
519 }
520 
521 /* ARGSUSED */
522 static int
523 fcoe_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
524     cred_t *credp, int *rval)
525 {
526 	fcoe_soft_state_t	*ss;
527 	int			 ret = 0;
528 
529 	if (drv_priv(credp) != 0) {
530 		return (EPERM);
531 	}
532 
533 	ss = ddi_get_soft_state(fcoe_state, (int32_t)getminor(dev));
534 	if (ss == NULL) {
535 		return (ENXIO);
536 	}
537 
538 	mutex_enter(&ss->ss_ioctl_mutex);
539 	if ((ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_OPEN) == 0) {
540 		mutex_exit(&ss->ss_ioctl_mutex);
541 		return (ENXIO);
542 	}
543 	mutex_exit(&ss->ss_ioctl_mutex);
544 
545 	switch (cmd) {
546 	case FCOEIO_CMD:
547 		ret = fcoe_iocmd(ss, data, mode);
548 		break;
549 	default:
550 		FCOE_LOG(0, "fcoe_ioctl: ioctl-0x%02X", cmd);
551 		ret = ENOTTY;
552 		break;
553 	}
554 
555 	return (ret);
556 }
557 
558 static int
559 fcoe_copyin_iocdata(intptr_t data, int mode, fcoeio_t **fcoeio,
560     void **ibuf, void **abuf, void **obuf)
561 {
562 	int ret = 0;
563 
564 	*ibuf = NULL;
565 	*abuf = NULL;
566 	*obuf = NULL;
567 	*fcoeio = kmem_zalloc(sizeof (fcoeio_t), KM_SLEEP);
568 	if (ddi_copyin((void *)data, *fcoeio, sizeof (fcoeio_t), mode) != 0) {
569 		ret = EFAULT;
570 		goto copyin_iocdata_fail;
571 	}
572 
573 	if ((*fcoeio)->fcoeio_ilen > FCOEIO_MAX_BUF_LEN ||
574 	    (*fcoeio)->fcoeio_alen > FCOEIO_MAX_BUF_LEN ||
575 	    (*fcoeio)->fcoeio_olen > FCOEIO_MAX_BUF_LEN) {
576 		ret = EFAULT;
577 		goto copyin_iocdata_fail;
578 	}
579 
580 	if ((*fcoeio)->fcoeio_ilen) {
581 		*ibuf = kmem_zalloc((*fcoeio)->fcoeio_ilen, KM_SLEEP);
582 		if (ddi_copyin((void *)(unsigned long)(*fcoeio)->fcoeio_ibuf,
583 		    *ibuf, (*fcoeio)->fcoeio_ilen, mode) != 0) {
584 			ret = EFAULT;
585 			goto copyin_iocdata_fail;
586 		}
587 	}
588 
589 	if ((*fcoeio)->fcoeio_alen) {
590 		*abuf = kmem_zalloc((*fcoeio)->fcoeio_alen, KM_SLEEP);
591 		if (ddi_copyin((void *)(unsigned long)(*fcoeio)->fcoeio_abuf,
592 		    *abuf, (*fcoeio)->fcoeio_alen, mode) != 0) {
593 			ret = EFAULT;
594 			goto copyin_iocdata_fail;
595 		}
596 	}
597 
598 	if ((*fcoeio)->fcoeio_olen) {
599 		*obuf = kmem_zalloc((*fcoeio)->fcoeio_olen, KM_SLEEP);
600 	}
601 	return (ret);
602 
603 copyin_iocdata_fail:
604 	if (*abuf) {
605 		kmem_free(*abuf, (*fcoeio)->fcoeio_alen);
606 		*abuf = NULL;
607 	}
608 
609 	if (*ibuf) {
610 		kmem_free(*ibuf, (*fcoeio)->fcoeio_ilen);
611 		*ibuf = NULL;
612 	}
613 
614 	kmem_free(*fcoeio, sizeof (fcoeio_t));
615 	return (ret);
616 }
617 
618 static int
619 fcoe_copyout_iocdata(intptr_t data, int mode, fcoeio_t *fcoeio, void *obuf)
620 {
621 	if (fcoeio->fcoeio_olen) {
622 		if (ddi_copyout(obuf,
623 		    (void *)(unsigned long)fcoeio->fcoeio_obuf,
624 		    fcoeio->fcoeio_olen, mode) != 0) {
625 			return (EFAULT);
626 		}
627 	}
628 
629 	if (ddi_copyout(fcoeio, (void *)data, sizeof (fcoeio_t), mode) != 0) {
630 		return (EFAULT);
631 	}
632 	return (0);
633 }
634 
635 static int
636 fcoe_iocmd(fcoe_soft_state_t *ss, intptr_t data, int mode)
637 {
638 	int		ret;
639 	fcoe_mac_t	*fcoe_mac;
640 	void		*ibuf = NULL;
641 	void		*obuf = NULL;
642 	void		*abuf = NULL;
643 	fcoeio_t	*fcoeio;
644 
645 	ret = fcoe_copyin_iocdata(data, mode, &fcoeio, &ibuf, &abuf, &obuf);
646 	if (ret != 0) {
647 		goto fcoeiocmd_release_buf;
648 	}
649 
650 	/*
651 	 * If an exclusive open was demanded during open, ensure that
652 	 * only one thread can execute an ioctl at a time
653 	 */
654 	mutex_enter(&ss->ss_ioctl_mutex);
655 	if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL) {
656 		if (ss->ss_ioctl_flags & FCOE_IOCTL_FLAG_EXCL_BUSY) {
657 			mutex_exit(&ss->ss_ioctl_mutex);
658 			fcoeio->fcoeio_status = FCOEIOE_BUSY;
659 			ret = EBUSY;
660 			goto fcoeiocmd_release_buf;
661 		}
662 		ss->ss_ioctl_flags |= FCOE_IOCTL_FLAG_EXCL_BUSY;
663 	}
664 	mutex_exit(&ss->ss_ioctl_mutex);
665 
666 	fcoeio->fcoeio_status = 0;
667 
668 	switch (fcoeio->fcoeio_cmd) {
669 	case FCOEIO_CREATE_FCOE_PORT: {
670 		fcoeio_create_port_param_t	*param =
671 		    (fcoeio_create_port_param_t *)ibuf;
672 		int		cmpwwn = 0;
673 		fcoe_port_t	*eport;
674 
675 		if (fcoeio->fcoeio_ilen !=
676 		    sizeof (fcoeio_create_port_param_t) ||
677 		    fcoeio->fcoeio_xfer != FCOEIO_XFER_WRITE) {
678 			fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG;
679 			ret = EINVAL;
680 			break;
681 		}
682 
683 		mutex_enter(&ss->ss_ioctl_mutex);
684 		fcoe_mac = fcoe_create_mac_by_id(param->fcp_mac_linkid);
685 		if (fcoe_mac == NULL) {
686 			mutex_exit(&ss->ss_ioctl_mutex);
687 			fcoeio->fcoeio_status = FCOEIOE_CREATE_MAC;
688 			ret = EIO;
689 			break;
690 		}
691 
692 		if (fcoe_mac->fm_flags & FCOE_MAC_FLAG_ENABLED) {
693 			mutex_exit(&ss->ss_ioctl_mutex);
694 			fcoeio->fcoeio_status = FCOEIOE_ALREADY;
695 			ret = EALREADY;
696 			break;
697 		} else {
698 			ret = fcoe_open_mac(fcoe_mac, param->fcp_force_promisc,
699 			    &fcoeio->fcoeio_status);
700 			if (ret != 0) {
701 				fcoe_destroy_mac(fcoe_mac);
702 				mutex_exit(&ss->ss_ioctl_mutex);
703 				if (fcoeio->fcoeio_status == 0) {
704 					fcoeio->fcoeio_status =
705 					    FCOEIOE_OPEN_MAC;
706 				}
707 				ret = EIO;
708 				break;
709 			} else {
710 				fcoe_mac->fm_flags |= FCOE_MAC_FLAG_ENABLED;
711 			}
712 		}
713 
714 		/*
715 		 * Provide PWWN and NWWN based on mac address
716 		 */
717 		eport = &fcoe_mac->fm_eport;
718 		if (!param->fcp_pwwn_provided) {
719 			fcoe_init_wwn_from_mac(eport->eport_portwwn,
720 			    fcoe_mac->fm_current_addr, 1, 0);
721 		} else {
722 			(void) memcpy(eport->eport_portwwn, param->fcp_pwwn, 8);
723 		}
724 
725 		if (!param->fcp_nwwn_provided) {
726 			fcoe_init_wwn_from_mac(eport->eport_nodewwn,
727 			    fcoe_mac->fm_current_addr, 0, 0);
728 		} else {
729 			(void) memcpy(eport->eport_nodewwn, param->fcp_nwwn, 8);
730 		}
731 
732 		cmpwwn = fcoe_cmp_wwn(fcoe_mac);
733 
734 		if (cmpwwn != 0) {
735 			if (cmpwwn == 1) {
736 				fcoeio->fcoeio_status = FCOEIOE_PWWN_CONFLICTED;
737 			} else if (cmpwwn == -1) {
738 				fcoeio->fcoeio_status = FCOEIOE_NWWN_CONFLICTED;
739 			}
740 			(void) fcoe_close_mac(fcoe_mac);
741 			fcoe_destroy_mac(fcoe_mac);
742 			mutex_exit(&ss->ss_ioctl_mutex);
743 			ret = ENOTUNIQ;
744 			break;
745 		}
746 
747 		if (ret == 0) {
748 			ret = fcoe_create_port(ss->ss_dip,
749 			    fcoe_mac,
750 			    (param->fcp_port_type == FCOE_CLIENT_TARGET));
751 			if (ret != 0) {
752 				if (fcoe_mac_existed(fcoe_mac) == B_TRUE) {
753 					(void) fcoe_close_mac(fcoe_mac);
754 					fcoe_destroy_mac(fcoe_mac);
755 				}
756 				fcoeio->fcoeio_status = FCOEIOE_CREATE_PORT;
757 				ret = EIO;
758 			}
759 		}
760 		mutex_exit(&ss->ss_ioctl_mutex);
761 
762 		break;
763 	}
764 
765 	case FCOEIO_DELETE_FCOE_PORT: {
766 		fcoeio_delete_port_param_t *del_port_param =
767 		    (fcoeio_delete_port_param_t *)ibuf;
768 		uint64_t *is_target = (uint64_t *)obuf;
769 
770 		if (fcoeio->fcoeio_ilen < sizeof (fcoeio_delete_port_param_t) ||
771 		    fcoeio->fcoeio_olen != sizeof (uint64_t) ||
772 		    fcoeio->fcoeio_xfer != FCOEIO_XFER_RW) {
773 			fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG;
774 			ret = EINVAL;
775 			break;
776 		}
777 
778 		mutex_enter(&ss->ss_ioctl_mutex);
779 		ret = fcoe_delete_port(ss->ss_dip, fcoeio,
780 		    del_port_param->fdp_mac_linkid, is_target);
781 		mutex_exit(&ss->ss_ioctl_mutex);
782 		FCOE_LOG("fcoe", "fcoe_delete_port %x return: %d",
783 		    del_port_param->fdp_mac_linkid, ret);
784 		break;
785 	}
786 
787 	case FCOEIO_GET_FCOE_PORT_LIST: {
788 		fcoe_port_list_t *list = (fcoe_port_list_t *)obuf;
789 		int		count;
790 
791 		if (fcoeio->fcoeio_xfer != FCOEIO_XFER_READ ||
792 		    fcoeio->fcoeio_olen < sizeof (fcoe_port_list_t)) {
793 			fcoeio->fcoeio_status = FCOEIOE_INVAL_ARG;
794 			ret = EINVAL;
795 			break;
796 		}
797 		mutex_enter(&ss->ss_ioctl_mutex);
798 
799 		list->numPorts = 1 + (fcoeio->fcoeio_olen -
800 		    sizeof (fcoe_port_list_t))/sizeof (fcoe_port_instance_t);
801 
802 		count = fcoe_get_port_list(list->ports, list->numPorts);
803 
804 		if (count > list->numPorts) {
805 			fcoeio->fcoeio_status = FCOEIOE_MORE_DATA;
806 			ret = ENOSPC;
807 		}
808 		list->numPorts = count;
809 		mutex_exit(&ss->ss_ioctl_mutex);
810 
811 		break;
812 
813 	}
814 
815 	default:
816 		return (ENOTTY);
817 	}
818 
819 	FCOE_LOG("fcoe", "fcoe_ioctl %x returned %d, fcoeio_status = %d",
820 	    fcoeio->fcoeio_cmd, ret, fcoeio->fcoeio_status);
821 
822 fcoeiocmd_release_buf:
823 	if (ret == 0) {
824 		ret = fcoe_copyout_iocdata(data, mode, fcoeio, obuf);
825 	} else if (fcoeio->fcoeio_status) {
826 		(void) fcoe_copyout_iocdata(data, mode, fcoeio, obuf);
827 	}
828 
829 	if (obuf != NULL) {
830 		kmem_free(obuf, fcoeio->fcoeio_olen);
831 		obuf = NULL;
832 	}
833 	if (abuf != NULL) {
834 		kmem_free(abuf, fcoeio->fcoeio_alen);
835 		abuf = NULL;
836 	}
837 
838 	if (ibuf != NULL) {
839 		kmem_free(ibuf, fcoeio->fcoeio_ilen);
840 		ibuf = NULL;
841 	}
842 	kmem_free(fcoeio, sizeof (fcoeio_t));
843 
844 	return (ret);
845 }
846 
847 /*
848  * Finish final initialization
849  */
850 static int
851 fcoe_attach_init(fcoe_soft_state_t *ss)
852 {
853 	char taskq_name[TASKQ_NAME_LEN];
854 
855 	if (ddi_create_minor_node(ss->ss_dip, "admin", S_IFCHR,
856 	    ddi_get_instance(ss->ss_dip), DDI_PSEUDO, 0) != DDI_SUCCESS) {
857 		FCOE_LOG("FCOE", "ddi_create_minor_node failed");
858 		return (FCOE_FAILURE);
859 	}
860 
861 	/*
862 	 * watchdog responsible for release frame and dispatch events
863 	 */
864 	(void) snprintf(taskq_name, sizeof (taskq_name), "fcoe_mac");
865 	taskq_name[TASKQ_NAME_LEN - 1] = 0;
866 	if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL,
867 	    taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) {
868 		return (FCOE_FAILURE);
869 	}
870 
871 	ss->ss_ioctl_flags = 0;
872 	mutex_init(&ss->ss_ioctl_mutex, NULL, MUTEX_DRIVER, NULL);
873 	list_create(&ss->ss_mac_list, sizeof (fcoe_mac_t),
874 	    offsetof(fcoe_mac_t, fm_ss_node));
875 	list_create(&ss->ss_pfrm_list, sizeof (fcoe_i_frame_t),
876 	    offsetof(fcoe_i_frame_t, fmi_pending_node));
877 
878 	mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0);
879 	cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL);
880 	ss->ss_flags &= ~SS_FLAG_TERMINATE_WATCHDOG;
881 	(void) ddi_taskq_dispatch(ss->ss_watchdog_taskq,
882 	    fcoe_watchdog, ss, DDI_SLEEP);
883 	while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) {
884 		delay(10);
885 	}
886 	fcoe_nworkers = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip,
887 	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, (char *)fcoe_workers_num, 4);
888 	if (fcoe_nworkers < 1) {
889 		fcoe_nworkers = 4;
890 	}
891 	fcoe_worker_init();
892 
893 	ddi_report_dev(ss->ss_dip);
894 	return (FCOE_SUCCESS);
895 }
896 
897 /*
898  * Finish final uninitialization
899  */
900 static int
901 fcoe_detach_uninit(fcoe_soft_state_t *ss)
902 {
903 	int ret;
904 	if (!list_is_empty(&ss->ss_mac_list)) {
905 		FCOE_LOG("fcoe", "ss_mac_list is not empty when detach");
906 		return (FCOE_FAILURE);
907 	}
908 
909 	if ((ret = fcoe_worker_fini()) != FCOE_SUCCESS) {
910 		return (ret);
911 	}
912 
913 	/*
914 	 * Stop watchdog
915 	 */
916 	if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
917 		mutex_enter(&ss->ss_watch_mutex);
918 		ss->ss_flags |= SS_FLAG_TERMINATE_WATCHDOG;
919 		cv_broadcast(&ss->ss_watch_cv);
920 		mutex_exit(&ss->ss_watch_mutex);
921 		while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
922 			delay(10);
923 		}
924 	}
925 
926 	ddi_taskq_destroy(ss->ss_watchdog_taskq);
927 	mutex_destroy(&ss->ss_watch_mutex);
928 	cv_destroy(&ss->ss_watch_cv);
929 
930 	ddi_remove_minor_node(ss->ss_dip, NULL);
931 	mutex_destroy(&ss->ss_ioctl_mutex);
932 	list_destroy(&ss->ss_mac_list);
933 
934 	return (FCOE_SUCCESS);
935 }
936 
937 /*
938  * Return mac instance if it exist, or else return NULL.
939  */
940 fcoe_mac_t *
941 fcoe_lookup_mac_by_id(datalink_id_t linkid)
942 {
943 	fcoe_mac_t	*mac = NULL;
944 
945 	ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex));
946 	for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac;
947 	    mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) {
948 		if (linkid != mac->fm_linkid) {
949 			continue;
950 		}
951 		return (mac);
952 	}
953 	return (NULL);
954 }
955 
956 /*
957  * Return B_TRUE if mac exists, or else return B_FALSE
958  */
959 static boolean_t
960 fcoe_mac_existed(fcoe_mac_t *pmac)
961 {
962 	fcoe_mac_t	*mac = NULL;
963 
964 	ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex));
965 	for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac;
966 	    mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) {
967 		if (mac == pmac) {
968 			return (B_TRUE);
969 		}
970 	}
971 	return (B_FALSE);
972 }
973 
974 /*
975  * port wwn will start with 20:..., node wwn will start with 10:...
976  */
977 static void
978 fcoe_init_wwn_from_mac(uint8_t *wwn, uint8_t *mac, int is_pwwn, uint8_t idx)
979 {
980 	ASSERT(wwn != NULL);
981 	ASSERT(mac != NULL);
982 	wwn[0] = (is_pwwn + 1) << 4;
983 	wwn[1] = idx;
984 	bcopy(mac, wwn + 2, ETHERADDRL);
985 }
986 
987 /*
988  * Return fcoe_mac if it exists, otherwise create a new one
989  */
990 static fcoe_mac_t *
991 fcoe_create_mac_by_id(datalink_id_t linkid)
992 {
993 	fcoe_mac_t	*mac = NULL;
994 	ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex));
995 
996 	mac = fcoe_lookup_mac_by_id(linkid);
997 	if (mac != NULL) {
998 		FCOE_LOG("fcoe", "fcoe_create_mac_by_id found one mac %d",
999 		    linkid);
1000 		return (mac);
1001 	}
1002 
1003 	mac = kmem_zalloc(sizeof (fcoe_mac_t), KM_SLEEP);
1004 	mac->fm_linkid = linkid;
1005 	mac->fm_flags = 0;
1006 	mac->fm_ss = fcoe_global_ss;
1007 	list_insert_tail(&mac->fm_ss->ss_mac_list, mac);
1008 	FCOE_LOG("fcoe", "fcoe_create_mac_by_id created one mac %d", linkid);
1009 	return (mac);
1010 }
1011 
1012 void
1013 fcoe_destroy_mac(fcoe_mac_t *mac)
1014 {
1015 	ASSERT(mac != NULL);
1016 	list_remove(&mac->fm_ss->ss_mac_list, mac);
1017 	kmem_free(mac, sizeof (fcoe_mac_t));
1018 }
1019 
1020 /*
1021  * raw frame layout:
1022  * ethernet header + vlan header (optional) + FCoE header +
1023  * FC frame + FCoE tailer
1024  */
1025 /* ARGSUSED */
1026 mblk_t *
1027 fcoe_get_mblk(fcoe_mac_t *mac, uint32_t raw_frame_size)
1028 {
1029 	mblk_t	*mp;
1030 	int	 err;
1031 
1032 	/*
1033 	 * FCFH_SIZE + PADDING_SIZE
1034 	 */
1035 	ASSERT(raw_frame_size >= 60);
1036 	while ((mp = allocb((size_t)raw_frame_size, 0)) == NULL) {
1037 		if ((err = strwaitbuf((size_t)raw_frame_size, BPRI_LO)) != 0) {
1038 			FCOE_LOG("fcoe_get_mblk", "strwaitbuf return %d", err);
1039 			return (NULL);
1040 		}
1041 	}
1042 	mp->b_wptr = mp->b_rptr + raw_frame_size;
1043 
1044 	/*
1045 	 * We should always zero FC frame header
1046 	 */
1047 	bzero(mp->b_rptr + PADDING_HEADER_SIZE,
1048 	    sizeof (fcoe_fc_frame_header_t));
1049 	return (mp);
1050 }
1051 
1052 static void
1053 fcoe_watchdog(void *arg)
1054 {
1055 	fcoe_soft_state_t	*ss	   = (fcoe_soft_state_t *)arg;
1056 	fcoe_i_frame_t		*fmi;
1057 	fcoe_mac_t		*mac = NULL;
1058 
1059 	FCOE_LOG("fcoe", "fcoe_soft_state is %p", ss);
1060 
1061 	mutex_enter(&ss->ss_watch_mutex);
1062 	ss->ss_flags |= SS_FLAG_WATCHDOG_RUNNING;
1063 	while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) {
1064 		while (fmi = (fcoe_i_frame_t *)list_head(&ss->ss_pfrm_list)) {
1065 			list_remove(&ss->ss_pfrm_list, fmi);
1066 			mutex_exit(&ss->ss_watch_mutex);
1067 
1068 			mac = EPORT2MAC(fmi->fmi_frame->frm_eport);
1069 			mac->fm_client.ect_release_sol_frame(fmi->fmi_frame);
1070 
1071 			mutex_enter(&ss->ss_watch_mutex);
1072 			mac->fm_frm_cnt--;
1073 		}
1074 
1075 		ss->ss_flags |= SS_FLAG_DOG_WAITING;
1076 		(void) cv_wait(&ss->ss_watch_cv, &ss->ss_watch_mutex);
1077 		ss->ss_flags &= ~SS_FLAG_DOG_WAITING;
1078 	}
1079 
1080 	ss->ss_flags &= ~SS_FLAG_WATCHDOG_RUNNING;
1081 	mutex_exit(&ss->ss_watch_mutex);
1082 }
1083 
1084 static void
1085 fcoe_worker_init()
1086 {
1087 	uint32_t i;
1088 
1089 	fcoe_nworkers_running = 0;
1090 	fcoe_worker_taskq = ddi_taskq_create(0, "FCOE_WORKER_TASKQ",
1091 	    fcoe_nworkers, TASKQ_DEFAULTPRI, 0);
1092 	fcoe_workers = (fcoe_worker_t *)kmem_zalloc(sizeof (fcoe_worker_t) *
1093 	    fcoe_nworkers, KM_SLEEP);
1094 	for (i = 0; i < fcoe_nworkers; i++) {
1095 		fcoe_worker_t *w = &fcoe_workers[i];
1096 		mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL);
1097 		cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL);
1098 		w->worker_flags &= ~FCOE_WORKER_TERMINATE;
1099 		list_create(&w->worker_frm_list, sizeof (fcoe_i_frame_t),
1100 		    offsetof(fcoe_i_frame_t, fmi_pending_node));
1101 		(void) ddi_taskq_dispatch(fcoe_worker_taskq, fcoe_worker_frame,
1102 		    w, DDI_SLEEP);
1103 	}
1104 	while (fcoe_nworkers_running != fcoe_nworkers) {
1105 		delay(10);
1106 	}
1107 }
1108 
1109 static int
1110 fcoe_worker_fini()
1111 {
1112 	uint32_t i;
1113 
1114 	for (i = 0; i < fcoe_nworkers; i++) {
1115 		fcoe_worker_t *w = &fcoe_workers[i];
1116 		mutex_enter(&w->worker_lock);
1117 		if (w->worker_flags & FCOE_WORKER_STARTED) {
1118 			w->worker_flags |= FCOE_WORKER_TERMINATE;
1119 			cv_signal(&w->worker_cv);
1120 		}
1121 		mutex_exit(&w->worker_lock);
1122 	}
1123 
1124 	while (fcoe_nworkers_running != 0) {
1125 		delay(drv_usectohz(10000));
1126 	}
1127 
1128 	ddi_taskq_destroy(fcoe_worker_taskq);
1129 	kmem_free(fcoe_workers, sizeof (fcoe_worker_t) * fcoe_nworkers);
1130 	fcoe_workers = NULL;
1131 	return (FCOE_SUCCESS);
1132 }
1133 
1134 static int
1135 fcoe_crc_verify(fcoe_frame_t *frm)
1136 {
1137 	uint32_t crc;
1138 	uint8_t *crc_array = FRM2FMI(frm)->fmi_fft->fft_crc;
1139 	uint32_t crc_from_frame = ~(crc_array[0] | (crc_array[1] << 8) |
1140 	    (crc_array[2] << 16) | (crc_array[3] << 24));
1141 	CRC32(crc, frm->frm_fc_frame, frm->frm_fc_frame_size, -1U, crc32_table);
1142 	return (crc == crc_from_frame ? FCOE_SUCCESS : FCOE_FAILURE);
1143 }
1144 
1145 static void
1146 fcoe_worker_frame(void *arg)
1147 {
1148 	fcoe_worker_t	*w = (fcoe_worker_t *)arg;
1149 	fcoe_i_frame_t	*fmi;
1150 	int		ret;
1151 
1152 	atomic_add_32(&fcoe_nworkers_running, 1);
1153 	mutex_enter(&w->worker_lock);
1154 	w->worker_flags |= FCOE_WORKER_STARTED | FCOE_WORKER_ACTIVE;
1155 	while ((w->worker_flags & FCOE_WORKER_TERMINATE) == 0) {
1156 		/*
1157 		 * loop through the frames
1158 		 */
1159 		while (fmi = list_head(&w->worker_frm_list)) {
1160 			list_remove(&w->worker_frm_list, fmi);
1161 			mutex_exit(&w->worker_lock);
1162 			/*
1163 			 * do the checksum
1164 			 */
1165 			ret = fcoe_crc_verify(fmi->fmi_frame);
1166 			if (ret == FCOE_SUCCESS) {
1167 				fmi->fmi_mac->fm_client.ect_rx_frame(
1168 				    fmi->fmi_frame);
1169 			} else {
1170 				fcoe_release_frame(fmi->fmi_frame);
1171 			}
1172 			mutex_enter(&w->worker_lock);
1173 			w->worker_ntasks--;
1174 		}
1175 		w->worker_flags &= ~FCOE_WORKER_ACTIVE;
1176 		cv_wait(&w->worker_cv, &w->worker_lock);
1177 		w->worker_flags |= FCOE_WORKER_ACTIVE;
1178 	}
1179 	w->worker_flags &= ~(FCOE_WORKER_STARTED | FCOE_WORKER_ACTIVE);
1180 	mutex_exit(&w->worker_lock);
1181 	atomic_add_32(&fcoe_nworkers_running, -1);
1182 	list_destroy(&w->worker_frm_list);
1183 }
1184 
1185 void
1186 fcoe_post_frame(fcoe_frame_t *frm)
1187 {
1188 	fcoe_worker_t *w;
1189 	uint16_t	oxid = FRM_OXID(frm);
1190 
1191 	w = &fcoe_workers[oxid % fcoe_nworkers_running];
1192 	mutex_enter(&w->worker_lock);
1193 	list_insert_tail(&w->worker_frm_list, frm->frm_fcoe_private);
1194 	w->worker_ntasks++;
1195 	if ((w->worker_flags & FCOE_WORKER_ACTIVE) == 0) {
1196 		cv_signal(&w->worker_cv);
1197 	}
1198 	mutex_exit(&w->worker_lock);
1199 }
1200 
1201 /*
1202  * The max length of every LOG is 158
1203  */
1204 void
1205 fcoe_trace(caddr_t ident, const char *fmt, ...)
1206 {
1207 	va_list args;
1208 	char	tbuf[160];
1209 	int	len;
1210 	clock_t curclock;
1211 	clock_t usec;
1212 
1213 	if (fcoe_trace_on == 0) {
1214 		return;
1215 	}
1216 
1217 	curclock = ddi_get_lbolt();
1218 	usec = (curclock - fcoe_trace_start) * usec_per_tick;
1219 	len = snprintf(tbuf, 158, "%lu.%03lus 0t%lu %s ", (usec /
1220 	    (1000 * 1000)), ((usec % (1000 * 1000)) / 1000),
1221 	    curclock, (ident ? ident : "unknown"));
1222 	va_start(args, fmt);
1223 	len += vsnprintf(tbuf + len, 158 - len, fmt, args);
1224 	va_end(args);
1225 
1226 	if (len > 158) {
1227 		len = 158;
1228 	}
1229 	tbuf[len++] = '\n';
1230 	tbuf[len] = 0;
1231 
1232 	mutex_enter(&fcoe_trace_buf_lock);
1233 	bcopy(tbuf, &fcoe_trace_buf[fcoe_trace_buf_curndx], len+1);
1234 	fcoe_trace_buf_curndx += len;
1235 	if (fcoe_trace_buf_curndx > (fcoe_trace_buf_size - 320)) {
1236 		fcoe_trace_buf_curndx = 0;
1237 	}
1238 	mutex_exit(&fcoe_trace_buf_lock);
1239 }
1240 
1241 /*
1242  * Check whether the pwwn or nwwn already exist or not
1243  * Return value:
1244  * 1: PWWN conflicted
1245  * -1: NWWN conflicted
1246  * 0: No conflict
1247  */
1248 static int
1249 fcoe_cmp_wwn(fcoe_mac_t *checkedmac)
1250 {
1251 	fcoe_mac_t	*mac;
1252 	uint8_t		*nwwn, *pwwn, *cnwwn, *cpwwn;
1253 
1254 	cnwwn = checkedmac->fm_eport.eport_nodewwn;
1255 	cpwwn = checkedmac->fm_eport.eport_portwwn;
1256 	ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex));
1257 
1258 	for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac;
1259 	    mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) {
1260 		if (mac == checkedmac) {
1261 			continue;
1262 		}
1263 		nwwn = mac->fm_eport.eport_nodewwn;
1264 		pwwn = mac->fm_eport.eport_portwwn;
1265 
1266 		if (memcmp(nwwn, cnwwn, 8) == 0) {
1267 			return (-1);
1268 		}
1269 
1270 		if (memcmp(pwwn, cpwwn, 8) == 0) {
1271 			return (1);
1272 		}
1273 	}
1274 	return (0);
1275 }
1276 
1277 static int
1278 fcoe_get_port_list(fcoe_port_instance_t *ports, int count)
1279 {
1280 	fcoe_mac_t	*mac = NULL;
1281 	int		i = 0;
1282 
1283 	ASSERT(ports != NULL);
1284 	ASSERT(MUTEX_HELD(&fcoe_global_ss->ss_ioctl_mutex));
1285 
1286 	for (mac = list_head(&fcoe_global_ss->ss_mac_list); mac;
1287 	    mac = list_next(&fcoe_global_ss->ss_mac_list, mac)) {
1288 		if (i < count) {
1289 			bcopy(mac->fm_eport.eport_portwwn,
1290 			    ports[i].fpi_pwwn, 8);
1291 			ports[i].fpi_mac_linkid = mac->fm_linkid;
1292 			bcopy(mac->fm_current_addr,
1293 			    ports[i].fpi_mac_current_addr, ETHERADDRL);
1294 			bcopy(mac->fm_primary_addr,
1295 			    ports[i].fpi_mac_factory_addr, ETHERADDRL);
1296 			ports[i].fpi_port_type =
1297 			    EPORT_CLT_TYPE(&mac->fm_eport);
1298 			ports[i].fpi_mtu_size =
1299 			    mac->fm_eport.eport_mtu;
1300 			ports[i].fpi_mac_promisc =
1301 			    mac->fm_promisc_handle != NULL ? 1 : 0;
1302 		}
1303 		i++;
1304 	}
1305 	return (i);
1306 }
1307