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 2010 Emulex. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 28 #include <emlxs.h> 29 30 31 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */ 32 EMLXS_MSG_DEF(EMLXS_THREAD_C); 33 34 static void emlxs_thread(emlxs_thread_t *ethread); 35 static void emlxs_taskq_thread(emlxs_taskq_thread_t *tthread); 36 37 38 static void 39 emlxs_taskq_thread(emlxs_taskq_thread_t *tthread) 40 { 41 emlxs_taskq_t *taskq; 42 void (*func) (); 43 void *arg; 44 45 taskq = tthread->taskq; 46 47 mutex_enter(&tthread->lock); 48 tthread->flags |= EMLXS_THREAD_STARTED; 49 50 while (!(tthread->flags & EMLXS_THREAD_KILLED)) { 51 mutex_enter(&taskq->put_lock); 52 tthread->next = taskq->put_head; 53 taskq->put_head = tthread; 54 taskq->put_count++; 55 mutex_exit(&taskq->put_lock); 56 57 tthread->flags |= EMLXS_THREAD_ASLEEP; 58 cv_wait(&tthread->cv_flag, &tthread->lock); 59 tthread->flags &= ~EMLXS_THREAD_ASLEEP; 60 61 if (tthread->func) { 62 func = tthread->func; 63 arg = tthread->arg; 64 65 tthread->flags |= EMLXS_THREAD_BUSY; 66 mutex_exit(&tthread->lock); 67 68 func(taskq->hba, arg); 69 70 mutex_enter(&tthread->lock); 71 tthread->flags &= ~EMLXS_THREAD_BUSY; 72 } 73 } 74 75 tthread->flags |= EMLXS_THREAD_ENDED; 76 mutex_exit(&tthread->lock); 77 78 thread_exit(); 79 80 return; 81 82 } /* emlxs_taskq_thread() */ 83 84 85 86 uint32_t 87 emlxs_taskq_dispatch(emlxs_taskq_t *taskq, void (*func) (), void *arg) 88 { 89 emlxs_taskq_thread_t *tthread = NULL; 90 91 mutex_enter(&taskq->get_lock); 92 93 /* Make sure taskq is open for business */ 94 if (!taskq->open) { 95 mutex_exit(&taskq->get_lock); 96 return (0); 97 } 98 99 /* Check get_list for a thread */ 100 if (taskq->get_head) { 101 /* Get the next thread */ 102 tthread = taskq->get_head; 103 taskq->get_count--; 104 taskq->get_head = (taskq->get_count) ? tthread->next : NULL; 105 tthread->next = NULL; 106 } 107 108 /* Else check put_list for a thread */ 109 else if (taskq->put_head) { 110 111 /* Move put_list to get_list */ 112 mutex_enter(&taskq->put_lock); 113 taskq->get_head = taskq->put_head; 114 taskq->get_count = taskq->put_count; 115 taskq->put_head = NULL; 116 taskq->put_count = 0; 117 mutex_exit(&taskq->put_lock); 118 119 /* Get the next thread */ 120 tthread = taskq->get_head; 121 taskq->get_count--; 122 taskq->get_head = (taskq->get_count) ? tthread->next : NULL; 123 tthread->next = NULL; 124 } 125 126 mutex_exit(&taskq->get_lock); 127 128 /* Wake up the thread if one exists */ 129 if (tthread) { 130 mutex_enter(&tthread->lock); 131 tthread->func = func; 132 tthread->arg = arg; 133 cv_signal(&tthread->cv_flag); 134 mutex_exit(&tthread->lock); 135 136 return (1); 137 } 138 139 return (0); 140 141 } /* emlxs_taskq_dispatch() */ 142 143 144 145 void 146 emlxs_taskq_create(emlxs_hba_t *hba, emlxs_taskq_t *taskq) 147 { 148 emlxs_taskq_thread_t *tthread; 149 char buf[64]; 150 uint32_t i; 151 152 153 /* If taskq is already open then quit */ 154 if (taskq->open) { 155 return; 156 } 157 158 /* Zero the taskq */ 159 bzero(taskq, sizeof (emlxs_taskq_t)); 160 161 (void) sprintf(buf, "%s%d_thread_taskq_get mutex", DRIVER_NAME, 162 hba->ddiinst); 163 mutex_init(&taskq->get_lock, buf, MUTEX_DRIVER, 164 DDI_INTR_PRI(hba->intr_arg)); 165 166 mutex_enter(&taskq->get_lock); 167 168 taskq->hba = hba; 169 170 (void) sprintf(buf, "%s%d_thread_taskq_put mutex", DRIVER_NAME, 171 hba->ddiinst); 172 mutex_init(&taskq->put_lock, buf, MUTEX_DRIVER, 173 DDI_INTR_PRI(hba->intr_arg)); 174 175 for (i = 0; i < EMLXS_MAX_TASKQ_THREADS; i++) { 176 tthread = &taskq->thread_list[i]; 177 tthread->taskq = taskq; 178 179 (void) sprintf(buf, "%s%d_thread%d mutex", DRIVER_NAME, 180 hba->ddiinst, i); 181 mutex_init(&tthread->lock, buf, MUTEX_DRIVER, 182 DDI_INTR_PRI(hba->intr_arg)); 183 184 (void) sprintf(buf, "%s%d_thread%d cv", DRIVER_NAME, 185 hba->ddiinst, i); 186 cv_init(&tthread->cv_flag, buf, CV_DRIVER, NULL); 187 188 tthread->flags |= EMLXS_THREAD_INITD; 189 tthread->thread = 190 thread_create(NULL, 0, emlxs_taskq_thread, 191 (char *)tthread, 0, &p0, TS_RUN, v.v_maxsyspri - 2); 192 } 193 194 /* Open the taskq */ 195 taskq->open = 1; 196 197 mutex_exit(&taskq->get_lock); 198 199 return; 200 201 } /* emlxs_taskq_create() */ 202 203 204 void 205 emlxs_taskq_destroy(emlxs_taskq_t *taskq) 206 { 207 emlxs_taskq_thread_t *tthread; 208 uint32_t i; 209 210 /* If taskq already closed, then quit */ 211 if (!taskq->open) { 212 return; 213 } 214 215 mutex_enter(&taskq->get_lock); 216 217 /* If taskq already closed, then quit */ 218 if (!taskq->open) { 219 mutex_exit(&taskq->get_lock); 220 return; 221 } 222 223 taskq->open = 0; 224 mutex_exit(&taskq->get_lock); 225 226 227 /* No more threads can be dispatched now */ 228 229 /* Kill the threads */ 230 for (i = 0; i < EMLXS_MAX_TASKQ_THREADS; i++) { 231 tthread = &taskq->thread_list[i]; 232 233 /* 234 * If the thread lock can be acquired, 235 * it is in one of these states: 236 * 1. Thread not started. 237 * 2. Thread asleep. 238 * 3. Thread busy. 239 * 4. Thread ended. 240 */ 241 mutex_enter(&tthread->lock); 242 tthread->flags |= EMLXS_THREAD_KILLED; 243 cv_signal(&tthread->cv_flag); 244 245 /* Wait for thread to die */ 246 while (!(tthread->flags & EMLXS_THREAD_ENDED)) { 247 mutex_exit(&tthread->lock); 248 delay(drv_usectohz(10000)); 249 mutex_enter(&tthread->lock); 250 } 251 mutex_exit(&tthread->lock); 252 253 /* Clean up thread */ 254 mutex_destroy(&tthread->lock); 255 cv_destroy(&tthread->cv_flag); 256 } 257 258 /* Clean up taskq */ 259 mutex_destroy(&taskq->put_lock); 260 mutex_destroy(&taskq->get_lock); 261 262 return; 263 264 } /* emlxs_taskq_destroy() */ 265 266 267 268 static void 269 emlxs_thread(emlxs_thread_t *ethread) 270 { 271 emlxs_hba_t *hba; 272 void (*func) (); 273 void *arg1; 274 void *arg2; 275 276 if (ethread->flags & EMLXS_THREAD_RUN_ONCE) { 277 hba = ethread->hba; 278 ethread->flags |= EMLXS_THREAD_STARTED; 279 280 if (!(ethread->flags & EMLXS_THREAD_KILLED)) { 281 func = ethread->func; 282 arg1 = ethread->arg1; 283 arg2 = ethread->arg2; 284 285 func(hba, arg1, arg2); 286 } 287 288 ethread->flags |= EMLXS_THREAD_ENDED; 289 ethread->flags &= ~EMLXS_THREAD_INITD; 290 291 /* Remove the thread from the spawn thread list */ 292 mutex_enter(&EMLXS_SPAWN_LOCK); 293 if (hba->spawn_thread_head == ethread) 294 hba->spawn_thread_head = ethread->next; 295 if (hba->spawn_thread_tail == ethread) 296 hba->spawn_thread_tail = ethread->prev; 297 298 if (ethread->prev) 299 ethread->prev->next = ethread->next; 300 if (ethread->next) 301 ethread->next->prev = ethread->prev; 302 303 ethread->next = ethread->prev = NULL; 304 305 kmem_free(ethread, sizeof (emlxs_thread_t)); 306 307 mutex_exit(&EMLXS_SPAWN_LOCK); 308 } 309 else 310 { 311 /* 312 * If the thread lock can be acquired, 313 * it is in one of these states: 314 * 1. Thread not started. 315 * 2. Thread asleep. 316 * 3. Thread busy. 317 * 4. Thread ended. 318 */ 319 mutex_enter(ðread->lock); 320 ethread->flags |= EMLXS_THREAD_STARTED; 321 322 while (!(ethread->flags & EMLXS_THREAD_KILLED)) { 323 if (!(ethread->flags & EMLXS_THREAD_TRIGGERED)) { 324 ethread->flags |= EMLXS_THREAD_ASLEEP; 325 cv_wait(ðread->cv_flag, ðread->lock); 326 } 327 328 ethread->flags &= 329 ~(EMLXS_THREAD_ASLEEP | EMLXS_THREAD_TRIGGERED); 330 331 if (ethread->func) { 332 func = ethread->func; 333 arg1 = ethread->arg1; 334 arg2 = ethread->arg2; 335 ethread->func = NULL; 336 ethread->arg1 = NULL; 337 ethread->arg2 = NULL; 338 339 ethread->flags |= EMLXS_THREAD_BUSY; 340 mutex_exit(ðread->lock); 341 342 func(ethread->hba, arg1, arg2); 343 344 mutex_enter(ðread->lock); 345 ethread->flags &= ~EMLXS_THREAD_BUSY; 346 } 347 } 348 349 ethread->flags |= EMLXS_THREAD_ENDED; 350 mutex_exit(ðread->lock); 351 } 352 353 thread_exit(); 354 355 } /* emlxs_thread() */ 356 357 358 void 359 emlxs_thread_create(emlxs_hba_t *hba, emlxs_thread_t *ethread) 360 { 361 char buf[64]; 362 uint16_t pri; 363 364 if (ethread->flags & EMLXS_THREAD_INITD) { 365 return; 366 } 367 368 bzero(ethread, sizeof (emlxs_thread_t)); 369 370 (void) sprintf(buf, "%s%d_thread_%08x mutex", DRIVER_NAME, hba->ddiinst, 371 (uint32_t)((uintptr_t)ethread & 0xFFFFFFFF)); 372 mutex_init(ðread->lock, buf, MUTEX_DRIVER, 373 DDI_INTR_PRI(hba->intr_arg)); 374 375 (void) sprintf(buf, "%s%d_thread_%08x cv", DRIVER_NAME, hba->ddiinst, 376 (uint32_t)((uintptr_t)ethread & 0xFFFFFFFF)); 377 cv_init(ðread->cv_flag, buf, CV_DRIVER, NULL); 378 379 ethread->hba = hba; 380 ethread->flags |= EMLXS_THREAD_INITD; 381 382 pri = v.v_maxsyspri - 2; 383 384 ethread->thread = 385 thread_create(NULL, 0, emlxs_thread, (char *)ethread, 0, &p0, 386 TS_RUN, pri); 387 388 } /* emlxs_thread_create() */ 389 390 391 void 392 emlxs_thread_destroy(emlxs_thread_t *ethread) 393 { 394 /* 395 * If the thread lock can be acquired, 396 * it is in one of these states: 397 * 1. Thread not started. 398 * 2. Thread asleep. 399 * 3. Thread busy. 400 * 4. Thread ended. 401 */ 402 if (!(ethread->flags & EMLXS_THREAD_INITD)) { 403 return; 404 } 405 406 407 mutex_enter(ðread->lock); 408 409 if (ethread->flags & EMLXS_THREAD_ENDED) { 410 mutex_exit(ðread->lock); 411 return; 412 } 413 414 ethread->flags &= ~EMLXS_THREAD_INITD; 415 ethread->flags |= (EMLXS_THREAD_KILLED | EMLXS_THREAD_TRIGGERED); 416 ethread->func = NULL; 417 ethread->arg1 = NULL; 418 ethread->arg2 = NULL; 419 cv_signal(ðread->cv_flag); 420 421 /* Wait for thread to end */ 422 while (!(ethread->flags & EMLXS_THREAD_ENDED)) { 423 mutex_exit(ðread->lock); 424 delay(drv_usectohz(10000)); 425 mutex_enter(ðread->lock); 426 } 427 428 mutex_exit(ðread->lock); 429 430 cv_destroy(ðread->cv_flag); 431 mutex_destroy(ðread->lock); 432 433 return; 434 435 } /* emlxs_thread_destroy() */ 436 437 438 void 439 emlxs_thread_trigger1(emlxs_thread_t *ethread, void (*func) ()) 440 { 441 442 /* 443 * If the thread lock can be acquired, 444 * it is in one of these states: 445 * 1. Thread not started. 446 * 2. Thread asleep. 447 * 3. Thread busy. 448 * 4. Thread ended. 449 */ 450 if (!(ethread->flags & EMLXS_THREAD_INITD)) { 451 return; 452 } 453 454 mutex_enter(ðread->lock); 455 456 if (ethread->flags & EMLXS_THREAD_ENDED) { 457 return; 458 } 459 460 while (!(ethread->flags & EMLXS_THREAD_STARTED)) { 461 mutex_exit(ðread->lock); 462 delay(drv_usectohz(10000)); 463 mutex_enter(ðread->lock); 464 465 if (ethread->flags & EMLXS_THREAD_ENDED) { 466 return; 467 } 468 } 469 470 ethread->flags |= EMLXS_THREAD_TRIGGERED; 471 ethread->func = func; 472 ethread->arg1 = NULL; 473 ethread->arg2 = NULL; 474 475 if (ethread->flags & EMLXS_THREAD_ASLEEP) { 476 cv_signal(ðread->cv_flag); 477 } 478 479 mutex_exit(ðread->lock); 480 481 return; 482 483 } /* emlxs_thread_trigger1() */ 484 485 486 void 487 emlxs_thread_trigger2(emlxs_thread_t *ethread, void (*func) (), CHANNEL *cp) 488 { 489 490 /* 491 * If the thread lock can be acquired, 492 * it is in one of these states: 493 * 1. Thread not started. 494 * 2. Thread asleep. 495 * 3. Thread busy. 496 * 4. Thread ended. 497 */ 498 if (!(ethread->flags & EMLXS_THREAD_INITD)) { 499 return; 500 } 501 502 mutex_enter(ðread->lock); 503 504 if (ethread->flags & EMLXS_THREAD_ENDED) { 505 return; 506 } 507 508 while (!(ethread->flags & EMLXS_THREAD_STARTED)) { 509 mutex_exit(ðread->lock); 510 delay(drv_usectohz(10000)); 511 mutex_enter(ðread->lock); 512 513 if (ethread->flags & EMLXS_THREAD_ENDED) { 514 return; 515 } 516 } 517 518 ethread->flags |= EMLXS_THREAD_TRIGGERED; 519 ethread->func = func; 520 ethread->arg1 = (void *)cp; 521 ethread->arg2 = NULL; 522 523 if (ethread->flags & EMLXS_THREAD_ASLEEP) { 524 cv_signal(ðread->cv_flag); 525 } 526 527 mutex_exit(ðread->lock); 528 529 return; 530 531 } /* emlxs_thread_trigger2() */ 532 533 534 void 535 emlxs_thread_spawn(emlxs_hba_t *hba, void (*func) (), void *arg1, void *arg2) 536 { 537 emlxs_port_t *port = &PPORT; 538 emlxs_thread_t *ethread; 539 540 /* Create a thread */ 541 ethread = (emlxs_thread_t *)kmem_alloc(sizeof (emlxs_thread_t), 542 KM_NOSLEEP); 543 544 if (ethread == NULL) { 545 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg, 546 "Unable to allocate thread object."); 547 548 return; 549 } 550 551 bzero(ethread, sizeof (emlxs_thread_t)); 552 ethread->hba = hba; 553 ethread->flags = EMLXS_THREAD_INITD | EMLXS_THREAD_RUN_ONCE; 554 ethread->func = func; 555 ethread->arg1 = arg1; 556 ethread->arg2 = arg2; 557 558 /* Queue the thread on the spawn thread list */ 559 mutex_enter(&EMLXS_SPAWN_LOCK); 560 561 /* Dont spawn the thread if the spawn list is closed */ 562 if (hba->spawn_open == 0) { 563 mutex_exit(&EMLXS_SPAWN_LOCK); 564 565 /* destroy the thread */ 566 kmem_free(ethread, sizeof (emlxs_thread_t)); 567 return; 568 } 569 570 if (hba->spawn_thread_head == NULL) { 571 hba->spawn_thread_head = ethread; 572 } 573 else 574 { 575 hba->spawn_thread_tail->next = ethread; 576 ethread->prev = hba->spawn_thread_tail; 577 } 578 579 hba->spawn_thread_tail = ethread; 580 mutex_exit(&EMLXS_SPAWN_LOCK); 581 582 (void) thread_create(NULL, 0, &emlxs_thread, (char *)ethread, 0, &p0, 583 TS_RUN, v.v_maxsyspri - 2); 584 585 } /* emlxs_thread_spawn() */ 586 587 588 void 589 emlxs_thread_spawn_create(emlxs_hba_t *hba) 590 { 591 mutex_enter(&EMLXS_SPAWN_LOCK); 592 if (hba->spawn_open) { 593 mutex_exit(&EMLXS_SPAWN_LOCK); 594 return; 595 } 596 597 hba->spawn_thread_head = NULL; 598 hba->spawn_thread_tail = NULL; 599 600 hba->spawn_open = 1; 601 mutex_exit(&EMLXS_SPAWN_LOCK); 602 603 } 604 605 606 void 607 emlxs_thread_spawn_destroy(emlxs_hba_t *hba) 608 { 609 emlxs_thread_t *ethread; 610 611 mutex_enter(&EMLXS_SPAWN_LOCK); 612 if (hba->spawn_open == 0) { 613 mutex_exit(&EMLXS_SPAWN_LOCK); 614 return; 615 } 616 617 hba->spawn_open = 0; 618 619 for (ethread = hba->spawn_thread_head; ethread; 620 ethread = ethread->next) { 621 ethread->flags |= EMLXS_THREAD_KILLED; 622 } 623 624 /* Wait for all the spawned threads to complete */ 625 while (hba->spawn_thread_head) { 626 mutex_exit(&EMLXS_SPAWN_LOCK); 627 delay(drv_usectohz(10000)); 628 mutex_enter(&EMLXS_SPAWN_LOCK); 629 } 630 631 mutex_exit(&EMLXS_SPAWN_LOCK); 632 } 633