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 	void (*func) ();
271 	void *arg1;
272 	void *arg2;
273 
274 	/*
275 	 * If the thread lock can be acquired,
276 	 * it is in one of these states:
277 	 * 1. Thread not started.
278 	 * 2. Thread asleep.
279 	 * 3. Thread busy.
280 	 * 4. Thread ended.
281 	 */
282 	mutex_enter(&ethread->lock);
283 	ethread->flags |= EMLXS_THREAD_STARTED;
284 
285 	while (!(ethread->flags & EMLXS_THREAD_KILLED)) {
286 		if (!(ethread->flags & EMLXS_THREAD_TRIGGERED)) {
287 			ethread->flags |= EMLXS_THREAD_ASLEEP;
288 			cv_wait(&ethread->cv_flag, &ethread->lock);
289 		}
290 
291 		ethread->flags &=
292 		    ~(EMLXS_THREAD_ASLEEP | EMLXS_THREAD_TRIGGERED);
293 
294 		if (ethread->func) {
295 			func = ethread->func;
296 			arg1 = ethread->arg1;
297 			arg2 = ethread->arg2;
298 			ethread->func = NULL;
299 			ethread->arg1 = NULL;
300 			ethread->arg2 = NULL;
301 
302 			ethread->flags |= EMLXS_THREAD_BUSY;
303 			mutex_exit(&ethread->lock);
304 
305 			func(ethread->hba, arg1, arg2);
306 
307 			mutex_enter(&ethread->lock);
308 			ethread->flags &= ~EMLXS_THREAD_BUSY;
309 		}
310 	}
311 
312 	ethread->flags |= EMLXS_THREAD_ENDED;
313 	mutex_exit(&ethread->lock);
314 
315 	thread_exit();
316 
317 	return;
318 
319 }  /* emlxs_thread() */
320 
321 
322 void
323 emlxs_thread_create(emlxs_hba_t *hba, emlxs_thread_t *ethread)
324 {
325 	char buf[64];
326 
327 	if (ethread->flags & EMLXS_THREAD_INITD) {
328 		return;
329 	}
330 
331 	bzero(ethread, sizeof (emlxs_thread_t));
332 
333 	(void) sprintf(buf, "%s%d_thread_%08x mutex", DRIVER_NAME, hba->ddiinst,
334 	    (uint32_t)((uintptr_t)ethread & 0xFFFFFFFF));
335 	mutex_init(&ethread->lock, buf, MUTEX_DRIVER, (void *)hba->intr_arg);
336 
337 	/* mutex_enter(&ethread->lock); */
338 
339 	(void) sprintf(buf, "%s%d_thread_%08x cv", DRIVER_NAME, hba->ddiinst,
340 	    (uint32_t)((uintptr_t)ethread & 0xFFFFFFFF));
341 	cv_init(&ethread->cv_flag, buf, CV_DRIVER, NULL);
342 
343 	ethread->hba = hba;
344 	ethread->flags |= EMLXS_THREAD_INITD;
345 
346 	/* mutex_exit(&ethread->lock); */
347 
348 	ethread->thread =
349 	    thread_create(NULL, 0, emlxs_thread, (char *)ethread, 0, &p0,
350 	    TS_RUN, v.v_maxsyspri - 2);
351 
352 	return;
353 
354 }  /* emlxs_thread_create() */
355 
356 
357 void
358 emlxs_thread_destroy(emlxs_thread_t *ethread)
359 {
360 	/*
361 	 * If the thread lock can be acquired,
362 	 * it is in one of these states:
363 	 * 1. Thread not started.
364 	 * 2. Thread asleep.
365 	 * 3. Thread busy.
366 	 * 4. Thread ended.
367 	 */
368 	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
369 		return;
370 	}
371 
372 	mutex_enter(&ethread->lock);
373 
374 	if (ethread->flags & EMLXS_THREAD_ENDED) {
375 		return;
376 	}
377 
378 	ethread->flags &= ~EMLXS_THREAD_INITD;
379 	ethread->flags |= (EMLXS_THREAD_KILLED | EMLXS_THREAD_TRIGGERED);
380 	ethread->func = NULL;
381 	ethread->arg1 = NULL;
382 	ethread->arg2 = NULL;
383 	cv_signal(&ethread->cv_flag);
384 
385 	/* Wait for thread to end */
386 	while (!(ethread->flags & EMLXS_THREAD_ENDED)) {
387 		mutex_exit(&ethread->lock);
388 		delay(drv_usectohz(10000));
389 		mutex_enter(&ethread->lock);
390 	}
391 
392 	mutex_exit(&ethread->lock);
393 
394 	cv_destroy(&ethread->cv_flag);
395 	mutex_destroy(&ethread->lock);
396 
397 	return;
398 
399 }  /* emlxs_thread_destroy() */
400 
401 
402 void
403 emlxs_thread_trigger1(emlxs_thread_t *ethread, void (*func) ())
404 {
405 
406 	/*
407 	 * If the thread lock can be acquired,
408 	 * it is in one of these states:
409 	 * 1. Thread not started.
410 	 * 2. Thread asleep.
411 	 * 3. Thread busy.
412 	 * 4. Thread ended.
413 	 */
414 	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
415 		return;
416 	}
417 
418 	mutex_enter(&ethread->lock);
419 
420 	if (ethread->flags & EMLXS_THREAD_ENDED) {
421 		return;
422 	}
423 
424 	while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
425 		mutex_exit(&ethread->lock);
426 		delay(drv_usectohz(10000));
427 		mutex_enter(&ethread->lock);
428 
429 		if (ethread->flags & EMLXS_THREAD_ENDED) {
430 			return;
431 		}
432 	}
433 
434 	ethread->flags |= EMLXS_THREAD_TRIGGERED;
435 	ethread->func = func;
436 	ethread->arg1 = NULL;
437 	ethread->arg2 = NULL;
438 
439 	if (ethread->flags & EMLXS_THREAD_ASLEEP) {
440 		cv_signal(&ethread->cv_flag);
441 	}
442 
443 	mutex_exit(&ethread->lock);
444 
445 	return;
446 
447 }  /* emlxs_thread_trigger1() */
448 
449 
450 void
451 emlxs_thread_trigger2(emlxs_thread_t *ethread, void (*func) (), RING *rp)
452 {
453 
454 	/*
455 	 * If the thread lock can be acquired,
456 	 * it is in one of these states:
457 	 * 1. Thread not started.
458 	 * 2. Thread asleep.
459 	 * 3. Thread busy.
460 	 * 4. Thread ended.
461 	 */
462 	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
463 		return;
464 	}
465 
466 	mutex_enter(&ethread->lock);
467 
468 	if (ethread->flags & EMLXS_THREAD_ENDED) {
469 		return;
470 	}
471 
472 	while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
473 		mutex_exit(&ethread->lock);
474 		delay(drv_usectohz(10000));
475 		mutex_enter(&ethread->lock);
476 
477 		if (ethread->flags & EMLXS_THREAD_ENDED) {
478 			return;
479 		}
480 	}
481 
482 	ethread->flags |= EMLXS_THREAD_TRIGGERED;
483 	ethread->func = func;
484 	ethread->arg1 = (void *)rp;
485 	ethread->arg2 = NULL;
486 
487 	if (ethread->flags & EMLXS_THREAD_ASLEEP) {
488 		cv_signal(&ethread->cv_flag);
489 	}
490 
491 	mutex_exit(&ethread->lock);
492 
493 	return;
494 
495 }  /* emlxs_thread_trigger2() */
496