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