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 inv channel 0x%lx\n", 419 vport->number, vport->ldc_id); 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_OPEN) { 1137 /* only one open per port */ 1138 cmn_err(CE_CONT, "vcc_open: virtual-console-concentrator@%d:%d " 1139 "is already open\n", instance, portno); 1140 mutex_exit(&vport->lock); 1141 return (EAGAIN); 1142 } 1143 1144 /* check minor no and pid */ 1145 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 1146 vport)) != 0) { 1147 mutex_exit(&vport->lock); 1148 return (rv); 1149 } 1150 1151 if (portno == VCC_CONTROL_PORT) { 1152 vport->status |= VCC_PORT_OPEN; 1153 mutex_exit(&vport->lock); 1154 return (0); 1155 } 1156 1157 1158 /* check if channel has been initialized */ 1159 if ((vport->status & VCC_PORT_LDC_CHANNEL_READY) == 0) { 1160 rv = i_vcc_ldc_init(vccp, vport); 1161 if (rv) { 1162 mutex_exit(&vport->lock); 1163 return (EIO); 1164 } 1165 1166 /* mark port as ready */ 1167 vport->status |= VCC_PORT_LDC_CHANNEL_READY; 1168 } 1169 1170 vport->status |= VCC_PORT_USE_READ_LDC | VCC_PORT_USE_WRITE_LDC| 1171 VCC_PORT_TERM_RD|VCC_PORT_TERM_WR|VCC_PORT_OPEN; 1172 1173 if ((flag & O_NONBLOCK) || (flag & O_NDELAY)) { 1174 vport->status |= VCC_PORT_NONBLOCK; 1175 } 1176 1177 mutex_exit(&vport->lock); 1178 1179 return (0); 1180 } 1181 1182 /* close port */ 1183 static int 1184 i_vcc_close_port(vcc_port_t *vport) 1185 { 1186 int rv = EIO; 1187 1188 if ((vport->status & VCC_PORT_OPEN) == 0) { 1189 return (0); 1190 } 1191 1192 ASSERT(mutex_owned(&vport->lock)); 1193 1194 if (vport->status & VCC_PORT_LDC_CHANNEL_READY) { 1195 /* clean up ldc channel */ 1196 if ((rv = i_vcc_ldc_fini(vport)) != 0) { 1197 return (rv); 1198 } 1199 vport->status &= ~VCC_PORT_LDC_CHANNEL_READY; 1200 } 1201 1202 /* reset rd/wr suspends */ 1203 vport->status |= VCC_PORT_TERM_RD | VCC_PORT_TERM_WR; 1204 vport->status &= ~VCC_PORT_NONBLOCK; 1205 vport->status &= ~VCC_PORT_OPEN; 1206 vport->valid_pid = VCC_NO_PID_BLOCKING; 1207 1208 /* signal any blocked read and write thread */ 1209 cv_broadcast(&vport->read_cv); 1210 cv_broadcast(&vport->write_cv); 1211 1212 return (0); 1213 } 1214 1215 /* cb_close */ 1216 static int 1217 vcc_close(dev_t dev, int flag, int otyp, cred_t *cred) 1218 { 1219 _NOTE(ARGUNUSED(flag, otyp, cred)) 1220 1221 int instance; 1222 minor_t minor; 1223 int rv = EIO; 1224 uint_t portno; 1225 vcc_t *vccp; 1226 vcc_port_t *vport; 1227 1228 minor = getminor(dev); 1229 1230 instance = VCCINST(minor); 1231 vccp = ddi_get_soft_state(vcc_ssp, instance); 1232 if (vccp == NULL) { 1233 return (ENXIO); 1234 } 1235 1236 portno = VCCPORT(vccp, minor); 1237 1238 D1("vcc_close: closing virtual-console-concentrator@%d:%d\n", 1239 instance, portno); 1240 vport = &(vccp->port[portno]); 1241 1242 1243 if ((vport->status & VCC_PORT_OPEN) == 0) { 1244 return (0); 1245 } 1246 1247 if (portno == VCC_CONTROL_PORT) { 1248 /* 1249 * vntsd closes control port before it exits. There 1250 * could be events still pending for vntsd. 1251 */ 1252 rv = i_vcc_reset_events(vccp); 1253 return (0); 1254 } 1255 1256 mutex_enter(&vport->lock); 1257 1258 /* check minor no and pid */ 1259 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 1260 vport)) != 0) { 1261 mutex_exit(&vport->lock); 1262 return (rv); 1263 } 1264 1265 rv = i_vcc_close_port(vport); 1266 mutex_exit(&vport->lock); 1267 1268 return (rv); 1269 } 1270 1271 /* 1272 * ioctl VCC_CONS_TBL - vntsd allocates buffer according to return of 1273 * VCC_NUM_PORTS. However, when vntsd requests for the console table, console 1274 * ports could be deleted or added. parameter num_ports is number of structures 1275 * that vntsd allocated for the table. If there are more ports than 1276 * num_ports, set up to wakeup vntsd to add ports. 1277 * If there less ports than num_ports, fill (-1) for cons_no to tell vntsd. 1278 */ 1279 static int 1280 i_vcc_cons_tbl(vcc_t *vccp, uint_t num_ports, caddr_t buf, int mode) 1281 { 1282 vcc_console_t cons; 1283 int i; 1284 vcc_port_t *vport; 1285 boolean_t notify_vntsd = B_FALSE; 1286 char pathname[MAXPATHLEN]; 1287 1288 1289 (void) ddi_pathname(vccp->dip, pathname); 1290 for (i = 0; i < VCC_MAX_PORTS; i++) { 1291 1292 vport = &vccp->port[i]; 1293 1294 if (i == VCC_CONTROL_PORT) { 1295 continue; 1296 } 1297 1298 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1299 continue; 1300 } 1301 1302 /* a port exists before vntsd becomes online */ 1303 mutex_enter(&vport->lock); 1304 1305 if (num_ports == 0) { 1306 /* more ports than vntsd's buffer can hold */ 1307 vport->status |= VCC_PORT_ADDED; 1308 notify_vntsd = B_TRUE; 1309 mutex_exit(&vport->lock); 1310 continue; 1311 } 1312 1313 bzero(&cons, sizeof (vcc_console_t)); 1314 1315 /* construct console buffer */ 1316 cons.cons_no = vport->number; 1317 cons.tcp_port = vport->tcp_port; 1318 (void) memcpy(cons.domain_name, 1319 vport->minorp->domain_name, MAXPATHLEN); 1320 1321 (void) memcpy(cons.group_name, vport->group_name, 1322 MAXPATHLEN); 1323 vport->status &= ~VCC_PORT_ADDED; 1324 mutex_exit(&vport->lock); 1325 1326 (void) snprintf(cons.dev_name, MAXPATHLEN-1, "%s:%s%s", 1327 pathname, VCC_MINOR_NAME_PREFIX, cons.domain_name); 1328 1329 /* copy out data */ 1330 if (ddi_copyout(&cons, (void *)buf, 1331 sizeof (vcc_console_t), mode)) { 1332 mutex_exit(&vport->lock); 1333 return (EFAULT); 1334 } 1335 buf += sizeof (vcc_console_t); 1336 1337 num_ports--; 1338 1339 } 1340 1341 if (num_ports == 0) { 1342 /* vntsd's buffer is full */ 1343 1344 if (notify_vntsd) { 1345 /* more ports need to notify vntsd */ 1346 vport = &vccp->port[VCC_CONTROL_PORT]; 1347 mutex_enter(&vport->lock); 1348 vport->pollevent |= VCC_POLL_ADD_PORT; 1349 mutex_exit(&vport->lock); 1350 } 1351 1352 return (0); 1353 } 1354 1355 /* less ports than vntsd expected */ 1356 bzero(&cons, sizeof (vcc_console_t)); 1357 cons.cons_no = -1; 1358 1359 while (num_ports > 0) { 1360 /* fill vntsd buffer with no console */ 1361 if (ddi_copyout(&cons, (void *)buf, 1362 sizeof (vcc_console_t), mode) != 0) { 1363 mutex_exit(&vport->lock); 1364 return (EFAULT); 1365 } 1366 D1("i_vcc_cons_tbl: a port is deleted\n"); 1367 buf += sizeof (vcc_console_t) +MAXPATHLEN; 1368 num_ports--; 1369 } 1370 1371 return (0); 1372 } 1373 1374 1375 /* turn off event flag if there is no more change */ 1376 static void 1377 i_vcc_turn_off_event(vcc_t *vccp, uint32_t port_status, uint32_t event) 1378 { 1379 1380 vcc_port_t *vport; 1381 int i; 1382 1383 for (i = 0; i < VCC_MAX_PORTS; i++) { 1384 1385 vport = &(vccp->port[i]); 1386 1387 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1388 continue; 1389 } 1390 1391 1392 if (vport->status & port_status) { 1393 /* more port changes status */ 1394 return; 1395 } 1396 1397 } 1398 1399 /* no more changed port */ 1400 vport = &vccp->port[VCC_CONTROL_PORT]; 1401 1402 /* turn off event */ 1403 mutex_enter(&vport->lock); 1404 vport->pollevent &= ~event; 1405 mutex_exit(&vport->lock); 1406 } 1407 1408 /* ioctl VCC_CONS_INFO */ 1409 static int 1410 i_vcc_cons_info(vcc_t *vccp, caddr_t buf, int mode) 1411 { 1412 vcc_console_t cons; 1413 uint_t portno; 1414 vcc_port_t *vport; 1415 char pathname[MAXPATHLEN]; 1416 1417 /* read in portno */ 1418 if (ddi_copyin((void*)buf, &portno, sizeof (uint_t), mode)) { 1419 return (EFAULT); 1420 } 1421 1422 D1("i_vcc_cons_info@%d:\n", portno); 1423 1424 if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) { 1425 return (EINVAL); 1426 } 1427 1428 vport = &vccp->port[portno]; 1429 1430 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1431 return (EINVAL); 1432 } 1433 1434 mutex_enter(&vport->lock); 1435 vport->status &= ~VCC_PORT_ADDED; 1436 1437 /* construct configruation data */ 1438 bzero(&cons, sizeof (vcc_console_t)); 1439 1440 cons.cons_no = vport->number; 1441 cons.tcp_port = vport->tcp_port; 1442 1443 (void) memcpy(cons.domain_name, vport->minorp->domain_name, MAXPATHLEN); 1444 1445 (void) memcpy(cons.group_name, vport->group_name, MAXPATHLEN); 1446 1447 mutex_exit(&vport->lock); 1448 1449 (void) ddi_pathname(vccp->dip, pathname), 1450 1451 /* copy device name */ 1452 (void) snprintf(cons.dev_name, MAXPATHLEN-1, "%s:%s%s", 1453 pathname, VCC_MINOR_NAME_PREFIX, cons.domain_name); 1454 /* copy data */ 1455 if (ddi_copyout(&cons, (void *)buf, 1456 sizeof (vcc_console_t), mode) != 0) { 1457 mutex_exit(&vport->lock); 1458 return (EFAULT); 1459 } 1460 1461 D1("i_vcc_cons_info@%d:domain:%s serv:%s tcp@%lld %s\n", 1462 cons.cons_no, cons.domain_name, 1463 cons.group_name, cons.tcp_port, cons.dev_name); 1464 1465 i_vcc_turn_off_event(vccp, VCC_PORT_ADDED, VCC_POLL_ADD_PORT); 1466 1467 return (0); 1468 } 1469 1470 1471 /* response to vntsd inquiry ioctl call */ 1472 static int 1473 i_vcc_inquiry(vcc_t *vccp, caddr_t buf, int mode) 1474 { 1475 vcc_port_t *vport; 1476 uint_t i; 1477 vcc_response_t msg; 1478 1479 vport = &(vccp->port[VCC_CONTROL_PORT]); 1480 1481 if ((vport->pollevent & VCC_POLL_ADD_PORT) == 0) { 1482 return (EINVAL); 1483 } 1484 1485 /* an added port */ 1486 1487 D1("i_vcc_inquiry\n"); 1488 1489 for (i = 0; i < VCC_MAX_PORTS; i++) { 1490 if ((vccp->port[i].status & VCC_PORT_AVAIL) == 0) { 1491 continue; 1492 } 1493 1494 if (vccp->port[i].status & VCC_PORT_ADDED) { 1495 /* port added */ 1496 msg.reason = VCC_CONS_ADDED; 1497 msg.cons_no = i; 1498 1499 if (ddi_copyout((void *)&msg, (void *)buf, 1500 sizeof (msg), mode) == -1) { 1501 cmn_err(CE_CONT, "i_vcc_find_changed_port:" 1502 "ddi_copyout" 1503 " failed\n"); 1504 return (EFAULT); 1505 } 1506 return (0); 1507 } 1508 } 1509 1510 /* the added port was deleted before vntsd wakes up */ 1511 msg.reason = VCC_CONS_MISS_ADDED; 1512 1513 if (ddi_copyout((void *)&msg, (void *)buf, 1514 sizeof (msg), mode) == -1) { 1515 cmn_err(CE_CONT, "i_vcc_find_changed_port: ddi_copyout" 1516 " failed\n"); 1517 return (EFAULT); 1518 } 1519 1520 return (0); 1521 } 1522 1523 /* clean up events after vntsd exits */ 1524 static int 1525 i_vcc_reset_events(vcc_t *vccp) 1526 { 1527 uint_t i; 1528 vcc_port_t *vport; 1529 1530 for (i = 0; i < VCC_MAX_PORTS; i++) { 1531 vport = &(vccp->port[i]); 1532 1533 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1534 continue; 1535 } 1536 1537 ASSERT(!mutex_owned(&vport->lock)); 1538 1539 if (i == VCC_CONTROL_PORT) { 1540 /* close control port */ 1541 mutex_enter(&vport->lock); 1542 vport->status &= ~VCC_PORT_OPEN; 1543 1544 /* clean up poll events */ 1545 vport->pollevent = 0; 1546 vport->pollflag = 0; 1547 mutex_exit(&vport->lock); 1548 continue; 1549 } 1550 if (vport->status & VCC_PORT_ADDED) { 1551 /* pending added port event to vntsd */ 1552 mutex_enter(&vport->lock); 1553 vport->status &= ~VCC_PORT_ADDED; 1554 mutex_exit(&vport->lock); 1555 } 1556 1557 } 1558 1559 vport = &vccp->port[VCC_CONTROL_PORT]; 1560 1561 return (0); 1562 } 1563 1564 /* ioctl VCC_FORCE_CLOSE */ 1565 static int 1566 i_vcc_force_close(vcc_t *vccp, caddr_t buf, int mode) 1567 { 1568 uint_t portno; 1569 vcc_port_t *vport; 1570 int rv; 1571 1572 /* read in portno */ 1573 if (ddi_copyin((void*)buf, &portno, sizeof (uint_t), mode)) { 1574 return (EFAULT); 1575 } 1576 1577 D1("i_vcc_force_close@%d:\n", portno); 1578 1579 if ((portno >= VCC_MAX_PORTS) || (portno == VCC_CONTROL_PORT)) { 1580 return (EINVAL); 1581 } 1582 1583 vport = &vccp->port[portno]; 1584 1585 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1586 return (EINVAL); 1587 } 1588 1589 mutex_enter(&vport->lock); 1590 1591 rv = i_vcc_close_port(vport); 1592 1593 /* block callers other than vntsd */ 1594 vport->valid_pid = ddi_get_pid(); 1595 1596 mutex_exit(&vport->lock); 1597 return (rv); 1598 1599 } 1600 1601 /* ioctl VCC_CONS_STATUS */ 1602 static int 1603 i_vcc_cons_status(vcc_t *vccp, caddr_t buf, int mode) 1604 { 1605 vcc_console_t console; 1606 vcc_port_t *vport; 1607 1608 /* read in portno */ 1609 if (ddi_copyin((void*)buf, &console, sizeof (console), mode)) { 1610 return (EFAULT); 1611 } 1612 1613 D1("i_vcc_cons_status@%d:\n", console.cons_no); 1614 1615 if ((console.cons_no >= VCC_MAX_PORTS) || 1616 (console.cons_no == VCC_CONTROL_PORT)) { 1617 return (EINVAL); 1618 } 1619 1620 1621 vport = &vccp->port[console.cons_no]; 1622 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1623 console.cons_no = -1; 1624 } else if (strncmp(console.domain_name, vport->minorp->domain_name, 1625 MAXPATHLEN)) { 1626 console.cons_no = -1; 1627 } else if (strncmp(console.group_name, vport->group_name, 1628 MAXPATHLEN)) { 1629 console.cons_no = -1; 1630 } else if (console.tcp_port != vport->tcp_port) { 1631 console.cons_no = -1; 1632 } 1633 1634 D1("i_vcc_cons_status@%d: %s %s %llx\n", console.cons_no, 1635 console.group_name, console.domain_name, console.tcp_port); 1636 if (ddi_copyout(&console, (void *)buf, sizeof (console), mode) == -1) { 1637 cmn_err(CE_CONT, "i_vcc_cons_status ddi_copyout failed\n"); 1638 return (EFAULT); 1639 } 1640 1641 return (0); 1642 } 1643 1644 /* cb_ioctl handler for vcc control port */ 1645 static int 1646 i_vcc_ctrl_ioctl(vcc_t *vccp, int cmd, void* arg, int mode) 1647 { 1648 1649 static uint_t num_ports; 1650 1651 1652 switch (cmd) { 1653 1654 case VCC_NUM_CONSOLE: 1655 1656 mutex_enter(&vccp->lock); 1657 num_ports = vccp->num_ports; 1658 mutex_exit(&vccp->lock); 1659 /* number of consoles */ 1660 1661 return (ddi_copyout((void *)&num_ports, arg, 1662 sizeof (int), mode)); 1663 case VCC_CONS_TBL: 1664 1665 /* console config table */ 1666 return (i_vcc_cons_tbl(vccp, num_ports, (caddr_t)arg, mode)); 1667 1668 case VCC_INQUIRY: 1669 1670 /* reason for wakeup */ 1671 return (i_vcc_inquiry(vccp, (caddr_t)arg, mode)); 1672 1673 case VCC_CONS_INFO: 1674 /* a console config */ 1675 return (i_vcc_cons_info(vccp, (caddr_t)arg, mode)); 1676 1677 case VCC_FORCE_CLOSE: 1678 /* force to close a console */ 1679 return (i_vcc_force_close(vccp, (caddr_t)arg, mode)); 1680 1681 case VCC_CONS_STATUS: 1682 /* console status */ 1683 return (i_vcc_cons_status(vccp, (caddr_t)arg, mode)); 1684 1685 default: 1686 1687 /* unknown command */ 1688 return (ENODEV); 1689 } 1690 1691 1692 } 1693 1694 /* write data to ldc. may block if channel has no space for write */ 1695 static int 1696 i_vcc_write_ldc(vcc_port_t *vport, vcc_msg_t *buf) 1697 { 1698 int rv = EIO; 1699 size_t size; 1700 1701 ASSERT(mutex_owned(&vport->lock)); 1702 ASSERT((vport->status & VCC_PORT_USE_WRITE_LDC) == 0); 1703 1704 for (; ; ) { 1705 1706 size = VCC_HDR_SZ + buf->size; 1707 rv = ldc_write(vport->ldc_handle, (caddr_t)buf, &size); 1708 1709 D1("i_vcc_write_ldc: port@%d: err=%d %d bytes\n", 1710 vport->number, rv, size); 1711 1712 if (rv == 0) { 1713 return (rv); 1714 } 1715 1716 if (rv != EWOULDBLOCK) { 1717 return (EIO); 1718 } 1719 1720 if (vport->status & VCC_PORT_NONBLOCK) { 1721 return (EAGAIN); 1722 } 1723 1724 /* block util ldc has more space */ 1725 1726 rv = i_vcc_wait_port_status(vport, &vport->write_cv, 1727 VCC_PORT_LDC_WRITE_READY); 1728 1729 if (rv) { 1730 return (rv); 1731 } 1732 1733 vport->status &= ~VCC_PORT_LDC_WRITE_READY; 1734 1735 } 1736 1737 } 1738 1739 1740 1741 /* cb_ioctl handler for port ioctl */ 1742 static int 1743 i_vcc_port_ioctl(vcc_t *vccp, minor_t minor, int portno, int cmd, void *arg, 1744 int mode) 1745 { 1746 1747 vcc_port_t *vport; 1748 struct termios term; 1749 vcc_msg_t buf; 1750 int rv; 1751 1752 D1("i_vcc_port_ioctl@%d cmd %d\n", portno, cmd); 1753 1754 vport = &(vccp->port[portno]); 1755 1756 if ((vport->status & VCC_PORT_AVAIL) == 0) { 1757 return (EIO); 1758 } 1759 1760 1761 switch (cmd) { 1762 1763 /* terminal support */ 1764 case TCGETA: 1765 case TCGETS: 1766 1767 mutex_enter(&vport->lock); 1768 1769 /* check minor no and pid */ 1770 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 1771 vport)) != 0) { 1772 mutex_exit(&vport->lock); 1773 return (rv); 1774 } 1775 1776 (void) memcpy(&term, &vport->term, sizeof (term)); 1777 mutex_exit(&vport->lock); 1778 1779 return (ddi_copyout(&term, arg, sizeof (term), mode)); 1780 1781 case TCSETS: 1782 case TCSETA: 1783 case TCSETAW: 1784 case TCSETAF: 1785 1786 if (ddi_copyin(arg, &term, sizeof (term), mode) != 0) { 1787 return (EFAULT); 1788 } 1789 1790 mutex_enter(&vport->lock); 1791 1792 /* check minor no and pid */ 1793 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 1794 vport)) != 0) { 1795 mutex_exit(&vport->lock); 1796 return (rv); 1797 } 1798 1799 (void) memcpy(&vport->term, &term, sizeof (term)); 1800 mutex_exit(&vport->lock); 1801 return (0); 1802 1803 1804 case TCSBRK: 1805 1806 /* send break to console */ 1807 mutex_enter(&vport->lock); 1808 1809 /* check minor no and pid */ 1810 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 1811 vport)) != 0) { 1812 mutex_exit(&vport->lock); 1813 return (rv); 1814 } 1815 1816 /* wait for write available */ 1817 rv = i_vcc_wait_port_status(vport, &vport->write_cv, 1818 VCC_PORT_LDC_CHANNEL_READY| VCC_PORT_USE_WRITE_LDC); 1819 if (rv) { 1820 mutex_exit(&vport->lock); 1821 return (rv); 1822 } 1823 1824 vport->status &= ~VCC_PORT_USE_WRITE_LDC; 1825 1826 buf.type = LDC_CONSOLE_CTRL; 1827 buf.ctrl_msg = LDC_CONSOLE_BREAK; 1828 buf.size = 0; 1829 1830 rv = i_vcc_write_ldc(vport, &buf); 1831 1832 mutex_exit(&vport->lock); 1833 1834 i_vcc_set_port_status(vport, &vport->write_cv, 1835 VCC_PORT_USE_WRITE_LDC); 1836 return (0); 1837 1838 case TCXONC: 1839 /* suspend read or write */ 1840 if (ddi_copyin(arg, &cmd, sizeof (int), mode) != 0) { 1841 return (EFAULT); 1842 } 1843 1844 mutex_enter(&vport->lock); 1845 1846 /* check minor no and pid */ 1847 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 1848 vport)) != 0) { 1849 mutex_exit(&vport->lock); 1850 return (rv); 1851 } 1852 1853 1854 switch (cmd) { 1855 1856 case 0: 1857 /* suspend read */ 1858 vport->status &= ~VCC_PORT_TERM_RD; 1859 break; 1860 1861 case 1: 1862 /* resume read */ 1863 vport->status |= VCC_PORT_TERM_RD; 1864 cv_broadcast(&vport->read_cv); 1865 break; 1866 1867 case 2: 1868 /* suspend write */ 1869 vport->status &= ~VCC_PORT_TERM_WR; 1870 break; 1871 1872 case 3: 1873 /* resume write */ 1874 vport->status |= VCC_PORT_TERM_WR; 1875 cv_broadcast(&vport->write_cv); 1876 break; 1877 1878 default: 1879 mutex_exit(&vport->lock); 1880 return (EINVAL); 1881 } 1882 1883 mutex_exit(&vport->lock); 1884 return (0); 1885 1886 case TCFLSH: 1887 return (0); 1888 1889 default: 1890 return (EINVAL); 1891 } 1892 1893 } 1894 1895 /* cb_ioctl */ 1896 static int 1897 vcc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 1898 cred_t *credp, int *rvalp) 1899 { 1900 _NOTE(ARGUNUSED(credp, rvalp)) 1901 1902 int instance; 1903 minor_t minor; 1904 int portno; 1905 vcc_t *vccp; 1906 1907 minor = getminor(dev); 1908 1909 instance = VCCINST(minor); 1910 1911 vccp = ddi_get_soft_state(vcc_ssp, instance); 1912 if (vccp == NULL) { 1913 return (ENXIO); 1914 } 1915 1916 portno = VCCPORT(vccp, minor); 1917 1918 D1("vcc_ioctl: virtual-console-concentrator@%d:%d\n", instance, portno); 1919 1920 if (portno >= VCC_MAX_PORTS) { 1921 cmn_err(CE_CONT, "vcc_ioctl:virtual-console-concentrator@%d" 1922 " invalid portno\n", portno); 1923 return (EINVAL); 1924 } 1925 1926 D1("vcc_ioctl: virtual-console-concentrator@%d:%d ioctl cmd=%d\n", 1927 instance, portno, cmd); 1928 1929 if (portno == VCC_CONTROL_PORT) { 1930 /* control ioctl */ 1931 return (i_vcc_ctrl_ioctl(vccp, cmd, (void *)arg, mode)); 1932 } 1933 1934 /* data port ioctl */ 1935 return (i_vcc_port_ioctl(vccp, minor, portno, cmd, (void *)arg, mode)); 1936 } 1937 1938 /* cb_read */ 1939 static int 1940 vcc_read(dev_t dev, struct uio *uiop, cred_t *credp) 1941 { 1942 _NOTE(ARGUNUSED(credp)) 1943 1944 int instance; 1945 minor_t minor; 1946 uint_t portno; 1947 vcc_t *vccp; 1948 vcc_port_t *vport; 1949 int rv = EIO; /* by default fail ! */ 1950 char *buf; 1951 size_t uio_size; 1952 size_t size; 1953 1954 minor = getminor(dev); 1955 1956 instance = VCCINST(minor); 1957 1958 vccp = ddi_get_soft_state(vcc_ssp, instance); 1959 if (vccp == NULL) { 1960 return (ENXIO); 1961 } 1962 1963 portno = VCCPORT(vccp, minor); 1964 1965 /* no read for control port */ 1966 if (portno == VCC_CONTROL_PORT) { 1967 return (EIO); 1968 } 1969 1970 /* temp buf to hold ldc data */ 1971 uio_size = uiop->uio_resid; 1972 1973 if (uio_size < VCC_MTU_SZ) { 1974 return (EINVAL); 1975 } 1976 1977 vport = &(vccp->port[portno]); 1978 1979 mutex_enter(&vport->lock); 1980 1981 /* check minor no and pid */ 1982 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 1983 vport)) != 0) { 1984 mutex_exit(&vport->lock); 1985 return (rv); 1986 } 1987 1988 rv = i_vcc_wait_port_status(vport, &vport->read_cv, 1989 VCC_PORT_TERM_RD|VCC_PORT_LDC_CHANNEL_READY| 1990 VCC_PORT_USE_READ_LDC); 1991 if (rv) { 1992 mutex_exit(&vport->lock); 1993 return (rv); 1994 } 1995 1996 buf = kmem_alloc(uio_size, KM_SLEEP); 1997 1998 vport->status &= ~VCC_PORT_USE_READ_LDC; 1999 2000 for (; ; ) { 2001 2002 size = uio_size; 2003 rv = i_vcc_read_ldc(vport, buf, &size); 2004 2005 2006 if (rv == EAGAIN) { 2007 /* should block? */ 2008 if (vport->status & VCC_PORT_NONBLOCK) { 2009 break; 2010 } 2011 2012 } else if (rv) { 2013 /* error */ 2014 break; 2015 } 2016 2017 if (size > 0) { 2018 /* got data */ 2019 break; 2020 } 2021 2022 /* wait for data from ldc */ 2023 vport->status &= ~VCC_PORT_LDC_DATA_READY; 2024 2025 mutex_exit(&vport->lock); 2026 i_vcc_set_port_status(vport, &vport->read_cv, 2027 VCC_PORT_USE_READ_LDC); 2028 mutex_enter(&vport->lock); 2029 2030 rv = i_vcc_wait_port_status(vport, &vport->read_cv, 2031 VCC_PORT_TERM_RD|VCC_PORT_LDC_CHANNEL_READY| 2032 VCC_PORT_USE_READ_LDC| VCC_PORT_LDC_DATA_READY); 2033 if (rv) { 2034 break; 2035 } 2036 2037 vport->status &= ~VCC_PORT_USE_READ_LDC; 2038 } 2039 2040 mutex_exit(&vport->lock); 2041 2042 if ((rv == 0) && (size > 0)) { 2043 /* data is in buf */ 2044 rv = uiomove(buf, size, UIO_READ, uiop); 2045 } 2046 2047 kmem_free(buf, uio_size); 2048 i_vcc_set_port_status(vport, &vport->read_cv, VCC_PORT_USE_READ_LDC); 2049 2050 return (rv); 2051 } 2052 2053 2054 /* cb_write */ 2055 static int 2056 vcc_write(dev_t dev, struct uio *uiop, cred_t *credp) 2057 { 2058 _NOTE(ARGUNUSED(credp)) 2059 2060 int instance; 2061 minor_t minor; 2062 size_t size; 2063 size_t bytes; 2064 uint_t portno; 2065 vcc_t *vccp; 2066 2067 vcc_port_t *vport; 2068 int rv = EIO; 2069 2070 vcc_msg_t buf; 2071 2072 minor = getminor(dev); 2073 2074 instance = VCCINST(minor); 2075 2076 vccp = ddi_get_soft_state(vcc_ssp, instance); 2077 if (vccp == NULL) { 2078 return (ENXIO); 2079 } 2080 2081 portno = VCCPORT(vccp, minor); 2082 2083 /* no write for control port */ 2084 if (portno == VCC_CONTROL_PORT) { 2085 return (EIO); 2086 } 2087 vport = &(vccp->port[portno]); 2088 2089 /* 2090 * check if the channel has been configured, 2091 * if write has been suspend and grab write lock. 2092 */ 2093 mutex_enter(&vport->lock); 2094 2095 /* check minor no and pid */ 2096 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 2097 vport)) != 0) { 2098 mutex_exit(&vport->lock); 2099 return (rv); 2100 } 2101 2102 rv = i_vcc_wait_port_status(vport, &vport->write_cv, 2103 VCC_PORT_TERM_WR|VCC_PORT_LDC_CHANNEL_READY| 2104 VCC_PORT_USE_WRITE_LDC); 2105 if (rv) { 2106 mutex_exit(&vport->lock); 2107 return (rv); 2108 } 2109 2110 vport->status &= ~VCC_PORT_USE_WRITE_LDC; 2111 mutex_exit(&vport->lock); 2112 size = uiop->uio_resid; 2113 2114 D2("vcc_write: virtual-console-concentrator@%d:%d writing %d bytes\n", 2115 instance, portno, size); 2116 2117 2118 2119 buf.type = LDC_CONSOLE_DATA; 2120 2121 while (size) { 2122 2123 bytes = MIN(size, VCC_MTU_SZ); 2124 /* move data */ 2125 rv = uiomove(&(buf.data), bytes, UIO_WRITE, uiop); 2126 2127 if (rv) { 2128 break; 2129 } 2130 2131 /* write to ldc */ 2132 buf.size = bytes; 2133 2134 mutex_enter(&vport->lock); 2135 2136 /* check minor no and pid */ 2137 if ((rv = i_vcc_can_use_port(VCCMINORP(vccp, minor), 2138 vport)) != 0) { 2139 mutex_exit(&vport->lock); 2140 return (rv); 2141 } 2142 2143 rv = i_vcc_write_ldc(vport, &buf); 2144 2145 mutex_exit(&vport->lock); 2146 2147 if (rv) { 2148 break; 2149 } 2150 2151 size -= bytes; 2152 2153 } 2154 2155 i_vcc_set_port_status(vport, &vport->write_cv, VCC_PORT_USE_WRITE_LDC); 2156 return (rv); 2157 } 2158 2159 /* mdeg callback for a removed port */ 2160 static int 2161 i_vcc_md_remove_port(md_t *mdp, mde_cookie_t mdep, vcc_t *vccp) 2162 { 2163 uint64_t portno; /* md requires 64bit for port number */ 2164 int rv = MDEG_FAILURE; 2165 vcc_port_t *vport; 2166 2167 if (md_get_prop_val(mdp, mdep, "id", &portno)) { 2168 cmn_err(CE_CONT, "vcc_mdeg_cb: port has no 'id' property\n"); 2169 return (MDEG_FAILURE); 2170 } 2171 2172 if ((portno >= VCC_MAX_PORTS) || (portno < 0)) { 2173 cmn_err(CE_CONT, "i_vcc_md_remove_port@%ld invalid port no\n", 2174 portno); 2175 return (MDEG_FAILURE); 2176 } 2177 2178 if (portno == VCC_CONTROL_PORT) { 2179 cmn_err(CE_CONT, "i_vcc_md_remove_port@%ld can not remove" 2180 "control port\n", 2181 portno); 2182 return (MDEG_FAILURE); 2183 } 2184 2185 vport = &(vccp->port[portno]); 2186 2187 /* delete the port */ 2188 mutex_enter(&vport->lock); 2189 rv = i_vcc_delete_port(vccp, vport); 2190 mutex_exit(&vport->lock); 2191 2192 mutex_enter(&vccp->lock); 2193 vccp->num_ports--; 2194 mutex_exit(&vccp->lock); 2195 2196 return (rv ? MDEG_FAILURE : MDEG_SUCCESS); 2197 } 2198 2199 static int 2200 i_vcc_get_ldc_id(md_t *md, mde_cookie_t mdep, uint64_t *ldc_id) 2201 { 2202 int num_nodes; 2203 size_t size; 2204 mde_cookie_t *channel; 2205 int num_channels; 2206 2207 2208 if ((num_nodes = md_node_count(md)) <= 0) { 2209 cmn_err(CE_CONT, "i_vcc_get_ldc_channel_id:" 2210 " Invalid node count in Machine Description subtree"); 2211 return (-1); 2212 } 2213 size = num_nodes*(sizeof (*channel)); 2214 channel = kmem_zalloc(size, KM_SLEEP); 2215 ASSERT(channel != NULL); /* because KM_SLEEP */ 2216 2217 2218 /* Look for channel endpoint child(ren) of the vdisk MD node */ 2219 if ((num_channels = md_scan_dag(md, mdep, 2220 md_find_name(md, "channel-endpoint"), 2221 md_find_name(md, "fwd"), channel)) <= 0) { 2222 cmn_err(CE_CONT, "i_vcc_get_ldc_id: No 'channel-endpoint'" 2223 " found for vcc"); 2224 kmem_free(channel, size); 2225 return (-1); 2226 } 2227 2228 /* Get the "id" value for the first channel endpoint node */ 2229 if (md_get_prop_val(md, channel[0], "id", ldc_id) != 0) { 2230 cmn_err(CE_CONT, "i_vcc_get_ldc: No id property found " 2231 "for channel-endpoint of vcc"); 2232 kmem_free(channel, size); 2233 return (-1); 2234 } 2235 2236 if (num_channels > 1) { 2237 cmn_err(CE_CONT, "i_vcc_get_ldc: Warning: Using ID of first" 2238 " of multiple channels for this vcc"); 2239 } 2240 2241 kmem_free(channel, size); 2242 return (0); 2243 } 2244 /* mdeg callback for an added port */ 2245 static int 2246 i_vcc_md_add_port(md_t *mdp, mde_cookie_t mdep, vcc_t *vccp) 2247 { 2248 uint64_t portno; /* md requires 64 bit */ 2249 char *domain_name; 2250 char *group_name; 2251 uint64_t ldc_id; 2252 uint64_t tcp_port; 2253 vcc_port_t *vport; 2254 2255 /* read in the port's reg property */ 2256 if (md_get_prop_val(mdp, mdep, "id", &portno)) { 2257 cmn_err(CE_CONT, "i_vcc_md_add_port_: port has no 'id' " 2258 "property\n"); 2259 return (MDEG_FAILURE); 2260 } 2261 2262 /* read in the port's "vcc-doman-name" property */ 2263 if (md_get_prop_str(mdp, mdep, "vcc-domain-name", &domain_name)) { 2264 cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has " 2265 "no 'vcc-domain-name' property\n", portno); 2266 return (MDEG_FAILURE); 2267 } 2268 2269 2270 /* read in the port's "vcc-group-name" property */ 2271 if (md_get_prop_str(mdp, mdep, "vcc-group-name", &group_name)) { 2272 cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has no " 2273 "'vcc-group-name'property\n", portno); 2274 return (MDEG_FAILURE); 2275 } 2276 2277 2278 /* read in the port's "vcc-tcp-port" property */ 2279 if (md_get_prop_val(mdp, mdep, "vcc-tcp-port", &tcp_port)) { 2280 cmn_err(CE_CONT, "i_vcc_md_add_port: port%ld has no" 2281 "'vcc-tcp-port' property\n", portno); 2282 return (MDEG_FAILURE); 2283 } 2284 2285 D1("i_vcc_md_add_port: port@%d domain-name=%s group-name=%s" 2286 " tcp-port=%lld\n", portno, domain_name, group_name, tcp_port); 2287 2288 /* add the port */ 2289 if (i_vcc_add_port(vccp, group_name, tcp_port, portno, domain_name)) { 2290 return (MDEG_FAILURE); 2291 } 2292 2293 vport = &vccp->port[portno]; 2294 if (i_vcc_get_ldc_id(mdp, mdep, &ldc_id)) { 2295 mutex_enter(&vport->lock); 2296 (void) i_vcc_delete_port(vccp, vport); 2297 mutex_exit(&vport->lock); 2298 return (MDEG_FAILURE); 2299 } 2300 2301 /* configure the port */ 2302 if (i_vcc_config_port(vccp, portno, 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 mutex_enter(&vccp->lock); 2310 vccp->num_ports++; 2311 mutex_exit(&vccp->lock); 2312 2313 vport = &vccp->port[VCC_CONTROL_PORT]; 2314 2315 if (vport->pollflag & VCC_POLL_CONFIG) { 2316 /* wakeup vntsd */ 2317 mutex_enter(&vport->lock); 2318 vport->pollevent |= VCC_POLL_ADD_PORT; 2319 mutex_exit(&vport->lock); 2320 pollwakeup(&vport->poll, POLLIN); 2321 } 2322 2323 return (MDEG_SUCCESS); 2324 } 2325 2326 /* mdeg callback */ 2327 static int 2328 vcc_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 2329 { 2330 int idx; 2331 vcc_t *vccp; 2332 int rv; 2333 2334 vccp = (vcc_t *)cb_argp; 2335 ASSERT(vccp); 2336 2337 if (resp == NULL) { 2338 return (MDEG_FAILURE); 2339 } 2340 2341 /* added port */ 2342 D1("vcc_mdeg_cb: added %d port(s)\n", resp->added.nelem); 2343 2344 for (idx = 0; idx < resp->added.nelem; idx++) { 2345 rv = i_vcc_md_add_port(resp->added.mdp, 2346 resp->added.mdep[idx], vccp); 2347 2348 if (rv != MDEG_SUCCESS) { 2349 return (rv); 2350 } 2351 } 2352 2353 /* removed port */ 2354 D1("vcc_mdeg_cb: removed %d port(s)\n", resp->removed.nelem); 2355 2356 for (idx = 0; idx < resp->removed.nelem; idx++) { 2357 rv = i_vcc_md_remove_port(resp->removed.mdp, 2358 resp->removed.mdep[idx], vccp); 2359 2360 if (rv != MDEG_SUCCESS) { 2361 return (rv); 2362 } 2363 } 2364 2365 /* 2366 * XXX - Currently no support for updating already active 2367 * ports. So, ignore the match_curr and match_prev arrays 2368 * for now. 2369 */ 2370 2371 2372 return (MDEG_SUCCESS); 2373 } 2374 2375 2376 /* cb_chpoll */ 2377 static int 2378 vcc_chpoll(dev_t dev, short events, int anyyet, short *reventsp, 2379 struct pollhead **phpp) 2380 { 2381 int instance; 2382 minor_t minor; 2383 uint_t portno; 2384 vcc_t *vccp; 2385 vcc_port_t *vport; 2386 2387 minor = getminor(dev); 2388 2389 instance = VCCINST(minor); 2390 2391 vccp = ddi_get_soft_state(vcc_ssp, instance); 2392 if (vccp == NULL) { 2393 return (ENXIO); 2394 } 2395 2396 portno = VCCPORT(vccp, minor); 2397 2398 vport = &(vccp->port[portno]); 2399 2400 D1("vcc_chpoll: virtual-console-concentrator@%d events 0x%x\n", 2401 portno, events); 2402 2403 *reventsp = 0; 2404 2405 if (portno != VCC_CONTROL_PORT) { 2406 return (ENXIO); 2407 } 2408 2409 /* poll for config change */ 2410 if (vport->pollevent) { 2411 *reventsp |= (events & POLLIN); 2412 } 2413 2414 if (((*reventsp) == 0) && (!anyyet)) { 2415 *phpp = &vport->poll; 2416 if (events & POLLIN) { 2417 mutex_enter(&vport->lock); 2418 vport->pollflag |= VCC_POLL_CONFIG; 2419 mutex_exit(&vport->lock); 2420 } else { 2421 return (ENXIO); 2422 } 2423 } 2424 2425 D1("vcc_chpoll: virtual-console-concentrator@%d:%d ev=0x%x, " 2426 "rev=0x%x pev=0x%x, flag=0x%x\n", 2427 instance, portno, events, (*reventsp), 2428 vport->pollevent, vport->pollflag); 2429 2430 2431 return (0); 2432 } 2433