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 
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 	    (void *)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 	    (void *)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 		    (void *)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(&hba->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(&hba->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(&ethread->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(&ethread->cv_flag, &ethread->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(&ethread->lock);
341 
342 			func(ethread->hba, arg1, arg2);
343 
344 			mutex_enter(&ethread->lock);
345 			ethread->flags &= ~EMLXS_THREAD_BUSY;
346 		}
347 	}
348 
349 	ethread->flags |= EMLXS_THREAD_ENDED;
350 	mutex_exit(&ethread->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(&ethread->lock, buf, MUTEX_DRIVER, (void *)hba->intr_arg);
373 
374 	(void) sprintf(buf, "%s%d_thread_%08x cv", DRIVER_NAME, hba->ddiinst,
375 	    (uint32_t)((uintptr_t)ethread & 0xFFFFFFFF));
376 	cv_init(&ethread->cv_flag, buf, CV_DRIVER, NULL);
377 
378 	ethread->hba = hba;
379 	ethread->flags |= EMLXS_THREAD_INITD;
380 
381 	pri = v.v_maxsyspri - 2;
382 
383 	ethread->thread =
384 	    thread_create(NULL, 0, emlxs_thread, (char *)ethread, 0, &p0,
385 	    TS_RUN, pri);
386 
387 } /* emlxs_thread_create() */
388 
389 
390 void
391 emlxs_thread_destroy(emlxs_thread_t *ethread)
392 {
393 	/*
394 	 * If the thread lock can be acquired,
395 	 * it is in one of these states:
396 	 * 1. Thread not started.
397 	 * 2. Thread asleep.
398 	 * 3. Thread busy.
399 	 * 4. Thread ended.
400 	 */
401 	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
402 		return;
403 	}
404 
405 
406 	mutex_enter(&ethread->lock);
407 
408 	if (ethread->flags & EMLXS_THREAD_ENDED) {
409 		mutex_exit(&ethread->lock);
410 		return;
411 	}
412 
413 	ethread->flags &= ~EMLXS_THREAD_INITD;
414 	ethread->flags |= (EMLXS_THREAD_KILLED | EMLXS_THREAD_TRIGGERED);
415 	ethread->func = NULL;
416 	ethread->arg1 = NULL;
417 	ethread->arg2 = NULL;
418 	cv_signal(&ethread->cv_flag);
419 
420 	/* Wait for thread to end */
421 	while (!(ethread->flags & EMLXS_THREAD_ENDED)) {
422 		mutex_exit(&ethread->lock);
423 		delay(drv_usectohz(10000));
424 		mutex_enter(&ethread->lock);
425 	}
426 
427 	mutex_exit(&ethread->lock);
428 
429 	cv_destroy(&ethread->cv_flag);
430 	mutex_destroy(&ethread->lock);
431 
432 	return;
433 
434 } /* emlxs_thread_destroy() */
435 
436 
437 void
438 emlxs_thread_trigger1(emlxs_thread_t *ethread, void (*func) ())
439 {
440 
441 	/*
442 	 * If the thread lock can be acquired,
443 	 * it is in one of these states:
444 	 * 1. Thread not started.
445 	 * 2. Thread asleep.
446 	 * 3. Thread busy.
447 	 * 4. Thread ended.
448 	 */
449 	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
450 		return;
451 	}
452 
453 	mutex_enter(&ethread->lock);
454 
455 	if (ethread->flags & EMLXS_THREAD_ENDED) {
456 		return;
457 	}
458 
459 	while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
460 		mutex_exit(&ethread->lock);
461 		delay(drv_usectohz(10000));
462 		mutex_enter(&ethread->lock);
463 
464 		if (ethread->flags & EMLXS_THREAD_ENDED) {
465 			return;
466 		}
467 	}
468 
469 	ethread->flags |= EMLXS_THREAD_TRIGGERED;
470 	ethread->func = func;
471 	ethread->arg1 = NULL;
472 	ethread->arg2 = NULL;
473 
474 	if (ethread->flags & EMLXS_THREAD_ASLEEP) {
475 		cv_signal(&ethread->cv_flag);
476 	}
477 
478 	mutex_exit(&ethread->lock);
479 
480 	return;
481 
482 } /* emlxs_thread_trigger1() */
483 
484 
485 void
486 emlxs_thread_trigger2(emlxs_thread_t *ethread, void (*func) (), CHANNEL *cp)
487 {
488 
489 	/*
490 	 * If the thread lock can be acquired,
491 	 * it is in one of these states:
492 	 * 1. Thread not started.
493 	 * 2. Thread asleep.
494 	 * 3. Thread busy.
495 	 * 4. Thread ended.
496 	 */
497 	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
498 		return;
499 	}
500 
501 	mutex_enter(&ethread->lock);
502 
503 	if (ethread->flags & EMLXS_THREAD_ENDED) {
504 		return;
505 	}
506 
507 	while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
508 		mutex_exit(&ethread->lock);
509 		delay(drv_usectohz(10000));
510 		mutex_enter(&ethread->lock);
511 
512 		if (ethread->flags & EMLXS_THREAD_ENDED) {
513 			return;
514 		}
515 	}
516 
517 	ethread->flags |= EMLXS_THREAD_TRIGGERED;
518 	ethread->func = func;
519 	ethread->arg1 = (void *)cp;
520 	ethread->arg2 = NULL;
521 
522 	if (ethread->flags & EMLXS_THREAD_ASLEEP) {
523 		cv_signal(&ethread->cv_flag);
524 	}
525 
526 	mutex_exit(&ethread->lock);
527 
528 	return;
529 
530 } /* emlxs_thread_trigger2() */
531 
532 
533 void
534 emlxs_thread_spawn(emlxs_hba_t *hba, void (*func) (), void *arg1, void *arg2)
535 {
536 	emlxs_port_t	*port = &PPORT;
537 	emlxs_thread_t	*ethread;
538 
539 	/* Create a thread */
540 	ethread = (emlxs_thread_t *)kmem_alloc(sizeof (emlxs_thread_t),
541 	    KM_NOSLEEP);
542 
543 	if (ethread == NULL) {
544 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg,
545 		    "Unable to allocate thread object.");
546 
547 		return;
548 	}
549 
550 	bzero(ethread, sizeof (emlxs_thread_t));
551 	ethread->hba = hba;
552 	ethread->flags = EMLXS_THREAD_INITD | EMLXS_THREAD_RUN_ONCE;
553 	ethread->func = func;
554 	ethread->arg1 = arg1;
555 	ethread->arg2 = arg2;
556 
557 	/* Queue the thread on the spawn thread list */
558 	mutex_enter(&hba->spawn_lock);
559 
560 	/* Dont spawn the thread if the spawn list is closed */
561 	if (hba->spawn_open == 0) {
562 		mutex_exit(&hba->spawn_lock);
563 
564 		/* destroy the thread */
565 		kmem_free(ethread, sizeof (emlxs_thread_t));
566 		return;
567 	}
568 
569 	if (hba->spawn_thread_head == NULL) {
570 		hba->spawn_thread_head = ethread;
571 	}
572 	else
573 	{
574 		hba->spawn_thread_tail->next = ethread;
575 		ethread->prev = hba->spawn_thread_tail;
576 	}
577 
578 	hba->spawn_thread_tail = ethread;
579 	mutex_exit(&hba->spawn_lock);
580 
581 	(void) thread_create(NULL, 0, &emlxs_thread, (char *)ethread, 0, &p0,
582 	    TS_RUN, v.v_maxsyspri - 2);
583 
584 } /* emlxs_thread_spawn() */
585 
586 
587 void
588 emlxs_thread_spawn_create(emlxs_hba_t *hba)
589 {
590 	char	buf[64];
591 
592 	if (hba->spawn_open)
593 		return;
594 
595 	(void) sprintf(buf, "%s%d_thread_lock mutex", DRIVER_NAME,
596 	    hba->ddiinst);
597 	mutex_init(&hba->spawn_lock, buf, MUTEX_DRIVER, (void *)hba->intr_arg);
598 
599 	hba->spawn_thread_head = NULL;
600 	hba->spawn_thread_tail = NULL;
601 
602 	mutex_enter(&hba->spawn_lock);
603 	hba->spawn_open = 1;
604 	mutex_exit(&hba->spawn_lock);
605 
606 }
607 
608 
609 void
610 emlxs_thread_spawn_destroy(emlxs_hba_t *hba)
611 {
612 	emlxs_thread_t	*ethread;
613 
614 	if (hba->spawn_open == 0) {
615 		return;
616 	}
617 
618 	mutex_enter(&hba->spawn_lock);
619 	hba->spawn_open = 0;
620 
621 	for (ethread = hba->spawn_thread_head; ethread;
622 	    ethread = ethread->next) {
623 		ethread->flags |= EMLXS_THREAD_KILLED;
624 	}
625 
626 	/* Wait for all the spawned threads to complete */
627 	while (hba->spawn_thread_head) {
628 		mutex_exit(&hba->spawn_lock);
629 		delay(drv_usectohz(10000));
630 		mutex_enter(&hba->spawn_lock);
631 	}
632 
633 	mutex_exit(&hba->spawn_lock);
634 	mutex_destroy(&hba->spawn_lock);
635 
636 }
637