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 ((lpath->status == MSU_LINK_NU) || 498 (lpath->status == MSU_SETID_NU) || 499 (upath->traditional_status == MSU_WSTR_ACK) || 500 (upath->traditional_status == MSU_WTCS_ACK) || 501 (upath->traditional_status == MSU_WTMS_ACK) || 502 (upath->traditional_status == MSU_WPPS_ACK) || 503 (upath->traditional_status == MSU_WWSZ_ACK) || 504 (upath->traditional_status == MSU_WCAR_ACK) || 505 (upath->traditional_status == MSU_WSTP_ACK) || 506 (upath->traditional_status == MSU_WPTH_CHG)) { 507 mutex_exit(&oplmsu_uinst->l_lock); 508 mutex_exit(&oplmsu_uinst->u_lock); 509 rw_exit(&oplmsu_uinst->lock); 510 freemsg(mp); 511 } else if ((upath->traditional_status == MSU_MAKE_INST) || 512 (upath->traditional_status == MSU_STOP) || 513 (upath->traditional_status == MSU_STANDBY) || 514 (upath->traditional_status == MSU_SETID) || 515 (upath->traditional_status == MSU_LINK)) { 516 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL, upath->status, 517 MSU_FAIL); 518 mutex_exit(&oplmsu_uinst->l_lock); 519 mutex_exit(&oplmsu_uinst->u_lock); 520 rw_exit(&oplmsu_uinst->lock); 521 freemsg(mp); 522 } else if (upath->traditional_status == MSU_FAIL) { 523 mutex_exit(&oplmsu_uinst->l_lock); 524 mutex_exit(&oplmsu_uinst->u_lock); 525 rw_exit(&oplmsu_uinst->lock); 526 freemsg(mp); 527 } else if (upath->traditional_status == MSU_ACTIVE) { 528 altn_upath = oplmsu_search_standby(); 529 if (altn_upath == NULL) { 530 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL, 531 upath->status, MSU_FAIL); 532 533 oplmsu_clear_ioctl_path(lpath); 534 lpath->src_upath = NULL; 535 lpath->status = MSU_EXT_NOTUSED; 536 lpath->uinst = NULL; 537 mutex_exit(&oplmsu_uinst->l_lock); 538 mutex_exit(&oplmsu_uinst->u_lock); 539 540 OPLMSU_RWLOCK_UPGRADE(); 541 oplmsu_uinst->lower_queue = NULL; 542 rw_exit(&oplmsu_uinst->lock); 543 freemsg(mp); 544 return (SUCCESS); 545 } 546 547 mutex_exit(&oplmsu_uinst->l_lock); 548 if (oplmsu_cmn_allocmb(lrq, mp, &fmp, sizeof (char), 549 MSU_READ_SIDE) == FAILURE) { 550 mutex_exit(&oplmsu_uinst->u_lock); 551 rw_exit(&oplmsu_uinst->lock); 552 return (FAILURE); 553 } 554 555 if (oplmsu_cmn_prechg(lrq, mp, MSU_READ_SIDE, &nmp, &term_ioctl, 556 &term_stat) == FAILURE) { 557 mutex_exit(&oplmsu_uinst->u_lock); 558 rw_exit(&oplmsu_uinst->lock); 559 freeb(fmp); 560 return (FAILURE); 561 } 562 563 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_FAIL, 564 upath->status, MSU_FAIL); 565 566 mutex_enter(&oplmsu_uinst->l_lock); 567 lpath->uinst = NULL; 568 569 altn_upath->traditional_status = term_stat; 570 altn_lpath = altn_upath->lpath; 571 572 altn_lpath->hndl_mp = NULL; 573 altn_lpath->hndl_uqueue = NULL; 574 altn_lpath->src_upath = upath; 575 altn_lpath->status = MSU_EXT_VOID; 576 dst_queue = RD(altn_lpath->lower_queue); 577 mutex_exit(&oplmsu_uinst->l_lock); 578 mutex_exit(&oplmsu_uinst->u_lock); 579 580 OPLMSU_RWLOCK_UPGRADE(); 581 oplmsu_uinst->lower_queue = NULL; 582 oplmsu_cmn_set_mflush(fmp); 583 584 if (ctrl != NULL) { 585 mutex_enter(&oplmsu_uinst->c_lock); 586 noenable(WR(ctrl->queue)); 587 mutex_exit(&oplmsu_uinst->c_lock); 588 589 oplmsu_queue_flag = 1; 590 } 591 592 rw_exit(&oplmsu_uinst->lock); 593 freemsg(mp); 594 595 OPLMSU_TRACE(dst_queue, fmp, MSU_TRC_LO); 596 qreply(dst_queue, fmp); 597 OPLMSU_TRACE(dst_queue, nmp, MSU_TRC_LO); 598 qreply(dst_queue, nmp); 599 } 600 return (SUCCESS); 601 } 602 603 /* M_DATA[xoff/xon] was received from serial port */ 604 int 605 oplmsu_lrdata_xoffxon(queue_t *lrq, mblk_t *mp) 606 { 607 upath_t *upath, *stp_upath = NULL; 608 lpath_t *lpath, *stp_lpath = NULL; 609 mblk_t *nmp = NULL, *fmp = NULL; 610 ctrl_t *ctrl; 611 int term_stat, term_ioctl; 612 613 rw_enter(&oplmsu_uinst->lock, RW_READER); 614 mutex_enter(&oplmsu_uinst->u_lock); 615 mutex_enter(&oplmsu_uinst->l_lock); 616 617 if (oplmsu_uinst->lower_queue != NULL) { 618 /* Get lower path of active status */ 619 stp_lpath = (lpath_t *)oplmsu_uinst->lower_queue->q_ptr; 620 if (stp_lpath != NULL) { 621 stp_upath = 622 oplmsu_search_upath_info(stp_lpath->path_no); 623 } 624 } 625 626 lpath = (lpath_t *)lrq->q_ptr; 627 upath = oplmsu_search_upath_info(lpath->path_no); 628 629 if ((stp_upath != NULL) && (stp_upath != upath)) { 630 if ((stp_upath->status != MSU_PSTAT_ACTIVE) || 631 (stp_upath->traditional_status != MSU_ACTIVE)) { 632 mutex_exit(&oplmsu_uinst->l_lock); 633 mutex_exit(&oplmsu_uinst->u_lock); 634 rw_exit(&oplmsu_uinst->lock); 635 putbq(lrq, mp); 636 return (FAILURE); 637 } 638 } 639 640 if ((upath->status == MSU_PSTAT_ACTIVE) && 641 ((upath->traditional_status == MSU_ACTIVE) || 642 (upath->traditional_status == MSU_WTCS_ACK) || 643 (upath->traditional_status == MSU_WTMS_ACK) || 644 (upath->traditional_status == MSU_WPPS_ACK) || 645 (upath->traditional_status == MSU_WWSZ_ACK) || 646 (upath->traditional_status == MSU_WCAR_ACK))) { 647 mutex_exit(&oplmsu_uinst->l_lock); 648 mutex_exit(&oplmsu_uinst->u_lock); 649 oplmsu_rcmn_through_hndl(lrq, mp, MSU_NORM); 650 rw_exit(&oplmsu_uinst->lock); 651 return (SUCCESS); 652 } else if ((upath->status != MSU_PSTAT_STANDBY) || 653 (upath->traditional_status != MSU_STANDBY)) { 654 mutex_exit(&oplmsu_uinst->l_lock); 655 mutex_exit(&oplmsu_uinst->u_lock); 656 rw_exit(&oplmsu_uinst->lock); 657 freemsg(mp); 658 cmn_err(CE_WARN, "oplmsu: lr-xoffxon: " 659 "Can't change to specified path"); 660 return (SUCCESS); 661 } 662 mutex_exit(&oplmsu_uinst->l_lock); 663 664 if (oplmsu_cmn_allocmb(lrq, mp, &fmp, sizeof (char), MSU_READ_SIDE) == 665 FAILURE) { 666 mutex_exit(&oplmsu_uinst->u_lock); 667 rw_exit(&oplmsu_uinst->lock); 668 return (FAILURE); 669 } 670 671 if (oplmsu_cmn_prechg(lrq, mp, MSU_READ_SIDE, &nmp, &term_ioctl, 672 &term_stat) == FAILURE) { 673 mutex_exit(&oplmsu_uinst->u_lock); 674 rw_exit(&oplmsu_uinst->lock); 675 freeb(fmp); 676 return (FAILURE); 677 } 678 679 oplmsu_cmn_set_mflush(fmp); 680 upath->traditional_status = term_stat; 681 682 mutex_enter(&oplmsu_uinst->l_lock); 683 lpath->hndl_mp = mp; 684 lpath->hndl_uqueue = NULL; 685 lpath->src_upath = stp_upath; 686 lpath->status = MSU_EXT_VOID; 687 688 mutex_enter(&oplmsu_uinst->c_lock); 689 ctrl = oplmsu_uinst->user_ctrl; 690 if (term_stat != MSU_WPTH_CHG) { 691 /* 692 * Send termios to new active path and wait response 693 */ 694 if (ctrl != NULL) { 695 noenable(WR(ctrl->queue)); 696 } 697 mutex_exit(&oplmsu_uinst->c_lock); 698 mutex_exit(&oplmsu_uinst->l_lock); 699 mutex_exit(&oplmsu_uinst->u_lock); 700 rw_exit(&oplmsu_uinst->lock); 701 702 OPLMSU_TRACE(RD(lrq), fmp, MSU_TRC_LO); 703 qreply(RD(lrq), fmp); 704 OPLMSU_TRACE(RD(lrq), nmp, MSU_TRC_LO); 705 qreply(RD(lrq), nmp); 706 } else { 707 /* 708 * No termios messages are received. Change active path. 709 */ 710 711 oplmsu_cmn_set_upath_sts(upath, MSU_PSTAT_ACTIVE, upath->status, 712 MSU_ACTIVE); 713 714 lpath->uinst = oplmsu_uinst; 715 lpath->src_upath = NULL; 716 lpath->status = MSU_EXT_NOTUSED; 717 718 /* Notify of the active path changing */ 719 prom_opl_switch_console(upath->ser_devcb.lsb); 720 721 putq(WR(lrq), fmp); 722 723 /* Send XON to notify active path */ 724 (void) oplmsu_cmn_put_xoffxon(WR(lrq), MSU_XON_4); 725 726 if (lpath->hndl_mp != NULL) { 727 /* Put a message(M_DATA) on a queue */ 728 if (ctrl != NULL) { 729 putq(RD(ctrl->queue), lpath->hndl_mp); 730 } 731 } 732 733 oplmsu_clear_ioctl_path(lpath); 734 735 if (ctrl != NULL) { 736 noenable(WR(ctrl->queue)); 737 } 738 739 if ((stp_upath != NULL) && (stp_lpath != NULL)) { 740 /* Change the status of stop path */ 741 oplmsu_cmn_set_upath_sts(stp_upath, MSU_PSTAT_STANDBY, 742 stp_upath->status, MSU_STANDBY); 743 744 oplmsu_clear_ioctl_path(stp_lpath); 745 stp_lpath->uinst = NULL; 746 stp_lpath->src_upath = NULL; 747 stp_lpath->status = MSU_EXT_NOTUSED; 748 } 749 #ifdef DEBUG 750 oplmsu_cmn_prt_pathname(upath->ser_devcb.dip); 751 #endif 752 /* Send XOFF to notify all standby paths */ 753 oplmsu_cmn_putxoff_standby(); 754 mutex_exit(&oplmsu_uinst->c_lock); 755 mutex_exit(&oplmsu_uinst->l_lock); 756 mutex_exit(&oplmsu_uinst->u_lock); 757 758 OPLMSU_RWLOCK_UPGRADE(); 759 mutex_enter(&oplmsu_uinst->u_lock); 760 oplmsu_uinst->lower_queue = lrq; 761 oplmsu_uinst->inst_status = oplmsu_get_inst_status(); 762 mutex_exit(&oplmsu_uinst->u_lock); 763 764 if (ctrl != NULL) { 765 queue_t *temp_queue; 766 767 mutex_enter(&oplmsu_uinst->c_lock); 768 temp_queue = WR(ctrl->queue); 769 mutex_exit(&oplmsu_uinst->c_lock); 770 771 /* Reschedule a queue for service */ 772 enableok(temp_queue); 773 774 oplmsu_queue_flag = 0; 775 oplmsu_wcmn_high_qenable(temp_queue, RW_WRITER); 776 } 777 rw_exit(&oplmsu_uinst->lock); 778 } 779 return (SUCCESS); 780 } 781