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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 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/param.h> 31 #include <sys/stat.h> 32 #include <fcntl.h> 33 #include <string.h> 34 #include <strings.h> 35 #include <errno.h> 36 #include <string.h> 37 #include <stdlib.h> 38 #include <stdio.h> 39 #include <unistd.h> 40 #include <sys/nvpair.h> 41 #include "libdevice.h" 42 43 static int _libdevice_debug = 0; 44 static const char *devctl_minorname = ":devctl"; 45 static const char *nullptr = "<null>"; 46 static const char *devctl_target_raw = "a,raw"; 47 48 typedef enum { DEVCTL_BUS, DEVCTL_DEVICE, DEVCTL_AP, DEVCTL_CLONE, 49 DEVCTL_PM_DEV, DEVCTL_PM_BUS } dc_type_t; 50 51 /* 52 * devctl_hdl structures are allocated by the devctl_XX_acquire() 53 * interfaces and passed to the remaining interfaces in this library. 54 */ 55 struct devctl_hdl { 56 char *opath; /* copy of the original path */ 57 dc_type_t hdltype; /* handle type */ 58 int fd; /* nexus device node */ 59 char *nodename; /* DEVCTL_DEVICE handles only */ 60 char *unitaddr; /* DEVCTL_DEVICE handles only */ 61 }; 62 #define DCP(x) ((struct devctl_hdl *)(x)) 63 64 static int dc_cmd(uint_t, uint_t, struct devctl_hdl *, nvlist_t *, void *); 65 static devctl_hdl_t dc_mkhndl(dc_type_t, char *, uint_t, devctl_hdl_t); 66 67 68 #pragma init(_libdevice_init) 69 void 70 _libdevice_init() 71 { 72 _libdevice_debug = getenv("LIBDEVICE_DEBUG") != NULL; 73 } 74 75 /* 76 * release a devctl_hdl structure 77 */ 78 void 79 devctl_release(devctl_hdl_t hdl) 80 { 81 if (_libdevice_debug) 82 (void) printf("devctl_release: %p\n", (void *)hdl); 83 84 if (hdl == NULL) 85 return; 86 87 if (DCP(hdl)->fd != -1) 88 (void) close(DCP(hdl)->fd); 89 90 if (DCP(hdl)->opath != NULL) 91 free(DCP(hdl)->opath); 92 93 if (DCP(hdl)->nodename != NULL) 94 free(DCP(hdl)->nodename); 95 96 if (DCP(hdl)->unitaddr != NULL) 97 free(DCP(hdl)->unitaddr); 98 99 free(hdl); 100 } 101 102 /* 103 * construct a handle suitable for devctl_bus_*() operations 104 */ 105 devctl_hdl_t 106 devctl_bus_acquire(char *devfs_path, uint_t flags) 107 { 108 uint_t oflags; 109 110 if (_libdevice_debug) 111 (void) printf("devctl_bus_acquire: %s (%d)\n", 112 ((devfs_path != NULL) ? devfs_path : nullptr), flags); 113 114 if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) { 115 errno = EINVAL; 116 return (NULL); 117 } 118 119 oflags = ((flags & DC_EXCL) != 0) ? O_EXCL|O_RDWR : O_RDWR; 120 return (dc_mkhndl(DEVCTL_BUS, devfs_path, oflags, NULL)); 121 } 122 123 124 /* 125 * construct a handle suitable for devctl_bus_*() and 126 * devctl_device_*() operations. 127 */ 128 devctl_hdl_t 129 devctl_device_acquire(char *devfs_path, uint_t flags) 130 { 131 uint_t oflags; 132 133 if (_libdevice_debug) 134 (void) printf("devctl_device_acquire: %s (%d)\n", 135 ((devfs_path != NULL) ? devfs_path : nullptr), flags); 136 137 if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) { 138 errno = EINVAL; 139 return (NULL); 140 } 141 142 oflags = ((flags & DC_EXCL) != 0) ? O_EXCL|O_RDWR : O_RDWR; 143 return (dc_mkhndl(DEVCTL_DEVICE, devfs_path, oflags, NULL)); 144 } 145 146 147 /* 148 * given a devfs (/devices) pathname to an attachment point device, 149 * access the device and return a handle to be passed to the 150 * devctl_ap_XXX() functions. 151 */ 152 devctl_hdl_t 153 devctl_ap_acquire(char *devfs_path, uint_t flags) 154 { 155 uint_t oflags; 156 157 if (_libdevice_debug) 158 (void) printf("devctl_ap_acquire: %s (%d)\n", 159 ((devfs_path != NULL) ? devfs_path : nullptr), flags); 160 161 if ((devfs_path == NULL) || 162 ((flags != 0) && ((flags & DC_EXCL) != 0) && 163 ((flags & DC_RDONLY) != 0))) { 164 errno = EINVAL; 165 return (NULL); 166 } 167 168 oflags = ((flags & DC_EXCL) != 0) ? O_EXCL : 0; 169 oflags |= ((flags & DC_RDONLY) != 0) ? O_RDONLY : O_RDWR; 170 171 return (dc_mkhndl(DEVCTL_AP, devfs_path, oflags, NULL)); 172 } 173 174 175 /* 176 * given a devfs (/devices) pathname access the device and return 177 * a handle to be passed to the devctl_pm_XXX() functions. 178 * The minor name ":devctl" is appended. 179 */ 180 devctl_hdl_t 181 devctl_pm_bus_acquire(char *devfs_path, uint_t flags) 182 { 183 uint_t oflags; 184 185 if (_libdevice_debug) 186 (void) printf("devctl_pm_bus_acquire: %s (%d)\n", 187 ((devfs_path != NULL) ? devfs_path : nullptr), flags); 188 189 if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) { 190 errno = EINVAL; 191 return (NULL); 192 } 193 194 oflags = ((flags & DC_EXCL) != 0) ? (O_EXCL | O_RDWR) : O_RDWR; 195 return (dc_mkhndl(DEVCTL_PM_BUS, devfs_path, oflags, NULL)); 196 } 197 198 199 /* 200 * given a devfs (/devices) pathname access the device and return 201 * a handle to be passed to the devctl_pm_XXX() functions. 202 * The minor name is derived from the device name. 203 */ 204 devctl_hdl_t 205 devctl_pm_dev_acquire(char *devfs_path, uint_t flags) 206 { 207 uint_t oflags; 208 209 if (_libdevice_debug) 210 (void) printf("devctl_pm_dev_acquire: %s (%d)\n", 211 ((devfs_path != NULL) ? devfs_path : nullptr), flags); 212 213 if ((devfs_path == NULL) || ((flags != 0) && (flags != DC_EXCL))) { 214 errno = EINVAL; 215 return (NULL); 216 } 217 218 oflags = ((flags & DC_EXCL) != 0) ? (O_EXCL | O_RDWR) : O_RDWR; 219 return (dc_mkhndl(DEVCTL_PM_DEV, devfs_path, oflags, NULL)); 220 } 221 222 223 /* 224 * allocate and initalize the devctl_hdl structure for the 225 * particular handle type. 226 */ 227 static devctl_hdl_t 228 dc_mkhndl(dc_type_t type, char *path, uint_t oflags, devctl_hdl_t pc) 229 { 230 struct devctl_hdl *dcp; 231 struct stat sb; 232 char iocpath[MAXPATHLEN]; 233 char *nodename, *unitsep, *minorsep, *chop; 234 char *minorname; 235 size_t strlcpy_size; 236 char *iocpath_dup; 237 char *tok; 238 239 if ((path == NULL) || (strlen(path) > MAXPATHLEN - 1)) { 240 errno = EINVAL; 241 return (NULL); 242 } 243 244 /* 245 * allocate handle and make a copy of the original path 246 */ 247 if ((dcp = calloc(1, sizeof (*dcp))) == NULL) { 248 errno = ENOMEM; 249 return (NULL); 250 } 251 if ((dcp->opath = strdup(path)) == NULL) { 252 devctl_release((devctl_hdl_t)dcp); 253 errno = ENOMEM; 254 return (NULL); 255 } 256 257 (void) strcpy(iocpath, path); 258 dcp->hdltype = type; 259 dcp->fd = -1; 260 261 /* 262 * break apart the pathname according to the type handle 263 */ 264 switch (type) { 265 case DEVCTL_PM_BUS: 266 /* 267 * chop off any minor name and concatenate the 268 * ":devctl" minor node name string. 269 */ 270 if ((chop = strrchr(iocpath, ':')) != NULL) 271 *chop = '\0'; 272 273 if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >= 274 MAXPATHLEN) { 275 devctl_release((devctl_hdl_t)dcp); 276 errno = EINVAL; 277 return (NULL); 278 } else if (_libdevice_debug) { 279 (void) printf("DEVCTL_PM_BUS: iocpath %s\n", iocpath); 280 } 281 break; 282 283 case DEVCTL_PM_DEV: 284 /* 285 * Chop up the last device component in the pathname. 286 * Concatenate either the device name itself, or the 287 * "a,raw" string, as the minor node name, to the iocpath. 288 */ 289 if ((iocpath_dup = strdup(iocpath)) == NULL) { 290 devctl_release((devctl_hdl_t)dcp); 291 errno = ENOMEM; 292 return (NULL); 293 } 294 if ((chop = strrchr(iocpath_dup, '/')) == NULL) { 295 devctl_release((devctl_hdl_t)dcp); 296 errno = EINVAL; 297 return (NULL); 298 } 299 *chop = '\0'; 300 nodename = chop + 1; 301 302 /* 303 * remove the "@0,0" string 304 */ 305 tok = strtok(nodename, "@"); 306 if ((minorname = malloc(strlen(tok) +1)) == NULL) { 307 if (_libdevice_debug) 308 (void) printf("DEVCTL_PM_DEV: failed malloc for" 309 " minorname\n"); 310 devctl_release((devctl_hdl_t)dcp); 311 errno = ENOMEM; 312 return (NULL); 313 } 314 (void) strcpy(minorname, tok); 315 if (_libdevice_debug) { 316 (void) printf("DEVCTL_PM_DEV: minorname %s\n", 317 minorname); 318 } 319 320 /* 321 * construct the name of the ioctl device 322 * by concatenating either ":a,raw" or ":"minorname 323 */ 324 (void) strlcat(iocpath, ":", MAXPATHLEN); 325 if (strcmp(minorname, "disk_chan") == 0 || 326 strcmp(minorname, "disk_wwn") == 0 || 327 strcmp(minorname, "disk_cdrom") == 0) { 328 strlcpy_size = strlcat(iocpath, devctl_target_raw, 329 MAXPATHLEN); 330 } else { 331 strlcpy_size = strlcat(iocpath, minorname, MAXPATHLEN); 332 } 333 if (strlcpy_size >= MAXPATHLEN) { 334 devctl_release((devctl_hdl_t)dcp); 335 errno = EINVAL; 336 return (NULL); 337 } else if (_libdevice_debug) { 338 (void) printf("DEVCTL_PM_DEV: iocpath %s\n", 339 iocpath); 340 } 341 break; 342 343 case DEVCTL_AP: 344 /* 345 * take the pathname as provided. 346 */ 347 break; 348 349 case DEVCTL_BUS: 350 /* 351 * chop off any minor name and concatenate the 352 * ":devctl" minor node name string. 353 */ 354 if ((chop = strrchr(iocpath, ':')) != NULL) 355 *chop = '\0'; 356 357 if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >= 358 MAXPATHLEN) { 359 devctl_release((devctl_hdl_t)dcp); 360 errno = EINVAL; 361 return (NULL); 362 } 363 break; 364 365 case DEVCTL_CLONE: 366 /* 367 * create a device handle for a new device created 368 * from a call to devctl_bus_dev_create() 369 */ 370 dcp->hdltype = DEVCTL_DEVICE; 371 372 /* FALLTHRU */ 373 374 case DEVCTL_DEVICE: 375 376 /* 377 * Chop up the last device component in the pathname. 378 * The componets are passed as nodename and unitaddr 379 * in the IOCTL data for DEVCTL ops on devices. 380 */ 381 if ((chop = strrchr(iocpath, '/')) == NULL) { 382 devctl_release((devctl_hdl_t)dcp); 383 errno = EINVAL; 384 return (NULL); 385 } 386 *chop = '\0'; 387 388 nodename = chop + 1; 389 unitsep = strchr(nodename, '@'); 390 minorsep = strchr(nodename, ':'); 391 392 if (unitsep == NULL) { 393 devctl_release((devctl_hdl_t)dcp); 394 errno = EINVAL; 395 return (NULL); 396 } 397 398 /* 399 * copy the nodename and unit address 400 */ 401 if (((dcp->nodename = malloc(MAXNAMELEN)) == NULL) || 402 ((dcp->unitaddr = malloc(MAXNAMELEN)) == NULL)) { 403 devctl_release((devctl_hdl_t)dcp); 404 errno = ENOMEM; 405 return (NULL); 406 } 407 *unitsep = '\0'; 408 if (minorsep != NULL) 409 *minorsep = '\0'; 410 (void) snprintf(dcp->nodename, MAXNAMELEN, "%s", nodename); 411 (void) snprintf(dcp->unitaddr, MAXNAMELEN, "%s", unitsep+1); 412 413 /* 414 * construct the name of the ioctl device 415 */ 416 if (strlcat(iocpath, devctl_minorname, MAXPATHLEN) >= 417 MAXPATHLEN) { 418 devctl_release((devctl_hdl_t)dcp); 419 errno = EINVAL; 420 return (NULL); 421 } 422 break; 423 424 default: 425 devctl_release((devctl_hdl_t)dcp); 426 errno = EINVAL; 427 return (NULL); 428 } 429 430 if (_libdevice_debug) 431 (void) printf("dc_mkhndl: iocpath %s ", iocpath); 432 433 /* 434 * verify the devctl or ap device exists and is a 435 * character device interface. 436 */ 437 if (stat(iocpath, &sb) == 0) { 438 if ((sb.st_mode & S_IFMT) != S_IFCHR) { 439 if (_libdevice_debug) 440 (void) printf(" - not character device\n"); 441 errno = ENODEV; 442 devctl_release((devctl_hdl_t)dcp); 443 return (NULL); 444 } 445 } else { 446 /* 447 * return failure with errno value set by stat 448 */ 449 if (_libdevice_debug) 450 (void) printf(" - stat failed\n"); 451 devctl_release((devctl_hdl_t)dcp); 452 return (NULL); 453 } 454 455 /* 456 * if this was a new device, dup the parents handle, otherwise 457 * just open the device. 458 */ 459 if (type == DEVCTL_CLONE) 460 dcp->fd = dup(DCP(pc)->fd); 461 else 462 dcp->fd = open(iocpath, oflags); 463 464 if (dcp->fd == -1) { 465 if (_libdevice_debug) 466 (void) printf(" - open/dup failed %d\n", errno); 467 /* 468 * leave errno as set by open/dup 469 */ 470 devctl_release((devctl_hdl_t)dcp); 471 return (NULL); 472 } 473 474 if (_libdevice_debug) 475 (void) printf(" - open success\n"); 476 477 return ((devctl_hdl_t)dcp); 478 } 479 480 /* 481 * Power up component 0, to level MAXPWR, via a pm_raise_power() call 482 */ 483 int 484 devctl_pm_raisepower(devctl_hdl_t dcp) 485 { 486 int rv; 487 488 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV && 489 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) { 490 errno = EINVAL; 491 return (-1); 492 } 493 494 rv = dc_cmd(DEVCTL_PM_RAISE_PWR, 0, DCP(dcp), NULL, NULL); 495 496 if (_libdevice_debug) 497 (void) printf("devctl_pm_raisepower: %d\n", rv); 498 499 return (rv); 500 } 501 502 /* 503 * Power up component 0, to level MAXPWR, via a power_has_changed() call 504 */ 505 int 506 devctl_pm_changepowerhigh(devctl_hdl_t dcp) 507 { 508 int rv; 509 510 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV && 511 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) { 512 errno = EINVAL; 513 return (-1); 514 } 515 516 rv = dc_cmd(DEVCTL_PM_CHANGE_PWR_HIGH, 0, DCP(dcp), NULL, NULL); 517 518 if (_libdevice_debug) 519 (void) printf("devctl_pm_changepowerhigh: %d\n", rv); 520 521 return (rv); 522 } 523 524 /* 525 * Power down component 0, to level 0, via a pm_change_power() call 526 */ 527 int 528 devctl_pm_changepowerlow(devctl_hdl_t dcp) 529 { 530 int rv; 531 532 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV && 533 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) { 534 errno = EINVAL; 535 return (-1); 536 } 537 538 rv = dc_cmd(DEVCTL_PM_CHANGE_PWR_LOW, 0, DCP(dcp), NULL, NULL); 539 540 if (_libdevice_debug) 541 (void) printf("devctl_pm_changepowerlow: %d\n", rv); 542 543 return (rv); 544 } 545 546 /* 547 * mark component 0 idle 548 */ 549 int 550 devctl_pm_idlecomponent(devctl_hdl_t dcp) 551 { 552 int rv; 553 554 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV && 555 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) { 556 errno = EINVAL; 557 return (-1); 558 } 559 560 rv = dc_cmd(DEVCTL_PM_IDLE_COMP, 0, DCP(dcp), NULL, NULL); 561 562 if (_libdevice_debug) 563 (void) printf("devctl_pm_idlecomponent: %d\n", rv); 564 565 return (rv); 566 } 567 568 /* 569 * mark component 0 busy 570 */ 571 int 572 devctl_pm_busycomponent(devctl_hdl_t dcp) 573 { 574 int rv; 575 576 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV && 577 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) { 578 errno = EINVAL; 579 return (-1); 580 } 581 582 rv = dc_cmd(DEVCTL_PM_BUSY_COMP, 0, DCP(dcp), NULL, NULL); 583 584 if (_libdevice_debug) 585 (void) printf("devctl_pm_busycomponent: %d\n", rv); 586 587 return (rv); 588 } 589 590 /* 591 * test pm busy state 592 */ 593 int 594 devctl_pm_testbusy(devctl_hdl_t dcp, uint_t *busystate) 595 { 596 int rv; 597 uint_t busy_state = 0; 598 599 if (busystate == NULL) { 600 errno = EINVAL; 601 return (-1); 602 } 603 604 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV && 605 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) { 606 errno = EINVAL; 607 return (-1); 608 } 609 610 rv = dc_cmd(DEVCTL_PM_BUSY_COMP_TEST, 0, DCP(dcp), NULL, 611 (void *)&busy_state); 612 613 if (rv == -1) 614 *busystate = 0; 615 else 616 *busystate = busy_state; 617 618 if (_libdevice_debug) 619 (void) printf("devctl_pm_bus_testbusy: rv %d busystate %x\n", 620 rv, *busystate); 621 622 return (rv); 623 } 624 625 /* 626 * set flag to fail DDI_SUSPEND 627 */ 628 int 629 devctl_pm_failsuspend(devctl_hdl_t dcp) 630 { 631 int rv; 632 633 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV && 634 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) { 635 errno = EINVAL; 636 return (-1); 637 } 638 639 rv = dc_cmd(DEVCTL_PM_FAIL_SUSPEND, 0, DCP(dcp), NULL, NULL); 640 641 if (_libdevice_debug) 642 (void) printf("devctl_pm_failsuspend: %d\n", rv); 643 return (rv); 644 } 645 646 int 647 devctl_pm_bus_teststrict(devctl_hdl_t dcp, uint_t *strict) 648 { 649 int rv; 650 uint_t strict_state; 651 652 if (strict == NULL) { 653 errno = EINVAL; 654 return (-1); 655 } 656 657 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_BUS)) { 658 errno = EINVAL; 659 return (-1); 660 } 661 662 rv = dc_cmd(DEVCTL_PM_BUS_STRICT_TEST, 0, DCP(dcp), NULL, 663 (void *)&strict_state); 664 665 if (rv == -1) 666 *strict = 0; 667 else 668 *strict = strict_state; 669 670 if (_libdevice_debug) 671 (void) printf("devctl_pm_bus_teststrict: rv %d strict %x\n", 672 rv, *strict); 673 674 return (rv); 675 } 676 677 /* 678 * issue prom_printf() call 679 */ 680 int 681 devctl_pm_device_promprintf(devctl_hdl_t dcp) 682 { 683 int rv; 684 685 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV && 686 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) { 687 errno = EINVAL; 688 return (-1); 689 } 690 691 rv = dc_cmd(DEVCTL_PM_PROM_PRINTF, 0, DCP(dcp), NULL, NULL); 692 693 if (_libdevice_debug) 694 (void) printf("devctl_pm_device_promprintf: %d\n", rv); 695 return (rv); 696 } 697 698 /* 699 * set flag to power up the device via 700 * pm_power_has_changed() calls vs. 701 * pm_raise_power(), during DDI_RESUME 702 */ 703 int 704 devctl_pm_device_changeonresume(devctl_hdl_t dcp) 705 { 706 int rv; 707 708 if (dcp == NULL || (DCP(dcp)->hdltype != DEVCTL_PM_DEV && 709 DCP(dcp)->hdltype != DEVCTL_PM_BUS)) { 710 errno = EINVAL; 711 return (-1); 712 } 713 714 rv = dc_cmd(DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME, 0, 715 DCP(dcp), NULL, NULL); 716 717 if (_libdevice_debug) 718 (void) printf("devctl_pm_device_changeonresume: %d\n", rv); 719 return (rv); 720 } 721 722 /* 723 * issue DEVCTL_PM_NO_LOWER_POWER to clear the LOWER_POWER_FLAG 724 * flag: pm_lower_power() will not be called on device detach 725 */ 726 int 727 devctl_pm_device_no_lower_power(devctl_hdl_t dcp) 728 { 729 int rv; 730 731 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_PM_DEV) { 732 errno = EINVAL; 733 return (-1); 734 } 735 736 rv = dc_cmd(DEVCTL_PM_NO_LOWER_POWER, 0, DCP(dcp), NULL, NULL); 737 738 if (_libdevice_debug) 739 (void) printf("devctl_pm_device_no_lower_power: %d\n", rv); 740 return (rv); 741 } 742 743 /* 744 * issue DEVCTL_PM_BUS_NO_INVOL ioctl to set the NO_INVOL_FLAG 745 * flag: parent driver will mark itself idle twice in 746 * DDI_CTLOPS_DETACH(POST) 747 */ 748 int 749 devctl_pm_bus_no_invol(devctl_hdl_t dcp) 750 { 751 int rv; 752 753 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_PM_BUS) { 754 errno = EINVAL; 755 return (-1); 756 } 757 758 rv = dc_cmd(DEVCTL_PM_BUS_NO_INVOL, 0, DCP(dcp), NULL, NULL); 759 760 if (_libdevice_debug) 761 (void) printf("devctl_pm_bus_no_invol: %d\n", rv); 762 return (rv); 763 } 764 765 /* 766 * Place the device ONLINE 767 */ 768 int 769 devctl_device_online(devctl_hdl_t dcp) 770 { 771 int rv; 772 773 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_DEVICE) { 774 errno = EINVAL; 775 return (-1); 776 } 777 778 rv = dc_cmd(DEVCTL_DEVICE_ONLINE, 0, DCP(dcp), NULL, NULL); 779 780 if (_libdevice_debug) 781 (void) printf("devctl_device_online: %d\n", rv); 782 783 return (rv); 784 } 785 786 /* 787 * take device OFFLINE 788 */ 789 int 790 devctl_device_offline(devctl_hdl_t dcp) 791 { 792 int rv; 793 794 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_DEVICE) { 795 errno = EINVAL; 796 return (-1); 797 } 798 799 rv = dc_cmd(DEVCTL_DEVICE_OFFLINE, 0, DCP(dcp), NULL, NULL); 800 801 if (_libdevice_debug) 802 (void) printf("devctl_device_offline: %d\n", rv); 803 804 return (rv); 805 } 806 807 /* 808 * take the device OFFLINE and remove its dev_info node 809 */ 810 int 811 devctl_device_remove(devctl_hdl_t dcp) 812 { 813 int rv; 814 815 if (dcp == NULL || DCP(dcp)->hdltype != DEVCTL_DEVICE) { 816 errno = EINVAL; 817 return (-1); 818 } 819 820 rv = dc_cmd(DEVCTL_DEVICE_REMOVE, 0, DCP(dcp), NULL, NULL); 821 822 if (_libdevice_debug) 823 (void) printf("devctl_device_remove: %d\n", rv); 824 825 return (rv); 826 } 827 828 829 /* 830 * QUIESCE the bus 831 */ 832 int 833 devctl_bus_quiesce(devctl_hdl_t dcp) 834 { 835 int rv; 836 837 rv = dc_cmd(DEVCTL_BUS_QUIESCE, 0, DCP(dcp), NULL, NULL); 838 839 if (_libdevice_debug) 840 (void) printf("devctl_bus_quiesce: %d\n", rv); 841 842 return (rv); 843 } 844 845 int 846 devctl_bus_unquiesce(devctl_hdl_t dcp) 847 { 848 int rv; 849 850 rv = dc_cmd(DEVCTL_BUS_UNQUIESCE, 0, DCP(dcp), NULL, NULL); 851 852 if (_libdevice_debug) 853 (void) printf("devctl_bus_unquiesce: %d\n", rv); 854 855 return (rv); 856 } 857 858 int 859 devctl_bus_reset(devctl_hdl_t dcp) 860 { 861 int rv; 862 863 rv = dc_cmd(DEVCTL_BUS_RESET, 0, DCP(dcp), NULL, NULL); 864 865 if (_libdevice_debug) 866 (void) printf("devctl_bus_reset: %d\n", rv); 867 868 return (rv); 869 } 870 871 int 872 devctl_bus_resetall(devctl_hdl_t dcp) 873 { 874 int rv; 875 876 rv = dc_cmd(DEVCTL_BUS_RESETALL, 0, DCP(dcp), NULL, NULL); 877 878 if (_libdevice_debug) 879 (void) printf("devctl_bus_resetall: %d\n", rv); 880 881 return (rv); 882 } 883 884 int 885 devctl_device_reset(devctl_hdl_t dcp) 886 { 887 int rv; 888 889 rv = dc_cmd(DEVCTL_DEVICE_RESET, 0, DCP(dcp), NULL, NULL); 890 891 if (_libdevice_debug) 892 (void) printf("devctl_device_reset: %d\n", rv); 893 894 return (rv); 895 } 896 897 int 898 devctl_device_getstate(devctl_hdl_t dcp, uint_t *devstate) 899 { 900 int rv; 901 uint_t device_state; 902 903 if (devstate == NULL) { 904 errno = EINVAL; 905 return (-1); 906 } 907 908 rv = dc_cmd(DEVCTL_DEVICE_GETSTATE, 0, DCP(dcp), NULL, 909 (void *)&device_state); 910 911 if (rv == -1) 912 *devstate = 0; 913 else 914 *devstate = device_state; 915 916 if (_libdevice_debug) 917 (void) printf("devctl_device_getstate: rv %d state %x\n", 918 rv, *devstate); 919 920 return (rv); 921 } 922 923 int 924 devctl_bus_getstate(devctl_hdl_t dcp, uint_t *devstate) 925 { 926 int rv; 927 uint_t device_state; 928 929 if (devstate == NULL) { 930 errno = EINVAL; 931 return (-1); 932 } 933 934 rv = dc_cmd(DEVCTL_BUS_GETSTATE, 0, DCP(dcp), NULL, 935 (void *)&device_state); 936 937 if (rv == -1) 938 *devstate = 0; 939 else 940 *devstate = device_state; 941 942 if (_libdevice_debug) 943 (void) printf("devctl_bus_getstate: rv %d, state %x\n", 944 rv, *devstate); 945 946 return (rv); 947 } 948 949 int 950 devctl_bus_configure(devctl_hdl_t dcp) 951 { 952 int rv; 953 954 rv = dc_cmd(DEVCTL_BUS_CONFIGURE, 0, DCP(dcp), NULL, NULL); 955 956 if (_libdevice_debug) 957 (void) printf("devctl_bus_configure: %d\n", rv); 958 959 return (rv); 960 } 961 962 int 963 devctl_bus_unconfigure(devctl_hdl_t dcp) 964 { 965 int rv; 966 967 rv = dc_cmd(DEVCTL_BUS_UNCONFIGURE, 0, DCP(dcp), NULL, NULL); 968 969 if (_libdevice_debug) 970 (void) printf("devctl_bus_unconfigure: %d\n", rv); 971 972 return (rv); 973 } 974 975 /* 976 * devctl_bus_dev_create() - create a new child device 977 * Attempt to construct and attach a new child device below a 978 * bus nexus (dcp). The device is defined using the devctl_ddef_*() 979 * routines to specify the set of bus-specific properties required 980 * to initalize and attach the device. 981 */ 982 int 983 devctl_bus_dev_create(devctl_hdl_t dcp, devctl_ddef_t ddef_hdl, 984 uint_t flags, devctl_hdl_t *new_dcp) 985 { 986 char devname[MAXNAMELEN]; 987 char devpath[MAXPATHLEN]; 988 int rv = 0; 989 990 if (dcp == NULL || ddef_hdl == NULL) { 991 errno = EINVAL; 992 return (-1); 993 } 994 995 (void) memset(devname, 0, sizeof (devname)); 996 rv = dc_cmd(DEVCTL_BUS_DEV_CREATE, flags, DCP(dcp), 997 (nvlist_t *)ddef_hdl, devname); 998 999 /* 1000 * construct a device handle for the new device 1001 */ 1002 if ((rv == 0) && (new_dcp != NULL)) { 1003 char *minorname, *lastslash; 1004 1005 (void) memset(devpath, 0, sizeof (devpath)); 1006 (void) strcat(devpath, DCP(dcp)->opath); 1007 1008 /* 1009 * Take the pathname of the parent device, chop off 1010 * any minor name info, and append the name@addr of 1011 * the new child device. 1012 * Call dc_mkhndl() with this constructed path and 1013 * the CLONE handle type to create a new handle which 1014 * references the new child device. 1015 */ 1016 lastslash = strrchr(devpath, '/'); 1017 if (*(lastslash + 1) == '\0') { 1018 *lastslash = '\0'; 1019 } else { 1020 if ((minorname = strchr(lastslash, ':')) != NULL) 1021 *minorname = '\0'; 1022 } 1023 (void) strcat(devpath, "/"); 1024 (void) strlcat(devpath, devname, MAXPATHLEN); 1025 *new_dcp = dc_mkhndl(DEVCTL_CLONE, devpath, 0, dcp); 1026 if (*new_dcp == NULL) 1027 rv = -1; 1028 } 1029 1030 return (rv); 1031 } 1032 1033 int 1034 devctl_ap_connect(devctl_hdl_t dcp, nvlist_t *ap_data) 1035 { 1036 int rv; 1037 1038 rv = dc_cmd(DEVCTL_AP_CONNECT, 0, DCP(dcp), ap_data, NULL); 1039 1040 if (_libdevice_debug) 1041 (void) printf("devctl_ap_connect: %d\n", rv); 1042 1043 return (rv); 1044 } 1045 1046 int 1047 devctl_ap_disconnect(devctl_hdl_t dcp, nvlist_t *ap_data) 1048 { 1049 int rv; 1050 1051 rv = dc_cmd(DEVCTL_AP_DISCONNECT, 0, DCP(dcp), ap_data, NULL); 1052 1053 if (_libdevice_debug) 1054 (void) printf("devctl_ap_disconnect: %d\n", rv); 1055 1056 return (rv); 1057 } 1058 1059 int 1060 devctl_ap_insert(devctl_hdl_t dcp, nvlist_t *ap_data) 1061 { 1062 int rv; 1063 1064 rv = dc_cmd(DEVCTL_AP_INSERT, 0, DCP(dcp), ap_data, NULL); 1065 1066 if (_libdevice_debug) 1067 (void) printf("devctl_ap_insert: %d\n", rv); 1068 1069 return (rv); 1070 } 1071 1072 int 1073 devctl_ap_remove(devctl_hdl_t dcp, nvlist_t *ap_data) 1074 { 1075 int rv; 1076 1077 rv = dc_cmd(DEVCTL_AP_REMOVE, 0, DCP(dcp), ap_data, NULL); 1078 1079 if (_libdevice_debug) 1080 (void) printf("devctl_ap_remove: %d\n", rv); 1081 1082 return (rv); 1083 } 1084 1085 int 1086 devctl_ap_configure(devctl_hdl_t dcp, nvlist_t *ap_data) 1087 { 1088 int rv; 1089 1090 rv = dc_cmd(DEVCTL_AP_CONFIGURE, 0, DCP(dcp), ap_data, NULL); 1091 1092 if (_libdevice_debug) 1093 (void) printf("devctl_ap_configure: %d\n", rv); 1094 1095 return (rv); 1096 } 1097 1098 int 1099 devctl_ap_unconfigure(devctl_hdl_t dcp, nvlist_t *ap_data) 1100 { 1101 int rv; 1102 1103 rv = dc_cmd(DEVCTL_AP_UNCONFIGURE, 0, DCP(dcp), ap_data, NULL); 1104 1105 if (_libdevice_debug) 1106 (void) printf("devctl_ap_unconfigure: %d\n", rv); 1107 1108 return (rv); 1109 } 1110 1111 int 1112 devctl_ap_getstate(devctl_hdl_t dcp, nvlist_t *ap_data, 1113 devctl_ap_state_t *apstate) 1114 { 1115 int rv; 1116 devctl_ap_state_t ap_state; 1117 1118 rv = dc_cmd(DEVCTL_AP_GETSTATE, 0, DCP(dcp), ap_data, 1119 (void *)&ap_state); 1120 1121 if (rv == -1) 1122 (void) memset(apstate, 0, sizeof (struct devctl_ap_state)); 1123 else 1124 *apstate = ap_state; 1125 1126 if (_libdevice_debug) 1127 (void) printf("devctl_ap_getstate: %d\n", rv); 1128 1129 return (rv); 1130 } 1131 1132 /* 1133 * Allocate a device 'definition' handle, in reality a list of 1134 * nvpair data. 1135 */ 1136 /* ARGSUSED */ 1137 devctl_ddef_t 1138 devctl_ddef_alloc(char *nodename, int flags) 1139 { 1140 1141 nvlist_t *nvlp; 1142 1143 if ((nodename == NULL) || *nodename == '\0') { 1144 errno = EINVAL; 1145 return (NULL); 1146 } 1147 1148 /* 1149 * allocate nvlist structure which is returned as an 1150 * opaque handle to the caller. If this fails, return 1151 * NULL with errno left set to the value 1152 */ 1153 if (nvlist_alloc(&nvlp, NV_UNIQUE_NAME_TYPE, 0) != 0) { 1154 errno = ENOMEM; 1155 return (NULL); 1156 } 1157 1158 /* 1159 * add the nodename of the new device to the list 1160 */ 1161 if (nvlist_add_string(nvlp, DC_DEVI_NODENAME, nodename) != 0) { 1162 nvlist_free(nvlp); 1163 errno = ENOMEM; 1164 return (NULL); 1165 } 1166 1167 if (_libdevice_debug) 1168 (void) printf("devctl_ddef_alloc: node %s nvp %p\n", nodename, 1169 (void *)nvlp); 1170 1171 return ((devctl_ddef_t)nvlp); 1172 } 1173 1174 /* 1175 * free the definition handle 1176 */ 1177 void 1178 devctl_ddef_free(devctl_ddef_t ddef_hdl) 1179 { 1180 if (_libdevice_debug) 1181 (void) printf("devctl_ddef_free: nvp %p\n", (void *)ddef_hdl); 1182 1183 if (ddef_hdl != NULL) { 1184 nvlist_free((nvlist_t *)ddef_hdl); 1185 } 1186 } 1187 1188 /* 1189 * define an integer property 1190 */ 1191 int 1192 devctl_ddef_int(devctl_ddef_t ddef_hdl, char *name, int32_t value) 1193 { 1194 1195 int rv; 1196 1197 if (ddef_hdl == NULL || name == NULL || *name == '\0') { 1198 errno = EINVAL; 1199 return (-1); 1200 } 1201 1202 rv = nvlist_add_int32((nvlist_t *)ddef_hdl, name, value); 1203 1204 if (_libdevice_debug) 1205 (void) printf("devctl_ddef_int: rv %d nvp %p name %s val %d\n", 1206 rv, (void *)ddef_hdl, name, value); 1207 1208 return (rv); 1209 } 1210 1211 /* 1212 * define an integer array property 1213 */ 1214 int 1215 devctl_ddef_int_array(devctl_ddef_t ddef_hdl, char *name, int nelements, 1216 int32_t *value) 1217 { 1218 int rv, i; 1219 1220 if (ddef_hdl == NULL || name == NULL || *name == '\0') { 1221 errno = EINVAL; 1222 return (-1); 1223 } 1224 1225 rv = nvlist_add_int32_array((nvlist_t *)ddef_hdl, name, value, 1226 nelements); 1227 1228 if (_libdevice_debug) { 1229 (void) printf("devctl_ddef_int_array: rv %d nvp %p name %s: ", 1230 rv, (void *)ddef_hdl, name); 1231 for (i = 0; i < nelements; i++) 1232 (void) printf("0x%x ", value[i]); 1233 (void) printf("\n"); 1234 } 1235 1236 return (rv); 1237 } 1238 1239 /* 1240 * define a string property 1241 */ 1242 int 1243 devctl_ddef_string(devctl_ddef_t ddef_hdl, char *name, char *value) 1244 { 1245 int rv; 1246 1247 if (ddef_hdl == NULL || name == NULL || *name == '\0') { 1248 errno = EINVAL; 1249 return (-1); 1250 } 1251 1252 rv = nvlist_add_string((nvlist_t *)ddef_hdl, name, value); 1253 1254 if (_libdevice_debug) 1255 (void) printf("devctl_ddef_string: rv %d nvp %p %s=\"%s\"\n", 1256 rv, (void *)ddef_hdl, name, value); 1257 1258 return (rv); 1259 } 1260 1261 /* 1262 * define a string array property 1263 */ 1264 int 1265 devctl_ddef_string_array(devctl_ddef_t ddef_hdl, char *name, int nelements, 1266 char **value) 1267 { 1268 int rv, i; 1269 1270 if (ddef_hdl == NULL || name == NULL || *name == '\0') { 1271 errno = EINVAL; 1272 return (-1); 1273 } 1274 1275 rv = nvlist_add_string_array((nvlist_t *)ddef_hdl, name, 1276 value, nelements); 1277 1278 if (_libdevice_debug) { 1279 (void) printf("devctl_ddef_string_array: rv %d nvp %p " 1280 "name %s:\n", rv, (void *)ddef_hdl, name); 1281 for (i = 0; i < nelements; i++) 1282 (void) printf("\t%d: \"%s\"\n", i, value[i]); 1283 } 1284 return (rv); 1285 } 1286 1287 /* 1288 * define a byte array property 1289 */ 1290 int 1291 devctl_ddef_byte_array(devctl_ddef_t ddef_hdl, char *name, int nelements, 1292 uchar_t *value) 1293 { 1294 int rv; 1295 1296 if (ddef_hdl == NULL || name == NULL || *name == '\0') { 1297 errno = EINVAL; 1298 return (-1); 1299 } 1300 1301 rv = nvlist_add_byte_array((nvlist_t *)ddef_hdl, name, value, 1302 nelements); 1303 1304 return (rv); 1305 } 1306 1307 /* 1308 * return the pathname which was used to acquire the handle 1309 */ 1310 char * 1311 devctl_get_pathname(devctl_hdl_t dcp, char *pathbuf, size_t bufsz) 1312 { 1313 if (dcp == NULL || pathbuf == NULL || bufsz == 0) { 1314 errno = EINVAL; 1315 return (NULL); 1316 } 1317 1318 (void) snprintf(pathbuf, bufsz, "%s", DCP(dcp)->opath); 1319 return (pathbuf); 1320 } 1321 1322 1323 /* 1324 * execute the IOCTL request 1325 */ 1326 static int 1327 dc_cmd(uint_t cmd, uint_t flags, struct devctl_hdl *dcp, nvlist_t *ulp, 1328 void *retinfo) 1329 { 1330 struct devctl_iocdata iocdata; 1331 int rv = 0; 1332 1333 if (_libdevice_debug) 1334 (void) printf("dc_cmd: %x dcp %p ulp %p flags %x rv %p\n", cmd, 1335 (void *)dcp, (void *)ulp, flags, retinfo); 1336 1337 if ((dcp == NULL) || (DCP(dcp)->fd == -1)) { 1338 errno = EINVAL; 1339 return (-1); 1340 } 1341 1342 (void) memset(&iocdata, 0, sizeof (struct devctl_iocdata)); 1343 1344 /* 1345 * if there was any user supplied data in the form of a nvlist, 1346 * pack the list prior to copyin. 1347 */ 1348 if (ulp != NULL) { 1349 if (rv = nvlist_pack(ulp, (char **)&iocdata.nvl_user, 1350 &iocdata.nvl_usersz, NV_ENCODE_NATIVE, 0)) { 1351 /* 1352 * exit with errno set by nvlist_pack() 1353 */ 1354 goto exit; 1355 } 1356 } else { 1357 iocdata.nvl_user = NULL; 1358 iocdata.nvl_usersz = 0; 1359 } 1360 1361 /* 1362 * finish initalizing the request and execute the IOCTL 1363 */ 1364 iocdata.cmd = cmd; 1365 iocdata.flags = flags; 1366 iocdata.c_nodename = dcp->nodename; 1367 iocdata.c_unitaddr = dcp->unitaddr; 1368 iocdata.cpyout_buf = retinfo; 1369 rv = ioctl(dcp->fd, cmd, &iocdata); 1370 if (rv < 0 && _libdevice_debug) { 1371 (void) printf("dc_cmd: exited with rv %d, errno(%d):%s\n", 1372 rv, errno, strerror(errno)); 1373 } 1374 1375 exit: 1376 if (iocdata.nvl_user != NULL) 1377 free(iocdata.nvl_user); 1378 1379 return (rv); 1380 } 1381