xref: /titanic_41/usr/src/uts/intel/io/dktp/hba/ghd/ghd_timer.c (revision f304523c1c8b168f5db72cb0e24ee8318a974f8d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <sys/types.h>
29 #include <sys/conf.h>
30 #include <sys/ddi.h>
31 #include <sys/sunddi.h>
32 #include <sys/ksynch.h>
33 #include <sys/scsi/conf/autoconf.h>
34 #include <sys/reboot.h>
35 
36 #include "ghd.h"
37 
38 /*
39  * Local functions
40  */
41 
42 static	gcmd_t	*ghd_timeout_get(ccc_t *cccp);
43 static	int	 ghd_timeout_loop(ccc_t *cccp);
44 static	uint_t	 ghd_timeout_softintr(caddr_t arg);
45 static	void	 ghd_timeout(void *arg);
46 static	void	 ghd_timeout_disable(tmr_t *tmrp);
47 static	void	 ghd_timeout_enable(tmr_t *tmrp);
48 
49 /*
50  * Local data
51  */
52 long	ghd_HZ;
53 static	kmutex_t tglobal_mutex;
54 
55 /* table of timeouts for abort processing steps */
56 cmdstate_t ghd_timeout_table[GCMD_NSTATES];
57 
58 /* This table indirectly initializes the ghd_timeout_table */
59 struct {
60 	int		valid;
61 	cmdstate_t	state;
62 	long		value;
63 } ghd_time_inits[] = {
64 	{ TRUE, GCMD_STATE_ABORTING_CMD, 3 },
65 	{ TRUE, GCMD_STATE_ABORTING_DEV, 3 },
66 	{ TRUE, GCMD_STATE_RESETTING_DEV, 5 },
67 	{ TRUE, GCMD_STATE_RESETTING_BUS, 10 },
68 	{ TRUE, GCMD_STATE_HUNG, 60},
69 	{ FALSE, 0, 0 },	/* spare entry */
70 	{ FALSE, 0, 0 },	/* spare entry */
71 	{ FALSE, 0, 0 },	/* spare entry */
72 	{ FALSE, 0, 0 },	/* spare entry */
73 	{ FALSE, 0, 0 }		/* spare entry */
74 };
75 int	ghd_ntime_inits = sizeof (ghd_time_inits)
76 				/ sizeof (ghd_time_inits[0]);
77 
78 /*
79  * Locally-used macros
80  */
81 
82 /*
83  * Compare two gcmd_t's to see if they're for the same device (same gdev_t)
84  */
85 #define	GCMD_SAME_DEV(gcmdp1, gcmdp2)		\
86 	(GCMDP2GDEVP(gcmdp1) == GCMDP2GDEVP(gcmdp2))
87 
88 /*
89  * Compare two gcmd_t's to see if they're for the same bus (same HBA inst)
90  */
91 #define	GCMD_SAME_BUS(gcmdp1, gcmdp2)		\
92 	(GCMDP2CCCP(gcmdp1) == GCMDP2CCCP(gcmdp2))
93 
94 
95 /*
96  * Update state of gcmdp (in one direction, increasing state number, only)
97  */
98 #define	GCMD_UPDATE_STATE(gcmdp, newstate) 		\
99 {							\
100 	if ((gcmdp)->cmd_state < (newstate)) {		\
101 		((gcmdp)->cmd_state = (newstate));	\
102 	}						\
103 }
104 
105 #ifdef ___notyet___
106 
107 #include <sys/modctl.h>
108 extern struct mod_ops mod_miscops;
109 static struct modlmisc modlmisc = {
110 	&mod_miscops,	/* Type of module */
111 	"CCB Timeout Utility Routines"
112 };
113 static struct modlinkage modlinkage = {
114 	MODREV_1, (void *)&modlmisc, NULL
115 };
116 
117 /*
118  * If this is a loadable module then there's a single CCB timer configure
119  * structure for all HBA drivers (rather than one per HBA driver).
120  */
121 static	tmr_t	tmr_conf;
122 
123 int
_init()124 _init()
125 {
126 	int	err;
127 
128 	ghd_timer_init(&tmr_conf, 0);
129 	return ((err = mod_install(&modlinkage)) != 0)
130 	    ghd_timer_fini(&tmr_conf);
131 	return (err);
132 }
133 
134 int
_fini()135 _fini()
136 {
137 	int	err;
138 
139 	if ((err = mod_remove(&modlinkage)) == 0)
140 		ghd_timer_fini(&tmr_conf);
141 	return (err);
142 }
143 
144 int
_info(struct modinfo * modinfop)145 _info(struct modinfo *modinfop)
146 {
147 	return (mod_info(&modlinkage, modinfop));
148 }
149 
150 #endif /* ___notyet___ */
151 
152 
153 
154 /*
155  *
156  * ghd_timeout_loop()
157  *
158  *	Check the CCB timer value for every active CCB for this
159  * HBA driver instance.
160  *
161  *	This function is called both by the ghd_timeout() interrupt
162  * handler when called via the timer callout, and by ghd_timer_poll()
163  * while procesing "polled" (FLAG_NOINTR) requests.
164  *
165  * 	The ccc_activel_mutex is held while a CCB list is being scanned.
166  * This prevents the HBA driver's transport or interrupt functions
167  * from changing the active CCB list. But we wake up very infrequently
168  * and do as little as possible so it shouldn't affect performance.
169  *
170  */
171 
172 static int
ghd_timeout_loop(ccc_t * cccp)173 ghd_timeout_loop(ccc_t *cccp)
174 {
175 	int	 got_any = FALSE;
176 	gcmd_t	*gcmdp;
177 	ulong_t	 lbolt;
178 
179 	mutex_enter(&cccp->ccc_activel_mutex);
180 	lbolt = ddi_get_lbolt();
181 	gcmdp = (gcmd_t *)L2_next(&cccp->ccc_activel);
182 	while (gcmdp) {
183 		/*
184 		 * check to see if this one has timed out
185 		 */
186 		if ((gcmdp->cmd_timeout > 0) &&
187 		    (lbolt - gcmdp->cmd_start_time >= gcmdp->cmd_timeout)) {
188 			got_any = TRUE;
189 		}
190 		gcmdp = (gcmd_t *)L2_next(&gcmdp->cmd_timer_link);
191 	}
192 	mutex_exit(&cccp->ccc_activel_mutex);
193 	return (got_any);
194 }
195 
196 /*
197  *
198  * ghd_timeout()
199  *
200  *	Called every t_ticks ticks to scan the CCB timer lists
201  *
202  *	The t_mutex mutex is held the entire time this routine is active.
203  *	It protects the list of ccc_t's.
204  *
205  *	The list of cmd_t's is protected by the ccc_activel_mutex mutex
206  *	in the ghd_timeout_loop() routine.
207  *
208  * 	We also check to see if the waitq is frozen, and if so,
209  * 	adjust our timeout to call back sooner if necessary (to
210  * 	unfreeze the waitq as soon as possible).
211  *
212  *
213  *	+------------+
214  *	|   tmr_t    |----+
215  *	+------------+    |
216  *			  |
217  *			  V
218  *			  +---------+
219  *			  |  ccc_t  |----+
220  *			  +---------+    |
221  *			  |		 V
222  *			  |		 +--------+   +--------+
223  *			  |		 | gcmd_t |-->| gcmd_t |--> ...
224  *			  |		 +--------+   +--------+
225  *			  V
226  *			  +---------+
227  *			  |  ccc_t  |----+
228  *			  +---------+    |
229  *			  |		 V
230  *			  |		 +--------+
231  *			  |		 | gcmd_t |
232  *			  V		 +--------+
233  *			  ...
234  *
235  *
236  *
237  */
238 
239 static void
ghd_timeout(void * arg)240 ghd_timeout(void *arg)
241 {
242 	tmr_t	*tmrp = (tmr_t *)arg;
243 	ccc_t	*cccp;
244 	clock_t	ufdelay_curr;
245 	clock_t	lbolt, delay_in_hz;
246 	clock_t	resched = (clock_t)0x7FFFFFFF;
247 
248 	/*
249 	 * Each HBA driver instance has a separate CCB timer list.  Skip
250 	 * timeout processing if there are no more active timeout lists
251 	 * to process.  (There are no lists only if there are no attached
252 	 * HBA instances; the list still exists if there are no outstanding
253 	 * active commands.)
254 	 */
255 	mutex_enter(&tmrp->t_mutex);
256 	if ((cccp = tmrp->t_ccc_listp) == NULL) {
257 		mutex_exit(&tmrp->t_mutex);
258 		return;
259 	}
260 
261 	lbolt = ddi_get_lbolt();
262 
263 	do {
264 		/*
265 		 * If any active CCBs on this HBA have timed out
266 		 * then kick off the HBA driver's softintr
267 		 * handler to do the timeout processing
268 		 */
269 		if (ghd_timeout_loop(cccp)) {
270 			cccp->ccc_timeout_pending = 1;
271 			ddi_trigger_softintr(cccp->ccc_soft_id);
272 		}
273 
274 		/* Record closest unfreeze time for use in next timeout */
275 
276 		mutex_enter(&cccp->ccc_waitq_mutex);
277 		if (cccp->ccc_waitq_frozen) {
278 
279 			delay_in_hz =
280 			    drv_usectohz(cccp->ccc_waitq_freezedelay * 1000);
281 			ufdelay_curr = delay_in_hz -
282 			    (lbolt - cccp->ccc_waitq_freezetime);
283 
284 			if (ufdelay_curr < resched)
285 				resched = ufdelay_curr;
286 
287 			/* frozen; trigger softintr to maybe unfreeze */
288 			ddi_trigger_softintr(cccp->ccc_soft_id);
289 		}
290 		mutex_exit(&cccp->ccc_waitq_mutex);
291 
292 	} while ((cccp = cccp->ccc_nextp) != NULL);
293 
294 	/* don't allow any unfreeze delays to increase the timeout delay */
295 	if (resched > tmrp->t_ticks)
296 		resched = tmrp->t_ticks;
297 
298 	/* re-establish the timeout callback */
299 	tmrp->t_timeout_id = timeout(ghd_timeout, (void *)tmrp, resched);
300 
301 	mutex_exit(&tmrp->t_mutex);
302 }
303 
304 
305 /*
306  *
307  * ghd_timer_newstate()
308  *
309  *	The HBA mutex is held by my caller.
310  *
311  */
312 
313 void
ghd_timer_newstate(ccc_t * cccp,gcmd_t * gcmdp,gtgt_t * gtgtp,gact_t action,int calltype)314 ghd_timer_newstate(ccc_t *cccp, gcmd_t *gcmdp, gtgt_t *gtgtp,
315     gact_t action, int calltype)
316 {
317 	gact_t	next_action;
318 	cmdstate_t next_state;
319 	char	*msgp;
320 	long	new_timeout;
321 	int	(*func)(void *, gcmd_t *, gtgt_t *, gact_t, int);
322 	void	*hba_handle;
323 	gcmd_t	gsav;
324 	int	gsav_used = 0;
325 	gcmd_t	*gcmdp_scan;
326 
327 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
328 
329 #ifdef	DEBUG
330 	/* it shouldn't be on the timer active list */
331 	if (gcmdp != NULL) {
332 		L2el_t	*lp = &gcmdp->cmd_timer_link;
333 		ASSERT(lp->l2_nextp == lp);
334 		ASSERT(lp->l2_prevp == lp);
335 	}
336 #endif
337 
338 	func = cccp->ccc_timeout_func;
339 	hba_handle = cccp->ccc_hba_handle;
340 
341 	for (;;) {
342 		switch (action) {
343 		case GACTION_EARLY_ABORT:
344 			/* done before it started */
345 			ASSERT(gcmdp != NULL);
346 			msgp = "early abort";
347 			next_state = GCMD_STATE_DONEQ;
348 			next_action = GACTION_ABORT_CMD;
349 			break;
350 
351 		case GACTION_EARLY_TIMEOUT:
352 			/* done before it started */
353 			ASSERT(gcmdp != NULL);
354 			msgp = "early timeout";
355 			next_state = GCMD_STATE_DONEQ;
356 			next_action = GACTION_ABORT_CMD;
357 			break;
358 
359 		case GACTION_ABORT_CMD:
360 			msgp = "abort request";
361 			ASSERT(gcmdp != NULL);
362 			next_state = GCMD_STATE_ABORTING_CMD;
363 			next_action = GACTION_ABORT_DEV;
364 			break;
365 
366 		case GACTION_ABORT_DEV:
367 			msgp = "abort device";
368 			next_state = GCMD_STATE_ABORTING_DEV;
369 			next_action = GACTION_RESET_TARGET;
370 			break;
371 
372 		case GACTION_RESET_TARGET:
373 			msgp = "reset target";
374 			next_state = GCMD_STATE_RESETTING_DEV;
375 			next_action = GACTION_RESET_BUS;
376 			break;
377 
378 		case GACTION_RESET_BUS:
379 			msgp = "reset bus";
380 			next_state = GCMD_STATE_RESETTING_BUS;
381 			next_action = GACTION_INCOMPLETE;
382 			break;
383 
384 		case GACTION_INCOMPLETE:
385 		default:
386 			/* be verbose about HBA resets */
387 			GDBG_ERROR(("?ghd_timer_newstate: HBA reset failed "
388 			    "hba 0x%p gcmdp 0x%p gtgtp 0x%p\n",
389 			    (void *)hba_handle, (void *)gcmdp, (void *)gtgtp));
390 			/*
391 			 * When all else fails, punt.
392 			 *
393 			 * We're in big trouble if we get to this point.
394 			 * Maybe we should try to re-initialize the HBA.
395 			 */
396 			msgp = "HBA reset";
397 			next_state = GCMD_STATE_HUNG;
398 			next_action = GACTION_INCOMPLETE;
399 			break;
400 		}
401 
402 		/*
403 		 * I want to see target requests only if verbose, but
404 		 * scsi_log() only prints the device pathname if level
405 		 * is CE_WARN or CE_PANIC...so I guess we can't use
406 		 * scsi_log for TGTREQ messages, or they must come to
407 		 * the console.  How silly.  Looking for "verbose boot"
408 		 * is non-DDI-compliant, but let's do it anyway.
409 		 */
410 
411 		if (calltype == GHD_TGTREQ) {
412 			if ((boothowto & RB_VERBOSE)) {
413 				scsi_log(cccp->ccc_hba_dip, cccp->ccc_label,
414 				    CE_WARN,
415 				    "target request: %s, target=%d lun=%d",
416 				    msgp, gtgtp->gt_target, gtgtp->gt_lun);
417 			}
418 		} else {
419 			scsi_log(cccp->ccc_hba_dip, cccp->ccc_label, CE_WARN,
420 			    "timeout: %s, target=%d lun=%d", msgp,
421 			    gtgtp->gt_target, gtgtp->gt_lun);
422 		}
423 
424 		/*
425 		 * Before firing off the HBA action, restart the timer
426 		 * using the timeout value from ghd_timeout_table[].
427 		 *
428 		 * The table entries should never restart the timer
429 		 * for the GHD_STATE_IDLE and GHD_STATE_DONEQ states.
430 		 *
431 		 */
432 		if (gcmdp) {
433 			gcmdp->cmd_state = next_state;
434 			new_timeout = ghd_timeout_table[gcmdp->cmd_state];
435 			if (new_timeout != 0)
436 				ghd_timer_start(cccp, gcmdp, new_timeout);
437 
438 			/* save a copy in case action function frees it */
439 			gsav = *gcmdp;
440 			gsav_used = 1;
441 		}
442 
443 		if (action == GACTION_RESET_BUS && cccp->ccc_waitq_frozen) {
444 			GDBG_WARN(("avoiding bus reset while waitq frozen\n"));
445 			break;
446 		}
447 
448 		/* invoke the HBA's action function */
449 		if ((*func)(hba_handle, gcmdp, gtgtp, action, calltype)) {
450 			/* if it took wait for an interrupt or timeout */
451 			break;
452 		}
453 		/*
454 		 * if the HBA reset fails leave the retry
455 		 * timer running and just exit.
456 		 */
457 		if (action == GACTION_INCOMPLETE)
458 			return;
459 
460 		/* all other failures cause transition to next action */
461 		if (gcmdp != NULL && new_timeout != 0) {
462 			/*
463 			 * But stop the old timer prior to
464 			 * restarting a new timer because each step may
465 			 * have a different timeout value.
466 			 */
467 			GHD_TIMER_STOP(cccp, gcmdp);
468 		}
469 		action = next_action;
470 	}
471 
472 	/*
473 	 * HBA action function is done with gsav (if used)
474 	 * or gtgtp/cccp (if gsav not used).  We need to mark other
475 	 * outstanding requests if they were affected by this action
476 	 * (say, a device reset which also cancels all outstanding
477 	 * requests on this device) to prevent multiple timeouts/HBA
478 	 * actions for the same device or bus condition.  Scan the timer
479 	 * list (all active requests) and update states as necessary.
480 	 * Hold the activel_mutex while scanning the active list.  Check
481 	 * for either same dev/bus as gsav (if used) or for same
482 	 * dev/bus as gtgtp or cccp (if gsav is not used).
483 	 */
484 
485 	mutex_enter(&cccp->ccc_activel_mutex);
486 
487 	for (gcmdp_scan = (gcmd_t *)L2_next(&cccp->ccc_activel);
488 	    gcmdp_scan != NULL;
489 	    gcmdp_scan = (gcmd_t *)L2_next(&gcmdp_scan->cmd_timer_link)) {
490 
491 		/* skip idle or waitq commands */
492 		if (gcmdp_scan->cmd_state <= GCMD_STATE_WAITQ)
493 			continue;
494 
495 		switch (action) {
496 
497 		case GACTION_ABORT_DEV:
498 			if ((gsav_used && GCMD_SAME_DEV(&gsav, gcmdp_scan)) ||
499 			    (GCMDP2GDEVP(gcmdp_scan) == GTGTP2GDEVP(gtgtp))) {
500 				GCMD_UPDATE_STATE(gcmdp_scan,
501 				    GCMD_STATE_ABORTING_DEV);
502 			}
503 			break;
504 
505 		case GACTION_RESET_TARGET:
506 			if ((gsav_used && GCMD_SAME_DEV(&gsav, gcmdp_scan)) ||
507 			    (GCMDP2GDEVP(gcmdp_scan) == GTGTP2GDEVP(gtgtp))) {
508 				GCMD_UPDATE_STATE(gcmdp_scan,
509 				    GCMD_STATE_RESETTING_DEV);
510 			}
511 			break;
512 
513 		case GACTION_RESET_BUS:
514 			if ((gsav_used && GCMD_SAME_BUS(&gsav, gcmdp_scan)) ||
515 			    (GCMDP2CCCP(gcmdp_scan) == cccp)) {
516 				GCMD_UPDATE_STATE(gcmdp_scan,
517 				    GCMD_STATE_RESETTING_BUS);
518 			}
519 			break;
520 		default:
521 			break;
522 		}
523 	}
524 
525 	mutex_exit(&cccp->ccc_activel_mutex);
526 }
527 
528 
529 /*
530  *
531  * ghd_timeout_softintr()
532  *
533  *	This interrupt is scheduled if a particular HBA instance's
534  *	CCB timer list has a timed out CCB, or if the waitq is in a
535  * 	frozen state.
536  *
537  *	Find the timed out CCB and then call the HBA driver's timeout
538  *	function.
539  *
540  *	In order to avoid race conditions all processing must be done
541  *	while holding the HBA instance's mutex. If the mutex wasn't
542  *	held the HBA driver's hardware interrupt routine could be
543  *	triggered and it might try to remove a CCB from the list at
544  *	same time as were trying to abort it.
545  *
546  *	For frozen-waitq processing, just call ghd_waitq_process...
547  *	it takes care of the time calculations.
548  *
549  */
550 
551 static uint_t
ghd_timeout_softintr(caddr_t arg)552 ghd_timeout_softintr(caddr_t arg)
553 {
554 	ccc_t	*cccp = (ccc_t *)arg;
555 
556 	if (cccp->ccc_timeout_pending) {
557 
558 		/* grab this HBA instance's mutex */
559 		mutex_enter(&cccp->ccc_hba_mutex);
560 
561 		/*
562 		 * The claim is we could reset "pending" outside the mutex, but
563 		 * since we have to acquire the mutex anyway, it doesn't hurt
564 		 */
565 		cccp->ccc_timeout_pending = 0;
566 
567 		/* timeout each expired CCB */
568 		ghd_timer_poll(cccp, GHD_TIMER_POLL_ALL);
569 
570 		mutex_enter(&cccp->ccc_waitq_mutex);
571 		ghd_waitq_process_and_mutex_exit(cccp);
572 
573 	} else if (cccp->ccc_waitq_frozen) {
574 		mutex_enter(&cccp->ccc_hba_mutex);
575 		mutex_enter(&cccp->ccc_waitq_mutex);
576 		ghd_waitq_process_and_mutex_exit(cccp);
577 	}
578 
579 	return (DDI_INTR_UNCLAIMED);
580 }
581 
582 
583 /*
584  * ghd_timer_poll()
585  *
586  * This function steps a packet to the next action in the recovery
587  * procedure.
588  *
589  * The caller must be  already holding the HBA mutex and take care of
590  * running the pkt completion functions.
591  *
592  */
593 
594 void
ghd_timer_poll(ccc_t * cccp,gtimer_poll_t calltype)595 ghd_timer_poll(ccc_t *cccp, gtimer_poll_t calltype)
596 {
597 	gcmd_t	*gcmdp;
598 	gact_t	 action;
599 
600 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
601 
602 	/* abort each expired CCB */
603 	while (gcmdp = ghd_timeout_get(cccp)) {
604 
605 		GDBG_INTR(("?ghd_timer_poll: cccp=0x%p gcmdp=0x%p\n",
606 		    (void *)cccp, (void *)gcmdp));
607 
608 		switch (gcmdp->cmd_state) {
609 		case GCMD_STATE_IDLE:
610 		case GCMD_STATE_DONEQ:
611 		default:
612 			/* not supposed to happen */
613 			GDBG_ERROR(("ghd_timer_poll: invalid state %d\n",
614 			    gcmdp->cmd_state));
615 			return;
616 
617 		case GCMD_STATE_WAITQ:
618 			action = GACTION_EARLY_TIMEOUT;
619 			break;
620 
621 		case GCMD_STATE_ACTIVE:
622 			action = GACTION_ABORT_CMD;
623 			break;
624 
625 		case GCMD_STATE_ABORTING_CMD:
626 			action = GACTION_ABORT_DEV;
627 			break;
628 
629 		case GCMD_STATE_ABORTING_DEV:
630 			action = GACTION_RESET_TARGET;
631 			break;
632 
633 		case GCMD_STATE_RESETTING_DEV:
634 			action = GACTION_RESET_BUS;
635 			break;
636 
637 		case GCMD_STATE_RESETTING_BUS:
638 			action = GACTION_INCOMPLETE;
639 			break;
640 
641 		case GCMD_STATE_HUNG:
642 			action = GACTION_INCOMPLETE;
643 			break;
644 		}
645 
646 		ghd_timer_newstate(cccp, gcmdp, gcmdp->cmd_gtgtp, action,
647 		    GHD_TIMEOUT);
648 
649 		/* return after processing first cmd if requested */
650 
651 		if (calltype == GHD_TIMER_POLL_ONE)
652 			return;
653 	}
654 }
655 
656 
657 
658 
659 /*
660  *
661  * ghd_timeout_get()
662  *
663  *	Remove the first expired CCB from a particular timer list.
664  *
665  */
666 
667 static gcmd_t *
ghd_timeout_get(ccc_t * cccp)668 ghd_timeout_get(ccc_t *cccp)
669 {
670 	gcmd_t	*gcmdp;
671 	ulong_t	lbolt;
672 
673 	ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
674 
675 	mutex_enter(&cccp->ccc_activel_mutex);
676 	lbolt = ddi_get_lbolt();
677 	gcmdp = (gcmd_t *)L2_next(&cccp->ccc_activel);
678 	while (gcmdp != NULL) {
679 		if ((gcmdp->cmd_timeout > 0) &&
680 		    (lbolt - gcmdp->cmd_start_time >= gcmdp->cmd_timeout))
681 			goto expired;
682 		gcmdp = (gcmd_t *)L2_next(&gcmdp->cmd_timer_link);
683 	}
684 	mutex_exit(&cccp->ccc_activel_mutex);
685 	return (NULL);
686 
687 expired:
688 	/* unlink if from the CCB timer list */
689 	L2_delete(&gcmdp->cmd_timer_link);
690 	mutex_exit(&cccp->ccc_activel_mutex);
691 	return (gcmdp);
692 }
693 
694 
695 /*
696  *
697  * ghd_timeout_enable()
698  *
699  *	Only start a single timeout callback for each HBA driver
700  *	regardless of the number of boards it supports.
701  *
702  */
703 
704 static void
ghd_timeout_enable(tmr_t * tmrp)705 ghd_timeout_enable(tmr_t *tmrp)
706 {
707 	mutex_enter(&tglobal_mutex);
708 	if (tmrp->t_refs++ == 0)  {
709 		/* establish the timeout callback */
710 		tmrp->t_timeout_id = timeout(ghd_timeout, (void *)tmrp,
711 		    tmrp->t_ticks);
712 	}
713 	mutex_exit(&tglobal_mutex);
714 }
715 
716 static void
ghd_timeout_disable(tmr_t * tmrp)717 ghd_timeout_disable(tmr_t *tmrp)
718 {
719 	ASSERT(tmrp != NULL);
720 
721 	mutex_enter(&tglobal_mutex);
722 	if (tmrp->t_refs-- <= 1) {
723 		(void) untimeout(tmrp->t_timeout_id);
724 	}
725 	mutex_exit(&tglobal_mutex);
726 }
727 
728 /* ************************************************************************ */
729 
730 	/* these are the externally callable routines */
731 
732 
733 void
ghd_timer_init(tmr_t * tmrp,long ticks)734 ghd_timer_init(tmr_t *tmrp, long ticks)
735 {
736 	int	indx;
737 
738 	mutex_init(&tglobal_mutex, NULL, MUTEX_DRIVER, NULL);
739 	mutex_init(&tmrp->t_mutex, NULL, MUTEX_DRIVER, NULL);
740 
741 	/*
742 	 * determine default timeout value
743 	 */
744 	ghd_HZ = drv_usectohz(1000000);
745 	if (ticks == 0)
746 		ticks = scsi_watchdog_tick * ghd_HZ;
747 	tmrp->t_ticks = ticks;
748 
749 
750 	/*
751 	 * Initialize the table of abort timer values using an
752 	 * indirect lookup table so that this code isn't dependant
753 	 * on the cmdstate_t enum values or order.
754 	 */
755 	for (indx = 0; indx < ghd_ntime_inits; indx++) {
756 		int	state;
757 		ulong_t	value;
758 
759 		if (!ghd_time_inits[indx].valid)
760 			continue;
761 		state = ghd_time_inits[indx].state;
762 		value = ghd_time_inits[indx].value;
763 		ghd_timeout_table[state] = (cmdstate_t)value;
764 	}
765 }
766 
767 void
ghd_timer_fini(tmr_t * tmrp)768 ghd_timer_fini(tmr_t *tmrp)
769 {
770 	mutex_destroy(&tmrp->t_mutex);
771 	mutex_destroy(&tglobal_mutex);
772 }
773 
774 int
ghd_timer_attach(ccc_t * cccp,tmr_t * tmrp,int (* timeout_func)(void *,gcmd_t *,gtgt_t *,gact_t,int))775 ghd_timer_attach(ccc_t *cccp, tmr_t *tmrp,
776     int (*timeout_func)(void *, gcmd_t *, gtgt_t *, gact_t, int))
777 {
778 	ddi_iblock_cookie_t iblock;
779 
780 	if (ddi_add_softintr(cccp->ccc_hba_dip, DDI_SOFTINT_LOW,
781 	    &cccp->ccc_soft_id, &iblock, NULL,
782 	    ghd_timeout_softintr, (caddr_t)cccp) != DDI_SUCCESS) {
783 		GDBG_ERROR((
784 		    "ghd_timer_attach: add softintr failed cccp 0x%p\n",
785 		    (void *)cccp));
786 		return (FALSE);
787 	}
788 
789 	/* init the per HBA-instance control fields */
790 	mutex_init(&cccp->ccc_activel_mutex, NULL, MUTEX_DRIVER, iblock);
791 	L2_INIT(&cccp->ccc_activel);
792 	cccp->ccc_timeout_func = timeout_func;
793 
794 	/* stick this HBA's control structure on the master list */
795 	mutex_enter(&tmrp->t_mutex);
796 
797 	cccp->ccc_nextp = tmrp->t_ccc_listp;
798 	tmrp->t_ccc_listp = cccp;
799 	cccp->ccc_tmrp = tmrp;
800 	mutex_exit(&tmrp->t_mutex);
801 
802 	/*
803 	 * The enable and disable routines use a separate mutex than
804 	 * t_mutex which is used by the timeout callback function.
805 	 * This is to avoid a deadlock when calling untimeout() from
806 	 * the disable routine.
807 	 */
808 	ghd_timeout_enable(tmrp);
809 
810 	return (TRUE);
811 }
812 
813 
814 /*
815  *
816  * ghd_timer_detach()
817  *
818  *	clean up for a detaching HBA instance
819  *
820  */
821 
822 void
ghd_timer_detach(ccc_t * cccp)823 ghd_timer_detach(ccc_t *cccp)
824 {
825 	tmr_t	*tmrp = cccp->ccc_tmrp;
826 	ccc_t	**prevpp;
827 
828 	/* make certain the CCB list is empty */
829 	ASSERT(cccp->ccc_activel.l2_nextp == &cccp->ccc_activel);
830 	ASSERT(cccp->ccc_activel.l2_nextp == cccp->ccc_activel.l2_prevp);
831 
832 	mutex_enter(&tmrp->t_mutex);
833 
834 	prevpp = &tmrp->t_ccc_listp;
835 	ASSERT(*prevpp != NULL);
836 
837 	/* run down the linked list to find the entry that preceeds this one */
838 	do {
839 		if (*prevpp == cccp)
840 			goto remove_it;
841 		prevpp = &(*prevpp)->ccc_nextp;
842 	} while (*prevpp != NULL);
843 
844 	/* fell off the end of the list */
845 	GDBG_ERROR(("ghd_timer_detach: corrupt list, cccp=0x%p\n",
846 	    (void *)cccp));
847 
848 remove_it:
849 	*prevpp = cccp->ccc_nextp;
850 	mutex_exit(&tmrp->t_mutex);
851 	mutex_destroy(&cccp->ccc_activel_mutex);
852 
853 	ddi_remove_softintr(cccp->ccc_soft_id);
854 
855 	ghd_timeout_disable(tmrp);
856 }
857 
858 /*
859  *
860  * ghd_timer_start()
861  *
862  *	Add a CCB to the CCB timer list.
863  */
864 
865 void
ghd_timer_start(ccc_t * cccp,gcmd_t * gcmdp,long cmd_timeout)866 ghd_timer_start(ccc_t *cccp, gcmd_t *gcmdp, long cmd_timeout)
867 {
868 	ulong_t	lbolt;
869 
870 	mutex_enter(&cccp->ccc_activel_mutex);
871 	lbolt = ddi_get_lbolt();
872 
873 	/* initialize this CCB's timer */
874 	gcmdp->cmd_start_time = lbolt;
875 	gcmdp->cmd_timeout = (cmd_timeout * ghd_HZ);
876 
877 	/* add it to the list */
878 	L2_add(&cccp->ccc_activel, &gcmdp->cmd_timer_link, gcmdp);
879 	mutex_exit(&cccp->ccc_activel_mutex);
880 }
881 
882 
883 /*
884  *
885  * ghd_timer_stop()
886  *
887  *	Remove a completed CCB from the CCB timer list.
888  *
889  *	See the GHD_TIMER_STOP_INLINE() macro in ghd.h for
890  *	the actual code.
891  */
892 
893 void
ghd_timer_stop(ccc_t * cccp,gcmd_t * gcmdp)894 ghd_timer_stop(ccc_t *cccp, gcmd_t *gcmdp)
895 {
896 	GHD_TIMER_STOP_INLINE(cccp, gcmdp);
897 }
898