1507c3241Smlf /*
2507c3241Smlf * CDDL HEADER START
3507c3241Smlf *
4507c3241Smlf * The contents of this file are subject to the terms of the
5507c3241Smlf * Common Development and Distribution License (the "License").
6507c3241Smlf * You may not use this file except in compliance with the License.
7507c3241Smlf *
8507c3241Smlf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9507c3241Smlf * or http://www.opensolaris.org/os/licensing.
10507c3241Smlf * See the License for the specific language governing permissions
11507c3241Smlf * and limitations under the License.
12507c3241Smlf *
13507c3241Smlf * When distributing Covered Code, include this CDDL HEADER in each
14507c3241Smlf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15507c3241Smlf * If applicable, add the following below this CDDL HEADER, with the
16507c3241Smlf * fields enclosed by brackets "[]" replaced with your own identifying
17507c3241Smlf * information: Portions Copyright [yyyy] [name of copyright owner]
18507c3241Smlf *
19507c3241Smlf * CDDL HEADER END
20507c3241Smlf */
21507c3241Smlf
22507c3241Smlf /*
23903a11ebSrh * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24507c3241Smlf * Use is subject to license terms.
25507c3241Smlf */
26507c3241Smlf
27507c3241Smlf
28507c3241Smlf #include <sys/types.h>
29507c3241Smlf #include <sys/conf.h>
30507c3241Smlf #include <sys/ddi.h>
31507c3241Smlf #include <sys/sunddi.h>
32507c3241Smlf #include <sys/ksynch.h>
33507c3241Smlf #include <sys/scsi/conf/autoconf.h>
34507c3241Smlf #include <sys/reboot.h>
35507c3241Smlf
36507c3241Smlf #include "ghd.h"
37507c3241Smlf
38507c3241Smlf /*
39507c3241Smlf * Local functions
40507c3241Smlf */
41507c3241Smlf
42507c3241Smlf static gcmd_t *ghd_timeout_get(ccc_t *cccp);
43507c3241Smlf static int ghd_timeout_loop(ccc_t *cccp);
44507c3241Smlf static uint_t ghd_timeout_softintr(caddr_t arg);
45507c3241Smlf static void ghd_timeout(void *arg);
46507c3241Smlf static void ghd_timeout_disable(tmr_t *tmrp);
47507c3241Smlf static void ghd_timeout_enable(tmr_t *tmrp);
48507c3241Smlf
49507c3241Smlf /*
50507c3241Smlf * Local data
51507c3241Smlf */
52507c3241Smlf long ghd_HZ;
53507c3241Smlf static kmutex_t tglobal_mutex;
54507c3241Smlf
55507c3241Smlf /* table of timeouts for abort processing steps */
56507c3241Smlf cmdstate_t ghd_timeout_table[GCMD_NSTATES];
57507c3241Smlf
58507c3241Smlf /* This table indirectly initializes the ghd_timeout_table */
59507c3241Smlf struct {
60507c3241Smlf int valid;
61507c3241Smlf cmdstate_t state;
62507c3241Smlf long value;
63507c3241Smlf } ghd_time_inits[] = {
64507c3241Smlf { TRUE, GCMD_STATE_ABORTING_CMD, 3 },
65507c3241Smlf { TRUE, GCMD_STATE_ABORTING_DEV, 3 },
66507c3241Smlf { TRUE, GCMD_STATE_RESETTING_DEV, 5 },
67507c3241Smlf { TRUE, GCMD_STATE_RESETTING_BUS, 10 },
68507c3241Smlf { TRUE, GCMD_STATE_HUNG, 60},
69507c3241Smlf { FALSE, 0, 0 }, /* spare entry */
70507c3241Smlf { FALSE, 0, 0 }, /* spare entry */
71507c3241Smlf { FALSE, 0, 0 }, /* spare entry */
72507c3241Smlf { FALSE, 0, 0 }, /* spare entry */
73507c3241Smlf { FALSE, 0, 0 } /* spare entry */
74507c3241Smlf };
75507c3241Smlf int ghd_ntime_inits = sizeof (ghd_time_inits)
76507c3241Smlf / sizeof (ghd_time_inits[0]);
77507c3241Smlf
78507c3241Smlf /*
79507c3241Smlf * Locally-used macros
80507c3241Smlf */
81507c3241Smlf
82507c3241Smlf /*
83507c3241Smlf * Compare two gcmd_t's to see if they're for the same device (same gdev_t)
84507c3241Smlf */
85507c3241Smlf #define GCMD_SAME_DEV(gcmdp1, gcmdp2) \
86507c3241Smlf (GCMDP2GDEVP(gcmdp1) == GCMDP2GDEVP(gcmdp2))
87507c3241Smlf
88507c3241Smlf /*
89507c3241Smlf * Compare two gcmd_t's to see if they're for the same bus (same HBA inst)
90507c3241Smlf */
91507c3241Smlf #define GCMD_SAME_BUS(gcmdp1, gcmdp2) \
92507c3241Smlf (GCMDP2CCCP(gcmdp1) == GCMDP2CCCP(gcmdp2))
93507c3241Smlf
94507c3241Smlf
95507c3241Smlf /*
96507c3241Smlf * Update state of gcmdp (in one direction, increasing state number, only)
97507c3241Smlf */
98*1bff1300SToomas Soome #define GCMD_UPDATE_STATE(gcmdp, newstate) \
99507c3241Smlf { \
100507c3241Smlf if ((gcmdp)->cmd_state < (newstate)) { \
101507c3241Smlf ((gcmdp)->cmd_state = (newstate)); \
102507c3241Smlf } \
103507c3241Smlf }
104507c3241Smlf
105507c3241Smlf #ifdef ___notyet___
106507c3241Smlf
107507c3241Smlf #include <sys/modctl.h>
108507c3241Smlf extern struct mod_ops mod_miscops;
109507c3241Smlf static struct modlmisc modlmisc = {
110507c3241Smlf &mod_miscops, /* Type of module */
111507c3241Smlf "CCB Timeout Utility Routines"
112507c3241Smlf };
113507c3241Smlf static struct modlinkage modlinkage = {
114507c3241Smlf MODREV_1, (void *)&modlmisc, NULL
115507c3241Smlf };
116507c3241Smlf
117507c3241Smlf /*
118507c3241Smlf * If this is a loadable module then there's a single CCB timer configure
119507c3241Smlf * structure for all HBA drivers (rather than one per HBA driver).
120507c3241Smlf */
121507c3241Smlf static tmr_t tmr_conf;
122507c3241Smlf
123507c3241Smlf int
_init()124507c3241Smlf _init()
125507c3241Smlf {
126507c3241Smlf int err;
127507c3241Smlf
128507c3241Smlf ghd_timer_init(&tmr_conf, 0);
129507c3241Smlf return ((err = mod_install(&modlinkage)) != 0)
130903a11ebSrh ghd_timer_fini(&tmr_conf);
131507c3241Smlf return (err);
132507c3241Smlf }
133507c3241Smlf
134507c3241Smlf int
_fini()135507c3241Smlf _fini()
136507c3241Smlf {
137507c3241Smlf int err;
138507c3241Smlf
139507c3241Smlf if ((err = mod_remove(&modlinkage)) == 0)
140507c3241Smlf ghd_timer_fini(&tmr_conf);
141507c3241Smlf return (err);
142507c3241Smlf }
143507c3241Smlf
144507c3241Smlf int
_info(struct modinfo * modinfop)145507c3241Smlf _info(struct modinfo *modinfop)
146507c3241Smlf {
147507c3241Smlf return (mod_info(&modlinkage, modinfop));
148507c3241Smlf }
149507c3241Smlf
150507c3241Smlf #endif /* ___notyet___ */
151507c3241Smlf
152507c3241Smlf
153507c3241Smlf
154507c3241Smlf /*
155507c3241Smlf *
156507c3241Smlf * ghd_timeout_loop()
157507c3241Smlf *
158507c3241Smlf * Check the CCB timer value for every active CCB for this
159507c3241Smlf * HBA driver instance.
160507c3241Smlf *
161507c3241Smlf * This function is called both by the ghd_timeout() interrupt
162507c3241Smlf * handler when called via the timer callout, and by ghd_timer_poll()
163507c3241Smlf * while procesing "polled" (FLAG_NOINTR) requests.
164507c3241Smlf *
165*1bff1300SToomas Soome * The ccc_activel_mutex is held while a CCB list is being scanned.
166507c3241Smlf * This prevents the HBA driver's transport or interrupt functions
167507c3241Smlf * from changing the active CCB list. But we wake up very infrequently
168507c3241Smlf * and do as little as possible so it shouldn't affect performance.
169507c3241Smlf *
170507c3241Smlf */
171507c3241Smlf
172507c3241Smlf static int
ghd_timeout_loop(ccc_t * cccp)173507c3241Smlf ghd_timeout_loop(ccc_t *cccp)
174507c3241Smlf {
175507c3241Smlf int got_any = FALSE;
176507c3241Smlf gcmd_t *gcmdp;
177507c3241Smlf ulong_t lbolt;
178507c3241Smlf
179507c3241Smlf mutex_enter(&cccp->ccc_activel_mutex);
180507c3241Smlf lbolt = ddi_get_lbolt();
181507c3241Smlf gcmdp = (gcmd_t *)L2_next(&cccp->ccc_activel);
182507c3241Smlf while (gcmdp) {
183507c3241Smlf /*
184507c3241Smlf * check to see if this one has timed out
185507c3241Smlf */
186507c3241Smlf if ((gcmdp->cmd_timeout > 0) &&
187507c3241Smlf (lbolt - gcmdp->cmd_start_time >= gcmdp->cmd_timeout)) {
188507c3241Smlf got_any = TRUE;
189507c3241Smlf }
190507c3241Smlf gcmdp = (gcmd_t *)L2_next(&gcmdp->cmd_timer_link);
191507c3241Smlf }
192507c3241Smlf mutex_exit(&cccp->ccc_activel_mutex);
193507c3241Smlf return (got_any);
194507c3241Smlf }
195507c3241Smlf
196507c3241Smlf /*
197507c3241Smlf *
198507c3241Smlf * ghd_timeout()
199507c3241Smlf *
200507c3241Smlf * Called every t_ticks ticks to scan the CCB timer lists
201507c3241Smlf *
202507c3241Smlf * The t_mutex mutex is held the entire time this routine is active.
203507c3241Smlf * It protects the list of ccc_t's.
204507c3241Smlf *
205507c3241Smlf * The list of cmd_t's is protected by the ccc_activel_mutex mutex
206507c3241Smlf * in the ghd_timeout_loop() routine.
207507c3241Smlf *
208*1bff1300SToomas Soome * We also check to see if the waitq is frozen, and if so,
209*1bff1300SToomas Soome * adjust our timeout to call back sooner if necessary (to
210*1bff1300SToomas Soome * unfreeze the waitq as soon as possible).
211507c3241Smlf *
212507c3241Smlf *
213507c3241Smlf * +------------+
214507c3241Smlf * | tmr_t |----+
215507c3241Smlf * +------------+ |
216507c3241Smlf * |
217507c3241Smlf * V
218507c3241Smlf * +---------+
219507c3241Smlf * | ccc_t |----+
220507c3241Smlf * +---------+ |
221507c3241Smlf * | V
222507c3241Smlf * | +--------+ +--------+
223507c3241Smlf * | | gcmd_t |-->| gcmd_t |--> ...
224507c3241Smlf * | +--------+ +--------+
225507c3241Smlf * V
226507c3241Smlf * +---------+
227507c3241Smlf * | ccc_t |----+
228507c3241Smlf * +---------+ |
229507c3241Smlf * | V
230507c3241Smlf * | +--------+
231507c3241Smlf * | | gcmd_t |
232507c3241Smlf * V +--------+
233507c3241Smlf * ...
234507c3241Smlf *
235507c3241Smlf *
236507c3241Smlf *
237507c3241Smlf */
238507c3241Smlf
239507c3241Smlf static void
ghd_timeout(void * arg)240507c3241Smlf ghd_timeout(void *arg)
241507c3241Smlf {
242507c3241Smlf tmr_t *tmrp = (tmr_t *)arg;
243507c3241Smlf ccc_t *cccp;
244507c3241Smlf clock_t ufdelay_curr;
245507c3241Smlf clock_t lbolt, delay_in_hz;
246507c3241Smlf clock_t resched = (clock_t)0x7FFFFFFF;
247507c3241Smlf
248507c3241Smlf /*
249507c3241Smlf * Each HBA driver instance has a separate CCB timer list. Skip
250507c3241Smlf * timeout processing if there are no more active timeout lists
251507c3241Smlf * to process. (There are no lists only if there are no attached
252507c3241Smlf * HBA instances; the list still exists if there are no outstanding
253507c3241Smlf * active commands.)
254507c3241Smlf */
255507c3241Smlf mutex_enter(&tmrp->t_mutex);
256507c3241Smlf if ((cccp = tmrp->t_ccc_listp) == NULL) {
257507c3241Smlf mutex_exit(&tmrp->t_mutex);
258507c3241Smlf return;
259507c3241Smlf }
260507c3241Smlf
261507c3241Smlf lbolt = ddi_get_lbolt();
262507c3241Smlf
263507c3241Smlf do {
264507c3241Smlf /*
265507c3241Smlf * If any active CCBs on this HBA have timed out
266507c3241Smlf * then kick off the HBA driver's softintr
267507c3241Smlf * handler to do the timeout processing
268507c3241Smlf */
269507c3241Smlf if (ghd_timeout_loop(cccp)) {
270507c3241Smlf cccp->ccc_timeout_pending = 1;
271507c3241Smlf ddi_trigger_softintr(cccp->ccc_soft_id);
272507c3241Smlf }
273507c3241Smlf
274507c3241Smlf /* Record closest unfreeze time for use in next timeout */
275507c3241Smlf
276507c3241Smlf mutex_enter(&cccp->ccc_waitq_mutex);
277507c3241Smlf if (cccp->ccc_waitq_frozen) {
278507c3241Smlf
279507c3241Smlf delay_in_hz =
280507c3241Smlf drv_usectohz(cccp->ccc_waitq_freezedelay * 1000);
281507c3241Smlf ufdelay_curr = delay_in_hz -
282507c3241Smlf (lbolt - cccp->ccc_waitq_freezetime);
283507c3241Smlf
284507c3241Smlf if (ufdelay_curr < resched)
285507c3241Smlf resched = ufdelay_curr;
286507c3241Smlf
287507c3241Smlf /* frozen; trigger softintr to maybe unfreeze */
288507c3241Smlf ddi_trigger_softintr(cccp->ccc_soft_id);
289507c3241Smlf }
290507c3241Smlf mutex_exit(&cccp->ccc_waitq_mutex);
291507c3241Smlf
292507c3241Smlf } while ((cccp = cccp->ccc_nextp) != NULL);
293507c3241Smlf
294507c3241Smlf /* don't allow any unfreeze delays to increase the timeout delay */
295507c3241Smlf if (resched > tmrp->t_ticks)
296507c3241Smlf resched = tmrp->t_ticks;
297507c3241Smlf
298507c3241Smlf /* re-establish the timeout callback */
299507c3241Smlf tmrp->t_timeout_id = timeout(ghd_timeout, (void *)tmrp, resched);
300507c3241Smlf
301507c3241Smlf mutex_exit(&tmrp->t_mutex);
302507c3241Smlf }
303507c3241Smlf
304507c3241Smlf
305507c3241Smlf /*
306507c3241Smlf *
307507c3241Smlf * ghd_timer_newstate()
308507c3241Smlf *
309507c3241Smlf * The HBA mutex is held by my caller.
310507c3241Smlf *
311507c3241Smlf */
312507c3241Smlf
313507c3241Smlf void
ghd_timer_newstate(ccc_t * cccp,gcmd_t * gcmdp,gtgt_t * gtgtp,gact_t action,int calltype)314507c3241Smlf ghd_timer_newstate(ccc_t *cccp, gcmd_t *gcmdp, gtgt_t *gtgtp,
315507c3241Smlf gact_t action, int calltype)
316507c3241Smlf {
317507c3241Smlf gact_t next_action;
318507c3241Smlf cmdstate_t next_state;
319507c3241Smlf char *msgp;
320*1bff1300SToomas Soome long new_timeout = 0;
321507c3241Smlf int (*func)(void *, gcmd_t *, gtgt_t *, gact_t, int);
322507c3241Smlf void *hba_handle;
323507c3241Smlf gcmd_t gsav;
324507c3241Smlf int gsav_used = 0;
325507c3241Smlf gcmd_t *gcmdp_scan;
326507c3241Smlf
327507c3241Smlf ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
328507c3241Smlf
329507c3241Smlf #ifdef DEBUG
330507c3241Smlf /* it shouldn't be on the timer active list */
331507c3241Smlf if (gcmdp != NULL) {
332507c3241Smlf L2el_t *lp = &gcmdp->cmd_timer_link;
333507c3241Smlf ASSERT(lp->l2_nextp == lp);
334507c3241Smlf ASSERT(lp->l2_prevp == lp);
335507c3241Smlf }
336507c3241Smlf #endif
337507c3241Smlf
338*1bff1300SToomas Soome bzero(&gsav, sizeof (gsav));
339507c3241Smlf func = cccp->ccc_timeout_func;
340507c3241Smlf hba_handle = cccp->ccc_hba_handle;
341507c3241Smlf
342507c3241Smlf for (;;) {
343507c3241Smlf switch (action) {
344507c3241Smlf case GACTION_EARLY_ABORT:
345507c3241Smlf /* done before it started */
346507c3241Smlf ASSERT(gcmdp != NULL);
347507c3241Smlf msgp = "early abort";
348507c3241Smlf next_state = GCMD_STATE_DONEQ;
349507c3241Smlf next_action = GACTION_ABORT_CMD;
350507c3241Smlf break;
351507c3241Smlf
352507c3241Smlf case GACTION_EARLY_TIMEOUT:
353507c3241Smlf /* done before it started */
354507c3241Smlf ASSERT(gcmdp != NULL);
355507c3241Smlf msgp = "early timeout";
356507c3241Smlf next_state = GCMD_STATE_DONEQ;
357507c3241Smlf next_action = GACTION_ABORT_CMD;
358507c3241Smlf break;
359507c3241Smlf
360507c3241Smlf case GACTION_ABORT_CMD:
361507c3241Smlf msgp = "abort request";
362507c3241Smlf ASSERT(gcmdp != NULL);
363507c3241Smlf next_state = GCMD_STATE_ABORTING_CMD;
364507c3241Smlf next_action = GACTION_ABORT_DEV;
365507c3241Smlf break;
366507c3241Smlf
367507c3241Smlf case GACTION_ABORT_DEV:
368507c3241Smlf msgp = "abort device";
369507c3241Smlf next_state = GCMD_STATE_ABORTING_DEV;
370507c3241Smlf next_action = GACTION_RESET_TARGET;
371507c3241Smlf break;
372507c3241Smlf
373507c3241Smlf case GACTION_RESET_TARGET:
374507c3241Smlf msgp = "reset target";
375507c3241Smlf next_state = GCMD_STATE_RESETTING_DEV;
376507c3241Smlf next_action = GACTION_RESET_BUS;
377507c3241Smlf break;
378507c3241Smlf
379507c3241Smlf case GACTION_RESET_BUS:
380507c3241Smlf msgp = "reset bus";
381507c3241Smlf next_state = GCMD_STATE_RESETTING_BUS;
382507c3241Smlf next_action = GACTION_INCOMPLETE;
383507c3241Smlf break;
384507c3241Smlf
385507c3241Smlf case GACTION_INCOMPLETE:
386507c3241Smlf default:
387507c3241Smlf /* be verbose about HBA resets */
388507c3241Smlf GDBG_ERROR(("?ghd_timer_newstate: HBA reset failed "
389507c3241Smlf "hba 0x%p gcmdp 0x%p gtgtp 0x%p\n",
390507c3241Smlf (void *)hba_handle, (void *)gcmdp, (void *)gtgtp));
391507c3241Smlf /*
392507c3241Smlf * When all else fails, punt.
393507c3241Smlf *
394507c3241Smlf * We're in big trouble if we get to this point.
395507c3241Smlf * Maybe we should try to re-initialize the HBA.
396507c3241Smlf */
397507c3241Smlf msgp = "HBA reset";
398507c3241Smlf next_state = GCMD_STATE_HUNG;
399507c3241Smlf next_action = GACTION_INCOMPLETE;
400507c3241Smlf break;
401507c3241Smlf }
402507c3241Smlf
403507c3241Smlf /*
404507c3241Smlf * I want to see target requests only if verbose, but
405507c3241Smlf * scsi_log() only prints the device pathname if level
406507c3241Smlf * is CE_WARN or CE_PANIC...so I guess we can't use
407507c3241Smlf * scsi_log for TGTREQ messages, or they must come to
408507c3241Smlf * the console. How silly. Looking for "verbose boot"
409507c3241Smlf * is non-DDI-compliant, but let's do it anyway.
410507c3241Smlf */
411507c3241Smlf
412507c3241Smlf if (calltype == GHD_TGTREQ) {
413507c3241Smlf if ((boothowto & RB_VERBOSE)) {
414507c3241Smlf scsi_log(cccp->ccc_hba_dip, cccp->ccc_label,
415507c3241Smlf CE_WARN,
416507c3241Smlf "target request: %s, target=%d lun=%d",
417507c3241Smlf msgp, gtgtp->gt_target, gtgtp->gt_lun);
418507c3241Smlf }
419507c3241Smlf } else {
420507c3241Smlf scsi_log(cccp->ccc_hba_dip, cccp->ccc_label, CE_WARN,
421507c3241Smlf "timeout: %s, target=%d lun=%d", msgp,
422903a11ebSrh gtgtp->gt_target, gtgtp->gt_lun);
423507c3241Smlf }
424507c3241Smlf
425507c3241Smlf /*
426507c3241Smlf * Before firing off the HBA action, restart the timer
427507c3241Smlf * using the timeout value from ghd_timeout_table[].
428507c3241Smlf *
429507c3241Smlf * The table entries should never restart the timer
430507c3241Smlf * for the GHD_STATE_IDLE and GHD_STATE_DONEQ states.
431507c3241Smlf *
432507c3241Smlf */
433507c3241Smlf if (gcmdp) {
434507c3241Smlf gcmdp->cmd_state = next_state;
435507c3241Smlf new_timeout = ghd_timeout_table[gcmdp->cmd_state];
436507c3241Smlf if (new_timeout != 0)
437507c3241Smlf ghd_timer_start(cccp, gcmdp, new_timeout);
438507c3241Smlf
439507c3241Smlf /* save a copy in case action function frees it */
440507c3241Smlf gsav = *gcmdp;
441507c3241Smlf gsav_used = 1;
442507c3241Smlf }
443507c3241Smlf
444507c3241Smlf if (action == GACTION_RESET_BUS && cccp->ccc_waitq_frozen) {
445507c3241Smlf GDBG_WARN(("avoiding bus reset while waitq frozen\n"));
446507c3241Smlf break;
447507c3241Smlf }
448507c3241Smlf
449507c3241Smlf /* invoke the HBA's action function */
450507c3241Smlf if ((*func)(hba_handle, gcmdp, gtgtp, action, calltype)) {
451507c3241Smlf /* if it took wait for an interrupt or timeout */
452507c3241Smlf break;
453507c3241Smlf }
454507c3241Smlf /*
455507c3241Smlf * if the HBA reset fails leave the retry
456507c3241Smlf * timer running and just exit.
457507c3241Smlf */
458507c3241Smlf if (action == GACTION_INCOMPLETE)
459507c3241Smlf return;
460507c3241Smlf
461507c3241Smlf /* all other failures cause transition to next action */
462507c3241Smlf if (gcmdp != NULL && new_timeout != 0) {
463507c3241Smlf /*
464507c3241Smlf * But stop the old timer prior to
465507c3241Smlf * restarting a new timer because each step may
466507c3241Smlf * have a different timeout value.
467507c3241Smlf */
468507c3241Smlf GHD_TIMER_STOP(cccp, gcmdp);
469507c3241Smlf }
470507c3241Smlf action = next_action;
471507c3241Smlf }
472507c3241Smlf
473507c3241Smlf /*
474507c3241Smlf * HBA action function is done with gsav (if used)
475507c3241Smlf * or gtgtp/cccp (if gsav not used). We need to mark other
476507c3241Smlf * outstanding requests if they were affected by this action
477507c3241Smlf * (say, a device reset which also cancels all outstanding
478507c3241Smlf * requests on this device) to prevent multiple timeouts/HBA
479507c3241Smlf * actions for the same device or bus condition. Scan the timer
480507c3241Smlf * list (all active requests) and update states as necessary.
481507c3241Smlf * Hold the activel_mutex while scanning the active list. Check
482507c3241Smlf * for either same dev/bus as gsav (if used) or for same
483507c3241Smlf * dev/bus as gtgtp or cccp (if gsav is not used).
484507c3241Smlf */
485507c3241Smlf
486507c3241Smlf mutex_enter(&cccp->ccc_activel_mutex);
487507c3241Smlf
488507c3241Smlf for (gcmdp_scan = (gcmd_t *)L2_next(&cccp->ccc_activel);
489507c3241Smlf gcmdp_scan != NULL;
490507c3241Smlf gcmdp_scan = (gcmd_t *)L2_next(&gcmdp_scan->cmd_timer_link)) {
491507c3241Smlf
492507c3241Smlf /* skip idle or waitq commands */
493507c3241Smlf if (gcmdp_scan->cmd_state <= GCMD_STATE_WAITQ)
494507c3241Smlf continue;
495507c3241Smlf
496507c3241Smlf switch (action) {
497507c3241Smlf
498507c3241Smlf case GACTION_ABORT_DEV:
499507c3241Smlf if ((gsav_used && GCMD_SAME_DEV(&gsav, gcmdp_scan)) ||
500507c3241Smlf (GCMDP2GDEVP(gcmdp_scan) == GTGTP2GDEVP(gtgtp))) {
501507c3241Smlf GCMD_UPDATE_STATE(gcmdp_scan,
502507c3241Smlf GCMD_STATE_ABORTING_DEV);
503507c3241Smlf }
504507c3241Smlf break;
505507c3241Smlf
506507c3241Smlf case GACTION_RESET_TARGET:
507507c3241Smlf if ((gsav_used && GCMD_SAME_DEV(&gsav, gcmdp_scan)) ||
508507c3241Smlf (GCMDP2GDEVP(gcmdp_scan) == GTGTP2GDEVP(gtgtp))) {
509507c3241Smlf GCMD_UPDATE_STATE(gcmdp_scan,
510507c3241Smlf GCMD_STATE_RESETTING_DEV);
511507c3241Smlf }
512507c3241Smlf break;
513507c3241Smlf
514507c3241Smlf case GACTION_RESET_BUS:
515507c3241Smlf if ((gsav_used && GCMD_SAME_BUS(&gsav, gcmdp_scan)) ||
516507c3241Smlf (GCMDP2CCCP(gcmdp_scan) == cccp)) {
517507c3241Smlf GCMD_UPDATE_STATE(gcmdp_scan,
518507c3241Smlf GCMD_STATE_RESETTING_BUS);
519507c3241Smlf }
520507c3241Smlf break;
521507c3241Smlf default:
522507c3241Smlf break;
523507c3241Smlf }
524507c3241Smlf }
525507c3241Smlf
526507c3241Smlf mutex_exit(&cccp->ccc_activel_mutex);
527507c3241Smlf }
528507c3241Smlf
529507c3241Smlf
530507c3241Smlf /*
531507c3241Smlf *
532507c3241Smlf * ghd_timeout_softintr()
533507c3241Smlf *
534507c3241Smlf * This interrupt is scheduled if a particular HBA instance's
535507c3241Smlf * CCB timer list has a timed out CCB, or if the waitq is in a
536*1bff1300SToomas Soome * frozen state.
537507c3241Smlf *
538507c3241Smlf * Find the timed out CCB and then call the HBA driver's timeout
539507c3241Smlf * function.
540507c3241Smlf *
541507c3241Smlf * In order to avoid race conditions all processing must be done
542507c3241Smlf * while holding the HBA instance's mutex. If the mutex wasn't
543507c3241Smlf * held the HBA driver's hardware interrupt routine could be
544507c3241Smlf * triggered and it might try to remove a CCB from the list at
545507c3241Smlf * same time as were trying to abort it.
546507c3241Smlf *
547507c3241Smlf * For frozen-waitq processing, just call ghd_waitq_process...
548507c3241Smlf * it takes care of the time calculations.
549507c3241Smlf *
550507c3241Smlf */
551507c3241Smlf
552507c3241Smlf static uint_t
ghd_timeout_softintr(caddr_t arg)553507c3241Smlf ghd_timeout_softintr(caddr_t arg)
554507c3241Smlf {
555507c3241Smlf ccc_t *cccp = (ccc_t *)arg;
556507c3241Smlf
557507c3241Smlf if (cccp->ccc_timeout_pending) {
558507c3241Smlf
559507c3241Smlf /* grab this HBA instance's mutex */
560507c3241Smlf mutex_enter(&cccp->ccc_hba_mutex);
561507c3241Smlf
562507c3241Smlf /*
563507c3241Smlf * The claim is we could reset "pending" outside the mutex, but
564507c3241Smlf * since we have to acquire the mutex anyway, it doesn't hurt
565507c3241Smlf */
566507c3241Smlf cccp->ccc_timeout_pending = 0;
567507c3241Smlf
568507c3241Smlf /* timeout each expired CCB */
569507c3241Smlf ghd_timer_poll(cccp, GHD_TIMER_POLL_ALL);
570507c3241Smlf
571507c3241Smlf mutex_enter(&cccp->ccc_waitq_mutex);
572507c3241Smlf ghd_waitq_process_and_mutex_exit(cccp);
573507c3241Smlf
574507c3241Smlf } else if (cccp->ccc_waitq_frozen) {
575507c3241Smlf mutex_enter(&cccp->ccc_hba_mutex);
576507c3241Smlf mutex_enter(&cccp->ccc_waitq_mutex);
577507c3241Smlf ghd_waitq_process_and_mutex_exit(cccp);
578507c3241Smlf }
579507c3241Smlf
580507c3241Smlf return (DDI_INTR_UNCLAIMED);
581507c3241Smlf }
582507c3241Smlf
583507c3241Smlf
584507c3241Smlf /*
585507c3241Smlf * ghd_timer_poll()
586507c3241Smlf *
587507c3241Smlf * This function steps a packet to the next action in the recovery
588507c3241Smlf * procedure.
589507c3241Smlf *
590507c3241Smlf * The caller must be already holding the HBA mutex and take care of
591507c3241Smlf * running the pkt completion functions.
592507c3241Smlf *
593507c3241Smlf */
594507c3241Smlf
595507c3241Smlf void
ghd_timer_poll(ccc_t * cccp,gtimer_poll_t calltype)596507c3241Smlf ghd_timer_poll(ccc_t *cccp, gtimer_poll_t calltype)
597507c3241Smlf {
598507c3241Smlf gcmd_t *gcmdp;
599507c3241Smlf gact_t action;
600507c3241Smlf
601507c3241Smlf ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
602507c3241Smlf
603507c3241Smlf /* abort each expired CCB */
604507c3241Smlf while (gcmdp = ghd_timeout_get(cccp)) {
605507c3241Smlf
606507c3241Smlf GDBG_INTR(("?ghd_timer_poll: cccp=0x%p gcmdp=0x%p\n",
607903a11ebSrh (void *)cccp, (void *)gcmdp));
608507c3241Smlf
609507c3241Smlf switch (gcmdp->cmd_state) {
610507c3241Smlf case GCMD_STATE_IDLE:
611507c3241Smlf case GCMD_STATE_DONEQ:
612507c3241Smlf default:
613507c3241Smlf /* not supposed to happen */
614507c3241Smlf GDBG_ERROR(("ghd_timer_poll: invalid state %d\n",
615507c3241Smlf gcmdp->cmd_state));
616507c3241Smlf return;
617507c3241Smlf
618507c3241Smlf case GCMD_STATE_WAITQ:
619507c3241Smlf action = GACTION_EARLY_TIMEOUT;
620507c3241Smlf break;
621507c3241Smlf
622507c3241Smlf case GCMD_STATE_ACTIVE:
623507c3241Smlf action = GACTION_ABORT_CMD;
624507c3241Smlf break;
625507c3241Smlf
626507c3241Smlf case GCMD_STATE_ABORTING_CMD:
627507c3241Smlf action = GACTION_ABORT_DEV;
628507c3241Smlf break;
629507c3241Smlf
630507c3241Smlf case GCMD_STATE_ABORTING_DEV:
631507c3241Smlf action = GACTION_RESET_TARGET;
632507c3241Smlf break;
633507c3241Smlf
634507c3241Smlf case GCMD_STATE_RESETTING_DEV:
635507c3241Smlf action = GACTION_RESET_BUS;
636507c3241Smlf break;
637507c3241Smlf
638507c3241Smlf case GCMD_STATE_RESETTING_BUS:
639507c3241Smlf action = GACTION_INCOMPLETE;
640507c3241Smlf break;
641507c3241Smlf
642507c3241Smlf case GCMD_STATE_HUNG:
643507c3241Smlf action = GACTION_INCOMPLETE;
644507c3241Smlf break;
645507c3241Smlf }
646507c3241Smlf
647507c3241Smlf ghd_timer_newstate(cccp, gcmdp, gcmdp->cmd_gtgtp, action,
648507c3241Smlf GHD_TIMEOUT);
649507c3241Smlf
650507c3241Smlf /* return after processing first cmd if requested */
651507c3241Smlf
652507c3241Smlf if (calltype == GHD_TIMER_POLL_ONE)
653507c3241Smlf return;
654507c3241Smlf }
655507c3241Smlf }
656507c3241Smlf
657507c3241Smlf
658507c3241Smlf
659507c3241Smlf
660507c3241Smlf /*
661507c3241Smlf *
662507c3241Smlf * ghd_timeout_get()
663507c3241Smlf *
664507c3241Smlf * Remove the first expired CCB from a particular timer list.
665507c3241Smlf *
666507c3241Smlf */
667507c3241Smlf
668507c3241Smlf static gcmd_t *
ghd_timeout_get(ccc_t * cccp)669507c3241Smlf ghd_timeout_get(ccc_t *cccp)
670507c3241Smlf {
671507c3241Smlf gcmd_t *gcmdp;
672507c3241Smlf ulong_t lbolt;
673507c3241Smlf
674507c3241Smlf ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
675507c3241Smlf
676507c3241Smlf mutex_enter(&cccp->ccc_activel_mutex);
677507c3241Smlf lbolt = ddi_get_lbolt();
678507c3241Smlf gcmdp = (gcmd_t *)L2_next(&cccp->ccc_activel);
679507c3241Smlf while (gcmdp != NULL) {
680507c3241Smlf if ((gcmdp->cmd_timeout > 0) &&
681507c3241Smlf (lbolt - gcmdp->cmd_start_time >= gcmdp->cmd_timeout))
682507c3241Smlf goto expired;
683507c3241Smlf gcmdp = (gcmd_t *)L2_next(&gcmdp->cmd_timer_link);
684507c3241Smlf }
685507c3241Smlf mutex_exit(&cccp->ccc_activel_mutex);
686507c3241Smlf return (NULL);
687507c3241Smlf
688507c3241Smlf expired:
689507c3241Smlf /* unlink if from the CCB timer list */
690507c3241Smlf L2_delete(&gcmdp->cmd_timer_link);
691507c3241Smlf mutex_exit(&cccp->ccc_activel_mutex);
692507c3241Smlf return (gcmdp);
693507c3241Smlf }
694507c3241Smlf
695507c3241Smlf
696507c3241Smlf /*
697507c3241Smlf *
698507c3241Smlf * ghd_timeout_enable()
699507c3241Smlf *
700507c3241Smlf * Only start a single timeout callback for each HBA driver
701507c3241Smlf * regardless of the number of boards it supports.
702507c3241Smlf *
703507c3241Smlf */
704507c3241Smlf
705507c3241Smlf static void
ghd_timeout_enable(tmr_t * tmrp)706507c3241Smlf ghd_timeout_enable(tmr_t *tmrp)
707507c3241Smlf {
708507c3241Smlf mutex_enter(&tglobal_mutex);
709507c3241Smlf if (tmrp->t_refs++ == 0) {
710507c3241Smlf /* establish the timeout callback */
711507c3241Smlf tmrp->t_timeout_id = timeout(ghd_timeout, (void *)tmrp,
712903a11ebSrh tmrp->t_ticks);
713507c3241Smlf }
714507c3241Smlf mutex_exit(&tglobal_mutex);
715507c3241Smlf }
716507c3241Smlf
717507c3241Smlf static void
ghd_timeout_disable(tmr_t * tmrp)718507c3241Smlf ghd_timeout_disable(tmr_t *tmrp)
719507c3241Smlf {
720507c3241Smlf ASSERT(tmrp != NULL);
721507c3241Smlf
722507c3241Smlf mutex_enter(&tglobal_mutex);
723b3c0e203Smlf if (tmrp->t_refs-- <= 1) {
724507c3241Smlf (void) untimeout(tmrp->t_timeout_id);
725b3c0e203Smlf }
726507c3241Smlf mutex_exit(&tglobal_mutex);
727507c3241Smlf }
728507c3241Smlf
729507c3241Smlf /* ************************************************************************ */
730507c3241Smlf
731507c3241Smlf /* these are the externally callable routines */
732507c3241Smlf
733507c3241Smlf
734507c3241Smlf void
ghd_timer_init(tmr_t * tmrp,long ticks)735507c3241Smlf ghd_timer_init(tmr_t *tmrp, long ticks)
736507c3241Smlf {
737507c3241Smlf int indx;
738507c3241Smlf
739507c3241Smlf mutex_init(&tglobal_mutex, NULL, MUTEX_DRIVER, NULL);
740507c3241Smlf mutex_init(&tmrp->t_mutex, NULL, MUTEX_DRIVER, NULL);
741507c3241Smlf
742507c3241Smlf /*
743507c3241Smlf * determine default timeout value
744507c3241Smlf */
745507c3241Smlf ghd_HZ = drv_usectohz(1000000);
746507c3241Smlf if (ticks == 0)
747507c3241Smlf ticks = scsi_watchdog_tick * ghd_HZ;
748507c3241Smlf tmrp->t_ticks = ticks;
749507c3241Smlf
750507c3241Smlf
751507c3241Smlf /*
752507c3241Smlf * Initialize the table of abort timer values using an
753507c3241Smlf * indirect lookup table so that this code isn't dependant
754507c3241Smlf * on the cmdstate_t enum values or order.
755507c3241Smlf */
756507c3241Smlf for (indx = 0; indx < ghd_ntime_inits; indx++) {
757507c3241Smlf int state;
758507c3241Smlf ulong_t value;
759507c3241Smlf
760507c3241Smlf if (!ghd_time_inits[indx].valid)
761507c3241Smlf continue;
762507c3241Smlf state = ghd_time_inits[indx].state;
763507c3241Smlf value = ghd_time_inits[indx].value;
764f304523cSzhongyan gu - Sun Microsystems - Beijing China ghd_timeout_table[state] = (cmdstate_t)value;
765507c3241Smlf }
766507c3241Smlf }
767507c3241Smlf
768507c3241Smlf void
ghd_timer_fini(tmr_t * tmrp)769507c3241Smlf ghd_timer_fini(tmr_t *tmrp)
770507c3241Smlf {
771507c3241Smlf mutex_destroy(&tmrp->t_mutex);
772507c3241Smlf mutex_destroy(&tglobal_mutex);
773507c3241Smlf }
774507c3241Smlf
775507c3241Smlf int
ghd_timer_attach(ccc_t * cccp,tmr_t * tmrp,int (* timeout_func)(void *,gcmd_t *,gtgt_t *,gact_t,int))776507c3241Smlf ghd_timer_attach(ccc_t *cccp, tmr_t *tmrp,
777507c3241Smlf int (*timeout_func)(void *, gcmd_t *, gtgt_t *, gact_t, int))
778507c3241Smlf {
779507c3241Smlf ddi_iblock_cookie_t iblock;
780507c3241Smlf
781507c3241Smlf if (ddi_add_softintr(cccp->ccc_hba_dip, DDI_SOFTINT_LOW,
782507c3241Smlf &cccp->ccc_soft_id, &iblock, NULL,
783507c3241Smlf ghd_timeout_softintr, (caddr_t)cccp) != DDI_SUCCESS) {
784507c3241Smlf GDBG_ERROR((
785507c3241Smlf "ghd_timer_attach: add softintr failed cccp 0x%p\n",
786507c3241Smlf (void *)cccp));
787507c3241Smlf return (FALSE);
788507c3241Smlf }
789507c3241Smlf
790507c3241Smlf /* init the per HBA-instance control fields */
791507c3241Smlf mutex_init(&cccp->ccc_activel_mutex, NULL, MUTEX_DRIVER, iblock);
792507c3241Smlf L2_INIT(&cccp->ccc_activel);
793507c3241Smlf cccp->ccc_timeout_func = timeout_func;
794507c3241Smlf
795507c3241Smlf /* stick this HBA's control structure on the master list */
796507c3241Smlf mutex_enter(&tmrp->t_mutex);
797507c3241Smlf
798507c3241Smlf cccp->ccc_nextp = tmrp->t_ccc_listp;
799507c3241Smlf tmrp->t_ccc_listp = cccp;
800507c3241Smlf cccp->ccc_tmrp = tmrp;
801507c3241Smlf mutex_exit(&tmrp->t_mutex);
802507c3241Smlf
803507c3241Smlf /*
804507c3241Smlf * The enable and disable routines use a separate mutex than
805507c3241Smlf * t_mutex which is used by the timeout callback function.
806507c3241Smlf * This is to avoid a deadlock when calling untimeout() from
807507c3241Smlf * the disable routine.
808507c3241Smlf */
809507c3241Smlf ghd_timeout_enable(tmrp);
810507c3241Smlf
811507c3241Smlf return (TRUE);
812507c3241Smlf }
813507c3241Smlf
814507c3241Smlf
815507c3241Smlf /*
816507c3241Smlf *
817507c3241Smlf * ghd_timer_detach()
818507c3241Smlf *
819507c3241Smlf * clean up for a detaching HBA instance
820507c3241Smlf *
821507c3241Smlf */
822507c3241Smlf
823507c3241Smlf void
ghd_timer_detach(ccc_t * cccp)824507c3241Smlf ghd_timer_detach(ccc_t *cccp)
825507c3241Smlf {
826507c3241Smlf tmr_t *tmrp = cccp->ccc_tmrp;
827507c3241Smlf ccc_t **prevpp;
828507c3241Smlf
829507c3241Smlf /* make certain the CCB list is empty */
830507c3241Smlf ASSERT(cccp->ccc_activel.l2_nextp == &cccp->ccc_activel);
831507c3241Smlf ASSERT(cccp->ccc_activel.l2_nextp == cccp->ccc_activel.l2_prevp);
832507c3241Smlf
833507c3241Smlf mutex_enter(&tmrp->t_mutex);
834507c3241Smlf
835507c3241Smlf prevpp = &tmrp->t_ccc_listp;
836507c3241Smlf ASSERT(*prevpp != NULL);
837507c3241Smlf
838507c3241Smlf /* run down the linked list to find the entry that preceeds this one */
839507c3241Smlf do {
840507c3241Smlf if (*prevpp == cccp)
841507c3241Smlf goto remove_it;
842507c3241Smlf prevpp = &(*prevpp)->ccc_nextp;
843507c3241Smlf } while (*prevpp != NULL);
844507c3241Smlf
845507c3241Smlf /* fell off the end of the list */
846507c3241Smlf GDBG_ERROR(("ghd_timer_detach: corrupt list, cccp=0x%p\n",
847507c3241Smlf (void *)cccp));
848507c3241Smlf
849507c3241Smlf remove_it:
850507c3241Smlf *prevpp = cccp->ccc_nextp;
851507c3241Smlf mutex_exit(&tmrp->t_mutex);
852507c3241Smlf mutex_destroy(&cccp->ccc_activel_mutex);
853507c3241Smlf
854507c3241Smlf ddi_remove_softintr(cccp->ccc_soft_id);
855507c3241Smlf
856507c3241Smlf ghd_timeout_disable(tmrp);
857507c3241Smlf }
858507c3241Smlf
859507c3241Smlf /*
860507c3241Smlf *
861507c3241Smlf * ghd_timer_start()
862507c3241Smlf *
863507c3241Smlf * Add a CCB to the CCB timer list.
864507c3241Smlf */
865507c3241Smlf
866507c3241Smlf void
ghd_timer_start(ccc_t * cccp,gcmd_t * gcmdp,long cmd_timeout)867507c3241Smlf ghd_timer_start(ccc_t *cccp, gcmd_t *gcmdp, long cmd_timeout)
868507c3241Smlf {
869507c3241Smlf ulong_t lbolt;
870507c3241Smlf
871507c3241Smlf mutex_enter(&cccp->ccc_activel_mutex);
872507c3241Smlf lbolt = ddi_get_lbolt();
873507c3241Smlf
874507c3241Smlf /* initialize this CCB's timer */
875507c3241Smlf gcmdp->cmd_start_time = lbolt;
876507c3241Smlf gcmdp->cmd_timeout = (cmd_timeout * ghd_HZ);
877507c3241Smlf
878507c3241Smlf /* add it to the list */
879507c3241Smlf L2_add(&cccp->ccc_activel, &gcmdp->cmd_timer_link, gcmdp);
880507c3241Smlf mutex_exit(&cccp->ccc_activel_mutex);
881507c3241Smlf }
882507c3241Smlf
883507c3241Smlf
884507c3241Smlf /*
885507c3241Smlf *
886507c3241Smlf * ghd_timer_stop()
887507c3241Smlf *
888507c3241Smlf * Remove a completed CCB from the CCB timer list.
889507c3241Smlf *
890507c3241Smlf * See the GHD_TIMER_STOP_INLINE() macro in ghd.h for
891507c3241Smlf * the actual code.
892507c3241Smlf */
893507c3241Smlf
894507c3241Smlf void
ghd_timer_stop(ccc_t * cccp,gcmd_t * gcmdp)895507c3241Smlf ghd_timer_stop(ccc_t *cccp, gcmd_t *gcmdp)
896507c3241Smlf {
897507c3241Smlf GHD_TIMER_STOP_INLINE(cccp, gcmdp);
898507c3241Smlf }
899