xref: /illumos-gate/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_thread.c (revision 8f23e9fa8abcb5857661066b954e63400d589b65)
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
9  * http://www.opensource.org/licenses/cddl1.txt.
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 (c) 2004-2011 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
emlxs_taskq_thread(emlxs_taskq_thread_t * tthread)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 } /* emlxs_taskq_thread() */
80 
81 
82 
83 uint32_t
emlxs_taskq_dispatch(emlxs_taskq_t * taskq,void (* func)(),void * arg)84 emlxs_taskq_dispatch(emlxs_taskq_t *taskq, void (*func) (), void *arg)
85 {
86 	emlxs_taskq_thread_t *tthread = NULL;
87 
88 	mutex_enter(&taskq->get_lock);
89 
90 	/* Make sure taskq is open for business */
91 	if (!taskq->open) {
92 		mutex_exit(&taskq->get_lock);
93 		return (0);
94 	}
95 
96 	/* Check get_list for a thread */
97 	if (taskq->get_head) {
98 		/* Get the next thread */
99 		tthread = taskq->get_head;
100 		taskq->get_count--;
101 		taskq->get_head = (taskq->get_count) ? tthread->next : NULL;
102 		tthread->next = NULL;
103 	}
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 
123 	mutex_exit(&taskq->get_lock);
124 
125 	/* Wake up the thread if one exists */
126 	if (tthread) {
127 		mutex_enter(&tthread->lock);
128 		tthread->func = func;
129 		tthread->arg = arg;
130 		cv_signal(&tthread->cv_flag);
131 		mutex_exit(&tthread->lock);
132 
133 		return (1);
134 	}
135 
136 	return (0);
137 
138 } /* emlxs_taskq_dispatch() */
139 
140 
141 
142 void
emlxs_taskq_create(emlxs_hba_t * hba,emlxs_taskq_t * taskq)143 emlxs_taskq_create(emlxs_hba_t *hba, emlxs_taskq_t *taskq)
144 {
145 	emlxs_taskq_thread_t *tthread;
146 	uint32_t i;
147 
148 
149 	/* If taskq is already open then quit */
150 	if (taskq->open) {
151 		return;
152 	}
153 
154 	/* Zero the taskq */
155 	bzero(taskq, sizeof (emlxs_taskq_t));
156 
157 	mutex_init(&taskq->get_lock, NULL, MUTEX_DRIVER,
158 	    DDI_INTR_PRI(hba->intr_arg));
159 
160 	mutex_enter(&taskq->get_lock);
161 
162 	taskq->hba = hba;
163 
164 	mutex_init(&taskq->put_lock, NULL, MUTEX_DRIVER,
165 	    DDI_INTR_PRI(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 		mutex_init(&tthread->lock, NULL, MUTEX_DRIVER,
172 		    DDI_INTR_PRI(hba->intr_arg));
173 
174 		cv_init(&tthread->cv_flag, NULL, CV_DRIVER, NULL);
175 
176 		tthread->flags |= EMLXS_THREAD_INITD;
177 		tthread->thread =
178 		    thread_create(NULL, 0, emlxs_taskq_thread,
179 		    (char *)tthread, 0, &p0, TS_RUN, v.v_maxsyspri - 2);
180 	}
181 
182 	/* Open the taskq */
183 	taskq->open = 1;
184 
185 	mutex_exit(&taskq->get_lock);
186 
187 	return;
188 
189 } /* emlxs_taskq_create() */
190 
191 
192 void
emlxs_taskq_destroy(emlxs_taskq_t * taskq)193 emlxs_taskq_destroy(emlxs_taskq_t *taskq)
194 {
195 	emlxs_taskq_thread_t *tthread;
196 	uint32_t i;
197 
198 	/* If taskq already closed, then quit */
199 	if (!taskq->open) {
200 		return;
201 	}
202 
203 	mutex_enter(&taskq->get_lock);
204 
205 	/* If taskq already closed, then quit */
206 	if (!taskq->open) {
207 		mutex_exit(&taskq->get_lock);
208 		return;
209 	}
210 
211 	taskq->open = 0;
212 	mutex_exit(&taskq->get_lock);
213 
214 
215 	/* No more threads can be dispatched now */
216 
217 	/* Kill the threads */
218 	for (i = 0; i < EMLXS_MAX_TASKQ_THREADS; i++) {
219 		tthread = &taskq->thread_list[i];
220 
221 		/*
222 		 * If the thread lock can be acquired,
223 		 * it is in one of these states:
224 		 * 1. Thread not started.
225 		 * 2. Thread asleep.
226 		 * 3. Thread busy.
227 		 * 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
emlxs_thread(emlxs_thread_t * ethread)257 emlxs_thread(emlxs_thread_t *ethread)
258 {
259 	emlxs_hba_t *hba;
260 	void (*func) ();
261 	void *arg1;
262 	void *arg2;
263 
264 	if (ethread->flags & EMLXS_THREAD_RUN_ONCE) {
265 		hba = ethread->hba;
266 		ethread->flags |= EMLXS_THREAD_STARTED;
267 
268 		if (!(ethread->flags & EMLXS_THREAD_KILLED)) {
269 			func = ethread->func;
270 			arg1 = ethread->arg1;
271 			arg2 = ethread->arg2;
272 
273 			func(hba, arg1, arg2);
274 		}
275 
276 		ethread->flags |= EMLXS_THREAD_ENDED;
277 		ethread->flags &= ~EMLXS_THREAD_INITD;
278 
279 		/* Remove the thread from the spawn thread list */
280 		mutex_enter(&EMLXS_SPAWN_LOCK);
281 		if (hba->spawn_thread_head == ethread)
282 			hba->spawn_thread_head = ethread->next;
283 		if (hba->spawn_thread_tail == ethread)
284 			hba->spawn_thread_tail = ethread->prev;
285 
286 		if (ethread->prev)
287 			ethread->prev->next = ethread->next;
288 		if (ethread->next)
289 			ethread->next->prev = ethread->prev;
290 
291 		ethread->next = ethread->prev = NULL;
292 
293 		kmem_free(ethread, sizeof (emlxs_thread_t));
294 
295 		mutex_exit(&EMLXS_SPAWN_LOCK);
296 	}
297 	else
298 	{
299 	/*
300 	 * If the thread lock can be acquired,
301 	 * it is in one of these states:
302 	 * 1. Thread not started.
303 	 * 2. Thread asleep.
304 	 * 3. Thread busy.
305 	 * 4. Thread ended.
306 	 */
307 	mutex_enter(&ethread->lock);
308 	ethread->flags |= EMLXS_THREAD_STARTED;
309 
310 	while (!(ethread->flags & EMLXS_THREAD_KILLED)) {
311 		if (!(ethread->flags & EMLXS_THREAD_TRIGGERED)) {
312 			ethread->flags |= EMLXS_THREAD_ASLEEP;
313 			cv_wait(&ethread->cv_flag, &ethread->lock);
314 		}
315 
316 		ethread->flags &=
317 		    ~(EMLXS_THREAD_ASLEEP | EMLXS_THREAD_TRIGGERED);
318 
319 		if (ethread->func) {
320 			func = ethread->func;
321 			arg1 = ethread->arg1;
322 			arg2 = ethread->arg2;
323 			ethread->func = NULL;
324 			ethread->arg1 = NULL;
325 			ethread->arg2 = NULL;
326 
327 			ethread->flags |= EMLXS_THREAD_BUSY;
328 			mutex_exit(&ethread->lock);
329 
330 			func(ethread->hba, arg1, arg2);
331 
332 			mutex_enter(&ethread->lock);
333 			ethread->flags &= ~EMLXS_THREAD_BUSY;
334 		}
335 	}
336 
337 	ethread->flags |= EMLXS_THREAD_ENDED;
338 	mutex_exit(&ethread->lock);
339 	}
340 
341 	thread_exit();
342 
343 } /* emlxs_thread() */
344 
345 
346 void
emlxs_thread_create(emlxs_hba_t * hba,emlxs_thread_t * ethread)347 emlxs_thread_create(emlxs_hba_t *hba, emlxs_thread_t *ethread)
348 {
349 	uint16_t pri;
350 
351 	if (ethread->flags & EMLXS_THREAD_INITD) {
352 		return;
353 	}
354 
355 	bzero(ethread, sizeof (emlxs_thread_t));
356 
357 	mutex_init(&ethread->lock, NULL, MUTEX_DRIVER,
358 	    DDI_INTR_PRI(hba->intr_arg));
359 
360 	cv_init(&ethread->cv_flag, NULL, CV_DRIVER, NULL);
361 
362 	ethread->hba = hba;
363 	ethread->flags |= EMLXS_THREAD_INITD;
364 
365 	pri = v.v_maxsyspri - 2;
366 
367 	ethread->thread =
368 	    thread_create(NULL, 0, emlxs_thread, (char *)ethread, 0, &p0,
369 	    TS_RUN, pri);
370 
371 } /* emlxs_thread_create() */
372 
373 
374 void
emlxs_thread_destroy(emlxs_thread_t * ethread)375 emlxs_thread_destroy(emlxs_thread_t *ethread)
376 {
377 	/*
378 	 * If the thread lock can be acquired,
379 	 * it is in one of these states:
380 	 * 1. Thread not started.
381 	 * 2. Thread asleep.
382 	 * 3. Thread busy.
383 	 * 4. Thread ended.
384 	 */
385 	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
386 		return;
387 	}
388 
389 
390 	mutex_enter(&ethread->lock);
391 
392 	if (ethread->flags & EMLXS_THREAD_ENDED) {
393 		mutex_exit(&ethread->lock);
394 		return;
395 	}
396 
397 	ethread->flags &= ~EMLXS_THREAD_INITD;
398 	ethread->flags |= (EMLXS_THREAD_KILLED | EMLXS_THREAD_TRIGGERED);
399 	ethread->func = NULL;
400 	ethread->arg1 = NULL;
401 	ethread->arg2 = NULL;
402 	cv_signal(&ethread->cv_flag);
403 
404 	/* Wait for thread to end */
405 	while (!(ethread->flags & EMLXS_THREAD_ENDED)) {
406 		mutex_exit(&ethread->lock);
407 		delay(drv_usectohz(10000));
408 		mutex_enter(&ethread->lock);
409 	}
410 
411 	mutex_exit(&ethread->lock);
412 
413 	cv_destroy(&ethread->cv_flag);
414 	mutex_destroy(&ethread->lock);
415 
416 	return;
417 
418 } /* emlxs_thread_destroy() */
419 
420 
421 void
emlxs_thread_trigger1(emlxs_thread_t * ethread,void (* func)())422 emlxs_thread_trigger1(emlxs_thread_t *ethread, void (*func) ())
423 {
424 
425 	/*
426 	 * If the thread lock can be acquired,
427 	 * it is in one of these states:
428 	 * 1. Thread not started.
429 	 * 2. Thread asleep.
430 	 * 3. Thread busy.
431 	 * 4. Thread ended.
432 	 */
433 	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
434 		return;
435 	}
436 
437 	mutex_enter(&ethread->lock);
438 
439 	if (ethread->flags & EMLXS_THREAD_ENDED) {
440 		return;
441 	}
442 
443 	while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
444 		mutex_exit(&ethread->lock);
445 		delay(drv_usectohz(10000));
446 		mutex_enter(&ethread->lock);
447 
448 		if (ethread->flags & EMLXS_THREAD_ENDED) {
449 			return;
450 		}
451 	}
452 
453 	ethread->flags |= EMLXS_THREAD_TRIGGERED;
454 	ethread->func = func;
455 	ethread->arg1 = NULL;
456 	ethread->arg2 = NULL;
457 
458 	if (ethread->flags & EMLXS_THREAD_ASLEEP) {
459 		cv_signal(&ethread->cv_flag);
460 	}
461 
462 	mutex_exit(&ethread->lock);
463 
464 	return;
465 
466 } /* emlxs_thread_trigger1() */
467 
468 
469 void
emlxs_thread_trigger2(emlxs_thread_t * ethread,void (* func)(),CHANNEL * cp)470 emlxs_thread_trigger2(emlxs_thread_t *ethread, void (*func) (), CHANNEL *cp)
471 {
472 
473 	/*
474 	 * If the thread lock can be acquired,
475 	 * it is in one of these states:
476 	 * 1. Thread not started.
477 	 * 2. Thread asleep.
478 	 * 3. Thread busy.
479 	 * 4. Thread ended.
480 	 */
481 	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
482 		return;
483 	}
484 
485 	mutex_enter(&ethread->lock);
486 
487 	if (ethread->flags & EMLXS_THREAD_ENDED) {
488 		return;
489 	}
490 
491 	while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
492 		mutex_exit(&ethread->lock);
493 		delay(drv_usectohz(10000));
494 		mutex_enter(&ethread->lock);
495 
496 		if (ethread->flags & EMLXS_THREAD_ENDED) {
497 			return;
498 		}
499 	}
500 
501 	ethread->flags |= EMLXS_THREAD_TRIGGERED;
502 	ethread->func = func;
503 	ethread->arg1 = (void *)cp;
504 	ethread->arg2 = NULL;
505 
506 	if (ethread->flags & EMLXS_THREAD_ASLEEP) {
507 		cv_signal(&ethread->cv_flag);
508 	}
509 
510 	mutex_exit(&ethread->lock);
511 
512 	return;
513 
514 } /* emlxs_thread_trigger2() */
515 
516 
517 void
emlxs_thread_spawn(emlxs_hba_t * hba,void (* func)(),void * arg1,void * arg2)518 emlxs_thread_spawn(emlxs_hba_t *hba, void (*func) (), void *arg1, void *arg2)
519 {
520 	emlxs_port_t	*port = &PPORT;
521 	emlxs_thread_t	*ethread;
522 
523 	/* Create a thread */
524 	ethread = (emlxs_thread_t *)kmem_alloc(sizeof (emlxs_thread_t),
525 	    KM_NOSLEEP);
526 
527 	if (ethread == NULL) {
528 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg,
529 		    "Unable to allocate thread object.");
530 
531 		return;
532 	}
533 
534 	bzero(ethread, sizeof (emlxs_thread_t));
535 	ethread->hba = hba;
536 	ethread->flags = EMLXS_THREAD_INITD | EMLXS_THREAD_RUN_ONCE;
537 	ethread->func = func;
538 	ethread->arg1 = arg1;
539 	ethread->arg2 = arg2;
540 
541 	/* Queue the thread on the spawn thread list */
542 	mutex_enter(&EMLXS_SPAWN_LOCK);
543 
544 	/* Dont spawn the thread if the spawn list is closed */
545 	if (hba->spawn_open == 0) {
546 		mutex_exit(&EMLXS_SPAWN_LOCK);
547 
548 		/* destroy the thread */
549 		kmem_free(ethread, sizeof (emlxs_thread_t));
550 		return;
551 	}
552 
553 	if (hba->spawn_thread_head == NULL) {
554 		hba->spawn_thread_head = ethread;
555 	}
556 	else
557 	{
558 		hba->spawn_thread_tail->next = ethread;
559 		ethread->prev = hba->spawn_thread_tail;
560 	}
561 
562 	hba->spawn_thread_tail = ethread;
563 	mutex_exit(&EMLXS_SPAWN_LOCK);
564 
565 	(void) thread_create(NULL, 0, &emlxs_thread, (char *)ethread, 0, &p0,
566 	    TS_RUN, v.v_maxsyspri - 2);
567 
568 } /* emlxs_thread_spawn() */
569 
570 
571 void
emlxs_thread_spawn_create(emlxs_hba_t * hba)572 emlxs_thread_spawn_create(emlxs_hba_t *hba)
573 {
574 	mutex_enter(&EMLXS_SPAWN_LOCK);
575 	if (hba->spawn_open) {
576 		mutex_exit(&EMLXS_SPAWN_LOCK);
577 		return;
578 	}
579 
580 	hba->spawn_thread_head = NULL;
581 	hba->spawn_thread_tail = NULL;
582 
583 	hba->spawn_open = 1;
584 	mutex_exit(&EMLXS_SPAWN_LOCK);
585 
586 }
587 
588 
589 void
emlxs_thread_spawn_destroy(emlxs_hba_t * hba)590 emlxs_thread_spawn_destroy(emlxs_hba_t *hba)
591 {
592 	emlxs_thread_t	*ethread;
593 
594 	mutex_enter(&EMLXS_SPAWN_LOCK);
595 	if (hba->spawn_open == 0) {
596 		mutex_exit(&EMLXS_SPAWN_LOCK);
597 		return;
598 	}
599 
600 	hba->spawn_open = 0;
601 
602 	for (ethread = hba->spawn_thread_head; ethread;
603 	    ethread = ethread->next) {
604 		ethread->flags |= EMLXS_THREAD_KILLED;
605 	}
606 
607 	/* Wait for all the spawned threads to complete */
608 	while (hba->spawn_thread_head) {
609 		mutex_exit(&EMLXS_SPAWN_LOCK);
610 		delay(drv_usectohz(10000));
611 		mutex_enter(&EMLXS_SPAWN_LOCK);
612 	}
613 
614 	mutex_exit(&EMLXS_SPAWN_LOCK);
615 }
616