xref: /onnv-gate/usr/src/uts/common/io/comstar/port/fct/discovery.c (revision 12571:05943d9c379f)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
22*12571SViswanathan.Kannappan@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
237836SJohn.Forte@Sun.COM  */
247836SJohn.Forte@Sun.COM 
257836SJohn.Forte@Sun.COM #include <sys/conf.h>
267836SJohn.Forte@Sun.COM #include <sys/file.h>
277836SJohn.Forte@Sun.COM #include <sys/ddi.h>
287836SJohn.Forte@Sun.COM #include <sys/sunddi.h>
297836SJohn.Forte@Sun.COM #include <sys/modctl.h>
307836SJohn.Forte@Sun.COM #include <sys/scsi/scsi.h>
317836SJohn.Forte@Sun.COM #include <sys/scsi/impl/scsi_reset_notify.h>
327836SJohn.Forte@Sun.COM #include <sys/disp.h>
337836SJohn.Forte@Sun.COM #include <sys/byteorder.h>
347836SJohn.Forte@Sun.COM #include <sys/varargs.h>
357836SJohn.Forte@Sun.COM #include <sys/atomic.h>
369578SSam.Cramer@Sun.COM #include <sys/sdt.h>
377836SJohn.Forte@Sun.COM 
38*12571SViswanathan.Kannappan@Sun.COM #include <sys/stmf.h>
39*12571SViswanathan.Kannappan@Sun.COM #include <sys/stmf_ioctl.h>
40*12571SViswanathan.Kannappan@Sun.COM #include <sys/portif.h>
41*12571SViswanathan.Kannappan@Sun.COM #include <sys/fct.h>
42*12571SViswanathan.Kannappan@Sun.COM #include <sys/fctio.h>
43*12571SViswanathan.Kannappan@Sun.COM 
44*12571SViswanathan.Kannappan@Sun.COM #include "fct_impl.h"
45*12571SViswanathan.Kannappan@Sun.COM #include "discovery.h"
467836SJohn.Forte@Sun.COM 
477836SJohn.Forte@Sun.COM disc_action_t fct_handle_local_port_event(fct_i_local_port_t *iport);
487836SJohn.Forte@Sun.COM disc_action_t fct_walk_discovery_queue(fct_i_local_port_t *iport);
497836SJohn.Forte@Sun.COM disc_action_t fct_process_els(fct_i_local_port_t *iport,
507836SJohn.Forte@Sun.COM     fct_i_remote_port_t *irp);
517836SJohn.Forte@Sun.COM fct_status_t fct_send_accrjt(fct_cmd_t *cmd, uint8_t accrjt,
527836SJohn.Forte@Sun.COM     uint8_t reason, uint8_t expl);
537836SJohn.Forte@Sun.COM disc_action_t fct_link_init_complete(fct_i_local_port_t *iport);
547836SJohn.Forte@Sun.COM fct_status_t fct_complete_previous_li_cmd(fct_i_local_port_t *iport);
557836SJohn.Forte@Sun.COM fct_status_t fct_sol_plogi(fct_i_local_port_t *iport, uint32_t id,
567836SJohn.Forte@Sun.COM     fct_cmd_t **ret_ppcmd, int implicit);
577836SJohn.Forte@Sun.COM fct_status_t fct_sol_ct(fct_i_local_port_t *iport, uint32_t id,
587836SJohn.Forte@Sun.COM     fct_cmd_t **ret_ppcmd, uint16_t opcode);
597836SJohn.Forte@Sun.COM fct_status_t fct_ns_scr(fct_i_local_port_t *iport, uint32_t id,
607836SJohn.Forte@Sun.COM     fct_cmd_t **ret_ppcmd);
617836SJohn.Forte@Sun.COM static disc_action_t fct_check_cmdlist(fct_i_local_port_t *iport);
627836SJohn.Forte@Sun.COM static disc_action_t fct_check_solcmd_queue(fct_i_local_port_t *iport);
637836SJohn.Forte@Sun.COM static void fct_rscn_verify(fct_i_local_port_t *iport,
647836SJohn.Forte@Sun.COM     uint8_t *rscn_req_payload, uint32_t rscn_req_size);
657836SJohn.Forte@Sun.COM void fct_gid_cb(fct_i_cmd_t *icmd);
667836SJohn.Forte@Sun.COM 
677836SJohn.Forte@Sun.COM char *fct_els_names[] = { 0, "LS_RJT", "ACC", "PLOGI", "FLOGI", "LOGO",
687836SJohn.Forte@Sun.COM 				"ABTX", "RCS", "RES", "RSS", "RSI", "ESTS",
697836SJohn.Forte@Sun.COM 				"ESTC", "ADVC", "RTV", "RLS",
707836SJohn.Forte@Sun.COM 	/* 0x10 */		"ECHO", "TEST", "RRQ", "REC", "SRR", 0, 0,
717836SJohn.Forte@Sun.COM 				0, 0, 0, 0, 0, 0, 0, 0, 0,
727836SJohn.Forte@Sun.COM 	/* 0x20 */		"PRLI", "PRLO", "SCN", "TPLS",
737836SJohn.Forte@Sun.COM 				"TPRLO", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
747836SJohn.Forte@Sun.COM 	/* 0x30 */		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
757836SJohn.Forte@Sun.COM 	/* 0x40 */		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
767836SJohn.Forte@Sun.COM 	/* 0x50 */		"PDISC", "FDISC", "ADISC", "RNC", "FARP",
777836SJohn.Forte@Sun.COM 				0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
787836SJohn.Forte@Sun.COM 	/* 0x60 */		"FAN", "RSCN", "SCR", 0, 0, 0, 0, 0, 0, 0, 0,
797836SJohn.Forte@Sun.COM 				0, 0, 0, 0, 0,
807836SJohn.Forte@Sun.COM 	/* 0x70 */		"LINIT", "LPC", "LSTS", 0, 0, 0, 0, 0,
817836SJohn.Forte@Sun.COM 				"RNID", "RLIR", "LIRR", 0, 0, 0, 0, 0
827836SJohn.Forte@Sun.COM 		};
837836SJohn.Forte@Sun.COM 
847836SJohn.Forte@Sun.COM extern uint32_t fct_rscn_options;
857836SJohn.Forte@Sun.COM 
867836SJohn.Forte@Sun.COM /*
877836SJohn.Forte@Sun.COM  * NOTE: if anybody drops the iport_worker_lock then they should not return
887836SJohn.Forte@Sun.COM  * DISC_ACTION_NO_WORK. Which also means, dont drop the lock if you have
897836SJohn.Forte@Sun.COM  * nothing to do. Or else return DISC_ACTION_RESCAN or DISC_ACTION_DELAY_RESCAN.
907836SJohn.Forte@Sun.COM  * But you cannot be infinitly returning those so have some logic to
917836SJohn.Forte@Sun.COM  * determine that there is nothing to do without dropping the lock.
927836SJohn.Forte@Sun.COM  */
937836SJohn.Forte@Sun.COM void
fct_port_worker(void * arg)947836SJohn.Forte@Sun.COM fct_port_worker(void *arg)
957836SJohn.Forte@Sun.COM {
967836SJohn.Forte@Sun.COM 	fct_local_port_t	*port = (fct_local_port_t *)arg;
977836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
987836SJohn.Forte@Sun.COM 	    port->port_fct_private;
997836SJohn.Forte@Sun.COM 	disc_action_t		suggested_action;
1007836SJohn.Forte@Sun.COM 	clock_t			dl, short_delay, long_delay;
1017836SJohn.Forte@Sun.COM 	int64_t			tmp_delay;
1027836SJohn.Forte@Sun.COM 
1037836SJohn.Forte@Sun.COM 	iport->iport_cmdcheck_clock = ddi_get_lbolt() +
1047836SJohn.Forte@Sun.COM 	    drv_usectohz(FCT_CMDLIST_CHECK_SECONDS * 1000000);
1057836SJohn.Forte@Sun.COM 	short_delay = drv_usectohz(10000);
1067836SJohn.Forte@Sun.COM 	long_delay = drv_usectohz(1000000);
1077836SJohn.Forte@Sun.COM 
1087836SJohn.Forte@Sun.COM 	stmf_trace(iport->iport_alias, "iport is %p", iport);
1097836SJohn.Forte@Sun.COM 	/* Discovery loop */
1107836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
1117836SJohn.Forte@Sun.COM 	atomic_or_32(&iport->iport_flags, IPORT_WORKER_RUNNING);
1127836SJohn.Forte@Sun.COM 	while ((iport->iport_flags & IPORT_TERMINATE_WORKER) == 0) {
1137836SJohn.Forte@Sun.COM 		suggested_action = DISC_ACTION_NO_WORK;
1147836SJohn.Forte@Sun.COM 		/*
1157836SJohn.Forte@Sun.COM 		 * Local port events are of the highest prioriy
1167836SJohn.Forte@Sun.COM 		 */
1177836SJohn.Forte@Sun.COM 		if (iport->iport_event_head) {
1187836SJohn.Forte@Sun.COM 			suggested_action |= fct_handle_local_port_event(iport);
1197836SJohn.Forte@Sun.COM 		}
1207836SJohn.Forte@Sun.COM 
1217836SJohn.Forte@Sun.COM 		/*
1227836SJohn.Forte@Sun.COM 		 * We could post solicited ELSes to discovery queue.
1237836SJohn.Forte@Sun.COM 		 * solicited CT will be processed inside fct_check_solcmd_queue
1247836SJohn.Forte@Sun.COM 		 */
1257836SJohn.Forte@Sun.COM 		if (iport->iport_solcmd_queue) {
1267836SJohn.Forte@Sun.COM 			suggested_action |= fct_check_solcmd_queue(iport);
1277836SJohn.Forte@Sun.COM 		}
1287836SJohn.Forte@Sun.COM 
1297836SJohn.Forte@Sun.COM 		/*
1307836SJohn.Forte@Sun.COM 		 * All solicited and unsolicited ELS will be handled here
1317836SJohn.Forte@Sun.COM 		 */
1327836SJohn.Forte@Sun.COM 		if (iport->iport_rpwe_head) {
1337836SJohn.Forte@Sun.COM 			suggested_action |= fct_walk_discovery_queue(iport);
1347836SJohn.Forte@Sun.COM 		}
1357836SJohn.Forte@Sun.COM 
1367836SJohn.Forte@Sun.COM 		/*
1377836SJohn.Forte@Sun.COM 		 * We only process it when there's no outstanding link init CMD
1387836SJohn.Forte@Sun.COM 		 */
1397836SJohn.Forte@Sun.COM 		if ((iport->iport_link_state ==	PORT_STATE_LINK_INIT_START) &&
1407836SJohn.Forte@Sun.COM 		    !(iport->iport_li_state & (LI_STATE_FLAG_CMD_WAITING |
1417836SJohn.Forte@Sun.COM 		    LI_STATE_FLAG_NO_LI_YET))) {
1427836SJohn.Forte@Sun.COM 			suggested_action |= fct_process_link_init(iport);
1437836SJohn.Forte@Sun.COM 		}
1447836SJohn.Forte@Sun.COM 
1457836SJohn.Forte@Sun.COM 		/*
1467836SJohn.Forte@Sun.COM 		 * We process cmd aborting in the end
1477836SJohn.Forte@Sun.COM 		 */
1487836SJohn.Forte@Sun.COM 		if (iport->iport_abort_queue) {
1497836SJohn.Forte@Sun.COM 			suggested_action |= fct_cmd_terminator(iport);
1507836SJohn.Forte@Sun.COM 		}
1517836SJohn.Forte@Sun.COM 
1527836SJohn.Forte@Sun.COM 		/*
1537836SJohn.Forte@Sun.COM 		 * Check cmd max/free
1547836SJohn.Forte@Sun.COM 		 */
1557836SJohn.Forte@Sun.COM 		if (iport->iport_cmdcheck_clock <= ddi_get_lbolt()) {
1567836SJohn.Forte@Sun.COM 			suggested_action |= fct_check_cmdlist(iport);
1577836SJohn.Forte@Sun.COM 			iport->iport_cmdcheck_clock = ddi_get_lbolt() +
1587836SJohn.Forte@Sun.COM 			    drv_usectohz(FCT_CMDLIST_CHECK_SECONDS * 1000000);
1597836SJohn.Forte@Sun.COM 			iport->iport_max_active_ncmds = 0;
1607836SJohn.Forte@Sun.COM 		}
1617836SJohn.Forte@Sun.COM 
1627836SJohn.Forte@Sun.COM 		if (iport->iport_offline_prstate != FCT_OPR_DONE) {
1637836SJohn.Forte@Sun.COM 			suggested_action |= fct_handle_port_offline(iport);
1647836SJohn.Forte@Sun.COM 		}
1657836SJohn.Forte@Sun.COM 
1667836SJohn.Forte@Sun.COM 		if (suggested_action & DISC_ACTION_RESCAN) {
1677836SJohn.Forte@Sun.COM 			continue;
1687836SJohn.Forte@Sun.COM 		} else if (suggested_action & DISC_ACTION_DELAY_RESCAN) {
1697836SJohn.Forte@Sun.COM 			/*
1707836SJohn.Forte@Sun.COM 			 * This is not very optimum as whoever returned
1717836SJohn.Forte@Sun.COM 			 * DISC_ACTION_DELAY_RESCAN must have dropped the lock
1727836SJohn.Forte@Sun.COM 			 * and more things might have queued up. But since
1737836SJohn.Forte@Sun.COM 			 * we are only doing small delays, it only delays
1747836SJohn.Forte@Sun.COM 			 * things by a few ms, which is okey.
1757836SJohn.Forte@Sun.COM 			 */
1767836SJohn.Forte@Sun.COM 			if (suggested_action & DISC_ACTION_USE_SHORT_DELAY) {
1777836SJohn.Forte@Sun.COM 				dl = short_delay;
1787836SJohn.Forte@Sun.COM 			} else {
1797836SJohn.Forte@Sun.COM 				dl = long_delay;
1807836SJohn.Forte@Sun.COM 			}
1817836SJohn.Forte@Sun.COM 			atomic_or_32(&iport->iport_flags,
1827836SJohn.Forte@Sun.COM 			    IPORT_WORKER_DOING_TIMEDWAIT);
18311066Srafael.vanoni@sun.com 			(void) cv_reltimedwait(&iport->iport_worker_cv,
18411066Srafael.vanoni@sun.com 			    &iport->iport_worker_lock, dl, TR_CLOCK_TICK);
1857836SJohn.Forte@Sun.COM 			atomic_and_32(&iport->iport_flags,
1867836SJohn.Forte@Sun.COM 			    ~IPORT_WORKER_DOING_TIMEDWAIT);
1877836SJohn.Forte@Sun.COM 		} else {
1887836SJohn.Forte@Sun.COM 			atomic_or_32(&iport->iport_flags,
1897836SJohn.Forte@Sun.COM 			    IPORT_WORKER_DOING_WAIT);
1907836SJohn.Forte@Sun.COM 			tmp_delay = (int64_t)(iport->iport_cmdcheck_clock -
1917836SJohn.Forte@Sun.COM 			    ddi_get_lbolt());
1927836SJohn.Forte@Sun.COM 			if (tmp_delay < 0) {
1937836SJohn.Forte@Sun.COM 				tmp_delay = (int64_t)short_delay;
1947836SJohn.Forte@Sun.COM 			}
19511066Srafael.vanoni@sun.com 			(void) cv_reltimedwait(&iport->iport_worker_cv,
19611066Srafael.vanoni@sun.com 			    &iport->iport_worker_lock, (clock_t)tmp_delay,
19711066Srafael.vanoni@sun.com 			    TR_CLOCK_TICK);
1987836SJohn.Forte@Sun.COM 			atomic_and_32(&iport->iport_flags,
1997836SJohn.Forte@Sun.COM 			    ~IPORT_WORKER_DOING_WAIT);
2007836SJohn.Forte@Sun.COM 		}
2017836SJohn.Forte@Sun.COM 	}
2027836SJohn.Forte@Sun.COM 
2037836SJohn.Forte@Sun.COM 	atomic_and_32(&iport->iport_flags, ~IPORT_WORKER_RUNNING);
2047836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
2057836SJohn.Forte@Sun.COM }
2067836SJohn.Forte@Sun.COM 
2077836SJohn.Forte@Sun.COM static char *topologies[] = { "Unknown", "Direct Pt-to-Pt", "Private Loop",
2087836SJohn.Forte@Sun.COM 				"Unknown", "Unknown", "Fabric Pt-to-Pt",
2097836SJohn.Forte@Sun.COM 				"Public Loop" };
2107836SJohn.Forte@Sun.COM 
2117836SJohn.Forte@Sun.COM void
fct_li_to_txt(fct_link_info_t * li,char * topology,char * speed)2127836SJohn.Forte@Sun.COM fct_li_to_txt(fct_link_info_t *li, char *topology, char *speed)
2137836SJohn.Forte@Sun.COM {
2147836SJohn.Forte@Sun.COM 	uint8_t s = li->port_speed;
2157836SJohn.Forte@Sun.COM 
2167836SJohn.Forte@Sun.COM 	if (li->port_topology > PORT_TOPOLOGY_PUBLIC_LOOP) {
2177836SJohn.Forte@Sun.COM 		(void) sprintf(topology, "Invalid %02x", li->port_topology);
2187836SJohn.Forte@Sun.COM 	} else {
2197836SJohn.Forte@Sun.COM 		(void) strcpy(topology, topologies[li->port_topology]);
2207836SJohn.Forte@Sun.COM 	}
2217836SJohn.Forte@Sun.COM 
2229087SZhong.Wang@Sun.COM 	if ((s == 0) || ((s & 0xf00) != 0) || ((s & (s - 1)) != 0)) {
2237836SJohn.Forte@Sun.COM 		speed[0] = '?';
2249087SZhong.Wang@Sun.COM 	} else if (s == PORT_SPEED_10G) {
2259087SZhong.Wang@Sun.COM 		speed[0] = '1';
2269087SZhong.Wang@Sun.COM 		speed[1] = '0';
2279087SZhong.Wang@Sun.COM 		speed[2] = 'G';
2289087SZhong.Wang@Sun.COM 		speed[3] = 0;
2297836SJohn.Forte@Sun.COM 	} else {
2307836SJohn.Forte@Sun.COM 		speed[0] = '0' + li->port_speed;
2319087SZhong.Wang@Sun.COM 		speed[1] = 'G';
2329087SZhong.Wang@Sun.COM 		speed[2] = 0;
2337836SJohn.Forte@Sun.COM 	}
2347836SJohn.Forte@Sun.COM }
2357836SJohn.Forte@Sun.COM 
2367836SJohn.Forte@Sun.COM /*
2377836SJohn.Forte@Sun.COM  * discovery lock held.
2387836SJohn.Forte@Sun.COM  * XXX: Implement command cleanup upon Link down.
2397836SJohn.Forte@Sun.COM  * XXX: Implement a clean start and FC-GS registrations upon Link up.
2407836SJohn.Forte@Sun.COM  *
2417836SJohn.Forte@Sun.COM  * ================ Local Port State Machine ============
2427836SJohn.Forte@Sun.COM  * <hba fatal>		 <Link up>---|
2437836SJohn.Forte@Sun.COM  *   |				     v
2447836SJohn.Forte@Sun.COM  *   |	      <Start>--->[LINK_DOWN]--->[LINK_INIT_START]--->[LINK_INIT_DONE]
2457836SJohn.Forte@Sun.COM  *   |			  ^    ^		  ^    |		   |
2467836SJohn.Forte@Sun.COM  *   |		      |---|    |  |--<Link down>  |-|  |---><Link Reset><--|
2477836SJohn.Forte@Sun.COM  *   |		      |	       |  v		    |	       v
2487836SJohn.Forte@Sun.COM  *   |->[FATAL_CLEANING]  [LINK_DOWN_CLEANING]--->[LINK_UP_CLEANING]
2497836SJohn.Forte@Sun.COM  *					       ^
2507836SJohn.Forte@Sun.COM  *					       |--<Link up>
2517836SJohn.Forte@Sun.COM  * =======================================================
2527836SJohn.Forte@Sun.COM  * An explicit port_online() is only allowed in LINK_DOWN state.
2537836SJohn.Forte@Sun.COM  * An explicit port_offline() is only allowed in LINKDOWN and
2547836SJohn.Forte@Sun.COM  * LINK_INIT_DONE state.
2557836SJohn.Forte@Sun.COM  */
2567836SJohn.Forte@Sun.COM disc_action_t
fct_handle_local_port_event(fct_i_local_port_t * iport)2577836SJohn.Forte@Sun.COM fct_handle_local_port_event(fct_i_local_port_t *iport)
2587836SJohn.Forte@Sun.COM {
2597836SJohn.Forte@Sun.COM 	disc_action_t	ret = DISC_ACTION_RESCAN;
2607836SJohn.Forte@Sun.COM 	fct_i_event_t	*in;
2617836SJohn.Forte@Sun.COM 	uint16_t	old_state, new_state, new_bits;
2627836SJohn.Forte@Sun.COM 	int		dqueue_and_free = 1;
2637836SJohn.Forte@Sun.COM 	int		retry_implicit_logo = 0;
2647836SJohn.Forte@Sun.COM 
2657836SJohn.Forte@Sun.COM 	if (iport->iport_event_head == NULL)
2667836SJohn.Forte@Sun.COM 		return (DISC_ACTION_NO_WORK);
2677836SJohn.Forte@Sun.COM 	in = iport->iport_event_head;
2687836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
2697836SJohn.Forte@Sun.COM 
2707836SJohn.Forte@Sun.COM 	rw_enter(&iport->iport_lock, RW_WRITER);
2719578SSam.Cramer@Sun.COM 
2729578SSam.Cramer@Sun.COM 	if (in->event_type == FCT_EVENT_LINK_UP) {
2739578SSam.Cramer@Sun.COM 		DTRACE_FC_1(link__up, fct_i_local_port_t, iport);
2749578SSam.Cramer@Sun.COM 	} else if (in->event_type == FCT_EVENT_LINK_DOWN) {
2759578SSam.Cramer@Sun.COM 		DTRACE_FC_1(link__down, fct_i_local_port_t, iport);
2769578SSam.Cramer@Sun.COM 	}
2779578SSam.Cramer@Sun.COM 
2787836SJohn.Forte@Sun.COM 	/* Calculate new state */
2797836SJohn.Forte@Sun.COM 	new_state = iport->iport_link_state;
2809578SSam.Cramer@Sun.COM 
2817836SJohn.Forte@Sun.COM 	if (in->event_type == FCT_EVENT_LINK_DOWN) {
2827836SJohn.Forte@Sun.COM 		new_state = PORT_STATE_LINK_DOWN_CLEANING;
2837836SJohn.Forte@Sun.COM 	} else if (in->event_type == FCT_EVENT_LINK_UP) {
2847836SJohn.Forte@Sun.COM 		if (iport->iport_link_state == PORT_STATE_LINK_DOWN_CLEANING)
2857836SJohn.Forte@Sun.COM 			new_state = PORT_STATE_LINK_UP_CLEANING;
2867836SJohn.Forte@Sun.COM 		else if (iport->iport_link_state == PORT_STATE_LINK_DOWN)
2877836SJohn.Forte@Sun.COM 			new_state = PORT_STATE_LINK_INIT_START;
2887836SJohn.Forte@Sun.COM 		else { /* This should not happen */
2897836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias,
2907836SJohn.Forte@Sun.COM 			    "Link up received when link state was"
2917836SJohn.Forte@Sun.COM 			    "%x, Ignoring...", iport->iport_link_state);
2927836SJohn.Forte@Sun.COM 		}
2937836SJohn.Forte@Sun.COM 	} else if (in->event_type == FCT_I_EVENT_CLEANUP_POLL) {
2947836SJohn.Forte@Sun.COM 		if (!fct_local_port_cleanup_done(iport)) {
2957836SJohn.Forte@Sun.COM 			if (iport->iport_link_cleanup_retry >= 3) {
2967836SJohn.Forte@Sun.COM 				iport->iport_link_cleanup_retry = 0;
2977836SJohn.Forte@Sun.COM 				retry_implicit_logo = 1;
2987836SJohn.Forte@Sun.COM 			} else {
2997836SJohn.Forte@Sun.COM 				iport->iport_link_cleanup_retry++;
3007836SJohn.Forte@Sun.COM 			}
3017836SJohn.Forte@Sun.COM 			dqueue_and_free = 0;
3027836SJohn.Forte@Sun.COM 			ret = DISC_ACTION_DELAY_RESCAN;
3037836SJohn.Forte@Sun.COM 		} else {
3047836SJohn.Forte@Sun.COM 			if (iport->iport_link_state ==
3057836SJohn.Forte@Sun.COM 			    PORT_STATE_LINK_DOWN_CLEANING) {
3067836SJohn.Forte@Sun.COM 				new_state = PORT_STATE_LINK_DOWN;
3077836SJohn.Forte@Sun.COM 			} else if (iport->iport_link_state ==
3087836SJohn.Forte@Sun.COM 			    PORT_STATE_LINK_UP_CLEANING) {
3097836SJohn.Forte@Sun.COM 				new_state = PORT_STATE_LINK_INIT_START;
3107836SJohn.Forte@Sun.COM 			} else { /* This should not have happened */
3117836SJohn.Forte@Sun.COM 				cmn_err(CE_WARN, "port state changed to %x "
3127836SJohn.Forte@Sun.COM 				    "during cleanup", iport->iport_link_state);
3137836SJohn.Forte@Sun.COM 				new_state = PORT_STATE_LINK_DOWN;
3147836SJohn.Forte@Sun.COM 			}
3157836SJohn.Forte@Sun.COM 		}
3167836SJohn.Forte@Sun.COM 	} else if (in->event_type == FCT_EVENT_LINK_RESET) {
3177836SJohn.Forte@Sun.COM 		/* Link reset is only allowed when we are Online */
3187836SJohn.Forte@Sun.COM 		if (iport->iport_link_state & S_LINK_ONLINE) {
3197836SJohn.Forte@Sun.COM 			new_state = PORT_STATE_LINK_UP_CLEANING;
3207836SJohn.Forte@Sun.COM 		}
3217836SJohn.Forte@Sun.COM 	} else if (in->event_type == FCT_I_EVENT_LINK_INIT_DONE) {
3227836SJohn.Forte@Sun.COM 		if (iport->iport_link_state == PORT_STATE_LINK_INIT_START) {
3237836SJohn.Forte@Sun.COM 			new_state = PORT_STATE_LINK_INIT_DONE;
3247836SJohn.Forte@Sun.COM 			iport->iport_li_state = LI_STATE_START;
3257836SJohn.Forte@Sun.COM 		}
3267836SJohn.Forte@Sun.COM 	} else {
3277836SJohn.Forte@Sun.COM 		ASSERT(0);
3287836SJohn.Forte@Sun.COM 	}
3297836SJohn.Forte@Sun.COM 	new_bits = iport->iport_link_state ^
3308585SAllan.Ou@Sun.COM 	    (iport->iport_link_state | new_state);
3317836SJohn.Forte@Sun.COM 	old_state = iport->iport_link_state;
3327836SJohn.Forte@Sun.COM 	iport->iport_link_state = new_state;
3337836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
3347836SJohn.Forte@Sun.COM 
3357836SJohn.Forte@Sun.COM 	stmf_trace(iport->iport_alias, "port state change from %x to %x",
3368585SAllan.Ou@Sun.COM 	    old_state, new_state);
3377836SJohn.Forte@Sun.COM 
3387836SJohn.Forte@Sun.COM 	if (new_bits & S_PORT_CLEANUP) {
3397836SJohn.Forte@Sun.COM 		(void) fct_implicitly_logo_all(iport, 0);
3407836SJohn.Forte@Sun.COM 		fct_handle_event(iport->iport_port,
3418585SAllan.Ou@Sun.COM 		    FCT_I_EVENT_CLEANUP_POLL, 0, 0);
3427836SJohn.Forte@Sun.COM 	}
3437836SJohn.Forte@Sun.COM 	if (retry_implicit_logo) {
3447836SJohn.Forte@Sun.COM 		(void) fct_implicitly_logo_all(iport, 1);
3457836SJohn.Forte@Sun.COM 	}
3467836SJohn.Forte@Sun.COM 	if (new_bits & S_INIT_LINK) {
3477836SJohn.Forte@Sun.COM 		fct_link_info_t *li = &iport->iport_link_info;
3487836SJohn.Forte@Sun.COM 		fct_status_t li_ret;
3497836SJohn.Forte@Sun.COM 		iport->iport_li_state |= LI_STATE_FLAG_NO_LI_YET;
3507836SJohn.Forte@Sun.COM 		bzero(li, sizeof (*li));
3517836SJohn.Forte@Sun.COM 		if ((li_ret = iport->iport_port->port_get_link_info(
3527836SJohn.Forte@Sun.COM 		    iport->iport_port, li)) != FCT_SUCCESS) {
3537836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "iport-%p: "
3547836SJohn.Forte@Sun.COM 			    "port_get_link_info failed, ret %llx, forcing "
3557836SJohn.Forte@Sun.COM 			    "link down.", iport, li_ret);
3567836SJohn.Forte@Sun.COM 			fct_handle_event(iport->iport_port,
3578585SAllan.Ou@Sun.COM 			    FCT_EVENT_LINK_DOWN, 0, 0);
3587836SJohn.Forte@Sun.COM 		} else {
3597836SJohn.Forte@Sun.COM 			iport->iport_login_retry = 0;
3607836SJohn.Forte@Sun.COM 			/* This will reset LI_STATE_FLAG_NO_LI_YET */
3617836SJohn.Forte@Sun.COM 			iport->iport_li_state = LI_STATE_START;
3627836SJohn.Forte@Sun.COM 			atomic_or_32(&iport->iport_flags,
3638585SAllan.Ou@Sun.COM 			    IPORT_ALLOW_UNSOL_FLOGI);
3647836SJohn.Forte@Sun.COM 		}
3657836SJohn.Forte@Sun.COM 		fct_log_local_port_event(iport->iport_port,
3667836SJohn.Forte@Sun.COM 		    ESC_SUNFC_PORT_ONLINE);
3677836SJohn.Forte@Sun.COM 	} else if (new_bits & S_RCVD_LINK_DOWN) {
3687836SJohn.Forte@Sun.COM 		fct_log_local_port_event(iport->iport_port,
3697836SJohn.Forte@Sun.COM 		    ESC_SUNFC_PORT_OFFLINE);
3707836SJohn.Forte@Sun.COM 	}
3717836SJohn.Forte@Sun.COM 
3727836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
3737836SJohn.Forte@Sun.COM 	if (in && dqueue_and_free) {
3747836SJohn.Forte@Sun.COM 		iport->iport_event_head = in->event_next;
3757836SJohn.Forte@Sun.COM 		if (iport->iport_event_head == NULL)
3767836SJohn.Forte@Sun.COM 			iport->iport_event_tail = NULL;
3777836SJohn.Forte@Sun.COM 		kmem_free(in, sizeof (*in));
3787836SJohn.Forte@Sun.COM 	}
3797836SJohn.Forte@Sun.COM 	return (ret);
3807836SJohn.Forte@Sun.COM }
3817836SJohn.Forte@Sun.COM 
3827836SJohn.Forte@Sun.COM int
fct_lport_has_bigger_wwn(fct_i_local_port_t * iport)3837836SJohn.Forte@Sun.COM fct_lport_has_bigger_wwn(fct_i_local_port_t *iport)
3847836SJohn.Forte@Sun.COM {
3857836SJohn.Forte@Sun.COM 	uint8_t *l, *r;
3867836SJohn.Forte@Sun.COM 	int i;
3877836SJohn.Forte@Sun.COM 	uint64_t wl, wr;
3887836SJohn.Forte@Sun.COM 
3897836SJohn.Forte@Sun.COM 	l = iport->iport_port->port_pwwn;
3907836SJohn.Forte@Sun.COM 	r = iport->iport_link_info.port_rpwwn;
3917836SJohn.Forte@Sun.COM 
3927836SJohn.Forte@Sun.COM 	for (i = 0, wl = 0; i < 8; i++) {
3937836SJohn.Forte@Sun.COM 		wl <<= 8;
3947836SJohn.Forte@Sun.COM 		wl |= l[i];
3957836SJohn.Forte@Sun.COM 	}
3967836SJohn.Forte@Sun.COM 	for (i = 0, wr = 0; i < 8; i++) {
3977836SJohn.Forte@Sun.COM 		wr <<= 8;
3987836SJohn.Forte@Sun.COM 		wr |= r[i];
3997836SJohn.Forte@Sun.COM 	}
4007836SJohn.Forte@Sun.COM 
4017836SJohn.Forte@Sun.COM 	if (wl > wr) {
4027836SJohn.Forte@Sun.COM 		return (1);
4037836SJohn.Forte@Sun.COM 	}
4047836SJohn.Forte@Sun.COM 
4057836SJohn.Forte@Sun.COM 	return (0);
4067836SJohn.Forte@Sun.COM }
4077836SJohn.Forte@Sun.COM 
4087836SJohn.Forte@Sun.COM void
fct_do_flogi(fct_i_local_port_t * iport)4097836SJohn.Forte@Sun.COM fct_do_flogi(fct_i_local_port_t *iport)
4107836SJohn.Forte@Sun.COM {
4117836SJohn.Forte@Sun.COM 	fct_flogi_xchg_t fx;
4127836SJohn.Forte@Sun.COM 	fct_status_t ret;
4137836SJohn.Forte@Sun.COM 	int force_link_down = 0;
4147836SJohn.Forte@Sun.COM 	int do_retry = 0;
4157836SJohn.Forte@Sun.COM 
4169578SSam.Cramer@Sun.COM 	DTRACE_FC_1(fabric__login__start, fct_i_local_port_t, iport);
4179578SSam.Cramer@Sun.COM 
4187836SJohn.Forte@Sun.COM 	bzero(&fx, sizeof (fx));
4197836SJohn.Forte@Sun.COM 	fx.fx_op = ELS_OP_FLOGI;
4207836SJohn.Forte@Sun.COM 	if (iport->iport_login_retry == 0) {
4217836SJohn.Forte@Sun.COM 		fx.fx_sec_timeout = 2;
4227836SJohn.Forte@Sun.COM 	} else {
4237836SJohn.Forte@Sun.COM 		fx.fx_sec_timeout = 5;
4247836SJohn.Forte@Sun.COM 	}
4257836SJohn.Forte@Sun.COM 	if (iport->iport_link_info.port_topology & PORT_TOPOLOGY_PRIVATE_LOOP) {
4267836SJohn.Forte@Sun.COM 		fx.fx_sid = iport->iport_link_info.portid & 0xFF;
4277836SJohn.Forte@Sun.COM 	}
4287836SJohn.Forte@Sun.COM 	fx.fx_did = 0xFFFFFE;
4297836SJohn.Forte@Sun.COM 	bcopy(iport->iport_port->port_nwwn, fx.fx_nwwn, 8);
4307836SJohn.Forte@Sun.COM 	bcopy(iport->iport_port->port_pwwn, fx.fx_pwwn, 8);
4317836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
4327836SJohn.Forte@Sun.COM 	ret = iport->iport_port->port_flogi_xchg(iport->iport_port, &fx);
4337836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
4347836SJohn.Forte@Sun.COM 	if (IPORT_FLOGI_DONE(iport)) {
4357836SJohn.Forte@Sun.COM 		/* The unsolicited path finished it. */
4369578SSam.Cramer@Sun.COM 		goto done;
4377836SJohn.Forte@Sun.COM 	}
4387836SJohn.Forte@Sun.COM 	if (ret == FCT_NOT_FOUND) {
4397836SJohn.Forte@Sun.COM 		if (iport->iport_link_info.port_topology &
4408585SAllan.Ou@Sun.COM 		    PORT_TOPOLOGY_PRIVATE_LOOP) {
4417836SJohn.Forte@Sun.COM 			/* This is a private loop. There is no switch. */
4427836SJohn.Forte@Sun.COM 			iport->iport_link_info.port_no_fct_flogi = 1;
4439578SSam.Cramer@Sun.COM 			goto done;
4447836SJohn.Forte@Sun.COM 		}
4457836SJohn.Forte@Sun.COM 		/*
4467836SJohn.Forte@Sun.COM 		 * This is really an error. This means we cannot init the
4477836SJohn.Forte@Sun.COM 		 * link. Lets force the link to go down.
4487836SJohn.Forte@Sun.COM 		 */
4497836SJohn.Forte@Sun.COM 		force_link_down = 1;
4507836SJohn.Forte@Sun.COM 	} else if ((ret == FCT_SUCCESS) && (fx.fx_op == ELS_OP_LSRJT)) {
4517836SJohn.Forte@Sun.COM 		if ((fx.fx_rjt_reason == 5) || (fx.fx_rjt_reason == 0xe) ||
4527836SJohn.Forte@Sun.COM 		    ((fx.fx_rjt_reason == 9) && (fx.fx_rjt_expl == 0x29))) {
4537836SJohn.Forte@Sun.COM 			do_retry = 1;
4547836SJohn.Forte@Sun.COM 		} else {
4557836SJohn.Forte@Sun.COM 			force_link_down = 1;
4567836SJohn.Forte@Sun.COM 		}
4577836SJohn.Forte@Sun.COM 	} else if (ret == STMF_TIMEOUT) {
4587836SJohn.Forte@Sun.COM 		do_retry = 1;
4597836SJohn.Forte@Sun.COM 	} else if (ret != FCT_SUCCESS) {
4607836SJohn.Forte@Sun.COM 		force_link_down = 1;
4617836SJohn.Forte@Sun.COM 	}
4627836SJohn.Forte@Sun.COM 
4637836SJohn.Forte@Sun.COM 	if (do_retry) {
4647836SJohn.Forte@Sun.COM 		iport->iport_login_retry++;
4657836SJohn.Forte@Sun.COM 		if (iport->iport_login_retry >= 5)
4667836SJohn.Forte@Sun.COM 			force_link_down = 1;
4679578SSam.Cramer@Sun.COM 		goto done;
4687836SJohn.Forte@Sun.COM 	}
4697836SJohn.Forte@Sun.COM 
4707836SJohn.Forte@Sun.COM 	if (force_link_down) {
4717836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias, "iport-%p: flogi xchg failed. "
4727836SJohn.Forte@Sun.COM 		    "Forcing link down, ret=%llx login_retry=%d ret_op=%d "
4737836SJohn.Forte@Sun.COM 		    "reason=%d expl=%d", iport, ret, iport->iport_login_retry,
4747836SJohn.Forte@Sun.COM 		    fx.fx_op, fx.fx_rjt_reason, fx.fx_rjt_expl);
4757836SJohn.Forte@Sun.COM 		mutex_exit(&iport->iport_worker_lock);
4767836SJohn.Forte@Sun.COM 		fct_handle_event(iport->iport_port, FCT_EVENT_LINK_DOWN, 0, 0);
4777836SJohn.Forte@Sun.COM 		mutex_enter(&iport->iport_worker_lock);
4789578SSam.Cramer@Sun.COM 		goto done;
4797836SJohn.Forte@Sun.COM 	}
4807836SJohn.Forte@Sun.COM 
4817836SJohn.Forte@Sun.COM 	/* FLOGI succeeded. Update local port state */
4827836SJohn.Forte@Sun.COM 	ASSERT(fx.fx_op == ELS_OP_ACC);
4837836SJohn.Forte@Sun.COM 	bcopy(fx.fx_nwwn, iport->iport_link_info.port_rnwwn, 8);
4847836SJohn.Forte@Sun.COM 	bcopy(fx.fx_pwwn, iport->iport_link_info.port_rpwwn, 8);
4857836SJohn.Forte@Sun.COM 	if (fx.fx_fport) {
4867836SJohn.Forte@Sun.COM 		iport->iport_link_info.port_topology |=
4878585SAllan.Ou@Sun.COM 		    PORT_TOPOLOGY_FABRIC_BIT;
4887836SJohn.Forte@Sun.COM 		iport->iport_link_info.portid = fx.fx_did;
4897836SJohn.Forte@Sun.COM 	}
4907836SJohn.Forte@Sun.COM 	iport->iport_link_info.port_fct_flogi_done = 1;
4919578SSam.Cramer@Sun.COM 
4929578SSam.Cramer@Sun.COM done:
4939578SSam.Cramer@Sun.COM 	DTRACE_FC_1(fabric__login__end,
4949578SSam.Cramer@Sun.COM 	    fct_i_local_port_t, iport);
4957836SJohn.Forte@Sun.COM }
4967836SJohn.Forte@Sun.COM 
4977836SJohn.Forte@Sun.COM /*
4987836SJohn.Forte@Sun.COM  * Called by FCAs to handle unsolicited FLOGIs.
4997836SJohn.Forte@Sun.COM  */
5007836SJohn.Forte@Sun.COM fct_status_t
fct_handle_rcvd_flogi(fct_local_port_t * port,fct_flogi_xchg_t * fx)5017836SJohn.Forte@Sun.COM fct_handle_rcvd_flogi(fct_local_port_t *port, fct_flogi_xchg_t *fx)
5027836SJohn.Forte@Sun.COM {
5037836SJohn.Forte@Sun.COM 	fct_i_local_port_t *iport;
5047836SJohn.Forte@Sun.COM 	uint32_t t;
5057836SJohn.Forte@Sun.COM 
5067836SJohn.Forte@Sun.COM 	iport = (fct_i_local_port_t *)port->port_fct_private;
5077836SJohn.Forte@Sun.COM 	if ((iport->iport_flags & IPORT_ALLOW_UNSOL_FLOGI) == 0) {
5087836SJohn.Forte@Sun.COM 		return (FCT_FAILURE);
5097836SJohn.Forte@Sun.COM 	}
5107836SJohn.Forte@Sun.COM 
5117836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
5127836SJohn.Forte@Sun.COM 	if (((iport->iport_flags & IPORT_ALLOW_UNSOL_FLOGI) == 0) ||
5137836SJohn.Forte@Sun.COM 	    (iport->iport_link_state !=	PORT_STATE_LINK_INIT_START) ||
5147836SJohn.Forte@Sun.COM 	    ((iport->iport_li_state & LI_STATE_MASK) > LI_STATE_N2N_PLOGI)) {
5157836SJohn.Forte@Sun.COM 		mutex_exit(&iport->iport_worker_lock);
5167836SJohn.Forte@Sun.COM 		return (FCT_FAILURE);
5177836SJohn.Forte@Sun.COM 	}
5187836SJohn.Forte@Sun.COM 
5197836SJohn.Forte@Sun.COM 	if (iport->iport_link_info.port_fct_flogi_done == 0) {
5207836SJohn.Forte@Sun.COM 		iport->iport_link_info.port_fct_flogi_done = 1;
5217836SJohn.Forte@Sun.COM 		bcopy(fx->fx_pwwn, iport->iport_link_info.port_rpwwn, 8);
5227836SJohn.Forte@Sun.COM 		bcopy(fx->fx_nwwn, iport->iport_link_info.port_rnwwn, 8);
5237836SJohn.Forte@Sun.COM 	}
5247836SJohn.Forte@Sun.COM 
5257836SJohn.Forte@Sun.COM 	fx->fx_op = ELS_OP_ACC;
5267836SJohn.Forte@Sun.COM 	t = fx->fx_sid;
5277836SJohn.Forte@Sun.COM 	fx->fx_sid = fx->fx_did;
5287836SJohn.Forte@Sun.COM 	fx->fx_did = t;
5297836SJohn.Forte@Sun.COM 	bcopy(iport->iport_port->port_pwwn, fx->fx_pwwn, 8);
5307836SJohn.Forte@Sun.COM 	bcopy(iport->iport_port->port_nwwn, fx->fx_nwwn, 8);
5317836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
5327836SJohn.Forte@Sun.COM 
5337836SJohn.Forte@Sun.COM 	return (FCT_SUCCESS);
5347836SJohn.Forte@Sun.COM }
5357836SJohn.Forte@Sun.COM 
5367836SJohn.Forte@Sun.COM /*
5377836SJohn.Forte@Sun.COM  * iport_li_state can only be changed here and local_event
5387836SJohn.Forte@Sun.COM  */
5397836SJohn.Forte@Sun.COM disc_action_t
fct_process_link_init(fct_i_local_port_t * iport)5407836SJohn.Forte@Sun.COM fct_process_link_init(fct_i_local_port_t *iport)
5417836SJohn.Forte@Sun.COM {
5427836SJohn.Forte@Sun.COM 	fct_cmd_t	*cmd	  = NULL;
5437836SJohn.Forte@Sun.COM 	char		*pname	  = NULL;
5447836SJohn.Forte@Sun.COM 	uint8_t		 elsop	  = 0;
5457836SJohn.Forte@Sun.COM 	uint16_t	 ctop	  = 0;
5467836SJohn.Forte@Sun.COM 	uint32_t	 wkdid	  = 0;
5477836SJohn.Forte@Sun.COM 	int		 implicit = 0;
5487836SJohn.Forte@Sun.COM 	int		force_login = 0;
5497836SJohn.Forte@Sun.COM 	disc_action_t	 ret	  = DISC_ACTION_RESCAN;
5507836SJohn.Forte@Sun.COM 	fct_link_info_t *li = &iport->iport_link_info;
5517836SJohn.Forte@Sun.COM 	char		topo[24], speed[4];
5527836SJohn.Forte@Sun.COM 
5537836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&iport->iport_worker_lock));
5547836SJohn.Forte@Sun.COM 
5557836SJohn.Forte@Sun.COM check_state_again:
5567836SJohn.Forte@Sun.COM 	switch (iport->iport_li_state & LI_STATE_MASK) {
5577836SJohn.Forte@Sun.COM 	case LI_STATE_DO_FLOGI:
5587836SJohn.Forte@Sun.COM 		/* Is FLOGI even needed or already done ? */
5597836SJohn.Forte@Sun.COM 		if ((iport->iport_link_info.port_no_fct_flogi) ||
5607836SJohn.Forte@Sun.COM 		    (IPORT_FLOGI_DONE(iport))) {
5617836SJohn.Forte@Sun.COM 			iport->iport_li_state++;
5627836SJohn.Forte@Sun.COM 			goto check_state_again;
5637836SJohn.Forte@Sun.COM 		}
5647836SJohn.Forte@Sun.COM 		fct_do_flogi(iport);
5657836SJohn.Forte@Sun.COM 		break;
5667836SJohn.Forte@Sun.COM 
5677836SJohn.Forte@Sun.COM 	case LI_STATE_FINI_TOPOLOGY:
5687836SJohn.Forte@Sun.COM 		fct_li_to_txt(li, topo, speed);
5697836SJohn.Forte@Sun.COM 		cmn_err(CE_NOTE, "%s LINK UP, portid %x, topology %s,"
5707836SJohn.Forte@Sun.COM 		    "speed %s", iport->iport_alias, li->portid,
5717836SJohn.Forte@Sun.COM 		    topo, speed);
5727836SJohn.Forte@Sun.COM 		if (li->port_topology !=
5737836SJohn.Forte@Sun.COM 		    iport->iport_link_old_topology) {
5747836SJohn.Forte@Sun.COM 			if (iport->iport_nrps) {
5757836SJohn.Forte@Sun.COM 				/*
5767836SJohn.Forte@Sun.COM 				 * rehash it if change from fabric to
5777836SJohn.Forte@Sun.COM 				 * none fabric, vice versa
5787836SJohn.Forte@Sun.COM 				 */
5797836SJohn.Forte@Sun.COM 				if ((li->port_topology ^
5807836SJohn.Forte@Sun.COM 				    iport->iport_link_old_topology) &
5817836SJohn.Forte@Sun.COM 				    PORT_TOPOLOGY_FABRIC_BIT) {
5827836SJohn.Forte@Sun.COM 					mutex_exit(&iport->iport_worker_lock);
5837836SJohn.Forte@Sun.COM 					fct_rehash(iport);
5847836SJohn.Forte@Sun.COM 					mutex_enter(&iport->iport_worker_lock);
5857836SJohn.Forte@Sun.COM 				}
5867836SJohn.Forte@Sun.COM 			}
5877836SJohn.Forte@Sun.COM 			iport->iport_link_old_topology = li->port_topology;
5887836SJohn.Forte@Sun.COM 		}
5897836SJohn.Forte@Sun.COM 		/* Skip next level if topo is not N2N */
5907836SJohn.Forte@Sun.COM 		if (li->port_topology != PORT_TOPOLOGY_PT_TO_PT) {
5917836SJohn.Forte@Sun.COM 			iport->iport_li_state += 2;
5927836SJohn.Forte@Sun.COM 			atomic_and_32(&iport->iport_flags,
5937836SJohn.Forte@Sun.COM 			    ~IPORT_ALLOW_UNSOL_FLOGI);
5947836SJohn.Forte@Sun.COM 		} else {
5957836SJohn.Forte@Sun.COM 			iport->iport_li_state++;
5967836SJohn.Forte@Sun.COM 			iport->iport_login_retry = 0;
5977836SJohn.Forte@Sun.COM 			iport->iport_li_cmd_timeout = ddi_get_lbolt() +
5988585SAllan.Ou@Sun.COM 			    drv_usectohz(25 * 1000000);
5997836SJohn.Forte@Sun.COM 		}
6007836SJohn.Forte@Sun.COM 		goto check_state_again;
6017836SJohn.Forte@Sun.COM 
6027836SJohn.Forte@Sun.COM 	case LI_STATE_N2N_PLOGI:
6037836SJohn.Forte@Sun.COM 		ASSERT(IPORT_FLOGI_DONE(iport));
6047836SJohn.Forte@Sun.COM 		ASSERT(iport->iport_link_info.port_topology ==
6058585SAllan.Ou@Sun.COM 		    PORT_TOPOLOGY_PT_TO_PT);
6067836SJohn.Forte@Sun.COM 		if (iport->iport_li_state & LI_STATE_FLAG_CMD_RETCHECK) {
6077836SJohn.Forte@Sun.COM 			iport->iport_li_state &= ~LI_STATE_FLAG_CMD_RETCHECK;
6087836SJohn.Forte@Sun.COM 			if (iport->iport_li_comp_status != FCT_SUCCESS) {
6097836SJohn.Forte@Sun.COM 				iport->iport_login_retry++;
6107836SJohn.Forte@Sun.COM 				if (iport->iport_login_retry >= 3) {
6117836SJohn.Forte@Sun.COM 					stmf_trace(iport->iport_alias, "Failing"
6127836SJohn.Forte@Sun.COM 					    " to PLOGI to remote port in N2N "
6137836SJohn.Forte@Sun.COM 					    " ret=%llx, forcing link down",
6147836SJohn.Forte@Sun.COM 					    iport->iport_li_comp_status);
6157836SJohn.Forte@Sun.COM 					mutex_exit(&iport->iport_worker_lock);
6167836SJohn.Forte@Sun.COM 					fct_handle_event(iport->iport_port,
6178585SAllan.Ou@Sun.COM 					    FCT_EVENT_LINK_DOWN, 0, 0);
6187836SJohn.Forte@Sun.COM 					mutex_enter(&iport->iport_worker_lock);
6197836SJohn.Forte@Sun.COM 				}
6207836SJohn.Forte@Sun.COM 			}
6217836SJohn.Forte@Sun.COM 		}
6227836SJohn.Forte@Sun.COM 		/* Find out if we need to do PLOGI at all */
6237836SJohn.Forte@Sun.COM 		if (iport->iport_nrps_login) {
6247836SJohn.Forte@Sun.COM 			iport->iport_li_state++;
6257836SJohn.Forte@Sun.COM 			atomic_and_32(&iport->iport_flags,
6267836SJohn.Forte@Sun.COM 			    ~IPORT_ALLOW_UNSOL_FLOGI);
6277836SJohn.Forte@Sun.COM 			goto check_state_again;
6287836SJohn.Forte@Sun.COM 		}
6297836SJohn.Forte@Sun.COM 		if ((ddi_get_lbolt() >= iport->iport_li_cmd_timeout) &&
6307836SJohn.Forte@Sun.COM 		    (!fct_lport_has_bigger_wwn(iport))) {
6317836SJohn.Forte@Sun.COM 			/* Cant wait forever */
6327836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "N2N: Remote port is "
6337836SJohn.Forte@Sun.COM 			    "not logging in, forcing from our side");
6347836SJohn.Forte@Sun.COM 			force_login = 1;
6357836SJohn.Forte@Sun.COM 		} else {
6367836SJohn.Forte@Sun.COM 			force_login = 0;
6377836SJohn.Forte@Sun.COM 		}
6387836SJohn.Forte@Sun.COM 		if (force_login || fct_lport_has_bigger_wwn(iport)) {
6397836SJohn.Forte@Sun.COM 			elsop	 = ELS_OP_PLOGI;
6407836SJohn.Forte@Sun.COM 			wkdid	 = 1;
6417836SJohn.Forte@Sun.COM 			iport->iport_link_info.portid = 0xEF;
6427836SJohn.Forte@Sun.COM 			implicit = 0;
6437836SJohn.Forte@Sun.COM 			iport->iport_li_state |= LI_STATE_FLAG_CMD_RETCHECK;
6447836SJohn.Forte@Sun.COM 		} else {
6457836SJohn.Forte@Sun.COM 			ret = DISC_ACTION_DELAY_RESCAN;
6467836SJohn.Forte@Sun.COM 		}
6477836SJohn.Forte@Sun.COM 		break;
6487836SJohn.Forte@Sun.COM 
6497836SJohn.Forte@Sun.COM 	case LI_STATE_DO_FCLOGIN:
6507836SJohn.Forte@Sun.COM 		if (iport->iport_li_state & LI_STATE_FLAG_CMD_RETCHECK) {
6517836SJohn.Forte@Sun.COM 			iport->iport_li_state &= ~LI_STATE_FLAG_CMD_RETCHECK;
6527836SJohn.Forte@Sun.COM 			if (iport->iport_li_comp_status != FCT_SUCCESS) {
6537836SJohn.Forte@Sun.COM 				/*
6547836SJohn.Forte@Sun.COM 				 * Fabric controller login failed. Just skip all
6557836SJohn.Forte@Sun.COM 				 * the fabric controller related cmds.
6567836SJohn.Forte@Sun.COM 				 */
6577836SJohn.Forte@Sun.COM 				iport->iport_li_state = LI_STATE_DO_SCR + 1;
6587836SJohn.Forte@Sun.COM 			} else {
6597836SJohn.Forte@Sun.COM 				/*
6607836SJohn.Forte@Sun.COM 				 * Good. Now lets go to next state
6617836SJohn.Forte@Sun.COM 				 */
6627836SJohn.Forte@Sun.COM 				iport->iport_li_state++;
6637836SJohn.Forte@Sun.COM 			}
6647836SJohn.Forte@Sun.COM 			goto check_state_again;
6657836SJohn.Forte@Sun.COM 		}
6667836SJohn.Forte@Sun.COM 		if (!IPORT_IN_NS_TOPO(iport)) {
6677836SJohn.Forte@Sun.COM 			iport->iport_li_state = LI_STATE_DO_SCR + 1;
6687836SJohn.Forte@Sun.COM 			goto check_state_again;
6697836SJohn.Forte@Sun.COM 		}
6707836SJohn.Forte@Sun.COM 
6717836SJohn.Forte@Sun.COM 		elsop	 = ELS_OP_PLOGI;
6727836SJohn.Forte@Sun.COM 		wkdid	 = FS_FABRIC_CONTROLLER;
6737836SJohn.Forte@Sun.COM 		implicit = 1;
6747836SJohn.Forte@Sun.COM 
6757836SJohn.Forte@Sun.COM 		/*
6767836SJohn.Forte@Sun.COM 		 * We want to come back in the same state and check its ret
6777836SJohn.Forte@Sun.COM 		 * We can't modify the state here
6787836SJohn.Forte@Sun.COM 		 */
6797836SJohn.Forte@Sun.COM 		iport->iport_li_state |= LI_STATE_FLAG_CMD_RETCHECK;
6807836SJohn.Forte@Sun.COM 		break;
6817836SJohn.Forte@Sun.COM 
6827836SJohn.Forte@Sun.COM 	case LI_STATE_DO_SCR:
6837836SJohn.Forte@Sun.COM 		elsop = ELS_OP_SCR;
6847836SJohn.Forte@Sun.COM 		wkdid = FS_FABRIC_CONTROLLER;
6857836SJohn.Forte@Sun.COM 
6867836SJohn.Forte@Sun.COM 		/*
6877836SJohn.Forte@Sun.COM 		 * We dont care about success of this state. Just go to
6887836SJohn.Forte@Sun.COM 		 * next state upon completion.
6897836SJohn.Forte@Sun.COM 		 */
6907836SJohn.Forte@Sun.COM 		iport->iport_li_state++;
6917836SJohn.Forte@Sun.COM 		break;
6927836SJohn.Forte@Sun.COM 
6937836SJohn.Forte@Sun.COM 	case LI_STATE_DO_NSLOGIN:
6947836SJohn.Forte@Sun.COM 		if (iport->iport_li_state & LI_STATE_FLAG_CMD_RETCHECK) {
6957836SJohn.Forte@Sun.COM 			iport->iport_li_state &= ~LI_STATE_FLAG_CMD_RETCHECK;
6967836SJohn.Forte@Sun.COM 			if (iport->iport_li_comp_status != FCT_SUCCESS) {
6977836SJohn.Forte@Sun.COM 				iport->iport_li_state = LI_STATE_DO_RSNN + 1;
6987836SJohn.Forte@Sun.COM 			} else {
6997836SJohn.Forte@Sun.COM 				iport->iport_li_state++;
7007836SJohn.Forte@Sun.COM 			}
7017836SJohn.Forte@Sun.COM 			goto check_state_again;
7027836SJohn.Forte@Sun.COM 		}
7037836SJohn.Forte@Sun.COM 
7047836SJohn.Forte@Sun.COM 		if (!IPORT_IN_NS_TOPO(iport)) {
7057836SJohn.Forte@Sun.COM 			iport->iport_li_state = LI_STATE_DO_RSNN + 1;
7067836SJohn.Forte@Sun.COM 			goto check_state_again;
7077836SJohn.Forte@Sun.COM 		}
7087836SJohn.Forte@Sun.COM 
7097836SJohn.Forte@Sun.COM 		elsop			= ELS_OP_PLOGI;
7107836SJohn.Forte@Sun.COM 		wkdid			= FS_NAME_SERVER;
7117836SJohn.Forte@Sun.COM 		iport->iport_li_state	|= LI_STATE_FLAG_CMD_RETCHECK;
7127836SJohn.Forte@Sun.COM 		break;
7137836SJohn.Forte@Sun.COM 
7147836SJohn.Forte@Sun.COM 		/*
7157836SJohn.Forte@Sun.COM 		 * CT state
7167836SJohn.Forte@Sun.COM 		 */
7177836SJohn.Forte@Sun.COM 	case LI_STATE_DO_RNN:
7187836SJohn.Forte@Sun.COM 		ctop = NS_RNN_ID;
7197836SJohn.Forte@Sun.COM 		iport->iport_li_state++;
7207836SJohn.Forte@Sun.COM 		break;
7217836SJohn.Forte@Sun.COM 
7227836SJohn.Forte@Sun.COM 	case LI_STATE_DO_RCS:
7237836SJohn.Forte@Sun.COM 		ctop = NS_RCS_ID;
7247836SJohn.Forte@Sun.COM 		iport->iport_li_state++;
7257836SJohn.Forte@Sun.COM 		break;
7267836SJohn.Forte@Sun.COM 
7277836SJohn.Forte@Sun.COM 	case LI_STATE_DO_RFT:
7287836SJohn.Forte@Sun.COM 		ctop = NS_RFT_ID;
7297836SJohn.Forte@Sun.COM 		iport->iport_li_state++;
7307836SJohn.Forte@Sun.COM 		break;
7317836SJohn.Forte@Sun.COM 
7327836SJohn.Forte@Sun.COM 	case LI_STATE_DO_RSPN:
7337836SJohn.Forte@Sun.COM 		/*
7347836SJohn.Forte@Sun.COM 		 * Check if we need skip the state
7357836SJohn.Forte@Sun.COM 		 */
7367836SJohn.Forte@Sun.COM 		pname = iport->iport_port->port_sym_port_name !=
7377836SJohn.Forte@Sun.COM 		    NULL ? iport->iport_port->port_sym_port_name : NULL;
7387836SJohn.Forte@Sun.COM 		if (pname == NULL) {
7397836SJohn.Forte@Sun.COM 			pname = iport->iport_port->port_default_alias !=
7407836SJohn.Forte@Sun.COM 			    NULL ? iport->iport_port->port_default_alias : NULL;
7417836SJohn.Forte@Sun.COM 			iport->iport_port->port_sym_port_name = pname;
7427836SJohn.Forte@Sun.COM 		}
7437836SJohn.Forte@Sun.COM 
7447836SJohn.Forte@Sun.COM 		if (pname == NULL) {
7457836SJohn.Forte@Sun.COM 			iport->iport_li_state++;
7467836SJohn.Forte@Sun.COM 			goto check_state_again;
7477836SJohn.Forte@Sun.COM 		}
7487836SJohn.Forte@Sun.COM 
7497836SJohn.Forte@Sun.COM 		ctop = NS_RSPN_ID;
7507836SJohn.Forte@Sun.COM 		iport->iport_li_state++;
7517836SJohn.Forte@Sun.COM 		break;
7527836SJohn.Forte@Sun.COM 
7537836SJohn.Forte@Sun.COM 	case LI_STATE_DO_RSNN:
7547836SJohn.Forte@Sun.COM 		ctop = NS_RSNN_NN;
7557836SJohn.Forte@Sun.COM 		iport->iport_li_state++;
7567836SJohn.Forte@Sun.COM 		break;
7577836SJohn.Forte@Sun.COM 
7587836SJohn.Forte@Sun.COM 	case LI_STATE_MAX:
7597836SJohn.Forte@Sun.COM 		mutex_exit(&iport->iport_worker_lock);
7607836SJohn.Forte@Sun.COM 
7617836SJohn.Forte@Sun.COM 		fct_handle_event(iport->iport_port,
7627836SJohn.Forte@Sun.COM 		    FCT_I_EVENT_LINK_INIT_DONE, 0, 0);
7637836SJohn.Forte@Sun.COM 
7647836SJohn.Forte@Sun.COM 		mutex_enter(&iport->iport_worker_lock);
7657836SJohn.Forte@Sun.COM 		break;
7667836SJohn.Forte@Sun.COM 
7677836SJohn.Forte@Sun.COM 	default:
7687836SJohn.Forte@Sun.COM 		ASSERT(0);
7697836SJohn.Forte@Sun.COM 	}
7707836SJohn.Forte@Sun.COM 
7717836SJohn.Forte@Sun.COM 	if (elsop != 0) {
7727836SJohn.Forte@Sun.COM 		cmd = fct_create_solels(iport->iport_port, NULL, implicit,
7737836SJohn.Forte@Sun.COM 		    elsop, wkdid, fct_link_init_cb);
7747836SJohn.Forte@Sun.COM 	} else if (ctop != 0) {
7757836SJohn.Forte@Sun.COM 		cmd = fct_create_solct(iport->iport_port, NULL, ctop,
7767836SJohn.Forte@Sun.COM 		    fct_link_init_cb);
7777836SJohn.Forte@Sun.COM 	}
7787836SJohn.Forte@Sun.COM 
7797836SJohn.Forte@Sun.COM 	if (cmd) {
7807836SJohn.Forte@Sun.COM 		iport->iport_li_state |= LI_STATE_FLAG_CMD_WAITING;
7817836SJohn.Forte@Sun.COM 		mutex_exit(&iport->iport_worker_lock);
7827836SJohn.Forte@Sun.COM 
7837836SJohn.Forte@Sun.COM 		fct_post_to_solcmd_queue(iport->iport_port, cmd);
7847836SJohn.Forte@Sun.COM 
7857836SJohn.Forte@Sun.COM 		mutex_enter(&iport->iport_worker_lock);
7867836SJohn.Forte@Sun.COM 	}
7877836SJohn.Forte@Sun.COM 
7887836SJohn.Forte@Sun.COM 	return (ret);
7897836SJohn.Forte@Sun.COM }
7907836SJohn.Forte@Sun.COM 
7917836SJohn.Forte@Sun.COM /*
7927836SJohn.Forte@Sun.COM  * Handles both solicited and unsolicited elses. Can be called inside
7937836SJohn.Forte@Sun.COM  * interrupt context.
7947836SJohn.Forte@Sun.COM  */
7957836SJohn.Forte@Sun.COM void
fct_handle_els(fct_cmd_t * cmd)7967836SJohn.Forte@Sun.COM fct_handle_els(fct_cmd_t *cmd)
7977836SJohn.Forte@Sun.COM {
7987836SJohn.Forte@Sun.COM 	fct_local_port_t	*port = cmd->cmd_port;
7997836SJohn.Forte@Sun.COM 	fct_i_local_port_t *iport =
8008585SAllan.Ou@Sun.COM 	    (fct_i_local_port_t *)port->port_fct_private;
8017836SJohn.Forte@Sun.COM 	fct_i_cmd_t		*icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
8027836SJohn.Forte@Sun.COM 	fct_els_t		*els  = (fct_els_t *)cmd->cmd_specific;
8037836SJohn.Forte@Sun.COM 	fct_remote_port_t	*rp;
8047836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp;
8057836SJohn.Forte@Sun.COM 	uint16_t		 cmd_slot;
8067836SJohn.Forte@Sun.COM 	uint8_t			 op;
8077836SJohn.Forte@Sun.COM 
8087836SJohn.Forte@Sun.COM 	op = els->els_req_payload[0];
8097836SJohn.Forte@Sun.COM 	icmd->icmd_start_time = ddi_get_lbolt();
8107836SJohn.Forte@Sun.COM 	if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
8117836SJohn.Forte@Sun.COM 		icmd->icmd_flags |= ICMD_KNOWN_TO_FCA;
8127836SJohn.Forte@Sun.COM 	}
8137836SJohn.Forte@Sun.COM 	stmf_trace(iport->iport_alias, "Posting %ssol ELS %x (%s) rp_id=%x"
8147836SJohn.Forte@Sun.COM 	    " lp_id=%x", (cmd->cmd_type == FCT_CMD_RCVD_ELS) ? "un" : "",
8158585SAllan.Ou@Sun.COM 	    op, FCT_ELS_NAME(op), cmd->cmd_rportid,
8168585SAllan.Ou@Sun.COM 	    cmd->cmd_lportid);
8177836SJohn.Forte@Sun.COM 
8187836SJohn.Forte@Sun.COM 	rw_enter(&iport->iport_lock, RW_READER);
8197836SJohn.Forte@Sun.COM start_els_posting:;
8207836SJohn.Forte@Sun.COM 	/* Make sure local port is sane */
8217836SJohn.Forte@Sun.COM 	if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
8227836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
8237836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias, "ELS %x not posted becasue"
8247836SJohn.Forte@Sun.COM 		    "port state was %x", els->els_req_payload[0],
8257836SJohn.Forte@Sun.COM 		    iport->iport_link_state);
8267836SJohn.Forte@Sun.COM 		fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE);
8277836SJohn.Forte@Sun.COM 		return;
8287836SJohn.Forte@Sun.COM 	}
8297836SJohn.Forte@Sun.COM 
8307836SJohn.Forte@Sun.COM 	/* Weed out any bad initiators in case of N2N topology */
8317836SJohn.Forte@Sun.COM 	if ((cmd->cmd_type == FCT_CMD_RCVD_ELS) &&
8327836SJohn.Forte@Sun.COM 	    (els->els_req_payload[0] == ELS_OP_PLOGI) &&
8337836SJohn.Forte@Sun.COM 	    (iport->iport_link_state == PORT_STATE_LINK_INIT_START) &&
8347836SJohn.Forte@Sun.COM 	    (iport->iport_link_info.port_topology == PORT_TOPOLOGY_PT_TO_PT)) {
8357836SJohn.Forte@Sun.COM 		int state;
8367836SJohn.Forte@Sun.COM 		int killit = 0;
8377836SJohn.Forte@Sun.COM 
8387836SJohn.Forte@Sun.COM 		mutex_enter(&iport->iport_worker_lock);
8397836SJohn.Forte@Sun.COM 		state = iport->iport_li_state & LI_STATE_MASK;
8407836SJohn.Forte@Sun.COM 		/*
8417836SJohn.Forte@Sun.COM 		 * We dont allow remote port to plogi in N2N if we have not yet
8427836SJohn.Forte@Sun.COM 		 * resolved the topology.
8437836SJohn.Forte@Sun.COM 		 */
8447836SJohn.Forte@Sun.COM 		if (state <= LI_STATE_FINI_TOPOLOGY) {
8457836SJohn.Forte@Sun.COM 			killit = 1;
8467836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "port %x is trying to "
8477836SJohn.Forte@Sun.COM 			    "PLOGI in N2N topology, While we have not resolved"
8487836SJohn.Forte@Sun.COM 			    " the topology. Dropping...", cmd->cmd_rportid);
8497836SJohn.Forte@Sun.COM 		} else if (state <= LI_STATE_N2N_PLOGI) {
8507836SJohn.Forte@Sun.COM 			if (fct_lport_has_bigger_wwn(iport)) {
8517836SJohn.Forte@Sun.COM 				killit = 1;
8527836SJohn.Forte@Sun.COM 				stmf_trace(iport->iport_alias, "port %x is "
8537836SJohn.Forte@Sun.COM 				    "trying to PLOGI in N2N topology, even "
8547836SJohn.Forte@Sun.COM 				    "though it has smaller PWWN",
8557836SJohn.Forte@Sun.COM 				    cmd->cmd_rportid);
8567836SJohn.Forte@Sun.COM 			} else {
8577836SJohn.Forte@Sun.COM 				/*
8587836SJohn.Forte@Sun.COM 				 * Remote port is assigning us a PORTID as
8597836SJohn.Forte@Sun.COM 				 * a part of PLOGI.
8607836SJohn.Forte@Sun.COM 				 */
8617836SJohn.Forte@Sun.COM 				iport->iport_link_info.portid =
8628585SAllan.Ou@Sun.COM 				    cmd->cmd_lportid;
8637836SJohn.Forte@Sun.COM 			}
8647836SJohn.Forte@Sun.COM 		}
8657836SJohn.Forte@Sun.COM 		mutex_exit(&iport->iport_worker_lock);
8667836SJohn.Forte@Sun.COM 		if (killit) {
8677836SJohn.Forte@Sun.COM 			rw_exit(&iport->iport_lock);
8687836SJohn.Forte@Sun.COM 			fct_queue_cmd_for_termination(cmd,
8698585SAllan.Ou@Sun.COM 			    FCT_LOCAL_PORT_OFFLINE);
8707836SJohn.Forte@Sun.COM 			return;
8717836SJohn.Forte@Sun.COM 		}
8727836SJohn.Forte@Sun.COM 	}
8737836SJohn.Forte@Sun.COM 
8747836SJohn.Forte@Sun.COM 	/*
8757836SJohn.Forte@Sun.COM 	 * For all unsolicited ELSes that are not FLOGIs, our portid
8767836SJohn.Forte@Sun.COM 	 * has been established by now. Sometimes port IDs change due to
8777836SJohn.Forte@Sun.COM 	 * link resets but remote ports may still send ELSes using the
8787836SJohn.Forte@Sun.COM 	 * old IDs. Kill those right here.
8797836SJohn.Forte@Sun.COM 	 */
8807836SJohn.Forte@Sun.COM 	if ((cmd->cmd_type == FCT_CMD_RCVD_ELS) &&
8817836SJohn.Forte@Sun.COM 	    (els->els_req_payload[0] != ELS_OP_FLOGI)) {
8827836SJohn.Forte@Sun.COM 		if (cmd->cmd_lportid != iport->iport_link_info.portid) {
8837836SJohn.Forte@Sun.COM 			rw_exit(&iport->iport_lock);
8847836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "Rcvd %s with "
8857836SJohn.Forte@Sun.COM 			    "wrong lportid %x, expecting %x. Killing ELS.",
8867836SJohn.Forte@Sun.COM 			    FCT_ELS_NAME(op), cmd->cmd_lportid,
8877836SJohn.Forte@Sun.COM 			    iport->iport_link_info.portid);
8887836SJohn.Forte@Sun.COM 			fct_queue_cmd_for_termination(cmd,
8898585SAllan.Ou@Sun.COM 			    FCT_NOT_FOUND);
8907836SJohn.Forte@Sun.COM 			return;
8917836SJohn.Forte@Sun.COM 		}
8927836SJohn.Forte@Sun.COM 	}
8937836SJohn.Forte@Sun.COM 
8947836SJohn.Forte@Sun.COM 	/*
8957836SJohn.Forte@Sun.COM 	 * We always lookup by portid. port handles are too
8967836SJohn.Forte@Sun.COM 	 * unreliable at this stage.
8977836SJohn.Forte@Sun.COM 	 */
8987836SJohn.Forte@Sun.COM 	irp = fct_portid_to_portptr(iport, cmd->cmd_rportid);
8997836SJohn.Forte@Sun.COM 	if (els->els_req_payload[0] == ELS_OP_PLOGI) {
9007836SJohn.Forte@Sun.COM 		if (irp == NULL) {
9017836SJohn.Forte@Sun.COM 			/* drop the lock while we do allocations */
9027836SJohn.Forte@Sun.COM 			rw_exit(&iport->iport_lock);
9037836SJohn.Forte@Sun.COM 			rp = fct_alloc(FCT_STRUCT_REMOTE_PORT,
9048585SAllan.Ou@Sun.COM 			    port->port_fca_rp_private_size, 0);
9057836SJohn.Forte@Sun.COM 			if (rp == NULL) {
9067836SJohn.Forte@Sun.COM 				fct_queue_cmd_for_termination(cmd,
9078585SAllan.Ou@Sun.COM 				    FCT_ALLOC_FAILURE);
9087836SJohn.Forte@Sun.COM 				return;
9097836SJohn.Forte@Sun.COM 			}
9107836SJohn.Forte@Sun.COM 			irp = (fct_i_remote_port_t *)rp->rp_fct_private;
9117836SJohn.Forte@Sun.COM 			rw_init(&irp->irp_lock, 0, RW_DRIVER, 0);
9127836SJohn.Forte@Sun.COM 			irp->irp_rp = rp;
9137836SJohn.Forte@Sun.COM 			irp->irp_portid = cmd->cmd_rportid;
9147836SJohn.Forte@Sun.COM 			rp->rp_port = port;
9157836SJohn.Forte@Sun.COM 			rp->rp_id = cmd->cmd_rportid;
9167836SJohn.Forte@Sun.COM 			rp->rp_handle = FCT_HANDLE_NONE;
9177836SJohn.Forte@Sun.COM 			/*
9187836SJohn.Forte@Sun.COM 			 * Grab port lock as writer since we are going
9197836SJohn.Forte@Sun.COM 			 * to modify the local port struct.
9207836SJohn.Forte@Sun.COM 			 */
9217836SJohn.Forte@Sun.COM 			rw_enter(&iport->iport_lock, RW_WRITER);
9227836SJohn.Forte@Sun.COM 			/* Make sure nobody created the struct except us */
9237836SJohn.Forte@Sun.COM 			if (fct_portid_to_portptr(iport, cmd->cmd_rportid)) {
9247836SJohn.Forte@Sun.COM 				/* Oh well, free it */
9257836SJohn.Forte@Sun.COM 				fct_free(rp);
9267836SJohn.Forte@Sun.COM 			} else {
9277836SJohn.Forte@Sun.COM 				fct_queue_rp(iport, irp);
9287836SJohn.Forte@Sun.COM 			}
9297836SJohn.Forte@Sun.COM 			rw_downgrade(&iport->iport_lock);
9307836SJohn.Forte@Sun.COM 			/* Start over becasue we dropped the lock */
9317836SJohn.Forte@Sun.COM 			goto start_els_posting;
9327836SJohn.Forte@Sun.COM 		}
9337836SJohn.Forte@Sun.COM 
9347836SJohn.Forte@Sun.COM 		/* A PLOGI is by default a logout of previous session */
9357836SJohn.Forte@Sun.COM 		irp->irp_deregister_timer = ddi_get_lbolt() +
9368585SAllan.Ou@Sun.COM 		    drv_usectohz(USEC_DEREG_RP_TIMEOUT);
9377836SJohn.Forte@Sun.COM 		irp->irp_dereg_count = 0;
9387836SJohn.Forte@Sun.COM 		fct_post_to_discovery_queue(iport, irp, NULL);
9397836SJohn.Forte@Sun.COM 
9407836SJohn.Forte@Sun.COM 		/* A PLOGI also invalidates any RSCNs related to this rp */
9417836SJohn.Forte@Sun.COM 		atomic_add_32(&irp->irp_rscn_counter, 1);
9427836SJohn.Forte@Sun.COM 	} else {
9437836SJohn.Forte@Sun.COM 		/*
9447836SJohn.Forte@Sun.COM 		 * For everything else, we have (or be able to lookup) a
9457836SJohn.Forte@Sun.COM 		 * valid port pointer.
9467836SJohn.Forte@Sun.COM 		 */
9477836SJohn.Forte@Sun.COM 		if (irp == NULL) {
9487836SJohn.Forte@Sun.COM 			rw_exit(&iport->iport_lock);
9497836SJohn.Forte@Sun.COM 			if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
9507836SJohn.Forte@Sun.COM 				/* XXX Throw a logout to the initiator */
9517836SJohn.Forte@Sun.COM 				stmf_trace(iport->iport_alias, "ELS %x "
9527836SJohn.Forte@Sun.COM 				    "received from %x without a session",
9537836SJohn.Forte@Sun.COM 				    els->els_req_payload[0], cmd->cmd_rportid);
9547836SJohn.Forte@Sun.COM 			} else {
9557836SJohn.Forte@Sun.COM 				stmf_trace(iport->iport_alias, "Sending ELS %x "
9567836SJohn.Forte@Sun.COM 				    "to %x without a session",
9577836SJohn.Forte@Sun.COM 				    els->els_req_payload[0], cmd->cmd_rportid);
9587836SJohn.Forte@Sun.COM 			}
9597836SJohn.Forte@Sun.COM 			fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN);
9607836SJohn.Forte@Sun.COM 			return;
9617836SJohn.Forte@Sun.COM 		}
9627836SJohn.Forte@Sun.COM 	}
9637836SJohn.Forte@Sun.COM 	cmd->cmd_rp = rp = irp->irp_rp;
9647836SJohn.Forte@Sun.COM 
9657836SJohn.Forte@Sun.COM 	/*
9667836SJohn.Forte@Sun.COM 	 * Lets get a slot for this els
9677836SJohn.Forte@Sun.COM 	 */
9687836SJohn.Forte@Sun.COM 	if (!(icmd->icmd_flags & ICMD_IMPLICIT)) {
9697836SJohn.Forte@Sun.COM 		cmd_slot = fct_alloc_cmd_slot(iport, cmd);
9707836SJohn.Forte@Sun.COM 		if (cmd_slot == FCT_SLOT_EOL) {
9717836SJohn.Forte@Sun.COM 			/* This should not have happened */
9727836SJohn.Forte@Sun.COM 			rw_exit(&iport->iport_lock);
9737836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias,
9748585SAllan.Ou@Sun.COM 			    "ran out of xchg resources");
9757836SJohn.Forte@Sun.COM 			fct_queue_cmd_for_termination(cmd,
9768585SAllan.Ou@Sun.COM 			    FCT_NO_XCHG_RESOURCE);
9777836SJohn.Forte@Sun.COM 			return;
9787836SJohn.Forte@Sun.COM 		}
9797836SJohn.Forte@Sun.COM 	} else {
9807836SJohn.Forte@Sun.COM 		/*
9817836SJohn.Forte@Sun.COM 		 * Tell the framework that fct_cmd_free() can decrement the
9827836SJohn.Forte@Sun.COM 		 * irp_nonfcp_xchg_count variable.
9837836SJohn.Forte@Sun.COM 		 */
9847836SJohn.Forte@Sun.COM 		atomic_or_32(&icmd->icmd_flags, ICMD_IMPLICIT_CMD_HAS_RESOURCE);
9857836SJohn.Forte@Sun.COM 	}
9867836SJohn.Forte@Sun.COM 	atomic_add_16(&irp->irp_nonfcp_xchg_count, 1);
9877836SJohn.Forte@Sun.COM 
9887836SJohn.Forte@Sun.COM 	/*
9897836SJohn.Forte@Sun.COM 	 * Grab the remote port lock while we modify the port state.
9907836SJohn.Forte@Sun.COM 	 * we should not drop the fca port lock (as a reader) until we
9917836SJohn.Forte@Sun.COM 	 * modify the remote port state.
9927836SJohn.Forte@Sun.COM 	 */
9937836SJohn.Forte@Sun.COM 	rw_enter(&irp->irp_lock, RW_WRITER);
9947836SJohn.Forte@Sun.COM 	if ((op == ELS_OP_PLOGI) || (op == ELS_OP_PRLI) ||
9957836SJohn.Forte@Sun.COM 	    (op == ELS_OP_LOGO) || (op == ELS_OP_PRLO) ||
9967836SJohn.Forte@Sun.COM 	    (op == ELS_OP_TPRLO)) {
9977836SJohn.Forte@Sun.COM 		uint32_t rf = IRP_PRLI_DONE;
9987836SJohn.Forte@Sun.COM 		if ((op == ELS_OP_PLOGI) || (op == ELS_OP_LOGO)) {
9997836SJohn.Forte@Sun.COM 			rf |= IRP_PLOGI_DONE;
10007836SJohn.Forte@Sun.COM 			if (irp->irp_flags & IRP_PLOGI_DONE)
10017836SJohn.Forte@Sun.COM 				atomic_add_32(&iport->iport_nrps_login, -1);
10027836SJohn.Forte@Sun.COM 		}
10037836SJohn.Forte@Sun.COM 		atomic_add_16(&irp->irp_sa_elses_count, 1);
10047836SJohn.Forte@Sun.COM 		atomic_and_32(&irp->irp_flags, ~rf);
10057836SJohn.Forte@Sun.COM 		atomic_or_32(&icmd->icmd_flags, ICMD_SESSION_AFFECTING);
10067836SJohn.Forte@Sun.COM 	} else {
10077836SJohn.Forte@Sun.COM 		atomic_add_16(&irp->irp_nsa_elses_count, 1);
10087836SJohn.Forte@Sun.COM 	}
10097836SJohn.Forte@Sun.COM 
10107836SJohn.Forte@Sun.COM 	fct_post_to_discovery_queue(iport, irp, icmd);
10117836SJohn.Forte@Sun.COM 
10127836SJohn.Forte@Sun.COM 	rw_exit(&irp->irp_lock);
10137836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
10147836SJohn.Forte@Sun.COM }
10157836SJohn.Forte@Sun.COM 
10167836SJohn.Forte@Sun.COM /*
10177836SJohn.Forte@Sun.COM  * Cleanup I/Os for a rport. ttc is a bit Mask of cmd types to clean.
10187836SJohn.Forte@Sun.COM  * No locks held.
10197836SJohn.Forte@Sun.COM  */
10207836SJohn.Forte@Sun.COM int
fct_trigger_rport_cleanup(fct_i_remote_port_t * irp,int ttc)10217836SJohn.Forte@Sun.COM fct_trigger_rport_cleanup(fct_i_remote_port_t *irp, int ttc)
10227836SJohn.Forte@Sun.COM {
10237836SJohn.Forte@Sun.COM 	fct_remote_port_t	*rp = irp->irp_rp;
10247836SJohn.Forte@Sun.COM 	fct_local_port_t	*port = rp->rp_port;
10257836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport =
10268585SAllan.Ou@Sun.COM 	    (fct_i_local_port_t *)port->port_fct_private;
10277836SJohn.Forte@Sun.COM 	fct_cmd_t		*cmd;
10287836SJohn.Forte@Sun.COM 	fct_i_cmd_t		*icmd;
10297836SJohn.Forte@Sun.COM 	int			i;
10307836SJohn.Forte@Sun.COM 	int			ret;
10317836SJohn.Forte@Sun.COM 	uint16_t		total, cleaned, skipped, unhandled;
10327836SJohn.Forte@Sun.COM 
10337836SJohn.Forte@Sun.COM 	rw_enter(&iport->iport_lock, RW_WRITER);
10347836SJohn.Forte@Sun.COM 	rw_enter(&irp->irp_lock, RW_WRITER);
10357836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
10367836SJohn.Forte@Sun.COM 	total = port->port_max_xchges - iport->iport_nslots_free;
10377836SJohn.Forte@Sun.COM 	cleaned = skipped = unhandled = 0;
10387836SJohn.Forte@Sun.COM 
10397836SJohn.Forte@Sun.COM 	for (i = 0; i < port->port_max_xchges; i++) {
10407836SJohn.Forte@Sun.COM 		if (iport->iport_cmd_slots[i].slot_cmd == NULL)
10417836SJohn.Forte@Sun.COM 			continue;
10427836SJohn.Forte@Sun.COM 		icmd = iport->iport_cmd_slots[i].slot_cmd;
10437836SJohn.Forte@Sun.COM 		if (icmd->icmd_flags & ICMD_IN_TRANSITION) {
10447836SJohn.Forte@Sun.COM 			unhandled++;
10457836SJohn.Forte@Sun.COM 			continue;
10467836SJohn.Forte@Sun.COM 		}
10477836SJohn.Forte@Sun.COM 
10487836SJohn.Forte@Sun.COM 		if (icmd->icmd_flags & ICMD_CMD_COMPLETE) {
10497836SJohn.Forte@Sun.COM 			unhandled++;
10507836SJohn.Forte@Sun.COM 			continue;
10517836SJohn.Forte@Sun.COM 		}
10527836SJohn.Forte@Sun.COM 
10537836SJohn.Forte@Sun.COM 		cmd = icmd->icmd_cmd;
10547836SJohn.Forte@Sun.COM 		if (cmd->cmd_rp != rp) {
10557836SJohn.Forte@Sun.COM 			skipped++;
10567836SJohn.Forte@Sun.COM 			continue;
10577836SJohn.Forte@Sun.COM 		}
10587836SJohn.Forte@Sun.COM 		if (cmd->cmd_type & ttc) {
10597836SJohn.Forte@Sun.COM 			if (cmd->cmd_type == FCT_CMD_FCP_XCHG)
10607836SJohn.Forte@Sun.COM 				fct_queue_scsi_task_for_termination(cmd,
10618585SAllan.Ou@Sun.COM 				    FCT_ABORTED);
10627836SJohn.Forte@Sun.COM 			else
10637836SJohn.Forte@Sun.COM 				fct_q_for_termination_lock_held(iport, icmd,
10648585SAllan.Ou@Sun.COM 				    FCT_ABORTED);
10657836SJohn.Forte@Sun.COM 			cleaned++;
10667836SJohn.Forte@Sun.COM 		} else {
10677836SJohn.Forte@Sun.COM 			skipped++;
10687836SJohn.Forte@Sun.COM 		}
10697836SJohn.Forte@Sun.COM 	}
10707836SJohn.Forte@Sun.COM 	if (((cleaned + skipped) == total) && (unhandled == 0)) {
10717836SJohn.Forte@Sun.COM 		ret = 1;
10727836SJohn.Forte@Sun.COM 	} else {
10737836SJohn.Forte@Sun.COM 		/*
10747836SJohn.Forte@Sun.COM 		 * XXX: handle this situation.
10757836SJohn.Forte@Sun.COM 		 */
10767836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias, "Clean up trouble for irp"
10777836SJohn.Forte@Sun.COM 		    " %p, c/s/u/t = %d/%d/%d/%d", irp, cleaned, skipped,
10788585SAllan.Ou@Sun.COM 		    unhandled, total);
10797836SJohn.Forte@Sun.COM 		ret = 0;
10807836SJohn.Forte@Sun.COM 	}
10817836SJohn.Forte@Sun.COM 	if ((cleaned) && IS_WORKER_SLEEPING(iport))
10827836SJohn.Forte@Sun.COM 		cv_signal(&iport->iport_worker_cv);
10837836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
10847836SJohn.Forte@Sun.COM 	rw_exit(&irp->irp_lock);
10857836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
10867836SJohn.Forte@Sun.COM 	return (ret);
10877836SJohn.Forte@Sun.COM }
10887836SJohn.Forte@Sun.COM 
10897836SJohn.Forte@Sun.COM void
fct_dequeue_els(fct_i_remote_port_t * irp)10907836SJohn.Forte@Sun.COM fct_dequeue_els(fct_i_remote_port_t *irp)
10917836SJohn.Forte@Sun.COM {
10927836SJohn.Forte@Sun.COM 	fct_i_cmd_t *icmd;
10937836SJohn.Forte@Sun.COM 
10947836SJohn.Forte@Sun.COM 	rw_enter(&irp->irp_lock, RW_WRITER);
10957836SJohn.Forte@Sun.COM 	icmd = irp->irp_els_list;
10967836SJohn.Forte@Sun.COM 	irp->irp_els_list = icmd->icmd_next;
10977836SJohn.Forte@Sun.COM 	atomic_and_32(&icmd->icmd_flags, ~ICMD_IN_IRP_QUEUE);
10987836SJohn.Forte@Sun.COM 	rw_exit(&irp->irp_lock);
10997836SJohn.Forte@Sun.COM }
11007836SJohn.Forte@Sun.COM 
11017836SJohn.Forte@Sun.COM fct_status_t
fct_register_remote_port(fct_local_port_t * port,fct_remote_port_t * rp,fct_cmd_t * cmd)11027836SJohn.Forte@Sun.COM fct_register_remote_port(fct_local_port_t *port, fct_remote_port_t *rp,
11037836SJohn.Forte@Sun.COM 				fct_cmd_t *cmd)
11047836SJohn.Forte@Sun.COM {
11057836SJohn.Forte@Sun.COM 	fct_status_t ret;
11067836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport;
11077836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp;
11087836SJohn.Forte@Sun.COM 	int			i;
1109*12571SViswanathan.Kannappan@Sun.COM 	char			info[FCT_INFO_LEN];
11107836SJohn.Forte@Sun.COM 
11117836SJohn.Forte@Sun.COM 	iport = (fct_i_local_port_t *)port->port_fct_private;
11127836SJohn.Forte@Sun.COM 	irp = (fct_i_remote_port_t *)rp->rp_fct_private;
11137836SJohn.Forte@Sun.COM 
11147836SJohn.Forte@Sun.COM 	if ((ret = port->port_register_remote_port(port, rp, cmd)) !=
11158585SAllan.Ou@Sun.COM 	    FCT_SUCCESS)
11167836SJohn.Forte@Sun.COM 		return (ret);
11177836SJohn.Forte@Sun.COM 
11187836SJohn.Forte@Sun.COM 	rw_enter(&iport->iport_lock, RW_WRITER);
11197836SJohn.Forte@Sun.COM 	rw_enter(&irp->irp_lock, RW_WRITER);
11207836SJohn.Forte@Sun.COM 	if (rp->rp_handle != FCT_HANDLE_NONE) {
11217836SJohn.Forte@Sun.COM 		if (rp->rp_handle >= port->port_max_logins) {
1122*12571SViswanathan.Kannappan@Sun.COM 			(void) snprintf(info, sizeof (info),
11237836SJohn.Forte@Sun.COM 			    "fct_register_remote_port: FCA "
11247836SJohn.Forte@Sun.COM 			    "returned a	handle (%d) for portid %x which is "
11257836SJohn.Forte@Sun.COM 			    "out of range (max logins = %d)", rp->rp_handle,
11267836SJohn.Forte@Sun.COM 			    rp->rp_id, port->port_max_logins);
11277836SJohn.Forte@Sun.COM 			goto hba_fatal_err;
11287836SJohn.Forte@Sun.COM 		}
11297836SJohn.Forte@Sun.COM 		if ((iport->iport_rp_slots[rp->rp_handle] != NULL) &&
11307836SJohn.Forte@Sun.COM 		    (iport->iport_rp_slots[rp->rp_handle] != irp)) {
11318585SAllan.Ou@Sun.COM 			fct_i_remote_port_t *t_irp =
11328585SAllan.Ou@Sun.COM 			    iport->iport_rp_slots[rp->rp_handle];
1133*12571SViswanathan.Kannappan@Sun.COM 			(void) snprintf(info, sizeof (info),
1134*12571SViswanathan.Kannappan@Sun.COM 			    "fct_register_remote_port: "
11357836SJohn.Forte@Sun.COM 			    "FCA returned a handle %d for portid %x "
11367836SJohn.Forte@Sun.COM 			    "which was already in use for a different "
11377836SJohn.Forte@Sun.COM 			    "portid (%x)", rp->rp_handle, rp->rp_id,
11388585SAllan.Ou@Sun.COM 			    t_irp->irp_rp->rp_id);
11397836SJohn.Forte@Sun.COM 			goto hba_fatal_err;
11407836SJohn.Forte@Sun.COM 		}
11417836SJohn.Forte@Sun.COM 	} else {
11427836SJohn.Forte@Sun.COM 		/* Pick a handle for this port */
11437836SJohn.Forte@Sun.COM 		for (i = 0; i < port->port_max_logins; i++) {
11447836SJohn.Forte@Sun.COM 			if (iport->iport_rp_slots[i] == NULL) {
11457836SJohn.Forte@Sun.COM 				break;
11467836SJohn.Forte@Sun.COM 			}
11477836SJohn.Forte@Sun.COM 		}
11487836SJohn.Forte@Sun.COM 		if (i == port->port_max_logins) {
11497836SJohn.Forte@Sun.COM 			/* This is really pushing it. */
1150*12571SViswanathan.Kannappan@Sun.COM 			(void) snprintf(info, sizeof (info),
1151*12571SViswanathan.Kannappan@Sun.COM 			    "fct_register_remote_port "
11527836SJohn.Forte@Sun.COM 			    "Cannot register portid %x because all the "
11537836SJohn.Forte@Sun.COM 			    "handles are used up", rp->rp_id);
11547836SJohn.Forte@Sun.COM 			goto hba_fatal_err;
11557836SJohn.Forte@Sun.COM 		}
11567836SJohn.Forte@Sun.COM 		rp->rp_handle = i;
11577836SJohn.Forte@Sun.COM 	}
11587836SJohn.Forte@Sun.COM 	/* By this time rport_handle is valid */
11597836SJohn.Forte@Sun.COM 	if ((irp->irp_flags & IRP_HANDLE_OPENED) == 0) {
11607836SJohn.Forte@Sun.COM 		iport->iport_rp_slots[rp->rp_handle] = irp;
11617836SJohn.Forte@Sun.COM 		atomic_or_32(&irp->irp_flags, IRP_HANDLE_OPENED);
11627836SJohn.Forte@Sun.COM 	}
11637836SJohn.Forte@Sun.COM 	(void) atomic_add_64_nv(&iport->iport_last_change, 1);
11647836SJohn.Forte@Sun.COM 	fct_log_remote_port_event(port, ESC_SUNFC_TARGET_ADD,
11657836SJohn.Forte@Sun.COM 	    rp->rp_pwwn, rp->rp_id);
11667836SJohn.Forte@Sun.COM 
11677836SJohn.Forte@Sun.COM register_rp_done:;
11687836SJohn.Forte@Sun.COM 	rw_exit(&irp->irp_lock);
11697836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
11707836SJohn.Forte@Sun.COM 	return (FCT_SUCCESS);
11717836SJohn.Forte@Sun.COM 
11727836SJohn.Forte@Sun.COM hba_fatal_err:;
11737836SJohn.Forte@Sun.COM 	rw_exit(&irp->irp_lock);
11747836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
11757836SJohn.Forte@Sun.COM 	/*
11767836SJohn.Forte@Sun.COM 	 * XXX Throw HBA fatal error event
11777836SJohn.Forte@Sun.COM 	 */
11787836SJohn.Forte@Sun.COM 	(void) fct_port_shutdown(iport->iport_port,
11797836SJohn.Forte@Sun.COM 	    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
11807836SJohn.Forte@Sun.COM 	return (FCT_FAILURE);
11817836SJohn.Forte@Sun.COM }
11827836SJohn.Forte@Sun.COM 
11837836SJohn.Forte@Sun.COM fct_status_t
fct_deregister_remote_port(fct_local_port_t * port,fct_remote_port_t * rp)11847836SJohn.Forte@Sun.COM fct_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp)
11857836SJohn.Forte@Sun.COM {
11867836SJohn.Forte@Sun.COM 	fct_status_t		 ret   = FCT_SUCCESS;
11877836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport = PORT_TO_IPORT(port);
11887836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp   = RP_TO_IRP(rp);
11897836SJohn.Forte@Sun.COM 
11907836SJohn.Forte@Sun.COM 	if (irp->irp_snn) {
11917836SJohn.Forte@Sun.COM 		kmem_free(irp->irp_snn, strlen(irp->irp_snn) + 1);
11927836SJohn.Forte@Sun.COM 		irp->irp_snn = NULL;
11937836SJohn.Forte@Sun.COM 	}
11947836SJohn.Forte@Sun.COM 	if (irp->irp_spn) {
11957836SJohn.Forte@Sun.COM 		kmem_free(irp->irp_spn, strlen(irp->irp_spn) + 1);
11967836SJohn.Forte@Sun.COM 		irp->irp_spn = NULL;
11977836SJohn.Forte@Sun.COM 	}
11987836SJohn.Forte@Sun.COM 
11997836SJohn.Forte@Sun.COM 	if ((ret = port->port_deregister_remote_port(port, rp)) !=
12007836SJohn.Forte@Sun.COM 	    FCT_SUCCESS) {
12017836SJohn.Forte@Sun.COM 		return (ret);
12027836SJohn.Forte@Sun.COM 	}
12037836SJohn.Forte@Sun.COM 
12047836SJohn.Forte@Sun.COM 	if (irp->irp_flags & IRP_HANDLE_OPENED) {
12057836SJohn.Forte@Sun.COM 		atomic_and_32(&irp->irp_flags, ~IRP_HANDLE_OPENED);
12067836SJohn.Forte@Sun.COM 		iport->iport_rp_slots[rp->rp_handle] = NULL;
12077836SJohn.Forte@Sun.COM 	}
12087836SJohn.Forte@Sun.COM 	(void) atomic_add_64_nv(&iport->iport_last_change, 1);
12097836SJohn.Forte@Sun.COM 	fct_log_remote_port_event(port, ESC_SUNFC_TARGET_REMOVE,
12107836SJohn.Forte@Sun.COM 	    rp->rp_pwwn, rp->rp_id);
12117836SJohn.Forte@Sun.COM 
12127836SJohn.Forte@Sun.COM 	return (FCT_SUCCESS);
12137836SJohn.Forte@Sun.COM }
12147836SJohn.Forte@Sun.COM 
12157836SJohn.Forte@Sun.COM fct_status_t
fct_send_accrjt(fct_cmd_t * cmd,uint8_t accrjt,uint8_t reason,uint8_t expl)12167836SJohn.Forte@Sun.COM fct_send_accrjt(fct_cmd_t *cmd, uint8_t accrjt, uint8_t reason, uint8_t expl)
12177836SJohn.Forte@Sun.COM {
12187836SJohn.Forte@Sun.COM 	fct_local_port_t *port = (fct_local_port_t *)cmd->cmd_port;
12197836SJohn.Forte@Sun.COM 	fct_els_t *els = (fct_els_t *)cmd->cmd_specific;
12207836SJohn.Forte@Sun.COM 
12217836SJohn.Forte@Sun.COM 	els->els_resp_size = els->els_resp_alloc_size = 8;
12227836SJohn.Forte@Sun.COM 	els->els_resp_payload = (uint8_t *)kmem_zalloc(8, KM_SLEEP);
12237836SJohn.Forte@Sun.COM 	els->els_resp_payload[0] = accrjt;
12247836SJohn.Forte@Sun.COM 	if (accrjt == 1) {
12257836SJohn.Forte@Sun.COM 		els->els_resp_payload[5] = reason;
12267836SJohn.Forte@Sun.COM 		els->els_resp_payload[6] = expl;
12277836SJohn.Forte@Sun.COM 	} else {
12287836SJohn.Forte@Sun.COM 		els->els_resp_size = 4;
12297836SJohn.Forte@Sun.COM 	}
12307836SJohn.Forte@Sun.COM 
12317836SJohn.Forte@Sun.COM 	return (port->port_send_cmd_response(cmd, 0));
12327836SJohn.Forte@Sun.COM }
12337836SJohn.Forte@Sun.COM 
12347836SJohn.Forte@Sun.COM 
12357836SJohn.Forte@Sun.COM disc_action_t
fct_walk_discovery_queue(fct_i_local_port_t * iport)12367836SJohn.Forte@Sun.COM fct_walk_discovery_queue(fct_i_local_port_t *iport)
12377836SJohn.Forte@Sun.COM {
1238*12571SViswanathan.Kannappan@Sun.COM 	char			info[FCT_INFO_LEN];
12397836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	**pirp;
12407836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*prev_irp = NULL;
12417836SJohn.Forte@Sun.COM 	disc_action_t		suggested_action = DISC_ACTION_NO_WORK;
12427836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp_dereg_list = NULL;
12437836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp_cur_item = NULL;
12447836SJohn.Forte@Sun.COM 
12457836SJohn.Forte@Sun.COM 	for (pirp = &iport->iport_rpwe_head; *pirp != NULL; ) {
12467836SJohn.Forte@Sun.COM 		fct_i_remote_port_t *irp = *pirp;
12477836SJohn.Forte@Sun.COM 		disc_action_t ret = DISC_ACTION_NO_WORK;
12487836SJohn.Forte@Sun.COM 		int do_deregister = 0;
12498585SAllan.Ou@Sun.COM 		int irp_deregister_timer = 0;
12507836SJohn.Forte@Sun.COM 
12517836SJohn.Forte@Sun.COM 		if (irp->irp_els_list) {
12527836SJohn.Forte@Sun.COM 			ret |= fct_process_els(iport, irp);
12537836SJohn.Forte@Sun.COM 		}
12548585SAllan.Ou@Sun.COM 
12558585SAllan.Ou@Sun.COM 		irp_deregister_timer = irp->irp_deregister_timer;
12568585SAllan.Ou@Sun.COM 		if (irp_deregister_timer) {
12578585SAllan.Ou@Sun.COM 			if (ddi_get_lbolt() >= irp_deregister_timer) {
12587836SJohn.Forte@Sun.COM 				do_deregister = 1;
12597836SJohn.Forte@Sun.COM 			} else {
12607836SJohn.Forte@Sun.COM 				ret |= DISC_ACTION_DELAY_RESCAN;
12617836SJohn.Forte@Sun.COM 			}
12627836SJohn.Forte@Sun.COM 		}
12637836SJohn.Forte@Sun.COM 		suggested_action |= ret;
12647836SJohn.Forte@Sun.COM 
12657836SJohn.Forte@Sun.COM 		if (irp->irp_els_list == NULL) {
12667836SJohn.Forte@Sun.COM 			mutex_exit(&iport->iport_worker_lock);
12677836SJohn.Forte@Sun.COM 			rw_enter(&iport->iport_lock, RW_WRITER);
12687836SJohn.Forte@Sun.COM 			rw_enter(&irp->irp_lock, RW_WRITER);
12697836SJohn.Forte@Sun.COM 			mutex_enter(&iport->iport_worker_lock);
12707836SJohn.Forte@Sun.COM 			if (irp->irp_els_list == NULL) {
12718585SAllan.Ou@Sun.COM 				if (!irp_deregister_timer ||
12727836SJohn.Forte@Sun.COM 				    (do_deregister &&
12737836SJohn.Forte@Sun.COM 				    !irp->irp_sa_elses_count &&
12747836SJohn.Forte@Sun.COM 				    !irp->irp_nsa_elses_count &&
12757836SJohn.Forte@Sun.COM 				    !irp->irp_fcp_xchg_count &&
12767836SJohn.Forte@Sun.COM 				    !irp->irp_nonfcp_xchg_count)) {
12777836SJohn.Forte@Sun.COM 					/* dequeue irp from discovery queue */
12787836SJohn.Forte@Sun.COM 					atomic_and_32(&irp->irp_flags,
12798585SAllan.Ou@Sun.COM 					    ~IRP_IN_DISCOVERY_QUEUE);
12807836SJohn.Forte@Sun.COM 					*pirp = irp->irp_discovery_next;
12817836SJohn.Forte@Sun.COM 					if (iport->iport_rpwe_head == NULL)
12827836SJohn.Forte@Sun.COM 						iport->iport_rpwe_tail = NULL;
12837836SJohn.Forte@Sun.COM 					else if (irp == iport->iport_rpwe_tail)
12847836SJohn.Forte@Sun.COM 						iport->iport_rpwe_tail =
12858585SAllan.Ou@Sun.COM 						    prev_irp;
12867836SJohn.Forte@Sun.COM 
12877836SJohn.Forte@Sun.COM 					irp->irp_discovery_next = NULL;
12887836SJohn.Forte@Sun.COM 					if (do_deregister) {
12897836SJohn.Forte@Sun.COM 						fct_deque_rp(iport, irp);
12907836SJohn.Forte@Sun.COM 						rw_exit(&irp->irp_lock);
12917836SJohn.Forte@Sun.COM 						/* queue irp for deregister */
12927836SJohn.Forte@Sun.COM 						irp->irp_next = NULL;
12937836SJohn.Forte@Sun.COM 						if (!irp_dereg_list) {
12947836SJohn.Forte@Sun.COM 							irp_dereg_list =
12957836SJohn.Forte@Sun.COM 							    irp_cur_item = irp;
12967836SJohn.Forte@Sun.COM 						} else {
12977836SJohn.Forte@Sun.COM 							irp_cur_item->irp_next =
12988585SAllan.Ou@Sun.COM 							    irp;
12997836SJohn.Forte@Sun.COM 							irp_cur_item = irp;
13007836SJohn.Forte@Sun.COM 						}
13017836SJohn.Forte@Sun.COM 					} else {
13027836SJohn.Forte@Sun.COM 						rw_exit(&irp->irp_lock);
13037836SJohn.Forte@Sun.COM 					}
13047836SJohn.Forte@Sun.COM 					rw_exit(&iport->iport_lock);
13057836SJohn.Forte@Sun.COM 					if ((irp = *pirp) == NULL)
13067836SJohn.Forte@Sun.COM 						break;
13077836SJohn.Forte@Sun.COM 				} else {
13087836SJohn.Forte@Sun.COM 					/*
13097836SJohn.Forte@Sun.COM 					 * wait for another scan until
13107836SJohn.Forte@Sun.COM 					 * deregister timeout
13117836SJohn.Forte@Sun.COM 					 */
13127836SJohn.Forte@Sun.COM 					rw_exit(&irp->irp_lock);
13137836SJohn.Forte@Sun.COM 					rw_exit(&iport->iport_lock);
13147836SJohn.Forte@Sun.COM 				}
13157836SJohn.Forte@Sun.COM 			} else {
13167836SJohn.Forte@Sun.COM 				rw_exit(&irp->irp_lock);
13177836SJohn.Forte@Sun.COM 				rw_exit(&iport->iport_lock);
13187836SJohn.Forte@Sun.COM 				/*
13197836SJohn.Forte@Sun.COM 				 * When we dropped the lock,
13207836SJohn.Forte@Sun.COM 				 * something went in.
13217836SJohn.Forte@Sun.COM 				 */
13227836SJohn.Forte@Sun.COM 				suggested_action |= DISC_ACTION_RESCAN;
13237836SJohn.Forte@Sun.COM 			}
13247836SJohn.Forte@Sun.COM 		}
13257836SJohn.Forte@Sun.COM 		pirp = &(irp->irp_discovery_next);
13267836SJohn.Forte@Sun.COM 		prev_irp = irp;
13277836SJohn.Forte@Sun.COM 	}
13287836SJohn.Forte@Sun.COM 	/* do deregister */
13297836SJohn.Forte@Sun.COM 	if (irp_dereg_list) {
13307836SJohn.Forte@Sun.COM 		fct_i_remote_port_t *irp_next_item;
13317836SJohn.Forte@Sun.COM 		/* drop the lock */
13327836SJohn.Forte@Sun.COM 		mutex_exit(&iport->iport_worker_lock);
13337836SJohn.Forte@Sun.COM 
13347836SJohn.Forte@Sun.COM 		for (irp_cur_item = irp_dereg_list; irp_cur_item != NULL; ) {
13357836SJohn.Forte@Sun.COM 			irp_next_item = irp_cur_item->irp_next;
13367836SJohn.Forte@Sun.COM 			if (fct_deregister_remote_port(iport->iport_port,
13377836SJohn.Forte@Sun.COM 			    irp_cur_item->irp_rp) == FCT_SUCCESS) {
13387836SJohn.Forte@Sun.COM 				fct_free(irp_cur_item->irp_rp);
13397836SJohn.Forte@Sun.COM 			} else if (++irp_cur_item->irp_dereg_count >= 5) {
13407836SJohn.Forte@Sun.COM 				irp_cur_item->irp_deregister_timer = 0;
13417836SJohn.Forte@Sun.COM 				irp_cur_item->irp_dereg_count = 0;
13427836SJohn.Forte@Sun.COM 
13437836SJohn.Forte@Sun.COM 				/*
13447836SJohn.Forte@Sun.COM 				 * It looks like we can't deregister it in the
13457836SJohn.Forte@Sun.COM 				 * normal way, so we have to use extrem way
13467836SJohn.Forte@Sun.COM 				 */
1347*12571SViswanathan.Kannappan@Sun.COM 				(void) snprintf(info, sizeof (info),
13487836SJohn.Forte@Sun.COM 				    "fct_walk_discovery_queue: "
13497836SJohn.Forte@Sun.COM 				    "iport-%p, can't deregister irp-%p after "
13507836SJohn.Forte@Sun.COM 				    "trying 5 times", (void *)iport,
13517836SJohn.Forte@Sun.COM 				    (void *)irp_cur_item);
13527836SJohn.Forte@Sun.COM 				(void) fct_port_shutdown(iport->iport_port,
13537836SJohn.Forte@Sun.COM 				    STMF_RFLAG_FATAL_ERROR |
13547836SJohn.Forte@Sun.COM 				    STMF_RFLAG_RESET, info);
13557836SJohn.Forte@Sun.COM 				suggested_action |= DISC_ACTION_RESCAN;
13567836SJohn.Forte@Sun.COM 				break;
13577836SJohn.Forte@Sun.COM 			} else {
13587836SJohn.Forte@Sun.COM 				/* grab the iport_lock */
13597836SJohn.Forte@Sun.COM 				rw_enter(&iport->iport_lock, RW_WRITER);
13607836SJohn.Forte@Sun.COM 				/* recover */
13617836SJohn.Forte@Sun.COM 				irp_cur_item->irp_deregister_timer =
13627836SJohn.Forte@Sun.COM 				    ddi_get_lbolt() +
13637836SJohn.Forte@Sun.COM 				    drv_usectohz(USEC_DEREG_RP_INTERVAL);
13647836SJohn.Forte@Sun.COM 				fct_post_to_discovery_queue(iport,
13657836SJohn.Forte@Sun.COM 				    irp_cur_item, NULL);
13667836SJohn.Forte@Sun.COM 				fct_queue_rp(iport, irp_cur_item);
13677836SJohn.Forte@Sun.COM 				rw_exit(&iport->iport_lock);
13687836SJohn.Forte@Sun.COM 				suggested_action |= DISC_ACTION_DELAY_RESCAN;
13697836SJohn.Forte@Sun.COM 			}
13707836SJohn.Forte@Sun.COM 			irp_cur_item = irp_next_item;
13717836SJohn.Forte@Sun.COM 		}
13727836SJohn.Forte@Sun.COM 		mutex_enter(&iport->iport_worker_lock);
13737836SJohn.Forte@Sun.COM 	}
13747836SJohn.Forte@Sun.COM 	return (suggested_action);
13757836SJohn.Forte@Sun.COM }
13767836SJohn.Forte@Sun.COM 
13777836SJohn.Forte@Sun.COM disc_action_t
fct_process_plogi(fct_i_cmd_t * icmd)13787836SJohn.Forte@Sun.COM fct_process_plogi(fct_i_cmd_t *icmd)
13797836SJohn.Forte@Sun.COM {
13807836SJohn.Forte@Sun.COM 	fct_cmd_t		*cmd = icmd->icmd_cmd;
13817836SJohn.Forte@Sun.COM 	fct_remote_port_t	*rp = cmd->cmd_rp;
13827836SJohn.Forte@Sun.COM 	fct_local_port_t	*port = cmd->cmd_port;
13837836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
13848585SAllan.Ou@Sun.COM 	    port->port_fct_private;
13857836SJohn.Forte@Sun.COM 	fct_els_t		*els = (fct_els_t *)
13868585SAllan.Ou@Sun.COM 	    cmd->cmd_specific;
13877836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp = (fct_i_remote_port_t *)
13888585SAllan.Ou@Sun.COM 	    rp->rp_fct_private;
13897836SJohn.Forte@Sun.COM 	uint8_t			*p;
13907836SJohn.Forte@Sun.COM 	fct_status_t		 ret;
13917836SJohn.Forte@Sun.COM 	uint8_t			 cmd_type   = cmd->cmd_type;
13927836SJohn.Forte@Sun.COM 	uint32_t		 icmd_flags = icmd->icmd_flags;
13937836SJohn.Forte@Sun.COM 	clock_t			 end_time;
1394*12571SViswanathan.Kannappan@Sun.COM 	char			 info[FCT_INFO_LEN];
13957836SJohn.Forte@Sun.COM 
13969578SSam.Cramer@Sun.COM 	DTRACE_FC_4(rport__login__start,
13979578SSam.Cramer@Sun.COM 	    fct_cmd_t, cmd,
13989578SSam.Cramer@Sun.COM 	    fct_local_port_t, port,
13999578SSam.Cramer@Sun.COM 	    fct_i_remote_port_t, irp,
14009578SSam.Cramer@Sun.COM 	    int, (cmd_type != FCT_CMD_RCVD_ELS));
14019578SSam.Cramer@Sun.COM 
14027836SJohn.Forte@Sun.COM 	/* Drain I/Os */
14037836SJohn.Forte@Sun.COM 	if ((irp->irp_nonfcp_xchg_count + irp->irp_fcp_xchg_count) > 1) {
14047836SJohn.Forte@Sun.COM 		/* Trigger cleanup if necessary */
14057836SJohn.Forte@Sun.COM 		if ((irp->irp_flags & IRP_SESSION_CLEANUP) == 0) {
14067836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "handling PLOGI rp_id"
14077836SJohn.Forte@Sun.COM 			    " %x. Triggering cleanup", cmd->cmd_rportid);
14087836SJohn.Forte@Sun.COM 			/* Cleanup everything except elses */
14097836SJohn.Forte@Sun.COM 			if (fct_trigger_rport_cleanup(irp, ~(cmd->cmd_type))) {
14107836SJohn.Forte@Sun.COM 				atomic_or_32(&irp->irp_flags,
14118585SAllan.Ou@Sun.COM 				    IRP_SESSION_CLEANUP);
14127836SJohn.Forte@Sun.COM 			} else {
14137836SJohn.Forte@Sun.COM 				/* XXX: handle this */
14147836SJohn.Forte@Sun.COM 				/* EMPTY */
14157836SJohn.Forte@Sun.COM 			}
14167836SJohn.Forte@Sun.COM 		}
14177836SJohn.Forte@Sun.COM 
14187836SJohn.Forte@Sun.COM 		end_time = icmd->icmd_start_time +
14197836SJohn.Forte@Sun.COM 		    drv_usectohz(USEC_ELS_TIMEOUT);
14207836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > end_time) {
1421*12571SViswanathan.Kannappan@Sun.COM 			(void) snprintf(info, sizeof (info),
14227836SJohn.Forte@Sun.COM 			    "fct_process_plogi: unable to "
14237836SJohn.Forte@Sun.COM 			    "clean up I/O. iport-%p, icmd-%p", (void *)iport,
14247836SJohn.Forte@Sun.COM 			    (void *)icmd);
14257836SJohn.Forte@Sun.COM 			(void) fct_port_shutdown(iport->iport_port,
14267836SJohn.Forte@Sun.COM 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
14277836SJohn.Forte@Sun.COM 
14287836SJohn.Forte@Sun.COM 			return (DISC_ACTION_DELAY_RESCAN);
14297836SJohn.Forte@Sun.COM 		}
14307836SJohn.Forte@Sun.COM 
14317836SJohn.Forte@Sun.COM 		if ((ddi_get_lbolt() & 0x7f) == 0) {
14327836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "handling"
14338585SAllan.Ou@Sun.COM 			    " PLOGI rp_id %x, waiting for cmds to"
14348585SAllan.Ou@Sun.COM 			    " drain", cmd->cmd_rportid);
14357836SJohn.Forte@Sun.COM 		}
14367836SJohn.Forte@Sun.COM 		return (DISC_ACTION_DELAY_RESCAN);
14377836SJohn.Forte@Sun.COM 	}
14387836SJohn.Forte@Sun.COM 	atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP);
14397836SJohn.Forte@Sun.COM 
14407836SJohn.Forte@Sun.COM 	/* Session can only be terminated after all the I/Os have drained */
14417836SJohn.Forte@Sun.COM 	if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) {
14427836SJohn.Forte@Sun.COM 		stmf_deregister_scsi_session(iport->iport_port->port_lport,
14437836SJohn.Forte@Sun.COM 		    irp->irp_session);
14447836SJohn.Forte@Sun.COM 		stmf_free(irp->irp_session);
14457836SJohn.Forte@Sun.COM 		irp->irp_session = NULL;
14467836SJohn.Forte@Sun.COM 		atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED);
14477836SJohn.Forte@Sun.COM 	}
14487836SJohn.Forte@Sun.COM 
14497836SJohn.Forte@Sun.COM 	if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
14507836SJohn.Forte@Sun.COM 		els->els_resp_size = els->els_req_size;
14517836SJohn.Forte@Sun.COM 		p = els->els_resp_payload = (uint8_t *)kmem_zalloc(
14528585SAllan.Ou@Sun.COM 		    els->els_resp_size, KM_SLEEP);
14537836SJohn.Forte@Sun.COM 		els->els_resp_alloc_size = els->els_resp_size;
14547836SJohn.Forte@Sun.COM 		bcopy(els->els_req_payload, p, els->els_resp_size);
14557836SJohn.Forte@Sun.COM 		p[0] = ELS_OP_ACC;
14567836SJohn.Forte@Sun.COM 		bcopy(p+20, rp->rp_pwwn, 8);
14577836SJohn.Forte@Sun.COM 		bcopy(p+28, rp->rp_nwwn, 8);
14587836SJohn.Forte@Sun.COM 		bcopy(port->port_pwwn, p+20, 8);
14597836SJohn.Forte@Sun.COM 		bcopy(port->port_nwwn, p+28, 8);
14609578SSam.Cramer@Sun.COM 		fct_wwn_to_str(rp->rp_pwwn_str, rp->rp_pwwn);
14619578SSam.Cramer@Sun.COM 		fct_wwn_to_str(rp->rp_nwwn_str, rp->rp_nwwn);
14629578SSam.Cramer@Sun.COM 		fct_wwn_to_str(port->port_pwwn_str, port->port_pwwn);
14639578SSam.Cramer@Sun.COM 		fct_wwn_to_str(port->port_nwwn_str, port->port_nwwn);
14649578SSam.Cramer@Sun.COM 
14657836SJohn.Forte@Sun.COM 		stmf_wwn_to_devid_desc((scsi_devid_desc_t *)irp->irp_id,
14667836SJohn.Forte@Sun.COM 		    rp->rp_pwwn, PROTOCOL_FIBRE_CHANNEL);
14677836SJohn.Forte@Sun.COM 	}
14687836SJohn.Forte@Sun.COM 
14697836SJohn.Forte@Sun.COM 	ret = fct_register_remote_port(port, rp, cmd);
14707836SJohn.Forte@Sun.COM 	fct_dequeue_els(irp);
14717836SJohn.Forte@Sun.COM 	if ((ret == FCT_SUCCESS) && !(icmd->icmd_flags & ICMD_IMPLICIT)) {
14727836SJohn.Forte@Sun.COM 		if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
14737836SJohn.Forte@Sun.COM 			ret = port->port_send_cmd_response(cmd, 0);
14747836SJohn.Forte@Sun.COM 			if ((ret == FCT_SUCCESS) && IPORT_IN_NS_TOPO(iport) &&
14757836SJohn.Forte@Sun.COM 			    !FC_WELL_KNOWN_ADDR(irp->irp_portid)) {
14767836SJohn.Forte@Sun.COM 				fct_cmd_t *ct_cmd = fct_create_solct(port,
14777836SJohn.Forte@Sun.COM 				    rp, NS_GSNN_NN, fct_gsnn_cb);
14787836SJohn.Forte@Sun.COM 				if (ct_cmd) {
14797836SJohn.Forte@Sun.COM 					fct_post_to_solcmd_queue(port, ct_cmd);
14807836SJohn.Forte@Sun.COM 				}
14817836SJohn.Forte@Sun.COM 				ct_cmd = fct_create_solct(port, rp,
14827836SJohn.Forte@Sun.COM 				    NS_GSPN_ID, fct_gspn_cb);
14837836SJohn.Forte@Sun.COM 				if (ct_cmd)
14847836SJohn.Forte@Sun.COM 					fct_post_to_solcmd_queue(port, ct_cmd);
14857836SJohn.Forte@Sun.COM 				ct_cmd = fct_create_solct(port, rp,
14867836SJohn.Forte@Sun.COM 				    NS_GCS_ID, fct_gcs_cb);
14877836SJohn.Forte@Sun.COM 				if (ct_cmd)
14887836SJohn.Forte@Sun.COM 					fct_post_to_solcmd_queue(port, ct_cmd);
14897836SJohn.Forte@Sun.COM 				ct_cmd = fct_create_solct(port, rp,
14907836SJohn.Forte@Sun.COM 				    NS_GFT_ID, fct_gft_cb);
14917836SJohn.Forte@Sun.COM 				if (ct_cmd)
14927836SJohn.Forte@Sun.COM 					fct_post_to_solcmd_queue(port, ct_cmd);
14937836SJohn.Forte@Sun.COM 			}
14947836SJohn.Forte@Sun.COM 		} else {
14957836SJohn.Forte@Sun.COM 			/*
14967836SJohn.Forte@Sun.COM 			 * The reason we set this flag is to prevent
14977836SJohn.Forte@Sun.COM 			 * killing a PRLI while we have not yet processed
14987836SJohn.Forte@Sun.COM 			 * a response to PLOGI. Because the initiator
14997836SJohn.Forte@Sun.COM 			 * will send a PRLI as soon as it responds to PLOGI.
15007836SJohn.Forte@Sun.COM 			 * Check fct_process_els() for more info.
15017836SJohn.Forte@Sun.COM 			 */
15027836SJohn.Forte@Sun.COM 			atomic_or_32(&irp->irp_flags,
15038585SAllan.Ou@Sun.COM 			    IRP_SOL_PLOGI_IN_PROGRESS);
15047836SJohn.Forte@Sun.COM 			atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA);
15057836SJohn.Forte@Sun.COM 			ret = port->port_send_cmd(cmd);
15067836SJohn.Forte@Sun.COM 			if (ret != FCT_SUCCESS) {
15077836SJohn.Forte@Sun.COM 				atomic_and_32(&icmd->icmd_flags,
15087836SJohn.Forte@Sun.COM 				    ~ICMD_KNOWN_TO_FCA);
15097836SJohn.Forte@Sun.COM 				atomic_and_32(&irp->irp_flags,
15108585SAllan.Ou@Sun.COM 				    ~IRP_SOL_PLOGI_IN_PROGRESS);
15117836SJohn.Forte@Sun.COM 			}
15127836SJohn.Forte@Sun.COM 		}
15137836SJohn.Forte@Sun.COM 	}
15147836SJohn.Forte@Sun.COM 	atomic_add_16(&irp->irp_sa_elses_count, -1);
15157836SJohn.Forte@Sun.COM 
15167836SJohn.Forte@Sun.COM 	if (ret == FCT_SUCCESS) {
15177836SJohn.Forte@Sun.COM 		if (cmd_type == FCT_CMD_RCVD_ELS) {
15187836SJohn.Forte@Sun.COM 			atomic_or_32(&irp->irp_flags, IRP_PLOGI_DONE);
15197836SJohn.Forte@Sun.COM 			atomic_add_32(&iport->iport_nrps_login, 1);
15207836SJohn.Forte@Sun.COM 			if (irp->irp_deregister_timer)
15217836SJohn.Forte@Sun.COM 				irp->irp_deregister_timer = 0;
15227836SJohn.Forte@Sun.COM 		}
15237836SJohn.Forte@Sun.COM 		if (icmd_flags & ICMD_IMPLICIT) {
15249578SSam.Cramer@Sun.COM 			DTRACE_FC_5(rport__login__end,
15259578SSam.Cramer@Sun.COM 			    fct_cmd_t, cmd,
15269578SSam.Cramer@Sun.COM 			    fct_local_port_t, port,
15279578SSam.Cramer@Sun.COM 			    fct_i_remote_port_t, irp,
15289578SSam.Cramer@Sun.COM 			    int, (cmd_type != FCT_CMD_RCVD_ELS),
15299578SSam.Cramer@Sun.COM 			    int, FCT_SUCCESS);
15309578SSam.Cramer@Sun.COM 
15317836SJohn.Forte@Sun.COM 			p = els->els_resp_payload;
15327836SJohn.Forte@Sun.COM 			p[0] = ELS_OP_ACC;
15337836SJohn.Forte@Sun.COM 			cmd->cmd_comp_status = FCT_SUCCESS;
15347836SJohn.Forte@Sun.COM 			fct_send_cmd_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE);
15357836SJohn.Forte@Sun.COM 		}
15367836SJohn.Forte@Sun.COM 	} else {
15379578SSam.Cramer@Sun.COM 		DTRACE_FC_5(rport__login__end,
15389578SSam.Cramer@Sun.COM 		    fct_cmd_t, cmd,
15399578SSam.Cramer@Sun.COM 		    fct_local_port_t, port,
15409578SSam.Cramer@Sun.COM 		    fct_i_remote_port_t, irp,
15419578SSam.Cramer@Sun.COM 		    int, (cmd_type != FCT_CMD_RCVD_ELS),
15429578SSam.Cramer@Sun.COM 		    int, ret);
15439578SSam.Cramer@Sun.COM 
15447836SJohn.Forte@Sun.COM 		fct_queue_cmd_for_termination(cmd, ret);
15457836SJohn.Forte@Sun.COM 	}
15467836SJohn.Forte@Sun.COM 
15477836SJohn.Forte@Sun.COM 	/* Do not touch cmd here as it may have been freed */
15487836SJohn.Forte@Sun.COM 
15497836SJohn.Forte@Sun.COM 	return (DISC_ACTION_RESCAN);
15507836SJohn.Forte@Sun.COM }
15517836SJohn.Forte@Sun.COM 
15527836SJohn.Forte@Sun.COM uint8_t fct_prli_temp[] = { 0x20, 0x10, 0, 0x14, 8, 0, 0x20, 0, 0, 0, 0, 0,
15537836SJohn.Forte@Sun.COM 				0, 0, 0, 0 };
15547836SJohn.Forte@Sun.COM 
15557836SJohn.Forte@Sun.COM disc_action_t
fct_process_prli(fct_i_cmd_t * icmd)15567836SJohn.Forte@Sun.COM fct_process_prli(fct_i_cmd_t *icmd)
15577836SJohn.Forte@Sun.COM {
15587836SJohn.Forte@Sun.COM 	fct_cmd_t		*cmd   = icmd->icmd_cmd;
15597836SJohn.Forte@Sun.COM 	fct_remote_port_t	*rp    = cmd->cmd_rp;
15607836SJohn.Forte@Sun.COM 	fct_local_port_t	*port  = cmd->cmd_port;
15617836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
15628585SAllan.Ou@Sun.COM 	    port->port_fct_private;
15637836SJohn.Forte@Sun.COM 	fct_els_t		*els   = (fct_els_t *)
15648585SAllan.Ou@Sun.COM 	    cmd->cmd_specific;
15657836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp   = (fct_i_remote_port_t *)
15668585SAllan.Ou@Sun.COM 	    rp->rp_fct_private;
15677836SJohn.Forte@Sun.COM 	stmf_scsi_session_t	*ses   = NULL;
15687836SJohn.Forte@Sun.COM 	fct_status_t		 ret;
15697836SJohn.Forte@Sun.COM 	clock_t			 end_time;
1570*12571SViswanathan.Kannappan@Sun.COM 	char			 info[FCT_INFO_LEN];
15717836SJohn.Forte@Sun.COM 
15727836SJohn.Forte@Sun.COM 	/* We dont support solicited PRLIs yet */
15737836SJohn.Forte@Sun.COM 	ASSERT(cmd->cmd_type == FCT_CMD_RCVD_ELS);
15747836SJohn.Forte@Sun.COM 
15757836SJohn.Forte@Sun.COM 	if (irp->irp_flags & IRP_SOL_PLOGI_IN_PROGRESS) {
15767836SJohn.Forte@Sun.COM 		/*
15777836SJohn.Forte@Sun.COM 		 * Dont process the PRLI yet. Let the framework process the
15787836SJohn.Forte@Sun.COM 		 * PLOGI completion 1st. This should be very quick because
15797836SJohn.Forte@Sun.COM 		 * the reason we got the PRLI is because the initiator
15807836SJohn.Forte@Sun.COM 		 * has responded to PLOGI already.
15817836SJohn.Forte@Sun.COM 		 */
15827836SJohn.Forte@Sun.COM 		/* XXX: Probably need a timeout here */
15837836SJohn.Forte@Sun.COM 		return (DISC_ACTION_DELAY_RESCAN);
15847836SJohn.Forte@Sun.COM 	}
15857836SJohn.Forte@Sun.COM 	/* The caller has made sure that login is done */
15867836SJohn.Forte@Sun.COM 
15877836SJohn.Forte@Sun.COM 	/* Make sure the process is fcp in this case */
15887836SJohn.Forte@Sun.COM 	if ((els->els_req_size != 20) || (bcmp(els->els_req_payload,
15898585SAllan.Ou@Sun.COM 	    fct_prli_temp, 16))) {
15907836SJohn.Forte@Sun.COM 		if (els->els_req_payload[4] != 0x08)
15917836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "PRLI received from"
15927836SJohn.Forte@Sun.COM 			    " %x for unknown FC-4 type %x", cmd->cmd_rportid,
15938585SAllan.Ou@Sun.COM 			    els->els_req_payload[4]);
15947836SJohn.Forte@Sun.COM 		else
15957836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "Rejecting PRLI from %x "
15967836SJohn.Forte@Sun.COM 			    " pld sz %d, prli_flags %x", cmd->cmd_rportid,
15977836SJohn.Forte@Sun.COM 			    els->els_req_size, els->els_req_payload[6]);
15987836SJohn.Forte@Sun.COM 
15997836SJohn.Forte@Sun.COM 		fct_dequeue_els(irp);
16007836SJohn.Forte@Sun.COM 		atomic_add_16(&irp->irp_sa_elses_count, -1);
16017836SJohn.Forte@Sun.COM 		ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0x2c);
16027836SJohn.Forte@Sun.COM 		goto prli_end;
16037836SJohn.Forte@Sun.COM 	}
16047836SJohn.Forte@Sun.COM 
16057836SJohn.Forte@Sun.COM 	if (irp->irp_fcp_xchg_count) {
16067836SJohn.Forte@Sun.COM 		/* Trigger cleanup if necessary */
16077836SJohn.Forte@Sun.COM 		if ((irp->irp_flags & IRP_FCP_CLEANUP) == 0) {
16087836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "handling PRLI from"
16097836SJohn.Forte@Sun.COM 			    " %x. Triggering cleanup", cmd->cmd_rportid);
16107836SJohn.Forte@Sun.COM 			if (fct_trigger_rport_cleanup(irp, FCT_CMD_FCP_XCHG)) {
16117836SJohn.Forte@Sun.COM 				atomic_or_32(&irp->irp_flags, IRP_FCP_CLEANUP);
16127836SJohn.Forte@Sun.COM 			} else {
16137836SJohn.Forte@Sun.COM 				/* XXX: handle this */
16147836SJohn.Forte@Sun.COM 				/* EMPTY */
16157836SJohn.Forte@Sun.COM 			}
16167836SJohn.Forte@Sun.COM 		}
16177836SJohn.Forte@Sun.COM 
16187836SJohn.Forte@Sun.COM 		end_time = icmd->icmd_start_time +
16197836SJohn.Forte@Sun.COM 		    drv_usectohz(USEC_ELS_TIMEOUT);
16207836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > end_time) {
1621*12571SViswanathan.Kannappan@Sun.COM 			(void) snprintf(info, sizeof (info),
16227836SJohn.Forte@Sun.COM 			    "fct_process_prli: unable to clean "
16237836SJohn.Forte@Sun.COM 			    "up I/O. iport-%p, icmd-%p", (void *)iport,
16247836SJohn.Forte@Sun.COM 			    (void *)icmd);
16257836SJohn.Forte@Sun.COM 			(void) fct_port_shutdown(iport->iport_port,
16267836SJohn.Forte@Sun.COM 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
16277836SJohn.Forte@Sun.COM 
16287836SJohn.Forte@Sun.COM 			return (DISC_ACTION_DELAY_RESCAN);
16297836SJohn.Forte@Sun.COM 		}
16307836SJohn.Forte@Sun.COM 
16317836SJohn.Forte@Sun.COM 		if ((ddi_get_lbolt() & 0x7f) == 0) {
16327836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "handling"
16338585SAllan.Ou@Sun.COM 			    " PRLI from %x, waiting for cmds to"
16348585SAllan.Ou@Sun.COM 			    " drain", cmd->cmd_rportid);
16357836SJohn.Forte@Sun.COM 		}
16367836SJohn.Forte@Sun.COM 		return (DISC_ACTION_DELAY_RESCAN);
16377836SJohn.Forte@Sun.COM 	}
16387836SJohn.Forte@Sun.COM 	atomic_and_32(&irp->irp_flags, ~IRP_FCP_CLEANUP);
16397836SJohn.Forte@Sun.COM 
16407836SJohn.Forte@Sun.COM 	/* Session can only be terminated after all the I/Os have drained */
16417836SJohn.Forte@Sun.COM 	if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) {
16427836SJohn.Forte@Sun.COM 		stmf_deregister_scsi_session(iport->iport_port->port_lport,
16437836SJohn.Forte@Sun.COM 		    irp->irp_session);
16447836SJohn.Forte@Sun.COM 		stmf_free(irp->irp_session);
16457836SJohn.Forte@Sun.COM 		irp->irp_session = NULL;
16467836SJohn.Forte@Sun.COM 		atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED);
16477836SJohn.Forte@Sun.COM 	}
16487836SJohn.Forte@Sun.COM 
16497836SJohn.Forte@Sun.COM 	/* All good, lets start a session */
16507836SJohn.Forte@Sun.COM 	ses = (stmf_scsi_session_t *)stmf_alloc(STMF_STRUCT_SCSI_SESSION, 0, 0);
16517836SJohn.Forte@Sun.COM 	if (ses) {
16527836SJohn.Forte@Sun.COM 		ses->ss_port_private = irp;
16537836SJohn.Forte@Sun.COM 		ses->ss_rport_id = (scsi_devid_desc_t *)irp->irp_id;
16547836SJohn.Forte@Sun.COM 		ses->ss_lport = port->port_lport;
16557836SJohn.Forte@Sun.COM 		if (stmf_register_scsi_session(port->port_lport, ses) !=
16568585SAllan.Ou@Sun.COM 		    STMF_SUCCESS) {
16577836SJohn.Forte@Sun.COM 			stmf_free(ses);
16587836SJohn.Forte@Sun.COM 			ses = NULL;
16597836SJohn.Forte@Sun.COM 		} else {
16607836SJohn.Forte@Sun.COM 			irp->irp_session = ses;
16617836SJohn.Forte@Sun.COM 			irp->irp_session->ss_rport_alias = irp->irp_snn;
16627836SJohn.Forte@Sun.COM 
16637836SJohn.Forte@Sun.COM 			/*
16647836SJohn.Forte@Sun.COM 			 * The reason IRP_SCSI_SESSION_STARTED is different
16657836SJohn.Forte@Sun.COM 			 * from IRP_PRLI_DONE is that we clear IRP_PRLI_DONE
16667836SJohn.Forte@Sun.COM 			 * inside interrupt context. We dont want to deregister
16677836SJohn.Forte@Sun.COM 			 * the session from an interrupt.
16687836SJohn.Forte@Sun.COM 			 */
16697836SJohn.Forte@Sun.COM 			atomic_or_32(&irp->irp_flags, IRP_SCSI_SESSION_STARTED);
16707836SJohn.Forte@Sun.COM 		}
16717836SJohn.Forte@Sun.COM 	}
16727836SJohn.Forte@Sun.COM 
16737836SJohn.Forte@Sun.COM 	fct_dequeue_els(irp);
16747836SJohn.Forte@Sun.COM 	atomic_add_16(&irp->irp_sa_elses_count, -1);
16757836SJohn.Forte@Sun.COM 	if (ses == NULL) {
16767836SJohn.Forte@Sun.COM 		/* fail PRLI */
16777836SJohn.Forte@Sun.COM 		ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0);
16787836SJohn.Forte@Sun.COM 	} else {
16797836SJohn.Forte@Sun.COM 		/* accept PRLI */
16807836SJohn.Forte@Sun.COM 		els->els_resp_payload = (uint8_t *)kmem_zalloc(20, KM_SLEEP);
16817836SJohn.Forte@Sun.COM 		bcopy(fct_prli_temp, els->els_resp_payload, 20);
16827836SJohn.Forte@Sun.COM 		els->els_resp_payload[0] = 2;
16837836SJohn.Forte@Sun.COM 		els->els_resp_payload[6] = 0x21;
16847836SJohn.Forte@Sun.COM 
16857836SJohn.Forte@Sun.COM 		/* XXX the two bytes below need to set as per capabilities */
16867836SJohn.Forte@Sun.COM 		els->els_resp_payload[18] = 0;
16877836SJohn.Forte@Sun.COM 		els->els_resp_payload[19] = 0x12;
16887836SJohn.Forte@Sun.COM 
16897836SJohn.Forte@Sun.COM 		els->els_resp_size = els->els_resp_alloc_size = 20;
16907836SJohn.Forte@Sun.COM 		if ((ret = port->port_send_cmd_response(cmd, 0)) !=
16917836SJohn.Forte@Sun.COM 		    FCT_SUCCESS) {
16927836SJohn.Forte@Sun.COM 			stmf_deregister_scsi_session(port->port_lport, ses);
16937836SJohn.Forte@Sun.COM 			stmf_free(irp->irp_session);
16947836SJohn.Forte@Sun.COM 			irp->irp_session = NULL;
16957836SJohn.Forte@Sun.COM 			atomic_and_32(&irp->irp_flags,
16967836SJohn.Forte@Sun.COM 			    ~IRP_SCSI_SESSION_STARTED);
16977836SJohn.Forte@Sun.COM 		} else {
16987836SJohn.Forte@Sun.COM 			/* Mark that PRLI is done */
16997836SJohn.Forte@Sun.COM 			atomic_or_32(&irp->irp_flags, IRP_PRLI_DONE);
17007836SJohn.Forte@Sun.COM 		}
17017836SJohn.Forte@Sun.COM 	}
17027836SJohn.Forte@Sun.COM 
17037836SJohn.Forte@Sun.COM prli_end:;
17047836SJohn.Forte@Sun.COM 	if (ret != FCT_SUCCESS)
17057836SJohn.Forte@Sun.COM 		fct_queue_cmd_for_termination(cmd, ret);
17067836SJohn.Forte@Sun.COM 
17077836SJohn.Forte@Sun.COM 	return (DISC_ACTION_RESCAN);
17087836SJohn.Forte@Sun.COM }
17097836SJohn.Forte@Sun.COM 
17107836SJohn.Forte@Sun.COM disc_action_t
fct_process_logo(fct_i_cmd_t * icmd)17117836SJohn.Forte@Sun.COM fct_process_logo(fct_i_cmd_t *icmd)
17127836SJohn.Forte@Sun.COM {
17137836SJohn.Forte@Sun.COM 	fct_cmd_t		*cmd   = icmd->icmd_cmd;
17147836SJohn.Forte@Sun.COM 	fct_remote_port_t	*rp    = cmd->cmd_rp;
17157836SJohn.Forte@Sun.COM 	fct_local_port_t	*port  = cmd->cmd_port;
17167836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
17178585SAllan.Ou@Sun.COM 	    port->port_fct_private;
17187836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp   = (fct_i_remote_port_t *)
17198585SAllan.Ou@Sun.COM 	    rp->rp_fct_private;
17207836SJohn.Forte@Sun.COM 	fct_status_t		 ret;
1721*12571SViswanathan.Kannappan@Sun.COM 	char			 info[FCT_INFO_LEN];
17227836SJohn.Forte@Sun.COM 	clock_t			 end_time;
17237836SJohn.Forte@Sun.COM 
17249578SSam.Cramer@Sun.COM 	DTRACE_FC_4(rport__logout__start,
17259578SSam.Cramer@Sun.COM 	    fct_cmd_t, cmd,
17269578SSam.Cramer@Sun.COM 	    fct_local_port_t, port,
17279578SSam.Cramer@Sun.COM 	    fct_i_remote_port_t, irp,
17289578SSam.Cramer@Sun.COM 	    int, (cmd->cmd_type != FCT_CMD_RCVD_ELS));
17299578SSam.Cramer@Sun.COM 
17307836SJohn.Forte@Sun.COM 	/* Drain I/Os */
17317836SJohn.Forte@Sun.COM 	if ((irp->irp_nonfcp_xchg_count + irp->irp_fcp_xchg_count) > 1) {
17327836SJohn.Forte@Sun.COM 		/* Trigger cleanup if necessary */
17337836SJohn.Forte@Sun.COM 		if ((irp->irp_flags & IRP_SESSION_CLEANUP) == 0) {
17347836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "handling LOGO rp_id"
17357836SJohn.Forte@Sun.COM 			    " %x. Triggering cleanup", cmd->cmd_rportid);
17367836SJohn.Forte@Sun.COM 			/* Cleanup everything except elses */
17377836SJohn.Forte@Sun.COM 			if (fct_trigger_rport_cleanup(irp, ~(cmd->cmd_type))) {
17387836SJohn.Forte@Sun.COM 				atomic_or_32(&irp->irp_flags,
17398585SAllan.Ou@Sun.COM 				    IRP_SESSION_CLEANUP);
17407836SJohn.Forte@Sun.COM 			} else {
17417836SJohn.Forte@Sun.COM 				/* XXX: need more handling */
17427836SJohn.Forte@Sun.COM 				return (DISC_ACTION_DELAY_RESCAN);
17437836SJohn.Forte@Sun.COM 			}
17447836SJohn.Forte@Sun.COM 		}
17457836SJohn.Forte@Sun.COM 
17467836SJohn.Forte@Sun.COM 		end_time = icmd->icmd_start_time +
17477836SJohn.Forte@Sun.COM 		    drv_usectohz(USEC_ELS_TIMEOUT);
17487836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > end_time) {
1749*12571SViswanathan.Kannappan@Sun.COM 			(void) snprintf(info, sizeof (info),
17507836SJohn.Forte@Sun.COM 			    "fct_process_logo: unable to clean "
17517836SJohn.Forte@Sun.COM 			    "up I/O. iport-%p, icmd-%p", (void *)iport,
17527836SJohn.Forte@Sun.COM 			    (void *)icmd);
17537836SJohn.Forte@Sun.COM 			(void) fct_port_shutdown(iport->iport_port,
17547836SJohn.Forte@Sun.COM 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
17557836SJohn.Forte@Sun.COM 
17567836SJohn.Forte@Sun.COM 			return (DISC_ACTION_DELAY_RESCAN);
17577836SJohn.Forte@Sun.COM 		}
17587836SJohn.Forte@Sun.COM 
17597836SJohn.Forte@Sun.COM 		if ((ddi_get_lbolt() & 0x7f) == 0) {
17607836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "handling"
17618585SAllan.Ou@Sun.COM 			    " LOGO rp_id %x, waiting for cmds to"
17628585SAllan.Ou@Sun.COM 			    " drain", cmd->cmd_rportid);
17637836SJohn.Forte@Sun.COM 		}
17647836SJohn.Forte@Sun.COM 		return (DISC_ACTION_DELAY_RESCAN);
17657836SJohn.Forte@Sun.COM 	}
17667836SJohn.Forte@Sun.COM 	atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP);
17677836SJohn.Forte@Sun.COM 
17687836SJohn.Forte@Sun.COM 	/* Session can only be terminated after all the I/Os have drained */
17697836SJohn.Forte@Sun.COM 	if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) {
17707836SJohn.Forte@Sun.COM 		stmf_deregister_scsi_session(iport->iport_port->port_lport,
17717836SJohn.Forte@Sun.COM 		    irp->irp_session);
17727836SJohn.Forte@Sun.COM 		stmf_free(irp->irp_session);
17737836SJohn.Forte@Sun.COM 		irp->irp_session = NULL;
17747836SJohn.Forte@Sun.COM 		atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED);
17757836SJohn.Forte@Sun.COM 	}
17767836SJohn.Forte@Sun.COM 
17777836SJohn.Forte@Sun.COM 	fct_dequeue_els(irp);
17787836SJohn.Forte@Sun.COM 	atomic_add_16(&irp->irp_sa_elses_count, -1);
17797836SJohn.Forte@Sun.COM 
17807836SJohn.Forte@Sun.COM 	/* don't send response if this is an implicit logout cmd */
17817836SJohn.Forte@Sun.COM 	if (!(icmd->icmd_flags & ICMD_IMPLICIT)) {
17827836SJohn.Forte@Sun.COM 		if (cmd->cmd_type == FCT_CMD_RCVD_ELS) {
17837836SJohn.Forte@Sun.COM 			ret = fct_send_accrjt(cmd, ELS_OP_ACC, 0, 0);
17847836SJohn.Forte@Sun.COM 		} else {
17857836SJohn.Forte@Sun.COM 			atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA);
17867836SJohn.Forte@Sun.COM 			ret = port->port_send_cmd(cmd);
17877836SJohn.Forte@Sun.COM 			if (ret != FCT_SUCCESS) {
17887836SJohn.Forte@Sun.COM 				atomic_and_32(&icmd->icmd_flags,
17897836SJohn.Forte@Sun.COM 				    ~ICMD_KNOWN_TO_FCA);
17907836SJohn.Forte@Sun.COM 			}
17917836SJohn.Forte@Sun.COM 		}
17927836SJohn.Forte@Sun.COM 
17937836SJohn.Forte@Sun.COM 		if (ret != FCT_SUCCESS) {
17947836SJohn.Forte@Sun.COM 			fct_queue_cmd_for_termination(cmd, ret);
17957836SJohn.Forte@Sun.COM 		}
17969578SSam.Cramer@Sun.COM 
17979578SSam.Cramer@Sun.COM 		DTRACE_FC_4(rport__logout__end,
17989578SSam.Cramer@Sun.COM 		    fct_cmd_t, cmd,
17999578SSam.Cramer@Sun.COM 		    fct_local_port_t, port,
18009578SSam.Cramer@Sun.COM 		    fct_i_remote_port_t, irp,
18019578SSam.Cramer@Sun.COM 		    int, (cmd->cmd_type != FCT_CMD_RCVD_ELS));
18029578SSam.Cramer@Sun.COM 
18037836SJohn.Forte@Sun.COM 	} else {
18049578SSam.Cramer@Sun.COM 		DTRACE_FC_4(rport__logout__end,
18059578SSam.Cramer@Sun.COM 		    fct_cmd_t, cmd,
18069578SSam.Cramer@Sun.COM 		    fct_local_port_t, port,
18079578SSam.Cramer@Sun.COM 		    fct_i_remote_port_t, irp,
18089578SSam.Cramer@Sun.COM 		    int, (cmd->cmd_type != FCT_CMD_RCVD_ELS));
18099578SSam.Cramer@Sun.COM 
18107836SJohn.Forte@Sun.COM 		fct_cmd_free(cmd);
18117836SJohn.Forte@Sun.COM 	}
18127836SJohn.Forte@Sun.COM 
18137836SJohn.Forte@Sun.COM 	irp->irp_deregister_timer = ddi_get_lbolt() +
18148585SAllan.Ou@Sun.COM 	    drv_usectohz(USEC_DEREG_RP_TIMEOUT);
18157836SJohn.Forte@Sun.COM 	irp->irp_dereg_count = 0;
18167836SJohn.Forte@Sun.COM 
18177836SJohn.Forte@Sun.COM 	/* Do not touch cmd here as it may have been freed */
18187836SJohn.Forte@Sun.COM 
18197836SJohn.Forte@Sun.COM 	ASSERT(irp->irp_flags & IRP_IN_DISCOVERY_QUEUE);
18207836SJohn.Forte@Sun.COM 
18217836SJohn.Forte@Sun.COM 	return (DISC_ACTION_RESCAN);
18227836SJohn.Forte@Sun.COM }
18237836SJohn.Forte@Sun.COM 
18247836SJohn.Forte@Sun.COM disc_action_t
fct_process_prlo(fct_i_cmd_t * icmd)18257836SJohn.Forte@Sun.COM fct_process_prlo(fct_i_cmd_t *icmd)
18267836SJohn.Forte@Sun.COM {
18277836SJohn.Forte@Sun.COM 	fct_cmd_t		*cmd   = icmd->icmd_cmd;
18287836SJohn.Forte@Sun.COM 	fct_remote_port_t	*rp    = cmd->cmd_rp;
18297836SJohn.Forte@Sun.COM 	fct_local_port_t	*port  = cmd->cmd_port;
18307836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
18318585SAllan.Ou@Sun.COM 	    port->port_fct_private;
18327836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp   = (fct_i_remote_port_t *)
18338585SAllan.Ou@Sun.COM 	    rp->rp_fct_private;
18347836SJohn.Forte@Sun.COM 	fct_status_t		 ret;
18357836SJohn.Forte@Sun.COM 	clock_t			 end_time;
1836*12571SViswanathan.Kannappan@Sun.COM 	char			 info[FCT_INFO_LEN];
18377836SJohn.Forte@Sun.COM 
18387836SJohn.Forte@Sun.COM 	/* We do not support solicited PRLOs yet */
18397836SJohn.Forte@Sun.COM 	ASSERT(cmd->cmd_type == FCT_CMD_RCVD_ELS);
18407836SJohn.Forte@Sun.COM 
18417836SJohn.Forte@Sun.COM 	/* Drain I/Os */
18427836SJohn.Forte@Sun.COM 	if (irp->irp_fcp_xchg_count) {
18437836SJohn.Forte@Sun.COM 		/* Trigger cleanup if necessary */
18447836SJohn.Forte@Sun.COM 		if ((irp->irp_flags & IRP_FCP_CLEANUP) == 0) {
18457836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "handling LOGO from"
18467836SJohn.Forte@Sun.COM 			    " %x. Triggering cleanup", cmd->cmd_rportid);
18477836SJohn.Forte@Sun.COM 			/* Cleanup everything except elses */
18487836SJohn.Forte@Sun.COM 			if (fct_trigger_rport_cleanup(irp, FCT_CMD_FCP_XCHG)) {
18497836SJohn.Forte@Sun.COM 				atomic_or_32(&irp->irp_flags,
18508585SAllan.Ou@Sun.COM 				    IRP_FCP_CLEANUP);
18517836SJohn.Forte@Sun.COM 			} else {
18527836SJohn.Forte@Sun.COM 				/* XXX: need more handling */
18537836SJohn.Forte@Sun.COM 				return (DISC_ACTION_DELAY_RESCAN);
18547836SJohn.Forte@Sun.COM 			}
18557836SJohn.Forte@Sun.COM 		}
18567836SJohn.Forte@Sun.COM 
18577836SJohn.Forte@Sun.COM 		end_time = icmd->icmd_start_time +
18587836SJohn.Forte@Sun.COM 		    drv_usectohz(USEC_ELS_TIMEOUT);
18597836SJohn.Forte@Sun.COM 		if (ddi_get_lbolt() > end_time) {
1860*12571SViswanathan.Kannappan@Sun.COM 			(void) snprintf(info, sizeof (info),
18617836SJohn.Forte@Sun.COM 			    "fct_process_prlo: unable to "
18627836SJohn.Forte@Sun.COM 			    "clean up I/O. iport-%p, icmd-%p", (void *)iport,
18637836SJohn.Forte@Sun.COM 			    (void *)icmd);
18647836SJohn.Forte@Sun.COM 			(void) fct_port_shutdown(iport->iport_port,
18657836SJohn.Forte@Sun.COM 			    STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
18667836SJohn.Forte@Sun.COM 
18677836SJohn.Forte@Sun.COM 			return (DISC_ACTION_DELAY_RESCAN);
18687836SJohn.Forte@Sun.COM 		}
18697836SJohn.Forte@Sun.COM 
18707836SJohn.Forte@Sun.COM 		if ((ddi_get_lbolt() & 0x7f) == 0) {
18717836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "handling"
18728585SAllan.Ou@Sun.COM 			    " PRLO from %x, waiting for cmds to"
18738585SAllan.Ou@Sun.COM 			    " drain", cmd->cmd_rportid);
18747836SJohn.Forte@Sun.COM 		}
18757836SJohn.Forte@Sun.COM 		return (DISC_ACTION_DELAY_RESCAN);
18767836SJohn.Forte@Sun.COM 	}
18777836SJohn.Forte@Sun.COM 	atomic_and_32(&irp->irp_flags, ~IRP_FCP_CLEANUP);
18787836SJohn.Forte@Sun.COM 
18797836SJohn.Forte@Sun.COM 	/* Session can only be terminated after all the I/Os have drained */
18807836SJohn.Forte@Sun.COM 	if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) {
18817836SJohn.Forte@Sun.COM 		stmf_deregister_scsi_session(iport->iport_port->port_lport,
18827836SJohn.Forte@Sun.COM 		    irp->irp_session);
18837836SJohn.Forte@Sun.COM 		stmf_free(irp->irp_session);
18847836SJohn.Forte@Sun.COM 		irp->irp_session = NULL;
18857836SJohn.Forte@Sun.COM 		atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED);
18867836SJohn.Forte@Sun.COM 	}
18877836SJohn.Forte@Sun.COM 
18887836SJohn.Forte@Sun.COM 	fct_dequeue_els(irp);
18897836SJohn.Forte@Sun.COM 	atomic_add_16(&irp->irp_sa_elses_count, -1);
18907836SJohn.Forte@Sun.COM 	ret = fct_send_accrjt(cmd, ELS_OP_ACC, 0, 0);
18917836SJohn.Forte@Sun.COM 	if (ret != FCT_SUCCESS)
18927836SJohn.Forte@Sun.COM 		fct_queue_cmd_for_termination(cmd, ret);
18937836SJohn.Forte@Sun.COM 
18947836SJohn.Forte@Sun.COM 	return (DISC_ACTION_RESCAN);
18957836SJohn.Forte@Sun.COM }
18967836SJohn.Forte@Sun.COM 
18977836SJohn.Forte@Sun.COM disc_action_t
fct_process_rcvd_adisc(fct_i_cmd_t * icmd)18987836SJohn.Forte@Sun.COM fct_process_rcvd_adisc(fct_i_cmd_t *icmd)
18997836SJohn.Forte@Sun.COM {
19007836SJohn.Forte@Sun.COM 	fct_cmd_t		*cmd = icmd->icmd_cmd;
19017836SJohn.Forte@Sun.COM 	fct_remote_port_t	*rp = cmd->cmd_rp;
19027836SJohn.Forte@Sun.COM 	fct_local_port_t	*port = cmd->cmd_port;
19037836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport = (fct_i_local_port_t *)
19048585SAllan.Ou@Sun.COM 	    port->port_fct_private;
19057836SJohn.Forte@Sun.COM 	fct_els_t		*els = (fct_els_t *)
19068585SAllan.Ou@Sun.COM 	    cmd->cmd_specific;
19077836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp = (fct_i_remote_port_t *)
19088585SAllan.Ou@Sun.COM 	    rp->rp_fct_private;
19097836SJohn.Forte@Sun.COM 	uint8_t			*p;
19107836SJohn.Forte@Sun.COM 	uint32_t		*q;
19117836SJohn.Forte@Sun.COM 	fct_status_t		ret;
19127836SJohn.Forte@Sun.COM 
19137836SJohn.Forte@Sun.COM 	fct_dequeue_els(irp);
19147836SJohn.Forte@Sun.COM 	atomic_add_16(&irp->irp_nsa_elses_count, -1);
19157836SJohn.Forte@Sun.COM 
19167836SJohn.Forte@Sun.COM 	/* Validate the adisc request */
19177836SJohn.Forte@Sun.COM 	p = els->els_req_payload;
19187836SJohn.Forte@Sun.COM 	q = (uint32_t *)p;
19197836SJohn.Forte@Sun.COM 	if ((els->els_req_size != 28) || (bcmp(rp->rp_pwwn, p + 8, 8)) ||
19207836SJohn.Forte@Sun.COM 	    (bcmp(rp->rp_nwwn, p + 16, 8))) {
19217836SJohn.Forte@Sun.COM 		ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0);
19227836SJohn.Forte@Sun.COM 	} else {
19237836SJohn.Forte@Sun.COM 		rp->rp_hard_address = BE_32(q[1]);
19247836SJohn.Forte@Sun.COM 		els->els_resp_size = els->els_resp_alloc_size = 28;
19257836SJohn.Forte@Sun.COM 		els->els_resp_payload = (uint8_t *)kmem_zalloc(28, KM_SLEEP);
19267836SJohn.Forte@Sun.COM 		bcopy(p, els->els_resp_payload, 28);
19277836SJohn.Forte@Sun.COM 		p = els->els_resp_payload;
19287836SJohn.Forte@Sun.COM 		q = (uint32_t *)p;
19297836SJohn.Forte@Sun.COM 		p[0] = ELS_OP_ACC;
19307836SJohn.Forte@Sun.COM 		q[1] = BE_32(port->port_hard_address);
19317836SJohn.Forte@Sun.COM 		bcopy(port->port_pwwn, p + 8, 8);
19327836SJohn.Forte@Sun.COM 		bcopy(port->port_nwwn, p + 16, 8);
19337836SJohn.Forte@Sun.COM 		q[6] = BE_32(iport->iport_link_info.portid);
19347836SJohn.Forte@Sun.COM 		ret = port->port_send_cmd_response(cmd, 0);
19357836SJohn.Forte@Sun.COM 	}
19367836SJohn.Forte@Sun.COM 	if (ret != FCT_SUCCESS) {
19377836SJohn.Forte@Sun.COM 		fct_queue_cmd_for_termination(cmd, ret);
19387836SJohn.Forte@Sun.COM 	}
19397836SJohn.Forte@Sun.COM 
19407836SJohn.Forte@Sun.COM 	return (DISC_ACTION_RESCAN);
19417836SJohn.Forte@Sun.COM }
19427836SJohn.Forte@Sun.COM 
19437836SJohn.Forte@Sun.COM disc_action_t
fct_process_unknown_els(fct_i_cmd_t * icmd)19447836SJohn.Forte@Sun.COM fct_process_unknown_els(fct_i_cmd_t *icmd)
19457836SJohn.Forte@Sun.COM {
19467836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport = ICMD_TO_IPORT(icmd);
19477836SJohn.Forte@Sun.COM 	fct_status_t		 ret   = FCT_FAILURE;
19487836SJohn.Forte@Sun.COM 	uint8_t			 op    = 0;
19497836SJohn.Forte@Sun.COM 
19507836SJohn.Forte@Sun.COM 	ASSERT(icmd->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS);
19517836SJohn.Forte@Sun.COM 	fct_dequeue_els(ICMD_TO_IRP(icmd));
19527836SJohn.Forte@Sun.COM 	atomic_add_16(&ICMD_TO_IRP(icmd)->irp_nsa_elses_count, -1);
19537836SJohn.Forte@Sun.COM 	op = ICMD_TO_ELS(icmd)->els_req_payload[0];
19547836SJohn.Forte@Sun.COM 	stmf_trace(iport->iport_alias, "Rejecting unknown unsol els %x (%s)",
19557836SJohn.Forte@Sun.COM 	    op, FCT_ELS_NAME(op));
19567836SJohn.Forte@Sun.COM 	ret = fct_send_accrjt(icmd->icmd_cmd, ELS_OP_LSRJT, 1, 0);
19577836SJohn.Forte@Sun.COM 	if (ret != FCT_SUCCESS) {
19587836SJohn.Forte@Sun.COM 		fct_queue_cmd_for_termination(icmd->icmd_cmd, ret);
19597836SJohn.Forte@Sun.COM 	}
19607836SJohn.Forte@Sun.COM 
19617836SJohn.Forte@Sun.COM 	return (DISC_ACTION_RESCAN);
19627836SJohn.Forte@Sun.COM }
19637836SJohn.Forte@Sun.COM 
19647836SJohn.Forte@Sun.COM disc_action_t
fct_process_rscn(fct_i_cmd_t * icmd)19657836SJohn.Forte@Sun.COM fct_process_rscn(fct_i_cmd_t *icmd)
19667836SJohn.Forte@Sun.COM {
19677836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport = ICMD_TO_IPORT(icmd);
19687836SJohn.Forte@Sun.COM 	fct_status_t		 ret   = FCT_FAILURE;
19697836SJohn.Forte@Sun.COM 	uint8_t			 op    = 0;
19707836SJohn.Forte@Sun.COM 	uint8_t			*rscn_req_payload;
19717836SJohn.Forte@Sun.COM 	uint32_t		 rscn_req_size;
19727836SJohn.Forte@Sun.COM 
19737836SJohn.Forte@Sun.COM 	fct_dequeue_els(ICMD_TO_IRP(icmd));
19747836SJohn.Forte@Sun.COM 	atomic_add_16(&ICMD_TO_IRP(icmd)->irp_nsa_elses_count, -1);
19757836SJohn.Forte@Sun.COM 	if (icmd->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS) {
19767836SJohn.Forte@Sun.COM 		op = ICMD_TO_ELS(icmd)->els_req_payload[0];
19777836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias, "Accepting RSCN %x (%s)",
19787836SJohn.Forte@Sun.COM 		    op, FCT_ELS_NAME(op));
19797836SJohn.Forte@Sun.COM 		rscn_req_size = ICMD_TO_ELS(icmd)->els_req_size;
19807836SJohn.Forte@Sun.COM 		rscn_req_payload = kmem_alloc(rscn_req_size, KM_SLEEP);
19817836SJohn.Forte@Sun.COM 		bcopy(ICMD_TO_ELS(icmd)->els_req_payload, rscn_req_payload,
19827836SJohn.Forte@Sun.COM 		    rscn_req_size);
19837836SJohn.Forte@Sun.COM 		ret = fct_send_accrjt(icmd->icmd_cmd, ELS_OP_ACC, 1, 0);
19847836SJohn.Forte@Sun.COM 		if (ret != FCT_SUCCESS) {
19857836SJohn.Forte@Sun.COM 			fct_queue_cmd_for_termination(icmd->icmd_cmd, ret);
19867836SJohn.Forte@Sun.COM 		} else {
19877836SJohn.Forte@Sun.COM 			if (fct_rscn_options & RSCN_OPTION_VERIFY) {
19887836SJohn.Forte@Sun.COM 				fct_rscn_verify(iport, rscn_req_payload,
19897836SJohn.Forte@Sun.COM 				    rscn_req_size);
19907836SJohn.Forte@Sun.COM 			}
19917836SJohn.Forte@Sun.COM 		}
19927836SJohn.Forte@Sun.COM 
19937836SJohn.Forte@Sun.COM 		kmem_free(rscn_req_payload, rscn_req_size);
19947836SJohn.Forte@Sun.COM 	} else {
19957836SJohn.Forte@Sun.COM 		ASSERT(0);
19967836SJohn.Forte@Sun.COM 	}
19977836SJohn.Forte@Sun.COM 
19987836SJohn.Forte@Sun.COM 	return (DISC_ACTION_RESCAN);
19997836SJohn.Forte@Sun.COM }
20007836SJohn.Forte@Sun.COM 
20017836SJohn.Forte@Sun.COM disc_action_t
fct_process_els(fct_i_local_port_t * iport,fct_i_remote_port_t * irp)20027836SJohn.Forte@Sun.COM fct_process_els(fct_i_local_port_t *iport, fct_i_remote_port_t *irp)
20037836SJohn.Forte@Sun.COM {
20047836SJohn.Forte@Sun.COM 	fct_i_cmd_t	*cmd_to_abort = NULL;
20057836SJohn.Forte@Sun.COM 	fct_i_cmd_t	**ppcmd, *icmd;
20067836SJohn.Forte@Sun.COM 	fct_cmd_t	*cmd;
20077836SJohn.Forte@Sun.COM 	fct_els_t	*els;
20087836SJohn.Forte@Sun.COM 	int		dq;
20097836SJohn.Forte@Sun.COM 	disc_action_t	ret = DISC_ACTION_NO_WORK;
20107836SJohn.Forte@Sun.COM 	uint8_t		op;
20117836SJohn.Forte@Sun.COM 
20127836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
20137836SJohn.Forte@Sun.COM 
20147836SJohn.Forte@Sun.COM 	/*
20157836SJohn.Forte@Sun.COM 	 * Do some cleanup based on the following.
20167836SJohn.Forte@Sun.COM 	 * - We can only have one session affecting els pending.
20177836SJohn.Forte@Sun.COM 	 * - If any session affecting els is pending no other els is allowed.
20187836SJohn.Forte@Sun.COM 	 * - If PLOGI is not done, nothing except PLOGI or LOGO is allowed.
20197836SJohn.Forte@Sun.COM 	 * NOTE: If port is down the cleanup is done outside of this
20207836SJohn.Forte@Sun.COM 	 *	function.
20217836SJohn.Forte@Sun.COM 	 * NOTE: There is a side effect, if a sa ELS (non PLOGI) is received
20227836SJohn.Forte@Sun.COM 	 * while a PLOGI is pending, it will kill itself and the PLOGI.
20237836SJohn.Forte@Sun.COM 	 * which is probably ok.
20247836SJohn.Forte@Sun.COM 	 */
20257836SJohn.Forte@Sun.COM 	rw_enter(&irp->irp_lock, RW_WRITER);
20267836SJohn.Forte@Sun.COM 	ppcmd = &irp->irp_els_list;
20277836SJohn.Forte@Sun.COM 	while ((*ppcmd) != NULL) {
20287836SJohn.Forte@Sun.COM 		int special_prli_cond = 0;
20297836SJohn.Forte@Sun.COM 		dq = 0;
20307836SJohn.Forte@Sun.COM 
20317836SJohn.Forte@Sun.COM 		els = (fct_els_t *)((*ppcmd)->icmd_cmd)->cmd_specific;
20327836SJohn.Forte@Sun.COM 
20337836SJohn.Forte@Sun.COM 		if (((*ppcmd)->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS) &&
20347836SJohn.Forte@Sun.COM 		    (els->els_req_payload[0] == ELS_OP_PRLI) &&
20357836SJohn.Forte@Sun.COM 		    (irp->irp_flags & IRP_SOL_PLOGI_IN_PROGRESS)) {
20367836SJohn.Forte@Sun.COM 			/*
20377836SJohn.Forte@Sun.COM 			 * The initiator sent a PRLI right after responding
20387836SJohn.Forte@Sun.COM 			 * to PLOGI and we have not yet finished processing
20397836SJohn.Forte@Sun.COM 			 * the PLOGI completion. We should not kill the PRLI
20407836SJohn.Forte@Sun.COM 			 * as the initiator may not retry it.
20417836SJohn.Forte@Sun.COM 			 */
20427836SJohn.Forte@Sun.COM 			special_prli_cond = 1;
20437836SJohn.Forte@Sun.COM 		}
20447836SJohn.Forte@Sun.COM 
20457836SJohn.Forte@Sun.COM 		if ((*ppcmd)->icmd_flags & ICMD_BEING_ABORTED) {
20467836SJohn.Forte@Sun.COM 			dq = 1;
20477979SSumit.Gupta@Sun.COM 		} else if (irp->irp_sa_elses_count > 1) {
20487836SJohn.Forte@Sun.COM 			dq = 1;
20497836SJohn.Forte@Sun.COM 			/* This els might have set the CLEANUP flag */
20507836SJohn.Forte@Sun.COM 			atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP);
20517836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "Killing ELS %x cond 1",
20528585SAllan.Ou@Sun.COM 			    els->els_req_payload[0]);
20537836SJohn.Forte@Sun.COM 		} else if (irp->irp_sa_elses_count &&
20547836SJohn.Forte@Sun.COM 		    (((*ppcmd)->icmd_flags & ICMD_SESSION_AFFECTING) == 0)) {
20557836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "Killing ELS %x cond 2",
20568585SAllan.Ou@Sun.COM 			    els->els_req_payload[0]);
20577836SJohn.Forte@Sun.COM 			dq = 1;
20587836SJohn.Forte@Sun.COM 		} else if (((irp->irp_flags & IRP_PLOGI_DONE) == 0) &&
20597836SJohn.Forte@Sun.COM 		    (els->els_req_payload[0] != ELS_OP_PLOGI) &&
20607836SJohn.Forte@Sun.COM 		    (els->els_req_payload[0] != ELS_OP_LOGO) &&
20617836SJohn.Forte@Sun.COM 		    (special_prli_cond == 0)) {
20627836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "Killing ELS %x cond 3",
20638585SAllan.Ou@Sun.COM 			    els->els_req_payload[0]);
20647836SJohn.Forte@Sun.COM 			dq = 1;
20657836SJohn.Forte@Sun.COM 		}
20667836SJohn.Forte@Sun.COM 
20677836SJohn.Forte@Sun.COM 		if (dq) {
20687836SJohn.Forte@Sun.COM 			fct_i_cmd_t *c = (*ppcmd)->icmd_next;
20697836SJohn.Forte@Sun.COM 
20707836SJohn.Forte@Sun.COM 			if ((*ppcmd)->icmd_flags & ICMD_SESSION_AFFECTING)
20717836SJohn.Forte@Sun.COM 				atomic_add_16(&irp->irp_sa_elses_count, -1);
20727836SJohn.Forte@Sun.COM 			else
20737836SJohn.Forte@Sun.COM 				atomic_add_16(&irp->irp_nsa_elses_count, -1);
20747836SJohn.Forte@Sun.COM 			(*ppcmd)->icmd_next = cmd_to_abort;
20757836SJohn.Forte@Sun.COM 			cmd_to_abort = *ppcmd;
20767836SJohn.Forte@Sun.COM 			*ppcmd = c;
20777836SJohn.Forte@Sun.COM 		} else {
20787836SJohn.Forte@Sun.COM 			ppcmd = &((*ppcmd)->icmd_next);
20797836SJohn.Forte@Sun.COM 		}
20807836SJohn.Forte@Sun.COM 	}
20817836SJohn.Forte@Sun.COM 	rw_exit(&irp->irp_lock);
20827836SJohn.Forte@Sun.COM 
20837836SJohn.Forte@Sun.COM 	while (cmd_to_abort) {
20847836SJohn.Forte@Sun.COM 		fct_i_cmd_t *c = cmd_to_abort->icmd_next;
20857836SJohn.Forte@Sun.COM 
20867836SJohn.Forte@Sun.COM 		atomic_and_32(&cmd_to_abort->icmd_flags, ~ICMD_IN_IRP_QUEUE);
20877836SJohn.Forte@Sun.COM 		fct_queue_cmd_for_termination(cmd_to_abort->icmd_cmd,
20888585SAllan.Ou@Sun.COM 		    FCT_ABORTED);
20897836SJohn.Forte@Sun.COM 		cmd_to_abort = c;
20907836SJohn.Forte@Sun.COM 	}
20917836SJohn.Forte@Sun.COM 
20927836SJohn.Forte@Sun.COM 	/*
20937836SJohn.Forte@Sun.COM 	 * pick from the top of the queue
20947836SJohn.Forte@Sun.COM 	 */
20957836SJohn.Forte@Sun.COM 	icmd = irp->irp_els_list;
20967836SJohn.Forte@Sun.COM 	if (icmd == NULL) {
20977836SJohn.Forte@Sun.COM 		/*
20987836SJohn.Forte@Sun.COM 		 * The cleanup took care of everything.
20997836SJohn.Forte@Sun.COM 		 */
21007836SJohn.Forte@Sun.COM 
21017836SJohn.Forte@Sun.COM 		mutex_enter(&iport->iport_worker_lock);
21027836SJohn.Forte@Sun.COM 		return (DISC_ACTION_RESCAN);
21037836SJohn.Forte@Sun.COM 	}
21047836SJohn.Forte@Sun.COM 
21057836SJohn.Forte@Sun.COM 	cmd = icmd->icmd_cmd;
21067836SJohn.Forte@Sun.COM 	els = ICMD_TO_ELS(icmd);
21077836SJohn.Forte@Sun.COM 	op = els->els_req_payload[0];
21087836SJohn.Forte@Sun.COM 	if ((icmd->icmd_flags & ICMD_ELS_PROCESSING_STARTED) == 0) {
21097836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias, "Processing %ssol ELS %x (%s) "
21107836SJohn.Forte@Sun.COM 		    "rp_id=%x", (cmd->cmd_type == FCT_CMD_RCVD_ELS) ? "un" : "",
21117836SJohn.Forte@Sun.COM 		    op, FCT_ELS_NAME(op), cmd->cmd_rportid);
21127836SJohn.Forte@Sun.COM 		atomic_or_32(&icmd->icmd_flags, ICMD_ELS_PROCESSING_STARTED);
21137836SJohn.Forte@Sun.COM 	}
21147836SJohn.Forte@Sun.COM 
21157836SJohn.Forte@Sun.COM 	if (op == ELS_OP_PLOGI) {
21167836SJohn.Forte@Sun.COM 		ret |= fct_process_plogi(icmd);
21177836SJohn.Forte@Sun.COM 	} else if (op == ELS_OP_PRLI) {
21187836SJohn.Forte@Sun.COM 		ret |= fct_process_prli(icmd);
21197836SJohn.Forte@Sun.COM 	} else if (op == ELS_OP_LOGO) {
21207836SJohn.Forte@Sun.COM 		ret |= fct_process_logo(icmd);
21217836SJohn.Forte@Sun.COM 	} else if ((op == ELS_OP_PRLO) || (op == ELS_OP_TPRLO)) {
21227836SJohn.Forte@Sun.COM 		ret |= fct_process_prlo(icmd);
21237836SJohn.Forte@Sun.COM 	} else if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
21247836SJohn.Forte@Sun.COM 		fct_status_t s;
21257836SJohn.Forte@Sun.COM 		fct_local_port_t *port = iport->iport_port;
21267836SJohn.Forte@Sun.COM 
21277836SJohn.Forte@Sun.COM 		fct_dequeue_els(irp);
21287836SJohn.Forte@Sun.COM 		atomic_add_16(&irp->irp_nsa_elses_count, -1);
21297836SJohn.Forte@Sun.COM 		atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA);
21307836SJohn.Forte@Sun.COM 		if ((s = port->port_send_cmd(cmd)) != FCT_SUCCESS) {
21317836SJohn.Forte@Sun.COM 			atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA);
21327836SJohn.Forte@Sun.COM 			fct_queue_cmd_for_termination(cmd, s);
21337836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias, "Solicited els "
21347836SJohn.Forte@Sun.COM 			    "transport failed, ret = %llx", s);
21357836SJohn.Forte@Sun.COM 		}
21367836SJohn.Forte@Sun.COM 	} else if (op == ELS_OP_ADISC) {
21377836SJohn.Forte@Sun.COM 		ret |= fct_process_rcvd_adisc(icmd);
21387836SJohn.Forte@Sun.COM 	} else if (op == ELS_OP_RSCN) {
21397836SJohn.Forte@Sun.COM 		(void) fct_process_rscn(icmd);
21407836SJohn.Forte@Sun.COM 	} else {
21417836SJohn.Forte@Sun.COM 		(void) fct_process_unknown_els(icmd);
21427836SJohn.Forte@Sun.COM 	}
21437836SJohn.Forte@Sun.COM 
21447836SJohn.Forte@Sun.COM 	/*
21457836SJohn.Forte@Sun.COM 	 * This if condition will be false if a sa ELS trigged a cleanup
21467836SJohn.Forte@Sun.COM 	 * and set the ret = DISC_ACTION_DELAY_RESCAN. In that case we should
21477836SJohn.Forte@Sun.COM 	 * keep it that way.
21487836SJohn.Forte@Sun.COM 	 */
21497836SJohn.Forte@Sun.COM 	if (ret == DISC_ACTION_NO_WORK) {
21507836SJohn.Forte@Sun.COM 		/*
21517836SJohn.Forte@Sun.COM 		 * Since we dropped the lock, we will force a rescan. The
21527836SJohn.Forte@Sun.COM 		 * only exception is if someone returned
21537836SJohn.Forte@Sun.COM 		 * DISC_ACTION_DELAY_RESCAN, in which case that should be the
21547836SJohn.Forte@Sun.COM 		 * return value.
21557836SJohn.Forte@Sun.COM 		 */
21567836SJohn.Forte@Sun.COM 		ret = DISC_ACTION_RESCAN;
21577836SJohn.Forte@Sun.COM 	}
21587836SJohn.Forte@Sun.COM 
21597836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
21607836SJohn.Forte@Sun.COM 	return (ret);
21617836SJohn.Forte@Sun.COM }
21627836SJohn.Forte@Sun.COM 
21637836SJohn.Forte@Sun.COM void
fct_handle_sol_els_completion(fct_i_local_port_t * iport,fct_i_cmd_t * icmd)21647836SJohn.Forte@Sun.COM fct_handle_sol_els_completion(fct_i_local_port_t *iport, fct_i_cmd_t *icmd)
21657836SJohn.Forte@Sun.COM {
21667836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp = NULL;
21677836SJohn.Forte@Sun.COM 	fct_els_t		*els = ICMD_TO_ELS(icmd);
21687836SJohn.Forte@Sun.COM 	uint8_t			 op  = els->els_req_payload[0];
21697836SJohn.Forte@Sun.COM 
21707836SJohn.Forte@Sun.COM 	if (icmd->icmd_cmd->cmd_rp) {
21717836SJohn.Forte@Sun.COM 		irp = ICMD_TO_IRP(icmd);
21727836SJohn.Forte@Sun.COM 	}
21737836SJohn.Forte@Sun.COM 	if (icmd->icmd_cmd->cmd_rp &&
21747836SJohn.Forte@Sun.COM 	    (icmd->icmd_cmd->cmd_comp_status == FCT_SUCCESS) &&
21757836SJohn.Forte@Sun.COM 	    (els->els_req_payload[0] == ELS_OP_PLOGI)) {
21767836SJohn.Forte@Sun.COM 		bcopy(els->els_resp_payload + 20, irp->irp_rp->rp_pwwn, 8);
21777836SJohn.Forte@Sun.COM 		bcopy(els->els_resp_payload + 28, irp->irp_rp->rp_nwwn, 8);
21787836SJohn.Forte@Sun.COM 
21797836SJohn.Forte@Sun.COM 		stmf_wwn_to_devid_desc((scsi_devid_desc_t *)irp->irp_id,
21807836SJohn.Forte@Sun.COM 		    irp->irp_rp->rp_pwwn, PROTOCOL_FIBRE_CHANNEL);
21817836SJohn.Forte@Sun.COM 		atomic_or_32(&irp->irp_flags, IRP_PLOGI_DONE);
21827836SJohn.Forte@Sun.COM 		atomic_add_32(&iport->iport_nrps_login, 1);
21837836SJohn.Forte@Sun.COM 		if (irp->irp_deregister_timer) {
21847836SJohn.Forte@Sun.COM 			irp->irp_deregister_timer = 0;
21857836SJohn.Forte@Sun.COM 			irp->irp_dereg_count = 0;
21867836SJohn.Forte@Sun.COM 		}
21877836SJohn.Forte@Sun.COM 	}
21887836SJohn.Forte@Sun.COM 
21897836SJohn.Forte@Sun.COM 	if (irp && (els->els_req_payload[0] == ELS_OP_PLOGI)) {
21907836SJohn.Forte@Sun.COM 		atomic_and_32(&irp->irp_flags, ~IRP_SOL_PLOGI_IN_PROGRESS);
21917836SJohn.Forte@Sun.COM 	}
21927836SJohn.Forte@Sun.COM 	atomic_or_32(&icmd->icmd_flags, ICMD_CMD_COMPLETE);
21937836SJohn.Forte@Sun.COM 	stmf_trace(iport->iport_alias, "Sol ELS %x (%s) completed with "
21947836SJohn.Forte@Sun.COM 	    "status %llx, did/%x", op, FCT_ELS_NAME(op),
21957836SJohn.Forte@Sun.COM 	    icmd->icmd_cmd->cmd_comp_status, icmd->icmd_cmd->cmd_rportid);
21967836SJohn.Forte@Sun.COM }
21977836SJohn.Forte@Sun.COM 
21987836SJohn.Forte@Sun.COM static disc_action_t
fct_check_cmdlist(fct_i_local_port_t * iport)21997836SJohn.Forte@Sun.COM fct_check_cmdlist(fct_i_local_port_t *iport)
22007836SJohn.Forte@Sun.COM {
22017836SJohn.Forte@Sun.COM 	int		num_to_release, ndx;
22027836SJohn.Forte@Sun.COM 	fct_i_cmd_t	*icmd;
22037836SJohn.Forte@Sun.COM 	uint32_t	total, max_active;
22047836SJohn.Forte@Sun.COM 
22057836SJohn.Forte@Sun.COM 	ASSERT(MUTEX_HELD(&iport->iport_worker_lock));
22067836SJohn.Forte@Sun.COM 
22077836SJohn.Forte@Sun.COM 	total = iport->iport_total_alloced_ncmds;
22087836SJohn.Forte@Sun.COM 	max_active = iport->iport_max_active_ncmds;
22097836SJohn.Forte@Sun.COM 
22107836SJohn.Forte@Sun.COM 	if (total <= max_active)
22117836SJohn.Forte@Sun.COM 		return (DISC_ACTION_NO_WORK);
22127836SJohn.Forte@Sun.COM 	/*
22137836SJohn.Forte@Sun.COM 	 * Everytime, we release half of the difference
22147836SJohn.Forte@Sun.COM 	 */
22157836SJohn.Forte@Sun.COM 	num_to_release = (total + 1 - max_active) / 2;
22167836SJohn.Forte@Sun.COM 
22177836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
22187836SJohn.Forte@Sun.COM 	for (ndx = 0; ndx < num_to_release; ndx++) {
22197836SJohn.Forte@Sun.COM 		mutex_enter(&iport->iport_cached_cmd_lock);
22207836SJohn.Forte@Sun.COM 		icmd = iport->iport_cached_cmdlist;
22217836SJohn.Forte@Sun.COM 		if (icmd == NULL) {
22227836SJohn.Forte@Sun.COM 			mutex_exit(&iport->iport_cached_cmd_lock);
22237836SJohn.Forte@Sun.COM 			break;
22247836SJohn.Forte@Sun.COM 		}
22257836SJohn.Forte@Sun.COM 		iport->iport_cached_cmdlist = icmd->icmd_next;
22267836SJohn.Forte@Sun.COM 		iport->iport_cached_ncmds--;
22277836SJohn.Forte@Sun.COM 		mutex_exit(&iport->iport_cached_cmd_lock);
22287836SJohn.Forte@Sun.COM 		atomic_add_32(&iport->iport_total_alloced_ncmds, -1);
22297836SJohn.Forte@Sun.COM 		fct_free(icmd->icmd_cmd);
22307836SJohn.Forte@Sun.COM 	}
22317836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
22327836SJohn.Forte@Sun.COM 	return (DISC_ACTION_RESCAN);
22337836SJohn.Forte@Sun.COM }
22347836SJohn.Forte@Sun.COM 
22357836SJohn.Forte@Sun.COM /*
22367836SJohn.Forte@Sun.COM  * The efficiency of handling solicited commands is very low here. But
22377836SJohn.Forte@Sun.COM  * fortunately, we seldom send solicited commands. So it will not hurt
22387836SJohn.Forte@Sun.COM  * the system performance much.
22397836SJohn.Forte@Sun.COM  */
22407836SJohn.Forte@Sun.COM static disc_action_t
fct_check_solcmd_queue(fct_i_local_port_t * iport)22417836SJohn.Forte@Sun.COM fct_check_solcmd_queue(fct_i_local_port_t *iport)
22427836SJohn.Forte@Sun.COM {
22437836SJohn.Forte@Sun.COM 	fct_i_cmd_t	*icmd	    = NULL;
22447836SJohn.Forte@Sun.COM 	fct_i_cmd_t	*prev_icmd  = NULL;
22457836SJohn.Forte@Sun.COM 	fct_i_cmd_t	*next_icmd  = NULL;
22467836SJohn.Forte@Sun.COM 
22477836SJohn.Forte@Sun.COM 	ASSERT(mutex_owned(&iport->iport_worker_lock));
22487836SJohn.Forte@Sun.COM 	for (icmd = iport->iport_solcmd_queue; icmd; icmd = next_icmd) {
22497836SJohn.Forte@Sun.COM 		ASSERT(icmd->icmd_flags | ICMD_IN_SOLCMD_QUEUE);
22507836SJohn.Forte@Sun.COM 		next_icmd = icmd->icmd_solcmd_next;
22517836SJohn.Forte@Sun.COM 		if (icmd->icmd_flags & ICMD_SOLCMD_NEW) {
22527836SJohn.Forte@Sun.COM 			/*
22537836SJohn.Forte@Sun.COM 			 * This solicited cmd is new.
22547836SJohn.Forte@Sun.COM 			 * Dispatch ELSes to discovery queue to make use of
22557836SJohn.Forte@Sun.COM 			 * existent framework.
22567836SJohn.Forte@Sun.COM 			 */
22577836SJohn.Forte@Sun.COM 			icmd->icmd_flags &= ~ICMD_SOLCMD_NEW;
22587836SJohn.Forte@Sun.COM 			mutex_exit(&iport->iport_worker_lock);
22597836SJohn.Forte@Sun.COM 
22607836SJohn.Forte@Sun.COM 			if (icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_ELS) {
22617836SJohn.Forte@Sun.COM 				fct_handle_els(icmd->icmd_cmd);
22627836SJohn.Forte@Sun.COM 			} else {
22637836SJohn.Forte@Sun.COM 				fct_handle_solct(icmd->icmd_cmd);
22647836SJohn.Forte@Sun.COM 			}
22657836SJohn.Forte@Sun.COM 
22667836SJohn.Forte@Sun.COM 			mutex_enter(&iport->iport_worker_lock);
22677836SJohn.Forte@Sun.COM 		} else if (icmd->icmd_flags & ICMD_CMD_COMPLETE) {
22687836SJohn.Forte@Sun.COM 			/*
22697836SJohn.Forte@Sun.COM 			 * To make fct_check_solcmd simple and flexible,
22707836SJohn.Forte@Sun.COM 			 * We need only call callback to finish post-handling.
22717836SJohn.Forte@Sun.COM 			 */
22727836SJohn.Forte@Sun.COM 			if (icmd->icmd_cb) {
22737836SJohn.Forte@Sun.COM 				/*
22747836SJohn.Forte@Sun.COM 				 * mutex ???
22757836SJohn.Forte@Sun.COM 				 */
22767836SJohn.Forte@Sun.COM 				icmd->icmd_cb(icmd);
22777836SJohn.Forte@Sun.COM 			}
22787836SJohn.Forte@Sun.COM 
22797836SJohn.Forte@Sun.COM 
22807836SJohn.Forte@Sun.COM 			/*
22817836SJohn.Forte@Sun.COM 			 * Release resources for this solicited cmd
22827836SJohn.Forte@Sun.COM 			 */
22837836SJohn.Forte@Sun.COM 			if (iport->iport_solcmd_queue == icmd) {
22847836SJohn.Forte@Sun.COM 				iport->iport_solcmd_queue = next_icmd;
22857836SJohn.Forte@Sun.COM 			} else {
22868585SAllan.Ou@Sun.COM 				prev_icmd = iport->iport_solcmd_queue;
22878585SAllan.Ou@Sun.COM 				while (prev_icmd->icmd_solcmd_next != icmd) {
22888585SAllan.Ou@Sun.COM 					prev_icmd = prev_icmd->icmd_solcmd_next;
22898585SAllan.Ou@Sun.COM 				}
22907836SJohn.Forte@Sun.COM 				prev_icmd->icmd_solcmd_next = next_icmd;
22917836SJohn.Forte@Sun.COM 			}
22927836SJohn.Forte@Sun.COM 
22937836SJohn.Forte@Sun.COM 			icmd->icmd_cb = NULL;
22947836SJohn.Forte@Sun.COM 			mutex_exit(&iport->iport_worker_lock);
22957836SJohn.Forte@Sun.COM 			fct_cmd_free(icmd->icmd_cmd);
22967836SJohn.Forte@Sun.COM 			mutex_enter(&iport->iport_worker_lock);
22977836SJohn.Forte@Sun.COM 		} else {
22987836SJohn.Forte@Sun.COM 			/*
22997836SJohn.Forte@Sun.COM 			 * This solicited cmd is still ongoing.
23007836SJohn.Forte@Sun.COM 			 * We need check if it's time to abort this cmd
23017836SJohn.Forte@Sun.COM 			 */
23027836SJohn.Forte@Sun.COM 			if (((icmd->icmd_start_time + drv_usectohz(
23037836SJohn.Forte@Sun.COM 			    USEC_SOL_TIMEOUT)) < ddi_get_lbolt()) &&
23047836SJohn.Forte@Sun.COM 			    !(icmd->icmd_flags & ICMD_BEING_ABORTED)) {
23057836SJohn.Forte@Sun.COM 				fct_q_for_termination_lock_held(iport,
23067836SJohn.Forte@Sun.COM 				    icmd, FCT_ABORTED);
23077836SJohn.Forte@Sun.COM 			}
23087836SJohn.Forte@Sun.COM 		}
23097836SJohn.Forte@Sun.COM 	}
23107836SJohn.Forte@Sun.COM 
23117836SJohn.Forte@Sun.COM 	return (DISC_ACTION_DELAY_RESCAN);
23127836SJohn.Forte@Sun.COM }
23137836SJohn.Forte@Sun.COM 
23147836SJohn.Forte@Sun.COM void
fct_handle_solct(fct_cmd_t * cmd)23157836SJohn.Forte@Sun.COM fct_handle_solct(fct_cmd_t *cmd)
23167836SJohn.Forte@Sun.COM {
23177836SJohn.Forte@Sun.COM 	fct_status_t		 ret	  = FCT_SUCCESS;
23187836SJohn.Forte@Sun.COM 	fct_i_cmd_t		*icmd	  = CMD_TO_ICMD(cmd);
23197836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport	  = ICMD_TO_IPORT(icmd);
23207836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp	  = ICMD_TO_IRP(icmd);
23217836SJohn.Forte@Sun.COM 
23227836SJohn.Forte@Sun.COM 	ASSERT(cmd->cmd_type == FCT_CMD_SOL_CT);
23237836SJohn.Forte@Sun.COM 	rw_enter(&iport->iport_lock, RW_READER);
23247836SJohn.Forte@Sun.COM 	/*
23257836SJohn.Forte@Sun.COM 	 * Let's make sure local port is sane
23267836SJohn.Forte@Sun.COM 	 */
23277836SJohn.Forte@Sun.COM 	if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
23287836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
23297836SJohn.Forte@Sun.COM 
23307836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias, "fct_transport_solct: "
23317836SJohn.Forte@Sun.COM 		    "solcmd-%p transport failed, becasue port state was %x",
23327836SJohn.Forte@Sun.COM 		    cmd, iport->iport_link_state);
23337836SJohn.Forte@Sun.COM 		fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE);
23347836SJohn.Forte@Sun.COM 		return;
23357836SJohn.Forte@Sun.COM 	}
23367836SJohn.Forte@Sun.COM 
23377836SJohn.Forte@Sun.COM 	/*
23387836SJohn.Forte@Sun.COM 	 * Let's make sure we have plogi-ed to name server
23397836SJohn.Forte@Sun.COM 	 */
23407836SJohn.Forte@Sun.COM 	rw_enter(&irp->irp_lock, RW_READER);
23417836SJohn.Forte@Sun.COM 	if (!(irp->irp_flags & IRP_PLOGI_DONE)) {
23427836SJohn.Forte@Sun.COM 		rw_exit(&irp->irp_lock);
23437836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
23447836SJohn.Forte@Sun.COM 
23457836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias, "fct_transport_solct: "
23467836SJohn.Forte@Sun.COM 		    "Must login to name server first - cmd-%p", cmd);
23477836SJohn.Forte@Sun.COM 		fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN);
23487836SJohn.Forte@Sun.COM 		return;
23497836SJohn.Forte@Sun.COM 	}
23507836SJohn.Forte@Sun.COM 
23517836SJohn.Forte@Sun.COM 	/*
23527836SJohn.Forte@Sun.COM 	 * Let's get a slot for this solcmd
23537836SJohn.Forte@Sun.COM 	 */
23547836SJohn.Forte@Sun.COM 	if (fct_alloc_cmd_slot(iport, cmd) == FCT_SLOT_EOL) {
23557836SJohn.Forte@Sun.COM 		rw_exit(&irp->irp_lock);
23567836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
23577836SJohn.Forte@Sun.COM 
23587836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias, "fct_transport_solcmd: "
23597836SJohn.Forte@Sun.COM 		    "ran out of xchg resources - cmd-%p", cmd);
23607836SJohn.Forte@Sun.COM 		fct_queue_cmd_for_termination(cmd, FCT_NO_XCHG_RESOURCE);
23617836SJohn.Forte@Sun.COM 		return;
23627836SJohn.Forte@Sun.COM 	}
23637836SJohn.Forte@Sun.COM 
23647836SJohn.Forte@Sun.COM 	if (fct_netbuf_to_value(ICMD_TO_CT(icmd)->ct_req_payload + 8, 2) ==
23657836SJohn.Forte@Sun.COM 	    NS_GID_PN) {
23667836SJohn.Forte@Sun.COM 		fct_i_remote_port_t	*query_irp = NULL;
23677836SJohn.Forte@Sun.COM 
23687836SJohn.Forte@Sun.COM 		query_irp = fct_lookup_irp_by_portwwn(iport,
23697836SJohn.Forte@Sun.COM 		    ICMD_TO_CT(icmd)->ct_req_payload + 16);
23707836SJohn.Forte@Sun.COM 		if (query_irp) {
23717836SJohn.Forte@Sun.COM 			atomic_and_32(&query_irp->irp_flags, ~IRP_RSCN_QUEUED);
23727836SJohn.Forte@Sun.COM 		}
23737836SJohn.Forte@Sun.COM 	}
23747836SJohn.Forte@Sun.COM 	rw_exit(&irp->irp_lock);
23757836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
23767836SJohn.Forte@Sun.COM 
23777836SJohn.Forte@Sun.COM 	atomic_add_16(&irp->irp_nonfcp_xchg_count, 1);
23787836SJohn.Forte@Sun.COM 	atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA);
23797836SJohn.Forte@Sun.COM 	icmd->icmd_start_time = ddi_get_lbolt();
23807836SJohn.Forte@Sun.COM 	ret = iport->iport_port->port_send_cmd(cmd);
23817836SJohn.Forte@Sun.COM 	if (ret != FCT_SUCCESS) {
23827836SJohn.Forte@Sun.COM 		atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA);
23837836SJohn.Forte@Sun.COM 		fct_queue_cmd_for_termination(cmd, ret);
23847836SJohn.Forte@Sun.COM 	}
23857836SJohn.Forte@Sun.COM }
23867836SJohn.Forte@Sun.COM 
23877836SJohn.Forte@Sun.COM void
fct_logo_cb(fct_i_cmd_t * icmd)23887836SJohn.Forte@Sun.COM fct_logo_cb(fct_i_cmd_t *icmd)
23897836SJohn.Forte@Sun.COM {
23907836SJohn.Forte@Sun.COM 	ASSERT(!(icmd->icmd_flags & ICMD_IMPLICIT));
23917836SJohn.Forte@Sun.COM 	if (!FCT_IS_ELS_ACC(icmd)) {
23927836SJohn.Forte@Sun.COM 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_logo_cb: "
23937836SJohn.Forte@Sun.COM 		    "solicited LOGO is not accepted - icmd/%p", icmd);
23947836SJohn.Forte@Sun.COM 	}
23957836SJohn.Forte@Sun.COM }
23967836SJohn.Forte@Sun.COM 
23977836SJohn.Forte@Sun.COM void
fct_gsnn_cb(fct_i_cmd_t * icmd)23987836SJohn.Forte@Sun.COM fct_gsnn_cb(fct_i_cmd_t *icmd)
23997836SJohn.Forte@Sun.COM {
24007836SJohn.Forte@Sun.COM 	int			 snlen	   = 0;
24017836SJohn.Forte@Sun.COM 	char			*sn	   = NULL;
24027836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*query_irp = NULL;
24037836SJohn.Forte@Sun.COM 
24047836SJohn.Forte@Sun.COM 	if (!FCT_IS_CT_ACC(icmd)) {
24057836SJohn.Forte@Sun.COM 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: "
24067836SJohn.Forte@Sun.COM 		    "GSNN is not accepted by NS - icmd/%p", icmd);
24077836SJohn.Forte@Sun.COM 		return;
24087836SJohn.Forte@Sun.COM 	}
24097836SJohn.Forte@Sun.COM 	mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
24107836SJohn.Forte@Sun.COM 
24117836SJohn.Forte@Sun.COM 	rw_enter(&ICMD_TO_IPORT(icmd)->iport_lock, RW_READER);
24127836SJohn.Forte@Sun.COM 	mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
24137836SJohn.Forte@Sun.COM 	query_irp = fct_lookup_irp_by_nodewwn(ICMD_TO_IPORT(icmd),
24147836SJohn.Forte@Sun.COM 	    ICMD_TO_CT(icmd)->ct_req_payload + 16);
24157836SJohn.Forte@Sun.COM 
24167836SJohn.Forte@Sun.COM 	if (!query_irp) {
24177836SJohn.Forte@Sun.COM 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: "
24187836SJohn.Forte@Sun.COM 		    "can't get rp icmd-%p", icmd);
24197836SJohn.Forte@Sun.COM 		goto exit_gsnn_cb;
24207836SJohn.Forte@Sun.COM 	} else {
24217836SJohn.Forte@Sun.COM 		snlen = ICMD_TO_CT(icmd)->ct_resp_payload[16];
24227836SJohn.Forte@Sun.COM 	}
24237836SJohn.Forte@Sun.COM 
24247836SJohn.Forte@Sun.COM 	if (query_irp && snlen) {
24257836SJohn.Forte@Sun.COM 		/*
24267836SJohn.Forte@Sun.COM 		 * Release previous resource, then allocate needed resource
24277836SJohn.Forte@Sun.COM 		 */
24287836SJohn.Forte@Sun.COM 		sn = query_irp->irp_snn;
24297836SJohn.Forte@Sun.COM 		if (sn) {
24307836SJohn.Forte@Sun.COM 			kmem_free(sn, strlen(sn) + 1);
24317836SJohn.Forte@Sun.COM 		}
24327836SJohn.Forte@Sun.COM 
24337836SJohn.Forte@Sun.COM 		query_irp->irp_snn = NULL;
24347836SJohn.Forte@Sun.COM 		sn = kmem_zalloc(snlen + 1, KM_SLEEP);
24357836SJohn.Forte@Sun.COM 		(void) strncpy(sn, (char *)
24367836SJohn.Forte@Sun.COM 		    ICMD_TO_CT(icmd)->ct_resp_payload + 17, snlen);
24377836SJohn.Forte@Sun.COM 		if (strlen(sn) != snlen) {
24387836SJohn.Forte@Sun.COM 			stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias,
24397836SJohn.Forte@Sun.COM 			    "fct_gsnn_cb: %s, but len=%d", sn, snlen);
24407836SJohn.Forte@Sun.COM 			kmem_free(sn, snlen + 1);
24417836SJohn.Forte@Sun.COM 			sn = NULL;
24427836SJohn.Forte@Sun.COM 		}
24437836SJohn.Forte@Sun.COM 
24447836SJohn.Forte@Sun.COM 		/*
24457836SJohn.Forte@Sun.COM 		 * Update symbolic node name
24467836SJohn.Forte@Sun.COM 		 */
24477836SJohn.Forte@Sun.COM 		query_irp->irp_snn = sn;
24487836SJohn.Forte@Sun.COM 		if ((query_irp->irp_flags & IRP_SCSI_SESSION_STARTED) &&
24497836SJohn.Forte@Sun.COM 		    (query_irp->irp_session)) {
24507836SJohn.Forte@Sun.COM 			query_irp->irp_session->ss_rport_alias =
24517836SJohn.Forte@Sun.COM 			    query_irp->irp_snn;
24527836SJohn.Forte@Sun.COM 		}
24537836SJohn.Forte@Sun.COM 	} else {
24547836SJohn.Forte@Sun.COM 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: "
24557836SJohn.Forte@Sun.COM 		    "irp/%p, snlen/%d", query_irp, snlen);
24567836SJohn.Forte@Sun.COM 	}
24577836SJohn.Forte@Sun.COM 
24587836SJohn.Forte@Sun.COM exit_gsnn_cb:
24597836SJohn.Forte@Sun.COM 	rw_exit(&ICMD_TO_IPORT(icmd)->iport_lock);
24607836SJohn.Forte@Sun.COM }
24617836SJohn.Forte@Sun.COM 
24627836SJohn.Forte@Sun.COM void
fct_link_init_cb(fct_i_cmd_t * icmd)24637836SJohn.Forte@Sun.COM fct_link_init_cb(fct_i_cmd_t *icmd)
24647836SJohn.Forte@Sun.COM {
24657836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport = ICMD_TO_IPORT(icmd);
24667836SJohn.Forte@Sun.COM 
24677836SJohn.Forte@Sun.COM 	iport->iport_li_state &= ~LI_STATE_FLAG_CMD_WAITING;
24687836SJohn.Forte@Sun.COM 	if (icmd->icmd_cmd->cmd_comp_status != FCT_SUCCESS) {
24697836SJohn.Forte@Sun.COM 		stmf_trace(iport->iport_alias, "fct_link_init_cb: ELS-%x failed"
24707836SJohn.Forte@Sun.COM 		    "comp_status- %llx", ICMD_TO_ELS(icmd)->els_req_payload[0],
24717836SJohn.Forte@Sun.COM 		    icmd->icmd_cmd->cmd_comp_status);
24727836SJohn.Forte@Sun.COM 		iport->iport_li_comp_status = icmd->icmd_cmd->cmd_comp_status;
24737836SJohn.Forte@Sun.COM 	} else if (icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_ELS) {
24747836SJohn.Forte@Sun.COM 		if (!FCT_IS_ELS_ACC(icmd)) {
24757836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias,
24767836SJohn.Forte@Sun.COM 			    "fct_link_init_cb: ELS-%x is rejected",
24777836SJohn.Forte@Sun.COM 			    ICMD_TO_ELS(icmd)->els_req_payload[0]);
24787836SJohn.Forte@Sun.COM 			iport->iport_li_comp_status = FCT_REJECT_STATUS(
24797836SJohn.Forte@Sun.COM 			    ICMD_TO_ELS(icmd)->els_resp_payload[1],
24807836SJohn.Forte@Sun.COM 			    ICMD_TO_ELS(icmd)->els_resp_payload[2]);
24817836SJohn.Forte@Sun.COM 		} else {
24827836SJohn.Forte@Sun.COM 			iport->iport_li_comp_status = FCT_SUCCESS;
24837836SJohn.Forte@Sun.COM 		}
24847836SJohn.Forte@Sun.COM 	} else {
24857836SJohn.Forte@Sun.COM 		ASSERT(icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_CT);
24867836SJohn.Forte@Sun.COM 		if (!FCT_IS_CT_ACC(icmd)) {
24877836SJohn.Forte@Sun.COM 			stmf_trace(iport->iport_alias,
24887836SJohn.Forte@Sun.COM 			    "fct_link_init_cb: CT-%02x%02x is rejected",
24897836SJohn.Forte@Sun.COM 			    ICMD_TO_CT(icmd)->ct_req_payload[8],
24907836SJohn.Forte@Sun.COM 			    ICMD_TO_CT(icmd)->ct_req_payload[9]);
24917836SJohn.Forte@Sun.COM 			iport->iport_li_comp_status = FCT_REJECT_STATUS(
24927836SJohn.Forte@Sun.COM 			    ICMD_TO_CT(icmd)->ct_resp_payload[8],
24937836SJohn.Forte@Sun.COM 			    ICMD_TO_CT(icmd)->ct_resp_payload[9]);
24947836SJohn.Forte@Sun.COM 		} else {
24957836SJohn.Forte@Sun.COM 			iport->iport_li_comp_status = FCT_SUCCESS;
24967836SJohn.Forte@Sun.COM 		}
24977836SJohn.Forte@Sun.COM 	}
24987836SJohn.Forte@Sun.COM }
24997836SJohn.Forte@Sun.COM 
25007836SJohn.Forte@Sun.COM void
fct_gcs_cb(fct_i_cmd_t * icmd)25017836SJohn.Forte@Sun.COM fct_gcs_cb(fct_i_cmd_t *icmd)
25027836SJohn.Forte@Sun.COM {
25037836SJohn.Forte@Sun.COM 	fct_sol_ct_t		*ct	   = ICMD_TO_CT(icmd);
25047836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*query_irp = NULL;
25057836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport	   = ICMD_TO_IPORT(icmd);
25067836SJohn.Forte@Sun.COM 	uint32_t		 query_portid;
25077836SJohn.Forte@Sun.COM 	uint8_t			*resp;
25087836SJohn.Forte@Sun.COM 	uint8_t			*req;
25097836SJohn.Forte@Sun.COM 
25107836SJohn.Forte@Sun.COM 	if (!FCT_IS_CT_ACC(icmd)) {
25117836SJohn.Forte@Sun.COM 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gcs_cb: "
25127836SJohn.Forte@Sun.COM 		    "GCS_ID is not accepted by NS - icmd/%p", icmd);
25137836SJohn.Forte@Sun.COM 		return;
25147836SJohn.Forte@Sun.COM 	}
25157836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
25167836SJohn.Forte@Sun.COM 
25177836SJohn.Forte@Sun.COM 	resp = ct->ct_resp_payload;
25187836SJohn.Forte@Sun.COM 	req = ct->ct_req_payload;
25197836SJohn.Forte@Sun.COM 	query_portid = (req[17] << 16) | (req[18] << 8) | req[19];
25207836SJohn.Forte@Sun.COM 
25217836SJohn.Forte@Sun.COM 	rw_enter(&iport->iport_lock, RW_READER);
25227836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
25237836SJohn.Forte@Sun.COM 	query_irp = fct_portid_to_portptr(iport, query_portid);
25247836SJohn.Forte@Sun.COM 
25257836SJohn.Forte@Sun.COM 	if (query_irp) {
25267836SJohn.Forte@Sun.COM 		query_irp->irp_cos = (resp[16] << 27) | (resp[17] << 18) |
25277836SJohn.Forte@Sun.COM 		    (resp[18] << 8) | resp[19];
25287836SJohn.Forte@Sun.COM 	}
25297836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
25307836SJohn.Forte@Sun.COM }
25317836SJohn.Forte@Sun.COM 
25327836SJohn.Forte@Sun.COM void
fct_gft_cb(fct_i_cmd_t * icmd)25337836SJohn.Forte@Sun.COM fct_gft_cb(fct_i_cmd_t *icmd)
25347836SJohn.Forte@Sun.COM {
25357836SJohn.Forte@Sun.COM 	fct_sol_ct_t		*ct	   = ICMD_TO_CT(icmd);
25367836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*query_irp = NULL;
25377836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport	   = ICMD_TO_IPORT(icmd);
25387836SJohn.Forte@Sun.COM 	uint32_t		 query_portid;
25397836SJohn.Forte@Sun.COM 	uint8_t			*resp;
25407836SJohn.Forte@Sun.COM 	uint8_t			*req;
25417836SJohn.Forte@Sun.COM 
25427836SJohn.Forte@Sun.COM 	if (!FCT_IS_CT_ACC(icmd)) {
25437836SJohn.Forte@Sun.COM 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gft_cb: "
25447836SJohn.Forte@Sun.COM 		    "GFT_ID is not accepted by NS - icmd/%p", icmd);
25457836SJohn.Forte@Sun.COM 		return;
25467836SJohn.Forte@Sun.COM 	}
25477836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
25487836SJohn.Forte@Sun.COM 
25497836SJohn.Forte@Sun.COM 	resp = ct->ct_resp_payload;
25507836SJohn.Forte@Sun.COM 	req = ct->ct_req_payload;
25517836SJohn.Forte@Sun.COM 	query_portid = (req[17] << 16) | (req[18] << 8) | req[19];
25527836SJohn.Forte@Sun.COM 
25537836SJohn.Forte@Sun.COM 	rw_enter(&iport->iport_lock, RW_READER);
25547836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
25557836SJohn.Forte@Sun.COM 	query_irp = fct_portid_to_portptr(iport, query_portid);
25567836SJohn.Forte@Sun.COM 
25577836SJohn.Forte@Sun.COM 	if (query_irp) {
25587836SJohn.Forte@Sun.COM 		(void) memcpy(query_irp->irp_fc4types, resp + 16, 32);
25597836SJohn.Forte@Sun.COM 	}
25607836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
25617836SJohn.Forte@Sun.COM }
25627836SJohn.Forte@Sun.COM 
25637836SJohn.Forte@Sun.COM void
fct_gid_cb(fct_i_cmd_t * icmd)25647836SJohn.Forte@Sun.COM fct_gid_cb(fct_i_cmd_t *icmd)
25657836SJohn.Forte@Sun.COM {
25667836SJohn.Forte@Sun.COM 	fct_cmd_t		*cmd	   = NULL;
25677836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*query_irp = NULL;
25687836SJohn.Forte@Sun.COM 	uint32_t		 nsportid  = 0;
25697836SJohn.Forte@Sun.COM 	int			 do_logo   = 0;
25707836SJohn.Forte@Sun.COM 
25717836SJohn.Forte@Sun.COM 	mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
25727836SJohn.Forte@Sun.COM 
25737836SJohn.Forte@Sun.COM 	rw_enter(&ICMD_TO_IPORT(icmd)->iport_lock, RW_READER);
25747836SJohn.Forte@Sun.COM 	mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
25757836SJohn.Forte@Sun.COM 	query_irp = fct_lookup_irp_by_portwwn(ICMD_TO_IPORT(icmd),
25767836SJohn.Forte@Sun.COM 	    ICMD_TO_CT(icmd)->ct_req_payload + 16);
25777836SJohn.Forte@Sun.COM 
25787836SJohn.Forte@Sun.COM 	if (!query_irp || (query_irp &&
25797836SJohn.Forte@Sun.COM 	    (PTR2INT(icmd->icmd_cb_private, uint32_t) !=
25807836SJohn.Forte@Sun.COM 	    query_irp->irp_rscn_counter))) {
25817836SJohn.Forte@Sun.COM 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: "
25827836SJohn.Forte@Sun.COM 		    "new RSCN arrived - query_irp/%p, private-%x", query_irp,
25837836SJohn.Forte@Sun.COM 		    PTR2INT(icmd->icmd_cb_private, uint32_t));
25847836SJohn.Forte@Sun.COM 		goto exit_gid_cb;
25857836SJohn.Forte@Sun.COM 	}
25867836SJohn.Forte@Sun.COM 
25877836SJohn.Forte@Sun.COM 	if ((query_irp->irp_flags & IRP_RSCN_QUEUED) ||
25887836SJohn.Forte@Sun.COM 	    (!(query_irp->irp_flags & IRP_PLOGI_DONE)))	{
25897836SJohn.Forte@Sun.COM 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: "
25907836SJohn.Forte@Sun.COM 		    "not proper irp_flags - query_irp/%p", query_irp);
25917836SJohn.Forte@Sun.COM 		goto exit_gid_cb;
25927836SJohn.Forte@Sun.COM 	}
25937836SJohn.Forte@Sun.COM 
25947836SJohn.Forte@Sun.COM 	if (!FCT_IS_CT_ACC(icmd)) {
25957836SJohn.Forte@Sun.COM 		/*
25967836SJohn.Forte@Sun.COM 		 * Check if it has disappeared
25977836SJohn.Forte@Sun.COM 		 */
25987836SJohn.Forte@Sun.COM 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: "
25997836SJohn.Forte@Sun.COM 		    "GPN_ID is not accepted by NS - icmd/%p", icmd);
26007836SJohn.Forte@Sun.COM 		do_logo = 1;
26017836SJohn.Forte@Sun.COM 	} else {
26027836SJohn.Forte@Sun.COM 		/*
26037836SJohn.Forte@Sun.COM 		 * Check if its portid has changed
26047836SJohn.Forte@Sun.COM 		 */
26057836SJohn.Forte@Sun.COM 		nsportid = fct_netbuf_to_value(
26067836SJohn.Forte@Sun.COM 		    ICMD_TO_CT(icmd)->ct_resp_payload + 17, 3);
26077836SJohn.Forte@Sun.COM 		if (nsportid != query_irp->irp_rp->rp_id) {
26087836SJohn.Forte@Sun.COM 			stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias,
26097836SJohn.Forte@Sun.COM 			    "portid has changed - query_irp/%p", query_irp);
26107836SJohn.Forte@Sun.COM 			do_logo = 1;
26117836SJohn.Forte@Sun.COM 		}
26127836SJohn.Forte@Sun.COM 	}
26137836SJohn.Forte@Sun.COM 
26147836SJohn.Forte@Sun.COM 	if (do_logo) {
26157836SJohn.Forte@Sun.COM 		cmd = fct_create_solels(ICMD_TO_PORT(icmd),
26167836SJohn.Forte@Sun.COM 		    query_irp->irp_rp, 1, ELS_OP_LOGO, 0, fct_logo_cb);
26177836SJohn.Forte@Sun.COM 		if (cmd) {
26187836SJohn.Forte@Sun.COM 			mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
26197836SJohn.Forte@Sun.COM 			fct_post_implicit_logo(cmd);
26207836SJohn.Forte@Sun.COM 			mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock);
26217836SJohn.Forte@Sun.COM 		}
26227836SJohn.Forte@Sun.COM 	}
26237836SJohn.Forte@Sun.COM 
26247836SJohn.Forte@Sun.COM exit_gid_cb:
26257836SJohn.Forte@Sun.COM 	rw_exit(&ICMD_TO_IPORT(icmd)->iport_lock);
26267836SJohn.Forte@Sun.COM }
26277836SJohn.Forte@Sun.COM 
26287836SJohn.Forte@Sun.COM void
fct_gspn_cb(fct_i_cmd_t * icmd)26297836SJohn.Forte@Sun.COM fct_gspn_cb(fct_i_cmd_t *icmd)
26307836SJohn.Forte@Sun.COM {
26317836SJohn.Forte@Sun.COM 	fct_sol_ct_t		*ct	   = ICMD_TO_CT(icmd);
26327836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*query_irp = NULL;
26337836SJohn.Forte@Sun.COM 	fct_i_local_port_t	*iport	   = ICMD_TO_IPORT(icmd);
26347836SJohn.Forte@Sun.COM 	uint32_t		 query_portid;
26357836SJohn.Forte@Sun.COM 	uint8_t			*resp;
26367836SJohn.Forte@Sun.COM 	uint8_t			*req;
26377836SJohn.Forte@Sun.COM 	uint8_t			 spnlen;
26387836SJohn.Forte@Sun.COM 
26397836SJohn.Forte@Sun.COM 	if (!FCT_IS_CT_ACC(icmd)) {
26407836SJohn.Forte@Sun.COM 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gspn_cb: "
26417836SJohn.Forte@Sun.COM 		    "GSPN_ID is not accepted by NS - icmd/%p", icmd);
26427836SJohn.Forte@Sun.COM 		return;
26437836SJohn.Forte@Sun.COM 	}
26447836SJohn.Forte@Sun.COM 	mutex_exit(&iport->iport_worker_lock);
26457836SJohn.Forte@Sun.COM 
26467836SJohn.Forte@Sun.COM 	resp = ct->ct_resp_payload;
26477836SJohn.Forte@Sun.COM 	req = ct->ct_req_payload;
26487836SJohn.Forte@Sun.COM 	query_portid = (req[17] << 16) | (req[18] << 8) | req[19];
26497836SJohn.Forte@Sun.COM 
26507836SJohn.Forte@Sun.COM 	rw_enter(&iport->iport_lock, RW_READER);
26517836SJohn.Forte@Sun.COM 	mutex_enter(&iport->iport_worker_lock);
26527836SJohn.Forte@Sun.COM 	query_irp = fct_portid_to_portptr(iport, query_portid);
26537836SJohn.Forte@Sun.COM 	if (query_irp) {
26547836SJohn.Forte@Sun.COM 		spnlen = resp[16];
26557836SJohn.Forte@Sun.COM 		if (spnlen > 0) {
26567836SJohn.Forte@Sun.COM 			if (query_irp->irp_spn) {
26577836SJohn.Forte@Sun.COM 				kmem_free(query_irp->irp_spn,
26587836SJohn.Forte@Sun.COM 				    strlen(query_irp->irp_spn) + 1);
26597836SJohn.Forte@Sun.COM 			}
26607836SJohn.Forte@Sun.COM 			query_irp->irp_spn = kmem_zalloc(spnlen + 1, KM_SLEEP);
26617836SJohn.Forte@Sun.COM 			(void) strncpy(query_irp->irp_spn,
26627836SJohn.Forte@Sun.COM 			    (char *)resp + 17, spnlen);
26637836SJohn.Forte@Sun.COM 		}
26647836SJohn.Forte@Sun.COM 	}
26657836SJohn.Forte@Sun.COM 	rw_exit(&iport->iport_lock);
26667836SJohn.Forte@Sun.COM }
26677836SJohn.Forte@Sun.COM 
266810088SAllan.Ou@Sun.COM void
fct_rls_cb(fct_i_cmd_t * icmd)266910088SAllan.Ou@Sun.COM fct_rls_cb(fct_i_cmd_t *icmd)
267010088SAllan.Ou@Sun.COM {
267110088SAllan.Ou@Sun.COM 	fct_els_t		*els = ICMD_TO_ELS(icmd);
267210088SAllan.Ou@Sun.COM 	uint8_t			*resp;
267310088SAllan.Ou@Sun.COM 	fct_rls_cb_data_t	*rls_cb_data = NULL;
267410088SAllan.Ou@Sun.COM 	fct_port_link_status_t	*rls_resp;
267510088SAllan.Ou@Sun.COM 	fct_i_local_port_t	*iport = ICMD_TO_IPORT(icmd);
267610088SAllan.Ou@Sun.COM 
267710088SAllan.Ou@Sun.COM 	rls_cb_data = icmd->icmd_cb_private;
267810088SAllan.Ou@Sun.COM 
267910088SAllan.Ou@Sun.COM 	if (!FCT_IS_ELS_ACC(icmd)) {
268010088SAllan.Ou@Sun.COM 		stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_rls_cb: "
268110088SAllan.Ou@Sun.COM 		    "solicited RLS is not accepted - icmd/%p", icmd);
268210088SAllan.Ou@Sun.COM 		if (rls_cb_data) {
268310088SAllan.Ou@Sun.COM 			rls_cb_data->fct_els_res = FCT_FAILURE;
268410088SAllan.Ou@Sun.COM 			sema_v(&iport->iport_rls_sema);
268510088SAllan.Ou@Sun.COM 		}
268610088SAllan.Ou@Sun.COM 		return;
268710088SAllan.Ou@Sun.COM 	}
268810088SAllan.Ou@Sun.COM 
268910088SAllan.Ou@Sun.COM 	if (!rls_cb_data) {
269010088SAllan.Ou@Sun.COM 		sema_v(&iport->iport_rls_sema);
269110088SAllan.Ou@Sun.COM 		return;
269210088SAllan.Ou@Sun.COM 	}
269310088SAllan.Ou@Sun.COM 
269410088SAllan.Ou@Sun.COM 	resp = els->els_resp_payload;
269510088SAllan.Ou@Sun.COM 
269610088SAllan.Ou@Sun.COM 	rls_cb_data = icmd->icmd_cb_private;
269710088SAllan.Ou@Sun.COM 
269810088SAllan.Ou@Sun.COM 	/* Get the response and store it somewhere */
269910088SAllan.Ou@Sun.COM 	rls_resp = (fct_port_link_status_t *)rls_cb_data->fct_link_status;
270010088SAllan.Ou@Sun.COM 	rls_resp->LinkFailureCount = BE_32(*((uint32_t *)(resp + 4)));
270110088SAllan.Ou@Sun.COM 	rls_resp->LossOfSyncCount = BE_32(*((uint32_t *)(resp + 8)));
270210088SAllan.Ou@Sun.COM 	rls_resp->LossOfSignalsCount = BE_32(*((uint32_t *)(resp + 12)));
270310088SAllan.Ou@Sun.COM 	rls_resp->PrimitiveSeqProtocolErrorCount =
270410088SAllan.Ou@Sun.COM 	    BE_32(*((uint32_t *)(resp + 16)));
270510088SAllan.Ou@Sun.COM 	rls_resp->InvalidTransmissionWordCount =
270610088SAllan.Ou@Sun.COM 	    BE_32(*((uint32_t *)(resp + 20)));
270710088SAllan.Ou@Sun.COM 	rls_resp->InvalidCRCCount = BE_32(*((uint32_t *)(resp + 24)));
270810088SAllan.Ou@Sun.COM 
270910088SAllan.Ou@Sun.COM 	rls_cb_data->fct_els_res = FCT_SUCCESS;
271010088SAllan.Ou@Sun.COM 	sema_v(&iport->iport_rls_sema);
271110088SAllan.Ou@Sun.COM 	icmd->icmd_cb_private = NULL;
271210088SAllan.Ou@Sun.COM }
271310088SAllan.Ou@Sun.COM 
27147836SJohn.Forte@Sun.COM /*
27157836SJohn.Forte@Sun.COM  * For lookup functions, we move locking up one level
27167836SJohn.Forte@Sun.COM  */
27177836SJohn.Forte@Sun.COM fct_i_remote_port_t *
fct_lookup_irp_by_nodewwn(fct_i_local_port_t * iport,uint8_t * nodewwn)27187836SJohn.Forte@Sun.COM fct_lookup_irp_by_nodewwn(fct_i_local_port_t *iport, uint8_t *nodewwn)
27197836SJohn.Forte@Sun.COM {
27207836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp = NULL;
27217836SJohn.Forte@Sun.COM 	int			 idx = 0;
27227836SJohn.Forte@Sun.COM 
27237836SJohn.Forte@Sun.COM 	for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) {
27247836SJohn.Forte@Sun.COM 		for (irp = iport->iport_rp_tb[idx]; irp;
27257836SJohn.Forte@Sun.COM 		    irp = irp->irp_next) {
27267836SJohn.Forte@Sun.COM 			if (bcmp(irp->irp_rp->rp_nwwn, nodewwn, FC_WWN_LEN)) {
27277836SJohn.Forte@Sun.COM 				continue;
27287836SJohn.Forte@Sun.COM 			} else {
27297836SJohn.Forte@Sun.COM 				return (irp);
27307836SJohn.Forte@Sun.COM 			}
27317836SJohn.Forte@Sun.COM 		}
27327836SJohn.Forte@Sun.COM 	}
27337836SJohn.Forte@Sun.COM 
27347836SJohn.Forte@Sun.COM 	return (NULL);
27357836SJohn.Forte@Sun.COM }
27367836SJohn.Forte@Sun.COM 
27377836SJohn.Forte@Sun.COM fct_i_remote_port_t *
fct_lookup_irp_by_portwwn(fct_i_local_port_t * iport,uint8_t * portwwn)27387836SJohn.Forte@Sun.COM fct_lookup_irp_by_portwwn(fct_i_local_port_t *iport, uint8_t *portwwn)
27397836SJohn.Forte@Sun.COM {
27407836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp = NULL;
27417836SJohn.Forte@Sun.COM 	int			 idx = 0;
27427836SJohn.Forte@Sun.COM 
27437836SJohn.Forte@Sun.COM 	for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) {
27447836SJohn.Forte@Sun.COM 		for (irp = iport->iport_rp_tb[idx]; irp;
27457836SJohn.Forte@Sun.COM 		    irp = irp->irp_next) {
27467836SJohn.Forte@Sun.COM 			if (bcmp(irp->irp_rp->rp_pwwn, portwwn, FC_WWN_LEN)) {
27477836SJohn.Forte@Sun.COM 				continue;
27487836SJohn.Forte@Sun.COM 			} else {
27497836SJohn.Forte@Sun.COM 				return (irp);
27507836SJohn.Forte@Sun.COM 			}
27517836SJohn.Forte@Sun.COM 		}
27527836SJohn.Forte@Sun.COM 	}
27537836SJohn.Forte@Sun.COM 
27547836SJohn.Forte@Sun.COM 	return (NULL);
27557836SJohn.Forte@Sun.COM }
27567836SJohn.Forte@Sun.COM 
27577836SJohn.Forte@Sun.COM #ifdef	lint
27587836SJohn.Forte@Sun.COM #define	FCT_VERIFY_RSCN()	_NOTE(EMPTY)
27597836SJohn.Forte@Sun.COM #else
27607836SJohn.Forte@Sun.COM #define	FCT_VERIFY_RSCN()						\
27617836SJohn.Forte@Sun.COM do {									\
27627836SJohn.Forte@Sun.COM 	ct_cmd = fct_create_solct(port, irp->irp_rp, NS_GID_PN,		\
27637836SJohn.Forte@Sun.COM 	    fct_gid_cb);						\
27647836SJohn.Forte@Sun.COM 	if (ct_cmd) {							\
27657836SJohn.Forte@Sun.COM 		uint32_t cnt;						\
27667836SJohn.Forte@Sun.COM 		cnt = atomic_add_32_nv(&irp->irp_rscn_counter, 1);	\
27677836SJohn.Forte@Sun.COM 		CMD_TO_ICMD(ct_cmd)->icmd_cb_private =			\
27687836SJohn.Forte@Sun.COM 		    INT2PTR(cnt, void *);				\
27697836SJohn.Forte@Sun.COM 		irp->irp_flags |= IRP_RSCN_QUEUED;			\
27707836SJohn.Forte@Sun.COM 		fct_post_to_solcmd_queue(port, ct_cmd);			\
27717836SJohn.Forte@Sun.COM 	}								\
27727836SJohn.Forte@Sun.COM } while (0)
27737836SJohn.Forte@Sun.COM #endif
27747836SJohn.Forte@Sun.COM 
27757836SJohn.Forte@Sun.COM /* ARGSUSED */
27767836SJohn.Forte@Sun.COM static void
fct_rscn_verify(fct_i_local_port_t * iport,uint8_t * rscn_req_payload,uint32_t rscn_req_size)27777836SJohn.Forte@Sun.COM fct_rscn_verify(fct_i_local_port_t *iport, uint8_t *rscn_req_payload,
27787836SJohn.Forte@Sun.COM     uint32_t rscn_req_size)
27797836SJohn.Forte@Sun.COM {
27807836SJohn.Forte@Sun.COM 	int			idx		= 0;
27817836SJohn.Forte@Sun.COM 	uint8_t			page_format	= 0;
27827836SJohn.Forte@Sun.COM 	uint32_t		page_portid	= 0;
27837836SJohn.Forte@Sun.COM 	uint8_t			*page_buf	= NULL;
27847836SJohn.Forte@Sun.COM 	uint8_t			*last_page_buf	= NULL;
27857836SJohn.Forte@Sun.COM #ifndef	lint
27867836SJohn.Forte@Sun.COM 	fct_cmd_t		*ct_cmd		= NULL;
27877836SJohn.Forte@Sun.COM 	fct_local_port_t	*port		= NULL;
27887836SJohn.Forte@Sun.COM #endif
27897836SJohn.Forte@Sun.COM 	fct_i_remote_port_t	*irp		= NULL;
27907836SJohn.Forte@Sun.COM 
27917836SJohn.Forte@Sun.COM 	page_buf = rscn_req_payload + 4;
27927836SJohn.Forte@Sun.COM 	last_page_buf = rscn_req_payload +
27937836SJohn.Forte@Sun.COM 	    fct_netbuf_to_value(rscn_req_payload + 2, 2) - 4;
27947836SJohn.Forte@Sun.COM #ifndef	lint
27957836SJohn.Forte@Sun.COM 	port = iport->iport_port;
27967836SJohn.Forte@Sun.COM #endif
27977836SJohn.Forte@Sun.COM 	for (; page_buf <= last_page_buf; page_buf += 4) {
27987836SJohn.Forte@Sun.COM 		page_format = 0x03 & page_buf[0];
27997836SJohn.Forte@Sun.COM 		page_portid = fct_netbuf_to_value(page_buf + 1, 3);
28007836SJohn.Forte@Sun.COM 
280110088SAllan.Ou@Sun.COM 		DTRACE_FC_2(rscn__receive,
280210088SAllan.Ou@Sun.COM 		    fct_i_local_port_t, iport,
280310088SAllan.Ou@Sun.COM 		    int, page_portid);
280410088SAllan.Ou@Sun.COM 
28057836SJohn.Forte@Sun.COM 		rw_enter(&iport->iport_lock, RW_READER);
28067836SJohn.Forte@Sun.COM 		if (!page_format) {
28077836SJohn.Forte@Sun.COM 			irp = fct_portid_to_portptr(iport, page_portid);
28087836SJohn.Forte@Sun.COM 			if (!(irp && !(irp->irp_flags & IRP_RSCN_QUEUED))) {
28097836SJohn.Forte@Sun.COM 				rw_exit(&iport->iport_lock);
28107836SJohn.Forte@Sun.COM 
28117836SJohn.Forte@Sun.COM 				continue; /* try next page */
28127836SJohn.Forte@Sun.COM 			}
28137836SJohn.Forte@Sun.COM 
28147836SJohn.Forte@Sun.COM 			if (FC_WELL_KNOWN_ADDR(irp->irp_portid) ||
28157836SJohn.Forte@Sun.COM 			    !(irp->irp_flags & IRP_PLOGI_DONE)) {
28167836SJohn.Forte@Sun.COM 				rw_exit(&iport->iport_lock);
28177836SJohn.Forte@Sun.COM 
28187836SJohn.Forte@Sun.COM 				continue; /* try next page */
28197836SJohn.Forte@Sun.COM 			}
28207836SJohn.Forte@Sun.COM 
28217836SJohn.Forte@Sun.COM 			FCT_VERIFY_RSCN();
28227836SJohn.Forte@Sun.COM 		} else {
28237836SJohn.Forte@Sun.COM 			for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) {
28247836SJohn.Forte@Sun.COM 				for (irp = iport->iport_rp_tb[idx];
28257836SJohn.Forte@Sun.COM 				    irp; irp = irp->irp_next) {
28267836SJohn.Forte@Sun.COM 					if (FC_WELL_KNOWN_ADDR(irp->irp_portid))
28277836SJohn.Forte@Sun.COM 						continue; /* try next irp */
28287836SJohn.Forte@Sun.COM 
28297836SJohn.Forte@Sun.COM 					if (!(irp->irp_flags & IRP_PLOGI_DONE))
28307836SJohn.Forte@Sun.COM 						continue; /* try next irp */
28317836SJohn.Forte@Sun.COM 
28327836SJohn.Forte@Sun.COM 					if (irp->irp_flags & IRP_RSCN_QUEUED) {
28337836SJohn.Forte@Sun.COM 						continue; /* try next irp */
28347836SJohn.Forte@Sun.COM 					}
28357836SJohn.Forte@Sun.COM #ifndef	lint
28367836SJohn.Forte@Sun.COM 					if (!((0xFFFFFF << (page_format * 8)) &
28377836SJohn.Forte@Sun.COM 					    (page_portid ^ irp->irp_portid))) {
28387836SJohn.Forte@Sun.COM 						FCT_VERIFY_RSCN();
28397836SJohn.Forte@Sun.COM 					}
28407836SJohn.Forte@Sun.COM #endif
28417836SJohn.Forte@Sun.COM 				}
28427836SJohn.Forte@Sun.COM 			}
28437836SJohn.Forte@Sun.COM 		}
28447836SJohn.Forte@Sun.COM 		rw_exit(&iport->iport_lock);
28457836SJohn.Forte@Sun.COM 	}
28467836SJohn.Forte@Sun.COM }
2847