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