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-2012 Emulex. All rights reserved.
2482527734SSukumar Swaminathan  * Use is subject to license terms.
25fcf3ce44SJohn Forte  */
26fcf3ce44SJohn Forte 
2793c20f26SSukumar Swaminathan #include <emlxs.h>
28fcf3ce44SJohn Forte 
29fcf3ce44SJohn Forte /* Timer period in seconds */
30fcf3ce44SJohn Forte #define	EMLXS_TIMER_PERIOD		1	/* secs */
31fcf3ce44SJohn Forte #define	EMLXS_PKT_PERIOD		5	/* secs */
32fcf3ce44SJohn Forte #define	EMLXS_UB_PERIOD			60	/* secs */
33fcf3ce44SJohn Forte 
34fcf3ce44SJohn Forte EMLXS_MSG_DEF(EMLXS_CLOCK_C);
35fcf3ce44SJohn Forte 
36fcf3ce44SJohn Forte 
37fcf3ce44SJohn Forte static void emlxs_timer_check_loopback(emlxs_hba_t *hba);
38fcf3ce44SJohn Forte 
39fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
40fcf3ce44SJohn Forte static void emlxs_timer_check_dhchap(emlxs_port_t *port);
41291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
42291a2b48SSukumar Swaminathan 
43*8f23e9faSHans Rosenfeld static void	emlxs_timer_check_pools(emlxs_hba_t *hba);
44291a2b48SSukumar Swaminathan static void	emlxs_timer(void *arg);
456a573d82SSukumar Swaminathan static void	emlxs_timer_check_fw_update(emlxs_hba_t *hba);
46291a2b48SSukumar Swaminathan static void	emlxs_timer_check_heartbeat(emlxs_hba_t *hba);
47291a2b48SSukumar Swaminathan static uint32_t	emlxs_timer_check_pkts(emlxs_hba_t *hba, uint8_t *flag);
48291a2b48SSukumar Swaminathan static void	emlxs_timer_check_nodes(emlxs_port_t *port, uint8_t *flag);
49291a2b48SSukumar Swaminathan static void	emlxs_timer_check_linkup(emlxs_hba_t *hba);
50291a2b48SSukumar Swaminathan static void	emlxs_timer_check_discovery(emlxs_port_t *port);
51*8f23e9faSHans Rosenfeld static void	emlxs_timer_check_clean_address(emlxs_port_t *port);
52291a2b48SSukumar Swaminathan static void	emlxs_timer_check_ub(emlxs_port_t *port);
5382527734SSukumar Swaminathan static void	emlxs_timer_check_channels(emlxs_hba_t *hba, uint8_t *flag);
54291a2b48SSukumar Swaminathan static uint32_t	emlxs_pkt_chip_timeout(emlxs_port_t *port, emlxs_buf_t *sbp,
55291a2b48SSukumar Swaminathan 			Q *abortq, uint8_t *flag);
56fcf3ce44SJohn Forte 
57fcf3ce44SJohn Forte #ifdef TX_WATCHDOG
58291a2b48SSukumar Swaminathan static void	emlxs_tx_watchdog(emlxs_hba_t *hba);
59291a2b48SSukumar Swaminathan #endif /* TX_WATCHDOG */
60fcf3ce44SJohn Forte 
61fcf3ce44SJohn Forte extern clock_t
emlxs_timeout(emlxs_hba_t * hba,uint32_t timeout)62fcf3ce44SJohn Forte emlxs_timeout(emlxs_hba_t *hba, uint32_t timeout)
63fcf3ce44SJohn Forte {
64fcf3ce44SJohn Forte 	emlxs_config_t *cfg = &CFG;
65fcf3ce44SJohn Forte 	clock_t time;
66fcf3ce44SJohn Forte 
67fcf3ce44SJohn Forte 	/* Set thread timeout */
68fcf3ce44SJohn Forte 	if (cfg[CFG_TIMEOUT_ENABLE].current) {
69fcf3ce44SJohn Forte 		(void) drv_getparm(LBOLT, &time);
70fcf3ce44SJohn Forte 		time += (timeout * drv_usectohz(1000000));
71fcf3ce44SJohn Forte 	} else {
72fcf3ce44SJohn Forte 		time = -1;
73fcf3ce44SJohn Forte 	}
74fcf3ce44SJohn Forte 
75fcf3ce44SJohn Forte 	return (time);
76fcf3ce44SJohn Forte 
7782527734SSukumar Swaminathan } /* emlxs_timeout() */
78fcf3ce44SJohn Forte 
79fcf3ce44SJohn Forte 
80fcf3ce44SJohn Forte static void
emlxs_timer(void * arg)81fcf3ce44SJohn Forte emlxs_timer(void *arg)
82fcf3ce44SJohn Forte {
83fcf3ce44SJohn Forte 	emlxs_hba_t *hba = (emlxs_hba_t *)arg;
84*8f23e9faSHans Rosenfeld 	emlxs_port_t *port = &PPORT;
85fcf3ce44SJohn Forte 
86fcf3ce44SJohn Forte 	if (!hba->timer_id) {
87fcf3ce44SJohn Forte 		return;
88fcf3ce44SJohn Forte 	}
89291a2b48SSukumar Swaminathan 
90fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_TIMER_LOCK);
91fcf3ce44SJohn Forte 
92fcf3ce44SJohn Forte 	/* Only one timer thread is allowed */
93fcf3ce44SJohn Forte 	if (hba->timer_flags & EMLXS_TIMER_BUSY) {
94fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_TIMER_LOCK);
95fcf3ce44SJohn Forte 		return;
96fcf3ce44SJohn Forte 	}
97291a2b48SSukumar Swaminathan 
98fcf3ce44SJohn Forte 	/* Check if a kill request has been made */
99fcf3ce44SJohn Forte 	if (hba->timer_flags & EMLXS_TIMER_KILL) {
100fcf3ce44SJohn Forte 		hba->timer_id = 0;
101*8f23e9faSHans Rosenfeld 		hba->timer_tics = 0;
102fcf3ce44SJohn Forte 		hba->timer_flags |= EMLXS_TIMER_ENDED;
103fcf3ce44SJohn Forte 
104fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_TIMER_LOCK);
105fcf3ce44SJohn Forte 		return;
106fcf3ce44SJohn Forte 	}
107291a2b48SSukumar Swaminathan 
108fcf3ce44SJohn Forte 	hba->timer_flags |= (EMLXS_TIMER_BUSY | EMLXS_TIMER_STARTED);
109fcf3ce44SJohn Forte 	hba->timer_tics = DRV_TIME;
110fcf3ce44SJohn Forte 
111*8f23e9faSHans Rosenfeld 	/* Check io_active count (Safety net) */
112*8f23e9faSHans Rosenfeld 	if (hba->io_active & 0x80000000) {
113*8f23e9faSHans Rosenfeld 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
114*8f23e9faSHans Rosenfeld 		    "Timer: io_active=0x%x. Reset to zero.", hba->io_active);
115*8f23e9faSHans Rosenfeld 		hba->io_active = 0;
116*8f23e9faSHans Rosenfeld 	}
117*8f23e9faSHans Rosenfeld 
118fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_TIMER_LOCK);
119fcf3ce44SJohn Forte 
120a9800bebSGarrett D'Amore 	EMLXS_SLI_POLL_ERRATT(hba);
121a9800bebSGarrett D'Amore 
122291a2b48SSukumar Swaminathan 	/* Perform standard checks */
123291a2b48SSukumar Swaminathan 	emlxs_timer_checks(hba);
124291a2b48SSukumar Swaminathan 
125291a2b48SSukumar Swaminathan 	/* Restart the timer */
126291a2b48SSukumar Swaminathan 	mutex_enter(&EMLXS_TIMER_LOCK);
127291a2b48SSukumar Swaminathan 
128291a2b48SSukumar Swaminathan 	hba->timer_flags &= ~EMLXS_TIMER_BUSY;
129291a2b48SSukumar Swaminathan 
130291a2b48SSukumar Swaminathan 	/* If timer is still enabled, restart it */
131291a2b48SSukumar Swaminathan 	if (!(hba->timer_flags & EMLXS_TIMER_KILL)) {
132291a2b48SSukumar Swaminathan 		hba->timer_id =
133291a2b48SSukumar Swaminathan 		    timeout(emlxs_timer, (void *)hba,
134291a2b48SSukumar Swaminathan 		    (EMLXS_TIMER_PERIOD * drv_usectohz(1000000)));
135291a2b48SSukumar Swaminathan 	} else {
136291a2b48SSukumar Swaminathan 		hba->timer_id = 0;
137291a2b48SSukumar Swaminathan 		hba->timer_flags |= EMLXS_TIMER_ENDED;
138291a2b48SSukumar Swaminathan 	}
139291a2b48SSukumar Swaminathan 
140291a2b48SSukumar Swaminathan 	mutex_exit(&EMLXS_TIMER_LOCK);
141291a2b48SSukumar Swaminathan 
142291a2b48SSukumar Swaminathan 	return;
143291a2b48SSukumar Swaminathan 
14482527734SSukumar Swaminathan } /* emlxs_timer() */
145291a2b48SSukumar Swaminathan 
146291a2b48SSukumar Swaminathan 
147291a2b48SSukumar Swaminathan extern void
emlxs_timer_checks(emlxs_hba_t * hba)148291a2b48SSukumar Swaminathan emlxs_timer_checks(emlxs_hba_t *hba)
149291a2b48SSukumar Swaminathan {
150291a2b48SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
15182527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
152291a2b48SSukumar Swaminathan 	uint32_t i;
153291a2b48SSukumar Swaminathan 	uint32_t rc;
154291a2b48SSukumar Swaminathan 
155fcf3ce44SJohn Forte 	/* Exit if we are still initializing */
156fcf3ce44SJohn Forte 	if (hba->state < FC_LINK_DOWN) {
157291a2b48SSukumar Swaminathan 		return;
158fcf3ce44SJohn Forte 	}
159291a2b48SSukumar Swaminathan 
160291a2b48SSukumar Swaminathan 	bzero((void *)flag, sizeof (flag));
161fcf3ce44SJohn Forte 
16282527734SSukumar Swaminathan 	/* Check SLI level timeouts */
16382527734SSukumar Swaminathan 	EMLXS_SLI_TIMER(hba);
16482527734SSukumar Swaminathan 
16582527734SSukumar Swaminathan 	/* Check event queue */
16682527734SSukumar Swaminathan 	emlxs_timer_check_events(hba);
167fcf3ce44SJohn Forte 
168fcf3ce44SJohn Forte 	/* Check heartbeat timer */
169fcf3ce44SJohn Forte 	emlxs_timer_check_heartbeat(hba);
170fcf3ce44SJohn Forte 
1716a573d82SSukumar Swaminathan 	/* Check fw update timer */
1726a573d82SSukumar Swaminathan 	emlxs_timer_check_fw_update(hba);
1736a573d82SSukumar Swaminathan 
174fcf3ce44SJohn Forte #ifdef IDLE_TIMER
175fcf3ce44SJohn Forte 	emlxs_pm_idle_timer(hba);
176291a2b48SSukumar Swaminathan #endif /* IDLE_TIMER */
177fcf3ce44SJohn Forte 
178fcf3ce44SJohn Forte 	/* Check for loopback timeouts */
179fcf3ce44SJohn Forte 	emlxs_timer_check_loopback(hba);
180fcf3ce44SJohn Forte 
181fcf3ce44SJohn Forte 	/* Check for packet timeouts */
182fcf3ce44SJohn Forte 	rc = emlxs_timer_check_pkts(hba, flag);
183fcf3ce44SJohn Forte 
184fcf3ce44SJohn Forte 	if (rc) {
185fcf3ce44SJohn Forte 		/* Link or adapter is being reset */
186291a2b48SSukumar Swaminathan 		return;
187fcf3ce44SJohn Forte 	}
188291a2b48SSukumar Swaminathan 
189fcf3ce44SJohn Forte 	/* Check for linkup timeout */
190fcf3ce44SJohn Forte 	emlxs_timer_check_linkup(hba);
191fcf3ce44SJohn Forte 
192fcf3ce44SJohn Forte 	/* Check the ports */
193fcf3ce44SJohn Forte 	for (i = 0; i < MAX_VPORTS; i++) {
194fcf3ce44SJohn Forte 		port = &VPORT(i);
195fcf3ce44SJohn Forte 
196fcf3ce44SJohn Forte 		if (!(port->flag & EMLXS_PORT_BOUND)) {
197fcf3ce44SJohn Forte 			continue;
198fcf3ce44SJohn Forte 		}
199291a2b48SSukumar Swaminathan 
200fcf3ce44SJohn Forte 		/* Check for node gate timeouts */
201fcf3ce44SJohn Forte 		emlxs_timer_check_nodes(port, flag);
202fcf3ce44SJohn Forte 
203*8f23e9faSHans Rosenfeld 		/* Check for clean address bit delay timeout */
204*8f23e9faSHans Rosenfeld 		emlxs_timer_check_clean_address(port);
205*8f23e9faSHans Rosenfeld 
206fcf3ce44SJohn Forte 		/* Check for tape discovery timeout */
207fcf3ce44SJohn Forte 		emlxs_timer_check_discovery(port);
208fcf3ce44SJohn Forte 
209fcf3ce44SJohn Forte 		/* Check for UB timeouts */
210fcf3ce44SJohn Forte 		emlxs_timer_check_ub(port);
211fcf3ce44SJohn Forte 
212fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
213fcf3ce44SJohn Forte 		/* Check for DHCHAP authentication timeouts */
214fcf3ce44SJohn Forte 		emlxs_timer_check_dhchap(port);
215291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
216fcf3ce44SJohn Forte 
217fcf3ce44SJohn Forte 	}
218fcf3ce44SJohn Forte 
219*8f23e9faSHans Rosenfeld 	/* Check memory pools */
220*8f23e9faSHans Rosenfeld 	emlxs_timer_check_pools(hba);
221*8f23e9faSHans Rosenfeld 
22282527734SSukumar Swaminathan 	/* Check for IO channel service timeouts */
223fcf3ce44SJohn Forte 	/* Always do this last */
22482527734SSukumar Swaminathan 	emlxs_timer_check_channels(hba, flag);
225fcf3ce44SJohn Forte 
226fcf3ce44SJohn Forte 	return;
227fcf3ce44SJohn Forte 
22882527734SSukumar Swaminathan } /* emlxs_timer_checks() */
229fcf3ce44SJohn Forte 
230fcf3ce44SJohn Forte 
231fcf3ce44SJohn Forte extern void
emlxs_timer_start(emlxs_hba_t * hba)232fcf3ce44SJohn Forte emlxs_timer_start(emlxs_hba_t *hba)
233fcf3ce44SJohn Forte {
234fcf3ce44SJohn Forte 	if (hba->timer_id) {
235fcf3ce44SJohn Forte 		return;
236fcf3ce44SJohn Forte 	}
237291a2b48SSukumar Swaminathan 
238fcf3ce44SJohn Forte 	/* Restart the timer */
239fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_TIMER_LOCK);
240fcf3ce44SJohn Forte 	if (!hba->timer_id) {
241fcf3ce44SJohn Forte 		hba->timer_flags = 0;
242291a2b48SSukumar Swaminathan 		hba->timer_id =
243291a2b48SSukumar Swaminathan 		    timeout(emlxs_timer, (void *)hba, drv_usectohz(1000000));
244fcf3ce44SJohn Forte 	}
245fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_TIMER_LOCK);
246fcf3ce44SJohn Forte 
24782527734SSukumar Swaminathan } /* emlxs_timer_start() */
248fcf3ce44SJohn Forte 
249fcf3ce44SJohn Forte 
250fcf3ce44SJohn Forte extern void
emlxs_timer_stop(emlxs_hba_t * hba)251fcf3ce44SJohn Forte emlxs_timer_stop(emlxs_hba_t *hba)
252fcf3ce44SJohn Forte {
253fcf3ce44SJohn Forte 	if (!hba->timer_id) {
254fcf3ce44SJohn Forte 		return;
255fcf3ce44SJohn Forte 	}
256291a2b48SSukumar Swaminathan 
257fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_TIMER_LOCK);
258fcf3ce44SJohn Forte 	hba->timer_flags |= EMLXS_TIMER_KILL;
259fcf3ce44SJohn Forte 
260fcf3ce44SJohn Forte 	while (hba->timer_id) {
261fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_TIMER_LOCK);
262fcf3ce44SJohn Forte 		delay(drv_usectohz(500000));
263fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_TIMER_LOCK);
264fcf3ce44SJohn Forte 	}
265fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_TIMER_LOCK);
266fcf3ce44SJohn Forte 
267fcf3ce44SJohn Forte 	return;
268fcf3ce44SJohn Forte 
26982527734SSukumar Swaminathan } /* emlxs_timer_stop() */
270fcf3ce44SJohn Forte 
271fcf3ce44SJohn Forte 
272fcf3ce44SJohn Forte static uint32_t
emlxs_timer_check_pkts(emlxs_hba_t * hba,uint8_t * flag)273fcf3ce44SJohn Forte emlxs_timer_check_pkts(emlxs_hba_t *hba, uint8_t *flag)
274fcf3ce44SJohn Forte {
275fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
276fcf3ce44SJohn Forte 	emlxs_config_t *cfg = &CFG;
277fcf3ce44SJohn Forte 	Q tmo;
27882527734SSukumar Swaminathan 	int32_t channelno;
27982527734SSukumar Swaminathan 	CHANNEL *cp;
280fcf3ce44SJohn Forte 	NODELIST *nlp;
281fcf3ce44SJohn Forte 	IOCBQ *prev;
282fcf3ce44SJohn Forte 	IOCBQ *next;
283fcf3ce44SJohn Forte 	IOCB *iocb;
284fcf3ce44SJohn Forte 	IOCBQ *iocbq;
285fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
286fcf3ce44SJohn Forte 	fc_packet_t *pkt;
287fcf3ce44SJohn Forte 	Q abort;
288fcf3ce44SJohn Forte 	uint32_t iotag;
289fcf3ce44SJohn Forte 	uint32_t rc;
290fcf3ce44SJohn Forte 
291fcf3ce44SJohn Forte 	if (!cfg[CFG_TIMEOUT_ENABLE].current) {
292fcf3ce44SJohn Forte 		return (0);
293fcf3ce44SJohn Forte 	}
294291a2b48SSukumar Swaminathan 
295fcf3ce44SJohn Forte 	if (hba->pkt_timer > hba->timer_tics) {
296fcf3ce44SJohn Forte 		return (0);
297fcf3ce44SJohn Forte 	}
298291a2b48SSukumar Swaminathan 
299fcf3ce44SJohn Forte 	hba->pkt_timer = hba->timer_tics + EMLXS_PKT_PERIOD;
300fcf3ce44SJohn Forte 
301fcf3ce44SJohn Forte 
302291a2b48SSukumar Swaminathan 	bzero((void *)&tmo, sizeof (Q));
303fcf3ce44SJohn Forte 
304fcf3ce44SJohn Forte 	/*
305fcf3ce44SJohn Forte 	 * We must hold the locks here because we never know when an iocb
306fcf3ce44SJohn Forte 	 * will be removed out from under us
307fcf3ce44SJohn Forte 	 */
308fcf3ce44SJohn Forte 
30982527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
310fcf3ce44SJohn Forte 
31182527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
31282527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
313fcf3ce44SJohn Forte 
31482527734SSukumar Swaminathan 		/* Scan the tx queues for each active node on the channel */
315fcf3ce44SJohn Forte 
316fcf3ce44SJohn Forte 		/* Get the first node */
31782527734SSukumar Swaminathan 		nlp = (NODELIST *)cp->nodeq.q_first;
318fcf3ce44SJohn Forte 
319fcf3ce44SJohn Forte 		while (nlp) {
320fcf3ce44SJohn Forte 			/* Scan the node's priority tx queue */
321fcf3ce44SJohn Forte 			prev = NULL;
32282527734SSukumar Swaminathan 			iocbq = (IOCBQ *)nlp->nlp_ptx[channelno].q_first;
323fcf3ce44SJohn Forte 
324fcf3ce44SJohn Forte 			while (iocbq) {
325fcf3ce44SJohn Forte 				next = (IOCBQ *)iocbq->next;
326fcf3ce44SJohn Forte 				iocb = &iocbq->iocb;
327fcf3ce44SJohn Forte 				sbp = (emlxs_buf_t *)iocbq->sbp;
328fcf3ce44SJohn Forte 
329fcf3ce44SJohn Forte 				/* Check if iocb has timed out */
330fcf3ce44SJohn Forte 				if (sbp && hba->timer_tics >= sbp->ticks) {
331fcf3ce44SJohn Forte 					/* iocb timed out, now deque it */
332fcf3ce44SJohn Forte 					if (next == NULL) {
33382527734SSukumar Swaminathan 						nlp->nlp_ptx[channelno].q_last =
334fcf3ce44SJohn Forte 						    (uint8_t *)prev;
335fcf3ce44SJohn Forte 					}
336291a2b48SSukumar Swaminathan 
337fcf3ce44SJohn Forte 					if (prev == NULL) {
33882527734SSukumar Swaminathan 						nlp->nlp_ptx[channelno].
33982527734SSukumar Swaminathan 						    q_first = (uint8_t *)next;
340fcf3ce44SJohn Forte 					} else {
341fcf3ce44SJohn Forte 						prev->next = next;
342fcf3ce44SJohn Forte 					}
343fcf3ce44SJohn Forte 
344fcf3ce44SJohn Forte 					iocbq->next = NULL;
34582527734SSukumar Swaminathan 					nlp->nlp_ptx[channelno].q_cnt--;
346fcf3ce44SJohn Forte 
347291a2b48SSukumar Swaminathan 					/* Add this iocb to our local */
348291a2b48SSukumar Swaminathan 					/* timout queue */
349fcf3ce44SJohn Forte 
350fcf3ce44SJohn Forte 					/*
35182527734SSukumar Swaminathan 					 * This way we don't hold the TX_CHANNEL
352fcf3ce44SJohn Forte 					 * lock too long
353fcf3ce44SJohn Forte 					 */
354fcf3ce44SJohn Forte 
355fcf3ce44SJohn Forte 					if (tmo.q_first) {
356fcf3ce44SJohn Forte 						((IOCBQ *)tmo.q_last)->next =
357fcf3ce44SJohn Forte 						    iocbq;
358291a2b48SSukumar Swaminathan 						tmo.q_last =
359291a2b48SSukumar Swaminathan 						    (uint8_t *)iocbq;
360fcf3ce44SJohn Forte 						tmo.q_cnt++;
361fcf3ce44SJohn Forte 					} else {
362291a2b48SSukumar Swaminathan 						tmo.q_first =
363291a2b48SSukumar Swaminathan 						    (uint8_t *)iocbq;
364291a2b48SSukumar Swaminathan 						tmo.q_last =
365291a2b48SSukumar Swaminathan 						    (uint8_t *)iocbq;
366fcf3ce44SJohn Forte 						tmo.q_cnt = 1;
367fcf3ce44SJohn Forte 					}
368fcf3ce44SJohn Forte 					iocbq->next = NULL;
369fcf3ce44SJohn Forte 
370fcf3ce44SJohn Forte 				} else {
371fcf3ce44SJohn Forte 					prev = iocbq;
372fcf3ce44SJohn Forte 				}
373fcf3ce44SJohn Forte 
374fcf3ce44SJohn Forte 				iocbq = next;
375fcf3ce44SJohn Forte 
376fcf3ce44SJohn Forte 			}	/* while (iocbq) */
377fcf3ce44SJohn Forte 
378fcf3ce44SJohn Forte 
379fcf3ce44SJohn Forte 			/* Scan the node's tx queue */
380fcf3ce44SJohn Forte 			prev = NULL;
38182527734SSukumar Swaminathan 			iocbq = (IOCBQ *)nlp->nlp_tx[channelno].q_first;
382fcf3ce44SJohn Forte 
383fcf3ce44SJohn Forte 			while (iocbq) {
384fcf3ce44SJohn Forte 				next = (IOCBQ *)iocbq->next;
385fcf3ce44SJohn Forte 				iocb = &iocbq->iocb;
386fcf3ce44SJohn Forte 				sbp = (emlxs_buf_t *)iocbq->sbp;
387fcf3ce44SJohn Forte 
388fcf3ce44SJohn Forte 				/* Check if iocb has timed out */
389fcf3ce44SJohn Forte 				if (sbp && hba->timer_tics >= sbp->ticks) {
390fcf3ce44SJohn Forte 					/* iocb timed out, now deque it */
391fcf3ce44SJohn Forte 					if (next == NULL) {
39282527734SSukumar Swaminathan 						nlp->nlp_tx[channelno].q_last =
393fcf3ce44SJohn Forte 						    (uint8_t *)prev;
394fcf3ce44SJohn Forte 					}
395291a2b48SSukumar Swaminathan 
396fcf3ce44SJohn Forte 					if (prev == NULL) {
39782527734SSukumar Swaminathan 						nlp->nlp_tx[channelno].q_first =
398fcf3ce44SJohn Forte 						    (uint8_t *)next;
399fcf3ce44SJohn Forte 					} else {
400fcf3ce44SJohn Forte 						prev->next = next;
401fcf3ce44SJohn Forte 					}
402fcf3ce44SJohn Forte 
403fcf3ce44SJohn Forte 					iocbq->next = NULL;
40482527734SSukumar Swaminathan 					nlp->nlp_tx[channelno].q_cnt--;
405fcf3ce44SJohn Forte 
406291a2b48SSukumar Swaminathan 					/* Add this iocb to our local */
407291a2b48SSukumar Swaminathan 					/* timout queue */
408fcf3ce44SJohn Forte 
409fcf3ce44SJohn Forte 					/*
41082527734SSukumar Swaminathan 					 * This way we don't hold the TX_CHANNEL
411fcf3ce44SJohn Forte 					 * lock too long
412fcf3ce44SJohn Forte 					 */
413fcf3ce44SJohn Forte 
414fcf3ce44SJohn Forte 					if (tmo.q_first) {
415fcf3ce44SJohn Forte 						((IOCBQ *)tmo.q_last)->next =
416fcf3ce44SJohn Forte 						    iocbq;
417291a2b48SSukumar Swaminathan 						tmo.q_last =
418291a2b48SSukumar Swaminathan 						    (uint8_t *)iocbq;
419fcf3ce44SJohn Forte 						tmo.q_cnt++;
420fcf3ce44SJohn Forte 					} else {
421291a2b48SSukumar Swaminathan 						tmo.q_first =
422291a2b48SSukumar Swaminathan 						    (uint8_t *)iocbq;
423291a2b48SSukumar Swaminathan 						tmo.q_last =
424291a2b48SSukumar Swaminathan 						    (uint8_t *)iocbq;
425fcf3ce44SJohn Forte 						tmo.q_cnt = 1;
426fcf3ce44SJohn Forte 					}
427fcf3ce44SJohn Forte 					iocbq->next = NULL;
428fcf3ce44SJohn Forte 
429fcf3ce44SJohn Forte 				} else {
430fcf3ce44SJohn Forte 					prev = iocbq;
431fcf3ce44SJohn Forte 				}
432fcf3ce44SJohn Forte 
433fcf3ce44SJohn Forte 				iocbq = next;
434fcf3ce44SJohn Forte 
435fcf3ce44SJohn Forte 			}	/* while (iocbq) */
436fcf3ce44SJohn Forte 
43782527734SSukumar Swaminathan 			if (nlp == (NODELIST *)cp->nodeq.q_last) {
438fcf3ce44SJohn Forte 				nlp = NULL;
439fcf3ce44SJohn Forte 			} else {
44082527734SSukumar Swaminathan 				nlp = nlp->nlp_next[channelno];
441fcf3ce44SJohn Forte 			}
442fcf3ce44SJohn Forte 
44382527734SSukumar Swaminathan 		}	/* while (nlp) */
444fcf3ce44SJohn Forte 
445fcf3ce44SJohn Forte 	}	/* end of for */
446fcf3ce44SJohn Forte 
447fcf3ce44SJohn Forte 	/* Now cleanup the iocb's */
448fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)tmo.q_first;
449fcf3ce44SJohn Forte 	while (iocbq) {
450fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
451fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
45282527734SSukumar Swaminathan 		channelno = ((CHANNEL *)iocbq->channel)->channelno;
45382527734SSukumar Swaminathan 		sbp = iocbq->sbp;
454fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
45582527734SSukumar Swaminathan 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
456*8f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
45782527734SSukumar Swaminathan 			} else {
45882527734SSukumar Swaminathan 				(void) emlxs_unregister_pkt(
45982527734SSukumar Swaminathan 				    (CHANNEL *)iocbq->channel,
46082527734SSukumar Swaminathan 				    iocb->ULPIOTAG, 0);
461fcf3ce44SJohn Forte 			}
46282527734SSukumar Swaminathan 
46382527734SSukumar Swaminathan 			mutex_enter(&sbp->mtx);
464fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_TIMEOUT;
465fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
466fcf3ce44SJohn Forte 		}
467291a2b48SSukumar Swaminathan 
468fcf3ce44SJohn Forte 		iocbq = (IOCBQ *)iocbq->next;
469fcf3ce44SJohn Forte 
470fcf3ce44SJohn Forte 	}	/* end of while */
471fcf3ce44SJohn Forte 
47282527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
473fcf3ce44SJohn Forte 
474fcf3ce44SJohn Forte 	/* Now complete the transmit timeouts outside the locks */
475fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)tmo.q_first;
476fcf3ce44SJohn Forte 	while (iocbq) {
477fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
478fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
479fcf3ce44SJohn Forte 
480fcf3ce44SJohn Forte 		/* Unlink this iocbq */
481fcf3ce44SJohn Forte 		iocbq->next = NULL;
482fcf3ce44SJohn Forte 
483fcf3ce44SJohn Forte 		/* Get the pkt */
484fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
485fcf3ce44SJohn Forte 
486fcf3ce44SJohn Forte 		if (sbp) {
487291a2b48SSukumar Swaminathan 			/* Warning: Some FCT sbp's don't have */
488291a2b48SSukumar Swaminathan 			/* fc_packet objects */
489fcf3ce44SJohn Forte 			pkt = PRIV2PKT(sbp);
490fcf3ce44SJohn Forte 
491fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_timeout_msg,
492*8f23e9faSHans Rosenfeld 			    "TXQ abort: sbp=%p iotag=%d tmo=%d", sbp,
493fcf3ce44SJohn Forte 			    sbp->iotag, (pkt) ? pkt->pkt_timeout : 0);
494fcf3ce44SJohn Forte 
495fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
496fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
497fcf3ce44SJohn Forte 				    IOERR_ABORT_TIMEOUT, 1);
498fcf3ce44SJohn Forte 			} else {
499fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
500fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
501fcf3ce44SJohn Forte 			}
502291a2b48SSukumar Swaminathan 
503fcf3ce44SJohn Forte 		}
504291a2b48SSukumar Swaminathan 
505fcf3ce44SJohn Forte 		iocbq = next;
506fcf3ce44SJohn Forte 
507fcf3ce44SJohn Forte 	}	/* end of while */
508fcf3ce44SJohn Forte 
509fcf3ce44SJohn Forte 
510fcf3ce44SJohn Forte 
511fcf3ce44SJohn Forte 	/* Now check the chip */
512291a2b48SSukumar Swaminathan 	bzero((void *)&abort, sizeof (Q));
513fcf3ce44SJohn Forte 
51482527734SSukumar Swaminathan 	/* Check the HBA for outstanding IOs */
515fcf3ce44SJohn Forte 	rc = 0;
51682527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
51782527734SSukumar Swaminathan 	for (iotag = 1; iotag < hba->max_iotag; iotag++) {
51882527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
519a9800bebSGarrett D'Amore 
520*8f23e9faSHans Rosenfeld 		if (!sbp || sbp == STALE_PACKET) {
521a9800bebSGarrett D'Amore 			continue;
522a9800bebSGarrett D'Amore 		}
523a9800bebSGarrett D'Amore 
524a9800bebSGarrett D'Amore 		/* Check if IO is valid */
525a9800bebSGarrett D'Amore 		if (!(sbp->pkt_flags & PACKET_VALID) ||
526a9800bebSGarrett D'Amore 		    (sbp->pkt_flags & (PACKET_ULP_OWNED|
527a9800bebSGarrett D'Amore 		    PACKET_COMPLETED|PACKET_IN_COMPLETION))) {
528a9800bebSGarrett D'Amore 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
529*8f23e9faSHans Rosenfeld 			    "timer_check_pkts: Invalid IO found. iotag=%d",
530a9800bebSGarrett D'Amore 			    iotag);
531a9800bebSGarrett D'Amore 
532a9800bebSGarrett D'Amore 			hba->fc_table[iotag] = STALE_PACKET;
533a9800bebSGarrett D'Amore 			hba->io_count--;
534a9800bebSGarrett D'Amore 			continue;
535a9800bebSGarrett D'Amore 		}
536a9800bebSGarrett D'Amore 
537a9800bebSGarrett D'Amore 		if ((sbp->pkt_flags & PACKET_IN_CHIPQ) &&
53882527734SSukumar Swaminathan 		    (hba->timer_tics >= sbp->ticks)) {
53982527734SSukumar Swaminathan 			rc = emlxs_pkt_chip_timeout(sbp->iocbq.port,
54082527734SSukumar Swaminathan 			    sbp, &abort, flag);
54182527734SSukumar Swaminathan 
54282527734SSukumar Swaminathan 			if (rc) {
54382527734SSukumar Swaminathan 				break;
544fcf3ce44SJohn Forte 			}
545fcf3ce44SJohn Forte 		}
546fcf3ce44SJohn Forte 	}
54782527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
548fcf3ce44SJohn Forte 
549fcf3ce44SJohn Forte 	/* Now put the iocb's on the tx queue */
550fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
551fcf3ce44SJohn Forte 	while (iocbq) {
552fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
553fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
554fcf3ce44SJohn Forte 
555fcf3ce44SJohn Forte 		/* Unlink this iocbq */
556fcf3ce44SJohn Forte 		iocbq->next = NULL;
557fcf3ce44SJohn Forte 
558fcf3ce44SJohn Forte 		/* Send this iocbq */
559fcf3ce44SJohn Forte 		emlxs_tx_put(iocbq, 1);
560fcf3ce44SJohn Forte 
561fcf3ce44SJohn Forte 		iocbq = next;
562fcf3ce44SJohn Forte 	}
563fcf3ce44SJohn Forte 
56482527734SSukumar Swaminathan 	/* Now trigger IO channel service to send these abort iocbq */
56582527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
56682527734SSukumar Swaminathan 		if (!flag[channelno]) {
56782527734SSukumar Swaminathan 			continue;
56882527734SSukumar Swaminathan 		}
56982527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
57082527734SSukumar Swaminathan 
57182527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, 0);
57282527734SSukumar Swaminathan 	}
57382527734SSukumar Swaminathan 
574fcf3ce44SJohn Forte 	if (rc == 1) {
575*8f23e9faSHans Rosenfeld 		mutex_enter(&EMLXS_PORT_LOCK);
576*8f23e9faSHans Rosenfeld 		/* If a link reset or port reset is already requested, exit */
577*8f23e9faSHans Rosenfeld 		if (!(hba->reset_request & (FC_LINK_RESET | FC_PORT_RESET))) {
578*8f23e9faSHans Rosenfeld 			hba->reset_request |= FC_LINK_RESET;
579*8f23e9faSHans Rosenfeld 			mutex_exit(&EMLXS_PORT_LOCK);
580*8f23e9faSHans Rosenfeld 			/* Spawn a thread to reset the link */
581*8f23e9faSHans Rosenfeld 			emlxs_thread_spawn(hba, emlxs_reset_link_thread, NULL,
582*8f23e9faSHans Rosenfeld 			    NULL);
583*8f23e9faSHans Rosenfeld 			goto exit;
584*8f23e9faSHans Rosenfeld 		}
585*8f23e9faSHans Rosenfeld 		mutex_exit(&EMLXS_PORT_LOCK);
586fcf3ce44SJohn Forte 	} else if (rc == 2) {
587*8f23e9faSHans Rosenfeld 		mutex_enter(&EMLXS_PORT_LOCK);
588*8f23e9faSHans Rosenfeld 		/* If a port reset is already requested, exit */
589*8f23e9faSHans Rosenfeld 		if (!(hba->reset_request & FC_PORT_RESET)) {
590*8f23e9faSHans Rosenfeld 			hba->reset_request |= FC_PORT_RESET;
591*8f23e9faSHans Rosenfeld 			mutex_exit(&EMLXS_PORT_LOCK);
592*8f23e9faSHans Rosenfeld 			/* Spawn a thread to reset the adapter */
593*8f23e9faSHans Rosenfeld 			emlxs_thread_spawn(hba, emlxs_restart_thread, NULL,
594*8f23e9faSHans Rosenfeld 			    NULL);
595*8f23e9faSHans Rosenfeld 			goto exit;
596*8f23e9faSHans Rosenfeld 		}
597*8f23e9faSHans Rosenfeld 		mutex_exit(&EMLXS_PORT_LOCK);
598fcf3ce44SJohn Forte 	}
599291a2b48SSukumar Swaminathan 
600*8f23e9faSHans Rosenfeld exit:
601fcf3ce44SJohn Forte 	return (rc);
602fcf3ce44SJohn Forte 
60382527734SSukumar Swaminathan } /* emlxs_timer_check_pkts() */
604fcf3ce44SJohn Forte 
605fcf3ce44SJohn Forte 
606fcf3ce44SJohn Forte static void
emlxs_timer_check_channels(emlxs_hba_t * hba,uint8_t * flag)60782527734SSukumar Swaminathan emlxs_timer_check_channels(emlxs_hba_t *hba, uint8_t *flag)
608fcf3ce44SJohn Forte {
609fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
610fcf3ce44SJohn Forte 	emlxs_config_t *cfg = &CFG;
61182527734SSukumar Swaminathan 	int32_t channelno;
61282527734SSukumar Swaminathan 	CHANNEL *cp;
61382527734SSukumar Swaminathan 	uint32_t logit;
614fcf3ce44SJohn Forte 
615fcf3ce44SJohn Forte 	if (!cfg[CFG_TIMEOUT_ENABLE].current) {
616fcf3ce44SJohn Forte 		return;
617fcf3ce44SJohn Forte 	}
618291a2b48SSukumar Swaminathan 
61982527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
62082527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
62182527734SSukumar Swaminathan 
62282527734SSukumar Swaminathan 		logit = 0;
623fcf3ce44SJohn Forte 
62482527734SSukumar Swaminathan 		/* Check for channel timeout now */
62582527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
62682527734SSukumar Swaminathan 		if (cp->timeout && (hba->timer_tics >= cp->timeout)) {
62782527734SSukumar Swaminathan 			/* Check if there is work to do on channel and */
628fcf3ce44SJohn Forte 			/* the link is still up */
62982527734SSukumar Swaminathan 			if (cp->nodeq.q_first) {
63082527734SSukumar Swaminathan 				flag[channelno] = 1;
63182527734SSukumar Swaminathan 				cp->timeout = hba->timer_tics + 10;
632fcf3ce44SJohn Forte 
633fcf3ce44SJohn Forte 				if (hba->state >= FC_LINK_UP) {
634728bdc9bSSukumar Swaminathan 					logit = 1;
635fcf3ce44SJohn Forte 				}
636fcf3ce44SJohn Forte 			} else {
63782527734SSukumar Swaminathan 				cp->timeout = 0;
638fcf3ce44SJohn Forte 			}
639fcf3ce44SJohn Forte 		}
64082527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
641fcf3ce44SJohn Forte 
642728bdc9bSSukumar Swaminathan 		if (logit) {
643728bdc9bSSukumar Swaminathan 			EMLXS_MSGF(EMLXS_CONTEXT,
64482527734SSukumar Swaminathan 			    &emlxs_chan_watchdog_msg,
64582527734SSukumar Swaminathan 			    "IO Channel %d cnt=%d,%d",
64682527734SSukumar Swaminathan 			    channelno,
64782527734SSukumar Swaminathan 			    hba->channel_tx_count,
64882527734SSukumar Swaminathan 			    hba->io_count);
649728bdc9bSSukumar Swaminathan 		}
650728bdc9bSSukumar Swaminathan 
651fcf3ce44SJohn Forte 		/*
65282527734SSukumar Swaminathan 		 * If IO channel flag is set, request iocb servicing
65382527734SSukumar Swaminathan 		 * here to send any iocb's that may still be queued
654fcf3ce44SJohn Forte 		 */
65582527734SSukumar Swaminathan 		if (flag[channelno]) {
65682527734SSukumar Swaminathan 			EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, 0);
657fcf3ce44SJohn Forte 		}
658fcf3ce44SJohn Forte 	}
659fcf3ce44SJohn Forte 
660fcf3ce44SJohn Forte 	return;
661fcf3ce44SJohn Forte 
66282527734SSukumar Swaminathan } /* emlxs_timer_check_channels() */
663fcf3ce44SJohn Forte 
664fcf3ce44SJohn Forte 
665fcf3ce44SJohn Forte static void
emlxs_timer_check_nodes(emlxs_port_t * port,uint8_t * flag)666fcf3ce44SJohn Forte emlxs_timer_check_nodes(emlxs_port_t *port, uint8_t *flag)
667fcf3ce44SJohn Forte {
668fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
669fcf3ce44SJohn Forte 	uint32_t found;
670fcf3ce44SJohn Forte 	uint32_t i;
671fcf3ce44SJohn Forte 	NODELIST *nlp;
67282527734SSukumar Swaminathan 	int32_t channelno;
673fcf3ce44SJohn Forte 
674fcf3ce44SJohn Forte 	for (;;) {
675fcf3ce44SJohn Forte 		/* Check node gate flag for expiration */
676fcf3ce44SJohn Forte 		found = 0;
677fcf3ce44SJohn Forte 
678fcf3ce44SJohn Forte 		/*
679291a2b48SSukumar Swaminathan 		 * We need to lock, scan, and unlock because we can't hold the
680291a2b48SSukumar Swaminathan 		 * lock while we call node_open
681fcf3ce44SJohn Forte 		 */
682fcf3ce44SJohn Forte 		rw_enter(&port->node_rwlock, RW_READER);
683fcf3ce44SJohn Forte 		for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
684fcf3ce44SJohn Forte 			nlp = port->node_table[i];
685