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 /*
28  * This file defines interfaces between FCOE and LEADVILLE
29  */
30 
31 /*
32  * Driver kernel header files
33  */
34 #include <sys/conf.h>
35 #include <sys/ddi.h>
36 #include <sys/stat.h>
37 #include <sys/pci.h>
38 #include <sys/sunddi.h>
39 #include <sys/modctl.h>
40 #include <sys/file.h>
41 #include <sys/cred.h>
42 #include <sys/byteorder.h>
43 #include <sys/atomic.h>
44 #include <sys/scsi/scsi.h>
45 #include <sys/mac_client.h>
46 #include <sys/modhash.h>
47 
48 /*
49  * LEADVILLE header files
50  */
51 #include <sys/fibre-channel/fc.h>
52 #include <sys/fibre-channel/impl/fc_fcaif.h>
53 
54 /*
55  * COMSTAR head files (BIT_* macro)
56  */
57 #include <sys/stmf_defines.h>
58 
59 /*
60  * FCOE header files
61  */
62 #include <sys/fcoe/fcoe_common.h>
63 
64 /*
65  * Driver's own header files
66  */
67 #include <fcoei.h>
68 
69 /*
70  * forward declaration of static functions
71  */
72 static void fcoei_port_enabled(void *arg);
73 
74 static void fcoei_populate_hba_fru_details(fcoei_soft_state_t *ss,
75     fc_fca_port_info_t *port_info);
76 
77 static void fcoei_initiate_ct_req(fcoei_exchange_t *xch);
78 static void fcoei_initiate_fcp_cmd(fcoei_exchange_t *xch);
79 static void fcoei_initiate_els_req(fcoei_exchange_t *xch);
80 static void fcoei_initiate_els_resp(fcoei_exchange_t *xch);
81 
82 static void fcoei_fill_els_logi_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
83 static void fcoei_fill_els_prli_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
84 static void fcoei_fill_els_logo_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
85 static void fcoei_fill_els_scr_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
86 static void fcoei_fill_els_adisc_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
87 static void fcoei_fill_els_linit_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
88 static void fcoei_fill_els_rls_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
89 static void fcoei_fill_els_rnid_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
90 
91 static void fcoei_fill_els_acc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
92 static void fcoei_fill_els_rjt_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
93 static void fcoei_fill_els_logi_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
94 static void fcoei_fill_els_prli_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
95 static void fcoei_fill_els_logo_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
96 static void fcoei_fill_els_adisc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
97 
98 static void fcoei_logo_peer(void *arg);
99 static void fcoei_fpkt_comp(fc_packet_t *fpkt);
100 
101 static uint32_t
102 fcoei_xch_abort(mod_hash_key_t key, mod_hash_val_t *val, void *arg);
103 
104 
105 /*
106  * fcoei_bind_port
107  *	Bind LV port instance with fcoei soft state
108  *
109  * Input:
110  *	dip = dev info of fcoei soft state
111  *	port_info = fcoei specific parameters about LV port
112  *	bind_info = LV specific parameters about fcoei soft state
113  *
114  * Returns:
115  *	The pointer to fcoei soft state
116  *
117  * Comments:
118  *	Unpon the completion of this call, the port must be offline.
119  *	fcoei_port_enabled could trigger it to online
120  */
121 static void *
122 fcoei_bind_port(dev_info_t *dip, fc_fca_port_info_t *port_info,
123     fc_fca_bind_info_t *bind_info)
124 {
125 	fcoei_soft_state_t	*ss;
126 
127 	/*
128 	 * get state info based on the dip
129 	 */
130 	ss = (fcoei_soft_state_t *)
131 	    ddi_get_soft_state(fcoei_state, ddi_get_instance(dip));
132 	if (!ss) {
133 		FCOEI_LOG(__FUNCTION__, "ss is NULL");
134 		return (NULL);
135 	}
136 
137 	/*
138 	 * make sure this port isn't bound
139 	 */
140 	if (ss->ss_flags & SS_FLAG_LV_BOUND) {
141 		port_info->pi_error = FC_ALREADY;
142 		FCOEI_LOG(__FUNCTION__, "ss has been bound");
143 		return (NULL);
144 	}
145 
146 	if (bind_info->port_num) {
147 		/*
148 		 * make sure request is in bounds
149 		 */
150 		port_info->pi_error = FC_OUTOFBOUNDS;
151 		FCOEI_LOG(__FUNCTION__, "port_num is not 0");
152 		return (NULL);
153 	}
154 
155 	/*
156 	 * stash the ss_bind_info supplied by the FC Transport
157 	 */
158 	bcopy(bind_info, &ss->ss_bind_info, sizeof (fc_fca_bind_info_t));
159 	ss->ss_port = bind_info->port_handle;
160 
161 	/*
162 	 * RNID parameter
163 	 */
164 	port_info->pi_rnid_params.status = FC_FAILURE;
165 
166 	/*
167 	 * populate T11 FC-HBA details
168 	 */
169 	fcoei_populate_hba_fru_details(ss, port_info);
170 
171 	/*
172 	 * set port's current state, and it is always offline before binding
173 	 *
174 	 * We hack pi_port_state to tell LV if it's NODMA_FCA
175 	 */
176 	port_info->pi_port_state = FC_STATE_FCA_IS_NODMA;
177 
178 	/*
179 	 * copy login param
180 	 */
181 	bcopy(&ss->ss_els_logi, &port_info->pi_login_params,
182 	    sizeof (la_els_logi_t));
183 
184 	/*
185 	 * Mark it as bound
186 	 */
187 	atomic_or_32(&ss->ss_flags, SS_FLAG_LV_BOUND);
188 
189 	/*
190 	 * Let fcoe to report the link status
191 	 */
192 	fcoei_port_enabled((void *)ss);
193 
194 	FCOEI_LOG(__FUNCTION__, "Exit fcoei_bind_port: %p", ss);
195 	return (ss);
196 }
197 
198 /*
199  * fcoei_unbind_port
200  *	Un-bind the fcoei port
201  *
202  * Input:
203  *	fca_handle = fcoei soft state set in fcoei_bind_port
204  *
205  * Returns:
206  *	N/A
207  *
208  * Comments:
209  *	Clear binding flag
210  */
211 static void
212 fcoei_unbind_port(void *fca_handle)
213 {
214 	fcoei_soft_state_t *ss = (fcoei_soft_state_t *)fca_handle;
215 
216 	atomic_and_32(&ss->ss_flags, ~SS_FLAG_LV_BOUND);
217 	ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, NULL);
218 	FCOEI_LOG(__FUNCTION__, "Exit fcoei_unbind_port: %p", ss);
219 }
220 
221 /*
222  * fcoei_init_pkt
223  *	Initialize fcoei related part of fc_packet
224  *
225  * Input:
226  *	fca_handle = fcoei soft state set in fcoei_bind_port
227  *	fpkt = The pointer to fc_packet
228  *	sleep = This call can sleep or not
229  *
230  * Returns:
231  *	FC_SUCCESS - Initialization completed successfully
232  *
233  * Comments:
234  *	Link the exchange elements with proper objects
235  */
236 static int
237 fcoei_init_pkt(void *fca_handle, fc_packet_t *fpkt, int sleep)
238 {
239 	fcoei_soft_state_t	*ss  = (fcoei_soft_state_t *)fca_handle;
240 	fcoei_exchange_t	*xch = FPKT2XCH(fpkt);
241 
242 	ASSERT(sleep + 1);
243 	xch->xch_ss = ss;
244 	xch->xch_fpkt = fpkt;
245 	xch->xch_flags = 0;
246 	return (FC_SUCCESS);
247 }
248 
249 /*
250  * fcoei_un_init_pkt
251  *	Uninitialize fcoei related part of fc_packet
252  *
253  * Input:
254  *	fca_handle = fcoei soft state set in fcoei_bind_port
255  *	fpkt = The pointer to fc_packet
256  *
257  * Returns:
258  *	FC_SUCCESS - Uninitialize successfully
259  *
260  * Comments:
261  *	Very simple, just return successfully
262  */
263 static int
264 fcoei_un_init_pkt(void *fca_handle, fc_packet_t *fpkt)
265 {
266 	ASSERT(fca_handle && fpkt);
267 	return (FC_SUCCESS);
268 }
269 
270 /*
271  * fcoei_get_cap
272  *	Export FCA hardware and software capability.
273  *
274  * Input:
275  *	fca_handle = fcoei soft state set in fcoei_bind_port
276  *	cap = pointer to the capability string
277  *	ptr = buffer pointer for returning capability
278  *
279  * Returns:
280  *	FC_CAP_ERROR - no such capability
281  *	FC_CAP_FOUND - the capability was returned and cannot be set
282  *
283  * Comments:
284  *	FC_CAP_UNSOL_BUF is one important capability, it will affect the
285  *	implementation of fcoei_ub_alloc/free.
286  */
287 static int
288 fcoei_get_cap(void * fca_handle, char *cap, void *ptr)
289 {
290 	fcoei_soft_state_t	*ss   = (fcoei_soft_state_t *)fca_handle;
291 	uint32_t		*rptr = (uint32_t *)ptr;
292 	int			 rval = FC_CAP_FOUND;
293 
294 	ASSERT(fca_handle);
295 	FCOEI_LOG(__FUNCTION__, "cap: %s", cap);
296 	if (strcmp(cap, FC_NODE_WWN) == 0) {
297 		bcopy(&ss->ss_els_logi.node_ww_name.raw_wwn[0], ptr, 8);
298 	} else if (strcmp(cap, FC_LOGIN_PARAMS) == 0) {
299 		bcopy((void *)&ss->ss_els_logi, ptr, sizeof (la_els_logi_t));
300 	} else if (strcmp(cap, FC_CAP_UNSOL_BUF) == 0) {
301 		*rptr = (uint32_t)0;
302 	} else if (strcmp(cap, FC_CAP_NOSTREAM_ON_UNALIGN_BUF) == 0) {
303 		*rptr = (uint32_t)FC_ALLOW_STREAMING;
304 	} else if (strcmp(cap, FC_CAP_PAYLOAD_SIZE) == 0) {
305 		*rptr = (uint32_t)2136;
306 	} else if (strcmp(cap, FC_CAP_POST_RESET_BEHAVIOR) == 0) {
307 		*rptr = FC_RESET_RETURN_ALL;
308 	} else if (strcmp(cap, FC_CAP_FCP_DMA) == 0) {
309 		*rptr = FC_NO_DVMA_SPACE;
310 	} else {
311 		rval = FC_CAP_ERROR;
312 		FCOEI_LOG(__FUNCTION__, "not supported");
313 	}
314 
315 	return (rval);
316 }
317 
318 /*
319  * fcoei_set_cap
320  *	Allow the FC Transport to set FCA capabilities if possible
321  *
322  * Input:
323  *	fca_handle = fcoei soft state set in fcoei_bind_port
324  *	cap = pointer to the capabilities string.
325  *	ptr = buffer pointer for capability.
326  *
327  * Returns:
328  *	FC_CAP_ERROR - no such capability
329  *
330  * Comments:
331  *	Currently, all capabilities can't be changed.
332  */
333 static int
334 fcoei_set_cap(void * fca_handle, char *cap, void *ptr)
335 {
336 	FCOEI_LOG(__FUNCTION__, "cap: %s, %p, %p", cap, fca_handle, ptr);
337 	return (FC_CAP_ERROR);
338 }
339 
340 /*
341  * fcoei_getmap
342  *	Get lilp map
343  *
344  * Input:
345  *	fca_handle = fcoei soft state set in fcoei_bind_port
346  *	mapbuf = the buffer to store lilp map
347  *
348  * Returns:
349  *	FC_FAILURE - Can't get the lilp map
350  *
351  * Comments:
352  *	fcoei can't work in loop topology, so it should never get called
353  */
354 static int
355 fcoei_getmap(void * fca_handle, fc_lilpmap_t *mapbuf)
356 {
357 	FCOEI_LOG(__FUNCTION__, "not: %p-%p", fca_handle, mapbuf);
358 	return (FC_FAILURE);
359 }
360 
361 /*
362  * fcoei_ub_alloc
363  *	Pre-allocate unsolicited buffers at the request of LV
364  *
365  * Input:
366  *	fca_handle = fcoei soft state set in fcoei_bind_port
367  *	tokens = token array for each buffer.
368  *	size = number of tokens
369  *	count = the acutual number of allocated unsolicited buffers
370  *	type = unsolicited buffer type
371  *
372  * Returns:
373  *	FC_SUCCESS - The requested buffers have been freeed
374  *
375  * Comments:
376  *	fcoei_get_cap will set UNSOL_BUF to 0, so it should never get called.
377  */
378 static int
379 fcoei_ub_alloc(void * fca_handle, uint64_t tokens[], uint32_t size,
380     uint32_t *count, uint32_t type)
381 {
382 	FCOEI_LOG(__FUNCTION__, "not: %p-%p-%x-%p-%x", fca_handle, tokens,
383 	    size, count, type);
384 	return (FC_SUCCESS);
385 }
386 
387 /*
388  * fcoei_ub_free
389  *	Free the pre-allocated unsolicited buffers at the request of LV
390  *
391  * Input:
392  *	fca_handle = fcoei soft state set in fcoei_bind_port
393  *	count = number of buffers.
394  *	tokens = token array for each buffer.
395  *
396  * Returns:
397  *	FC_SUCCESS - The requested buffers have been freeed
398  *
399  * Comments:
400  *	fcoei_get_cap will set UNSOL_BUF to 0, so it should never get called.
401  */
402 static int
403 fcoei_ub_free(void * fca_handle, uint32_t count, uint64_t tokens[])
404 {
405 	FCOEI_EXT_LOG(__FUNCTION__, "not: %p-%x-%p", fca_handle, count, tokens);
406 	return (FC_SUCCESS);
407 }
408 
409 /*
410  * fcoei_ub_release
411  *	Release unsolicited buffers from FC Transport to FCA for future use
412  *
413  * Input:
414  *	fca_handle = fcoei soft state set in fcoei_bind_port
415  *	count = number of buffers.
416  *	tokens = token array for each buffer.
417  *
418  * Returns:
419  *	FC_SUCCESS - The requested buffers have been released.
420  *	FC_FAILURE - The requested buffers have not been released.
421  *
422  * Comments:
423  *	It will always succeed. It has nothing to do with fcoei_ub_alloc/free.
424  */
425 static int
426 fcoei_ub_release(void * fca_handle, uint32_t count, uint64_t tokens[])
427 {
428 	fc_unsol_buf_t *ub = *((fc_unsol_buf_t **)tokens);
429 
430 	if (count != 1) {
431 		FCOEI_LOG(__FUNCTION__, "count is not 1: %p", fca_handle);
432 		return (FC_FAILURE);
433 	}
434 
435 	kmem_free(ub->ub_buffer, ub->ub_bufsize);
436 	kmem_free(ub, sizeof (fc_unsol_buf_t));
437 	FCOEI_EXT_LOG(__FUNCTION__, "ub is freeed");
438 	return (FC_SUCCESS);
439 }
440 
441 /*
442  * fcoei_abort
443  *	Direct FCA driver to abort an outstanding exchange associated with a
444  *	specified fc_packet_t struct
445  *
446  * Input:
447  *	fca_handle - fcoei soft state set in fcoei_bind_port
448  *	fpkt - A pointer to the fc_packet_t for the exchange to be aborted.
449  *	flags - Set to KM_SLEEP if the function may sleep, or KM_NOSLEEP if
450  *		the function may not sleep.
451  *
452  * Returns:
453  *	FC_ABORTED - The specified exchange was successfully aborted.
454  *	FC_ABORTING - The specified exchange is being aborted.
455  *	FC_ABORT_FAILED - The specified exchange could not be aborted.
456  *	FC_TRANSPORT_ERROR - A transport error occurred while attempting to
457  *		abort the specified exchange.
458  *	FC_BADEXCHANGE - The specified exchange does not exist.
459  *
460  * Comments:
461  *	After the exchange is aborted, the FCA driver must update the relevant
462  *	fields in the fc_packet_t struct as per normal exchange completion and
463  *	call the pkt_comp function to return the fc_packet_t struct to the FC
464  *	Transport.
465  *	When an exchange is successfully aborted, the FCA driver must set the
466  *	pkt_reason field in the fc_packet_t to FC_REASON_ABORTED and the
467  *	pkt_state field in the fc_packet_t to FC_PKT_LOCAL_RJT before returning
468  *	the fc_packet_t to the FC Transport.
469  *
470  *	Unfortunately, LV doesn't conform to the spec. It will take all these
471  *	legal return value as failure to abort.
472  */
473 static int
474 fcoei_abort(void * fca_handle, fc_packet_t *fpkt, int flags)
475 {
476 	FCOEI_LOG(__FUNCTION__, "not: %p-%p-%x", fca_handle, fpkt, flags);
477 	return (FC_SUCCESS);
478 }
479 
480 /*
481  * fcoei_reset
482  *	Reset link or hardware
483  *
484  * Input:
485  *	fca_handle = fcoei soft state set in fcoei_bind_port
486  *	cmd = reset type command
487  *
488  * Returns:
489  *	FC_SUCCESS - Reset has completed successfully
490  *	FC_FAILURE - Reset has failed
491  *
492  * Comments:
493  *	N/A
494  */
495 static int
496 fcoei_reset(void * fca_handle, uint32_t cmd)
497 {
498 	int			 rval = FC_SUCCESS;
499 	fcoei_soft_state_t	*ss   = (fcoei_soft_state_t *)fca_handle;
500 	fcoei_event_t *ae;
501 
502 	switch (cmd) {
503 	case FC_FCA_LINK_RESET:
504 		if (ss->ss_link_state != FC_STATE_ONLINE) {
505 			FCOEI_LOG(__FUNCTION__, "not online now: ss-%p", ss);
506 			rval = FC_FAILURE;
507 			break;
508 		}
509 
510 		/*
511 		 * This is linkreset phase I
512 		 */
513 		fcoei_logo_peer(ss);
514 		delay(FCOE_SEC2TICK(1) / 10);
515 		ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, 0);
516 		fcoei_port_event(ss->ss_eport, FCOE_NOTIFY_EPORT_LINK_DOWN);
517 
518 		/*
519 		 * Perpare linkreset phase II
520 		 */
521 		ae = kmem_zalloc(sizeof (*ae), KM_SLEEP);
522 		ae->ae_type = AE_EVENT_RESET;
523 		ae->ae_obj = ss;
524 
525 		mutex_enter(&ss->ss_watchdog_mutex);
526 		list_insert_tail(&ss->ss_event_list, ae);
527 		mutex_exit(&ss->ss_watchdog_mutex);
528 		break;
529 
530 	case FC_FCA_RESET:
531 		break;
532 
533 	case FC_FCA_CORE:
534 		break;
535 
536 	case FC_FCA_RESET_CORE:
537 		break;
538 
539 	default:
540 		rval = FC_FAILURE;
541 		FCOEI_LOG(__FUNCTION__, "cmd-%x not supported", cmd);
542 		break;
543 	}
544 
545 	return (rval);
546 }
547 
548 /*
549  * fcoei_port_manage
550  *	Perform various port management operations at the request of LV
551  *
552  * Input:
553  *	fca_handle = fcoei soft state set in fcoei_bind_port
554  *	pm = the pointer to the struct specifying the port management operation
555  *
556  * Returns:
557  *	FC_SUCCESS - The request completed successfully
558  *	FC_FAILURE - The request did not complete successfully
559  *
560  * Comments:
561  *	N/A
562  */
563 static int
564 fcoei_port_manage(void * fca_handle, fc_fca_pm_t *pm)
565 {
566 	int	rval = FC_FAILURE;
567 	fcoei_soft_state_t	*ss = (fcoei_soft_state_t *)fca_handle;
568 
569 	if (fca_handle == NULL || pm == NULL) {
570 		return (rval);
571 	}
572 
573 	FCOEI_LOG(__FUNCTION__, "code0x%x, %p", pm->pm_cmd_code, fca_handle);
574 	switch (pm->pm_cmd_code) {
575 
576 	case FC_PORT_GET_NODE_ID:
577 	{
578 		if (pm->pm_data_len < sizeof (fc_rnid_t)) {
579 			rval = FC_NOMEM;
580 			break;
581 		}
582 		ss->ss_rnid.port_id = ss->ss_p2p_info.fca_d_id;
583 		bcopy((void *)&ss->ss_rnid,
584 		    pm->pm_data_buf, sizeof (fc_rnid_t));
585 		rval = FC_SUCCESS;
586 		break;
587 	}
588 
589 	case FC_PORT_SET_NODE_ID:
590 	{
591 		if (pm->pm_data_len < sizeof (fc_rnid_t)) {
592 			rval = FC_NOMEM;
593 			break;
594 		}
595 		bcopy(pm->pm_data_buf,
596 		    (void *)&ss->ss_rnid, sizeof (fc_rnid_t));
597 		rval = FC_SUCCESS;
598 		break;
599 	}
600 
601 	default:
602 		FCOEI_LOG(__FUNCTION__, "unsupported cmd-%x", pm->pm_cmd_code);
603 		rval = FC_INVALID_REQUEST;
604 		break;
605 	}
606 
607 	return (rval);
608 }
609 
610 /*
611  * fcoei_get_device
612  *	Get fcoei remote port with FCID of d_id
613  *
614  * Input:
615  *	fca_handle = fcoei soft state set in fcoei_bind_port
616  *	d_id = 24-bit FCID of remote port
617  *
618  * Returns:
619  *	The pointer to fcoei remote port
620  *
621  * Comments:
622  *	fcoei has no remote port device
623  */
624 static void *
625 fcoei_get_device(void *fca_handle, fc_portid_t d_id)
626 {
627 	FCOEI_EXT_LOG(__FUNCTION__, "not supported: %p-%x", fca_handle, d_id);
628 	return (NULL);
629 }
630 
631 /*
632  * fcoei_notify
633  *	Notify the change of target device
634  *
635  * Input:
636  *	fca_handle = fcoei soft state set in fcoei_bind_port
637  *	cmd = detailed cmd
638  *
639  * Returns:
640  *	FC_SUCCESS - Notification completed successfully
641  *
642  * Comments:
643  *	It's only needed to support non-COMSTAR FC target, so it should
644  *	never get called.
645  */
646 static int
647 fcoei_notify(void *fca_handle, uint32_t cmd)
648 {
649 	FCOEI_LOG(__FUNCTION__, "not supported: %p-%x", fca_handle, cmd);
650 	return (FC_SUCCESS);
651 }
652 
653 /*
654  * fcoei_transport
655  *	Submit FCP/CT requests
656  *
657  * Input:
658  *	fca_handle - fcoei soft state set in fcoei_bind_port
659  *	fpkt - LV fc_packet
660  *
661  * Returns:
662  *	N/A
663  *
664  * Comments:
665  *	N/A
666  */
667 static int
668 fcoei_transport(void *fca_handle, fc_packet_t *fpkt)
669 {
670 	fcoei_soft_state_t	*ss  = (fcoei_soft_state_t *)fca_handle;
671 	fcoei_exchange_t	*xch = FPKT2XCH(fpkt);
672 	uint16_t		 pkt_tran_flags = fpkt->pkt_tran_flags;
673 
674 	xch->xch_start_tick = ddi_get_lbolt();
675 	xch->xch_end_tick = xch->xch_start_tick +
676 	    FCOE_SEC2TICK(fpkt->pkt_timeout);
677 	xch->xch_ae.ae_type = AE_EVENT_EXCHANGE;
678 	xch->xch_ae.ae_obj = xch;
679 
680 	if (pkt_tran_flags & FC_TRAN_NO_INTR) {
681 		FCOEI_LOG(__FUNCTION__, "AaA polling: %p-%p", fpkt, xch);
682 		sema_init(&xch->xch_sema, 0, NULL, SEMA_DRIVER, NULL);
683 	}
684 
685 	mutex_enter(&ss->ss_watchdog_mutex);
686 	list_insert_tail(&ss->ss_event_list, &xch->xch_ae);
687 	if (ss->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
688 		cv_signal(&ss->ss_watchdog_cv);
689 	}
690 	mutex_exit(&ss->ss_watchdog_mutex);
691 
692 	if (pkt_tran_flags & FC_TRAN_NO_INTR) {
693 		FCOEI_LOG(__FUNCTION__, "BaB polling: %p-%p", fpkt, xch);
694 		sema_p(&xch->xch_sema);
695 		sema_destroy(&xch->xch_sema);
696 		FCOEI_LOG(__FUNCTION__, "after polling: %p-%p", fpkt, xch);
697 	}
698 
699 	return (FC_SUCCESS);
700 }
701 
702 /*
703  * fcoei_els_send
704  *	Submit ELS request or response
705  *
706  * Input:
707  *	fca_handle - fcoei soft state set in fcoei_bind_port
708  *	fpkt = LV fc_packet
709  *
710  * Returns:
711  *	N/A
712  *
713  * Comments:
714  *	N/A
715  */
716 static int
717 fcoei_els_send(void *fca_handle, fc_packet_t *fpkt)
718 {
719 	fcoei_soft_state_t	*ss  = (fcoei_soft_state_t *)fca_handle;
720 	fcoei_exchange_t	*xch = FPKT2XCH(fpkt);
721 
722 	if (fpkt->pkt_tran_flags & FC_TRAN_NO_INTR) {
723 		FCOEI_LOG(__FUNCTION__, "ELS poll mode is not supported");
724 		return (FC_BADPACKET);
725 	}
726 
727 	xch->xch_start_tick = ddi_get_lbolt();
728 	xch->xch_end_tick = xch->xch_start_tick +
729 	    FCOE_SEC2TICK(fpkt->pkt_timeout);
730 	xch->xch_ae.ae_type = AE_EVENT_EXCHANGE;
731 	xch->xch_ae.ae_obj = xch;
732 
733 	/*
734 	 * LV could release ub after this call, so we must save the ub type
735 	 * for later use
736 	 */
737 	if (fpkt->pkt_cmd_fhdr.r_ctl == R_CTL_ELS_RSP) {
738 		((uint8_t *)&fpkt->pkt_fca_rsvd1)[0] =
739 		    ((fc_unsol_buf_t *)fpkt->pkt_ub_resp_token)->ub_buffer[0];
740 	}
741 
742 	mutex_enter(&ss->ss_watchdog_mutex);
743 	list_insert_tail(&ss->ss_event_list, &xch->xch_ae);
744 	if (ss->ss_flags & SS_FLAG_WATCHDOG_IDLE) {
745 		cv_signal(&ss->ss_watchdog_cv);
746 	}
747 	mutex_exit(&ss->ss_watchdog_mutex);
748 
749 	return (FC_SUCCESS);
750 }
751 
752 /*
753  * fcoei_populate_hba_fru_details
754  *	Fill detailed information about HBA
755  *
756  * Input:
757  *	ss - fcoei soft state
758  *	port_info = fc_fca_port_info_t that need be updated
759  *
760  * Returns:
761  *	N/A
762  *
763  * Comments:
764  *	N/A
765  */
766 static void
767 fcoei_populate_hba_fru_details(fcoei_soft_state_t *ss,
768     fc_fca_port_info_t *port_info)
769 {
770 	fca_port_attrs_t *port_attrs = &(port_info->pi_attrs);
771 	int	instance;
772 
773 	ASSERT(ss != NULL);
774 	(void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN,
775 	    "Sun Microsystems, Inc.");
776 	(void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN,
777 	    "%s", FCOEI_NAME_VERSION);
778 	(void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN,
779 	    "%s", FCOEI_VERSION);
780 	(void) strcpy(port_attrs->serial_number, "N/A");
781 	(void) strcpy(port_attrs->hardware_version, "N/A");
782 	(void) strcpy(port_attrs->model, "FCoE Virtual FC HBA");
783 	(void) strcpy(port_attrs->model_description, "N/A");
784 	(void) strcpy(port_attrs->firmware_version, "N/A");
785 	(void) strcpy(port_attrs->option_rom_version, "N/A");
786 
787 	port_attrs->vendor_specific_id = 0xFC0E;
788 	port_attrs->max_frame_size = FCOE_MAX_FC_FRAME_SIZE;
789 	port_attrs->supported_cos = 0x10000000;
790 	port_attrs->supported_speed = FC_HBA_PORTSPEED_1GBIT |
791 	    FC_HBA_PORTSPEED_10GBIT;
792 	instance = ddi_get_instance(ss->ss_dip);
793 	port_attrs->hba_fru_details.high =
794 	    (short)((instance & 0xffff0000) >> 16);
795 	port_attrs->hba_fru_details.low =
796 	    (short)(instance & 0x0000ffff);
797 }
798 
799 /*
800  * fcoei_port_enabled
801  *	Notify fcoe that the port has been enabled
802  *
803  * Input:
804  *	arg = the related soft state
805  *
806  * Returns:
807  *	N/A
808  *
809  * Comments:
810  *	Only after this, fcoe will report the link status to us
811  */
812 static void
813 fcoei_port_enabled(void *arg)
814 {
815 	fcoei_soft_state_t	*ss  = (fcoei_soft_state_t *)arg;
816 
817 	ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, NULL);
818 }
819 
820 
821 /*
822  * fcoei_initiate_ct_req
823  *	Fill and submit CT request
824  *
825  * Input:
826  *	xch - the exchange that will be initiated
827  *
828  * Returns:
829  *	N/A
830  *
831  * Comments:
832  *	N/A
833  */
834 static void
835 fcoei_initiate_ct_req(fcoei_exchange_t *xch)
836 {
837 	fc_packet_t	*fpkt	 = xch->xch_fpkt;
838 	fc_ct_header_t	*ct	 = (fc_ct_header_t *)(void *)fpkt->pkt_cmd;
839 	uint8_t		*bp	 = (uint8_t *)fpkt->pkt_cmd;
840 	fcoe_frame_t	*frm;
841 	int		 offset;
842 	int		 idx;
843 	uint32_t	 cmd_len = fpkt->pkt_cmdlen;
844 
845 	/*
846 	 * Ensure it's 4-byte aligned
847 	 */
848 	cmd_len = P2ROUNDUP(cmd_len, 4);
849 
850 	/*
851 	 * Allocate CT request frame
852 	 */
853 	frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
854 	    cmd_len + FCFH_SIZE, NULL);
855 	if (frm == NULL) {
856 		FCOEI_LOG(__FUNCTION__, "failed to alloc: %p", xch);
857 		return;
858 	}
859 
860 	bzero(frm->frm_payload, cmd_len);
861 	xch->xch_cnt = xch->xch_ss->ss_sol_cnt;
862 	atomic_add_32(xch->xch_cnt, 1);
863 
864 	FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
865 	FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
866 	FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
867 	FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
868 	FFM_F_CTL(fpkt->pkt_cmd_fhdr.f_ctl, frm);
869 	FFM_OXID(xch->xch_oxid, frm);
870 	FFM_RXID(xch->xch_rxid, frm);
871 	fcoei_init_ifm(frm, xch);
872 
873 	/*
874 	 * CT header (FC payload)
875 	 */
876 	offset = 0;
877 	FCOE_V2B_1(ct->ct_rev, FPLD + offset);
878 
879 	offset = 1;
880 	FCOE_V2B_3(ct->ct_inid, FPLD + offset);
881 
882 	offset = 4;
883 	FCOE_V2B_1(ct->ct_fcstype, FPLD + offset);
884 
885 	offset = 5;
886 	FCOE_V2B_1(ct->ct_fcssubtype, FPLD + offset);
887 
888 	offset = 6;
889 	FCOE_V2B_1(ct->ct_options, FPLD + offset);
890 
891 	offset = 8;
892 	FCOE_V2B_2(ct->ct_cmdrsp, FPLD + offset);
893 
894 	offset = 10;
895 	FCOE_V2B_2(ct->ct_aiusize, FPLD + offset);
896 
897 	offset = 13;
898 	FCOE_V2B_1(ct->ct_reason, FPLD + offset);
899 
900 	offset = 14;
901 	FCOE_V2B_1(ct->ct_expln, FPLD + offset);
902 
903 	offset = 15;
904 	FCOE_V2B_1(ct->ct_vendor, FPLD + offset);
905 
906 	/*
907 	 * CT payload (FC payload)
908 	 */
909 	switch (ct->ct_fcstype) {
910 	case FCSTYPE_DIRECTORY:
911 		switch (ct->ct_cmdrsp) {
912 		case NS_GA_NXT:
913 		case NS_GPN_ID:
914 		case NS_GNN_ID:
915 		case NS_GCS_ID:
916 		case NS_GFT_ID:
917 		case NS_GSPN_ID:
918 		case NS_GPT_ID:
919 		case NS_GID_FT:
920 		case NS_GID_PT:
921 		case NS_DA_ID:
922 			offset = 16;
923 			FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
924 			    FPLD + offset);
925 			break;
926 
927 		case NS_GID_PN:
928 			offset = 16;
929 			bcopy(bp + offset, FPLD + offset, 8);
930 			break;
931 
932 		case NS_RNN_ID:
933 		case NS_RPN_ID:
934 			offset = 16;
935 			FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
936 			    FPLD + offset);
937 
938 			offset = 20;
939 			bcopy(bp + offset, FPLD + offset, 8);
940 			break;
941 
942 		case NS_RSPN_ID:
943 			offset = 16;
944 			FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
945 			    FPLD + offset);
946 
947 			offset = 20;
948 			bcopy(bp + offset, FPLD + offset, bp[20] + 1);
949 			break;
950 
951 		case NS_RSNN_NN:
952 			offset = 16;
953 			bcopy(bp + offset, FPLD + offset, 8);
954 
955 			offset = 24;
956 			bcopy(bp + offset, FPLD + offset, bp[24] + 1);
957 			break;
958 
959 		case NS_RFT_ID:
960 			offset = 16;
961 			FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
962 			    FPLD + offset);
963 
964 			/*
965 			 * fp use bcopy to copy fp_fc4_types,
966 			 * we need to swap order for each integer
967 			 */
968 			offset = 20;
969 			for (idx = 0; idx < 8; idx++) {
970 				FCOE_V2B_4(
971 				    ((uint32_t *)(intptr_t)(bp + offset))[0],
972 				    FPLD + offset);
973 				offset += 4;
974 			}
975 			break;
976 
977 		case NS_RCS_ID:
978 		case NS_RPT_ID:
979 			offset = 16;
980 			FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
981 			    FPLD + offset);
982 
983 			offset = 20;
984 			FCOE_V2B_4(((uint32_t *)(intptr_t)(bp + offset))[0],
985 			    FPLD + offset);
986 			break;
987 
988 		case NS_RIP_NN:
989 			offset = 16;
990 			bcopy(bp + offset, FPLD + offset, 24);
991 			break;
992 
993 		default:
994 			fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
995 			    FC_REASON_CMD_UNSUPPORTED);
996 			break;
997 		}
998 		break; /* FCSTYPE_DIRECTORY */
999 
1000 	case FCSTYPE_MGMTSERVICE:
1001 		switch (ct->ct_cmdrsp) {
1002 		case MS_GIEL:
1003 			FCOEI_LOG(__FUNCTION__,
1004 			    "MS_GIEL ct_fcstype %x, ct_cmdrsp: %x",
1005 			    ct->ct_fcstype, ct->ct_cmdrsp);
1006 			break;
1007 
1008 		default:
1009 			fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
1010 			    FC_REASON_CMD_UNSUPPORTED);
1011 			break;
1012 		}
1013 		break; /* FCSTYPE_MGMTSERVICE */
1014 
1015 	default:
1016 		fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
1017 		    FC_REASON_CMD_UNSUPPORTED);
1018 		break;
1019 	}
1020 	xch->xch_ss->ss_eport->eport_tx_frame(frm);
1021 }
1022 
1023 /*
1024  * fcoei_initiate_fcp_cmd
1025  *	Submit FCP command
1026  *
1027  * Input:
1028  *	xch - the exchange to be submitted
1029  *
1030  * Returns:
1031  *	N/A
1032  *
1033  * Comments:
1034  *	N/A
1035  */
1036 static void
1037 fcoei_initiate_fcp_cmd(fcoei_exchange_t *xch)
1038 {
1039 	fc_packet_t	*fpkt = xch->xch_fpkt;
1040 	fcoe_frame_t	*frm;
1041 	fcp_cmd_t	*fcp_cmd_iu = (fcp_cmd_t *)(void *)fpkt->pkt_cmd;
1042 	int		 offset = 0;
1043 
1044 	ASSERT((fpkt->pkt_cmdlen % 4) == 0);
1045 	frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
1046 	    fpkt->pkt_cmdlen + FCFH_SIZE, NULL);
1047 	if (!frm) {
1048 		ASSERT(0);
1049 	} else {
1050 		fcoei_init_ifm(frm, xch);
1051 		bzero(frm->frm_payload, fpkt->pkt_cmdlen);
1052 	}
1053 
1054 	/*
1055 	 * This will affect timing check
1056 	 */
1057 	xch->xch_cnt = xch->xch_ss->ss_sol_cnt;
1058 	atomic_add_32(xch->xch_cnt, 1);
1059 
1060 	/*
1061 	 * Set exchange residual bytes
1062 	 */
1063 	xch->xch_resid = (int)fpkt->pkt_datalen;
1064 
1065 	/*
1066 	 * Fill FCP command IU
1067 	 *
1068 	 * fcp_ent_addr
1069 	 */
1070 	FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_0,
1071 	    frm->frm_payload + offset);
1072 	offset += 2;
1073 	FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_1,
1074 	    frm->frm_payload + offset);
1075 	offset += 2;
1076 	FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_2,
1077 	    frm->frm_payload + offset);
1078 	offset += 2;
1079 	FCOE_V2B_2(fcp_cmd_iu->fcp_ent_addr.ent_addr_3,
1080 	    frm->frm_payload + offset);
1081 	/*
1082 	 * fcp_cntl
1083 	 */
1084 	offset = offsetof(fcp_cmd_t, fcp_cntl);
1085 	frm->frm_payload[offset] = 0;
1086 
1087 	offset += 1;
1088 	frm->frm_payload[offset] = fcp_cmd_iu->fcp_cntl.cntl_qtype & 0x07;
1089 	offset += 1;
1090 	frm->frm_payload[offset] =
1091 	    (fcp_cmd_iu->fcp_cntl.cntl_kill_tsk * BIT_7) |
1092 	    (fcp_cmd_iu->fcp_cntl.cntl_clr_aca * BIT_6) |
1093 	    (fcp_cmd_iu->fcp_cntl.cntl_reset_tgt * BIT_5) |
1094 	    (fcp_cmd_iu->fcp_cntl.cntl_reset_lun * BIT_4) |
1095 	    (fcp_cmd_iu->fcp_cntl.cntl_clr_tsk * BIT_2) |
1096 	    (fcp_cmd_iu->fcp_cntl.cntl_abort_tsk * BIT_1);
1097 	offset += 1;
1098 	frm->frm_payload[offset] =
1099 	    (fcp_cmd_iu->fcp_cntl.cntl_read_data * BIT_1) |
1100 	    (fcp_cmd_iu->fcp_cntl.cntl_write_data * BIT_0);
1101 	/*
1102 	 * fcp_cdb
1103 	 */
1104 	offset = offsetof(fcp_cmd_t, fcp_cdb);
1105 	bcopy(fcp_cmd_iu->fcp_cdb, frm->frm_payload + offset, FCP_CDB_SIZE);
1106 	/*
1107 	 * fcp_data_len
1108 	 */
1109 	offset += FCP_CDB_SIZE;
1110 	FCOE_V2B_4(fcp_cmd_iu->fcp_data_len, frm->frm_payload + offset);
1111 
1112 	/*
1113 	 * FC frame header
1114 	 */
1115 	FRM2IFM(frm)->ifm_rctl = fpkt->pkt_cmd_fhdr.r_ctl;
1116 
1117 	FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
1118 	FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
1119 	FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
1120 	FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
1121 	FFM_F_CTL(0x290000, frm);
1122 	FFM_OXID(xch->xch_oxid, frm);
1123 	FFM_RXID(xch->xch_rxid, frm);
1124 
1125 	xch->xch_ss->ss_eport->eport_tx_frame(frm);
1126 }
1127 
1128 /*
1129  * fcoei_initiate_els_req
1130  *	Initiate ELS request
1131  *
1132  * Input:
1133  *	xch = the exchange that will be initiated
1134  *
1135  * Returns:
1136  *	N/A
1137  *
1138  * Comments:
1139  *	N/A
1140  */
1141 static void
1142 fcoei_initiate_els_req(fcoei_exchange_t *xch)
1143 {
1144 	fc_packet_t	*fpkt = xch->xch_fpkt;
1145 	fcoe_frame_t	*frm;
1146 	ls_code_t	*els_code;
1147 
1148 	ASSERT((fpkt->pkt_cmdlen % 4) == 0);
1149 	frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
1150 	    fpkt->pkt_cmdlen + FCFH_SIZE, NULL);
1151 	if (!frm) {
1152 		ASSERT(0);
1153 	} else {
1154 		fcoei_init_ifm(frm, xch);
1155 		bzero(frm->frm_payload, fpkt->pkt_cmdlen);
1156 	}
1157 
1158 	/*
1159 	 * This will affect timing check
1160 	 */
1161 	xch->xch_cnt = xch->xch_ss->ss_sol_cnt;
1162 	atomic_add_32(xch->xch_cnt, 1);
1163 
1164 	els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
1165 	switch (els_code->ls_code) {
1166 	case LA_ELS_FLOGI:
1167 		/*
1168 		 * For FLOGI, we expect response within E_D_TOV
1169 		 */
1170 		xch->xch_start_tick = ddi_get_lbolt();
1171 		xch->xch_end_tick = xch->xch_start_tick +
1172 		    FCOE_SEC2TICK(2);
1173 		xch->xch_ss->ss_flags &= ~SS_FLAG_FLOGI_FAILED;
1174 		/* FALLTHROUGH */
1175 
1176 	case LA_ELS_PLOGI:
1177 		fcoei_fill_els_logi_cmd(fpkt, frm);
1178 		break;
1179 
1180 	case LA_ELS_PRLI:
1181 		fcoei_fill_els_prli_cmd(fpkt, frm);
1182 		break;
1183 
1184 	case LA_ELS_SCR:
1185 		fcoei_fill_els_scr_cmd(fpkt, frm);
1186 		break;
1187 
1188 	case LA_ELS_LINIT:
1189 		fcoei_fill_els_linit_cmd(fpkt, frm);
1190 		break;
1191 
1192 	case LA_ELS_ADISC:
1193 		fcoei_fill_els_adisc_cmd(fpkt, frm);
1194 		break;
1195 
1196 	case LA_ELS_LOGO:
1197 		/*
1198 		 * For LOGO, we expect response within E_D_TOV
1199 		 */
1200 		xch->xch_start_tick = ddi_get_lbolt();
1201 		xch->xch_end_tick = xch->xch_start_tick +
1202 		    FCOE_SEC2TICK(2);
1203 		fcoei_fill_els_logo_cmd(fpkt, frm);
1204 		break;
1205 	case LA_ELS_RLS:
1206 		fcoei_fill_els_rls_cmd(fpkt, frm);
1207 		break;
1208 	case LA_ELS_RNID:
1209 		fcoei_fill_els_rnid_cmd(fpkt, frm);
1210 		break;
1211 	default:
1212 		fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
1213 		    FC_REASON_CMD_UNSUPPORTED);
1214 		return;
1215 	}
1216 
1217 	/*
1218 	 * set ifm_rtcl
1219 	 */
1220 	FRM2IFM(frm)->ifm_rctl = fpkt->pkt_cmd_fhdr.r_ctl;
1221 
1222 	/*
1223 	 * FCPH
1224 	 */
1225 	FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
1226 	FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
1227 	FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
1228 	FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
1229 	FFM_F_CTL(0x290000, frm);
1230 	FFM_OXID(xch->xch_oxid, frm);
1231 	FFM_RXID(xch->xch_rxid, frm);
1232 
1233 	xch->xch_ss->ss_eport->eport_tx_frame(frm);
1234 }
1235 
1236 /*
1237  * fcoei_initiate_els_resp
1238  *	Originate ELS response
1239  *
1240  * Input:
1241  *	xch = the associated exchange
1242  *
1243  * Returns:
1244  *	N/A
1245  *
1246  * Comments:
1247  *	N/A
1248  */
1249 static void
1250 fcoei_initiate_els_resp(fcoei_exchange_t *xch)
1251 {
1252 	fc_packet_t	*fpkt = xch->xch_fpkt;
1253 	fcoe_frame_t	*frm;
1254 
1255 	ASSERT((fpkt->pkt_cmdlen % 4) == 0);
1256 	frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport,
1257 	    fpkt->pkt_cmdlen + FCFH_SIZE, NULL);
1258 	if (!frm) {
1259 		ASSERT(0);
1260 	} else {
1261 		fcoei_init_ifm(frm, xch);
1262 		bzero(frm->frm_payload, fpkt->pkt_cmdlen);
1263 	}
1264 
1265 	/*
1266 	 * This will affect timing check
1267 	 */
1268 	xch->xch_cnt = xch->xch_ss->ss_unsol_cnt;
1269 	atomic_add_32(xch->xch_cnt, 1);
1270 
1271 	/*
1272 	 * Set ifm_rctl
1273 	 */
1274 	FRM2IFM(frm)->ifm_rctl = fpkt->pkt_cmd_fhdr.r_ctl;
1275 
1276 	/*
1277 	 * FCPH
1278 	 */
1279 	FFM_R_CTL(fpkt->pkt_cmd_fhdr.r_ctl, frm);
1280 	FFM_D_ID(fpkt->pkt_cmd_fhdr.d_id, frm);
1281 	FFM_S_ID(fpkt->pkt_cmd_fhdr.s_id, frm);
1282 	FFM_TYPE(fpkt->pkt_cmd_fhdr.type, frm);
1283 	FFM_F_CTL(0x980000, frm);
1284 	FFM_OXID(xch->xch_oxid, frm);
1285 	FFM_RXID(xch->xch_rxid, frm);
1286 
1287 	switch (((uint8_t *)&fpkt->pkt_fca_rsvd1)[0]) {
1288 	case LA_ELS_FLOGI:
1289 		fcoei_fill_els_logi_resp(fpkt, frm);
1290 		break;
1291 
1292 	case LA_ELS_PLOGI:
1293 		if (FRM2SS(frm)->ss_eport->eport_flags &
1294 		    EPORT_FLAG_IS_DIRECT_P2P) {
1295 			FRM2SS(frm)->ss_p2p_info.fca_d_id = FRM_S_ID(frm);
1296 			FRM2SS(frm)->ss_p2p_info.d_id = FRM_D_ID(frm);
1297 		}
1298 
1299 		fcoei_fill_els_logi_resp(fpkt, frm);
1300 		break;
1301 
1302 	case LA_ELS_PRLI:
1303 		fcoei_fill_els_prli_resp(fpkt, frm);
1304 		break;
1305 
1306 	case LA_ELS_ADISC:
1307 		fcoei_fill_els_adisc_resp(fpkt, frm);
1308 		break;
1309 
1310 	case LA_ELS_LOGO:
1311 		fcoei_fill_els_logo_resp(fpkt, frm);
1312 		break;
1313 	case LA_ELS_RSCN:
1314 		fcoei_fill_els_acc_resp(fpkt, frm);
1315 		break;
1316 
1317 	default:
1318 		fcoei_complete_xch(xch, frm, FC_PKT_FAILURE,
1319 		    FC_REASON_CMD_UNSUPPORTED);
1320 		return;
1321 	}
1322 
1323 	xch->xch_ss->ss_eport->eport_tx_frame(frm);
1324 }
1325 
1326 /*
1327  * fcoei_fill_els_logi_cmd
1328  *	Fill SCR (state change register) command frame
1329  *
1330  * Input:
1331  *	fpkt = LV fc_packet
1332  *	frm = Unsolicited frame containing LOGI response
1333  *
1334  * Returns:
1335  *	N/A
1336  *
1337  * Comments:
1338  *	N/A
1339  */
1340 static void
1341 fcoei_fill_els_logi_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1342 {
1343 	la_els_logi_t	*els_logi = (la_els_logi_t *)(void *)fpkt->pkt_cmd;
1344 	int		 offset;
1345 
1346 	/*
1347 	 * fill ls_code
1348 	 */
1349 	offset = 0;
1350 	FCOE_V2B_1(els_logi->ls_code.ls_code, FPLD + offset);
1351 
1352 	/*
1353 	 * fill common service parameters
1354 	 */
1355 	offset = 4;
1356 	FCOE_V2B_2(els_logi->common_service.fcph_version, FPLD + offset);
1357 
1358 	offset = 6;
1359 	FCOE_V2B_2(els_logi->common_service.btob_credit, FPLD + offset);
1360 
1361 	offset = 8;
1362 	FCOE_V2B_2(els_logi->common_service.cmn_features, FPLD + offset);
1363 
1364 	offset = 10;
1365 	FCOE_V2B_2(els_logi->common_service.rx_bufsize, FPLD + offset);
1366 
1367 	offset = 12;
1368 	FCOE_V2B_2(els_logi->common_service.conc_sequences, FPLD + offset);
1369 
1370 	offset = 14;
1371 	FCOE_V2B_2(els_logi->common_service.relative_offset, FPLD + offset);
1372 
1373 	offset = 16;
1374 	FCOE_V2B_4(els_logi->common_service.e_d_tov, FPLD + offset);
1375 
1376 	/*
1377 	 * port/node wwn
1378 	 */
1379 	offset = 20;
1380 	bcopy(&els_logi->nport_ww_name, FPLD + offset, 8);
1381 
1382 	offset = 28;
1383 	bcopy(&els_logi->node_ww_name, FPLD + offset, 8);
1384 
1385 	/*
1386 	 * class_3
1387 	 */
1388 	offset = 68;
1389 	FCOE_V2B_2(els_logi->class_3.class_opt, FPLD + offset);
1390 
1391 	offset = 70;
1392 	FCOE_V2B_2(els_logi->class_3.initiator_ctl, FPLD + offset);
1393 
1394 	offset = 72;
1395 	FCOE_V2B_2(els_logi->class_3.recipient_ctl, FPLD + offset);
1396 
1397 	offset = 74;
1398 	FCOE_V2B_2(els_logi->class_3.rcv_size, FPLD + offset);
1399 
1400 	offset = 76;
1401 	FCOE_V2B_2(els_logi->class_3.conc_sequences, FPLD + offset);
1402 
1403 	offset = 78;
1404 	FCOE_V2B_2(els_logi->class_3.n_port_e_to_e_credit, FPLD + offset);
1405 
1406 	offset = 80;
1407 	FCOE_V2B_2(els_logi->class_3.open_seq_per_xchng, FPLD + offset);
1408 	/*
1409 	 * needn't touch other fields
1410 	 */
1411 }
1412 
1413 /*
1414  * fcoei_fill_prli_cmd
1415  *	Fill PRLI command frame
1416  *
1417  * Input:
1418  *	fpkt = LV fc_packet
1419  *	frm = Unsolicited frame containing PRLI response
1420  *
1421  * Returns:
1422  *	N/A
1423  *
1424  * Comments:
1425  *	N/A
1426  */
1427 static void
1428 fcoei_fill_els_prli_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1429 {
1430 	int		 offset	    = 0;
1431 	la_els_prli_t	*els_prli   = (la_els_prli_t *)(void *)fpkt->pkt_cmd;
1432 	struct fcp_prli *fcp_spp    =
1433 	    (struct fcp_prli *)(void *)els_prli->service_params;
1434 
1435 	/*
1436 	 * fill basic PRLI fields
1437 	 */
1438 	offset = 0;
1439 	FCOE_V2B_1(els_prli->ls_code, FPLD + offset);
1440 
1441 	offset = 1;
1442 	FCOE_V2B_1(els_prli->page_length, FPLD + offset);
1443 
1444 	offset = 2;
1445 	FCOE_V2B_2(els_prli->payload_length, FPLD + offset);
1446 
1447 	/*
1448 	 * fill FCP service parameters page
1449 	 */
1450 	offset = 4;
1451 	FCOE_V2B_1(fcp_spp->type, FPLD + offset);
1452 
1453 	/*
1454 	 * PRLI flags, only 3 bits are valid
1455 	 */
1456 	offset = 6;
1457 	FCOE_V2B_2((fcp_spp->orig_process_assoc_valid * BIT_15) |
1458 	    (fcp_spp->resp_process_assoc_valid * BIT_14) |
1459 	    (fcp_spp->establish_image_pair * BIT_13), FPLD + offset);
1460 
1461 	/*
1462 	 * process associator
1463 	 */
1464 	offset = 8;
1465 	FCOE_V2B_4(fcp_spp->orig_process_associator, FPLD + offset);
1466 
1467 	offset = 12;
1468 	FCOE_V2B_4(fcp_spp->resp_process_associator, FPLD + offset);
1469 
1470 	/*
1471 	 * FC-4 type
1472 	 */
1473 	offset = 16;
1474 	FCOE_V2B_4((fcp_spp->retry * BIT_8) |
1475 	    (fcp_spp->confirmed_compl_allowed * BIT_7) |
1476 	    (fcp_spp->data_overlay_allowed * BIT_6) |
1477 	    (fcp_spp->initiator_fn * BIT_5) | (fcp_spp->target_fn * BIT_4) |
1478 	    (fcp_spp->read_xfer_rdy_disabled * BIT_1) |
1479 	    (fcp_spp->write_xfer_rdy_disabled * BIT_0), FPLD + offset);
1480 }
1481 
1482 /*
1483  * fcoei_fill_els_scr_cmd
1484  *	Fill SCR (state change register) command frame
1485  *
1486  * Input:
1487  *	fpkt = LV fc_packet
1488  *	frm = Unsolicited frame containing SCR command
1489  *
1490  * Returns:
1491  *	N/A
1492  *
1493  * Comments:
1494  *	N/A
1495  */
1496 static void
1497 fcoei_fill_els_scr_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1498 {
1499 	fc_scr_req_t	*els_scr = (fc_scr_req_t *)(void *)fpkt->pkt_cmd;
1500 	int		 offset;
1501 
1502 	offset = 0;
1503 	FCOE_V2B_1(els_scr->ls_code.ls_code, FPLD + offset);
1504 
1505 	offset = 7;
1506 	FCOE_V2B_1(els_scr->scr_func, FPLD + offset);
1507 }
1508 
1509 /*
1510  * fcoei_fill_els_adisc_cmd
1511  *	Fill ADISC command frame
1512  *
1513  * Input:
1514  *	fpkt = LV fc_packet
1515  *	frm = Unsolicited frame containing ADISC command
1516  *
1517  * Returns:
1518  *	N/A
1519  *
1520  * Comments:
1521  *	N/A
1522  */
1523 static void
1524 fcoei_fill_els_adisc_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1525 {
1526 	la_els_adisc_t	*els_adisc = (la_els_adisc_t *)(void *)fpkt->pkt_cmd;
1527 	int		 offset;
1528 
1529 	offset = 0;
1530 	FCOE_V2B_1(els_adisc->ls_code.ls_code, FPLD + offset);
1531 
1532 	offset = 5;
1533 	FCOE_V2B_3(els_adisc->hard_addr.hard_addr, FPLD + offset);
1534 
1535 	offset = 8;
1536 	bcopy(&els_adisc->port_wwn, FPLD + offset, 8);
1537 
1538 	offset = 16;
1539 	bcopy(&els_adisc->node_wwn, FPLD + offset, 8);
1540 
1541 	offset = 25;
1542 	FCOE_V2B_3(els_adisc->nport_id.port_id, FPLD + offset);
1543 }
1544 
1545 /*
1546  * fcoei_fill_els_linit_cmd
1547  *	Fill LINIT command frame
1548  *
1549  * Input:
1550  *	fpkt = LV fc_packet
1551  *	frm = Unsolicited frame containing LINIT command
1552  *
1553  * Returns:
1554  *	N/A
1555  *
1556  * Comments:
1557  *	N/A
1558  */
1559 static void
1560 fcoei_fill_els_linit_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1561 {
1562 	ASSERT(fpkt && frm);
1563 }
1564 
1565 /*
1566  * fcoei_fill_els_logo_cmd
1567  *	Fill LOGO command frame
1568  *
1569  * Input:
1570  *	fpkt = LV fc_packet
1571  *	frm = Unsolicited frame containing LOGO command
1572  *
1573  * Returns:
1574  *	N/A
1575  *
1576  * Comments:
1577  *	N/A
1578  */
1579 static void
1580 fcoei_fill_els_logo_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1581 {
1582 	la_els_logo_t	*els_logo   = (la_els_logo_t *)(void *)fpkt->pkt_cmd;
1583 	int		 offset;
1584 
1585 	offset = 0;
1586 	FCOE_V2B_1(els_logo->ls_code.ls_code, FPLD + offset);
1587 
1588 	offset = 5;
1589 	FCOE_V2B_3(els_logo->nport_id.port_id, FPLD + offset);
1590 
1591 	offset = 8;
1592 	bcopy(&els_logo->nport_ww_name, FPLD + offset, 8);
1593 }
1594 
1595 static void
1596 fcoei_fill_els_rls_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1597 {
1598 	la_els_rls_t	*els_rls = (la_els_rls_t *)(void *)fpkt->pkt_cmd;
1599 	int		offset;
1600 
1601 	offset = 0;
1602 	FCOE_V2B_1(els_rls->ls_code.ls_code, FPLD + offset);
1603 
1604 	offset = 5;
1605 	FCOE_V2B_3(els_rls->rls_portid.port_id, FPLD + offset);
1606 }
1607 
1608 static void
1609 fcoei_fill_els_rnid_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm)
1610 {
1611 	la_els_rnid_t *els_rnid = (la_els_rnid_t *)(void *)fpkt->pkt_cmd;
1612 	int		offset;
1613 
1614 	offset = 0;
1615 	FCOE_V2B_1(els_rnid->ls_code.ls_code, FPLD + offset);
1616 
1617 	offset = 4;
1618 	bcopy(&els_rnid->data_format, FPLD + offset, 1);
1619 }
1620 /*
1621  * fcoei_fill_els_acc_resp
1622  *	Fill ELS ACC response frame
1623  *
1624  * Input:
1625  *	fpkt = LV fc_packet
1626  *	frm = Unsolicited frame containing ELS ACC response
1627  *
1628  * Returns:
1629  *	N/A
1630  *
1631  * Comments:
1632  *	N/A
1633  */
1634 static void
1635 fcoei_fill_els_acc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1636 {
1637 	ls_code_t	*els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
1638 	int		 offset;
1639 
1640 	offset = 0;
1641 	FCOE_V2B_1(els_code->ls_code, FPLD + offset);
1642 
1643 	offset = 1;
1644 	FCOE_V2B_3(els_code->mbz, FPLD + offset);
1645 }
1646 
1647 /*
1648  * fcoei_fill_els_rjt_resp
1649  *	Fill ELS RJT response frame
1650  *
1651  * Input:
1652  *	fpkt = LV fc_packet
1653  *	frm = Unsolicited frame containg ELS RJT response
1654  *
1655  * Returns:
1656  *	N/A
1657  *
1658  * Comments:
1659  *	N/A
1660  */
1661 static void
1662 fcoei_fill_els_rjt_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1663 {
1664 	la_els_rjt_t	*els_rjt = (la_els_rjt_t *)(void *)fpkt->pkt_cmd;
1665 	int		 offset;
1666 
1667 	offset = 0; /* reset ls code */
1668 	FCOE_V2B_1(els_rjt->ls_code.ls_code, FPLD + offset);
1669 
1670 	offset = 5; /* reason code */
1671 	FCOE_V2B_1(els_rjt->action, FPLD + offset);
1672 
1673 	offset = 6; /* reason explanation */
1674 	FCOE_V2B_1(els_rjt->reason, FPLD + offset);
1675 
1676 	offset = 7; /* vendor unique */
1677 	FCOE_V2B_1(els_rjt->vu, FPLD + offset);
1678 }
1679 
1680 /*
1681  * fcoei_fill_els_adisc_resp
1682  *	Fill ADISC response frame
1683  *
1684  * Input:
1685  *	fpkt = LV fc_packet
1686  *	frm = Unsolicited frame containing ADISC response
1687  *
1688  * Returns:
1689  *	N/A
1690  *
1691  * Comments:
1692  *	N/A
1693  */
1694 static void
1695 fcoei_fill_els_adisc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1696 {
1697 	la_els_adisc_t	*els_adisc = (la_els_adisc_t *)(void *)fpkt->pkt_cmd;
1698 	int		 offset;
1699 
1700 	if (els_adisc->ls_code.ls_code == LA_ELS_RJT) {
1701 		fcoei_fill_els_rjt_resp(fpkt, frm);
1702 	} else {
1703 		offset = 0;
1704 		FCOE_V2B_1(els_adisc->ls_code.ls_code, FPLD + offset);
1705 
1706 		offset = 5;
1707 		FCOE_V2B_3(els_adisc->hard_addr.hard_addr, FPLD + offset);
1708 
1709 		offset = 8;
1710 		bcopy(&els_adisc->port_wwn, FPLD + offset, FC_WWN_SIZE);
1711 
1712 		offset = 16;
1713 		bcopy(&els_adisc->node_wwn, FPLD + offset, FC_WWN_SIZE);
1714 
1715 		offset = 25;
1716 		FCOE_V2B_3(els_adisc->nport_id.port_id, FPLD + offset);
1717 	}
1718 }
1719 
1720 /*
1721  * fcoei_fill_els_logi_resp
1722  *	Fill FLOGI/PLOGI response frame
1723  *
1724  * Input:
1725  *	fpkt = LV fc_packet
1726  *	frm = Unsolicited frame containing LOGI response
1727  *
1728  * Returns:
1729  *	N/A
1730  *
1731  * Comments:
1732  *	N/A
1733  */
1734 static void
1735 fcoei_fill_els_logi_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1736 {
1737 	ls_code_t	*els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
1738 
1739 	if (els_code->ls_code == LA_ELS_RJT) {
1740 		fcoei_fill_els_rjt_resp(fpkt, frm);
1741 	} else {
1742 		fcoei_fill_els_logi_cmd(fpkt, frm);
1743 	}
1744 }
1745 
1746 /*
1747  * fcoei_fill_els_prli_resp
1748  *	Fill PRLI response frame
1749  *
1750  * Input:
1751  *	fpkt = LV fc_packet
1752  *	frm = Unsolicited frame containing PRLI response
1753  *
1754  * Returns:
1755  *	N/A
1756  *
1757  * Comments:
1758  *	N/A
1759  */
1760 static void
1761 fcoei_fill_els_prli_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1762 {
1763 	ls_code_t	*els_code = (ls_code_t *)(void *)fpkt->pkt_cmd;
1764 
1765 	if (els_code->ls_code == LA_ELS_RJT) {
1766 		fcoei_fill_els_rjt_resp(fpkt, frm);
1767 	} else {
1768 		fcoei_fill_els_prli_cmd(fpkt, frm);
1769 	}
1770 }
1771 
1772 /*
1773  * fcoei_fill_els_logo_resp
1774  *	Fill LOGO response frame
1775  *
1776  * Input:
1777  *	fpkt = LV fc_packet
1778  *	frm = Unsolicited frame containing LOGO response
1779  *
1780  * Returns:
1781  *	N/A
1782  *
1783  * Comments:
1784  *	N/A
1785  */
1786 static void
1787 fcoei_fill_els_logo_resp(fc_packet_t *fpkt, fcoe_frame_t *frm)
1788 {
1789 	ls_code_t	*els_code   = (ls_code_t *)(void *)fpkt->pkt_cmd;
1790 
1791 	if (els_code->ls_code == LA_ELS_RJT) {
1792 		fcoei_fill_els_rjt_resp(fpkt, frm);
1793 	} else {
1794 		fcoei_fill_els_acc_resp(fpkt, frm);
1795 	}
1796 }
1797 
1798 /*
1799  * fcoei_logo_peer
1800  *	Send LOGO to the peer to emulate link offline event
1801  *
1802  * Input:
1803  *	arg - fcoei soft state set in fcoei_bind_port
1804  *
1805  * Returns:
1806  *	N/A
1807  *
1808  * Comments:
1809  *	N/A
1810  */
1811 static void
1812 fcoei_logo_peer(void *arg)
1813 {
1814 	fcoei_soft_state_t	*ss = (fcoei_soft_state_t *)arg;
1815 	fc_packet_t		*fpkt;
1816 	fcoei_exchange_t	*xch;
1817 	la_els_logo_t		*els_logo;
1818 
1819 	/*
1820 	 * Allocate space for exchange
1821 	 */
1822 	xch = kmem_zalloc(sizeof (*xch), KM_SLEEP);
1823 
1824 	/*
1825 	 * Allocate space for fc_packet
1826 	 */
1827 	fpkt = kmem_zalloc(sizeof (fc_packet_t), KM_SLEEP);
1828 	fpkt->pkt_cmdlen = 20;
1829 	fpkt->pkt_cmd = kmem_zalloc(fpkt->pkt_cmdlen, KM_SLEEP);
1830 	fpkt->pkt_rsplen = 20;
1831 	fpkt->pkt_resp = kmem_zalloc(fpkt->pkt_rsplen, KM_SLEEP);
1832 
1833 	/*
1834 	 * Link them together
1835 	 */
1836 	fpkt->pkt_fca_private = xch;
1837 	(void) fcoei_init_pkt(ss, fpkt, 0);
1838 
1839 	/*
1840 	 * Initialize FC frame header
1841 	 */
1842 	if (ss->ss_eport->eport_flags & EPORT_FLAG_IS_DIRECT_P2P) {
1843 		fpkt->pkt_cmd_fhdr.d_id = ss->ss_p2p_info.d_id;
1844 	} else {
1845 		fpkt->pkt_cmd_fhdr.d_id = 0xFFFFFE;
1846 	}
1847 
1848 	fpkt->pkt_cmd_fhdr.s_id = ss->ss_p2p_info.fca_d_id;
1849 	fpkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
1850 	fpkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
1851 	fpkt->pkt_cmd_fhdr.f_ctl = 0x290000;
1852 	fpkt->pkt_timeout = 1;
1853 
1854 	/*
1855 	 * Initialize LOGO payload
1856 	 */
1857 	els_logo = (la_els_logo_t *)(void *)fpkt->pkt_cmd;
1858 	els_logo->ls_code.ls_code = LA_ELS_LOGO;
1859 	els_logo->nport_id.port_id = ss->ss_p2p_info.fca_d_id;
1860 	bcopy(ss->ss_eport->eport_portwwn, &els_logo->nport_ww_name, 8);
1861 
1862 	/*
1863 	 * Set the completion function
1864 	 */
1865 	fpkt->pkt_comp = fcoei_fpkt_comp;
1866 	if (fcoei_transport(ss, fpkt) != FC_SUCCESS) {
1867 		FCOEI_LOG(__FUNCTION__, "fcoei_transport LOGO failed");
1868 		fcoei_fpkt_comp(fpkt);
1869 	}
1870 }
1871 
1872 /*
1873  * fcoei_fpkt_comp
1874  *	internal exchange completion
1875  *
1876  * Input:
1877  *	fpkt - fc_packet_t to be completed
1878  *
1879  * Returns:
1880  *	N/A
1881  *
1882  * Comments:
1883  *
1884  */
1885 static void
1886 fcoei_fpkt_comp(fc_packet_t *fpkt)
1887 {
1888 	fcoei_exchange_t	*xch = FPKT2XCH(fpkt);
1889 
1890 	FCOEI_LOG(__FUNCTION__, "internal exchange is completed: %p", xch);
1891 
1892 	(void) fcoei_un_init_pkt(xch->xch_ss, xch->xch_fpkt);
1893 	kmem_free(xch->xch_fpkt->pkt_cmd, xch->xch_fpkt->pkt_cmdlen);
1894 	kmem_free(xch->xch_fpkt->pkt_resp, xch->xch_fpkt->pkt_rsplen);
1895 	kmem_free(xch->xch_fpkt, sizeof (fc_packet_t));
1896 	kmem_free(xch, sizeof (fcoei_exchange_t));
1897 }
1898 
1899 /*
1900  * fcoei_xch_abort
1901  *	Prepare to abort the exchange
1902  *
1903  * Input:
1904  *	key = oxid/rxid of the exchange
1905  *	val = the exchange
1906  *	arg = the soft state
1907  *
1908  * Returns:
1909  *	MH_WALK_CONTINUE = continue to walk
1910  *
1911  * Comments:
1912  *	N/A
1913  */
1914 static uint32_t
1915 fcoei_xch_abort(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
1916 {
1917 	fcoei_exchange_t	*xch = (fcoei_exchange_t *)val;
1918 
1919 	ASSERT(arg == xch->xch_ss);
1920 	ASSERT(CMHK(key) != 0xFFFF);
1921 	xch->xch_flags |= XCH_FLAG_ABORT;
1922 	xch->xch_fpkt->pkt_state = FC_PKT_LOCAL_RJT;
1923 	xch->xch_fpkt->pkt_reason = FC_REASON_OFFLINE;
1924 	list_insert_tail(&xch->xch_ss->ss_comp_xch_list, xch);
1925 	return (MH_WALK_CONTINUE);
1926 }
1927 
1928 /*
1929  * fcoei_init_fcatran_vectors
1930  *	Initialize fc_fca_tran vectors that are defined in this file
1931  *
1932  * Input:
1933  *	fcatran - fc_fca_tran of the soft state
1934  *
1935  * Returns:
1936  *	N/A
1937  *
1938  * Comments:
1939  *	N/A
1940  */
1941 void
1942 fcoei_init_fcatran_vectors(fc_fca_tran_t *fcatran)
1943 {
1944 	fcatran->fca_bind_port	 = fcoei_bind_port;
1945 	fcatran->fca_unbind_port = fcoei_unbind_port;
1946 	fcatran->fca_init_pkt	 = fcoei_init_pkt;
1947 	fcatran->fca_un_init_pkt = fcoei_un_init_pkt;
1948 	fcatran->fca_els_send	 = fcoei_els_send;
1949 	fcatran->fca_get_cap	 = fcoei_get_cap;
1950 	fcatran->fca_set_cap	 = fcoei_set_cap;
1951 	fcatran->fca_getmap	 = fcoei_getmap;
1952 	fcatran->fca_transport	 = fcoei_transport;
1953 	fcatran->fca_ub_alloc	 = fcoei_ub_alloc;
1954 	fcatran->fca_ub_free	 = fcoei_ub_free;
1955 	fcatran->fca_ub_release	 = fcoei_ub_release;
1956 	fcatran->fca_abort	 = fcoei_abort;
1957 	fcatran->fca_reset	 = fcoei_reset;
1958 	fcatran->fca_port_manage = fcoei_port_manage;
1959 	fcatran->fca_get_device	 = fcoei_get_device;
1960 	fcatran->fca_notify	 = fcoei_notify;
1961 }
1962 
1963 /*
1964  * fcoei_process_event_reset
1965  *	link reset phase II
1966  *
1967  * Input:
1968  *	arg - fcoei soft state set in fcoei_bind_port
1969  *
1970  * Returns:
1971  *	N/A
1972  *
1973  * Comments:
1974  *
1975  */
1976 void
1977 fcoei_process_event_reset(fcoei_event_t *ae)
1978 {
1979 	fcoei_soft_state_t	*ss = (fcoei_soft_state_t *)ae->ae_obj;
1980 
1981 	ASSERT(!MUTEX_HELD(&ss->ss_watchdog_mutex));
1982 	kmem_free(ae, sizeof (*ae));
1983 
1984 	mod_hash_walk(ss->ss_sol_oxid_hash, fcoei_xch_abort, ss);
1985 	mod_hash_walk(ss->ss_unsol_rxid_hash, fcoei_xch_abort, ss);
1986 	fcoei_handle_comp_xch_list(ss);
1987 
1988 	/*
1989 	 * Notify LV that the link is up now
1990 	 */
1991 	ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, 0);
1992 }
1993 
1994 /*
1995  * fcoei_process_event_exchange
1996  *	Process exchange in the single thread context
1997  *
1998  * Input:
1999  *	ae = the exchange event
2000  *
2001  * Returns:
2002  *	N/A
2003  *
2004  * Comments:
2005  *	N/A
2006  */
2007 void
2008 fcoei_process_event_exchange(fcoei_event_t *ae)
2009 {
2010 	fcoei_exchange_t	*xch  = (fcoei_exchange_t *)ae->ae_obj;
2011 	fcoei_exchange_t	*xch_tmp;
2012 	fc_packet_t		*fpkt = xch->xch_fpkt;
2013 
2014 	/*
2015 	 * These 4 elements need reset, pkt_state & pkt_reason will be set
2016 	 */
2017 	fpkt->pkt_action = 0;
2018 	fpkt->pkt_expln = 0;
2019 	fpkt->pkt_data_resid = 0;
2020 	fpkt->pkt_resp_resid = 0;
2021 
2022 	/*
2023 	 * port state sanity checking
2024 	 */
2025 	if ((xch->xch_ss->ss_link_state != FC_STATE_ONLINE) ||
2026 	    xch->xch_ss->ss_port_event_counter) {
2027 		/*
2028 		 * LV will retry it after one second
2029 		 */
2030 		fcoei_complete_xch(xch, NULL, FC_PKT_PORT_OFFLINE,
2031 		    FC_REASON_OFFLINE);
2032 		return;
2033 	}
2034 
2035 	switch (fpkt->pkt_cmd_fhdr.r_ctl) {
2036 	case R_CTL_COMMAND:
2037 		FCOEI_INIT_SOL_ID_HASH(xch, xch_tmp);
2038 		fcoei_initiate_fcp_cmd(xch);
2039 		break;
2040 
2041 	case R_CTL_ELS_REQ:
2042 		FCOEI_INIT_SOL_ID_HASH(xch, xch_tmp);
2043 		fcoei_initiate_els_req(xch);
2044 		break;
2045 
2046 	case R_CTL_UNSOL_CONTROL:
2047 		FCOEI_INIT_SOL_ID_HASH(xch, xch_tmp);
2048 		fcoei_initiate_ct_req(xch);
2049 		break;
2050 
2051 	case R_CTL_ELS_RSP:
2052 		/*
2053 		 * Caution: in leadville, it still uses pkt_cmd_fhdr
2054 		 * oxid & rxid have been decided when we get unsolicited frames.
2055 		 * pkt_cmd_fhdr has contained the right oxid and rxid now.
2056 		 */
2057 		FCOEI_INIT_UNSOL_ID_HASH(xch);
2058 		fcoei_initiate_els_resp(xch);
2059 		break;
2060 
2061 	default:
2062 		fcoei_complete_xch(xch, NULL, FC_PKT_FAILURE,
2063 		    FC_REASON_CMD_UNSUPPORTED);
2064 	}
2065 }
2066