1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8*8f23e9faSHans Rosenfeld  * You can obtain a copy of the license at
9*8f23e9faSHans Rosenfeld  * http://www.opensource.org/licenses/cddl1.txt.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte 
22fcf3ce44SJohn Forte /*
23*8f23e9faSHans Rosenfeld  * Copyright (c) 2004-2011 Emulex. All rights reserved.
2482527734SSukumar Swaminathan  * Use is subject to license terms.
25fcf3ce44SJohn Forte  */
26fcf3ce44SJohn Forte 
27291a2b48SSukumar Swaminathan #include <emlxs.h>
28fcf3ce44SJohn Forte 
29fcf3ce44SJohn Forte 
30fcf3ce44SJohn Forte /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
31fcf3ce44SJohn Forte EMLXS_MSG_DEF(EMLXS_NODE_C);
32fcf3ce44SJohn Forte 
33*8f23e9faSHans Rosenfeld static void	emlxs_node_add(emlxs_port_t *, NODELIST *);
34*8f23e9faSHans Rosenfeld static int	emlxs_node_match_did(emlxs_port_t *, NODELIST *, uint32_t);
35*8f23e9faSHans Rosenfeld 
36291a2b48SSukumar Swaminathan /* Timeout == -1 will enable the offline timer */
3782527734SSukumar Swaminathan /* Timeout not -1 will apply the timeout */
38fcf3ce44SJohn Forte extern void
emlxs_node_close(emlxs_port_t * port,NODELIST * ndlp,uint32_t channelno,int32_t timeout)3982527734SSukumar Swaminathan emlxs_node_close(emlxs_port_t *port, NODELIST *ndlp, uint32_t channelno,
40291a2b48SSukumar Swaminathan     int32_t timeout)
41fcf3ce44SJohn Forte {
42fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
43291a2b48SSukumar Swaminathan 	emlxs_config_t *cfg = &CFG;
4482527734SSukumar Swaminathan 	CHANNEL *cp;
45fcf3ce44SJohn Forte 	NODELIST *prev;
46291a2b48SSukumar Swaminathan 	uint32_t offline = 0;
47fcf3ce44SJohn Forte 
4882527734SSukumar Swaminathan 
4982527734SSukumar Swaminathan 	/* If node is on a channel service queue, then remove it */
5082527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
51fcf3ce44SJohn Forte 
52fcf3ce44SJohn Forte 	/* Return if node destroyed */
53fcf3ce44SJohn Forte 	if (!ndlp || !ndlp->nlp_active) {
5482527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
55fcf3ce44SJohn Forte 
56fcf3ce44SJohn Forte 		return;
57fcf3ce44SJohn Forte 	}
58291a2b48SSukumar Swaminathan 
59291a2b48SSukumar Swaminathan 	/* Check offline support */
60291a2b48SSukumar Swaminathan 	if (timeout == -1) {
61291a2b48SSukumar Swaminathan 		if (cfg[CFG_OFFLINE_TIMEOUT].current) {
62291a2b48SSukumar Swaminathan 			timeout = cfg[CFG_OFFLINE_TIMEOUT].current;
63291a2b48SSukumar Swaminathan 			offline = 1;
64291a2b48SSukumar Swaminathan 		} else {
65291a2b48SSukumar Swaminathan 			timeout = 0;
66291a2b48SSukumar Swaminathan 		}
67291a2b48SSukumar Swaminathan 	}
68291a2b48SSukumar Swaminathan 
6982527734SSukumar Swaminathan 	if (channelno == hba->channel_ip) {
70fcf3ce44SJohn Forte 		/* Clear IP XRI */
71fcf3ce44SJohn Forte 		ndlp->nlp_Xri = 0;
72fcf3ce44SJohn Forte 	}
73291a2b48SSukumar Swaminathan 
74fcf3ce44SJohn Forte 	/* Check if node is already closed */
7582527734SSukumar Swaminathan 	if (ndlp->nlp_flag[channelno] & NLP_CLOSED) {
7682527734SSukumar Swaminathan 		if (ndlp->nlp_flag[channelno] & NLP_OFFLINE) {
7782527734SSukumar Swaminathan 			mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
78291a2b48SSukumar Swaminathan 			return;
79291a2b48SSukumar Swaminathan 		}
80291a2b48SSukumar Swaminathan 
81291a2b48SSukumar Swaminathan 		if (offline) {
8282527734SSukumar Swaminathan 			ndlp->nlp_tics[channelno] = hba->timer_tics + timeout;
8382527734SSukumar Swaminathan 			ndlp->nlp_flag[channelno] |= NLP_OFFLINE;
8482527734SSukumar Swaminathan 			mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
85291a2b48SSukumar Swaminathan 
86291a2b48SSukumar Swaminathan 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_closed_msg,
87fe199829SSukumar Swaminathan 			    "node=%p did=%06x channel=%d. offline=%d update.",
8882527734SSukumar Swaminathan 			    ndlp, ndlp->nlp_DID, channelno, timeout);
89291a2b48SSukumar Swaminathan 
90291a2b48SSukumar Swaminathan 		} else if (timeout) {
9182527734SSukumar Swaminathan 			ndlp->nlp_tics[channelno] = hba->timer_tics + timeout;
9282527734SSukumar Swaminathan 			mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
93291a2b48SSukumar Swaminathan 
94291a2b48SSukumar Swaminathan 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_closed_msg,
95fe199829SSukumar Swaminathan 			    "node=%p did=%06x channel=%d. timeout=%d update.",
9682527734SSukumar Swaminathan 			    ndlp, ndlp->nlp_DID, channelno, timeout);
97291a2b48SSukumar Swaminathan 		} else {
9882527734SSukumar Swaminathan 			mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
99fcf3ce44SJohn Forte 		}
100fcf3ce44SJohn Forte 
101fcf3ce44SJohn Forte 		return;
102fcf3ce44SJohn Forte 	}
103291a2b48SSukumar Swaminathan 
104fcf3ce44SJohn Forte 	/* Set the node closed */
10582527734SSukumar Swaminathan 	ndlp->nlp_flag[channelno] |= NLP_CLOSED;
106fcf3ce44SJohn Forte 
107291a2b48SSukumar Swaminathan 	if (offline) {
10882527734SSukumar Swaminathan 		ndlp->nlp_tics[channelno] = hba->timer_tics + timeout;
10982527734SSukumar Swaminathan 		ndlp->nlp_flag[channelno] |= NLP_OFFLINE;
110291a2b48SSukumar Swaminathan 
111fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_closed_msg,
112fe199829SSukumar Swaminathan 		    "node=%p did=%06x channel=%d. offline=%d set.",
113fe199829SSukumar Swaminathan 		    ndlp, ndlp->nlp_DID, channelno, timeout);
114fe199829SSukumar Swaminathan 
115291a2b48SSukumar Swaminathan 	} else if (timeout) {
11682527734SSukumar Swaminathan 		ndlp->nlp_tics[channelno] = hba->timer_tics + timeout;
117fe199829SSukumar Swaminathan 
118fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_closed_msg,
119fe199829SSukumar Swaminathan 		    "node=%p did=%06x channel=%d. timeout=%d set.",
120fe199829SSukumar Swaminathan 		    ndlp, ndlp->nlp_DID, channelno, timeout);
121fe199829SSukumar Swaminathan 	} else {
122fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_closed_msg,
123fe199829SSukumar Swaminathan 		    "node=%p did=%06x channel=%d.",
124fe199829SSukumar Swaminathan 		    ndlp, ndlp->nlp_DID, channelno);
125fcf3ce44SJohn Forte 	}
126fcf3ce44SJohn Forte 
12782527734SSukumar Swaminathan 
12882527734SSukumar Swaminathan 	/*
12982527734SSukumar Swaminathan 	 * ndlp->nlp_next[] and cp->nodeq list have to be updated
13082527734SSukumar Swaminathan 	 * simulaneously
13182527734SSukumar Swaminathan 	 */
13282527734SSukumar Swaminathan 	if (ndlp->nlp_next[channelno]) {
13382527734SSukumar Swaminathan 		/* Remove node from channel queue */
13482527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
135fcf3ce44SJohn Forte 
136fcf3ce44SJohn Forte 		/* If this is the only node on list */
13782527734SSukumar Swaminathan 		if (cp->nodeq.q_first == (void *)ndlp &&
13882527734SSukumar Swaminathan 		    cp->nodeq.q_last == (void *)ndlp) {
13982527734SSukumar Swaminathan 			cp->nodeq.q_last = NULL;
14082527734SSukumar Swaminathan 			cp->nodeq.q_first = NULL;
14182527734SSukumar Swaminathan 			cp->nodeq.q_cnt = 0;
14282527734SSukumar Swaminathan 		} else if (cp->nodeq.q_first == (void *)ndlp) {
14382527734SSukumar Swaminathan 			cp->nodeq.q_first = ndlp->nlp_next[channelno];
14482527734SSukumar Swaminathan 			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
14582527734SSukumar Swaminathan 			    cp->nodeq.q_first;
14682527734SSukumar Swaminathan 			cp->nodeq.q_cnt--;
147fcf3ce44SJohn Forte 		} else {	/* This is a little more difficult */
148291a2b48SSukumar Swaminathan 
14982527734SSukumar Swaminathan 			/* Find the previous node in circular channel queue */
150fcf3ce44SJohn Forte 			prev = ndlp;
15182527734SSukumar Swaminathan 			while (prev->nlp_next[channelno] != ndlp) {
15282527734SSukumar Swaminathan 				prev = prev->nlp_next[channelno];
153fcf3ce44SJohn Forte 			}
154fcf3ce44SJohn Forte 
15582527734SSukumar Swaminathan 			prev->nlp_next[channelno] = ndlp->nlp_next[channelno];
156fcf3ce44SJohn Forte 
15782527734SSukumar Swaminathan 			if (cp->nodeq.q_last == (void *)ndlp) {
15882527734SSukumar Swaminathan 				cp->nodeq.q_last = (void *)prev;
159fcf3ce44SJohn Forte 			}
16082527734SSukumar Swaminathan 			cp->nodeq.q_cnt--;
161fcf3ce44SJohn Forte 
162fcf3ce44SJohn Forte 		}
163fcf3ce44SJohn Forte 
164fcf3ce44SJohn Forte 		/* Clear node */
16582527734SSukumar Swaminathan 		ndlp->nlp_next[channelno] = NULL;
166fcf3ce44SJohn Forte 	}
167291a2b48SSukumar Swaminathan 
16882527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
169728bdc9bSSukumar Swaminathan 
170291a2b48SSukumar Swaminathan 	return;
171291a2b48SSukumar Swaminathan 
17282527734SSukumar Swaminathan } /* emlxs_node_close() */
173291a2b48SSukumar Swaminathan 
174291a2b48SSukumar Swaminathan 
175291a2b48SSukumar Swaminathan /* Called by emlxs_timer_check_nodes() */
176291a2b48SSukumar Swaminathan extern void
emlxs_node_timeout(emlxs_port_t * port,NODELIST * ndlp,uint32_t channelno)17782527734SSukumar Swaminathan emlxs_node_timeout(emlxs_port_t *port, NODELIST *ndlp, uint32_t channelno)
178291a2b48SSukumar Swaminathan {
179291a2b48SSukumar Swaminathan 	emlxs_hba_t *hba = HBA;
180291a2b48SSukumar Swaminathan 
18182527734SSukumar Swaminathan 	/* If node needs servicing, then add it to the channel queues */
18282527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
183291a2b48SSukumar Swaminathan 
184291a2b48SSukumar Swaminathan 	/* Return if node destroyed */
185291a2b48SSukumar Swaminathan 	if (!ndlp || !ndlp->nlp_active) {
18682527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
187291a2b48SSukumar Swaminathan 		return;
188291a2b48SSukumar Swaminathan 	}
189291a2b48SSukumar Swaminathan 
190291a2b48SSukumar Swaminathan 	/* Open the node if not offline */
19182527734SSukumar Swaminathan 	if (!(ndlp->nlp_flag[channelno] & NLP_OFFLINE)) {
19282527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
193291a2b48SSukumar Swaminathan 
194291a2b48SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_timeout_msg,
19582527734SSukumar Swaminathan 		    "node=%p did=%06x channel=%d Opening.", ndlp, ndlp->nlp_DID,
19682527734SSukumar Swaminathan 		    channelno);
197291a2b48SSukumar Swaminathan 
19882527734SSukumar Swaminathan 		emlxs_node_open(port, ndlp, channelno);
199291a2b48SSukumar Swaminathan 		return;
200728bdc9bSSukumar Swaminathan 	}
201fcf3ce44SJohn Forte 
202291a2b48SSukumar Swaminathan 	/* OFFLINE TIMEOUT OCCURRED! */
203291a2b48SSukumar Swaminathan 
204291a2b48SSukumar Swaminathan 	/* Clear the timer */
20582527734SSukumar Swaminathan 	ndlp->nlp_tics[channelno] = 0;
206291a2b48SSukumar Swaminathan 
20782527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
208291a2b48SSukumar Swaminathan 
209291a2b48SSukumar Swaminathan 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_timeout_msg,
210a9800bebSGarrett D'Amore 	    "node=%p did=%06x channel=%d. Flushing.", ndlp, ndlp->nlp_DID,
21182527734SSukumar Swaminathan 	    channelno);
212291a2b48SSukumar Swaminathan 
21382527734SSukumar Swaminathan 	/* Flush tx queue for this channel */
21482527734SSukumar Swaminathan 	(void) emlxs_tx_node_flush(port, ndlp, &hba->chan[channelno], 0, 0);
215291a2b48SSukumar Swaminathan 
21682527734SSukumar Swaminathan 	/* Flush chip queue for this channel */
21782527734SSukumar Swaminathan 	(void) emlxs_chipq_node_flush(port, &hba->chan[channelno], ndlp, 0);
218291a2b48SSukumar Swaminathan 
219fcf3ce44SJohn Forte 	return;
220fcf3ce44SJohn Forte 
22182527734SSukumar Swaminathan } /* emlxs_node_timeout() */
222fcf3ce44SJohn Forte 
223fcf3ce44SJohn Forte 
224fcf3ce44SJohn Forte extern void
emlxs_node_open(emlxs_port_t * port,NODELIST * ndlp,uint32_t channelno)22582527734SSukumar Swaminathan emlxs_node_open(emlxs_port_t *port, NODELIST *ndlp, uint32_t channelno)
226fcf3ce44SJohn Forte {
227fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
22882527734SSukumar Swaminathan 	CHANNEL *cp;
229fcf3ce44SJohn Forte 	uint32_t found;
230fcf3ce44SJohn Forte 	NODELIST *nlp;
231fcf3ce44SJohn Forte 	MAILBOXQ *mbox;
232fcf3ce44SJohn Forte 	uint32_t i;
23382527734SSukumar Swaminathan 	int rc;
234fcf3ce44SJohn Forte 
23582527734SSukumar Swaminathan 	/* If node needs servicing, then add it to the channel queues */
23682527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
237fcf3ce44SJohn Forte 
238fcf3ce44SJohn Forte 	/* Return if node destroyed */
239fcf3ce44SJohn Forte 	if (!ndlp || !ndlp->nlp_active) {
24082527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
241fcf3ce44SJohn Forte 
242fcf3ce44SJohn Forte 		return;
243fcf3ce44SJohn Forte 	}
244291a2b48SSukumar Swaminathan 
245fcf3ce44SJohn Forte 	/* Return if node already open */
24682527734SSukumar Swaminathan 	if (!(ndlp->nlp_flag[channelno] & NLP_CLOSED)) {
24782527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
248fcf3ce44SJohn Forte 
249fcf3ce44SJohn Forte 		return;
250fcf3ce44SJohn Forte 	}
251fcf3ce44SJohn Forte 
252291a2b48SSukumar Swaminathan 	/* Set the node open (not closed) */
25382527734SSukumar Swaminathan 	ndlp->nlp_flag[channelno] &= ~(NLP_CLOSED|NLP_OFFLINE);
254fcf3ce44SJohn Forte 
255fcf3ce44SJohn Forte 	/* Clear the timer */
25682527734SSukumar Swaminathan 	ndlp->nlp_tics[channelno] = 0;
257fcf3ce44SJohn Forte 
258fcf3ce44SJohn Forte 	/*
259291a2b48SSukumar Swaminathan 	 * If the ptx or the tx queue needs servicing and
26082527734SSukumar Swaminathan 	 * the node is not already on the channel queue
261fcf3ce44SJohn Forte 	 */
26282527734SSukumar Swaminathan 	if ((ndlp->nlp_ptx[channelno].q_first ||
26382527734SSukumar Swaminathan 	    ndlp->nlp_tx[channelno].q_first) && !ndlp->nlp_next[channelno]) {
26482527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
265fcf3ce44SJohn Forte 
26682527734SSukumar Swaminathan 		/* If so, then add it to the channel queue */
26782527734SSukumar Swaminathan 		if (cp->nodeq.q_first) {
26882527734SSukumar Swaminathan 			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
269fcf3ce44SJohn Forte 			    (uint8_t *)ndlp;
27082527734SSukumar Swaminathan 			ndlp->nlp_next[channelno] = cp->nodeq.q_first;
271fcf3ce44SJohn Forte 
272291a2b48SSukumar Swaminathan 			/* If this is not the base node then */
273291a2b48SSukumar Swaminathan 			/* add it to the tail */
274fcf3ce44SJohn Forte 			if (!ndlp->nlp_base) {
27582527734SSukumar Swaminathan 				cp->nodeq.q_last = (uint8_t *)ndlp;
276fcf3ce44SJohn Forte 			} else {	/* Otherwise, add it to the head */
277291a2b48SSukumar Swaminathan 
278fcf3ce44SJohn Forte 				/* The command node always gets priority */
27982527734SSukumar Swaminathan 				cp->nodeq.q_first = (uint8_t *)ndlp;
280fcf3ce44SJohn Forte 			}
281fcf3ce44SJohn Forte 
28282527734SSukumar Swaminathan 			cp->nodeq.q_cnt++;
283fcf3ce44SJohn Forte 		} else {
28482527734SSukumar Swaminathan 			cp->nodeq.q_first = (uint8_t *)ndlp;
28582527734SSukumar Swaminathan 			cp->nodeq.q_last = (uint8_t *)ndlp;
28682527734SSukumar Swaminathan 			ndlp->nlp_next[channelno] = ndlp;
28782527734SSukumar Swaminathan 			cp->nodeq.q_cnt = 1;
288fcf3ce44SJohn Forte 		}
289fcf3ce44SJohn Forte 	}
290291a2b48SSukumar Swaminathan 
29182527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
292fcf3ce44SJohn Forte 
293291a2b48SSukumar Swaminathan 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_opened_msg,
294*8f23e9faSHans Rosenfeld 	    "node=%p did=%06x rpi=%d channel=%d", ndlp, ndlp->nlp_DID,
295a9800bebSGarrett D'Amore 	    ndlp->nlp_Rpi, channelno);
296728bdc9bSSukumar Swaminathan 
297fcf3ce44SJohn Forte 	/* If link attention needs to be cleared */
29882527734SSukumar Swaminathan 	if ((hba->state == FC_LINK_UP) && (channelno == hba->channel_fcp)) {
29982527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
30082527734SSukumar Swaminathan 			goto done;
30182527734SSukumar Swaminathan 		}
302fcf3ce44SJohn Forte 
303fcf3ce44SJohn Forte 		/* Scan to see if any FCP2 devices are still closed */
304fcf3ce44SJohn Forte 		found = 0;
305fcf3ce44SJohn Forte 		rw_enter(&port->node_rwlock, RW_READER);
306fcf3ce44SJohn Forte 		for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
307fcf3ce44SJohn Forte 			nlp = port->node_table[i];
308fcf3ce44SJohn Forte 			while (nlp != NULL) {
309fcf3ce44SJohn Forte 				if ((nlp->nlp_fcp_info & NLP_FCP_2_DEVICE) &&
31082527734SSukumar Swaminathan 				    (nlp->nlp_flag[hba->channel_fcp] &
31182527734SSukumar Swaminathan 				    NLP_CLOSED)) {
312fcf3ce44SJohn Forte 					found = 1;
313fcf3ce44SJohn Forte 					break;
314291a2b48SSukumar Swaminathan 
315fcf3ce44SJohn Forte 				}
316fcf3ce44SJohn Forte 				nlp = nlp->nlp_list_next;
317fcf3ce44SJohn Forte 			}
318fcf3ce44SJohn Forte 
319fcf3ce44SJohn Forte 			if (found) {
320fcf3ce44SJohn Forte 				break;
321fcf3ce44SJohn Forte 			}
322fcf3ce44SJohn Forte 		}
323fcf3ce44SJohn Forte 
324fcf3ce44SJohn Forte 		rw_exit(&port->node_rwlock);
325fcf3ce44SJohn Forte 
326fcf3ce44SJohn Forte 		if (!found) {
327fcf3ce44SJohn Forte 			/* Clear link attention */
328291a2b48SSukumar Swaminathan 			if ((mbox = (MAILBOXQ *)emlxs_mem_get(hba,
329*8f23e9faSHans Rosenfeld 			    MEM_MBOX))) {
330fcf3ce44SJohn Forte 				mutex_enter(&EMLXS_PORT_LOCK);
331fcf3ce44SJohn Forte 
332fcf3ce44SJohn Forte 				/*
333291a2b48SSukumar Swaminathan 				 * If state is not FC_LINK_UP, then either the
334291a2b48SSukumar Swaminathan 				 * link has gone down or a FC_CLEAR_LA has
335291a2b48SSukumar Swaminathan 				 * already been issued
336fcf3ce44SJohn Forte 				 */
337fcf3ce44SJohn Forte 				if (hba->state != FC_LINK_UP) {
338fcf3ce44SJohn Forte 					mutex_exit(&EMLXS_PORT_LOCK);
339a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_MBOX,
340a9800bebSGarrett D'Amore 					    (void *)mbox);
341fcf3ce44SJohn Forte 					goto done;
342fcf3ce44SJohn Forte 				}
343291a2b48SSukumar Swaminathan 
34482527734SSukumar Swaminathan 				EMLXS_STATE_CHANGE_LOCKED(hba, FC_CLEAR_LA);
345fcf3ce44SJohn Forte 				hba->discovery_timer = 0;
346fcf3ce44SJohn Forte 				mutex_exit(&EMLXS_PORT_LOCK);
347fcf3ce44SJohn Forte 
34882527734SSukumar Swaminathan 				emlxs_mb_clear_la(hba, mbox);
349fcf3ce44SJohn Forte 
35082527734SSukumar Swaminathan 				rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba,
35182527734SSukumar Swaminathan 				    mbox, MBX_NOWAIT, 0);
35282527734SSukumar Swaminathan 				if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
353a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_MBOX,
354a9800bebSGarrett D'Amore 					    (void *)mbox);
355fcf3ce44SJohn Forte 				}
356fcf3ce44SJohn Forte 			} else {
357291a2b48SSukumar Swaminathan 				/* Close the node and try again */
358291a2b48SSukumar Swaminathan 				/* in a few seconds */
35982527734SSukumar Swaminathan 				emlxs_node_close(port, ndlp, channelno, 5);
360fcf3ce44SJohn Forte 				return;
361fcf3ce44SJohn Forte 			}
362fcf3ce44SJohn Forte 		}
363fcf3ce44SJohn Forte 	}
364291a2b48SSukumar Swaminathan 
365fcf3ce44SJohn Forte done:
366fcf3ce44SJohn Forte 
367fcf3ce44SJohn Forte 	/* Wake any sleeping threads */
368fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PKT_LOCK);
369fcf3ce44SJohn Forte 	cv_broadcast(&EMLXS_PKT_CV);
370fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PKT_LOCK);
371fcf3ce44SJohn Forte 
372fcf3ce44SJohn Forte 	return;
373fcf3ce44SJohn Forte 
37482527734SSukumar Swaminathan } /* emlxs_node_open() */
375fcf3ce44SJohn Forte 
376fcf3ce44SJohn Forte 
377fcf3ce44SJohn Forte static int
emlxs_node_match_did(emlxs_port_t * port,NODELIST * ndlp,uint32_t did)378fcf3ce44SJohn Forte emlxs_node_match_did(emlxs_port_t *port, NODELIST *ndlp, uint32_t did)
379fcf3ce44SJohn Forte {
380fcf3ce44SJohn Forte 	D_ID mydid;
381fcf3ce44SJohn Forte 	D_ID odid;
382fcf3ce44SJohn Forte 	D_ID ndid;
383fcf3ce44SJohn Forte 
384291a2b48SSukumar Swaminathan 	if (ndlp->nlp_DID == did)
385fcf3ce44SJohn Forte 		return (1);
386fcf3ce44SJohn Forte 
387fcf3ce44SJohn Forte 	/*
388fcf3ce44SJohn Forte 	 * Next check for area/domain == 0 match
389fcf3ce44SJohn Forte 	 */
390fcf3ce44SJohn Forte 	mydid.un.word = port->did;
391fcf3ce44SJohn Forte 	if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) {
392fcf3ce44SJohn Forte 		goto out;
393fcf3ce44SJohn Forte 	}
394291a2b48SSukumar Swaminathan 
395fcf3ce44SJohn Forte 	ndid.un.word = did;
396fcf3ce44SJohn Forte 	odid.un.word = ndlp->nlp_DID;
397fcf3ce44SJohn Forte 	if (ndid.un.b.id == odid.un.b.id) {
398fcf3ce44SJohn Forte 		if ((mydid.un.b.domain == ndid.un.b.domain) &&
399fcf3ce44SJohn Forte 		    (mydid.un.b.area == ndid.un.b.area)) {
400fcf3ce44SJohn Forte 			ndid.un.word = ndlp->nlp_DID;
401fcf3ce44SJohn Forte 			odid.un.word = did;
402291a2b48SSukumar Swaminathan 			if ((ndid.un.b.domain == 0) && (ndid.un.b.area == 0)) {
403fcf3ce44SJohn Forte 				return (1);
404fcf3ce44SJohn Forte 			}
405fcf3ce44SJohn Forte 			goto out;
406fcf3ce44SJohn Forte 		}
407291a2b48SSukumar Swaminathan 
408fcf3ce44SJohn Forte 		ndid.un.word = ndlp->nlp_DID;
409fcf3ce44SJohn Forte 		if ((mydid.un.b.domain == ndid.un.b.domain) &&
410fcf3ce44SJohn Forte 		    (mydid.un.b.area == ndid.un.b.area)) {
411fcf3ce44SJohn Forte 			odid.un.word = ndlp->nlp_DID;
412fcf3ce44SJohn Forte 			ndid.un.word = did;
413291a2b48SSukumar Swaminathan 			if ((ndid.un.b.domain == 0) && (ndid.un.b.area == 0)) {
414fcf3ce44SJohn Forte 				return (1);
415fcf3ce44SJohn Forte 			}
416fcf3ce44SJohn Forte 		}
417fcf3ce44SJohn Forte 	}
418291a2b48SSukumar Swaminathan 
419fcf3ce44SJohn Forte out:
420fcf3ce44SJohn Forte 
421fcf3ce44SJohn Forte 	return (0);
422fcf3ce44SJohn Forte 
423*8f23e9faSHans Rosenfeld } /* emlxs_node_match_did() */
424fcf3ce44SJohn Forte 
425fcf3ce44SJohn Forte 
426fcf3ce44SJohn Forte 
427fcf3ce44SJohn Forte extern NODELIST *
emlxs_node_find_mac(emlxs_port_t * port,uint8_t * mac)428fcf3ce44SJohn Forte emlxs_node_find_mac(emlxs_port_t *port, uint8_t *mac)
429fcf3ce44SJohn Forte {
430fcf3ce44SJohn Forte 	NODELIST *nlp;
431fcf3ce44SJohn Forte 	uint32_t i;
432fcf3ce44SJohn Forte 
433fcf3ce44SJohn Forte 	rw_enter(&port->node_rwlock, RW_READER);
434fcf3ce44SJohn Forte 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
435fcf3ce44SJohn Forte 		nlp = port->node_table[i];
436fcf3ce44SJohn Forte 		while (nlp != NULL) {
437fcf3ce44SJohn Forte 			/*
438291a2b48SSukumar Swaminathan 			 * If portname matches mac address,
439291a2b48SSukumar Swaminathan 			 * return NODELIST entry
440fcf3ce44SJohn Forte 			 */
441fcf3ce44SJohn Forte 			if ((nlp->nlp_portname.IEEE[0] == mac[0])) {
44282527734SSukumar Swaminathan 				if ((nlp->nlp_DID != BCAST_DID) &&
44382527734SSukumar Swaminathan 				    ((nlp->nlp_DID & FABRIC_DID_MASK) ==
44482527734SSukumar Swaminathan 				    FABRIC_DID_MASK)) {
445291a2b48SSukumar Swaminathan 					nlp = (NODELIST *)nlp->nlp_list_next;
446fcf3ce44SJohn Forte 					continue;
447fcf3ce44SJohn Forte 				}
448291a2b48SSukumar Swaminathan 
449fcf3ce44SJohn Forte 				if ((nlp->nlp_portname.IEEE[1] == mac[1]) &&
450fcf3ce44SJohn Forte 				    (nlp->nlp_portname.IEEE[2] == mac[2]) &&
451fcf3ce44SJohn Forte 				    (nlp->nlp_portname.IEEE[3] == mac[3]) &&
452fcf3ce44SJohn Forte 				    (nlp->nlp_portname.IEEE[4] == mac[4]) &&
453fcf3ce44SJohn Forte 				    (nlp->nlp_portname.IEEE[5] == mac[5])) {
454fcf3ce44SJohn Forte 					rw_exit(&port->node_rwlock);
455fcf3ce44SJohn Forte 					return (nlp);
456fcf3ce44SJohn Forte 				}
457291a2b48SSukumar Swaminathan 
458fcf3ce44SJohn Forte 			}
459291a2b48SSukumar Swaminathan 
460291a2b48SSukumar Swaminathan 			nlp = (NODELIST *)nlp->nlp_list_next;
461fcf3ce44SJohn Forte 		}
462fcf3ce44SJohn Forte 	}
463fcf3ce44SJohn Forte 	rw_exit(&port->node_rwlock);
464fcf3ce44SJohn Forte 
465fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg,
466291a2b48SSukumar Swaminathan 	    "find: MAC=%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2],
467291a2b48SSukumar Swaminathan 	    mac[3], mac[4], mac[5]);
468fcf3ce44SJohn Forte 
469fcf3ce44SJohn Forte 	return (NULL);
470fcf3ce44SJohn Forte 
47182527734SSukumar Swaminathan } /* emlxs_node_find_mac() */
472fcf3ce44SJohn Forte 
473fcf3ce44SJohn Forte 
474fcf3ce44SJohn Forte extern NODELIST *
emlxs_node_find_did(emlxs_port_t * port,uint32_t did,uint32_t lock)475*8f23e9faSHans Rosenfeld emlxs_node_find_did(emlxs_port_t *port, uint32_t did, uint32_t lock)
476fcf3ce44SJohn Forte {
477fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
478fcf3ce44SJohn Forte 	NODELIST *nlp;
479fcf3ce44SJohn Forte 	uint32_t hash;
480fcf3ce44SJohn Forte 
481fcf3ce44SJohn Forte 	/* Check for invalid node ids  */
482291a2b48SSukumar Swaminathan 	if ((did == 0) && (!(hba->flag & FC_LOOPBACK_MODE))) {
483291a2b48SSukumar Swaminathan 		return ((NODELIST *)0);
484291a2b48SSukumar Swaminathan 	}
485291a2b48SSukumar Swaminathan 
486291a2b48SSukumar Swaminathan 	if (did & 0xff000000) {
487291a2b48SSukumar Swaminathan 		return ((NODELIST *)0);
488fcf3ce44SJohn Forte 	}
489291a2b48SSukumar Swaminathan 
490fcf3ce44SJohn Forte 	/* Check for bcast node */
49182527734SSukumar Swaminathan 	if (did == BCAST_DID) {
492fcf3ce44SJohn Forte 		/* Use the base node here */
493fcf3ce44SJohn Forte 		return (&port->node_base);
494fcf3ce44SJohn Forte 	}
495fcf3ce44SJohn Forte #ifdef MENLO_SUPPORT
496fcf3ce44SJohn Forte 	/* Check for menlo node */
497fcf3ce44SJohn Forte 	if (did == EMLXS_MENLO_DID) {
498fcf3ce44SJohn Forte 		/* Use the base node here */
499fcf3ce44SJohn Forte 		return (&port->node_base);
500fcf3ce44SJohn Forte 	}
501291a2b48SSukumar Swaminathan #endif /* MENLO_SUPPORT */
502fcf3ce44SJohn Forte 
503fcf3ce44SJohn Forte 	/* Check for host node */
504fcf3ce44SJohn Forte 	if (did == port->did && !(hba->flag & FC_LOOPBACK_MODE)) {
505fcf3ce44SJohn Forte 		/* Use the base node here */
506fcf3ce44SJohn Forte 		return (&port->node_base);
507fcf3ce44SJohn Forte 	}
508291a2b48SSukumar Swaminathan 
509fcf3ce44SJohn Forte 	/*
51082527734SSukumar Swaminathan 	 * Convert well known fabric addresses to the FABRIC_DID,
511291a2b48SSukumar Swaminathan 	 * since we don't login to some of them
512fcf3ce44SJohn Forte 	 */
513fcf3ce44SJohn Forte 	if ((did == SCR_DID)) {
51482527734SSukumar Swaminathan 		did = FABRIC_DID;
515fcf3ce44SJohn Forte 	}
516291a2b48SSukumar Swaminathan 
517*8f23e9faSHans Rosenfeld 	if (lock) {
518*8f23e9faSHans Rosenfeld 		rw_enter(&port->node_rwlock, RW_READER);
519*8f23e9faSHans Rosenfeld 	}
520fcf3ce44SJohn Forte 	hash = EMLXS_DID_HASH(did);
521fcf3ce44SJohn Forte 	nlp = port->node_table[hash];
522fcf3ce44SJohn Forte 	while (nlp != NULL) {
523fcf3ce44SJohn Forte 		/* Check for obvious match */
524fcf3ce44SJohn Forte 		if (nlp->nlp_DID == did) {
525*8f23e9faSHans Rosenfeld 			if (lock) {
526*8f23e9faSHans Rosenfeld 				rw_exit(&port->node_rwlock);
527*8f23e9faSHans Rosenfeld 			}
528fcf3ce44SJohn Forte 			return (nlp);
529fcf3ce44SJohn Forte 		}
530291a2b48SSukumar Swaminathan 
531fcf3ce44SJohn Forte 		/* Check for detailed match */
532fcf3ce44SJohn Forte 		else if (emlxs_node_match_did(port, nlp, did)) {
533*8f23e9faSHans Rosenfeld 			if (lock) {
534*8f23e9faSHans Rosenfeld 				rw_exit(&port->node_rwlock);
535*8f23e9faSHans Rosenfeld 			}
536fcf3ce44SJohn Forte 			return (nlp);
537fcf3ce44SJohn Forte 		}
538291a2b48SSukumar Swaminathan 
539291a2b48SSukumar Swaminathan 		nlp = (NODELIST *)nlp->nlp_list_next;
540fcf3ce44SJohn Forte 	}
541*8f23e9faSHans Rosenfeld 
542*8f23e9faSHans Rosenfeld 	if (lock) {
543*8f23e9faSHans Rosenfeld 		rw_exit(&port->node_rwlock);
544*8f23e9faSHans Rosenfeld 	}
545fcf3ce44SJohn Forte 
546291a2b48SSukumar Swaminathan 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, "find: did=%x",
547291a2b48SSukumar Swaminathan 	    did);
548fcf3ce44SJohn Forte 
549fcf3ce44SJohn Forte 	/* no match found */
550291a2b48SSukumar Swaminathan 	return ((NODELIST *)0);
551fcf3ce44SJohn Forte 
55282527734SSukumar Swaminathan } /* emlxs_node_find_did() */
553fcf3ce44SJohn Forte 
554fcf3ce44SJohn Forte 
555fcf3ce44SJohn Forte extern NODELIST *
emlxs_node_find_rpi(emlxs_port_t * port,uint32_t rpi)556fcf3ce44SJohn Forte emlxs_node_find_rpi(emlxs_port_t *port, uint32_t rpi)
557fcf3ce44SJohn Forte {
558fcf3ce44SJohn Forte 	NODELIST *nlp;
559fcf3ce44SJohn Forte 	uint32_t i;
560fcf3ce44SJohn Forte 
561fcf3ce44SJohn Forte 	rw_enter(&port->node_rwlock, RW_READER);
562fcf3ce44SJohn Forte 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
563fcf3ce44SJohn Forte 		nlp = port->node_table[i];
564fcf3ce44SJohn Forte 		while (nlp != NULL) {
565fcf3ce44SJohn Forte 			if (nlp->nlp_Rpi == rpi) {
566fcf3ce44SJohn Forte 				rw_exit(&port->node_rwlock);
567fcf3ce44SJohn Forte 				return (nlp);
568fcf3ce44SJohn Forte 			}
569291a2b48SSukumar Swaminathan 
570291a2b48SSukumar Swaminathan 			nlp = (NODELIST *)nlp->nlp_list_next;
571fcf3ce44SJohn Forte 		}
572fcf3ce44SJohn Forte 	}
573fcf3ce44SJohn Forte 	rw_exit(&port->node_rwlock);
574fcf3ce44SJohn Forte 
575*8f23e9faSHans Rosenfeld 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_not_found_msg, "find: rpi=%d",
576291a2b48SSukumar Swaminathan 	    rpi);
577fcf3ce44SJohn Forte 
578fcf3ce44SJohn Forte 	/* no match found */
579291a2b48SSukumar Swaminathan 	return ((NODELIST *)0);
580fcf3ce44SJohn Forte 
58182527734SSukumar Swaminathan } /* emlxs_node_find_rpi() */
582fcf3ce44SJohn Forte 
583fcf3ce44SJohn Forte 
584fcf3ce44SJohn Forte extern NODELIST *
emlxs_node_find_wwpn(emlxs_port_t * port,uint8_t * wwpn,uint32_t lock)585*8f23e9faSHans Rosenfeld emlxs_node_find_wwpn(emlxs_port_t *port, uint8_t *wwpn, uint32_t lock)
586fcf3ce44SJohn Forte {
587fcf3ce44SJohn Forte 	NODELIST *nlp;
588fcf3ce44SJohn Forte 	uint32_t i;
589fcf3ce44SJohn Forte 	uint32_t j;
590fcf3ce44SJohn Forte 	uint8_t *bptr1;
591fcf3ce44SJohn Forte 	uint8_t *bptr2;
592fcf3ce44SJohn Forte 
593*8f23e9faSHans Rosenfeld 	if (lock) {
594*8f23e9faSHans Rosenfeld 		rw_enter(&port->node_rwlock, RW_READER);
595