1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006
24 */
25
26 #include <sys/errno.h>
27 #include <sys/modctl.h>
28 #include <sys/stat.h>
29 #include <sys/kmem.h>
30 #include <sys/ksynch.h>
31 #include <sys/stream.h>
32 #include <sys/stropts.h>
33 #include <sys/termio.h>
34 #include <sys/ddi.h>
35 #include <sys/file.h>
36 #include <sys/disp.h>
37 #include <sys/sunddi.h>
38 #include <sys/sunldi.h>
39 #include <sys/sunndi.h>
40 #include <sys/prom_plat.h>
41 #include <sys/oplmsu/oplmsu.h>
42 #include <sys/oplmsu/oplmsu_proto.h>
43
44 /*
45 * LOWER READ SERVICE PROCEDURE
46 */
47
48 /* termios ioctl response received */
49 int
oplmsu_lrioctl_termios(queue_t * lrq,mblk_t * mp)50 oplmsu_lrioctl_termios(queue_t *lrq, mblk_t *mp)
51 {
52 upath_t *upath, *altn_upath = NULL, *stp_upath = NULL;
53 lpath_t *lpath, *altn_lpath = NULL, *stp_lpath = NULL;
54 struct iocblk *iocp, *temp_iocp = NULL;
55 mblk_t *hndl_mp, *nmp = NULL, *fmp = NULL;
56 queue_t *dst_queue;
57 int term_ioctl, term_stat, sts;
58 int ack_flag, termio_flag, chkflag;
59 ulong_t trad_sts;
60
61 rw_enter(&oplmsu_uinst->lock, RW_READER);
62 iocp = (struct iocblk *)mp->b_rptr;
63
64 mutex_enter(&oplmsu_uinst->u_lock);
65 mutex_enter(&oplmsu_uinst->l_lock);
66 lpath = (lpath_t *)lrq->q_ptr;
67 hndl_mp = lpath->hndl_mp;
68
69 upath = oplmsu_search_upath_info(lpath->path_no);
70 trad_sts = upath->traditional_status;
71 mutex_exit(&oplmsu_uinst->l_lock);
72 mutex_exit(&oplmsu_uinst->u_lock);
73
74 if (((iocp->ioc_cmd == TCSETS) && (trad_sts == MSU_WTCS_ACK)) ||
75 ((iocp->ioc_cmd == TCSETSW) && (trad_sts == MSU_WTCS_ACK)) ||
76 ((iocp->ioc_cmd == TCSETSF) && (trad_sts == MSU_WTCS_ACK)) ||
77 ((iocp->ioc_cmd == TIOCMSET) && (trad_sts == MSU_WTMS_ACK)) ||
78 ((iocp->ioc_cmd == TIOCSPPS) && (trad_sts == MSU_WPPS_ACK)) ||
79 ((iocp->ioc_cmd == TIOCSWINSZ) && (trad_sts == MSU_WWSZ_ACK)) ||
80 ((iocp->ioc_cmd == TIOCSSOFTCAR) && (trad_sts == MSU_WCAR_ACK))) {
81 if (mp->b_datap->db_type == M_IOCACK) {
82 ack_flag = ACK_RES;
83 } else {
84 ack_flag = NAK_RES;
85 }
86 } else {
87 rw_exit(&oplmsu_uinst->lock);
88 freemsg(mp);
89 cmn_err(CE_WARN, "oplmsu: lr-termios: "
90 "Status of path is improper");
91 return (SUCCESS);
92 }
93
94 switch (trad_sts) {
95 case MSU_WTCS_ACK :
96 termio_flag = MSU_TIOS_TCSETS;
97 break;
98
99 case MSU_WTMS_ACK :
100 termio_flag = MSU_TIOS_MSET;
101 break;
102
103 case MSU_WPPS_ACK :
104 termio_flag = MSU_TIOS_PPS;
105 break;
106
107 case MSU_WWSZ_ACK :
108 termio_flag = MSU_TIOS_WINSZP;
109 break;
110
111 case MSU_WCAR_ACK :
112 termio_flag = MSU_TIOS_SOFTCAR;
113 break;
114
115 default :
116 termio_flag = MSU_TIOS_END;
117 break;
118 }
119
120 if (hndl_mp == NULL) {
121 switch (trad_sts) {
122 case MSU_WTCS_ACK : /* FALLTHRU */
123 case MSU_WTMS_ACK : /* FALLTHRU */
124 case MSU_WPPS_ACK : /* FALLTHRU */
125 case MSU_WWSZ_ACK : /* FALLTHRU */
126 case MSU_WCAR_ACK :
127 chkflag = MSU_CMD_STOP;
128 break;
129
130 default :
131 chkflag = FAILURE;
132 break;
133 }
134 } else {
135 /* xoff/xon received */
136 if (hndl_mp->b_datap->db_type == M_DATA) {
137 chkflag = MSU_CMD_ACTIVE;
138 } else { /* Normal termios */
139 temp_iocp = (struct iocblk *)hndl_mp->b_rptr;
140 chkflag = temp_iocp->ioc_cmd;
141 }
142 }
143
144 if ((chkflag == MSU_CMD_ACTIVE) || (chkflag == MSU_CMD_STOP)) {
145 if (ack_flag == ACK_RES) { /* M_IOCACK received */
146 ctrl_t *ctrl;
147
148 if (oplmsu_cmn_prechg_termio(lrq, mp, MSU_READ_SIDE,
149 termio_flag, &nmp, &term_stat) == FAILURE) {
150 rw_exit(&oplmsu_uinst->lock);
151 return (FAILURE);
152 }
153
154 OPLMSU_RWLOCK_UPGRADE();
155 mutex_enter(&oplmsu_uinst->u_lock);
156 if (term_stat != MSU_WPTH_CHG) {
157 upath->traditional_status = term_stat;
158 mutex_exit(&oplmsu_uinst->u_lock);
159 rw_exit(&oplmsu_uinst->lock);
160 freemsg(mp);
161
162 OPLMSU_TRACE(RD(lrq), nmp, MSU_TRC_LO);
163
164 /* Continue sending termios ioctls */
165 qreply(RD(lrq), nmp);
166 return (SUCCESS);
167 }
168 freemsg(mp);
169
170 /* Change status of new active path */
171 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_ACTIVE,
172 upath->status, MSU_ACTIVE);
173
174 mutex_enter(&oplmsu_uinst->l_lock);
175 lpath->uinst = oplmsu_uinst;
176 dst_queue = lpath->hndl_uqueue;
177
178 ctrl = oplmsu_uinst->user_ctrl;
179 if ((chkflag == MSU_CMD_ACTIVE) && (hndl_mp != NULL)) {
180 /* Put a message(M_DATA) on a queue */
181 if (ctrl != NULL) {
182 mutex_enter(&oplmsu_uinst->c_lock);
183 (void) putq(RD(ctrl->queue), hndl_mp);
184 mutex_exit(&oplmsu_uinst->c_lock);
185 }
186 }
187
188 oplmsu_clear_ioctl_path(lpath);
189 stp_upath = lpath->src_upath;
190 lpath->src_upath = NULL;
191 lpath->status = MSU_EXT_NOTUSED;
192
193 /* Notify of the active path changing */
194 (void) prom_opl_switch_console(upath->ser_devcb.lsb);
195
196 /* Send XON to notify active path */
197 (void) oplmsu_cmn_put_xoffxon(WR(lrq), MSU_XON_4);
198
199 stp_lpath = stp_upath->lpath;
200 stp_lpath->uinst = NULL;
201 oplmsu_clear_ioctl_path(stp_lpath);
202 stp_lpath->src_upath = NULL;
203 stp_lpath->status = MSU_EXT_NOTUSED;
204
205 /* Change status of stopped or old-active path */
206 if (chkflag == MSU_CMD_STOP) {
207 sts = MSU_PSTAT_STOP;
208 trad_sts = MSU_STOP;
209 } else { /* == MSU_CMD_ACTIVE */
210 sts = MSU_PSTAT_STANDBY;
211 trad_sts = MSU_STANDBY;
212 }
213 oplmsu_cmn_set_upath_sts(stp_upath, sts,
214 stp_upath->status, trad_sts);
215
216 /* Send XOFF to notify all standby paths */
217 oplmsu_cmn_putxoff_standby();
218 oplmsu_uinst->lower_queue = lrq;
219 oplmsu_uinst->inst_status = oplmsu_get_inst_status();
220 mutex_exit(&oplmsu_uinst->l_lock);
221 mutex_exit(&oplmsu_uinst->u_lock);
222
223 /* Change active path of user node */
224 if (ctrl != NULL) {
225 queue_t *temp_queue;
226
227 mutex_enter(&oplmsu_uinst->c_lock);
228 temp_queue = WR(ctrl->queue);
229 mutex_exit(&oplmsu_uinst->c_lock);
230
231 /* Reschedule a queue for service */
232 enableok(temp_queue);
233
234 oplmsu_queue_flag = 0;
235 oplmsu_wcmn_high_qenable(temp_queue, RW_WRITER);
236 }
237 rw_exit(&oplmsu_uinst->lock);
238
239 if (nmp != NULL) {
240 freemsg(nmp);
241 }
242
243 /* Wake up oplmsu_config_stop */
244 mutex_enter(&oplmsu_uinst->l_lock);
245 if (stp_lpath->sw_flag) {
246 stp_lpath->sw_flag = 0;
247 cv_signal(&stp_lpath->sw_cv);
248 }
249 mutex_exit(&oplmsu_uinst->l_lock);
250 return (SUCCESS);
251 } else { /* M_IOCNAK received */
252 mutex_enter(&oplmsu_uinst->u_lock);
253 mutex_enter(&oplmsu_uinst->l_lock);
254 if ((chkflag == MSU_CMD_ACTIVE) &&
255 (lpath->hndl_uqueue == NULL)) {
256 oplmsu_clear_ioctl_path(lpath);
257 stp_upath = lpath->src_upath;
258 lpath->src_upath = NULL;
259 lpath->status = MSU_EXT_NOTUSED;
260 mutex_exit(&oplmsu_uinst->l_lock);
261
262 oplmsu_cmn_set_upath_sts(upath,
263 MSU_PSTAT_STANDBY, upath->status,
264 MSU_STANDBY);
265 mutex_exit(&oplmsu_uinst->u_lock);
266
267 if (hndl_mp != NULL) {
268 freemsg(hndl_mp);
269 }
270
271 OPLMSU_RWLOCK_UPGRADE();
272 mutex_enter(&oplmsu_uinst->u_lock);
273 oplmsu_uinst->inst_status =
274 oplmsu_get_inst_status();
275 mutex_exit(&oplmsu_uinst->u_lock);
276 rw_exit(&oplmsu_uinst->lock);
277 return (SUCCESS);
278 } else if ((chkflag == MSU_CMD_STOP) &&
279 (lpath->src_upath != NULL) &&
280 (lpath->src_upath->lpath->sw_flag)) {
281 /* MSU_CMD_STOP for active path */
282
283 dst_queue = RD(lpath->hndl_uqueue);
284 stp_upath = lpath->src_upath;
285
286 /* Search alternate path from standby paths */
287 altn_upath = oplmsu_search_standby();
288 if (altn_upath == NULL) {
289 altn_upath = upath;
290 }
291
292 mutex_exit(&oplmsu_uinst->l_lock);
293 if (oplmsu_cmn_allocmb(lrq, mp, &fmp,
294 sizeof (char), MSU_READ_SIDE) == FAILURE) {
295 mutex_exit(&oplmsu_uinst->u_lock);
296 rw_exit(&oplmsu_uinst->lock);
297 return (FAILURE);
298 }
299
300 if (oplmsu_cmn_prechg(lrq, mp, MSU_READ_SIDE,
301 &nmp, &term_ioctl, &term_stat) == FAILURE) {
302 mutex_exit(&oplmsu_uinst->u_lock);
303 rw_exit(&oplmsu_uinst->lock);
304 freeb(fmp);
305 return (FAILURE);
306 }
307
308 altn_upath->traditional_status = term_stat;
309 altn_lpath = altn_upath->lpath;
310
311 mutex_enter(&oplmsu_uinst->l_lock);
312 altn_lpath->hndl_mp = hndl_mp;
313 altn_lpath->hndl_uqueue = dst_queue;
314 altn_lpath->src_upath = stp_upath;
315 altn_lpath->status = MSU_EXT_VOID;
316 dst_queue = RD(altn_lpath->lower_queue);
317
318 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL,
319 upath->status, MSU_FAIL);
320
321 oplmsu_clear_ioctl_path(lpath);
322 lpath->src_upath = NULL;
323 lpath->status = MSU_EXT_NOTUSED;
324 mutex_exit(&oplmsu_uinst->l_lock);
325 mutex_exit(&oplmsu_uinst->u_lock);
326
327 OPLMSU_RWLOCK_UPGRADE();
328 mutex_enter(&oplmsu_uinst->u_lock);
329 oplmsu_uinst->inst_status =
330 oplmsu_get_inst_status();
331 mutex_exit(&oplmsu_uinst->u_lock);
332 rw_exit(&oplmsu_uinst->lock);
333 freemsg(mp);
334 oplmsu_cmn_set_mflush(fmp);
335
336 OPLMSU_TRACE(dst_queue, fmp, MSU_TRC_LO);
337 qreply(dst_queue, fmp);
338
339 OPLMSU_TRACE(dst_queue, nmp, MSU_TRC_LO);
340 qreply(dst_queue, nmp);
341 return (SUCCESS);
342 }
343 }
344 } else if ((chkflag == TCSETS) || (chkflag == TCSETSW) ||
345 (chkflag == TCSETSF) || (chkflag == TIOCMSET) ||
346 (chkflag == TIOCSPPS) || (chkflag == TIOCSWINSZ) ||
347 (chkflag == TIOCSSOFTCAR)) {
348 mutex_enter(&oplmsu_uinst->u_lock);
349 mutex_enter(&oplmsu_uinst->l_lock);
350
351 if ((ack_flag == ACK_RES) &&
352 (lpath->hndl_uqueue != NULL)) { /* M_IOCACK received */
353 mutex_exit(&oplmsu_uinst->l_lock);
354 mutex_exit(&oplmsu_uinst->u_lock);
355 if (oplmsu_cmn_copymb(lrq, mp, &nmp, hndl_mp,
356 MSU_READ_SIDE) == FAILURE) {
357 rw_exit(&oplmsu_uinst->lock);
358 return (FAILURE);
359 }
360
361 OPLMSU_RWLOCK_UPGRADE();
362 switch (chkflag) {
363 case TCSETS : /* FALLTHRU */
364 case TCSETSW : /* FALLTHRU */
365 case TCSETSF :
366 if (oplmsu_uinst->tcsets_p != NULL) {
367 freemsg(oplmsu_uinst->tcsets_p);
368 }
369 oplmsu_uinst->tcsets_p = nmp;
370 break;
371
372 case TIOCMSET :
373 if (oplmsu_uinst->tiocmset_p != NULL) {
374 freemsg(oplmsu_uinst->tiocmset_p);
375 }
376 oplmsu_uinst->tiocmset_p = nmp;
377 break;
378
379 case TIOCSPPS :
380 if (oplmsu_uinst->tiocspps_p != NULL) {
381 freemsg(oplmsu_uinst->tiocspps_p);
382 }
383 oplmsu_uinst->tiocspps_p = nmp;
384 break;
385
386 case TIOCSWINSZ :
387 if (oplmsu_uinst->tiocswinsz_p != NULL) {
388 freemsg(oplmsu_uinst->tiocswinsz_p);
389 }
390 oplmsu_uinst->tiocswinsz_p = nmp;
391 break;
392
393 case TIOCSSOFTCAR :
394 if (oplmsu_uinst->tiocssoftcar_p != NULL) {
395 freemsg(oplmsu_uinst->tiocssoftcar_p);
396 }
397 oplmsu_uinst->tiocssoftcar_p = nmp;
398 break;
399 }
400
401 mutex_enter(&oplmsu_uinst->u_lock);
402 mutex_enter(&oplmsu_uinst->l_lock);
403 upath->traditional_status = lpath->status;
404 nmp = lpath->hndl_mp;
405 nmp->b_datap->db_type = M_IOCACK;
406 dst_queue = RD(lpath->hndl_uqueue);
407 bcopy(mp->b_rptr, nmp->b_rptr, sizeof (struct iocblk));
408
409 oplmsu_clear_ioctl_path(lpath);
410 lpath->src_upath = NULL;
411 lpath->status = MSU_EXT_NOTUSED;
412 mutex_exit(&oplmsu_uinst->l_lock);
413 mutex_exit(&oplmsu_uinst->u_lock);
414 freemsg(mp);
415 (void) putq(dst_queue, nmp);
416
417 /* Check sleep flag and wake up thread */
418 oplmsu_cmn_wakeup(dst_queue);
419 rw_exit(&oplmsu_uinst->lock);
420 return (SUCCESS);
421 } else if ((ack_flag == NAK_RES) &&
422 (lpath->hndl_uqueue != NULL)) { /* M_IOCNAK received */
423 upath->traditional_status = lpath->status;
424
425 nmp = lpath->hndl_mp;
426 nmp->b_datap->db_type = M_IOCNAK;
427 dst_queue = RD(lpath->hndl_uqueue);
428
429 oplmsu_clear_ioctl_path(lpath);
430 lpath->src_upath = NULL;
431 lpath->status = MSU_EXT_NOTUSED;
432 mutex_exit(&oplmsu_uinst->l_lock);
433 mutex_exit(&oplmsu_uinst->u_lock);
434 freemsg(mp);
435 (void) putq(dst_queue, nmp);
436
437 /* Check sleep flag and wake up thread */
438 oplmsu_cmn_wakeup(dst_queue);
439 rw_exit(&oplmsu_uinst->lock);
440 return (SUCCESS);
441 }
442 }
443
444 mutex_enter(&oplmsu_uinst->u_lock);
445 switch (upath->status) {
446 case MSU_PSTAT_FAIL :
447 upath->traditional_status = MSU_FAIL;
448 break;
449
450 case MSU_PSTAT_STOP :
451 upath->traditional_status = MSU_STOP;
452 break;
453
454 case MSU_PSTAT_STANDBY :
455 upath->traditional_status = MSU_STANDBY;
456 break;
457
458 case MSU_PSTAT_ACTIVE :
459 upath->traditional_status = MSU_ACTIVE;
460 break;
461 }
462
463 mutex_enter(&oplmsu_uinst->l_lock);
464 oplmsu_clear_ioctl_path(lpath);
465 mutex_exit(&oplmsu_uinst->l_lock);
466 mutex_exit(&oplmsu_uinst->u_lock);
467 rw_exit(&oplmsu_uinst->lock);
468 freemsg(mp);
469 return (SUCCESS);
470 }
471
472 /* M_ERROR or M_HANGUP response received */
473 int
oplmsu_lrmsg_error(queue_t * lrq,mblk_t * mp)474 oplmsu_lrmsg_error(queue_t *lrq, mblk_t *mp)
475 {
476 upath_t *upath, *altn_upath = NULL;
477 lpath_t *lpath, *altn_lpath = NULL;
478 mblk_t *nmp = NULL, *fmp = NULL;
479 queue_t *dst_queue = NULL;
480 ctrl_t *ctrl;
481 int term_stat, term_ioctl;
482
483 rw_enter(&oplmsu_uinst->lock, RW_READER);
484 mutex_enter(&oplmsu_uinst->c_lock);
485 ctrl = oplmsu_uinst->user_ctrl;
486 if (ctrl != NULL) {
487 dst_queue = RD(ctrl->queue);
488 }
489 mutex_exit(&oplmsu_uinst->c_lock);
490
491 mutex_enter(&oplmsu_uinst->u_lock);
492 mutex_enter(&oplmsu_uinst->l_lock);
493 lpath = (lpath_t *)lrq->q_ptr;
494 upath = oplmsu_search_upath_info(lpath->path_no);
495
496 if (upath == NULL) {
497 mutex_exit(&oplmsu_uinst->l_lock);
498 mutex_exit(&oplmsu_uinst->u_lock);
499 rw_exit(&oplmsu_uinst->lock);
500 freemsg(mp);
501 return (SUCCESS);
502 }
503
504 if ((lpath->status == MSU_LINK_NU) ||
505 (lpath->status == MSU_SETID_NU) ||
506 (upath->traditional_status == MSU_WSTR_ACK) ||
507 (upath->traditional_status == MSU_WTCS_ACK) ||
508 (upath->traditional_status == MSU_WTMS_ACK) ||
509 (upath->traditional_status == MSU_WPPS_ACK) ||
510 (upath->traditional_status == MSU_WWSZ_ACK) ||
511 (upath->traditional_status == MSU_WCAR_ACK) ||
512 (upath->traditional_status == MSU_WSTP_ACK) ||
513 (upath->traditional_status == MSU_WPTH_CHG)) {
514 mutex_exit(&oplmsu_uinst->l_lock);
515 mutex_exit(&oplmsu_uinst->u_lock);
516 rw_exit(&oplmsu_uinst->lock);
517 freemsg(mp);
518 } else if ((upath->traditional_status == MSU_MAKE_INST) ||
519 (upath->traditional_status == MSU_STOP) ||
520 (upath->traditional_status == MSU_STANDBY) ||
521 (upath->traditional_status == MSU_SETID) ||
522 (upath->traditional_status == MSU_LINK)) {
523 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL, upath->status,
524 MSU_FAIL);
525 mutex_exit(&oplmsu_uinst->l_lock);
526 mutex_exit(&oplmsu_uinst->u_lock);
527 rw_exit(&oplmsu_uinst->lock);
528 freemsg(mp);
529 } else if (upath->traditional_status == MSU_FAIL) {
530 mutex_exit(&oplmsu_uinst->l_lock);
531 mutex_exit(&oplmsu_uinst->u_lock);
532 rw_exit(&oplmsu_uinst->lock);
533 freemsg(mp);
534 } else if (upath->traditional_status == MSU_ACTIVE) {
535 altn_upath = oplmsu_search_standby();
536 if (altn_upath == NULL) {
537 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL,
538 upath->status, MSU_FAIL);
539
540 oplmsu_clear_ioctl_path(lpath);
541 lpath->src_upath = NULL;
542 lpath->status = MSU_EXT_NOTUSED;
543 lpath->uinst = NULL;
544 mutex_exit(&oplmsu_uinst->l_lock);
545 mutex_exit(&oplmsu_uinst->u_lock);
546
547 OPLMSU_RWLOCK_UPGRADE();
548 oplmsu_uinst->lower_queue = NULL;
549 rw_exit(&oplmsu_uinst->lock);
550 freemsg(mp);
551 return (SUCCESS);
552 }
553
554 mutex_exit(&oplmsu_uinst->l_lock);
555 if (oplmsu_cmn_allocmb(lrq, mp, &fmp, sizeof (char),
556 MSU_READ_SIDE) == FAILURE) {
557 mutex_exit(&oplmsu_uinst->u_lock);
558 rw_exit(&oplmsu_uinst->lock);
559 return (FAILURE);
560 }
561
562 if (oplmsu_cmn_prechg(lrq, mp, MSU_READ_SIDE, &nmp, &term_ioctl,
563 &term_stat) == FAILURE) {
564 mutex_exit(&oplmsu_uinst->u_lock);
565 rw_exit(&oplmsu_uinst->lock);
566 freeb(fmp);
567 return (FAILURE);
568 }
569
570 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL,
571 upath->status, MSU_FAIL);
572
573 mutex_enter(&oplmsu_uinst->l_lock);
574 lpath->uinst = NULL;
575
576 altn_upath->traditional_status = term_stat;
577 altn_lpath = altn_upath->lpath;
578
579 altn_lpath->hndl_mp = NULL;
580 altn_lpath->hndl_uqueue = NULL;
581 altn_lpath->src_upath = upath;
582 altn_lpath->status = MSU_EXT_VOID;
583 dst_queue = RD(altn_lpath->lower_queue);
584 mutex_exit(&oplmsu_uinst->l_lock);
585 mutex_exit(&oplmsu_uinst->u_lock);
586
587 OPLMSU_RWLOCK_UPGRADE();
588 oplmsu_uinst->lower_queue = NULL;
589 oplmsu_cmn_set_mflush(fmp);
590
591 if (ctrl != NULL) {
592 mutex_enter(&oplmsu_uinst->c_lock);
593 noenable(WR(ctrl->queue));
594 mutex_exit(&oplmsu_uinst->c_lock);
595
596 oplmsu_queue_flag = 1;
597 }
598
599 rw_exit(&oplmsu_uinst->lock);
600 freemsg(mp);
601
602 OPLMSU_TRACE(dst_queue, fmp, MSU_TRC_LO);
603 qreply(dst_queue, fmp);
604 OPLMSU_TRACE(dst_queue, nmp, MSU_TRC_LO);
605 qreply(dst_queue, nmp);
606 }
607 return (SUCCESS);
608 }
609
610 /* M_DATA[xoff/xon] was received from serial port */
611 int
oplmsu_lrdata_xoffxon(queue_t * lrq,mblk_t * mp)612 oplmsu_lrdata_xoffxon(queue_t *lrq, mblk_t *mp)
613 {
614 upath_t *upath, *stp_upath = NULL;
615 lpath_t *lpath, *stp_lpath = NULL;
616 mblk_t *nmp = NULL, *fmp = NULL;
617 ctrl_t *ctrl;
618 int term_stat, term_ioctl;
619
620 rw_enter(&oplmsu_uinst->lock, RW_READER);
621 mutex_enter(&oplmsu_uinst->u_lock);
622 mutex_enter(&oplmsu_uinst->l_lock);
623
624 if (oplmsu_uinst->lower_queue != NULL) {
625 /* Get lower path of active status */
626 stp_lpath = (lpath_t *)oplmsu_uinst->lower_queue->q_ptr;
627 if (stp_lpath != NULL) {
628 stp_upath =
629 oplmsu_search_upath_info(stp_lpath->path_no);
630 }
631 }
632
633 lpath = (lpath_t *)lrq->q_ptr;
634 upath = oplmsu_search_upath_info(lpath->path_no);
635
636 if (upath == NULL) {
637 mutex_exit(&oplmsu_uinst->l_lock);
638 mutex_exit(&oplmsu_uinst->u_lock);
639 rw_exit(&oplmsu_uinst->lock);
640 freemsg(mp);
641 return (SUCCESS);
642 }
643
644 if ((stp_upath != NULL) && (stp_upath != upath)) {
645 if ((stp_upath->status != MSU_PSTAT_ACTIVE) ||
646 (stp_upath->traditional_status != MSU_ACTIVE)) {
647 mutex_exit(&oplmsu_uinst->l_lock);
648 mutex_exit(&oplmsu_uinst->u_lock);
649 rw_exit(&oplmsu_uinst->lock);
650 (void) putbq(lrq, mp);
651 return (FAILURE);
652 }
653 }
654
655 if ((upath->status == MSU_PSTAT_ACTIVE) &&
656 ((upath->traditional_status == MSU_ACTIVE) ||
657 (upath->traditional_status == MSU_WTCS_ACK) ||
658 (upath->traditional_status == MSU_WTMS_ACK) ||
659 (upath->traditional_status == MSU_WPPS_ACK) ||
660 (upath->traditional_status == MSU_WWSZ_ACK) ||
661 (upath->traditional_status == MSU_WCAR_ACK))) {
662 mutex_exit(&oplmsu_uinst->l_lock);
663 mutex_exit(&oplmsu_uinst->u_lock);
664 (void) oplmsu_rcmn_through_hndl(lrq, mp, MSU_NORM);
665 rw_exit(&oplmsu_uinst->lock);
666 return (SUCCESS);
667 } else if ((upath->status != MSU_PSTAT_STANDBY) ||
668 (upath->traditional_status != MSU_STANDBY)) {
669 mutex_exit(&oplmsu_uinst->l_lock);
670 mutex_exit(&oplmsu_uinst->u_lock);
671 rw_exit(&oplmsu_uinst->lock);
672 freemsg(mp);
673 cmn_err(CE_WARN, "oplmsu: lr-xoffxon: "
674 "Can't change to specified path");
675 return (SUCCESS);
676 }
677 mutex_exit(&oplmsu_uinst->l_lock);
678
679 if (oplmsu_cmn_allocmb(lrq, mp, &fmp, sizeof (char), MSU_READ_SIDE) ==
680 FAILURE) {
681 mutex_exit(&oplmsu_uinst->u_lock);
682 rw_exit(&oplmsu_uinst->lock);
683 return (FAILURE);
684 }
685
686 if (oplmsu_cmn_prechg(lrq, mp, MSU_READ_SIDE, &nmp, &term_ioctl,
687 &term_stat) == FAILURE) {
688 mutex_exit(&oplmsu_uinst->u_lock);
689 rw_exit(&oplmsu_uinst->lock);
690 freeb(fmp);
691 return (FAILURE);
692 }
693
694 oplmsu_cmn_set_mflush(fmp);
695 upath->traditional_status = term_stat;
696
697 mutex_enter(&oplmsu_uinst->l_lock);
698 lpath->hndl_mp = mp;
699 lpath->hndl_uqueue = NULL;
700 lpath->src_upath = stp_upath;
701 lpath->status = MSU_EXT_VOID;
702
703 mutex_enter(&oplmsu_uinst->c_lock);
704 ctrl = oplmsu_uinst->user_ctrl;
705 if (term_stat != MSU_WPTH_CHG) {
706 /*
707 * Send termios to new active path and wait response
708 */
709 if (ctrl != NULL) {
710 noenable(WR(ctrl->queue));
711 }
712 mutex_exit(&oplmsu_uinst->c_lock);
713 mutex_exit(&oplmsu_uinst->l_lock);
714 mutex_exit(&oplmsu_uinst->u_lock);
715 rw_exit(&oplmsu_uinst->lock);
716
717 OPLMSU_TRACE(RD(lrq), fmp, MSU_TRC_LO);
718 qreply(RD(lrq), fmp);
719 OPLMSU_TRACE(RD(lrq), nmp, MSU_TRC_LO);
720 qreply(RD(lrq), nmp);
721 } else {
722 /*
723 * No termios messages are received. Change active path.
724 */
725
726 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_ACTIVE, upath->status,
727 MSU_ACTIVE);
728
729 lpath->uinst = oplmsu_uinst;
730 lpath->src_upath = NULL;
731 lpath->status = MSU_EXT_NOTUSED;
732
733 /* Notify of the active path changing */
734 (void) prom_opl_switch_console(upath->ser_devcb.lsb);
735
736 (void) putq(WR(lrq), fmp);
737
738 /* Send XON to notify active path */
739 (void) oplmsu_cmn_put_xoffxon(WR(lrq), MSU_XON_4);
740
741 if (lpath->hndl_mp != NULL) {
742 /* Put a message(M_DATA) on a queue */
743 if (ctrl != NULL) {
744 (void) putq(RD(ctrl->queue), lpath->hndl_mp);
745 }
746 }
747
748 oplmsu_clear_ioctl_path(lpath);
749
750 if (ctrl != NULL) {
751 noenable(WR(ctrl->queue));
752 }
753
754 if ((stp_upath != NULL) && (stp_lpath != NULL)) {
755 /* Change the status of stop path */
756 oplmsu_cmn_set_upath_sts(stp_upath, MSU_PSTAT_STANDBY,
757 stp_upath->status, MSU_STANDBY);
758
759 oplmsu_clear_ioctl_path(stp_lpath);
760 stp_lpath->uinst = NULL;
761 stp_lpath->src_upath = NULL;
762 stp_lpath->status = MSU_EXT_NOTUSED;
763 }
764 #ifdef DEBUG
765 oplmsu_cmn_prt_pathname(upath->ser_devcb.dip);
766 #endif
767 /* Send XOFF to notify all standby paths */
768 oplmsu_cmn_putxoff_standby();
769 mutex_exit(&oplmsu_uinst->c_lock);
770 mutex_exit(&oplmsu_uinst->l_lock);
771 mutex_exit(&oplmsu_uinst->u_lock);
772
773 OPLMSU_RWLOCK_UPGRADE();
774 mutex_enter(&oplmsu_uinst->u_lock);
775 oplmsu_uinst->lower_queue = lrq;
776 oplmsu_uinst->inst_status = oplmsu_get_inst_status();
777 mutex_exit(&oplmsu_uinst->u_lock);
778
779 if (ctrl != NULL) {
780 queue_t *temp_queue;
781
782 mutex_enter(&oplmsu_uinst->c_lock);
783 temp_queue = WR(ctrl->queue);
784 mutex_exit(&oplmsu_uinst->c_lock);
785
786 /* Reschedule a queue for service */
787 enableok(temp_queue);
788
789 oplmsu_queue_flag = 0;
790 oplmsu_wcmn_high_qenable(temp_queue, RW_WRITER);
791 }
792 rw_exit(&oplmsu_uinst->lock);
793 }
794 return (SUCCESS);
795 }
796