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 = 0;
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 bzero(&gsav, sizeof (gsav));
339 func = cccp->ccc_timeout_func;
340 hba_handle = cccp->ccc_hba_handle;
341
342 for (;;) {
343 switch (action) {
344 case GACTION_EARLY_ABORT:
345 /* done before it started */
346 ASSERT(gcmdp != NULL);
347 msgp = "early abort";
348 next_state = GCMD_STATE_DONEQ;
349 next_action = GACTION_ABORT_CMD;
350 break;
351
352 case GACTION_EARLY_TIMEOUT:
353 /* done before it started */
354 ASSERT(gcmdp != NULL);
355 msgp = "early timeout";
356 next_state = GCMD_STATE_DONEQ;
357 next_action = GACTION_ABORT_CMD;
358 break;
359
360 case GACTION_ABORT_CMD:
361 msgp = "abort request";
362 ASSERT(gcmdp != NULL);
363 next_state = GCMD_STATE_ABORTING_CMD;
364 next_action = GACTION_ABORT_DEV;
365 break;
366
367 case GACTION_ABORT_DEV:
368 msgp = "abort device";
369 next_state = GCMD_STATE_ABORTING_DEV;
370 next_action = GACTION_RESET_TARGET;
371 break;
372
373 case GACTION_RESET_TARGET:
374 msgp = "reset target";
375 next_state = GCMD_STATE_RESETTING_DEV;
376 next_action = GACTION_RESET_BUS;
377 break;
378
379 case GACTION_RESET_BUS:
380 msgp = "reset bus";
381 next_state = GCMD_STATE_RESETTING_BUS;
382 next_action = GACTION_INCOMPLETE;
383 break;
384
385 case GACTION_INCOMPLETE:
386 default:
387 /* be verbose about HBA resets */
388 GDBG_ERROR(("?ghd_timer_newstate: HBA reset failed "
389 "hba 0x%p gcmdp 0x%p gtgtp 0x%p\n",
390 (void *)hba_handle, (void *)gcmdp, (void *)gtgtp));
391 /*
392 * When all else fails, punt.
393 *
394 * We're in big trouble if we get to this point.
395 * Maybe we should try to re-initialize the HBA.
396 */
397 msgp = "HBA reset";
398 next_state = GCMD_STATE_HUNG;
399 next_action = GACTION_INCOMPLETE;
400 break;
401 }
402
403 /*
404 * I want to see target requests only if verbose, but
405 * scsi_log() only prints the device pathname if level
406 * is CE_WARN or CE_PANIC...so I guess we can't use
407 * scsi_log for TGTREQ messages, or they must come to
408 * the console. How silly. Looking for "verbose boot"
409 * is non-DDI-compliant, but let's do it anyway.
410 */
411
412 if (calltype == GHD_TGTREQ) {
413 if ((boothowto & RB_VERBOSE)) {
414 scsi_log(cccp->ccc_hba_dip, cccp->ccc_label,
415 CE_WARN,
416 "target request: %s, target=%d lun=%d",
417 msgp, gtgtp->gt_target, gtgtp->gt_lun);
418 }
419 } else {
420 scsi_log(cccp->ccc_hba_dip, cccp->ccc_label, CE_WARN,
421 "timeout: %s, target=%d lun=%d", msgp,
422 gtgtp->gt_target, gtgtp->gt_lun);
423 }
424
425 /*
426 * Before firing off the HBA action, restart the timer
427 * using the timeout value from ghd_timeout_table[].
428 *
429 * The table entries should never restart the timer
430 * for the GHD_STATE_IDLE and GHD_STATE_DONEQ states.
431 *
432 */
433 if (gcmdp) {
434 gcmdp->cmd_state = next_state;
435 new_timeout = ghd_timeout_table[gcmdp->cmd_state];
436 if (new_timeout != 0)
437 ghd_timer_start(cccp, gcmdp, new_timeout);
438
439 /* save a copy in case action function frees it */
440 gsav = *gcmdp;
441 gsav_used = 1;
442 }
443
444 if (action == GACTION_RESET_BUS && cccp->ccc_waitq_frozen) {
445 GDBG_WARN(("avoiding bus reset while waitq frozen\n"));
446 break;
447 }
448
449 /* invoke the HBA's action function */
450 if ((*func)(hba_handle, gcmdp, gtgtp, action, calltype)) {
451 /* if it took wait for an interrupt or timeout */
452 break;
453 }
454 /*
455 * if the HBA reset fails leave the retry
456 * timer running and just exit.
457 */
458 if (action == GACTION_INCOMPLETE)
459 return;
460
461 /* all other failures cause transition to next action */
462 if (gcmdp != NULL && new_timeout != 0) {
463 /*
464 * But stop the old timer prior to
465 * restarting a new timer because each step may
466 * have a different timeout value.
467 */
468 GHD_TIMER_STOP(cccp, gcmdp);
469 }
470 action = next_action;
471 }
472
473 /*
474 * HBA action function is done with gsav (if used)
475 * or gtgtp/cccp (if gsav not used). We need to mark other
476 * outstanding requests if they were affected by this action
477 * (say, a device reset which also cancels all outstanding
478 * requests on this device) to prevent multiple timeouts/HBA
479 * actions for the same device or bus condition. Scan the timer
480 * list (all active requests) and update states as necessary.
481 * Hold the activel_mutex while scanning the active list. Check
482 * for either same dev/bus as gsav (if used) or for same
483 * dev/bus as gtgtp or cccp (if gsav is not used).
484 */
485
486 mutex_enter(&cccp->ccc_activel_mutex);
487
488 for (gcmdp_scan = (gcmd_t *)L2_next(&cccp->ccc_activel);
489 gcmdp_scan != NULL;
490 gcmdp_scan = (gcmd_t *)L2_next(&gcmdp_scan->cmd_timer_link)) {
491
492 /* skip idle or waitq commands */
493 if (gcmdp_scan->cmd_state <= GCMD_STATE_WAITQ)
494 continue;
495
496 switch (action) {
497
498 case GACTION_ABORT_DEV:
499 if ((gsav_used && GCMD_SAME_DEV(&gsav, gcmdp_scan)) ||
500 (GCMDP2GDEVP(gcmdp_scan) == GTGTP2GDEVP(gtgtp))) {
501 GCMD_UPDATE_STATE(gcmdp_scan,
502 GCMD_STATE_ABORTING_DEV);
503 }
504 break;
505
506 case GACTION_RESET_TARGET:
507 if ((gsav_used && GCMD_SAME_DEV(&gsav, gcmdp_scan)) ||
508 (GCMDP2GDEVP(gcmdp_scan) == GTGTP2GDEVP(gtgtp))) {
509 GCMD_UPDATE_STATE(gcmdp_scan,
510 GCMD_STATE_RESETTING_DEV);
511 }
512 break;
513
514 case GACTION_RESET_BUS:
515 if ((gsav_used && GCMD_SAME_BUS(&gsav, gcmdp_scan)) ||
516 (GCMDP2CCCP(gcmdp_scan) == cccp)) {
517 GCMD_UPDATE_STATE(gcmdp_scan,
518 GCMD_STATE_RESETTING_BUS);
519 }
520 break;
521 default:
522 break;
523 }
524 }
525
526 mutex_exit(&cccp->ccc_activel_mutex);
527 }
528
529
530 /*
531 *
532 * ghd_timeout_softintr()
533 *
534 * This interrupt is scheduled if a particular HBA instance's
535 * CCB timer list has a timed out CCB, or if the waitq is in a
536 * frozen state.
537 *
538 * Find the timed out CCB and then call the HBA driver's timeout
539 * function.
540 *
541 * In order to avoid race conditions all processing must be done
542 * while holding the HBA instance's mutex. If the mutex wasn't
543 * held the HBA driver's hardware interrupt routine could be
544 * triggered and it might try to remove a CCB from the list at
545 * same time as were trying to abort it.
546 *
547 * For frozen-waitq processing, just call ghd_waitq_process...
548 * it takes care of the time calculations.
549 *
550 */
551
552 static uint_t
ghd_timeout_softintr(caddr_t arg)553 ghd_timeout_softintr(caddr_t arg)
554 {
555 ccc_t *cccp = (ccc_t *)arg;
556
557 if (cccp->ccc_timeout_pending) {
558
559 /* grab this HBA instance's mutex */
560 mutex_enter(&cccp->ccc_hba_mutex);
561
562 /*
563 * The claim is we could reset "pending" outside the mutex, but
564 * since we have to acquire the mutex anyway, it doesn't hurt
565 */
566 cccp->ccc_timeout_pending = 0;
567
568 /* timeout each expired CCB */
569 ghd_timer_poll(cccp, GHD_TIMER_POLL_ALL);
570
571 mutex_enter(&cccp->ccc_waitq_mutex);
572 ghd_waitq_process_and_mutex_exit(cccp);
573
574 } else if (cccp->ccc_waitq_frozen) {
575 mutex_enter(&cccp->ccc_hba_mutex);
576 mutex_enter(&cccp->ccc_waitq_mutex);
577 ghd_waitq_process_and_mutex_exit(cccp);
578 }
579
580 return (DDI_INTR_UNCLAIMED);
581 }
582
583
584 /*
585 * ghd_timer_poll()
586 *
587 * This function steps a packet to the next action in the recovery
588 * procedure.
589 *
590 * The caller must be already holding the HBA mutex and take care of
591 * running the pkt completion functions.
592 *
593 */
594
595 void
ghd_timer_poll(ccc_t * cccp,gtimer_poll_t calltype)596 ghd_timer_poll(ccc_t *cccp, gtimer_poll_t calltype)
597 {
598 gcmd_t *gcmdp;
599 gact_t action;
600
601 ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
602
603 /* abort each expired CCB */
604 while (gcmdp = ghd_timeout_get(cccp)) {
605
606 GDBG_INTR(("?ghd_timer_poll: cccp=0x%p gcmdp=0x%p\n",
607 (void *)cccp, (void *)gcmdp));
608
609 switch (gcmdp->cmd_state) {
610 case GCMD_STATE_IDLE:
611 case GCMD_STATE_DONEQ:
612 default:
613 /* not supposed to happen */
614 GDBG_ERROR(("ghd_timer_poll: invalid state %d\n",
615 gcmdp->cmd_state));
616 return;
617
618 case GCMD_STATE_WAITQ:
619 action = GACTION_EARLY_TIMEOUT;
620 break;
621
622 case GCMD_STATE_ACTIVE:
623 action = GACTION_ABORT_CMD;
624 break;
625
626 case GCMD_STATE_ABORTING_CMD:
627 action = GACTION_ABORT_DEV;
628 break;
629
630 case GCMD_STATE_ABORTING_DEV:
631 action = GACTION_RESET_TARGET;
632 break;
633
634 case GCMD_STATE_RESETTING_DEV:
635 action = GACTION_RESET_BUS;
636 break;
637
638 case GCMD_STATE_RESETTING_BUS:
639 action = GACTION_INCOMPLETE;
640 break;
641
642 case GCMD_STATE_HUNG:
643 action = GACTION_INCOMPLETE;
644 break;
645 }
646
647 ghd_timer_newstate(cccp, gcmdp, gcmdp->cmd_gtgtp, action,
648 GHD_TIMEOUT);
649
650 /* return after processing first cmd if requested */
651
652 if (calltype == GHD_TIMER_POLL_ONE)
653 return;
654 }
655 }
656
657
658
659
660 /*
661 *
662 * ghd_timeout_get()
663 *
664 * Remove the first expired CCB from a particular timer list.
665 *
666 */
667
668 static gcmd_t *
ghd_timeout_get(ccc_t * cccp)669 ghd_timeout_get(ccc_t *cccp)
670 {
671 gcmd_t *gcmdp;
672 ulong_t lbolt;
673
674 ASSERT(mutex_owned(&cccp->ccc_hba_mutex));
675
676 mutex_enter(&cccp->ccc_activel_mutex);
677 lbolt = ddi_get_lbolt();
678 gcmdp = (gcmd_t *)L2_next(&cccp->ccc_activel);
679 while (gcmdp != NULL) {
680 if ((gcmdp->cmd_timeout > 0) &&
681 (lbolt - gcmdp->cmd_start_time >= gcmdp->cmd_timeout))
682 goto expired;
683 gcmdp = (gcmd_t *)L2_next(&gcmdp->cmd_timer_link);
684 }
685 mutex_exit(&cccp->ccc_activel_mutex);
686 return (NULL);
687
688 expired:
689 /* unlink if from the CCB timer list */
690 L2_delete(&gcmdp->cmd_timer_link);
691 mutex_exit(&cccp->ccc_activel_mutex);
692 return (gcmdp);
693 }
694
695
696 /*
697 *
698 * ghd_timeout_enable()
699 *
700 * Only start a single timeout callback for each HBA driver
701 * regardless of the number of boards it supports.
702 *
703 */
704
705 static void
ghd_timeout_enable(tmr_t * tmrp)706 ghd_timeout_enable(tmr_t *tmrp)
707 {
708 mutex_enter(&tglobal_mutex);
709 if (tmrp->t_refs++ == 0) {
710 /* establish the timeout callback */
711 tmrp->t_timeout_id = timeout(ghd_timeout, (void *)tmrp,
712 tmrp->t_ticks);
713 }
714 mutex_exit(&tglobal_mutex);
715 }
716
717 static void
ghd_timeout_disable(tmr_t * tmrp)718 ghd_timeout_disable(tmr_t *tmrp)
719 {
720 ASSERT(tmrp != NULL);
721
722 mutex_enter(&tglobal_mutex);
723 if (tmrp->t_refs-- <= 1) {
724 (void) untimeout(tmrp->t_timeout_id);
725 }
726 mutex_exit(&tglobal_mutex);
727 }
728
729 /* ************************************************************************ */
730
731 /* these are the externally callable routines */
732
733
734 void
ghd_timer_init(tmr_t * tmrp,long ticks)735 ghd_timer_init(tmr_t *tmrp, long ticks)
736 {
737 int indx;
738
739 mutex_init(&tglobal_mutex, NULL, MUTEX_DRIVER, NULL);
740 mutex_init(&tmrp->t_mutex, NULL, MUTEX_DRIVER, NULL);
741
742 /*
743 * determine default timeout value
744 */
745 ghd_HZ = drv_usectohz(1000000);
746 if (ticks == 0)
747 ticks = scsi_watchdog_tick * ghd_HZ;
748 tmrp->t_ticks = ticks;
749
750
751 /*
752 * Initialize the table of abort timer values using an
753 * indirect lookup table so that this code isn't dependant
754 * on the cmdstate_t enum values or order.
755 */
756 for (indx = 0; indx < ghd_ntime_inits; indx++) {
757 int state;
758 ulong_t value;
759
760 if (!ghd_time_inits[indx].valid)
761 continue;
762 state = ghd_time_inits[indx].state;
763 value = ghd_time_inits[indx].value;
764 ghd_timeout_table[state] = (cmdstate_t)value;
765 }
766 }
767
768 void
ghd_timer_fini(tmr_t * tmrp)769 ghd_timer_fini(tmr_t *tmrp)
770 {
771 mutex_destroy(&tmrp->t_mutex);
772 mutex_destroy(&tglobal_mutex);
773 }
774
775 int
ghd_timer_attach(ccc_t * cccp,tmr_t * tmrp,int (* timeout_func)(void *,gcmd_t *,gtgt_t *,gact_t,int))776 ghd_timer_attach(ccc_t *cccp, tmr_t *tmrp,
777 int (*timeout_func)(void *, gcmd_t *, gtgt_t *, gact_t, int))
778 {
779 ddi_iblock_cookie_t iblock;
780
781 if (ddi_add_softintr(cccp->ccc_hba_dip, DDI_SOFTINT_LOW,
782 &cccp->ccc_soft_id, &iblock, NULL,
783 ghd_timeout_softintr, (caddr_t)cccp) != DDI_SUCCESS) {
784 GDBG_ERROR((
785 "ghd_timer_attach: add softintr failed cccp 0x%p\n",
786 (void *)cccp));
787 return (FALSE);
788 }
789
790 /* init the per HBA-instance control fields */
791 mutex_init(&cccp->ccc_activel_mutex, NULL, MUTEX_DRIVER, iblock);
792 L2_INIT(&cccp->ccc_activel);
793 cccp->ccc_timeout_func = timeout_func;
794
795 /* stick this HBA's control structure on the master list */
796 mutex_enter(&tmrp->t_mutex);
797
798 cccp->ccc_nextp = tmrp->t_ccc_listp;
799 tmrp->t_ccc_listp = cccp;
800 cccp->ccc_tmrp = tmrp;
801 mutex_exit(&tmrp->t_mutex);
802
803 /*
804 * The enable and disable routines use a separate mutex than
805 * t_mutex which is used by the timeout callback function.
806 * This is to avoid a deadlock when calling untimeout() from
807 * the disable routine.
808 */
809 ghd_timeout_enable(tmrp);
810
811 return (TRUE);
812 }
813
814
815 /*
816 *
817 * ghd_timer_detach()
818 *
819 * clean up for a detaching HBA instance
820 *
821 */
822
823 void
ghd_timer_detach(ccc_t * cccp)824 ghd_timer_detach(ccc_t *cccp)
825 {
826 tmr_t *tmrp = cccp->ccc_tmrp;
827 ccc_t **prevpp;
828
829 /* make certain the CCB list is empty */
830 ASSERT(cccp->ccc_activel.l2_nextp == &cccp->ccc_activel);
831 ASSERT(cccp->ccc_activel.l2_nextp == cccp->ccc_activel.l2_prevp);
832
833 mutex_enter(&tmrp->t_mutex);
834
835 prevpp = &tmrp->t_ccc_listp;
836 ASSERT(*prevpp != NULL);
837
838 /* run down the linked list to find the entry that preceeds this one */
839 do {
840 if (*prevpp == cccp)
841 goto remove_it;
842 prevpp = &(*prevpp)->ccc_nextp;
843 } while (*prevpp != NULL);
844
845 /* fell off the end of the list */
846 GDBG_ERROR(("ghd_timer_detach: corrupt list, cccp=0x%p\n",
847 (void *)cccp));
848
849 remove_it:
850 *prevpp = cccp->ccc_nextp;
851 mutex_exit(&tmrp->t_mutex);
852 mutex_destroy(&cccp->ccc_activel_mutex);
853
854 ddi_remove_softintr(cccp->ccc_soft_id);
855
856 ghd_timeout_disable(tmrp);
857 }
858
859 /*
860 *
861 * ghd_timer_start()
862 *
863 * Add a CCB to the CCB timer list.
864 */
865
866 void
ghd_timer_start(ccc_t * cccp,gcmd_t * gcmdp,long cmd_timeout)867 ghd_timer_start(ccc_t *cccp, gcmd_t *gcmdp, long cmd_timeout)
868 {
869 ulong_t lbolt;
870
871 mutex_enter(&cccp->ccc_activel_mutex);
872 lbolt = ddi_get_lbolt();
873
874 /* initialize this CCB's timer */
875 gcmdp->cmd_start_time = lbolt;
876 gcmdp->cmd_timeout = (cmd_timeout * ghd_HZ);
877
878 /* add it to the list */
879 L2_add(&cccp->ccc_activel, &gcmdp->cmd_timer_link, gcmdp);
880 mutex_exit(&cccp->ccc_activel_mutex);
881 }
882
883
884 /*
885 *
886 * ghd_timer_stop()
887 *
888 * Remove a completed CCB from the CCB timer list.
889 *
890 * See the GHD_TIMER_STOP_INLINE() macro in ghd.h for
891 * the actual code.
892 */
893
894 void
ghd_timer_stop(ccc_t * cccp,gcmd_t * gcmdp)895 ghd_timer_stop(ccc_t *cccp, gcmd_t *gcmdp)
896 {
897 GHD_TIMER_STOP_INLINE(cccp, gcmdp);
898 }
899