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 2008 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 	(void) 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 	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 	/* Check get_list for a thread */
98 	if (taskq->get_head) {
99 		/* Get the next thread */
100 		tthread = taskq->get_head;
101 		taskq->get_count--;
102 		taskq->get_head = (taskq->get_count) ? tthread->next : NULL;
103 		tthread->next = NULL;
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 	mutex_exit(&taskq->get_lock);
123 
124 	/* Wake up the thread if one exists */
125 	if (tthread) {
126 		mutex_enter(&tthread->lock);
127 		tthread->func = func;
128 		tthread->arg = arg;
129 		cv_signal(&tthread->cv_flag);
130 		mutex_exit(&tthread->lock);
131 
132 		return (1);
133 	}
134 	return (0);
135 
136 } /* emlxs_taskq_dispatch() */
137 
138 
139 
140 void
141 emlxs_taskq_create(emlxs_hba_t *hba, emlxs_taskq_t *taskq)
142 {
143 	emlxs_taskq_thread_t *tthread;
144 	char buf[64];
145 	uint32_t i = 0;
146 
147 
148 	/* If taskq is already open then quit */
149 	if (taskq->open) {
150 		return;
151 	}
152 	/* Zero the taskq */
153 	bzero(taskq, sizeof (emlxs_taskq_t));
154 
155 	(void) sprintf(buf, "%s%d_thread_taskq_get mutex", DRIVER_NAME,
156 	    hba->ddiinst);
157 	mutex_init(&taskq->get_lock, buf, MUTEX_DRIVER, (void *) hba->intr_arg);
158 
159 	mutex_enter(&taskq->get_lock);
160 
161 	taskq->hba = hba;
162 
163 	(void) sprintf(buf, "%s%d_thread_taskq_put mutex", DRIVER_NAME,
164 	    hba->ddiinst);
165 	mutex_init(&taskq->put_lock, buf, MUTEX_DRIVER, (void *) 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 		(void) sprintf(buf, "%s%d_thread%d mutex", DRIVER_NAME,
172 		    hba->ddiinst, i);
173 		mutex_init(&tthread->lock, buf, MUTEX_DRIVER,
174 		    (void *) hba->intr_arg);
175 
176 		(void) sprintf(buf, "%s%d_thread%d cv", DRIVER_NAME,
177 		    hba->ddiinst, i);
178 		cv_init(&tthread->cv_flag, buf, CV_DRIVER, NULL);
179 
180 		tthread->flags |= EMLXS_THREAD_INITD;
181 		tthread->thread = thread_create(NULL, 0, emlxs_taskq_thread,
182 		    (char *)tthread, 0, &p0, TS_RUN, v.v_maxsyspri - 2);
183 	}
184 
185 	/* Open the taskq */
186 	taskq->open = 1;
187 
188 	mutex_exit(&taskq->get_lock);
189 
190 	return;
191 
192 } /* emlxs_taskq_create() */
193 
194 
195 void
196 emlxs_taskq_destroy(emlxs_taskq_t *taskq)
197 {
198 	emlxs_taskq_thread_t *tthread;
199 	uint32_t i;
200 
201 	/* hba = taskq->hba; */
202 
203 	/* If taskq already closed, then quit */
204 	if (!taskq->open) {
205 		return;
206 	}
207 	mutex_enter(&taskq->get_lock);
208 
209 	/* If taskq already closed, then quit */
210 	if (!taskq->open) {
211 		mutex_exit(&taskq->get_lock);
212 		return;
213 	}
214 	taskq->open = 0;
215 	mutex_exit(&taskq->get_lock);
216 
217 
218 	/* No more threads can be dispatched now */
219 
220 	/* Kill the threads */
221 	for (i = 0; i < EMLXS_MAX_TASKQ_THREADS; i++) {
222 		tthread = &taskq->thread_list[i];
223 
224 		/*
225 		 * If the thread lock can be acquired, it is in one of these
226 		 * states: 1. Thread not started. 2. Thread asleep. 3. Thread
227 		 * busy. 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
257 emlxs_thread(emlxs_thread_t *ethread)
258 {
259 	void (*func) ();
260 	void *arg1;
261 	void *arg2;
262 
263 	/*
264 	 * If the thread lock can be acquired, it is in one of these states:
265 	 * 1. Thread not started. 2. Thread asleep. 3. Thread busy. 4. Thread
266 	 * ended.
267 	 */
268 	mutex_enter(&ethread->lock);
269 	ethread->flags |= EMLXS_THREAD_STARTED;
270 
271 	while (!(ethread->flags & EMLXS_THREAD_KILLED)) {
272 		if (!(ethread->flags & EMLXS_THREAD_TRIGGERED)) {
273 			ethread->flags |= EMLXS_THREAD_ASLEEP;
274 			cv_wait(&ethread->cv_flag, &ethread->lock);
275 		}
276 		ethread->flags &=
277 		    ~(EMLXS_THREAD_ASLEEP | EMLXS_THREAD_TRIGGERED);
278 
279 		if (ethread->func) {
280 			func = ethread->func;
281 			arg1 = ethread->arg1;
282 			arg2 = ethread->arg2;
283 			ethread->func = NULL;
284 			ethread->arg1 = NULL;
285 			ethread->arg2 = NULL;
286 
287 			ethread->flags |= EMLXS_THREAD_BUSY;
288 			mutex_exit(&ethread->lock);
289 
290 			func(ethread->hba, arg1, arg2);
291 
292 			mutex_enter(&ethread->lock);
293 			ethread->flags &= ~EMLXS_THREAD_BUSY;
294 		}
295 	}
296 
297 	ethread->flags |= EMLXS_THREAD_ENDED;
298 	mutex_exit(&ethread->lock);
299 
300 	(void) thread_exit();
301 
302 	return;
303 
304 } /* emlxs_thread() */
305 
306 
307 void
308 emlxs_thread_create(emlxs_hba_t *hba, emlxs_thread_t *ethread)
309 {
310 	char buf[64];
311 
312 	if (ethread->flags & EMLXS_THREAD_INITD) {
313 		return;
314 	}
315 	bzero(ethread, sizeof (emlxs_thread_t));
316 
317 	(void) sprintf(buf, "%s%d_thread_%08x mutex", DRIVER_NAME,
318 	    hba->ddiinst, (int)((uintptr_t)ethread & 0xFFFFFFFF));
319 	mutex_init(&ethread->lock, buf, MUTEX_DRIVER, (void *) hba->intr_arg);
320 
321 	/* mutex_enter(&ethread->lock); */
322 
323 	(void) sprintf(buf, "%s%d_thread_%08x cv", DRIVER_NAME,
324 	    hba->ddiinst, (int)((uintptr_t)ethread & 0xFFFFFFFF));
325 	cv_init(&ethread->cv_flag, buf, CV_DRIVER, NULL);
326 
327 	ethread->hba = hba;
328 	ethread->flags |= EMLXS_THREAD_INITD;
329 
330 	/* mutex_exit(&ethread->lock); */
331 
332 	ethread->thread = thread_create(NULL, 0, emlxs_thread,
333 	    (char *)ethread, 0, &p0, TS_RUN, v.v_maxsyspri - 2);
334 
335 	return;
336 
337 } /* emlxs_thread_create() */
338 
339 
340 void
341 emlxs_thread_destroy(emlxs_thread_t *ethread)
342 {
343 	/*
344 	 * If the thread lock can be acquired, it is in one of these states:
345 	 * 1. Thread not started. 2. Thread asleep. 3. Thread busy. 4. Thread
346 	 * ended.
347 	 */
348 	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
349 		return;
350 	}
351 	mutex_enter(&ethread->lock);
352 
353 	if (ethread->flags & EMLXS_THREAD_ENDED) {
354 		return;
355 	}
356 	ethread->flags &= ~EMLXS_THREAD_INITD;
357 	ethread->flags |= (EMLXS_THREAD_KILLED | EMLXS_THREAD_TRIGGERED);
358 	ethread->func = NULL;
359 	ethread->arg1 = NULL;
360 	ethread->arg2 = NULL;
361 	cv_signal(&ethread->cv_flag);
362 
363 	/* Wait for thread to end */
364 	while (!(ethread->flags & EMLXS_THREAD_ENDED)) {
365 		mutex_exit(&ethread->lock);
366 		delay(drv_usectohz(10000));
367 		mutex_enter(&ethread->lock);
368 	}
369 
370 	mutex_exit(&ethread->lock);
371 
372 	cv_destroy(&ethread->cv_flag);
373 	mutex_destroy(&ethread->lock);
374 
375 	return;
376 
377 } /* emlxs_thread_destroy() */
378 
379 
380 void
381 emlxs_thread_trigger1(emlxs_thread_t *ethread, void (*func) ())
382 {
383 
384 	/*
385 	 * If the thread lock can be acquired, it is in one of these states:
386 	 * 1. Thread not started. 2. Thread asleep. 3. Thread busy. 4. Thread
387 	 * ended.
388 	 */
389 	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
390 		return;
391 	}
392 	mutex_enter(&ethread->lock);
393 
394 	if (ethread->flags & EMLXS_THREAD_ENDED) {
395 		return;
396 	}
397 	while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
398 		mutex_exit(&ethread->lock);
399 		delay(drv_usectohz(10000));
400 		mutex_enter(&ethread->lock);
401 
402 		if (ethread->flags & EMLXS_THREAD_ENDED) {
403 			return;
404 		}
405 	}
406 
407 	ethread->flags |= EMLXS_THREAD_TRIGGERED;
408 	ethread->func = func;
409 	ethread->arg1 = NULL;
410 	ethread->arg2 = NULL;
411 
412 	if (ethread->flags & EMLXS_THREAD_ASLEEP) {
413 		cv_signal(&ethread->cv_flag);
414 	}
415 	mutex_exit(&ethread->lock);
416 
417 	return;
418 
419 } /* emlxs_thread_trigger1() */
420 
421 
422 void
423 emlxs_thread_trigger2(emlxs_thread_t *ethread, void (*func) (), RING *rp) {
424 
425 	/*
426 	 * If the thread lock can be acquired, it is in one of these states:
427 	 * 1. Thread not started. 2. Thread asleep. 3. Thread busy. 4. Thread
428 	 * ended.
429 	 */
430 	if (!(ethread->flags & EMLXS_THREAD_INITD)) {
431 		return;
432 	}
433 	mutex_enter(&ethread->lock);
434 
435 	if (ethread->flags & EMLXS_THREAD_ENDED) {
436 		return;
437 	}
438 	while (!(ethread->flags & EMLXS_THREAD_STARTED)) {
439 		mutex_exit(&ethread->lock);
440 		delay(drv_usectohz(10000));
441 		mutex_enter(&ethread->lock);
442 
443 		if (ethread->flags & EMLXS_THREAD_ENDED) {
444 			return;
445 		}
446 	}
447 
448 	ethread->flags |= EMLXS_THREAD_TRIGGERED;
449 	ethread->func = func;
450 	ethread->arg1 = (void *) rp;
451 	ethread->arg2 = NULL;
452 
453 	if (ethread->flags & EMLXS_THREAD_ASLEEP) {
454 		cv_signal(&ethread->cv_flag);
455 	}
456 	mutex_exit(&ethread->lock);
457 
458 	return;
459 
460 } /* emlxs_thread_trigger2() */
461