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