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 2009 Emulex. All rights reserved. 24 * Use is subject to License terms. 25 */ 26 27 #include <emlxs.h> 28 29 30 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */ 31 EMLXS_MSG_DEF(EMLXS_THREAD_C); 32 33 static void emlxs_thread(emlxs_thread_t *ethread); 34 static void emlxs_taskq_thread(emlxs_taskq_thread_t *tthread); 35 36 37 static void 38 emlxs_taskq_thread(emlxs_taskq_thread_t *tthread) 39 { 40 emlxs_taskq_t *taskq; 41 void (*func) (); 42 void *arg; 43 44 taskq = tthread->taskq; 45 46 mutex_enter(&tthread->lock); 47 tthread->flags |= EMLXS_THREAD_STARTED; 48 49 while (!(tthread->flags & EMLXS_THREAD_KILLED)) { 50 mutex_enter(&taskq->put_lock); 51 tthread->next = taskq->put_head; 52 taskq->put_head = tthread; 53 taskq->put_count++; 54 mutex_exit(&taskq->put_lock); 55 56 tthread->flags |= EMLXS_THREAD_ASLEEP; 57 cv_wait(&tthread->cv_flag, &tthread->lock); 58 tthread->flags &= ~EMLXS_THREAD_ASLEEP; 59 60 if (tthread->func) { 61 func = tthread->func; 62 arg = tthread->arg; 63 64 tthread->flags |= EMLXS_THREAD_BUSY; 65 mutex_exit(&tthread->lock); 66 67 func(taskq->hba, arg); 68 69 mutex_enter(&tthread->lock); 70 tthread->flags &= ~EMLXS_THREAD_BUSY; 71 } 72 } 73 74 tthread->flags |= EMLXS_THREAD_ENDED; 75 mutex_exit(&tthread->lock); 76 77 thread_exit(); 78 79 return; 80 81 } /* emlxs_taskq_thread() */ 82 83 84 85 uint32_t 86 emlxs_taskq_dispatch(emlxs_taskq_t *taskq, void (*func) (), void *arg) 87 { 88 emlxs_taskq_thread_t *tthread = NULL; 89 90 mutex_enter(&taskq->get_lock); 91 92 /* Make sure taskq is open for business */ 93 if (!taskq->open) { 94 mutex_exit(&taskq->get_lock); 95 return (0); 96 } 97 98 /* Check get_list for a thread */ 99 if (taskq->get_head) { 100 /* Get the next thread */ 101 tthread = taskq->get_head; 102 taskq->get_count--; 103 taskq->get_head = (taskq->get_count) ? tthread->next : NULL; 104 tthread->next = NULL; 105 } 106 107 /* Else check put_list for a thread */ 108 else if (taskq->put_head) { 109 110 /* Move put_list to get_list */ 111 mutex_enter(&taskq->put_lock); 112 taskq->get_head = taskq->put_head; 113 taskq->get_count = taskq->put_count; 114 taskq->put_head = NULL; 115 taskq->put_count = 0; 116 mutex_exit(&taskq->put_lock); 117 118 /* Get the next thread */ 119 tthread = taskq->get_head; 120 taskq->get_count--; 121 taskq->get_head = (taskq->get_count) ? tthread->next : NULL; 122 tthread->next = NULL; 123 } 124 125 mutex_exit(&taskq->get_lock); 126 127 /* Wake up the thread if one exists */ 128 if (tthread) { 129 mutex_enter(&tthread->lock); 130 tthread->func = func; 131 tthread->arg = arg; 132 cv_signal(&tthread->cv_flag); 133 mutex_exit(&tthread->lock); 134 135 return (1); 136 } 137 138 return (0); 139 140 } /* emlxs_taskq_dispatch() */ 141 142 143 144 void 145 emlxs_taskq_create(emlxs_hba_t *hba, emlxs_taskq_t *taskq) 146 { 147 emlxs_taskq_thread_t *tthread; 148 char buf[64]; 149 uint32_t i; 150 151 152 /* If taskq is already open then quit */ 153 if (taskq->open) { 154 return; 155 } 156 157 /* Zero the taskq */ 158 bzero(taskq, sizeof (emlxs_taskq_t)); 159 160 (void) sprintf(buf, "%s%d_thread_taskq_get mutex", DRIVER_NAME, 161 hba->ddiinst); 162 mutex_init(&taskq->get_lock, buf, MUTEX_DRIVER, 163 (void *)hba->intr_arg); 164 165 mutex_enter(&taskq->get_lock); 166 167 taskq->hba = hba; 168 169 (void) sprintf(buf, "%s%d_thread_taskq_put mutex", DRIVER_NAME, 170 hba->ddiinst); 171 mutex_init(&taskq->put_lock, buf, MUTEX_DRIVER, 172 (void *)hba->intr_arg); 173 174 for (i = 0; i < EMLXS_MAX_TASKQ_THREADS; i++) { 175 tthread = &taskq->thread_list[i]; 176 tthread->taskq = taskq; 177 178 (void) sprintf(buf, "%s%d_thread%d mutex", DRIVER_NAME, 179 hba->ddiinst, i); 180 mutex_init(&tthread->lock, buf, MUTEX_DRIVER, 181 (void *)hba->intr_arg); 182 183 (void) sprintf(buf, "%s%d_thread%d cv", DRIVER_NAME, 184 hba->ddiinst, i); 185 cv_init(&tthread->cv_flag, buf, CV_DRIVER, NULL); 186 187 tthread->flags |= EMLXS_THREAD_INITD; 188 tthread->thread = 189 thread_create(NULL, 0, emlxs_taskq_thread, 190 (char *)tthread, 0, &p0, TS_RUN, v.v_maxsyspri - 2); 191 } 192 193 /* Open the taskq */ 194 taskq->open = 1; 195 196 mutex_exit(&taskq->get_lock); 197 198 return; 199 200 } /* emlxs_taskq_create() */ 201 202 203 void 204 emlxs_taskq_destroy(emlxs_taskq_t *taskq) 205 { 206 emlxs_taskq_thread_t *tthread; 207 uint32_t i; 208 209 /* If taskq already closed, then quit */ 210 if (!taskq->open) { 211 return; 212 } 213 214 mutex_enter(&taskq->get_lock); 215 216 /* If taskq already closed, then quit */ 217 if (!taskq->open) { 218 mutex_exit(&taskq->get_lock); 219 return; 220 } 221 222 taskq->open = 0; 223 mutex_exit(&taskq->get_lock); 224 225 226 /* No more threads can be dispatched now */ 227 228 /* Kill the threads */ 229 for (i = 0; i < EMLXS_MAX_TASKQ_THREADS; i++) { 230 tthread = &taskq->thread_list[i]; 231 232 /* 233 * If the thread lock can be acquired, 234 * it is in one of these states: 235 * 1. Thread not started. 236 * 2. Thread asleep. 237 * 3. Thread busy. 238 * 4. Thread ended. 239 */ 240 mutex_enter(&tthread->lock); 241 tthread->flags |= EMLXS_THREAD_KILLED; 242 cv_signal(&tthread->cv_flag); 243 244 /* Wait for thread to die */ 245 while (!(tthread->flags & EMLXS_THREAD_ENDED)) { 246 mutex_exit(&tthread->lock); 247 delay(drv_usectohz(10000)); 248 mutex_enter(&tthread->lock); 249 } 250 mutex_exit(&tthread->lock); 251 252 /* Clean up thread */ 253 mutex_destroy(&tthread->lock); 254 cv_destroy(&tthread->cv_flag); 255 } 256 257 /* Clean up taskq */ 258 mutex_destroy(&taskq->put_lock); 259 mutex_destroy(&taskq->get_lock); 260 261 return; 262 263 } /* emlxs_taskq_destroy() */ 264 265 266 267 static void 268 emlxs_thread(emlxs_thread_t *ethread) 269 { 270 void (*func) (); 271 void *arg1; 272 void *arg2; 273 274 /* 275 * If the thread lock can be acquired, 276 * it is in one of these states: 277 * 1. Thread not started. 278 * 2. Thread asleep. 279 * 3. Thread busy. 280 * 4. Thread ended. 281 */ 282 mutex_enter(ðread->lock); 283 ethread->flags |= EMLXS_THREAD_STARTED; 284 285 while (!(ethread->flags & EMLXS_THREAD_KILLED)) { 286 if (!(ethread->flags & EMLXS_THREAD_TRIGGERED)) { 287 ethread->flags |= EMLXS_THREAD_ASLEEP; 288 cv_wait(ðread->cv_flag, ðread->lock); 289 } 290 291 ethread->flags &= 292 ~(EMLXS_THREAD_ASLEEP | EMLXS_THREAD_TRIGGERED); 293 294 if (ethread->func) { 295 func = ethread->func; 296 arg1 = ethread->arg1; 297 arg2 = ethread->arg2; 298 ethread->func = NULL; 299 ethread->arg1 = NULL; 300 ethread->arg2 = NULL; 301 302 ethread->flags |= EMLXS_THREAD_BUSY; 303 mutex_exit(ðread->lock); 304 305 func(ethread->hba, arg1, arg2); 306 307 mutex_enter(ðread->lock); 308 ethread->flags &= ~EMLXS_THREAD_BUSY; 309 } 310 } 311 312 ethread->flags |= EMLXS_THREAD_ENDED; 313 mutex_exit(ðread->lock); 314 315 thread_exit(); 316 317 return; 318 319 } /* emlxs_thread() */ 320 321 322 void 323 emlxs_thread_create(emlxs_hba_t *hba, emlxs_thread_t *ethread) 324 { 325 char buf[64]; 326 327 if (ethread->flags & EMLXS_THREAD_INITD) { 328 return; 329 } 330 331 bzero(ethread, sizeof (emlxs_thread_t)); 332 333 (void) sprintf(buf, "%s%d_thread_%08x mutex", DRIVER_NAME, hba->ddiinst, 334 (uint32_t)((uintptr_t)ethread & 0xFFFFFFFF)); 335 mutex_init(ðread->lock, buf, MUTEX_DRIVER, (void *)hba->intr_arg); 336 337 /* mutex_enter(ðread->lock); */ 338 339 (void) sprintf(buf, "%s%d_thread_%08x cv", DRIVER_NAME, hba->ddiinst, 340 (uint32_t)((uintptr_t)ethread & 0xFFFFFFFF)); 341 cv_init(ðread->cv_flag, buf, CV_DRIVER, NULL); 342 343 ethread->hba = hba; 344 ethread->flags |= EMLXS_THREAD_INITD; 345 346 /* mutex_exit(ðread->lock); */ 347 348 ethread->thread = 349 thread_create(NULL, 0, emlxs_thread, (char *)ethread, 0, &p0, 350 TS_RUN, v.v_maxsyspri - 2); 351 352 return; 353 354 } /* emlxs_thread_create() */ 355 356 357 void 358 emlxs_thread_destroy(emlxs_thread_t *ethread) 359 { 360 /* 361 * If the thread lock can be acquired, 362 * it is in one of these states: 363 * 1. Thread not started. 364 * 2. Thread asleep. 365 * 3. Thread busy. 366 * 4. Thread ended. 367 */ 368 if (!(ethread->flags & EMLXS_THREAD_INITD)) { 369 return; 370 } 371 372 mutex_enter(ðread->lock); 373 374 if (ethread->flags & EMLXS_THREAD_ENDED) { 375 return; 376 } 377 378 ethread->flags &= ~EMLXS_THREAD_INITD; 379 ethread->flags |= (EMLXS_THREAD_KILLED | EMLXS_THREAD_TRIGGERED); 380 ethread->func = NULL; 381 ethread->arg1 = NULL; 382 ethread->arg2 = NULL; 383 cv_signal(ðread->cv_flag); 384 385 /* Wait for thread to end */ 386 while (!(ethread->flags & EMLXS_THREAD_ENDED)) { 387 mutex_exit(ðread->lock); 388 delay(drv_usectohz(10000)); 389 mutex_enter(ðread->lock); 390 } 391 392 mutex_exit(ðread->lock); 393 394 cv_destroy(ðread->cv_flag); 395 mutex_destroy(ðread->lock); 396 397 return; 398 399 } /* emlxs_thread_destroy() */ 400 401 402 void 403 emlxs_thread_trigger1(emlxs_thread_t *ethread, void (*func) ()) 404 { 405 406 /* 407 * If the thread lock can be acquired, 408 * it is in one of these states: 409 * 1. Thread not started. 410 * 2. Thread asleep. 411 * 3. Thread busy. 412 * 4. Thread ended. 413 */ 414 if (!(ethread->flags & EMLXS_THREAD_INITD)) { 415 return; 416 } 417 418 mutex_enter(ðread->lock); 419 420 if (ethread->flags & EMLXS_THREAD_ENDED) { 421 return; 422 } 423 424 while (!(ethread->flags & EMLXS_THREAD_STARTED)) { 425 mutex_exit(ðread->lock); 426 delay(drv_usectohz(10000)); 427 mutex_enter(ðread->lock); 428 429 if (ethread->flags & EMLXS_THREAD_ENDED) { 430 return; 431 } 432 } 433 434 ethread->flags |= EMLXS_THREAD_TRIGGERED; 435 ethread->func = func; 436 ethread->arg1 = NULL; 437 ethread->arg2 = NULL; 438 439 if (ethread->flags & EMLXS_THREAD_ASLEEP) { 440 cv_signal(ðread->cv_flag); 441 } 442 443 mutex_exit(ðread->lock); 444 445 return; 446 447 } /* emlxs_thread_trigger1() */ 448 449 450 void 451 emlxs_thread_trigger2(emlxs_thread_t *ethread, void (*func) (), RING *rp) 452 { 453 454 /* 455 * If the thread lock can be acquired, 456 * it is in one of these states: 457 * 1. Thread not started. 458 * 2. Thread asleep. 459 * 3. Thread busy. 460 * 4. Thread ended. 461 */ 462 if (!(ethread->flags & EMLXS_THREAD_INITD)) { 463 return; 464 } 465 466 mutex_enter(ðread->lock); 467 468 if (ethread->flags & EMLXS_THREAD_ENDED) { 469 return; 470 } 471 472 while (!(ethread->flags & EMLXS_THREAD_STARTED)) { 473 mutex_exit(ðread->lock); 474 delay(drv_usectohz(10000)); 475 mutex_enter(ðread->lock); 476 477 if (ethread->flags & EMLXS_THREAD_ENDED) { 478 return; 479 } 480 } 481 482 ethread->flags |= EMLXS_THREAD_TRIGGERED; 483 ethread->func = func; 484 ethread->arg1 = (void *)rp; 485 ethread->arg2 = NULL; 486 487 if (ethread->flags & EMLXS_THREAD_ASLEEP) { 488 cv_signal(ðread->cv_flag); 489 } 490 491 mutex_exit(ðread->lock); 492 493 return; 494 495 } /* emlxs_thread_trigger2() */ 496