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/sysmacros.h> 43 #include <sys/types.h> 44 #include <sys/cred.h> 45 #include <sys/promif.h> 46 #include <sys/ddi.h> 47 #include <sys/sunddi.h> 48 #include <sys/cyclic.h> 49 #include <sys/note.h> 50 #include <sys/mach_descrip.h> 51 #include <sys/mdeg.h> 52 #include <sys/ldc.h> 53 #include <sys/vldc_impl.h> 54 55 /* 56 * Function prototypes. 57 */ 58 59 /* DDI entrypoints */ 60 static int vldc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 61 static int vldc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 62 static int vldc_open(dev_t *devp, int flag, int otyp, cred_t *cred); 63 static int vldc_close(dev_t dev, int flag, int otyp, cred_t *cred); 64 static int vldc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 65 cred_t *credp, int *rvalp); 66 static int vldc_read(dev_t dev, struct uio *uiop, cred_t *credp); 67 static int vldc_write(dev_t dev, struct uio *uiop, cred_t *credp); 68 static int vldc_chpoll(dev_t dev, short events, int anyyet, 69 short *reventsp, struct pollhead **phpp); 70 71 /* Internal functions */ 72 static uint_t i_vldc_cb(uint64_t event, caddr_t arg); 73 static int i_vldc_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 74 static int i_vldc_mdeg_register(vldc_t *vldcp); 75 static int i_vldc_mdeg_unregister(vldc_t *vldcp); 76 static int i_vldc_add_port(vldc_t *vldcp, md_t *mdp, mde_cookie_t node); 77 static int i_vldc_remove_port(vldc_t *vldcp, uint_t portno); 78 static int i_vldc_close_port(vldc_t *vldcp, uint_t portno); 79 80 /* soft state structure */ 81 static void *vldc_ssp; 82 83 /* 84 * Matching criteria passed to the MDEG to register interest 85 * in changes to 'virtual-device-port' nodes identified by their 86 * 'id' property. 87 */ 88 static md_prop_match_t vport_prop_match[] = { 89 { MDET_PROP_VAL, "id" }, 90 { MDET_LIST_END, NULL } 91 }; 92 93 static mdeg_node_match_t vport_match = { "virtual-device-port", 94 vport_prop_match }; 95 96 /* 97 * Specification of an MD node passed to the MDEG to filter any 98 * 'virtual-device-port' nodes that do not belong to the specified 99 * node. This template is copied for each vldc instance and filled 100 * in with the appropriate 'name' and 'cfg-handle' values before 101 * being passed to the MDEG. 102 */ 103 static mdeg_prop_spec_t vldc_prop_template[] = { 104 { MDET_PROP_STR, "name", NULL }, 105 { MDET_PROP_VAL, "cfg-handle", NULL }, 106 { MDET_LIST_END, NULL, NULL } 107 }; 108 109 #define VLDC_MDEG_PROP_NAME(specp) ((specp)[0].ps_str) 110 #define VLDC_SET_MDEG_PROP_NAME(specp, name) ((specp)[0].ps_str = (name)) 111 #define VLDC_SET_MDEG_PROP_INST(specp, inst) ((specp)[1].ps_val = (inst)) 112 113 114 static struct cb_ops vldc_cb_ops = { 115 vldc_open, /* open */ 116 vldc_close, /* close */ 117 nodev, /* strategy */ 118 nodev, /* print */ 119 nodev, /* dump */ 120 vldc_read, /* read */ 121 vldc_write, /* write */ 122 vldc_ioctl, /* ioctl */ 123 nodev, /* devmap */ 124 nodev, /* mmap */ 125 ddi_segmap, /* segmap */ 126 vldc_chpoll, /* chpoll */ 127 ddi_prop_op, /* prop_op */ 128 NULL, /* stream */ 129 D_NEW | D_MP /* flag */ 130 }; 131 132 static struct dev_ops vldc_ops = { 133 DEVO_REV, /* rev */ 134 0, /* ref count */ 135 ddi_getinfo_1to1, /* getinfo */ 136 nulldev, /* identify */ 137 nulldev, /* probe */ 138 vldc_attach, /* attach */ 139 vldc_detach, /* detach */ 140 nodev, /* reset */ 141 &vldc_cb_ops, /* cb_ops */ 142 (struct bus_ops *)NULL /* bus_ops */ 143 }; 144 145 extern struct mod_ops mod_driverops; 146 147 static struct modldrv md = { 148 &mod_driverops, /* Type - it is a driver */ 149 "sun4v Virtual LDC Driver %I%", /* Name of the module */ 150 &vldc_ops, /* driver specific ops */ 151 }; 152 153 static struct modlinkage ml = { 154 MODREV_1, 155 &md, 156 NULL 157 }; 158 159 /* maximum MTU and cookie size tunables */ 160 uint32_t vldc_max_mtu = VLDC_MAX_MTU; 161 uint64_t vldc_max_cookie = VLDC_MAX_COOKIE; 162 163 /* 164 * when calls to LDC return EWOULDBLOCK or EAGAIN the operation is retried 165 * up to 'vldc_retries' times with a wait of 'vldc_delay' microseconds 166 * between each retry. 167 */ 168 static clock_t vldc_delay = 100; 169 static int vldc_retries = 3; 170 171 #ifdef DEBUG 172 173 /* 174 * Print debug messages 175 * 176 * set vldcdbg to 0x7 to enable all messages 177 * 178 * 0x4 - Warnings 179 * 0x2 - All debug messages (most verbose) 180 * 0x1 - Minimal debug messages 181 */ 182 183 int vldcdbg = 0x0; 184 185 static void 186 vldcdebug(const char *fmt, ...) 187 { 188 char buf[512]; 189 va_list ap; 190 191 va_start(ap, fmt); 192 (void) vsnprintf(buf, sizeof (buf), fmt, ap); 193 va_end(ap); 194 195 cmn_err(CE_CONT, "?%s", buf); 196 } 197 198 #define D1 if (vldcdbg & 0x01) vldcdebug 199 #define D2 if (vldcdbg & 0x02) vldcdebug 200 #define DWARN if (vldcdbg & 0x04) vldcdebug 201 202 #else /* not DEBUG */ 203 204 #define D1 if (0) printf 205 #define D2 if (0) printf 206 #define DWARN if (0) printf 207 208 #endif /* not DEBUG */ 209 210 211 /* _init(9E): initialize the loadable module */ 212 int 213 _init(void) 214 { 215 int error; 216 217 /* init the soft state structure */ 218 error = ddi_soft_state_init(&vldc_ssp, sizeof (vldc_t), 1); 219 if (error != 0) { 220 return (error); 221 } 222 223 /* Link the driver into the system */ 224 error = mod_install(&ml); 225 226 return (error); 227 } 228 229 /* _info(9E): return information about the loadable module */ 230 int 231 _info(struct modinfo *modinfop) 232 { 233 /* Report status of the dynamically loadable driver module */ 234 return (mod_info(&ml, modinfop)); 235 } 236 237 /* _fini(9E): prepare the module for unloading. */ 238 int 239 _fini(void) 240 { 241 int error; 242 243 /* Unlink the driver module from the system */ 244 if ((error = mod_remove(&ml)) == 0) { 245 /* 246 * We have successfully "removed" the driver. 247 * destroy soft state 248 */ 249 ddi_soft_state_fini(&vldc_ssp); 250 } 251 252 return (error); 253 } 254 255 /* ldc callback */ 256 static uint_t 257 i_vldc_cb(uint64_t event, caddr_t arg) 258 { 259 int rv; 260 vldc_port_t *vport = (vldc_port_t *)arg; 261 ldc_status_t old_status; 262 short pollevents = 0; 263 264 ASSERT(vport != NULL); 265 ASSERT(vport->minorp != NULL); 266 267 D1("i_vldc_cb: vldc@%d:%d callback invoked, channel=0x%lx, " 268 "event=0x%lx\n", vport->inst, vport->number, vport->ldc_id, event); 269 270 /* ensure the port can't be destroyed while we are handling the cb */ 271 mutex_enter(&vport->minorp->lock); 272 273 old_status = vport->ldc_status; 274 rv = ldc_status(vport->ldc_handle, &vport->ldc_status); 275 if (rv != 0) { 276 DWARN("i_vldc_cb: vldc@%d:%d could not get ldc status, " 277 "rv=%d\n", vport->inst, vport->number, rv); 278 mutex_exit(&vport->minorp->lock); 279 return (LDC_SUCCESS); 280 } 281 282 if (event & LDC_EVT_UP) { 283 pollevents |= POLLOUT; 284 vport->hanged_up = B_FALSE; 285 286 } else if (event & LDC_EVT_RESET) { 287 /* 288 * Mark the port in reset, if it is not CLOSED and 289 * the channel was previously in LDC_UP state. This 290 * implies that the port cannot be used until it has 291 * been closed and reopened. 292 */ 293 if (vport->status != VLDC_PORT_CLOSED && old_status == LDC_UP) { 294 vport->status = VLDC_PORT_RESET; 295 vport->hanged_up = B_TRUE; 296 pollevents = POLLHUP; 297 } else { 298 rv = ldc_up(vport->ldc_handle); 299 if (rv) { 300 DWARN("i_vldc_cb: vldc@%d:%d cannot bring " 301 "channel UP rv=%d\n", vport->inst, 302 vport->number, rv); 303 mutex_exit(&vport->minorp->lock); 304 return (LDC_SUCCESS); 305 } 306 rv = ldc_status(vport->ldc_handle, &vport->ldc_status); 307 if (rv != 0) { 308 DWARN("i_vldc_cb: vldc@%d:%d could not get " 309 "ldc status, rv=%d\n", vport->inst, 310 vport->number, rv); 311 mutex_exit(&vport->minorp->lock); 312 return (LDC_SUCCESS); 313 } 314 if (vport->ldc_status == LDC_UP) { 315 pollevents |= POLLOUT; 316 vport->hanged_up = B_FALSE; 317 } 318 } 319 320 } else if (event & LDC_EVT_DOWN) { 321 /* 322 * The other side went away - mark port in RESET state 323 */ 324 vport->status = VLDC_PORT_RESET; 325 vport->hanged_up = B_TRUE; 326 pollevents = POLLHUP; 327 } 328 329 if (event & LDC_EVT_READ) 330 pollevents |= POLLIN; 331 332 mutex_exit(&vport->minorp->lock); 333 334 if (pollevents != 0) { 335 D1("i_vldc_cb: port@%d pollwakeup=0x%x\n", 336 vport->number, pollevents); 337 pollwakeup(&vport->poll, pollevents); 338 } 339 340 return (LDC_SUCCESS); 341 } 342 343 /* mdeg callback */ 344 static int 345 i_vldc_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 346 { 347 vldc_t *vldcp; 348 int idx; 349 uint64_t portno; 350 int rv; 351 md_t *mdp; 352 mde_cookie_t node; 353 354 if (resp == NULL) { 355 D1("i_vldc_mdeg_cb: no result returned\n"); 356 return (MDEG_FAILURE); 357 } 358 359 vldcp = (vldc_t *)cb_argp; 360 361 mutex_enter(&vldcp->lock); 362 if (vldcp->detaching == B_TRUE) { 363 D1("i_vldc_mdeg_cb: detach in progress\n"); 364 mutex_exit(&vldcp->lock); 365 return (MDEG_FAILURE); 366 } 367 368 D1("i_vldc_mdeg_cb: added=%d, removed=%d, matched=%d\n", 369 resp->added.nelem, resp->removed.nelem, resp->match_prev.nelem); 370 371 /* process added ports */ 372 for (idx = 0; idx < resp->added.nelem; idx++) { 373 mdp = resp->added.mdp; 374 node = resp->added.mdep[idx]; 375 376 D1("i_vldc_mdeg_cb: processing added node 0x%lx\n", node); 377 378 /* attempt to add a port */ 379 if ((rv = i_vldc_add_port(vldcp, mdp, node)) != MDEG_SUCCESS) { 380 cmn_err(CE_NOTE, "?i_vldc_mdeg_cb: unable to add port, " 381 "err = %d", rv); 382 } 383 } 384 385 /* process removed ports */ 386 for (idx = 0; idx < resp->removed.nelem; idx++) { 387 mdp = resp->removed.mdp; 388 node = resp->removed.mdep[idx]; 389 390 D1("i_vldc_mdeg_cb: processing removed node 0x%lx\n", node); 391 392 /* read in the port's id property */ 393 if (md_get_prop_val(mdp, node, "id", &portno)) { 394 cmn_err(CE_NOTE, "?i_vldc_mdeg_cb: node 0x%lx of " 395 "removed list has no 'id' property", node); 396 continue; 397 } 398 399 /* attempt to remove a port */ 400 if ((rv = i_vldc_remove_port(vldcp, portno)) != 0) { 401 cmn_err(CE_NOTE, "?i_vldc_mdeg_cb: unable to remove " 402 "port %lu, err %d", portno, rv); 403 } 404 } 405 406 /* 407 * Currently no support for updating already active ports. So, ignore 408 * the match_curr and match_prev arrays for now. 409 */ 410 411 mutex_exit(&vldcp->lock); 412 413 return (MDEG_SUCCESS); 414 } 415 416 /* register callback to mdeg */ 417 static int 418 i_vldc_mdeg_register(vldc_t *vldcp) 419 { 420 mdeg_prop_spec_t *pspecp; 421 mdeg_node_spec_t *inst_specp; 422 mdeg_handle_t mdeg_hdl; 423 size_t templatesz; 424 int inst; 425 char *name; 426 size_t namesz; 427 char *nameprop; 428 int rv; 429 430 /* get the unique vldc instance assigned by the LDom manager */ 431 inst = ddi_prop_get_int(DDI_DEV_T_ANY, vldcp->dip, 432 DDI_PROP_DONTPASS, "reg", -1); 433 if (inst == -1) { 434 cmn_err(CE_NOTE, "?vldc%d has no 'reg' property", 435 ddi_get_instance(vldcp->dip)); 436 return (DDI_FAILURE); 437 } 438 439 /* get the name of the vldc instance */ 440 rv = ddi_prop_lookup_string(DDI_DEV_T_ANY, vldcp->dip, 441 DDI_PROP_DONTPASS, "name", &nameprop); 442 if (rv != DDI_PROP_SUCCESS) { 443 cmn_err(CE_NOTE, "?vldc%d has no 'name' property", 444 ddi_get_instance(vldcp->dip)); 445 return (DDI_FAILURE); 446 } 447 448 D1("i_vldc_mdeg_register: name=%s, instance=%d\n", nameprop, inst); 449 450 /* 451 * Allocate and initialize a per-instance copy 452 * of the global property spec array that will 453 * uniquely identify this vldc instance. 454 */ 455 templatesz = sizeof (vldc_prop_template); 456 pspecp = kmem_alloc(templatesz, KM_SLEEP); 457 458 bcopy(vldc_prop_template, pspecp, templatesz); 459 460 /* copy in the name property */ 461 namesz = strlen(nameprop) + 1; 462 name = kmem_alloc(namesz, KM_SLEEP); 463 464 bcopy(nameprop, name, namesz); 465 VLDC_SET_MDEG_PROP_NAME(pspecp, name); 466 ddi_prop_free(nameprop); 467 468 /* copy in the instance property */ 469 VLDC_SET_MDEG_PROP_INST(pspecp, inst); 470 471 /* initialize the complete prop spec structure */ 472 inst_specp = kmem_alloc(sizeof (mdeg_node_spec_t), KM_SLEEP); 473 inst_specp->namep = "virtual-device"; 474 inst_specp->specp = pspecp; 475 476 /* perform the registration */ 477 rv = mdeg_register(inst_specp, &vport_match, i_vldc_mdeg_cb, 478 vldcp, &mdeg_hdl); 479 480 if (rv != MDEG_SUCCESS) { 481 cmn_err(CE_NOTE, "?i_vldc_mdeg_register: mdeg_register " 482 "failed, err = %d", rv); 483 kmem_free(name, namesz); 484 kmem_free(pspecp, templatesz); 485 kmem_free(inst_specp, sizeof (mdeg_node_spec_t)); 486 return (DDI_FAILURE); 487 } 488 489 /* save off data that will be needed later */ 490 vldcp->inst_spec = inst_specp; 491 vldcp->mdeg_hdl = mdeg_hdl; 492 493 return (DDI_SUCCESS); 494 } 495 496 /* unregister callback from mdeg */ 497 static int 498 i_vldc_mdeg_unregister(vldc_t *vldcp) 499 { 500 char *name; 501 int rv; 502 503 D1("i_vldc_mdeg_unregister: hdl=0x%lx\n", vldcp->mdeg_hdl); 504 505 rv = mdeg_unregister(vldcp->mdeg_hdl); 506 if (rv != MDEG_SUCCESS) { 507 return (rv); 508 } 509 510 /* 511 * Clean up cached MDEG data 512 */ 513 name = VLDC_MDEG_PROP_NAME(vldcp->inst_spec->specp); 514 if (name != NULL) { 515 kmem_free(name, strlen(name) + 1); 516 } 517 kmem_free(vldcp->inst_spec->specp, sizeof (vldc_prop_template)); 518 vldcp->inst_spec->specp = NULL; 519 520 kmem_free(vldcp->inst_spec, sizeof (mdeg_node_spec_t)); 521 vldcp->inst_spec = NULL; 522 523 return (MDEG_SUCCESS); 524 } 525 526 static int 527 i_vldc_get_port_channel(md_t *mdp, mde_cookie_t node, uint64_t *ldc_id) 528 { 529 int num_nodes, nchan; 530 size_t listsz; 531 mde_cookie_t *listp; 532 533 /* 534 * Find the channel-endpoint node(s) (which should be under this 535 * port node) which contain the channel id(s). 536 */ 537 if ((num_nodes = md_node_count(mdp)) <= 0) { 538 cmn_err(CE_NOTE, "?i_vldc_get_port_channel: invalid number of " 539 "channel-endpoint nodes found (%d)", num_nodes); 540 return (-1); 541 } 542 543 /* allocate space for node list */ 544 listsz = num_nodes * sizeof (mde_cookie_t); 545 listp = kmem_alloc(listsz, KM_SLEEP); 546 547 nchan = md_scan_dag(mdp, node, md_find_name(mdp, "channel-endpoint"), 548 md_find_name(mdp, "fwd"), listp); 549 550 if (nchan <= 0) { 551 cmn_err(CE_NOTE, "?i_vldc_get_port_channel: no channel-endpoint" 552 " nodes found"); 553 kmem_free(listp, listsz); 554 return (-1); 555 } 556 557 D2("i_vldc_get_port_channel: %d channel-endpoint nodes found", nchan); 558 559 /* use property from first node found */ 560 if (md_get_prop_val(mdp, listp[0], "id", ldc_id)) { 561 cmn_err(CE_NOTE, "?i_vldc_get_port_channel: channel-endpoint " 562 "has no 'id' property"); 563 kmem_free(listp, listsz); 564 return (-1); 565 } 566 567 kmem_free(listp, listsz); 568 569 return (0); 570 } 571 572 /* add a vldc port */ 573 static int 574 i_vldc_add_port(vldc_t *vldcp, md_t *mdp, mde_cookie_t node) 575 { 576 vldc_port_t *vport; 577 char *sname; 578 uint64_t portno; 579 int vldc_inst; 580 minor_t minor; 581 int minor_idx; 582 boolean_t new_minor; 583 int rv; 584 585 ASSERT(MUTEX_HELD(&vldcp->lock)); 586 587 /* read in the port's id property */ 588 if (md_get_prop_val(mdp, node, "id", &portno)) { 589 cmn_err(CE_NOTE, "?i_vldc_add_port: node 0x%lx of added " 590 "list has no 'id' property", node); 591 return (MDEG_FAILURE); 592 } 593 594 if (portno >= VLDC_MAX_PORTS) { 595 cmn_err(CE_NOTE, "?i_vldc_add_port: found port number (%lu) " 596 "larger than maximum supported number of ports", portno); 597 return (MDEG_FAILURE); 598 } 599 600 vport = &(vldcp->port[portno]); 601 602 if (vport->minorp != NULL) { 603 cmn_err(CE_NOTE, "?i_vldc_add_port: trying to add a port (%lu)" 604 " which is already bound", portno); 605 return (MDEG_FAILURE); 606 } 607 608 vport->number = portno; 609 610 /* get all channels for this device (currently only one) */ 611 if (i_vldc_get_port_channel(mdp, node, &vport->ldc_id) == -1) { 612 return (MDEG_FAILURE); 613 } 614 615 /* set the default MTU */ 616 vport->mtu = VLDC_DEFAULT_MTU; 617 618 /* get the service being exported by this port */ 619 if (md_get_prop_str(mdp, node, "vldc-svc-name", &sname)) { 620 cmn_err(CE_NOTE, "?i_vldc_add_port: vdevice has no " 621 "'vldc-svc-name' property"); 622 return (MDEG_FAILURE); 623 } 624 625 /* minor number look up */ 626 for (minor_idx = 0; minor_idx < vldcp->minors_assigned; 627 minor_idx++) { 628 if (strcmp(vldcp->minor_tbl[minor_idx].sname, sname) == 0) { 629 /* found previously assigned minor number */ 630 break; 631 } 632 } 633 634 new_minor = B_FALSE; 635 if (minor_idx == vldcp->minors_assigned) { 636 /* end of lookup - assign new minor number */ 637 if (vldcp->minors_assigned == VLDC_MAX_MINORS) { 638 cmn_err(CE_NOTE, "?i_vldc_add_port: too many minor " 639 "nodes (%d)", minor_idx); 640 return (MDEG_FAILURE); 641 } 642 643 (void) strlcpy(vldcp->minor_tbl[minor_idx].sname, 644 sname, MAXPATHLEN); 645 646 vldcp->minors_assigned++; 647 new_minor = B_TRUE; 648 } 649 650 if (vldcp->minor_tbl[minor_idx].portno != VLDC_INVALID_PORTNO) { 651 cmn_err(CE_NOTE, "?i_vldc_add_port: trying to add a port (%lu)" 652 " which has a minor number in use by port (%u)", 653 portno, vldcp->minor_tbl[minor_idx].portno); 654 return (MDEG_FAILURE); 655 } 656 657 vldc_inst = ddi_get_instance(vldcp->dip); 658 659 vport->inst = vldc_inst; 660 vport->minorp = &vldcp->minor_tbl[minor_idx]; 661 vldcp->minor_tbl[minor_idx].portno = portno; 662 vldcp->minor_tbl[minor_idx].in_use = 0; 663 664 D1("i_vldc_add_port: vldc@%d:%d mtu=%d, ldc=%ld, service=%s\n", 665 vport->inst, vport->number, vport->mtu, vport->ldc_id, sname); 666 667 /* 668 * Create a minor node. The minor number is 669 * (vldc_inst << VLDC_INST_SHIFT) | minor_idx 670 */ 671 minor = (vldc_inst << VLDC_INST_SHIFT) | (minor_idx); 672 673 rv = ddi_create_minor_node(vldcp->dip, sname, S_IFCHR, 674 minor, DDI_NT_SERIAL, 0); 675 676 if (rv != DDI_SUCCESS) { 677 cmn_err(CE_NOTE, "?i_vldc_add_port: failed to create minor" 678 "node (%u), err = %d", minor, rv); 679 vldcp->minor_tbl[minor_idx].portno = VLDC_INVALID_PORTNO; 680 if (new_minor) { 681 vldcp->minors_assigned--; 682 } 683 return (MDEG_FAILURE); 684 } 685 686 /* 687 * The port is now bound to a minor node and is initially in the 688 * closed state. 689 */ 690 vport->status = VLDC_PORT_CLOSED; 691 692 D1("i_vldc_add_port: port %lu initialized\n", portno); 693 694 return (MDEG_SUCCESS); 695 } 696 697 /* remove a vldc port */ 698 static int 699 i_vldc_remove_port(vldc_t *vldcp, uint_t portno) 700 { 701 vldc_port_t *vport; 702 vldc_minor_t *vminor; 703 704 ASSERT(vldcp != NULL); 705 ASSERT(MUTEX_HELD(&vldcp->lock)); 706 707 vport = &(vldcp->port[portno]); 708 vminor = vport->minorp; 709 if (vminor == NULL) { 710 cmn_err(CE_NOTE, "?i_vldc_remove_port: trying to remove a " 711 "port (%u) which is not bound", portno); 712 return (MDEG_FAILURE); 713 } 714 715 /* 716 * Make sure that all new attempts to open or use the minor node 717 * associated with the port will fail. 718 */ 719 mutex_enter(&vminor->lock); 720 vminor->portno = VLDC_INVALID_PORTNO; 721 mutex_exit(&vminor->lock); 722 723 /* send hangup to anyone polling */ 724 pollwakeup(&vport->poll, POLLHUP); 725 726 /* Now wait for all current users of the minor node to finish. */ 727 mutex_enter(&vminor->lock); 728 while (vminor->in_use > 0) { 729 cv_wait(&vminor->cv, &vminor->lock); 730 } 731 732 if (vport->status != VLDC_PORT_CLOSED) { 733 /* close the port before it is torn down */ 734 (void) i_vldc_close_port(vldcp, portno); 735 } 736 737 /* remove minor node */ 738 ddi_remove_minor_node(vldcp->dip, vport->minorp->sname); 739 vport->minorp = NULL; 740 741 mutex_exit(&vminor->lock); 742 743 D1("i_vldc_remove_port: removed vldc port %u\n", portno); 744 745 return (MDEG_SUCCESS); 746 } 747 748 /* 749 * Close and destroy the ldc channel associated with the port 'vport' 750 * 751 * NOTE It may not be possible close and destroy the channel if resources 752 * are still in use so the fucntion may exit before all the teardown 753 * operations are completed and would have to be called again by the 754 * vldc framework. 755 * 756 * This function needs to be able to handle the case where it is called 757 * more than once and has to pick up from where it left off. 758 */ 759 static int 760 i_vldc_ldc_close(vldc_port_t *vport) 761 { 762 int retries = 0; /* count of number of retries attempted */ 763 int err = 0; 764 765 ASSERT(MUTEX_HELD(&vport->minorp->lock)); 766 767 while ((err = ldc_close(vport->ldc_handle)) == EAGAIN) { 768 drv_usecwait(vldc_delay); 769 if (++retries > vldc_retries) 770 break; 771 } 772 /* 773 * If ldc_close() succeeded or if the channel was already closed[*] 774 * (possibly by a previously unsuccessful call to this function) 775 * we keep going and try to teardown the rest of the LDC state, 776 * otherwise we bail out. 777 * 778 * [*] indicated by ldc_close() returning a value of EFAULT 779 */ 780 if ((err != 0) && (err != EFAULT)) 781 return (err); 782 783 err = ldc_unreg_callback(vport->ldc_handle); 784 if (err != 0) 785 return (err); 786 787 err = ldc_fini(vport->ldc_handle); 788 if (err != 0) 789 return (err); 790 791 vport->status = VLDC_PORT_OPEN; 792 793 return (0); 794 } 795 796 /* close a vldc port */ 797 static int 798 i_vldc_close_port(vldc_t *vldcp, uint_t portno) 799 { 800 vldc_port_t *vport; 801 int rv = DDI_SUCCESS; 802 803 vport = &(vldcp->port[portno]); 804 805 ASSERT(MUTEX_HELD(&vport->minorp->lock)); 806 807 D1("i_vldc_close_port: vldc@%d:%d: closing port\n", 808 vport->inst, vport->minorp->portno); 809 810 switch (vport->status) { 811 case VLDC_PORT_CLOSED: 812 /* nothing to do */ 813 DWARN("i_vldc_close_port: port %d in an unexpected " 814 "state (%d)\n", portno, vport->status); 815 return (DDI_SUCCESS); 816 817 case VLDC_PORT_READY: 818 case VLDC_PORT_RESET: 819 rv = i_vldc_ldc_close(vport); 820 if (rv != 0) 821 return (rv); 822 break; 823 824 case VLDC_PORT_OPEN: 825 break; 826 827 default: 828 DWARN("i_vldc_close_port: port %d in an unexpected " 829 "state (%d)\n", portno, vport->status); 830 ASSERT(0); /* fail quickly to help diagnosis */ 831 return (EINVAL); 832 } 833 834 ASSERT(vport->status == VLDC_PORT_OPEN); 835 836 /* free memory */ 837 kmem_free(vport->send_buf, vport->mtu); 838 kmem_free(vport->recv_buf, vport->mtu); 839 840 if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME) == 0) 841 kmem_free(vport->cookie_buf, vldc_max_cookie); 842 843 vport->status = VLDC_PORT_CLOSED; 844 845 return (rv); 846 } 847 848 /* 849 * attach(9E): attach a device to the system. 850 * called once for each instance of the device on the system. 851 */ 852 static int 853 vldc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 854 { 855 int i, instance; 856 vldc_t *vldcp; 857 858 switch (cmd) { 859 860 case DDI_ATTACH: 861 862 instance = ddi_get_instance(dip); 863 864 if (ddi_soft_state_zalloc(vldc_ssp, instance) != DDI_SUCCESS) { 865 return (DDI_FAILURE); 866 } 867 868 vldcp = ddi_get_soft_state(vldc_ssp, instance); 869 if (vldcp == NULL) { 870 ddi_soft_state_free(vldc_ssp, instance); 871 return (ENXIO); 872 } 873 874 D1("vldc_attach: DDI_ATTACH instance=%d\n", instance); 875 876 mutex_init(&vldcp->lock, NULL, MUTEX_DRIVER, NULL); 877 vldcp->dip = dip; 878 vldcp->detaching = B_FALSE; 879 880 for (i = 0; i < VLDC_MAX_PORTS; i++) { 881 /* No minor node association to start with */ 882 vldcp->port[i].minorp = NULL; 883 } 884 885 for (i = 0; i < VLDC_MAX_MINORS; i++) { 886 mutex_init(&(vldcp->minor_tbl[i].lock), NULL, 887 MUTEX_DRIVER, NULL); 888 cv_init(&(vldcp->minor_tbl[i].cv), NULL, 889 CV_DRIVER, NULL); 890 /* No port association to start with */ 891 vldcp->minor_tbl[i].portno = VLDC_INVALID_PORTNO; 892 } 893 894 /* Register for MD update notification */ 895 if (i_vldc_mdeg_register(vldcp) != DDI_SUCCESS) { 896 ddi_soft_state_free(vldc_ssp, instance); 897 return (DDI_FAILURE); 898 } 899 900 return (DDI_SUCCESS); 901 902 case DDI_RESUME: 903 904 return (DDI_SUCCESS); 905 906 default: 907 908 return (DDI_FAILURE); 909 } 910 } 911 912 /* 913 * detach(9E): detach a device from the system. 914 */ 915 static int 916 vldc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 917 { 918 int i, instance; 919 vldc_t *vldcp; 920 921 switch (cmd) { 922 923 case DDI_DETACH: 924 925 instance = ddi_get_instance(dip); 926 927 vldcp = ddi_get_soft_state(vldc_ssp, instance); 928 if (vldcp == NULL) { 929 return (DDI_FAILURE); 930 } 931 932 D1("vldc_detach: DDI_DETACH instance=%d\n", instance); 933 934 mutex_enter(&vldcp->lock); 935 936 /* Fail the detach if all ports have not been removed. */ 937 for (i = 0; i < VLDC_MAX_MINORS; i++) { 938 if (vldcp->minor_tbl[i].portno != VLDC_INVALID_PORTNO) { 939 D1("vldc_detach: vldc@%d:%d is bound, " 940 "detach failed\n", 941 instance, vldcp->minor_tbl[i].portno); 942 mutex_exit(&vldcp->lock); 943 return (DDI_FAILURE); 944 } 945 } 946 947 /* 948 * Prevent MDEG from adding new ports before the callback can 949 * be unregistered. The lock can't be held accross the 950 * unregistration call because a callback may be in progress 951 * and blocked on the lock. 952 */ 953 vldcp->detaching = B_TRUE; 954 955 mutex_exit(&vldcp->lock); 956 957 if (i_vldc_mdeg_unregister(vldcp) != MDEG_SUCCESS) { 958 vldcp->detaching = B_FALSE; 959 return (DDI_FAILURE); 960 } 961 962 /* Tear down all bound ports and free resources. */ 963 for (i = 0; i < VLDC_MAX_MINORS; i++) { 964 if (vldcp->minor_tbl[i].portno != VLDC_INVALID_PORTNO) { 965 (void) i_vldc_remove_port(vldcp, i); 966 } 967 mutex_destroy(&(vldcp->minor_tbl[i].lock)); 968 cv_destroy(&(vldcp->minor_tbl[i].cv)); 969 } 970 971 mutex_destroy(&vldcp->lock); 972 ddi_soft_state_free(vldc_ssp, instance); 973 974 return (DDI_SUCCESS); 975 976 case DDI_SUSPEND: 977 978 return (DDI_SUCCESS); 979 980 default: 981 982 return (DDI_FAILURE); 983 } 984 } 985 986 /* cb_open */ 987 static int 988 vldc_open(dev_t *devp, int flag, int otyp, cred_t *cred) 989 { 990 _NOTE(ARGUNUSED(flag, otyp, cred)) 991 992 int instance; 993 minor_t minor; 994 uint64_t portno; 995 vldc_t *vldcp; 996 vldc_port_t *vport; 997 vldc_minor_t *vminor; 998 999 minor = getminor(*devp); 1000 instance = VLDCINST(minor); 1001 vldcp = ddi_get_soft_state(vldc_ssp, instance); 1002 if (vldcp == NULL) 1003 return (ENXIO); 1004 1005 vminor = VLDCMINOR(vldcp, minor); 1006 mutex_enter(&vminor->lock); 1007 portno = vminor->portno; 1008 if (portno == VLDC_INVALID_PORTNO) { 1009 mutex_exit(&vminor->lock); 1010 return (ENXIO); 1011 } 1012 1013 vport = &(vldcp->port[portno]); 1014 1015 D1("vldc_open: opening vldc@%d:%lu\n", instance, portno); 1016 1017 if (vport->status != VLDC_PORT_CLOSED) { 1018 mutex_exit(&vminor->lock); 1019 return (EBUSY); 1020 } 1021 1022 vport->recv_buf = kmem_alloc(vport->mtu, KM_SLEEP); 1023 vport->send_buf = kmem_alloc(vport->mtu, KM_SLEEP); 1024 1025 if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME) == 0) 1026 vport->cookie_buf = kmem_alloc(vldc_max_cookie, KM_SLEEP); 1027 1028 vport->is_stream = B_FALSE; /* assume not a stream */ 1029 vport->hanged_up = B_FALSE; 1030 1031 vport->status = VLDC_PORT_OPEN; 1032 1033 mutex_exit(&vminor->lock); 1034 1035 return (DDI_SUCCESS); 1036 } 1037 1038 /* cb_close */ 1039 static int 1040 vldc_close(dev_t dev, int flag, int otyp, cred_t *cred) 1041 { 1042 _NOTE(ARGUNUSED(flag, otyp, cred)) 1043 1044 int instance; 1045 minor_t minor; 1046 uint64_t portno; 1047 vldc_t *vldcp; 1048 vldc_minor_t *vminor; 1049 int rv; 1050 1051 minor = getminor(dev); 1052 instance = VLDCINST(minor); 1053 vldcp = ddi_get_soft_state(vldc_ssp, instance); 1054 if (vldcp == NULL) { 1055 return (ENXIO); 1056 } 1057 1058 vminor = VLDCMINOR(vldcp, minor); 1059 mutex_enter(&vminor->lock); 1060 portno = vminor->portno; 1061 if (portno == VLDC_INVALID_PORTNO) { 1062 mutex_exit(&vminor->lock); 1063 return (ENOLINK); 1064 } 1065 1066 D1("vldc_close: closing vldc@%d:%lu\n", instance, portno); 1067 1068 rv = i_vldc_close_port(vldcp, portno); 1069 1070 mutex_exit(&vminor->lock); 1071 1072 return (rv); 1073 } 1074 1075 static int 1076 vldc_set_ldc_mode(vldc_port_t *vport, vldc_t *vldcp, int channel_mode) 1077 { 1078 ldc_attr_t attr; 1079 int rv; 1080 1081 ASSERT(MUTEX_HELD(&vport->minorp->lock)); 1082 1083 /* validate mode */ 1084 switch (channel_mode) { 1085 case LDC_MODE_STREAM: 1086 vport->is_stream = B_TRUE; 1087 break; 1088 case LDC_MODE_RAW: 1089 case LDC_MODE_UNRELIABLE: 1090 case LDC_MODE_RELIABLE: 1091 vport->is_stream = B_FALSE; 1092 break; 1093 default: 1094 return (EINVAL); 1095 } 1096 1097 if (vport->status == VLDC_PORT_READY) { 1098 rv = i_vldc_ldc_close(vport); 1099 if (rv != 0) { 1100 DWARN("vldc_set_ldc_mode: i_vldc_ldc_close " 1101 "failed, rv=%d\n", rv); 1102 return (rv); 1103 } 1104 } 1105 1106 D1("vldc_set_ldc_mode: vport status %d, mode %d\n", 1107 vport->status, channel_mode); 1108 1109 vport->ldc_mode = channel_mode; 1110 1111 /* initialize the channel */ 1112 attr.devclass = LDC_DEV_SERIAL; 1113 attr.instance = ddi_get_instance(vldcp->dip); 1114 attr.mtu = vport->mtu; 1115 attr.mode = vport->ldc_mode; 1116 1117 if ((rv = ldc_init(vport->ldc_id, &attr, 1118 &vport->ldc_handle)) != 0) { 1119 DWARN("vldc_ioctl_opt_op: ldc_init failed, rv=%d\n", rv); 1120 goto error_init; 1121 } 1122 1123 /* register it */ 1124 if ((rv = ldc_reg_callback(vport->ldc_handle, 1125 i_vldc_cb, (caddr_t)vport)) != 0) { 1126 DWARN("vldc_ioctl_opt_op: ldc_reg_callback failed, rv=%d\n", 1127 rv); 1128 goto error_reg; 1129 } 1130 1131 /* open the channel */ 1132 if ((rv = ldc_open(vport->ldc_handle)) != 0) { 1133 DWARN("vldc_ioctl_opt_op: ldc_open failed, rv=%d\n", rv); 1134 goto error_open; 1135 } 1136 1137 vport->status = VLDC_PORT_READY; 1138 1139 /* 1140 * Attempt to bring the channel up, but do not 1141 * fail if the other end is not up yet. 1142 */ 1143 rv = ldc_up(vport->ldc_handle); 1144 if (rv == ECONNREFUSED) { 1145 D1("vldc_ioctl_opt_op: remote endpoint not up yet\n"); 1146 } else if (rv != 0) { 1147 DWARN("vldc_ioctl_opt_op: ldc_up failed, rv=%d\n", rv); 1148 goto error_up; 1149 } 1150 1151 rv = ldc_status(vport->ldc_handle, &vport->ldc_status); 1152 if (rv != 0) { 1153 DWARN("vldc_ioctl_opt_op: vldc@%d:%d could not get ldc " 1154 "status, rv=%d\n", vport->inst, vport->number, rv); 1155 goto error_up; 1156 } 1157 1158 D1("vldc_ioctl_opt_op: ldc %ld initialized successfully\n", 1159 vport->ldc_id); 1160 1161 return (0); 1162 1163 error_up: 1164 vport->status = VLDC_PORT_OPEN; 1165 (void) ldc_close(vport->ldc_handle); 1166 error_open: 1167 (void) ldc_unreg_callback(vport->ldc_handle); 1168 error_reg: 1169 (void) ldc_fini(vport->ldc_handle); 1170 error_init: 1171 return (rv); 1172 } 1173 1174 /* ioctl to read cookie */ 1175 static int 1176 i_vldc_ioctl_read_cookie(vldc_port_t *vport, int vldc_instance, void *arg, 1177 int mode) 1178 { 1179 vldc_data_t copy_info; 1180 uint64_t len, balance, copy_size; 1181 caddr_t src_addr, dst_addr; 1182 int rv; 1183 1184 if (ddi_copyin(arg, ©_info, sizeof (copy_info), mode) == -1) { 1185 return (EFAULT); 1186 } 1187 1188 len = balance = copy_info.length; 1189 src_addr = (caddr_t)copy_info.src_addr; 1190 dst_addr = (caddr_t)copy_info.dst_addr; 1191 while (balance > 0) { 1192 1193 /* get the max amount to the copied */ 1194 copy_size = MIN(balance, vldc_max_cookie); 1195 1196 mutex_enter(&vport->minorp->lock); 1197 1198 D2("i_vldc_ioctl_read_cookie: vldc@%d:%d reading from 0x%p " 1199 "size 0x%lx to 0x%p\n", vldc_instance, vport->number, 1200 dst_addr, copy_size, src_addr); 1201 1202 /* read from the HV into the temporary buffer */ 1203 rv = ldc_mem_rdwr_cookie(vport->ldc_handle, vport->cookie_buf, 1204 ©_size, dst_addr, LDC_COPY_IN); 1205 if (rv != 0) { 1206 DWARN("i_vldc_ioctl_read_cookie: vldc@%d:%d cannot " 1207 "read address 0x%p, rv=%d\n", 1208 vldc_instance, vport->number, dst_addr, rv); 1209 mutex_exit(&vport->minorp->lock); 1210 return (EFAULT); 1211 } 1212 1213 D2("i_vldc_ioctl_read_cookie: vldc@%d:%d read succeeded\n", 1214 vldc_instance, vport->number); 1215 1216 mutex_exit(&vport->minorp->lock); 1217 1218 /* 1219 * copy data from temporary buffer out to the 1220 * caller and free buffer 1221 */ 1222 rv = ddi_copyout(vport->cookie_buf, src_addr, copy_size, mode); 1223 if (rv != 0) { 1224 return (EFAULT); 1225 } 1226 1227 /* adjust len, source and dest */ 1228 balance -= copy_size; 1229 src_addr += copy_size; 1230 dst_addr += copy_size; 1231 } 1232 1233 /* set the structure to reflect outcome */ 1234 copy_info.length = len; 1235 if (ddi_copyout(©_info, arg, sizeof (copy_info), mode) != 0) { 1236 return (EFAULT); 1237 } 1238 1239 return (0); 1240 } 1241 1242 /* ioctl to write cookie */ 1243 static int 1244 i_vldc_ioctl_write_cookie(vldc_port_t *vport, int vldc_instance, void *arg, 1245 int mode) 1246 { 1247 vldc_data_t copy_info; 1248 uint64_t len, balance, copy_size; 1249 caddr_t src_addr, dst_addr; 1250 int rv; 1251 1252 if (ddi_copyin(arg, ©_info, sizeof (copy_info), mode) != 0) { 1253 return (EFAULT); 1254 } 1255 1256 D2("i_vldc_ioctl_write_cookie: vldc@%d:%d writing 0x%lx size 0x%lx " 1257 "to 0x%lx\n", vldc_instance, vport->number, copy_info.src_addr, 1258 copy_info.length, copy_info.dst_addr); 1259 1260 len = balance = copy_info.length; 1261 src_addr = (caddr_t)copy_info.src_addr; 1262 dst_addr = (caddr_t)copy_info.dst_addr; 1263 while (balance > 0) { 1264 1265 /* get the max amount to the copied */ 1266 copy_size = MIN(balance, vldc_max_cookie); 1267 1268 /* 1269 * copy into the temporary buffer the data 1270 * to be written to the HV 1271 */ 1272 if (ddi_copyin((caddr_t)src_addr, vport->cookie_buf, 1273 copy_size, mode) != 0) { 1274 return (EFAULT); 1275 } 1276 1277 mutex_enter(&vport->minorp->lock); 1278 1279 /* write the data from the temporary buffer to the HV */ 1280 rv = ldc_mem_rdwr_cookie(vport->ldc_handle, vport->cookie_buf, 1281 ©_size, dst_addr, LDC_COPY_OUT); 1282 if (rv != 0) { 1283 DWARN("i_vldc_ioctl_write_cookie: vldc@%d:%d " 1284 "failed to write at address 0x%p\n, rv=%d", 1285 vldc_instance, vport->number, dst_addr, rv); 1286 mutex_exit(&vport->minorp->lock); 1287 return (EFAULT); 1288 } 1289 1290 D2("i_vldc_ioctl_write_cookie: vldc@%d:%d write succeeded\n", 1291 vldc_instance, vport->number); 1292 1293 mutex_exit(&vport->minorp->lock); 1294 1295 /* adjust len, source and dest */ 1296 balance -= copy_size; 1297 src_addr += copy_size; 1298 dst_addr += copy_size; 1299 } 1300 1301 /* set the structure to reflect outcome */ 1302 copy_info.length = len; 1303 if (ddi_copyout(©_info, (caddr_t)arg, 1304 sizeof (copy_info), mode) != 0) { 1305 return (EFAULT); 1306 } 1307 1308 return (0); 1309 } 1310 1311 /* vldc specific ioctl option commands */ 1312 static int 1313 i_vldc_ioctl_opt_op(vldc_port_t *vport, vldc_t *vldcp, void *arg, int mode) 1314 { 1315 vldc_opt_op_t vldc_cmd; 1316 uint32_t new_mtu; 1317 int rv = 0; 1318 1319 if (ddi_copyin(arg, &vldc_cmd, sizeof (vldc_cmd), mode) != 0) { 1320 return (EFAULT); 1321 } 1322 1323 D1("vldc_ioctl_opt_op: op %d\n", vldc_cmd.opt_sel); 1324 1325 switch (vldc_cmd.opt_sel) { 1326 1327 case VLDC_OPT_MTU_SZ: 1328 1329 if (vldc_cmd.op_sel == VLDC_OP_GET) { 1330 vldc_cmd.opt_val = vport->mtu; 1331 if (ddi_copyout(&vldc_cmd, arg, 1332 sizeof (vldc_cmd), mode) == -1) { 1333 return (EFAULT); 1334 } 1335 } else { 1336 new_mtu = vldc_cmd.opt_val; 1337 1338 if ((new_mtu < LDC_PACKET_SIZE) || 1339 (new_mtu > vldc_max_mtu)) { 1340 return (EINVAL); 1341 } 1342 1343 mutex_enter(&vport->minorp->lock); 1344 1345 if ((vport->status != VLDC_PORT_CLOSED) && 1346 (new_mtu != vport->mtu)) { 1347 /* 1348 * The port has buffers allocated since it is 1349 * not closed plus the MTU size has changed. 1350 * Reallocate the buffers to the new MTU size. 1351 */ 1352 kmem_free(vport->recv_buf, vport->mtu); 1353 vport->recv_buf = kmem_alloc(new_mtu, KM_SLEEP); 1354 1355 kmem_free(vport->send_buf, vport->mtu); 1356 vport->send_buf = kmem_alloc(new_mtu, KM_SLEEP); 1357 1358 vport->mtu = new_mtu; 1359 } 1360 1361 mutex_exit(&vport->minorp->lock); 1362 } 1363 1364 break; 1365 1366 case VLDC_OPT_STATUS: 1367 1368 if (vldc_cmd.op_sel == VLDC_OP_GET) { 1369 vldc_cmd.opt_val = vport->status; 1370 if (ddi_copyout(&vldc_cmd, arg, 1371 sizeof (vldc_cmd), mode) == -1) { 1372 return (EFAULT); 1373 } 1374 } else { 1375 return (ENOTSUP); 1376 } 1377 1378 break; 1379 1380 case VLDC_OPT_MODE: 1381 1382 if (vldc_cmd.op_sel == VLDC_OP_GET) { 1383 vldc_cmd.opt_val = vport->ldc_mode; 1384 if (ddi_copyout(&vldc_cmd, arg, 1385 sizeof (vldc_cmd), mode) == -1) { 1386 return (EFAULT); 1387 } 1388 } else { 1389 mutex_enter(&vport->minorp->lock); 1390 rv = vldc_set_ldc_mode(vport, vldcp, vldc_cmd.opt_val); 1391 mutex_exit(&vport->minorp->lock); 1392 } 1393 1394 break; 1395 1396 default: 1397 1398 D1("vldc_ioctl_opt_op: unsupported op %d\n", vldc_cmd.opt_sel); 1399 return (ENOTSUP); 1400 } 1401 1402 return (rv); 1403 } 1404 1405 /* cb_ioctl */ 1406 static int 1407 vldc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 1408 int *rvalp) 1409 { 1410 _NOTE(ARGUNUSED(credp, rvalp)) 1411 1412 int rv = EINVAL; 1413 int instance; 1414 minor_t minor; 1415 uint64_t portno; 1416 vldc_t *vldcp; 1417 vldc_port_t *vport; 1418 vldc_minor_t *vminor; 1419 1420 minor = getminor(dev); 1421 instance = VLDCINST(minor); 1422 vldcp = ddi_get_soft_state(vldc_ssp, instance); 1423 if (vldcp == NULL) { 1424 return (ENXIO); 1425 } 1426 1427 vminor = VLDCMINOR(vldcp, minor); 1428 mutex_enter(&vminor->lock); 1429 portno = vminor->portno; 1430 if (portno == VLDC_INVALID_PORTNO) { 1431 mutex_exit(&vminor->lock); 1432 return (ENOLINK); 1433 } 1434 vminor->in_use += 1; 1435 mutex_exit(&vminor->lock); 1436 1437 vport = &(vldcp->port[portno]); 1438 1439 D1("vldc_ioctl: vldc@%d:%lu cmd=0x%x\n", instance, portno, cmd); 1440 1441 switch (cmd) { 1442 1443 case VLDC_IOCTL_OPT_OP: 1444 rv = i_vldc_ioctl_opt_op(vport, vldcp, (void *)arg, mode); 1445 break; 1446 1447 case VLDC_IOCTL_READ_COOKIE: 1448 if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME)) { 1449 rv = EINVAL; 1450 break; 1451 } 1452 rv = i_vldc_ioctl_read_cookie(vport, instance, 1453 (void *)arg, mode); 1454 break; 1455 1456 case VLDC_IOCTL_WRITE_COOKIE: 1457 if (strcmp(vport->minorp->sname, VLDC_HVCTL_SVCNAME)) { 1458 rv = EINVAL; 1459 break; 1460 } 1461 rv = i_vldc_ioctl_write_cookie(vport, instance, 1462 (void *)arg, mode); 1463 break; 1464 1465 default: 1466 DWARN("vldc_ioctl: vldc@%d:%lu unknown cmd=0x%x\n", 1467 instance, portno, cmd); 1468 rv = EINVAL; 1469 break; 1470 } 1471 1472 mutex_enter(&vminor->lock); 1473 vminor->in_use -= 1; 1474 if (vminor->in_use == 0) { 1475 cv_signal(&vminor->cv); 1476 } 1477 mutex_exit(&vminor->lock); 1478 1479 D1("vldc_ioctl: rv=%d\n", rv); 1480 1481 return (rv); 1482 } 1483 1484 /* cb_read */ 1485 static int 1486 vldc_read(dev_t dev, struct uio *uiop, cred_t *credp) 1487 { 1488 _NOTE(ARGUNUSED(credp)) 1489 1490 int instance; 1491 minor_t minor; 1492 size_t size = 0; 1493 uint64_t portno; 1494 vldc_t *vldcp; 1495 vldc_port_t *vport; 1496 vldc_minor_t *vminor; 1497 int rv = 0; 1498 1499 minor = getminor(dev); 1500 instance = VLDCINST(minor); 1501 vldcp = ddi_get_soft_state(vldc_ssp, instance); 1502 if (vldcp == NULL) { 1503 return (ENXIO); 1504 } 1505 1506 vminor = VLDCMINOR(vldcp, minor); 1507 mutex_enter(&vminor->lock); 1508 portno = vminor->portno; 1509 if (portno == VLDC_INVALID_PORTNO) { 1510 mutex_exit(&vminor->lock); 1511 return (ENOLINK); 1512 } 1513 1514 D2("vldc_read: vldc@%d:%lu reading data\n", instance, portno); 1515 1516 vport = &(vldcp->port[portno]); 1517 1518 /* check the port status */ 1519 if (vport->status != VLDC_PORT_READY) { 1520 DWARN("vldc_read: vldc@%d:%lu not in the ready state\n", 1521 instance, portno); 1522 mutex_exit(&vminor->lock); 1523 return (ENOTACTIVE); 1524 } 1525 1526 /* read data */ 1527 size = MIN(vport->mtu, uiop->uio_resid); 1528 rv = ldc_read(vport->ldc_handle, vport->recv_buf, &size); 1529 1530 D2("vldc_read: vldc@%d:%lu ldc_read size=%ld, rv=%d\n", 1531 instance, portno, size, rv); 1532 1533 if (rv == 0) { 1534 if (size != 0) { 1535 rv = uiomove(vport->recv_buf, size, UIO_READ, uiop); 1536 } else { 1537 rv = EWOULDBLOCK; 1538 } 1539 } else { 1540 switch (rv) { 1541 case ENOBUFS: 1542 break; 1543 case ETIMEDOUT: 1544 case EWOULDBLOCK: 1545 rv = EWOULDBLOCK; 1546 break; 1547 default: 1548 rv = ECONNRESET; 1549 break; 1550 } 1551 } 1552 1553 mutex_exit(&vminor->lock); 1554 1555 return (rv); 1556 } 1557 1558 /* cb_write */ 1559 static int 1560 vldc_write(dev_t dev, struct uio *uiop, cred_t *credp) 1561 { 1562 _NOTE(ARGUNUSED(credp)) 1563 1564 int instance; 1565 minor_t minor; 1566 size_t size; 1567 size_t orig_size; 1568 uint64_t portno; 1569 vldc_t *vldcp; 1570 vldc_port_t *vport; 1571 vldc_minor_t *vminor; 1572 int rv = EINVAL; 1573 1574 minor = getminor(dev); 1575 instance = VLDCINST(minor); 1576 vldcp = ddi_get_soft_state(vldc_ssp, instance); 1577 if (vldcp == NULL) { 1578 return (ENXIO); 1579 } 1580 1581 vminor = VLDCMINOR(vldcp, minor); 1582 mutex_enter(&vminor->lock); 1583 portno = vminor->portno; 1584 if (portno == VLDC_INVALID_PORTNO) { 1585 mutex_exit(&vminor->lock); 1586 return (ENOLINK); 1587 } 1588 1589 vport = &(vldcp->port[portno]); 1590 1591 /* check the port status */ 1592 if (vport->status != VLDC_PORT_READY) { 1593 DWARN("vldc_write: vldc@%d:%lu not in the ready state\n", 1594 instance, portno); 1595 mutex_exit(&vminor->lock); 1596 return (ENOTACTIVE); 1597 } 1598 1599 orig_size = uiop->uio_resid; 1600 size = orig_size; 1601 1602 if (size > vport->mtu) { 1603 if (vport->is_stream) { 1604 /* can only send MTU size at a time */ 1605 size = vport->mtu; 1606 } else { 1607 mutex_exit(&vminor->lock); 1608 return (EMSGSIZE); 1609 } 1610 } 1611 1612 D2("vldc_write: vldc@%d:%lu writing %lu bytes\n", instance, portno, 1613 size); 1614 1615 rv = uiomove(vport->send_buf, size, UIO_WRITE, uiop); 1616 if (rv == 0) { 1617 rv = ldc_write(vport->ldc_handle, (caddr_t)vport->send_buf, 1618 &size); 1619 if (rv != 0) { 1620 DWARN("vldc_write: vldc@%d:%lu failed writing %lu " 1621 "bytes rv=%d\n", instance, portno, size, rv); 1622 } 1623 } else { 1624 size = 0; 1625 } 1626 1627 mutex_exit(&vminor->lock); 1628 1629 /* resid is total number of bytes *not* sent */ 1630 uiop->uio_resid = orig_size - size; 1631 1632 return (rv); 1633 } 1634 1635 /* cb_chpoll */ 1636 static int 1637 vldc_chpoll(dev_t dev, short events, int anyyet, short *reventsp, 1638 struct pollhead **phpp) 1639 { 1640 int instance; 1641 minor_t minor; 1642 uint64_t portno; 1643 vldc_t *vldcp; 1644 vldc_port_t *vport; 1645 vldc_minor_t *vminor; 1646 boolean_t haspkts; 1647 1648 minor = getminor(dev); 1649 instance = VLDCINST(minor); 1650 vldcp = ddi_get_soft_state(vldc_ssp, instance); 1651 if (vldcp == NULL) { 1652 return (ENXIO); 1653 } 1654 1655 vminor = VLDCMINOR(vldcp, minor); 1656 mutex_enter(&vminor->lock); 1657 portno = vminor->portno; 1658 if (portno == VLDC_INVALID_PORTNO) { 1659 mutex_exit(&vminor->lock); 1660 return (ENOLINK); 1661 } 1662 1663 vport = &(vldcp->port[portno]); 1664 1665 /* check the port status */ 1666 if (vport->status != VLDC_PORT_READY) { 1667 mutex_exit(&vminor->lock); 1668 return (ENOTACTIVE); 1669 } 1670 1671 D2("vldc_chpoll: vldc@%d:%lu polling events 0x%x\n", 1672 instance, portno, events); 1673 1674 *reventsp = 0; 1675 1676 if (vport->ldc_status == LDC_UP) { 1677 /* 1678 * Check if the receive queue is empty and if not, signal that 1679 * there is data ready to read. 1680 */ 1681 if (events & POLLIN) { 1682 if ((ldc_chkq(vport->ldc_handle, &haspkts) == 0) && 1683 haspkts) { 1684 *reventsp |= POLLIN; 1685 } 1686 } 1687 1688 if (events & POLLOUT) 1689 *reventsp |= POLLOUT; 1690 1691 } else if (vport->hanged_up) { 1692 *reventsp |= POLLHUP; 1693 vport->hanged_up = B_FALSE; 1694 } 1695 1696 mutex_exit(&vminor->lock); 1697 1698 if (((*reventsp) == 0) && (!anyyet)) { 1699 *phpp = &vport->poll; 1700 } 1701 1702 D2("vldc_chpoll: vldc@%d:%lu ev=0x%x, rev=0x%x\n", 1703 instance, portno, events, *reventsp); 1704 1705 return (0); 1706 } 1707