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