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