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 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 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 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