8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / cfgadm_plugins / sata / common / cfga_sata.c
blob29f059b2db69e02ef662f1f2f688a40f3cb34b0a
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/param.h>
28 #include <sys/stat.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <dirent.h>
32 #include "cfga_sata.h"
35 * This file contains the entry points to the plug-in as defined in the
36 * config_admin(3X) man page.
40 * Set the version number for the cfgadm library's use.
42 int cfga_version = CFGA_HSL_V2;
44 enum {
45 HELP_HEADER = 1,
46 HELP_CONFIG,
47 HELP_RESET_PORT,
48 HELP_RESET_DEVICE,
49 HELP_RESET_ALL,
50 HELP_PORT_DEACTIVATE,
51 HELP_PORT_ACTIVATE,
52 HELP_PORT_SELF_TEST,
53 HELP_CNTRL_SELF_TEST,
54 HELP_UNKNOWN
57 /* SATA specific help messages */
58 static char *sata_help[] = {
59 NULL,
60 "SATA specific commands:\n",
61 " cfgadm -c [configure|unconfigure|disconnect|connect] ap_id "
62 "[ap_id...]\n",
63 " cfgadm -x sata_reset_port ap_id [ap_id...]\n",
64 " cfgadm -x sata_reset_device ap_id [ap_id...]\n",
65 " cfgadm -x sata_reset_all ap_id\n",
66 " cfgadm -x sata_port_deactivate ap_id [ap_id...]\n",
67 " cfgadm -x sata_port_activate ap_id [ap_id...]\n",
68 " cfgadm -x sata_port_self_test ap_id [ap_id...]\n",
69 " cfgadm -t ap_id\n",
70 "\tunknown command or option:\n",
71 NULL
72 }; /* End help messages */
76 * Messages.
78 static msgcvt_t sata_msgs[] = {
79 /* CFGA_SATA_OK */
80 { CVT, CFGA_OK, "" },
82 /* CFGA_SATA_NACK */
83 { CVT, CFGA_NACK, "" },
85 /* CFGA_SATA_DEVICE_UNCONFIGURED */
86 { CVT, CFGA_OK, "Device unconfigured prior to disconnect" },
88 /* CFGA_SATA_UNKNOWN / CFGA_LIB_ERROR -> "Library error" */
89 { CVT, CFGA_LIB_ERROR, "Unknown message; internal error" },
91 /* CFGA_SATA_INTERNAL_ERROR / CFGA_LIB_ERROR -> "Library error" */
92 { CVT, CFGA_LIB_ERROR, "Internal error" },
94 /* CFGA_SATA_DATA_ERROR / CFGA_DATA_ERROR -> "Data error" */
95 { CVT, CFGA_DATA_ERROR, "cfgadm data error" },
97 /* CFGA_SATA_OPTIONS / CFGA_ERROR -> "Hardware specific failure" */
98 { CVT, CFGA_ERROR, "Hardware specific option not supported" },
100 /* CFGA_SATA_HWOPNOTSUPP / CFGA_ERROR -> "Hardware specific failure" */
101 { CVT, CFGA_ERROR, "Hardware specific operation not supported" },
104 * CFGA_SATA_DYNAMIC_AP /
105 * CFGA_LIB_ERROR -> "Configuration operation invalid"
107 { CVT, CFGA_INVAL, "Cannot identify attached device" },
109 /* CFGA_SATA_AP / CFGA_APID_NOEXIST -> "Attachment point not found" */
110 { CVT, CFGA_APID_NOEXIST, "" },
112 /* CFGA_SATA_PORT / CFGA_LIB_ERROR -> "Library error" */
113 { CVT, CFGA_LIB_ERROR, "Cannot determine sata port number for " },
115 /* CFGA_SATA_DEVCTL / CFGA_LIB_ERROR -> "Library error" */
116 { CVT, CFGA_LIB_ERROR, "Internal error: "
117 "Cannot allocate devctl handle " },
120 * CFGA_SATA_DEV_CONFIGURE /
121 * CFGA_ERROR -> "Hardware specific failure"
123 { CVT, CFGA_ERROR, "Failed to config device at " },
126 * CFGA_SATA_DEV_UNCONFIGURE /
127 * CFGA_ERROR -> "Hardware specific failure"
129 { CVT, CFGA_ERROR, "Failed to unconfig device at " },
132 * CFGA_SATA_DISCONNECTED
133 * CFGA_INVAL -> "Configuration operation invalid"
135 { CVT, CFGA_INVAL, "Port already disconnected " },
138 * CFGA_SATA_NOT_CONNECTED
139 * CFGA_INVAL -> "Configuration operation invalid"
141 { CVT, CFGA_INVAL, "No device connected to " },
144 * CFGA_SATA_NOT_CONFIGURED /
145 * CFGA_INVAL -> "Configuration operation invalid"
147 { CVT, CFGA_INVAL, "No device configured at " },
150 * CFGA_SATA_ALREADY_CONNECTED /
151 * CFGA_INVAL -> "Configuration operation invalid"
153 { CVT, CFGA_INVAL, "Device already connected to " },
156 * CFGA_SATA_ALREADY_CONFIGURED /
157 * CFGA_INVAL -> "Configuration operation invalid"
159 { CVT, CFGA_INVAL, "Device already configured at " },
162 * CFGA_SATA_INVALID_DEVNAME /
163 * CFGA_INVAL -> "Configuration operation invalid"
165 { CVT, CFGA_INVAL, "Cannot specify device name" },
167 /* CFGA_SATA_OPEN / CFGA_LIB_ERROR -> "Library error" */
168 { CVT, CFGA_LIB_ERROR, "Cannot open " },
170 /* CFGA_SATA_IOCTL / CFGA_ERROR -> "Hardware specific failure" */
171 { CVT, CFGA_ERROR, "Driver ioctl failed " },
174 * CFGA_SATA_BUSY /
175 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
177 { CVT, CFGA_SYSTEM_BUSY, "" },
179 /* CFGA_SATA_ALLOC_FAIL / CFGA_LIB_ERROR -> "Library error" */
180 { CVT, CFGA_LIB_ERROR, "Memory allocation failure" },
183 * CFGA_SATA_OPNOTSUPP /
184 * CFGA_OPNOTSUPP -> "Configuration operation not supported"
186 { CVT, CFGA_OPNOTSUPP, "Operation not supported" },
188 /* CFGA_SATA_DEVLINK / CFGA_LIB_ERROR -> "Library error" */
189 { CVT, CFGA_LIB_ERROR, "Could not find /dev/cfg link for " },
191 /* CFGA_SATA_STATE / CFGA_LIB_ERROR -> "Library error" */
192 { CVT, CFGA_LIB_ERROR, "Internal error: Unrecognized ap state" },
194 /* CFGA_SATA_PRIV / CFGA_PRIV -> "Insufficient privileges" */
195 { CVT, CFGA_PRIV, "" },
197 /* CFGA_SATA_NVLIST / CFGA_ERROR -> "Hardware specific failure" */
198 { CVT, CFGA_ERROR, "Internal error (nvlist)" },
200 /* CFGA_SATA_ZEROLEN / CFGA_ERROR -> "Hardware specific failure" */
201 { CVT, CFGA_ERROR, "Internal error (zerolength string)" },
203 /* CFGA_SATA_RCM_HANDLE / CFGA_ERROR -> "Hardware specific failure" */
204 { CVT, CFGA_ERROR, "cannot get RCM handle"},
207 * CFGA_SATA_RCM_ONLINE /
208 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
210 { CVT, CFGA_SYSTEM_BUSY, "failed to online: "},
213 * CFGA_SATA_RCM_OFFLINE /
214 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
216 { CVT, CFGA_SYSTEM_BUSY, "failed to offline: "},
218 /* CFGA_SATA_RCM_INFO / CFGA_ERROR -> "Hardware specific failure" */
219 { CVT, CFGA_ERROR, "failed to query: "}
221 }; /* End error messages */
223 static cfga_sata_ret_t
224 verify_params(const char *ap_id, const char *options, char **errstring);
227 static cfga_sata_ret_t
228 setup_for_devctl_cmd(const char *ap_id, devctl_hdl_t *devctl_hdl,
229 nvlist_t **user_nvlistp, uint_t oflag);
231 static cfga_sata_ret_t
232 port_state(devctl_hdl_t hdl, nvlist_t *list,
233 ap_rstate_t *rstate, ap_ostate_t *ostate);
235 static cfga_sata_ret_t
236 do_control_ioctl(const char *ap_id, sata_cfga_apctl_t subcommand, uint_t arg,
237 void **descrp, size_t *sizep);
239 static void
240 cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist);
242 static char *
243 sata_get_devicepath(const char *ap_id);
245 static int
246 sata_confirm(struct cfga_confirm *confp, char *msg);
248 static cfga_sata_ret_t
249 get_port_num(const char *ap_id, uint32_t *port);
251 /* Utilities */
253 static cfga_sata_ret_t
254 physpath_to_devlink(const char *basedir, const char *node_path,
255 char **logpp, int *l_errnop)
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;
270 * Using libdevinfo for this is overkill and kills performance
271 * when multiple consumers of libcfgadm are executing
272 * concurrently.
274 if ((dp = opendir(basedir)) == NULL) {
275 *l_errnop = errno;
276 return (CFGA_SATA_INTERNAL_ERROR);
279 linkpath = malloc(PATH_MAX);
280 buf = malloc(PATH_MAX);
281 real_path = malloc(PATH_MAX);
283 deplen = pathconf(basedir, _PC_NAME_MAX);
284 deplen = (deplen <= 0 ? MAXNAMELEN : deplen) +
285 sizeof (struct dirent);
286 dep = (struct dirent *)malloc(deplen);
288 if (dep == NULL || linkpath == NULL || buf == NULL ||
289 real_path == NULL) {
290 *l_errnop = ENOMEM;
291 rv = CFGA_SATA_ALLOC_FAIL;
292 goto pp_cleanup;
295 *logpp = NULL;
297 while (!found && (err = readdir_r(dp, dep, &newdep)) == 0 &&
298 newdep != NULL) {
300 assert(newdep == dep);
302 if (strcmp(dep->d_name, ".") == 0 ||
303 strcmp(dep->d_name, "..") == 0)
304 continue;
306 (void) snprintf(linkpath, MAXPATHLEN,
307 "%s/%s", basedir, dep->d_name);
309 if (lstat(linkpath, &sb) < 0)
310 continue;
312 if (S_ISDIR(sb.st_mode)) {
314 if ((rv = physpath_to_devlink(linkpath, node_path,
315 logpp, l_errnop)) != CFGA_SATA_OK) {
317 goto pp_cleanup;
320 if (*logpp != NULL)
321 found = B_TRUE;
323 } else if (S_ISLNK(sb.st_mode)) {
325 bzero(buf, PATH_MAX);
326 if (readlink(linkpath, buf, PATH_MAX) < 0)
327 continue;
331 * realpath() is too darn slow, so fake
332 * it, by using what we know about /dev
333 * links: they are always of the form:
334 * <"../">+/devices/<path>
336 p = buf;
337 while (strncmp(p, "../", 3) == 0)
338 p += 3;
340 if (p != buf)
341 p--; /* back up to get a slash */
343 assert (*p == '/');
345 if (strcmp(p, node_path) == 0) {
346 *logpp = strdup(linkpath);
347 if (*logpp == NULL) {
349 rv = CFGA_SATA_ALLOC_FAIL;
350 goto pp_cleanup;
353 found = B_TRUE;
358 free(linkpath);
359 free(buf);
360 free(real_path);
361 free(dep);
362 (void) closedir(dp);
364 if (err != 0) {
365 *l_errnop = err;
366 return (CFGA_SATA_INTERNAL_ERROR);
369 return (CFGA_SATA_OK);
371 pp_cleanup:
373 if (dp)
374 (void) closedir(dp);
375 if (dep)
376 free(dep);
377 if (linkpath)
378 free(linkpath);
379 if (buf)
380 free(buf);
381 if (real_path)
382 free(real_path);
383 if (*logpp) {
384 free(*logpp);
385 *logpp = NULL;
387 return (rv);
392 * Given the index into a table (msgcvt_t) of messages, get the message
393 * string, converting it to the proper locale if necessary.
394 * NOTE: Indexes are defined in cfga_sata.h
396 static const char *
397 get_msg(uint_t msg_index, msgcvt_t *msg_tbl, uint_t tbl_size)
399 if (msg_index >= tbl_size) {
400 msg_index = CFGA_SATA_UNKNOWN;
403 return ((msg_tbl[msg_index].intl) ?
404 dgettext(TEXT_DOMAIN, msg_tbl[msg_index].msgstr) :
405 msg_tbl[msg_index].msgstr);
409 * Allocates and creates a message string (in *ret_str),
410 * by concatenating all the (char *) args together, in order.
411 * Last arg MUST be NULL.
413 static void
414 set_msg(char **ret_str, ...)
416 char *str;
417 size_t total_len;
418 va_list valist;
420 va_start(valist, ret_str);
422 total_len = (*ret_str == NULL) ? 0 : strlen(*ret_str);
424 while ((str = va_arg(valist, char *)) != NULL) {
425 size_t len = strlen(str);
426 char *old_str = *ret_str;
428 *ret_str = (char *)realloc(*ret_str, total_len + len + 1);
429 if (*ret_str == NULL) {
430 /* We're screwed */
431 free(old_str);
432 va_end(valist);
433 return;
436 (void) strcpy(*ret_str + total_len, str);
437 total_len += len;
440 va_end(valist);
444 * Error message handling.
445 * For the rv passed in, looks up the corresponding error message string(s),
446 * internationalized if necessary, and concatenates it into a new
447 * memory buffer, and points *errstring to it.
448 * Note not all rvs will result in an error message return, as not all
449 * error conditions warrant a SATA-specific error message - for those
450 * conditions the cfgadm generic messages are sufficient.
452 * Some messages may display ap_id or errno, which is why they are passed
453 * in.
456 cfga_err_t
457 sata_err_msg(
458 char **errstring,
459 cfga_sata_ret_t rv,
460 const char *ap_id,
461 int l_errno)
463 if (errstring == NULL) {
464 return (sata_msgs[rv].cfga_err);
468 * Generate the appropriate SATA-specific error message(s) (if any).
470 switch (rv) {
471 case CFGA_SATA_OK:
472 case CFGA_NACK:
473 /* Special case - do nothing. */
474 break;
476 case CFGA_SATA_UNKNOWN:
477 case CFGA_SATA_DYNAMIC_AP:
478 case CFGA_SATA_INTERNAL_ERROR:
479 case CFGA_SATA_OPTIONS:
480 case CFGA_SATA_ALLOC_FAIL:
481 case CFGA_SATA_STATE:
482 case CFGA_SATA_PRIV:
483 case CFGA_SATA_OPNOTSUPP:
484 case CFGA_SATA_DATA_ERROR:
485 /* These messages require no additional strings passed. */
486 set_msg(errstring, ERR_STR(rv), NULL);
487 break;
489 case CFGA_SATA_HWOPNOTSUPP:
490 /* hardware-specific help needed */
491 set_msg(errstring, ERR_STR(rv), NULL);
492 set_msg(errstring, "\n",
493 dgettext(TEXT_DOMAIN, sata_help[HELP_HEADER]), NULL);
494 set_msg(errstring, sata_help[HELP_RESET_PORT], NULL);
495 set_msg(errstring, sata_help[HELP_RESET_DEVICE], NULL);
496 set_msg(errstring, sata_help[HELP_RESET_ALL], NULL);
497 set_msg(errstring, sata_help[HELP_PORT_ACTIVATE], NULL);
498 set_msg(errstring, sata_help[HELP_PORT_DEACTIVATE], NULL);
499 set_msg(errstring, sata_help[HELP_PORT_SELF_TEST], NULL);
500 set_msg(errstring, sata_help[HELP_CNTRL_SELF_TEST], NULL);
501 break;
503 case CFGA_SATA_AP:
504 case CFGA_SATA_PORT:
505 case CFGA_SATA_NOT_CONNECTED:
506 case CFGA_SATA_NOT_CONFIGURED:
507 case CFGA_SATA_ALREADY_CONNECTED:
508 case CFGA_SATA_ALREADY_CONFIGURED:
509 case CFGA_SATA_BUSY:
510 case CFGA_SATA_DEVLINK:
511 case CFGA_SATA_RCM_HANDLE:
512 case CFGA_SATA_RCM_ONLINE:
513 case CFGA_SATA_RCM_OFFLINE:
514 case CFGA_SATA_RCM_INFO:
515 case CFGA_SATA_DEV_CONFIGURE:
516 case CFGA_SATA_DEV_UNCONFIGURE:
517 case CFGA_SATA_DISCONNECTED:
518 /* These messages also print ap_id. */
519 set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "", NULL);
520 break;
523 case CFGA_SATA_IOCTL:
524 case CFGA_SATA_NVLIST:
525 /* These messages also print errno. */
527 char *errno_str = l_errno ? strerror(l_errno) : "";
529 set_msg(errstring, ERR_STR(rv), errno_str,
530 l_errno ? "\n" : "", NULL);
531 break;
534 case CFGA_SATA_OPEN:
535 /* These messages also apid and errno. */
537 char *errno_str = l_errno ? strerror(l_errno) : "";
539 set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "\n",
540 errno_str, l_errno ? "\n" : "", NULL);
541 break;
544 default:
545 set_msg(errstring, ERR_STR(CFGA_SATA_INTERNAL_ERROR), NULL);
547 } /* end switch */
551 * Determine the proper error code to send back to the cfgadm library.
553 return (sata_msgs[rv].cfga_err);
558 * Entry points
560 /* cfgadm entry point */
561 /*ARGSUSED*/
562 cfga_err_t
563 cfga_change_state(
564 cfga_cmd_t state_change_cmd,
565 const char *ap_id,
566 const char *options,
567 struct cfga_confirm *confp,
568 struct cfga_msg *msgp,
569 char **errstring,
570 cfga_flags_t flags)
572 int ret;
573 int len;
574 char *msg;
575 char *devpath;
576 nvlist_t *nvl = NULL;
577 ap_rstate_t rstate;
578 ap_ostate_t ostate;
579 devctl_hdl_t hdl = NULL;
580 cfga_sata_ret_t rv = CFGA_SATA_OK;
581 char *pdyn;
582 char *str_type;
583 size_t size;
584 boolean_t pmult = B_FALSE;
587 * All sub-commands which can change state of device require
588 * root privileges.
590 if (geteuid() != 0) {
591 rv = CFGA_SATA_PRIV;
592 goto bailout;
595 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) {
596 (void) cfga_help(msgp, options, flags);
597 goto bailout;
600 if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &nvl,
601 DC_RDONLY)) != CFGA_SATA_OK) {
602 goto bailout;
606 * Checking device type. A port multiplier is not configurable - it is
607 * already configured as soon as it is connected.
609 if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, NULL,
610 (void **)&str_type, &size)) != CFGA_SATA_OK) {
611 /* no such deivce */
612 goto bailout;
614 if (strncmp(str_type, "sata-pmult", sizeof ("sata-pmult")) == 0) {
615 pmult = B_TRUE;
618 switch (state_change_cmd) {
619 case CFGA_CMD_CONFIGURE:
620 if (pmult == B_TRUE) {
621 rv = CFGA_SATA_HWOPNOTSUPP;
622 goto bailout;
625 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
626 CFGA_SATA_OK)
627 goto bailout;
629 if (ostate == AP_OSTATE_CONFIGURED) {
630 rv = CFGA_SATA_ALREADY_CONFIGURED;
631 goto bailout;
633 /* Disallow dynamic AP name component */
634 if (GET_DYN(ap_id) != NULL) {
635 rv = CFGA_SATA_INVALID_DEVNAME;
636 goto bailout;
639 if (rstate == AP_RSTATE_EMPTY) {
640 rv = CFGA_SATA_NOT_CONNECTED;
641 goto bailout;
643 rv = CFGA_SATA_OK;
645 if (devctl_ap_configure(hdl, nvl) != 0) {
646 rv = CFGA_SATA_DEV_CONFIGURE;
647 goto bailout;
650 devpath = sata_get_devicepath(ap_id);
651 if (devpath == NULL) {
652 int i;
654 * Try for some time as SATA hotplug thread
655 * takes a while to create the path then
656 * eventually give up.
658 for (i = 0; i < 12 && (devpath == NULL); i++) {
659 (void) sleep(6);
660 devpath = sata_get_devicepath(ap_id);
663 if (devpath == NULL) {
664 rv = CFGA_SATA_DEV_CONFIGURE;
665 break;
669 S_FREE(devpath);
670 break;
672 case CFGA_CMD_UNCONFIGURE:
673 if (pmult == B_TRUE) {
674 rv = CFGA_SATA_HWOPNOTSUPP;
675 goto bailout;
678 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
679 CFGA_SATA_OK)
680 goto bailout;
682 if (rstate != AP_RSTATE_CONNECTED) {
683 rv = CFGA_SATA_NOT_CONNECTED;
684 goto bailout;
687 if (ostate != AP_OSTATE_CONFIGURED) {
688 rv = CFGA_SATA_NOT_CONFIGURED;
689 goto bailout;
691 /* Strip off AP name dynamic component, if present */
692 if ((pdyn = GET_DYN(ap_id)) != NULL) {
693 *pdyn = '\0';
696 rv = CFGA_SATA_OK;
698 len = strlen(SATA_CONFIRM_DEVICE) +
699 strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
700 strlen("Unconfigure") + strlen(ap_id);
701 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
702 (void) snprintf(msg, len + 3, "Unconfigure"
703 " %s%s\n%s",
704 SATA_CONFIRM_DEVICE, ap_id,
705 SATA_CONFIRM_DEVICE_SUSPEND);
708 if (!sata_confirm(confp, msg)) {
709 free(msg);
710 rv = CFGA_SATA_NACK;
711 break;
713 free(msg);
715 devpath = sata_get_devicepath(ap_id);
716 if (devpath == NULL) {
717 (void) printf(
718 "cfga_change_state: get device path failed\n");
719 rv = CFGA_SATA_DEV_UNCONFIGURE;
720 break;
723 if ((rv = sata_rcm_offline(ap_id, errstring, devpath, flags))
724 != CFGA_SATA_OK) {
725 break;
728 ret = devctl_ap_unconfigure(hdl, nvl);
730 if (ret != 0) {
731 rv = CFGA_SATA_DEV_UNCONFIGURE;
732 if (errno == EBUSY) {
733 rv = CFGA_SATA_BUSY;
735 (void) sata_rcm_online(ap_id, errstring, devpath,
736 flags);
737 } else {
738 (void) sata_rcm_remove(ap_id, errstring, devpath,
739 flags);
742 S_FREE(devpath);
744 break;
746 case CFGA_CMD_DISCONNECT:
747 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
748 CFGA_SATA_OK)
749 goto bailout;
751 if (rstate == AP_RSTATE_DISCONNECTED) {
752 rv = CFGA_SATA_DISCONNECTED;
753 goto bailout;
756 /* Strip off AP name dynamic component, if present */
757 if ((pdyn = GET_DYN(ap_id)) != NULL) {
758 *pdyn = '\0';
762 rv = CFGA_SATA_OK; /* other statuses don't matter */
765 * If the port originally with device attached and was
766 * unconfigured already, the devicepath for the sd will be
767 * removed. sata_get_devicepath in this case is not necessary.
769 /* only call rcm_offline if the state was CONFIGURED */
770 if (ostate == AP_OSTATE_CONFIGURED &&
771 pmult == B_FALSE) {
772 devpath = sata_get_devicepath(ap_id);
773 if (devpath == NULL) {
774 (void) printf(
775 "cfga_change_state: get path failed\n");
776 rv = CFGA_SATA_DEV_UNCONFIGURE;
777 break;
780 len = strlen(SATA_CONFIRM_DEVICE) +
781 strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
782 strlen("Disconnect") + strlen(ap_id);
783 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
784 (void) snprintf(msg, len + 3,
785 "Disconnect"
786 " %s%s\n%s",
787 SATA_CONFIRM_DEVICE, ap_id,
788 SATA_CONFIRM_DEVICE_SUSPEND);
790 if (!sata_confirm(confp, msg)) {
791 free(msg);
792 rv = CFGA_SATA_NACK;
793 break;
795 free(msg);
797 if ((rv = sata_rcm_offline(ap_id, errstring,
798 devpath, flags)) != CFGA_SATA_OK) {
799 break;
802 ret = devctl_ap_unconfigure(hdl, nvl);
803 if (ret != 0) {
804 (void) printf(
805 "devctl_ap_unconfigure failed\n");
806 rv = CFGA_SATA_DEV_UNCONFIGURE;
807 if (errno == EBUSY)
808 rv = CFGA_SATA_BUSY;
809 (void) sata_rcm_online(ap_id, errstring,
810 devpath, flags);
811 S_FREE(devpath);
814 * The current policy is that if unconfigure
815 * failed, do not continue with disconnect.
816 * If the port needs to be forced into the
817 * disconnect (shutdown) state,
818 * the -x sata_port_poweroff command should be
819 * used instead of -c disconnect
821 break;
822 } else {
823 (void) printf("%s\n",
824 ERR_STR(CFGA_SATA_DEVICE_UNCONFIGURED));
825 (void) sata_rcm_remove(ap_id, errstring,
826 devpath, flags);
828 S_FREE(devpath);
829 } else if (rstate == AP_RSTATE_CONNECTED ||
830 rstate == AP_RSTATE_EMPTY) {
831 len = strlen(SATA_CONFIRM_PORT) +
832 strlen(SATA_CONFIRM_PORT_DISABLE) +
833 strlen("Deactivate Port") + strlen(ap_id);
834 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
835 (void) snprintf(msg, len +3,
836 "Disconnect"
837 " %s%s\n%s",
838 SATA_CONFIRM_PORT, ap_id,
839 SATA_CONFIRM_PORT_DISABLE);
841 if (!sata_confirm(confp, msg)) {
842 free(msg);
843 rv = CFGA_SATA_NACK;
844 break;
847 ret = devctl_ap_disconnect(hdl, nvl);
848 if (ret != 0) {
849 rv = CFGA_SATA_IOCTL;
850 if (errno == EBUSY) {
851 rv = CFGA_SATA_BUSY;
854 break;
856 case CFGA_CMD_CONNECT:
857 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
858 CFGA_SATA_OK)
859 goto bailout;
861 if (rstate == AP_RSTATE_CONNECTED) {
862 rv = CFGA_SATA_ALREADY_CONNECTED;
863 goto bailout;
866 len = strlen(SATA_CONFIRM_PORT) +
867 strlen(SATA_CONFIRM_PORT_ENABLE) +
868 strlen("Activate Port") + strlen(ap_id);
869 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
870 (void) snprintf(msg, len +3, "Activate"
871 " %s%s\n%s",
872 SATA_CONFIRM_PORT, ap_id,
873 SATA_CONFIRM_PORT_ENABLE);
875 if (!sata_confirm(confp, msg)) {
876 rv = CFGA_SATA_NACK;
877 break;
880 /* Disallow dynamic AP name component */
881 if (GET_DYN(ap_id) != NULL) {
882 rv = CFGA_SATA_INVALID_DEVNAME;
883 goto bailout;
886 ret = devctl_ap_connect(hdl, nvl);
887 if (ret != 0) {
888 rv = CFGA_SATA_IOCTL;
889 } else {
890 rv = CFGA_SATA_OK;
893 break;
895 case CFGA_CMD_LOAD:
896 case CFGA_CMD_UNLOAD:
897 (void) cfga_help(msgp, options, flags);
898 rv = CFGA_SATA_OPNOTSUPP;
899 break;
901 case CFGA_CMD_NONE:
902 default:
903 (void) cfga_help(msgp, options, flags);
904 rv = CFGA_SATA_INTERNAL_ERROR;
907 bailout:
908 cleanup_after_devctl_cmd(hdl, nvl);
910 return (sata_err_msg(errstring, rv, ap_id, errno));
913 /* cfgadm entry point */
914 cfga_err_t
915 cfga_private_func(
916 const char *func,
917 const char *ap_id,
918 const char *options,
919 struct cfga_confirm *confp,
920 struct cfga_msg *msgp,
921 char **errstring,
922 cfga_flags_t flags)
924 int len;
925 char *msg;
926 nvlist_t *list = NULL;
927 ap_ostate_t ostate;
928 ap_rstate_t rstate;
929 devctl_hdl_t hdl = NULL;
930 cfga_sata_ret_t rv;
931 char *str_p;
932 size_t size;
934 if ((rv = verify_params(ap_id, NULL, errstring)) != CFGA_SATA_OK) {
935 (void) cfga_help(msgp, options, flags);
936 return (sata_err_msg(errstring, rv, ap_id, errno));
940 * All subcommands which can change state of device require
941 * root privileges.
943 if (geteuid() != 0) {
944 rv = CFGA_SATA_PRIV;
945 goto bailout;
948 if (func == NULL) {
949 (void) printf("No valid option specified\n");
950 rv = CFGA_SATA_OPTIONS;
951 goto bailout;
954 if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &list, 0)) !=
955 CFGA_SATA_OK) {
956 goto bailout;
959 /* We do not care here about dynamic AP name component */
960 if ((str_p = GET_DYN(ap_id)) != NULL) {
961 *str_p = '\0';
964 rv = CFGA_SATA_OK;
966 if (strcmp(func, SATA_RESET_PORT) == 0) {
967 len = strlen(SATA_CONFIRM_PORT) +
968 strlen(SATA_CONFIRM_DEVICE_ABORT) +
969 strlen("Reset Port") + strlen(ap_id);
971 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
972 (void) snprintf(msg, len +3, "Reset"
973 " %s%s\n%s",
974 SATA_CONFIRM_PORT, ap_id,
975 SATA_CONFIRM_DEVICE_ABORT);
976 } else {
977 rv = CFGA_SATA_NACK;
978 goto bailout;
981 if (!sata_confirm(confp, msg)) {
982 rv = CFGA_SATA_NACK;
983 goto bailout;
986 rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_PORT, NULL,
987 (void **)&str_p, &size);
989 } else if (strcmp(func, SATA_RESET_DEVICE) == 0) {
990 if ((rv = port_state(hdl, list, &rstate, &ostate)) !=
991 CFGA_SATA_OK)
992 goto bailout;
994 * Reset device function requires device to be connected
996 if (rstate != AP_RSTATE_CONNECTED) {
997 rv = CFGA_SATA_NOT_CONNECTED;
998 goto bailout;
1001 len = strlen(SATA_CONFIRM_DEVICE) +
1002 strlen(SATA_CONFIRM_DEVICE_ABORT) +
1003 strlen("Reset Device") + strlen(ap_id);
1005 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1006 (void) snprintf(msg, len +3, "Reset"
1007 " %s%s\n%s",
1008 SATA_CONFIRM_DEVICE, ap_id,
1009 SATA_CONFIRM_DEVICE_ABORT);
1010 } else {
1011 rv = CFGA_SATA_NACK;
1012 goto bailout;
1015 if (!sata_confirm(confp, msg)) {
1016 rv = CFGA_SATA_NACK;
1017 goto bailout;
1020 rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_DEVICE, NULL,
1021 (void **)&str_p, &size);
1023 } else if (strcmp(func, SATA_RESET_ALL) == 0) {
1024 len = strlen(SATA_CONFIRM_CONTROLLER) +
1025 strlen(SATA_CONFIRM_CONTROLLER_ABORT) +
1026 strlen("Reset All") + strlen(ap_id);
1028 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1029 (void) snprintf(msg, len +3, "Reset"
1030 " %s%s\n%s",
1031 SATA_CONFIRM_CONTROLLER, ap_id,
1032 SATA_CONFIRM_CONTROLLER_ABORT);
1033 } else {
1034 rv = CFGA_SATA_NACK;
1035 goto bailout;
1038 if (!sata_confirm(confp, msg)) {
1039 rv = CFGA_SATA_NACK;
1040 goto bailout;
1042 rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_ALL, NULL,
1043 (void **)&str_p, &size);
1045 } else if (strcmp(func, SATA_PORT_DEACTIVATE) == 0) {
1046 len = strlen(SATA_CONFIRM_PORT) +
1047 strlen(SATA_CONFIRM_PORT_DISABLE) +
1048 strlen("Deactivate Port") + strlen(ap_id);
1050 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1051 (void) snprintf(msg, len +3, "Deactivate"
1052 " %s%s\n%s",
1053 SATA_CONFIRM_PORT, ap_id,
1054 SATA_CONFIRM_PORT_DISABLE);
1055 } else {
1056 rv = CFGA_SATA_NACK;
1057 goto bailout;
1059 if (!sata_confirm(confp, msg)) {
1060 rv = CFGA_SATA_NACK;
1061 goto bailout;
1064 rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_DEACTIVATE, NULL,
1065 (void **)&str_p, &size);
1067 } else if (strcmp(func, SATA_PORT_ACTIVATE) == 0) {
1068 len = strlen(SATA_CONFIRM_PORT) +
1069 strlen(SATA_CONFIRM_PORT_ENABLE) +
1070 strlen("Activate Port") + strlen(ap_id);
1072 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1073 (void) snprintf(msg, len +3, "Activate"
1074 " %s%s\n%s",
1075 SATA_CONFIRM_PORT, ap_id,
1076 SATA_CONFIRM_PORT_ENABLE);
1077 } else {
1078 rv = CFGA_SATA_NACK;
1079 goto bailout;
1081 if (!sata_confirm(confp, msg)) {
1082 rv = CFGA_SATA_NACK;
1083 goto bailout;
1086 rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_ACTIVATE,
1087 NULL, (void **)&str_p, &size);
1088 goto bailout;
1090 } else if (strcmp(func, SATA_PORT_SELF_TEST) == 0) {
1091 len = strlen(SATA_CONFIRM_PORT) +
1092 strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
1093 strlen("Self Test Port") + strlen(ap_id);
1095 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1096 (void) snprintf(msg, len +3, "Self Test"
1097 " %s%s\n%s",
1098 SATA_CONFIRM_PORT, ap_id,
1099 SATA_CONFIRM_DEVICE_SUSPEND);
1100 } else {
1101 rv = CFGA_SATA_NACK;
1102 goto bailout;
1104 if (!sata_confirm(confp, msg)) {
1105 rv = CFGA_SATA_NACK;
1106 goto bailout;
1109 rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_SELF_TEST,
1110 NULL, (void **)&str_p, &size);
1111 } else {
1112 /* Unrecognized operation request */
1113 rv = CFGA_SATA_HWOPNOTSUPP;
1116 bailout:
1117 cleanup_after_devctl_cmd(hdl, list);
1119 return (sata_err_msg(errstring, rv, ap_id, errno));
1123 /* cfgadm entry point */
1124 /*ARGSUSED*/
1125 cfga_err_t
1126 cfga_test(
1127 const char *ap_id,
1128 const char *options,
1129 struct cfga_msg *msgp,
1130 char **errstring,
1131 cfga_flags_t flags)
1133 /* Should call ioctl for self test - phase 2 */
1134 return (CFGA_OPNOTSUPP);
1139 sata_check_target_node(di_node_t node, void *arg)
1141 char *minorpath;
1142 char *cp;
1144 minorpath = di_devfs_minor_path(di_minor_next(node, DI_MINOR_NIL));
1145 if (minorpath != NULL) {
1146 if (strstr(minorpath, arg) != NULL) {
1147 cp = strrchr(minorpath, (int)*MINOR_SEP);
1148 if (cp != NULL) {
1149 (void) strcpy(arg, cp);
1151 free(minorpath);
1152 return (DI_WALK_TERMINATE);
1154 free(minorpath);
1156 return (DI_WALK_CONTINUE);
1159 struct chk_dev {
1160 int c_isblk;
1161 char *c_minor;
1164 /*ARGSUSED*/
1165 static int
1166 chk_dev_fcn(di_node_t node, di_minor_t minor, void *arg)
1168 char *mn;
1169 struct chk_dev *chkp = (struct chk_dev *)arg;
1171 mn = di_minor_name(minor);
1172 if (mn == NULL)
1173 return (DI_WALK_CONTINUE);
1175 if (strcmp(mn, chkp->c_minor) != 0)
1176 return (DI_WALK_CONTINUE);
1178 chkp->c_isblk = di_minor_spectype(minor) == S_IFBLK ? 1 : 0;
1180 return (DI_WALK_TERMINATE);
1184 * Don't use devfs if stat() in /devices fails. Use libdevinfo instead.
1185 * Retired devices don't show up in devfs.
1187 * Returns:
1188 * 1 - minor exists and is of type BLK
1189 * 0 - minor does not exist or is not of type BLK.
1191 static int
1192 is_devinfo_blk(char *minor_path)
1194 char *minor_portion;
1195 struct chk_dev chk_dev;
1196 di_node_t node;
1197 int rv;
1200 * prune minor path for di_init() - no /devices prefix and no minor name
1202 if (strncmp(minor_path, "/devices/", strlen("/devices/")) != 0)
1203 return (0);
1205 minor_portion = strrchr(minor_path, *MINOR_SEP);
1206 if (minor_portion == NULL)
1207 return (0);
1209 *minor_portion = 0;
1211 node = di_init(minor_path + strlen("/devices"), DINFOMINOR);
1213 *minor_portion = *MINOR_SEP;
1215 if (node == DI_NODE_NIL)
1216 return (0);
1218 chk_dev.c_isblk = 0;
1219 chk_dev.c_minor = minor_portion + 1;
1221 rv = di_walk_minor(node, NULL, 0, &chk_dev, chk_dev_fcn);
1223 di_fini(node);
1225 if (rv == 0 && chk_dev.c_isblk)
1226 return (1);
1227 else
1228 return (0);
1232 * The dynamic component buffer returned by this function has to be freed!
1235 sata_make_dyncomp(const char *ap_id, char **dyncomp, const char *type)
1237 char *devpath = NULL;
1238 char *cp = NULL;
1239 int l_errno;
1240 char minor_path[MAXPATHLEN];
1241 char name_part[MAXNAMELEN];
1242 char *devlink = NULL;
1243 char *minor_portion = NULL;
1244 int deplen;
1245 int err;
1246 DIR *dp = NULL;
1247 struct stat sb;
1248 struct dirent *dep = NULL;
1249 struct dirent *newdep = NULL;
1250 char *p;
1252 assert(dyncomp != NULL);
1255 * Get target node path
1257 devpath = sata_get_devicepath(ap_id);
1258 if (devpath == NULL) {
1260 (void) printf("cfga_list_ext: cannot locate target device\n");
1261 return (CFGA_SATA_DYNAMIC_AP);
1263 } else {
1265 cp = strrchr(devpath, *PATH_SEP);
1266 assert(cp != NULL);
1267 *cp = 0; /* terminate path for opendir() */
1269 (void) strncpy(name_part, cp + 1, MAXNAMELEN);
1272 * Using libdevinfo for this is overkill and kills
1273 * performance when many consumers are using libcfgadm
1274 * concurrently.
1276 if ((dp = opendir(devpath)) == NULL) {
1277 goto bailout;
1281 * deplen is large enough to fit the largest path-
1282 * struct dirent includes one byte (the terminator)
1283 * so we don't add 1 to the calculation here.
1285 deplen = pathconf(devpath, _PC_NAME_MAX);
1286 deplen = ((deplen <= 0) ? MAXNAMELEN : deplen) +
1287 sizeof (struct dirent);
1288 dep = (struct dirent *)malloc(deplen);
1289 if (dep == NULL)
1290 goto bailout;
1292 while ((err = readdir_r(dp, dep, &newdep)) == 0 &&
1293 newdep != NULL) {
1295 assert(newdep == dep);
1297 if (strcmp(dep->d_name, ".") == 0 ||
1298 strcmp(dep->d_name, "..") == 0 ||
1299 (minor_portion = strchr(dep->d_name,
1300 *MINOR_SEP)) == NULL)
1301 continue;
1303 *minor_portion = 0;
1304 if (strcmp(dep->d_name, name_part) != 0)
1305 continue;
1306 *minor_portion = *MINOR_SEP;
1308 (void) snprintf(minor_path, MAXPATHLEN,
1309 "%s/%s", devpath, dep->d_name);
1312 * Break directly for tape device
1314 if (strcmp(type, "tape") == 0)
1315 break;
1318 * If stat() fails, the device *may* be retired.
1319 * Check via libdevinfo if the device has a BLK minor.
1320 * We don't use libdevinfo all the time, since taking
1321 * a snapshot is slower than a stat().
1323 if (stat(minor_path, &sb) < 0) {
1324 if (is_devinfo_blk(minor_path)) {
1325 break;
1326 } else {
1327 continue;
1331 if (S_ISBLK(sb.st_mode))
1332 break;
1336 (void) closedir(dp);
1337 free(dep);
1338 free(devpath);
1340 dp = NULL;
1341 dep = NULL;
1342 devpath = NULL;
1345 * If there was an error, or we didn't exit the loop
1346 * by finding a block or character device, bail out.
1348 if (err != 0 || newdep == NULL)
1349 goto bailout;
1352 * Look for links to the physical path in /dev/dsk
1353 * and /dev/rmt. So far, sata modue supports disk,
1354 * dvd and tape devices, so we will first look for
1355 * BLOCK devices, and then look for tape devices.
1357 (void) physpath_to_devlink("/dev/dsk",
1358 minor_path, &devlink, &l_errno);
1360 /* postprocess and copy logical name here */
1361 if (devlink != NULL) {
1363 * For disks, remove partition/slice info
1365 if ((cp = strstr(devlink, "dsk/")) != NULL) {
1366 /* cXtYdZ[(s[0..15])|(p[0..X])] */
1367 if ((p = strchr(cp + 4, 'd')) != NULL) {
1368 p++; /* Skip the 'd' */
1369 while (*p != 0 && isdigit(*p))
1370 p++;
1371 *p = 0;
1373 *dyncomp = strdup(cp);
1376 free(devlink);
1377 } else if (strcmp(type, "tape") == 0) {
1380 * For tape device, logical name looks like
1381 * rmt/X
1383 (void) physpath_to_devlink("/dev/rmt",
1384 minor_path, &devlink, &l_errno);
1386 if (devlink != NULL) {
1387 if ((cp = strstr(devlink, "rmt/")) != NULL) {
1388 *dyncomp = strdup(cp);
1391 free(devlink);
1395 return (SATA_CFGA_OK);
1398 bailout:
1399 if (dp)
1400 (void) closedir(dp);
1401 if (devpath)
1402 free(devpath);
1403 if (dep)
1404 free(dep);
1405 return (CFGA_SATA_DYNAMIC_AP);
1408 /* cfgadm entry point */
1409 /*ARGSUSED*/
1410 cfga_err_t
1411 cfga_list_ext(
1412 const char *ap_id,
1413 cfga_list_data_t **ap_id_list,
1414 int *nlistp,
1415 const char *options,
1416 const char *listopts,
1417 char **errstring,
1418 cfga_flags_t flags)
1420 int l_errno;
1421 char *ap_id_log = NULL;
1422 size_t size;
1423 nvlist_t *user_nvlist = NULL;
1424 devctl_hdl_t devctl_hdl = NULL;
1425 cfga_sata_ret_t rv = CFGA_SATA_OK;
1426 devctl_ap_state_t devctl_ap_state;
1427 char *pdyn;
1428 boolean_t pmult = B_FALSE;
1429 uint32_t port;
1432 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) {
1433 (void) cfga_help(NULL, options, flags);
1434 goto bailout;
1436 /* We do not care here about dynamic AP name component */
1437 if ((pdyn = GET_DYN(ap_id)) != NULL) {
1438 *pdyn = '\0';
1441 if (ap_id_list == NULL || nlistp == NULL) {
1442 rv = CFGA_SATA_DATA_ERROR;
1443 (void) cfga_help(NULL, options, flags);
1444 goto bailout;
1447 /* Get ap status */
1448 if ((rv = setup_for_devctl_cmd(ap_id, &devctl_hdl, &user_nvlist,
1449 DC_RDONLY)) != CFGA_SATA_OK) {
1450 goto bailout;
1453 /* will call dc_cmd to send IOCTL to kernel */
1454 if (devctl_ap_getstate(devctl_hdl, user_nvlist,
1455 &devctl_ap_state) == -1) {
1456 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
1457 rv = CFGA_SATA_IOCTL;
1458 goto bailout;
1461 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
1464 * Create cfga_list_data_t struct.
1466 if ((*ap_id_list =
1467 (cfga_list_data_t *)malloc(sizeof (**ap_id_list))) == NULL) {
1468 rv = CFGA_SATA_ALLOC_FAIL;
1469 goto bailout;
1471 *nlistp = 1;
1474 * Rest of the code fills in the cfga_list_data_t struct.
1477 /* Get /dev/cfg path to corresponding to the physical ap_id */
1478 /* Remember ap_id_log must be freed */
1479 rv = physpath_to_devlink(CFGA_DEV_DIR, (char *)ap_id,
1480 &ap_id_log, &l_errno);
1482 if (rv != 0) {
1483 rv = CFGA_SATA_DEVLINK;
1484 goto bailout;
1487 /* Get logical ap_id corresponding to the physical */
1488 if (ap_id_log == NULL || strstr(ap_id_log, CFGA_DEV_DIR) == NULL) {
1489 rv = CFGA_SATA_DEVLINK;
1490 goto bailout;
1493 (void) strlcpy((*ap_id_list)->ap_log_id,
1494 /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR)+ 1,
1495 sizeof ((*ap_id_list)->ap_log_id));
1497 free(ap_id_log);
1498 ap_id_log = NULL;
1500 (void) strlcpy((*ap_id_list)->ap_phys_id, ap_id,
1501 sizeof ((*ap_id_list)->ap_phys_id));
1503 switch (devctl_ap_state.ap_rstate) {
1504 case AP_RSTATE_EMPTY:
1505 (*ap_id_list)->ap_r_state = CFGA_STAT_EMPTY;
1506 break;
1508 case AP_RSTATE_DISCONNECTED:
1509 (*ap_id_list)->ap_r_state = CFGA_STAT_DISCONNECTED;
1510 break;
1512 case AP_RSTATE_CONNECTED:
1513 (*ap_id_list)->ap_r_state = CFGA_STAT_CONNECTED;
1514 break;
1516 default:
1517 rv = CFGA_SATA_STATE;
1518 goto bailout;
1521 switch (devctl_ap_state.ap_ostate) {
1522 case AP_OSTATE_CONFIGURED:
1523 (*ap_id_list)->ap_o_state = CFGA_STAT_CONFIGURED;
1524 break;
1526 case AP_OSTATE_UNCONFIGURED:
1527 (*ap_id_list)->ap_o_state = CFGA_STAT_UNCONFIGURED;
1528 break;
1530 default:
1531 rv = CFGA_SATA_STATE;
1532 goto bailout;
1535 switch (devctl_ap_state.ap_condition) {
1536 case AP_COND_OK:
1537 (*ap_id_list)->ap_cond = CFGA_COND_OK;
1538 break;
1540 case AP_COND_FAILING:
1541 (*ap_id_list)->ap_cond = CFGA_COND_FAILING;
1542 break;
1544 case AP_COND_FAILED:
1545 (*ap_id_list)->ap_cond = CFGA_COND_FAILED;
1546 break;
1548 case AP_COND_UNUSABLE:
1549 (*ap_id_list)->ap_cond = CFGA_COND_UNUSABLE;
1550 break;
1552 case AP_COND_UNKNOWN:
1553 (*ap_id_list)->ap_cond = CFGA_COND_UNKNOWN;
1554 break;
1556 default:
1557 rv = CFGA_SATA_STATE;
1558 goto bailout;
1561 (*ap_id_list)->ap_class[0] = '\0'; /* Filled by libcfgadm */
1562 (*ap_id_list)->ap_busy = devctl_ap_state.ap_in_transition;
1563 (*ap_id_list)->ap_status_time = devctl_ap_state.ap_last_change;
1564 (*ap_id_list)->ap_info[0] = NULL;
1566 if ((*ap_id_list)->ap_r_state == CFGA_STAT_CONNECTED) {
1567 char *str_p;
1568 int skip, i;
1571 * Fill in the 'Information' field for the -v option
1572 * Model (MOD:)
1574 if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_MODEL_INFO,
1575 NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) {
1576 (void) printf(
1577 "SATA_CFGA_GET_MODULE_INFO ioctl failed\n");
1578 goto bailout;
1580 /* drop leading and trailing spaces */
1581 skip = strspn(str_p, " ");
1582 for (i = size - 1; i >= 0; i--) {
1583 if (str_p[i] == '\040')
1584 str_p[i] = '\0';
1585 else if (str_p[i] != '\0')
1586 break;
1589 (void) strlcpy((*ap_id_list)->ap_info, "Mod: ",
1590 sizeof ((*ap_id_list)->ap_info));
1591 (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
1592 sizeof ((*ap_id_list)->ap_info));
1594 free(str_p);
1597 * Fill in the 'Information' field for the -v option
1598 * Firmware revision (FREV:)
1600 if ((rv = do_control_ioctl(ap_id,
1601 SATA_CFGA_GET_REVFIRMWARE_INFO,
1602 NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) {
1603 (void) printf(
1604 "SATA_CFGA_GET_REVFIRMWARE_INFO ioctl failed\n");
1605 goto bailout;
1607 /* drop leading and trailing spaces */
1608 skip = strspn(str_p, " ");
1609 for (i = size - 1; i >= 0; i--) {
1610 if (str_p[i] == '\040')
1611 str_p[i] = '\0';
1612 else if (str_p[i] != '\0')
1613 break;
1615 (void) strlcat((*ap_id_list)->ap_info, " FRev: ",
1616 sizeof ((*ap_id_list)->ap_info));
1617 (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
1618 sizeof ((*ap_id_list)->ap_info));
1620 free(str_p);
1624 * Fill in the 'Information' field for the -v option
1625 * Serial Number (SN:)
1627 if ((rv = do_control_ioctl(ap_id,
1628 SATA_CFGA_GET_SERIALNUMBER_INFO,
1629 NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) {
1630 (void) printf(
1631 "SATA_CFGA_GET_SERIALNUMBER_INFO ioctl failed\n");
1632 goto bailout;
1634 /* drop leading and trailing spaces */
1635 skip = strspn(str_p, " ");
1636 for (i = size - 1; i >= 0; i--) {
1637 if (str_p[i] == '\040')
1638 str_p[i] = '\0';
1639 else if (str_p[i] != '\0')
1640 break;
1642 (void) strlcat((*ap_id_list)->ap_info, " SN: ",
1643 sizeof ((*ap_id_list)->ap_info));
1644 (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
1645 sizeof ((*ap_id_list)->ap_info));
1647 free(str_p);
1651 /* Fill in ap_type which is collected from HBA driver */
1652 /* call do_control_ioctl TBD */
1653 if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, NULL,
1654 (void **)&str_p, &size)) != CFGA_SATA_OK) {
1655 (void) printf(
1656 "SATA_CFGA_GET_AP_TYPE ioctl failed\n");
1657 goto bailout;
1660 (void) strlcpy((*ap_id_list)->ap_type, str_p,
1661 sizeof ((*ap_id_list)->ap_type));
1663 free(str_p);
1666 * Checking device type. Port multiplier has no dynamic
1667 * suffix.
1669 if (strncmp((*ap_id_list)->ap_type, "sata-pmult",
1670 sizeof ("sata-pmult")) == 0)
1671 pmult = B_TRUE;
1673 if ((*ap_id_list)->ap_o_state == CFGA_STAT_CONFIGURED &&
1674 pmult == B_FALSE) {
1676 char *dyncomp = NULL;
1679 * This is the case where we need to generate
1680 * a dynamic component of the ap_id, i.e. device.
1682 rv = sata_make_dyncomp(ap_id, &dyncomp,
1683 (*ap_id_list)->ap_type);
1684 if (rv != CFGA_SATA_OK)
1685 goto bailout;
1686 if (dyncomp != NULL) {
1687 (void) strcat((*ap_id_list)->ap_log_id,
1688 DYN_SEP);
1689 (void) strlcat((*ap_id_list)->ap_log_id,
1690 dyncomp,
1691 sizeof ((*ap_id_list)->ap_log_id));
1692 free(dyncomp);
1696 } else {
1697 /* This is an empty port */
1698 if (get_port_num(ap_id, &port) != CFGA_SATA_OK) {
1699 goto bailout;
1702 if (port & SATA_CFGA_PMPORT_QUAL) {
1703 (void) strlcpy((*ap_id_list)->ap_type, "pmult-port",
1704 sizeof ((*ap_id_list)->ap_type));
1705 } else {
1706 (void) strlcpy((*ap_id_list)->ap_type, "sata-port",
1707 sizeof ((*ap_id_list)->ap_type));
1711 return (sata_err_msg(errstring, rv, ap_id, errno));
1713 bailout:
1714 if (*ap_id_list != NULL) {
1715 free(*ap_id_list);
1717 if (ap_id_log != NULL) {
1718 free(ap_id_log);
1721 return (sata_err_msg(errstring, rv, ap_id, errno));
1724 * This routine accepts a string adn prints it using
1725 * the message print routine argument.
1727 static void
1728 cfga_msg(struct cfga_msg *msgp, const char *str)
1730 int len;
1731 char *q;
1733 if (msgp == NULL || msgp->message_routine == NULL) {
1734 (void) printf("cfga_msg: NULL msgp\n");
1735 return;
1738 if ((len = strlen(str)) == 0) {
1739 (void) printf("cfga_msg: null str\n");
1740 return;
1743 if ((q = (char *)calloc(len + 1, 1)) == NULL) {
1744 perror("cfga_msg");
1745 return;
1748 (void) strcpy(q, str);
1749 (*msgp->message_routine)(msgp->appdata_ptr, q);
1751 free(q);
1754 /* cfgadm entry point */
1755 /* ARGSUSED */
1756 cfga_err_t
1757 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
1759 if (options != NULL) {
1760 cfga_msg(msgp, dgettext(TEXT_DOMAIN, sata_help[HELP_UNKNOWN]));
1761 cfga_msg(msgp, options);
1763 cfga_msg(msgp, dgettext(TEXT_DOMAIN, sata_help[HELP_HEADER]));
1764 cfga_msg(msgp, sata_help[HELP_CONFIG]);
1765 cfga_msg(msgp, sata_help[HELP_RESET_PORT]);
1766 cfga_msg(msgp, sata_help[HELP_RESET_DEVICE]);
1767 cfga_msg(msgp, sata_help[HELP_RESET_ALL]);
1768 cfga_msg(msgp, sata_help[HELP_PORT_ACTIVATE]);
1769 cfga_msg(msgp, sata_help[HELP_PORT_DEACTIVATE]);
1770 cfga_msg(msgp, sata_help[HELP_PORT_SELF_TEST]);
1771 cfga_msg(msgp, sata_help[HELP_CNTRL_SELF_TEST]);
1773 return (CFGA_OK);
1778 * Ensure the ap_id passed is in the correct (physical ap_id) form:
1779 * path/device:xx[.xx]
1780 * where xx is a one or two-digit number.
1782 * Note the library always calls the plugin with a physical ap_id.
1784 static int
1785 verify_valid_apid(const char *ap_id)
1787 char *l_ap_id;
1789 if (ap_id == NULL)
1790 return (-1);
1792 l_ap_id = strrchr(ap_id, (int)*MINOR_SEP);
1793 l_ap_id++;
1795 if (strspn(l_ap_id, "0123456789.") != strlen(l_ap_id)) {
1796 /* Bad characters in the ap_id */
1797 return (-1);
1800 if (strstr(l_ap_id, "..") != NULL) {
1801 /* ap_id has 1..2 or more than 2 dots */
1802 return (-1);
1805 return (0);
1811 * Verify the params passed in are valid.
1813 static cfga_sata_ret_t
1814 verify_params(
1815 const char *ap_id,
1816 const char *options,
1817 char **errstring)
1819 char *pdyn, *lap_id;
1820 int rv;
1822 if (errstring != NULL) {
1823 *errstring = NULL;
1826 if (options != NULL) {
1827 return (CFGA_SATA_OPTIONS);
1830 /* Strip dynamic AP name component if it is present. */
1831 lap_id = strdup(ap_id);
1832 if (lap_id == NULL) {
1833 return (CFGA_SATA_ALLOC_FAIL);
1835 if ((pdyn = GET_DYN(lap_id)) != NULL) {
1836 *pdyn = '\0';
1839 if (verify_valid_apid(lap_id) != 0) {
1840 rv = CFGA_SATA_AP;
1841 } else {
1842 rv = CFGA_SATA_OK;
1844 free(lap_id);
1846 return (rv);
1850 * Takes a validated ap_id and extracts the port number.
1851 * Port multiplier is supported now.
1853 static cfga_sata_ret_t
1854 get_port_num(const char *ap_id, uint32_t *port)
1856 uint32_t cport, pmport = 0, qual = 0;
1857 char *cport_str, *pmport_str;
1859 /* Get the cport number */
1860 cport_str = strrchr(ap_id, (int)*MINOR_SEP) + strlen(MINOR_SEP);
1862 errno = 0;
1863 cport = strtol(cport_str, NULL, 10);
1864 if ((cport & ~SATA_CFGA_CPORT_MASK) != 0 || errno != 0) {
1865 return (CFGA_SATA_PORT);
1868 /* Get pmport number if there is a PORT_SEPARATOR */
1869 errno = 0;
1870 if ((pmport_str = strrchr(ap_id, (int)*PORT_SEPARATOR)) != 0) {
1871 pmport_str += strlen(PORT_SEPARATOR);
1872 pmport = strtol(pmport_str, NULL, 10);
1873 qual = SATA_CFGA_PMPORT_QUAL;
1874 if ((pmport & ~SATA_CFGA_PMPORT_MASK) != 0 || errno != 0) {
1875 return (CFGA_SATA_PORT);
1879 *port = cport | (pmport << SATA_CFGA_PMPORT_SHIFT) | qual;
1880 return (CFGA_SATA_OK);
1884 * Pair of routines to set up for/clean up after a devctl_ap_* lib call.
1886 static void
1887 cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist)
1889 if (user_nvlist != NULL) {
1890 nvlist_free(user_nvlist);
1892 if (devctl_hdl != NULL) {
1893 devctl_release(devctl_hdl);
1897 static cfga_sata_ret_t
1898 setup_for_devctl_cmd(
1899 const char *ap_id,
1900 devctl_hdl_t *devctl_hdl,
1901 nvlist_t **user_nvlistp,
1902 uint_t oflag)
1905 uint_t port;
1906 cfga_sata_ret_t rv = CFGA_SATA_OK;
1907 char *lap_id, *pdyn;
1909 lap_id = strdup(ap_id);
1910 if (lap_id == NULL)
1911 return (CFGA_SATA_ALLOC_FAIL);
1912 if ((pdyn = GET_DYN(lap_id)) != NULL) {
1913 *pdyn = '\0';
1916 /* Get a devctl handle to pass to the devctl_ap_XXX functions */
1917 if ((*devctl_hdl = devctl_ap_acquire((char *)lap_id, oflag)) == NULL) {
1918 (void) fprintf(stderr, "[libcfgadm:sata] "
1919 "setup_for_devctl_cmd: devctl_ap_acquire failed: %s\n",
1920 strerror(errno));
1921 rv = CFGA_SATA_DEVCTL;
1922 goto bailout;
1925 /* Set up nvlist to pass the port number down to the driver */
1926 if (nvlist_alloc(user_nvlistp, NV_UNIQUE_NAME_TYPE, NULL) != 0) {
1927 *user_nvlistp = NULL;
1928 rv = CFGA_SATA_NVLIST;
1929 (void) printf("nvlist_alloc failed\n");
1930 goto bailout;
1934 * Get port id, for Port Multiplier port, things could be a little bit
1935 * complicated because of "port.port" format in ap_id, thus for
1936 * port multiplier port, port number should be coded as 32bit int
1937 * with the sig 16 bit as sata channel number, least 16 bit as
1938 * the port number of sata port multiplier port.
1940 if ((rv = get_port_num(lap_id, &port)) != CFGA_SATA_OK) {
1941 (void) printf(
1942 "setup_for_devctl_cmd: get_port_num, errno: %d\n",
1943 errno);
1944 goto bailout;
1947 /* Creates an int32_t entry */
1948 if (nvlist_add_int32(*user_nvlistp, PORT, port) == -1) {
1949 (void) printf("nvlist_add_int32 failed\n");
1950 rv = CFGA_SATA_NVLIST;
1951 goto bailout;
1954 free(lap_id);
1955 return (rv);
1957 bailout:
1958 free(lap_id);
1959 (void) cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
1961 return (rv);
1965 static cfga_sata_ret_t
1966 port_state(devctl_hdl_t hdl, nvlist_t *list,
1967 ap_rstate_t *rstate, ap_ostate_t *ostate)
1969 devctl_ap_state_t devctl_ap_state;
1971 if (devctl_ap_getstate(hdl, list, &devctl_ap_state) == -1) {
1972 (void) printf("devctl_ap_getstate failed, errno: %d\n", errno);
1973 return (CFGA_SATA_IOCTL);
1975 *rstate = devctl_ap_state.ap_rstate;
1976 *ostate = devctl_ap_state.ap_ostate;
1977 return (CFGA_SATA_OK);
1982 * Given a subcommand to the DEVCTL_AP_CONTROL ioctl, rquest the size of
1983 * the data to be returned, allocate a buffer, then get the data.
1984 * Returns *descrp (which must be freed) and size.
1986 * Note SATA_DESCR_TYPE_STRING returns an ASCII NULL-terminated string,
1987 * not a string descr.
1989 cfga_sata_ret_t
1990 do_control_ioctl(const char *ap_id, sata_cfga_apctl_t subcommand, uint_t arg,
1991 void **descrp, size_t *sizep)
1993 int fd = -1;
1994 uint_t port;
1995 uint32_t local_size;
1996 cfga_sata_ret_t rv = CFGA_SATA_OK;
1997 struct sata_ioctl_data ioctl_data;
1999 assert(descrp != NULL);
2000 *descrp = NULL;
2001 assert(sizep != NULL);
2003 if ((rv = get_port_num(ap_id, &port)) != CFGA_SATA_OK) {
2004 goto bailout;
2007 if ((fd = open(ap_id, O_RDONLY)) == -1) {
2008 (void) printf("do_control_ioctl: open failed: errno:%d\n",
2009 errno);
2010 rv = CFGA_SATA_OPEN;
2011 if (errno == EBUSY) {
2012 rv = CFGA_SATA_BUSY;
2014 goto bailout;
2017 ioctl_data.cmd = subcommand;
2018 ioctl_data.port = port;
2019 ioctl_data.misc_arg = (uint_t)arg;
2022 * Find out how large a buf we need to get the data.
2023 * Note the ioctls only accept/return a 32-bit int for a get_size
2024 * to avoid 32/64 and BE/LE issues.
2026 if ((subcommand == SATA_CFGA_GET_AP_TYPE) ||
2027 (subcommand == SATA_CFGA_GET_DEVICE_PATH) ||
2028 (subcommand == SATA_CFGA_GET_MODEL_INFO) ||
2029 (subcommand == SATA_CFGA_GET_REVFIRMWARE_INFO) ||
2030 (subcommand == SATA_CFGA_GET_SERIALNUMBER_INFO)) {
2031 ioctl_data.get_size = B_TRUE;
2032 ioctl_data.buf = (caddr_t)&local_size;
2033 ioctl_data.bufsiz = sizeof (local_size);
2035 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
2036 perror("ioctl failed (size)");
2037 rv = CFGA_SATA_IOCTL;
2038 goto bailout;
2040 *sizep = local_size;
2042 if (local_size == 0) {
2043 (void) printf("zero length data\n");
2044 rv = CFGA_SATA_ZEROLEN;
2045 goto bailout;
2047 if ((*descrp = malloc(*sizep)) == NULL) {
2048 (void) printf("do_control_ioctl: malloc failed\n");
2049 rv = CFGA_SATA_ALLOC_FAIL;
2050 goto bailout;
2052 } else {
2053 *sizep = 0;
2055 ioctl_data.get_size = B_FALSE;
2056 ioctl_data.buf = *descrp;
2057 ioctl_data.bufsiz = *sizep;
2059 /* Execute IOCTL */
2061 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
2062 rv = CFGA_SATA_IOCTL;
2063 goto bailout;
2066 (void) close(fd);
2068 return (rv);
2070 bailout:
2071 if (fd != -1) {
2072 (void) close(fd);
2074 if (*descrp != NULL) {
2075 free(*descrp);
2076 *descrp = NULL;
2079 if (rv == CFGA_SATA_IOCTL && errno == EBUSY) {
2080 rv = CFGA_SATA_BUSY;
2083 return (rv);
2087 static int
2088 sata_confirm(struct cfga_confirm *confp, char *msg)
2090 int rval;
2092 if (confp == NULL || confp->confirm == NULL) {
2093 return (0);
2095 rval = (*confp->confirm)(confp->appdata_ptr, msg);
2097 return (rval);
2101 static char *
2102 sata_get_devicepath(const char *ap_id)
2104 char *devpath = NULL;
2105 size_t size;
2106 cfga_sata_ret_t rv;
2108 rv = do_control_ioctl(ap_id, SATA_CFGA_GET_DEVICE_PATH, NULL,
2109 (void **)&devpath, &size);
2111 if (rv == CFGA_SATA_OK) {
2112 return (devpath);
2113 } else {
2114 return ((char *)NULL);