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