1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte /*
224558d122SViswanathan Kannappan  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23fcf3ce44SJohn Forte  */
24fcf3ce44SJohn Forte 
25*de710d24SJosef 'Jeff' Sipek #include <sys/sysmacros.h>
26fcf3ce44SJohn Forte #include <sys/conf.h>
27fcf3ce44SJohn Forte #include <sys/file.h>
28fcf3ce44SJohn Forte #include <sys/ddi.h>
29fcf3ce44SJohn Forte #include <sys/sunddi.h>
30fcf3ce44SJohn Forte #include <sys/modctl.h>
31fcf3ce44SJohn Forte #include <sys/scsi/scsi.h>
32fcf3ce44SJohn Forte #include <sys/scsi/impl/scsi_reset_notify.h>
33fcf3ce44SJohn Forte #include <sys/disp.h>
34fcf3ce44SJohn Forte #include <sys/byteorder.h>
35fcf3ce44SJohn Forte #include <sys/varargs.h>
36fcf3ce44SJohn Forte #include <sys/atomic.h>
37d8c54e3dSSam Cramer #include <sys/sdt.h>
38fcf3ce44SJohn Forte 
394558d122SViswanathan Kannappan #include <sys/stmf.h>
404558d122SViswanathan Kannappan #include <sys/stmf_ioctl.h>
414558d122SViswanathan Kannappan #include <sys/portif.h>
424558d122SViswanathan Kannappan #include <sys/fct.h>
434558d122SViswanathan Kannappan #include <sys/fctio.h>
444558d122SViswanathan Kannappan 
454558d122SViswanathan Kannappan #include "fct_impl.h"
464558d122SViswanathan Kannappan #include "discovery.h"
47fcf3ce44SJohn Forte 
48fcf3ce44SJohn Forte disc_action_t fct_handle_local_port_event(fct_i_local_port_t *iport);
49fcf3ce44SJohn Forte disc_action_t fct_walk_discovery_queue(fct_i_local_port_t *iport);
50fcf3ce44SJohn Forte disc_action_t fct_process_els(fct_i_local_port_t *iport,
51fcf3ce44SJohn Forte     fct_i_remote_port_t *irp);
52fcf3ce44SJohn Forte fct_status_t fct_send_accrjt(fct_cmd_t *cmd, uint8_t accrjt,
53fcf3ce44SJohn Forte     uint8_t reason, uint8_t expl);
54fcf3ce44SJohn Forte disc_action_t fct_link_init_complete(fct_i_local_port_t *iport);
55fcf3ce44SJohn Forte fct_status_t fct_complete_previous_li_cmd(fct_i_local_port_t *iport);
56fcf3ce44SJohn Forte fct_status_t fct_sol_plogi(fct_i_local_port_t *iport, uint32_t id,
57fcf3ce44SJohn Forte     fct_cmd_t **ret_ppcmd, int implicit);
58fcf3ce44SJohn Forte fct_status_t fct_sol_ct(fct_i_local_port_t *iport, uint32_t id,
59fcf3ce44SJohn Forte     fct_cmd_t **ret_ppcmd, uint16_t opcode);
60fcf3ce44SJohn Forte fct_status_t fct_ns_scr(fct_i_local_port_t *iport, uint32_t id,
61fcf3ce44SJohn Forte     fct_cmd_t **ret_ppcmd);
62fcf3ce44SJohn Forte static disc_action_t fct_check_cmdlist(fct_i_local_port_t *iport);
63fcf3ce44SJohn Forte static disc_action_t fct_check_solcmd_queue(fct_i_local_port_t *iport);
64fcf3ce44SJohn Forte static void fct_rscn_verify(fct_i_local_port_t *iport,
65fcf3ce44SJohn Forte     uint8_t *rscn_req_payload, uint32_t rscn_req_size);
66fcf3ce44SJohn Forte void fct_gid_cb(fct_i_cmd_t *icmd);
67fcf3ce44SJohn Forte 
68fcf3ce44SJohn Forte char *fct_els_names[] = { 0, "LS_RJT", "ACC", "PLOGI", "FLOGI", "LOGO",
69fcf3ce44SJohn Forte 				"ABTX", "RCS", "RES", "RSS", "RSI", "ESTS",
70fcf3ce44SJohn Forte 				"ESTC", "ADVC", "RTV", "RLS",
71fcf3ce44SJohn Forte 	/* 0x10 */		"ECHO", "TEST", "RRQ", "REC", "SRR", 0, 0,
72fcf3ce44SJohn Forte 				0, 0, 0, 0, 0, 0, 0, 0, 0,
73fcf3ce44SJohn Forte 	/* 0x20 */		"PRLI", "PRLO", "SCN", "TPLS",
74fcf3ce44SJohn Forte 				"TPRLO", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75fcf3ce44SJohn Forte 	/* 0x30 */		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
76fcf3ce44SJohn Forte 	/* 0x40 */		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
77fcf3ce44SJohn Forte 	/* 0x50 */		"PDISC", "FDISC", "ADISC", "RNC", "FARP",
78fcf3ce44SJohn Forte 				0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
79fcf3ce44SJohn Forte 	/* 0x60 */		"FAN", "RSCN", "SCR", 0, 0, 0, 0, 0, 0, 0, 0,
80fcf3ce44SJohn Forte 				0, 0, 0, 0, 0,
81fcf3ce44SJohn Forte 	/* 0x70 */		"LINIT", "LPC", "LSTS", 0, 0, 0, 0, 0,
82fcf3ce44SJohn Forte 				"RNID", "RLIR", "LIRR", 0, 0, 0, 0, 0
83fcf3ce44SJohn Forte 		};
84fcf3ce44SJohn Forte 
85fcf3ce44SJohn Forte extern uint32_t fct_rscn_options;
86fcf3ce44SJohn Forte 
87fcf3ce44SJohn Forte /*
88fcf3ce44SJohn Forte  * NOTE: if anybody drops the iport_worker_lock then they should not return
89fcf3ce44SJohn Forte  * DISC_ACTION_NO_WORK. Which also means, dont drop the lock if you have
90fcf3ce44SJohn Forte  * nothing to do. Or else return DISC_ACTION_RESCAN or DISC_ACTION_DELAY_RESCAN.
91fcf3ce44SJohn Forte  * But you cannot be infinitly returning those so have some logic to
92fcf3ce44SJohn Forte  * determine that there is nothing to do without dropping the lock.
93fcf3ce44SJohn Forte  */
94fcf3ce44SJohn Forte void
fct_port_worker(void * arg)95fcf3ce44SJohn Forte fct_port_worker(void *arg)
96fcf3ce44SJohn Forte {
97fcf3ce44SJohn Forte 	fct_local_port_t	*port = (fct_local_port_t *)arg;
98fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
99fcf3ce44SJohn Forte 	    port->port_fct_private;
100fcf3ce44SJohn Forte 	disc_action_t		suggested_action;
101fcf3ce44SJohn Forte 	clock_t			dl, short_delay, long_delay;
102fcf3ce44SJohn Forte 	int64_t			tmp_delay;
103fcf3ce44SJohn Forte 
104fcf3ce44SJohn Forte 	iport->iport_cmdcheck_clock = ddi_get_lbolt() +
105fcf3ce44SJohn Forte 	    drv_usectohz(FCT_CMDLIST_CHECK_SECONDS * 1000000);
106fcf3ce44SJohn Forte 	short_delay = drv_usectohz(10000);
107fcf3ce44SJohn Forte 	long_delay = drv_usectohz(1000000);
108fcf3ce44SJohn Forte 
109fcf3ce44SJohn Forte 	stmf_trace(iport->iport_alias, "iport is %p", iport);
110fcf3ce44SJohn Forte 	/* Discovery loop */
111fcf3ce44SJohn Forte 	mutex_enter(&iport->iport_worker_lock);
112fcf3ce44SJohn Forte 	atomic_or_32(&iport->iport_flags, IPORT_WORKER_RUNNING);
113fcf3ce44SJohn Forte 	while ((iport->iport_flags & IPORT_TERMINATE_WORKER) == 0) {
114fcf3ce44SJohn Forte 		suggested_action = DISC_ACTION_NO_WORK;
115fcf3ce44SJohn Forte 		/*
116fcf3ce44SJohn Forte 		 * Local port events are of the highest prioriy
117fcf3ce44SJohn Forte 		 */
118fcf3ce44SJohn Forte 		if (iport->iport_event_head) {
119fcf3ce44SJohn Forte 			suggested_action |= fct_handle_local_port_event(iport);
120fcf3ce44SJohn Forte 		}
121fcf3ce44SJohn Forte 
122fcf3ce44SJohn Forte 		/*
123fcf3ce44SJohn Forte 		 * We could post solicited ELSes to discovery queue.
124fcf3ce44SJohn Forte 		 * solicited CT will be processed inside fct_check_solcmd_queue
125fcf3ce44SJohn Forte 		 */
126fcf3ce44SJohn Forte 		if (iport->iport_solcmd_queue) {
127fcf3ce44SJohn Forte 			suggested_action |= fct_check_solcmd_queue(iport);
128fcf3ce44SJohn Forte 		}
129fcf3ce44SJohn Forte 
130fcf3ce44SJohn Forte 		/*
131fcf3ce44SJohn Forte 		 * All solicited and unsolicited ELS will be handled here
132fcf3ce44SJohn Forte 		 */
133fcf3ce44SJohn Forte 		if (iport->iport_rpwe_head) {
134fcf3ce44SJohn Forte 			suggested_action |= fct_walk_discovery_queue(iport);
135fcf3ce44SJohn Forte 		}
136fcf3ce44SJohn Forte 
137fcf3ce44SJohn Forte 		/*
138fcf3ce44SJohn Forte 		 * We only process it when there's no outstanding link init CMD
139fcf3ce44SJohn Forte 		 */
140fcf3ce44SJohn Forte 		if ((iport->iport_link_state ==	PORT_STATE_LINK_INIT_START) &&
141fcf3ce44SJohn Forte 		    !(iport->iport_li_state & (LI_STATE_FLAG_CMD_WAITING |
142fcf3ce44SJohn Forte 		    LI_STATE_FLAG_NO_LI_YET))) {
143fcf3ce44SJohn Forte 			suggested_action |= fct_process_link_init(iport);
144fcf3ce44SJohn Forte 		}
145fcf3ce44SJohn Forte 
146fcf3ce44SJohn Forte 		/*
147fcf3ce44SJohn Forte 		 * We process cmd aborting in the end
148fcf3ce44SJohn Forte 		 */
149fcf3ce44SJohn Forte 		if (iport->iport_abort_queue) {
150fcf3ce44SJohn Forte 			suggested_action |= fct_cmd_terminator(iport);
151fcf3ce44SJohn Forte 		}
152fcf3ce44SJohn Forte 
153fcf3ce44SJohn Forte 		/*
154fcf3ce44SJohn Forte 		 * Check cmd max/free
155fcf3ce44SJohn Forte 		 */
156fcf3ce44SJohn Forte 		if (iport->iport_cmdcheck_clock <= ddi_get_lbolt()) {
157fcf3ce44SJohn Forte 			suggested_action |= fct_check_cmdlist(iport);
158fcf3ce44SJohn Forte 			iport->iport_cmdcheck_clock = ddi_get_lbolt() +
159fcf3ce44SJohn Forte 			    drv_usectohz(FCT_CMDLIST_CHECK_SECONDS * 1000000);
160fcf3ce44SJohn Forte 			iport->iport_max_active_ncmds = 0;
161fcf3ce44SJohn Forte 		}
162fcf3ce44SJohn Forte 
163fcf3ce44SJohn Forte 		if (iport->iport_offline_prstate != FCT_OPR_DONE) {
164fcf3ce44SJohn Forte 			suggested_action |= fct_handle_port_offline(iport);
165fcf3ce44SJohn Forte 		}
166fcf3ce44SJohn Forte 
167fcf3ce44SJohn Forte 		if (suggested_action & DISC_ACTION_RESCAN) {
168fcf3ce44SJohn Forte 			continue;
169fcf3ce44SJohn Forte 		} else if (suggested_action & DISC_ACTION_DELAY_RESCAN) {
170fcf3ce44SJohn Forte 			/*
171fcf3ce44SJohn Forte 			 * This is not very optimum as whoever returned
172fcf3ce44SJohn Forte 			 * DISC_ACTION_DELAY_RESCAN must have dropped the lock
173fcf3ce44SJohn Forte 			 * and more things might have queued up. But since
174fcf3ce44SJohn Forte 			 * we are only doing small delays, it only delays
175fcf3ce44SJohn Forte 			 * things by a few ms, which is okey.
176fcf3ce44SJohn Forte 			 */
177fcf3ce44SJohn Forte 			if (suggested_action & DISC_ACTION_USE_SHORT_DELAY) {
178fcf3ce44SJohn Forte 				dl = short_delay;
179fcf3ce44SJohn Forte 			} else {
180fcf3ce44SJohn Forte 				dl = long_delay;
181fcf3ce44SJohn Forte 			}
182fcf3ce44SJohn Forte 			atomic_or_32(&iport->iport_flags,
183fcf3ce44SJohn Forte 			    IPORT_WORKER_DOING_TIMEDWAIT);
184d3d50737SRafael Vanoni 			(void) cv_reltimedwait(&iport->iport_worker_cv,
185d3d50737SRafael Vanoni 			    &iport->iport_worker_lock, dl, TR_CLOCK_TICK);
186fcf3ce44SJohn Forte 			atomic_and_32(&iport->iport_flags,
187fcf3ce44SJohn Forte 			    ~IPORT_WORKER_DOING_TIMEDWAIT);
188fcf3ce44SJohn Forte 		} else {
189fcf3ce44SJohn Forte 			atomic_or_32(&iport->iport_flags,
190fcf3ce44SJohn Forte 			    IPORT_WORKER_DOING_WAIT);
191fcf3ce44SJohn Forte 			tmp_delay = (int64_t)(iport->iport_cmdcheck_clock -
192fcf3ce44SJohn Forte 			    ddi_get_lbolt());
193fcf3ce44SJohn Forte 			if (tmp_delay < 0) {
194fcf3ce44SJohn Forte 				tmp_delay = (int64_t)short_delay;
195fcf3ce44SJohn Forte 			}
196d3d50737SRafael Vanoni 			(void) cv_reltimedwait(&iport->iport_worker_cv,
197d3d50737SRafael Vanoni 			    &iport->iport_worker_lock, (clock_t)tmp_delay,
198d3d50737SRafael Vanoni 			    TR_CLOCK_TICK);
199fcf3ce44SJohn Forte 			atomic_and_32(&iport->iport_flags,
200fcf3ce44SJohn Forte 			    ~IPORT_WORKER_DOING_WAIT);
201fcf3ce44SJohn Forte 		}
202fcf3ce44SJohn Forte 	}
203fcf3ce44SJohn Forte 
204fcf3ce44SJohn Forte 	atomic_and_32(&iport->iport_flags, ~IPORT_WORKER_RUNNING);
205fcf3ce44SJohn Forte 	mutex_exit(&iport->iport_worker_lock);
206fcf3ce44SJohn Forte }
207fcf3ce44SJohn Forte 
208fcf3ce44SJohn Forte static char *topologies[] = { "Unknown", "Direct Pt-to-Pt", "Private Loop",
209fcf3ce44SJohn Forte 				"Unknown", "Unknown", "Fabric Pt-to-Pt",
210fcf3ce44SJohn Forte 				"Public Loop" };
211fcf3ce44SJohn Forte 
212fcf3ce44SJohn Forte void
fct_li_to_txt(fct_link_info_t * li,char * topology,char * speed)213fcf3ce44SJohn Forte fct_li_to_txt(fct_link_info_t *li, char *topology, char *speed)
214fcf3ce44SJohn Forte {
215fcf3ce44SJohn Forte 	uint8_t s = li->port_speed;
216fcf3ce44SJohn Forte 
217fcf3ce44SJohn Forte 	if (li->port_topology > PORT_TOPOLOGY_PUBLIC_LOOP) {
218fcf3ce44SJohn Forte 		(void) sprintf(topology, "Invalid %02x", li->port_topology);
219fcf3ce44SJohn Forte 	} else {
220fcf3ce44SJohn Forte 		(void) strcpy(topology, topologies[li->port_topology]);
221fcf3ce44SJohn Forte 	}
222fcf3ce44SJohn Forte 
223*de710d24SJosef 'Jeff' Sipek 	if ((s == 0) || ((s & 0xf00) != 0) || !ISP2(s)) {
224fcf3ce44SJohn Forte 		speed[0] = '?';
2252a8164dfSZhong Wang 	} else if (s == PORT_SPEED_10G) {
2262a8164dfSZhong Wang 		speed[0] = '1';
2272a8164dfSZhong Wang 		speed[1] = '0';
2282a8164dfSZhong Wang 		speed[2] = 'G';
2292a8164dfSZhong Wang 		speed[3] = 0;
230fcf3ce44SJohn Forte 	} else {
231fcf3ce44SJohn Forte 		speed[0] = '0' + li->port_speed;
2322a8164dfSZhong Wang 		speed[1] = 'G';
2332a8164dfSZhong Wang 		speed[2] = 0;
234fcf3ce44SJohn Forte 	}
235fcf3ce44SJohn Forte }
236fcf3ce44SJohn Forte 
237fcf3ce44SJohn Forte /*
238fcf3ce44SJohn Forte  * discovery lock held.
239fcf3ce44SJohn Forte  * XXX: Implement command cleanup upon Link down.
240fcf3ce44SJohn Forte  * XXX: Implement a clean start and FC-GS registrations upon Link up.
241fcf3ce44SJohn Forte  *
242fcf3ce44SJohn Forte  * ================ Local Port State Machine ============
243fcf3ce44SJohn Forte  * <hba fatal>		 <Link up>---|
244fcf3ce44SJohn Forte  *   |				     v
245fcf3ce44SJohn Forte  *   |	      <Start>--->[LINK_DOWN]--->[LINK_INIT_START]--->[LINK_INIT_DONE]
246fcf3ce44SJohn Forte  *   |			  ^    ^		  ^    |		   |
247fcf3ce44SJohn Forte  *   |		      |---|    |  |--<Link down>  |-|  |---><Link Reset><--|
248fcf3ce44SJohn Forte  *   |		      |	       |  v		    |	       v
249fcf3ce44SJohn Forte  *   |->[FATAL_CLEANING]  [LINK_DOWN_CLEANING]--->[LINK_UP_CLEANING]
250fcf3ce44SJohn Forte  *					       ^
251fcf3ce44SJohn Forte  *					       |--<Link up>
252fcf3ce44SJohn Forte  * =======================================================
253fcf3ce44SJohn Forte  * An explicit port_online() is only allowed in LINK_DOWN state.
254fcf3ce44SJohn Forte  * An explicit port_offline() is only allowed in LINKDOWN and
255fcf3ce44SJohn Forte  * LINK_INIT_DONE state.
256fcf3ce44SJohn Forte  */
257fcf3ce44SJohn Forte disc_action_t
fct_handle_local_port_event(fct_i_local_port_t * iport)258fcf3ce44SJohn Forte fct_handle_local_port_event(fct_i_local_port_t *iport)
259fcf3ce44SJohn Forte {
260fcf3ce44SJohn Forte 	disc_action_t	ret = DISC_ACTION_RESCAN;
261fcf3ce44SJohn Forte 	fct_i_event_t	*in;
262fcf3ce44SJohn Forte 	uint16_t	old_state, new_state, new_bits;
263fcf3ce44SJohn Forte 	int		dqueue_and_free = 1;
264fcf3ce44SJohn Forte 	int		retry_implicit_logo = 0;
265fcf3ce44SJohn Forte 
266fcf3ce44SJohn Forte 	if (iport->iport_event_head == NULL)
267fcf3ce44SJohn Forte 		return (DISC_ACTION_NO_WORK);
268fcf3ce44SJohn Forte 	in = iport->iport_event_head;
269fcf3ce44SJohn Forte 	mutex_exit(&iport->iport_worker_lock);
270fcf3ce44SJohn Forte 
271fcf3ce44SJohn Forte 	rw_enter(&iport->iport_lock, RW_WRITER);
272d8c54e3dSSam Cramer 
273d8c54e3dSSam Cramer 	if (in->event_type == FCT_EVENT_LINK_UP) {
274d8c54e3dSSam Cramer 		DTRACE_FC_1(link__up, fct_i_local_port_t, iport);
275d8c54e3dSSam Cramer 	} else if (in->event_type == FCT_EVENT_LINK_DOWN) {
276d8c54e3dSSam Cramer 		DTRACE_FC_1(link__down, fct_i_local_port_t, iport);
277d8c54e3dSSam Cramer 	}
278d8c54e3dSSam Cramer 
279fcf3ce44SJohn Forte 	/* Calculate new state */
280fcf3ce44SJohn Forte 	new_state = iport->iport_link_state;
281d8c54e3dSSam Cramer 
282fcf3ce44SJohn Forte 	if (in->event_type == FCT_EVENT_LINK_DOWN) {
283fcf3ce44SJohn Forte 		new_state = PORT_STATE_LINK_DOWN_CLEANING;
284fcf3ce44SJohn Forte 	} else if (in->event_type == FCT_EVENT_LINK_UP) {
285fcf3ce44SJohn Forte 		if (iport->iport_link_state == PORT_STATE_LINK_DOWN_CLEANING)
286fcf3ce44SJohn Forte 			new_state = PORT_STATE_LINK_UP_CLEANING;
287fcf3ce44SJohn Forte 		else if (iport->iport_link_state == PORT_STATE_LINK_DOWN)
288fcf3ce44SJohn Forte 			new_state = PORT_STATE_LINK_INIT_START;
289fcf3ce44SJohn Forte 		else { /* This should not happen */
290fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias,
291fcf3ce44SJohn Forte 			    "Link up received when link state was"
292fcf3ce44SJohn Forte 			    "%x, Ignoring...", iport->iport_link_state);
293fcf3ce44SJohn Forte 		}
294fcf3ce44SJohn Forte 	} else if (in->event_type == FCT_I_EVENT_CLEANUP_POLL) {
295fcf3ce44SJohn Forte 		if (!fct_local_port_cleanup_done(iport)) {
296fcf3ce44SJohn Forte 			if (iport->iport_link_cleanup_retry >= 3) {
297fcf3ce44SJohn Forte 				iport->iport_link_cleanup_retry = 0;
298fcf3ce44SJohn Forte 				retry_implicit_logo = 1;
299fcf3ce44SJohn Forte 			} else {
300fcf3ce44SJohn Forte 				iport->iport_link_cleanup_retry++;
301fcf3ce44SJohn Forte 			}
302fcf3ce44SJohn Forte 			dqueue_and_free = 0;
303fcf3ce44SJohn Forte 			ret = DISC_ACTION_DELAY_RESCAN;
304fcf3ce44SJohn Forte 		} else {
305fcf3ce44SJohn Forte 			if (iport->iport_link_state ==
306fcf3ce44SJohn Forte 			    PORT_STATE_LINK_DOWN_CLEANING) {
307fcf3ce44SJohn Forte 				new_state = PORT_STATE_LINK_DOWN;
308fcf3ce44SJohn Forte 			} else if (iport->iport_link_state ==
309fcf3ce44SJohn Forte 			    PORT_STATE_LINK_UP_CLEANING) {
310fcf3ce44SJohn Forte 				new_state = PORT_STATE_LINK_INIT_START;
311fcf3ce44SJohn Forte 			} else { /* This should not have happened */
312fcf3ce44SJohn Forte 				cmn_err(CE_WARN, "port state changed to %x "
313fcf3ce44SJohn Forte 				    "during cleanup", iport->iport_link_state);
314fcf3ce44SJohn Forte 				new_state = PORT_STATE_LINK_DOWN;
315fcf3ce44SJohn Forte 			}
316fcf3ce44SJohn Forte 		}
317fcf3ce44SJohn Forte 	} else if (in->event_type == FCT_EVENT_LINK_RESET) {
318fcf3ce44SJohn Forte 		/* Link reset is only allowed when we are Online */
319fcf3ce44SJohn Forte 		if (iport->iport_link_state & S_LINK_ONLINE) {
320fcf3ce44SJohn Forte 			new_state = PORT_STATE_LINK_UP_CLEANING;
321fcf3ce44SJohn Forte 		}
322fcf3ce44SJohn Forte 	} else if (in->event_type == FCT_I_EVENT_LINK_INIT_DONE) {
323fcf3ce44SJohn Forte 		if (iport->iport_link_state == PORT_STATE_LINK_INIT_START) {
324fcf3ce44SJohn Forte 			new_state = PORT_STATE_LINK_INIT_DONE;
325fcf3ce44SJohn Forte 			iport->iport_li_state = LI_STATE_START;
326fcf3ce44SJohn Forte 		}
327fcf3ce44SJohn Forte 	} else {
328fcf3ce44SJohn Forte 		ASSERT(0);
329fcf3ce44SJohn Forte 	}
330fcf3ce44SJohn Forte 	new_bits = iport->iport_link_state ^
331590ebdb0Sallan 	    (iport->iport_link_state | new_state);
332fcf3ce44SJohn Forte 	old_state = iport->iport_link_state;
333fcf3ce44SJohn Forte 	iport->iport_link_state = new_state;
334fcf3ce44SJohn Forte 	rw_exit(&iport->iport_lock);
335fcf3ce44SJohn Forte 
336fcf3ce44SJohn Forte 	stmf_trace(iport->iport_alias, "port state change from %x to %x",
337590ebdb0Sallan 	    old_state, new_state);
338fcf3ce44SJohn Forte 
339fcf3ce44SJohn Forte 	if (new_bits & S_PORT_CLEANUP) {
340fcf3ce44SJohn Forte 		(void) fct_implicitly_logo_all(iport, 0);
341fcf3ce44SJohn Forte 		fct_handle_event(iport->iport_port,
342590ebdb0Sallan 		    FCT_I_EVENT_CLEANUP_POLL, 0, 0);
343fcf3ce44SJohn Forte 	}
344fcf3ce44SJohn Forte 	if (retry_implicit_logo) {
345fcf3ce44SJohn Forte 		(void) fct_implicitly_logo_all(iport, 1);
346fcf3ce44SJohn Forte 	}
347fcf3ce44SJohn Forte 	if (new_bits & S_INIT_LINK) {
348fcf3ce44SJohn Forte 		fct_link_info_t *li = &iport->iport_link_info;
349fcf3ce44SJohn Forte 		fct_status_t li_ret;
350fcf3ce44SJohn Forte 		iport->iport_li_state |= LI_STATE_FLAG_NO_LI_YET;
351fcf3ce44SJohn Forte 		bzero(li, sizeof (*li));
352fcf3ce44SJohn Forte 		if ((li_ret = iport->iport_port->port_get_link_info(
353fcf3ce44SJohn Forte 		    iport->iport_port, li)) != FCT_SUCCESS) {
354fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "iport-%p: "
355fcf3ce44SJohn Forte 			    "port_get_link_info failed, ret %llx, forcing "
356fcf3ce44SJohn Forte 			    "link down.", iport, li_ret);
357fcf3ce44SJohn Forte 			fct_handle_event(iport->iport_port,
358590ebdb0Sallan 			    FCT_EVENT_LINK_DOWN, 0, 0);
359fcf3ce44SJohn Forte 		} else {
360fcf3ce44SJohn Forte 			iport->iport_login_retry = 0;
361fcf3ce44SJohn Forte 			/* This will reset LI_STATE_FLAG_NO_LI_YET */
362fcf3ce44SJohn Forte 			iport->iport_li_state = LI_STATE_START;
363fcf3ce44SJohn Forte 			atomic_or_32(&iport->iport_flags,
364590ebdb0Sallan 			    IPORT_ALLOW_UNSOL_FLOGI);
365fcf3ce44SJohn Forte 		}
366fcf3ce44SJohn Forte 		fct_log_local_port_event(iport->iport_port,
367fcf3ce44SJohn Forte 		    ESC_SUNFC_PORT_ONLINE);
368fcf3ce44SJohn Forte 	} else if (new_bits & S_RCVD_LINK_DOWN) {
369fcf3ce44SJohn Forte 		fct_log_local_port_event(iport->iport_port,
370fcf3ce44SJohn Forte 		    ESC_SUNFC_PORT_OFFLINE);
371fcf3ce44SJohn Forte 	}
372fcf3ce44SJohn Forte 
373fcf3ce44SJohn Forte 	mutex_enter(&iport->iport_worker_lock);
374fcf3ce44SJohn Forte 	if (in && dqueue_and_free) {
375fcf3ce44SJohn Forte 		iport->iport_event_head = in->event_next;
376fcf3ce44SJohn Forte 		if (iport->iport_event_head == NULL)
377fcf3ce44SJohn Forte 			iport->iport_event_tail = NULL;
378fcf3ce44SJohn Forte 		kmem_free(in, sizeof (*in));
379fcf3ce44SJohn Forte 	}
380fcf3ce44SJohn Forte 	return (ret);
381fcf3ce44SJohn Forte }
382fcf3ce44SJohn Forte 
383fcf3ce44SJohn Forte int
fct_lport_has_bigger_wwn(fct_i_local_port_t * iport)384fcf3ce44SJohn Forte fct_lport_has_bigger_wwn(fct_i_local_port_t *iport)
385fcf3ce44SJohn Forte {
386fcf3ce44SJohn Forte 	uint8_t *l, *r;
387fcf3ce44SJohn Forte 	int i;
388fcf3ce44SJohn Forte 	uint64_t wl, wr;
389fcf3ce44SJohn Forte 
390fcf3ce44SJohn Forte 	l = iport->iport_port->port_pwwn;
391fcf3ce44SJohn Forte 	r = iport->iport_link_info.port_rpwwn;
392fcf3ce44SJohn Forte 
393fcf3ce44SJohn Forte 	for (i = 0, wl = 0; i < 8; i++) {
394fcf3ce44SJohn Forte 		wl <<= 8;
395fcf3ce44SJohn Forte 		wl |= l[i];
396fcf3ce44SJohn Forte 	}
397fcf3ce44SJohn Forte 	for (i = 0, wr = 0; i < 8; i++) {
398fcf3ce44SJohn Forte 		wr <<= 8;
399fcf3ce44SJohn Forte 		wr |= r[i];
400fcf3ce44SJohn Forte 	}
401fcf3ce44SJohn Forte 
402fcf3ce44SJohn Forte 	if (wl > wr) {
403fcf3ce44SJohn Forte 		return (1);
404fcf3ce44SJohn Forte 	}
405fcf3ce44SJohn Forte 
406fcf3ce44SJohn Forte 	return (0);
407fcf3ce44SJohn Forte }
408fcf3ce44SJohn Forte 
409fcf3ce44SJohn Forte void
fct_do_flogi(fct_i_local_port_t * iport)410fcf3ce44SJohn Forte fct_do_flogi(fct_i_local_port_t *iport)
411fcf3ce44SJohn Forte {
412fcf3ce44SJohn Forte 	fct_flogi_xchg_t fx;
413fcf3ce44SJohn Forte 	fct_status_t ret;
414fcf3ce44SJohn Forte 	int force_link_down = 0;
415fcf3ce44SJohn Forte 	int do_retry = 0;
416fcf3ce44SJohn Forte 
417d8c54e3dSSam Cramer 	DTRACE_FC_1(fabric__login__start, fct_i_local_port_t, iport);
418d8c54e3dSSam Cramer 
419fcf3ce44SJohn Forte 	bzero(&fx, sizeof (fx));
420fcf3ce44SJohn Forte 	fx.fx_op = ELS_OP_FLOGI;
421fcf3ce44SJohn Forte 	if (iport->iport_login_retry == 0) {
422fcf3ce44SJohn Forte 		fx.fx_sec_timeout = 2;
423fcf3ce44SJohn Forte 	} else {
424fcf3ce44SJohn Forte 		fx.fx_sec_timeout = 5;
425fcf3ce44SJohn Forte 	}
426fcf3ce44SJohn Forte 	if (iport->iport_link_info.port_topology & PORT_TOPOLOGY_PRIVATE_LOOP) {
427fcf3ce44SJohn Forte 		fx.fx_sid = iport->iport_link_info.portid & 0xFF;
428fcf3ce44SJohn Forte 	}
429fcf3ce44SJohn Forte 	fx.fx_did = 0xFFFFFE;
430fcf3ce44SJohn Forte 	bcopy(iport->iport_port->port_nwwn, fx.fx_nwwn, 8);
431fcf3ce44SJohn Forte 	bcopy(iport->iport_port->port_pwwn, fx.fx_pwwn, 8);
432fcf3ce44SJohn Forte 	mutex_exit(&iport->iport_worker_lock);
433fcf3ce44SJohn Forte 	ret = iport->iport_port->port_flogi_xchg(iport->iport_port, &fx);
434fcf3ce44SJohn Forte 	mutex_enter(&iport->iport_worker_lock);
435fcf3ce44SJohn Forte 	if (IPORT_FLOGI_DONE(iport)) {
436fcf3ce44SJohn Forte 		/* The unsolicited path finished it. */
437d8c54e3dSSam Cramer 		goto done;
438fcf3ce44SJohn Forte 	}
439fcf3ce44SJohn Forte 	if (ret == FCT_NOT_FOUND) {
440fcf3ce44SJohn Forte 		if (iport->iport_link_info.port_topology &
441590ebdb0Sallan 		    PORT_TOPOLOGY_PRIVATE_LOOP) {
442fcf3ce44SJohn Forte 			/* This is a private loop. There is no switch. */
443fcf3ce44SJohn Forte 			iport->iport_link_info.port_no_fct_flogi = 1;
444d8c54e3dSSam Cramer 			goto done;
445fcf3ce44SJohn Forte 		}
446fcf3ce44SJohn Forte 		/*
447fcf3ce44SJohn Forte 		 * This is really an error. This means we cannot init the
448fcf3ce44SJohn Forte 		 * link. Lets force the link to go down.
449fcf3ce44SJohn Forte 		 */
450fcf3ce44SJohn Forte 		force_link_down = 1;
451fcf3ce44SJohn Forte 	} else if ((ret == FCT_SUCCESS) && (fx.fx_op == ELS_OP_LSRJT)) {
452fcf3ce44SJohn Forte 		if ((fx.fx_rjt_reason == 5) || (fx.fx_rjt_reason == 0xe) ||
453fcf3ce44SJohn Forte 		    ((fx.fx_rjt_reason == 9) && (fx.fx_rjt_expl == 0x29))) {
454fcf3ce44SJohn Forte 			do_retry = 1;
455fcf3ce44SJohn Forte 		} else {
456fcf3ce44SJohn Forte 			force_link_down = 1;
457fcf3ce44SJohn Forte 		}
458fcf3ce44SJohn Forte 	} else if (ret == STMF_TIMEOUT) {
459fcf3ce44SJohn Forte 		do_retry = 1;
460fcf3ce44SJohn Forte 	} else if (ret != FCT_SUCCESS) {
461fcf3ce44SJohn Forte 		force_link_down = 1;
462fcf3ce44SJohn Forte 	}
463fcf3ce44SJohn Forte 
464fcf3ce44SJohn Forte 	if (do_retry) {
465fcf3ce44SJohn Forte 		iport->iport_login_retry++;
466fcf3ce44SJohn Forte 		if (iport->iport_login_retry >= 5)
467fcf3ce44SJohn Forte 			force_link_down = 1;
468d8c54e3dSSam Cramer 		goto done;
469fcf3ce44SJohn Forte 	}
470fcf3ce44SJohn Forte 
471fcf3ce44SJohn Forte 	if (force_link_down) {
472fcf3ce44SJohn Forte 		stmf_trace(iport->iport_alias, "iport-%p: flogi xchg failed. "
473fcf3ce44SJohn Forte 		    "Forcing link down, ret=%llx login_retry=%d ret_op=%d "
474fcf3ce44SJohn Forte 		    "reason=%d expl=%d", iport, ret, iport->iport_login_retry,
475fcf3ce44SJohn Forte 		    fx.fx_op, fx.fx_rjt_reason, fx.fx_rjt_expl);
476fcf3ce44SJohn Forte 		mutex_exit(&iport->iport_worker_lock);
477fcf3ce44SJohn Forte 		fct_handle_event(iport->iport_port, FCT_EVENT_LINK_DOWN, 0, 0);
478fcf3ce44SJohn Forte 		mutex_enter(&iport->iport_worker_lock);
479d8c54e3dSSam Cramer 		goto done;
480fcf3ce44SJohn Forte 	}
481fcf3ce44SJohn Forte 
482fcf3ce44SJohn Forte 	/* FLOGI succeeded. Update local port state */
483fcf3ce44SJohn Forte 	ASSERT(fx.fx_op == ELS_OP_ACC);
484fcf3ce44SJohn Forte 	bcopy(fx.fx_nwwn, iport->iport_link_info.port_rnwwn, 8);
485fcf3ce44SJohn Forte 	bcopy(fx.fx_pwwn, iport->iport_link_info.port_rpwwn, 8);
486fcf3ce44SJohn Forte 	if (fx.fx_fport) {
487fcf3ce44SJohn Forte 		iport->iport_link_info.port_topology |=
488590ebdb0Sallan 		    PORT_TOPOLOGY_FABRIC_BIT;
489fcf3ce44SJohn Forte 		iport->iport_link_info.portid = fx.fx_did;
490fcf3ce44SJohn Forte 	}
491fcf3ce44SJohn Forte 	iport->iport_link_info.port_fct_flogi_done = 1;
492d8c54e3dSSam Cramer 
493d8c54e3dSSam Cramer done:
494d8c54e3dSSam Cramer 	DTRACE_FC_1(fabric__login__end,
495d8c54e3dSSam Cramer 	    fct_i_local_port_t, iport);
496fcf3ce44SJohn Forte }
497fcf3ce44SJohn Forte 
498fcf3ce44SJohn Forte /*
499fcf3ce44SJohn Forte  * Called by FCAs to handle unsolicited FLOGIs.
500fcf3ce44SJohn Forte  */
501fcf3ce44SJohn Forte fct_status_t
fct_handle_rcvd_flogi(fct_local_port_t * port,fct_flogi_xchg_t * fx)502fcf3ce44SJohn Forte fct_handle_rcvd_flogi(fct_local_port_t *port, fct_flogi_xchg_t *fx)
503fcf3ce44SJohn Forte {
504fcf3ce44SJohn Forte 	fct_i_local_port_t *iport;
505fcf3ce44SJohn Forte 	uint32_t t;
506fcf3ce44SJohn Forte 
507fcf3ce44SJohn Forte 	iport = (fct_i_local_port_t *)port->port_fct_private;
508fcf3ce44SJohn Forte 	if ((iport->iport_flags & IPORT_ALLOW_UNSOL_FLOGI) == 0) {
509fcf3ce44SJohn Forte 		return (FCT_FAILURE);
510fcf3ce44SJohn Forte 	}
511fcf3ce44SJohn Forte 
512fcf3ce44SJohn Forte 	mutex_enter(&iport->iport_worker_lock);
513fcf3ce44SJohn Forte 	if (((iport->iport_flags & IPORT_ALLOW_UNSOL_FLOGI) == 0) ||
514fcf3ce44SJohn Forte 	    (iport->iport_link_state !=	PORT_STATE_LINK_INIT_START) ||
515fcf3ce44SJohn Forte 	    ((iport->iport_li_state & LI_STATE_MASK) > LI_STATE_N2N_PLOGI)) {
516fcf3ce44SJohn Forte 		mutex_exit(&iport->iport_worker_lock);
517fcf3ce44SJohn Forte 		return (FCT_FAILURE);
518fcf3ce44SJohn Forte 	}
519fcf3ce44SJohn Forte 
520fcf3ce44SJohn Forte 	if (iport->iport_link_info.port_fct_flogi_done == 0) {
521fcf3ce44SJohn Forte 		iport->iport_link_info.port_fct_flogi_done = 1;
522fcf3ce44SJohn Forte 		bcopy(fx->fx_pwwn, iport->iport_link_info.port_rpwwn, 8);
523fcf3ce44SJohn Forte 		bcopy(fx->fx_nwwn, iport->iport_link_info.port_rnwwn, 8);
524fcf3ce44SJohn Forte 	}
525fcf3ce44SJohn Forte 
526fcf3ce44SJohn Forte 	fx->fx_op = ELS_OP_ACC;
527fcf3ce44SJohn Forte 	t = fx->fx_sid;
528fcf3ce44SJohn Forte 	fx->fx_sid = fx->fx_did;
529fcf3ce44SJohn Forte 	fx->fx_did = t;
530fcf3ce44SJohn Forte 	bcopy(iport->iport_port->port_pwwn, fx->fx_pwwn, 8);
531fcf3ce44SJohn Forte 	bcopy(iport->iport_port->port_nwwn, fx->fx_nwwn, 8);
532fcf3ce44SJohn Forte 	mutex_exit(&iport->iport_worker_lock);
533fcf3ce44SJohn Forte 
534fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
535fcf3ce44SJohn Forte }
536fcf3ce44SJohn Forte 
537fcf3ce44SJohn Forte /*
538fcf3ce44SJohn Forte  * iport_li_state can only be changed here and local_event
539fcf3ce44SJohn Forte  */
540fcf3ce44SJohn Forte disc_action_t
fct_process_link_init(fct_i_local_port_t * iport)541fcf3ce44SJohn Forte fct_process_link_init(fct_i_local_port_t *iport)
542fcf3ce44SJohn Forte {
543fcf3ce44SJohn Forte 	fct_cmd_t	*cmd	  = NULL;
544fcf3ce44SJohn Forte 	char		*pname	  = NULL;
545fcf3ce44SJohn Forte 	uint8_t		 elsop	  = 0;
546fcf3ce44SJohn Forte 	uint16_t	 ctop	  = 0;
547fcf3ce44SJohn Forte 	uint32_t	 wkdid	  = 0;
548fcf3ce44SJohn Forte 	int		 implicit = 0;
549fcf3ce44SJohn Forte 	int		force_login = 0;
550fcf3ce44SJohn Forte 	disc_action_t	 ret	  = DISC_ACTION_RESCAN;
551fcf3ce44SJohn Forte 	fct_link_info_t *li = &iport->iport_link_info;
552fcf3ce44SJohn Forte 	char		topo[24], speed[4];
553fcf3ce44SJohn Forte 
554fcf3ce44SJohn Forte 	ASSERT(MUTEX_HELD(&iport->iport_worker_lock));
555fcf3ce44SJohn Forte 
556fcf3ce44SJohn Forte check_state_again:
557fcf3ce44SJohn Forte 	switch (iport->iport_li_state & LI_STATE_MASK) {
558fcf3ce44SJohn Forte 	case LI_STATE_DO_FLOGI:
559fcf3ce44SJohn Forte 		/* Is FLOGI even needed or already done ? */
560fcf3ce44SJohn Forte 		if ((iport->iport_link_info.port_no_fct_flogi) ||
561fcf3ce44SJohn Forte 		    (IPORT_FLOGI_DONE(iport))) {
562fcf3ce44SJohn Forte 			iport->iport_li_state++;
563fcf3ce44SJohn Forte 			goto check_state_again;
564fcf3ce44SJohn Forte 		}
565fcf3ce44SJohn Forte 		fct_do_flogi(iport);
566fcf3ce44SJohn Forte 		break;
567fcf3ce44SJohn Forte 
568fcf3ce44SJohn Forte 	case LI_STATE_FINI_TOPOLOGY:
569fcf3ce44SJohn Forte 		fct_li_to_txt(li, topo, speed);
570fcf3ce44SJohn Forte 		cmn_err(CE_NOTE, "%s LINK UP, portid %x, topology %s,"
571fcf3ce44SJohn Forte 		    "speed %s", iport->iport_alias, li->portid,
572fcf3ce44SJohn Forte 		    topo, speed);
573fcf3ce44SJohn Forte 		if (li->port_topology !=
574fcf3ce44SJohn Forte 		    iport->iport_link_old_topology) {
575fcf3ce44SJohn Forte 			if (iport->iport_nrps) {
576fcf3ce44SJohn Forte 				/*
577fcf3ce44SJohn Forte 				 * rehash it if change from fabric to
578fcf3ce44SJohn Forte 				 * none fabric, vice versa
579fcf3ce44SJohn Forte 				 */
580fcf3ce44SJohn Forte 				if ((li->port_topology ^
581fcf3ce44SJohn Forte 				    iport->iport_link_old_topology) &
582fcf3ce44SJohn Forte 				    PORT_TOPOLOGY_FABRIC_BIT) {
583fcf3ce44SJohn Forte 					mutex_exit(&iport->iport_worker_lock);
584fcf3ce44SJohn Forte 					fct_rehash(iport);
585fcf3ce44SJohn Forte 					mutex_enter(&iport->iport_worker_lock);
586fcf3ce44SJohn Forte 				}
587fcf3ce44SJohn Forte 			}
588fcf3ce44SJohn Forte 			iport->iport_link_old_topology = li->port_topology;
589fcf3ce44SJohn Forte 		}
590fcf3ce44SJohn Forte 		/* Skip next level if topo is not N2N */
591fcf3ce44SJohn Forte 		if (li->port_topology != PORT_TOPOLOGY_PT_TO_PT) {
592fcf3ce44SJohn Forte 			iport->iport_li_state += 2;
593fcf3ce44SJohn Forte 			atomic_and_32(&iport->iport_flags,
594fcf3ce44SJohn Forte 			    ~IPORT_ALLOW_UNSOL_FLOGI);
595fcf3ce44SJohn Forte 		} else {
596fcf3ce44SJohn Forte 			iport->iport_li_state++;
597fcf3ce44SJohn Forte 			iport->iport_login_retry = 0;
598fcf3ce44SJohn Forte 			iport->iport_li_cmd_timeout = ddi_get_lbolt() +
599590ebdb0Sallan 			    drv_usectohz(25 * 1000000);
600fcf3ce44SJohn Forte 		}
601fcf3ce44SJohn Forte 		goto check_state_again;
602fcf3ce44SJohn Forte 
603fcf3ce44SJohn Forte 	case LI_STATE_N2N_PLOGI:
604fcf3ce44SJohn Forte 		ASSERT(IPORT_FLOGI_DONE(iport));
605fcf3ce44SJohn Forte 		ASSERT(iport->iport_link_info.port_topology ==
606590ebdb0Sallan 		    PORT_TOPOLOGY_PT_TO_PT);
607fcf3ce44SJohn Forte 		if (iport->iport_li_state & LI_STATE_FLAG_CMD_RETCHECK) {
608fcf3ce44SJohn Forte 			iport->iport_li_state &= ~LI_STATE_FLAG_CMD_RETCHECK;
609fcf3ce44SJohn Forte 			if (iport->iport_li_comp_status != FCT_SUCCESS) {
610fcf3ce44SJohn Forte 				iport->iport_login_retry++;
611fcf3ce44SJohn Forte 				if (iport->iport_login_retry >= 3) {
612fcf3ce44SJohn Forte 					stmf_trace(iport->iport_alias, "Failing"
613fcf3ce44SJohn Forte 					    " to PLOGI to remote port in N2N "
614fcf3ce44SJohn Forte 					    " ret=%llx, forcing link down",
615fcf3ce44SJohn Forte 					    iport->iport_li_comp_status);
616fcf3ce44SJohn Forte 					mutex_exit(&iport->iport_worker_lock);
617fcf3ce44SJohn Forte 					fct_handle_event(iport->iport_port,
618590ebdb0Sallan 					    FCT_EVENT_LINK_DOWN, 0, 0);
619fcf3ce44SJohn Forte 					mutex_enter(&iport->iport_worker_lock);
620fcf3ce44SJohn Forte 				}
621fcf3ce44SJohn Forte 			}
622fcf3ce44SJohn Forte 		}
623fcf3ce44SJohn Forte 		/* Find out if we need to do PLOGI at all */
624fcf3ce44SJohn Forte 		if (iport->iport_nrps_login) {
625fcf3ce44SJohn Forte 			iport->iport_li_state++;
626fcf3ce44SJohn Forte 			atomic_and_32(&iport->iport_flags,
627fcf3ce44SJohn Forte 			    ~IPORT_ALLOW_UNSOL_FLOGI);
628fcf3ce44SJohn Forte 			goto check_state_again;
629fcf3ce44SJohn Forte 		}
630fcf3ce44SJohn Forte 		if ((ddi_get_lbolt() >= iport->iport_li_cmd_timeout) &&
631fcf3ce44SJohn Forte 		    (!fct_lport_has_bigger_wwn(iport))) {
632fcf3ce44SJohn Forte 			/* Cant wait forever */
633fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "N2N: Remote port is "
634fcf3ce44SJohn Forte 			    "not logging in, forcing from our side");
635fcf3ce44SJohn Forte 			force_login = 1;
636fcf3ce44SJohn Forte 		} else {
637fcf3ce44SJohn Forte 			force_login = 0;
638fcf3ce44SJohn Forte 		}
639fcf3ce44SJohn Forte 		if (force_login || fct_lport_has_bigger_wwn(iport)) {
640fcf3ce44SJohn Forte 			elsop	 = ELS_OP_PLOGI;
641fcf3ce44SJohn Forte 			wkdid	 = 1;
642fcf3ce44SJohn Forte 			iport->iport_link_info.portid = 0xEF;
643fcf3ce44SJohn Forte 			implicit = 0;
644fcf3ce44SJohn Forte 			iport->iport_li_state |= LI_STATE_FLAG_CMD_RETCHECK;
645fcf3ce44SJohn Forte 		} else {
646fcf3ce44SJohn Forte 			ret = DISC_ACTION_DELAY_RESCAN;
647fcf3ce44SJohn Forte 		}
648fcf3ce44SJohn Forte 		break;
649fcf3ce44SJohn Forte 
650fcf3ce44SJohn Forte 	case LI_STATE_DO_FCLOGIN:
651fcf3ce44SJohn Forte 		if (iport->iport_li_state & LI_STATE_FLAG_CMD_RETCHECK) {
652fcf3ce44SJohn Forte 			iport->iport_li_state &= ~LI_STATE_FLAG_CMD_RETCHECK;
653fcf3ce44SJohn Forte 			if (iport->iport_li_comp_status != FCT_SUCCESS) {
654fcf3ce44SJohn Forte 				/*
655fcf3ce44SJohn Forte 				 * Fabric controller login failed. Just skip all
656fcf3ce44SJohn Forte 				 * the fabric controller related cmds.
657fcf3ce44SJohn Forte 				 */
658fcf3ce44SJohn Forte 				iport->iport_li_state = LI_STATE_DO_SCR + 1;
659fcf3ce44SJohn Forte 			} else {
660fcf3ce44SJohn Forte 				/*
661fcf3ce44SJohn Forte 				 * Good. Now lets go to next state
662fcf3ce44SJohn Forte 				 */
663fcf3ce44SJohn Forte 				iport->iport_li_state++;
664fcf3ce44SJohn Forte 			}
665fcf3ce44SJohn Forte 			goto check_state_again;
666fcf3ce44SJohn Forte 		}
667fcf3ce44SJohn Forte 		if (!IPORT_IN_NS_TOPO(iport)) {
668fcf3ce44SJohn Forte 			iport->iport_li_state = LI_STATE_DO_SCR + 1;
669fcf3ce44SJohn Forte 			goto check_state_again;
670fcf3ce44SJohn Forte 		}
671fcf3ce44SJohn Forte 
672fcf3ce44SJohn Forte 		elsop	 = ELS_OP_PLOGI;
673fcf3ce44SJohn Forte 		wkdid	 = FS_FABRIC_CONTROLLER;
674fcf3ce44SJohn Forte 		implicit = 1;
675fcf3ce44SJohn Forte 
676fcf3ce44SJohn Forte 		/*
677fcf3ce44SJohn Forte 		 * We want to come back in the same state and check its ret
678fcf3ce44SJohn Forte 		 * We can't modify the state here
679fcf3ce44SJohn Forte 		 */
680fcf3ce44SJohn Forte 		iport->iport_li_state |= LI_STATE_FLAG_CMD_RETCHECK;
681fcf3ce44SJohn Forte 		break;
682fcf3ce44SJohn Forte 
683fcf3ce44SJohn Forte 	case LI_STATE_DO_SCR:
684fcf3ce44SJohn Forte 		elsop = ELS_OP_SCR;
685fcf3ce44SJohn Forte 		wkdid = FS_FABRIC_CONTROLLER;
686fcf3ce44SJohn Forte 
687fcf3ce44SJohn Forte 		/*
688fcf3ce44SJohn Forte 		 * We dont care about success of this state. Just go to
689fcf3ce44SJohn Forte 		 * next state upon completion.
690fcf3ce44SJohn Forte 		 */
691fcf3ce44SJohn Forte 		iport->iport_li_state++;
692fcf3ce44SJohn Forte 		break;
693fcf3ce44SJohn Forte 
694fcf3ce44SJohn Forte 	case LI_STATE_DO_NSLOGIN:
695fcf3ce44SJohn Forte 		if (iport->iport_li_state & LI_STATE_FLAG_CMD_RETCHECK) {
696fcf3ce44SJohn Forte 			iport->iport_li_state &= ~LI_STATE_FLAG_CMD_RETCHECK;
697fcf3ce44SJohn Forte 			if (iport->iport_li_comp_status != FCT_SUCCESS) {
698fcf3ce44SJohn Forte 				iport->iport_li_state = LI_STATE_DO_RSNN + 1;
699fcf3ce44SJohn Forte 			} else {
700fcf3ce44SJohn Forte 				iport->iport_li_state++;
701fcf3ce44SJohn Forte 			}
702fcf3ce44SJohn Forte 			goto check_state_again;
703fcf3ce44SJohn Forte 		}
704fcf3ce44SJohn Forte 
705fcf3ce44SJohn Forte 		if (!IPORT_IN_NS_TOPO(iport)) {
706fcf3ce44SJohn Forte 			iport->iport_li_state = LI_STATE_DO_RSNN + 1;
707fcf3ce44SJohn Forte 			goto check_state_again;
708fcf3ce44SJohn Forte 		}
709fcf3ce44SJohn Forte 
710fcf3ce44SJohn Forte 		elsop			= ELS_OP_PLOGI;
711fcf3ce44SJohn Forte 		wkdid			= FS_NAME_SERVER;
712fcf3ce44SJohn Forte 		iport->iport_li_state	|= LI_STATE_FLAG_CMD_RETCHECK;
713fcf3ce44SJohn Forte 		break;
714fcf3ce44SJohn Forte 
715fcf3ce44SJohn Forte 		/*
716fcf3ce44SJohn Forte 		 * CT state
717fcf3ce44SJohn Forte 		 */
718fcf3ce44SJohn Forte 	case LI_STATE_DO_RNN:
719fcf3ce44SJohn Forte 		ctop = NS_RNN_ID;
720fcf3ce44SJohn Forte 		iport->iport_li_state++;
721fcf3ce44SJohn Forte 		break;
722fcf3ce44SJohn Forte 
723fcf3ce44SJohn Forte 	case LI_STATE_DO_RCS:
724fcf3ce44SJohn Forte 		ctop = NS_RCS_ID;
725fcf3ce44SJohn Forte 		iport->iport_li_state++;
726fcf3ce44SJohn Forte 		break;
727fcf3ce44SJohn Forte 
728fcf3ce44SJohn Forte 	case LI_STATE_DO_RFT:
729fcf3ce44SJohn Forte 		ctop = NS_RFT_ID;
730fcf3ce44SJohn Forte 		iport->iport_li_state++;
731fcf3ce44SJohn Forte 		break;
732fcf3ce44SJohn Forte 
733fcf3ce44SJohn Forte 	case LI_STATE_DO_RSPN:
734fcf3ce44SJohn Forte 		/*
735fcf3ce44SJohn Forte 		 * Check if we need skip the state
736fcf3ce44SJohn Forte 		 */
737fcf3ce44SJohn Forte 		pname = iport->iport_port->port_sym_port_name !=
738fcf3ce44SJohn Forte 		    NULL ? iport->iport_port->port_sym_port_name : NULL;
739fcf3ce44SJohn Forte 		if (pname == NULL) {
740fcf3ce44SJohn Forte 			pname = iport->iport_port->port_default_alias !=
741fcf3ce44SJohn Forte 			    NULL ? iport->iport_port->port_default_alias : NULL;
742fcf3ce44SJohn Forte 			iport->iport_port->port_sym_port_name = pname;
743fcf3ce44SJohn Forte 		}
744fcf3ce44SJohn Forte 
745fcf3ce44SJohn Forte 		if (pname == NULL) {
746fcf3ce44SJohn Forte 			iport->iport_li_state++;
747fcf3ce44SJohn Forte 			goto check_state_again;
748fcf3ce44SJohn Forte 		}
749fcf3ce44SJohn Forte 
750fcf3ce44SJohn Forte 		ctop = NS_RSPN_ID;
751fcf3ce44SJohn Forte 		iport->iport_li_state++;
752fcf3ce44SJohn Forte 		break;
753fcf3ce44SJohn Forte 
754fcf3ce44SJohn Forte 	case LI_STATE_DO_RSNN:
755fcf3ce44SJohn Forte 		ctop = NS_RSNN_NN;
756fcf3ce44SJohn Forte 		iport->iport_li_state++;
757fcf3ce44SJohn Forte 		break;
758fcf3ce44SJohn Forte 
759fcf3ce44SJohn Forte 	case LI_STATE_MAX:
760fcf3ce44SJohn Forte 		mutex_exit(&iport->iport_worker_lock);
761fcf3ce44SJohn Forte 
762fcf3ce44SJohn Forte 		fct_handle_event(iport->iport_port,
763fcf3ce44SJohn Forte 		    FCT_I_EVENT_LINK_INIT_DONE, 0, 0);
764fcf3ce44SJohn Forte 
765fcf3ce44SJohn Forte 		mutex_enter(&iport->iport_worker_lock);
766fcf3ce44SJohn Forte 		break;
767fcf3ce44SJohn Forte 
768fcf3ce44SJohn Forte 	default:
769fcf3ce44SJohn Forte 		ASSERT(0);
770fcf3ce44SJohn Forte 	}
771fcf3ce44SJohn Forte 
772fcf3ce44SJohn Forte 	if (elsop != 0) {
773fcf3ce44SJohn Forte 		cmd = fct_create_solels(iport->iport_port, NULL, implicit,
774fcf3ce44SJohn Forte 		    elsop, wkdid, fct_link_init_cb);
775fcf3ce44SJohn Forte 	} else if (ctop != 0) {
776fcf3ce44SJohn Forte 		cmd = fct_create_solct(iport->iport_port, NULL, ctop,
777fcf3ce44SJohn Forte 		    fct_link_init_cb);
778fcf3ce44SJohn Forte 	}
779fcf3ce44SJohn Forte 
780fcf3ce44SJohn Forte 	if (cmd) {
781fcf3ce44SJohn Forte 		iport->iport_li_state |= LI_STATE_FLAG_CMD_WAITING;
782fcf3ce44SJohn Forte 		mutex_exit(&iport->iport_worker_lock);
783fcf3ce44SJohn Forte 
784fcf3ce44SJohn Forte 		fct_post_to_solcmd_queue(iport->iport_port, cmd);
785fcf3ce44SJohn Forte 
786fcf3ce44SJohn Forte 		mutex_enter(&iport->iport_worker_lock);
787fcf3ce44SJohn Forte 	}
788fcf3ce44SJohn Forte 
789fcf3ce44SJohn Forte 	return (ret);
790fcf3ce44SJohn Forte }
791fcf3ce44SJohn Forte 
792fcf3ce44SJohn Forte /*
793fcf3ce44SJohn Forte  * Handles both solicited and unsolicited elses. Can be called inside
794fcf3ce44SJohn Forte  * interrupt context.
795fcf3ce44SJohn Forte  */
796fcf3ce44SJohn Forte void
fct_handle_els(fct_cmd_t * cmd)797fcf3ce44SJohn Forte fct_handle_els(fct_cmd_t *cmd)
798fcf3ce44SJohn Forte {
799fcf3ce44SJohn Forte 	fct_local_port_t	*port = cmd->cmd_port;
800fcf3ce44SJohn Forte 	fct_i_local_port_t *iport =
801590ebdb0Sallan 	    (fct_i_local_port_t *)port->port_fct_private;
802fcf3ce44SJohn Forte 	fct_i_cmd_t		*icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
803fcf3ce44SJohn Forte 	fct_els_t		*els  = (fct_els_t *)cmd->cmd_specific;
804fcf3ce44SJohn Forte 	fct_remote_port_t	*rp;
805fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp;
806fcf3ce44SJohn Forte 	uint16_t		 cmd_slot;
807fcf3ce44SJohn Forte 	uint8_t			 op;
808fcf3ce44SJohn Forte 
809fcf3ce44SJohn Forte 	op = els->els_req_payload[0];
810fcf3ce44SJohn Forte 	icmd->icmd_start_time = ddi_get_lbolt();
811fcf3ce44SJohn Forte 	if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
812fcf3ce44SJohn Forte 		icmd->icmd_flags |= ICMD_KNOWN_TO_FCA;
813fcf3ce44SJohn Forte 	}
814fcf3ce44SJohn Forte 	stmf_trace(iport->iport_alias, "Posting %ssol ELS %x (%s) rp_id=%x"
815fcf3ce44SJohn Forte 	    " lp_id=%x", (cmd->cmd_type == FCT_CMD_RCVD_ELS) ? "un" : "",
816590ebdb0Sallan 	    op, FCT_ELS_NAME(op), cmd->cmd_rportid,
817590ebdb0Sallan 	    cmd->cmd_lportid);
818fcf3ce44SJohn Forte 
819fcf3ce44SJohn Forte 	rw_enter(&iport->iport_lock, RW_READER);
820fcf3ce44SJohn Forte start_els_posting:;
821fcf3ce44SJohn Forte 	/* Make sure local port is sane */
822fcf3ce44SJohn Forte 	if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
823fcf3ce44SJohn Forte 		rw_exit(&iport->iport_lock);
824fcf3ce44SJohn Forte 		stmf_trace(iport->iport_alias, "ELS %x not posted becasue"
825fcf3ce44SJohn Forte 		    "port state was %x", els->els_req_payload[0],
826fcf3ce44SJohn Forte 		    iport->iport_link_state);
827fcf3ce44SJohn Forte 		fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE);
828fcf3ce44SJohn Forte 		return;
829fcf3ce44SJohn Forte 	}
830fcf3ce44SJohn Forte 
831fcf3ce44SJohn Forte 	/* Weed out any bad initiators in case of N2N topology */
832fcf3ce44SJohn Forte 	if ((cmd->cmd_type == FCT_CMD_RCVD_ELS) &&
833fcf3ce44SJohn Forte 	    (els->els_req_payload[0] == ELS_OP_PLOGI) &&
834fcf3ce44SJohn Forte 	    (iport->iport_link_state == PORT_STATE_LINK_INIT_START) &&
835fcf3ce44SJohn Forte 	    (iport->iport_link_info.port_topology == PORT_TOPOLOGY_PT_TO_PT)) {
836fcf3ce44SJohn Forte 		int state;
837fcf3ce44SJohn Forte 		int killit = 0;
838fcf3ce44SJohn Forte 
839fcf3ce44SJohn Forte 		mutex_enter(&iport->iport_worker_lock);
840fcf3ce44SJohn Forte 		state = iport->iport_li_state & LI_STATE_MASK;
841fcf3ce44SJohn Forte 		/*
842fcf3ce44SJohn Forte 		 * We dont allow remote port to plogi in N2N if we have not yet
843fcf3ce44SJohn Forte 		 * resolved the topology.
844fcf3ce44SJohn Forte 		 */
845fcf3ce44SJohn Forte 		if (state <= LI_STATE_FINI_TOPOLOGY) {
846fcf3ce44SJohn Forte 			killit = 1;
847fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "port %x is trying to "
848fcf3ce44SJohn Forte 			    "PLOGI in N2N topology, While we have not resolved"
849fcf3ce44SJohn Forte 			    " the topology. Dropping...", cmd->cmd_rportid);
850fcf3ce44SJohn Forte 		} else if (state <= LI_STATE_N2N_PLOGI) {
851fcf3ce44SJohn Forte 			if (fct_lport_has_bigger_wwn(iport)) {
852fcf3ce44SJohn Forte 				killit = 1;
853fcf3ce44SJohn Forte 				stmf_trace(iport->iport_alias, "port %x is "
854fcf3ce44SJohn Forte 				    "trying to PLOGI in N2N topology, even "
855fcf3ce44SJohn Forte 				    "though it has smaller PWWN",
856fcf3ce44SJohn Forte 				    cmd->cmd_rportid);
857fcf3ce44SJohn Forte 			} else {
858fcf3ce44SJohn Forte 				/*
859fcf3ce44SJohn Forte 				 * Remote port is assigning us a PORTID as
860fcf3ce44SJohn Forte 				 * a part of PLOGI.
861fcf3ce44SJohn Forte 				 */
862fcf3ce44SJohn Forte 				iport->iport_link_info.portid =
863590ebdb0Sallan 				    cmd->cmd_lportid;
864fcf3ce44SJohn Forte 			}
865fcf3ce44SJohn Forte 		}
866fcf3ce44SJohn Forte 		mutex_exit(&iport->iport_worker_lock);
867fcf3ce44SJohn Forte 		if (killit) {
868fcf3ce44SJohn Forte 			rw_exit(&iport->iport_lock);
869fcf3ce44SJohn Forte 			fct_queue_cmd_for_termination(cmd,
870590ebdb0Sallan 			    FCT_LOCAL_PORT_OFFLINE);
871fcf3ce44SJohn Forte 			return;
872fcf3ce44SJohn Forte 		}
873fcf3ce44SJohn Forte 	}
874fcf3ce44SJohn Forte 
875fcf3ce44SJohn Forte 	/*
876fcf3ce44SJohn Forte 	 * For all unsolicited ELSes that are not FLOGIs, our portid
877fcf3ce44SJohn Forte 	 * has been established by now. Sometimes port IDs change due to
878fcf3ce44SJohn Forte 	 * link resets but remote ports may still send ELSes using the
879fcf3ce44SJohn Forte 	 * old IDs. Kill those right here.
880fcf3ce44SJohn Forte 	 */
881fcf3ce44SJohn Forte 	if ((cmd->cmd_type == FCT_CMD_RCVD_ELS) &&
882fcf3ce44SJohn Forte 	    (els->els_req_payload[0] != ELS_OP_FLOGI)) {
883fcf3ce44SJohn Forte 		if (cmd->cmd_lportid != iport->iport_link_info.portid) {
884fcf3ce44SJohn Forte 			rw_exit(&iport->iport_lock);
885fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "Rcvd %s with "
886fcf3ce44SJohn Forte 			    "wrong lportid %x, expecting %x. Killing ELS.",
887fcf3ce44SJohn Forte 			    FCT_ELS_NAME(op), cmd->cmd_lportid,
888fcf3ce44SJohn Forte 			    iport->iport_link_info.portid);
889fcf3ce44SJohn Forte 			fct_queue_cmd_for_termination(cmd,
890590ebdb0Sallan 			    FCT_NOT_FOUND);
891fcf3ce44SJohn Forte 			return;
892fcf3ce44SJohn Forte 		}
893fcf3ce44SJohn Forte 	}
894fcf3ce44SJohn Forte 
895fcf3ce44SJohn Forte 	/*
896fcf3ce44SJohn Forte 	 * We always lookup by portid. port handles are too
897fcf3ce44SJohn Forte 	 * unreliable at this stage.
898fcf3ce44SJohn Forte 	 */
899fcf3ce44SJohn Forte 	irp = fct_portid_to_portptr(iport, cmd->cmd_rportid);
900fcf3ce44SJohn Forte 	if (els->els_req_payload[0] == ELS_OP_PLOGI) {
901fcf3ce44SJohn Forte 		if (irp == NULL) {
902fcf3ce44SJohn Forte 			/* drop the lock while we do allocations */
903fcf3ce44SJohn Forte 			rw_exit(&iport->iport_lock);
904fcf3ce44SJohn Forte 			rp = fct_alloc(FCT_STRUCT_REMOTE_PORT,
905590ebdb0Sallan 			    port->port_fca_rp_private_size, 0);
906fcf3ce44SJohn Forte 			if (rp == NULL) {
907fcf3ce44SJohn Forte 				fct_queue_cmd_for_termination(cmd,
908590ebdb0Sallan 				    FCT_ALLOC_FAILURE);
909fcf3ce44SJohn Forte 				return;
910fcf3ce44SJohn Forte 			}
911fcf3ce44SJohn Forte 			irp = (fct_i_remote_port_t *)rp->rp_fct_private;
912fcf3ce44SJohn Forte 			rw_init(&irp->irp_lock, 0, RW_DRIVER, 0);
913fcf3ce44SJohn Forte 			irp->irp_rp = rp;
914fcf3ce44SJohn Forte 			irp->irp_portid = cmd->cmd_rportid;
915fcf3ce44SJohn Forte 			rp->rp_port = port;
916fcf3ce44SJohn Forte 			rp->rp_id = cmd->cmd_rportid;
917fcf3ce44SJohn Forte 			rp->rp_handle = FCT_HANDLE_NONE;
918fcf3ce44SJohn Forte 			/*
919fcf3ce44SJohn Forte 			 * Grab port lock as writer since we are going
920fcf3ce44SJohn Forte 			 * to modify the local port struct.
921fcf3ce44SJohn Forte 			 */
922fcf3ce44SJohn Forte 			rw_enter(&iport->iport_lock, RW_WRITER);
923fcf3ce44SJohn Forte 			/* Make sure nobody created the struct except us */
924fcf3ce44SJohn Forte 			if (fct_portid_to_portptr(iport, cmd->cmd_rportid)) {
925fcf3ce44SJohn Forte 				/* Oh well, free it */
926fcf3ce44SJohn Forte 				fct_free(rp);
927fcf3ce44SJohn Forte 			} else {
928fcf3ce44SJohn Forte 				fct_queue_rp(iport, irp);
929fcf3ce44SJohn Forte 			}
930fcf3ce44SJohn Forte 			rw_downgrade(&iport->iport_lock);
931fcf3ce44SJohn Forte 			/* Start over becasue we dropped the lock */
932fcf3ce44SJohn Forte 			goto start_els_posting;
933fcf3ce44SJohn Forte 		}
934fcf3ce44SJohn Forte 
935fcf3ce44SJohn Forte 		/* A PLOGI is by default a logout of previous session */
936fcf3ce44SJohn Forte 		irp->irp_deregister_timer = ddi_get_lbolt() +
937590ebdb0Sallan 		    drv_usectohz(USEC_DEREG_RP_TIMEOUT);
938fcf3ce44SJohn Forte 		irp->irp_dereg_count = 0;
939fcf3ce44SJohn Forte 		fct_post_to_discovery_queue(iport, irp, NULL);
940fcf3ce44SJohn Forte 
941fcf3ce44SJohn Forte 		/* A PLOGI also invalidates any RSCNs related to this rp */
9421a5e258fSJosef 'Jeff' Sipek 		atomic_inc_32(&irp->irp_rscn_counter);
943fcf3ce44SJohn Forte 	} else {
944fcf3ce44SJohn Forte 		/*
945fcf3ce44SJohn Forte 		 * For everything else, we have (or be able to lookup) a
946fcf3ce44SJohn Forte 		 * valid port pointer.
947fcf3ce44SJohn Forte 		 */
948fcf3ce44SJohn Forte 		if (irp == NULL) {
949fcf3ce44SJohn Forte 			rw_exit(&iport->iport_lock);
950fcf3ce44SJohn Forte 			if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
951fcf3ce44SJohn Forte 				/* XXX Throw a logout to the initiator */
952fcf3ce44SJohn Forte 				stmf_trace(iport->iport_alias, "ELS %x "
953fcf3ce44SJohn Forte 				    "received from %x without a session",
954fcf3ce44SJohn Forte 				    els->els_req_payload[0], cmd->cmd_rportid);
955fcf3ce44SJohn Forte 			} else {
956fcf3ce44SJohn Forte 				stmf_trace(iport->iport_alias, "Sending ELS %x "
957fcf3ce44SJohn Forte 				    "to %x without a session",
958fcf3ce44SJohn Forte 				    els->els_req_payload[0], cmd->cmd_rportid);
959fcf3ce44SJohn Forte 			}
960fcf3ce44SJohn Forte 			fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN);
961fcf3ce44SJohn Forte 			return;
962fcf3ce44SJohn Forte 		}
963fcf3ce44SJohn Forte 	}
964fcf3ce44SJohn Forte 	cmd->cmd_rp = rp = irp->irp_rp;
965fcf3ce44SJohn Forte 
966fcf3ce44SJohn Forte 	/*
967fcf3ce44SJohn Forte 	 * Lets get a slot for this els
968fcf3ce44SJohn Forte 	 */
969fcf3ce44SJohn Forte 	if (!(icmd->icmd_flags & ICMD_IMPLICIT)) {
970fcf3ce44SJohn Forte 		cmd_slot = fct_alloc_cmd_slot(iport, cmd);
971fcf3ce44SJohn Forte 		if (cmd_slot == FCT_SLOT_EOL) {
972fcf3ce44SJohn Forte 			/* This should not have happened */
973fcf3ce44SJohn Forte 			rw_exit(&iport->iport_lock);
974fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias,
975590ebdb0Sallan 			    "ran out of xchg resources");
976fcf3ce44SJohn Forte 			fct_queue_cmd_for_termination(cmd,
977590ebdb0Sallan 			    FCT_NO_XCHG_RESOURCE);
978fcf3ce44SJohn Forte 			return;
979fcf3ce44SJohn Forte 		}
980fcf3ce44SJohn Forte 	} else {
981fcf3ce44SJohn Forte 		/*
982fcf3ce44SJohn Forte 		 * Tell the framework that fct_cmd_free() can decrement the
983fcf3ce44SJohn Forte 		 * irp_nonfcp_xchg_count variable.
984fcf3ce44SJohn Forte 		 */
985fcf3ce44SJohn Forte 		atomic_or_32(&icmd->icmd_flags, ICMD_IMPLICIT_CMD_HAS_RESOURCE);
986fcf3ce44SJohn Forte 	}
9871a5e258fSJosef 'Jeff' Sipek 	atomic_inc_16(&irp->irp_nonfcp_xchg_count);
988fcf3ce44SJohn Forte 
989fcf3ce44SJohn Forte 	/*
990fcf3ce44SJohn Forte 	 * Grab the remote port lock while we modify the port state.
991fcf3ce44SJohn Forte 	 * we should not drop the fca port lock (as a reader) until we
992fcf3ce44SJohn Forte 	 * modify the remote port state.
993fcf3ce44SJohn Forte 	 */
994fcf3ce44SJohn Forte 	rw_enter(&irp->irp_lock, RW_WRITER);
995fcf3ce44SJohn Forte 	if ((op == ELS_OP_PLOGI) || (op == ELS_OP_PRLI) ||
996fcf3ce44SJohn Forte 	    (op == ELS_OP_LOGO) || (op == ELS_OP_PRLO) ||
997fcf3ce44SJohn Forte 	    (op == ELS_OP_TPRLO)) {
998fcf3ce44SJohn Forte 		uint32_t rf = IRP_PRLI_DONE;
999fcf3ce44SJohn Forte 		if ((op == ELS_OP_PLOGI) || (op == ELS_OP_LOGO)) {
1000fcf3ce44SJohn Forte 			rf |= IRP_PLOGI_DONE;
1001fcf3ce44SJohn Forte 			if (irp->irp_flags & IRP_PLOGI_DONE)
10021a5e258fSJosef 'Jeff' Sipek 				atomic_dec_32(&iport->iport_nrps_login);
1003fcf3ce44SJohn Forte 		}
10041a5e258fSJosef 'Jeff' Sipek 		atomic_inc_16(&irp->irp_sa_elses_count);
1005fcf3ce44SJohn Forte 		atomic_and_32(&irp->irp_flags, ~rf);
1006fcf3ce44SJohn Forte 		atomic_or_32(&icmd->icmd_flags, ICMD_SESSION_AFFECTING);
1007fcf3ce44SJohn Forte 	} else {
10081a5e258fSJosef 'Jeff' Sipek 		atomic_inc_16(&irp->irp_nsa_elses_count);
1009fcf3ce44SJohn Forte 	}
1010fcf3ce44SJohn Forte 
1011fcf3ce44SJohn Forte 	fct_post_to_discovery_queue(iport, irp, icmd);
1012fcf3ce44SJohn Forte 
1013fcf3ce44SJohn Forte 	rw_exit(&irp->irp_lock);
1014fcf3ce44SJohn Forte 	rw_exit(&iport->iport_lock);
1015fcf3ce44SJohn Forte }
1016fcf3ce44SJohn Forte 
1017fcf3ce44SJohn Forte /*
1018fcf3ce44SJohn Forte  * Cleanup I/Os for a rport. ttc is a bit Mask of cmd types to clean.
1019fcf3ce44SJohn Forte  * No locks held.
1020fcf3ce44SJohn Forte  */
1021fcf3ce44SJohn Forte int
fct_trigger_rport_cleanup(fct_i_remote_port_t * irp,int ttc)1022fcf3ce44SJohn Forte fct_trigger_rport_cleanup(fct_i_remote_port_t *irp, int ttc)
1023fcf3ce44SJohn Forte {
1024fcf3ce44SJohn Forte 	fct_remote_port_t	*rp = irp->irp_rp;
1025fcf3ce44SJohn Forte 	fct_local_port_t	*port = rp->rp_port;
1026fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport =
1027590ebdb0Sallan 	    (fct_i_local_port_t *)port->port_fct_private;
1028fcf3ce44SJohn Forte 	fct_cmd_t		*cmd;
1029fcf3ce44SJohn Forte 	fct_i_cmd_t		*icmd;
1030fcf3ce44SJohn Forte 	int			i;
1031fcf3ce44SJohn Forte 	int			ret;
1032fcf3ce44SJohn Forte 	uint16_t		total, cleaned, skipped, unhandled;
1033fcf3ce44SJohn Forte 
1034fcf3ce44SJohn Forte 	rw_enter(&iport->iport_lock, RW_WRITER);
1035fcf3ce44SJohn Forte 	rw_enter(&irp->irp_lock, RW_WRITER);
1036fcf3ce44SJohn Forte 	mutex_enter(&iport->iport_worker_lock);
1037fcf3ce44SJohn Forte 	total = port->port_max_xchges - iport->iport_nslots_free;
1038fcf3ce44SJohn Forte 	cleaned = skipped = unhandled = 0;
1039fcf3ce44SJohn Forte 
1040fcf3ce44SJohn Forte 	for (i = 0; i < port->port_max_xchges; i++) {
1041fcf3ce44SJohn Forte 		if (iport->iport_cmd_slots[i].slot_cmd == NULL)
1042fcf3ce44SJohn Forte 			continue;
1043fcf3ce44SJohn Forte 		icmd = iport->iport_cmd_slots[i].slot_cmd;
1044fcf3ce44SJohn Forte 		if (icmd->icmd_flags & ICMD_IN_TRANSITION) {
1045fcf3ce44SJohn Forte 			unhandled++;
1046fcf3ce44SJohn Forte 			continue;
1047fcf3ce44SJohn Forte 		}
1048fcf3ce44SJohn Forte 
1049fcf3ce44SJohn Forte 		if (icmd->icmd_flags & ICMD_CMD_COMPLETE) {
1050fcf3ce44SJohn Forte 			unhandled++;
1051fcf3ce44SJohn Forte 			continue;
1052fcf3ce44SJohn Forte 		}
1053fcf3ce44SJohn Forte 
1054fcf3ce44SJohn Forte 		cmd = icmd->icmd_cmd;
1055fcf3ce44SJohn Forte 		if (cmd->cmd_rp != rp) {
1056fcf3ce44SJohn Forte 			skipped++;
1057fcf3ce44SJohn Forte 			continue;
1058fcf3ce44SJohn Forte 		}
1059fcf3ce44SJohn Forte 		if (cmd->cmd_type & ttc) {
1060fcf3ce44SJohn Forte 			if (cmd->cmd_type == FCT_CMD_FCP_XCHG)
1061fcf3ce44SJohn Forte 				fct_queue_scsi_task_for_termination(cmd,
1062590ebdb0Sallan 				    FCT_ABORTED);
1063fcf3ce44SJohn Forte 			else
1064fcf3ce44SJohn Forte 				fct_q_for_termination_lock_held(iport, icmd,
1065590ebdb0Sallan 				    FCT_ABORTED);
1066fcf3ce44SJohn Forte 			cleaned++;
1067fcf3ce44SJohn Forte 		} else {
1068fcf3ce44SJohn Forte 			skipped++;
1069fcf3ce44SJohn Forte 		}
1070fcf3ce44SJohn Forte 	}
1071fcf3ce44SJohn Forte 	if (((cleaned + skipped) == total) && (unhandled == 0)) {
1072fcf3ce44SJohn Forte 		ret = 1;
1073fcf3ce44SJohn Forte 	} else {
1074fcf3ce44SJohn Forte 		/*
1075fcf3ce44SJohn Forte 		 * XXX: handle this situation.
1076fcf3ce44SJohn Forte 		 */
1077fcf3ce44SJohn Forte 		stmf_trace(iport->iport_alias, "Clean up trouble for irp"
1078fcf3ce44SJohn Forte 		    " %p, c/s/u/t = %d/%d/%d/%d", irp, cleaned, skipped,
1079590ebdb0Sallan 		    unhandled, total);
1080fcf3ce44SJohn Forte 		ret = 0;
1081fcf3ce44SJohn Forte 	}
1082fcf3ce44SJohn Forte 	if ((cleaned) && IS_WORKER_SLEEPING(iport))
1083fcf3ce44SJohn Forte 		cv_signal(&iport->iport_worker_cv);
1084fcf3ce44SJohn Forte 	mutex_exit(&iport->iport_worker_lock);
1085fcf3ce44SJohn Forte 	rw_exit(&irp->irp_lock);
1086fcf3ce44SJohn Forte 	rw_exit(&iport->iport_lock);
1087fcf3ce44SJohn Forte 	return (ret);
1088fcf3ce44SJohn Forte }
1089fcf3ce44SJohn Forte 
1090fcf3ce44SJohn Forte void
fct_dequeue_els(fct_i_remote_port_t * irp)1091fcf3ce44SJohn Forte fct_dequeue_els(fct_i_remote_port_t *irp)
1092fcf3ce44SJohn Forte {
1093fcf3ce44SJohn Forte 	fct_i_cmd_t *icmd;
1094fcf3ce44SJohn Forte 
1095fcf3ce44SJohn Forte 	rw_enter(&irp->irp_lock, RW_WRITER);
1096fcf3ce44SJohn Forte 	icmd = irp->irp_els_list;
1097fcf3ce44SJohn Forte 	irp->irp_els_list = icmd->icmd_next;
1098fcf3ce44SJohn Forte 	atomic_and_32(&icmd->icmd_flags, ~ICMD_IN_IRP_QUEUE);
1099fcf3ce44SJohn Forte 	rw_exit(&irp->irp_lock);
1100fcf3ce44SJohn Forte }
1101fcf3ce44SJohn Forte 
1102fcf3ce44SJohn Forte fct_status_t
fct_register_remote_port(fct_local_port_t * port,fct_remote_port_t * rp,fct_cmd_t * cmd)1103fcf3ce44SJohn Forte fct_register_remote_port(fct_local_port_t *port, fct_remote_port_t *rp,
1104fcf3ce44SJohn Forte 				fct_cmd_t *cmd)
1105fcf3ce44SJohn Forte {
1106fcf3ce44SJohn Forte 	fct_status_t ret;
1107fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport;
1108fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp;
1109fcf3ce44SJohn Forte 	int			i;
11104558d122SViswanathan Kannappan 	char			info[FCT_INFO_LEN];
1111fcf3ce44SJohn Forte 
1112fcf3ce44SJohn Forte 	iport = (fct_i_local_port_t *)port->port_fct_private;
1113fcf3ce44SJohn Forte 	irp = (fct_i_remote_port_t *)rp->rp_fct_private;
1114fcf3ce44SJohn Forte 
1115fcf3ce44SJohn Forte 	if ((ret = port->port_register_remote_port(port, rp, cmd)) !=
1116590ebdb0Sallan 	    FCT_SUCCESS)
1117fcf3ce44SJohn Forte 		return (ret);
1118fcf3ce44SJohn Forte 
1119fcf3ce44SJohn Forte 	rw_enter(&iport->iport_lock, RW_WRITER);
1120fcf3ce44SJohn Forte 	rw_enter(&irp->irp_lock, RW_WRITER);
1121fcf3ce44SJohn Forte 	if (rp->rp_handle != FCT_HANDLE_NONE) {
1122fcf3ce44SJohn Forte 		if (rp->rp_handle >= port->port_max_logins) {
11234558d122SViswanathan Kannappan 			(void) snprintf(info, sizeof (info),
1124fcf3ce44SJohn Forte 			    "fct_register_remote_port: FCA "
1125fcf3ce44SJohn Forte 			    "returned a	handle (%d) for portid %x which is "
1126fcf3ce44SJohn Forte 			    "out of range (max logins = %d)", rp->rp_handle,
1127fcf3ce44SJohn Forte 			    rp->rp_id, port->port_max_logins);
1128fcf3ce44SJohn Forte 			goto hba_fatal_err;
1129fcf3ce44SJohn Forte 		}
1130fcf3ce44SJohn Forte 		if ((iport->iport_rp_slots[rp->rp_handle] != NULL) &&
1131fcf3ce44SJohn Forte 		    (iport->iport_rp_slots[rp->rp_handle] != irp)) {
1132590ebdb0Sallan 			fct_i_remote_port_t *t_irp =
1133590ebdb0Sallan 			    iport->iport_rp_slots[rp->rp_handle];
11344558d122SViswanathan Kannappan 			(void) snprintf(info, sizeof (info),
11354558d122SViswanathan Kannappan 			    "fct_register_remote_port: "
1136fcf3ce44SJohn Forte 			    "FCA returned a handle %d for portid %x "
1137fcf3ce44SJohn Forte 			    "which was already in use for a different "
1138fcf3ce44SJohn Forte 			    "portid (%x)", rp->rp_handle, rp->rp_id,
1139590ebdb0Sallan 			    t_irp->irp_rp->rp_id);
1140fcf3ce44SJohn Forte 			goto hba_fatal_err;
1141fcf3ce44SJohn Forte 		}
1142fcf3ce44SJohn Forte 	} else {
1143fcf3ce44SJohn Forte 		/* Pick a handle for this port */
1144fcf3ce44SJohn Forte 		for (i = 0; i < port->port_max_logins; i++) {
1145fcf3ce44SJohn Forte 			if (iport->iport_rp_slots[i] == NULL) {
1146fcf3ce44SJohn Forte 				break;
1147fcf3ce44SJohn Forte 			}
1148fcf3ce44SJohn Forte 		}
1149fcf3ce44SJohn Forte 		if (i == port->port_max_logins) {
1150fcf3ce44SJohn Forte 			/* This is really pushing it. */
11514558d122SViswanathan Kannappan 			(void) snprintf(info, sizeof (info),
11524558d122SViswanathan Kannappan 			    "fct_register_remote_port "
1153fcf3ce44SJohn Forte 			    "Cannot register portid %x because all the "
1154fcf3ce44SJohn Forte 			    "handles are used up", rp->rp_id);
1155fcf3ce44SJohn Forte 			goto hba_fatal_err;
1156fcf3ce44SJohn Forte 		}
1157fcf3ce44SJohn Forte 		rp->rp_handle = i;
1158fcf3ce44SJohn Forte 	}
1159fcf3ce44SJohn Forte 	/* By this time rport_handle is valid */
1160fcf3ce44SJohn Forte 	if ((irp->irp_flags & IRP_HANDLE_OPENED) == 0) {
1161fcf3ce44SJohn Forte 		iport->iport_rp_slots[rp->rp_handle] = irp;
1162fcf3ce44SJohn Forte 		atomic_or_32(&irp->irp_flags, IRP_HANDLE_OPENED);
1163fcf3ce44SJohn Forte 	}
1164640c1670SJosef 'Jeff' Sipek 	atomic_inc_64(&iport->iport_last_change);
1165fcf3ce44SJohn Forte 	fct_log_remote_port_event(port, ESC_SUNFC_TARGET_ADD,
1166fcf3ce44SJohn Forte 	    rp->rp_pwwn, rp->rp_id);
1167fcf3ce44SJohn Forte 
1168fcf3ce44SJohn Forte register_rp_done:;
1169fcf3ce44SJohn Forte 	rw_exit(&irp->irp_lock);
1170fcf3ce44SJohn Forte 	rw_exit(&iport->iport_lock);
1171fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
1172fcf3ce44SJohn Forte 
1173fcf3ce44SJohn Forte hba_fatal_err:;
1174fcf3ce44SJohn Forte 	rw_exit(&irp->irp_lock);
1175fcf3ce44SJohn Forte 	rw_exit(&iport->iport_lock);
1176fcf3ce44SJohn Forte 	/*
1177fcf3ce44SJohn Forte 	 * XXX Throw HBA fatal error event
1178fcf3ce44SJohn Forte 	 */
1179fcf3ce44SJohn Forte 	(void) fct_port_shutdown(iport->iport_port,
1180fcf3ce44SJohn Forte 	    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
1181fcf3ce44SJohn Forte 	return (FCT_FAILURE);
1182fcf3ce44SJohn Forte }
1183fcf3ce44SJohn Forte 
1184fcf3ce44SJohn Forte fct_status_t
fct_deregister_remote_port(fct_local_port_t * port,fct_remote_port_t * rp)1185fcf3ce44SJohn Forte fct_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp)
1186fcf3ce44SJohn Forte {
1187fcf3ce44SJohn Forte 	fct_status_t		 ret   = FCT_SUCCESS;
1188fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport = PORT_TO_IPORT(port);
1189fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp   = RP_TO_IRP(rp);
1190fcf3ce44SJohn Forte 
1191fcf3ce44SJohn Forte 	if (irp->irp_snn) {
1192fcf3ce44SJohn Forte 		kmem_free(irp->irp_snn, strlen(irp->irp_snn) + 1);
1193fcf3ce44SJohn Forte 		irp->irp_snn = NULL;
1194fcf3ce44SJohn Forte 	}
1195fcf3ce44SJohn Forte 	if (irp->irp_spn) {
1196fcf3ce44SJohn Forte 		kmem_free(irp->irp_spn, strlen(irp->irp_spn) + 1);
1197fcf3ce44SJohn Forte 		irp->irp_spn = NULL;
1198fcf3ce44SJohn Forte 	}
1199fcf3ce44SJohn Forte 
1200fcf3ce44SJohn Forte 	if ((ret = port->port_deregister_remote_port(port, rp)) !=
1201fcf3ce44SJohn Forte 	    FCT_SUCCESS) {
1202fcf3ce44SJohn Forte 		return (ret);
1203fcf3ce44SJohn Forte 	}
1204fcf3ce44SJohn Forte 
1205fcf3ce44SJohn Forte 	if (irp->irp_flags & IRP_HANDLE_OPENED) {
1206fcf3ce44SJohn Forte 		atomic_and_32(&irp->irp_flags, ~IRP_HANDLE_OPENED);
1207fcf3ce44SJohn Forte 		iport->iport_rp_slots[rp->rp_handle] = NULL;
1208fcf3ce44SJohn Forte 	}
1209640c1670SJosef 'Jeff' Sipek 	atomic_inc_64(&iport->iport_last_change);
1210fcf3ce44SJohn Forte 	fct_log_remote_port_event(port, ESC_SUNFC_TARGET_REMOVE,
1211fcf3ce44SJohn Forte 	    rp->rp_pwwn, rp->rp_id);
1212fcf3ce44SJohn Forte 
1213fcf3ce44SJohn Forte 	return (FCT_SUCCESS);
1214fcf3ce44SJohn Forte }
1215fcf3ce44SJohn Forte 
1216fcf3ce44SJohn Forte fct_status_t
fct_send_accrjt(fct_cmd_t * cmd,uint8_t accrjt,uint8_t reason,uint8_t expl)1217fcf3ce44SJohn Forte fct_send_accrjt(fct_cmd_t *cmd, uint8_t accrjt, uint8_t reason, uint8_t expl)
1218fcf3ce44SJohn Forte {
1219fcf3ce44SJohn Forte 	fct_local_port_t *port = (fct_local_port_t *)cmd->cmd_port;
1220fcf3ce44SJohn Forte 	fct_els_t *els = (fct_els_t *)cmd->cmd_specific;
1221fcf3ce44SJohn Forte 
1222fcf3ce44SJohn Forte 	els->els_resp_size = els->els_resp_alloc_size = 8;
1223fcf3ce44SJohn Forte 	els->els_resp_payload = (uint8_t *)kmem_zalloc(8, KM_SLEEP);
1224fcf3ce44SJohn Forte 	els->els_resp_payload[0] = accrjt;
1225fcf3ce44SJohn Forte 	if (accrjt == 1) {
1226fcf3ce44SJohn Forte 		els->els_resp_payload[5] = reason;
1227fcf3ce44SJohn Forte 		els->els_resp_payload[6] = expl;
1228fcf3ce44SJohn Forte 	} else {
1229fcf3ce44SJohn Forte 		els->els_resp_size = 4;
1230fcf3ce44SJohn Forte 	}
1231fcf3ce44SJohn Forte 
1232fcf3ce44SJohn Forte 	return (port->port_send_cmd_response(cmd, 0));
1233fcf3ce44SJohn Forte }
1234fcf3ce44SJohn Forte 
1235fcf3ce44SJohn Forte 
1236fcf3ce44SJohn Forte disc_action_t
fct_walk_discovery_queue(fct_i_local_port_t * iport)1237fcf3ce44SJohn Forte fct_walk_discovery_queue(fct_i_local_port_t *iport)
1238fcf3ce44SJohn Forte {
12394558d122SViswanathan Kannappan 	char			info[FCT_INFO_LEN];
1240fcf3ce44SJohn Forte 	fct_i_remote_port_t	**pirp;
1241fcf3ce44SJohn Forte 	fct_i_remote_port_t	*prev_irp = NULL;
1242fcf3ce44SJohn Forte 	disc_action_t		suggested_action = DISC_ACTION_NO_WORK;
1243fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp_dereg_list = NULL;
1244fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp_cur_item = NULL;
1245fcf3ce44SJohn Forte 
1246fcf3ce44SJohn Forte 	for (pirp = &iport->iport_rpwe_head; *pirp != NULL; ) {
1247fcf3ce44SJohn Forte 		fct_i_remote_port_t *irp = *pirp;
1248fcf3ce44SJohn Forte 		disc_action_t ret = DISC_ACTION_NO_WORK;
1249fcf3ce44SJohn Forte 		int do_deregister = 0;
1250590ebdb0Sallan 		int irp_deregister_timer = 0;
1251fcf3ce44SJohn Forte 
1252fcf3ce44SJohn Forte 		if (irp->irp_els_list) {
1253fcf3ce44SJohn Forte 			ret |= fct_process_els(iport, irp);
1254fcf3ce44SJohn Forte 		}
1255590ebdb0Sallan 
1256590ebdb0Sallan 		irp_deregister_timer = irp->irp_deregister_timer;
1257590ebdb0Sallan 		if (irp_deregister_timer) {
1258590ebdb0Sallan 			if (ddi_get_lbolt() >= irp_deregister_timer) {
1259fcf3ce44SJohn Forte 				do_deregister = 1;
1260fcf3ce44SJohn Forte 			} else {
1261fcf3ce44SJohn Forte 				ret |= DISC_ACTION_DELAY_RESCAN;
1262fcf3ce44SJohn Forte 			}
1263fcf3ce44SJohn Forte 		}
1264fcf3ce44SJohn Forte 		suggested_action |= ret;
1265fcf3ce44SJohn Forte 
1266fcf3ce44SJohn Forte 		if (irp->irp_els_list == NULL) {
1267fcf3ce44SJohn Forte 			mutex_exit(&iport->iport_worker_lock);
1268fcf3ce44SJohn Forte 			rw_enter(&iport->iport_lock, RW_WRITER);
1269fcf3ce44SJohn Forte 			rw_enter(&irp->irp_lock, RW_WRITER);
1270fcf3ce44SJohn Forte 			mutex_enter(&iport->iport_worker_lock);
1271fcf3ce44SJohn Forte 			if (irp->irp_els_list == NULL) {
1272590ebdb0Sallan 				if (!irp_deregister_timer ||
1273fcf3ce44SJohn Forte 				    (do_deregister &&
1274fcf3ce44SJohn Forte 				    !irp->irp_sa_elses_count &&
1275fcf3ce44SJohn Forte 				    !irp->irp_nsa_elses_count &&
1276fcf3ce44SJohn Forte 				    !irp->irp_fcp_xchg_count &&
1277fcf3ce44SJohn Forte 				    !irp->irp_nonfcp_xchg_count)) {
1278fcf3ce44SJohn Forte 					/* dequeue irp from discovery queue */
1279fcf3ce44SJohn Forte 					atomic_and_32(&irp->irp_flags,
1280590ebdb0Sallan 					    ~IRP_IN_DISCOVERY_QUEUE);
1281fcf3ce44SJohn Forte 					*pirp = irp->irp_discovery_next;
1282fcf3ce44SJohn Forte 					if (iport->iport_rpwe_head == NULL)
1283fcf3ce44SJohn Forte 						iport->iport_rpwe_tail = NULL;
1284fcf3ce44SJohn Forte 					else if (irp == iport->iport_rpwe_tail)
1285fcf3ce44SJohn Forte 						iport->iport_rpwe_tail =
1286590ebdb0Sallan 						    prev_irp;
1287fcf3ce44SJohn Forte 
1288fcf3ce44SJohn Forte 					irp->irp_discovery_next = NULL;
1289fcf3ce44SJohn Forte 					if (do_deregister) {
1290fcf3ce44SJohn Forte 						fct_deque_rp(iport, irp);
1291fcf3ce44SJohn Forte 						rw_exit(&irp->irp_lock);
1292fcf3ce44SJohn Forte 						/* queue irp for deregister */
1293fcf3ce44SJohn Forte 						irp->irp_next = NULL;
1294fcf3ce44SJohn Forte 						if (!irp_dereg_list) {
1295fcf3ce44SJohn Forte 							irp_dereg_list =
1296fcf3ce44SJohn Forte 							    irp_cur_item = irp;
1297fcf3ce44SJohn Forte 						} else {
1298fcf3ce44SJohn Forte 							irp_cur_item->irp_next =
1299590ebdb0Sallan 							    irp;
1300fcf3ce44SJohn Forte 							irp_cur_item = irp;
1301fcf3ce44SJohn Forte 						}
1302fcf3ce44SJohn Forte 					} else {
1303fcf3ce44SJohn Forte 						rw_exit(&irp->irp_lock);
1304fcf3ce44SJohn Forte 					}
1305fcf3ce44SJohn Forte 					rw_exit(&iport->iport_lock);
1306fcf3ce44SJohn Forte 					if ((irp = *pirp) == NULL)
1307fcf3ce44SJohn Forte 						break;
1308fcf3ce44SJohn Forte 				} else {
1309fcf3ce44SJohn Forte 					/*
1310fcf3ce44SJohn Forte 					 * wait for another scan until
1311fcf3ce44SJohn Forte 					 * deregister timeout
1312fcf3ce44SJohn Forte 					 */
1313fcf3ce44SJohn Forte 					rw_exit(&irp->irp_lock);
1314fcf3ce44SJohn Forte 					rw_exit(&iport->iport_lock);
1315fcf3ce44SJohn Forte 				}
1316fcf3ce44SJohn Forte 			} else {
1317fcf3ce44SJohn Forte 				rw_exit(&irp->irp_lock);
1318fcf3ce44SJohn Forte 				rw_exit(&iport->iport_lock);
1319fcf3ce44SJohn Forte 				/*
1320fcf3ce44SJohn Forte 				 * When we dropped the lock,
1321fcf3ce44SJohn Forte 				 * something went in.
1322fcf3ce44SJohn Forte 				 */
1323fcf3ce44SJohn Forte 				suggested_action |= DISC_ACTION_RESCAN;
1324fcf3ce44SJohn Forte 			}
1325fcf3ce44SJohn Forte 		}
1326fcf3ce44SJohn Forte 		pirp = &(irp->irp_discovery_next);
1327fcf3ce44SJohn Forte 		prev_irp = irp;
1328fcf3ce44SJohn Forte 	}
1329fcf3ce44SJohn Forte 	/* do deregister */
1330fcf3ce44SJohn Forte 	if (irp_dereg_list) {
1331fcf3ce44SJohn Forte 		fct_i_remote_port_t *irp_next_item;
1332fcf3ce44SJohn Forte 		/* drop the lock */
1333fcf3ce44SJohn Forte 		mutex_exit(&iport->iport_worker_lock);
1334fcf3ce44SJohn Forte 
1335fcf3ce44SJohn Forte 		for (irp_cur_item = irp_dereg_list; irp_cur_item != NULL; ) {
1336fcf3ce44SJohn Forte 			irp_next_item = irp_cur_item->irp_next;
1337fcf3ce44SJohn Forte 			if (fct_deregister_remote_port(iport->iport_port,
1338fcf3ce44SJohn Forte 			    irp_cur_item->irp_rp) == FCT_SUCCESS) {
1339fcf3ce44SJohn Forte 				fct_free(irp_cur_item->irp_rp);
1340fcf3ce44SJohn Forte 			} else if (++irp_cur_item->irp_dereg_count >= 5) {
1341fcf3ce44SJohn Forte 				irp_cur_item->irp_deregister_timer = 0;
1342fcf3ce44SJohn Forte 				irp_cur_item->irp_dereg_count = 0;
1343fcf3ce44SJohn Forte 
1344fcf3ce44SJohn Forte 				/*
1345fcf3ce44SJohn Forte 				 * It looks like we can't deregister it in the
1346fcf3ce44SJohn Forte 				 * normal way, so we have to use extrem way
1347fcf3ce44SJohn Forte 				 */
13484558d122SViswanathan Kannappan 				(void) snprintf(info, sizeof (info),
1349fcf3ce44SJohn Forte 				    "fct_walk_discovery_queue: "
1350fcf3ce44SJohn Forte 				    "iport-%p, can't deregister irp-%p after "
1351fcf3ce44SJohn Forte 				    "trying 5 times", (void *)iport,
1352fcf3ce44SJohn Forte 				    (void *)irp_cur_item);
1353fcf3ce44SJohn Forte 				(void) fct_port_shutdown(iport->iport_port,
1354fcf3ce44SJohn Forte 				    STMF_RFLAG_FATAL_ERROR |
1355fcf3ce44SJohn Forte 				    STMF_RFLAG_RESET, info);
1356fcf3ce44SJohn Forte 				suggested_action |= DISC_ACTION_RESCAN;
1357fcf3ce44SJohn Forte 				break;
1358fcf3ce44SJohn Forte 			} else {
1359fcf3ce44SJohn Forte 				/* grab the iport_lock */
1360fcf3ce44SJohn Forte 				rw_enter(&iport->iport_lock, RW_WRITER);
1361fcf3ce44SJohn Forte 				/* recover */
1362fcf3ce44SJohn Forte 				irp_cur_item->irp_deregister_timer =
1363fcf3ce44SJohn Forte 				    ddi_get_lbolt() +
1364fcf3ce44SJohn Forte 				    drv_usectohz(USEC_DEREG_RP_INTERVAL);
1365fcf3ce44SJohn Forte 				fct_post_to_discovery_queue(iport,
1366fcf3ce44SJohn Forte 				    irp_cur_item, NULL);
1367fcf3ce44SJohn Forte 				fct_queue_rp(iport, irp_cur_item);
1368fcf3ce44SJohn Forte 				rw_exit(&iport->iport_lock);
1369fcf3ce44SJohn Forte 				suggested_action |= DISC_ACTION_DELAY_RESCAN;
1370fcf3ce44SJohn Forte 			}
1371fcf3ce44SJohn Forte 			irp_cur_item = irp_next_item;
1372fcf3ce44SJohn Forte 		}
1373fcf3ce44SJohn Forte 		mutex_enter(&iport->iport_worker_lock);
1374fcf3ce44SJohn Forte 	}
1375fcf3ce44SJohn Forte 	return (suggested_action);
1376fcf3ce44SJohn Forte }
1377fcf3ce44SJohn Forte 
1378fcf3ce44SJohn Forte disc_action_t
fct_process_plogi(fct_i_cmd_t * icmd)1379fcf3ce44SJohn Forte fct_process_plogi(fct_i_cmd_t *icmd)
1380fcf3ce44SJohn Forte {
1381fcf3ce44SJohn Forte 	fct_cmd_t		*cmd = icmd->icmd_cmd;
1382fcf3ce44SJohn Forte 	fct_remote_port_t	*rp = cmd->cmd_rp;
1383fcf3ce44SJohn Forte 	fct_local_port_t	*port = cmd->cmd_port;
1384fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
1385590ebdb0Sallan 	    port->port_fct_private;
1386fcf3ce44SJohn Forte 	fct_els_t		*els = (fct_els_t *)
1387590ebdb0Sallan 	    cmd->cmd_specific;
1388fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp = (fct_i_remote_port_t *)
1389590ebdb0Sallan 	    rp->rp_fct_private;
1390fcf3ce44SJohn Forte 	uint8_t			*p;
1391fcf3ce44SJohn Forte 	fct_status_t		 ret;
1392fcf3ce44SJohn Forte 	uint8_t			 cmd_type   = cmd->cmd_type;
1393fcf3ce44SJohn Forte 	uint32_t		 icmd_flags = icmd->icmd_flags;
1394fcf3ce44SJohn Forte 	clock_t			 end_time;
13954558d122SViswanathan Kannappan 	char			 info[FCT_INFO_LEN];
1396fcf3ce44SJohn Forte 
1397d8c54e3dSSam Cramer 	DTRACE_FC_4(rport__login__start,
1398d8c54e3dSSam Cramer 	    fct_cmd_t, cmd,
1399d8c54e3dSSam Cramer 	    fct_local_port_t, port,
1400d8c54e3dSSam Cramer 	    fct_i_remote_port_t, irp,
1401d8c54e3dSSam Cramer 	    int, (cmd_type != FCT_CMD_RCVD_ELS));
1402d8c54e3dSSam Cramer 
1403fcf3ce44SJohn Forte 	/* Drain I/Os */
1404fcf3ce44SJohn Forte 	if ((irp->irp_nonfcp_xchg_count + irp->irp_fcp_xchg_count) > 1) {
1405fcf3ce44SJohn Forte 		/* Trigger cleanup if necessary */
1406fcf3ce44SJohn Forte 		if ((irp->irp_flags & IRP_SESSION_CLEANUP) == 0) {
1407fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "handling PLOGI rp_id"
1408fcf3ce44SJohn Forte 			    " %x. Triggering cleanup", cmd->cmd_rportid);
1409fcf3ce44SJohn Forte 			/* Cleanup everything except elses */
1410fcf3ce44SJohn Forte 			if (fct_trigger_rport_cleanup(irp, ~(cmd->cmd_type))) {
1411fcf3ce44SJohn Forte 				atomic_or_32(&irp->irp_flags,
1412590ebdb0Sallan 				    IRP_SESSION_CLEANUP);
1413fcf3ce44SJohn Forte 			} else {
1414fcf3ce44SJohn Forte 				/* XXX: handle this */
1415fcf3ce44SJohn Forte 				/* EMPTY */
1416fcf3ce44SJohn Forte 			}
1417fcf3ce44SJohn Forte 		}
1418fcf3ce44SJohn Forte 
1419fcf3ce44SJohn Forte 		end_time = icmd->icmd_start_time +
1420fcf3ce44SJohn Forte 		    drv_usectohz(USEC_ELS_TIMEOUT);
1421fcf3ce44SJohn Forte 		if (ddi_get_lbolt() > end_time) {
14224558d122SViswanathan Kannappan 			(void) snprintf(info, sizeof (info),
1423fcf3ce44SJohn Forte 			    "fct_process_plogi: unable to "
1424fcf3ce44SJohn Forte 			    "clean up I/O. iport-%p, icmd-%p", (void *)iport,
1425fcf3ce44SJohn Forte 			    (void *)icmd);
1426fcf3ce44SJohn Forte 			(void) fct_port_shutdown(iport->iport_port,
1427fcf3ce44SJohn Forte 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
1428fcf3ce44SJohn Forte 
1429fcf3ce44SJohn Forte 			return (DISC_ACTION_DELAY_RESCAN);
1430fcf3ce44SJohn Forte 		}
1431fcf3ce44SJohn Forte 
1432fcf3ce44SJohn Forte 		if ((ddi_get_lbolt() & 0x7f) == 0) {
1433fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "handling"
1434590ebdb0Sallan 			    " PLOGI rp_id %x, waiting for cmds to"
1435590ebdb0Sallan 			    " drain", cmd->cmd_rportid);
1436fcf3ce44SJohn Forte 		}
1437fcf3ce44SJohn Forte 		return (DISC_ACTION_DELAY_RESCAN);
1438fcf3ce44SJohn Forte 	}
1439fcf3ce44SJohn Forte 	atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP);
1440fcf3ce44SJohn Forte 
1441fcf3ce44SJohn Forte 	/* Session can only be terminated after all the I/Os have drained */
1442fcf3ce44SJohn Forte 	if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) {
1443fcf3ce44SJohn Forte 		stmf_deregister_scsi_session(iport->iport_port->port_lport,
1444fcf3ce44SJohn Forte 		    irp->irp_session);
1445fcf3ce44SJohn Forte 		stmf_free(irp->irp_session);
1446fcf3ce44SJohn Forte 		irp->irp_session = NULL;
1447fcf3ce44SJohn Forte 		atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED);
1448fcf3ce44SJohn Forte 	}
1449fcf3ce44SJohn Forte 
1450fcf3ce44SJohn Forte 	if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
1451fcf3ce44SJohn Forte 		els->els_resp_size = els->els_req_size;
1452fcf3ce44SJohn Forte 		p = els->els_resp_payload = (uint8_t *)kmem_zalloc(
1453590ebdb0Sallan 		    els->els_resp_size, KM_SLEEP);
1454fcf3ce44SJohn Forte 		els->els_resp_alloc_size = els->els_resp_size;
1455fcf3ce44SJohn Forte 		bcopy(els->els_req_payload, p, els->els_resp_size);
1456fcf3ce44SJohn Forte 		p[0] = ELS_OP_ACC;
1457fcf3ce44SJohn Forte 		bcopy(p+20, rp->rp_pwwn, 8);
1458fcf3ce44SJohn Forte 		bcopy(p+28, rp->rp_nwwn, 8);
1459fcf3ce44SJohn Forte 		bcopy(port->port_pwwn, p+20, 8);
1460fcf3ce44SJohn Forte 		bcopy(port->port_nwwn, p+28, 8);
1461d8c54e3dSSam Cramer 		fct_wwn_to_str(rp->rp_pwwn_str, rp->rp_pwwn);
1462d8c54e3dSSam Cramer 		fct_wwn_to_str(rp->rp_nwwn_str, rp->rp_nwwn);
1463d8c54e3dSSam Cramer 		fct_wwn_to_str(port->port_pwwn_str, port->port_pwwn);
1464d8c54e3dSSam Cramer 		fct_wwn_to_str(port->port_nwwn_str, port->port_nwwn);
1465d8c54e3dSSam Cramer 
1466fcf3ce44SJohn Forte 		stmf_wwn_to_devid_desc((scsi_devid_desc_t *)irp->irp_id,
1467fcf3ce44SJohn Forte 		    rp->rp_pwwn, PROTOCOL_FIBRE_CHANNEL);
1468fcf3ce44SJohn Forte 	}
1469fcf3ce44SJohn Forte 
1470fcf3ce44SJohn Forte 	ret = fct_register_remote_port(port, rp, cmd);
1471fcf3ce44SJohn Forte 	fct_dequeue_els(irp);
1472fcf3ce44SJohn Forte 	if ((ret == FCT_SUCCESS) && !(icmd->icmd_flags & ICMD_IMPLICIT)) {
1473fcf3ce44SJohn Forte 		if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
1474fcf3ce44SJohn Forte 			ret = port->port_send_cmd_response(cmd, 0);
1475fcf3ce44SJohn Forte 			if ((ret == FCT_SUCCESS) && IPORT_IN_NS_TOPO(iport) &&
1476fcf3ce44SJohn Forte 			    !FC_WELL_KNOWN_ADDR(irp->irp_portid)) {
1477fcf3ce44SJohn Forte 				fct_cmd_t *ct_cmd = fct_create_solct(port,
1478fcf3ce44SJohn Forte 				    rp, NS_GSNN_NN, fct_gsnn_cb);
1479fcf3ce44SJohn Forte 				if (ct_cmd) {
1480fcf3ce44SJohn Forte 					fct_post_to_solcmd_queue(port, ct_cmd);
1481fcf3ce44SJohn Forte 				}
1482fcf3ce44SJohn Forte 				ct_cmd = fct_create_solct(port, rp,
1483fcf3ce44SJohn Forte 				    NS_GSPN_ID, fct_gspn_cb);
1484fcf3ce44SJohn Forte 				if (ct_cmd)
1485fcf3ce44SJohn Forte 					fct_post_to_solcmd_queue(port, ct_cmd);
1486fcf3ce44SJohn Forte 				ct_cmd = fct_create_solct(port, rp,
1487fcf3ce44SJohn Forte 				    NS_GCS_ID, fct_gcs_cb);
1488fcf3ce44SJohn Forte 				if (ct_cmd)
1489fcf3ce44SJohn Forte 					fct_post_to_solcmd_queue(port, ct_cmd);
1490fcf3ce44SJohn Forte 				ct_cmd = fct_create_solct(port, rp,
1491fcf3ce44SJohn Forte 				    NS_GFT_ID, fct_gft_cb);
1492fcf3ce44SJohn Forte 				if (ct_cmd)
1493fcf3ce44SJohn Forte 					fct_post_to_solcmd_queue(port, ct_cmd);
1494fcf3ce44SJohn Forte 			}
1495fcf3ce44SJohn Forte 		} else {
1496fcf3ce44SJohn Forte 			/*
1497fcf3ce44SJohn Forte 			 * The reason we set this flag is to prevent
1498fcf3ce44SJohn Forte 			 * killing a PRLI while we have not yet processed
1499fcf3ce44SJohn Forte 			 * a response to PLOGI. Because the initiator
1500fcf3ce44SJohn Forte 			 * will send a PRLI as soon as it responds to PLOGI.
1501fcf3ce44SJohn Forte 			 * Check fct_process_els() for more info.
1502fcf3ce44SJohn Forte 			 */
1503fcf3ce44SJohn Forte 			atomic_or_32(&irp->irp_flags,
1504590ebdb0Sallan 			    IRP_SOL_PLOGI_IN_PROGRESS);
1505fcf3ce44SJohn Forte 			atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA);
1506fcf3ce44SJohn Forte 			ret = port->port_send_cmd(cmd);
1507fcf3ce44SJohn Forte 			if (ret != FCT_SUCCESS) {
1508fcf3ce44SJohn Forte 				atomic_and_32(&icmd->icmd_flags,
1509fcf3ce44SJohn Forte 				    ~ICMD_KNOWN_TO_FCA);
1510fcf3ce44SJohn Forte 				atomic_and_32(&irp->irp_flags,
1511590ebdb0Sallan 				    ~IRP_SOL_PLOGI_IN_PROGRESS);
1512fcf3ce44SJohn Forte 			}
1513fcf3ce44SJohn Forte 		}
1514fcf3ce44SJohn Forte 	}
15151a5e258fSJosef 'Jeff' Sipek 	atomic_dec_16(&irp->irp_sa_elses_count);
1516fcf3ce44SJohn Forte 
1517fcf3ce44SJohn Forte 	if (ret == FCT_SUCCESS) {
1518fcf3ce44SJohn Forte 		if (cmd_type == FCT_CMD_RCVD_ELS) {
1519fcf3ce44SJohn Forte 			atomic_or_32(&irp->irp_flags, IRP_PLOGI_DONE);
15201a5e258fSJosef 'Jeff' Sipek 			atomic_inc_32(&iport->iport_nrps_login);
1521fcf3ce44SJohn Forte 			if (irp->irp_deregister_timer)
1522fcf3ce44SJohn Forte 				irp->irp_deregister_timer = 0;
1523fcf3ce44SJohn Forte 		}
1524fcf3ce44SJohn Forte 		if (icmd_flags & ICMD_IMPLICIT) {
1525d8c54e3dSSam Cramer 			DTRACE_FC_5(rport__login__end,
1526d8c54e3dSSam Cramer 			    fct_cmd_t, cmd,
1527d8c54e3dSSam Cramer 			    fct_local_port_t, port,
1528d8c54e3dSSam Cramer 			    fct_i_remote_port_t, irp,
1529d8c54e3dSSam Cramer 			    int, (cmd_type != FCT_CMD_RCVD_ELS),
1530d8c54e3dSSam Cramer 			    int, FCT_SUCCESS);
1531d8c54e3dSSam Cramer 
1532fcf3ce44SJohn Forte 			p = els->els_resp_payload;
1533fcf3ce44SJohn Forte 			p[0] = ELS_OP_ACC;
1534fcf3ce44SJohn Forte 			cmd->cmd_comp_status = FCT_SUCCESS;
1535fcf3ce44SJohn Forte 			fct_send_cmd_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE);
1536fcf3ce44SJohn Forte 		}
1537fcf3ce44SJohn Forte 	} else {
1538d8c54e3dSSam Cramer 		DTRACE_FC_5(rport__login__end,
1539d8c54e3dSSam Cramer 		    fct_cmd_t, cmd,
1540d8c54e3dSSam Cramer 		    fct_local_port_t, port,
1541d8c54e3dSSam Cramer 		    fct_i_remote_port_t, irp,
1542d8c54e3dSSam Cramer 		    int, (cmd_type != FCT_CMD_RCVD_ELS),
1543d8c54e3dSSam Cramer 		    int, ret);
1544d8c54e3dSSam Cramer 
1545fcf3ce44SJohn Forte 		fct_queue_cmd_for_termination(cmd, ret);
1546fcf3ce44SJohn Forte 	}
1547fcf3ce44SJohn Forte 
1548fcf3ce44SJohn Forte 	/* Do not touch cmd here as it may have been freed */
1549fcf3ce44SJohn Forte 
1550fcf3ce44SJohn Forte 	return (DISC_ACTION_RESCAN);
1551fcf3ce44SJohn Forte }
1552fcf3ce44SJohn Forte 
1553fcf3ce44SJohn Forte uint8_t fct_prli_temp[] = { 0x20, 0x10, 0, 0x14, 8, 0, 0x20, 0, 0, 0, 0, 0,
1554fcf3ce44SJohn Forte 				0, 0, 0, 0 };
1555fcf3ce44SJohn Forte 
1556fcf3ce44SJohn Forte disc_action_t
fct_process_prli(fct_i_cmd_t * icmd)1557fcf3ce44SJohn Forte fct_process_prli(fct_i_cmd_t *icmd)
1558fcf3ce44SJohn Forte {
1559fcf3ce44SJohn Forte 	fct_cmd_t		*cmd   = icmd->icmd_cmd;
1560fcf3ce44SJohn Forte 	fct_remote_port_t	*rp    = cmd->cmd_rp;
1561fcf3ce44SJohn Forte 	fct_local_port_t	*port  = cmd->cmd_port;
1562fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
1563590ebdb0Sallan 	    port->port_fct_private;
1564fcf3ce44SJohn Forte 	fct_els_t		*els   = (fct_els_t *)
1565590ebdb0Sallan 	    cmd->cmd_specific;
1566fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp   = (fct_i_remote_port_t *)
1567590ebdb0Sallan 	    rp->rp_fct_private;
1568fcf3ce44SJohn Forte 	stmf_scsi_session_t	*ses   = NULL;
1569fcf3ce44SJohn Forte 	fct_status_t		 ret;
1570fcf3ce44SJohn Forte 	clock_t			 end_time;
15714558d122SViswanathan Kannappan 	char			 info[FCT_INFO_LEN];
1572fcf3ce44SJohn Forte 
1573fcf3ce44SJohn Forte 	/* We dont support solicited PRLIs yet */
1574fcf3ce44SJohn Forte 	ASSERT(cmd->cmd_type == FCT_CMD_RCVD_ELS);
1575fcf3ce44SJohn Forte 
1576fcf3ce44SJohn Forte 	if (irp->irp_flags & IRP_SOL_PLOGI_IN_PROGRESS) {
1577fcf3ce44SJohn Forte 		/*
1578fcf3ce44SJohn Forte 		 * Dont process the PRLI yet. Let the framework process the
1579fcf3ce44SJohn Forte 		 * PLOGI completion 1st. This should be very quick because
1580fcf3ce44SJohn Forte 		 * the reason we got the PRLI is because the initiator
1581fcf3ce44SJohn Forte 		 * has responded to PLOGI already.
1582fcf3ce44SJohn Forte 		 */
1583fcf3ce44SJohn Forte 		/* XXX: Probably need a timeout here */
1584fcf3ce44SJohn Forte 		return (DISC_ACTION_DELAY_RESCAN);
1585fcf3ce44SJohn Forte 	}
1586fcf3ce44SJohn Forte 	/* The caller has made sure that login is done */
1587fcf3ce44SJohn Forte 
1588fcf3ce44SJohn Forte 	/* Make sure the process is fcp in this case */
1589fcf3ce44SJohn Forte 	if ((els->els_req_size != 20) || (bcmp(els->els_req_payload,
1590590ebdb0Sallan 	    fct_prli_temp, 16))) {
1591fcf3ce44SJohn Forte 		if (els->els_req_payload[4] != 0x08)
1592fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "PRLI received from"
1593fcf3ce44SJohn Forte 			    " %x for unknown FC-4 type %x", cmd->cmd_rportid,
1594590ebdb0Sallan 			    els->els_req_payload[4]);
1595fcf3ce44SJohn Forte 		else
1596fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "Rejecting PRLI from %x "
1597fcf3ce44SJohn Forte 			    " pld sz %d, prli_flags %x", cmd->cmd_rportid,
1598fcf3ce44SJohn Forte 			    els->els_req_size, els->els_req_payload[6]);
1599fcf3ce44SJohn Forte 
1600fcf3ce44SJohn Forte 		fct_dequeue_els(irp);
16011a5e258fSJosef 'Jeff' Sipek 		atomic_dec_16(&irp->irp_sa_elses_count);
1602fcf3ce44SJohn Forte 		ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0x2c);
1603fcf3ce44SJohn Forte 		goto prli_end;
1604fcf3ce44SJohn Forte 	}
1605fcf3ce44SJohn Forte 
1606fcf3ce44SJohn Forte 	if (irp->irp_fcp_xchg_count) {
1607fcf3ce44SJohn Forte 		/* Trigger cleanup if necessary */
1608fcf3ce44SJohn Forte 		if ((irp->irp_flags & IRP_FCP_CLEANUP) == 0) {
1609fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "handling PRLI from"
1610fcf3ce44SJohn Forte 			    " %x. Triggering cleanup", cmd->cmd_rportid);
1611fcf3ce44SJohn Forte 			if (fct_trigger_rport_cleanup(irp, FCT_CMD_FCP_XCHG)) {
1612fcf3ce44SJohn Forte 				atomic_or_32(&irp->irp_flags, IRP_FCP_CLEANUP);
1613fcf3ce44SJohn Forte 			} else {
1614fcf3ce44SJohn Forte 				/* XXX: handle this */
1615fcf3ce44SJohn Forte 				/* EMPTY */
1616fcf3ce44SJohn Forte 			}
1617fcf3ce44SJohn Forte 		}
1618fcf3ce44SJohn Forte 
1619fcf3ce44SJohn Forte 		end_time = icmd->icmd_start_time +
1620fcf3ce44SJohn Forte 		    drv_usectohz(USEC_ELS_TIMEOUT);
1621fcf3ce44SJohn Forte 		if (ddi_get_lbolt() > end_time) {
16224558d122SViswanathan Kannappan 			(void) snprintf(info, sizeof (info),
1623fcf3ce44SJohn Forte 			    "fct_process_prli: unable to clean "
1624fcf3ce44SJohn Forte 			    "up I/O. iport-%p, icmd-%p", (void *)iport,
1625fcf3ce44SJohn Forte 			    (void *)icmd);
1626fcf3ce44SJohn Forte 			(void) fct_port_shutdown(iport->iport_port,
1627fcf3ce44SJohn Forte 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
1628fcf3ce44SJohn Forte 
1629fcf3ce44SJohn Forte 			return (DISC_ACTION_DELAY_RESCAN);
1630fcf3ce44SJohn Forte 		}
1631fcf3ce44SJohn Forte 
1632fcf3ce44SJohn Forte 		if ((ddi_get_lbolt() & 0x7f) == 0) {
1633fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "handling"
1634590ebdb0Sallan 			    " PRLI from %x, waiting for cmds to"
1635590ebdb0Sallan 			    " drain", cmd->cmd_rportid);
1636fcf3ce44SJohn Forte 		}
1637fcf3ce44SJohn Forte 		return (DISC_ACTION_DELAY_RESCAN);
1638fcf3ce44SJohn Forte 	}
1639fcf3ce44SJohn Forte 	atomic_and_32(&irp->irp_flags, ~IRP_FCP_CLEANUP);
1640fcf3ce44SJohn Forte 
1641fcf3ce44SJohn Forte 	/* Session can only be terminated after all the I/Os have drained */
1642fcf3ce44SJohn Forte 	if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) {
1643fcf3ce44SJohn Forte 		stmf_deregister_scsi_session(iport->iport_port->port_lport,
1644fcf3ce44SJohn Forte 		    irp->irp_session);
1645fcf3ce44SJohn Forte 		stmf_free(irp->irp_session);
1646fcf3ce44SJohn Forte 		irp->irp_session = NULL;
1647fcf3ce44SJohn Forte 		atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED);
1648fcf3ce44SJohn Forte 	}
1649fcf3ce44SJohn Forte 
1650fcf3ce44SJohn Forte 	/* All good, lets start a session */
1651fcf3ce44SJohn Forte 	ses = (stmf_scsi_session_t *)stmf_alloc(STMF_STRUCT_SCSI_SESSION, 0, 0);
1652fcf3ce44SJohn Forte 	if (ses) {
1653fcf3ce44SJohn Forte 		ses->ss_port_private = irp;
1654fcf3ce44SJohn Forte 		ses->ss_rport_id = (scsi_devid_desc_t *)irp->irp_id;
1655fcf3ce44SJohn Forte 		ses->ss_lport = port->port_lport;
1656fcf3ce44SJohn Forte 		if (stmf_register_scsi_session(port->port_lport, ses) !=
1657590ebdb0Sallan 		    STMF_SUCCESS) {
1658fcf3ce44SJohn Forte 			stmf_free(ses);
1659fcf3ce44SJohn Forte 			ses = NULL;
1660fcf3ce44SJohn Forte 		} else {
1661fcf3ce44SJohn Forte 			irp->irp_session = ses;
1662fcf3ce44SJohn Forte 			irp->irp_session->ss_rport_alias = irp->irp_snn;
1663fcf3ce44SJohn Forte 
1664fcf3ce44SJohn Forte 			/*
1665fcf3ce44SJohn Forte 			 * The reason IRP_SCSI_SESSION_STARTED is different
1666fcf3ce44SJohn Forte 			 * from IRP_PRLI_DONE is that we clear IRP_PRLI_DONE
1667fcf3ce44SJohn Forte 			 * inside interrupt context. We dont want to deregister
1668fcf3ce44SJohn Forte 			 * the session from an interrupt.
1669fcf3ce44SJohn Forte 			 */
1670fcf3ce44SJohn Forte 			atomic_or_32(&irp->irp_flags, IRP_SCSI_SESSION_STARTED);
1671fcf3ce44SJohn Forte 		}
1672fcf3ce44SJohn Forte 	}
1673fcf3ce44SJohn Forte 
1674fcf3ce44SJohn Forte 	fct_dequeue_els(irp);
16751a5e258fSJosef 'Jeff' Sipek 	atomic_dec_16(&irp->irp_sa_elses_count);
1676fcf3ce44SJohn Forte 	if (ses == NULL) {
1677fcf3ce44SJohn Forte 		/* fail PRLI */
1678fcf3ce44SJohn Forte 		ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0);
1679fcf3ce44SJohn Forte 	} else {
1680fcf3ce44SJohn Forte 		/* accept PRLI */
1681fcf3ce44SJohn Forte 		els->els_resp_payload = (uint8_t *)kmem_zalloc(20, KM_SLEEP);
1682fcf3ce44SJohn Forte 		bcopy(fct_prli_temp, els->els_resp_payload, 20);
1683fcf3ce44SJohn Forte 		els->els_resp_payload[0] = 2;
1684fcf3ce44SJohn Forte 		els->els_resp_payload[6] = 0x21;
1685fcf3ce44SJohn Forte 
1686fcf3ce44SJohn Forte 		/* XXX the two bytes below need to set as per capabilities */
1687fcf3ce44SJohn Forte 		els->els_resp_payload[18] = 0;
1688fcf3ce44SJohn Forte 		els->els_resp_payload[19] = 0x12;
1689fcf3ce44SJohn Forte 
1690fcf3ce44SJohn Forte 		els->els_resp_size = els->els_resp_alloc_size = 20;
1691fcf3ce44SJohn Forte 		if ((ret = port->port_send_cmd_response(cmd, 0)) !=
1692fcf3ce44SJohn Forte 		    FCT_SUCCESS) {
1693fcf3ce44SJohn Forte 			stmf_deregister_scsi_session(port->port_lport, ses);
1694fcf3ce44SJohn Forte 			stmf_free(irp->irp_session);
1695fcf3ce44SJohn Forte 			irp->irp_session = NULL;
1696fcf3ce44SJohn Forte 			atomic_and_32(&irp->irp_flags,
1697fcf3ce44SJohn Forte 			    ~IRP_SCSI_SESSION_STARTED);
1698fcf3ce44SJohn Forte 		} else {
1699fcf3ce44SJohn Forte 			/* Mark that PRLI is done */
1700fcf3ce44SJohn Forte 			atomic_or_32(&irp->irp_flags, IRP_PRLI_DONE);
1701fcf3ce44SJohn Forte 		}
1702fcf3ce44SJohn Forte 	}
1703fcf3ce44SJohn Forte 
1704fcf3ce44SJohn Forte prli_end:;
1705fcf3ce44SJohn Forte 	if (ret != FCT_SUCCESS)
1706fcf3ce44SJohn Forte 		fct_queue_cmd_for_termination(cmd, ret);
1707fcf3ce44SJohn Forte 
1708fcf3ce44SJohn Forte 	return (DISC_ACTION_RESCAN);
1709fcf3ce44SJohn Forte }
1710fcf3ce44SJohn Forte 
1711fcf3ce44SJohn Forte disc_action_t
fct_process_logo(fct_i_cmd_t * icmd)1712fcf3ce44SJohn Forte fct_process_logo(fct_i_cmd_t *icmd)
1713fcf3ce44SJohn Forte {
1714fcf3ce44SJohn Forte 	fct_cmd_t		*cmd   = icmd->icmd_cmd;
1715fcf3ce44SJohn Forte 	fct_remote_port_t	*rp    = cmd->cmd_rp;
1716fcf3ce44SJohn Forte 	fct_local_port_t	*port  = cmd->cmd_port;
1717fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
1718590ebdb0Sallan 	    port->port_fct_private;
1719fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp   = (fct_i_remote_port_t *)
1720590ebdb0Sallan 	    rp->rp_fct_private;
1721fcf3ce44SJohn Forte 	fct_status_t		 ret;
17224558d122SViswanathan Kannappan 	char			 info[FCT_INFO_LEN];
1723fcf3ce44SJohn Forte 	clock_t			 end_time;
1724fcf3ce44SJohn Forte 
1725d8c54e3dSSam Cramer 	DTRACE_FC_4(rport__logout__start,
1726d8c54e3dSSam Cramer 	    fct_cmd_t, cmd,
1727d8c54e3dSSam Cramer 	    fct_local_port_t, port,
1728d8c54e3dSSam Cramer 	    fct_i_remote_port_t, irp,
1729d8c54e3dSSam Cramer 	    int, (cmd->cmd_type != FCT_CMD_RCVD_ELS));
1730d8c54e3dSSam Cramer 
1731fcf3ce44SJohn Forte 	/* Drain I/Os */
1732fcf3ce44SJohn Forte 	if ((irp->irp_nonfcp_xchg_count + irp->irp_fcp_xchg_count) > 1) {
1733fcf3ce44SJohn Forte 		/* Trigger cleanup if necessary */
1734fcf3ce44SJohn Forte 		if ((irp->irp_flags & IRP_SESSION_CLEANUP) == 0) {
1735fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "handling LOGO rp_id"
1736fcf3ce44SJohn Forte 			    " %x. Triggering cleanup", cmd->cmd_rportid);
1737fcf3ce44SJohn Forte 			/* Cleanup everything except elses */
1738fcf3ce44SJohn Forte 			if (fct_trigger_rport_cleanup(irp, ~(cmd->cmd_type))) {
1739fcf3ce44SJohn Forte 				atomic_or_32(&irp->irp_flags,
1740590ebdb0Sallan 				    IRP_SESSION_CLEANUP);
1741fcf3ce44SJohn Forte 			} else {
1742fcf3ce44SJohn Forte 				/* XXX: need more handling */
1743fcf3ce44SJohn Forte 				return (DISC_ACTION_DELAY_RESCAN);
1744fcf3ce44SJohn Forte 			}
1745fcf3ce44SJohn Forte 		}
1746fcf3ce44SJohn Forte 
1747fcf3ce44SJohn Forte 		end_time = icmd->icmd_start_time +
1748fcf3ce44SJohn Forte 		    drv_usectohz(USEC_ELS_TIMEOUT);
1749fcf3ce44SJohn Forte 		if (ddi_get_lbolt() > end_time) {
17504558d122SViswanathan Kannappan 			(void) snprintf(info, sizeof (info),
1751fcf3ce44SJohn Forte 			    "fct_process_logo: unable to clean "
1752fcf3ce44SJohn Forte 			    "up I/O. iport-%p, icmd-%p", (void *)iport,
1753fcf3ce44SJohn Forte 			    (void *)icmd);
1754fcf3ce44SJohn Forte 			(void) fct_port_shutdown(iport->iport_port,
1755fcf3ce44SJohn Forte 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
1756fcf3ce44SJohn Forte 
1757fcf3ce44SJohn Forte 			return (DISC_ACTION_DELAY_RESCAN);
1758fcf3ce44SJohn Forte 		}
1759fcf3ce44SJohn Forte 
1760fcf3ce44SJohn Forte 		if ((ddi_get_lbolt() & 0x7f) == 0) {
1761fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "handling"
1762590ebdb0Sallan 			    " LOGO rp_id %x, waiting for cmds to"
1763590ebdb0Sallan 			    " drain", cmd->cmd_rportid);
1764fcf3ce44SJohn Forte 		}
1765fcf3ce44SJohn Forte 		return (DISC_ACTION_DELAY_RESCAN);
1766fcf3ce44SJohn Forte 	}
1767fcf3ce44SJohn Forte 	atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP);
1768fcf3ce44SJohn Forte 
1769fcf3ce44SJohn Forte 	/* Session can only be terminated after all the I/Os have drained */
1770fcf3ce44SJohn Forte 	if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) {
1771fcf3ce44SJohn Forte 		stmf_deregister_scsi_session(iport->iport_port->port_lport,
1772fcf3ce44SJohn Forte 		    irp->irp_session);
1773fcf3ce44SJohn Forte 		stmf_free(irp->irp_session);
1774fcf3ce44SJohn Forte 		irp->irp_session = NULL;
1775fcf3ce44SJohn Forte 		atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED);
1776fcf3ce44SJohn Forte 	}
1777fcf3ce44SJohn Forte 
1778fcf3ce44SJohn Forte 	fct_dequeue_els(irp);
17791a5e258fSJosef 'Jeff' Sipek 	atomic_dec_16(&irp->irp_sa_elses_count);
1780fcf3ce44SJohn Forte 
1781fcf3ce44SJohn Forte 	/* don't send response if this is an implicit logout cmd */
1782fcf3ce44SJohn Forte 	if (!(icmd->icmd_flags & ICMD_IMPLICIT)) {
1783fcf3ce44SJohn Forte 		if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
1784fcf3ce44SJohn Forte 			ret = fct_send_accrjt(cmd, ELS_OP_ACC, 0, 0);
1785fcf3ce44SJohn Forte 		} else {
1786fcf3ce44SJohn Forte 			atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA);
1787fcf3ce44SJohn Forte 			ret = port->port_send_cmd(cmd);
1788fcf3ce44SJohn Forte 			if (ret != FCT_SUCCESS) {
1789fcf3ce44SJohn Forte 				atomic_and_32(&icmd->icmd_flags,
1790fcf3ce44SJohn Forte 				    ~ICMD_KNOWN_TO_FCA);
1791fcf3ce44SJohn Forte 			}
1792fcf3ce44SJohn Forte 		}
1793fcf3ce44SJohn Forte 
1794fcf3ce44SJohn Forte 		if (ret != FCT_SUCCESS) {
1795fcf3ce44SJohn Forte 			fct_queue_cmd_for_termination(cmd, ret);
1796fcf3ce44SJohn Forte 		}
1797d8c54e3dSSam Cramer 
1798d8c54e3dSSam Cramer 		DTRACE_FC_4(rport__logout__end,
1799d8c54e3dSSam Cramer 		    fct_cmd_t, cmd,
1800d8c54e3dSSam Cramer 		    fct_local_port_t, port,
1801d8c54e3dSSam Cramer 		    fct_i_remote_port_t, irp,
1802d8c54e3dSSam Cramer 		    int, (cmd->cmd_type != FCT_CMD_RCVD_ELS));
1803d8c54e3dSSam Cramer 
1804fcf3ce44SJohn Forte 	} else {
1805d8c54e3dSSam Cramer 		DTRACE_FC_4(rport__logout__end,
1806d8c54e3dSSam Cramer 		    fct_cmd_t, cmd,
1807d8c54e3dSSam Cramer 		    fct_local_port_t, port,
1808d8c54e3dSSam Cramer 		    fct_i_remote_port_t, irp,
1809d8c54e3dSSam Cramer 		    int, (cmd->cmd_type != FCT_CMD_RCVD_ELS));
1810d8c54e3dSSam Cramer 
1811fcf3ce44SJohn Forte 		fct_cmd_free(cmd);
1812fcf3ce44SJohn Forte 	}
1813fcf3ce44SJohn Forte 
1814fcf3ce44SJohn Forte 	irp->irp_deregister_timer = ddi_get_lbolt() +
1815590ebdb0Sallan 	    drv_usectohz(USEC_DEREG_RP_TIMEOUT);
1816fcf3ce44SJohn Forte 	irp->irp_dereg_count = 0;
1817fcf3ce44SJohn Forte 
1818fcf3ce44SJohn Forte 	/* Do not touch cmd here as it may have been freed */
1819fcf3ce44SJohn Forte 
1820fcf3ce44SJohn Forte 	ASSERT(irp->irp_flags & IRP_IN_DISCOVERY_QUEUE);
1821fcf3ce44SJohn Forte 
1822fcf3ce44SJohn Forte 	return (DISC_ACTION_RESCAN);
1823fcf3ce44SJohn Forte }
1824fcf3ce44SJohn Forte 
1825fcf3ce44SJohn Forte disc_action_t
fct_process_prlo(fct_i_cmd_t * icmd)1826fcf3ce44SJohn Forte fct_process_prlo(fct_i_cmd_t *icmd)
1827fcf3ce44SJohn Forte {
1828fcf3ce44SJohn Forte 	fct_cmd_t		*cmd   = icmd->icmd_cmd;
1829fcf3ce44SJohn Forte 	fct_remote_port_t	*rp    = cmd->cmd_rp;
1830fcf3ce44SJohn Forte 	fct_local_port_t	*port  = cmd->cmd_port;
1831fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
1832590ebdb0Sallan 	    port->port_fct_private;
1833fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp   = (fct_i_remote_port_t *)
1834590ebdb0Sallan 	    rp->rp_fct_private;
1835fcf3ce44SJohn Forte 	fct_status_t		 ret;
1836fcf3ce44SJohn Forte 	clock_t			 end_time;
18374558d122SViswanathan Kannappan 	char			 info[FCT_INFO_LEN];
1838fcf3ce44SJohn Forte 
1839fcf3ce44SJohn Forte 	/* We do not support solicited PRLOs yet */
1840fcf3ce44SJohn Forte 	ASSERT(cmd->cmd_type == FCT_CMD_RCVD_ELS);
1841fcf3ce44SJohn Forte 
1842fcf3ce44SJohn Forte 	/* Drain I/Os */
1843fcf3ce44SJohn Forte 	if (irp->irp_fcp_xchg_count) {
1844fcf3ce44SJohn Forte 		/* Trigger cleanup if necessary */
1845fcf3ce44SJohn Forte 		if ((irp->irp_flags & IRP_FCP_CLEANUP) == 0) {
1846fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "handling LOGO from"
1847fcf3ce44SJohn Forte 			    " %x. Triggering cleanup", cmd->cmd_rportid);
1848fcf3ce44SJohn Forte 			/* Cleanup everything except elses */
1849fcf3ce44SJohn Forte 			if (fct_trigger_rport_cleanup(irp, FCT_CMD_FCP_XCHG)) {
1850fcf3ce44SJohn Forte 				atomic_or_32(&irp->irp_flags,
1851590ebdb0Sallan 				    IRP_FCP_CLEANUP);
1852fcf3ce44SJohn Forte 			} else {
1853fcf3ce44SJohn Forte 				/* XXX: need more handling */
1854fcf3ce44SJohn Forte 				return (DISC_ACTION_DELAY_RESCAN);
1855fcf3ce44SJohn Forte 			}
1856fcf3ce44SJohn Forte 		}
1857fcf3ce44SJohn Forte 
1858fcf3ce44SJohn Forte 		end_time = icmd->icmd_start_time +
1859fcf3ce44SJohn Forte 		    drv_usectohz(USEC_ELS_TIMEOUT);
1860fcf3ce44SJohn Forte 		if (ddi_get_lbolt() > end_time) {
18614558d122SViswanathan Kannappan 			(void) snprintf(info, sizeof (info),
1862fcf3ce44SJohn Forte 			    "fct_process_prlo: unable to "
1863fcf3ce44SJohn Forte 			    "clean up I/O. iport-%p, icmd-%p", (void *)iport,
1864fcf3ce44SJohn Forte 			    (void *)icmd);
1865fcf3ce44SJohn Forte 			(void) fct_port_shutdown(iport->iport_port,
1866fcf3ce44SJohn Forte 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
1867fcf3ce44SJohn Forte 
1868fcf3ce44SJohn Forte 			return (DISC_ACTION_DELAY_RESCAN);
1869fcf3ce44SJohn Forte 		}
1870fcf3ce44SJohn Forte 
1871fcf3ce44SJohn Forte 		if ((ddi_get_lbolt() & 0x7f) == 0) {
1872fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "handling"
1873590ebdb0Sallan 			    " PRLO from %x, waiting for cmds to"
1874590ebdb0Sallan 			    " drain", cmd->cmd_rportid);
1875fcf3ce44SJohn Forte 		}
1876fcf3ce44SJohn Forte 		return (DISC_ACTION_DELAY_RESCAN);
1877fcf3ce44SJohn Forte 	}
1878fcf3ce44SJohn Forte 	atomic_and_32(&irp->irp_flags, ~IRP_FCP_CLEANUP);
1879fcf3ce44SJohn Forte 
1880fcf3ce44SJohn Forte 	/* Session can only be terminated after all the I/Os have drained */
1881fcf3ce44SJohn Forte 	if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) {
1882fcf3ce44SJohn Forte 		stmf_deregister_scsi_session(iport->iport_port->port_lport,
1883fcf3ce44SJohn Forte 		    irp->irp_session);
1884fcf3ce44SJohn Forte 		stmf_free(irp->irp_session);
1885fcf3ce44SJohn Forte 		irp->irp_session = NULL;
1886fcf3ce44SJohn Forte 		atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED);
1887fcf3ce44SJohn Forte 	}
1888fcf3ce44SJohn Forte 
1889fcf3ce44SJohn Forte 	fct_dequeue_els(irp);
18901a5e258fSJosef 'Jeff' Sipek 	atomic_dec_16(&irp->irp_sa_elses_count);
1891fcf3ce44SJohn Forte 	ret = fct_send_accrjt(cmd, ELS_OP_ACC, 0, 0);
1892fcf3ce44SJohn Forte 	if (ret != FCT_SUCCESS)
1893fcf3ce44SJohn Forte 		fct_queue_cmd_for_termination(cmd, ret);
1894fcf3ce44SJohn Forte 
1895fcf3ce44SJohn Forte 	return (DISC_ACTION_RESCAN);
1896fcf3ce44SJohn Forte }
1897fcf3ce44SJohn Forte 
1898fcf3ce44SJohn Forte disc_action_t
fct_process_rcvd_adisc(fct_i_cmd_t * icmd)1899fcf3ce44SJohn Forte fct_process_rcvd_adisc(fct_i_cmd_t *icmd)
1900fcf3ce44SJohn Forte {
1901fcf3ce44SJohn Forte 	fct_cmd_t		*cmd = icmd->icmd_cmd;
1902fcf3ce44SJohn Forte 	fct_remote_port_t	*rp = cmd->cmd_rp;
1903fcf3ce44SJohn Forte 	fct_local_port_t	*port = cmd->cmd_port;
1904fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
1905590ebdb0Sallan 	    port->port_fct_private;
1906fcf3ce44SJohn Forte 	fct_els_t		*els = (fct_els_t *)
1907590ebdb0Sallan 	    cmd->cmd_specific;
1908fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp = (fct_i_remote_port_t *)
1909590ebdb0Sallan 	    rp->rp_fct_private;
1910fcf3ce44SJohn Forte 	uint8_t			*p;
1911fcf3ce44SJohn Forte 	uint32_t		*q;
1912fcf3ce44SJohn Forte 	fct_status_t		ret;
1913fcf3ce44SJohn Forte 
1914fcf3ce44SJohn Forte 	fct_dequeue_els(irp);
19151a5e258fSJosef 'Jeff' Sipek 	atomic_dec_16(&irp->irp_nsa_elses_count);
1916fcf3ce44SJohn Forte 
1917fcf3ce44SJohn Forte 	/* Validate the adisc request */
1918fcf3ce44SJohn Forte 	p = els->els_req_payload;
1919fcf3ce44SJohn Forte 	q = (uint32_t *)p;
1920fcf3ce44SJohn Forte 	if ((els->els_req_size != 28) || (bcmp(rp->rp_pwwn, p + 8, 8)) ||
1921fcf3ce44SJohn Forte 	    (bcmp(rp->rp_nwwn, p + 16, 8))) {
1922fcf3ce44SJohn Forte 		ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0);
1923fcf3ce44SJohn Forte 	} else {
1924fcf3ce44SJohn Forte 		rp->rp_hard_address = BE_32(q[1]);
1925fcf3ce44SJohn Forte 		els->els_resp_size = els->els_resp_alloc_size = 28;
1926fcf3ce44SJohn Forte 		els->els_resp_payload = (uint8_t *)kmem_zalloc(28, KM_SLEEP);
1927fcf3ce44SJohn Forte 		bcopy(p, els->els_resp_payload, 28);
1928fcf3ce44SJohn Forte 		p = els->els_resp_payload;
1929fcf3ce44SJohn Forte 		q = (uint32_t *)p;
1930fcf3ce44SJohn Forte 		p[0] = ELS_OP_ACC;
1931fcf3ce44SJohn Forte 		q[1] = BE_32(port->port_hard_address);
1932fcf3ce44SJohn Forte 		bcopy(port->port_pwwn, p + 8, 8);
1933fcf3ce44SJohn Forte 		bcopy(port->port_nwwn, p + 16, 8);
1934fcf3ce44SJohn Forte 		q[6] = BE_32(iport->iport_link_info.portid);
1935fcf3ce44SJohn Forte 		ret = port->port_send_cmd_response(cmd, 0);
1936fcf3ce44SJohn Forte 	}
1937fcf3ce44SJohn Forte 	if (ret != FCT_SUCCESS) {
1938fcf3ce44SJohn Forte 		fct_queue_cmd_for_termination(cmd, ret);
1939fcf3ce44SJohn Forte 	}
1940fcf3ce44SJohn Forte 
1941fcf3ce44SJohn Forte 	return (DISC_ACTION_RESCAN);
1942fcf3ce44SJohn Forte }
1943fcf3ce44SJohn Forte 
1944fcf3ce44SJohn Forte disc_action_t
fct_process_unknown_els(fct_i_cmd_t * icmd)1945fcf3ce44SJohn Forte fct_process_unknown_els(fct_i_cmd_t *icmd)
1946fcf3ce44SJohn Forte {
1947fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport = ICMD_TO_IPORT(icmd);
1948fcf3ce44SJohn Forte 	fct_status_t		 ret   = FCT_FAILURE;
1949fcf3ce44SJohn Forte 	uint8_t			 op    = 0;
1950fcf3ce44SJohn Forte 
1951fcf3ce44SJohn Forte 	ASSERT(icmd->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS);
1952fcf3ce44SJohn Forte 	fct_dequeue_els(ICMD_TO_IRP(icmd));
19531a5e258fSJosef 'Jeff' Sipek 	atomic_dec_16(&ICMD_TO_IRP(icmd)->irp_nsa_elses_count);
1954fcf3ce44SJohn Forte 	op = ICMD_TO_ELS(icmd)->els_req_payload[0];
1955fcf3ce44SJohn Forte 	stmf_trace(iport->iport_alias, "Rejecting unknown unsol els %x (%s)",
1956fcf3ce44SJohn Forte 	    op, FCT_ELS_NAME(op));
1957fcf3ce44SJohn Forte 	ret = fct_send_accrjt(icmd->icmd_cmd, ELS_OP_LSRJT, 1, 0);
1958fcf3ce44SJohn Forte 	if (ret != FCT_SUCCESS) {
1959fcf3ce44SJohn Forte 		fct_queue_cmd_for_termination(icmd->icmd_cmd, ret);
1960fcf3ce44SJohn Forte 	}
1961fcf3ce44SJohn Forte 
1962fcf3ce44SJohn Forte 	return (DISC_ACTION_RESCAN);
1963fcf3ce44SJohn Forte }
1964fcf3ce44SJohn Forte 
1965fcf3ce44SJohn Forte disc_action_t
fct_process_rscn(fct_i_cmd_t * icmd)1966fcf3ce44SJohn Forte fct_process_rscn(fct_i_cmd_t *icmd)
1967fcf3ce44SJohn Forte {
1968fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport = ICMD_TO_IPORT(icmd);
1969fcf3ce44SJohn Forte 	fct_status_t		 ret   = FCT_FAILURE;
1970fcf3ce44SJohn Forte 	uint8_t			 op    = 0;
1971fcf3ce44SJohn Forte 	uint8_t			*rscn_req_payload;
1972fcf3ce44SJohn Forte 	uint32_t		 rscn_req_size;
1973fcf3ce44SJohn Forte 
1974fcf3ce44SJohn Forte 	fct_dequeue_els(ICMD_TO_IRP(icmd));
19751a5e258fSJosef 'Jeff' Sipek 	atomic_dec_16(&ICMD_TO_IRP(icmd)->irp_nsa_elses_count);
1976fcf3ce44SJohn Forte 	if (icmd->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS) {
1977fcf3ce44SJohn Forte 		op = ICMD_TO_ELS(icmd)->els_req_payload[0];
1978fcf3ce44SJohn Forte 		stmf_trace(iport->iport_alias, "Accepting RSCN %x (%s)",
1979fcf3ce44SJohn Forte 		    op, FCT_ELS_NAME(op));
1980fcf3ce44SJohn Forte 		rscn_req_size = ICMD_TO_ELS(icmd)->els_req_size;
1981fcf3ce44SJohn Forte 		rscn_req_payload = kmem_alloc(rscn_req_size, KM_SLEEP);
1982fcf3ce44SJohn Forte 		bcopy(ICMD_TO_ELS(icmd)->els_req_payload, rscn_req_payload,
1983fcf3ce44SJohn Forte 		    rscn_req_size);
1984fcf3ce44SJohn Forte 		ret = fct_send_accrjt(icmd->icmd_cmd, ELS_OP_ACC, 1, 0);
1985fcf3ce44SJohn Forte 		if (ret != FCT_SUCCESS) {
1986fcf3ce44SJohn Forte 			fct_queue_cmd_for_termination(icmd->icmd_cmd, ret);
1987fcf3ce44SJohn Forte 		} else {
1988fcf3ce44SJohn Forte 			if (fct_rscn_options & RSCN_OPTION_VERIFY) {
1989fcf3ce44SJohn Forte 				fct_rscn_verify(iport, rscn_req_payload,
1990fcf3ce44SJohn Forte 				    rscn_req_size);
1991fcf3ce44SJohn Forte 			}
1992fcf3ce44SJohn Forte 		}
1993fcf3ce44SJohn Forte 
1994fcf3ce44SJohn Forte 		kmem_free(rscn_req_payload, rscn_req_size);
1995fcf3ce44SJohn Forte 	} else {
1996fcf3ce44SJohn Forte 		ASSERT(0);
1997fcf3ce44SJohn Forte 	}
1998fcf3ce44SJohn Forte 
1999fcf3ce44SJohn Forte 	return (DISC_ACTION_RESCAN);
2000fcf3ce44SJohn Forte }
2001fcf3ce44SJohn Forte 
2002fcf3ce44SJohn Forte disc_action_t
fct_process_els(fct_i_local_port_t * iport,fct_i_remote_port_t * irp)2003fcf3ce44SJohn Forte fct_process_els(fct_i_local_port_t *iport, fct_i_remote_port_t *irp)
2004fcf3ce44SJohn Forte {
2005fcf3ce44SJohn Forte 	fct_i_cmd_t	*cmd_to_abort = NULL;
2006fcf3ce44SJohn Forte 	fct_i_cmd_t	**ppcmd, *icmd;
2007fcf3ce44SJohn Forte 	fct_cmd_t	*cmd;
2008fcf3ce44SJohn Forte 	fct_els_t	*els;
2009fcf3ce44SJohn Forte 	int		dq;
2010fcf3ce44SJohn Forte 	disc_action_t	ret = DISC_ACTION_NO_WORK;
2011fcf3ce44SJohn Forte 	uint8_t		op;
2012fcf3ce44SJohn Forte 
2013fcf3ce44SJohn Forte 	mutex_exit(&iport->iport_worker_lock);
2014fcf3ce44SJohn Forte 
2015fcf3ce44SJohn Forte 	/*
2016fcf3ce44SJohn Forte 	 * Do some cleanup based on the following.
2017fcf3ce44SJohn Forte 	 * - We can only have one session affecting els pending.
2018fcf3ce44SJohn Forte 	 * - If any session affecting els is pending no other els is allowed.
2019fcf3ce44SJohn Forte 	 * - If PLOGI is not done, nothing except PLOGI or LOGO is allowed.
2020fcf3ce44SJohn Forte 	 * NOTE: If port is down the cleanup is done outside of this
2021fcf3ce44SJohn Forte 	 *	function.
2022fcf3ce44SJohn Forte 	 * NOTE: There is a side effect, if a sa ELS (non PLOGI) is received
2023fcf3ce44SJohn Forte 	 * while a PLOGI is pending, it will kill itself and the PLOGI.
2024fcf3ce44SJohn Forte 	 * which is probably ok.
2025fcf3ce44SJohn Forte 	 */
2026fcf3ce44SJohn Forte 	rw_enter(&irp->irp_lock, RW_WRITER);
2027fcf3ce44SJohn Forte 	ppcmd = &irp->irp_els_list;
2028fcf3ce44SJohn Forte 	while ((*ppcmd) != NULL) {
2029fcf3ce44SJohn Forte 		int special_prli_cond = 0;
2030fcf3ce44SJohn Forte 		dq = 0;
2031fcf3ce44SJohn Forte 
2032fcf3ce44SJohn Forte 		els = (fct_els_t *)((*ppcmd)->icmd_cmd)->cmd_specific;
2033fcf3ce44SJohn Forte 
2034fcf3ce44SJohn Forte 		if (((*ppcmd)->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS) &&
2035fcf3ce44SJohn Forte 		    (els->els_req_payload[0] == ELS_OP_PRLI) &&
2036fcf3ce44SJohn Forte 		    (irp->irp_flags & IRP_SOL_PLOGI_IN_PROGRESS)) {
2037fcf3ce44SJohn Forte 			/*
2038fcf3ce44SJohn Forte 			 * The initiator sent a PRLI right after responding
2039fcf3ce44SJohn Forte 			 * to PLOGI and we have not yet finished processing
2040fcf3ce44SJohn Forte 			 * the PLOGI completion. We should not kill the PRLI
2041fcf3ce44SJohn Forte 			 * as the initiator may not retry it.
2042fcf3ce44SJohn Forte 			 */
2043fcf3ce44SJohn Forte 			special_prli_cond = 1;
2044fcf3ce44SJohn Forte 		}
2045fcf3ce44SJohn Forte 
2046fcf3ce44SJohn Forte 		if ((*ppcmd)->icmd_flags & ICMD_BEING_ABORTED) {
2047fcf3ce44SJohn Forte 			dq = 1;
2048d6b3018dSSumit Gupta 		} else if (irp->irp_sa_elses_count > 1) {
2049fcf3ce44SJohn Forte 			dq = 1;
2050fcf3ce44SJohn Forte 			/* This els might have set the CLEANUP flag */
2051fcf3ce44SJohn Forte 			atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP);
2052fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "Killing ELS %x cond 1",
2053590ebdb0Sallan 			    els->els_req_payload[0]);
2054fcf3ce44SJohn Forte 		} else if (irp->irp_sa_elses_count &&
2055fcf3ce44SJohn Forte 		    (((*ppcmd)->icmd_flags & ICMD_SESSION_AFFECTING) == 0)) {
2056fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "Killing ELS %x cond 2",
2057590ebdb0Sallan 			    els->els_req_payload[0]);
2058fcf3ce44SJohn Forte 			dq = 1;
2059fcf3ce44SJohn Forte 		} else if (((irp->irp_flags & IRP_PLOGI_DONE) == 0) &&
2060fcf3ce44SJohn Forte 		    (els->els_req_payload[0] != ELS_OP_PLOGI) &&
2061fcf3ce44SJohn Forte 		    (els->els_req_payload[0] != ELS_OP_LOGO) &&
2062fcf3ce44SJohn Forte 		    (special_prli_cond == 0)) {
2063fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "Killing ELS %x cond 3",
2064590ebdb0Sallan 			    els->els_req_payload[0]);
2065fcf3ce44SJohn Forte 			dq = 1;
2066fcf3ce44SJohn Forte 		}
2067fcf3ce44SJohn Forte 
2068fcf3ce44SJohn Forte 		if (dq) {
2069fcf3ce44SJohn Forte 			fct_i_cmd_t *c = (*ppcmd)->icmd_next;
2070fcf3ce44SJohn Forte 
2071fcf3ce44SJohn Forte 			if ((*ppcmd)->icmd_flags & ICMD_SESSION_AFFECTING)
20721a5e258fSJosef 'Jeff' Sipek 				atomic_dec_16(&irp->irp_sa_elses_count);
2073fcf3ce44SJohn Forte 			else
20741a5e258fSJosef 'Jeff' Sipek 				atomic_dec_16(&irp->irp_nsa_elses_count);
2075fcf3ce44SJohn Forte 			(*ppcmd)->icmd_next = cmd_to_abort;
2076fcf3ce44SJohn Forte 			cmd_to_abort = *ppcmd;
2077fcf3ce44SJohn Forte 			*ppcmd = c;
2078fcf3ce44SJohn Forte 		} else {
2079fcf3ce44SJohn Forte 			ppcmd = &((*ppcmd)->icmd_next);
2080fcf3ce44SJohn Forte 		}
2081fcf3ce44SJohn Forte 	}
2082fcf3ce44SJohn Forte 	rw_exit(&irp->irp_lock);
2083fcf3ce44SJohn Forte 
2084fcf3ce44SJohn Forte 	while (cmd_to_abort) {
2085fcf3ce44SJohn Forte 		fct_i_cmd_t *c = cmd_to_abort->icmd_next;
2086fcf3ce44SJohn Forte 
2087fcf3ce44SJohn Forte 		atomic_and_32(&cmd_to_abort->icmd_flags, ~ICMD_IN_IRP_QUEUE);
2088fcf3ce44SJohn Forte 		fct_queue_cmd_for_termination(cmd_to_abort->icmd_cmd,
2089590ebdb0Sallan 		    FCT_ABORTED);
2090fcf3ce44SJohn Forte 		cmd_to_abort = c;
2091fcf3ce44SJohn Forte 	}
2092fcf3ce44SJohn Forte 
2093fcf3ce44SJohn Forte 	/*
2094fcf3ce44SJohn Forte 	 * pick from the top of the queue
2095fcf3ce44SJohn Forte 	 */
2096fcf3ce44SJohn Forte 	icmd = irp->irp_els_list;
2097fcf3ce44SJohn Forte 	if (icmd == NULL) {
2098fcf3ce44SJohn Forte 		/*
2099fcf3ce44SJohn Forte 		 * The cleanup took care of everything.
2100fcf3ce44SJohn Forte 		 */
2101fcf3ce44SJohn Forte 
2102fcf3ce44SJohn Forte 		mutex_enter(&iport->iport_worker_lock);
2103fcf3ce44SJohn Forte 		return (DISC_ACTION_RESCAN);
2104fcf3ce44SJohn Forte 	}
2105fcf3ce44SJohn Forte 
2106fcf3ce44SJohn Forte 	cmd = icmd->icmd_cmd;
2107fcf3ce44SJohn Forte 	els = ICMD_TO_ELS(icmd);
2108fcf3ce44SJohn Forte 	op = els->els_req_payload[0];
2109fcf3ce44SJohn Forte 	if ((icmd->icmd_flags & ICMD_ELS_PROCESSING_STARTED) == 0) {
2110fcf3ce44SJohn Forte 		stmf_trace(iport->iport_alias, "Processing %ssol ELS %x (%s) "
2111fcf3ce44SJohn Forte 		    "rp_id=%x", (cmd->cmd_type == FCT_CMD_RCVD_ELS) ? "un" : "",
2112fcf3ce44SJohn Forte 		    op, FCT_ELS_NAME(op), cmd->cmd_rportid);
2113fcf3ce44SJohn Forte 		atomic_or_32(&icmd->icmd_flags, ICMD_ELS_PROCESSING_STARTED);
2114fcf3ce44SJohn Forte 	}
2115fcf3ce44SJohn Forte 
2116fcf3ce44SJohn Forte 	if (op == ELS_OP_PLOGI) {
2117fcf3ce44SJohn Forte 		ret |= fct_process_plogi(icmd);
2118fcf3ce44SJohn Forte 	} else if (op == ELS_OP_PRLI) {
2119fcf3ce44SJohn Forte 		ret |= fct_process_prli(icmd);
2120fcf3ce44SJohn Forte 	} else if (op == ELS_OP_LOGO) {
2121fcf3ce44SJohn Forte 		ret |= fct_process_logo(icmd);
2122fcf3ce44SJohn Forte 	} else if ((op == ELS_OP_PRLO) || (op == ELS_OP_TPRLO)) {
2123fcf3ce44SJohn Forte 		ret |= fct_process_prlo(icmd);
2124fcf3ce44SJohn Forte 	} else if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
2125fcf3ce44SJohn Forte 		fct_status_t s;
2126fcf3ce44SJohn Forte 		fct_local_port_t *port = iport->iport_port;
2127fcf3ce44SJohn Forte 
2128fcf3ce44SJohn Forte 		fct_dequeue_els(irp);
21291a5e258fSJosef 'Jeff' Sipek 		atomic_dec_16(&irp->irp_nsa_elses_count);
2130fcf3ce44SJohn Forte 		atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA);
2131fcf3ce44SJohn Forte 		if ((s = port->port_send_cmd(cmd)) != FCT_SUCCESS) {
2132fcf3ce44SJohn Forte 			atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA);
2133fcf3ce44SJohn Forte 			fct_queue_cmd_for_termination(cmd, s);
2134fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias, "Solicited els "
2135fcf3ce44SJohn Forte 			    "transport failed, ret = %llx", s);
2136fcf3ce44SJohn Forte 		}
2137fcf3ce44SJohn Forte 	} else if (op == ELS_OP_ADISC) {
2138fcf3ce44SJohn Forte 		ret |= fct_process_rcvd_adisc(icmd);
2139fcf3ce44SJohn Forte 	} else if (op == ELS_OP_RSCN) {
2140fcf3ce44SJohn Forte 		(void) fct_process_rscn(icmd);
2141fcf3ce44SJohn Forte 	} else {
2142fcf3ce44SJohn Forte 		(void) fct_process_unknown_els(icmd);
2143fcf3ce44SJohn Forte 	}
2144fcf3ce44SJohn Forte 
2145fcf3ce44SJohn Forte 	/*
2146fcf3ce44SJohn Forte 	 * This if condition will be false if a sa ELS trigged a cleanup
2147fcf3ce44SJohn Forte 	 * and set the ret = DISC_ACTION_DELAY_RESCAN. In that case we should
2148fcf3ce44SJohn Forte 	 * keep it that way.
2149fcf3ce44SJohn Forte 	 */
2150fcf3ce44SJohn Forte 	if (ret == DISC_ACTION_NO_WORK) {
2151fcf3ce44SJohn Forte 		/*
2152fcf3ce44SJohn Forte 		 * Since we dropped the lock, we will force a rescan. The
2153fcf3ce44SJohn Forte 		 * only exception is if someone returned
2154fcf3ce44SJohn Forte 		 * DISC_ACTION_DELAY_RESCAN, in which case that should be the
2155fcf3ce44SJohn Forte 		 * return value.
2156fcf3ce44SJohn Forte 		 */
2157fcf3ce44SJohn Forte 		ret = DISC_ACTION_RESCAN;
2158fcf3ce44SJohn Forte 	}
2159fcf3ce44SJohn Forte 
2160fcf3ce44SJohn Forte 	mutex_enter(&iport->iport_worker_lock);
2161fcf3ce44SJohn Forte 	return (ret);
2162fcf3ce44SJohn Forte }
2163fcf3ce44SJohn Forte 
2164fcf3ce44SJohn Forte void
fct_handle_sol_els_completion(fct_i_local_port_t * iport,fct_i_cmd_t * icmd)2165fcf3ce44SJohn Forte fct_handle_sol_els_completion(fct_i_local_port_t *iport, fct_i_cmd_t *icmd)
2166fcf3ce44SJohn Forte {
2167fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp = NULL;
2168fcf3ce44SJohn Forte 	fct_els_t		*els = ICMD_TO_ELS(icmd);
2169fcf3ce44SJohn Forte 	uint8_t			 op  = els->els_req_payload[0];
2170fcf3ce44SJohn Forte 
2171fcf3ce44SJohn Forte 	if (icmd->icmd_cmd->cmd_rp) {
2172fcf3ce44SJohn Forte 		irp = ICMD_TO_IRP(icmd);
2173fcf3ce44SJohn Forte 	}
2174fcf3ce44SJohn Forte 	if (icmd->icmd_cmd->cmd_rp &&
2175fcf3ce44SJohn Forte 	    (icmd->icmd_cmd->cmd_comp_status == FCT_SUCCESS) &&
2176fcf3ce44SJohn Forte 	    (els->els_req_payload[0] == ELS_OP_PLOGI)) {
2177fcf3ce44SJohn Forte 		bcopy(els->els_resp_payload + 20, irp->irp_rp->rp_pwwn, 8);
2178fcf3ce44SJohn Forte 		bcopy(els->els_resp_payload + 28, irp->irp_rp->rp_nwwn, 8);
2179fcf3ce44SJohn Forte 
2180fcf3ce44SJohn Forte 		stmf_wwn_to_devid_desc((scsi_devid_desc_t *)irp->irp_id,
2181fcf3ce44SJohn Forte 		    irp->irp_rp->rp_pwwn, PROTOCOL_FIBRE_CHANNEL);
2182fcf3ce44SJohn Forte 		atomic_or_32(&irp->irp_flags, IRP_PLOGI_DONE);
21831a5e258fSJosef 'Jeff' Sipek 		atomic_inc_32(&iport->iport_nrps_login);
2184fcf3ce44SJohn Forte 		if (irp->irp_deregister_timer) {
2185fcf3ce44SJohn Forte 			irp->irp_deregister_timer = 0;
2186fcf3ce44SJohn Forte 			irp->irp_dereg_count = 0;
2187fcf3ce44SJohn Forte 		}
2188fcf3ce44SJohn Forte 	}
2189fcf3ce44SJohn Forte 
2190fcf3ce44SJohn Forte 	if (irp && (els->els_req_payload[0] == ELS_OP_PLOGI)) {
2191fcf3ce44SJohn Forte 		atomic_and_32(&irp->irp_flags, ~IRP_SOL_PLOGI_IN_PROGRESS);
2192fcf3ce44SJohn Forte 	}
2193fcf3ce44SJohn Forte 	atomic_or_32(&icmd->icmd_flags, ICMD_CMD_COMPLETE);
2194fcf3ce44SJohn Forte 	stmf_trace(iport->iport_alias, "Sol ELS %x (%s) completed with "
2195fcf3ce44SJohn Forte 	    "status %llx, did/%x", op, FCT_ELS_NAME(op),
2196fcf3ce44SJohn Forte 	    icmd->icmd_cmd->cmd_comp_status, icmd->icmd_cmd->cmd_rportid);
2197fcf3ce44SJohn Forte }
2198fcf3ce44SJohn Forte 
2199fcf3ce44SJohn Forte static disc_action_t
fct_check_cmdlist(fct_i_local_port_t * iport)2200fcf3ce44SJohn Forte fct_check_cmdlist(fct_i_local_port_t *iport)
2201fcf3ce44SJohn Forte {
2202fcf3ce44SJohn Forte 	int		num_to_release, ndx;
2203fcf3ce44SJohn Forte 	fct_i_cmd_t	*icmd;
2204fcf3ce44SJohn Forte 	uint32_t	total, max_active;
2205fcf3ce44SJohn Forte 
2206fcf3ce44SJohn Forte 	ASSERT(MUTEX_HELD(&iport->iport_worker_lock));
2207fcf3ce44SJohn Forte 
2208fcf3ce44SJohn Forte 	total = iport->iport_total_alloced_ncmds;
2209fcf3ce44SJohn Forte 	max_active = iport->iport_max_active_ncmds;
2210fcf3ce44SJohn Forte 
2211fcf3ce44SJohn Forte 	if (total <= max_active)
2212fcf3ce44SJohn Forte 		return (DISC_ACTION_NO_WORK);
2213fcf3ce44SJohn Forte 	/*
2214fcf3ce44SJohn Forte 	 * Everytime, we release half of the difference
2215fcf3ce44SJohn Forte 	 */
2216fcf3ce44SJohn Forte 	num_to_release = (total + 1 - max_active) / 2;
2217fcf3ce44SJohn Forte 
2218fcf3ce44SJohn Forte 	mutex_exit(&iport->iport_worker_lock);
2219fcf3ce44SJohn Forte 	for (ndx = 0; ndx < num_to_release; ndx++) {
2220fcf3ce44SJohn Forte 		mutex_enter(&iport->iport_cached_cmd_lock);
2221fcf3ce44SJohn Forte 		icmd = iport->iport_cached_cmdlist;
2222fcf3ce44SJohn Forte 		if (icmd == NULL) {
2223fcf3ce44SJohn Forte 			mutex_exit(&iport->iport_cached_cmd_lock);
2224fcf3ce44SJohn Forte 			break;
2225fcf3ce44SJohn Forte 		}
2226fcf3ce44SJohn Forte 		iport->iport_cached_cmdlist = icmd->icmd_next;
2227fcf3ce44SJohn Forte 		iport->iport_cached_ncmds--;
2228fcf3ce44SJohn Forte 		mutex_exit(&iport->iport_cached_cmd_lock);
22291a5e258fSJosef 'Jeff' Sipek 		atomic_dec_32(&iport->iport_total_alloced_ncmds);
2230fcf3ce44SJohn Forte 		fct_free(icmd->icmd_cmd);
2231fcf3ce44SJohn Forte 	}
2232fcf3ce44SJohn Forte 	mutex_enter(&iport->iport_worker_lock);
2233fcf3ce44SJohn Forte 	return (DISC_ACTION_RESCAN);
2234fcf3ce44SJohn Forte }
2235fcf3ce44SJohn Forte 
2236fcf3ce44SJohn Forte /*
2237fcf3ce44SJohn Forte  * The efficiency of handling solicited commands is very low here. But
2238fcf3ce44SJohn Forte  * fortunately, we seldom send solicited commands. So it will not hurt
2239fcf3ce44SJohn Forte  * the system performance much.
2240fcf3ce44SJohn Forte  */
2241fcf3ce44SJohn Forte static disc_action_t
fct_check_solcmd_queue(fct_i_local_port_t * iport)2242fcf3ce44SJohn Forte fct_check_solcmd_queue(fct_i_local_port_t *iport)
2243fcf3ce44SJohn Forte {
2244fcf3ce44SJohn Forte 	fct_i_cmd_t	*icmd	    = NULL;
2245fcf3ce44SJohn Forte 	fct_i_cmd_t	*prev_icmd  = NULL;
2246fcf3ce44SJohn Forte 	fct_i_cmd_t	*next_icmd  = NULL;
2247fcf3ce44SJohn Forte 
2248fcf3ce44SJohn Forte 	ASSERT(mutex_owned(&iport->iport_worker_lock));
2249fcf3ce44SJohn Forte 	for (icmd = iport->iport_solcmd_queue; icmd; icmd = next_icmd) {
2250fcf3ce44SJohn Forte 		ASSERT(icmd->icmd_flags | ICMD_IN_SOLCMD_QUEUE);
2251fcf3ce44SJohn Forte 		next_icmd = icmd->icmd_solcmd_next;
2252fcf3ce44SJohn Forte 		if (icmd->icmd_flags & ICMD_SOLCMD_NEW) {
2253fcf3ce44SJohn Forte 			/*
2254fcf3ce44SJohn Forte 			 * This solicited cmd is new.
2255fcf3ce44SJohn Forte 			 * Dispatch ELSes to discovery queue to make use of
2256fcf3ce44SJohn Forte 			 * existent framework.
2257fcf3ce44SJohn Forte 			 */
2258fcf3ce44SJohn Forte 			icmd->icmd_flags &= ~ICMD_SOLCMD_NEW;
2259fcf3ce44SJohn Forte 			mutex_exit(&iport->iport_worker_lock);
2260fcf3ce44SJohn Forte 
2261fcf3ce44SJohn Forte 			if (icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_ELS) {
2262fcf3ce44SJohn Forte 				fct_handle_els(icmd->icmd_cmd);
2263fcf3ce44SJohn Forte 			} else {
2264fcf3ce44SJohn Forte 				fct_handle_solct(icmd->icmd_cmd);
2265fcf3ce44SJohn Forte 			}
2266fcf3ce44SJohn Forte 
2267fcf3ce44SJohn Forte 			mutex_enter(&iport->iport_worker_lock);
2268fcf3ce44SJohn Forte 		} else if (icmd->icmd_flags & ICMD_CMD_COMPLETE) {
2269fcf3ce44SJohn Forte 			/*
2270fcf3ce44SJohn Forte 			 * To make fct_check_solcmd simple and flexible,
2271fcf3ce44SJohn Forte 			 * We need only call callback to finish post-handling.
2272fcf3ce44SJohn Forte 			 */
2273fcf3ce44SJohn Forte 			if (icmd->icmd_cb) {
2274fcf3ce44SJohn Forte 				/*
2275fcf3ce44SJohn Forte 				 * mutex ???
2276fcf3ce44SJohn Forte 				 */
2277fcf3ce44SJohn Forte 				icmd->icmd_cb(icmd);
2278fcf3ce44SJohn Forte 			}
2279fcf3ce44SJohn Forte 
2280fcf3ce44SJohn Forte 
2281fcf3ce44SJohn Forte 			/*
2282fcf3ce44SJohn Forte 			 * Release resources for this solicited cmd
2283fcf3ce44SJohn Forte 			 */
2284fcf3ce44SJohn Forte 			if (iport->iport_solcmd_queue == icmd) {
2285fcf3ce44SJohn Forte 				iport->iport_solcmd_queue = next_icmd;
2286fcf3ce44SJohn Forte 			} else {
2287590ebdb0Sallan 				prev_icmd = iport->iport_solcmd_queue;
2288590ebdb0Sallan 				while (prev_icmd->icmd_solcmd_next != icmd) {
2289590ebdb0Sallan 					prev_icmd = prev_icmd->icmd_solcmd_next;
2290590ebdb0Sallan 				}
2291fcf3ce44SJohn Forte 				prev_icmd->icmd_solcmd_next = next_icmd;
2292fcf3ce44SJohn Forte 			}
2293fcf3ce44SJohn Forte 
2294fcf3ce44SJohn Forte 			icmd->icmd_cb = NULL;
2295fcf3ce44SJohn Forte 			mutex_exit(&iport->iport_worker_lock);
2296fcf3ce44SJohn Forte 			fct_cmd_free(icmd->icmd_cmd);
2297fcf3ce44SJohn Forte 			mutex_enter(&iport->iport_worker_lock);
2298fcf3ce44SJohn Forte 		} else {
2299fcf3ce44SJohn Forte 			/*
2300fcf3ce44SJohn Forte 			 * This solicited cmd is still ongoing.
2301fcf3ce44SJohn Forte 			 * We need check if it's time to abort this cmd
2302fcf3ce44SJohn Forte 			 */
2303fcf3ce44SJohn Forte 			if (((icmd->icmd_start_time + drv_usectohz(
2304fcf3ce44SJohn Forte 			    USEC_SOL_TIMEOUT)) < ddi_get_lbolt()) &&
2305fcf3ce44SJohn Forte 			    !(icmd->icmd_flags & ICMD_BEING_ABORTED)) {
2306fcf3ce44SJohn Forte 				fct_q_for_termination_lock_held(iport,
2307fcf3ce44SJohn Forte 				    icmd, FCT_ABORTED);
2308fcf3ce44SJohn Forte 			}
2309fcf3ce44SJohn Forte 		}
2310fcf3ce44SJohn Forte 	}
2311fcf3ce44SJohn Forte 
2312fcf3ce44SJohn Forte 	return (DISC_ACTION_DELAY_RESCAN);
2313fcf3ce44SJohn Forte }
2314fcf3ce44SJohn Forte 
2315fcf3ce44SJohn Forte void
fct_handle_solct(fct_cmd_t * cmd)2316fcf3ce44SJohn Forte fct_handle_solct(fct_cmd_t *cmd)
2317fcf3ce44SJohn Forte {
2318fcf3ce44SJohn Forte 	fct_status_t		 ret	  = FCT_SUCCESS;
2319fcf3ce44SJohn Forte 	fct_i_cmd_t		*icmd	  = CMD_TO_ICMD(cmd);
2320fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport	  = ICMD_TO_IPORT(icmd);
2321fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp	  = ICMD_TO_IRP(icmd);
2322fcf3ce44SJohn Forte 
2323fcf3ce44SJohn Forte 	ASSERT(cmd->cmd_type == FCT_CMD_SOL_CT);
2324fcf3ce44SJohn Forte 	rw_enter(&iport->iport_lock, RW_READER);
2325fcf3ce44SJohn Forte 	/*
2326fcf3ce44SJohn Forte 	 * Let's make sure local port is sane
2327fcf3ce44SJohn Forte 	 */
2328fcf3ce44SJohn Forte 	if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
2329fcf3ce44SJohn Forte 		rw_exit(&iport->iport_lock);
2330fcf3ce44SJohn Forte 
2331fcf3ce44SJohn Forte 		stmf_trace(iport->iport_alias, "fct_transport_solct: "
2332fcf3ce44SJohn Forte 		    "solcmd-%p transport failed, becasue port state was %x",
2333fcf3ce44SJohn Forte 		    cmd, iport->iport_link_state);
2334fcf3ce44SJohn Forte 		fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE);
2335fcf3ce44SJohn Forte 		return;
2336fcf3ce44SJohn Forte 	}
2337fcf3ce44SJohn Forte 
2338fcf3ce44SJohn Forte 	/*
2339fcf3ce44SJohn Forte 	 * Let's make sure we have plogi-ed to name server
2340fcf3ce44SJohn Forte 	 */
2341fcf3ce44SJohn Forte 	rw_enter(&irp->irp_lock, RW_READER);
2342fcf3ce44SJohn Forte 	if (!(irp->irp_flags & IRP_PLOGI_DONE)) {
2343fcf3ce44SJohn Forte 		rw_exit(&irp->irp_lock);
2344fcf3ce44SJohn Forte 		rw_exit(&iport->iport_lock);
2345fcf3ce44SJohn Forte 
2346fcf3ce44SJohn Forte 		stmf_trace(iport->iport_alias, "fct_transport_solct: "
2347fcf3ce44SJohn Forte 		    "Must login to name server first - cmd-%p", cmd);
2348fcf3ce44SJohn Forte 		fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN);
2349fcf3ce44SJohn Forte 		return;
2350fcf3ce44SJohn Forte 	}
2351fcf3ce44SJohn Forte 
2352fcf3ce44SJohn Forte 	/*
2353fcf3ce44SJohn Forte 	 * Let's get a slot for this solcmd
2354fcf3ce44SJohn Forte 	 */
2355fcf3ce44SJohn Forte 	if (fct_alloc_cmd_slot(iport, cmd) == FCT_SLOT_EOL) {
2356fcf3ce44SJohn Forte 		rw_exit(&irp->irp_lock);
2357fcf3ce44SJohn Forte 		rw_exit(&iport->iport_lock);
2358fcf3ce44SJohn Forte 
2359fcf3ce44SJohn Forte 		stmf_trace(iport->iport_alias, "fct_transport_solcmd: "
2360fcf3ce44SJohn Forte 		    "ran out of xchg resources - cmd-%p", cmd);
2361fcf3ce44SJohn Forte 		fct_queue_cmd_for_termination(cmd, FCT_NO_XCHG_RESOURCE);
2362fcf3ce44SJohn Forte 		return;
2363fcf3ce44SJohn Forte 	}
2364fcf3ce44SJohn Forte 
2365fcf3ce44SJohn Forte 	if (fct_netbuf_to_value(ICMD_TO_CT(icmd)->ct_req_payload + 8, 2) ==
2366fcf3ce44SJohn Forte 	    NS_GID_PN) {
2367fcf3ce44SJohn Forte 		fct_i_remote_port_t	*query_irp = NULL;
2368fcf3ce44SJohn Forte 
2369fcf3ce44SJohn Forte 		query_irp = fct_lookup_irp_by_portwwn(iport,
2370fcf3ce44SJohn Forte 		    ICMD_TO_CT(icmd)->ct_req_payload + 16);
2371fcf3ce44SJohn Forte 		if (query_irp) {
2372fcf3ce44SJohn Forte 			atomic_and_32(&query_irp->irp_flags, ~IRP_RSCN_QUEUED);
2373fcf3ce44SJohn Forte 		}
2374fcf3ce44SJohn Forte 	}
2375fcf3ce44SJohn Forte 	rw_exit(&irp->irp_lock);
2376fcf3ce44SJohn Forte 	rw_exit(&iport->iport_lock);
2377fcf3ce44SJohn Forte 
23781a5e258fSJosef 'Jeff' Sipek 	atomic_inc_16(&irp->irp_nonfcp_xchg_count);
2379fcf3ce44SJohn Forte 	atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA);
2380fcf3ce44SJohn Forte 	icmd->icmd_start_time = ddi_get_lbolt();
2381fcf3ce44SJohn Forte 	ret = iport->iport_port->port_send_cmd(cmd);
2382fcf3ce44SJohn Forte 	if (ret != FCT_SUCCESS) {
2383fcf3ce44SJohn Forte 		atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA);
2384fcf3ce44SJohn Forte 		fct_queue_cmd_for_termination(cmd, ret);
2385fcf3ce44SJohn Forte 	}
2386fcf3ce44SJohn Forte }
2387fcf3ce44SJohn Forte 
2388fcf3ce44SJohn Forte void
fct_logo_cb(fct_i_cmd_t * icmd)2389fcf3ce44SJohn Forte fct_logo_cb(fct_i_cmd_t *icmd)
2390fcf3ce44SJohn Forte {
2391fcf3ce44SJohn Forte 	ASSERT(!(icmd->icmd_flags & ICMD_IMPLICIT));
2392fcf3ce44SJohn Forte 	if (!FCT_IS_ELS_ACC(icmd)) {
2393fcf3ce44SJohn Forte 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_logo_cb: "
2394fcf3ce44SJohn Forte 		    "solicited LOGO is not accepted - icmd/%p", icmd);
2395fcf3ce44SJohn Forte 	}
2396fcf3ce44SJohn Forte }
2397fcf3ce44SJohn Forte 
2398fcf3ce44SJohn Forte void
fct_gsnn_cb(fct_i_cmd_t * icmd)2399fcf3ce44SJohn Forte fct_gsnn_cb(fct_i_cmd_t *icmd)
2400fcf3ce44SJohn Forte {
2401fcf3ce44SJohn Forte 	int			 snlen	   = 0;
2402fcf3ce44SJohn Forte 	char			*sn	   = NULL;
2403fcf3ce44SJohn Forte 	fct_i_remote_port_t	*query_irp = NULL;
2404fcf3ce44SJohn Forte 
2405fcf3ce44SJohn Forte 	if (!FCT_IS_CT_ACC(icmd)) {
2406fcf3ce44SJohn Forte 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: "
2407fcf3ce44SJohn Forte 		    "GSNN is not accepted by NS - icmd/%p", icmd);
2408fcf3ce44SJohn Forte 		return;
2409fcf3ce44SJohn Forte 	}
2410fcf3ce44SJohn Forte 	mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
2411fcf3ce44SJohn Forte 
2412fcf3ce44SJohn Forte 	rw_enter(&ICMD_TO_IPORT(icmd)->iport_lock, RW_READER);
2413fcf3ce44SJohn Forte 	mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
2414fcf3ce44SJohn Forte 	query_irp = fct_lookup_irp_by_nodewwn(ICMD_TO_IPORT(icmd),
2415fcf3ce44SJohn Forte 	    ICMD_TO_CT(icmd)->ct_req_payload + 16);
2416fcf3ce44SJohn Forte 
2417fcf3ce44SJohn Forte 	if (!query_irp) {
2418fcf3ce44SJohn Forte 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: "
2419fcf3ce44SJohn Forte 		    "can't get rp icmd-%p", icmd);
2420fcf3ce44SJohn Forte 		goto exit_gsnn_cb;
2421fcf3ce44SJohn Forte 	} else {
2422fcf3ce44SJohn Forte 		snlen = ICMD_TO_CT(icmd)->ct_resp_payload[16];
2423fcf3ce44SJohn Forte 	}
2424fcf3ce44SJohn Forte 
2425fcf3ce44SJohn Forte 	if (query_irp && snlen) {
2426fcf3ce44SJohn Forte 		/*
2427fcf3ce44SJohn Forte 		 * Release previous resource, then allocate needed resource
2428fcf3ce44SJohn Forte 		 */
2429fcf3ce44SJohn Forte 		sn = query_irp->irp_snn;
2430fcf3ce44SJohn Forte 		if (sn) {
2431fcf3ce44SJohn Forte 			kmem_free(sn, strlen(sn) + 1);
2432fcf3ce44SJohn Forte 		}
2433fcf3ce44SJohn Forte 
2434fcf3ce44SJohn Forte 		query_irp->irp_snn = NULL;
2435fcf3ce44SJohn Forte 		sn = kmem_zalloc(snlen + 1, KM_SLEEP);
2436fcf3ce44SJohn Forte 		(void) strncpy(sn, (char *)
2437fcf3ce44SJohn Forte 		    ICMD_TO_CT(icmd)->ct_resp_payload + 17, snlen);
2438fcf3ce44SJohn Forte 		if (strlen(sn) != snlen) {
2439fcf3ce44SJohn Forte 			stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias,
2440fcf3ce44SJohn Forte 			    "fct_gsnn_cb: %s, but len=%d", sn, snlen);
2441fcf3ce44SJohn Forte 			kmem_free(sn, snlen + 1);
2442fcf3ce44SJohn Forte 			sn = NULL;
2443fcf3ce44SJohn Forte 		}
2444fcf3ce44SJohn Forte 
2445fcf3ce44SJohn Forte 		/*
2446fcf3ce44SJohn Forte 		 * Update symbolic node name
2447fcf3ce44SJohn Forte 		 */
2448fcf3ce44SJohn Forte 		query_irp->irp_snn = sn;
2449fcf3ce44SJohn Forte 		if ((query_irp->irp_flags & IRP_SCSI_SESSION_STARTED) &&
2450fcf3ce44SJohn Forte 		    (query_irp->irp_session)) {
2451fcf3ce44SJohn Forte 			query_irp->irp_session->ss_rport_alias =
2452fcf3ce44SJohn Forte 			    query_irp->irp_snn;
2453fcf3ce44SJohn Forte 		}
2454fcf3ce44SJohn Forte 	} else {
2455fcf3ce44SJohn Forte 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: "
2456fcf3ce44SJohn Forte 		    "irp/%p, snlen/%d", query_irp, snlen);
2457fcf3ce44SJohn Forte 	}
2458fcf3ce44SJohn Forte 
2459fcf3ce44SJohn Forte exit_gsnn_cb:
2460fcf3ce44SJohn Forte 	rw_exit(&ICMD_TO_IPORT(icmd)->iport_lock);
2461fcf3ce44SJohn Forte }
2462fcf3ce44SJohn Forte 
2463fcf3ce44SJohn Forte void
fct_link_init_cb(fct_i_cmd_t * icmd)2464fcf3ce44SJohn Forte fct_link_init_cb(fct_i_cmd_t *icmd)
2465fcf3ce44SJohn Forte {
2466fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport = ICMD_TO_IPORT(icmd);
2467fcf3ce44SJohn Forte 
2468fcf3ce44SJohn Forte 	iport->iport_li_state &= ~LI_STATE_FLAG_CMD_WAITING;
2469fcf3ce44SJohn Forte 	if (icmd->icmd_cmd->cmd_comp_status != FCT_SUCCESS) {
2470fcf3ce44SJohn Forte 		stmf_trace(iport->iport_alias, "fct_link_init_cb: ELS-%x failed"
2471fcf3ce44SJohn Forte 		    "comp_status- %llx", ICMD_TO_ELS(icmd)->els_req_payload[0],
2472fcf3ce44SJohn Forte 		    icmd->icmd_cmd->cmd_comp_status);
2473fcf3ce44SJohn Forte 		iport->iport_li_comp_status = icmd->icmd_cmd->cmd_comp_status;
2474fcf3ce44SJohn Forte 	} else if (icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_ELS) {
2475fcf3ce44SJohn Forte 		if (!FCT_IS_ELS_ACC(icmd)) {
2476fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias,
2477fcf3ce44SJohn Forte 			    "fct_link_init_cb: ELS-%x is rejected",
2478fcf3ce44SJohn Forte 			    ICMD_TO_ELS(icmd)->els_req_payload[0]);
2479fcf3ce44SJohn Forte 			iport->iport_li_comp_status = FCT_REJECT_STATUS(
2480fcf3ce44SJohn Forte 			    ICMD_TO_ELS(icmd)->els_resp_payload[1],
2481fcf3ce44SJohn Forte 			    ICMD_TO_ELS(icmd)->els_resp_payload[2]);
2482fcf3ce44SJohn Forte 		} else {
2483fcf3ce44SJohn Forte 			iport->iport_li_comp_status = FCT_SUCCESS;
2484fcf3ce44SJohn Forte 		}
2485fcf3ce44SJohn Forte 	} else {
2486fcf3ce44SJohn Forte 		ASSERT(icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_CT);
2487fcf3ce44SJohn Forte 		if (!FCT_IS_CT_ACC(icmd)) {
2488fcf3ce44SJohn Forte 			stmf_trace(iport->iport_alias,
2489fcf3ce44SJohn Forte 			    "fct_link_init_cb: CT-%02x%02x is rejected",
2490fcf3ce44SJohn Forte 			    ICMD_TO_CT(icmd)->ct_req_payload[8],
2491fcf3ce44SJohn Forte 			    ICMD_TO_CT(icmd)->ct_req_payload[9]);
2492fcf3ce44SJohn Forte 			iport->iport_li_comp_status = FCT_REJECT_STATUS(
2493fcf3ce44SJohn Forte 			    ICMD_TO_CT(icmd)->ct_resp_payload[8],
2494fcf3ce44SJohn Forte 			    ICMD_TO_CT(icmd)->ct_resp_payload[9]);
2495fcf3ce44SJohn Forte 		} else {
2496fcf3ce44SJohn Forte 			iport->iport_li_comp_status = FCT_SUCCESS;
2497fcf3ce44SJohn Forte 		}
2498fcf3ce44SJohn Forte 	}
2499fcf3ce44SJohn Forte }
2500fcf3ce44SJohn Forte 
2501fcf3ce44SJohn Forte void
fct_gcs_cb(fct_i_cmd_t * icmd)2502fcf3ce44SJohn Forte fct_gcs_cb(fct_i_cmd_t *icmd)
2503fcf3ce44SJohn Forte {
2504fcf3ce44SJohn Forte 	fct_sol_ct_t		*ct	   = ICMD_TO_CT(icmd);
2505fcf3ce44SJohn Forte 	fct_i_remote_port_t	*query_irp = NULL;
2506fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport	   = ICMD_TO_IPORT(icmd);
2507fcf3ce44SJohn Forte 	uint32_t		 query_portid;
2508fcf3ce44SJohn Forte 	uint8_t			*resp;
2509fcf3ce44SJohn Forte 	uint8_t			*req;
2510fcf3ce44SJohn Forte 
2511fcf3ce44SJohn Forte 	if (!FCT_IS_CT_ACC(icmd)) {
2512fcf3ce44SJohn Forte 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gcs_cb: "
2513fcf3ce44SJohn Forte 		    "GCS_ID is not accepted by NS - icmd/%p", icmd);
2514fcf3ce44SJohn Forte 		return;
2515fcf3ce44SJohn Forte 	}
2516fcf3ce44SJohn Forte 	mutex_exit(&iport->iport_worker_lock);
2517fcf3ce44SJohn Forte 
2518fcf3ce44SJohn Forte 	resp = ct->ct_resp_payload;
2519fcf3ce44SJohn Forte 	req = ct->ct_req_payload;
2520fcf3ce44SJohn Forte 	query_portid = (req[17] << 16) | (req[18] << 8) | req[19];
2521fcf3ce44SJohn Forte 
2522fcf3ce44SJohn Forte 	rw_enter(&iport->iport_lock, RW_READER);
2523fcf3ce44SJohn Forte 	mutex_enter(&iport->iport_worker_lock);
2524fcf3ce44SJohn Forte 	query_irp = fct_portid_to_portptr(iport, query_portid);
2525fcf3ce44SJohn Forte 
2526fcf3ce44SJohn Forte 	if (query_irp) {
2527fcf3ce44SJohn Forte 		query_irp->irp_cos = (resp[16] << 27) | (resp[17] << 18) |
2528fcf3ce44SJohn Forte 		    (resp[18] << 8) | resp[19];
2529fcf3ce44SJohn Forte 	}
2530fcf3ce44SJohn Forte 	rw_exit(&iport->iport_lock);
2531fcf3ce44SJohn Forte }
2532fcf3ce44SJohn Forte 
2533fcf3ce44SJohn Forte void
fct_gft_cb(fct_i_cmd_t * icmd)2534fcf3ce44SJohn Forte fct_gft_cb(fct_i_cmd_t *icmd)
2535fcf3ce44SJohn Forte {
2536fcf3ce44SJohn Forte 	fct_sol_ct_t		*ct	   = ICMD_TO_CT(icmd);
2537fcf3ce44SJohn Forte 	fct_i_remote_port_t	*query_irp = NULL;
2538fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport	   = ICMD_TO_IPORT(icmd);
2539fcf3ce44SJohn Forte 	uint32_t		 query_portid;
2540fcf3ce44SJohn Forte 	uint8_t			*resp;
2541fcf3ce44SJohn Forte 	uint8_t			*req;
2542fcf3ce44SJohn Forte 
2543fcf3ce44SJohn Forte 	if (!FCT_IS_CT_ACC(icmd)) {
2544fcf3ce44SJohn Forte 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gft_cb: "
2545fcf3ce44SJohn Forte 		    "GFT_ID is not accepted by NS - icmd/%p", icmd);
2546fcf3ce44SJohn Forte 		return;
2547fcf3ce44SJohn Forte 	}
2548fcf3ce44SJohn Forte 	mutex_exit(&iport->iport_worker_lock);
2549fcf3ce44SJohn Forte 
2550fcf3ce44SJohn Forte 	resp = ct->ct_resp_payload;
2551fcf3ce44SJohn Forte 	req = ct->ct_req_payload;
2552fcf3ce44SJohn Forte 	query_portid = (req[17] << 16) | (req[18] << 8) | req[19];
2553fcf3ce44SJohn Forte 
2554fcf3ce44SJohn Forte 	rw_enter(&iport->iport_lock, RW_READER);
2555fcf3ce44SJohn Forte 	mutex_enter(&iport->iport_worker_lock);
2556fcf3ce44SJohn Forte 	query_irp = fct_portid_to_portptr(iport, query_portid);
2557fcf3ce44SJohn Forte 
2558fcf3ce44SJohn Forte 	if (query_irp) {
2559fcf3ce44SJohn Forte 		(void) memcpy(query_irp->irp_fc4types, resp + 16, 32);
2560fcf3ce44SJohn Forte 	}
2561fcf3ce44SJohn Forte 	rw_exit(&iport->iport_lock);
2562fcf3ce44SJohn Forte }
2563fcf3ce44SJohn Forte 
2564fcf3ce44SJohn Forte void
fct_gid_cb(fct_i_cmd_t * icmd)2565fcf3ce44SJohn Forte fct_gid_cb(fct_i_cmd_t *icmd)
2566fcf3ce44SJohn Forte {
2567fcf3ce44SJohn Forte 	fct_cmd_t		*cmd	   = NULL;
2568fcf3ce44SJohn Forte 	fct_i_remote_port_t	*query_irp = NULL;
2569fcf3ce44SJohn Forte 	uint32_t		 nsportid  = 0;
2570fcf3ce44SJohn Forte 	int			 do_logo   = 0;
2571fcf3ce44SJohn Forte 
2572fcf3ce44SJohn Forte 	mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
2573fcf3ce44SJohn Forte 
2574fcf3ce44SJohn Forte 	rw_enter(&ICMD_TO_IPORT(icmd)->iport_lock, RW_READER);
2575fcf3ce44SJohn Forte 	mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
2576fcf3ce44SJohn Forte 	query_irp = fct_lookup_irp_by_portwwn(ICMD_TO_IPORT(icmd),
2577fcf3ce44SJohn Forte 	    ICMD_TO_CT(icmd)->ct_req_payload + 16);
2578fcf3ce44SJohn Forte 
2579fcf3ce44SJohn Forte 	if (!query_irp || (query_irp &&
2580fcf3ce44SJohn Forte 	    (PTR2INT(icmd->icmd_cb_private, uint32_t) !=
2581fcf3ce44SJohn Forte 	    query_irp->irp_rscn_counter))) {
2582fcf3ce44SJohn Forte 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: "
2583fcf3ce44SJohn Forte 		    "new RSCN arrived - query_irp/%p, private-%x", query_irp,
2584fcf3ce44SJohn Forte 		    PTR2INT(icmd->icmd_cb_private, uint32_t));
2585fcf3ce44SJohn Forte 		goto exit_gid_cb;
2586fcf3ce44SJohn Forte 	}
2587fcf3ce44SJohn Forte 
2588fcf3ce44SJohn Forte 	if ((query_irp->irp_flags & IRP_RSCN_QUEUED) ||
2589fcf3ce44SJohn Forte 	    (!(query_irp->irp_flags & IRP_PLOGI_DONE)))	{
2590fcf3ce44SJohn Forte 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: "
2591fcf3ce44SJohn Forte 		    "not proper irp_flags - query_irp/%p", query_irp);
2592fcf3ce44SJohn Forte 		goto exit_gid_cb;
2593fcf3ce44SJohn Forte 	}
2594fcf3ce44SJohn Forte 
2595fcf3ce44SJohn Forte 	if (!FCT_IS_CT_ACC(icmd)) {
2596fcf3ce44SJohn Forte 		/*
2597fcf3ce44SJohn Forte 		 * Check if it has disappeared
2598fcf3ce44SJohn Forte 		 */
2599fcf3ce44SJohn Forte 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: "
2600fcf3ce44SJohn Forte 		    "GPN_ID is not accepted by NS - icmd/%p", icmd);
2601fcf3ce44SJohn Forte 		do_logo = 1;
2602fcf3ce44SJohn Forte 	} else {
2603fcf3ce44SJohn Forte 		/*
2604fcf3ce44SJohn Forte 		 * Check if its portid has changed
2605fcf3ce44SJohn Forte 		 */
2606fcf3ce44SJohn Forte 		nsportid = fct_netbuf_to_value(
2607fcf3ce44SJohn Forte 		    ICMD_TO_CT(icmd)->ct_resp_payload + 17, 3);
2608fcf3ce44SJohn Forte 		if (nsportid != query_irp->irp_rp->rp_id) {
2609fcf3ce44SJohn Forte 			stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias,
2610fcf3ce44SJohn Forte 			    "portid has changed - query_irp/%p", query_irp);
2611fcf3ce44SJohn Forte 			do_logo = 1;
2612fcf3ce44SJohn Forte 		}
2613fcf3ce44SJohn Forte 	}
2614fcf3ce44SJohn Forte 
2615fcf3ce44SJohn Forte 	if (do_logo) {
2616fcf3ce44SJohn Forte 		cmd = fct_create_solels(ICMD_TO_PORT(icmd),
2617fcf3ce44SJohn Forte 		    query_irp->irp_rp, 1, ELS_OP_LOGO, 0, fct_logo_cb);
2618fcf3ce44SJohn Forte 		if (cmd) {
2619fcf3ce44SJohn Forte 			mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
2620fcf3ce44SJohn Forte 			fct_post_implicit_logo(cmd);
2621fcf3ce44SJohn Forte 			mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
2622fcf3ce44SJohn Forte 		}
2623fcf3ce44SJohn Forte 	}
2624fcf3ce44SJohn Forte 
2625fcf3ce44SJohn Forte exit_gid_cb:
2626fcf3ce44SJohn Forte 	rw_exit(&ICMD_TO_IPORT(icmd)->iport_lock);
2627fcf3ce44SJohn Forte }
2628fcf3ce44SJohn Forte 
2629fcf3ce44SJohn Forte void
fct_gspn_cb(fct_i_cmd_t * icmd)2630fcf3ce44SJohn Forte fct_gspn_cb(fct_i_cmd_t *icmd)
2631fcf3ce44SJohn Forte {
2632fcf3ce44SJohn Forte 	fct_sol_ct_t		*ct	   = ICMD_TO_CT(icmd);
2633fcf3ce44SJohn Forte 	fct_i_remote_port_t	*query_irp = NULL;
2634fcf3ce44SJohn Forte 	fct_i_local_port_t	*iport	   = ICMD_TO_IPORT(icmd);
2635fcf3ce44SJohn Forte 	uint32_t		 query_portid;
2636fcf3ce44SJohn Forte 	uint8_t			*resp;
2637fcf3ce44SJohn Forte 	uint8_t			*req;
2638fcf3ce44SJohn Forte 	uint8_t			 spnlen;
2639fcf3ce44SJohn Forte 
2640fcf3ce44SJohn Forte 	if (!FCT_IS_CT_ACC(icmd)) {
2641fcf3ce44SJohn Forte 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gspn_cb: "
2642fcf3ce44SJohn Forte 		    "GSPN_ID is not accepted by NS - icmd/%p", icmd);
2643fcf3ce44SJohn Forte 		return;
2644fcf3ce44SJohn Forte 	}
2645fcf3ce44SJohn Forte 	mutex_exit(&iport->iport_worker_lock);
2646fcf3ce44SJohn Forte 
2647fcf3ce44SJohn Forte 	resp = ct->ct_resp_payload;
2648fcf3ce44SJohn Forte 	req = ct->ct_req_payload;
2649fcf3ce44SJohn Forte 	query_portid = (req[17] << 16) | (req[18] << 8) | req[19];
2650fcf3ce44SJohn Forte 
2651fcf3ce44SJohn Forte 	rw_enter(&iport->iport_lock, RW_READER);
2652fcf3ce44SJohn Forte 	mutex_enter(&iport->iport_worker_lock);
2653fcf3ce44SJohn Forte 	query_irp = fct_portid_to_portptr(iport, query_portid);
2654fcf3ce44SJohn Forte 	if (query_irp) {
2655fcf3ce44SJohn Forte 		spnlen = resp[16];
2656fcf3ce44SJohn Forte 		if (spnlen > 0) {
2657fcf3ce44SJohn Forte 			if (query_irp->irp_spn) {
2658fcf3ce44SJohn Forte 				kmem_free(query_irp->irp_spn,
2659fcf3ce44SJohn Forte 				    strlen(query_irp->irp_spn) + 1);
2660fcf3ce44SJohn Forte 			}
2661fcf3ce44SJohn Forte 			query_irp->irp_spn = kmem_zalloc(spnlen + 1, KM_SLEEP);
2662fcf3ce44SJohn Forte 			(void) strncpy(query_irp->irp_spn,
2663fcf3ce44SJohn Forte 			    (char *)resp + 17, spnlen);
2664fcf3ce44SJohn Forte 		}
2665fcf3ce44SJohn Forte 	}
2666fcf3ce44SJohn Forte 	rw_exit(&iport->iport_lock);
2667fcf3ce44SJohn Forte }
2668fcf3ce44SJohn Forte 
2669c946facaSallan void
fct_rls_cb(fct_i_cmd_t * icmd)2670c946facaSallan fct_rls_cb(fct_i_cmd_t *icmd)
2671c946facaSallan {
2672c946facaSallan 	fct_els_t		*els = ICMD_TO_ELS(icmd);
2673c946facaSallan 	uint8_t			*resp;
2674c946facaSallan 	fct_rls_cb_data_t	*rls_cb_data = NULL;
2675c946facaSallan 	fct_port_link_status_t	*rls_resp;
2676c946facaSallan 	fct_i_local_port_t	*iport = ICMD_TO_IPORT(icmd);
2677c946facaSallan 
2678c946facaSallan 	rls_cb_data = icmd->icmd_cb_private;
2679c946facaSallan 
2680c946facaSallan 	if (!FCT_IS_ELS_ACC(icmd)) {
2681c946facaSallan 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_rls_cb: "
2682c946facaSallan 		    "solicited RLS is not accepted - icmd/%p", icmd);
2683c946facaSallan 		if (rls_cb_data) {
2684c946facaSallan 			rls_cb_data->fct_els_res = FCT_FAILURE;
2685c946facaSallan 			sema_v(&iport->iport_rls_sema);
2686c946facaSallan 		}
2687c946facaSallan 		return;
2688c946facaSallan 	}
2689c946facaSallan 
2690c946facaSallan 	if (!rls_cb_data) {
2691c946facaSallan 		sema_v(&iport->iport_rls_sema);
2692c946facaSallan 		return;
2693c946facaSallan 	}
2694c946facaSallan 
2695c946facaSallan 	resp = els->els_resp_payload;
2696c946facaSallan 
2697c946facaSallan 	rls_cb_data = icmd->icmd_cb_private;
2698c946facaSallan 
2699c946facaSallan 	/* Get the response and store it somewhere */
2700c946facaSallan 	rls_resp = (fct_port_link_status_t *)rls_cb_data->fct_link_status;
2701c946facaSallan 	rls_resp->LinkFailureCount = BE_32(*((uint32_t *)(resp + 4)));
2702c946facaSallan 	rls_resp->LossOfSyncCount = BE_32(*((uint32_t *)(resp + 8)));
2703c946facaSallan 	rls_resp->LossOfSignalsCount = BE_32(*((uint32_t *)(resp + 12)));
2704c946facaSallan 	rls_resp->PrimitiveSeqProtocolErrorCount =
2705c946facaSallan 	    BE_32(*((uint32_t *)(resp + 16)));
2706c946facaSallan 	rls_resp->InvalidTransmissionWordCount =
2707c946facaSallan 	    BE_32(*((uint32_t *)(resp + 20)));
2708c946facaSallan 	rls_resp->InvalidCRCCount = BE_32(*((uint32_t *)(resp + 24)));
2709c946facaSallan 
2710c946facaSallan 	rls_cb_data->fct_els_res = FCT_SUCCESS;
2711c946facaSallan 	sema_v(&iport->iport_rls_sema);
2712c946facaSallan 	icmd->icmd_cb_private = NULL;
2713c946facaSallan }
2714c946facaSallan 
2715fcf3ce44SJohn Forte /*
2716fcf3ce44SJohn Forte  * For lookup functions, we move locking up one level
2717fcf3ce44SJohn Forte  */
2718fcf3ce44SJohn Forte fct_i_remote_port_t *
fct_lookup_irp_by_nodewwn(fct_i_local_port_t * iport,uint8_t * nodewwn)2719fcf3ce44SJohn Forte fct_lookup_irp_by_nodewwn(fct_i_local_port_t *iport, uint8_t *nodewwn)
2720fcf3ce44SJohn Forte {
2721fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp = NULL;
2722fcf3ce44SJohn Forte 	int			 idx = 0;
2723fcf3ce44SJohn Forte 
2724fcf3ce44SJohn Forte 	for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) {
2725fcf3ce44SJohn Forte 		for (irp = iport->iport_rp_tb[idx]; irp;
2726fcf3ce44SJohn Forte 		    irp = irp->irp_next) {
2727fcf3ce44SJohn Forte 			if (bcmp(irp->irp_rp->rp_nwwn, nodewwn, FC_WWN_LEN)) {
2728fcf3ce44SJohn Forte 				continue;
2729fcf3ce44SJohn Forte 			} else {
2730fcf3ce44SJohn Forte 				return (irp);
2731fcf3ce44SJohn Forte 			}
2732fcf3ce44SJohn Forte 		}
2733fcf3ce44SJohn Forte 	}
2734fcf3ce44SJohn Forte 
2735fcf3ce44SJohn Forte 	return (NULL);
2736fcf3ce44SJohn Forte }
2737fcf3ce44SJohn Forte 
2738fcf3ce44SJohn Forte fct_i_remote_port_t *
fct_lookup_irp_by_portwwn(fct_i_local_port_t * iport,uint8_t * portwwn)2739fcf3ce44SJohn Forte fct_lookup_irp_by_portwwn(fct_i_local_port_t *iport, uint8_t *portwwn)
2740fcf3ce44SJohn Forte {
2741fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp = NULL;
2742fcf3ce44SJohn Forte 	int			 idx = 0;
2743fcf3ce44SJohn Forte 
2744fcf3ce44SJohn Forte 	for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) {
2745fcf3ce44SJohn Forte 		for (irp = iport->iport_rp_tb[idx]; irp;
2746fcf3ce44SJohn Forte 		    irp = irp->irp_next) {
2747fcf3ce44SJohn Forte 			if (bcmp(irp->irp_rp->rp_pwwn, portwwn, FC_WWN_LEN)) {
2748fcf3ce44SJohn Forte 				continue;
2749fcf3ce44SJohn Forte 			} else {
2750fcf3ce44SJohn Forte 				return (irp);
2751fcf3ce44SJohn Forte 			}
2752fcf3ce44SJohn Forte 		}
2753fcf3ce44SJohn Forte 	}
2754fcf3ce44SJohn Forte 
2755fcf3ce44SJohn Forte 	return (NULL);
2756fcf3ce44SJohn Forte }
2757fcf3ce44SJohn Forte 
2758fcf3ce44SJohn Forte #ifdef	lint
2759fcf3ce44SJohn Forte #define	FCT_VERIFY_RSCN()	_NOTE(EMPTY)
2760fcf3ce44SJohn Forte #else
2761fcf3ce44SJohn Forte #define	FCT_VERIFY_RSCN()						\
2762fcf3ce44SJohn Forte do {									\
2763fcf3ce44SJohn Forte 	ct_cmd = fct_create_solct(port, irp->irp_rp, NS_GID_PN,		\
2764fcf3ce44SJohn Forte 	    fct_gid_cb);						\
2765fcf3ce44SJohn Forte 	if (ct_cmd) {							\
2766fcf3ce44SJohn Forte 		uint32_t cnt;						\
27671a5e258fSJosef 'Jeff' Sipek 		cnt = atomic_inc_32_nv(&irp->irp_rscn_counter);	\
2768fcf3ce44SJohn Forte 		CMD_TO_ICMD(ct_cmd)->icmd_cb_private =			\
2769fcf3ce44SJohn Forte 		    INT2PTR(cnt, void *);				\
2770fcf3ce44SJohn Forte 		irp->irp_flags |= IRP_RSCN_QUEUED;			\
2771fcf3ce44SJohn Forte 		fct_post_to_solcmd_queue(port, ct_cmd);			\
2772fcf3ce44SJohn Forte 	}								\
2773fcf3ce44SJohn Forte } while (0)
2774fcf3ce44SJohn Forte #endif
2775fcf3ce44SJohn Forte 
2776fcf3ce44SJohn Forte /* ARGSUSED */
2777fcf3ce44SJohn Forte static void
fct_rscn_verify(fct_i_local_port_t * iport,uint8_t * rscn_req_payload,uint32_t rscn_req_size)2778fcf3ce44SJohn Forte fct_rscn_verify(fct_i_local_port_t *iport, uint8_t *rscn_req_payload,
2779fcf3ce44SJohn Forte     uint32_t rscn_req_size)
2780fcf3ce44SJohn Forte {
2781fcf3ce44SJohn Forte 	int			idx		= 0;
2782fcf3ce44SJohn Forte 	uint8_t			page_format	= 0;
2783fcf3ce44SJohn Forte 	uint32_t		page_portid	= 0;
2784fcf3ce44SJohn Forte 	uint8_t			*page_buf	= NULL;
2785fcf3ce44SJohn Forte 	uint8_t			*last_page_buf	= NULL;
2786fcf3ce44SJohn Forte #ifndef	lint
2787fcf3ce44SJohn Forte 	fct_cmd_t		*ct_cmd		= NULL;
2788fcf3ce44SJohn Forte 	fct_local_port_t	*port		= NULL;
2789fcf3ce44SJohn Forte #endif
2790fcf3ce44SJohn Forte 	fct_i_remote_port_t	*irp		= NULL;
2791fcf3ce44SJohn Forte 
2792fcf3ce44SJohn Forte 	page_buf = rscn_req_payload + 4;
2793fcf3ce44SJohn Forte 	last_page_buf = rscn_req_payload +
2794fcf3ce44SJohn Forte 	    fct_netbuf_to_value(rscn_req_payload + 2, 2) - 4;
2795fcf3ce44SJohn Forte #ifndef	lint
2796fcf3ce44SJohn Forte 	port = iport->iport_port;
2797fcf3ce44SJohn Forte #endif
2798fcf3ce44SJohn Forte 	for (; page_buf <= last_page_buf; page_buf += 4) {
2799fcf3ce44SJohn Forte 		page_format = 0x03 & page_buf[0];
2800fcf3ce44SJohn Forte 		page_portid = fct_netbuf_to_value(page_buf + 1, 3);
2801fcf3ce44SJohn Forte 
2802c946facaSallan 		DTRACE_FC_2(rscn__receive,
2803c946facaSallan 		    fct_i_local_port_t, iport,
2804c946facaSallan 		    int, page_portid);
2805c946facaSallan 
2806fcf3ce44SJohn Forte 		rw_enter(&iport->iport_lock, RW_READER);
2807fcf3ce44SJohn Forte 		if (!page_format) {
2808fcf3ce44SJohn Forte 			irp = fct_portid_to_portptr(iport, page_portid);
2809fcf3ce44SJohn Forte 			if (!(irp && !(irp->irp_flags & IRP_RSCN_QUEUED))) {
2810fcf3ce44SJohn Forte 				rw_exit(&iport->iport_lock);
2811fcf3ce44SJohn Forte 
2812fcf3ce44SJohn Forte 				continue; /* try next page */
2813fcf3ce44SJohn Forte 			}
2814fcf3ce44SJohn Forte 
2815fcf3ce44SJohn Forte 			if (FC_WELL_KNOWN_ADDR(irp->irp_portid) ||
2816fcf3ce44SJohn Forte 			    !(irp->irp_flags & IRP_PLOGI_DONE)) {
2817fcf3ce44SJohn Forte 				rw_exit(&iport->iport_lock);
2818fcf3ce44SJohn Forte 
2819fcf3ce44SJohn Forte 				continue; /* try next page */
2820fcf3ce44SJohn Forte 			}
2821fcf3ce44SJohn Forte 
2822fcf3ce44SJohn Forte 			FCT_VERIFY_RSCN();
2823fcf3ce44SJohn Forte 		} else {
2824fcf3ce44SJohn Forte 			for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) {
2825fcf3ce44SJohn Forte 				for (irp = iport->iport_rp_tb[idx];
2826fcf3ce44SJohn Forte 				    irp; irp = irp->irp_next) {
2827fcf3ce44SJohn Forte 					if (FC_WELL_KNOWN_ADDR(irp->irp_portid))
2828fcf3ce44SJohn Forte 						continue; /* try next irp */
2829fcf3ce44SJohn Forte 
2830fcf3ce44SJohn Forte 					if (!(irp->irp_flags & IRP_PLOGI_DONE))
2831fcf3ce44SJohn Forte 						continue; /* try next irp */
2832fcf3ce44SJohn Forte 
2833fcf3ce44SJohn Forte 					if (irp->irp_flags & IRP_RSCN_QUEUED) {
2834fcf3ce44SJohn Forte 						continue; /* try next irp */
2835fcf3ce44SJohn Forte 					}
2836fcf3ce44SJohn Forte #ifndef	lint
2837fcf3ce44SJohn Forte 					if (!((0xFFFFFF << (page_format * 8)) &
2838fcf3ce44SJohn Forte 					    (page_portid ^ irp->irp_portid))) {
2839fcf3ce44SJohn Forte 						FCT_VERIFY_RSCN();
2840fcf3ce44SJohn Forte 					}
2841fcf3ce44SJohn Forte #endif
2842fcf3ce44SJohn Forte 				}
2843fcf3ce44SJohn Forte 			}
2844fcf3ce44SJohn Forte 		}
2845fcf3ce44SJohn Forte 		rw_exit(&iport->iport_lock);
2846fcf3ce44SJohn Forte 	}
2847fcf3ce44SJohn Forte }
2848