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