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