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