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 char *p; 1154 1155 assert(dyncomp != NULL); 1156 1157 /* 1158 * Get target node path 1159 */ 1160 devpath = sata_get_devicepath(ap_id); 1161 if (devpath == NULL) { 1162 1163 (void) printf("cfga_list_ext: cannot locate target device\n"); 1164 return (CFGA_SATA_DYNAMIC_AP); 1165 1166 } else { 1167 1168 cp = strrchr(devpath, *PATH_SEP); 1169 assert(cp != NULL); 1170 *cp = 0; /* terminate path for opendir() */ 1171 1172 (void) strncpy(name_part, cp + 1, MAXNAMELEN); 1173 1174 /* 1175 * Using libdevinfo for this is overkill and kills 1176 * performance when many consumers are using libcfgadm 1177 * concurrently. 1178 */ 1179 if ((dp = opendir(devpath)) == NULL) { 1180 goto bailout; 1181 } 1182 1183 /* 1184 * deplen is large enough to fit the largest path- 1185 * struct dirent includes one byte (the terminator) 1186 * so we don't add 1 to the calculation here. 1187 */ 1188 deplen = pathconf(devpath, _PC_NAME_MAX) + 1189 sizeof (struct dirent); 1190 dep = (struct dirent *)malloc(deplen); 1191 if (dep == NULL) 1192 goto bailout; 1193 1194 while ((err = readdir_r(dp, dep, &newdep)) == 0 && 1195 newdep != NULL) { 1196 1197 assert(newdep == dep); 1198 1199 if (strcmp(dep->d_name, ".") == 0 || 1200 strcmp(dep->d_name, "..") == 0 || 1201 (minor_portion = strchr(dep->d_name, 1202 *MINOR_SEP)) == NULL) 1203 continue; 1204 1205 *minor_portion = 0; 1206 if (strcmp(dep->d_name, name_part) != 0) 1207 continue; 1208 *minor_portion = *MINOR_SEP; 1209 1210 (void) snprintf(minor_path, MAXPATHLEN, 1211 "%s/%s", devpath, dep->d_name); 1212 1213 if (stat(minor_path, &sb) < 0) 1214 continue; 1215 1216 if (S_ISBLK(sb.st_mode)) 1217 break; 1218 } 1219 1220 (void) closedir(dp); 1221 free(dep); 1222 free(devpath); 1223 1224 dp = NULL; 1225 dep = NULL; 1226 devpath = NULL; 1227 1228 /* 1229 * If there was an error, or we didn't exit the loop 1230 * by finding a block or character device, bail out. 1231 */ 1232 if (err != 0 || newdep == NULL) 1233 goto bailout; 1234 1235 /* 1236 * Look for links to the physical path in /dev/dsk, 1237 * since we ONLY looked for BLOCK devices above. 1238 */ 1239 (void) physpath_to_devlink("/dev/dsk", 1240 minor_path, &devlink, &l_errno); 1241 1242 /* postprocess and copy logical name here */ 1243 if (devlink != NULL) { 1244 /* 1245 * For disks, remove partition/slice info 1246 */ 1247 if ((cp = strstr(devlink, "dsk/")) != NULL) { 1248 /* cXtYdZ[(s[0..15])|(p[0..X])] */ 1249 if ((p = strchr(cp + 4, 'd')) != NULL) { 1250 p++; /* Skip the 'd' */ 1251 while (*p != 0 && isdigit(*p)) 1252 p++; 1253 *p = 0; 1254 } 1255 *dyncomp = strdup(cp); 1256 } 1257 1258 free(devlink); 1259 } 1260 1261 return (SATA_CFGA_OK); 1262 } 1263 1264 bailout: 1265 if (dp) 1266 (void) closedir(dp); 1267 if (devpath) 1268 free(devpath); 1269 if (dep) 1270 free(dep); 1271 return (CFGA_SATA_DYNAMIC_AP); 1272 } 1273 1274 /* cfgadm entry point */ 1275 /*ARGSUSED*/ 1276 cfga_err_t 1277 cfga_list_ext( 1278 const char *ap_id, 1279 cfga_list_data_t **ap_id_list, 1280 int *nlistp, 1281 const char *options, 1282 const char *listopts, 1283 char **errstring, 1284 cfga_flags_t flags) 1285 { 1286 int l_errno; 1287 char *ap_id_log = NULL; 1288 size_t size; 1289 nvlist_t *user_nvlist = NULL; 1290 devctl_hdl_t devctl_hdl = NULL; 1291 cfga_sata_ret_t rv = CFGA_SATA_OK; 1292 devctl_ap_state_t devctl_ap_state; 1293 char *pdyn; 1294 1295 1296 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) { 1297 (void) cfga_help(NULL, options, flags); 1298 goto bailout; 1299 } 1300 /* We do not care here about dynamic AP name component */ 1301 if ((pdyn = GET_DYN(ap_id)) != NULL) { 1302 *pdyn = '\0'; 1303 } 1304 1305 if (ap_id_list == NULL || nlistp == NULL) { 1306 rv = CFGA_SATA_DATA_ERROR; 1307 (void) cfga_help(NULL, options, flags); 1308 goto bailout; 1309 } 1310 1311 /* Get ap status */ 1312 if ((rv = setup_for_devctl_cmd(ap_id, &devctl_hdl, &user_nvlist, 1313 DC_RDONLY)) != CFGA_SATA_OK) { 1314 goto bailout; 1315 } 1316 1317 /* will call dc_cmd to send IOCTL to kernel */ 1318 if (devctl_ap_getstate(devctl_hdl, user_nvlist, 1319 &devctl_ap_state) == -1) { 1320 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist); 1321 rv = CFGA_SATA_IOCTL; 1322 goto bailout; 1323 } 1324 1325 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist); 1326 1327 /* 1328 * Create cfga_list_data_t struct. 1329 */ 1330 if ((*ap_id_list = 1331 (cfga_list_data_t *)malloc(sizeof (**ap_id_list))) == NULL) { 1332 rv = CFGA_SATA_ALLOC_FAIL; 1333 goto bailout; 1334 } 1335 *nlistp = 1; 1336 1337 /* 1338 * Rest of the code fills in the cfga_list_data_t struct. 1339 */ 1340 1341 /* Get /dev/cfg path to corresponding to the physical ap_id */ 1342 /* Remember ap_id_log must be freed */ 1343 rv = physpath_to_devlink(CFGA_DEV_DIR, (char *)ap_id, 1344 &ap_id_log, &l_errno); 1345 1346 if (rv != 0) { 1347 rv = CFGA_SATA_DEVLINK; 1348 goto bailout; 1349 } 1350 1351 /* Get logical ap_id corresponding to the physical */ 1352 if (ap_id_log == NULL || strstr(ap_id_log, CFGA_DEV_DIR) == NULL) { 1353 rv = CFGA_SATA_DEVLINK; 1354 goto bailout; 1355 } 1356 1357 (void) strlcpy((*ap_id_list)->ap_log_id, 1358 /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR)+ 1, 1359 sizeof ((*ap_id_list)->ap_log_id)); 1360 1361 free(ap_id_log); 1362 ap_id_log = NULL; 1363 1364 (void) strlcpy((*ap_id_list)->ap_phys_id, ap_id, 1365 sizeof ((*ap_id_list)->ap_phys_id)); 1366 1367 switch (devctl_ap_state.ap_rstate) { 1368 case AP_RSTATE_EMPTY: 1369 (*ap_id_list)->ap_r_state = CFGA_STAT_EMPTY; 1370 break; 1371 1372 case AP_RSTATE_DISCONNECTED: 1373 (*ap_id_list)->ap_r_state = CFGA_STAT_DISCONNECTED; 1374 break; 1375 1376 case AP_RSTATE_CONNECTED: 1377 (*ap_id_list)->ap_r_state = CFGA_STAT_CONNECTED; 1378 break; 1379 1380 default: 1381 rv = CFGA_SATA_STATE; 1382 goto bailout; 1383 } 1384 1385 switch (devctl_ap_state.ap_ostate) { 1386 case AP_OSTATE_CONFIGURED: 1387 (*ap_id_list)->ap_o_state = CFGA_STAT_CONFIGURED; 1388 break; 1389 1390 case AP_OSTATE_UNCONFIGURED: 1391 (*ap_id_list)->ap_o_state = CFGA_STAT_UNCONFIGURED; 1392 break; 1393 1394 default: 1395 rv = CFGA_SATA_STATE; 1396 goto bailout; 1397 } 1398 1399 switch (devctl_ap_state.ap_condition) { 1400 case AP_COND_OK: 1401 (*ap_id_list)->ap_cond = CFGA_COND_OK; 1402 break; 1403 1404 case AP_COND_FAILING: 1405 (*ap_id_list)->ap_cond = CFGA_COND_FAILING; 1406 break; 1407 1408 case AP_COND_FAILED: 1409 (*ap_id_list)->ap_cond = CFGA_COND_FAILED; 1410 break; 1411 1412 case AP_COND_UNUSABLE: 1413 (*ap_id_list)->ap_cond = CFGA_COND_UNUSABLE; 1414 break; 1415 1416 case AP_COND_UNKNOWN: 1417 (*ap_id_list)->ap_cond = CFGA_COND_UNKNOWN; 1418 break; 1419 1420 default: 1421 rv = CFGA_SATA_STATE; 1422 goto bailout; 1423 } 1424 1425 (*ap_id_list)->ap_class[0] = '\0'; /* Filled by libcfgadm */ 1426 (*ap_id_list)->ap_busy = devctl_ap_state.ap_in_transition; 1427 (*ap_id_list)->ap_status_time = devctl_ap_state.ap_last_change; 1428 (*ap_id_list)->ap_info[0] = NULL; 1429 1430 if ((*ap_id_list)->ap_r_state == CFGA_STAT_CONNECTED) { 1431 char *str_p; 1432 int skip, i; 1433 1434 /* 1435 * Fill in the 'Information' field for the -v option 1436 * Model (MOD:) 1437 */ 1438 if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_MODEL_INFO, 1439 NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) { 1440 (void) printf( 1441 "SATA_CFGA_GET_MODULE_INFO ioctl failed\n"); 1442 goto bailout; 1443 } 1444 /* drop leading and trailing spaces */ 1445 skip = strspn(str_p, " "); 1446 for (i = size - 1; i >= 0; i--) { 1447 if (str_p[i] == '\040') 1448 str_p[i] = '\0'; 1449 else if (str_p[i] != '\0') 1450 break; 1451 } 1452 1453 (void) strlcpy((*ap_id_list)->ap_info, "Mod: ", 1454 sizeof ((*ap_id_list)->ap_info)); 1455 (void) strlcat((*ap_id_list)->ap_info, str_p + skip, 1456 sizeof ((*ap_id_list)->ap_info)); 1457 1458 free(str_p); 1459 1460 /* 1461 * Fill in the 'Information' field for the -v option 1462 * Firmware revision (FREV:) 1463 */ 1464 if ((rv = do_control_ioctl(ap_id, 1465 SATA_CFGA_GET_REVFIRMWARE_INFO, 1466 NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) { 1467 (void) printf( 1468 "SATA_CFGA_GET_REVFIRMWARE_INFO ioctl failed\n"); 1469 goto bailout; 1470 } 1471 /* drop leading and trailing spaces */ 1472 skip = strspn(str_p, " "); 1473 for (i = size - 1; i >= 0; i--) { 1474 if (str_p[i] == '\040') 1475 str_p[i] = '\0'; 1476 else if (str_p[i] != '\0') 1477 break; 1478 } 1479 (void) strlcat((*ap_id_list)->ap_info, " FRev: ", 1480 sizeof ((*ap_id_list)->ap_info)); 1481 (void) strlcat((*ap_id_list)->ap_info, str_p + skip, 1482 sizeof ((*ap_id_list)->ap_info)); 1483 1484 free(str_p); 1485 1486 1487 /* 1488 * Fill in the 'Information' field for the -v option 1489 * Serial Number (SN:) 1490 */ 1491 if ((rv = do_control_ioctl(ap_id, 1492 SATA_CFGA_GET_SERIALNUMBER_INFO, 1493 NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) { 1494 (void) printf( 1495 "SATA_CFGA_GET_SERIALNUMBER_INFO ioctl failed\n"); 1496 goto bailout; 1497 } 1498 /* drop leading and trailing spaces */ 1499 skip = strspn(str_p, " "); 1500 for (i = size - 1; i >= 0; i--) { 1501 if (str_p[i] == '\040') 1502 str_p[i] = '\0'; 1503 else if (str_p[i] != '\0') 1504 break; 1505 } 1506 (void) strlcat((*ap_id_list)->ap_info, " SN: ", 1507 sizeof ((*ap_id_list)->ap_info)); 1508 (void) strlcat((*ap_id_list)->ap_info, str_p + skip, 1509 sizeof ((*ap_id_list)->ap_info)); 1510 1511 free(str_p); 1512 1513 1514 1515 /* Fill in ap_type which is collected from HBA driver */ 1516 /* call do_control_ioctl TBD */ 1517 if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, NULL, 1518 (void **)&str_p, &size)) != CFGA_SATA_OK) { 1519 (void) printf( 1520 "SATA_CFGA_GET_AP_TYPE ioctl failed\n"); 1521 goto bailout; 1522 } 1523 1524 (void) strlcpy((*ap_id_list)->ap_type, str_p, 1525 sizeof ((*ap_id_list)->ap_type)); 1526 1527 free(str_p); 1528 1529 if ((*ap_id_list)->ap_o_state == CFGA_STAT_CONFIGURED) { 1530 1531 char *dyncomp = NULL; 1532 1533 /* 1534 * This is the case where we need to generate 1535 * a dynamic component of the ap_id, i.e. device. 1536 */ 1537 rv = sata_make_dyncomp(ap_id, &dyncomp); 1538 if (rv != CFGA_SATA_OK) 1539 goto bailout; 1540 if (dyncomp != NULL) { 1541 (void) strcat((*ap_id_list)->ap_log_id, 1542 DYN_SEP); 1543 (void) strlcat((*ap_id_list)->ap_log_id, 1544 dyncomp, 1545 sizeof ((*ap_id_list)->ap_log_id)); 1546 free(dyncomp); 1547 } 1548 } 1549 1550 } else { 1551 /* Change it when port multiplier is supported */ 1552 (void) strlcpy((*ap_id_list)->ap_type, "sata-port", 1553 sizeof ((*ap_id_list)->ap_type)); 1554 } 1555 1556 return (sata_err_msg(errstring, rv, ap_id, errno)); 1557 1558 bailout: 1559 if (*ap_id_list != NULL) { 1560 free(*ap_id_list); 1561 } 1562 if (ap_id_log != NULL) { 1563 free(ap_id_log); 1564 } 1565 1566 return (sata_err_msg(errstring, rv, ap_id, errno)); 1567 } 1568 /* 1569 * This routine accepts a string adn prints it using 1570 * the message print routine argument. 1571 */ 1572 static void 1573 cfga_msg(struct cfga_msg *msgp, const char *str) 1574 { 1575 int len; 1576 char *q; 1577 1578 if (msgp == NULL || msgp->message_routine == NULL) { 1579 (void) printf("cfga_msg: NULL msgp\n"); 1580 return; 1581 } 1582 1583 if ((len = strlen(str)) == 0) { 1584 (void) printf("cfga_msg: null str\n"); 1585 return; 1586 } 1587 1588 if ((q = (char *)calloc(len + 1, 1)) == NULL) { 1589 perror("cfga_msg" 1590 ); 1591 return; 1592 } 1593 1594 (void) strcpy(q, str); 1595 (*msgp->message_routine)(msgp->appdata_ptr, q); 1596 1597 free(q); 1598 } 1599 1600 /* cfgadm entry point */ 1601 /* ARGSUSED */ 1602 cfga_err_t 1603 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags) 1604 { 1605 if (options != NULL) { 1606 cfga_msg(msgp, dgettext(TEXT_DOMAIN, sata_help[HELP_UNKNOWN])); 1607 cfga_msg(msgp, options); 1608 } 1609 cfga_msg(msgp, dgettext(TEXT_DOMAIN, sata_help[HELP_HEADER])); 1610 cfga_msg(msgp, sata_help[HELP_CONFIG]); 1611 cfga_msg(msgp, sata_help[HELP_RESET_PORT]); 1612 cfga_msg(msgp, sata_help[HELP_RESET_DEVICE]); 1613 cfga_msg(msgp, sata_help[HELP_RESET_ALL]); 1614 cfga_msg(msgp, sata_help[HELP_PORT_ACTIVATE]); 1615 cfga_msg(msgp, sata_help[HELP_PORT_DEACTIVATE]); 1616 cfga_msg(msgp, sata_help[HELP_PORT_SELF_TEST]); 1617 cfga_msg(msgp, sata_help[HELP_CNTRL_SELF_TEST]); 1618 1619 return (CFGA_OK); 1620 } 1621 1622 1623 /* 1624 * Ensure the ap_id passed is in the correct (physical ap_id) form: 1625 * path/device:xx[.xx] 1626 * where xx is a one or two-digit number. 1627 * 1628 * Note the library always calls the plugin with a physical ap_id. 1629 */ 1630 static int 1631 verify_valid_apid(const char *ap_id) 1632 { 1633 char *l_ap_id; 1634 1635 if (ap_id == NULL) 1636 return (-1); 1637 1638 l_ap_id = strrchr(ap_id, (int)*MINOR_SEP); 1639 l_ap_id++; 1640 1641 if (strspn(l_ap_id, "0123456789.") != strlen(l_ap_id)) { 1642 /* Bad characters in the ap_id */ 1643 return (-1); 1644 } 1645 1646 if (strstr(l_ap_id, "..") != NULL) { 1647 /* ap_id has 1..2 or more than 2 dots */ 1648 return (-1); 1649 } 1650 1651 return (0); 1652 } 1653 1654 1655 1656 /* 1657 * Verify the params passed in are valid. 1658 */ 1659 static cfga_sata_ret_t 1660 verify_params( 1661 const char *ap_id, 1662 const char *options, 1663 char **errstring) 1664 { 1665 char *pdyn, *lap_id; 1666 int rv; 1667 1668 if (errstring != NULL) { 1669 *errstring = NULL; 1670 } 1671 1672 if (options != NULL) { 1673 return (CFGA_SATA_OPTIONS); 1674 } 1675 1676 /* Strip dynamic AP name component if it is present. */ 1677 lap_id = strdup(ap_id); 1678 if (lap_id == NULL) { 1679 return (CFGA_SATA_ALLOC_FAIL); 1680 } 1681 if ((pdyn = GET_DYN(lap_id)) != NULL) { 1682 *pdyn = '\0'; 1683 } 1684 1685 if (verify_valid_apid(lap_id) != 0) { 1686 rv = CFGA_SATA_AP; 1687 } else { 1688 rv = CFGA_SATA_OK; 1689 } 1690 free(lap_id); 1691 1692 return (rv); 1693 } 1694 1695 /* 1696 * Takes a validated ap_id and extracts the port number. 1697 * For now, we do not support port multiplier port . 1698 */ 1699 static cfga_sata_ret_t 1700 get_port_num(const char *ap_id, uint32_t *port) 1701 { 1702 char *port_nbr_str; 1703 char *temp; 1704 uint32_t cport; 1705 uint32_t pmport = 0; /* port multiplier not supported yet */ 1706 int pmport_qual = 0; /* port multiplier not supported yet */ 1707 1708 port_nbr_str = strrchr(ap_id, (int)*MINOR_SEP) + strlen(MINOR_SEP); 1709 if ((temp = strrchr(ap_id, (int)*PORT_SEPARATOR)) != 0) { 1710 port_nbr_str = temp + strlen(PORT_SEPARATOR); 1711 } 1712 1713 errno = 0; 1714 cport = strtol(port_nbr_str, NULL, 10); 1715 if ((cport & ~SATA_CFGA_CPORT_MASK) != 0 || errno != 0) 1716 return (CFGA_SATA_PORT); 1717 1718 *port = cport + (pmport << SATA_CFGA_PMPORT_SHIFT) + pmport_qual; 1719 1720 return (CFGA_SATA_OK); 1721 } 1722 1723 /* 1724 * Pair of routines to set up for/clean up after a devctl_ap_* lib call. 1725 */ 1726 static void 1727 cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist) 1728 { 1729 if (user_nvlist != NULL) { 1730 nvlist_free(user_nvlist); 1731 } 1732 if (devctl_hdl != NULL) { 1733 devctl_release(devctl_hdl); 1734 } 1735 } 1736 1737 static cfga_sata_ret_t 1738 setup_for_devctl_cmd( 1739 const char *ap_id, 1740 devctl_hdl_t *devctl_hdl, 1741 nvlist_t **user_nvlistp, 1742 uint_t oflag) 1743 { 1744 1745 uint_t port; 1746 cfga_sata_ret_t rv = CFGA_SATA_OK; 1747 char *lap_id, *pdyn; 1748 1749 lap_id = strdup(ap_id); 1750 if (lap_id == NULL) 1751 return (CFGA_SATA_ALLOC_FAIL); 1752 if ((pdyn = GET_DYN(lap_id)) != NULL) { 1753 *pdyn = '\0'; 1754 } 1755 1756 /* Get a devctl handle to pass to the devctl_ap_XXX functions */ 1757 if ((*devctl_hdl = devctl_ap_acquire((char *)lap_id, oflag)) == NULL) { 1758 (void) fprintf(stderr, "[libcfgadm:sata] " 1759 "setup_for_devctl_cmd: devctl_ap_acquire failed: %s\n", 1760 strerror(errno)); 1761 rv = CFGA_SATA_DEVCTL; 1762 goto bailout; 1763 } 1764 1765 /* Set up nvlist to pass the port number down to the driver */ 1766 if (nvlist_alloc(user_nvlistp, NV_UNIQUE_NAME_TYPE, NULL) != 0) { 1767 *user_nvlistp = NULL; 1768 rv = CFGA_SATA_NVLIST; 1769 (void) printf("nvlist_alloc failed\n"); 1770 goto bailout; 1771 } 1772 1773 /* 1774 * Get port id, for Port Multiplier port, things could be a little bit 1775 * complicated because of "port.port" format in ap_id, thus for 1776 * port multiplier port, port number should be coded as 32bit int 1777 * with the sig 16 bit as sata channel number, least 16 bit as 1778 * the port number of sata port multiplier port. 1779 */ 1780 if ((rv = get_port_num(lap_id, &port)) != CFGA_SATA_OK) { 1781 (void) printf( 1782 "setup_for_devctl_cmd: get_port_num, errno: %d\n", 1783 errno); 1784 goto bailout; 1785 } 1786 1787 /* Creates an int32_t entry */ 1788 if (nvlist_add_int32(*user_nvlistp, PORT, port) == -1) { 1789 (void) printf("nvlist_add_int32 failed\n"); 1790 rv = CFGA_SATA_NVLIST; 1791 goto bailout; 1792 } 1793 1794 free(lap_id); 1795 return (rv); 1796 1797 bailout: 1798 free(lap_id); 1799 (void) cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp); 1800 1801 return (rv); 1802 } 1803 1804 1805 static cfga_sata_ret_t 1806 port_state(devctl_hdl_t hdl, nvlist_t *list, 1807 ap_rstate_t *rstate, ap_ostate_t *ostate) 1808 { 1809 devctl_ap_state_t devctl_ap_state; 1810 1811 if (devctl_ap_getstate(hdl, list, &devctl_ap_state) == -1) { 1812 (void) printf("devctl_ap_getstate failed, errno: %d\n", errno); 1813 return (CFGA_SATA_IOCTL); 1814 } 1815 *rstate = devctl_ap_state.ap_rstate; 1816 *ostate = devctl_ap_state.ap_ostate; 1817 return (CFGA_SATA_OK); 1818 } 1819 1820 1821 /* 1822 * Given a subcommand to the DEVCTL_AP_CONTROL ioctl, rquest the size of 1823 * the data to be returned, allocate a buffer, then get the data. 1824 * Returns *descrp (which must be freed) and size. 1825 * 1826 * Note SATA_DESCR_TYPE_STRING returns an ASCII NULL-terminated string, 1827 * not a string descr. 1828 */ 1829 cfga_sata_ret_t 1830 do_control_ioctl(const char *ap_id, sata_cfga_apctl_t subcommand, uint_t arg, 1831 void **descrp, size_t *sizep) 1832 { 1833 int fd = -1; 1834 uint_t port; 1835 uint32_t local_size; 1836 cfga_sata_ret_t rv = CFGA_SATA_OK; 1837 struct sata_ioctl_data ioctl_data; 1838 1839 assert(descrp != NULL); 1840 *descrp = NULL; 1841 assert(sizep != NULL); 1842 1843 if ((rv = get_port_num(ap_id, &port)) != CFGA_SATA_OK) { 1844 goto bailout; 1845 } 1846 1847 if ((fd = open(ap_id, O_RDONLY)) == -1) { 1848 (void) printf("do_control_ioctl: open failed: errno:%d\n", 1849 errno); 1850 rv = CFGA_SATA_OPEN; 1851 if (errno == EBUSY) { 1852 rv = CFGA_SATA_BUSY; 1853 } 1854 goto bailout; 1855 } 1856 1857 ioctl_data.cmd = subcommand; 1858 ioctl_data.port = port; 1859 ioctl_data.misc_arg = (uint_t)arg; 1860 1861 /* 1862 * Find out how large a buf we need to get the data. 1863 * Note the ioctls only accept/return a 32-bit int for a get_size 1864 * to avoid 32/64 and BE/LE issues. 1865 */ 1866 if ((subcommand == SATA_CFGA_GET_AP_TYPE) || 1867 (subcommand == SATA_CFGA_GET_DEVICE_PATH) || 1868 (subcommand == SATA_CFGA_GET_MODEL_INFO) || 1869 (subcommand == SATA_CFGA_GET_REVFIRMWARE_INFO) || 1870 (subcommand == SATA_CFGA_GET_SERIALNUMBER_INFO)) { 1871 ioctl_data.get_size = B_TRUE; 1872 ioctl_data.buf = (caddr_t)&local_size; 1873 ioctl_data.bufsiz = sizeof (local_size); 1874 1875 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) { 1876 perror("ioctl failed (size)"); 1877 rv = CFGA_SATA_IOCTL; 1878 goto bailout; 1879 } 1880 *sizep = local_size; 1881 1882 if (local_size == 0) { 1883 (void) printf("zero length data\n"); 1884 rv = CFGA_SATA_ZEROLEN; 1885 goto bailout; 1886 } 1887 if ((*descrp = malloc(*sizep)) == NULL) { 1888 (void) printf("do_control_ioctl: malloc failed\n"); 1889 rv = CFGA_SATA_ALLOC_FAIL; 1890 goto bailout; 1891 } 1892 } else { 1893 *sizep = 0; 1894 } 1895 ioctl_data.get_size = B_FALSE; 1896 ioctl_data.buf = *descrp; 1897 ioctl_data.bufsiz = *sizep; 1898 1899 /* Execute IOCTL */ 1900 1901 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) { 1902 rv = CFGA_SATA_IOCTL; 1903 goto bailout; 1904 } 1905 1906 (void) close(fd); 1907 1908 return (rv); 1909 1910 bailout: 1911 if (fd != -1) { 1912 (void) close(fd); 1913 } 1914 if (*descrp != NULL) { 1915 free(*descrp); 1916 *descrp = NULL; 1917 } 1918 1919 if (rv == CFGA_SATA_IOCTL && errno == EBUSY) { 1920 rv = CFGA_SATA_BUSY; 1921 } 1922 1923 return (rv); 1924 } 1925 1926 1927 static int 1928 sata_confirm(struct cfga_confirm *confp, char *msg) 1929 { 1930 int rval; 1931 1932 if (confp == NULL || confp->confirm == NULL) { 1933 return (0); 1934 } 1935 rval = (*confp->confirm)(confp->appdata_ptr, msg); 1936 1937 return (rval); 1938 } 1939 1940 1941 static char * 1942 sata_get_devicepath(const char *ap_id) 1943 { 1944 char *devpath = NULL; 1945 size_t size; 1946 cfga_sata_ret_t rv; 1947 1948 rv = do_control_ioctl(ap_id, SATA_CFGA_GET_DEVICE_PATH, NULL, 1949 (void **)&devpath, &size); 1950 1951 if (rv == CFGA_SATA_OK) { 1952 return (devpath); 1953 } else { 1954 return ((char *)NULL); 1955 } 1956 1957 } 1958