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