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