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 2010 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 	    DDI_INTR_PRI(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 	    DDI_INTR_PRI(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 		    DDI_INTR_PRI(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(&EMLXS_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(&EMLXS_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,
373 	    DDI_INTR_PRI(hba->intr_arg));
374 
375 	(void) sprintf(buf, "%s%d_thread_%08x cv", DRIVER_NAME, hba->ddiinst,
376 	    (uint32_t)((uintptr_t)ethread & 0xFFFFFFFF));
377 	cv_init(&ethread->cv_flag, buf, CV_DRIVER, NULL);
378 
379 	ethread->hba = hba;
380 	ethread->flags |= EMLXS_THREAD_INITD;
381 
382 	pri = v.v_maxsyspri - 2;
383 
384 	ethread->thread =
385 	    thread_create(NULL, 0, emlxs_thread, (char *)ethread, 0, &p0,
386 	    TS_RUN, pri);
387 
388 } /* emlxs_thread_create() */
389 
390 
391 void
392 emlxs_thread_destroy(emlxs_thread_t *ethread)
393 {
394 	/*
395 	 * If the thread lock can be acquired,
396 	 * it is in one of these states:
397 	 * 1. Thread not started.
398 	 * 2. Thread asleep.
399 	 * 3. Thread busy.
400 	 * 4. Thread ended.
401 	 */
402 	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
403 		return;
404 	}
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) (), CHANNEL *cp)
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 *)cp;
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(&EMLXS_SPAWN_LOCK);
560 
561 	/* Dont spawn the thread if the spawn list is closed */
562 	if (hba->spawn_open == 0) {
563 		mutex_exit(&EMLXS_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(&EMLXS_SPAWN_LOCK);
581 
582 	(void) thread_create(NULL, 0, &emlxs_thread, (char *)ethread, 0, &p0,
583 	    TS_RUN, v.v_maxsyspri - 2);
584 
585 } /* emlxs_thread_spawn() */
586 
587 
588 void
589 emlxs_thread_spawn_create(emlxs_hba_t *hba)
590 {
591 	mutex_enter(&EMLXS_SPAWN_LOCK);
592 	if (hba->spawn_open) {
593 		mutex_exit(&EMLXS_SPAWN_LOCK);
594 		return;
595 	}
596 
597 	hba->spawn_thread_head = NULL;
598 	hba->spawn_thread_tail = NULL;
599 
600 	hba->spawn_open = 1;
601 	mutex_exit(&EMLXS_SPAWN_LOCK);
602 
603 }
604 
605 
606 void
607 emlxs_thread_spawn_destroy(emlxs_hba_t *hba)
608 {
609 	emlxs_thread_t	*ethread;
610 
611 	mutex_enter(&EMLXS_SPAWN_LOCK);
612 	if (hba->spawn_open == 0) {
613 		mutex_exit(&EMLXS_SPAWN_LOCK);
614 		return;
615 	}
616 
617 	hba->spawn_open = 0;
618 
619 	for (ethread = hba->spawn_thread_head; ethread;
620 	    ethread = ethread->next) {
621 		ethread->flags |= EMLXS_THREAD_KILLED;
622 	}
623 
624 	/* Wait for all the spawned threads to complete */
625 	while (hba->spawn_thread_head) {
626 		mutex_exit(&EMLXS_SPAWN_LOCK);
627 		delay(drv_usectohz(10000));
628 		mutex_enter(&EMLXS_SPAWN_LOCK);
629 	}
630 
631 	mutex_exit(&EMLXS_SPAWN_LOCK);
632 }
633