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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/stat.h> 30 #include <errno.h> 31 #include <string.h> 32 #include <dirent.h> 33 #include "cfga_sata.h" 34 35 /* 36 * This file contains the entry points to the plug-in as defined in the 37 * config_admin(3X) man page. 38 */ 39 40 /* 41 * Set the version number for the cfgadm library's use. 42 */ 43 int cfga_version = CFGA_HSL_V2; 44 45 enum { 46 HELP_HEADER = 1, 47 HELP_CONFIG, 48 HELP_RESET_PORT, 49 HELP_RESET_DEVICE, 50 HELP_RESET_ALL, 51 HELP_PORT_DEACTIVATE, 52 HELP_PORT_ACTIVATE, 53 HELP_PORT_SELF_TEST, 54 HELP_CNTRL_SELF_TEST, 55 HELP_UNKNOWN 56 }; 57 58 /* SATA specific help messages */ 59 static char *sata_help[] = { 60 NULL, 61 "SATA specific commands:\n", 62 " cfgadm -c [configure|unconfigure|disconnect|connect] ap_id " 63 "[ap_id...]\n", 64 " cfgadm -x sata_reset_port ap_id [ap_id...]\n", 65 " cfgadm -x sata_reset_device ap_id [ap_id...]\n", 66 " cfgadm -x sata_reset_all ap_id\n", 67 " cfgadm -x sata_port_deactivate ap_id [ap_id...]\n", 68 " cfgadm -x sata_port_activate ap_id [ap_id...]\n", 69 " cfgadm -x sata_port_self_test ap_id [ap_id...]\n", 70 " cfgadm -t ap_id\n", 71 "\tunknown command or option:\n", 72 NULL 73 }; /* End help messages */ 74 75 76 /* 77 * Messages. 78 */ 79 static msgcvt_t sata_msgs[] = { 80 /* CFGA_SATA_OK */ 81 { CVT, CFGA_OK, "" }, 82 83 /* CFGA_SATA_NACK */ 84 { CVT, CFGA_NACK, "" }, 85 86 /* CFGA_SATA_DEVICE_UNCONFIGURED */ 87 { CVT, CFGA_OK, "Device unconfigured prior to disconnect" }, 88 89 /* CFGA_SATA_UNKNOWN / CFGA_LIB_ERROR -> "Library error" */ 90 { CVT, CFGA_LIB_ERROR, "Unknown message; internal error" }, 91 92 /* CFGA_SATA_INTERNAL_ERROR / CFGA_LIB_ERROR -> "Library error" */ 93 { CVT, CFGA_LIB_ERROR, "Internal error" }, 94 95 /* CFGA_SATA_DATA_ERROR / CFGA_DATA_ERROR -> "Data error" */ 96 { CVT, CFGA_DATA_ERROR, "cfgadm data error" }, 97 98 /* CFGA_SATA_OPTIONS / CFGA_ERROR -> "Hardware specific failure" */ 99 { CVT, CFGA_ERROR, "Hardware specific option not supported" }, 100 101 /* CFGA_SATA_HWOPNOTSUPP / CFGA_ERROR -> "Hardware specific failure" */ 102 { CVT, CFGA_ERROR, "Hardware specific operation not supported" }, 103 104 /* 105 * CFGA_SATA_DYNAMIC_AP / 106 * CFGA_LIB_ERROR -> "Configuration operation invalid" 107 */ 108 { CVT, CFGA_INVAL, "Cannot identify attached device" }, 109 110 /* CFGA_SATA_AP / CFGA_APID_NOEXIST -> "Attachment point not found" */ 111 { CVT, CFGA_APID_NOEXIST, "" }, 112 113 /* CFGA_SATA_PORT / CFGA_LIB_ERROR -> "Library error" */ 114 { CVT, CFGA_LIB_ERROR, "Cannot determine sata port number for " }, 115 116 /* CFGA_SATA_DEVCTL / CFGA_LIB_ERROR -> "Library error" */ 117 { CVT, CFGA_LIB_ERROR, "Internal error: " 118 "Cannot allocate devctl handle " }, 119 120 /* 121 * CFGA_SATA_DEV_CONFIGURE / 122 * CFGA_ERROR -> "Hardware specific failure" 123 */ 124 { CVT, CFGA_ERROR, "Failed to config device at " }, 125 126 /* 127 * CFGA_SATA_DEV_UNCONFIGURE / 128 * CFGA_ERROR -> "Hardware specific failure" 129 */ 130 { CVT, CFGA_ERROR, "Failed to unconfig device at " }, 131 132 /* 133 * CFGA_SATA_DISCONNECTED 134 * CFGA_INVAL -> "Configuration operation invalid" 135 */ 136 { CVT, CFGA_INVAL, "Port already disconnected " }, 137 138 /* 139 * CFGA_SATA_NOT_CONNECTED 140 * CFGA_INVAL -> "Configuration operation invalid" 141 */ 142 { CVT, CFGA_INVAL, "No device connected to " }, 143 144 /* 145 * CFGA_SATA_NOT_CONFIGURED / 146 * CFGA_INVAL -> "Configuration operation invalid" 147 */ 148 { CVT, CFGA_INVAL, "No device configured at " }, 149 150 /* 151 * CFGA_SATA_ALREADY_CONNECTED / 152 * CFGA_INVAL -> "Configuration operation invalid" 153 */ 154 { CVT, CFGA_INVAL, "Device already connected to " }, 155 156 /* 157 * CFGA_SATA_ALREADY_CONFIGURED / 158 * CFGA_INVAL -> "Configuration operation invalid" 159 */ 160 { CVT, CFGA_INVAL, "Device already configured at " }, 161 162 /* 163 * CFGA_SATA_INVALID_DEVNAME / 164 * CFGA_INVAL -> "Configuration operation invalid" 165 */ 166 { CVT, CFGA_INVAL, "Cannot specify device name" }, 167 168 /* CFGA_SATA_OPEN / CFGA_LIB_ERROR -> "Library error" */ 169 { CVT, CFGA_LIB_ERROR, "Cannot open " }, 170 171 /* CFGA_SATA_IOCTL / CFGA_ERROR -> "Hardware specific failure" */ 172 { CVT, CFGA_ERROR, "Driver ioctl failed " }, 173 174 /* 175 * CFGA_SATA_BUSY / 176 * CFGA_SYSTEM_BUSY -> "System is busy, try again" 177 */ 178 { CVT, CFGA_SYSTEM_BUSY, "" }, 179 180 /* CFGA_SATA_ALLOC_FAIL / CFGA_LIB_ERROR -> "Library error" */ 181 { CVT, CFGA_LIB_ERROR, "Memory allocation failure" }, 182 183 /* 184 * CFGA_SATA_OPNOTSUPP / 185 * CFGA_OPNOTSUPP -> "Configuration operation not supported" 186 */ 187 { CVT, CFGA_OPNOTSUPP, "Operation not supported" }, 188 189 /* CFGA_SATA_DEVLINK / CFGA_LIB_ERROR -> "Library error" */ 190 { CVT, CFGA_LIB_ERROR, "Could not find /dev/cfg link for " }, 191 192 /* CFGA_SATA_STATE / CFGA_LIB_ERROR -> "Library error" */ 193 { CVT, CFGA_LIB_ERROR, "Internal error: Unrecognized ap state" }, 194 195 /* CFGA_SATA_PRIV / CFGA_PRIV -> "Insufficient privileges" */ 196 { CVT, CFGA_PRIV, "" }, 197 198 /* CFGA_SATA_NVLIST / CFGA_ERROR -> "Hardware specific failure" */ 199 { CVT, CFGA_ERROR, "Internal error (nvlist)" }, 200 201 /* CFGA_SATA_ZEROLEN / CFGA_ERROR -> "Hardware specific failure" */ 202 { CVT, CFGA_ERROR, "Internal error (zerolength string)" }, 203 204 /* CFGA_SATA_RCM_HANDLE / CFGA_ERROR -> "Hardware specific failure" */ 205 { CVT, CFGA_ERROR, "cannot get RCM handle"}, 206 207 /* 208 * CFGA_SATA_RCM_ONLINE / 209 * CFGA_SYSTEM_BUSY -> "System is busy, try again" 210 */ 211 { CVT, CFGA_SYSTEM_BUSY, "failed to online: "}, 212 213 /* 214 * CFGA_SATA_RCM_OFFLINE / 215 * CFGA_SYSTEM_BUSY -> "System is busy, try again" 216 */ 217 { CVT, CFGA_SYSTEM_BUSY, "failed to offline: "}, 218 219 /* CFGA_SATA_RCM_INFO / CFGA_ERROR -> "Hardware specific failure" */ 220 { CVT, CFGA_ERROR, "failed to query: "} 221 222 }; /* End error messages */ 223 224 static cfga_sata_ret_t 225 verify_params(const char *ap_id, const char *options, char **errstring); 226 227 228 static cfga_sata_ret_t 229 setup_for_devctl_cmd(const char *ap_id, devctl_hdl_t *devctl_hdl, 230 nvlist_t **user_nvlistp, uint_t oflag); 231 232 static cfga_sata_ret_t 233 port_state(devctl_hdl_t hdl, nvlist_t *list, 234 ap_rstate_t *rstate, ap_ostate_t *ostate); 235 236 static cfga_sata_ret_t 237 do_control_ioctl(const char *ap_id, sata_cfga_apctl_t subcommand, uint_t arg, 238 void **descrp, size_t *sizep); 239 240 static void 241 cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist); 242 243 static char * 244 sata_get_devicepath(const char *ap_id); 245 246 static int 247 sata_confirm(struct cfga_confirm *confp, char *msg); 248 249 static cfga_sata_ret_t 250 get_port_num(const char *ap_id, uint32_t *port); 251 252 /* Utilities */ 253 254 static cfga_sata_ret_t 255 physpath_to_devlink(const char *basedir, const char *node_path, 256 char **logpp, int *l_errnop) 257 { 258 char *linkpath; 259 char *buf; 260 char *real_path; 261 DIR *dp; 262 struct dirent *dep, *newdep; 263 int deplen; 264 boolean_t found = B_FALSE; 265 int err = 0; 266 struct stat sb; 267 char *p; 268 cfga_sata_ret_t rv = CFGA_SATA_INTERNAL_ERROR; 269 270 /* 271 * Using libdevinfo for this is overkill and kills performance 272 * when multiple consumers of libcfgadm are executing 273 * concurrently. 274 */ 275 if ((dp = opendir(basedir)) == NULL) { 276 *l_errnop = errno; 277 return (CFGA_SATA_INTERNAL_ERROR); 278 } 279 280 linkpath = malloc(PATH_MAX); 281 buf = malloc(PATH_MAX); 282 real_path = malloc(PATH_MAX); 283 284 deplen = pathconf(basedir, _PC_NAME_MAX); 285 deplen = (deplen <= 0 ? MAXNAMELEN : deplen) + 286 sizeof (struct dirent); 287 dep = (struct dirent *)malloc(deplen); 288 289 if (dep == NULL || linkpath == NULL || buf == NULL || 290 real_path == NULL) { 291 *l_errnop = ENOMEM; 292 rv = CFGA_SATA_ALLOC_FAIL; 293 goto pp_cleanup; 294 } 295 296 *logpp = NULL; 297 298 while (!found && (err = readdir_r(dp, dep, &newdep)) == 0 && 299 newdep != NULL) { 300 301 assert(newdep == dep); 302 303 if (strcmp(dep->d_name, ".") == 0 || 304 strcmp(dep->d_name, "..") == 0) 305 continue; 306 307 (void) snprintf(linkpath, MAXPATHLEN, 308 "%s/%s", basedir, dep->d_name); 309 310 if (lstat(linkpath, &sb) < 0) 311 continue; 312 313 if (S_ISDIR(sb.st_mode)) { 314 315 if ((rv = physpath_to_devlink(linkpath, node_path, 316 logpp, l_errnop)) != CFGA_SATA_OK) { 317 318 goto pp_cleanup; 319 } 320 321 if (*logpp != NULL) 322 found = B_TRUE; 323 324 } else if (S_ISLNK(sb.st_mode)) { 325 326 bzero(buf, PATH_MAX); 327 if (readlink(linkpath, buf, PATH_MAX) < 0) 328 continue; 329 330 331 /* 332 * realpath() is too darn slow, so fake 333 * it, by using what we know about /dev 334 * links: they are always of the form: 335 * <"../">+/devices/<path> 336 */ 337 p = buf; 338 while (strncmp(p, "../", 3) == 0) 339 p += 3; 340 341 if (p != buf) 342 p--; /* back up to get a slash */ 343 344 assert (*p == '/'); 345 346 if (strcmp(p, node_path) == 0) { 347 *logpp = strdup(linkpath); 348 if (*logpp == NULL) { 349 350 rv = CFGA_SATA_ALLOC_FAIL; 351 goto pp_cleanup; 352 } 353 354 found = B_TRUE; 355 } 356 } 357 } 358 359 free(linkpath); 360 free(buf); 361 free(real_path); 362 free(dep); 363 (void) closedir(dp); 364 365 if (err != 0) { 366 *l_errnop = err; 367 return (CFGA_SATA_INTERNAL_ERROR); 368 } 369 370 return (CFGA_SATA_OK); 371 372 pp_cleanup: 373 374 if (dp) 375 (void) closedir(dp); 376 if (dep) 377 free(dep); 378 if (linkpath) 379 free(linkpath); 380 if (buf) 381 free(buf); 382 if (real_path) 383 free(real_path); 384 if (*logpp) { 385 free(*logpp); 386 *logpp = NULL; 387 } 388 return (rv); 389 } 390 391 392 /* 393 * Given the index into a table (msgcvt_t) of messages, get the message 394 * string, converting it to the proper locale if necessary. 395 * NOTE: Indexes are defined in cfga_sata.h 396 */ 397 static const char * 398 get_msg(uint_t msg_index, msgcvt_t *msg_tbl, uint_t tbl_size) 399 { 400 if (msg_index >= tbl_size) { 401 msg_index = CFGA_SATA_UNKNOWN; 402 } 403 404 return ((msg_tbl[msg_index].intl) ? 405 dgettext(TEXT_DOMAIN, msg_tbl[msg_index].msgstr) : 406 msg_tbl[msg_index].msgstr); 407 } 408 409 /* 410 * Allocates and creates a message string (in *ret_str), 411 * by concatenating all the (char *) args together, in order. 412 * Last arg MUST be NULL. 413 */ 414 static void 415 set_msg(char **ret_str, ...) 416 { 417 char *str; 418 size_t total_len; 419 va_list valist; 420 421 va_start(valist, ret_str); 422 423 total_len = (*ret_str == NULL) ? 0 : strlen(*ret_str); 424 425 while ((str = va_arg(valist, char *)) != NULL) { 426 size_t len = strlen(str); 427 char *old_str = *ret_str; 428 429 *ret_str = (char *)realloc(*ret_str, total_len + len + 1); 430 if (*ret_str == NULL) { 431 /* We're screwed */ 432 free(old_str); 433 va_end(valist); 434 return; 435 } 436 437 (void) strcpy(*ret_str + total_len, str); 438 total_len += len; 439 } 440 441 va_end(valist); 442 } 443 444 /* 445 * Error message handling. 446 * For the rv passed in, looks up the corresponding error message string(s), 447 * internationalized if necessary, and concatenates it into a new 448 * memory buffer, and points *errstring to it. 449 * Note not all rvs will result in an error message return, as not all 450 * error conditions warrant a SATA-specific error message - for those 451 * conditions the cfgadm generic messages are sufficient. 452 * 453 * Some messages may display ap_id or errno, which is why they are passed 454 * in. 455 */ 456 457 cfga_err_t 458 sata_err_msg( 459 char **errstring, 460 cfga_sata_ret_t rv, 461 const char *ap_id, 462 int l_errno) 463 { 464 if (errstring == NULL) { 465 return (sata_msgs[rv].cfga_err); 466 } 467 468 /* 469 * Generate the appropriate SATA-specific error message(s) (if any). 470 */ 471 switch (rv) { 472 case CFGA_SATA_OK: 473 case CFGA_NACK: 474 /* Special case - do nothing. */ 475 break; 476 477 case CFGA_SATA_UNKNOWN: 478 case CFGA_SATA_DYNAMIC_AP: 479 case CFGA_SATA_INTERNAL_ERROR: 480 case CFGA_SATA_OPTIONS: 481 case CFGA_SATA_ALLOC_FAIL: 482 case CFGA_SATA_STATE: 483 case CFGA_SATA_PRIV: 484 case CFGA_SATA_OPNOTSUPP: 485 case CFGA_SATA_DATA_ERROR: 486 /* These messages require no additional strings passed. */ 487 set_msg(errstring, ERR_STR(rv), NULL); 488 break; 489 490 case CFGA_SATA_HWOPNOTSUPP: 491 /* hardware-specific help needed */ 492 set_msg(errstring, ERR_STR(rv), NULL); 493 set_msg(errstring, "\n", 494 dgettext(TEXT_DOMAIN, sata_help[HELP_HEADER]), NULL); 495 set_msg(errstring, sata_help[HELP_RESET_PORT], NULL); 496 set_msg(errstring, sata_help[HELP_RESET_DEVICE], NULL); 497 set_msg(errstring, sata_help[HELP_RESET_ALL], NULL); 498 set_msg(errstring, sata_help[HELP_PORT_ACTIVATE], NULL); 499 set_msg(errstring, sata_help[HELP_PORT_DEACTIVATE], NULL); 500 set_msg(errstring, sata_help[HELP_PORT_SELF_TEST], NULL); 501 set_msg(errstring, sata_help[HELP_CNTRL_SELF_TEST], NULL); 502 break; 503 504 case CFGA_SATA_AP: 505 case CFGA_SATA_PORT: 506 case CFGA_SATA_NOT_CONNECTED: 507 case CFGA_SATA_NOT_CONFIGURED: 508 case CFGA_SATA_ALREADY_CONNECTED: 509 case CFGA_SATA_ALREADY_CONFIGURED: 510 case CFGA_SATA_BUSY: 511 case CFGA_SATA_DEVLINK: 512 case CFGA_SATA_RCM_HANDLE: 513 case CFGA_SATA_RCM_ONLINE: 514 case CFGA_SATA_RCM_OFFLINE: 515 case CFGA_SATA_RCM_INFO: 516 case CFGA_SATA_DEV_CONFIGURE: 517 case CFGA_SATA_DEV_UNCONFIGURE: 518 case CFGA_SATA_DISCONNECTED: 519 /* These messages also print ap_id. */ 520 set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "", NULL); 521 break; 522 523 524 case CFGA_SATA_IOCTL: 525 case CFGA_SATA_NVLIST: 526 /* These messages also print errno. */ 527 { 528 char *errno_str = l_errno ? strerror(l_errno) : ""; 529 530 set_msg(errstring, ERR_STR(rv), errno_str, 531 l_errno ? "\n" : "", NULL); 532 break; 533 } 534 535 case CFGA_SATA_OPEN: 536 /* These messages also apid and errno. */ 537 { 538 char *errno_str = l_errno ? strerror(l_errno) : ""; 539 540 set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "\n", 541 errno_str, l_errno ? "\n" : "", NULL); 542 break; 543 } 544 545 default: 546 set_msg(errstring, ERR_STR(CFGA_SATA_INTERNAL_ERROR), NULL); 547 548 } /* end switch */ 549 550 551 /* 552 * Determine the proper error code to send back to the cfgadm library. 553 */ 554 return (sata_msgs[rv].cfga_err); 555 } 556 557 558 /* 559 * Entry points 560 */ 561 /* cfgadm entry point */ 562 /*ARGSUSED*/ 563 cfga_err_t 564 cfga_change_state( 565 cfga_cmd_t state_change_cmd, 566 const char *ap_id, 567 const char *options, 568 struct cfga_confirm *confp, 569 struct cfga_msg *msgp, 570 char **errstring, 571 cfga_flags_t flags) 572 { 573 int ret; 574 int len; 575 char *msg; 576 char *devpath; 577 nvlist_t *nvl = NULL; 578 ap_rstate_t rstate; 579 ap_ostate_t ostate; 580 devctl_hdl_t hdl = NULL; 581 cfga_sata_ret_t rv = CFGA_SATA_OK; 582 char *pdyn; 583 char *str_type; 584 size_t size; 585 boolean_t pmult = B_FALSE; 586 587 /* 588 * All sub-commands which can change state of device require 589 * root privileges. 590 */ 591 if (geteuid() != 0) { 592 rv = CFGA_SATA_PRIV; 593 goto bailout; 594 } 595 596 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) { 597 (void) cfga_help(msgp, options, flags); 598 goto bailout; 599 } 600 601 if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &nvl, 602 DC_RDONLY)) != CFGA_SATA_OK) { 603 goto bailout; 604 } 605 606 /* 607 * Checking device type. A port multiplier is not configurable - it is 608 * already configured as soon as it is connected. 609 */ 610 if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, NULL, 611 (void **)&str_type, &size)) != CFGA_SATA_OK) { 612 /* no such deivce */ 613 goto bailout; 614 } 615 if (strncmp(str_type, "sata-pmult", sizeof ("sata-pmult")) == 0) { 616 pmult = B_TRUE; 617 } 618 619 switch (state_change_cmd) { 620 case CFGA_CMD_CONFIGURE: 621 if (pmult == B_TRUE) { 622 rv = CFGA_SATA_HWOPNOTSUPP; 623 goto bailout; 624 } 625 626 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) != 627 CFGA_SATA_OK) 628 goto bailout; 629 630 if (ostate == AP_OSTATE_CONFIGURED) { 631 rv = CFGA_SATA_ALREADY_CONFIGURED; 632 goto bailout; 633 } 634 /* Disallow dynamic AP name component */ 635 if (GET_DYN(ap_id) != NULL) { 636 rv = CFGA_SATA_INVALID_DEVNAME; 637 goto bailout; 638 } 639 640 if (rstate == AP_RSTATE_EMPTY) { 641 rv = CFGA_SATA_NOT_CONNECTED; 642 goto bailout; 643 } 644 rv = CFGA_SATA_OK; 645 646 if (devctl_ap_configure(hdl, nvl) != 0) { 647 rv = CFGA_SATA_DEV_CONFIGURE; 648 goto bailout; 649 } 650 651 devpath = sata_get_devicepath(ap_id); 652 if (devpath == NULL) { 653 int i; 654 /* 655 * Try for some time as SATA hotplug thread 656 * takes a while to create the path then 657 * eventually give up. 658 */ 659 for (i = 0; i < 12 && (devpath == NULL); i++) { 660 (void) sleep(6); 661 devpath = sata_get_devicepath(ap_id); 662 } 663 664 if (devpath == NULL) { 665 rv = CFGA_SATA_DEV_CONFIGURE; 666 break; 667 } 668 } 669 670 S_FREE(devpath); 671 break; 672 673 case CFGA_CMD_UNCONFIGURE: 674 if (pmult == B_TRUE) { 675 rv = CFGA_SATA_HWOPNOTSUPP; 676 goto bailout; 677 } 678 679 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) != 680 CFGA_SATA_OK) 681 goto bailout; 682 683 if (rstate != AP_RSTATE_CONNECTED) { 684 rv = CFGA_SATA_NOT_CONNECTED; 685 goto bailout; 686 } 687 688 if (ostate != AP_OSTATE_CONFIGURED) { 689 rv = CFGA_SATA_NOT_CONFIGURED; 690 goto bailout; 691 } 692 /* Strip off AP name dynamic component, if present */ 693 if ((pdyn = GET_DYN(ap_id)) != NULL) { 694 *pdyn = '\0'; 695 } 696 697 rv = CFGA_SATA_OK; 698 699 len = strlen(SATA_CONFIRM_DEVICE) + 700 strlen(SATA_CONFIRM_DEVICE_SUSPEND) + 701 strlen("Unconfigure") + strlen(ap_id); 702 if ((msg = (char *)calloc(len +3, 1)) != NULL) { 703 (void) snprintf(msg, len + 3, "Unconfigure" 704 " %s%s\n%s", 705 SATA_CONFIRM_DEVICE, ap_id, 706 SATA_CONFIRM_DEVICE_SUSPEND); 707 } 708 709 if (!sata_confirm(confp, msg)) { 710 free(msg); 711 rv = CFGA_SATA_NACK; 712 break; 713 } 714 free(msg); 715 716 devpath = sata_get_devicepath(ap_id); 717 if (devpath == NULL) { 718 (void) printf( 719 "cfga_change_state: get device path failed\n"); 720 rv = CFGA_SATA_DEV_UNCONFIGURE; 721 break; 722 } 723 724 if ((rv = sata_rcm_offline(ap_id, errstring, devpath, flags)) 725 != CFGA_SATA_OK) { 726 break; 727 } 728 729 ret = devctl_ap_unconfigure(hdl, nvl); 730 731 if (ret != 0) { 732 rv = CFGA_SATA_DEV_UNCONFIGURE; 733 if (errno == EBUSY) { 734 rv = CFGA_SATA_BUSY; 735 } 736 (void) sata_rcm_online(ap_id, errstring, devpath, 737 flags); 738 } else { 739 (void) sata_rcm_remove(ap_id, errstring, devpath, 740 flags); 741 742 } 743 S_FREE(devpath); 744 745 break; 746 747 case CFGA_CMD_DISCONNECT: 748 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) != 749 CFGA_SATA_OK) 750 goto bailout; 751 752 if (rstate == AP_RSTATE_DISCONNECTED) { 753 rv = CFGA_SATA_DISCONNECTED; 754 goto bailout; 755 } 756 757 /* Strip off AP name dynamic component, if present */ 758 if ((pdyn = GET_DYN(ap_id)) != NULL) { 759 *pdyn = '\0'; 760 } 761 762 763 rv = CFGA_SATA_OK; /* other statuses don't matter */ 764 765 /* 766 * If the port originally with device attached and was 767 * unconfigured already, the devicepath for the sd will be 768 * removed. sata_get_devicepath in this case is not necessary. 769 */ 770 /* only call rcm_offline if the state was CONFIGURED */ 771 if (ostate == AP_OSTATE_CONFIGURED && 772 pmult == B_FALSE) { 773 devpath = sata_get_devicepath(ap_id); 774 if (devpath == NULL) { 775 (void) printf( 776 "cfga_change_state: get path failed\n"); 777 rv = CFGA_SATA_DEV_UNCONFIGURE; 778 break; 779 } 780 781 len = strlen(SATA_CONFIRM_DEVICE) + 782 strlen(SATA_CONFIRM_DEVICE_SUSPEND) + 783 strlen("Disconnect") + strlen(ap_id); 784 if ((msg = (char *)calloc(len +3, 1)) != NULL) { 785 (void) snprintf(msg, len + 3, 786 "Disconnect" 787 " %s%s\n%s", 788 SATA_CONFIRM_DEVICE, ap_id, 789 SATA_CONFIRM_DEVICE_SUSPEND); 790 } 791 if (!sata_confirm(confp, msg)) { 792 free(msg); 793 rv = CFGA_SATA_NACK; 794 break; 795 } 796 free(msg); 797 798 if ((rv = sata_rcm_offline(ap_id, errstring, 799 devpath, flags)) != CFGA_SATA_OK) { 800 break; 801 } 802 803 ret = devctl_ap_unconfigure(hdl, nvl); 804 if (ret != 0) { 805 (void) printf( 806 "devctl_ap_unconfigure failed\n"); 807 rv = CFGA_SATA_DEV_UNCONFIGURE; 808 if (errno == EBUSY) 809 rv = CFGA_SATA_BUSY; 810 (void) sata_rcm_online(ap_id, errstring, 811 devpath, flags); 812 S_FREE(devpath); 813 814 /* 815 * The current policy is that if unconfigure 816 * failed, do not continue with disconnect. 817 * If the port needs to be forced into the 818 * disconnect (shutdown) state, 819 * the -x sata_port_poweroff command should be 820 * used instead of -c disconnect 821 */ 822 break; 823 } else { 824 (void) printf("%s\n", 825 ERR_STR(CFGA_SATA_DEVICE_UNCONFIGURED)); 826 (void) sata_rcm_remove(ap_id, errstring, 827 devpath, flags); 828 } 829 S_FREE(devpath); 830 } else if (rstate == AP_RSTATE_CONNECTED || 831 rstate == AP_RSTATE_EMPTY) { 832 len = strlen(SATA_CONFIRM_PORT) + 833 strlen(SATA_CONFIRM_PORT_DISABLE) + 834 strlen("Deactivate Port") + strlen(ap_id); 835 if ((msg = (char *)calloc(len +3, 1)) != NULL) { 836 (void) snprintf(msg, len +3, 837 "Disconnect" 838 " %s%s\n%s", 839 SATA_CONFIRM_PORT, ap_id, 840 SATA_CONFIRM_PORT_DISABLE); 841 } 842 if (!sata_confirm(confp, msg)) { 843 free(msg); 844 rv = CFGA_SATA_NACK; 845 break; 846 } 847 } 848 ret = devctl_ap_disconnect(hdl, nvl); 849 if (ret != 0) { 850 rv = CFGA_SATA_IOCTL; 851 if (errno == EBUSY) { 852 rv = CFGA_SATA_BUSY; 853 } 854 } 855 break; 856 857 case CFGA_CMD_CONNECT: 858 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) != 859 CFGA_SATA_OK) 860 goto bailout; 861 862 if (rstate == AP_RSTATE_CONNECTED) { 863 rv = CFGA_SATA_ALREADY_CONNECTED; 864 goto bailout; 865 } 866 867 len = strlen(SATA_CONFIRM_PORT) + 868 strlen(SATA_CONFIRM_PORT_ENABLE) + 869 strlen("Activate Port") + strlen(ap_id); 870 if ((msg = (char *)calloc(len +3, 1)) != NULL) { 871 (void) snprintf(msg, len +3, "Activate" 872 " %s%s\n%s", 873 SATA_CONFIRM_PORT, ap_id, 874 SATA_CONFIRM_PORT_ENABLE); 875 } 876 if (!sata_confirm(confp, msg)) { 877 rv = CFGA_SATA_NACK; 878 break; 879 } 880 881 /* Disallow dynamic AP name component */ 882 if (GET_DYN(ap_id) != NULL) { 883 rv = CFGA_SATA_INVALID_DEVNAME; 884 goto bailout; 885 } 886 887 ret = devctl_ap_connect(hdl, nvl); 888 if (ret != 0) { 889 rv = CFGA_SATA_IOCTL; 890 } else { 891 rv = CFGA_SATA_OK; 892 } 893 894 break; 895 896 case CFGA_CMD_LOAD: 897 case CFGA_CMD_UNLOAD: 898 (void) cfga_help(msgp, options, flags); 899 rv = CFGA_SATA_OPNOTSUPP; 900 break; 901 902 case CFGA_CMD_NONE: 903 default: 904 (void) cfga_help(msgp, options, flags); 905 rv = CFGA_SATA_INTERNAL_ERROR; 906 } 907 908 bailout: 909 cleanup_after_devctl_cmd(hdl, nvl); 910 911 return (sata_err_msg(errstring, rv, ap_id, errno)); 912 } 913 914 /* cfgadm entry point */ 915 cfga_err_t 916 cfga_private_func( 917 const char *func, 918 const char *ap_id, 919 const char *options, 920 struct cfga_confirm *confp, 921 struct cfga_msg *msgp, 922 char **errstring, 923 cfga_flags_t flags) 924 { 925 int len; 926 char *msg; 927 nvlist_t *list = NULL; 928 ap_ostate_t ostate; 929 ap_rstate_t rstate; 930 devctl_hdl_t hdl = NULL; 931 cfga_sata_ret_t rv; 932 char *str_p; 933 size_t size; 934 935 if ((rv = verify_params(ap_id, NULL, errstring)) != CFGA_SATA_OK) { 936 (void) cfga_help(msgp, options, flags); 937 return (sata_err_msg(errstring, rv, ap_id, errno)); 938 } 939 940 /* 941 * All subcommands which can change state of device require 942 * root privileges. 943 */ 944 if (geteuid() != 0) { 945 rv = CFGA_SATA_PRIV; 946 goto bailout; 947 } 948 949 if (func == NULL) { 950 (void) printf("No valid option specified\n"); 951 rv = CFGA_SATA_OPTIONS; 952 goto bailout; 953 } 954 955 if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &list, 0)) != 956 CFGA_SATA_OK) { 957 goto bailout; 958 } 959 960 /* We do not care here about dynamic AP name component */ 961 if ((str_p = GET_DYN(ap_id)) != NULL) { 962 *str_p = '\0'; 963 } 964 965 rv = CFGA_SATA_OK; 966 967 if (strcmp(func, SATA_RESET_PORT) == 0) { 968 len = strlen(SATA_CONFIRM_PORT) + 969 strlen(SATA_CONFIRM_DEVICE_ABORT) + 970 strlen("Reset Port") + strlen(ap_id); 971 972 if ((msg = (char *)calloc(len +3, 1)) != NULL) { 973 (void) snprintf(msg, len +3, "Reset" 974 " %s%s\n%s", 975 SATA_CONFIRM_PORT, ap_id, 976 SATA_CONFIRM_DEVICE_ABORT); 977 } else { 978 rv = CFGA_SATA_NACK; 979 goto bailout; 980 } 981 982 if (!sata_confirm(confp, msg)) { 983 rv = CFGA_SATA_NACK; 984 goto bailout; 985 } 986 987 rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_PORT, NULL, 988 (void **)&str_p, &size); 989 990 } else if (strcmp(func, SATA_RESET_DEVICE) == 0) { 991 if ((rv = port_state(hdl, list, &rstate, &ostate)) != 992 CFGA_SATA_OK) 993 goto bailout; 994 /* 995 * Reset device function requires device to be connected 996 */ 997 if (rstate != AP_RSTATE_CONNECTED) { 998 rv = CFGA_SATA_NOT_CONNECTED; 999 goto bailout; 1000 } 1001 1002 len = strlen(SATA_CONFIRM_DEVICE) + 1003 strlen(SATA_CONFIRM_DEVICE_ABORT) + 1004 strlen("Reset Device") + strlen(ap_id); 1005 1006 if ((msg = (char *)calloc(len +3, 1)) != NULL) { 1007 (void) snprintf(msg, len +3, "Reset" 1008 " %s%s\n%s", 1009 SATA_CONFIRM_DEVICE, ap_id, 1010 SATA_CONFIRM_DEVICE_ABORT); 1011 } else { 1012 rv = CFGA_SATA_NACK; 1013 goto bailout; 1014 } 1015 1016 if (!sata_confirm(confp, msg)) { 1017 rv = CFGA_SATA_NACK; 1018 goto bailout; 1019 } 1020 1021 rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_DEVICE, NULL, 1022 (void **)&str_p, &size); 1023 1024 } else if (strcmp(func, SATA_RESET_ALL) == 0) { 1025 len = strlen(SATA_CONFIRM_CONTROLLER) + 1026 strlen(SATA_CONFIRM_CONTROLLER_ABORT) + 1027 strlen("Reset All") + strlen(ap_id); 1028 1029 if ((msg = (char *)calloc(len +3, 1)) != NULL) { 1030 (void) snprintf(msg, len +3, "Reset" 1031 " %s%s\n%s", 1032 SATA_CONFIRM_CONTROLLER, ap_id, 1033 SATA_CONFIRM_CONTROLLER_ABORT); 1034 } else { 1035 rv = CFGA_SATA_NACK; 1036 goto bailout; 1037 } 1038 1039 if (!sata_confirm(confp, msg)) { 1040 rv = CFGA_SATA_NACK; 1041 goto bailout; 1042 } 1043 rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_ALL, NULL, 1044 (void **)&str_p, &size); 1045 1046 } else if (strcmp(func, SATA_PORT_DEACTIVATE) == 0) { 1047 len = strlen(SATA_CONFIRM_PORT) + 1048 strlen(SATA_CONFIRM_PORT_DISABLE) + 1049 strlen("Deactivate Port") + strlen(ap_id); 1050 1051 if ((msg = (char *)calloc(len +3, 1)) != NULL) { 1052 (void) snprintf(msg, len +3, "Deactivate" 1053 " %s%s\n%s", 1054 SATA_CONFIRM_PORT, ap_id, 1055 SATA_CONFIRM_PORT_DISABLE); 1056 } else { 1057 rv = CFGA_SATA_NACK; 1058 goto bailout; 1059 } 1060 if (!sata_confirm(confp, msg)) { 1061 rv = CFGA_SATA_NACK; 1062 goto bailout; 1063 } 1064 1065 rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_DEACTIVATE, NULL, 1066 (void **)&str_p, &size); 1067 1068 } else if (strcmp(func, SATA_PORT_ACTIVATE) == 0) { 1069 len = strlen(SATA_CONFIRM_PORT) + 1070 strlen(SATA_CONFIRM_PORT_ENABLE) + 1071 strlen("Activate Port") + strlen(ap_id); 1072 1073 if ((msg = (char *)calloc(len +3, 1)) != NULL) { 1074 (void) snprintf(msg, len +3, "Activate" 1075 " %s%s\n%s", 1076 SATA_CONFIRM_PORT, ap_id, 1077 SATA_CONFIRM_PORT_ENABLE); 1078 } else { 1079 rv = CFGA_SATA_NACK; 1080 goto bailout; 1081 } 1082 if (!sata_confirm(confp, msg)) { 1083 rv = CFGA_SATA_NACK; 1084 goto bailout; 1085 } 1086 1087 rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_ACTIVATE, 1088 NULL, (void **)&str_p, &size); 1089 goto bailout; 1090 1091 } else if (strcmp(func, SATA_PORT_SELF_TEST) == 0) { 1092 len = strlen(SATA_CONFIRM_PORT) + 1093 strlen(SATA_CONFIRM_DEVICE_SUSPEND) + 1094 strlen("Self Test Port") + strlen(ap_id); 1095 1096 if ((msg = (char *)calloc(len +3, 1)) != NULL) { 1097 (void) snprintf(msg, len +3, "Self Test" 1098 " %s%s\n%s", 1099 SATA_CONFIRM_PORT, ap_id, 1100 SATA_CONFIRM_DEVICE_SUSPEND); 1101 } else { 1102 rv = CFGA_SATA_NACK; 1103 goto bailout; 1104 } 1105 if (!sata_confirm(confp, msg)) { 1106 rv = CFGA_SATA_NACK; 1107 goto bailout; 1108 } 1109 1110 rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_SELF_TEST, 1111 NULL, (void **)&str_p, &size); 1112 } else { 1113 /* Unrecognized operation request */ 1114 rv = CFGA_SATA_HWOPNOTSUPP; 1115 } 1116 1117 bailout: 1118 cleanup_after_devctl_cmd(hdl, list); 1119 1120 return (sata_err_msg(errstring, rv, ap_id, errno)); 1121 1122 } 1123 1124 /* cfgadm entry point */ 1125 /*ARGSUSED*/ 1126 cfga_err_t 1127 cfga_test( 1128 const char *ap_id, 1129 const char *options, 1130 struct cfga_msg *msgp, 1131 char **errstring, 1132 cfga_flags_t flags) 1133 { 1134 /* Should call ioctl for self test - phase 2 */ 1135 return (CFGA_OPNOTSUPP); 1136 } 1137 1138 1139 int 1140 sata_check_target_node(di_node_t node, void *arg) 1141 { 1142 char *minorpath; 1143 char *cp; 1144 1145 minorpath = di_devfs_minor_path(di_minor_next(node, DI_MINOR_NIL)); 1146 if (minorpath != NULL) { 1147 if (strstr(minorpath, arg) != NULL) { 1148 cp = strrchr(minorpath, (int)*MINOR_SEP); 1149 if (cp != NULL) { 1150 (void) strcpy(arg, cp); 1151 } 1152 free(minorpath); 1153 return (DI_WALK_TERMINATE); 1154 } 1155 free(minorpath); 1156 } 1157 return (DI_WALK_CONTINUE); 1158 } 1159 1160 struct chk_dev { 1161 int c_isblk; 1162 char *c_minor; 1163 }; 1164 1165 /*ARGSUSED*/ 1166 static int 1167 chk_dev_fcn(di_node_t node, di_minor_t minor, void *arg) 1168 { 1169 char *mn; 1170 struct chk_dev *chkp = (struct chk_dev *)arg; 1171 1172 mn = di_minor_name(minor); 1173 if (mn == NULL) 1174 return (DI_WALK_CONTINUE); 1175 1176 if (strcmp(mn, chkp->c_minor) != 0) 1177 return (DI_WALK_CONTINUE); 1178 1179 chkp->c_isblk = di_minor_spectype(minor) == S_IFBLK ? 1 : 0; 1180 1181 return (DI_WALK_TERMINATE); 1182 } 1183 1184 /* 1185 * Don't use devfs if stat() in /devices fails. Use libdevinfo instead. 1186 * Retired devices don't show up in devfs. 1187 * 1188 * Returns: 1189 * 1 - minor exists and is of type BLK 1190 * 0 - minor does not exist or is not of type BLK. 1191 */ 1192 static int 1193 is_devinfo_blk(char *minor_path) 1194 { 1195 char *minor_portion; 1196 struct chk_dev chk_dev; 1197 di_node_t node; 1198 int rv; 1199 1200 /* 1201 * prune minor path for di_init() - no /devices prefix and no minor name 1202 */ 1203 if (strncmp(minor_path, "/devices/", strlen("/devices/")) != 0) 1204 return (0); 1205 1206 minor_portion = strrchr(minor_path, *MINOR_SEP); 1207 if (minor_portion == NULL) 1208 return (0); 1209 1210 *minor_portion = 0; 1211 1212 node = di_init(minor_path + strlen("/devices"), DINFOMINOR); 1213 1214 *minor_portion = *MINOR_SEP; 1215 1216 if (node == DI_NODE_NIL) 1217 return (0); 1218 1219 chk_dev.c_isblk = 0; 1220 chk_dev.c_minor = minor_portion + 1; 1221 1222 rv = di_walk_minor(node, NULL, 0, &chk_dev, chk_dev_fcn); 1223 1224 di_fini(node); 1225 1226 if (rv == 0 && chk_dev.c_isblk) 1227 return (1); 1228 else 1229 return (0); 1230 } 1231 1232 /* 1233 * The dynamic component buffer returned by this function has to be freed! 1234 */ 1235 int 1236 sata_make_dyncomp(const char *ap_id, char **dyncomp, const char *type) 1237 { 1238 char *devpath = NULL; 1239 char *cp = NULL; 1240 int l_errno; 1241 char minor_path[MAXPATHLEN]; 1242 char name_part[MAXNAMELEN]; 1243 char *devlink = NULL; 1244 char *minor_portion = NULL; 1245 int deplen; 1246 int err; 1247 DIR *dp = NULL; 1248 struct stat sb; 1249 struct dirent *dep = NULL; 1250 struct dirent *newdep = NULL; 1251 char *p; 1252 1253 assert(dyncomp != NULL); 1254 1255 /* 1256 * Get target node path 1257 */ 1258 devpath = sata_get_devicepath(ap_id); 1259 if (devpath == NULL) { 1260 1261 (void) printf("cfga_list_ext: cannot locate target device\n"); 1262 return (CFGA_SATA_DYNAMIC_AP); 1263 1264 } else { 1265 1266 cp = strrchr(devpath, *PATH_SEP); 1267 assert(cp != NULL); 1268 *cp = 0; /* terminate path for opendir() */ 1269 1270 (void) strncpy(name_part, cp + 1, MAXNAMELEN); 1271 1272 /* 1273 * Using libdevinfo for this is overkill and kills 1274 * performance when many consumers are using libcfgadm 1275 * concurrently. 1276 */ 1277 if ((dp = opendir(devpath)) == NULL) { 1278 goto bailout; 1279 } 1280 1281 /* 1282 * deplen is large enough to fit the largest path- 1283 * struct dirent includes one byte (the terminator) 1284 * so we don't add 1 to the calculation here. 1285 */ 1286 deplen = pathconf(devpath, _PC_NAME_MAX); 1287 deplen = ((deplen <= 0) ? MAXNAMELEN : deplen) + 1288 sizeof (struct dirent); 1289 dep = (struct dirent *)malloc(deplen); 1290 if (dep == NULL) 1291 goto bailout; 1292 1293 while ((err = readdir_r(dp, dep, &newdep)) == 0 && 1294 newdep != NULL) { 1295 1296 assert(newdep == dep); 1297 1298 if (strcmp(dep->d_name, ".") == 0 || 1299 strcmp(dep->d_name, "..") == 0 || 1300 (minor_portion = strchr(dep->d_name, 1301 *MINOR_SEP)) == NULL) 1302 continue; 1303 1304 *minor_portion = 0; 1305 if (strcmp(dep->d_name, name_part) != 0) 1306 continue; 1307 *minor_portion = *MINOR_SEP; 1308 1309 (void) snprintf(minor_path, MAXPATHLEN, 1310 "%s/%s", devpath, dep->d_name); 1311 1312 /* 1313 * Break directly for tape device 1314 */ 1315 if (strcmp(type, "tape") == 0) 1316 break; 1317 1318 /* 1319 * If stat() fails, the device *may* be retired. 1320 * Check via libdevinfo if the device has a BLK minor. 1321 * We don't use libdevinfo all the time, since taking 1322 * a snapshot is slower than a stat(). 1323 */ 1324 if (stat(minor_path, &sb) < 0) { 1325 if (is_devinfo_blk(minor_path)) { 1326 break; 1327 } else { 1328 continue; 1329 } 1330 } 1331 1332 if (S_ISBLK(sb.st_mode)) 1333 break; 1334 1335 } 1336 1337 (void) closedir(dp); 1338 free(dep); 1339 free(devpath); 1340 1341 dp = NULL; 1342 dep = NULL; 1343 devpath = NULL; 1344 1345 /* 1346 * If there was an error, or we didn't exit the loop 1347 * by finding a block or character device, bail out. 1348 */ 1349 if (err != 0 || newdep == NULL) 1350 goto bailout; 1351 1352 /* 1353 * Look for links to the physical path in /dev/dsk 1354 * and /dev/rmt. So far, sata modue supports disk, 1355 * dvd and tape devices, so we will first look for 1356 * BLOCK devices, and then look for tape devices. 1357 */ 1358 (void) physpath_to_devlink("/dev/dsk", 1359 minor_path, &devlink, &l_errno); 1360 1361 /* postprocess and copy logical name here */ 1362 if (devlink != NULL) { 1363 /* 1364 * For disks, remove partition/slice info 1365 */ 1366 if ((cp = strstr(devlink, "dsk/")) != NULL) { 1367 /* cXtYdZ[(s[0..15])|(p[0..X])] */ 1368 if ((p = strchr(cp + 4, 'd')) != NULL) { 1369 p++; /* Skip the 'd' */ 1370 while (*p != 0 && isdigit(*p)) 1371 p++; 1372 *p = 0; 1373 } 1374 *dyncomp = strdup(cp); 1375 } 1376 1377 free(devlink); 1378 } else if (strcmp(type, "tape") == 0) { 1379 1380 /* 1381 * For tape device, logical name looks like 1382 * rmt/X 1383 */ 1384 (void) physpath_to_devlink("/dev/rmt", 1385 minor_path, &devlink, &l_errno); 1386 1387 if (devlink != NULL) { 1388 if ((cp = strstr(devlink, "rmt/")) != NULL) { 1389 *dyncomp = strdup(cp); 1390 } 1391 1392 free(devlink); 1393 } 1394 } 1395 1396 return (SATA_CFGA_OK); 1397 } 1398 1399 bailout: 1400 if (dp) 1401 (void) closedir(dp); 1402 if (devpath) 1403 free(devpath); 1404 if (dep) 1405 free(dep); 1406 return (CFGA_SATA_DYNAMIC_AP); 1407 } 1408 1409 /* cfgadm entry point */ 1410 /*ARGSUSED*/ 1411 cfga_err_t 1412 cfga_list_ext( 1413 const char *ap_id, 1414 cfga_list_data_t **ap_id_list, 1415 int *nlistp, 1416 const char *options, 1417 const char *listopts, 1418 char **errstring, 1419 cfga_flags_t flags) 1420 { 1421 int l_errno; 1422 char *ap_id_log = NULL; 1423 size_t size; 1424 nvlist_t *user_nvlist = NULL; 1425 devctl_hdl_t devctl_hdl = NULL; 1426 cfga_sata_ret_t rv = CFGA_SATA_OK; 1427 devctl_ap_state_t devctl_ap_state; 1428 char *pdyn; 1429 boolean_t pmult = B_FALSE; 1430 uint32_t port; 1431 1432 1433 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) { 1434 goto bailout; 1435 } 1436 /* We do not care here about dynamic AP name component */ 1437 if ((pdyn = GET_DYN(ap_id)) != NULL) { 1438 *pdyn = '\0'; 1439 } 1440 1441 if (ap_id_list == NULL || nlistp == NULL) { 1442 rv = CFGA_SATA_DATA_ERROR; 1443 goto bailout; 1444 } 1445 1446 /* Get ap status */ 1447 if ((rv = setup_for_devctl_cmd(ap_id, &devctl_hdl, &user_nvlist, 1448 DC_RDONLY)) != CFGA_SATA_OK) { 1449 goto bailout; 1450 } 1451 1452 /* will call dc_cmd to send IOCTL to kernel */ 1453 if (devctl_ap_getstate(devctl_hdl, user_nvlist, 1454 &devctl_ap_state) == -1) { 1455 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist); 1456 rv = CFGA_SATA_IOCTL; 1457 goto bailout; 1458 } 1459 1460 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist); 1461 1462 /* 1463 * Create cfga_list_data_t struct. 1464 */ 1465 if ((*ap_id_list = 1466 (cfga_list_data_t *)malloc(sizeof (**ap_id_list))) == NULL) { 1467 rv = CFGA_SATA_ALLOC_FAIL; 1468 goto bailout; 1469 } 1470 *nlistp = 1; 1471 1472 /* 1473 * Rest of the code fills in the cfga_list_data_t struct. 1474 */ 1475 1476 /* Get /dev/cfg path to corresponding to the physical ap_id */ 1477 /* Remember ap_id_log must be freed */ 1478 rv = physpath_to_devlink(CFGA_DEV_DIR, (char *)ap_id, 1479 &ap_id_log, &l_errno); 1480 1481 if (rv != 0) { 1482 rv = CFGA_SATA_DEVLINK; 1483 goto bailout; 1484 } 1485 1486 /* Get logical ap_id corresponding to the physical */ 1487 if (ap_id_log == NULL || strstr(ap_id_log, CFGA_DEV_DIR) == NULL) { 1488 rv = CFGA_SATA_DEVLINK; 1489 goto bailout; 1490 } 1491 1492 (void) strlcpy((*ap_id_list)->ap_log_id, 1493 /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR)+ 1, 1494 sizeof ((*ap_id_list)->ap_log_id)); 1495 1496 free(ap_id_log); 1497 ap_id_log = NULL; 1498 1499 (void) strlcpy((*ap_id_list)->ap_phys_id, ap_id, 1500 sizeof ((*ap_id_list)->ap_phys_id)); 1501 1502 switch (devctl_ap_state.ap_rstate) { 1503 case AP_RSTATE_EMPTY: 1504 (*ap_id_list)->ap_r_state = CFGA_STAT_EMPTY; 1505 break; 1506 1507 case AP_RSTATE_DISCONNECTED: 1508 (*ap_id_list)->ap_r_state = CFGA_STAT_DISCONNECTED; 1509 break; 1510 1511 case AP_RSTATE_CONNECTED: 1512 (*ap_id_list)->ap_r_state = CFGA_STAT_CONNECTED; 1513 break; 1514 1515 default: 1516 rv = CFGA_SATA_STATE; 1517 goto bailout; 1518 } 1519 1520 switch (devctl_ap_state.ap_ostate) { 1521 case AP_OSTATE_CONFIGURED: 1522 (*ap_id_list)->ap_o_state = CFGA_STAT_CONFIGURED; 1523 break; 1524 1525 case AP_OSTATE_UNCONFIGURED: 1526 (*ap_id_list)->ap_o_state = CFGA_STAT_UNCONFIGURED; 1527 break; 1528 1529 default: 1530 rv = CFGA_SATA_STATE; 1531 goto bailout; 1532 } 1533 1534 switch (devctl_ap_state.ap_condition) { 1535 case AP_COND_OK: 1536 (*ap_id_list)->ap_cond = CFGA_COND_OK; 1537 break; 1538 1539 case AP_COND_FAILING: 1540 (*ap_id_list)->ap_cond = CFGA_COND_FAILING; 1541 break; 1542 1543 case AP_COND_FAILED: 1544 (*ap_id_list)->ap_cond = CFGA_COND_FAILED; 1545 break; 1546 1547 case AP_COND_UNUSABLE: 1548 (*ap_id_list)->ap_cond = CFGA_COND_UNUSABLE; 1549 break; 1550 1551 case AP_COND_UNKNOWN: 1552 (*ap_id_list)->ap_cond = CFGA_COND_UNKNOWN; 1553 break; 1554 1555 default: 1556 rv = CFGA_SATA_STATE; 1557 goto bailout; 1558 } 1559 1560 (*ap_id_list)->ap_class[0] = '\0'; /* Filled by libcfgadm */ 1561 (*ap_id_list)->ap_busy = devctl_ap_state.ap_in_transition; 1562 (*ap_id_list)->ap_status_time = devctl_ap_state.ap_last_change; 1563 (*ap_id_list)->ap_info[0] = NULL; 1564 1565 if ((*ap_id_list)->ap_r_state == CFGA_STAT_CONNECTED) { 1566 char *str_p; 1567 int skip, i; 1568 1569 /* 1570 * Fill in the 'Information' field for the -v option 1571 * Model (MOD:) 1572 */ 1573 if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_MODEL_INFO, 1574 NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) { 1575 (void) printf( 1576 "SATA_CFGA_GET_MODULE_INFO ioctl failed\n"); 1577 goto bailout; 1578 } 1579 /* drop leading and trailing spaces */ 1580 skip = strspn(str_p, " "); 1581 for (i = size - 1; i >= 0; i--) { 1582 if (str_p[i] == '\040') 1583 str_p[i] = '\0'; 1584 else if (str_p[i] != '\0') 1585 break; 1586 } 1587 1588 (void) strlcpy((*ap_id_list)->ap_info, "Mod: ", 1589 sizeof ((*ap_id_list)->ap_info)); 1590 (void) strlcat((*ap_id_list)->ap_info, str_p + skip, 1591 sizeof ((*ap_id_list)->ap_info)); 1592 1593 free(str_p); 1594 1595 /* 1596 * Fill in the 'Information' field for the -v option 1597 * Firmware revision (FREV:) 1598 */ 1599 if ((rv = do_control_ioctl(ap_id, 1600 SATA_CFGA_GET_REVFIRMWARE_INFO, 1601 NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) { 1602 (void) printf( 1603 "SATA_CFGA_GET_REVFIRMWARE_INFO ioctl failed\n"); 1604 goto bailout; 1605 } 1606 /* drop leading and trailing spaces */ 1607 skip = strspn(str_p, " "); 1608 for (i = size - 1; i >= 0; i--) { 1609 if (str_p[i] == '\040') 1610 str_p[i] = '\0'; 1611 else if (str_p[i] != '\0') 1612 break; 1613 } 1614 (void) strlcat((*ap_id_list)->ap_info, " FRev: ", 1615 sizeof ((*ap_id_list)->ap_info)); 1616 (void) strlcat((*ap_id_list)->ap_info, str_p + skip, 1617 sizeof ((*ap_id_list)->ap_info)); 1618 1619 free(str_p); 1620 1621 1622 /* 1623 * Fill in the 'Information' field for the -v option 1624 * Serial Number (SN:) 1625 */ 1626 if ((rv = do_control_ioctl(ap_id, 1627 SATA_CFGA_GET_SERIALNUMBER_INFO, 1628 NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) { 1629 (void) printf( 1630 "SATA_CFGA_GET_SERIALNUMBER_INFO ioctl failed\n"); 1631 goto bailout; 1632 } 1633 /* drop leading and trailing spaces */ 1634 skip = strspn(str_p, " "); 1635 for (i = size - 1; i >= 0; i--) { 1636 if (str_p[i] == '\040') 1637 str_p[i] = '\0'; 1638 else if (str_p[i] != '\0') 1639 break; 1640 } 1641 (void) strlcat((*ap_id_list)->ap_info, " SN: ", 1642 sizeof ((*ap_id_list)->ap_info)); 1643 (void) strlcat((*ap_id_list)->ap_info, str_p + skip, 1644 sizeof ((*ap_id_list)->ap_info)); 1645 1646 free(str_p); 1647 1648 1649 1650 /* Fill in ap_type which is collected from HBA driver */ 1651 /* call do_control_ioctl TBD */ 1652 if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, NULL, 1653 (void **)&str_p, &size)) != CFGA_SATA_OK) { 1654 (void) printf( 1655 "SATA_CFGA_GET_AP_TYPE ioctl failed\n"); 1656 goto bailout; 1657 } 1658 1659 (void) strlcpy((*ap_id_list)->ap_type, str_p, 1660 sizeof ((*ap_id_list)->ap_type)); 1661 1662 free(str_p); 1663 1664 /* 1665 * Checking device type. Port multiplier has no dynamic 1666 * suffix. 1667 */ 1668 if (strncmp((*ap_id_list)->ap_type, "sata-pmult", 1669 sizeof ("sata-pmult")) == 0) 1670 pmult = B_TRUE; 1671 1672 if ((*ap_id_list)->ap_o_state == CFGA_STAT_CONFIGURED && 1673 pmult == B_FALSE) { 1674 1675 char *dyncomp = NULL; 1676 1677 /* 1678 * This is the case where we need to generate 1679 * a dynamic component of the ap_id, i.e. device. 1680 */ 1681 rv = sata_make_dyncomp(ap_id, &dyncomp, 1682 (*ap_id_list)->ap_type); 1683 if (rv != CFGA_SATA_OK) 1684 goto bailout; 1685 if (dyncomp != NULL) { 1686 (void) strcat((*ap_id_list)->ap_log_id, 1687 DYN_SEP); 1688 (void) strlcat((*ap_id_list)->ap_log_id, 1689 dyncomp, 1690 sizeof ((*ap_id_list)->ap_log_id)); 1691 free(dyncomp); 1692 } 1693 } 1694 1695 } else { 1696 /* This is an empty port */ 1697 if (get_port_num(ap_id, &port) != CFGA_SATA_OK) { 1698 goto bailout; 1699 } 1700 1701 if (port & SATA_CFGA_PMPORT_QUAL) { 1702 (void) strlcpy((*ap_id_list)->ap_type, "pmult-port", 1703 sizeof ((*ap_id_list)->ap_type)); 1704 } else { 1705 (void) strlcpy((*ap_id_list)->ap_type, "sata-port", 1706 sizeof ((*ap_id_list)->ap_type)); 1707 } 1708 } 1709 1710 return (sata_err_msg(errstring, rv, ap_id, errno)); 1711 1712 bailout: 1713 if (*ap_id_list != NULL) { 1714 free(*ap_id_list); 1715 } 1716 if (ap_id_log != NULL) { 1717 free(ap_id_log); 1718 } 1719 1720 return (sata_err_msg(errstring, rv, ap_id, errno)); 1721 } 1722 /* 1723 * This routine accepts a string adn prints it using 1724 * the message print routine argument. 1725 */ 1726 static void 1727 cfga_msg(struct cfga_msg *msgp, const char *str) 1728 { 1729 int len; 1730 char *q; 1731 1732 if (msgp == NULL || msgp->message_routine == NULL) { 1733 (void) printf("cfga_msg: NULL msgp\n"); 1734 return; 1735 } 1736 1737 if ((len = strlen(str)) == 0) { 1738 (void) printf("cfga_msg: null str\n"); 1739 return; 1740 } 1741 1742 if ((q = (char *)calloc(len + 1, 1)) == NULL) { 1743 perror("cfga_msg"); 1744 return; 1745 } 1746 1747 (void) strcpy(q, str); 1748 (*msgp->message_routine)(msgp->appdata_ptr, q); 1749 1750 free(q); 1751 } 1752 1753 /* cfgadm entry point */ 1754 /* ARGSUSED */ 1755 cfga_err_t 1756 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags) 1757 { 1758 if (options != NULL) { 1759 cfga_msg(msgp, dgettext(TEXT_DOMAIN, sata_help[HELP_UNKNOWN])); 1760 cfga_msg(msgp, options); 1761 } 1762 cfga_msg(msgp, dgettext(TEXT_DOMAIN, sata_help[HELP_HEADER])); 1763 cfga_msg(msgp, sata_help[HELP_CONFIG]); 1764 cfga_msg(msgp, sata_help[HELP_RESET_PORT]); 1765 cfga_msg(msgp, sata_help[HELP_RESET_DEVICE]); 1766 cfga_msg(msgp, sata_help[HELP_RESET_ALL]); 1767 cfga_msg(msgp, sata_help[HELP_PORT_ACTIVATE]); 1768 cfga_msg(msgp, sata_help[HELP_PORT_DEACTIVATE]); 1769 cfga_msg(msgp, sata_help[HELP_PORT_SELF_TEST]); 1770 cfga_msg(msgp, sata_help[HELP_CNTRL_SELF_TEST]); 1771 1772 return (CFGA_OK); 1773 } 1774 1775 1776 /* 1777 * Ensure the ap_id passed is in the correct (physical ap_id) form: 1778 * path/device:xx[.xx] 1779 * where xx is a one or two-digit number. 1780 * 1781 * Note the library always calls the plugin with a physical ap_id. 1782 */ 1783 static int 1784 verify_valid_apid(const char *ap_id) 1785 { 1786 char *l_ap_id; 1787 1788 if (ap_id == NULL) 1789 return (-1); 1790 1791 l_ap_id = strrchr(ap_id, (int)*MINOR_SEP); 1792 l_ap_id++; 1793 1794 if (strspn(l_ap_id, "0123456789.") != strlen(l_ap_id)) { 1795 /* Bad characters in the ap_id */ 1796 return (-1); 1797 } 1798 1799 if (strstr(l_ap_id, "..") != NULL) { 1800 /* ap_id has 1..2 or more than 2 dots */ 1801 return (-1); 1802 } 1803 1804 return (0); 1805 } 1806 1807 1808 1809 /* 1810 * Verify the params passed in are valid. 1811 */ 1812 static cfga_sata_ret_t 1813 verify_params( 1814 const char *ap_id, 1815 const char *options, 1816 char **errstring) 1817 { 1818 char *pdyn, *lap_id; 1819 int rv; 1820 1821 if (errstring != NULL) { 1822 *errstring = NULL; 1823 } 1824 1825 if (options != NULL) { 1826 return (CFGA_SATA_OPTIONS); 1827 } 1828 1829 /* Strip dynamic AP name component if it is present. */ 1830 lap_id = strdup(ap_id); 1831 if (lap_id == NULL) { 1832 return (CFGA_SATA_ALLOC_FAIL); 1833 } 1834 if ((pdyn = GET_DYN(lap_id)) != NULL) { 1835 *pdyn = '\0'; 1836 } 1837 1838 if (verify_valid_apid(lap_id) != 0) { 1839 rv = CFGA_SATA_AP; 1840 } else { 1841 rv = CFGA_SATA_OK; 1842 } 1843 free(lap_id); 1844 1845 return (rv); 1846 } 1847 1848 /* 1849 * Takes a validated ap_id and extracts the port number. 1850 * Port multiplier is supported now. 1851 */ 1852 static cfga_sata_ret_t 1853 get_port_num(const char *ap_id, uint32_t *port) 1854 { 1855 uint32_t cport, pmport = 0, qual = 0; 1856 char *cport_str, *pmport_str; 1857 1858 /* Get the cport number */ 1859 cport_str = strrchr(ap_id, (int)*MINOR_SEP) + strlen(MINOR_SEP); 1860 1861 errno = 0; 1862 cport = strtol(cport_str, NULL, 10); 1863 if ((cport & ~SATA_CFGA_CPORT_MASK) != 0 || errno != 0) { 1864 return (CFGA_SATA_PORT); 1865 } 1866 1867 /* Get pmport number if there is a PORT_SEPARATOR */ 1868 errno = 0; 1869 if ((pmport_str = strrchr(ap_id, (int)*PORT_SEPARATOR)) != 0) { 1870 pmport_str += strlen(PORT_SEPARATOR); 1871 pmport = strtol(pmport_str, NULL, 10); 1872 qual = SATA_CFGA_PMPORT_QUAL; 1873 if ((pmport & ~SATA_CFGA_PMPORT_MASK) != 0 || errno != 0) { 1874 return (CFGA_SATA_PORT); 1875 } 1876 } 1877 1878 *port = cport | (pmport << SATA_CFGA_PMPORT_SHIFT) | qual; 1879 return (CFGA_SATA_OK); 1880 } 1881 1882 /* 1883 * Pair of routines to set up for/clean up after a devctl_ap_* lib call. 1884 */ 1885 static void 1886 cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist) 1887 { 1888 if (user_nvlist != NULL) { 1889 nvlist_free(user_nvlist); 1890 } 1891 if (devctl_hdl != NULL) { 1892 devctl_release(devctl_hdl); 1893 } 1894 } 1895 1896 static cfga_sata_ret_t 1897 setup_for_devctl_cmd( 1898 const char *ap_id, 1899 devctl_hdl_t *devctl_hdl, 1900 nvlist_t **user_nvlistp, 1901 uint_t oflag) 1902 { 1903 1904 uint_t port; 1905 cfga_sata_ret_t rv = CFGA_SATA_OK; 1906 char *lap_id, *pdyn; 1907 1908 lap_id = strdup(ap_id); 1909 if (lap_id == NULL) 1910 return (CFGA_SATA_ALLOC_FAIL); 1911 if ((pdyn = GET_DYN(lap_id)) != NULL) { 1912 *pdyn = '\0'; 1913 } 1914 1915 /* Get a devctl handle to pass to the devctl_ap_XXX functions */ 1916 if ((*devctl_hdl = devctl_ap_acquire((char *)lap_id, oflag)) == NULL) { 1917 (void) fprintf(stderr, "[libcfgadm:sata] " 1918 "setup_for_devctl_cmd: devctl_ap_acquire failed: %s\n", 1919 strerror(errno)); 1920 rv = CFGA_SATA_DEVCTL; 1921 goto bailout; 1922 } 1923 1924 /* Set up nvlist to pass the port number down to the driver */ 1925 if (nvlist_alloc(user_nvlistp, NV_UNIQUE_NAME_TYPE, NULL) != 0) { 1926 *user_nvlistp = NULL; 1927 rv = CFGA_SATA_NVLIST; 1928 (void) printf("nvlist_alloc failed\n"); 1929 goto bailout; 1930 } 1931 1932 /* 1933 * Get port id, for Port Multiplier port, things could be a little bit 1934 * complicated because of "port.port" format in ap_id, thus for 1935 * port multiplier port, port number should be coded as 32bit int 1936 * with the sig 16 bit as sata channel number, least 16 bit as 1937 * the port number of sata port multiplier port. 1938 */ 1939 if ((rv = get_port_num(lap_id, &port)) != CFGA_SATA_OK) { 1940 (void) printf( 1941 "setup_for_devctl_cmd: get_port_num, errno: %d\n", 1942 errno); 1943 goto bailout; 1944 } 1945 1946 /* Creates an int32_t entry */ 1947 if (nvlist_add_int32(*user_nvlistp, PORT, port) == -1) { 1948 (void) printf("nvlist_add_int32 failed\n"); 1949 rv = CFGA_SATA_NVLIST; 1950 goto bailout; 1951 } 1952 1953 free(lap_id); 1954 return (rv); 1955 1956 bailout: 1957 free(lap_id); 1958 (void) cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp); 1959 1960 return (rv); 1961 } 1962 1963 1964 static cfga_sata_ret_t 1965 port_state(devctl_hdl_t hdl, nvlist_t *list, 1966 ap_rstate_t *rstate, ap_ostate_t *ostate) 1967 { 1968 devctl_ap_state_t devctl_ap_state; 1969 1970 if (devctl_ap_getstate(hdl, list, &devctl_ap_state) == -1) { 1971 (void) printf("devctl_ap_getstate failed, errno: %d\n", errno); 1972 return (CFGA_SATA_IOCTL); 1973 } 1974 *rstate = devctl_ap_state.ap_rstate; 1975 *ostate = devctl_ap_state.ap_ostate; 1976 return (CFGA_SATA_OK); 1977 } 1978 1979 1980 /* 1981 * Given a subcommand to the DEVCTL_AP_CONTROL ioctl, rquest the size of 1982 * the data to be returned, allocate a buffer, then get the data. 1983 * Returns *descrp (which must be freed) and size. 1984 * 1985 * Note SATA_DESCR_TYPE_STRING returns an ASCII NULL-terminated string, 1986 * not a string descr. 1987 */ 1988 cfga_sata_ret_t 1989 do_control_ioctl(const char *ap_id, sata_cfga_apctl_t subcommand, uint_t arg, 1990 void **descrp, size_t *sizep) 1991 { 1992 int fd = -1; 1993 uint_t port; 1994 uint32_t local_size; 1995 cfga_sata_ret_t rv = CFGA_SATA_OK; 1996 struct sata_ioctl_data ioctl_data; 1997 1998 assert(descrp != NULL); 1999 *descrp = NULL; 2000 assert(sizep != NULL); 2001 2002 if ((rv = get_port_num(ap_id, &port)) != CFGA_SATA_OK) { 2003 goto bailout; 2004 } 2005 2006 if ((fd = open(ap_id, O_RDONLY)) == -1) { 2007 (void) printf("do_control_ioctl: open failed: errno:%d\n", 2008 errno); 2009 rv = CFGA_SATA_OPEN; 2010 if (errno == EBUSY) { 2011 rv = CFGA_SATA_BUSY; 2012 } 2013 goto bailout; 2014 } 2015 2016 ioctl_data.cmd = subcommand; 2017 ioctl_data.port = port; 2018 ioctl_data.misc_arg = (uint_t)arg; 2019 2020 /* 2021 * Find out how large a buf we need to get the data. 2022 * Note the ioctls only accept/return a 32-bit int for a get_size 2023 * to avoid 32/64 and BE/LE issues. 2024 */ 2025 if ((subcommand == SATA_CFGA_GET_AP_TYPE) || 2026 (subcommand == SATA_CFGA_GET_DEVICE_PATH) || 2027 (subcommand == SATA_CFGA_GET_MODEL_INFO) || 2028 (subcommand == SATA_CFGA_GET_REVFIRMWARE_INFO) || 2029 (subcommand == SATA_CFGA_GET_SERIALNUMBER_INFO)) { 2030 ioctl_data.get_size = B_TRUE; 2031 ioctl_data.buf = (caddr_t)&local_size; 2032 ioctl_data.bufsiz = sizeof (local_size); 2033 2034 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) { 2035 perror("ioctl failed (size)"); 2036 rv = CFGA_SATA_IOCTL; 2037 goto bailout; 2038 } 2039 *sizep = local_size; 2040 2041 if (local_size == 0) { 2042 (void) printf("zero length data\n"); 2043 rv = CFGA_SATA_ZEROLEN; 2044 goto bailout; 2045 } 2046 if ((*descrp = malloc(*sizep)) == NULL) { 2047 (void) printf("do_control_ioctl: malloc failed\n"); 2048 rv = CFGA_SATA_ALLOC_FAIL; 2049 goto bailout; 2050 } 2051 } else { 2052 *sizep = 0; 2053 } 2054 ioctl_data.get_size = B_FALSE; 2055 ioctl_data.buf = *descrp; 2056 ioctl_data.bufsiz = *sizep; 2057 2058 /* Execute IOCTL */ 2059 2060 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) { 2061 rv = CFGA_SATA_IOCTL; 2062 goto bailout; 2063 } 2064 2065 (void) close(fd); 2066 2067 return (rv); 2068 2069 bailout: 2070 if (fd != -1) { 2071 (void) close(fd); 2072 } 2073 if (*descrp != NULL) { 2074 free(*descrp); 2075 *descrp = NULL; 2076 } 2077 2078 if (rv == CFGA_SATA_IOCTL && errno == EBUSY) { 2079 rv = CFGA_SATA_BUSY; 2080 } 2081 2082 return (rv); 2083 } 2084 2085 2086 static int 2087 sata_confirm(struct cfga_confirm *confp, char *msg) 2088 { 2089 int rval; 2090 2091 if (confp == NULL || confp->confirm == NULL) { 2092 return (0); 2093 } 2094 rval = (*confp->confirm)(confp->appdata_ptr, msg); 2095 2096 return (rval); 2097 } 2098 2099 2100 static char * 2101 sata_get_devicepath(const char *ap_id) 2102 { 2103 char *devpath = NULL; 2104 size_t size; 2105 cfga_sata_ret_t rv; 2106 2107 rv = do_control_ioctl(ap_id, SATA_CFGA_GET_DEVICE_PATH, NULL, 2108 (void **)&devpath, &size); 2109 2110 if (rv == CFGA_SATA_OK) { 2111 return (devpath); 2112 } else { 2113 return ((char *)NULL); 2114 } 2115 2116 } 2117