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 */
52void
53oplmsu_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 */
84void
85oplmsu_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 */
126void
127oplmsu_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 */
157void
158oplmsu_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 */
199void
200oplmsu_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 */
227int
228oplmsu_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 */
256upath_t	*
257oplmsu_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 */
283void
284oplmsu_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 */
317void
318oplmsu_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 */
345int
346oplmsu_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 */
382void
383oplmsu_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 */
402int
403oplmsu_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 */
449upath_t	*
450oplmsu_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 */
483void
484oplmsu_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 */
536int
537oplmsu_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 */
564int
565oplmsu_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 */
598void
599oplmsu_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 */
632void
633oplmsu_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 */
650void
651oplmsu_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 */
672int
673oplmsu_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 */
698int
699oplmsu_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 */
722void
723oplmsu_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 */
808int
809oplmsu_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 */
874int
875oplmsu_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 */
935int
936oplmsu_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 */
990int
991oplmsu_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 */
1017void
1018oplmsu_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 */
1042void
1043oplmsu_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 */
1127void
1128oplmsu_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 */
1176int
1177oplmsu_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 */
1211void
1212oplmsu_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 */
1249int
1250oplmsu_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 */
1324mblk_t *
1325oplmsu_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 */
1359void
1360oplmsu_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 */
1385void
1386oplmsu_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 */
1423void
1424oplmsu_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 */
1481int
1482oplmsu_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 */
1544void
1545oplmsu_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 */
1638void
1639oplmsu_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 */
1757void
1758oplmsu_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
1830void
1831oplmsu_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