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 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/conf.h>
28 #include <sys/ddi.h>
29 #include <sys/stat.h>
30 #include <sys/pci.h>
31 #include <sys/sunddi.h>
32 #include <sys/modctl.h>
33 #include <sys/file.h>
34 #include <sys/cred.h>
35 #include <sys/byteorder.h>
36 #include <sys/atomic.h>
37 #include <sys/scsi/scsi.h>
38 #include <sys/mac_client.h>
39 #include <sys/modhash.h>
40 
41 /*
42  * leadville header files
43  */
44 #include <sys/fibre-channel/fc.h>
45 #include <sys/fibre-channel/impl/fc_fcaif.h>
46 
47 /*
48  * fcoe header files
49  */
50 #include <sys/fcoe/fcoe_common.h>
51 
52 /*
53  * fcoei header files
54  */
55 #include <fcoei.h>
56 
57 /*
58  * forward declaration of stack functions
59  */
60 static uint32_t fcoei_xch_check(
61 	mod_hash_key_t key, mod_hash_val_t *val, void *arg);
62 static int fcoei_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
63 static int fcoei_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
64 static int fcoei_open(dev_t *devp, int flag, int otype, cred_t *credp);
65 static int fcoei_close(dev_t dev, int flag, int otype, cred_t *credp);
66 static int fcoei_ioctl(
67 	dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp, int *rval);
68 static int fcoei_attach_init(fcoei_soft_state_t *ss);
69 static int fcoei_detach_uninit(fcoei_soft_state_t *ss);
70 static void fcoei_watchdog(void *arg);
71 static void fcoei_process_events(fcoei_soft_state_t *ss);
72 static void fcoei_trigger_fp_attach(void *arg);
73 static void fcoei_abts_exchange(fcoei_exchange_t *xch);
74 static void fcoei_clear_watchdog_jobs(fcoei_soft_state_t *ss);
75 
76 /*
77  * Driver identificaton stuff
78  */
79 static struct cb_ops fcoei_cb_ops = {
80 	fcoei_open,
81 	fcoei_close,
82 	nodev,
83 	nodev,
84 	nodev,
85 	nodev,
86 	nodev,
87 	fcoei_ioctl,
88 	nodev,
89 	nodev,
90 	nodev,
91 	nochpoll,
92 	ddi_prop_op,
93 	0,
94 	D_MP | D_NEW | D_HOTPLUG,
95 	CB_REV,
96 	nodev,
97 	nodev
98 };
99 
100 static struct dev_ops fcoei_ops = {
101 	DEVO_REV,
102 	0,
103 	nodev,
104 	nulldev,
105 	nulldev,
106 	fcoei_attach,
107 	fcoei_detach,
108 	nodev,
109 	&fcoei_cb_ops,
110 	NULL,
111 	ddi_power,
112 	ddi_quiesce_not_needed
113 };
114 
115 static struct modldrv modldrv = {
116 	&mod_driverops,
117 	FCOEI_NAME_VERSION,
118 	&fcoei_ops,
119 };
120 
121 static struct modlinkage modlinkage = {
122 	MODREV_1,
123 	&modldrv,
124 	NULL
125 };
126 
127 /*
128  * Driver's global variables
129  */
130 void	*fcoei_state	   = NULL;
131 int	 fcoei_use_ext_log = 0;
132 
133 /*
134  * Common loadable module entry points _init, _fini, _info
135  */
136 int
137 _init(void)
138 {
139 	int ret;
140 
141 	ret = ddi_soft_state_init(&fcoei_state, sizeof (fcoei_soft_state_t), 0);
142 	if (ret != DDI_SUCCESS) {
143 		FCOEI_LOG(__FUNCTION__, "soft state init failed: %x", ret);
144 		return (ret);
145 	}
146 
147 	ret = mod_install(&modlinkage);
148 	if (ret != 0) {
149 		ddi_soft_state_fini(&fcoei_state);
150 		FCOEI_LOG(__FUNCTION__, "fcoei mod_install failed: %x", ret);
151 		return (ret);
152 	}
153 
154 	/*
155 	 * Let FCTL initialize devo_bus_ops
156 	 */
157 	fc_fca_init(&fcoei_ops);
158 
159 	FCOEI_LOG(__FUNCTION__, "fcoei _init succeeded");
160 	return (ret);
161 }
162 
163 int
164 _fini(void)
165 {
166 	int ret;
167 
168 	ret = mod_remove(&modlinkage);
169 	if (ret != 0) {
170 		FCOEI_EXT_LOG(__FUNCTION__, "fcoei mod_remove failed: %x", ret);
171 		return (ret);
172 	}
173 
174 	ddi_soft_state_fini(&fcoei_state);
175 	FCOEI_LOG(__FUNCTION__, "fcoei _fini succeeded");
176 	return (ret);
177 }
178 
179 int
180 _info(struct modinfo *modinfop)
181 {
182 	return (mod_info(&modlinkage, modinfop));
183 }
184 
185 /*
186  * Autoconfiguration entry points: attach, detach, getinfo
187  */
188 
189 static int
190 fcoei_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
191 {
192 	int			 ret;
193 	int			 fcoe_ret;
194 	int			 instance;
195 	fcoei_soft_state_t	*ss;
196 
197 	instance = ddi_get_instance(dip);
198 	FCOEI_LOG(__FUNCTION__, "instance is %d", instance);
199 	switch (cmd) {
200 	case DDI_ATTACH:
201 		ret = ddi_soft_state_zalloc(fcoei_state, instance);
202 		if (ret != DDI_SUCCESS) {
203 			FCOEI_LOG(__FUNCTION__, "ss zalloc failed: %x", ret);
204 			return (ret);
205 		}
206 
207 		/*
208 		 * Get the soft state, and do basic initialization with dip
209 		 */
210 		ss = ddi_get_soft_state(fcoei_state, instance);
211 		ss->ss_dip = dip;
212 
213 		fcoe_ret = fcoei_attach_init(ss);
214 		if (fcoe_ret != FCOE_SUCCESS) {
215 			ddi_soft_state_free(fcoei_state, instance);
216 			FCOEI_LOG(__FUNCTION__, "fcoei_attach_init failed: "
217 			    "%x", fcoe_ret);
218 			return (DDI_FAILURE);
219 		}
220 
221 		ss->ss_flags |= SS_FLAG_TRIGGER_FP_ATTACH;
222 		(void) timeout(fcoei_trigger_fp_attach, ss, FCOE_SEC2TICK(1));
223 		FCOEI_LOG(__FUNCTION__, "fcoei_attach succeeded: dip-%p, "
224 		    "cmd-%x", dip, cmd);
225 		return (DDI_SUCCESS);
226 
227 	case DDI_RESUME:
228 		return (DDI_SUCCESS);
229 
230 	default:
231 		FCOEI_LOG(__FUNCTION__, "unsupported attach cmd-%X", cmd);
232 		return (DDI_FAILURE);
233 	}
234 }
235 
236 static int
237 fcoei_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
238 {
239 	int			 fcoe_ret;
240 	int			 instance;
241 	fcoei_soft_state_t	*ss;
242 
243 	instance = ddi_get_instance(dip);
244 	ss = ddi_get_soft_state(fcoei_state, instance);
245 	if (ss == NULL) {
246 		FCOEI_LOG(__FUNCTION__, "get ss failed: dip-%p", dip);
247 		return (DDI_FAILURE);
248 	}
249 
250 	switch (cmd) {
251 	case DDI_DETACH:
252 		if (ss->ss_flags & SS_FLAG_TRIGGER_FP_ATTACH) {
253 			FCOEI_LOG(__FUNCTION__, "still await fp attach");
254 			return (DDI_FAILURE);
255 		}
256 
257 		if (ss->ss_flags & SS_FLAG_LV_BOUND) {
258 			FCOEI_LOG(__FUNCTION__, "fp is not detached yet");
259 			return (DDI_FAILURE);
260 		}
261 
262 		fcoe_ret = fcoei_detach_uninit(ss);
263 		if (fcoe_ret != FCOE_SUCCESS) {
264 			FCOEI_LOG(__FUNCTION__, "fcoei_detach_uninit failed:"
265 			    " dip-%p, fcoe_ret-%d", dip, fcoe_ret);
266 			return (DDI_FAILURE);
267 		}
268 
269 		FCOEI_LOG(__FUNCTION__, "succeeded: dip-%p, cmd-%x", dip, cmd);
270 		return (DDI_SUCCESS);
271 
272 	case DDI_SUSPEND:
273 		return (DDI_SUCCESS);
274 
275 	default:
276 		FCOEI_LOG(__FUNCTION__, "unspported detach cmd-%X", cmd);
277 		return (DDI_FAILURE);
278 	}
279 }
280 
281 /*
282  * Device access entry points: open, close, ioctl
283  */
284 
285 static int
286 fcoei_open(dev_t *devp, int flag, int otype, cred_t *credp)
287 {
288 	fcoei_soft_state_t	*ss;
289 
290 	if (otype != OTYP_CHR) {
291 		FCOEI_LOG(__FUNCTION__, "flag: %x", flag);
292 		return (EINVAL);
293 	}
294 
295 	if (drv_priv(credp)) {
296 		return (EPERM);
297 	}
298 
299 	/*
300 	 * First of all, get related soft state
301 	 */
302 	ss = ddi_get_soft_state(fcoei_state, (int)getminor(*devp));
303 	if (ss == NULL) {
304 		return (ENXIO);
305 	}
306 
307 	mutex_enter(&ss->ss_ioctl_mutex);
308 	if (ss->ss_ioctl_flags & FCOEI_IOCTL_FLAG_OPEN) {
309 		/*
310 		 * We don't support concurrent open
311 		 */
312 		mutex_exit(&ss->ss_ioctl_mutex);
313 		return (EBUSY);
314 	}
315 
316 	ss->ss_ioctl_flags |= FCOEI_IOCTL_FLAG_OPEN;
317 	mutex_exit(&ss->ss_ioctl_mutex);
318 
319 	return (0);
320 }
321 
322 static int
323 fcoei_close(dev_t dev, int flag, int otype, cred_t *credp)
324 {
325 	fcoei_soft_state_t	*ss;
326 
327 	if (otype != OTYP_CHR) {
328 		FCOEI_LOG(__FUNCTION__, "flag: %x, %p", flag, credp);
329 		return (EINVAL);
330 	}
331 
332 	/*
333 	 * First of all, get related soft state
334 	 */
335 	ss = ddi_get_soft_state(fcoei_state, (int)getminor(dev));
336 	if (ss == NULL) {
337 		return (ENXIO);
338 	}
339 
340 	mutex_enter(&ss->ss_ioctl_mutex);
341 	if (!(ss->ss_ioctl_flags & FCOEI_IOCTL_FLAG_OPEN)) {
342 		/*
343 		 * If it's not open, we can exit
344 		 */
345 
346 		mutex_exit(&ss->ss_ioctl_mutex);
347 		return (ENODEV);
348 	}
349 
350 	ss->ss_ioctl_flags &= ~FCOEI_IOCTL_FLAG_OPEN;
351 	mutex_exit(&ss->ss_ioctl_mutex);
352 
353 	return (0);
354 }
355 
356 static int
357 fcoei_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
358     cred_t *credp, int *rval)
359 {
360 	fcoei_soft_state_t	*ss;
361 	int			 ret = 0;
362 
363 	if (drv_priv(credp) != 0) {
364 		FCOEI_LOG(__FUNCTION__, "data: %p, %x", data, mode);
365 		return (EPERM);
366 	}
367 
368 	/*
369 	 * Get related soft state
370 	 */
371 	ss = ddi_get_soft_state(fcoei_state, (int32_t)getminor(dev));
372 	if (!ss) {
373 		return (ENXIO);
374 	}
375 
376 	/*
377 	 * Process ioctl
378 	 */
379 	switch (cmd) {
380 
381 	default:
382 		FCOEI_LOG(__FUNCTION__, "ioctl-0x%02X", cmd);
383 		ret = ENOTTY;
384 	}
385 
386 	/*
387 	 * Set return value
388 	 */
389 	*rval = ret;
390 	return (ret);
391 }
392 
393 /*
394  * fcoei_attach_init
395  *	init related stuff of the soft state
396  *
397  * Input:
398  *	ss = the soft state that will be processed
399  *
400  * Return:
401  *	if it succeeded or not
402  *
403  * Comment:
404  *	N/A
405  */
406 static int
407 fcoei_attach_init(fcoei_soft_state_t *ss)
408 {
409 	fcoe_port_t		*eport;
410 	fcoe_client_t		 client_fcoei;
411 	char			 taskq_name[32];
412 	int			 ret;
413 	la_els_logi_t		*els = &ss->ss_els_logi;
414 	svc_param_t		*class3_param;
415 
416 	/*
417 	 * Register fcoei to FCOE as its client
418 	 */
419 	client_fcoei.ect_eport_flags = EPORT_FLAG_INI_MODE |
420 	    EPORT_FLAG_IS_DIRECT_P2P;
421 	client_fcoei.ect_max_fc_frame_size = FCOE_MAX_FC_FRAME_SIZE;
422 	client_fcoei.ect_private_frame_struct_size = sizeof (fcoei_frame_t);
423 	fcoei_init_ect_vectors(&client_fcoei);
424 	client_fcoei.ect_client_port_struct = ss;
425 	client_fcoei.ect_fcoe_ver = FCOE_VER_NOW;
426 	FCOEI_LOG(__FUNCTION__, "version: %x %x", FCOE_VER_NOW, fcoe_ver_now);
427 	ret = ddi_prop_get_int(DDI_DEV_T_ANY, ss->ss_dip,
428 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "mac_id", -1);
429 	if (ret == -1) {
430 		FCOEI_LOG(__FUNCTION__, "get mac_id failed");
431 		return (DDI_FAILURE);
432 	} else {
433 		client_fcoei.ect_channelid = ret;
434 	}
435 
436 	/*
437 	 * It's fcoe's responsiblity to initialize eport's all elements,
438 	 * so we needn't do eport initialization
439 	 */
440 	eport = fcoe_register_client(&client_fcoei);
441 	if (eport == NULL) {
442 		goto fail_register_client;
443 	} else {
444 		ss->ss_eport = eport;
445 		FCOE_SET_DEFAULT_FPORT_ADDR(eport->eport_efh_dst);
446 	}
447 
448 	/*
449 	 * Now it's time to register fca_tran to FCTL
450 	 * Remember fc_local_port is transparent to FCA (fcoei)
451 	 */
452 	ss->ss_fca_tran.fca_version  = FCTL_FCA_MODREV_5;
453 	ss->ss_fca_tran.fca_numports = 1;
454 	ss->ss_fca_tran.fca_pkt_size = sizeof (fcoei_exchange_t);
455 	ss->ss_fca_tran.fca_cmd_max  = 2048;
456 
457 	/*
458 	 * scsi_tran_hba_setup could need these stuff
459 	 */
460 	ss->ss_fca_tran.fca_dma_lim  = NULL;
461 	ss->ss_fca_tran.fca_iblock   = NULL;
462 	ss->ss_fca_tran.fca_dma_attr = NULL;
463 	ss->ss_fca_tran.fca_acc_attr = NULL;
464 
465 	/*
466 	 * Initialize vectors
467 	 */
468 	fcoei_init_fcatran_vectors(&ss->ss_fca_tran);
469 
470 	/*
471 	 * fc_fca_attach only sets driver's private, it has nothing to with
472 	 * common port object between fcoei and leadville.
473 	 * After this attach, fp_attach will be triggered, and it will call
474 	 * fca_bind_port to let fcoei to know about common port object.
475 	 */
476 	if (fc_fca_attach(ss->ss_dip, &ss->ss_fca_tran) != DDI_SUCCESS) {
477 		goto fail_fca_attach;
478 	}
479 
480 	/*
481 	 * It's time to do ss initialization
482 	 */
483 	ret = ddi_create_minor_node(ss->ss_dip, "admin",
484 	    S_IFCHR, ddi_get_instance(ss->ss_dip), DDI_NT_NEXUS, 0);
485 	if (ret != DDI_SUCCESS) {
486 		goto fail_minor_node;
487 	}
488 
489 	ss->ss_flags	   = 0;
490 	ss->ss_port	   = NULL;
491 	/*
492 	 * ss->ss_eport has been initialized
493 	 */
494 
495 	ss->ss_sol_oxid_hash = mod_hash_create_idhash(
496 	    "fcoei_sol_oxid_hash", FCOEI_SOL_HASH_SIZE,
497 	    mod_hash_null_valdtor);
498 	ss->ss_unsol_rxid_hash = mod_hash_create_idhash(
499 	    "fcoei_unsol_rxid_hash", FCOEI_UNSOL_HASH_SIZE,
500 	    mod_hash_null_valdtor);
501 	list_create(&ss->ss_comp_xch_list, sizeof (fcoei_exchange_t),
502 	    offsetof(fcoei_exchange_t, xch_comp_node));
503 	ss->ss_next_sol_oxid   = 0xFFFF;
504 	ss->ss_next_unsol_rxid = 0xFFFF;
505 
506 	mutex_init(&ss->ss_watchdog_mutex, 0, MUTEX_DRIVER, 0);
507 	cv_init(&ss->ss_watchdog_cv, NULL, CV_DRIVER, NULL);
508 	(void) snprintf(taskq_name, 32, "leadville_fcoei_%d_taskq",
509 	    ddi_get_instance(ss->ss_dip));
510 	taskq_name[31] = 0;
511 	ss->ss_taskq = ddi_taskq_create(ss->ss_dip,
512 	    taskq_name, 64, TASKQ_DEFAULTPRI, DDI_SLEEP);
513 
514 	ss->ss_link_state	  = FC_STATE_OFFLINE;
515 	ss->ss_link_speed	  = 0;
516 	ss->ss_port_event_counter = 0;
517 
518 	list_create(&ss->ss_event_list, sizeof (fcoei_event_t),
519 	    offsetof(fcoei_event_t, ae_node));
520 
521 	ss->ss_sol_cnt1   = 0;
522 	ss->ss_sol_cnt2   = 0;
523 	ss->ss_sol_cnt	   = &ss->ss_sol_cnt1;
524 	ss->ss_unsol_cnt1 = 0;
525 	ss->ss_unsol_cnt2 = 0;
526 	ss->ss_unsol_cnt  = &ss->ss_unsol_cnt1;
527 	ss->ss_ioctl_flags = 0;
528 
529 	mutex_init(&ss->ss_ioctl_mutex, 0, MUTEX_DRIVER, 0);
530 
531 	bcopy(eport->eport_portwwn, els->nport_ww_name.raw_wwn, 8);
532 	bcopy(eport->eport_nodewwn, els->node_ww_name.raw_wwn, 8);
533 	els->common_service.fcph_version = 0x2008;
534 	els->common_service.btob_credit = 3;
535 	els->common_service.cmn_features = 0x8800;
536 	els->common_service.conc_sequences = 0xff;
537 	els->common_service.relative_offset = 3;
538 	els->common_service.e_d_tov = 0x07d0;
539 	class3_param = (svc_param_t *)&els->class_3;
540 	class3_param->class_opt = 0x8800;
541 	class3_param->rcv_size = els->common_service.rx_bufsize = 2048;
542 	class3_param->conc_sequences = 0xff;
543 	class3_param->open_seq_per_xchng = 1;
544 
545 	/*
546 	 * Fill out RNID Management Information
547 	 */
548 	bcopy(ss->ss_eport->eport_portwwn, ss->ss_rnid.global_id, 8);
549 	ss->ss_rnid.unit_type  = FCOEI_RNID_HBA;
550 	ss->ss_rnid.ip_version = FCOEI_RNID_IPV4;
551 
552 	/*
553 	 * Start our watchdog
554 	 */
555 	(void) ddi_taskq_dispatch(ss->ss_taskq,
556 	    fcoei_watchdog, ss, DDI_SLEEP);
557 	while (!(ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING)) {
558 		delay(50);
559 	}
560 
561 	/*
562 	 * Report the device to the system
563 	 */
564 	ddi_report_dev(ss->ss_dip);
565 	return (DDI_SUCCESS);
566 
567 
568 fail_minor_node:
569 	FCOEI_LOG(__FUNCTION__, "fail_minor_node");
570 	fc_fca_detach(ss->ss_dip);
571 
572 fail_fca_attach:
573 	eport->eport_deregister_client(eport);
574 	FCOEI_LOG(__FUNCTION__, "fail_fca_attach");
575 
576 fail_register_client:
577 	FCOEI_LOG(__FUNCTION__, "fail_register_client");
578 	return (DDI_FAILURE);
579 }
580 
581 /*
582  * fcoei_detach_uninit
583  *	uninit related stuff of the soft state
584  *
585  * Input:
586  *	ss = the soft state that will be processed
587  *
588  * Return:
589  *	if it succeeded or not
590  *
591  * Comment:
592  *	N/A
593  */
594 int
595 fcoei_detach_uninit(fcoei_soft_state_t *ss)
596 {
597 	/*
598 	 * Stop watchdog first
599 	 */
600 	if (ss->ss_flags & SS_FLAG_WATCHDOG_RUNNING) {
601 		ss->ss_flags |= SS_FLAG_TERMINATE_WATCHDOG;
602 		cv_broadcast(&ss->ss_watchdog_cv);
603 	}
604 
605 	/*
606 	 * Destroy the taskq
607 	 */
608 	ddi_taskq_wait(ss->ss_taskq);
609 	ddi_taskq_destroy(ss->ss_taskq);
610 
611 	/*
612 	 * Release all allocated resources
613 	 */
614 	mutex_destroy(&ss->ss_ioctl_mutex);
615 	mutex_destroy(&ss->ss_watchdog_mutex);
616 	cv_destroy(&ss->ss_watchdog_cv);
617 	mod_hash_destroy_idhash(ss->ss_sol_oxid_hash);
618 	mod_hash_destroy_idhash(ss->ss_unsol_rxid_hash);
619 	list_destroy(&ss->ss_event_list);
620 	ss->ss_eport->eport_deregister_client(ss->ss_eport);
621 	ddi_remove_minor_node(ss->ss_dip, NULL);
622 
623 	/*
624 	 * Release itself
625 	 */
626 	ddi_soft_state_free(fcoei_state, ddi_get_instance(ss->ss_dip));
627 	return (FCOE_SUCCESS);
628 }
629 
630 /*
631  * fcoei_watchdog
632  *	Perform periodic checking and routine tasks
633  *
634  * Input:
635  *	arg = the soft state that will be processed
636  *
637  * Return:
638  *	N/A
639  *
640  * Comment:
641  *	N/A
642  */
643 static void
644 fcoei_watchdog(void *arg)
645 {
646 	fcoei_soft_state_t	*ss;
647 	clock_t			 tmp_delay;
648 	clock_t			 start_clock;
649 	clock_t			 last_clock;
650 
651 	/*
652 	 * For debugging
653 	 */
654 	ss = (fcoei_soft_state_t *)arg;
655 	FCOEI_LOG(__FUNCTION__, "ss %p", ss);
656 	FCOEI_LOG(__FUNCTION__, "sol_hash %p", ss->ss_sol_oxid_hash);
657 	FCOEI_LOG(__FUNCTION__, "unsol_hash %p", ss->ss_unsol_rxid_hash);
658 	ss->ss_flags |= SS_FLAG_WATCHDOG_RUNNING;
659 	tmp_delay = FCOE_SEC2TICK(1) / 2;
660 	last_clock = CURRENT_CLOCK;
661 
662 	/*
663 	 * If nobody reqeusts to terminate the watchdog, we will work forever
664 	 */
665 	while (!(ss->ss_flags & SS_FLAG_TERMINATE_WATCHDOG)) {
666 		/*
667 		 * We handle all asynchronous events serially
668 		 */
669 		fcoei_process_events(ss);
670 
671 		/*
672 		 * To avoid to check timing too freqently, we check
673 		 * if we need skip timing stuff.
674 		 */
675 		start_clock = CURRENT_CLOCK;
676 		if ((start_clock - last_clock) < tmp_delay) {
677 			goto end_timing;
678 		} else {
679 			last_clock = start_clock;
680 		}
681 
682 		/*
683 		 * It's time to do timeout checking of solicited exchanges
684 		 */
685 		if (ss->ss_sol_cnt == (&ss->ss_sol_cnt1)) {
686 			if (ss->ss_sol_cnt2 == 0) {
687 				ss->ss_sol_cnt = &ss->ss_sol_cnt2;
688 			} else {
689 				mod_hash_walk(ss->ss_sol_oxid_hash,
690 				    fcoei_xch_check, ss);
691 			}
692 		} else {
693 			if (ss->ss_sol_cnt1 == 0) {
694 				ss->ss_sol_cnt = &ss->ss_sol_cnt1;
695 			} else {
696 				mod_hash_walk(ss->ss_sol_oxid_hash,
697 				    fcoei_xch_check, ss);
698 			}
699 		}
700 
701 		/*
702 		 * It's time to do timeout checking of unsolicited exchange
703 		 */
704 		if (ss->ss_unsol_cnt == (&ss->ss_unsol_cnt1)) {
705 			if (ss->ss_unsol_cnt2 == 0) {
706 				ss->ss_unsol_cnt = &ss->ss_unsol_cnt2;
707 			} else {
708 				mod_hash_walk(ss->ss_unsol_rxid_hash,
709 				    fcoei_xch_check, ss);
710 			}
711 		} else {
712 			if (ss->ss_unsol_cnt1 == 0) {
713 				ss->ss_unsol_cnt = &ss->ss_unsol_cnt1;
714 			} else {
715 				mod_hash_walk(ss->ss_unsol_rxid_hash,
716 				    fcoei_xch_check, ss);
717 			}
718 		}
719 
720 		/*
721 		 * Check if there are exchanges which are ready to complete
722 		 */
723 		fcoei_handle_comp_xch_list(ss);
724 
725 	end_timing:
726 		/*
727 		 * Wait for next cycle
728 		 */
729 		mutex_enter(&ss->ss_watchdog_mutex);
730 		ss->ss_flags |= SS_FLAG_WATCHDOG_IDLE;
731 		if (!list_is_empty(&ss->ss_event_list)) {
732 			goto skip_wait;
733 		}
734 
735 		(void) cv_timedwait(&ss->ss_watchdog_cv,
736 		    &ss->ss_watchdog_mutex, CURRENT_CLOCK +
737 		    (clock_t)tmp_delay);
738 	skip_wait:
739 		ss->ss_flags &= ~SS_FLAG_WATCHDOG_IDLE;
740 		mutex_exit(&ss->ss_watchdog_mutex);
741 	}
742 
743 	/*
744 	 * Do clear work before exit
745 	 */
746 	fcoei_clear_watchdog_jobs(ss);
747 
748 	/*
749 	 * Watchdog has stopped
750 	 */
751 	ss->ss_flags &= ~SS_FLAG_WATCHDOG_RUNNING;
752 }
753 
754 static void
755 fcoei_clear_watchdog_jobs(fcoei_soft_state_t *ss)
756 {
757 	fcoei_event_t 		*ae;
758 	fcoe_frame_t		*frm;
759 
760 	mutex_enter(&ss->ss_watchdog_mutex);
761 	while (!list_is_empty(&ss->ss_event_list)) {
762 		ae = (fcoei_event_t *)list_head(&ss->ss_event_list);
763 		list_remove(&ss->ss_event_list, ae);
764 		switch (ae->ae_type) {
765 		case AE_EVENT_SOL_FRAME:
766 			frm = (fcoe_frame_t *)ae->ae_obj;
767 			frm->frm_eport->eport_release_frame(frm);
768 			break;
769 
770 		case AE_EVENT_UNSOL_FRAME:
771 			frm = (fcoe_frame_t *)ae->ae_obj;
772 			frm->frm_eport->eport_free_netb(frm->frm_netb);
773 			frm->frm_eport->eport_release_frame(frm);
774 			break;
775 
776 		case AE_EVENT_PORT:
777 			atomic_add_32(&ss->ss_port_event_counter, -1);
778 			/* FALLTHROUGH */
779 
780 		case AE_EVENT_RESET:
781 			kmem_free(ae, sizeof (fcoei_event_t));
782 			break;
783 
784 		case AE_EVENT_EXCHANGE:
785 			/* FALLTHROUGH */
786 
787 		default:
788 			break;
789 		}
790 	}
791 
792 	mod_hash_clear(ss->ss_unsol_rxid_hash);
793 	mod_hash_clear(ss->ss_sol_oxid_hash);
794 
795 	while (!list_is_empty(&ss->ss_comp_xch_list)) {
796 		list_remove_head(&ss->ss_comp_xch_list);
797 	}
798 	mutex_exit(&ss->ss_watchdog_mutex);
799 }
800 
801 /*
802  * fcoei_process_events
803  *	Process the events one by one
804  *
805  * Input:
806  *	ss = the soft state that will be processed
807  *
808  * Return:
809  *	N/A
810  *
811  * Comment:
812  *	N/A
813  */
814 static void
815 fcoei_process_events(fcoei_soft_state_t *ss)
816 {
817 	fcoei_event_t	*ae = NULL;
818 
819 	/*
820 	 * It's the only place to delete node from ss_event_list, so we needn't
821 	 * hold mutex to check if the list is empty.
822 	 */
823 	ASSERT(!MUTEX_HELD(&ss->ss_watchdog_mutex));
824 	while (list_is_empty(&ss->ss_event_list) == B_FALSE) {
825 		mutex_enter(&ss->ss_watchdog_mutex);
826 		ae = (fcoei_event_t *)list_remove_head(&ss->ss_event_list);
827 		mutex_exit(&ss->ss_watchdog_mutex);
828 
829 		switch (ae->ae_type) {
830 		case AE_EVENT_SOL_FRAME:
831 			fcoei_handle_sol_frame_done((fcoe_frame_t *)ae->ae_obj);
832 			break;
833 
834 		case AE_EVENT_UNSOL_FRAME:
835 			fcoei_process_unsol_frame((fcoe_frame_t *)ae->ae_obj);
836 			break;
837 
838 		case AE_EVENT_EXCHANGE:
839 			fcoei_process_event_exchange(ae);
840 			break;
841 
842 		case AE_EVENT_PORT:
843 			fcoei_process_event_port(ae);
844 			break;
845 
846 		case AE_EVENT_RESET:
847 			fcoei_process_event_reset(ae);
848 			break;
849 
850 		default:
851 			FCOEI_LOG(__FUNCTION__, "unsupported events");
852 		}
853 
854 	}
855 }
856 
857 /*
858  * fcoei_handle_tmout_xch_list
859  *	Complete every exchange in the timed-out xch list of the soft state
860  *
861  * Input:
862  *	ss = the soft state that need be handled
863  *
864  * Return:
865  *	N/A
866  *
867  * Comment:
868  *	When mod_hash_walk is in progress, we can't change the hashtable.
869  *	This is post-walk handling of exchange timing
870  */
871 void
872 fcoei_handle_comp_xch_list(fcoei_soft_state_t *ss)
873 {
874 	fcoei_exchange_t	*xch	  = NULL;
875 
876 	while ((xch = list_remove_head(&ss->ss_comp_xch_list)) != NULL) {
877 		fcoei_complete_xch(xch, NULL, xch->xch_fpkt->pkt_state,
878 		    xch->xch_fpkt->pkt_reason);
879 	}
880 }
881 
882 /*
883  * fcoei_xch_check
884  *	Check if the exchange timed out or link is down
885  *
886  * Input:
887  *	key = rxid of the unsolicited exchange
888  *	val = the unsolicited exchange
889  *	arg = the soft state
890  *
891  * Return:
892  *	MH_WALK_CONTINUE = continue to walk
893  *
894  * Comment:
895  *	We need send ABTS for timed-out for solicited exchange
896  *	If it's solicited FLOGI, we need set SS_FLAG_FLOGI_FAILED
897  *	If the link is down, we think it has timed out too.
898  */
899 static uint32_t
900 fcoei_xch_check(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
901 {
902 	fcoei_exchange_t	*xch = (fcoei_exchange_t *)val;
903 
904 	ASSERT(xch->xch_ss == arg);
905 	if ((xch->xch_end_tick < CURRENT_CLOCK) &&
906 	    (xch->xch_ss->ss_link_state != FC_STATE_OFFLINE)) {
907 		if (xch->xch_flags & XCH_FLAG_IN_SOL_HASH) {
908 			ASSERT(xch->xch_oxid == CMHK(key));
909 			/*
910 			 * It's solicited exchange
911 			 */
912 			fcoei_abts_exchange(xch);
913 			if (LA_ELS_FLOGI == ((ls_code_t *)(void *)
914 			    xch->xch_fpkt->pkt_cmd)->ls_code) {
915 				/*
916 				 * It's solicited FLOGI
917 				 */
918 				xch->xch_ss->ss_flags |= SS_FLAG_FLOGI_FAILED;
919 			}
920 		}
921 
922 		FCOEI_LOG(__FUNCTION__, "oxid-%x/rxid-%x  timed out",
923 		    xch->xch_oxid, xch->xch_rxid);
924 		xch->xch_flags |= XCH_FLAG_TMOUT;
925 		xch->xch_fpkt->pkt_state = FC_PKT_TIMEOUT;
926 		xch->xch_fpkt->pkt_reason = FC_REASON_ABORTED;
927 		list_insert_tail(&xch->xch_ss->ss_comp_xch_list, xch);
928 	} else if (xch->xch_ss->ss_link_state == FC_STATE_OFFLINE) {
929 		FCOEI_LOG(__FUNCTION__, "oxid-%x/rxid-%x  offline complete",
930 		    xch->xch_oxid, xch->xch_rxid);
931 		xch->xch_flags |= XCH_FLAG_TMOUT;
932 		xch->xch_fpkt->pkt_state = FC_PKT_PORT_OFFLINE;
933 		xch->xch_fpkt->pkt_reason = FC_REASON_OFFLINE;
934 		list_insert_tail(&xch->xch_ss->ss_comp_xch_list, xch);
935 	}
936 
937 	return (MH_WALK_CONTINUE);
938 }
939 
940 /*
941  * fcoei_init_ifm
942  *	initialize fcoei_frame
943  *
944  * Input:
945  *	frm = the frame that ifm need link to
946  *	xch = the exchange that ifm need link to
947  *
948  * Return:
949  *	N/A
950  *
951  * Comment:
952  *	For solicited frames, it's called after FC frame header initialization
953  *	For unsolicited frames, it's called just after the frame enters fcoei
954  */
955 void
956 fcoei_init_ifm(fcoe_frame_t *frm, fcoei_exchange_t *xch)
957 {
958 	FRM2IFM(frm)->ifm_frm = frm;
959 	FRM2IFM(frm)->ifm_xch = xch;
960 	FRM2IFM(frm)->ifm_rctl = FRM_R_CTL(frm);
961 }
962 
963 /*
964  * fcoei_trigger_fp_attach
965  *	Trigger fp_attach for this fcoei port
966  *
967  * Input:
968  *	arg = the soft state that fp will attach
969  *
970  * Return:
971  *	N/A
972  *
973  * Comment:
974  *	N/A
975  */
976 static void
977 fcoei_trigger_fp_attach(void * arg)
978 {
979 	fcoei_soft_state_t	*ss    = (fcoei_soft_state_t *)arg;
980 	dev_info_t		*child = NULL;
981 	int			 rval  = NDI_FAILURE;
982 
983 	ndi_devi_alloc_sleep(ss->ss_dip, "fp", DEVI_PSEUDO_NODEID, &child);
984 	if (child == NULL) {
985 		FCOEI_LOG(__FUNCTION__, "can't alloc dev_info");
986 		return;
987 	}
988 
989 	/*
990 	 * fp/fctl need this property
991 	 */
992 	if (ddi_prop_update_string(DDI_DEV_T_NONE, child,
993 	    "bus-addr", "0,0") != DDI_PROP_SUCCESS) {
994 		FCOEI_LOG(__FUNCTION__, "update bus-addr failed");
995 		(void) ndi_devi_free(child);
996 		return;
997 	}
998 
999 	/*
1000 	 * If it's physical HBA, fp.conf will register the property.
1001 	 * fcoei is one software HBA, so we need register it manually
1002 	 */
1003 	if (ddi_prop_update_int(DDI_DEV_T_NONE, child,
1004 	    "port", 0) != DDI_PROP_SUCCESS) {
1005 		FCOEI_LOG(__FUNCTION__, "update port failed");
1006 		(void) ndi_devi_free(child);
1007 		return;
1008 	}
1009 
1010 	/*
1011 	 * It will call fp_attach eventually
1012 	 */
1013 	rval = ndi_devi_online(child, NDI_ONLINE_ATTACH);
1014 	ss->ss_flags &= ~SS_FLAG_TRIGGER_FP_ATTACH;
1015 	if (rval != NDI_SUCCESS) {
1016 		FCOEI_LOG(__FUNCTION__, "devi_online: %d", rval);
1017 	} else {
1018 		FCOEI_LOG(__FUNCTION__, "triggered successfully");
1019 	}
1020 }
1021 
1022 /*
1023  * fcoei_abts_exchange
1024  *	Send ABTS to abort solicited exchange
1025  *
1026  * Input:
1027  *	xch = the exchange that will be aborted
1028  *
1029  * Return:
1030  *	N/A
1031  *
1032  * Comment:
1033  *	ABTS frame uses the same oxid as the exchange
1034  */
1035 static void
1036 fcoei_abts_exchange(fcoei_exchange_t *xch)
1037 {
1038 	fc_packet_t	*fpkt = xch->xch_fpkt;
1039 	fcoe_frame_t	*frm  = NULL;
1040 
1041 	/*
1042 	 * BLS_ABTS doesn't contain any other payload except FCFH
1043 	 */
1044 	frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
1045 	    FCFH_SIZE, NULL);
1046 	if (frm == NULL) {
1047 		FCOEI_LOG(__FUNCTION__, "can't alloc frame: %p", xch);
1048 		return;
1049 	}
1050 
1051 	FFM_R_CTL(0x81, frm);
1052 	FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
1053 	FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
1054 	FFM_F_CTL(0x090000, frm);
1055 	FFM_SEQ_ID(0x01, frm);
1056 	FFM_OXID(xch->xch_oxid, frm);
1057 	FFM_RXID(xch->xch_rxid, frm);
1058 	fcoei_init_ifm(frm, xch);
1059 	xch->xch_ss->ss_eport->eport_tx_frame(frm);
1060 }
1061 
1062 /*
1063  * fcoei_complete_xch
1064  *	Complete the exchange
1065  *
1066  * Input:
1067  *	xch = the exchange that will be completed
1068  *	frm = newly-allocated frame that has not been submitted
1069  *	pkt_state = LV fpkt state
1070  *	pkt_reason = LV fpkt reason
1071  *
1072  * Return:
1073  *	N/A
1074  *
1075  * Comment:
1076  *	N/A
1077  */
1078 void
1079 fcoei_complete_xch(fcoei_exchange_t *xch, fcoe_frame_t *frm,
1080     uint8_t pkt_state, uint8_t pkt_reason)
1081 {
1082 	mod_hash_val_t val;
1083 
1084 	if (pkt_state != FC_PKT_SUCCESS) {
1085 		FCOEI_LOG(__FUNCTION__, "FHDR: %x/%x/%x, %x/%x/%x",
1086 		    xch->xch_fpkt->pkt_cmd_fhdr.r_ctl,
1087 		    xch->xch_fpkt->pkt_cmd_fhdr.f_ctl,
1088 		    xch->xch_fpkt->pkt_cmd_fhdr.type,
1089 		    xch->xch_fpkt->pkt_resp_fhdr.r_ctl,
1090 		    xch->xch_fpkt->pkt_resp_fhdr.f_ctl,
1091 		    xch->xch_fpkt->pkt_resp_fhdr.type);
1092 		FCOEI_LOG(__FUNCTION__, "%p/%p/%x/%x",
1093 		    xch, frm, pkt_state, pkt_reason);
1094 	}
1095 
1096 	if (frm != NULL) {
1097 		/*
1098 		 * It's newly-allocated frame , which we haven't sent out
1099 		 */
1100 		xch->xch_ss->ss_eport->eport_free_netb(frm->frm_netb);
1101 		xch->xch_ss->ss_eport->eport_release_frame(frm);
1102 		FCOEI_LOG(__FUNCTION__, "xch: %p, not submitted", xch);
1103 	}
1104 
1105 	/*
1106 	 * If xch is in hash table, we need remove it
1107 	 */
1108 	if (xch->xch_flags & XCH_FLAG_IN_SOL_HASH) {
1109 		mod_hash_remove(xch->xch_ss->ss_sol_oxid_hash,
1110 		    FMHK(xch->xch_oxid), &val);
1111 		ASSERT((fcoei_exchange_t *)val == xch);
1112 		xch->xch_flags &= ~XCH_FLAG_IN_SOL_HASH;
1113 	} else if (xch->xch_flags & XCH_FLAG_IN_UNSOL_HASH) {
1114 		mod_hash_remove(xch->xch_ss->ss_unsol_rxid_hash,
1115 		    FMHK(xch->xch_rxid), &val);
1116 		ASSERT((fcoei_exchange_t *)val == xch);
1117 		xch->xch_flags &= ~XCH_FLAG_IN_UNSOL_HASH;
1118 	} else {
1119 		FCOEI_LOG(__FUNCTION__, "xch not in any hash: %p", xch);
1120 	}
1121 
1122 	xch->xch_fpkt->pkt_state = pkt_state;
1123 	xch->xch_fpkt->pkt_reason = pkt_reason;
1124 	if (xch->xch_fpkt->pkt_tran_flags & FC_TRAN_NO_INTR) {
1125 		FCOEI_LOG(__FUNCTION__, "polled xch is done: %p", xch);
1126 		sema_v(&xch->xch_sema);
1127 	} else {
1128 		xch->xch_fpkt->pkt_comp(xch->xch_fpkt);
1129 	}
1130 }
1131