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