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 	emlxs_hba_t *hba;
271 	void (*func) ();
272 	void *arg1;
273 	void *arg2;
274 
275 	if (ethread->flags & EMLXS_THREAD_RUN_ONCE) {
276 		hba = ethread->hba;
277 		ethread->flags |= EMLXS_THREAD_STARTED;
278 
279 		if (!(ethread->flags & EMLXS_THREAD_KILLED)) {
280 			func = ethread->func;
281 			arg1 = ethread->arg1;
282 			arg2 = ethread->arg2;
283 
284 			func(hba, arg1, arg2);
285 		}
286 
287 		ethread->flags |= EMLXS_THREAD_ENDED;
288 		ethread->flags &= ~EMLXS_THREAD_INITD;
289 
290 		/* Remove the thread from the spawn thread list */
291 		mutex_enter(&hba->spawn_lock);
292 		if (hba->spawn_thread_head == ethread)
293 			hba->spawn_thread_head = ethread->next;
294 		if (hba->spawn_thread_tail == ethread)
295 			hba->spawn_thread_tail = ethread->prev;
296 
297 		if (ethread->prev)
298 			ethread->prev->next = ethread->next;
299 		if (ethread->next)
300 			ethread->next->prev = ethread->prev;
301 
302 		ethread->next = ethread->prev = NULL;
303 
304 		kmem_free(ethread, sizeof (emlxs_thread_t));
305 
306 		mutex_exit(&hba->spawn_lock);
307 	}
308 	else
309 	{
310 		/*
311 		 * If the thread lock can be acquired,
312 		 * it is in one of these states:
313 		 * 1. Thread not started.
314 		 * 2. Thread asleep.
315 		 * 3. Thread busy.
316 		 * 4. Thread ended.
317 		 */
318 		mutex_enter(&ethread->lock);
319 		ethread->flags |= EMLXS_THREAD_STARTED;
320 
321 		while (!(ethread->flags & EMLXS_THREAD_KILLED)) {
322 			if (!(ethread->flags & EMLXS_THREAD_TRIGGERED)) {
323 				ethread->flags |= EMLXS_THREAD_ASLEEP;
324 				cv_wait(&ethread->cv_flag, &ethread->lock);
325 			}
326 
327 			ethread->flags &=
328 			    ~(EMLXS_THREAD_ASLEEP | EMLXS_THREAD_TRIGGERED);
329 
330 			if (ethread->func) {
331 				func = ethread->func;
332 				arg1 = ethread->arg1;
333 				arg2 = ethread->arg2;
334 				ethread->func = NULL;
335 				ethread->arg1 = NULL;
336 				ethread->arg2 = NULL;
337 
338 				ethread->flags |= EMLXS_THREAD_BUSY;
339 				mutex_exit(&ethread->lock);
340 
341 				func(ethread->hba, arg1, arg2);
342 
343 				mutex_enter(&ethread->lock);
344 				ethread->flags &= ~EMLXS_THREAD_BUSY;
345 			}
346 		}
347 
348 		ethread->flags |= EMLXS_THREAD_ENDED;
349 		mutex_exit(&ethread->lock);
350 	}
351 
352 	thread_exit();
353 
354 }  /* emlxs_thread() */
355 
356 
357 void
358 emlxs_thread_create(emlxs_hba_t *hba, emlxs_thread_t *ethread)
359 {
360 	char buf[64];
361 
362 	if (ethread->flags & EMLXS_THREAD_INITD) {
363 		return;
364 	}
365 
366 	bzero(ethread, sizeof (emlxs_thread_t));
367 
368 	(void) sprintf(buf, "%s%d_thread_%08x mutex", DRIVER_NAME, hba->ddiinst,
369 	    (uint32_t)((uintptr_t)ethread & 0xFFFFFFFF));
370 	mutex_init(&ethread->lock, buf, MUTEX_DRIVER, (void *)hba->intr_arg);
371 
372 	/* mutex_enter(&ethread->lock); */
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 	/* mutex_exit(&ethread->lock); */
382 
383 	ethread->thread =
384 	    thread_create(NULL, 0, emlxs_thread, (char *)ethread, 0, &p0,
385 	    TS_RUN, v.v_maxsyspri - 2);
386 
387 	return;
388 
389 }  /* emlxs_thread_create() */
390 
391 
392 void
393 emlxs_thread_destroy(emlxs_thread_t *ethread)
394 {
395 	/*
396 	 * If the thread lock can be acquired,
397 	 * it is in one of these states:
398 	 * 1. Thread not started.
399 	 * 2. Thread asleep.
400 	 * 3. Thread busy.
401 	 * 4. Thread ended.
402 	 */
403 	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
404 		return;
405 	}
406 
407 	mutex_enter(&ethread->lock);
408 
409 	if (ethread->flags & EMLXS_THREAD_ENDED) {
410 		mutex_exit(&ethread->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(&ethread->cv_flag);
420 
421 	/* Wait for thread to end */
422 	while (!(ethread->flags & EMLXS_THREAD_ENDED)) {
423 		mutex_exit(&ethread->lock);
424 		delay(drv_usectohz(10000));
425 		mutex_enter(&ethread->lock);
426 	}
427 
428 	mutex_exit(&ethread->lock);
429 
430 	cv_destroy(&ethread->cv_flag);
431 	mutex_destroy(&ethread->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(&ethread->lock);
455 
456 	if (ethread->flags & EMLXS_THREAD_ENDED) {
457 		return;
458 	}
459 
460 	while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
461 		mutex_exit(&ethread->lock);
462 		delay(drv_usectohz(10000));
463 		mutex_enter(&ethread->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(&ethread->cv_flag);
477 	}
478 
479 	mutex_exit(&ethread->lock);
480 
481 	return;
482 
483 }  /* emlxs_thread_trigger1() */
484 
485 
486 void
487 emlxs_thread_trigger2(emlxs_thread_t *ethread, void (*func) (), RING *rp)
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(&ethread->lock);
503 
504 	if (ethread->flags & EMLXS_THREAD_ENDED) {
505 		return;
506 	}
507 
508 	while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
509 		mutex_exit(&ethread->lock);
510 		delay(drv_usectohz(10000));
511 		mutex_enter(&ethread->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 *)rp;
521 	ethread->arg2 = NULL;
522 
523 	if (ethread->flags & EMLXS_THREAD_ASLEEP) {
524 		cv_signal(&ethread->cv_flag);
525 	}
526 
527 	mutex_exit(&ethread->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(&hba->spawn_lock);
560 
561 	/* Dont spawn the thread if the spawn list is closed */
562 	if (hba->spawn_open == 0) {
563 		mutex_exit(&hba->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(&hba->spawn_lock);
581 
582 	(void) thread_create(NULL, 0, &emlxs_thread, (char *)ethread, 0, &p0,
583 	    TS_RUN, v.v_maxsyspri - 2);
584 
585 }
586 
587 
588 void
589 emlxs_thread_spawn_create(emlxs_hba_t *hba)
590 {
591 	char	buf[64];
592 
593 	if (hba->spawn_open)
594 		return;
595 
596 	(void) sprintf(buf, "%s%d_thread_lock mutex", DRIVER_NAME,
597 	    hba->ddiinst);
598 	mutex_init(&hba->spawn_lock, buf, MUTEX_DRIVER, (void *)hba->intr_arg);
599 
600 	hba->spawn_thread_head = NULL;
601 	hba->spawn_thread_tail = NULL;
602 
603 	mutex_enter(&hba->spawn_lock);
604 	hba->spawn_open = 1;
605 	mutex_exit(&hba->spawn_lock);
606 
607 }
608 
609 
610 void
611 emlxs_thread_spawn_destroy(emlxs_hba_t *hba)
612 {
613 	emlxs_thread_t	*ethread;
614 
615 	if (hba->spawn_open == 0) {
616 		return;
617 	}
618 
619 	mutex_enter(&hba->spawn_lock);
620 	hba->spawn_open = 0;
621 
622 	for (ethread = hba->spawn_thread_head; ethread;
623 	    ethread = ethread->next) {
624 		ethread->flags |= EMLXS_THREAD_KILLED;
625 	}
626 
627 	/* Wait for all the spawned threads to complete */
628 	while (hba->spawn_thread_head) {
629 		mutex_exit(&hba->spawn_lock);
630 		delay(drv_usectohz(10000));
631 		mutex_enter(&hba->spawn_lock);
632 	}
633 
634 	mutex_exit(&hba->spawn_lock);
635 	mutex_destroy(&hba->spawn_lock);
636 
637 }
638