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  * Driver kernel header files
63  */
64 #include <sys/conf.h>
65 #include <sys/ddi.h>
66 #include <sys/stat.h>
67 #include <sys/pci.h>
68 #include <sys/sunddi.h>
69 #include <sys/modctl.h>
70 #include <sys/file.h>
71 #include <sys/cred.h>
72 #include <sys/byteorder.h>
73 #include <sys/atomic.h>
74 #include <sys/modhash.h>
75 #include <sys/scsi/scsi.h>
76 #include <sys/ethernet.h>
77 
78 /*
79  * COMSTAR header files
80  */
81 #include <sys/stmf_defines.h>
82 #include <sys/fct_defines.h>
83 #include <sys/stmf.h>
84 #include <sys/portif.h>
85 #include <sys/fct.h>
86 
87 /*
88  * FCoE header files
89  */
90 #include <sys/fcoe/fcoe_common.h>
91 
92 /*
93  * Driver's own header files
94  */
95 #include <fcoet.h>
96 #include <fcoet_eth.h>
97 #include <fcoet_fc.h>
98 
99 /*
100  * static function forward declaration
101  */
102 static int fcoet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
103 static int fcoet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
104 static int fcoet_open(dev_t *devp, int flag, int otype, cred_t *credp);
105 static int fcoet_close(dev_t dev, int flag, int otype, cred_t *credp);
106 static int fcoet_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
107     cred_t *credp, int *rval);
108 static fct_status_t fcoet_attach_init(fcoet_soft_state_t *ss);
109 static fct_status_t fcoet_detach_uninit(fcoet_soft_state_t *ss);
110 static void fcoet_watchdog(void *arg);
111 static void fcoet_handle_sol_flogi(fcoet_soft_state_t *ss);
112 static stmf_data_buf_t *fcoet_dbuf_alloc(fct_local_port_t *port,
113     uint32_t size, uint32_t *pminsize, uint32_t flags);
114 static void fcoet_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf);
115 static int fcoet_dbuf_init(fcoet_soft_state_t *ss);
116 static void fcoet_dbuf_destroy(fcoet_soft_state_t *ss);
117 static uint_t
118 fcoet_sol_oxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg);
119 static uint_t
120 fcoet_unsol_rxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg);
121 
122 /*
123  * Driver identificaton stuff
124  */
125 static struct cb_ops fcoet_cb_ops = {
126 	fcoet_open,
127 	fcoet_close,
128 	nodev,
129 	nodev,
130 	nodev,
131 	nodev,
132 	nodev,
133 	fcoet_ioctl,
134 	nodev,
135 	nodev,
136 	nodev,
137 	nochpoll,
138 	ddi_prop_op,
139 	0,
140 	D_MP | D_NEW
141 };
142 
143 static struct dev_ops fcoet_ops = {
144 	DEVO_REV,
145 	0,
146 	nodev,
147 	nulldev,
148 	nulldev,
149 	fcoet_attach,
150 	fcoet_detach,
151 	nodev,
152 	&fcoet_cb_ops,
153 	NULL,
154 	ddi_power,
155 	ddi_quiesce_not_needed
156 };
157 
158 static struct modldrv modldrv = {
159 	&mod_driverops,
160 	FCOET_MOD_NAME,
161 	&fcoet_ops,
162 };
163 
164 static struct modlinkage modlinkage = {
165 	MODREV_1, &modldrv, NULL
166 };
167 
168 /*
169  * Driver's global variables
170  */
171 static kmutex_t	 fcoet_mutex;
172 static void	*fcoet_state = NULL;
173 
174 int fcoet_use_ext_log = 1;
175 static char				 fcoet_provider_name[] = "fcoet";
176 static struct stmf_port_provider	*fcoet_pp	= NULL;
177 
178 /*
179  * Common loadable module entry points _init, _fini, _info
180  */
181 
182 int
183 _init(void)
184 {
185 	int ret;
186 
187 	ret = ddi_soft_state_init(&fcoet_state, sizeof (fcoet_soft_state_t), 0);
188 	if (ret == 0) {
189 		fcoet_pp = (stmf_port_provider_t *)
190 		    stmf_alloc(STMF_STRUCT_PORT_PROVIDER, 0, 0);
191 		fcoet_pp->pp_portif_rev = PORTIF_REV_1;
192 		fcoet_pp->pp_name = fcoet_provider_name;
193 		if (stmf_register_port_provider(fcoet_pp) != STMF_SUCCESS) {
194 			stmf_free(fcoet_pp);
195 			ddi_soft_state_fini(&fcoet_state);
196 			return (EIO);
197 		}
198 
199 		mutex_init(&fcoet_mutex, 0, MUTEX_DRIVER, 0);
200 		ret = mod_install(&modlinkage);
201 		if (ret) {
202 			(void) stmf_deregister_port_provider(fcoet_pp);
203 			stmf_free(fcoet_pp);
204 			mutex_destroy(&fcoet_mutex);
205 			ddi_soft_state_fini(&fcoet_state);
206 		}
207 	}
208 
209 	FCOET_LOG("_init", "exit _init with %x", ret);
210 	return (ret);
211 }
212 
213 int
214 _fini(void)
215 {
216 	int ret;
217 
218 	ret = mod_remove(&modlinkage);
219 	if (ret == 0) {
220 		(void) stmf_deregister_port_provider(fcoet_pp);
221 		stmf_free(fcoet_pp);
222 		mutex_destroy(&fcoet_mutex);
223 		ddi_soft_state_fini(&fcoet_state);
224 	}
225 
226 	FCOET_LOG("_fini", "exit _fini with %x", ret);
227 	return (ret);
228 }
229 
230 int
231 _info(struct modinfo *modinfop)
232 {
233 	return (mod_info(&modlinkage, modinfop));
234 }
235 
236 /*
237  * Autoconfiguration entry points: attach, detach, getinfo
238  */
239 
240 static int
241 fcoet_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
242 {
243 	int			 ret = DDI_FAILURE;
244 	int			 instance;
245 	fcoet_soft_state_t	*ss;
246 
247 	instance = ddi_get_instance(dip);
248 	FCOET_LOG("fcoet_attach", "get instance %d", instance);
249 
250 	switch (cmd) {
251 	case DDI_ATTACH:
252 		ret = ddi_soft_state_zalloc(fcoet_state, instance);
253 		if (ret != DDI_SUCCESS) {
254 			return (ret);
255 		}
256 
257 		ss = ddi_get_soft_state(fcoet_state, instance);
258 		ss->ss_instance = instance;
259 		ss->ss_dip = dip;
260 
261 		ret = fcoet_attach_init(ss);
262 		if (ret != FCOE_SUCCESS) {
263 			ddi_soft_state_free(fcoet_state, instance);
264 			ret = DDI_FAILURE;
265 		}
266 
267 		FCOET_LOG("fcoet_attach", "end with-%x", ret);
268 		break;
269 
270 	case DDI_RESUME:
271 		ret = DDI_SUCCESS;
272 		break;
273 
274 	default:
275 		FCOET_LOG("fcoet_attach", "unspported attach cmd-%x", cmd);
276 		break;
277 	}
278 
279 	return (ret);
280 }
281 
282 static int
283 fcoet_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
284 {
285 	int			 ret = DDI_FAILURE;
286 	int			 fcoe_ret;
287 	int			 instance;
288 	fcoet_soft_state_t	*ss;
289 
290 	instance = ddi_get_instance(dip);
291 	ss = ddi_get_soft_state(fcoet_state, instance);
292 	if (ss == NULL) {
293 		return (ret);
294 	}
295 
296 	switch (cmd) {
297 	case DDI_DETACH:
298 		fcoe_ret = fcoet_detach_uninit(ss);
299 		if (fcoe_ret == FCOE_SUCCESS) {
300 			ret = DDI_SUCCESS;
301 		}
302 
303 		FCOET_LOG("fcoet_detach", "fcoet_detach_uninit end with-%x",
304 		    fcoe_ret);
305 		break;
306 
307 	case DDI_SUSPEND:
308 		ret = DDI_SUCCESS;
309 		break;
310 
311 	default:
312 		FCOET_LOG("fcoet_detach", "unsupported detach cmd-%x", cmd);
313 		break;
314 	}
315 
316 	return (ret);
317 }
318 
319 /*
320  * Device access entry points
321  */
322 static int
323 fcoet_open(dev_t *devp, int flag, int otype, cred_t *credp)
324 {
325 	int			 instance;
326 	fcoet_soft_state_t	*ss;
327 
328 	if (otype != OTYP_CHR) {
329 		return (EINVAL);
330 	}
331 
332 	/*
333 	 * Since this is for debugging only, only allow root to issue ioctl now
334 	 */
335 	if (drv_priv(credp)) {
336 		return (EPERM);
337 	}
338 
339 	instance = (int)getminor(*devp);
340 	ss = ddi_get_soft_state(fcoet_state, instance);
341 	if (ss == NULL) {
342 		return (ENXIO);
343 	}
344 
345 	mutex_enter(&ss->ss_ioctl_mutex);
346 	if (ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_EXCL) {
347 		/*
348 		 * It is already open for exclusive access.
349 		 * So shut the door on this caller.
350 		 */
351 		mutex_exit(&ss->ss_ioctl_mutex);
352 		return (EBUSY);
353 	}
354 
355 	if (flag & FEXCL) {
356 		if (ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_OPEN) {
357 			/*
358 			 * Exclusive operation not possible
359 			 * as it is already opened
360 			 */
361 			mutex_exit(&ss->ss_ioctl_mutex);
362 			return (EBUSY);
363 		}
364 		ss->ss_ioctl_flags |= FCOET_IOCTL_FLAG_EXCL;
365 	}
366 	ss->ss_ioctl_flags |= FCOET_IOCTL_FLAG_OPEN;
367 	mutex_exit(&ss->ss_ioctl_mutex);
368 
369 	return (0);
370 }
371 
372 /* ARGSUSED */
373 static int
374 fcoet_close(dev_t dev, int flag, int otype, cred_t *credp)
375 {
376 	int			 instance;
377 	fcoet_soft_state_t	*ss;
378 
379 	if (otype != OTYP_CHR) {
380 		return (EINVAL);
381 	}
382 
383 	instance = (int)getminor(dev);
384 	ss = ddi_get_soft_state(fcoet_state, instance);
385 	if (ss == NULL) {
386 		return (ENXIO);
387 	}
388 
389 	mutex_enter(&ss->ss_ioctl_mutex);
390 	if ((ss->ss_ioctl_flags & FCOET_IOCTL_FLAG_OPEN) == 0) {
391 		mutex_exit(&ss->ss_ioctl_mutex);
392 		return (ENODEV);
393 	}
394 
395 	/*
396 	 * It looks there's one hole here, maybe there could several concurrent
397 	 * shareed open session, but we never check this case.
398 	 * But it will not hurt too much, disregard it now.
399 	 */
400 	ss->ss_ioctl_flags &= ~FCOET_IOCTL_FLAG_MASK;
401 	mutex_exit(&ss->ss_ioctl_mutex);
402 
403 	return (0);
404 }
405 
406 /* ARGSUSED */
407 static int
408 fcoet_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
409     cred_t *credp, int *rval)
410 {
411 	fcoet_soft_state_t	*ss;
412 	int		 ret = 0;
413 
414 	if (drv_priv(credp) != 0) {
415 		return (EPERM);
416 	}
417 
418 	ss = ddi_get_soft_state(fcoet_state, (int32_t)getminor(dev));
419 	if (ss == NULL) {
420 		return (ENXIO);
421 	}
422 
423 	switch (cmd) {
424 	default:
425 		FCOET_LOG("fcoet_ioctl", "ioctl-0x%02X", cmd);
426 		ret = ENOTTY;
427 		break;
428 	}
429 
430 	*rval = ret;
431 	return (ret);
432 }
433 
434 static fct_status_t
435 fcoet_attach_init(fcoet_soft_state_t *ss)
436 {
437 	fcoe_client_t		 client_fcoet;
438 	fcoe_port_t		*eport;
439 	fct_local_port_t	*port;
440 	fct_dbuf_store_t	*fds;
441 	char			 taskq_name[32];
442 	int			 ret;
443 
444 	/*
445 	 * FCoE (fcoe is fcoet's dependent driver)
446 	 * First we need register fcoet to FCoE as one client
447 	 */
448 	client_fcoet.ect_eport_flags = EPORT_FLAG_TGT_MODE |
449 	    EPORT_FLAG_IS_DIRECT_P2P;
450 	client_fcoet.ect_max_fc_frame_size = 2136;
451 	client_fcoet.ect_private_frame_struct_size = sizeof (fcoet_frame_t);
452 	client_fcoet.ect_rx_frame = fcoet_rx_frame;
453 	client_fcoet.ect_port_event = fcoet_port_event;
454 	client_fcoet.ect_release_sol_frame = fcoet_release_sol_frame;
455 	client_fcoet.ect_client_port_struct = ss;
456 	client_fcoet.ect_fcoe_ver = FCOE_VER_NOW;
457 	FCOET_LOG(__FUNCTION__, "version: %x %x", FCOE_VER_NOW, fcoe_ver_now);
458 	ret = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip,
459 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1);
460 	if (ret == -1) {
461 		FCOET_LOG("fcoet_attach_init", "get mac_id failed");
462 		return (DDI_FAILURE);
463 	} else {
464 		client_fcoet.ect_channelid = ret;
465 	}
466 	FCOET_LOG("fcoet_attach_init", "channel_id is %d",
467 	    client_fcoet.ect_channelid);
468 
469 	/*
470 	 * It's FCoE's responsiblity to initialize eport's all elements
471 	 */
472 	eport = fcoe_register_client(&client_fcoet);
473 	if (eport == NULL) {
474 		goto fail_register_client;
475 	}
476 
477 	/*
478 	 * Now it's time to register local port to FCT
479 	 */
480 	if (fcoet_dbuf_init(ss) != FCOE_SUCCESS) {
481 		goto fail_init_dbuf;
482 	}
483 
484 	fds = (fct_dbuf_store_t *)fct_alloc(FCT_STRUCT_DBUF_STORE, 0, 0);
485 	if (fds == NULL) {
486 		goto fail_alloc_dbuf;
487 	} else {
488 		fds->fds_alloc_data_buf = fcoet_dbuf_alloc;
489 		fds->fds_free_data_buf = fcoet_dbuf_free;
490 		fds->fds_fca_private = (void *)ss;
491 	}
492 
493 	port = (fct_local_port_t *)fct_alloc(FCT_STRUCT_LOCAL_PORT, 0, 0);
494 	if (port == NULL) {
495 		goto fail_alloc_port;
496 	} else {
497 		/*
498 		 * Do ss's initialization now
499 		 */
500 		(void) snprintf(ss->ss_alias, sizeof (ss->ss_alias), "fcoet%d",
501 		    ss->ss_instance);
502 		ret = ddi_create_minor_node(ss->ss_dip, "admin",
503 		    S_IFCHR, ss->ss_instance, DDI_NT_STMF_PP, 0);
504 		if (ret != DDI_SUCCESS) {
505 			goto fail_minor_node;
506 		}
507 
508 		ss->ss_state = FCT_STATE_OFFLINE;
509 		ss->ss_state_not_acked = 1;
510 		ss->ss_flags = 0;
511 		ss->ss_port = port;
512 		ss->ss_eport = eport;
513 		FCOE_SET_DEFAULT_FPORT_ADDR(eport->eport_efh_dst);
514 
515 		ss->ss_rportid_in_dereg = 0;
516 		ss->ss_rport_dereg_state = 0;
517 
518 		ss->ss_next_sol_oxid = 0xFFFF;
519 		ss->ss_next_unsol_rxid = 0xFFFF;
520 		ss->ss_sol_oxid_hash = mod_hash_create_idhash(
521 		    "ss_sol_oxid_hash", FCOET_SOL_HASH_SIZE,
522 		    mod_hash_null_valdtor);
523 		ss->ss_unsol_rxid_hash = mod_hash_create_idhash(
524 		    "ss_unsol_rxid_hash", FCOET_SOL_HASH_SIZE,
525 		    mod_hash_null_valdtor);
526 
527 		ss->ss_watch_count = 0;
528 		mutex_init(&ss->ss_watch_mutex, 0, MUTEX_DRIVER, 0);
529 		cv_init(&ss->ss_watch_cv, NULL, CV_DRIVER, NULL);
530 
531 		list_create(&ss->ss_abort_xchg_list, sizeof (fcoet_exchange_t),
532 		    offsetof(fcoet_exchange_t, xch_abort_node));
533 
534 		ss->ss_sol_flogi = NULL;
535 		ss->ss_sol_flogi_state = SFS_WAIT_LINKUP;
536 
537 		bzero(&ss->ss_link_info, sizeof (fct_link_info_t));
538 
539 		ss->ss_ioctl_flags = 0;
540 		mutex_init(&ss->ss_ioctl_mutex, 0, MUTEX_DRIVER, 0);
541 
542 		ss->ss_change_state_flags = 0;
543 	}
544 
545 	/*
546 	 * Do port's initialization
547 	 *
548 	 * port_fct_private and port_lport have been initialized by fct_alloc
549 	 */
550 	port->port_fca_private = ss;
551 	bcopy(ss->ss_eport->eport_nodewwn, port->port_nwwn, 8);
552 	bcopy(ss->ss_eport->eport_portwwn, port->port_pwwn, 8);
553 	port->port_default_alias = ss->ss_alias;
554 	port->port_sym_node_name = NULL;
555 	port->port_sym_port_name = NULL;
556 
557 	port->port_pp = fcoet_pp;
558 
559 	port->port_hard_address = 0;
560 	port->port_max_logins = FCOET_MAX_LOGINS;
561 	port->port_max_xchges = FCOET_MAX_XCHGES;
562 	port->port_fca_fcp_cmd_size = sizeof (fcoet_exchange_t);
563 	port->port_fca_rp_private_size = 0;
564 	port->port_fca_sol_els_private_size = sizeof (fcoet_exchange_t);
565 	port->port_fca_sol_ct_private_size = sizeof (fcoet_exchange_t);
566 
567 	port->port_fca_abort_timeout = 5 * 1000;	/* 5 seconds */
568 	port->port_fds = fds;
569 
570 	port->port_get_link_info = fcoet_get_link_info;
571 	port->port_register_remote_port = fcoet_register_remote_port;
572 	port->port_deregister_remote_port = fcoet_deregister_remote_port;
573 	port->port_send_cmd = fcoet_send_cmd;
574 	port->port_xfer_scsi_data = fcoet_xfer_scsi_data;
575 	port->port_send_cmd_response = fcoet_send_cmd_response;
576 	port->port_abort_cmd = fcoet_abort_cmd;
577 	port->port_ctl = fcoet_ctl;
578 	port->port_flogi_xchg = fcoet_do_flogi;
579 	port->port_populate_hba_details = fcoet_populate_hba_fru_details;
580 	if (fct_register_local_port(port) != FCT_SUCCESS) {
581 		goto fail_register_port;
582 	}
583 
584 	/*
585 	 * Start watchdog thread
586 	 */
587 	(void) snprintf(taskq_name, 32, "stmf_fct_fcoet_%d_taskq",
588 	    ss->ss_instance);
589 	taskq_name[31] = 0;
590 	if ((ss->ss_watchdog_taskq = ddi_taskq_create(NULL,
591 	    taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) {
592 		goto fail_create_taskq;
593 	}
594 
595 	atomic_and_32(&ss->ss_flags, ~SS_FLAG_TERMINATE_WATCHDOG);
596 	(void) ddi_taskq_dispatch(ss->ss_watchdog_taskq,
597 	    fcoet_watchdog, ss, DDI_SLEEP);
598 	while ((ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) == 0) {
599 		delay(10);
600 	}
601 
602 	ddi_report_dev(ss->ss_dip);
603 	return (DDI_SUCCESS);
604 
605 fail_create_taskq:
606 	if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
607 		atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG);
608 		cv_broadcast(&ss->ss_watch_cv);
609 		while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
610 			delay(10);
611 		}
612 	}
613 
614 	ddi_taskq_destroy(ss->ss_watchdog_taskq);
615 	FCOET_LOG("fcoet_attach_init", "fail_register_port");
616 
617 fail_register_port:
618 	mutex_destroy(&ss->ss_ioctl_mutex);
619 	mutex_destroy(&ss->ss_watch_mutex);
620 	cv_destroy(&ss->ss_watch_cv);
621 	mod_hash_destroy_hash(ss->ss_sol_oxid_hash);
622 	mod_hash_destroy_hash(ss->ss_unsol_rxid_hash);
623 	list_destroy(&ss->ss_abort_xchg_list);
624 	FCOET_LOG("fcoet_attach_init", "fail_create_taskq");
625 
626 fail_minor_node:
627 	fct_free(port);
628 	FCOET_LOG("fcoet_attach_init", "fail_minor_node");
629 
630 fail_alloc_port:
631 	fct_free(fds);
632 	FCOET_LOG("fcoet_attach_init", "fail_alloc_port");
633 
634 fail_alloc_dbuf:
635 	fcoet_dbuf_destroy(ss);
636 	FCOET_LOG("fcoet_attach_init", "fail_alloc_dbuf");
637 
638 fail_init_dbuf:
639 	ss->ss_eport->eport_deregister_client(ss->ss_eport);
640 	FCOET_LOG("fcoet_attach_init", "fail_init_dbuf");
641 
642 fail_register_client:
643 	FCOET_LOG("fcoet_attach_init", "fail_register_client");
644 	return (DDI_FAILURE);
645 }
646 
647 static fct_status_t
648 fcoet_detach_uninit(fcoet_soft_state_t *ss)
649 {
650 	if ((ss->ss_state != FCT_STATE_OFFLINE) ||
651 	    ss->ss_state_not_acked) {
652 		return (FCOE_FAILURE);
653 	}
654 
655 	/*
656 	 * Avoid modunload before running fcinfo remove-target-port
657 	 */
658 	if (ss->ss_eport != NULL &&
659 	    ss->ss_eport->eport_flags & EPORT_FLAG_MAC_IN_USE) {
660 		return (FCOE_FAILURE);
661 	}
662 
663 	if (ss->ss_port == NULL) {
664 		return (FCOE_SUCCESS);
665 	}
666 
667 	ss->ss_sol_oxid_hash_empty = 1;
668 	ss->ss_unsol_rxid_hash_empty = 1;
669 	mod_hash_walk(ss->ss_sol_oxid_hash, fcoet_sol_oxid_hash_empty, ss);
670 	mod_hash_walk(ss->ss_unsol_rxid_hash, fcoet_unsol_rxid_hash_empty, ss);
671 	if ((!ss->ss_sol_oxid_hash_empty) || (!ss->ss_unsol_rxid_hash_empty)) {
672 		return (FCOE_FAILURE);
673 	}
674 
675 	/*
676 	 * We need offline the port manually, before we want to detach it
677 	 * or it will not succeed.
678 	 */
679 	if (fct_deregister_local_port(ss->ss_port) != FCT_SUCCESS) {
680 		FCOET_LOG("fcoet_detach_uninit",
681 		    "fct_deregister_local_port failed");
682 		return (FCOE_FAILURE);
683 	}
684 
685 	/*
686 	 * Stop watchdog
687 	 */
688 	if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
689 		atomic_or_32(&ss->ss_flags, SS_FLAG_TERMINATE_WATCHDOG);
690 		cv_broadcast(&ss->ss_watch_cv);
691 		while (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
692 			delay(10);
693 		}
694 	}
695 
696 	ddi_taskq_destroy(ss->ss_watchdog_taskq);
697 
698 	/*
699 	 * Release all resources
700 	 */
701 	mutex_destroy(&ss->ss_ioctl_mutex);
702 	mutex_destroy(&ss->ss_watch_mutex);
703 	cv_destroy(&ss->ss_watch_cv);
704 	mod_hash_destroy_hash(ss->ss_sol_oxid_hash);
705 	mod_hash_destroy_hash(ss->ss_unsol_rxid_hash);
706 	list_destroy(&ss->ss_abort_xchg_list);
707 
708 	fct_free(ss->ss_port->port_fds);
709 	fct_free(ss->ss_port);
710 	ss->ss_port = NULL;
711 
712 	fcoet_dbuf_destroy(ss);
713 
714 	if (ss->ss_eport != NULL &&
715 	    ss->ss_eport->eport_deregister_client != NULL) {
716 		ss->ss_eport->eport_deregister_client(ss->ss_eport);
717 	}
718 	ddi_soft_state_free(fcoet_state, ss->ss_instance);
719 	return (FCOE_SUCCESS);
720 }
721 
722 static void
723 fcoet_watchdog(void *arg)
724 {
725 	fcoet_soft_state_t	*ss = (fcoet_soft_state_t *)arg;
726 	clock_t			 tmp_delay = 0;
727 	fcoet_exchange_t	*xchg, *xchg_next;
728 
729 	FCOET_LOG("fcoet_watchdog", "fcoet_soft_state is %p", ss);
730 
731 	mutex_enter(&ss->ss_watch_mutex);
732 	atomic_or_32(&ss->ss_flags, SS_FLAG_WATCHDOG_RUNNING);
733 	tmp_delay = STMF_SEC2TICK(1)/2;
734 
735 	while ((ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG) == 0) {
736 		ss->ss_watch_count++;
737 
738 		if (ss->ss_sol_flogi_state != SFS_FLOGI_DONE) {
739 			fcoet_handle_sol_flogi(ss);
740 		}
741 		for (xchg = list_head(&ss->ss_abort_xchg_list); xchg; ) {
742 			xchg_next = list_next(&ss->ss_abort_xchg_list, xchg);
743 			if (xchg->xch_ref == 0) {
744 				list_remove(&ss->ss_abort_xchg_list, xchg);
745 				mutex_exit(&ss->ss_watch_mutex);
746 				/* xchg abort done */
747 				if (xchg->xch_dbuf_num) {
748 					kmem_free((void*)xchg->xch_dbufs,
749 					    xchg->xch_dbuf_num *
750 					    sizeof (void *));
751 					xchg->xch_dbufs = NULL;
752 					xchg->xch_dbuf_num = 0;
753 				}
754 				fct_cmd_fca_aborted(xchg->xch_cmd,
755 				    FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE);
756 				mutex_enter(&ss->ss_watch_mutex);
757 			}
758 			xchg = xchg_next;
759 		}
760 
761 		atomic_or_32(&ss->ss_flags, SS_FLAG_DOG_WAITING);
762 		(void) cv_reltimedwait(&ss->ss_watch_cv, &ss->ss_watch_mutex,
763 		    (clock_t)tmp_delay, TR_CLOCK_TICK);
764 		atomic_and_32(&ss->ss_flags, ~SS_FLAG_DOG_WAITING);
765 	}
766 
767 	/*
768 	 * Ensure no ongoing FLOGI, before terminate the watchdog
769 	 */
770 	if (ss->ss_sol_flogi) {
771 		fcoet_clear_sol_exchange(ss->ss_sol_flogi);
772 		fct_free(ss->ss_sol_flogi->xch_cmd);
773 		ss->ss_sol_flogi = NULL;
774 	}
775 
776 	atomic_and_32(&ss->ss_flags, ~SS_FLAG_WATCHDOG_RUNNING);
777 	mutex_exit(&ss->ss_watch_mutex);
778 }
779 
780 static void
781 fcoet_handle_sol_flogi(fcoet_soft_state_t *ss)
782 {
783 	clock_t			twosec = STMF_SEC2TICK(2);
784 
785 check_state_again:
786 	if (ss->ss_flags & SS_FLAG_PORT_DISABLED) {
787 		ss->ss_sol_flogi_state = SFS_WAIT_LINKUP;
788 	}
789 
790 	switch (ss->ss_sol_flogi_state) {
791 	case SFS_WAIT_LINKUP:
792 		if (ss->ss_sol_flogi) {
793 			if (ss->ss_sol_flogi->xch_ref == 0) {
794 				fcoet_clear_sol_exchange(ss->ss_sol_flogi);
795 				fct_free(ss->ss_sol_flogi->xch_cmd);
796 				ss->ss_sol_flogi = NULL;
797 			}
798 		}
799 		break;
800 
801 	case SFS_FLOGI_INIT:
802 		if (ss->ss_sol_flogi) {
803 			/*
804 			 * wait for the response to finish
805 			 */
806 			ss->ss_sol_flogi_state = SFS_CLEAR_FLOGI;
807 			break;
808 		}
809 		fcoet_send_sol_flogi(ss);
810 		ss->ss_sol_flogi_state++;
811 		break;
812 
813 	case SFS_FLOGI_CHECK_TIMEOUT:
814 		if ((ss->ss_sol_flogi->xch_start_time + twosec) <
815 		    ddi_get_lbolt()) {
816 			ss->ss_sol_flogi_state++;
817 		}
818 		break;
819 
820 	case SFS_ABTS_INIT:
821 		fcoet_send_sol_abts(ss->ss_sol_flogi);
822 		ss->ss_sol_flogi_state++;
823 		break;
824 
825 	case SFS_CLEAR_FLOGI:
826 		if (ss->ss_sol_flogi) {
827 			if (ss->ss_sol_flogi->xch_ref) {
828 				break;
829 			}
830 			fcoet_clear_sol_exchange(ss->ss_sol_flogi);
831 			fct_free(ss->ss_sol_flogi->xch_cmd);
832 			ss->ss_sol_flogi = NULL;
833 		}
834 		ss->ss_sol_flogi_state = SFS_FLOGI_INIT;
835 		goto check_state_again;
836 
837 	case SFS_FLOGI_ACC:
838 		ss->ss_sol_flogi_state++;
839 		goto check_state_again;
840 
841 	case SFS_FLOGI_DONE:
842 		if (!(ss->ss_flags & SS_FLAG_PORT_DISABLED) &&
843 		    ss->ss_sol_flogi) {
844 			fcoet_clear_sol_exchange(ss->ss_sol_flogi);
845 			fct_free(ss->ss_sol_flogi->xch_cmd);
846 			ss->ss_sol_flogi = NULL;
847 		}
848 
849 		/*
850 		 * We'd better to offline it first, and delay 0.1 seconds,
851 		 * before we say it's on again.
852 		 */
853 		fct_handle_event(ss->ss_port,
854 		    FCT_EVENT_LINK_DOWN, 0, NULL);
855 		delay(STMF_SEC2TICK(1)/10);
856 		fct_handle_event(ss->ss_port,
857 		    FCT_EVENT_LINK_UP, 0, NULL);
858 		break;
859 
860 	default:
861 		ASSERT(0);
862 		break;
863 	}
864 }
865 
866 /* ARGSUSED */
867 static int
868 fcoet_dbuf_init(fcoet_soft_state_t *ss)
869 {
870 	return (FCOE_SUCCESS);
871 }
872 
873 /* ARGSUSED */
874 static void
875 fcoet_dbuf_destroy(fcoet_soft_state_t *ss)
876 {
877 
878 }
879 
880 /* ARGSUSED */
881 static stmf_data_buf_t *
882 fcoet_dbuf_alloc(fct_local_port_t *port, uint32_t size, uint32_t *pminsize,
883     uint32_t flags)
884 {
885 	stmf_data_buf_t	*dbuf;
886 	int		 add_size;
887 	int		 sge_num;
888 	int		 sge_size;
889 	int		 idx;
890 	int		 ii;
891 	void		*netb;
892 	uint8_t		*fc_buf;
893 	fcoet_soft_state_t	*ss =
894 	    (fcoet_soft_state_t *)port->port_fca_private;
895 
896 	if (size > FCOET_MAX_DBUF_LEN) {
897 		if (*pminsize > FCOET_MAX_DBUF_LEN) {
898 			return (NULL);
899 		}
900 
901 		size = FCOET_MAX_DBUF_LEN;
902 	}
903 
904 	sge_num = (size - 1) / ss->ss_fcp_data_payload_size + 1;
905 	add_size = (sge_num - 1) * sizeof (struct stmf_sglist_ent) +
906 	    sge_num * sizeof (mblk_t *);
907 	dbuf = stmf_alloc(STMF_STRUCT_DATA_BUF, add_size, 0);
908 	if (dbuf == NULL) {
909 		return (NULL);
910 	}
911 	dbuf->db_buf_size = size;
912 	dbuf->db_data_size = size;
913 	dbuf->db_sglist_length = 0;
914 	dbuf->db_flags |= DB_DONT_REUSE;
915 	FCOET_SET_SEG_NUM(dbuf, sge_num);
916 
917 	/*
918 	 * Initialize non-last sg entries
919 	 */
920 	for (idx = 0; idx < sge_num - 1; idx++) {
921 		sge_size = ss->ss_fcp_data_payload_size;
922 		netb = ss->ss_eport->eport_alloc_netb(
923 		    ss->ss_eport, sizeof (fcoe_fc_frame_header_t) +
924 		    sge_size, &fc_buf);
925 		if (netb == NULL) {
926 			for (ii = 0; ii < idx; ii++) {
927 				ss->ss_eport->eport_free_netb(
928 				    FCOET_GET_NETB(dbuf, ii));
929 			}
930 			stmf_free(dbuf);
931 			FCOET_LOG("fcoe_dbuf_alloc", "no netb");
932 			return (NULL);
933 		}
934 		FCOET_SET_NETB(dbuf, idx, netb);
935 		dbuf->db_sglist[idx].seg_addr = fc_buf +
936 		    sizeof (fcoe_fc_frame_header_t);
937 		dbuf->db_sglist[idx].seg_length = sge_size;
938 	}
939 
940 	/*
941 	 * Initialize the last sg entry
942 	 */
943 	if (size % ss->ss_fcp_data_payload_size) {
944 		sge_size = P2ROUNDUP(size % ss->ss_fcp_data_payload_size, 4);
945 	} else {
946 		sge_size = ss->ss_fcp_data_payload_size;
947 	}
948 
949 	netb = ss->ss_eport->eport_alloc_netb(
950 	    ss->ss_eport,
951 	    sizeof (fcoe_fc_frame_header_t) +
952 	    sge_size, &fc_buf);
953 	if (netb == NULL) {
954 		for (ii = 0; ii < idx; ii++) {
955 			ss->ss_eport->eport_free_netb(
956 			    FCOET_GET_NETB(dbuf, ii));
957 		}
958 		stmf_free(dbuf);
959 		FCOET_LOG("fcoe_dbuf_alloc", "no netb");
960 		return (NULL);
961 	}
962 
963 	FCOET_SET_NETB(dbuf, idx, netb);
964 	dbuf->db_sglist[idx].seg_addr = fc_buf +
965 	    sizeof (fcoe_fc_frame_header_t);
966 	dbuf->db_sglist[idx].seg_length = sge_size;
967 
968 	/*
969 	 * Let COMSTAR know how many sg entries we will use
970 	 */
971 	dbuf->db_sglist_length = idx + 1;
972 
973 	return (dbuf);
974 }
975 
976 static void
977 fcoet_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf)
978 {
979 	int	idx;
980 	fcoet_soft_state_t	*ss =
981 	    (fcoet_soft_state_t *)fds->fds_fca_private;
982 
983 	for (idx = 0; idx < FCOET_GET_SEG_NUM(dbuf); idx++) {
984 		if (FCOET_GET_NETB(dbuf, idx)) {
985 			ss->ss_eport->eport_free_netb(
986 			    FCOET_GET_NETB(dbuf, idx));
987 		}
988 	}
989 
990 	stmf_free(dbuf);
991 }
992 
993 /*
994  * We should have initialized fcoe_frame_t before
995  */
996 void
997 fcoet_init_tfm(fcoe_frame_t *frm, fcoet_exchange_t *xch)
998 {
999 	FRM2TFM(frm)->tfm_fcoe_frame = frm;
1000 	FRM2TFM(frm)->tfm_xch = xch;
1001 	FRM2TFM(frm)->tfm_seq = NULL;
1002 }
1003 
1004 /* ARGSUSED */
1005 static uint_t
1006 fcoet_sol_oxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1007 {
1008 	fcoet_soft_state_t	*ss = (fcoet_soft_state_t *)arg;
1009 
1010 	ss->ss_sol_oxid_hash_empty = 0;
1011 	FCOET_LOG("fcoet_sol_oxid_hash_empty", "one ongoing xch: %p", val);
1012 	return (MH_WALK_CONTINUE);
1013 }
1014 
1015 /* ARGSUSED */
1016 static uint_t
1017 fcoet_unsol_rxid_hash_empty(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1018 {
1019 	fcoet_soft_state_t	*ss = (fcoet_soft_state_t *)arg;
1020 
1021 	ss->ss_sol_oxid_hash_empty = 0;
1022 	FCOET_LOG("fcoet_unsol_rxid_hash_empty", "one ongoing xch: %p", val);
1023 	return (MH_WALK_CONTINUE);
1024 }
1025 
1026 /* ARGSUSED */
1027 void
1028 fcoet_modhash_find_cb(mod_hash_key_t key, mod_hash_val_t val)
1029 {
1030 	ASSERT(val != NULL);
1031 	fcoet_exchange_t *xch = (fcoet_exchange_t *)val;
1032 	FCOET_BUSY_XCHG(xch);
1033 }
1034