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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * generic scsi device watch 28 */ 29 30 #if DEBUG || lint 31 #define SWDEBUG 32 #endif 33 34 /* 35 * debug goodies 36 */ 37 #ifdef SWDEBUG 38 static int swdebug = 0; 39 #define DEBUGGING ((scsi_options & SCSI_DEBUG_TGT) && sddebug > 1) 40 #define SW_DEBUG if (swdebug == 1) scsi_log 41 #define SW_DEBUG2 if (swdebug > 1) scsi_log 42 #else /* SWDEBUG */ 43 #define swdebug (0) 44 #define DEBUGGING (0) 45 #define SW_DEBUG if (0) scsi_log 46 #define SW_DEBUG2 if (0) scsi_log 47 #endif 48 49 50 51 /* 52 * Includes, Declarations and Local Data 53 */ 54 55 #include <sys/note.h> 56 #include <sys/scsi/scsi.h> 57 #include <sys/var.h> 58 #include <sys/proc.h> 59 #include <sys/thread.h> 60 #include <sys/callb.h> 61 62 /* 63 * macro for filling in lun value for scsi-1 support 64 */ 65 #define FILL_SCSI1_LUN(devp, pkt) \ 66 if ((devp->sd_address.a_lun > 0) && \ 67 (devp->sd_inq->inq_ansi == 0x1)) { \ 68 ((union scsi_cdb *)(pkt)->pkt_cdbp)->scc_lun = \ 69 devp->sd_address.a_lun; \ 70 } 71 72 char *sw_label = "scsi-watch"; 73 74 static int scsi_watch_io_time = SCSI_WATCH_IO_TIME; 75 76 /* 77 * all info resides in the scsi watch structure 78 * 79 * the monitoring is performed by one separate thread which works 80 * from a linked list of scsi_watch_request packets 81 */ 82 static struct scsi_watch { 83 kthread_t *sw_thread; /* the watch thread */ 84 kmutex_t sw_mutex; /* mutex protecting list */ 85 /* and this structure */ 86 kcondvar_t sw_cv; /* cv for waking up thread */ 87 struct scsi_watch_request *sw_head; /* head of linked list */ 88 /* of request structures */ 89 uchar_t sw_state; /* for suspend-resume */ 90 uchar_t sw_flags; /* to start at head of list */ 91 /* for watch thread */ 92 struct scsi_watch_request *swr_current; /* the command waiting to be */ 93 /* processed by the watch */ 94 /* thread which is being */ 95 /* blocked */ 96 } sw; 97 98 #if !defined(lint) 99 _NOTE(MUTEX_PROTECTS_DATA(scsi_watch::sw_mutex, scsi_watch)) 100 #endif 101 102 /* 103 * Values for sw_state 104 */ 105 #define SW_RUNNING 0 106 #define SW_SUSPEND_REQUESTED 1 107 #define SW_SUSPENDED 2 108 109 /* 110 * values for sw_flags 111 */ 112 #define SW_START_HEAD 0x1 113 114 struct scsi_watch_request { 115 struct scsi_watch_request *swr_next; /* linked request list */ 116 struct scsi_watch_request *swr_prev; 117 clock_t swr_interval; /* interval between TURs */ 118 clock_t swr_timeout; /* count down */ 119 uchar_t swr_busy; /* TUR in progress */ 120 uchar_t swr_what; /* watch or stop */ 121 uchar_t swr_sense_length; /* required sense length */ 122 struct scsi_pkt *swr_pkt; /* TUR pkt itself */ 123 struct scsi_pkt *swr_rqpkt; /* request sense pkt */ 124 struct buf *swr_rqbp; /* bp for request sense data */ 125 struct buf *swr_mmcbp; /* bp for MMC command data */ 126 int (*swr_callback)(); /* callback to driver */ 127 caddr_t swr_callback_arg; 128 kcondvar_t swr_terminate_cv; /* cv to wait on to cleanup */ 129 /* request synchronously */ 130 int swr_ref; /* refer count to the swr */ 131 uchar_t suspend_destroy; /* flag for free later */ 132 }; 133 134 /* 135 * values for swr flags 136 */ 137 #define SUSPEND_DESTROY 1 138 139 #if !defined(lint) 140 _NOTE(SCHEME_PROTECTS_DATA("unshared data", scsi_watch_request)) 141 #endif 142 143 /* 144 * values for sw_what 145 */ 146 #define SWR_WATCH 0 /* device watch */ 147 #define SWR_STOP 1 /* stop monitoring and destroy swr */ 148 #define SWR_SUSPEND_REQUESTED 2 /* req. pending suspend */ 149 #define SWR_SUSPENDED 3 /* req. is suspended */ 150 151 static opaque_t scsi_watch_request_submit_impl(struct scsi_device *devp, 152 int interval, int sense_length, int (*callback)(), caddr_t cb_arg, 153 boolean_t mmc); 154 static void scsi_watch_request_destroy(struct scsi_watch_request *swr); 155 static void scsi_watch_thread(void); 156 static void scsi_watch_request_intr(struct scsi_pkt *pkt); 157 158 /* 159 * setup, called from _init(), the thread is created when we need it 160 * and exits when there is nothing to do anymore and everything has been 161 * cleaned up (ie. resources deallocated) 162 */ 163 void 164 scsi_watch_init() 165 { 166 /* NO OTHER THREADS ARE RUNNING */ 167 mutex_init(&sw.sw_mutex, NULL, MUTEX_DRIVER, NULL); 168 cv_init(&sw.sw_cv, NULL, CV_DRIVER, NULL); 169 sw.sw_state = SW_RUNNING; 170 sw.sw_flags = 0; 171 sw.swr_current = NULL; 172 } 173 174 /* 175 * cleaning up, called from _fini() 176 */ 177 void 178 scsi_watch_fini() 179 { 180 /* NO OTHER THREADS ARE RUNNING */ 181 /* 182 * hope and pray that the thread has exited 183 */ 184 ASSERT(sw.sw_thread == 0); 185 mutex_destroy(&sw.sw_mutex); 186 cv_destroy(&sw.sw_cv); 187 } 188 189 /* 190 * allocate an swr (scsi watch request structure) and initialize pkts 191 */ 192 #define ROUTE &devp->sd_address 193 194 opaque_t 195 scsi_watch_request_submit( 196 struct scsi_device *devp, 197 int interval, 198 int sense_length, 199 int (*callback)(), /* callback function */ 200 caddr_t cb_arg) /* device number */ 201 { 202 return (scsi_watch_request_submit_impl(devp, interval, sense_length, 203 callback, cb_arg, B_FALSE)); 204 } 205 206 opaque_t 207 scsi_mmc_watch_request_submit( 208 struct scsi_device *devp, 209 int interval, 210 int sense_length, 211 int (*callback)(), /* callback function */ 212 caddr_t cb_arg) /* device number */ 213 { 214 return (scsi_watch_request_submit_impl(devp, interval, sense_length, 215 callback, cb_arg, B_TRUE)); 216 } 217 218 static opaque_t 219 scsi_watch_request_submit_impl( 220 struct scsi_device *devp, 221 int interval, 222 int sense_length, 223 int (*callback)(), /* callback function */ 224 caddr_t cb_arg, /* device number */ 225 boolean_t mmc) 226 { 227 register struct scsi_watch_request *swr = NULL; 228 register struct scsi_watch_request *sswr, *p; 229 struct buf *bp = NULL; 230 struct buf *mmcbp = NULL; 231 struct scsi_pkt *rqpkt = NULL; 232 struct scsi_pkt *pkt = NULL; 233 uchar_t dtype; 234 235 SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG, 236 "scsi_watch_request_submit: Entering ...\n"); 237 238 mutex_enter(&sw.sw_mutex); 239 if (sw.sw_thread == 0) { 240 register kthread_t *t; 241 242 t = thread_create((caddr_t)NULL, 0, scsi_watch_thread, 243 NULL, 0, &p0, TS_RUN, v.v_maxsyspri - 2); 244 sw.sw_thread = t; 245 } 246 247 for (p = sw.sw_head; p != NULL; p = p->swr_next) { 248 if ((p->swr_callback_arg == cb_arg) && 249 (p->swr_callback == callback)) 250 break; 251 } 252 253 /* update time interval for an existing request */ 254 if (p) { 255 if (p->swr_what != SWR_STOP) { 256 p->swr_timeout = p->swr_interval 257 = drv_usectohz(interval); 258 p->swr_what = SWR_WATCH; 259 p->swr_ref++; 260 cv_signal(&sw.sw_cv); 261 mutex_exit(&sw.sw_mutex); 262 return ((opaque_t)p); 263 } 264 } 265 mutex_exit(&sw.sw_mutex); 266 267 /* 268 * allocate space for scsi_watch_request 269 */ 270 swr = kmem_zalloc(sizeof (struct scsi_watch_request), KM_SLEEP); 271 272 /* 273 * allocate request sense bp and pkt and make cmd 274 * we shouldn't really need it if ARQ is enabled but it is useful 275 * if the ARQ failed. 276 */ 277 bp = scsi_alloc_consistent_buf(ROUTE, NULL, 278 sense_length, B_READ, SLEEP_FUNC, NULL); 279 280 rqpkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, 281 bp, CDB_GROUP0, 1, 0, PKT_CONSISTENT, SLEEP_FUNC, NULL); 282 283 (void) scsi_setup_cdb((union scsi_cdb *)rqpkt->pkt_cdbp, 284 SCMD_REQUEST_SENSE, 0, SENSE_LENGTH, 0); 285 FILL_SCSI1_LUN(devp, rqpkt); 286 rqpkt->pkt_private = (opaque_t)swr; 287 rqpkt->pkt_time = scsi_watch_io_time; 288 rqpkt->pkt_comp = scsi_watch_request_intr; 289 rqpkt->pkt_flags |= FLAG_HEAD; 290 291 /* 292 * Create TUR pkt or GET STATUS EVENT NOTIFICATION for MMC requests or 293 * a zero byte WRITE(10) based on the disk-type for reservation state. 294 * For inq_dtype of SBC (DIRECT, dtype == 0) 295 * OR for RBC devices (dtype is 0xE) AND for 296 * ANSI version of SPC/SPC-2/SPC-3 (inq_ansi == 3-5). 297 */ 298 299 dtype = devp->sd_inq->inq_dtype & DTYPE_MASK; 300 if (mmc) { 301 mmcbp = scsi_alloc_consistent_buf(ROUTE, NULL, 302 8, B_READ, SLEEP_FUNC, NULL); 303 304 pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, mmcbp, 305 CDB_GROUP1, sizeof (struct scsi_arq_status), 306 0, 0, SLEEP_FUNC, NULL); 307 308 (void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp, 309 SCMD_GET_EVENT_STATUS_NOTIFICATION, 0, 8, 0); 310 pkt->pkt_cdbp[1] = 1; /* polled */ 311 pkt->pkt_cdbp[4] = 1 << SD_GESN_MEDIA_CLASS; 312 } else if (((dtype == 0) || (dtype == 0xE)) && 313 (devp->sd_inq->inq_ansi > 2)) { 314 pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, NULL, 315 CDB_GROUP1, sizeof (struct scsi_arq_status), 316 0, 0, SLEEP_FUNC, NULL); 317 318 (void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp, 319 SCMD_WRITE_G1, 0, 0, 0); 320 } else { 321 pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, NULL, 322 CDB_GROUP0, sizeof (struct scsi_arq_status), 323 0, 0, SLEEP_FUNC, NULL); 324 325 (void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp, 326 SCMD_TEST_UNIT_READY, 0, 0, 0); 327 FILL_SCSI1_LUN(devp, pkt); 328 } 329 330 pkt->pkt_private = (opaque_t)swr; 331 pkt->pkt_time = scsi_watch_io_time; 332 pkt->pkt_comp = scsi_watch_request_intr; 333 if (scsi_ifgetcap(&pkt->pkt_address, "tagged-qing", 1) == 1) { 334 pkt->pkt_flags |= FLAG_STAG; 335 } 336 337 /* 338 * set the allocated resources in swr 339 */ 340 swr->swr_rqbp = bp; 341 swr->swr_rqpkt = rqpkt; 342 swr->swr_mmcbp = mmcbp; 343 swr->swr_pkt = pkt; 344 swr->swr_timeout = swr->swr_interval = drv_usectohz(interval); 345 swr->swr_callback = callback; 346 swr->swr_callback_arg = cb_arg; 347 swr->swr_what = SWR_WATCH; 348 swr->swr_sense_length = (uchar_t)sense_length; 349 swr->swr_ref = 1; 350 cv_init(&swr->swr_terminate_cv, NULL, CV_DRIVER, NULL); 351 352 /* 353 * add to the list and wake up the thread 354 */ 355 mutex_enter(&sw.sw_mutex); 356 swr->swr_next = sw.sw_head; 357 swr->swr_prev = NULL; 358 if (sw.sw_head) { 359 sw.sw_head->swr_prev = swr; 360 } 361 sw.sw_head = swr; 362 363 /* 364 * reset all timeouts, so all requests are in sync again 365 * XXX there is a small window where the watch thread releases 366 * the mutex so that could upset the resyncing 367 */ 368 sswr = swr; 369 while (sswr) { 370 sswr->swr_timeout = swr->swr_interval; 371 sswr = sswr->swr_next; 372 } 373 cv_signal(&sw.sw_cv); 374 mutex_exit(&sw.sw_mutex); 375 return ((opaque_t)swr); 376 } 377 378 379 /* 380 * called by (eg. pwr management) to resume the scsi_watch_thread 381 */ 382 void 383 scsi_watch_resume(opaque_t token) 384 { 385 struct scsi_watch_request *swr = (struct scsi_watch_request *)NULL; 386 /* 387 * Change the state to SW_RUNNING and wake up the scsi_watch_thread 388 */ 389 SW_DEBUG(0, sw_label, SCSI_DEBUG, "scsi_watch_resume:\n"); 390 mutex_enter(&sw.sw_mutex); 391 392 if (!sw.sw_head) 393 goto exit; 394 395 /* search for token */ 396 for (swr = sw.sw_head; swr; swr = swr->swr_next) { 397 if (swr == (struct scsi_watch_request *)token) 398 break; 399 } 400 401 /* if we can't find this value, then we just do nothing */ 402 if (swr == (struct scsi_watch_request *)NULL) 403 goto exit; 404 405 swr->swr_what = SWR_WATCH; 406 407 408 /* see if all swr's are awake, then start the thread again */ 409 for (swr = sw.sw_head; swr; swr = swr->swr_next) { 410 if (swr->swr_what != SWR_WATCH) 411 goto exit; 412 } 413 414 sw.sw_state = SW_RUNNING; 415 cv_signal(&sw.sw_cv); 416 417 exit: 418 mutex_exit(&sw.sw_mutex); 419 } 420 421 422 /* 423 * called by clients (eg. pwr management) to suspend the scsi_watch_thread 424 */ 425 void 426 scsi_watch_suspend(opaque_t token) 427 { 428 struct scsi_watch_request *swr = (struct scsi_watch_request *)NULL; 429 clock_t halfsec_delay = drv_usectohz(500000); 430 431 SW_DEBUG(0, sw_label, SCSI_DEBUG, "scsi_watch_suspend:\n"); 432 433 mutex_enter(&sw.sw_mutex); 434 435 if (!sw.sw_head) 436 goto exit; 437 438 /* search for token */ 439 for (swr = sw.sw_head; swr; swr = swr->swr_next) { 440 if (swr == (struct scsi_watch_request *)token) 441 break; 442 } 443 444 /* if we can't find this value, then we just do nothing */ 445 if (swr == (struct scsi_watch_request *)NULL) 446 goto exit; 447 448 449 for (;;) { 450 if (swr->swr_busy) { 451 /* 452 * XXX: Assumes that this thread can rerun 453 * till all outstanding cmds are complete 454 */ 455 swr->swr_what = SWR_SUSPEND_REQUESTED; 456 (void) cv_reltimedwait(&sw.sw_cv, &sw.sw_mutex, 457 halfsec_delay, TR_CLOCK_TICK); 458 } else { 459 swr->swr_what = SWR_SUSPENDED; 460 break; 461 } 462 } 463 464 /* see if all swr's are suspended, then suspend the thread */ 465 for (swr = sw.sw_head; swr; swr = swr->swr_next) { 466 if (swr->swr_what != SWR_SUSPENDED) 467 goto exit; 468 } 469 470 sw.sw_state = SW_SUSPENDED; 471 472 exit: 473 mutex_exit(&sw.sw_mutex); 474 } 475 476 /* 477 * destroy swr, called for watch thread 478 */ 479 static void 480 scsi_watch_request_destroy(struct scsi_watch_request *swr) 481 { 482 ASSERT(MUTEX_HELD(&sw.sw_mutex)); 483 ASSERT(swr->swr_busy == 0); 484 485 SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG, 486 "scsi_watch_request_destroy: Entering ...\n"); 487 if (swr->swr_ref != 0) 488 return; 489 490 /* 491 * remove swr from linked list and destroy pkts 492 */ 493 if (swr->swr_prev) { 494 swr->swr_prev->swr_next = swr->swr_next; 495 } 496 if (swr->swr_next) { 497 swr->swr_next->swr_prev = swr->swr_prev; 498 } 499 if (sw.sw_head == swr) { 500 sw.sw_head = swr->swr_next; 501 } 502 if (sw.swr_current == swr) { 503 swr->suspend_destroy = SUSPEND_DESTROY; 504 sw.swr_current = NULL; 505 } 506 507 scsi_destroy_pkt(swr->swr_rqpkt); 508 scsi_free_consistent_buf(swr->swr_rqbp); 509 if (swr->swr_mmcbp != NULL) { 510 scsi_free_consistent_buf(swr->swr_mmcbp); 511 } 512 scsi_destroy_pkt(swr->swr_pkt); 513 cv_signal(&swr->swr_terminate_cv); 514 } 515 516 /* 517 * scsi_watch_request_terminate() 518 * called by requestor to terminate any pending watch request. 519 * if the request is currently "busy", and the caller cannot wait, failure 520 * is returned. O/w the request is cleaned up immediately. 521 */ 522 int 523 scsi_watch_request_terminate(opaque_t token, int flags) 524 { 525 struct scsi_watch_request *swr = 526 (struct scsi_watch_request *)token; 527 struct scsi_watch_request *sswr; 528 529 int count = 0; 530 int free_flag = 0; 531 532 /* 533 * We try to clean up this request if we can. We also inform 534 * the watch thread that we mucked around the list so it has 535 * to start reading from head of list again. 536 */ 537 SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG, 538 "scsi_watch_request_terminate: Entering(0x%p) ...\n", 539 (void *)swr); 540 mutex_enter(&sw.sw_mutex); 541 542 /* 543 * check if it is still in the list 544 */ 545 sswr = sw.sw_head; 546 while (sswr) { 547 if (sswr == swr) { 548 swr->swr_ref--; 549 count = swr->swr_ref; 550 551 if (swr->swr_busy) { 552 if (flags == SCSI_WATCH_TERMINATE_NOWAIT) { 553 mutex_exit(&sw.sw_mutex); 554 return (SCSI_WATCH_TERMINATE_FAIL); 555 } 556 if (count != 0 && flags != 557 SCSI_WATCH_TERMINATE_ALL_WAIT) { 558 mutex_exit(&sw.sw_mutex); 559 return (SCSI_WATCH_TERMINATE_SUCCESS); 560 } 561 if (SCSI_WATCH_TERMINATE_ALL_WAIT == flags) { 562 swr->swr_ref = 0; 563 count = 0; 564 } 565 swr->swr_what = SWR_STOP; 566 cv_wait(&swr->swr_terminate_cv, &sw.sw_mutex); 567 free_flag = 1; 568 goto done; 569 } else { 570 if (SCSI_WATCH_TERMINATE_NOWAIT == flags || 571 SCSI_WATCH_TERMINATE_ALL_WAIT == flags) { 572 swr->swr_ref = 0; 573 count = 0; 574 } 575 scsi_watch_request_destroy(swr); 576 if (0 == count) { 577 sw.sw_flags |= SW_START_HEAD; 578 free_flag = 1; 579 } 580 goto done; 581 } 582 } 583 sswr = sswr->swr_next; 584 } 585 done: 586 mutex_exit(&sw.sw_mutex); 587 if (!sswr) { 588 return (SCSI_WATCH_TERMINATE_FAIL); 589 } 590 if (1 == free_flag && 591 sswr->suspend_destroy != SUSPEND_DESTROY) { 592 cv_destroy(&swr->swr_terminate_cv); 593 kmem_free((caddr_t)swr, sizeof (struct scsi_watch_request)); 594 } 595 596 return (SCSI_WATCH_TERMINATE_SUCCESS); 597 } 598 599 600 /* 601 * The routines scsi_watch_thread & scsi_watch_request_intr are 602 * on different threads. 603 * If there is no work to be done by the lower level driver 604 * then swr->swr_busy will not be set. 605 * In this case we will call CALLB_CPR_SAFE_BEGIN before 606 * calling cv_timedwait. 607 * In the other case where there is work to be done by 608 * the lower level driver then the flag swr->swr_busy will 609 * be set. 610 * We cannot call CALLB_CPR_SAFE_BEGIN at this point the reason 611 * is the intr thread can interfere with our operations. So 612 * we do a cv_timedwait here. Now at the completion of the 613 * lower level driver's work we will call CALLB_CPR_SAFE_BEGIN 614 * in scsi_watch_request_intr. 615 * In all the cases we will call CALLB_CPR_SAFE_END only if 616 * we already called a CALLB_CPR_SAFE_BEGIN and this is flagged 617 * by sw_cpr_flag. 618 * Warlock has a problem when we use different locks 619 * on the same type of structure in different contexts. 620 * We use callb_cpr_t in both scsi_watch and esp_callback threads. 621 * we use different mutexe's in different threads. And 622 * this is not acceptable to warlock. To avoid this 623 * problem we use the same name for the mutex in 624 * both scsi_watch & esp_callback. when __lock_lint is not defined 625 * esp_callback uses the mutex on the stack and in scsi_watch 626 * a static variable. But when __lock_lint is defined 627 * we make a mutex which is global in esp_callback and 628 * a external mutex for scsi_watch. 629 */ 630 static int sw_cmd_count = 0; 631 static int sw_cpr_flag = 0; 632 static callb_cpr_t cpr_info; 633 #ifndef __lock_lint 634 static kmutex_t cpr_mutex; 635 #else 636 extern kmutex_t cpr_mutex; 637 #endif 638 639 #if !defined(lint) 640 _NOTE(MUTEX_PROTECTS_DATA(cpr_mutex, cpr_info)) 641 _NOTE(MUTEX_PROTECTS_DATA(cpr_mutex, sw_cmd_count)) 642 #endif 643 /* 644 * the scsi watch thread: 645 * it either wakes up if there is work to do or if the cv_timeait 646 * timed out 647 * normally, it wakes up every <delay> seconds and checks the list. 648 * the interval is not very accurate if the cv was signalled but that 649 * really doesn't matter much 650 * it is more important that we fire off all TURs simulataneously so 651 * we don't have to wake up frequently 652 */ 653 static void 654 scsi_watch_thread() 655 { 656 struct scsi_watch_request *swr, *next; 657 clock_t last_delay = 0; 658 clock_t next_delay = 0; 659 clock_t onesec = drv_sectohz(1); 660 clock_t exit_delay = 60 * onesec; 661 662 SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG, 663 "scsi_watch_thread: Entering ...\n"); 664 665 #if !defined(lint) 666 _NOTE(NO_COMPETING_THREADS_NOW); 667 #endif 668 mutex_init(&cpr_mutex, NULL, MUTEX_DRIVER, NULL); 669 CALLB_CPR_INIT(&cpr_info, 670 &cpr_mutex, callb_generic_cpr, "scsi_watch"); 671 sw_cpr_flag = 0; 672 #if !defined(lint) 673 /*LINTED*/ 674 _NOTE(COMPETING_THREADS_NOW); 675 #endif 676 /* 677 * grab the mutex and wait for work 678 */ 679 mutex_enter(&sw.sw_mutex); 680 if (sw.sw_head == NULL) { 681 cv_wait(&sw.sw_cv, &sw.sw_mutex); 682 } 683 684 /* 685 * now loop forever for work; if queue is empty exit 686 */ 687 for (;;) { 688 head: 689 swr = sw.sw_head; 690 while (swr) { 691 692 /* 693 * If state is not running, wait for scsi_watch_resume 694 * to signal restart, but before going into cv_wait 695 * need to let the PM framework know that it is safe 696 * to stop this thread for CPR 697 */ 698 if (sw.sw_state != SW_RUNNING) { 699 SW_DEBUG(0, sw_label, SCSI_DEBUG, 700 "scsi_watch_thread suspended\n"); 701 mutex_enter(&cpr_mutex); 702 if (!sw_cmd_count) { 703 CALLB_CPR_SAFE_BEGIN(&cpr_info); 704 sw_cpr_flag = 1; 705 } 706 mutex_exit(&cpr_mutex); 707 sw.swr_current = swr; 708 cv_wait(&sw.sw_cv, &sw.sw_mutex); 709 710 711 /* 712 * Need to let the PM framework know that it 713 * is no longer safe to stop the thread for 714 * CPR. 715 */ 716 mutex_exit(&sw.sw_mutex); 717 mutex_enter(&cpr_mutex); 718 if (sw_cpr_flag == 1) { 719 CALLB_CPR_SAFE_END( 720 &cpr_info, &cpr_mutex); 721 sw_cpr_flag = 0; 722 } 723 mutex_exit(&cpr_mutex); 724 mutex_enter(&sw.sw_mutex); 725 if (SUSPEND_DESTROY == swr->suspend_destroy) { 726 cv_destroy(&swr->swr_terminate_cv); 727 kmem_free((caddr_t)swr, 728 sizeof (struct scsi_watch_request)); 729 goto head; 730 } else { 731 sw.swr_current = NULL; 732 } 733 } 734 if (next_delay == 0) { 735 next_delay = swr->swr_timeout; 736 } else { 737 next_delay = min(swr->swr_timeout, next_delay); 738 } 739 740 swr->swr_timeout -= last_delay; 741 next = swr->swr_next; 742 743 SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG, 744 "scsi_watch_thread: " 745 "swr(0x%p),what=%x,timeout=%lx," 746 "interval=%lx,delay=%lx\n", 747 (void *)swr, swr->swr_what, swr->swr_timeout, 748 swr->swr_interval, last_delay); 749 750 switch (swr->swr_what) { 751 case SWR_SUSPENDED: 752 case SWR_SUSPEND_REQUESTED: 753 /* if we are suspended, don't do anything */ 754 break; 755 756 case SWR_STOP: 757 if (swr->swr_busy == 0) { 758 scsi_watch_request_destroy(swr); 759 } 760 break; 761 762 default: 763 if (swr->swr_timeout <= 0 && !swr->swr_busy) { 764 swr->swr_busy = 1; 765 swr->swr_timeout = swr->swr_interval; 766 767 /* 768 * submit the cmd and let the completion 769 * function handle the result 770 * release the mutex (good practice) 771 * this should be safe even if the list 772 * is changing 773 */ 774 mutex_exit(&sw.sw_mutex); 775 mutex_enter(&cpr_mutex); 776 sw_cmd_count++; 777 mutex_exit(&cpr_mutex); 778 SW_DEBUG((dev_info_t *)NULL, 779 sw_label, SCSI_DEBUG, 780 "scsi_watch_thread: " 781 "Starting TUR\n"); 782 if (scsi_transport(swr->swr_pkt) != 783 TRAN_ACCEPT) { 784 785 /* 786 * try again later 787 */ 788 swr->swr_busy = 0; 789 SW_DEBUG((dev_info_t *)NULL, 790 sw_label, SCSI_DEBUG, 791 "scsi_watch_thread: " 792 "Transport Failed\n"); 793 mutex_enter(&cpr_mutex); 794 sw_cmd_count--; 795 mutex_exit(&cpr_mutex); 796 } 797 mutex_enter(&sw.sw_mutex); 798 } 799 break; 800 } 801 swr = next; 802 if (sw.sw_flags & SW_START_HEAD) { 803 sw.sw_flags &= ~SW_START_HEAD; 804 goto head; 805 } 806 } 807 808 /* 809 * delay using cv_timedwait; we return when 810 * signalled or timed out 811 */ 812 if (sw.sw_head != NULL) { 813 if (next_delay <= 0) { 814 next_delay = onesec; 815 } 816 } else { 817 next_delay = exit_delay; 818 } 819 820 mutex_enter(&cpr_mutex); 821 if (!sw_cmd_count) { 822 CALLB_CPR_SAFE_BEGIN(&cpr_info); 823 sw_cpr_flag = 1; 824 } 825 mutex_exit(&cpr_mutex); 826 /* 827 * if we return from cv_timedwait because we were 828 * signalled, the delay is not accurate but that doesn't 829 * really matter 830 */ 831 (void) cv_reltimedwait(&sw.sw_cv, &sw.sw_mutex, next_delay, 832 TR_CLOCK_TICK); 833 mutex_exit(&sw.sw_mutex); 834 mutex_enter(&cpr_mutex); 835 if (sw_cpr_flag == 1) { 836 CALLB_CPR_SAFE_END(&cpr_info, &cpr_mutex); 837 sw_cpr_flag = 0; 838 } 839 mutex_exit(&cpr_mutex); 840 mutex_enter(&sw.sw_mutex); 841 last_delay = next_delay; 842 next_delay = 0; 843 844 /* 845 * is there still work to do? 846 */ 847 if (sw.sw_head == NULL) { 848 break; 849 } 850 } 851 852 /* 853 * no more work to do, reset sw_thread and exit 854 */ 855 sw.sw_thread = 0; 856 mutex_exit(&sw.sw_mutex); 857 #ifndef __lock_lint 858 mutex_enter(&cpr_mutex); 859 CALLB_CPR_EXIT(&cpr_info); 860 #endif 861 mutex_destroy(&cpr_mutex); 862 SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG, 863 "scsi_watch_thread: Exiting ...\n"); 864 } 865 866 /* 867 * callback completion function for scsi watch pkt 868 */ 869 #define SCBP(pkt) ((struct scsi_status *)(pkt)->pkt_scbp) 870 #define SCBP_C(pkt) ((*(pkt)->pkt_scbp) & STATUS_MASK) 871 872 static void 873 scsi_watch_request_intr(struct scsi_pkt *pkt) 874 { 875 struct scsi_watch_result result; 876 struct scsi_watch_request *swr = 877 (struct scsi_watch_request *)pkt->pkt_private; 878 struct scsi_status *rqstatusp; 879 struct scsi_extended_sense *rqsensep = NULL; 880 int amt = 0; 881 882 SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG, 883 "scsi_watch_intr: Entering ...\n"); 884 885 /* 886 * first check if it is the TUR or RQS pkt 887 */ 888 if (pkt == swr->swr_pkt) { 889 if (SCBP_C(pkt) != STATUS_GOOD && 890 SCBP_C(pkt) != STATUS_RESERVATION_CONFLICT) { 891 if (SCBP(pkt)->sts_chk && 892 ((pkt->pkt_state & STATE_ARQ_DONE) == 0)) { 893 894 /* 895 * submit the request sense pkt 896 */ 897 SW_DEBUG((dev_info_t *)NULL, 898 sw_label, SCSI_DEBUG, 899 "scsi_watch_intr: " 900 "Submitting a Request Sense " 901 "Packet\n"); 902 if (scsi_transport(swr->swr_rqpkt) != 903 TRAN_ACCEPT) { 904 905 /* 906 * just give up and try again later 907 */ 908 SW_DEBUG((dev_info_t *)NULL, 909 sw_label, SCSI_DEBUG, 910 "scsi_watch_intr: " 911 "Request Sense " 912 "Transport Failed\n"); 913 goto done; 914 } 915 916 /* 917 * wait for rqsense to complete 918 */ 919 return; 920 921 } else if (SCBP(pkt)->sts_chk) { 922 923 /* 924 * check the autorequest sense data 925 */ 926 struct scsi_arq_status *arqstat = 927 (struct scsi_arq_status *)pkt->pkt_scbp; 928 929 rqstatusp = &arqstat->sts_rqpkt_status; 930 rqsensep = &arqstat->sts_sensedata; 931 amt = swr->swr_sense_length - 932 arqstat->sts_rqpkt_resid; 933 SW_DEBUG((dev_info_t *)NULL, 934 sw_label, SCSI_DEBUG, 935 "scsi_watch_intr: " 936 "Auto Request Sense, amt=%x\n", amt); 937 } 938 } 939 940 } else if (pkt == swr->swr_rqpkt) { 941 942 /* 943 * check the request sense data 944 */ 945 rqstatusp = (struct scsi_status *)pkt->pkt_scbp; 946 rqsensep = (struct scsi_extended_sense *) 947 swr->swr_rqbp->b_un.b_addr; 948 amt = swr->swr_sense_length - pkt->pkt_resid; 949 SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG, 950 "scsi_watch_intr: " 951 "Request Sense Completed, amt=%x\n", amt); 952 } else { 953 954 /* 955 * should not reach here!!! 956 */ 957 scsi_log((dev_info_t *)NULL, sw_label, CE_PANIC, 958 "scsi_watch_intr: Bad Packet(0x%p)", (void *)pkt); 959 } 960 961 if (rqsensep) { 962 963 /* 964 * check rqsense status and data 965 */ 966 if (rqstatusp->sts_busy || rqstatusp->sts_chk) { 967 968 /* 969 * try again later 970 */ 971 SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG, 972 "scsi_watch_intr: " 973 "Auto Request Sense Failed - " 974 "Busy or Check Condition\n"); 975 goto done; 976 } 977 978 SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG, 979 "scsi_watch_intr: " 980 "es_key=%x, adq=%x, amt=%x\n", 981 rqsensep->es_key, rqsensep->es_add_code, amt); 982 } 983 984 /* 985 * callback to target driver to do the real work 986 */ 987 result.statusp = SCBP(swr->swr_pkt); 988 result.sensep = rqsensep; 989 result.actual_sense_length = (uchar_t)amt; 990 result.pkt = swr->swr_pkt; 991 if (swr->swr_mmcbp != NULL) { 992 bcopy(swr->swr_mmcbp->b_un.b_addr, result.mmc_data, 8); 993 } 994 995 if ((*swr->swr_callback)(swr->swr_callback_arg, &result)) { 996 swr->swr_what = SWR_STOP; 997 } 998 999 done: 1000 swr->swr_busy = 0; 1001 mutex_enter(&cpr_mutex); 1002 sw_cmd_count --; 1003 if (!sw_cmd_count) { 1004 CALLB_CPR_SAFE_BEGIN(&cpr_info); 1005 sw_cpr_flag = 1; 1006 } 1007 mutex_exit(&cpr_mutex); 1008 } 1009 1010 /* 1011 * scsi_watch_get_ref_count 1012 * called by clients to query the reference count for a given token. 1013 * return the number of reference count or 0 if the given token is 1014 * not found. 1015 */ 1016 int 1017 scsi_watch_get_ref_count(opaque_t token) 1018 { 1019 struct scsi_watch_request *swr = 1020 (struct scsi_watch_request *)token; 1021 struct scsi_watch_request *sswr; 1022 int rval = 0; 1023 1024 SW_DEBUG((dev_info_t *)NULL, sw_label, SCSI_DEBUG, 1025 "scsi_watch_get_ref_count: Entering(0x%p) ...\n", 1026 (void *)swr); 1027 mutex_enter(&sw.sw_mutex); 1028 1029 sswr = sw.sw_head; 1030 while (sswr) { 1031 if (sswr == swr) { 1032 rval = swr->swr_ref; 1033 mutex_exit(&sw.sw_mutex); 1034 return (rval); 1035 } 1036 sswr = sswr->swr_next; 1037 } 1038 1039 mutex_exit(&sw.sw_mutex); 1040 return (rval); 1041 }