xref: /titanic_51/usr/src/uts/sun4u/opl/io/oplmsu/oplmsu_cmn_func.c (revision 07d06da50d310a325b457d6330165aebab1e0064)
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  * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006
23  */
24 
25 #include <sys/errno.h>
26 #include <sys/modctl.h>
27 #include <sys/stat.h>
28 #include <sys/kmem.h>
29 #include <sys/ksynch.h>
30 #include <sys/stream.h>
31 #include <sys/stropts.h>
32 #include <sys/termio.h>
33 #include <sys/ddi.h>
34 #include <sys/file.h>
35 #include <sys/disp.h>
36 #include <sys/sunddi.h>
37 #include <sys/sunldi.h>
38 #include <sys/sunndi.h>
39 #include <sys/strsun.h>
40 #include <sys/oplmsu/oplmsu.h>
41 #include <sys/oplmsu/oplmsu_proto.h>
42 
43 /*
44  * Link upper_path_table structure
45  *
46  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
47  *  -. uinst_t->lock   : M [RW_WRITER]
48  *  -. uinst_t->u_lock : M
49  *  -. uinst_t->l_lock : A
50  *  -. uinst_t->c_lock : A
51  */
52 void
53 oplmsu_link_upath(upath_t *add_upath)
54 {
55 
56 	ASSERT(add_upath != NULL);
57 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
58 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
59 
60 	if (oplmsu_uinst->first_upath == NULL) {
61 		oplmsu_uinst->first_upath = add_upath;
62 		add_upath->u_prev = NULL;
63 	} else {
64 		upath_t	*last_upath;
65 
66 		last_upath = oplmsu_uinst->last_upath;
67 		last_upath->u_next = add_upath;
68 		add_upath->u_prev = last_upath;
69 	}
70 
71 	oplmsu_uinst->last_upath = add_upath;
72 	add_upath->u_next = NULL;
73 }
74 
75 /*
76  * Unlink upper_path_table structure
77  *
78  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
79  *  -. uinst_t->lock   : M [RW_WRITER]
80  *  -. uinst_t->u_lock : P
81  *  -. uinst_t->l_lock : P
82  *  -. uinst_t->c_lock : P
83  */
84 void
85 oplmsu_unlink_upath(upath_t *del_upath)
86 {
87 	upath_t **first, **last;
88 
89 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
90 
91 	first = &oplmsu_uinst->first_upath;
92 	last = &oplmsu_uinst->last_upath;
93 
94 	if ((*first != del_upath) && (*last != del_upath)) {
95 		del_upath->u_prev->u_next = del_upath->u_next;
96 		del_upath->u_next->u_prev = del_upath->u_prev;
97 	} else {
98 		if (*first == del_upath) {
99 			*first = (*first)->u_next;
100 			if (*first) {
101 				(*first)->u_prev = NULL;
102 			}
103 		}
104 
105 		if (*last == del_upath) {
106 			*last = (*last)->u_prev;
107 			if (*last) {
108 				(*last)->u_next = NULL;
109 			}
110 		}
111 	}
112 
113 	del_upath->u_next = NULL;
114 	del_upath->u_prev = NULL;
115 }
116 
117 /*
118  * Link lower_path_table structure
119  *
120  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
121  *  -. uinst_t->lock   : M [RW_WRITER]
122  *  -. uinst_t->u_lock : A
123  *  -. uinst_t->l_lock : M
124  *  -. uinst_t->c_lock : A
125  */
126 void
127 oplmsu_link_lpath(lpath_t *add_lpath)
128 {
129 
130 	ASSERT(add_lpath != NULL);
131 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
132 
133 	if (oplmsu_uinst->first_lpath == NULL) {
134 		oplmsu_uinst->first_lpath = add_lpath;
135 		add_lpath->l_prev = NULL;
136 	} else {
137 		lpath_t	*last_lpath;
138 
139 		last_lpath = oplmsu_uinst->last_lpath;
140 		last_lpath->l_next = add_lpath;
141 		add_lpath->l_prev = last_lpath;
142 	}
143 
144 	oplmsu_uinst->last_lpath = add_lpath;
145 	add_lpath->l_next = NULL;
146 }
147 
148 /*
149  * Unlink lower_path_table structure
150  *
151  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
152  *  -. uinst_t->lock   : M [RW_WRITER]
153  *  -. uinst_t->u_lock : P
154  *  -. uinst_t->l_lock : P
155  *  -. uinst_t->c_lock : P
156  */
157 void
158 oplmsu_unlink_lpath(lpath_t *del_lpath)
159 {
160 	lpath_t **first, **last;
161 
162 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
163 
164 	first = &oplmsu_uinst->first_lpath;
165 	last = &oplmsu_uinst->last_lpath;
166 
167 	if ((*first != del_lpath) && (*last != del_lpath)) {
168 		del_lpath->l_prev->l_next = del_lpath->l_next;
169 		del_lpath->l_next->l_prev = del_lpath->l_prev;
170 	} else {
171 		if (*first == del_lpath) {
172 			*first = (*first)->l_next;
173 			if (*first) {
174 				(*first)->l_prev = NULL;
175 			}
176 		}
177 
178 		if (*last == del_lpath) {
179 			*last = (*last)->l_prev;
180 			if (*last) {
181 				(*last)->l_next = NULL;
182 			}
183 		}
184 	}
185 
186 	del_lpath->l_next = NULL;
187 	del_lpath->l_prev = NULL;
188 }
189 
190 /*
191  * Link msgb structure of high priority
192  *
193  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
194  *  -. uinst_t->lock   : M [RW_READER]
195  *  -. uinst_t->u_lock : A
196  *  -. uinst_t->l_lock : A [It depends on caller]
197  *  -. uinst_t->c_lock : A [It depends on caller]
198  */
199 void
200 oplmsu_link_high_primsg(mblk_t **first, mblk_t **last, mblk_t *add_msg)
201 {
202 
203 	ASSERT(add_msg != NULL);
204 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
205 
206 	if (*first == NULL) {
207 		*first = add_msg;
208 		add_msg->b_prev = NULL;
209 	} else {
210 		(*last)->b_next = add_msg;
211 		add_msg->b_prev = *last;
212 	}
213 
214 	*last = add_msg;
215 	add_msg->b_next = NULL;
216 }
217 
218 /*
219  * Check whether lower path is usable by lower path info table address
220  *
221  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
222  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
223  *  -. uinst_t->u_lock : A
224  *  -. uinst_t->l_lock : M
225  *  -. uinst_t->c_lock : P
226  */
227 int
228 oplmsu_check_lpath_usable(void)
229 {
230 	lpath_t	*lpath;
231 	int	rval = SUCCESS;
232 
233 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
234 	ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock));
235 
236 	lpath = oplmsu_uinst->first_lpath;
237 	while (lpath) {
238 		if ((lpath->hndl_uqueue != NULL) || (lpath->hndl_mp != NULL)) {
239 			rval = BUSY;
240 			break;
241 		}
242 		lpath = lpath->l_next;
243 	}
244 	return (rval);
245 }
246 
247 /*
248  * Search upath_t by path number
249  *
250  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
251  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
252  *  -. uinst_t->u_lock : M
253  *  -. uinst_t->l_lock : A
254  *  -. uinst_t->c_lock : P
255  */
256 upath_t	*
257 oplmsu_search_upath_info(int path_no)
258 {
259 	upath_t	*upath;
260 
261 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
262 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
263 
264 	upath = oplmsu_uinst->first_upath;
265 	while (upath) {
266 		if (upath->path_no == path_no) {
267 			break;
268 		}
269 		upath = upath->u_next;
270 	}
271 	return (upath);
272 }
273 
274 /*
275  * Send M_IOCACK(or M_IOCNAK) message to stream
276  *
277  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
278  *  -. uinst_t->lock   : P
279  *  -. uinst_t->u_lock : P
280  *  -. uinst_t->l_lock : P
281  *  -. uinst_t->c_lock : P
282  */
283 void
284 oplmsu_iocack(queue_t *q, mblk_t *mp, int errno)
285 {
286 	struct iocblk	*iocp = NULL;
287 
288 	ASSERT(mp != NULL);
289 
290 	iocp = (struct iocblk *)mp->b_rptr;
291 	iocp->ioc_error = errno;
292 
293 	if (errno) {	/* Error */
294 		mp->b_datap->db_type = M_IOCNAK;
295 		iocp->ioc_rval = FAILURE;
296 
297 		OPLMSU_TRACE(q, mp, MSU_TRC_UO);
298 		qreply(q, mp);
299 	} else {	/* Good */
300 		mp->b_datap->db_type = M_IOCACK;
301 		iocp->ioc_rval = SUCCESS;
302 
303 		OPLMSU_TRACE(q, mp, MSU_TRC_UO);
304 		qreply(q, mp);
305 	}
306 }
307 
308 /*
309  * Delete all upath_t
310  *
311  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
312  *  -. uinst_t->lock   : M [RW_WRITER]
313  *  -. uinst_t->u_lock : M
314  *  -. uinst_t->l_lock : A
315  *  -. uinst_t->c_lock : A
316  */
317 void
318 oplmsu_delete_upath_info(void)
319 {
320 	upath_t	*upath, *next_upath;
321 
322 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
323 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
324 
325 	upath = oplmsu_uinst->first_upath;
326 	oplmsu_uinst->first_upath = NULL;
327 	oplmsu_uinst->last_upath = NULL;
328 
329 	while (upath) {
330 		next_upath = upath->u_next;
331 		kmem_free(upath, sizeof (upath_t));
332 		upath = next_upath;
333 	}
334 }
335 
336 /*
337  * Set queue and ioctl to lpath_t
338  *
339  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
340  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
341  *  -. uinst_t->u_lock : A
342  *  -. uinst_t->l_lock : M
343  *  -. uinst_t->c_lock : P
344  */
345 int
346 oplmsu_set_ioctl_path(lpath_t *lpath, queue_t *hndl_queue, mblk_t *mp)
347 {
348 	int	rval = SUCCESS;
349 
350 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
351 	ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock));
352 
353 	if ((lpath->hndl_uqueue == NULL) && (lpath->hndl_mp == NULL) &&
354 	    (lpath->sw_flag == 0)) {
355 		if ((lpath->status == MSU_EXT_NOTUSED) ||
356 		    (lpath->status == MSU_EXT_ACTIVE_CANDIDATE) ||
357 		    (lpath->status == MSU_SETID_NU)) {
358 			if (hndl_queue == NULL) {
359 				lpath->hndl_uqueue = hndl_queue;
360 			} else {
361 				lpath->hndl_uqueue = WR(hndl_queue);
362 			}
363 			lpath->hndl_mp = mp;
364 		} else {
365 			rval = BUSY;
366 		}
367 	} else {
368 		rval = BUSY;
369 	}
370 	return (rval);
371 }
372 
373 /*
374  * Clear queue and ioctl to lpath_t
375  *
376  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
377  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
378  *  -. uinst_t->u_lock : A
379  *  -. uinst_t->l_lock : M
380  *  -. uinst_t->c_lock : P
381  */
382 void
383 oplmsu_clear_ioctl_path(lpath_t *lpath)
384 {
385 
386 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
387 	ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock));
388 
389 	lpath->hndl_uqueue = NULL;
390 	lpath->hndl_mp = NULL;
391 }
392 
393 /*
394  * Get instanse status from status of upath_t
395  *
396  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
397  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
398  *  -. uinst_t->u_lock : M
399  *  -. uinst_t->l_lock : A
400  *  -. uinst_t->c_lock : P
401  */
402 int
403 oplmsu_get_inst_status(void)
404 {
405 	upath_t	*upath;
406 	int	sts, pre_sts = INST_STAT_UNCONFIGURED;
407 
408 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
409 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
410 
411 	upath = oplmsu_uinst->first_upath;
412 	while (upath) {
413 		if (((upath->status == MSU_PSTAT_ACTIVE) &&
414 		    (upath->traditional_status == MSU_ACTIVE)) ||
415 		    ((upath->status == MSU_PSTAT_STANDBY) &&
416 		    (upath->traditional_status == MSU_STANDBY))) {
417 			sts = INST_STAT_ONLINE;
418 		} else if (((upath->status == MSU_PSTAT_STOP) &&
419 		    (upath->traditional_status == MSU_STOP)) ||
420 		    ((upath->status == MSU_PSTAT_FAIL) &&
421 		    (upath->traditional_status == MSU_FAIL))) {
422 			sts = INST_STAT_OFFLINE;
423 		} else if (((upath->status == MSU_PSTAT_DISCON) &&
424 		    (upath->traditional_status == MSU_DISCON)) ||
425 		    ((upath->status == MSU_PSTAT_EMPTY) &&
426 		    (upath->traditional_status == MSU_EMPTY))) {
427 			sts = INST_STAT_UNCONFIGURED;
428 		} else {
429 			sts = INST_STAT_BUSY;
430 		}
431 
432 		if (pre_sts > sts) {
433 			pre_sts = sts;
434 		}
435 		upath = upath->u_next;
436 	}
437 	return (pre_sts);
438 }
439 
440 /*
441  * Search path of "online:standby" status
442  *
443  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
444  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
445  *  -. uinst_t->u_lock : M
446  *  -. uinst_t->l_lock : A
447  *  -. uinst_t->c_lock : P
448  */
449 upath_t	*
450 oplmsu_search_standby(void)
451 {
452 	upath_t	*upath, *altn_upath = NULL;
453 	int	max_pathnum = UNDEFINED;
454 
455 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
456 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
457 
458 	upath = oplmsu_uinst->first_upath;
459 	while (upath) {
460 		if ((upath->status == MSU_PSTAT_STANDBY) &&
461 		    (upath->traditional_status == MSU_STANDBY) &&
462 		    (upath->lpath != NULL)) {
463 			if ((max_pathnum == UNDEFINED) ||
464 			    (max_pathnum > upath->path_no)) {
465 				max_pathnum = upath->path_no;
466 				altn_upath = upath;
467 			}
468 		}
469 		upath = upath->u_next;
470 	}
471 	return (altn_upath);
472 }
473 
474 /*
475  * Search path of "offline:stop" status, and minimum path number
476  *
477  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
478  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
479  *  -. uinst_t->u_lock : M
480  *  -. uinst_t->l_lock : P
481  *  -. uinst_t->c_lock : P
482  */
483 void
484 oplmsu_search_min_stop_path(void)
485 {
486 	upath_t	*upath, *min_upath;
487 	lpath_t	*lpath;
488 	int	min_no = UNDEFINED;
489 	int	active_flag = 0;
490 
491 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
492 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
493 
494 	upath = oplmsu_uinst->first_upath;
495 	while (upath) {
496 		if ((upath->status == MSU_PSTAT_ACTIVE) &&
497 		    (upath->traditional_status == MSU_ACTIVE)) {
498 			active_flag = 1;
499 			break;
500 		} else if ((upath->status == MSU_PSTAT_STOP) &&
501 		    (upath->traditional_status == MSU_STOP)) {
502 			if (upath->lpath != NULL) {
503 				if ((min_no == UNDEFINED) ||
504 				    (upath->path_no < min_no)) {
505 					lpath = upath->lpath;
506 					mutex_enter(&oplmsu_uinst->l_lock);
507 					if (lpath->status == MSU_EXT_NOTUSED) {
508 						min_upath = upath;
509 						min_no = upath->path_no;
510 					}
511 					mutex_exit(&oplmsu_uinst->l_lock);
512 				}
513 			}
514 		}
515 		upath = upath->u_next;
516 	}
517 
518 	if (active_flag == 0) {
519 		lpath = min_upath->lpath;
520 		mutex_enter(&oplmsu_uinst->l_lock);
521 		lpath->src_upath = NULL;
522 		lpath->status = MSU_EXT_ACTIVE_CANDIDATE;
523 		mutex_exit(&oplmsu_uinst->l_lock);
524 	}
525 }
526 
527 /*
528  * Get the total number of serial paths
529  *
530  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
531  *  -. uinst_t->lock   : M [RW_WRITER]
532  *  -. uinst_t->u_lock : M
533  *  -. uinst_t->l_lock : A
534  *  -. uinst_t->c_lock : A
535  */
536 int
537 oplmsu_get_pathnum(void)
538 {
539 	upath_t	*upath;
540 	int	total_num = 0;
541 
542 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
543 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
544 
545 	if (oplmsu_uinst->first_upath != NULL) {
546 		upath = oplmsu_uinst->first_upath;
547 		while (upath) {
548 			total_num++;
549 			upath = upath->u_next;
550 		}
551 	}
552 	return (total_num);
553 }
554 
555 /*
556  * Put XOFF/ XON message on write queue
557  *
558  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
559  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
560  *  -. uinst_t->u_lock : A
561  *  -. uinst_t->l_lock : A
562  *  -. uinst_t->c_lock : A
563  */
564 int
565 oplmsu_cmn_put_xoffxon(queue_t *queue, int data)
566 {
567 	mblk_t	*mp;
568 	int	rval = SUCCESS;
569 
570 	/* Send M_START */
571 	if ((mp = allocb(0, BPRI_LO)) != NULL) {
572 		mp->b_datap->db_type = M_START;
573 		(void) putq(queue, mp);
574 
575 		/* Send M_DATA(XOFF, XON) */
576 		if ((mp = allocb(sizeof (int), BPRI_LO)) != NULL) {
577 			*(uint_t *)mp->b_rptr = data;
578 			mp->b_wptr = mp->b_rptr + sizeof (int);
579 			(void) putq(queue, mp);
580 		} else {
581 			rval = FAILURE;
582 		}
583 	} else {
584 		rval = FAILURE;
585 	}
586 	return (rval);
587 }
588 
589 /*
590  * Put XOFF message on write queue for all standby paths
591  *
592  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
593  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
594  *  -. uinst_t->u_lock : M
595  *  -. uinst_t->l_lock : M
596  *  -. uinst_t->c_lock : P
597  */
598 void
599 oplmsu_cmn_putxoff_standby(void)
600 {
601 	upath_t	*upath;
602 	lpath_t	*lpath;
603 
604 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
605 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
606 	ASSERT(MUTEX_HELD(&oplmsu_uinst->l_lock));
607 
608 	upath = oplmsu_uinst->first_upath;
609 	while (upath) {
610 		lpath = upath->lpath;
611 		if ((upath->status != MSU_PSTAT_STANDBY) ||
612 		    (lpath == NULL)) {
613 			upath = upath->u_next;
614 			continue;
615 		}
616 
617 		(void) oplmsu_cmn_put_xoffxon(
618 		    WR(lpath->lower_queue), MSU_XOFF_4);
619 		upath = upath->u_next;
620 	}
621 }
622 
623 /*
624  * Set M_FLUSH message
625  *
626  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
627  *  -. uinst_t->lock   : A [RW_READER or RW_WRITER]
628  *  -. uinst_t->u_lock : A
629  *  -. uinst_t->l_lock : A
630  *  -. uinst_t->c_lock : A
631  */
632 void
633 oplmsu_cmn_set_mflush(mblk_t *mp)
634 {
635 
636 	mp->b_datap->db_type = M_FLUSH;
637 	*mp->b_rptr = FLUSHW;
638 	mp->b_wptr = mp->b_rptr + sizeof (char);
639 }
640 
641 /*
642  * Set status informations of upath_t
643  *
644  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
645  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
646  *  -. uinst_t->u_lock : M
647  *  -. uinst_t->l_lock : A
648  *  -. uinst_t->c_lock : A
649  */
650 void
651 oplmsu_cmn_set_upath_sts(upath_t *upath, int sts, int prev_sts,
652     ulong_t trad_sts)
653 {
654 
655 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
656 	ASSERT(MUTEX_HELD(&oplmsu_uinst->u_lock));
657 
658 	upath->status = sts;
659 	upath->prev_status = prev_sts;
660 	upath->traditional_status = trad_sts;
661 }
662 
663 /*
664  * Allocate a message block
665  *
666  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
667  *  -. uinst_t->lock   : M [RW_READER]
668  *  -. uinst_t->u_lock : A
669  *  -. uinst_t->l_lock : P
670  *  -. uinst_t->c_lock : P
671  */
672 int
673 oplmsu_cmn_allocmb(queue_t *q, mblk_t *mp, mblk_t **nmp, size_t size,
674     int rw_flag)
675 {
676 	int	rval = SUCCESS;
677 
678 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
679 
680 	if ((*nmp = (mblk_t *)allocb(size, BPRI_LO)) == NULL) {
681 		oplmsu_cmn_bufcall(q, mp, size, rw_flag);
682 		rval = FAILURE;
683 	} else {
684 		(*nmp)->b_wptr = (*nmp)->b_rptr + size;
685 	}
686 	return (rval);
687 }
688 
689 /*
690  * Copy a message
691  *
692  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
693  *  -. uinst_t->lock   : M [RW_READER]
694  *  -. uinst_t->u_lock : A
695  *  -. uinst_t->l_lock : P
696  *  -. uinst_t->c_lock : P
697  */
698 int
699 oplmsu_cmn_copymb(queue_t *q, mblk_t *mp, mblk_t **nmp, mblk_t *cmp,
700     int rw_flag)
701 {
702 	int	rval = SUCCESS;
703 
704 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
705 
706 	if ((*nmp = copymsg(cmp)) == NULL) {
707 		oplmsu_cmn_bufcall(q, mp, msgsize(cmp), rw_flag);
708 		rval = FAILURE;
709 	}
710 	return (rval);
711 }
712 
713 /*
714  * bufcall request
715  *
716  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
717  *  -. uinst_t->lock   : M [RW_READER]
718  *  -. uinst_t->u_lock : A
719  *  -. uinst_t->l_lock : P
720  *  -. uinst_t->c_lock : P
721  */
722 void
723 oplmsu_cmn_bufcall(queue_t *q, mblk_t *mp, size_t size, int rw_flag)
724 {
725 
726 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
727 
728 	if (rw_flag == MSU_WRITE_SIDE) {
729 		ctrl_t	*ctrl;
730 
731 		(void) putbq(q, mp);
732 
733 		mutex_enter(&oplmsu_uinst->c_lock);
734 		ctrl = (ctrl_t *)q->q_ptr;
735 		if (ctrl->wbuf_id != 0) {
736 			mutex_exit(&oplmsu_uinst->c_lock);
737 			return;
738 		}
739 
740 		ctrl->wbuftbl->q = q;
741 		ctrl->wbuftbl->rw_flag = rw_flag;
742 		ctrl->wbuf_id = bufcall(size, BPRI_LO, oplmsu_cmn_bufcb,
743 		    (void *)ctrl->wbuftbl);
744 
745 		if (ctrl->wbuf_id == 0) {
746 			if (ctrl->wtout_id != 0) {
747 				mutex_exit(&oplmsu_uinst->c_lock);
748 				return;
749 			}
750 
751 			ctrl->wtout_id = timeout(oplmsu_cmn_bufcb,
752 			    (void *)ctrl->wbuftbl, drv_usectohz(MSU_TM_500MS));
753 		}
754 		mutex_exit(&oplmsu_uinst->c_lock);
755 	} else if (rw_flag == MSU_READ_SIDE) {
756 		lpath_t	*lpath;
757 		mblk_t	*wrk_msg;
758 
759 		mutex_enter(&oplmsu_uinst->l_lock);
760 		lpath = (lpath_t *)q->q_ptr;
761 		if (mp->b_datap->db_type >= QPCTL) {
762 			if (lpath->first_lpri_hi == NULL) {
763 				lpath->last_lpri_hi = mp;
764 				mp->b_next = NULL;
765 			} else {
766 				wrk_msg = lpath->first_lpri_hi;
767 				wrk_msg->b_prev = mp;
768 				mp->b_next = wrk_msg;
769 			}
770 			mp->b_prev = NULL;
771 			lpath->first_lpri_hi = mp;
772 		} else {
773 			(void) putbq(q, mp);
774 		}
775 
776 		if (lpath->rbuf_id != 0) {
777 			mutex_exit(&oplmsu_uinst->l_lock);
778 			return;
779 		}
780 
781 		lpath->rbuftbl->q = q;
782 		lpath->rbuftbl->rw_flag = rw_flag;
783 		lpath->rbuf_id = bufcall(size, BPRI_LO, oplmsu_cmn_bufcb,
784 		    (void *)lpath->rbuftbl);
785 
786 		if (lpath->rbuf_id == 0) {
787 			if (lpath->rtout_id != 0) {
788 				mutex_exit(&oplmsu_uinst->l_lock);
789 				return;
790 			}
791 
792 			lpath->rtout_id = timeout(oplmsu_cmn_bufcb,
793 			    (void *)lpath->rbuftbl, drv_usectohz(MSU_TM_500MS));
794 		}
795 		mutex_exit(&oplmsu_uinst->l_lock);
796 	}
797 }
798 
799 /*
800  * Previous sequence for active path change
801  *
802  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
803  *  -. uinst_t->lock   : M [RW_READER]
804  *  -. uinst_t->u_lock : A
805  *  -. uinst_t->l_lock : P
806  *  -. uinst_t->c_lock : P
807  */
808 int
809 oplmsu_cmn_prechg(queue_t *q, mblk_t *mp, int rw_flag, mblk_t **term_mp,
810     int *term_ioctl, int *term_stat)
811 {
812 
813 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
814 
815 	if (oplmsu_uinst->tcsets_p != NULL) {
816 		struct iocblk	*iocp;
817 
818 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tcsets_p,
819 		    rw_flag) == -1) {
820 			return (FAILURE);
821 		}
822 
823 		iocp = (struct iocblk *)(*term_mp)->b_rptr;
824 		*term_ioctl = iocp->ioc_cmd;
825 		*term_stat = MSU_WTCS_ACK;
826 	} else if (oplmsu_uinst->tiocmset_p != NULL) {
827 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocmset_p,
828 		    rw_flag) == -1) {
829 			return (FAILURE);
830 		}
831 
832 		*term_ioctl = TIOCMSET;
833 		*term_stat = MSU_WTMS_ACK;
834 	} else if (oplmsu_uinst->tiocspps_p != NULL) {
835 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocspps_p,
836 		    rw_flag) == -1) {
837 			return (FAILURE);
838 		}
839 
840 		*term_ioctl = TIOCSPPS;
841 		*term_stat = MSU_WPPS_ACK;
842 	} else if (oplmsu_uinst->tiocswinsz_p != NULL) {
843 		if (oplmsu_cmn_copymb(q, mp, term_mp,
844 		    oplmsu_uinst->tiocswinsz_p, rw_flag) == -1) {
845 			return (FAILURE);
846 		}
847 
848 		*term_ioctl = TIOCSWINSZ;
849 		*term_stat = MSU_WWSZ_ACK;
850 	} else if (oplmsu_uinst->tiocssoftcar_p != NULL) {
851 		if (oplmsu_cmn_copymb(q, mp, term_mp,
852 		    oplmsu_uinst->tiocssoftcar_p, rw_flag) == -1) {
853 			return (FAILURE);
854 		}
855 
856 		*term_ioctl = TIOCSSOFTCAR;
857 		*term_stat = MSU_WCAR_ACK;
858 	} else {
859 		*term_stat = MSU_WPTH_CHG;
860 		*term_mp = NULL;
861 	}
862 	return (SUCCESS);
863 }
864 
865 /*
866  * Pick up termios to re-set
867  *
868  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
869  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
870  *  -. uinst_t->u_lock : A
871  *  -. uinst_t->l_lock : A
872  *  -. uinst_t->c_lock : A
873  */
874 int
875 oplmsu_stop_prechg(mblk_t **term_mp, int *term_ioctl, int *term_stat)
876 {
877 
878 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
879 
880 	if (oplmsu_uinst->tcsets_p != NULL) {
881 		struct iocblk	*iocp;
882 
883 		if ((*term_mp = copymsg(oplmsu_uinst->tcsets_p)) == NULL) {
884 			return (FAILURE);
885 		}
886 
887 		iocp = (struct iocblk *)(*term_mp)->b_rptr;
888 		*term_ioctl = iocp->ioc_cmd;
889 		*term_stat = MSU_WTCS_ACK;
890 	} else if (oplmsu_uinst->tiocmset_p != NULL) {
891 		if ((*term_mp = copymsg(oplmsu_uinst->tiocmset_p)) == NULL) {
892 			return (FAILURE);
893 		}
894 
895 		*term_ioctl = TIOCMSET;
896 		*term_stat = MSU_WTMS_ACK;
897 	} else if (oplmsu_uinst->tiocspps_p != NULL) {
898 		if ((*term_mp = copymsg(oplmsu_uinst->tiocspps_p)) == NULL) {
899 			return (FAILURE);
900 		}
901 
902 		*term_ioctl = TIOCSPPS;
903 		*term_stat = MSU_WPPS_ACK;
904 	} else if (oplmsu_uinst->tiocswinsz_p != NULL) {
905 		if ((*term_mp = copymsg(oplmsu_uinst->tiocswinsz_p)) == NULL) {
906 			return (FAILURE);
907 		}
908 
909 		*term_ioctl = TIOCSWINSZ;
910 		*term_stat = MSU_WWSZ_ACK;
911 	} else if (oplmsu_uinst->tiocssoftcar_p != NULL) {
912 		if ((*term_mp = copymsg(oplmsu_uinst->tiocssoftcar_p))
913 		    == NULL) {
914 			return (FAILURE);
915 		}
916 
917 		*term_ioctl = TIOCSSOFTCAR;
918 		*term_stat = MSU_WCAR_ACK;
919 	} else {
920 		*term_stat = MSU_WPTH_CHG;
921 		*term_mp = NULL;
922 	}
923 	return (SUCCESS);
924 }
925 
926 /*
927  * Previous sequence for active path change termio
928  *
929  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
930  *  -. uinst_t->lock   : M [RW_READER]
931  *  -. uinst_t->u_lock : A
932  *  -. uinst_t->l_lock : P
933  *  -. uinst_t->c_lock : P
934  */
935 int
936 oplmsu_cmn_prechg_termio(queue_t *q, mblk_t *mp, int rw_flag, int prev_flag,
937     mblk_t **term_mp, int *term_stat)
938 {
939 
940 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
941 
942 	if ((prev_flag == MSU_TIOS_TCSETS) &&
943 	    (oplmsu_uinst->tiocmset_p != NULL)) {
944 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocmset_p,
945 		    rw_flag) == FAILURE) {
946 			return (FAILURE);
947 		}
948 
949 		*term_stat = MSU_WTMS_ACK;
950 	} else if ((prev_flag <= MSU_TIOS_MSET) &&
951 	    (oplmsu_uinst->tiocspps_p != NULL)) {
952 		if (oplmsu_cmn_copymb(q, mp, term_mp, oplmsu_uinst->tiocspps_p,
953 		    rw_flag) == FAILURE) {
954 			return (FAILURE);
955 		}
956 
957 		*term_stat = MSU_WPPS_ACK;
958 	} else if ((prev_flag <= MSU_TIOS_PPS) &&
959 	    (oplmsu_uinst->tiocswinsz_p != NULL)) {
960 		if (oplmsu_cmn_copymb(q, mp, term_mp,
961 		    oplmsu_uinst->tiocswinsz_p, rw_flag) == FAILURE) {
962 			return (FAILURE);
963 		}
964 
965 		*term_stat = MSU_WWSZ_ACK;
966 	} else if ((prev_flag <= MSU_TIOS_WINSZP) &&
967 	    (oplmsu_uinst->tiocssoftcar_p != NULL)) {
968 		if (oplmsu_cmn_copymb(q, mp, term_mp,
969 		    oplmsu_uinst->tiocssoftcar_p, rw_flag) == FAILURE) {
970 			return (FAILURE);
971 		}
972 
973 		*term_stat = MSU_WCAR_ACK;
974 	} else if (prev_flag <= MSU_TIOS_SOFTCAR) {
975 		*term_mp = NULL;
976 		*term_stat = MSU_WPTH_CHG;
977 	}
978 	return (SUCCESS);
979 }
980 
981 /*
982  * Pull up messages
983  *
984  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
985  *  -. uinst_t->lock   : P
986  *  -. uinst_t->u_lock : P
987  *  -. uinst_t->l_lock : P
988  *  -. uinst_t->c_lock : P
989  */
990 int
991 oplmsu_cmn_pullup_msg(queue_t *q, mblk_t *mp)
992 {
993 	mblk_t	*nmp = NULL;
994 
995 	if ((mp != NULL) && (mp->b_cont != NULL) &&
996 	    (mp->b_cont->b_cont != NULL)) {
997 		if ((nmp = msgpullup(mp->b_cont, -1)) == NULL) {
998 			oplmsu_iocack(q, mp, ENOSR);
999 			return (FAILURE);
1000 		} else {
1001 			freemsg(mp->b_cont);
1002 			mp->b_cont = nmp;
1003 		}
1004 	}
1005 	return (SUCCESS);
1006 }
1007 
1008 /*
1009  * Wake up flow control
1010  *
1011  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1012  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
1013  *  -. uinst_t->u_lock : P
1014  *  -. uinst_t->l_lock : P
1015  *  -. uinst_t->c_lock : P
1016  */
1017 void
1018 oplmsu_cmn_wakeup(queue_t *q)
1019 {
1020 	ctrl_t	*ctrl;
1021 
1022 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
1023 
1024 	mutex_enter(&oplmsu_uinst->c_lock);
1025 	ctrl = (ctrl_t *)q->q_ptr;
1026 	if (ctrl->sleep_flag == CV_SLEEP) {
1027 		ctrl->sleep_flag = CV_WAKEUP;
1028 		cv_signal(&ctrl->cvp);
1029 	}
1030 	mutex_exit(&oplmsu_uinst->c_lock);
1031 }
1032 
1033 /*
1034  * bufcall() and timeout() callback entry for read/write stream
1035  *
1036  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1037  *  -. uinst_t->lock   : P
1038  *  -. uinst_t->u_lock : P
1039  *  -. uinst_t->l_lock : P
1040  *  -. uinst_t->c_lock : P
1041  */
1042 void
1043 oplmsu_cmn_bufcb(void *arg)
1044 {
1045 	struct buf_tbl	*buftbl = arg;
1046 	lpath_t		*lpath;
1047 	ctrl_t		*ctrl;
1048 	queue_t		*q;
1049 	int		lq_flag = 0;
1050 
1051 	rw_enter(&oplmsu_uinst->lock, RW_WRITER);
1052 	mutex_enter(&oplmsu_uinst->l_lock);
1053 
1054 	lpath = oplmsu_uinst->first_lpath;
1055 	while (lpath) {
1056 		if ((buftbl == lpath->rbuftbl) &&
1057 		    (buftbl->rw_flag == MSU_READ_SIDE)) {
1058 			if ((lpath->rbuf_id == 0) && (lpath->rtout_id == 0)) {
1059 				mutex_exit(&oplmsu_uinst->l_lock);
1060 				rw_exit(&oplmsu_uinst->lock);
1061 			} else {
1062 				q = lpath->rbuftbl->q;
1063 				lpath->rbuftbl->q = NULL;
1064 				lpath->rbuftbl->rw_flag = UNDEFINED;
1065 
1066 				if (lpath->rbuf_id) {
1067 					lpath->rbuf_id = 0;
1068 				} else {
1069 					lpath->rtout_id = 0;
1070 				}
1071 				mutex_exit(&oplmsu_uinst->l_lock);
1072 
1073 				if (oplmsu_queue_flag == 1) {
1074 					lq_flag = 1;
1075 					oplmsu_queue_flag = 0;
1076 				}
1077 
1078 				rw_exit(&oplmsu_uinst->lock);
1079 				oplmsu_rcmn_high_qenable(q);
1080 
1081 				if (lq_flag == 1) {
1082 					rw_enter(&oplmsu_uinst->lock,
1083 					    RW_WRITER);
1084 					oplmsu_queue_flag = 1;
1085 					rw_exit(&oplmsu_uinst->lock);
1086 				}
1087 			}
1088 			return;
1089 		}
1090 		lpath = lpath->l_next;
1091 	}
1092 	mutex_exit(&oplmsu_uinst->l_lock);
1093 
1094 	mutex_enter(&oplmsu_uinst->c_lock);
1095 	if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) {
1096 		if ((buftbl == ctrl->wbuftbl) &&
1097 		    (buftbl->rw_flag == MSU_WRITE_SIDE)) {
1098 			oplmsu_wbufcb_posthndl(ctrl);
1099 			mutex_exit(&oplmsu_uinst->c_lock);
1100 			rw_exit(&oplmsu_uinst->lock);
1101 			return;
1102 		}
1103 	}
1104 
1105 	if ((ctrl = oplmsu_uinst->meta_ctrl) != NULL) {
1106 		if ((buftbl == ctrl->wbuftbl) &&
1107 		    (buftbl->rw_flag == MSU_WRITE_SIDE)) {
1108 			oplmsu_wbufcb_posthndl(ctrl);
1109 			mutex_exit(&oplmsu_uinst->c_lock);
1110 			rw_exit(&oplmsu_uinst->lock);
1111 			return;
1112 		}
1113 	}
1114 	mutex_exit(&oplmsu_uinst->c_lock);
1115 	rw_exit(&oplmsu_uinst->lock);
1116 }
1117 
1118 /*
1119  * bufcall() or timeout() callback post handling for write stream
1120  *
1121  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1122  *  -. uinst_t->lock   : M [RW_WRITER]
1123  *  -. uinst_t->u_lock : P
1124  *  -. uinst_t->l_lock : P
1125  *  -. uinst_t->c_lock : M
1126  */
1127 void
1128 oplmsu_wbufcb_posthndl(ctrl_t *ctrl)
1129 {
1130 	queue_t	*q;
1131 	int	lq_flag = 0;
1132 
1133 	ASSERT(RW_WRITE_HELD(&oplmsu_uinst->lock));
1134 	ASSERT(MUTEX_HELD(&oplmsu_uinst->c_lock));
1135 
1136 	if ((ctrl->wbuf_id == 0) && (ctrl->wtout_id == 0)) {
1137 		return;
1138 	}
1139 
1140 	q = ctrl->wbuftbl->q;
1141 	ctrl->wbuftbl->q = NULL;
1142 	ctrl->wbuftbl->rw_flag = UNDEFINED;
1143 	if (ctrl->wbuf_id) {
1144 		ctrl->wbuf_id = 0;
1145 	} else {
1146 		ctrl->wtout_id = 0;
1147 	}
1148 
1149 	if (oplmsu_queue_flag == 1) {
1150 		lq_flag = 1;
1151 		oplmsu_queue_flag = 0;
1152 	}
1153 
1154 	mutex_exit(&oplmsu_uinst->c_lock);
1155 	oplmsu_wcmn_high_qenable(q, RW_WRITER);
1156 	mutex_enter(&oplmsu_uinst->c_lock);
1157 
1158 	if (lq_flag == 1) {
1159 		oplmsu_queue_flag = 1;
1160 	}
1161 }
1162 
1163 /*
1164  *	COMMON FUNCTIONS FOR WRITE STREAM
1165  */
1166 
1167 /*
1168  * Check control node and driver privilege
1169  *
1170  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1171  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
1172  *  -. uinst_t->u_lock : A
1173  *  -. uinst_t->l_lock : A
1174  *  -. uinst_t->c_lock : P
1175  */
1176 int
1177 oplmsu_wcmn_chknode(queue_t *q, int node, mblk_t *mp)
1178 {
1179 	struct iocblk	*iocp;
1180 
1181 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
1182 
1183 	mutex_enter(&oplmsu_uinst->c_lock);
1184 	if (((ctrl_t *)q->q_ptr)->node_type != node) {
1185 		mutex_exit(&oplmsu_uinst->c_lock);
1186 		cmn_err(CE_WARN, "oplmsu: chk-node: ctrl node type = %d", node);
1187 		return (EINVAL);
1188 	}
1189 	mutex_exit(&oplmsu_uinst->c_lock);
1190 
1191 	/* Check super-user by oplmsu.conf */
1192 	if (oplmsu_check_su != 0) {
1193 		iocp = (struct iocblk *)mp->b_rptr;
1194 		if (drv_priv(iocp->ioc_cr) != 0) {
1195 			cmn_err(CE_WARN, "oplmsu: chk-node: Permission denied");
1196 			return (EPERM);
1197 		}
1198 	}
1199 	return (SUCCESS);
1200 }
1201 
1202 /*
1203  * Flush handle for write side stream
1204  *
1205  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1206  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
1207  *  -. uinst_t->u_lock : P
1208  *  -. uinst_t->l_lock : P
1209  *  -. uinst_t->c_lock : P
1210  */
1211 void
1212 oplmsu_wcmn_flush_hndl(queue_t *q, mblk_t *mp, krw_t rw)
1213 {
1214 	queue_t	*dst_queue = NULL;
1215 
1216 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
1217 
1218 	if (*mp->b_rptr & FLUSHW) {	/* Write side */
1219 		flushq(q, FLUSHDATA);
1220 	}
1221 
1222 	dst_queue = oplmsu_uinst->lower_queue;
1223 	if (dst_queue == NULL) {
1224 		if (*mp->b_rptr & FLUSHR) {
1225 			flushq(RD(q), FLUSHDATA);
1226 			*mp->b_rptr &= ~FLUSHW;
1227 
1228 			rw_exit(&oplmsu_uinst->lock);
1229 			OPLMSU_TRACE(q, mp, MSU_TRC_UO);
1230 			qreply(q, mp);
1231 			rw_enter(&oplmsu_uinst->lock, rw);
1232 		} else {
1233 			freemsg(mp);
1234 		}
1235 	} else {
1236 		(void) putq(WR(dst_queue), mp);
1237 	}
1238 }
1239 
1240 /*
1241  * Through message handle for write side stream
1242  *
1243  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1244  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
1245  *  -. uinst_t->u_lock : P
1246  *  -. uinst_t->l_lock : P
1247  *  -. uinst_t->c_lock : P
1248  */
1249 int
1250 oplmsu_wcmn_through_hndl(queue_t *q, mblk_t *mp, int pri_flag, krw_t rw)
1251 {
1252 	queue_t	*usr_queue = NULL, *dst_queue = NULL;
1253 	ctrl_t	*ctrl;
1254 
1255 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
1256 
1257 	mutex_enter(&oplmsu_uinst->c_lock);
1258 	if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) {
1259 		usr_queue = ctrl->queue;
1260 		mutex_exit(&oplmsu_uinst->c_lock);
1261 	} else {
1262 		mutex_exit(&oplmsu_uinst->c_lock);
1263 		if (mp->b_datap->db_type == M_IOCTL) {
1264 			rw_exit(&oplmsu_uinst->lock);
1265 			oplmsu_iocack(q, mp, ENODEV);
1266 			rw_enter(&oplmsu_uinst->lock, rw);
1267 		} else {
1268 			freemsg(mp);
1269 		}
1270 		return (SUCCESS);
1271 	}
1272 
1273 	if (oplmsu_uinst->lower_queue != NULL) {
1274 		dst_queue = WR(oplmsu_uinst->lower_queue);
1275 	} else {
1276 		cmn_err(CE_WARN, "!oplmsu: through-lwq: "
1277 		    "Active path doesn't exist");
1278 
1279 		if (mp->b_datap->db_type == M_IOCTL) {
1280 			rw_exit(&oplmsu_uinst->lock);
1281 			oplmsu_iocack(q, mp, ENODEV);
1282 			rw_enter(&oplmsu_uinst->lock, rw);
1283 		} else {
1284 			freemsg(mp);
1285 		}
1286 		return (SUCCESS);
1287 	}
1288 
1289 	if ((usr_queue == WR(q)) || (usr_queue == RD(q))) {
1290 		if (pri_flag == MSU_HIGH) {
1291 			(void) putq(dst_queue, mp);
1292 		} else {
1293 			if (canput(dst_queue)) {
1294 				(void) putq(dst_queue, mp);
1295 			} else {
1296 				oplmsu_wcmn_norm_putbq(WR(q), mp, dst_queue);
1297 				return (FAILURE);
1298 			}
1299 		}
1300 	} else {
1301 		cmn_err(CE_WARN, "oplmsu: through-lwq: "
1302 		    "Inappropriate message for this node");
1303 
1304 		if (mp->b_datap->db_type == M_IOCTL) {
1305 			rw_exit(&oplmsu_uinst->lock);
1306 			oplmsu_iocack(q, mp, ENODEV);
1307 			rw_enter(&oplmsu_uinst->lock, rw);
1308 		} else {
1309 			freemsg(mp);
1310 		}
1311 	}
1312 	return (SUCCESS);
1313 }
1314 
1315 /*
1316  * Get high priority message from buffer for upper write stream
1317  *
1318  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1319  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
1320  *  -. uinst_t->u_lock : A
1321  *  -. uinst_t->l_lock : A
1322  *  -. uinst_t->c_lock : P
1323  */
1324 mblk_t *
1325 oplmsu_wcmn_high_getq(queue_t *uwq)
1326 {
1327 	mblk_t	*mp;
1328 	ctrl_t	*ctrl;
1329 
1330 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
1331 
1332 	mutex_enter(&oplmsu_uinst->c_lock);
1333 	ctrl = (ctrl_t *)uwq->q_ptr;
1334 	mp = ctrl->first_upri_hi;
1335 	if (mp != NULL) {
1336 		if (mp->b_next == NULL) {
1337 			ctrl->first_upri_hi = NULL;
1338 			ctrl->last_upri_hi = NULL;
1339 		} else {
1340 			ctrl->first_upri_hi = mp->b_next;
1341 			mp->b_next->b_prev = NULL;
1342 			mp->b_next = NULL;
1343 		}
1344 		mp->b_prev = NULL;
1345 	}
1346 	mutex_exit(&oplmsu_uinst->c_lock);
1347 	return (mp);
1348 }
1349 
1350 /*
1351  * putbq() function for normal priority message of write stream
1352  *
1353  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1354  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
1355  *  -. uinst_t->u_lock : A
1356  *  -. uinst_t->l_lock : P
1357  *  -. uinst_t->c_lock : P
1358  */
1359 void
1360 oplmsu_wcmn_norm_putbq(queue_t *uwq, mblk_t *mp, queue_t *dq)
1361 {
1362 	lpath_t	*lpath;
1363 
1364 	ASSERT(mp != NULL);
1365 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
1366 
1367 	mutex_enter(&oplmsu_uinst->l_lock);
1368 	lpath = (lpath_t *)dq->q_ptr;
1369 	lpath->uwq_flag = 1;
1370 	lpath->uwq_queue = uwq;
1371 	mutex_exit(&oplmsu_uinst->l_lock);
1372 	(void) putbq(uwq, mp);
1373 }
1374 
1375 /*
1376  * Restart queuing for high priority message of write stream when flow control
1377  * failed
1378  *
1379  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1380  *  -. uinst_t->lock   : M [RW_READER or RW_WRITER]
1381  *  -. uinst_t->u_lock : P
1382  *  -. uinst_t->l_lock : P
1383  *  -. uinst_t->c_lock : P
1384  */
1385 void
1386 oplmsu_wcmn_high_qenable(queue_t *q, krw_t rw)
1387 {
1388 	mblk_t	*mp;
1389 
1390 	ASSERT(RW_LOCK_HELD(&oplmsu_uinst->lock));
1391 
1392 	if (oplmsu_queue_flag == 1) {
1393 		return;
1394 	}
1395 
1396 	/* Handle high priority message */
1397 	while (mp = oplmsu_wcmn_high_getq(WR(q))) {
1398 		if (mp->b_datap->db_type & M_FLUSH) {
1399 			oplmsu_wcmn_flush_hndl(q, mp, rw);
1400 			continue;
1401 		}
1402 
1403 		if (oplmsu_wcmn_through_hndl(q, mp, MSU_HIGH, rw) == FAILURE) {
1404 			return;
1405 		}
1406 	}
1407 	qenable(WR(q));	/* enable upper write queue */
1408 }
1409 
1410 /*
1411  *	COMMON FUNCTIONS FOR READ STREAM
1412  */
1413 
1414 /*
1415  * Flush handle for read side stream
1416  *
1417  * Requires lock ( M: mandatory  P: prohibited  A: allowed
1418  *  -. uinst_t->lock   : M [RW_READER]
1419  *  -. uinst_t->u_lock : P
1420  *  -. uinst_t->l_lock : P
1421  *  -. uinst_t->c_lock : P
1422  */
1423 void
1424 oplmsu_rcmn_flush_hndl(queue_t *q, mblk_t *mp)
1425 {
1426 	queue_t	*dst_queue = NULL;
1427 	ctrl_t	*ctrl;
1428 
1429 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
1430 
1431 	if (*mp->b_rptr & FLUSHR) {
1432 		/* Remove only data messages from read queue */
1433 		flushq(q, FLUSHDATA);
1434 	}
1435 
1436 	mutex_enter(&oplmsu_uinst->c_lock);
1437 	if ((ctrl = oplmsu_uinst->user_ctrl) != NULL) {
1438 		dst_queue = RD(ctrl->queue);
1439 		mutex_exit(&oplmsu_uinst->c_lock);
1440 
1441 		if (dst_queue != NULL) {
1442 			(void) putq(dst_queue, mp);
1443 		} else {
1444 			if (*mp->b_rptr & FLUSHW) {
1445 				flushq(WR(q), FLUSHDATA);
1446 				*mp->b_rptr &= ~FLUSHR;
1447 
1448 				rw_exit(&oplmsu_uinst->lock);
1449 				OPLMSU_TRACE(q, mp, MSU_TRC_LO);
1450 				qreply(q, mp);
1451 				rw_enter(&oplmsu_uinst->lock, RW_READER);
1452 			} else {
1453 				freemsg(mp);
1454 			}
1455 		}
1456 	} else {
1457 		mutex_exit(&oplmsu_uinst->c_lock);
1458 		if (*mp->b_rptr & FLUSHW) {
1459 			flushq(WR(q), FLUSHDATA);
1460 			*mp->b_rptr &= ~FLUSHR;
1461 
1462 			rw_exit(&oplmsu_uinst->lock);
1463 			OPLMSU_TRACE(q, mp, MSU_TRC_LO);
1464 			qreply(q, mp);
1465 			rw_enter(&oplmsu_uinst->lock, RW_READER);
1466 		} else {
1467 			freemsg(mp);
1468 		}
1469 	}
1470 }
1471 
1472 /*
1473  * Through message handle for read side stream
1474  *
1475  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1476  *  -. uinst_t->lock   : M [RW_READER]
1477  *  -. uinst_t->u_lock : A
1478  *  -. uinst_t->l_lock : P
1479  *  -. uinst_t->c_lock : P
1480  */
1481 int
1482 oplmsu_rcmn_through_hndl(queue_t *q, mblk_t *mp, int pri_flag)
1483 {
1484 	lpath_t	*lpath;
1485 	ctrl_t	*ctrl;
1486 	queue_t	*dst_queue = NULL;
1487 	int	act_flag;
1488 
1489 	ASSERT(RW_READ_HELD(&oplmsu_uinst->lock));
1490 
1491 	mutex_enter(&oplmsu_uinst->l_lock);
1492 	lpath = (lpath_t *)q->q_ptr;
1493 	if (lpath->uinst != NULL) {
1494 		act_flag = ACTIVE_RES;
1495 	} else {
1496 		act_flag = NOT_ACTIVE_RES;
1497 	}
1498 	mutex_exit(&oplmsu_uinst->l_lock);
1499 
1500 	mutex_enter(&oplmsu_uinst->c_lock);
1501 	if (((ctrl = oplmsu_uinst->user_ctrl) != NULL) &&
1502 	    (((mp->b_datap->db_type == M_IOCACK) ||
1503 	    (mp->b_datap->db_type == M_IOCNAK)) || (act_flag == ACTIVE_RES))) {
1504 		dst_queue = RD(ctrl->queue);
1505 	} else {
1506 		mutex_exit(&oplmsu_uinst->c_lock);
1507 		freemsg(mp);
1508 		return (SUCCESS);
1509 	}
1510 
1511 	if (pri_flag == MSU_HIGH) {
1512 		(void) putq(dst_queue, mp);
1513 	} else {
1514 		if (canput(dst_queue)) {
1515 			(void) putq(dst_queue, mp);
1516 		} else {
1517 			/*
1518 			 * Place a normal priority message at the head of
1519 			 * read queue
1520 			 */
1521 
1522 			ctrl = (ctrl_t *)dst_queue->q_ptr;
1523 			ctrl->lrq_flag = 1;
1524 			ctrl->lrq_queue = q;
1525 			mutex_exit(&oplmsu_uinst->c_lock);
1526 			(void) putbq(q, mp);
1527 			return (FAILURE);
1528 		}
1529 	}
1530 	mutex_exit(&oplmsu_uinst->c_lock);
1531 	return (SUCCESS);
1532 }
1533 
1534 /*
1535  * Restart queuing for high priority message of read stream
1536  * when flow control failed
1537  *
1538  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1539  *  -. uinst_t->lock   : P
1540  *  -. uinst_t->u_lock : P
1541  *  -. uinst_t->l_lock : P
1542  *  -. uinst_t->c_lock : P
1543  */
1544 void
1545 oplmsu_rcmn_high_qenable(queue_t *q)
1546 {
1547 	mblk_t		*mp;
1548 	struct iocblk	*iocp = NULL;
1549 	lpath_t		*lpath;
1550 	int		rval;
1551 
1552 	rw_enter(&oplmsu_uinst->lock, RW_READER);
1553 
1554 	for (;;) {	/* Handle high priority message */
1555 		mutex_enter(&oplmsu_uinst->l_lock);
1556 		lpath = (lpath_t *)q->q_ptr;
1557 		if ((mp = lpath->first_lpri_hi) == NULL) {
1558 			mutex_exit(&oplmsu_uinst->l_lock);
1559 			break;
1560 		}
1561 
1562 		if (mp->b_next == NULL) {
1563 			lpath->first_lpri_hi = NULL;
1564 			lpath->last_lpri_hi = NULL;
1565 		} else {
1566 			lpath->first_lpri_hi = mp->b_next;
1567 			mp->b_next->b_prev = NULL;
1568 			mp->b_next = NULL;
1569 		}
1570 		mp->b_prev = NULL;
1571 		mutex_exit(&oplmsu_uinst->l_lock);
1572 
1573 		rval = SUCCESS;
1574 		switch (mp->b_datap->db_type) {
1575 		case M_IOCACK :		/* FALLTHRU */
1576 		case M_IOCNAK :
1577 			iocp = (struct iocblk *)mp->b_rptr;
1578 			switch (iocp->ioc_cmd) {
1579 			case TCSETS :		/* FALLTHRU */
1580 			case TCSETSW :		/* FALLTHRU */
1581 			case TCSETSF :		/* FALLTHRU */
1582 			case TIOCMSET :		/* FALLTHRU */
1583 			case TIOCSPPS :		/* FALLTHRU */
1584 			case TIOCSWINSZ :	/* FALLTHRU */
1585 			case TIOCSSOFTCAR :
1586 				rw_exit(&oplmsu_uinst->lock);
1587 				rval = oplmsu_lrioctl_termios(q, mp);
1588 				rw_enter(&oplmsu_uinst->lock, RW_WRITER);
1589 				break;
1590 
1591 			default :
1592 				rval = oplmsu_rcmn_through_hndl(
1593 				    q, mp, MSU_HIGH);
1594 				if (rval == FAILURE) {
1595 					rw_exit(&oplmsu_uinst->lock);
1596 					return;
1597 				}
1598 			}
1599 			break;
1600 
1601 		case M_ERROR :
1602 			rw_exit(&oplmsu_uinst->lock);
1603 			rval = oplmsu_lrmsg_error(q, mp);
1604 			rw_enter(&oplmsu_uinst->lock, RW_WRITER);
1605 			break;
1606 
1607 		case M_FLUSH :
1608 			oplmsu_rcmn_flush_hndl(q, mp);
1609 			break;
1610 
1611 		default :
1612 			rval = oplmsu_rcmn_through_hndl(q, mp, MSU_HIGH);
1613 			if (rval == FAILURE) {
1614 				rw_exit(&oplmsu_uinst->lock);
1615 				return;
1616 			}
1617 		}
1618 
1619 		if (rval == FAILURE) {
1620 			break;
1621 		}
1622 	}
1623 
1624 	rw_exit(&oplmsu_uinst->lock);
1625 	qenable(q);	/* Enable lower read queue */
1626 }
1627 
1628 #ifdef DEBUG
1629 /*
1630  * Online trace
1631  *
1632  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1633  *  -. uinst_t->lock   : P
1634  *  -. uinst_t->u_lock : P
1635  *  -. uinst_t->l_lock : P
1636  *  -. uinst_t->c_lock : P
1637  */
1638 void
1639 oplmsu_cmn_trace(queue_t *q, mblk_t *mp, int op)
1640 {
1641 	struct iocblk	*iocp;
1642 
1643 	if ((op < MSU_TRC_UI) || (op > MSU_TRC_CLS)) {
1644 		return;
1645 	}
1646 
1647 	mutex_enter(&oplmsu_ltrc_lock);
1648 
1649 	if (oplmsu_debug_mode & MSU_DPRINT_ON) {
1650 		oplmsu_cmn_msglog(mp, op);
1651 	}
1652 
1653 	/* Trace current counter */
1654 	(void) drv_getparm(LBOLT, (void *)&oplmsu_ltrc_ccnt);
1655 
1656 	if (oplmsu_ltrc_cur == oplmsu_ltrc_tail) {
1657 		oplmsu_ltrc_cur = oplmsu_ltrc_top;
1658 	} else {
1659 		oplmsu_ltrc_cur++;
1660 	}
1661 	oplmsu_ltrc_cur->q = q;
1662 	oplmsu_ltrc_cur->mp = mp;
1663 
1664 	switch (op) {
1665 	case MSU_TRC_UI :
1666 		oplmsu_ltrc_cur->op[0] = 'u';
1667 		oplmsu_ltrc_cur->op[1] = 'i';
1668 		break;
1669 
1670 	case MSU_TRC_UO :
1671 		oplmsu_ltrc_cur->op[0] = 'u';
1672 		oplmsu_ltrc_cur->op[1] = 'o';
1673 		break;
1674 
1675 	case MSU_TRC_LI :
1676 		oplmsu_ltrc_cur->op[0] = 'l';
1677 		oplmsu_ltrc_cur->op[1] = 'i';
1678 		break;
1679 
1680 	case MSU_TRC_LO :
1681 		oplmsu_ltrc_cur->op[0] = 'l';
1682 		oplmsu_ltrc_cur->op[1] = 'o';
1683 		break;
1684 
1685 	case MSU_TRC_OPN :
1686 		oplmsu_ltrc_cur->op[0] = 'o';
1687 		oplmsu_ltrc_cur->op[1] = 'p';
1688 		break;
1689 
1690 	case MSU_TRC_CLS :
1691 		oplmsu_ltrc_cur->op[0] = 'c';
1692 		oplmsu_ltrc_cur->op[1] = 'l';
1693 		break;
1694 	}
1695 
1696 	if ((op == MSU_TRC_LI) || (op == MSU_TRC_LO)) {
1697 		mutex_enter(&oplmsu_uinst->l_lock);
1698 		oplmsu_ltrc_cur->pathno = ((lpath_t *)q->q_ptr)->path_no;
1699 		mutex_exit(&oplmsu_uinst->l_lock);
1700 	} else {
1701 		oplmsu_ltrc_cur->pathno = 0;
1702 	}
1703 
1704 	if ((op == MSU_TRC_OPN) || (op == MSU_TRC_CLS)) {
1705 		oplmsu_ltrc_cur->msg_type = 0;
1706 		oplmsu_ltrc_cur->msg_cmd = 0;
1707 		oplmsu_ltrc_cur->data = 0;
1708 
1709 		switch ((ulong_t)mp) {
1710 		case MSU_NODE_USER :
1711 			oplmsu_ltrc_cur->data = MSU_TRC_USER;
1712 			break;
1713 
1714 		case MSU_NODE_META :
1715 			oplmsu_ltrc_cur->data = MSU_TRC_META;
1716 			break;
1717 		}
1718 		oplmsu_ltrc_cur->mp = NULL;
1719 	} else {
1720 		oplmsu_ltrc_cur->msg_type = mp->b_datap->db_type;
1721 		iocp = (struct iocblk *)mp->b_rptr;
1722 		oplmsu_ltrc_cur->msg_cmd = iocp->ioc_cmd;
1723 
1724 		if ((mp->b_datap->db_type == M_IOCTL) ||
1725 		    (mp->b_datap->db_type == M_IOCACK) ||
1726 		    (mp->b_datap->db_type == M_IOCNAK)) {
1727 			oplmsu_ltrc_cur->msg_cmd = iocp->ioc_cmd;
1728 
1729 			if (mp->b_cont != NULL) {
1730 				oplmsu_ltrc_cur->data =
1731 				    (ulong_t)mp->b_cont->b_rptr;
1732 			} else {
1733 				oplmsu_ltrc_cur->data = 0;
1734 			}
1735 		} else {
1736 			oplmsu_ltrc_cur->msg_cmd = 0;
1737 
1738 			if (mp->b_rptr == NULL) {
1739 				oplmsu_ltrc_cur->data = 0;
1740 			} else {
1741 				oplmsu_ltrc_cur->data = *(ulong_t *)mp->b_rptr;
1742 			}
1743 		}
1744 	}
1745 	mutex_exit(&oplmsu_ltrc_lock);
1746 }
1747 
1748 /*
1749  * Display message log to console
1750  *
1751  * Requires Lock (( M: Mandatory, P: Prohibited, A: Allowed ))
1752  *  -. uinst_t->lock   : P
1753  *  -. uinst_t->u_lock : P
1754  *  -. uinst_t->l_lock : P
1755  *  -. uinst_t->c_lock : P
1756  */
1757 void
1758 oplmsu_cmn_msglog(mblk_t *mp, int direction)
1759 {
1760 	uchar_t	*cur = NULL;
1761 	mblk_t	*tmp_mp = NULL;
1762 	ulong_t	len;
1763 	ulong_t	line;
1764 	ulong_t	col;
1765 	ulong_t	row;
1766 	ulong_t	count;
1767 	char	buffer[70];
1768 	char	*bufp;
1769 
1770 	if (mp == NULL) {
1771 		return;
1772 	}
1773 
1774 	switch (direction) {
1775 	case 0:
1776 		cmn_err(CE_NOTE, "!---------- Upper in --------");
1777 		break;
1778 
1779 	case 1:
1780 		cmn_err(CE_NOTE, "!---------- Upper out -------");
1781 		break;
1782 
1783 	case 2:
1784 		cmn_err(CE_NOTE, "!---------- Lower in --------");
1785 		break;
1786 
1787 	case 3:
1788 		cmn_err(CE_NOTE, "!---------- Lower out -------");
1789 		break;
1790 
1791 	default:
1792 		return;
1793 	}
1794 
1795 	for (tmp_mp = mp; tmp_mp; tmp_mp = tmp_mp->b_cont) {
1796 		cmn_err(CE_NOTE, "!db_type = 0x%02x", tmp_mp->b_datap->db_type);
1797 
1798 		len = tmp_mp->b_wptr - tmp_mp->b_rptr;
1799 		line = (len + 31) / 32;
1800 		cur = (uchar_t *)tmp_mp->b_rptr;
1801 		count = 0;
1802 
1803 		for (col = 0; col < line; col++) {
1804 			bufp = buffer;
1805 
1806 			for (row = 0; row < 32; row++) {
1807 				if (row != 0 && (row % 8) == 0) {
1808 					*bufp = ' ';
1809 					bufp++;
1810 				}
1811 				(void) sprintf(bufp, "%02x", *cur);
1812 				bufp += 2;
1813 				cur++;
1814 				count++;
1815 
1816 				if (count >= len) {
1817 					break;
1818 				}
1819 			}
1820 			*bufp = '\0';
1821 			cmn_err(CE_NOTE, "!%s", buffer);
1822 
1823 			if (count >= len) {
1824 				break;
1825 			}
1826 		}
1827 	}
1828 }
1829 
1830 void
1831 oplmsu_cmn_prt_pathname(dev_info_t *dip)
1832 {
1833 	char	pathname[128];
1834 	char	wrkbuf[128];
1835 
1836 	(void) ddi_pathname(dip, wrkbuf);
1837 	*(wrkbuf + strlen(wrkbuf)) = '\0';
1838 	(void) sprintf(pathname, "/devices%s:%c", wrkbuf,
1839 	    'a'+ ddi_get_instance(dip));
1840 
1841 	DBG_PRINT((CE_NOTE, "oplmsu: debug-info: "
1842 	    "Active path change to path => %s", pathname));
1843 }
1844 #endif
1845