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