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