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 */
71static void fcoei_port_enabled(void *arg);
72
73static void fcoei_populate_hba_fru_details(fcoei_soft_state_t *ss,
74    fc_fca_port_info_t *port_info);
75
76static void fcoei_initiate_ct_req(fcoei_exchange_t *xch);
77static void fcoei_initiate_fcp_cmd(fcoei_exchange_t *xch);
78static void fcoei_initiate_els_req(fcoei_exchange_t *xch);
79static void fcoei_initiate_els_resp(fcoei_exchange_t *xch);
80
81static void fcoei_fill_els_logi_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
82static void fcoei_fill_els_prli_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
83static void fcoei_fill_els_logo_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
84static void fcoei_fill_els_scr_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
85static void fcoei_fill_els_adisc_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
86static void fcoei_fill_els_linit_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
87static void fcoei_fill_els_rls_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
88static void fcoei_fill_els_rnid_cmd(fc_packet_t *fpkt, fcoe_frame_t *frm);
89
90static void fcoei_fill_els_acc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
91static void fcoei_fill_els_rjt_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
92static void fcoei_fill_els_logi_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
93static void fcoei_fill_els_prli_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
94static void fcoei_fill_els_logo_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
95static void fcoei_fill_els_adisc_resp(fc_packet_t *fpkt, fcoe_frame_t *frm);
96
97static void fcoei_logo_peer(void *arg);
98static void fcoei_fpkt_comp(fc_packet_t *fpkt);
99
100static uint32_t
101fcoei_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 */
120static void *
121fcoei_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 */
210static void
211fcoei_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 */
236static int
237fcoei_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 */
264static int
265fcoei_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 */
288static int
289fcoei_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 */
334static int
335fcoei_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 */
355static int
356fcoei_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 */
379static int
380fcoei_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 */
403static int
404fcoei_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 */
426static int
427fcoei_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 */
474static int
475fcoei_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 */
496static int
497fcoei_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 */
564static int
565fcoei_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 */
625static void *
626fcoei_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 */
647static int
648fcoei_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 */
668static int
669fcoei_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 */
717static int
718fcoei_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 */
767static void
768fcoei_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 */
813static void
814fcoei_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 */
835static void
836fcoei_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 */
1037static void
1038fcoei_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 */
1142static void
1143fcoei_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 */
1250static void
1251fcoei_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 */
1341static void
1342fcoei_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 */
1428static void
1429fcoei_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 */
1498static void
1499fcoei_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 */
1525static void
1526fcoei_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 */
1562static void
1563fcoei_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 */
1582static void
1583fcoei_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
1598static void
1599fcoei_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
1611static void
1612fcoei_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 */
1637static void
1638fcoei_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 */
1664static void
1665fcoei_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 */
1697static void
1698fcoei_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 */
1737static void
1738fcoei_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 */
1763static void
1764fcoei_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 */
1789static void
1790fcoei_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 */
1814static void
1815fcoei_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 */
1888static void
1889fcoei_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 */
1918static uint32_t
1919fcoei_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 */
1945void
1946fcoei_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 */
1980void
1981fcoei_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 */
2011void
2012fcoei_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