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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 2014, Joyent, Inc. All rights reserved. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/file.h> 33 #include <sys/errno.h> 34 #include <sys/uio.h> 35 #include <sys/open.h> 36 #include <sys/cred.h> 37 #include <sys/kmem.h> 38 #include <sys/conf.h> 39 #include <sys/cmn_err.h> 40 #include <sys/ksynch.h> 41 #include <sys/modctl.h> 42 #include <sys/stat.h> /* needed for S_IFBLK and S_IFCHR */ 43 #include <sys/debug.h> 44 #include <sys/promif.h> 45 #include <sys/ddi.h> 46 #include <sys/sunddi.h> 47 #include <sys/cyclic.h> 48 #include <sys/termio.h> 49 #include <sys/intr.h> 50 #include <sys/ivintr.h> 51 #include <sys/note.h> 52 #include <sys/stat.h> 53 #include <sys/fcntl.h> 54 #include <sys/sysmacros.h> 55 56 #include <sys/ldc.h> 57 #include <sys/mdeg.h> 58 #include <sys/vcc_impl.h> 59 60 #define VCC_LDC_RETRIES 5 61 #define VCC_LDC_DELAY 1000 /* usec */ 62 63 /* 64 * Function prototypes. 65 */ 66 67 /* DDI entrypoints */ 68 static int vcc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 69 static int vcc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 70 static int vcc_open(dev_t *devp, int flag, int otyp, cred_t *cred); 71 static int vcc_close(dev_t dev, int flag, int otyp, cred_t *cred); 72 static int vcc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 73 cred_t *credp, int *rvalp); 74 static int vcc_read(dev_t dev, struct uio *uiop, cred_t *credp); 75 static int vcc_write(dev_t dev, struct uio *uiop, cred_t *credp); 76 static int vcc_chpoll(dev_t dev, short events, int anyyet, 77 short *reventsp, struct pollhead **phpp); 78 static int vcc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 79 void *arg, void **resultp); 80 81 /* callback functions */ 82 static uint_t vcc_ldc_cb(uint64_t event, caddr_t arg); 83 static int vcc_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 84 85 /* Internal functions */ 86 static int i_vcc_ldc_init(vcc_t *vccp, vcc_port_t *vport); 87 static int i_vcc_add_port(vcc_t *vccp, char *group_name, uint64_t tcp_port, 88 uint_t portno, char *domain_name); 89 static int i_vcc_config_port(vcc_t *vccp, uint_t portno, uint64_t ldc_id); 90 static int i_vcc_reset_events(vcc_t *vccp); 91 static int i_vcc_cons_tbl(vcc_t *vccp, uint_t num_ports, 92 caddr_t buf, int mode); 93 static int i_vcc_del_cons_ok(vcc_t *vccp, caddr_t buf, int mode); 94 static int i_vcc_close_port(vcc_port_t *vport); 95 static int i_vcc_write_ldc(vcc_port_t *vport, vcc_msg_t *buf); 96 static int i_vcc_read_ldc(vcc_port_t *vport, char *data_buf, size_t *sz); 97 98 static void *vcc_ssp; 99 100 static struct cb_ops vcc_cb_ops = { 101 vcc_open, /* open */ 102 vcc_close, /* close */ 103 nodev, /* strategy */ 104 nodev, /* print */ 105 nodev, /* dump */ 106 vcc_read, /* read */ 107 vcc_write, /* write */ 108 vcc_ioctl, /* ioctl */ 109 nodev, /* devmap */ 110 nodev, /* mmap */ 111 ddi_segmap, /* segmap */ 112 vcc_chpoll, /* chpoll */ 113 ddi_prop_op, /* prop_op */ 114 NULL, /* stream */ 115 D_NEW | D_MP /* flags */ 116 }; 117 118 119 static struct dev_ops vcc_ops = { 120 DEVO_REV, /* rev */ 121 0, /* ref count */ 122 vcc_getinfo, /* getinfo */ 123 nulldev, /* identify */ 124 nulldev, /* probe */ 125 vcc_attach, /* attach */ 126 vcc_detach, /* detach */ 127 nodev, /* reset */ 128 &vcc_cb_ops, /* cb_ops */ 129 (struct bus_ops *)NULL, /* bus_ops */ 130 NULL, /* power */ 131 ddi_quiesce_not_needed, /* quiesce */ 132 }; 133 134 extern struct mod_ops mod_driverops; 135 136 #define VCC_CHANNEL_ENDPOINT "channel-endpoint" 137 #define VCC_ID_PROP "id" 138 139 /* 140 * This is the string displayed by modinfo(8). 141 */ 142 static char vcc_ident[] = "sun4v Virtual Console Concentrator Driver"; 143 144 static struct modldrv md = { 145 &mod_driverops, /* Type - it is a driver */ 146 vcc_ident, /* Name of the module */ 147 &vcc_ops, /* driver specfic opts */ 148 }; 149 150 static struct modlinkage ml = { 151 MODREV_1, 152 &md, 153 NULL 154 }; 155 156 /* 157 * Matching criteria passed to the MDEG to register interest 158 * in changes to 'virtual-device-port' nodes identified by their 159 * 'id' property. 160 */ 161 static md_prop_match_t vcc_port_prop_match[] = { 162 { MDET_PROP_VAL, "id" }, 163 { MDET_LIST_END, NULL } 164 }; 165 166 static mdeg_node_match_t vcc_port_match = {"virtual-device-port", 167 vcc_port_prop_match}; 168 169 /* 170 * Specification of an MD node passed to the MDEG to filter any 171 * 'virtual-device-port' nodes that do not belong to the specified node. 172 * This template is copied for each vldc instance and filled in with 173 * the appropriate 'cfg-handle' value before being passed to the MDEG. 174 */ 175 static mdeg_prop_spec_t vcc_prop_template[] = { 176 { MDET_PROP_STR, "name", "virtual-console-concentrator" }, 177 { MDET_PROP_VAL, "cfg-handle", NULL }, 178 { MDET_LIST_END, NULL, NULL } 179 }; 180 181 #define VCC_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val); 182 183 184 #ifdef DEBUG 185 186 /* 187 * Print debug messages 188 * 189 * set vldcdbg to 0xf to enable all messages 190 * 191 * 0x8 - Errors 192 * 0x4 - Warnings 193 * 0x2 - All debug messages (most verbose) 194 * 0x1 - Minimal debug messages 195 */ 196 197 int vccdbg = 0x8; 198 199 static void 200 vccdebug(const char *fmt, ...) 201 { 202 char buf[512]; 203 va_list ap; 204 205 va_start(ap, fmt); 206 (void) vsprintf(buf, fmt, ap); 207 va_end(ap); 208 209 cmn_err(CE_CONT, "%s\n", buf); 210 } 211 212 #define D1 \ 213 if (vccdbg & 0x01) \ 214 vccdebug 215 216 #define D2 \ 217 if (vccdbg & 0x02) \ 218 vccdebug 219 220 #define DWARN \ 221 if (vccdbg & 0x04) \ 222 vccdebug 223 224 #else 225 226 #define D1 227 #define D2 228 #define DWARN 229 230 #endif 231 232 /* _init(9E): initialize the loadable module */ 233 int 234 _init(void) 235 { 236 int error; 237 238 /* init the soft state structure */ 239 error = ddi_soft_state_init(&vcc_ssp, sizeof (vcc_t), 1); 240 if (error != 0) { 241 return (error); 242 } 243 244 /* Link the driver into the system */ 245 error = mod_install(&ml); 246 247 return (error); 248 249 } 250 251 /* _info(9E): return information about the loadable module */ 252 int 253 _info(struct modinfo *modinfop) 254 { 255 /* Report status of the dynamically loadable driver module */ 256 return (mod_info(&ml, modinfop)); 257 } 258 259 /* _fini(9E): prepare the module for unloading. */ 260 int 261 _fini(void) 262 { 263 int error; 264 265 /* Unlink the driver module from the system */ 266 if ((error = mod_remove(&ml)) == 0) { 267 /* 268 * We have successfully "removed" the driver. 269 * destroy soft state 270 */ 271 ddi_soft_state_fini(&vcc_ssp); 272 } 273 274 return (error); 275 } 276 277 /* getinfo(9E) */ 278 static int 279 vcc_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 280 { 281 _NOTE(ARGUNUSED(dip)) 282 283 int instance = VCCINST(getminor((dev_t)arg)); 284 vcc_t *vccp = NULL; 285 286 switch (cmd) { 287 288 case DDI_INFO_DEVT2DEVINFO: 289 if ((vccp = ddi_get_soft_state(vcc_ssp, instance)) == NULL) { 290 *resultp = NULL; 291 return (DDI_FAILURE); 292 } 293 *resultp = vccp->dip; 294 return (DDI_SUCCESS); 295 296 case DDI_INFO_DEVT2INSTANCE: 297 *resultp = (void *)(uintptr_t)instance; 298 return (DDI_SUCCESS); 299 300 default: 301 *resultp = NULL; 302 return (DDI_FAILURE); 303 } 304 } 305 306 /* 307 * There are two cases that need special blocking. One of them is to block 308 * a minor node without a port and another is to block application other 309 * than vntsd. 310 * 311 * A minor node can exist in the file system without associated with a port 312 * because when a port is deleted, ddi_remove_minor does not unlink it. 313 * Clients might try to open a minor node even after the corresponding port 314 * node has been removed. To identify and block these calls, 315 * we need to validate the association between a port and its minor node. 316 * 317 * An application other than vntsd can access a console port as long 318 * as vntsd is not using the port. A port opened by an application other 319 * than vntsd will be closed when vntsd wants to use the port. 320 * However, other application could use same file descriptor 321 * access vcc cb_ops. So we need to identify and block caller other 322 * than vntsd, when vntsd is using the port. 323 */ 324 static int 325 i_vcc_can_use_port(vcc_minor_t *minorp, vcc_port_t *vport) 326 { 327 if (vport->minorp != minorp) { 328 /* port config changed */ 329 return (ENXIO); 330 } 331 332 if (vport->valid_pid == VCC_NO_PID_BLOCKING) { 333 /* no blocking needed */ 334 return (0); 335 } 336 337 if (vport->valid_pid != ddi_get_pid()) { 338 return (EIO); 339 } 340 341 return (0); 342 } 343 344 345 /* Syncronization between thread using cv_wait */ 346 static int 347 i_vcc_wait_port_status(vcc_port_t *vport, kcondvar_t *cv, uint32_t status) 348 { 349 350 int rv; 351 352 ASSERT(mutex_owned(&vport->lock)); 353 354 for (; ; ) { 355 356 if ((vport->status & VCC_PORT_AVAIL) == 0) { 357 /* port has been deleted */ 358 D1("i_vcc_wait_port_status: port%d deleted\n", 359 vport->number); 360 return (EIO); 361 } 362 363 if ((vport->status & VCC_PORT_OPEN) == 0) { 364 D1("i_vcc_wait_port_status: port%d is closed \n", 365 vport->number); 366 return (EIO); 367 } 368 369 if (vport->status & VCC_PORT_LDC_LINK_DOWN) { 370 return (EIO); 371 } 372 373 if ((vport->valid_pid != VCC_NO_PID_BLOCKING) && 374 (vport->valid_pid != ddi_get_pid())) { 375 return (EIO); 376 } 377 378 if ((vport->status & status) == status) { 379 return (0); 380 } 381 382 if (!ddi_can_receive_sig()) { 383 return (EIO); 384 } 385 386 rv = cv_wait_sig(cv, &vport->lock); 387 if (rv == 0) { 388 D1("i_vcc_wait_port_status: port%d get intr \n", 389 vport->number); 390 /* got signal */ 391 return (EINTR); 392 } 393 } 394 395 } 396 397 /* Syncronization between threads, signal state change */ 398 static void 399 i_vcc_set_port_status(vcc_port_t *vport, kcondvar_t *cv, uint32_t status) 400 { 401 402 mutex_enter(&vport->lock); 403 vport->status |= status; 404 cv_broadcast(cv); 405 mutex_exit(&vport->lock); 406 } 407 408 /* initialize a ldc channel */ 409 static int 410 i_vcc_ldc_init(vcc_t *vccp, vcc_port_t *vport) 411 { 412 ldc_attr_t attr; 413 int rv = EIO; 414 415 ASSERT(mutex_owned(&vport->lock)); 416 ASSERT(vport->ldc_id != VCC_INVALID_CHANNEL); 417 418 /* initialize the channel */ 419 attr.devclass = LDC_DEV_SERIAL; 420 attr.instance = ddi_get_instance(vccp->dip); 421 attr.mtu = VCC_MTU_SZ; 422 attr.mode = LDC_MODE_RAW; 423 424 if ((rv = ldc_init(vport->ldc_id, &attr, &(vport->ldc_handle))) != 0) { 425 cmn_err(CE_CONT, "i_vcc_ldc_init: port %d ldc channel %ld" 426 " failed ldc_init %d \n", vport->number, vport->ldc_id, rv); 427 vport->ldc_id = VCC_INVALID_CHANNEL; 428 return (rv); 429 } 430 431 /* register it */ 432 if ((rv = ldc_reg_callback(vport->ldc_handle, vcc_ldc_cb, 433 (caddr_t)vport)) != 0) { 434 cmn_err(CE_CONT, "i_vcc_ldc_init: port@%d ldc_register_cb" 435 "failed\n", vport->number); 436 (void) ldc_fini(vport->ldc_handle); 437 vport->ldc_id = VCC_INVALID_CHANNEL; 438 return (rv); 439 } 440 441 /* open and bring channel up */ 442 if ((rv = ldc_open(vport->ldc_handle)) != 0) { 443 cmn_err(CE_CONT, "i_vcc_ldc_init: port@%d inv channel 0x%lx\n", 444 vport->number, vport->ldc_id); 445 (void) ldc_unreg_callback(vport->ldc_handle); 446 (void) ldc_fini(vport->ldc_handle); 447 vport->ldc_id = VCC_INVALID_CHANNEL; 448 return (rv); 449 } 450 451 /* init the channel status */ 452 if ((rv = ldc_status(vport->ldc_handle, &vport->ldc_status)) != 0) { 453 cmn_err(CE_CONT, "i_vcc_ldc_init: port@%d ldc_status failed\n", 454 vport->number); 455 (void) ldc_close(vport->ldc_handle); 456 (void) ldc_unreg_callback(vport->ldc_handle); 457 (void) ldc_fini(vport->ldc_handle); 458 vport->ldc_id = VCC_INVALID_CHANNEL; 459 return (rv); 460 } 461 462 return (0); 463 } 464 465 /* release a ldc channel */ 466 static void 467 i_vcc_ldc_fini(vcc_port_t *vport) 468 { 469 int rv = EIO; 470 vcc_msg_t buf; 471 size_t sz; 472 int retry = 0; 473 474 D1("i_vcc_ldc_fini: port@%lld, ldc_id%%llx\n", vport->number, 475 vport->ldc_id); 476 477 ASSERT(mutex_owned(&vport->lock)); 478 479 /* wait for write available */ 480 rv = i_vcc_wait_port_status(vport, &vport->write_cv, 481 VCC_PORT_USE_WRITE_LDC); 482 483 if (rv == 0) { 484 vport->status &= ~VCC_PORT_USE_WRITE_LDC; 485 486 /* send a HUP message */ 487 buf.type = LDC_CONSOLE_CTRL; 488 buf.ctrl_msg = LDC_CONSOLE_HUP; 489 buf.size = 0; 490 491 /* 492 * ignore write error since we still want to clean up 493 * ldc channel. 494 */ 495 (void) i_vcc_write_ldc(vport, &buf); 496 497 mutex_exit(&vport->lock); 498 i_vcc_set_port_status(vport, &vport->write_cv, 499 VCC_PORT_USE_WRITE_LDC); 500 mutex_enter(&vport->lock); 501 } 502 503 /* flush ldc channel */ 504 rv = i_vcc_wait_port_status(vport, &vport->read_cv, 505 VCC_PORT_USE_READ_LDC); 506 507 if (rv == 0) { 508 vport->status &= ~VCC_PORT_USE_READ_LDC; 509 do { 510 sz = sizeof (buf); 511 rv = i_vcc_read_ldc(vport, (char *)&buf, &sz); 512 } while (rv == 0 && sz > 0); 513 514 vport->status |= VCC_PORT_USE_READ_LDC; 515 516 } 517 518 /* 519 * ignore read error since we still want to clean up 520 * ldc channel. 521 */ 522 523 (void) ldc_set_cb_mode(vport->ldc_handle, LDC_CB_DISABLE); 524 525 /* close LDC channel - retry on EAGAIN */ 526 while ((rv = ldc_close(vport->ldc_handle)) == EAGAIN) { 527 528 if (++retry > VCC_LDC_RETRIES) { 529 cmn_err(CE_CONT, "i_vcc_ldc_fini: cannot close channel" 530 " %ld\n", vport->ldc_id); 531 break; 532 } 533 534 drv_usecwait(VCC_LDC_DELAY); 535 } 536 537 if (rv == 0) { 538 (void) ldc_unreg_callback(vport->ldc_handle); 539 (void) ldc_fini(vport->ldc_handle); 540 } else { 541 /* 542 * Closing the LDC channel has failed. Ideally we should 543 * fail here but there is no Zeus level infrastructure 544 * to handle this. The MD has already been changed and 545 * we have to do the close. So we try to do as much 546 * clean up as we can. 547 */ 548 while (ldc_unreg_callback(vport->ldc_handle) == EAGAIN) 549 drv_usecwait(VCC_LDC_DELAY); 550 } 551 552 } 553 554 /* read data from ldc channel */ 555 556 static int 557 i_vcc_read_ldc(vcc_port_t *vport, char *data_buf, size_t *sz) 558 { 559 560 int rv; 561 size_t size; 562 size_t space_left = *sz; 563 vcc_msg_t buf; 564 int i; 565 566 567 568 569 /* make sure holding read lock */ 570 ASSERT((vport->status & VCC_PORT_USE_READ_LDC) == 0); 571 ASSERT(space_left >= VCC_MTU_SZ); 572 573 *sz = 0; 574 while (space_left >= VCC_MTU_SZ) { 575 size = sizeof (buf); 576 577 rv = ldc_read(vport->ldc_handle, (caddr_t)&buf, &size); 578 579 if (rv) { 580 return (rv); 581 } 582 583 584 /* 585 * FIXME: ldc_read should not reaturn 0 with 586 * either size == 0, buf.size == 0 or size < VCC_HDR_SZ 587 */ 588 if (size == 0) { 589 if (*sz > 0) { 590 return (0); 591 } 592 return (EAGAIN); 593 } 594 595 if (size < VCC_HDR_SZ) { 596 return (EIO); 597 } 598 599 /* 600 * only data is expected from console - otherwise 601 * return error 602 */ 603 if (buf.type != LDC_CONSOLE_DATA) { 604 return (EIO); 605 } 606 607 if (buf.size == 0) { 608 if (*sz > 0) { 609 return (0); 610 } 611 return (EAGAIN); 612 } 613 614 /* copy data */ 615 for (i = 0; i < buf.size; i++, (*sz)++) { 616 data_buf[*sz] = buf.data[i]; 617 } 618 619 space_left -= buf.size; 620 } 621 622 return (0); 623 } 624 625 /* callback from ldc */ 626 static uint_t 627 vcc_ldc_cb(uint64_t event, caddr_t arg) 628 { 629 630 vcc_port_t *vport = (vcc_port_t *)arg; 631 boolean_t hasdata; 632 633 /* 634 * do not need to hold lock because if ldc calls back, the 635 * ldc_handle must be valid. 636 */ 637 D2("vcc_ldc_cb: callback invoked port=%d events=%llx\n", 638 vport->number, event); 639 640 /* check event from ldc */ 641 if (event & LDC_EVT_WRITE) { 642 /* channel has space for write */ 643 644 i_vcc_set_port_status(vport, &vport->write_cv, 645 VCC_PORT_LDC_WRITE_READY); 646 return (LDC_SUCCESS); 647 } 648 649 if (event & LDC_EVT_READ) { 650 651 /* channel has data for read */ 652 (void) ldc_chkq(vport->ldc_handle, &hasdata); 653 if (!hasdata) { 654 /* data already read */ 655 return (LDC_SUCCESS); 656 } 657 658 i_vcc_set_port_status(vport, &vport->read_cv, 659 VCC_PORT_LDC_DATA_READY); 660 return (LDC_SUCCESS); 661 } 662 663 if (event & LDC_EVT_DOWN) { 664 /* channel is down */ 665 i_vcc_set_port_status(vport, &vport->write_cv, 666 VCC_PORT_LDC_LINK_DOWN); 667 cv_broadcast(&vport->read_cv); 668 669 } 670 671 return (LDC_SUCCESS); 672 673 } 674 675 676 /* configure a vcc port with ldc channel */ 677 static int 678 i_vcc_config_port(vcc_t *vccp, uint_t portno, uint64_t ldc_id) 679 { 680 int rv = EIO; 681 vcc_port_t *vport; 682 683 if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) { 684 cmn_err(CE_CONT, "i_vcc_config_port: invalid port number %d\n", 685 portno); 686 return (EINVAL); 687 } 688 689 vport = &(vccp->port[portno]); 690 if ((vport->status & VCC_PORT_AVAIL) == 0) { 691 cmn_err(CE_CONT, "i_vcc_config_port: port@%d does not exist\n", 692 portno); 693 return (EINVAL); 694 } 695 696 697 if (vport->ldc_id != VCC_INVALID_CHANNEL) { 698 cmn_err(CE_CONT, "i_vcc_config_port: port@%d channel already" 699 "configured\n", portno); 700 return (EINVAL); 701 } 702 703 mutex_enter(&vport->lock); 704 705 /* store the ldc ID */ 706 vport->ldc_id = ldc_id; 707 /* check if someone has already opened this port */ 708 if (vport->status & VCC_PORT_OPEN) { 709 710 if ((rv = i_vcc_ldc_init(vccp, vport)) != 0) { 711 mutex_exit(&vport->lock); 712 return (rv); 713 } 714 715 /* mark port as ready */ 716 vport->status |= VCC_PORT_LDC_CHANNEL_READY; 717 cv_broadcast(&vport->read_cv); 718 cv_broadcast(&vport->write_cv); 719 } 720 721 mutex_exit(&vport->lock); 722 723 D1("i_vcc_config_port: port@%d ldc=%d, domain=%s", 724 vport->number, vport->ldc_id, vport->minorp->domain_name); 725 726 return (0); 727 } 728 729 /* add a vcc console port */ 730 static int 731 i_vcc_add_port(vcc_t *vccp, char *group_name, uint64_t tcp_port, 732 uint_t portno, char *domain_name) 733 { 734 int instance; 735 int rv = MDEG_FAILURE; 736 minor_t minor; 737 vcc_port_t *vport; 738 uint_t minor_idx; 739 char name[MAXPATHLEN]; 740 741 if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) { 742 DWARN("i_vcc_add_port: invalid port number %d\n", portno); 743 return (MDEG_FAILURE); 744 } 745 746 vport = &(vccp->port[portno]); 747 if (vport->status & VCC_PORT_AVAIL) { 748 /* this port already exists */ 749 cmn_err(CE_CONT, "i_vcc_add_port: invalid port - port@%d " 750 "exists\n", portno); 751 return (MDEG_FAILURE); 752 } 753 754 vport->number = portno; 755 vport->ldc_id = VCC_INVALID_CHANNEL; 756 757 if (domain_name == NULL) { 758 cmn_err(CE_CONT, "i_vcc_add_port: invalid domain name\n"); 759 return (MDEG_FAILURE); 760 } 761 762 if (group_name == NULL) { 763 cmn_err(CE_CONT, "i_vcc_add_port: invalid group name\n"); 764 return (MDEG_FAILURE); 765 } 766 767 /* look up minor number */ 768 for (minor_idx = 0; minor_idx < vccp->minors_assigned; minor_idx++) { 769 if (strcmp(vccp->minor_tbl[minor_idx].domain_name, 770 domain_name) == 0) { 771 /* found previous assigned minor number */ 772 break; 773 } 774 } 775 776 if (minor_idx == vccp->minors_assigned) { 777 /* end of lookup - assign new minor number */ 778 if (minor_idx == VCC_MAX_PORTS) { 779 cmn_err(CE_CONT, "i_vcc_add_port:" 780 "too many minornodes (%d)\n", 781 minor_idx); 782 return (MDEG_FAILURE); 783 } 784 785 (void) strlcpy(vccp->minor_tbl[minor_idx].domain_name, 786 domain_name, MAXPATHLEN); 787 788 vccp->minors_assigned++; 789 } 790 791 vport->minorp = &vccp->minor_tbl[minor_idx]; 792 vccp->minor_tbl[minor_idx].portno = portno; 793 794 (void) strlcpy(vport->group_name, group_name, MAXPATHLEN); 795 796 vport->tcp_port = tcp_port; 797 D1("i_vcc_add_port:@%d domain=%s, group=%s, tcp=%lld", 798 vport->number, vport->minorp->domain_name, 799 vport->group_name, vport->tcp_port); 800 801 802 /* 803 * Create a minor node. The minor number is 804 * (instance << VCC_INST_SHIFT) | minor_idx 805 */ 806 instance = ddi_get_instance(vccp->dip); 807 808 minor = (instance << VCC_INST_SHIFT) | (minor_idx); 809 810 (void) snprintf(name, MAXPATHLEN - 1, "%s%s", VCC_MINOR_NAME_PREFIX, 811 domain_name); 812 813 rv = ddi_create_minor_node(vccp->dip, name, S_IFCHR, minor, 814 DDI_NT_SERIAL, 0); 815 816 if (rv != DDI_SUCCESS) { 817 vccp->minors_assigned--; 818 return (MDEG_FAILURE); 819 } 820 821 mutex_enter(&vport->lock); 822 vport->status = VCC_PORT_AVAIL | VCC_PORT_ADDED; 823 mutex_exit(&vport->lock); 824 825 826 return (MDEG_SUCCESS); 827 } 828 829 /* delete a port */ 830 static int 831 i_vcc_delete_port(vcc_t *vccp, vcc_port_t *vport) 832 { 833 834 char name[MAXPATHLEN]; 835 int rv; 836 837 838 ASSERT(mutex_owned(&vport->lock)); 839 840 if ((vport->status & VCC_PORT_AVAIL) == 0) { 841 D1("vcc_del_port port already deleted \n"); 842 return (0); 843 } 844 845 if (vport->status & VCC_PORT_OPEN) { 846 /* do not block mdeg callback */ 847 vport->valid_pid = VCC_NO_PID_BLOCKING; 848 rv = i_vcc_close_port(vport); 849 } 850 851 /* remove minor node */ 852 (void) snprintf(name, MAXPATHLEN-1, "%s%s", VCC_MINOR_NAME_PREFIX, 853 vport->minorp->domain_name); 854 855 ddi_remove_minor_node(vccp->dip, name); 856 857 /* let read and write thread know */ 858 cv_broadcast(&vport->read_cv); 859 cv_broadcast(&vport->write_cv); 860 vport->status = 0; 861 return (rv); 862 863 864 } 865 866 /* register callback to MDEG */ 867 static int 868 i_vcc_mdeg_register(vcc_t *vccp, int instance) 869 { 870 mdeg_prop_spec_t *pspecp; 871 mdeg_node_spec_t *ispecp; 872 mdeg_handle_t mdeg_hdl; 873 int sz; 874 int rv; 875 876 /* 877 * Allocate and initialize a per-instance copy 878 * of the global property spec array that will 879 * uniquely identify this vcc instance. 880 */ 881 sz = sizeof (vcc_prop_template); 882 pspecp = kmem_alloc(sz, KM_SLEEP); 883 884 bcopy(vcc_prop_template, pspecp, sz); 885 886 VCC_SET_MDEG_PROP_INST(pspecp, instance); 887 888 /* initialize the complete prop spec structure */ 889 ispecp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_SLEEP); 890 ispecp->namep = "virtual-device"; 891 ispecp->specp = pspecp; 892 893 /* perform the registration */ 894 rv = mdeg_register(ispecp, &vcc_port_match, vcc_mdeg_cb, 895 vccp, &mdeg_hdl); 896 897 if (rv != MDEG_SUCCESS) { 898 cmn_err(CE_CONT, "i_vcc_mdeg_register:" 899 "mdeg_register failed (%d)\n", rv); 900 kmem_free(ispecp, sizeof (mdeg_node_spec_t)); 901 kmem_free(pspecp, sz); 902 return (DDI_FAILURE); 903 } 904 905 /* save off data that will be needed later */ 906 vccp->md_ispecp = (void *)ispecp; 907 vccp->mdeg_hdl = mdeg_hdl; 908 909 return (0); 910 } 911 912 /* destroy all mutex from port table */ 913 static void 914 i_vcc_cleanup_port_table(vcc_t *vccp) 915 { 916 int i; 917 vcc_port_t *vport; 918 919 for (i = 0; i < VCC_MAX_PORTS; i++) { 920 vport = &(vccp->port[i]); 921 mutex_destroy(&vport->lock); 922 cv_destroy(&vport->read_cv); 923 cv_destroy(&vport->write_cv); 924 } 925 } 926 927 /* 928 * attach(9E): attach a device to the system. 929 * called once for each instance of the device on the system. 930 */ 931 static int 932 vcc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 933 { 934 int i, instance, inst; 935 int rv = DDI_FAILURE; 936 vcc_t *vccp; 937 minor_t minor; 938 vcc_port_t *vport; 939 940 switch (cmd) { 941 942 case DDI_ATTACH: 943 944 instance = ddi_get_instance(dip); 945 if (ddi_soft_state_zalloc(vcc_ssp, instance) != DDI_SUCCESS) 946 return (DDI_FAILURE); 947 948 vccp = ddi_get_soft_state(vcc_ssp, instance); 949 if (vccp == NULL) { 950 ddi_soft_state_free(vccp, instance); 951 return (ENXIO); 952 } 953 954 D1("vcc_attach: DDI_ATTACH instance=%d\n", instance); 955 956 /* initialize the mutex */ 957 mutex_init(&vccp->lock, NULL, MUTEX_DRIVER, NULL); 958 959 mutex_enter(&vccp->lock); 960 961 vccp->dip = dip; 962 963 for (i = 0; i < VCC_MAX_PORTS; i++) { 964 vport = &(vccp->port[i]); 965 mutex_init(&vport->lock, NULL, MUTEX_DRIVER, NULL); 966 cv_init(&vport->read_cv, NULL, CV_DRIVER, NULL); 967 cv_init(&vport->write_cv, NULL, CV_DRIVER, NULL); 968 vport->valid_pid = VCC_NO_PID_BLOCKING; 969 } 970 971 vport = &vccp->port[VCC_CONTROL_PORT]; 972 mutex_enter(&vport->lock); 973 974 vport->minorp = &vccp->minor_tbl[VCC_CONTROL_MINOR_IDX]; 975 vport->status |= VCC_PORT_AVAIL; 976 977 /* create a minor node for vcc control */ 978 minor = (instance << VCC_INST_SHIFT) | VCC_CONTROL_MINOR_IDX; 979 980 vccp->minor_tbl[VCC_CONTROL_PORT].portno = 981 VCC_CONTROL_MINOR_IDX; 982 983 984 rv = ddi_create_minor_node(vccp->dip, "ctl", S_IFCHR, minor, 985 DDI_NT_SERIAL, 0); 986 987 mutex_exit(&vport->lock); 988 989 if (rv != DDI_SUCCESS) { 990 cmn_err(CE_CONT, "vcc_attach: error" 991 "creating control minor node\n"); 992 993 i_vcc_cleanup_port_table(vccp); 994 995 mutex_exit(&vccp->lock); 996 /* clean up soft state */ 997 ddi_soft_state_free(vccp, instance); 998 999 return (DDI_FAILURE); 1000 } 1001 1002 /* get the instance number by reading 'reg' property */ 1003 inst = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 1004 "reg", -1); 1005 if (inst == -1) { 1006 cmn_err(CE_CONT, "vcc_attach: vcc%d has no " 1007 "'reg' property\n", 1008 ddi_get_instance(dip)); 1009 1010 i_vcc_cleanup_port_table(vccp); 1011 1012 /* remove minor */ 1013 ddi_remove_minor_node(vccp->dip, NULL); 1014 1015 /* clean up soft state */ 1016 mutex_exit(&vccp->lock); 1017 ddi_soft_state_free(vccp, instance); 1018 1019 return (DDI_FAILURE); 1020 } 1021 1022 /* 1023 * Mdeg might invoke callback in the same call sequence 1024 * if there is a domain port at the time of registration. 1025 * Since the callback also grabs vcc->lock mutex, to avoid 1026 * mutex reentry error, release the lock before registration 1027 */ 1028 mutex_exit(&vccp->lock); 1029 1030 /* register for notifications from Zeus */ 1031 rv = i_vcc_mdeg_register(vccp, inst); 1032 if (rv != MDEG_SUCCESS) { 1033 cmn_err(CE_CONT, "vcc_attach: error register to MD\n"); 1034 1035 i_vcc_cleanup_port_table(vccp); 1036 1037 /* remove minor */ 1038 ddi_remove_minor_node(vccp->dip, NULL); 1039 1040 /* clean up soft state */ 1041 ddi_soft_state_free(vccp, instance); 1042 1043 return (DDI_FAILURE); 1044 } 1045 1046 return (DDI_SUCCESS); 1047 1048 case DDI_RESUME: 1049 1050 return (DDI_SUCCESS); 1051 1052 default: 1053 1054 return (DDI_FAILURE); 1055 } 1056 } 1057 1058 /* 1059 * detach(9E): detach a device from the system. 1060 */ 1061 static int 1062 vcc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 1063 { 1064 int i, instance; 1065 vcc_t *vccp; 1066 mdeg_node_spec_t *ispecp; 1067 vcc_port_t *vport; 1068 1069 switch (cmd) { 1070 1071 case DDI_DETACH: 1072 1073 instance = ddi_get_instance(dip); 1074 vccp = ddi_get_soft_state(vcc_ssp, instance); 1075 if (vccp == NULL) 1076 return (ENXIO); 1077 1078 D1("vcc_detach: DDI_DETACH instance=%d\n", instance); 1079 1080 mutex_enter(&vccp->lock); 1081 1082 /* unregister from MD event generator */ 1083 1084 ASSERT(vccp->mdeg_hdl); 1085 (void) mdeg_unregister(vccp->mdeg_hdl); 1086 1087 ispecp = (mdeg_node_spec_t *)vccp->md_ispecp; 1088 ASSERT(ispecp); 1089 1090 kmem_free(ispecp->specp, sizeof (vcc_prop_template)); 1091 kmem_free(ispecp, sizeof (mdeg_node_spec_t)); 1092 1093 /* remove minor nodes */ 1094 ddi_remove_minor_node(vccp->dip, NULL); 1095 mutex_exit(&vccp->lock); 1096 1097 for (i = 0; i < VCC_MAX_PORTS; i++) { 1098 1099 vport = &vccp->port[i]; 1100 mutex_enter(&vport->lock); 1101 if (i == VCC_CONTROL_PORT) { 1102 if (vport->status & VCC_PORT_OPEN) { 1103 (void) i_vcc_close_port(vport); 1104 } 1105 } 1106 1107 if ((vccp->port[i].status & VCC_PORT_AVAIL) && 1108 (i != VCC_CONTROL_PORT)) { 1109 D1("vcc_detach: removing port port@%d\n", i); 1110 (void) i_vcc_delete_port(vccp, vport); 1111 } 1112 mutex_exit(&vport->lock); 1113 cv_destroy(&vport->read_cv); 1114 cv_destroy(&vport->write_cv); 1115 mutex_destroy(&vport->lock); 1116 } 1117 1118 1119 1120 /* destroy mutex and free the soft state */ 1121 mutex_destroy(&vccp->lock); 1122 ddi_soft_state_free(vcc_ssp, instance); 1123 1124 return (DDI_SUCCESS); 1125 1126 case DDI_SUSPEND: 1127 1128 return (DDI_SUCCESS); 1129 1130 default: 1131 1132 return (DDI_FAILURE); 1133 } 1134 } 1135 1136 /* cb_open */ 1137 static int 1138 vcc_open(dev_t *devp, int flag, int otyp, cred_t *cred) 1139 { 1140 _NOTE(ARGUNUSED(otyp, cred)) 1141 1142 int instance; 1143 int rv = EIO; 1144 minor_t minor; 1145 uint_t portno; 1146 vcc_t *vccp; 1147 vcc_port_t *vport; 1148 1149 minor = getminor(*devp); 1150 instance = VCCINST(minor); 1151 1152 vccp = ddi_get_soft_state(vcc_ssp, instance); 1153 if (vccp == NULL) { 1154 return (ENXIO); 1155 } 1156 1157 portno = VCCPORT(vccp, minor); 1158 1159 vport = &(vccp->port[portno]); 1160 1161 mutex_enter(&vport->lock); 1162 1163 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1164 /* port may be removed */ 1165 mutex_exit(&vport->lock); 1166 return (ENXIO); 1167 } 1168 1169 if (vport->status & VCC_PORT_OPEN) { 1170 /* only one open per port */ 1171 cmn_err(CE_CONT, "vcc_open: virtual-console-concentrator@%d:%d " 1172 "is already open\n", instance, portno); 1173 mutex_exit(&vport->lock); 1174 return (EAGAIN); 1175 } 1176 1177 /* check minor no and pid */ 1178 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 1179 vport)) != 0) { 1180 mutex_exit(&vport->lock); 1181 return (rv); 1182 } 1183 1184 if (portno == VCC_CONTROL_PORT) { 1185 vport->status |= VCC_PORT_OPEN; 1186 mutex_exit(&vport->lock); 1187 return (0); 1188 } 1189 1190 /* 1191 * the port may just be added by mdeg callback and may 1192 * not be configured yet. 1193 */ 1194 if (vport->ldc_id == VCC_INVALID_CHANNEL) { 1195 mutex_exit(&vport->lock); 1196 return (ENXIO); 1197 } 1198 1199 1200 /* check if channel has been initialized */ 1201 if ((vport->status & VCC_PORT_LDC_CHANNEL_READY) == 0) { 1202 rv = i_vcc_ldc_init(vccp, vport); 1203 if (rv) { 1204 mutex_exit(&vport->lock); 1205 return (EIO); 1206 } 1207 1208 /* mark port as ready */ 1209 vport->status |= VCC_PORT_LDC_CHANNEL_READY; 1210 } 1211 1212 vport->status |= VCC_PORT_USE_READ_LDC | VCC_PORT_USE_WRITE_LDC| 1213 VCC_PORT_TERM_RD|VCC_PORT_TERM_WR|VCC_PORT_OPEN; 1214 1215 if ((flag & O_NONBLOCK) || (flag & O_NDELAY)) { 1216 vport->status |= VCC_PORT_NONBLOCK; 1217 } 1218 1219 mutex_exit(&vport->lock); 1220 1221 return (0); 1222 } 1223 1224 /* close port */ 1225 static int 1226 i_vcc_close_port(vcc_port_t *vport) 1227 { 1228 1229 if ((vport->status & VCC_PORT_OPEN) == 0) { 1230 return (0); 1231 } 1232 1233 ASSERT(mutex_owned(&vport->lock)); 1234 1235 if (vport->status & VCC_PORT_LDC_CHANNEL_READY) { 1236 /* clean up ldc channel */ 1237 i_vcc_ldc_fini(vport); 1238 vport->status &= ~VCC_PORT_LDC_CHANNEL_READY; 1239 } 1240 1241 /* reset rd/wr suspends */ 1242 vport->status |= VCC_PORT_TERM_RD | VCC_PORT_TERM_WR; 1243 vport->status &= ~VCC_PORT_NONBLOCK; 1244 vport->status &= ~VCC_PORT_OPEN; 1245 vport->valid_pid = VCC_NO_PID_BLOCKING; 1246 1247 /* signal any blocked read and write thread */ 1248 cv_broadcast(&vport->read_cv); 1249 cv_broadcast(&vport->write_cv); 1250 1251 return (0); 1252 } 1253 1254 /* cb_close */ 1255 static int 1256 vcc_close(dev_t dev, int flag, int otyp, cred_t *cred) 1257 { 1258 _NOTE(ARGUNUSED(flag, otyp, cred)) 1259 1260 int instance; 1261 minor_t minor; 1262 int rv = EIO; 1263 uint_t portno; 1264 vcc_t *vccp; 1265 vcc_port_t *vport; 1266 1267 minor = getminor(dev); 1268 1269 instance = VCCINST(minor); 1270 vccp = ddi_get_soft_state(vcc_ssp, instance); 1271 if (vccp == NULL) { 1272 return (ENXIO); 1273 } 1274 1275 portno = VCCPORT(vccp, minor); 1276 1277 D1("vcc_close: closing virtual-console-concentrator@%d:%d\n", 1278 instance, portno); 1279 vport = &(vccp->port[portno]); 1280 1281 1282 /* 1283 * needs lock to provent i_vcc_delete_port, which is called by 1284 * the mdeg callback, from closing port. 1285 */ 1286 mutex_enter(&vport->lock); 1287 1288 if ((vport->status & VCC_PORT_OPEN) == 0) { 1289 mutex_exit(&vport->lock); 1290 return (0); 1291 } 1292 1293 if (portno == VCC_CONTROL_PORT) { 1294 /* 1295 * vntsd closes control port before it exits. There 1296 * could be events still pending for vntsd. 1297 */ 1298 mutex_exit(&vport->lock); 1299 rv = i_vcc_reset_events(vccp); 1300 return (0); 1301 } 1302 1303 1304 /* check minor no and pid */ 1305 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 1306 vport)) != 0) { 1307 mutex_exit(&vport->lock); 1308 return (rv); 1309 } 1310 1311 rv = i_vcc_close_port(vport); 1312 mutex_exit(&vport->lock); 1313 1314 return (rv); 1315 } 1316 1317 /* 1318 * ioctl VCC_CONS_TBL - vntsd allocates buffer according to return of 1319 * VCC_NUM_PORTS. However, when vntsd requests for the console table, console 1320 * ports could be deleted or added. parameter num_ports is number of structures 1321 * that vntsd allocated for the table. If there are more ports than 1322 * num_ports, set up to wakeup vntsd to add ports. 1323 * If there less ports than num_ports, fill (-1) for cons_no to tell vntsd. 1324 */ 1325 static int 1326 i_vcc_cons_tbl(vcc_t *vccp, uint_t num_ports, caddr_t buf, int mode) 1327 { 1328 vcc_console_t cons; 1329 int i; 1330 vcc_port_t *vport; 1331 boolean_t notify_vntsd = B_FALSE; 1332 char pathname[MAXPATHLEN]; 1333 1334 1335 (void) ddi_pathname(vccp->dip, pathname); 1336 for (i = 0; i < VCC_MAX_PORTS; i++) { 1337 1338 vport = &vccp->port[i]; 1339 1340 if (i == VCC_CONTROL_PORT) { 1341 continue; 1342 } 1343 1344 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1345 continue; 1346 } 1347 1348 /* a port exists before vntsd becomes online */ 1349 mutex_enter(&vport->lock); 1350 1351 if (num_ports == 0) { 1352 /* more ports than vntsd's buffer can hold */ 1353 vport->status |= VCC_PORT_ADDED; 1354 notify_vntsd = B_TRUE; 1355 mutex_exit(&vport->lock); 1356 continue; 1357 } 1358 1359 bzero(&cons, sizeof (vcc_console_t)); 1360 1361 /* construct console buffer */ 1362 cons.cons_no = vport->number; 1363 cons.tcp_port = vport->tcp_port; 1364 (void) memcpy(cons.domain_name, 1365 vport->minorp->domain_name, MAXPATHLEN); 1366 1367 (void) memcpy(cons.group_name, vport->group_name, 1368 MAXPATHLEN); 1369 vport->status &= ~VCC_PORT_ADDED; 1370 mutex_exit(&vport->lock); 1371 1372 (void) snprintf(cons.dev_name, MAXPATHLEN-1, "%s:%s%s", 1373 pathname, VCC_MINOR_NAME_PREFIX, cons.domain_name); 1374 1375 /* copy out data */ 1376 if (ddi_copyout(&cons, (void *)buf, 1377 sizeof (vcc_console_t), mode)) { 1378 mutex_exit(&vport->lock); 1379 return (EFAULT); 1380 } 1381 buf += sizeof (vcc_console_t); 1382 1383 num_ports--; 1384 1385 } 1386 1387 if (num_ports == 0) { 1388 /* vntsd's buffer is full */ 1389 1390 if (notify_vntsd) { 1391 /* more ports need to notify vntsd */ 1392 vport = &vccp->port[VCC_CONTROL_PORT]; 1393 mutex_enter(&vport->lock); 1394 vport->pollevent |= VCC_POLL_ADD_PORT; 1395 mutex_exit(&vport->lock); 1396 } 1397 1398 return (0); 1399 } 1400 1401 /* less ports than vntsd expected */ 1402 bzero(&cons, sizeof (vcc_console_t)); 1403 cons.cons_no = -1; 1404 1405 while (num_ports > 0) { 1406 /* fill vntsd buffer with no console */ 1407 if (ddi_copyout(&cons, (void *)buf, 1408 sizeof (vcc_console_t), mode) != 0) { 1409 mutex_exit(&vport->lock); 1410 return (EFAULT); 1411 } 1412 D1("i_vcc_cons_tbl: a port is deleted\n"); 1413 buf += sizeof (vcc_console_t) +MAXPATHLEN; 1414 num_ports--; 1415 } 1416 1417 return (0); 1418 } 1419 1420 1421 /* turn off event flag if there is no more change */ 1422 static void 1423 i_vcc_turn_off_event(vcc_t *vccp, uint32_t port_status, uint32_t event) 1424 { 1425 1426 vcc_port_t *vport; 1427 int i; 1428 1429 for (i = 0; i < VCC_MAX_PORTS; i++) { 1430 1431 vport = &(vccp->port[i]); 1432 1433 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1434 continue; 1435 } 1436 1437 1438 if (vport->status & port_status) { 1439 /* more port changes status */ 1440 return; 1441 } 1442 1443 } 1444 1445 /* no more changed port */ 1446 vport = &vccp->port[VCC_CONTROL_PORT]; 1447 1448 /* turn off event */ 1449 mutex_enter(&vport->lock); 1450 vport->pollevent &= ~event; 1451 mutex_exit(&vport->lock); 1452 } 1453 1454 /* ioctl VCC_CONS_INFO */ 1455 static int 1456 i_vcc_cons_info(vcc_t *vccp, caddr_t buf, int mode) 1457 { 1458 vcc_console_t cons; 1459 uint_t portno; 1460 vcc_port_t *vport; 1461 char pathname[MAXPATHLEN]; 1462 1463 /* read in portno */ 1464 if (ddi_copyin((void*)buf, &portno, sizeof (uint_t), mode)) { 1465 return (EFAULT); 1466 } 1467 1468 D1("i_vcc_cons_info@%d:\n", portno); 1469 1470 if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) { 1471 return (EINVAL); 1472 } 1473 1474 vport = &vccp->port[portno]; 1475 1476 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1477 return (EINVAL); 1478 } 1479 1480 mutex_enter(&vport->lock); 1481 vport->status &= ~VCC_PORT_ADDED; 1482 1483 /* construct configruation data */ 1484 bzero(&cons, sizeof (vcc_console_t)); 1485 1486 cons.cons_no = vport->number; 1487 cons.tcp_port = vport->tcp_port; 1488 1489 (void) memcpy(cons.domain_name, vport->minorp->domain_name, MAXPATHLEN); 1490 1491 (void) memcpy(cons.group_name, vport->group_name, MAXPATHLEN); 1492 1493 mutex_exit(&vport->lock); 1494 1495 (void) ddi_pathname(vccp->dip, pathname), 1496 1497 /* copy device name */ 1498 (void) snprintf(cons.dev_name, MAXPATHLEN-1, "%s:%s%s", 1499 pathname, VCC_MINOR_NAME_PREFIX, cons.domain_name); 1500 /* copy data */ 1501 if (ddi_copyout(&cons, (void *)buf, 1502 sizeof (vcc_console_t), mode) != 0) { 1503 mutex_exit(&vport->lock); 1504 return (EFAULT); 1505 } 1506 1507 D1("i_vcc_cons_info@%d:domain:%s serv:%s tcp@%lld %s\n", 1508 cons.cons_no, cons.domain_name, 1509 cons.group_name, cons.tcp_port, cons.dev_name); 1510 1511 i_vcc_turn_off_event(vccp, VCC_PORT_ADDED, VCC_POLL_ADD_PORT); 1512 1513 return (0); 1514 } 1515 1516 1517 /* response to vntsd inquiry ioctl call */ 1518 static int 1519 i_vcc_inquiry(vcc_t *vccp, caddr_t buf, int mode) 1520 { 1521 vcc_port_t *vport; 1522 uint_t i; 1523 vcc_response_t msg; 1524 1525 vport = &(vccp->port[VCC_CONTROL_PORT]); 1526 1527 if ((vport->pollevent & VCC_POLL_ADD_PORT) == 0) { 1528 return (EINVAL); 1529 } 1530 1531 /* an added port */ 1532 1533 D1("i_vcc_inquiry\n"); 1534 1535 for (i = 0; i < VCC_MAX_PORTS; i++) { 1536 if ((vccp->port[i].status & VCC_PORT_AVAIL) == 0) { 1537 continue; 1538 } 1539 1540 if (vccp->port[i].status & VCC_PORT_ADDED) { 1541 /* port added */ 1542 msg.reason = VCC_CONS_ADDED; 1543 msg.cons_no = i; 1544 1545 if (ddi_copyout((void *)&msg, (void *)buf, 1546 sizeof (msg), mode) == -1) { 1547 cmn_err(CE_CONT, "i_vcc_find_changed_port:" 1548 "ddi_copyout" 1549 " failed\n"); 1550 return (EFAULT); 1551 } 1552 return (0); 1553 } 1554 } 1555 1556 /* the added port was deleted before vntsd wakes up */ 1557 msg.reason = VCC_CONS_MISS_ADDED; 1558 1559 if (ddi_copyout((void *)&msg, (void *)buf, 1560 sizeof (msg), mode) == -1) { 1561 cmn_err(CE_CONT, "i_vcc_find_changed_port: ddi_copyout" 1562 " failed\n"); 1563 return (EFAULT); 1564 } 1565 1566 return (0); 1567 } 1568 1569 /* clean up events after vntsd exits */ 1570 static int 1571 i_vcc_reset_events(vcc_t *vccp) 1572 { 1573 uint_t i; 1574 vcc_port_t *vport; 1575 1576 for (i = 0; i < VCC_MAX_PORTS; i++) { 1577 vport = &(vccp->port[i]); 1578 1579 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1580 continue; 1581 } 1582 1583 ASSERT(!mutex_owned(&vport->lock)); 1584 1585 if (i == VCC_CONTROL_PORT) { 1586 /* close control port */ 1587 mutex_enter(&vport->lock); 1588 vport->status &= ~VCC_PORT_OPEN; 1589 1590 /* clean up poll events */ 1591 vport->pollevent = 0; 1592 vport->pollflag = 0; 1593 mutex_exit(&vport->lock); 1594 continue; 1595 } 1596 if (vport->status & VCC_PORT_ADDED) { 1597 /* pending added port event to vntsd */ 1598 mutex_enter(&vport->lock); 1599 vport->status &= ~VCC_PORT_ADDED; 1600 mutex_exit(&vport->lock); 1601 } 1602 1603 } 1604 1605 vport = &vccp->port[VCC_CONTROL_PORT]; 1606 1607 return (0); 1608 } 1609 1610 /* ioctl VCC_FORCE_CLOSE */ 1611 static int 1612 i_vcc_force_close(vcc_t *vccp, caddr_t buf, int mode) 1613 { 1614 uint_t portno; 1615 vcc_port_t *vport; 1616 int rv; 1617 1618 /* read in portno */ 1619 if (ddi_copyin((void*)buf, &portno, sizeof (uint_t), mode)) { 1620 return (EFAULT); 1621 } 1622 1623 D1("i_vcc_force_close@%d:\n", portno); 1624 1625 if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) { 1626 return (EINVAL); 1627 } 1628 1629 vport = &vccp->port[portno]; 1630 1631 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1632 return (EINVAL); 1633 } 1634 1635 mutex_enter(&vport->lock); 1636 1637 rv = i_vcc_close_port(vport); 1638 1639 /* block callers other than vntsd */ 1640 vport->valid_pid = ddi_get_pid(); 1641 1642 mutex_exit(&vport->lock); 1643 return (rv); 1644 1645 } 1646 1647 /* ioctl VCC_CONS_STATUS */ 1648 static int 1649 i_vcc_cons_status(vcc_t *vccp, caddr_t buf, int mode) 1650 { 1651 vcc_console_t console; 1652 vcc_port_t *vport; 1653 1654 /* read in portno */ 1655 if (ddi_copyin((void*)buf, &console, sizeof (console), mode)) { 1656 return (EFAULT); 1657 } 1658 1659 D1("i_vcc_cons_status@%d:\n", console.cons_no); 1660 1661 if ((console.cons_no >= VCC_MAX_PORTS) || 1662 (console.cons_no == VCC_CONTROL_PORT)) { 1663 return (EINVAL); 1664 } 1665 1666 1667 vport = &vccp->port[console.cons_no]; 1668 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1669 console.cons_no = -1; 1670 } else if (strncmp(console.domain_name, vport->minorp->domain_name, 1671 MAXPATHLEN)) { 1672 console.cons_no = -1; 1673 } else if (strncmp(console.group_name, vport->group_name, 1674 MAXPATHLEN)) { 1675 console.cons_no = -1; 1676 } else if (console.tcp_port != vport->tcp_port) { 1677 console.cons_no = -1; 1678 } else if (vport->ldc_id == VCC_INVALID_CHANNEL) { 1679 console.cons_no = -1; 1680 } 1681 1682 D1("i_vcc_cons_status@%d: %s %s %llx\n", console.cons_no, 1683 console.group_name, console.domain_name, console.tcp_port); 1684 if (ddi_copyout(&console, (void *)buf, sizeof (console), mode) == -1) { 1685 cmn_err(CE_CONT, "i_vcc_cons_status ddi_copyout failed\n"); 1686 return (EFAULT); 1687 } 1688 1689 return (0); 1690 } 1691 1692 /* cb_ioctl handler for vcc control port */ 1693 static int 1694 i_vcc_ctrl_ioctl(vcc_t *vccp, int cmd, void* arg, int mode) 1695 { 1696 1697 static uint_t num_ports; 1698 1699 1700 switch (cmd) { 1701 1702 case VCC_NUM_CONSOLE: 1703 1704 mutex_enter(&vccp->lock); 1705 num_ports = vccp->num_ports; 1706 mutex_exit(&vccp->lock); 1707 /* number of consoles */ 1708 1709 return (ddi_copyout((void *)&num_ports, arg, 1710 sizeof (int), mode)); 1711 case VCC_CONS_TBL: 1712 1713 /* console config table */ 1714 return (i_vcc_cons_tbl(vccp, num_ports, (caddr_t)arg, mode)); 1715 1716 case VCC_INQUIRY: 1717 1718 /* reason for wakeup */ 1719 return (i_vcc_inquiry(vccp, (caddr_t)arg, mode)); 1720 1721 case VCC_CONS_INFO: 1722 /* a console config */ 1723 return (i_vcc_cons_info(vccp, (caddr_t)arg, mode)); 1724 1725 case VCC_FORCE_CLOSE: 1726 /* force to close a console */ 1727 return (i_vcc_force_close(vccp, (caddr_t)arg, mode)); 1728 1729 case VCC_CONS_STATUS: 1730 /* console status */ 1731 return (i_vcc_cons_status(vccp, (caddr_t)arg, mode)); 1732 1733 default: 1734 1735 /* unknown command */ 1736 return (ENODEV); 1737 } 1738 1739 1740 } 1741 1742 /* write data to ldc. may block if channel has no space for write */ 1743 static int 1744 i_vcc_write_ldc(vcc_port_t *vport, vcc_msg_t *buf) 1745 { 1746 int rv = EIO; 1747 size_t size; 1748 1749 ASSERT(mutex_owned(&vport->lock)); 1750 ASSERT((vport->status & VCC_PORT_USE_WRITE_LDC) == 0); 1751 1752 for (; ; ) { 1753 1754 size = VCC_HDR_SZ + buf->size; 1755 rv = ldc_write(vport->ldc_handle, (caddr_t)buf, &size); 1756 1757 D1("i_vcc_write_ldc: port@%d: err=%d %d bytes\n", 1758 vport->number, rv, size); 1759 1760 if (rv == 0) { 1761 return (rv); 1762 } 1763 1764 if (rv != EWOULDBLOCK) { 1765 return (EIO); 1766 } 1767 1768 if (vport->status & VCC_PORT_NONBLOCK) { 1769 return (EAGAIN); 1770 } 1771 1772 /* block util ldc has more space */ 1773 1774 rv = i_vcc_wait_port_status(vport, &vport->write_cv, 1775 VCC_PORT_LDC_WRITE_READY); 1776 1777 if (rv) { 1778 return (rv); 1779 } 1780 1781 vport->status &= ~VCC_PORT_LDC_WRITE_READY; 1782 1783 } 1784 1785 } 1786 1787 1788 1789 /* cb_ioctl handler for port ioctl */ 1790 static int 1791 i_vcc_port_ioctl(vcc_t *vccp, minor_t minor, int portno, int cmd, void *arg, 1792 int mode) 1793 { 1794 1795 vcc_port_t *vport; 1796 struct termios term; 1797 vcc_msg_t buf; 1798 int rv; 1799 1800 D1("i_vcc_port_ioctl@%d cmd %d\n", portno, cmd); 1801 1802 vport = &(vccp->port[portno]); 1803 1804 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1805 return (EIO); 1806 } 1807 1808 1809 switch (cmd) { 1810 1811 /* terminal support */ 1812 case TCGETA: 1813 case TCGETS: 1814 1815 mutex_enter(&vport->lock); 1816 1817 /* check minor no and pid */ 1818 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 1819 vport)) != 0) { 1820 mutex_exit(&vport->lock); 1821 return (rv); 1822 } 1823 1824 (void) memcpy(&term, &vport->term, sizeof (term)); 1825 mutex_exit(&vport->lock); 1826 1827 return (ddi_copyout(&term, arg, sizeof (term), mode)); 1828 1829 case TCSETS: 1830 case TCSETA: 1831 case TCSETAW: 1832 case TCSETAF: 1833 1834 if (ddi_copyin(arg, &term, sizeof (term), mode) != 0) { 1835 return (EFAULT); 1836 } 1837 1838 mutex_enter(&vport->lock); 1839 1840 /* check minor no and pid */ 1841 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 1842 vport)) != 0) { 1843 mutex_exit(&vport->lock); 1844 return (rv); 1845 } 1846 1847 (void) memcpy(&vport->term, &term, sizeof (term)); 1848 mutex_exit(&vport->lock); 1849 return (0); 1850 1851 1852 case TCSBRK: 1853 1854 /* send break to console */ 1855 mutex_enter(&vport->lock); 1856 1857 /* check minor no and pid */ 1858 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 1859 vport)) != 0) { 1860 mutex_exit(&vport->lock); 1861 return (rv); 1862 } 1863 1864 /* wait for write available */ 1865 rv = i_vcc_wait_port_status(vport, &vport->write_cv, 1866 VCC_PORT_LDC_CHANNEL_READY| VCC_PORT_USE_WRITE_LDC); 1867 if (rv) { 1868 mutex_exit(&vport->lock); 1869 return (rv); 1870 } 1871 1872 vport->status &= ~VCC_PORT_USE_WRITE_LDC; 1873 1874 buf.type = LDC_CONSOLE_CTRL; 1875 buf.ctrl_msg = LDC_CONSOLE_BREAK; 1876 buf.size = 0; 1877 1878 rv = i_vcc_write_ldc(vport, &buf); 1879 1880 mutex_exit(&vport->lock); 1881 1882 i_vcc_set_port_status(vport, &vport->write_cv, 1883 VCC_PORT_USE_WRITE_LDC); 1884 return (0); 1885 1886 case TCXONC: 1887 /* suspend read or write */ 1888 if (ddi_copyin(arg, &cmd, sizeof (int), mode) != 0) { 1889 return (EFAULT); 1890 } 1891 1892 mutex_enter(&vport->lock); 1893 1894 /* check minor no and pid */ 1895 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 1896 vport)) != 0) { 1897 mutex_exit(&vport->lock); 1898 return (rv); 1899 } 1900 1901 1902 switch (cmd) { 1903 1904 case 0: 1905 /* suspend read */ 1906 vport->status &= ~VCC_PORT_TERM_RD; 1907 break; 1908 1909 case 1: 1910 /* resume read */ 1911 vport->status |= VCC_PORT_TERM_RD; 1912 cv_broadcast(&vport->read_cv); 1913 break; 1914 1915 case 2: 1916 /* suspend write */ 1917 vport->status &= ~VCC_PORT_TERM_WR; 1918 break; 1919 1920 case 3: 1921 /* resume write */ 1922 vport->status |= VCC_PORT_TERM_WR; 1923 cv_broadcast(&vport->write_cv); 1924 break; 1925 1926 default: 1927 mutex_exit(&vport->lock); 1928 return (EINVAL); 1929 } 1930 1931 mutex_exit(&vport->lock); 1932 return (0); 1933 1934 case TCFLSH: 1935 return (0); 1936 1937 default: 1938 return (EINVAL); 1939 } 1940 1941 } 1942 1943 /* cb_ioctl */ 1944 static int 1945 vcc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 1946 cred_t *credp, int *rvalp) 1947 { 1948 _NOTE(ARGUNUSED(credp, rvalp)) 1949 1950 int instance; 1951 minor_t minor; 1952 int portno; 1953 vcc_t *vccp; 1954 1955 minor = getminor(dev); 1956 1957 instance = VCCINST(minor); 1958 1959 vccp = ddi_get_soft_state(vcc_ssp, instance); 1960 if (vccp == NULL) { 1961 return (ENXIO); 1962 } 1963 1964 portno = VCCPORT(vccp, minor); 1965 1966 D1("vcc_ioctl: virtual-console-concentrator@%d:%d\n", instance, portno); 1967 1968 if (portno >= VCC_MAX_PORTS) { 1969 cmn_err(CE_CONT, "vcc_ioctl:virtual-console-concentrator@%d" 1970 " invalid portno\n", portno); 1971 return (EINVAL); 1972 } 1973 1974 D1("vcc_ioctl: virtual-console-concentrator@%d:%d ioctl cmd=%d\n", 1975 instance, portno, cmd); 1976 1977 if (portno == VCC_CONTROL_PORT) { 1978 /* control ioctl */ 1979 return (i_vcc_ctrl_ioctl(vccp, cmd, (void *)arg, mode)); 1980 } 1981 1982 /* data port ioctl */ 1983 return (i_vcc_port_ioctl(vccp, minor, portno, cmd, (void *)arg, mode)); 1984 } 1985 1986 /* cb_read */ 1987 static int 1988 vcc_read(dev_t dev, struct uio *uiop, cred_t *credp) 1989 { 1990 _NOTE(ARGUNUSED(credp)) 1991 1992 int instance; 1993 minor_t minor; 1994 uint_t portno; 1995 vcc_t *vccp; 1996 vcc_port_t *vport; 1997 int rv = EIO; /* by default fail ! */ 1998 char *buf; 1999 size_t uio_size; 2000 size_t size; 2001 2002 minor = getminor(dev); 2003 2004 instance = VCCINST(minor); 2005 2006 vccp = ddi_get_soft_state(vcc_ssp, instance); 2007 if (vccp == NULL) { 2008 return (ENXIO); 2009 } 2010 2011 portno = VCCPORT(vccp, minor); 2012 2013 /* no read for control port */ 2014 if (portno == VCC_CONTROL_PORT) { 2015 return (EIO); 2016 } 2017 2018 /* temp buf to hold ldc data */ 2019 uio_size = uiop->uio_resid; 2020 2021 if (uio_size < VCC_MTU_SZ) { 2022 return (EINVAL); 2023 } 2024 2025 vport = &(vccp->port[portno]); 2026 2027 mutex_enter(&vport->lock); 2028 2029 /* check minor no and pid */ 2030 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 2031 vport)) != 0) { 2032 mutex_exit(&vport->lock); 2033 return (rv); 2034 } 2035 2036 rv = i_vcc_wait_port_status(vport, &vport->read_cv, 2037 VCC_PORT_TERM_RD|VCC_PORT_LDC_CHANNEL_READY| 2038 VCC_PORT_USE_READ_LDC); 2039 if (rv) { 2040 mutex_exit(&vport->lock); 2041 return (rv); 2042 } 2043 2044 buf = kmem_alloc(uio_size, KM_SLEEP); 2045 2046 vport->status &= ~VCC_PORT_USE_READ_LDC; 2047 2048 for (; ; ) { 2049 2050 size = uio_size; 2051 rv = i_vcc_read_ldc(vport, buf, &size); 2052 2053 2054 if (rv == EAGAIN) { 2055 /* should block? */ 2056 if (vport->status & VCC_PORT_NONBLOCK) { 2057 break; 2058 } 2059 2060 } else if (rv) { 2061 /* error */ 2062 break; 2063 } 2064 2065 if (size > 0) { 2066 /* got data */ 2067 break; 2068 } 2069 2070 /* wait for data from ldc */ 2071 vport->status &= ~VCC_PORT_LDC_DATA_READY; 2072 2073 mutex_exit(&vport->lock); 2074 i_vcc_set_port_status(vport, &vport->read_cv, 2075 VCC_PORT_USE_READ_LDC); 2076 mutex_enter(&vport->lock); 2077 2078 rv = i_vcc_wait_port_status(vport, &vport->read_cv, 2079 VCC_PORT_TERM_RD|VCC_PORT_LDC_CHANNEL_READY| 2080 VCC_PORT_USE_READ_LDC| VCC_PORT_LDC_DATA_READY); 2081 if (rv) { 2082 break; 2083 } 2084 2085 vport->status &= ~VCC_PORT_USE_READ_LDC; 2086 } 2087 2088 mutex_exit(&vport->lock); 2089 2090 if ((rv == 0) && (size > 0)) { 2091 /* data is in buf */ 2092 rv = uiomove(buf, size, UIO_READ, uiop); 2093 } 2094 2095 kmem_free(buf, uio_size); 2096 i_vcc_set_port_status(vport, &vport->read_cv, VCC_PORT_USE_READ_LDC); 2097 2098 return (rv); 2099 } 2100 2101 2102 /* cb_write */ 2103 static int 2104 vcc_write(dev_t dev, struct uio *uiop, cred_t *credp) 2105 { 2106 _NOTE(ARGUNUSED(credp)) 2107 2108 int instance; 2109 minor_t minor; 2110 size_t size; 2111 size_t bytes; 2112 uint_t portno; 2113 vcc_t *vccp; 2114 2115 vcc_port_t *vport; 2116 int rv = EIO; 2117 2118 vcc_msg_t buf; 2119 2120 minor = getminor(dev); 2121 2122 instance = VCCINST(minor); 2123 2124 vccp = ddi_get_soft_state(vcc_ssp, instance); 2125 if (vccp == NULL) { 2126 return (ENXIO); 2127 } 2128 2129 portno = VCCPORT(vccp, minor); 2130 2131 /* no write for control port */ 2132 if (portno == VCC_CONTROL_PORT) { 2133 return (EIO); 2134 } 2135 vport = &(vccp->port[portno]); 2136 2137 /* 2138 * check if the channel has been configured, 2139 * if write has been suspend and grab write lock. 2140 */ 2141 mutex_enter(&vport->lock); 2142 2143 /* check minor no and pid */ 2144 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 2145 vport)) != 0) { 2146 mutex_exit(&vport->lock); 2147 return (rv); 2148 } 2149 2150 rv = i_vcc_wait_port_status(vport, &vport->write_cv, 2151 VCC_PORT_TERM_WR|VCC_PORT_LDC_CHANNEL_READY| 2152 VCC_PORT_USE_WRITE_LDC); 2153 if (rv) { 2154 mutex_exit(&vport->lock); 2155 return (rv); 2156 } 2157 2158 vport->status &= ~VCC_PORT_USE_WRITE_LDC; 2159 mutex_exit(&vport->lock); 2160 size = uiop->uio_resid; 2161 2162 D2("vcc_write: virtual-console-concentrator@%d:%d writing %d bytes\n", 2163 instance, portno, size); 2164 2165 2166 2167 buf.type = LDC_CONSOLE_DATA; 2168 2169 while (size) { 2170 2171 bytes = MIN(size, VCC_MTU_SZ); 2172 /* move data */ 2173 rv = uiomove(&(buf.data), bytes, UIO_WRITE, uiop); 2174 2175 if (rv) { 2176 break; 2177 } 2178 2179 /* write to ldc */ 2180 buf.size = bytes; 2181 2182 mutex_enter(&vport->lock); 2183 2184 /* check minor no and pid */ 2185 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 2186 vport)) != 0) { 2187 mutex_exit(&vport->lock); 2188 return (rv); 2189 } 2190 2191 rv = i_vcc_write_ldc(vport, &buf); 2192 2193 mutex_exit(&vport->lock); 2194 2195 if (rv) { 2196 break; 2197 } 2198 2199 size -= bytes; 2200 2201 } 2202 2203 i_vcc_set_port_status(vport, &vport->write_cv, VCC_PORT_USE_WRITE_LDC); 2204 return (rv); 2205 } 2206 2207 /* mdeg callback for a removed port */ 2208 static int 2209 i_vcc_md_remove_port(md_t *mdp, mde_cookie_t mdep, vcc_t *vccp) 2210 { 2211 uint64_t portno; /* md requires 64bit for port number */ 2212 int rv = MDEG_FAILURE; 2213 vcc_port_t *vport; 2214 2215 if (md_get_prop_val(mdp, mdep, "id", &portno)) { 2216 cmn_err(CE_CONT, "vcc_mdeg_cb: port has no 'id' property\n"); 2217 return (MDEG_FAILURE); 2218 } 2219 2220 if ((portno >= VCC_MAX_PORTS) || (portno < 0)) { 2221 cmn_err(CE_CONT, "i_vcc_md_remove_port@%ld invalid port no\n", 2222 portno); 2223 return (MDEG_FAILURE); 2224 } 2225 2226 if (portno == VCC_CONTROL_PORT) { 2227 cmn_err(CE_CONT, "i_vcc_md_remove_port@%ld can not remove" 2228 "control port\n", 2229 portno); 2230 return (MDEG_FAILURE); 2231 } 2232 2233 vport = &(vccp->port[portno]); 2234 2235 /* delete the port */ 2236 mutex_enter(&vport->lock); 2237 rv = i_vcc_delete_port(vccp, vport); 2238 mutex_exit(&vport->lock); 2239 2240 mutex_enter(&vccp->lock); 2241 vccp->num_ports--; 2242 mutex_exit(&vccp->lock); 2243 2244 return (rv ? MDEG_FAILURE : MDEG_SUCCESS); 2245 } 2246 2247 static int 2248 i_vcc_get_ldc_id(md_t *md, mde_cookie_t mdep, uint64_t *ldc_id) 2249 { 2250 int num_nodes; 2251 size_t size; 2252 mde_cookie_t *channel; 2253 int num_channels; 2254 2255 2256 if ((num_nodes = md_node_count(md)) <= 0) { 2257 cmn_err(CE_CONT, "i_vcc_get_ldc_channel_id:" 2258 " Invalid node count in Machine Description subtree"); 2259 return (-1); 2260 } 2261 size = num_nodes*(sizeof (*channel)); 2262 channel = kmem_zalloc(size, KM_SLEEP); 2263 ASSERT(channel != NULL); /* because KM_SLEEP */ 2264 2265 2266 /* Look for channel endpoint child(ren) of the vdisk MD node */ 2267 if ((num_channels = md_scan_dag(md, mdep, 2268 md_find_name(md, "channel-endpoint"), 2269 md_find_name(md, "fwd"), channel)) <= 0) { 2270 cmn_err(CE_CONT, "i_vcc_get_ldc_id: No 'channel-endpoint'" 2271 " found for vcc"); 2272 kmem_free(channel, size); 2273 return (-1); 2274 } 2275 2276 /* Get the "id" value for the first channel endpoint node */ 2277 if (md_get_prop_val(md, channel[0], "id", ldc_id) != 0) { 2278 cmn_err(CE_CONT, "i_vcc_get_ldc: No id property found " 2279 "for channel-endpoint of vcc"); 2280 kmem_free(channel, size); 2281 return (-1); 2282 } 2283 2284 if (num_channels > 1) { 2285 cmn_err(CE_CONT, "i_vcc_get_ldc: Warning: Using ID of first" 2286 " of multiple channels for this vcc"); 2287 } 2288 2289 kmem_free(channel, size); 2290 return (0); 2291 } 2292 /* mdeg callback for an added port */ 2293 static int 2294 i_vcc_md_add_port(md_t *mdp, mde_cookie_t mdep, vcc_t *vccp) 2295 { 2296 uint64_t portno; /* md requires 64 bit */ 2297 char *domain_name; 2298 char *group_name; 2299 uint64_t ldc_id; 2300 uint64_t tcp_port; 2301 vcc_port_t *vport; 2302 2303 /* read in the port's reg property */ 2304 if (md_get_prop_val(mdp, mdep, "id", &portno)) { 2305 cmn_err(CE_CONT, "i_vcc_md_add_port_: port has no 'id' " 2306 "property\n"); 2307 return (MDEG_FAILURE); 2308 } 2309 2310 /* read in the port's "vcc-doman-name" property */ 2311 if (md_get_prop_str(mdp, mdep, "vcc-domain-name", &domain_name)) { 2312 cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has " 2313 "no 'vcc-domain-name' property\n", portno); 2314 return (MDEG_FAILURE); 2315 } 2316 2317 2318 /* read in the port's "vcc-group-name" property */ 2319 if (md_get_prop_str(mdp, mdep, "vcc-group-name", &group_name)) { 2320 cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has no " 2321 "'vcc-group-name'property\n", portno); 2322 return (MDEG_FAILURE); 2323 } 2324 2325 2326 /* read in the port's "vcc-tcp-port" property */ 2327 if (md_get_prop_val(mdp, mdep, "vcc-tcp-port", &tcp_port)) { 2328 cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has no" 2329 "'vcc-tcp-port' property\n", portno); 2330 return (MDEG_FAILURE); 2331 } 2332 2333 D1("i_vcc_md_add_port: port@%d domain-name=%s group-name=%s" 2334 " tcp-port=%lld\n", portno, domain_name, group_name, tcp_port); 2335 2336 /* add the port */ 2337 if (i_vcc_add_port(vccp, group_name, tcp_port, portno, domain_name)) { 2338 return (MDEG_FAILURE); 2339 } 2340 2341 vport = &vccp->port[portno]; 2342 if (i_vcc_get_ldc_id(mdp, mdep, &ldc_id)) { 2343 mutex_enter(&vport->lock); 2344 (void) i_vcc_delete_port(vccp, vport); 2345 mutex_exit(&vport->lock); 2346 return (MDEG_FAILURE); 2347 } 2348 2349 /* configure the port */ 2350 if (i_vcc_config_port(vccp, portno, ldc_id)) { 2351 mutex_enter(&vport->lock); 2352 (void) i_vcc_delete_port(vccp, vport); 2353 mutex_exit(&vport->lock); 2354 return (MDEG_FAILURE); 2355 } 2356 2357 mutex_enter(&vccp->lock); 2358 vccp->num_ports++; 2359 mutex_exit(&vccp->lock); 2360 2361 vport = &vccp->port[VCC_CONTROL_PORT]; 2362 2363 if (vport->pollflag & VCC_POLL_CONFIG) { 2364 /* wakeup vntsd */ 2365 mutex_enter(&vport->lock); 2366 vport->pollevent |= VCC_POLL_ADD_PORT; 2367 mutex_exit(&vport->lock); 2368 pollwakeup(&vport->poll, POLLIN); 2369 } 2370 2371 return (MDEG_SUCCESS); 2372 } 2373 2374 /* mdeg callback */ 2375 static int 2376 vcc_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 2377 { 2378 int idx; 2379 vcc_t *vccp; 2380 int rv; 2381 2382 vccp = (vcc_t *)cb_argp; 2383 ASSERT(vccp); 2384 2385 if (resp == NULL) { 2386 return (MDEG_FAILURE); 2387 } 2388 2389 /* added port */ 2390 D1("vcc_mdeg_cb: added %d port(s)\n", resp->added.nelem); 2391 2392 for (idx = 0; idx < resp->added.nelem; idx++) { 2393 rv = i_vcc_md_add_port(resp->added.mdp, 2394 resp->added.mdep[idx], vccp); 2395 2396 if (rv != MDEG_SUCCESS) { 2397 return (rv); 2398 } 2399 } 2400 2401 /* removed port */ 2402 D1("vcc_mdeg_cb: removed %d port(s)\n", resp->removed.nelem); 2403 2404 for (idx = 0; idx < resp->removed.nelem; idx++) { 2405 rv = i_vcc_md_remove_port(resp->removed.mdp, 2406 resp->removed.mdep[idx], vccp); 2407 2408 if (rv != MDEG_SUCCESS) { 2409 return (rv); 2410 } 2411 2412 } 2413 2414 /* 2415 * XXX - Currently no support for updating already active 2416 * ports. So, ignore the match_curr and match_prev arrays 2417 * for now. 2418 */ 2419 2420 return (MDEG_SUCCESS); 2421 } 2422 2423 2424 /* cb_chpoll */ 2425 static int 2426 vcc_chpoll(dev_t dev, short events, int anyyet, short *reventsp, 2427 struct pollhead **phpp) 2428 { 2429 int instance; 2430 minor_t minor; 2431 uint_t portno; 2432 vcc_t *vccp; 2433 vcc_port_t *vport; 2434 2435 minor = getminor(dev); 2436 2437 instance = VCCINST(minor); 2438 2439 vccp = ddi_get_soft_state(vcc_ssp, instance); 2440 if (vccp == NULL) { 2441 return (ENXIO); 2442 } 2443 2444 portno = VCCPORT(vccp, minor); 2445 2446 vport = &(vccp->port[portno]); 2447 2448 D1("vcc_chpoll: virtual-console-concentrator@%d events 0x%x\n", 2449 portno, events); 2450 2451 *reventsp = 0; 2452 2453 if (portno != VCC_CONTROL_PORT) { 2454 return (ENXIO); 2455 } 2456 2457 /* poll for config change */ 2458 if (vport->pollevent) { 2459 *reventsp |= (events & POLLIN); 2460 } 2461 2462 if ((((*reventsp) == 0) && (!anyyet)) || (events & POLLET)) { 2463 *phpp = &vport->poll; 2464 if (events & POLLIN) { 2465 mutex_enter(&vport->lock); 2466 vport->pollflag |= VCC_POLL_CONFIG; 2467 mutex_exit(&vport->lock); 2468 } else { 2469 return (ENXIO); 2470 } 2471 } 2472 2473 D1("vcc_chpoll: virtual-console-concentrator@%d:%d ev=0x%x, " 2474 "rev=0x%x pev=0x%x, flag=0x%x\n", 2475 instance, portno, events, (*reventsp), 2476 vport->pollevent, vport->pollflag); 2477 2478 2479 return (0); 2480 } 2481