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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/conf.h> 31 #include <sys/ddi.h> 32 #include <sys/sunddi.h> 33 #include <sys/ksynch.h> 34 #include <sys/scsi/conf/autoconf.h> 35 #include <sys/reboot.h> 36 37 #include "ghd.h" 38 39 /* 40 * Local functions 41 */ 42 43 static gcmd_t *ghd_timeout_get(ccc_t *cccp); 44 static int ghd_timeout_loop(ccc_t *cccp); 45 static uint_t ghd_timeout_softintr(caddr_t arg); 46 static void ghd_timeout(void *arg); 47 static void ghd_timeout_disable(tmr_t *tmrp); 48 static void ghd_timeout_enable(tmr_t *tmrp); 49 50 /* 51 * Local data 52 */ 53 long ghd_HZ; 54 static kmutex_t tglobal_mutex; 55 56 /* table of timeouts for abort processing steps */ 57 cmdstate_t ghd_timeout_table[GCMD_NSTATES]; 58 59 /* This table indirectly initializes the ghd_timeout_table */ 60 struct { 61 int valid; 62 cmdstate_t state; 63 long value; 64 } ghd_time_inits[] = { 65 { TRUE, GCMD_STATE_ABORTING_CMD, 3 }, 66 { TRUE, GCMD_STATE_ABORTING_DEV, 3 }, 67 { TRUE, GCMD_STATE_RESETTING_DEV, 5 }, 68 { TRUE, GCMD_STATE_RESETTING_BUS, 10 }, 69 { TRUE, GCMD_STATE_HUNG, 60}, 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 { FALSE, 0, 0 } /* spare entry */ 75 }; 76 int ghd_ntime_inits = sizeof (ghd_time_inits) 77 / sizeof (ghd_time_inits[0]); 78 79 /* 80 * Locally-used macros 81 */ 82 83 /* 84 * Compare two gcmd_t's to see if they're for the same device (same gdev_t) 85 */ 86 #define GCMD_SAME_DEV(gcmdp1, gcmdp2) \ 87 (GCMDP2GDEVP(gcmdp1) == GCMDP2GDEVP(gcmdp2)) 88 89 /* 90 * Compare two gcmd_t's to see if they're for the same bus (same HBA inst) 91 */ 92 #define GCMD_SAME_BUS(gcmdp1, gcmdp2) \ 93 (GCMDP2CCCP(gcmdp1) == GCMDP2CCCP(gcmdp2)) 94 95 96 /* 97 * Update state of gcmdp (in one direction, increasing state number, only) 98 */ 99 #define GCMD_UPDATE_STATE(gcmdp, newstate) \ 100 { \ 101 if ((gcmdp)->cmd_state < (newstate)) { \ 102 ((gcmdp)->cmd_state = (newstate)); \ 103 } \ 104 } 105 106 #ifdef ___notyet___ 107 108 #include <sys/modctl.h> 109 extern struct mod_ops mod_miscops; 110 static struct modlmisc modlmisc = { 111 &mod_miscops, /* Type of module */ 112 "CCB Timeout Utility Routines" 113 }; 114 static struct modlinkage modlinkage = { 115 MODREV_1, (void *)&modlmisc, NULL 116 }; 117 118 /* 119 * If this is a loadable module then there's a single CCB timer configure 120 * structure for all HBA drivers (rather than one per HBA driver). 121 */ 122 static tmr_t tmr_conf; 123 124 int 125 _init() 126 { 127 int err; 128 129 ghd_timer_init(&tmr_conf, 0); 130 return ((err = mod_install(&modlinkage)) != 0) 131 ghd_timer_fini(&tmr_conf); 132 return (err); 133 } 134 135 int 136 _fini() 137 { 138 int err; 139 140 if ((err = mod_remove(&modlinkage)) == 0) 141 ghd_timer_fini(&tmr_conf); 142 return (err); 143 } 144 145 int 146 _info(struct modinfo *modinfop) 147 { 148 return (mod_info(&modlinkage, modinfop)); 149 } 150 151 #endif /* ___notyet___ */ 152 153 154 155 /* 156 * 157 * ghd_timeout_loop() 158 * 159 * Check the CCB timer value for every active CCB for this 160 * HBA driver instance. 161 * 162 * This function is called both by the ghd_timeout() interrupt 163 * handler when called via the timer callout, and by ghd_timer_poll() 164 * while procesing "polled" (FLAG_NOINTR) requests. 165 * 166 * The ccc_activel_mutex is held while a CCB list is being scanned. 167 * This prevents the HBA driver's transport or interrupt functions 168 * from changing the active CCB list. But we wake up very infrequently 169 * and do as little as possible so it shouldn't affect performance. 170 * 171 */ 172 173 static int 174 ghd_timeout_loop(ccc_t *cccp) 175 { 176 int got_any = FALSE; 177 gcmd_t *gcmdp; 178 ulong_t lbolt; 179 180 mutex_enter(&cccp->ccc_activel_mutex); 181 lbolt = ddi_get_lbolt(); 182 gcmdp = (gcmd_t *)L2_next(&cccp->ccc_activel); 183 while (gcmdp) { 184 /* 185 * check to see if this one has timed out 186 */ 187 if ((gcmdp->cmd_timeout > 0) && 188 (lbolt - gcmdp->cmd_start_time >= gcmdp->cmd_timeout)) { 189 got_any = TRUE; 190 } 191 gcmdp = (gcmd_t *)L2_next(&gcmdp->cmd_timer_link); 192 } 193 mutex_exit(&cccp->ccc_activel_mutex); 194 return (got_any); 195 } 196 197 /* 198 * 199 * ghd_timeout() 200 * 201 * Called every t_ticks ticks to scan the CCB timer lists 202 * 203 * The t_mutex mutex is held the entire time this routine is active. 204 * It protects the list of ccc_t's. 205 * 206 * The list of cmd_t's is protected by the ccc_activel_mutex mutex 207 * in the ghd_timeout_loop() routine. 208 * 209 * We also check to see if the waitq is frozen, and if so, 210 * adjust our timeout to call back sooner if necessary (to 211 * unfreeze the waitq as soon as possible). 212 * 213 * 214 * +------------+ 215 * | tmr_t |----+ 216 * +------------+ | 217 * | 218 * V 219 * +---------+ 220 * | ccc_t |----+ 221 * +---------+ | 222 * | V 223 * | +--------+ +--------+ 224 * | | gcmd_t |-->| gcmd_t |--> ... 225 * | +--------+ +--------+ 226 * V 227 * +---------+ 228 * | ccc_t |----+ 229 * +---------+ | 230 * | V 231 * | +--------+ 232 * | | gcmd_t | 233 * V +--------+ 234 * ... 235 * 236 * 237 * 238 */ 239 240 static void 241 ghd_timeout(void *arg) 242 { 243 tmr_t *tmrp = (tmr_t *)arg; 244 ccc_t *cccp; 245 clock_t ufdelay_curr; 246 clock_t lbolt, delay_in_hz; 247 clock_t resched = (clock_t)0x7FFFFFFF; 248 249 /* 250 * Each HBA driver instance has a separate CCB timer list. Skip 251 * timeout processing if there are no more active timeout lists 252 * to process. (There are no lists only if there are no attached 253 * HBA instances; the list still exists if there are no outstanding 254 * active commands.) 255 */ 256 mutex_enter(&tmrp->t_mutex); 257 if ((cccp = tmrp->t_ccc_listp) == NULL) { 258 mutex_exit(&tmrp->t_mutex); 259 return; 260 } 261 262 lbolt = ddi_get_lbolt(); 263 264 do { 265 /* 266 * If any active CCBs on this HBA have timed out 267 * then kick off the HBA driver's softintr 268 * handler to do the timeout processing 269 */ 270 if (ghd_timeout_loop(cccp)) { 271 cccp->ccc_timeout_pending = 1; 272 ddi_trigger_softintr(cccp->ccc_soft_id); 273 } 274 275 /* Record closest unfreeze time for use in next timeout */ 276 277 mutex_enter(&cccp->ccc_waitq_mutex); 278 if (cccp->ccc_waitq_frozen) { 279 280 delay_in_hz = 281 drv_usectohz(cccp->ccc_waitq_freezedelay * 1000); 282 ufdelay_curr = delay_in_hz - 283 (lbolt - cccp->ccc_waitq_freezetime); 284 285 if (ufdelay_curr < resched) 286 resched = ufdelay_curr; 287 288 /* frozen; trigger softintr to maybe unfreeze */ 289 ddi_trigger_softintr(cccp->ccc_soft_id); 290 } 291 mutex_exit(&cccp->ccc_waitq_mutex); 292 293 } while ((cccp = cccp->ccc_nextp) != NULL); 294 295 /* don't allow any unfreeze delays to increase the timeout delay */ 296 if (resched > tmrp->t_ticks) 297 resched = tmrp->t_ticks; 298 299 /* re-establish the timeout callback */ 300 tmrp->t_timeout_id = timeout(ghd_timeout, (void *)tmrp, resched); 301 302 mutex_exit(&tmrp->t_mutex); 303 } 304 305 306 /* 307 * 308 * ghd_timer_newstate() 309 * 310 * The HBA mutex is held by my caller. 311 * 312 */ 313 314 void 315 ghd_timer_newstate(ccc_t *cccp, gcmd_t *gcmdp, gtgt_t *gtgtp, 316 gact_t action, int calltype) 317 { 318 gact_t next_action; 319 cmdstate_t next_state; 320 char *msgp; 321 long new_timeout; 322 int (*func)(void *, gcmd_t *, gtgt_t *, gact_t, int); 323 void *hba_handle; 324 gcmd_t gsav; 325 int gsav_used = 0; 326 gcmd_t *gcmdp_scan; 327 328 ASSERT(mutex_owned(&cccp->ccc_hba_mutex)); 329 330 #ifdef DEBUG 331 /* it shouldn't be on the timer active list */ 332 if (gcmdp != NULL) { 333 L2el_t *lp = &gcmdp->cmd_timer_link; 334 ASSERT(lp->l2_nextp == lp); 335 ASSERT(lp->l2_prevp == lp); 336 } 337 #endif 338 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 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 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 cccp, 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 * 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 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 718 ghd_timeout_disable(tmr_t *tmrp) 719 { 720 ASSERT(tmrp != NULL); 721 ASSERT(tmrp->t_ccc_listp == NULL); 722 723 mutex_enter(&tglobal_mutex); 724 if (tmrp->t_refs-- <= 1) 725 (void) untimeout(tmrp->t_timeout_id); 726 mutex_exit(&tglobal_mutex); 727 } 728 729 /* ************************************************************************ */ 730 731 /* these are the externally callable routines */ 732 733 734 void 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] = value; 765 } 766 } 767 768 void 769 ghd_timer_fini(tmr_t *tmrp) 770 { 771 mutex_destroy(&tmrp->t_mutex); 772 mutex_destroy(&tglobal_mutex); 773 } 774 775 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 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 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 895 ghd_timer_stop(ccc_t *cccp, gcmd_t *gcmdp) 896 { 897 GHD_TIMER_STOP_INLINE(cccp, gcmdp); 898 } 899