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