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