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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 #include <sys/time.h> 28 #include <sys/errno.h> 29 #include <sys/kmem.h> 30 #include <sys/stat.h> 31 #include <sys/cmn_err.h> 32 33 #include <sys/conf.h> 34 #include <sys/modctl.h> 35 #include <sys/devops.h> 36 #include <sys/ddi.h> 37 #include <sys/sunddi.h> 38 #include <sys/callb.h> 39 #include <sys/disp.h> 40 #include <sys/strlog.h> 41 #include <sys/file.h> 42 43 #include <sys/uadmin.h> 44 #include <sys/machsystm.h> 45 #include <sys/hypervisor_api.h> 46 #include <sys/hsvc.h> 47 #include <sys/glvc.h> 48 49 /* 50 * Global Variables - can be patched from Solaris 51 * ============================================== 52 */ 53 54 /* bit defination in virtual device register */ 55 #define GLVC_REG_RECV 0x0001 56 #define GLVC_REG_RECV_ENA 0x0002 57 #define GLVC_REG_SEND 0x0004 58 #define GLVC_REG_SEND_ENA 0x0008 59 #define GLVC_REG_ERR 0x8000 60 61 /* 62 * For interrupt mode 63 */ 64 #define GLVC_MODE_NONE 0 65 #define GLVC_POLLING_MODE 1 66 #define GLVC_INTR_MODE 2 67 68 /* 69 * For open 70 */ 71 #define GLVC_NO_OPEN 0 72 #define GLVC_OPEN 1 73 #define GLVC_EXCL_OPEN 2 74 75 /* 76 * For timeout polling, in microsecond. 77 */ 78 #define GLVC_TIMEOUT_POLL 5000000 /* Timeout in intr mode */ 79 #define GLVC_POLLMODE_POLL 500000 /* Interval in polling mode */ 80 81 /* 82 * For debug printing 83 */ 84 #define _PRINTF printf 85 #define DPRINTF(args) if (glvc_debug) _PRINTF args; 86 87 /* 88 * Driver entry points 89 */ 90 static int glvc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 91 static int glvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 92 static int glvc_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p); 93 static int glvc_close(dev_t dev, int flag, int otyp, cred_t *cred_p); 94 static int glvc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 95 cred_t *cred_p, int *rval_p); 96 static int glvc_read(dev_t dev, struct uio *uiop, cred_t *credp); 97 static int glvc_write(dev_t dev, struct uio *uiop, cred_t *credp); 98 99 static struct cb_ops glvc_cb_ops = { 100 glvc_open, /* open */ 101 glvc_close, /* close */ 102 nodev, /* strategy() */ 103 nodev, /* print() */ 104 nodev, /* dump() */ 105 glvc_read, /* read() */ 106 glvc_write, /* write() */ 107 glvc_ioctl, /* ioctl() */ 108 nodev, /* devmap() */ 109 nodev, /* mmap() */ 110 ddi_segmap, /* segmap() */ 111 nochpoll, /* poll() */ 112 ddi_prop_op, /* prop_op() */ 113 NULL, /* cb_str */ 114 D_NEW | D_MP /* cb_flag */ 115 }; 116 117 118 static struct dev_ops glvc_ops = { 119 DEVO_REV, 120 0, /* ref count */ 121 ddi_getinfo_1to1, /* getinfo() */ 122 nulldev, /* identify() */ 123 nulldev, /* probe() */ 124 glvc_attach, /* attach() */ 125 glvc_detach, /* detach */ 126 nodev, /* reset */ 127 &glvc_cb_ops, /* pointer to cb_ops structure */ 128 (struct bus_ops *)NULL, 129 nulldev, /* power() */ 130 ddi_quiesce_not_needed, /* quiesce */ 131 }; 132 133 /* 134 * Loadable module support. 135 */ 136 extern struct mod_ops mod_driverops; 137 138 static struct modldrv modldrv = { 139 &mod_driverops, /* Type of module. This is a driver */ 140 "Sun4v virtual channel driver", /* Name of the module */ 141 &glvc_ops /* pointer to the dev_ops structure */ 142 }; 143 144 static struct modlinkage modlinkage = { 145 MODREV_1, 146 &modldrv, 147 NULL 148 }; 149 150 typedef struct glvc_soft_state { 151 dev_info_t *dip; /* dev info of myself */ 152 uint64_t s_id; /* service id for this node */ 153 uint64_t mtu; /* max transmit unit size */ 154 uint64_t flag; /* flag register */ 155 kmutex_t open_mutex; /* protect open_state flag */ 156 uint8_t open_state; /* no-open, open or open exclusively */ 157 kmutex_t recv_mutex; 158 kmutex_t send_complete_mutex; 159 uint8_t send_complete_flag; /* 1 = send completed */ 160 uint8_t intr_mode; /* 1 = polling mode, 2 = interrupt mode */ 161 clock_t polling_interval; 162 ddi_softintr_t poll_mode_softint_id; 163 kcondvar_t recv_cv; 164 kcondvar_t send_complete_cv; 165 kmutex_t statusreg_mutex; /* Protects status register */ 166 char *mb_recv_buf; 167 char *mb_send_buf; 168 uint64_t mb_recv_buf_pa; 169 uint64_t mb_send_buf_pa; 170 } glvc_soft_state_t; 171 172 /* 173 * Hypervisor VSC api versioning information for glvc driver. 174 */ 175 static uint64_t glvc_vsc_min_ver; /* Negotiated VSC API minor version */ 176 static uint_t glvc_vsc_users = 0; /* VSC API users */ 177 static kmutex_t glvc_vsc_users_mutex; /* Mutex to protect user count */ 178 179 static hsvc_info_t glvc_hsvc = { 180 HSVC_REV_1, NULL, HSVC_GROUP_VSC, GLVC_VSC_MAJOR_VER, 181 GLVC_VSC_MINOR_VER, "glvc" 182 }; 183 184 /* 185 * Module Variables 186 * ================ 187 */ 188 189 /* 190 * functions local to this driver. 191 */ 192 static int glvc_add_intr_handlers(dev_info_t *dip); 193 static int glvc_remove_intr_handlers(dev_info_t *dip); 194 static uint_t glvc_intr(caddr_t arg); 195 static int glvc_peek(glvc_soft_state_t *softsp, 196 glvc_xport_msg_peek_t *msg_peek); 197 static uint_t glvc_soft_intr(caddr_t arg); 198 static int glvc_emap_h2s(uint64_t hv_errcode); 199 static int glvc_ioctl_opt_op(glvc_soft_state_t *softsp, 200 intptr_t arg, int mode); 201 202 /* 203 * Driver globals 204 */ 205 static void *glvc_ssp; /* pointer to driver soft state */ 206 207 static uint_t glvc_debug = 0; 208 209 int 210 _init(void) 211 { 212 int error = 0; 213 214 if ((error = ddi_soft_state_init(&glvc_ssp, 215 sizeof (glvc_soft_state_t), 1)) != 0) 216 return (error); 217 218 /* 219 * Initialize the mutex for global data structure 220 */ 221 mutex_init(&glvc_vsc_users_mutex, NULL, MUTEX_DRIVER, NULL); 222 223 error = mod_install(&modlinkage); 224 225 return (error); 226 } 227 228 229 int 230 _info(struct modinfo *modinfop) 231 { 232 return (mod_info(&modlinkage, modinfop)); 233 } 234 235 236 int 237 _fini(void) 238 { 239 int error = 0; 240 241 error = mod_remove(&modlinkage); 242 if (error) 243 return (error); 244 245 mutex_destroy(&glvc_vsc_users_mutex); 246 247 ddi_soft_state_fini(&glvc_ssp); 248 return (0); 249 } 250 251 252 static int 253 glvc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 254 { 255 int instance; 256 int err; 257 glvc_soft_state_t *softsp; 258 259 switch (cmd) { 260 case DDI_ATTACH: 261 instance = ddi_get_instance(dip); 262 263 /* 264 * Negotiate the API version for VSC hypervisor services. 265 */ 266 mutex_enter(&glvc_vsc_users_mutex); 267 if (glvc_vsc_users == 0 && 268 (err = hsvc_register(&glvc_hsvc, &glvc_vsc_min_ver)) 269 != 0) { 270 cmn_err(CE_WARN, "%s: cannot negotiate hypervisor " 271 "services group: 0x%lx major: 0x%lx minor: 0x%lx " 272 "errno: %d\n", glvc_hsvc.hsvc_modname, 273 glvc_hsvc.hsvc_group, glvc_hsvc.hsvc_major, 274 glvc_hsvc.hsvc_minor, err); 275 276 mutex_exit(&glvc_vsc_users_mutex); 277 return (DDI_FAILURE); 278 } else { 279 glvc_vsc_users++; 280 mutex_exit(&glvc_vsc_users_mutex); 281 } 282 283 DPRINTF(("Glvc instance %d negotiated VSC API version, " 284 " major 0x%lx minor 0x%lx\n", 285 instance, glvc_hsvc.hsvc_major, glvc_vsc_min_ver)); 286 287 if (ddi_soft_state_zalloc(glvc_ssp, instance) 288 != DDI_SUCCESS) { 289 mutex_enter(&glvc_vsc_users_mutex); 290 if (--glvc_vsc_users == 0) 291 (void) hsvc_unregister(&glvc_hsvc); 292 mutex_exit(&glvc_vsc_users_mutex); 293 return (DDI_FAILURE); 294 } 295 296 softsp = ddi_get_soft_state(glvc_ssp, instance); 297 298 /* Set the dip in the soft state */ 299 softsp->dip = dip; 300 301 softsp->open_state = GLVC_NO_OPEN; 302 softsp->send_complete_flag = 1; 303 304 glvc_debug = (uint64_t)ddi_getprop(DDI_DEV_T_ANY, 305 softsp->dip, DDI_PROP_DONTPASS, "glvc_debug", glvc_debug); 306 307 if ((softsp->s_id = (uint64_t)ddi_getprop(DDI_DEV_T_ANY, 308 softsp->dip, DDI_PROP_DONTPASS, "channel#", -1)) 309 == -1) { 310 cmn_err(CE_WARN, "Failed to get channel#"); 311 goto bad; 312 } 313 314 if ((softsp->mtu = (uint64_t)ddi_getprop(DDI_DEV_T_ANY, 315 softsp->dip, DDI_PROP_DONTPASS, "mtu", -1)) 316 <= 0) { 317 cmn_err(CE_WARN, "Failed to get mtu"); 318 goto bad; 319 } 320 321 softsp->mb_recv_buf = 322 (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP); 323 if (softsp->mb_recv_buf == NULL) { 324 cmn_err(CE_WARN, "Failed to alloc mem for recv buf"); 325 goto bad; 326 } 327 softsp->mb_recv_buf_pa = 328 va_to_pa((caddr_t)softsp->mb_recv_buf); 329 330 softsp->mb_send_buf = 331 (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP); 332 if (softsp->mb_send_buf == NULL) { 333 kmem_free(softsp->mb_recv_buf, softsp->mtu); 334 cmn_err(CE_WARN, "Failed to alloc mem for send buf"); 335 goto bad; 336 } 337 softsp->mb_send_buf_pa = 338 va_to_pa((caddr_t)softsp->mb_send_buf); 339 340 err = ddi_create_minor_node(dip, "glvc", S_IFCHR, 341 instance, DDI_PSEUDO, NULL); 342 if (err != DDI_SUCCESS) { 343 kmem_free(softsp->mb_recv_buf, softsp->mtu); 344 kmem_free(softsp->mb_send_buf, softsp->mtu); 345 cmn_err(CE_WARN, "Failed to create minor node"); 346 goto bad; 347 } 348 349 mutex_init(&(softsp->open_mutex), NULL, MUTEX_DRIVER, NULL); 350 mutex_init(&(softsp->recv_mutex), NULL, MUTEX_DRIVER, NULL); 351 mutex_init(&(softsp->send_complete_mutex), NULL, 352 MUTEX_DRIVER, NULL); 353 mutex_init(&(softsp->statusreg_mutex), NULL, 354 MUTEX_DRIVER, NULL); 355 cv_init(&(softsp->recv_cv), NULL, CV_DRIVER, NULL); 356 cv_init(&(softsp->send_complete_cv), NULL, CV_DRIVER, NULL); 357 358 /* 359 * Add the handlers which watch for unsolicited messages 360 * and post event to Sysevent Framework. 361 */ 362 err = glvc_add_intr_handlers(dip); 363 if (err != DDI_SUCCESS) { 364 cmn_err(CE_WARN, "Failed to add intr handler"); 365 kmem_free(softsp->mb_recv_buf, softsp->mtu); 366 kmem_free(softsp->mb_send_buf, softsp->mtu); 367 ddi_remove_minor_node(dip, NULL); 368 goto bad1; 369 } 370 371 /* 372 * Trigger soft interrupt to start polling device if 373 * we are in the polling mode 374 */ 375 if (softsp->intr_mode == GLVC_POLLING_MODE) 376 ddi_trigger_softintr(softsp->poll_mode_softint_id); 377 378 ddi_report_dev(dip); 379 380 DPRINTF(("glvc instance %d, s_id %lu," 381 "mtu %lu attached\n", instance, softsp->s_id, 382 softsp->mtu)); 383 384 return (DDI_SUCCESS); 385 case DDI_RESUME: 386 return (DDI_SUCCESS); 387 default: 388 return (DDI_FAILURE); 389 } 390 391 bad1: 392 cv_destroy(&(softsp->send_complete_cv)); 393 cv_destroy(&(softsp->recv_cv)); 394 mutex_destroy(&(softsp->open_mutex)); 395 mutex_destroy(&(softsp->send_complete_mutex)); 396 mutex_destroy(&(softsp->recv_mutex)); 397 mutex_destroy(&(softsp->statusreg_mutex)); 398 399 bad: 400 mutex_enter(&glvc_vsc_users_mutex); 401 if (--glvc_vsc_users == 0) 402 (void) hsvc_unregister(&glvc_hsvc); 403 mutex_exit(&glvc_vsc_users_mutex); 404 cmn_err(CE_WARN, "glvc: attach failed for instance %d\n", instance); 405 ddi_soft_state_free(glvc_ssp, instance); 406 return (DDI_FAILURE); 407 } 408 409 410 static int 411 glvc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 412 { 413 int instance; 414 int err; 415 glvc_soft_state_t *softsp; 416 417 418 switch (cmd) { 419 case DDI_DETACH: 420 instance = ddi_get_instance(dip); 421 422 softsp = ddi_get_soft_state(glvc_ssp, instance); 423 424 cv_destroy(&(softsp->send_complete_cv)); 425 cv_destroy(&(softsp->recv_cv)); 426 mutex_destroy(&(softsp->open_mutex)); 427 mutex_destroy(&(softsp->statusreg_mutex)); 428 mutex_destroy(&(softsp->send_complete_mutex)); 429 mutex_destroy(&(softsp->recv_mutex)); 430 431 kmem_free(softsp->mb_recv_buf, softsp->mtu); 432 kmem_free(softsp->mb_send_buf, softsp->mtu); 433 434 err = glvc_remove_intr_handlers(dip); 435 436 if (err != DDI_SUCCESS) { 437 cmn_err(CE_WARN, "Failed to remove event handlers"); 438 return (DDI_FAILURE); 439 } 440 441 ddi_remove_minor_node(dip, NULL); 442 443 ddi_soft_state_free(glvc_ssp, instance); 444 445 mutex_enter(&glvc_vsc_users_mutex); 446 if (--glvc_vsc_users == 0) 447 (void) hsvc_unregister(&glvc_hsvc); 448 mutex_exit(&glvc_vsc_users_mutex); 449 450 return (DDI_SUCCESS); 451 case DDI_SUSPEND: 452 return (DDI_SUCCESS); 453 default: 454 return (DDI_FAILURE); 455 } 456 } 457 458 static int 459 glvc_add_intr_handlers(dev_info_t *dip) 460 { 461 int instance; 462 glvc_soft_state_t *softsp; 463 int err = DDI_FAILURE; 464 uint64_t polling_interval; 465 466 instance = ddi_get_instance(dip); 467 softsp = ddi_get_soft_state(glvc_ssp, instance); 468 469 if ((uint64_t)ddi_getprop(DDI_DEV_T_ANY, softsp->dip, 470 DDI_PROP_DONTPASS, "flags", -1) != -1) { 471 err = ddi_add_intr(dip, 0, NULL, NULL, glvc_intr, 472 (caddr_t)softsp); 473 if (err != DDI_SUCCESS) 474 cmn_err(CE_NOTE, "glvc, instance %d" 475 " ddi_add_intr() failed, using" 476 " polling mode", instance); 477 } 478 479 if (err == DDI_SUCCESS) { 480 softsp->intr_mode = GLVC_INTR_MODE; 481 polling_interval = (uint64_t)ddi_getprop(DDI_DEV_T_ANY, 482 softsp->dip, DDI_PROP_DONTPASS, "intrmode_poll", 483 GLVC_TIMEOUT_POLL); 484 DPRINTF(("glvc instance %d polling_interval = %lu\n", 485 instance, polling_interval)); 486 softsp->polling_interval = drv_usectohz(polling_interval); 487 } else { 488 DPRINTF(("glvc, instance %d intr support not found, " 489 "err = %d , use polling mode", instance, err)); 490 softsp->intr_mode = GLVC_POLLING_MODE; 491 polling_interval = 492 (uint64_t)ddi_getprop(DDI_DEV_T_ANY, 493 softsp->dip, DDI_PROP_DONTPASS, "pollmode_poll", 494 GLVC_POLLMODE_POLL); 495 DPRINTF(("glvc instance %d polling_interval = %lu\n", 496 instance, polling_interval)); 497 softsp->polling_interval = 498 drv_usectohz(polling_interval); 499 } 500 501 /* Now enable interrupt bits in the status register */ 502 if (softsp->intr_mode == GLVC_INTR_MODE) { 503 err = hv_service_setstatus(softsp->s_id, 504 GLVC_REG_RECV_ENA|GLVC_REG_SEND_ENA); 505 if (err != H_EOK) { 506 cmn_err(CE_NOTE, "glvc instance %d" 507 " cannot enable receive interrupt\n", 508 instance); 509 return (DDI_FAILURE); 510 } 511 } 512 513 514 err = ddi_add_softintr(dip, DDI_SOFTINT_LOW, 515 &softsp->poll_mode_softint_id, NULL, NULL, 516 glvc_soft_intr, (caddr_t)softsp); 517 518 return (err); 519 } 520 521 static int 522 glvc_remove_intr_handlers(dev_info_t *dip) 523 { 524 int instance; 525 glvc_soft_state_t *softsp; 526 527 instance = ddi_get_instance(dip); 528 softsp = ddi_get_soft_state(glvc_ssp, instance); 529 530 if (softsp->intr_mode == GLVC_INTR_MODE) 531 ddi_remove_intr(dip, 0, NULL); 532 533 ddi_remove_softintr(softsp->poll_mode_softint_id); 534 535 softsp->intr_mode = GLVC_MODE_NONE; 536 softsp->polling_interval = 0; 537 538 return (DDI_SUCCESS); 539 } 540 541 static uint_t 542 glvc_soft_intr(caddr_t arg) 543 { 544 /* 545 * Call the interrupt handle routine to check the register 546 * status. 547 */ 548 (uint_t)glvc_intr(arg); 549 550 return (DDI_INTR_CLAIMED); 551 } 552 553 /*ARGSUSED*/ 554 static int 555 glvc_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) 556 { 557 int error = 0; 558 int instance; 559 glvc_soft_state_t *softsp; 560 561 instance = getminor(*dev_p); 562 563 softsp = ddi_get_soft_state(glvc_ssp, instance); 564 565 mutex_enter(&softsp->open_mutex); 566 567 switch (softsp->open_state) { 568 case GLVC_NO_OPEN: 569 if (flag & FEXCL) 570 softsp->open_state = GLVC_EXCL_OPEN; 571 else 572 softsp->open_state = GLVC_OPEN; 573 break; 574 575 case GLVC_OPEN: 576 if (flag & FEXCL) 577 error = EBUSY; 578 break; 579 580 case GLVC_EXCL_OPEN: 581 error = EBUSY; 582 break; 583 584 default: 585 /* Should not happen */ 586 cmn_err(CE_WARN, "glvc_open: bad open state %d.", 587 softsp->open_state); 588 error = ENXIO; 589 break; 590 } 591 592 mutex_exit(&softsp->open_mutex); 593 594 return (error); 595 } 596 597 /*ARGSUSED*/ 598 static int 599 glvc_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 600 { 601 glvc_soft_state_t *softsp; 602 int instance; 603 int error = 0; 604 605 instance = getminor(dev); 606 607 softsp = ddi_get_soft_state(glvc_ssp, instance); 608 609 mutex_enter(&softsp->open_mutex); 610 if (softsp->open_state == GLVC_NO_OPEN) { 611 cmn_err(CE_WARN, 612 "glvc_close: device already closed"); 613 error = ENXIO; 614 } else { 615 softsp->open_state = GLVC_NO_OPEN; 616 } 617 mutex_exit(&softsp->open_mutex); 618 619 return (error); 620 } 621 622 /*ARGSUSED*/ 623 static int 624 glvc_read(dev_t dev, struct uio *uiop, cred_t *credp) 625 { 626 glvc_soft_state_t *softsp; 627 int instance; 628 int rv, error = DDI_SUCCESS; 629 uint64_t hverr, recv_count = 0; 630 uint64_t status_reg; 631 clock_t tick; 632 633 instance = getminor(dev); 634 635 softsp = ddi_get_soft_state(glvc_ssp, instance); 636 637 mutex_enter(&softsp->recv_mutex); 638 639 hverr = hv_service_getstatus(softsp->s_id, &status_reg); 640 DPRINTF(("glvc_read: err = %ld, getstatus = 0x%lx", 641 hverr, status_reg)); 642 643 644 /* 645 * If no data available, we wait till we get some. 646 * Notice we still holding the recv_mutex lock at this 647 * point. 648 */ 649 while (hverr == H_EOK && (status_reg & GLVC_REG_RECV) != 650 GLVC_REG_RECV) { 651 tick = ddi_get_lbolt() + softsp->polling_interval; 652 rv = cv_timedwait_sig(&softsp->recv_cv, 653 &softsp->recv_mutex, tick); 654 if (rv == 0) { 655 /* 656 * We got interrupted. 657 */ 658 mutex_exit(&softsp->recv_mutex); 659 return (EINTR); 660 } 661 if (rv == -1) { 662 /* 663 * Timeout wait, trigger a soft intr in case 664 * we miss an interrupt or in polling mode. 665 */ 666 ddi_trigger_softintr(softsp->poll_mode_softint_id); 667 } 668 hverr = hv_service_getstatus(softsp->s_id, &status_reg); 669 DPRINTF(("glvc_read: err = %ld, getstatus = 0x%lx", 670 hverr, status_reg)); 671 } 672 673 /* Read data into kernel buffer */ 674 hverr = hv_service_recv(softsp->s_id, softsp->mb_recv_buf_pa, 675 softsp->mtu, &recv_count); 676 677 DPRINTF(("Instance %d glvc_read returns error = %ld, recv_count = %lu", 678 instance, hverr, recv_count)); 679 680 if (hverr == H_EOK) { 681 if (uiop->uio_resid < recv_count) { 682 DPRINTF(("Instance %d, glvc_read user buffer " 683 "size(%lu) smaller than number of bytes " 684 "received(%lu).", instance, uiop->uio_resid, 685 recv_count)); 686 mutex_exit(&softsp->recv_mutex); 687 return (EINVAL); 688 } 689 /* move data from kernel to user space */ 690 error = uiomove(softsp->mb_recv_buf, recv_count, 691 UIO_READ, uiop); 692 } else { 693 error = glvc_emap_h2s(hverr); 694 } 695 696 /* Clear the RECV data interrupt bit on device register */ 697 if (hv_service_clrstatus(softsp->s_id, GLVC_REG_RECV) != H_EOK) { 698 cmn_err(CE_WARN, "glvc_read clear status reg failed"); 699 } 700 701 /* Set RECV interrupt enable bit so we can receive interrupt */ 702 if (softsp->intr_mode == GLVC_INTR_MODE) 703 if (hv_service_setstatus(softsp->s_id, GLVC_REG_RECV_ENA) 704 != H_EOK) { 705 cmn_err(CE_WARN, "glvc_read set status reg failed"); 706 } 707 708 mutex_exit(&softsp->recv_mutex); 709 710 return (error); 711 } 712 713 /*ARGSUSED*/ 714 static int 715 glvc_write(dev_t dev, struct uio *uiop, cred_t *credp) 716 { 717 glvc_soft_state_t *softsp; 718 int instance; 719 int rv, error = DDI_SUCCESS; 720 uint64_t hverr, send_count = 0; 721 clock_t tick; 722 723 instance = getminor(dev); 724 725 softsp = ddi_get_soft_state(glvc_ssp, instance); 726 727 if (uiop->uio_resid > softsp->mtu) 728 return (EINVAL); 729 730 send_count = uiop->uio_resid; 731 DPRINTF(("instance %d glvc_write: request to send %lu bytes", 732 instance, send_count)); 733 734 mutex_enter(&softsp->send_complete_mutex); 735 while (softsp->send_complete_flag == 0) { 736 tick = ddi_get_lbolt() + softsp->polling_interval; 737 rv = cv_timedwait_sig(&softsp->send_complete_cv, 738 &softsp->send_complete_mutex, tick); 739 if (rv == 0) { 740 /* 741 * We got interrupted. 742 */ 743 mutex_exit(&softsp->send_complete_mutex); 744 return (EINTR); 745 } 746 if (rv == -1) { 747 /* 748 * Timeout wait, trigger a soft intr in case 749 * we miss an interrupt or in polling mode. 750 */ 751 ddi_trigger_softintr(softsp->poll_mode_softint_id); 752 } 753 } 754 755 /* move data from to user to kernel space */ 756 error = uiomove(softsp->mb_send_buf, send_count, 757 UIO_WRITE, uiop); 758 759 if (error == 0) { 760 hverr = hv_service_send(softsp->s_id, 761 softsp->mb_send_buf_pa, send_count, &send_count); 762 error = glvc_emap_h2s(hverr); 763 } 764 765 DPRINTF(("instance %d glvc_write write check error = %d," 766 " send_count = %lu", instance, error, send_count)); 767 768 softsp->send_complete_flag = 0; 769 770 mutex_exit(&softsp->send_complete_mutex); 771 772 return (error); 773 } 774 775 /* 776 * Interrupt handler 777 */ 778 static uint_t 779 glvc_intr(caddr_t arg) 780 { 781 glvc_soft_state_t *softsp = (glvc_soft_state_t *)arg; 782 uint64_t status_reg; 783 int error = DDI_INTR_UNCLAIMED; 784 uint64_t hverr = H_EOK; 785 uint64_t clr_bits = 0; 786 787 mutex_enter(&softsp->recv_mutex); 788 mutex_enter(&softsp->send_complete_mutex); 789 hverr = hv_service_getstatus(softsp->s_id, &status_reg); 790 DPRINTF(("glvc_intr: err = %ld, getstatus = 0x%lx", 791 hverr, status_reg)); 792 793 /* 794 * Clear SEND_COMPLETE bit and disable RECV interrupt 795 */ 796 if (status_reg & GLVC_REG_SEND) 797 clr_bits |= GLVC_REG_SEND; 798 if ((softsp->intr_mode == GLVC_INTR_MODE) && 799 (status_reg & GLVC_REG_RECV)) 800 clr_bits |= GLVC_REG_RECV_ENA; 801 802 if ((hverr = hv_service_clrstatus(softsp->s_id, clr_bits)) 803 != H_EOK) { 804 cmn_err(CE_WARN, "glvc_intr clear status reg failed" 805 "error = %ld", hverr); 806 mutex_exit(&softsp->send_complete_mutex); 807 mutex_exit(&softsp->recv_mutex); 808 return (DDI_INTR_UNCLAIMED); 809 } 810 811 if (status_reg & GLVC_REG_RECV) { 812 cv_broadcast(&softsp->recv_cv); 813 error = DDI_INTR_CLAIMED; 814 } 815 816 if (status_reg & GLVC_REG_SEND) { 817 softsp->send_complete_flag = 1; 818 cv_broadcast(&softsp->send_complete_cv); 819 error = DDI_INTR_CLAIMED; 820 } 821 822 mutex_exit(&softsp->send_complete_mutex); 823 mutex_exit(&softsp->recv_mutex); 824 825 return (error); 826 } 827 828 /* 829 * Peek to see if there is data received. If no data available, 830 * we sleep wait. If there is data, read from hypervisor and copy 831 * to ioctl buffer. We don't clear the receive data interrupt bit. 832 */ 833 static int 834 glvc_peek(glvc_soft_state_t *softsp, glvc_xport_msg_peek_t *msg_peek) 835 { 836 int rv, error = 0; 837 uint64_t hverr = H_EOK; 838 uint64_t recv_count = 0; 839 uint64_t status_reg; 840 clock_t tick; 841 842 mutex_enter(&softsp->recv_mutex); 843 844 hverr = hv_service_getstatus(softsp->s_id, &status_reg); 845 DPRINTF(("glvc_peek: err = %ld, getstatus = 0x%lx", 846 hverr, status_reg)); 847 848 /* 849 * If no data available, we wait till we get some. 850 * Notice we still holding the recv_mutex lock at 851 * this point. 852 */ 853 while (hverr == H_EOK && (status_reg & GLVC_REG_RECV) != 854 GLVC_REG_RECV) { 855 tick = ddi_get_lbolt() + softsp->polling_interval; 856 rv = cv_timedwait_sig(&softsp->recv_cv, 857 &softsp->recv_mutex, tick); 858 if (rv == 0) { 859 /* 860 * We got interrupted. 861 */ 862 mutex_exit(&softsp->recv_mutex); 863 return (EINTR); 864 } 865 if (rv == -1) { 866 /* 867 * Timeout wait, trigger a soft intr in case 868 * we miss an interrupt or in polling mode. 869 */ 870 ddi_trigger_softintr(softsp->poll_mode_softint_id); 871 } 872 hverr = hv_service_getstatus(softsp->s_id, &status_reg); 873 DPRINTF(("glvc_peek: err = %ld, getstatus = 0x%lx", 874 hverr, status_reg)); 875 } 876 877 /* Read data into kernel buffer */ 878 hverr = hv_service_recv(softsp->s_id, softsp->mb_recv_buf_pa, 879 softsp->mtu, &recv_count); 880 DPRINTF(("glvc_peek recv data, error = %ld, recv_count = %lu", 881 hverr, recv_count)); 882 883 if (hverr == H_EOK && recv_count > 0) { 884 (void *) memcpy(msg_peek->buf, 885 softsp->mb_recv_buf, recv_count); 886 msg_peek->buflen = recv_count; 887 } else { 888 error = glvc_emap_h2s(hverr); 889 } 890 891 mutex_exit(&softsp->recv_mutex); 892 893 return (error); 894 } 895 896 static int 897 glvc_ioctl_opt_op(glvc_soft_state_t *softsp, intptr_t arg, int mode) 898 { 899 glvc_xport_opt_op_t glvc_xport_cmd; 900 uint64_t status_reg; 901 int retval = 0; 902 uint64_t hverr; 903 904 if (ddi_copyin((caddr_t)arg, (caddr_t)&glvc_xport_cmd, 905 sizeof (glvc_xport_opt_op_t), mode) != 0) { 906 return (EFAULT); 907 } 908 909 switch (glvc_xport_cmd.opt_sel) { 910 case GLVC_XPORT_OPT_MTU_SZ: 911 if (glvc_xport_cmd.op_sel == GLVC_XPORT_OPT_GET) { 912 glvc_xport_cmd.opt_val = softsp->mtu; 913 retval = ddi_copyout((caddr_t)&glvc_xport_cmd, 914 (caddr_t)arg, sizeof (glvc_xport_opt_op_t), 915 mode); 916 } else 917 retval = ENOTSUP; 918 919 break; 920 921 case GLVC_XPORT_OPT_REG_STATUS: 922 if (glvc_xport_cmd.op_sel == GLVC_XPORT_OPT_GET) { 923 mutex_enter(&softsp->statusreg_mutex); 924 hverr = hv_service_getstatus(softsp->s_id, &status_reg); 925 mutex_exit(&softsp->statusreg_mutex); 926 if (hverr == H_EOK) { 927 glvc_xport_cmd.opt_val = (uint32_t)status_reg; 928 retval = ddi_copyout((caddr_t)&glvc_xport_cmd, 929 (caddr_t)arg, sizeof (glvc_xport_opt_op_t), 930 mode); 931 } else { 932 retval = EIO; 933 } 934 } else { 935 retval = ENOTSUP; 936 } 937 938 break; 939 940 default: 941 retval = ENOTSUP; 942 break; 943 } 944 945 return (retval); 946 } 947 948 949 /*ARGSUSED*/ 950 static int 951 glvc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, 952 int *rval_p) 953 { 954 glvc_soft_state_t *softsp; 955 int instance = getminor(dev); 956 glvc_xport_msg_peek_t glvc_peek_msg, msg_peek_cmd; 957 glvc_xport_msg_peek32_t msg_peek_cmd32; 958 959 int retval = 0; 960 961 softsp = ddi_get_soft_state(glvc_ssp, instance); 962 963 switch (cmd) { 964 case GLVC_XPORT_IOCTL_OPT_OP: 965 retval = glvc_ioctl_opt_op(softsp, arg, mode); 966 break; 967 968 case GLVC_XPORT_IOCTL_DATA_PEEK: 969 glvc_peek_msg.buf = 970 (char *)kmem_zalloc(softsp->mtu, KM_NOSLEEP); 971 if (glvc_peek_msg.buf == NULL) 972 return (EBUSY); 973 retval = glvc_peek(softsp, &glvc_peek_msg); 974 if (retval == 0) { 975 switch (ddi_model_convert_from(mode)) { 976 case DDI_MODEL_ILP32: 977 if (ddi_copyin((caddr_t)arg, 978 (caddr_t)&msg_peek_cmd32, 979 sizeof (glvc_xport_msg_peek32_t), 980 mode) == -1) { 981 retval = EFAULT; 982 break; 983 } 984 985 if (msg_peek_cmd32.buflen32 == 0) { 986 retval = EINVAL; 987 break; 988 } 989 990 if (msg_peek_cmd32.buflen32 > 991 glvc_peek_msg.buflen) 992 msg_peek_cmd32.buflen32 = 993 glvc_peek_msg.buflen; 994 995 if (ddi_copyout((caddr_t)glvc_peek_msg.buf, 996 (caddr_t)(uintptr_t)msg_peek_cmd32.buf32, 997 msg_peek_cmd32.buflen32, mode) == -1) { 998 retval = EFAULT; 999 break; 1000 } 1001 1002 if (ddi_copyout((caddr_t)&msg_peek_cmd32, 1003 (caddr_t)arg, 1004 sizeof (glvc_xport_msg_peek32_t), mode) 1005 == -1) 1006 retval = EFAULT; 1007 break; 1008 1009 case DDI_MODEL_NONE: 1010 if (ddi_copyin((caddr_t)arg, 1011 (caddr_t)&msg_peek_cmd, 1012 sizeof (glvc_xport_msg_peek_t), mode) == -1) 1013 retval = EFAULT; 1014 1015 if (msg_peek_cmd.buflen == 0) { 1016 retval = EINVAL; 1017 break; 1018 } 1019 1020 if (msg_peek_cmd.buflen > glvc_peek_msg.buflen) 1021 msg_peek_cmd.buflen = 1022 glvc_peek_msg.buflen; 1023 1024 if (ddi_copyout((caddr_t)glvc_peek_msg.buf, 1025 (caddr_t)msg_peek_cmd.buf, 1026 msg_peek_cmd.buflen, mode) == -1) { 1027 retval = EFAULT; 1028 break; 1029 } 1030 1031 if (ddi_copyout((caddr_t)&msg_peek_cmd, 1032 (caddr_t)arg, 1033 sizeof (glvc_xport_msg_peek_t), mode) == -1) 1034 retval = EFAULT; 1035 break; 1036 1037 default: 1038 retval = EFAULT; 1039 break; 1040 } 1041 } 1042 kmem_free(glvc_peek_msg.buf, softsp->mtu); 1043 break; 1044 1045 default: 1046 retval = ENOTSUP; 1047 break; 1048 } 1049 return (retval); 1050 } 1051 1052 /* 1053 * Map hypervisor error code to solaris. Only 1054 * H_EOK, H_EINVA, H_EWOULDBLOCK and H_EIO are meaningful 1055 * to this device. All other error codes are mapped to EIO. 1056 */ 1057 static int 1058 glvc_emap_h2s(uint64_t hv_errcode) 1059 { 1060 int s_errcode; 1061 1062 switch (hv_errcode) { 1063 case H_EOK: 1064 s_errcode = 0; 1065 break; 1066 1067 case H_EINVAL: 1068 s_errcode = EINVAL; 1069 break; 1070 1071 case H_EWOULDBLOCK: 1072 s_errcode = EWOULDBLOCK; 1073 break; 1074 1075 case H_EIO: 1076 s_errcode = EIO; 1077 break; 1078 1079 default: 1080 /* should not happen */ 1081 DPRINTF(("Unexpected device error code %ld received, " 1082 "mapped to EIO", hv_errcode)); 1083 s_errcode = EIO; 1084 break; 1085 } 1086 1087 return (s_errcode); 1088 } 1089