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 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 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 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 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 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 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 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 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 * 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 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 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 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 768 ghd_timer_fini(tmr_t *tmrp) 769 { 770 mutex_destroy(&tmrp->t_mutex); 771 mutex_destroy(&tglobal_mutex); 772 } 773 774 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 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 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 894 ghd_timer_stop(ccc_t *cccp, gcmd_t *gcmdp) 895 { 896 GHD_TIMER_STOP_INLINE(cccp, gcmdp); 897 } 898