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