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