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