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
oplmsu_link_upath(upath_t * add_upath)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
oplmsu_unlink_upath(upath_t * del_upath)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
oplmsu_link_lpath(lpath_t * add_lpath)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
oplmsu_unlink_lpath(lpath_t * del_lpath)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
oplmsu_link_high_primsg(mblk_t ** first,mblk_t ** last,mblk_t * add_msg)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
oplmsu_check_lpath_usable(void)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 *
oplmsu_search_upath_info(int path_no)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
oplmsu_iocack(queue_t * q,mblk_t * mp,int errno)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
oplmsu_delete_upath_info(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
oplmsu_set_ioctl_path(lpath_t * lpath,queue_t * hndl_queue,mblk_t * mp)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
oplmsu_clear_ioctl_path(lpath_t * lpath)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
oplmsu_get_inst_status(void)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 *
oplmsu_search_standby(void)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
oplmsu_search_min_stop_path(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
oplmsu_get_pathnum(void)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
oplmsu_cmn_put_xoffxon(queue_t * queue,int data)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
oplmsu_cmn_putxoff_standby(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
oplmsu_cmn_set_mflush(mblk_t * mp)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
oplmsu_cmn_set_upath_sts(upath_t * upath,int sts,int prev_sts,ulong_t trad_sts)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
oplmsu_cmn_allocmb(queue_t * q,mblk_t * mp,mblk_t ** nmp,size_t size,int rw_flag)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
oplmsu_cmn_copymb(queue_t * q,mblk_t * mp,mblk_t ** nmp,mblk_t * cmp,int rw_flag)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
oplmsu_cmn_bufcall(queue_t * q,mblk_t * mp,size_t size,int rw_flag)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
oplmsu_cmn_prechg(queue_t * q,mblk_t * mp,int rw_flag,mblk_t ** term_mp,int * term_ioctl,int * term_stat)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
oplmsu_stop_prechg(mblk_t ** term_mp,int * term_ioctl,int * term_stat)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
oplmsu_cmn_prechg_termio(queue_t * q,mblk_t * mp,int rw_flag,int prev_flag,mblk_t ** term_mp,int * term_stat)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
oplmsu_cmn_pullup_msg(queue_t * q,mblk_t * mp)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
oplmsu_cmn_wakeup(queue_t * q)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
oplmsu_cmn_bufcb(void * arg)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
oplmsu_wbufcb_posthndl(ctrl_t * ctrl)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
oplmsu_wcmn_chknode(queue_t * q,int node,mblk_t * mp)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
oplmsu_wcmn_flush_hndl(queue_t * q,mblk_t * mp,krw_t rw)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
oplmsu_wcmn_through_hndl(queue_t * q,mblk_t * mp,int pri_flag,krw_t rw)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 *
oplmsu_wcmn_high_getq(queue_t * uwq)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
oplmsu_wcmn_norm_putbq(queue_t * uwq,mblk_t * mp,queue_t * dq)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
oplmsu_wcmn_high_qenable(queue_t * q,krw_t rw)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
oplmsu_rcmn_flush_hndl(queue_t * q,mblk_t * mp)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
oplmsu_rcmn_through_hndl(queue_t * q,mblk_t * mp,int pri_flag)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
oplmsu_rcmn_high_qenable(queue_t * q)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
oplmsu_cmn_trace(queue_t * q,mblk_t * mp,int op)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
oplmsu_cmn_msglog(mblk_t * mp,int direction)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
oplmsu_cmn_prt_pathname(dev_info_t * dip)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