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