11258Smlf /*
21258Smlf * CDDL HEADER START
31258Smlf *
41258Smlf * The contents of this file are subject to the terms of the
51258Smlf * Common Development and Distribution License (the "License").
61258Smlf * You may not use this file except in compliance with the License.
71258Smlf *
81258Smlf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91258Smlf * or http://www.opensolaris.org/os/licensing.
101258Smlf * See the License for the specific language governing permissions
111258Smlf * and limitations under the License.
121258Smlf *
131258Smlf * When distributing Covered Code, include this CDDL HEADER in each
141258Smlf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151258Smlf * If applicable, add the following below this CDDL HEADER, with the
161258Smlf * fields enclosed by brackets "[]" replaced with your own identifying
171258Smlf * information: Portions Copyright [yyyy] [name of copyright owner]
181258Smlf *
191258Smlf * CDDL HEADER END
201258Smlf */
211258Smlf
221258Smlf /*
23*10318SXiao-Yu.Zhang@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
241258Smlf * Use is subject to license terms.
251258Smlf */
261258Smlf
272027Ssethg #include <sys/param.h>
282027Ssethg #include <sys/stat.h>
292027Ssethg #include <errno.h>
302027Ssethg #include <string.h>
312027Ssethg #include <dirent.h>
321258Smlf #include "cfga_sata.h"
331258Smlf
341258Smlf /*
351258Smlf * This file contains the entry points to the plug-in as defined in the
361258Smlf * config_admin(3X) man page.
371258Smlf */
381258Smlf
391258Smlf /*
401258Smlf * Set the version number for the cfgadm library's use.
411258Smlf */
421258Smlf int cfga_version = CFGA_HSL_V2;
431258Smlf
441258Smlf enum {
451258Smlf HELP_HEADER = 1,
461258Smlf HELP_CONFIG,
471258Smlf HELP_RESET_PORT,
481258Smlf HELP_RESET_DEVICE,
491258Smlf HELP_RESET_ALL,
501258Smlf HELP_PORT_DEACTIVATE,
511258Smlf HELP_PORT_ACTIVATE,
521258Smlf HELP_PORT_SELF_TEST,
531258Smlf HELP_CNTRL_SELF_TEST,
541258Smlf HELP_UNKNOWN
551258Smlf };
561258Smlf
571258Smlf /* SATA specific help messages */
581258Smlf static char *sata_help[] = {
591258Smlf NULL,
601258Smlf "SATA specific commands:\n",
611258Smlf " cfgadm -c [configure|unconfigure|disconnect|connect] ap_id "
62*10318SXiao-Yu.Zhang@Sun.COM "[ap_id...]\n",
631258Smlf " cfgadm -x sata_reset_port ap_id [ap_id...]\n",
641258Smlf " cfgadm -x sata_reset_device ap_id [ap_id...]\n",
651258Smlf " cfgadm -x sata_reset_all ap_id\n",
661258Smlf " cfgadm -x sata_port_deactivate ap_id [ap_id...]\n",
671258Smlf " cfgadm -x sata_port_activate ap_id [ap_id...]\n",
681258Smlf " cfgadm -x sata_port_self_test ap_id [ap_id...]\n",
691258Smlf " cfgadm -t ap_id\n",
701258Smlf "\tunknown command or option:\n",
711258Smlf NULL
721258Smlf }; /* End help messages */
731258Smlf
741258Smlf
751258Smlf /*
761258Smlf * Messages.
771258Smlf */
781258Smlf static msgcvt_t sata_msgs[] = {
791258Smlf /* CFGA_SATA_OK */
801258Smlf { CVT, CFGA_OK, "" },
811258Smlf
821258Smlf /* CFGA_SATA_NACK */
831258Smlf { CVT, CFGA_NACK, "" },
841258Smlf
851258Smlf /* CFGA_SATA_DEVICE_UNCONFIGURED */
861258Smlf { CVT, CFGA_OK, "Device unconfigured prior to disconnect" },
871258Smlf
881258Smlf /* CFGA_SATA_UNKNOWN / CFGA_LIB_ERROR -> "Library error" */
891258Smlf { CVT, CFGA_LIB_ERROR, "Unknown message; internal error" },
901258Smlf
911258Smlf /* CFGA_SATA_INTERNAL_ERROR / CFGA_LIB_ERROR -> "Library error" */
921258Smlf { CVT, CFGA_LIB_ERROR, "Internal error" },
931258Smlf
941258Smlf /* CFGA_SATA_DATA_ERROR / CFGA_DATA_ERROR -> "Data error" */
951258Smlf { CVT, CFGA_DATA_ERROR, "cfgadm data error" },
961258Smlf
971258Smlf /* CFGA_SATA_OPTIONS / CFGA_ERROR -> "Hardware specific failure" */
981258Smlf { CVT, CFGA_ERROR, "Hardware specific option not supported" },
991258Smlf
1001258Smlf /* CFGA_SATA_HWOPNOTSUPP / CFGA_ERROR -> "Hardware specific failure" */
1011258Smlf { CVT, CFGA_ERROR, "Hardware specific operation not supported" },
1021258Smlf
1031258Smlf /*
1041258Smlf * CFGA_SATA_DYNAMIC_AP /
1051258Smlf * CFGA_LIB_ERROR -> "Configuration operation invalid"
1061258Smlf */
1071258Smlf { CVT, CFGA_INVAL, "Cannot identify attached device" },
1081258Smlf
1091258Smlf /* CFGA_SATA_AP / CFGA_APID_NOEXIST -> "Attachment point not found" */
1101258Smlf { CVT, CFGA_APID_NOEXIST, "" },
1111258Smlf
1121258Smlf /* CFGA_SATA_PORT / CFGA_LIB_ERROR -> "Library error" */
1131258Smlf { CVT, CFGA_LIB_ERROR, "Cannot determine sata port number for " },
1141258Smlf
1151258Smlf /* CFGA_SATA_DEVCTL / CFGA_LIB_ERROR -> "Library error" */
1161258Smlf { CVT, CFGA_LIB_ERROR, "Internal error: "
117*10318SXiao-Yu.Zhang@Sun.COM "Cannot allocate devctl handle " },
1181258Smlf
1191258Smlf /*
1201258Smlf * CFGA_SATA_DEV_CONFIGURE /
1211258Smlf * CFGA_ERROR -> "Hardware specific failure"
1221258Smlf */
1231258Smlf { CVT, CFGA_ERROR, "Failed to config device at " },
1241258Smlf
1251258Smlf /*
1261258Smlf * CFGA_SATA_DEV_UNCONFIGURE /
1271258Smlf * CFGA_ERROR -> "Hardware specific failure"
1281258Smlf */
1291258Smlf { CVT, CFGA_ERROR, "Failed to unconfig device at " },
1301258Smlf
1311258Smlf /*
1321258Smlf * CFGA_SATA_DISCONNECTED
1331258Smlf * CFGA_INVAL -> "Configuration operation invalid"
1341258Smlf */
1351258Smlf { CVT, CFGA_INVAL, "Port already disconnected " },
1361258Smlf
1371258Smlf /*
1381258Smlf * CFGA_SATA_NOT_CONNECTED
1391258Smlf * CFGA_INVAL -> "Configuration operation invalid"
1401258Smlf */
1411258Smlf { CVT, CFGA_INVAL, "No device connected to " },
1421258Smlf
1431258Smlf /*
1441258Smlf * CFGA_SATA_NOT_CONFIGURED /
1451258Smlf * CFGA_INVAL -> "Configuration operation invalid"
1461258Smlf */
1471258Smlf { CVT, CFGA_INVAL, "No device configured at " },
1481258Smlf
1491258Smlf /*
1501258Smlf * CFGA_SATA_ALREADY_CONNECTED /
1511258Smlf * CFGA_INVAL -> "Configuration operation invalid"
1521258Smlf */
1531258Smlf { CVT, CFGA_INVAL, "Device already connected to " },
1541258Smlf
1551258Smlf /*
1561258Smlf * CFGA_SATA_ALREADY_CONFIGURED /
1571258Smlf * CFGA_INVAL -> "Configuration operation invalid"
1581258Smlf */
1591258Smlf { CVT, CFGA_INVAL, "Device already configured at " },
1601258Smlf
1611258Smlf /*
1621258Smlf * CFGA_SATA_INVALID_DEVNAME /
1631258Smlf * CFGA_INVAL -> "Configuration operation invalid"
1641258Smlf */
1651258Smlf { CVT, CFGA_INVAL, "Cannot specify device name" },
1661258Smlf
1671258Smlf /* CFGA_SATA_OPEN / CFGA_LIB_ERROR -> "Library error" */
1681258Smlf { CVT, CFGA_LIB_ERROR, "Cannot open " },
1691258Smlf
1701258Smlf /* CFGA_SATA_IOCTL / CFGA_ERROR -> "Hardware specific failure" */
1711258Smlf { CVT, CFGA_ERROR, "Driver ioctl failed " },
1721258Smlf
1731258Smlf /*
1741258Smlf * CFGA_SATA_BUSY /
1751258Smlf * CFGA_SYSTEM_BUSY -> "System is busy, try again"
1761258Smlf */
1771258Smlf { CVT, CFGA_SYSTEM_BUSY, "" },
1781258Smlf
1791258Smlf /* CFGA_SATA_ALLOC_FAIL / CFGA_LIB_ERROR -> "Library error" */
1801258Smlf { CVT, CFGA_LIB_ERROR, "Memory allocation failure" },
1811258Smlf
1821258Smlf /*
1831258Smlf * CFGA_SATA_OPNOTSUPP /
1841258Smlf * CFGA_OPNOTSUPP -> "Configuration operation not supported"
1851258Smlf */
1861258Smlf { CVT, CFGA_OPNOTSUPP, "Operation not supported" },
1871258Smlf
1881258Smlf /* CFGA_SATA_DEVLINK / CFGA_LIB_ERROR -> "Library error" */
1891258Smlf { CVT, CFGA_LIB_ERROR, "Could not find /dev/cfg link for " },
1901258Smlf
1911258Smlf /* CFGA_SATA_STATE / CFGA_LIB_ERROR -> "Library error" */
1921258Smlf { CVT, CFGA_LIB_ERROR, "Internal error: Unrecognized ap state" },
1931258Smlf
1941258Smlf /* CFGA_SATA_PRIV / CFGA_PRIV -> "Insufficient privileges" */
1951258Smlf { CVT, CFGA_PRIV, "" },
1961258Smlf
1971258Smlf /* CFGA_SATA_NVLIST / CFGA_ERROR -> "Hardware specific failure" */
1981258Smlf { CVT, CFGA_ERROR, "Internal error (nvlist)" },
1991258Smlf
2001258Smlf /* CFGA_SATA_ZEROLEN / CFGA_ERROR -> "Hardware specific failure" */
2011258Smlf { CVT, CFGA_ERROR, "Internal error (zerolength string)" },
2021258Smlf
2031258Smlf /* CFGA_SATA_RCM_HANDLE / CFGA_ERROR -> "Hardware specific failure" */
2041258Smlf { CVT, CFGA_ERROR, "cannot get RCM handle"},
2051258Smlf
2061258Smlf /*
2071258Smlf * CFGA_SATA_RCM_ONLINE /
2081258Smlf * CFGA_SYSTEM_BUSY -> "System is busy, try again"
2091258Smlf */
2101258Smlf { CVT, CFGA_SYSTEM_BUSY, "failed to online: "},
2111258Smlf
2121258Smlf /*
2131258Smlf * CFGA_SATA_RCM_OFFLINE /
2141258Smlf * CFGA_SYSTEM_BUSY -> "System is busy, try again"
2151258Smlf */
2161258Smlf { CVT, CFGA_SYSTEM_BUSY, "failed to offline: "},
2171258Smlf
2181258Smlf /* CFGA_SATA_RCM_INFO / CFGA_ERROR -> "Hardware specific failure" */
2191258Smlf { CVT, CFGA_ERROR, "failed to query: "}
2201258Smlf
2211258Smlf }; /* End error messages */
2221258Smlf
2231258Smlf static cfga_sata_ret_t
2241258Smlf verify_params(const char *ap_id, const char *options, char **errstring);
2251258Smlf
2261258Smlf
2271258Smlf static cfga_sata_ret_t
2281258Smlf setup_for_devctl_cmd(const char *ap_id, devctl_hdl_t *devctl_hdl,
229*10318SXiao-Yu.Zhang@Sun.COM nvlist_t **user_nvlistp, uint_t oflag);
2301258Smlf
2311258Smlf static cfga_sata_ret_t
2321258Smlf port_state(devctl_hdl_t hdl, nvlist_t *list,
233*10318SXiao-Yu.Zhang@Sun.COM ap_rstate_t *rstate, ap_ostate_t *ostate);
2341258Smlf
2351258Smlf static cfga_sata_ret_t
2361258Smlf do_control_ioctl(const char *ap_id, sata_cfga_apctl_t subcommand, uint_t arg,
237*10318SXiao-Yu.Zhang@Sun.COM void **descrp, size_t *sizep);
2381258Smlf
2391258Smlf static void
2401258Smlf cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist);
2411258Smlf
2421258Smlf static char *
2431258Smlf sata_get_devicepath(const char *ap_id);
2441258Smlf
2451258Smlf static int
2461258Smlf sata_confirm(struct cfga_confirm *confp, char *msg);
2471258Smlf
248*10318SXiao-Yu.Zhang@Sun.COM static cfga_sata_ret_t
249*10318SXiao-Yu.Zhang@Sun.COM get_port_num(const char *ap_id, uint32_t *port);
2501258Smlf
2511258Smlf /* Utilities */
2521258Smlf
2532027Ssethg static cfga_sata_ret_t
physpath_to_devlink(const char * basedir,const char * node_path,char ** logpp,int * l_errnop)2542027Ssethg physpath_to_devlink(const char *basedir, const char *node_path,
2552027Ssethg char **logpp, int *l_errnop)
2561258Smlf {
2572027Ssethg char *linkpath;
2582027Ssethg char *buf;
2592027Ssethg char *real_path;
2602027Ssethg DIR *dp;
2612027Ssethg struct dirent *dep, *newdep;
2622027Ssethg int deplen;
2632027Ssethg boolean_t found = B_FALSE;
2642027Ssethg int err = 0;
2652027Ssethg struct stat sb;
2662027Ssethg char *p;
2672027Ssethg cfga_sata_ret_t rv = CFGA_SATA_INTERNAL_ERROR;
2681258Smlf
2691258Smlf /*
2702027Ssethg * Using libdevinfo for this is overkill and kills performance
2712027Ssethg * when multiple consumers of libcfgadm are executing
2722027Ssethg * concurrently.
2731258Smlf */
2742027Ssethg if ((dp = opendir(basedir)) == NULL) {
2752027Ssethg *l_errnop = errno;
2762027Ssethg return (CFGA_SATA_INTERNAL_ERROR);
2772027Ssethg }
2782027Ssethg
2792027Ssethg linkpath = malloc(PATH_MAX);
2802027Ssethg buf = malloc(PATH_MAX);
2812027Ssethg real_path = malloc(PATH_MAX);
2822027Ssethg
2833019Ssethg deplen = pathconf(basedir, _PC_NAME_MAX);
2843019Ssethg deplen = (deplen <= 0 ? MAXNAMELEN : deplen) +
2852027Ssethg sizeof (struct dirent);
2862027Ssethg dep = (struct dirent *)malloc(deplen);
2872027Ssethg
2882027Ssethg if (dep == NULL || linkpath == NULL || buf == NULL ||
2892027Ssethg real_path == NULL) {
2902027Ssethg *l_errnop = ENOMEM;
2912027Ssethg rv = CFGA_SATA_ALLOC_FAIL;
2922027Ssethg goto pp_cleanup;
2932027Ssethg }
2942027Ssethg
2952027Ssethg *logpp = NULL;
2962027Ssethg
2972027Ssethg while (!found && (err = readdir_r(dp, dep, &newdep)) == 0 &&
2982027Ssethg newdep != NULL) {
2992027Ssethg
3002027Ssethg assert(newdep == dep);
3012027Ssethg
3022027Ssethg if (strcmp(dep->d_name, ".") == 0 ||
3032027Ssethg strcmp(dep->d_name, "..") == 0)
3042027Ssethg continue;
3052027Ssethg
3062027Ssethg (void) snprintf(linkpath, MAXPATHLEN,
3072027Ssethg "%s/%s", basedir, dep->d_name);
3082027Ssethg
3092027Ssethg if (lstat(linkpath, &sb) < 0)
3102027Ssethg continue;
3111258Smlf
3122027Ssethg if (S_ISDIR(sb.st_mode)) {
3132027Ssethg
3142027Ssethg if ((rv = physpath_to_devlink(linkpath, node_path,
3152027Ssethg logpp, l_errnop)) != CFGA_SATA_OK) {
3162027Ssethg
3172027Ssethg goto pp_cleanup;
3182027Ssethg }
3192027Ssethg
3202027Ssethg if (*logpp != NULL)
3212027Ssethg found = B_TRUE;
3222027Ssethg
3232027Ssethg } else if (S_ISLNK(sb.st_mode)) {
3242027Ssethg
3252027Ssethg bzero(buf, PATH_MAX);
3262027Ssethg if (readlink(linkpath, buf, PATH_MAX) < 0)
3272027Ssethg continue;
3282027Ssethg
3291258Smlf
3302027Ssethg /*
3312027Ssethg * realpath() is too darn slow, so fake
3322027Ssethg * it, by using what we know about /dev
3332027Ssethg * links: they are always of the form:
3342027Ssethg * <"../">+/devices/<path>
3352027Ssethg */
3362027Ssethg p = buf;
3372027Ssethg while (strncmp(p, "../", 3) == 0)
3382027Ssethg p += 3;
3392027Ssethg
3402027Ssethg if (p != buf)
3412027Ssethg p--; /* back up to get a slash */
3422027Ssethg
3432027Ssethg assert (*p == '/');
3442027Ssethg
3452027Ssethg if (strcmp(p, node_path) == 0) {
3462027Ssethg *logpp = strdup(linkpath);
3472027Ssethg if (*logpp == NULL) {
3482027Ssethg
3492027Ssethg rv = CFGA_SATA_ALLOC_FAIL;
3502027Ssethg goto pp_cleanup;
3512027Ssethg }
3522027Ssethg
3532027Ssethg found = B_TRUE;
3542027Ssethg }
3551258Smlf }
3561258Smlf }
3571258Smlf
3582027Ssethg free(linkpath);
3592027Ssethg free(buf);
3602027Ssethg free(real_path);
3612027Ssethg free(dep);
3622027Ssethg (void) closedir(dp);
3631258Smlf
3642027Ssethg if (err != 0) {
3652027Ssethg *l_errnop = err;
3662027Ssethg return (CFGA_SATA_INTERNAL_ERROR);
3671258Smlf }
3681258Smlf
3692027Ssethg return (CFGA_SATA_OK);
3702027Ssethg
3712027Ssethg pp_cleanup:
3722027Ssethg
3732027Ssethg if (dp)
3742027Ssethg (void) closedir(dp);
3752027Ssethg if (dep)
3762027Ssethg free(dep);
3772027Ssethg if (linkpath)
3782027Ssethg free(linkpath);
3792027Ssethg if (buf)
3802027Ssethg free(buf);
3812027Ssethg if (real_path)
3822027Ssethg free(real_path);
3832027Ssethg if (*logpp) {
3842027Ssethg free(*logpp);
3852027Ssethg *logpp = NULL;
3861258Smlf }
3872027Ssethg return (rv);
3881258Smlf }
3891258Smlf
3901258Smlf
3911258Smlf /*
3921258Smlf * Given the index into a table (msgcvt_t) of messages, get the message
3931258Smlf * string, converting it to the proper locale if necessary.
3941258Smlf * NOTE: Indexes are defined in cfga_sata.h
3951258Smlf */
3961258Smlf static const char *
get_msg(uint_t msg_index,msgcvt_t * msg_tbl,uint_t tbl_size)3971258Smlf get_msg(uint_t msg_index, msgcvt_t *msg_tbl, uint_t tbl_size)
3981258Smlf {
3991258Smlf if (msg_index >= tbl_size) {
4001258Smlf msg_index = CFGA_SATA_UNKNOWN;
4011258Smlf }
4021258Smlf
4031258Smlf return ((msg_tbl[msg_index].intl) ?
404*10318SXiao-Yu.Zhang@Sun.COM dgettext(TEXT_DOMAIN, msg_tbl[msg_index].msgstr) :
405*10318SXiao-Yu.Zhang@Sun.COM msg_tbl[msg_index].msgstr);
4061258Smlf }
4071258Smlf
4081258Smlf /*
4091258Smlf * Allocates and creates a message string (in *ret_str),
4101258Smlf * by concatenating all the (char *) args together, in order.
4111258Smlf * Last arg MUST be NULL.
4121258Smlf */
4131258Smlf static void
set_msg(char ** ret_str,...)4141258Smlf set_msg(char **ret_str, ...)
4151258Smlf {
4161258Smlf char *str;
4171258Smlf size_t total_len;
4181258Smlf va_list valist;
4191258Smlf
4201258Smlf va_start(valist, ret_str);
4211258Smlf
4221258Smlf total_len = (*ret_str == NULL) ? 0 : strlen(*ret_str);
4231258Smlf
4241258Smlf while ((str = va_arg(valist, char *)) != NULL) {
4251258Smlf size_t len = strlen(str);
4261258Smlf char *old_str = *ret_str;
4271258Smlf
4281258Smlf *ret_str = (char *)realloc(*ret_str, total_len + len + 1);
4291258Smlf if (*ret_str == NULL) {
4301258Smlf /* We're screwed */
4311258Smlf free(old_str);
4321258Smlf va_end(valist);
4331258Smlf return;
4341258Smlf }
4351258Smlf
4361258Smlf (void) strcpy(*ret_str + total_len, str);
4371258Smlf total_len += len;
4381258Smlf }
4391258Smlf
4401258Smlf va_end(valist);
4411258Smlf }
4421258Smlf
4431258Smlf /*
4441258Smlf * Error message handling.
4451258Smlf * For the rv passed in, looks up the corresponding error message string(s),
4461258Smlf * internationalized if necessary, and concatenates it into a new
4471258Smlf * memory buffer, and points *errstring to it.
4481258Smlf * Note not all rvs will result in an error message return, as not all
4491258Smlf * error conditions warrant a SATA-specific error message - for those
4501258Smlf * conditions the cfgadm generic messages are sufficient.
4511258Smlf *
4521258Smlf * Some messages may display ap_id or errno, which is why they are passed
4531258Smlf * in.
4541258Smlf */
4551258Smlf
4561258Smlf cfga_err_t
sata_err_msg(char ** errstring,cfga_sata_ret_t rv,const char * ap_id,int l_errno)4571258Smlf sata_err_msg(
458*10318SXiao-Yu.Zhang@Sun.COM char **errstring,
459*10318SXiao-Yu.Zhang@Sun.COM cfga_sata_ret_t rv,
460*10318SXiao-Yu.Zhang@Sun.COM const char *ap_id,
461*10318SXiao-Yu.Zhang@Sun.COM int l_errno)
4621258Smlf {
4631258Smlf if (errstring == NULL) {
4641258Smlf return (sata_msgs[rv].cfga_err);
4651258Smlf }
4661258Smlf
4671258Smlf /*
4681258Smlf * Generate the appropriate SATA-specific error message(s) (if any).
4691258Smlf */
4701258Smlf switch (rv) {
4711258Smlf case CFGA_SATA_OK:
4721258Smlf case CFGA_NACK:
4731258Smlf /* Special case - do nothing. */
4741258Smlf break;
4751258Smlf
4761258Smlf case CFGA_SATA_UNKNOWN:
4771258Smlf case CFGA_SATA_DYNAMIC_AP:
4781258Smlf case CFGA_SATA_INTERNAL_ERROR:
4791258Smlf case CFGA_SATA_OPTIONS:
4801258Smlf case CFGA_SATA_ALLOC_FAIL:
4811258Smlf case CFGA_SATA_STATE:
4821258Smlf case CFGA_SATA_PRIV:
4831258Smlf case CFGA_SATA_OPNOTSUPP:
4841258Smlf case CFGA_SATA_DATA_ERROR:
4851258Smlf /* These messages require no additional strings passed. */
4861258Smlf set_msg(errstring, ERR_STR(rv), NULL);
4871258Smlf break;
4881258Smlf
4891258Smlf case CFGA_SATA_HWOPNOTSUPP:
4901258Smlf /* hardware-specific help needed */
4911258Smlf set_msg(errstring, ERR_STR(rv), NULL);
4921258Smlf set_msg(errstring, "\n",
493*10318SXiao-Yu.Zhang@Sun.COM dgettext(TEXT_DOMAIN, sata_help[HELP_HEADER]), NULL);
4941258Smlf set_msg(errstring, sata_help[HELP_RESET_PORT], NULL);
4951258Smlf set_msg(errstring, sata_help[HELP_RESET_DEVICE], NULL);
4961258Smlf set_msg(errstring, sata_help[HELP_RESET_ALL], NULL);
4971258Smlf set_msg(errstring, sata_help[HELP_PORT_ACTIVATE], NULL);
4981258Smlf set_msg(errstring, sata_help[HELP_PORT_DEACTIVATE], NULL);
4991258Smlf set_msg(errstring, sata_help[HELP_PORT_SELF_TEST], NULL);
5001258Smlf set_msg(errstring, sata_help[HELP_CNTRL_SELF_TEST], NULL);
5011258Smlf break;
5021258Smlf
5031258Smlf case CFGA_SATA_AP:
5041258Smlf case CFGA_SATA_PORT:
5051258Smlf case CFGA_SATA_NOT_CONNECTED:
5061258Smlf case CFGA_SATA_NOT_CONFIGURED:
5071258Smlf case CFGA_SATA_ALREADY_CONNECTED:
5081258Smlf case CFGA_SATA_ALREADY_CONFIGURED:
5091258Smlf case CFGA_SATA_BUSY:
5101258Smlf case CFGA_SATA_DEVLINK:
5111258Smlf case CFGA_SATA_RCM_HANDLE:
5121258Smlf case CFGA_SATA_RCM_ONLINE:
5131258Smlf case CFGA_SATA_RCM_OFFLINE:
5141258Smlf case CFGA_SATA_RCM_INFO:
5151258Smlf case CFGA_SATA_DEV_CONFIGURE:
5161258Smlf case CFGA_SATA_DEV_UNCONFIGURE:
5171258Smlf case CFGA_SATA_DISCONNECTED:
5181258Smlf /* These messages also print ap_id. */
5191258Smlf set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "", NULL);
5201258Smlf break;
5211258Smlf
5221258Smlf
5231258Smlf case CFGA_SATA_IOCTL:
5241258Smlf case CFGA_SATA_NVLIST:
5251258Smlf /* These messages also print errno. */
5261258Smlf {
5271258Smlf char *errno_str = l_errno ? strerror(l_errno) : "";
5281258Smlf
5291258Smlf set_msg(errstring, ERR_STR(rv), errno_str,
5301258Smlf l_errno ? "\n" : "", NULL);
5311258Smlf break;
5321258Smlf }
5331258Smlf
5341258Smlf case CFGA_SATA_OPEN:
5351258Smlf /* These messages also apid and errno. */
5361258Smlf {
5371258Smlf char *errno_str = l_errno ? strerror(l_errno) : "";
5381258Smlf
5391258Smlf set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "\n",
5401258Smlf errno_str, l_errno ? "\n" : "", NULL);
5411258Smlf break;
5421258Smlf }
5431258Smlf
5441258Smlf default:
5451258Smlf set_msg(errstring, ERR_STR(CFGA_SATA_INTERNAL_ERROR), NULL);
5461258Smlf
5471258Smlf } /* end switch */
5481258Smlf
5491258Smlf
5501258Smlf /*
5511258Smlf * Determine the proper error code to send back to the cfgadm library.
5521258Smlf */
5531258Smlf return (sata_msgs[rv].cfga_err);
5541258Smlf }
5551258Smlf
5561258Smlf
5571258Smlf /*
5581258Smlf * Entry points
5591258Smlf */
5601258Smlf /* cfgadm entry point */
5611258Smlf /*ARGSUSED*/
5621258Smlf cfga_err_t
cfga_change_state(cfga_cmd_t state_change_cmd,const char * ap_id,const char * options,struct cfga_confirm * confp,struct cfga_msg * msgp,char ** errstring,cfga_flags_t flags)5631258Smlf cfga_change_state(
564*10318SXiao-Yu.Zhang@Sun.COM cfga_cmd_t state_change_cmd,
565*10318SXiao-Yu.Zhang@Sun.COM const char *ap_id,
566*10318SXiao-Yu.Zhang@Sun.COM const char *options,
567*10318SXiao-Yu.Zhang@Sun.COM struct cfga_confirm *confp,
568*10318SXiao-Yu.Zhang@Sun.COM struct cfga_msg *msgp,
569*10318SXiao-Yu.Zhang@Sun.COM char **errstring,
570*10318SXiao-Yu.Zhang@Sun.COM cfga_flags_t flags)
5711258Smlf {
5721258Smlf int ret;
5731258Smlf int len;
5741258Smlf char *msg;
5751258Smlf char *devpath;
5761258Smlf nvlist_t *nvl = NULL;
5771258Smlf ap_rstate_t rstate;
5781258Smlf ap_ostate_t ostate;
5791258Smlf devctl_hdl_t hdl = NULL;
5801258Smlf cfga_sata_ret_t rv = CFGA_SATA_OK;
5811258Smlf char *pdyn;
582*10318SXiao-Yu.Zhang@Sun.COM char *str_type;
583*10318SXiao-Yu.Zhang@Sun.COM size_t size;
584*10318SXiao-Yu.Zhang@Sun.COM boolean_t pmult = B_FALSE;
5851258Smlf
5861258Smlf /*
5871258Smlf * All sub-commands which can change state of device require
5881258Smlf * root privileges.
5891258Smlf */
5901258Smlf if (geteuid() != 0) {
5911258Smlf rv = CFGA_SATA_PRIV;
5921258Smlf goto bailout;
5931258Smlf }
5941258Smlf
5951258Smlf if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) {
5961258Smlf (void) cfga_help(msgp, options, flags);
5971258Smlf goto bailout;
5981258Smlf }
5991258Smlf
6001258Smlf if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &nvl,
601*10318SXiao-Yu.Zhang@Sun.COM DC_RDONLY)) != CFGA_SATA_OK) {
6021258Smlf goto bailout;
6031258Smlf }
6041258Smlf
605*10318SXiao-Yu.Zhang@Sun.COM /*
606*10318SXiao-Yu.Zhang@Sun.COM * Checking device type. A port multiplier is not configurable - it is
607*10318SXiao-Yu.Zhang@Sun.COM * already configured as soon as it is connected.
608*10318SXiao-Yu.Zhang@Sun.COM */
609*10318SXiao-Yu.Zhang@Sun.COM if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, NULL,
610*10318SXiao-Yu.Zhang@Sun.COM (void **)&str_type, &size)) != CFGA_SATA_OK) {
611*10318SXiao-Yu.Zhang@Sun.COM /* no such deivce */
612*10318SXiao-Yu.Zhang@Sun.COM goto bailout;
613*10318SXiao-Yu.Zhang@Sun.COM }
614*10318SXiao-Yu.Zhang@Sun.COM if (strncmp(str_type, "sata-pmult", sizeof ("sata-pmult")) == 0) {
615*10318SXiao-Yu.Zhang@Sun.COM pmult = B_TRUE;
616*10318SXiao-Yu.Zhang@Sun.COM }
617*10318SXiao-Yu.Zhang@Sun.COM
6181258Smlf switch (state_change_cmd) {
6191258Smlf case CFGA_CMD_CONFIGURE:
620*10318SXiao-Yu.Zhang@Sun.COM if (pmult == B_TRUE) {
621*10318SXiao-Yu.Zhang@Sun.COM rv = CFGA_SATA_HWOPNOTSUPP;
622*10318SXiao-Yu.Zhang@Sun.COM goto bailout;
623*10318SXiao-Yu.Zhang@Sun.COM }
624*10318SXiao-Yu.Zhang@Sun.COM
6251258Smlf if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
6261258Smlf CFGA_SATA_OK)
6271258Smlf goto bailout;
6281258Smlf
6291258Smlf if (ostate == AP_OSTATE_CONFIGURED) {
6301258Smlf rv = CFGA_SATA_ALREADY_CONFIGURED;
6311258Smlf goto bailout;
6321258Smlf }
6331258Smlf /* Disallow dynamic AP name component */
6341258Smlf if (GET_DYN(ap_id) != NULL) {
6351258Smlf rv = CFGA_SATA_INVALID_DEVNAME;
6361258Smlf goto bailout;
6371258Smlf }
6381258Smlf
6391258Smlf if (rstate == AP_RSTATE_EMPTY) {
6401258Smlf rv = CFGA_SATA_NOT_CONNECTED;
6411258Smlf goto bailout;
6421258Smlf }
6431258Smlf rv = CFGA_SATA_OK;
6441258Smlf
6451258Smlf if (devctl_ap_configure(hdl, nvl) != 0) {
6461258Smlf rv = CFGA_SATA_DEV_CONFIGURE;
6471258Smlf goto bailout;
6481258Smlf }
6491258Smlf
6501258Smlf devpath = sata_get_devicepath(ap_id);
6511258Smlf if (devpath == NULL) {
6521258Smlf int i;
6531258Smlf /*
6541258Smlf * Try for some time as SATA hotplug thread
6551258Smlf * takes a while to create the path then
6561258Smlf * eventually give up.
6571258Smlf */
6581258Smlf for (i = 0; i < 12 && (devpath == NULL); i++) {
6591258Smlf (void) sleep(6);
6601258Smlf devpath = sata_get_devicepath(ap_id);
6611258Smlf }
6621258Smlf
6631258Smlf if (devpath == NULL) {
6641258Smlf rv = CFGA_SATA_DEV_CONFIGURE;
6651258Smlf break;
6661258Smlf }
6671258Smlf }
6681258Smlf
6691258Smlf S_FREE(devpath);
6701258Smlf break;
6711258Smlf
6721258Smlf case CFGA_CMD_UNCONFIGURE:
673*10318SXiao-Yu.Zhang@Sun.COM if (pmult == B_TRUE) {
674*10318SXiao-Yu.Zhang@Sun.COM rv = CFGA_SATA_HWOPNOTSUPP;
675*10318SXiao-Yu.Zhang@Sun.COM goto bailout;
676*10318SXiao-Yu.Zhang@Sun.COM }
677*10318SXiao-Yu.Zhang@Sun.COM
6781258Smlf if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
6791258Smlf CFGA_SATA_OK)
6801258Smlf goto bailout;
6811258Smlf
6821258Smlf if (rstate != AP_RSTATE_CONNECTED) {
6831258Smlf rv = CFGA_SATA_NOT_CONNECTED;
6841258Smlf goto bailout;
6851258Smlf }
6861258Smlf
6871258Smlf if (ostate != AP_OSTATE_CONFIGURED) {
6881258Smlf rv = CFGA_SATA_NOT_CONFIGURED;
6891258Smlf goto bailout;
6901258Smlf }
6911258Smlf /* Strip off AP name dynamic component, if present */
6921258Smlf if ((pdyn = GET_DYN(ap_id)) != NULL) {
6931258Smlf *pdyn = '\0';
6941258Smlf }
6951258Smlf
6961258Smlf rv = CFGA_SATA_OK;
6971258Smlf
6981258Smlf len = strlen(SATA_CONFIRM_DEVICE) +
699*10318SXiao-Yu.Zhang@Sun.COM strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
700*10318SXiao-Yu.Zhang@Sun.COM strlen("Unconfigure") + strlen(ap_id);
7011258Smlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
7021258Smlf (void) snprintf(msg, len + 3, "Unconfigure"
703*10318SXiao-Yu.Zhang@Sun.COM " %s%s\n%s",
704*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_DEVICE, ap_id,
705*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_DEVICE_SUSPEND);
7061258Smlf }
7071258Smlf
7081258Smlf if (!sata_confirm(confp, msg)) {
7091258Smlf free(msg);
7101258Smlf rv = CFGA_SATA_NACK;
7111258Smlf break;
7121258Smlf }
7131258Smlf free(msg);
7141258Smlf
7151258Smlf devpath = sata_get_devicepath(ap_id);
7161258Smlf if (devpath == NULL) {
7171258Smlf (void) printf(
718*10318SXiao-Yu.Zhang@Sun.COM "cfga_change_state: get device path failed\n");
7191258Smlf rv = CFGA_SATA_DEV_UNCONFIGURE;
7201258Smlf break;
7211258Smlf }
7221258Smlf
7231258Smlf if ((rv = sata_rcm_offline(ap_id, errstring, devpath, flags))
7241258Smlf != CFGA_SATA_OK) {
7251258Smlf break;
7261258Smlf }
7271258Smlf
7281258Smlf ret = devctl_ap_unconfigure(hdl, nvl);
7291258Smlf
7301258Smlf if (ret != 0) {
7311258Smlf rv = CFGA_SATA_DEV_UNCONFIGURE;
7321258Smlf if (errno == EBUSY) {
7331258Smlf rv = CFGA_SATA_BUSY;
7341258Smlf }
7351258Smlf (void) sata_rcm_online(ap_id, errstring, devpath,
736*10318SXiao-Yu.Zhang@Sun.COM flags);
7371258Smlf } else {
7381258Smlf (void) sata_rcm_remove(ap_id, errstring, devpath,
739*10318SXiao-Yu.Zhang@Sun.COM flags);
7401258Smlf
7411258Smlf }
7421258Smlf S_FREE(devpath);
7431258Smlf
7441258Smlf break;
7451258Smlf
7461258Smlf case CFGA_CMD_DISCONNECT:
7471258Smlf if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
7481258Smlf CFGA_SATA_OK)
7491258Smlf goto bailout;
7501258Smlf
7511258Smlf if (rstate == AP_RSTATE_DISCONNECTED) {
7521258Smlf rv = CFGA_SATA_DISCONNECTED;
7531258Smlf goto bailout;
7541258Smlf }
7551258Smlf
7561258Smlf /* Strip off AP name dynamic component, if present */
7571258Smlf if ((pdyn = GET_DYN(ap_id)) != NULL) {
7581258Smlf *pdyn = '\0';
7591258Smlf }
7601258Smlf
7611258Smlf
7621258Smlf rv = CFGA_SATA_OK; /* other statuses don't matter */
7631258Smlf
7641258Smlf /*
7651258Smlf * If the port originally with device attached and was
7661258Smlf * unconfigured already, the devicepath for the sd will be
7671258Smlf * removed. sata_get_devicepath in this case is not necessary.
7681258Smlf */
7691258Smlf /* only call rcm_offline if the state was CONFIGURED */
770*10318SXiao-Yu.Zhang@Sun.COM if (ostate == AP_OSTATE_CONFIGURED &&
771*10318SXiao-Yu.Zhang@Sun.COM pmult == B_FALSE) {
7721258Smlf devpath = sata_get_devicepath(ap_id);
7731258Smlf if (devpath == NULL) {
7741258Smlf (void) printf(
7751258Smlf "cfga_change_state: get path failed\n");
7761258Smlf rv = CFGA_SATA_DEV_UNCONFIGURE;
7771258Smlf break;
7781258Smlf }
7791258Smlf
7801258Smlf len = strlen(SATA_CONFIRM_DEVICE) +
781*10318SXiao-Yu.Zhang@Sun.COM strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
782*10318SXiao-Yu.Zhang@Sun.COM strlen("Disconnect") + strlen(ap_id);
7831258Smlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
7841258Smlf (void) snprintf(msg, len + 3,
785*10318SXiao-Yu.Zhang@Sun.COM "Disconnect"
786*10318SXiao-Yu.Zhang@Sun.COM " %s%s\n%s",
787*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_DEVICE, ap_id,
788*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_DEVICE_SUSPEND);
7891258Smlf }
7901258Smlf if (!sata_confirm(confp, msg)) {
7911258Smlf free(msg);
7921258Smlf rv = CFGA_SATA_NACK;
7931258Smlf break;
7941258Smlf }
7951258Smlf free(msg);
7961258Smlf
7971258Smlf if ((rv = sata_rcm_offline(ap_id, errstring,
7981258Smlf devpath, flags)) != CFGA_SATA_OK) {
7991258Smlf break;
8001258Smlf }
8011258Smlf
8021258Smlf ret = devctl_ap_unconfigure(hdl, nvl);
8031258Smlf if (ret != 0) {
8041258Smlf (void) printf(
8051258Smlf "devctl_ap_unconfigure failed\n");
8061258Smlf rv = CFGA_SATA_DEV_UNCONFIGURE;
8071258Smlf if (errno == EBUSY)
8081258Smlf rv = CFGA_SATA_BUSY;
8091258Smlf (void) sata_rcm_online(ap_id, errstring,
810*10318SXiao-Yu.Zhang@Sun.COM devpath, flags);
8111258Smlf S_FREE(devpath);
8121258Smlf
8131258Smlf /*
8141258Smlf * The current policy is that if unconfigure
8151258Smlf * failed, do not continue with disconnect.
8161258Smlf * If the port needs to be forced into the
8171258Smlf * disconnect (shutdown) state,
8181258Smlf * the -x sata_port_poweroff command should be
8191258Smlf * used instead of -c disconnect
8201258Smlf */
8211258Smlf break;
8221258Smlf } else {
8231258Smlf (void) printf("%s\n",
8241258Smlf ERR_STR(CFGA_SATA_DEVICE_UNCONFIGURED));
8251258Smlf (void) sata_rcm_remove(ap_id, errstring,
826*10318SXiao-Yu.Zhang@Sun.COM devpath, flags);
8271258Smlf }
8281258Smlf S_FREE(devpath);
8291258Smlf } else if (rstate == AP_RSTATE_CONNECTED ||
8301258Smlf rstate == AP_RSTATE_EMPTY) {
8311258Smlf len = strlen(SATA_CONFIRM_PORT) +
832*10318SXiao-Yu.Zhang@Sun.COM strlen(SATA_CONFIRM_PORT_DISABLE) +
833*10318SXiao-Yu.Zhang@Sun.COM strlen("Deactivate Port") + strlen(ap_id);
8341258Smlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
8351258Smlf (void) snprintf(msg, len +3,
836*10318SXiao-Yu.Zhang@Sun.COM "Disconnect"
837*10318SXiao-Yu.Zhang@Sun.COM " %s%s\n%s",
838*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_PORT, ap_id,
839*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_PORT_DISABLE);
8401258Smlf }
8411258Smlf if (!sata_confirm(confp, msg)) {
8421258Smlf free(msg);
8431258Smlf rv = CFGA_SATA_NACK;
8441258Smlf break;
8451258Smlf }
8461258Smlf }
8471258Smlf ret = devctl_ap_disconnect(hdl, nvl);
8481258Smlf if (ret != 0) {
8491258Smlf rv = CFGA_SATA_IOCTL;
8501258Smlf if (errno == EBUSY) {
8511258Smlf rv = CFGA_SATA_BUSY;
8521258Smlf }
8531258Smlf }
8541258Smlf break;
8551258Smlf
8561258Smlf case CFGA_CMD_CONNECT:
8571258Smlf if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
8581258Smlf CFGA_SATA_OK)
8591258Smlf goto bailout;
8601258Smlf
8611258Smlf if (rstate == AP_RSTATE_CONNECTED) {
8621258Smlf rv = CFGA_SATA_ALREADY_CONNECTED;
8631258Smlf goto bailout;
8641258Smlf }
8651258Smlf
8661258Smlf len = strlen(SATA_CONFIRM_PORT) +
867*10318SXiao-Yu.Zhang@Sun.COM strlen(SATA_CONFIRM_PORT_ENABLE) +
868*10318SXiao-Yu.Zhang@Sun.COM strlen("Activate Port") + strlen(ap_id);
8691258Smlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
8701258Smlf (void) snprintf(msg, len +3, "Activate"
871*10318SXiao-Yu.Zhang@Sun.COM " %s%s\n%s",
872*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_PORT, ap_id,
873*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_PORT_ENABLE);
8741258Smlf }
8751258Smlf if (!sata_confirm(confp, msg)) {
8761258Smlf rv = CFGA_SATA_NACK;
8771258Smlf break;
8781258Smlf }
8791258Smlf
8801258Smlf /* Disallow dynamic AP name component */
8811258Smlf if (GET_DYN(ap_id) != NULL) {
8821258Smlf rv = CFGA_SATA_INVALID_DEVNAME;
8831258Smlf goto bailout;
8841258Smlf }
8851258Smlf
8861258Smlf ret = devctl_ap_connect(hdl, nvl);
8871258Smlf if (ret != 0) {
8881258Smlf rv = CFGA_SATA_IOCTL;
8891258Smlf } else {
8901258Smlf rv = CFGA_SATA_OK;
8911258Smlf }
8921258Smlf
8931258Smlf break;
8941258Smlf
8951258Smlf case CFGA_CMD_LOAD:
8961258Smlf case CFGA_CMD_UNLOAD:
8971258Smlf (void) cfga_help(msgp, options, flags);
8981258Smlf rv = CFGA_SATA_OPNOTSUPP;
8991258Smlf break;
9001258Smlf
9011258Smlf case CFGA_CMD_NONE:
9021258Smlf default:
9031258Smlf (void) cfga_help(msgp, options, flags);
9041258Smlf rv = CFGA_SATA_INTERNAL_ERROR;
9051258Smlf }
9061258Smlf
9071258Smlf bailout:
9081258Smlf cleanup_after_devctl_cmd(hdl, nvl);
9091258Smlf
9101258Smlf return (sata_err_msg(errstring, rv, ap_id, errno));
9111258Smlf }
9121258Smlf
9131258Smlf /* cfgadm entry point */
9141258Smlf cfga_err_t
cfga_private_func(const char * func,const char * ap_id,const char * options,struct cfga_confirm * confp,struct cfga_msg * msgp,char ** errstring,cfga_flags_t flags)9151258Smlf cfga_private_func(
916*10318SXiao-Yu.Zhang@Sun.COM const char *func,
917*10318SXiao-Yu.Zhang@Sun.COM const char *ap_id,
918*10318SXiao-Yu.Zhang@Sun.COM const char *options,
919*10318SXiao-Yu.Zhang@Sun.COM struct cfga_confirm *confp,
920*10318SXiao-Yu.Zhang@Sun.COM struct cfga_msg *msgp,
921*10318SXiao-Yu.Zhang@Sun.COM char **errstring,
922*10318SXiao-Yu.Zhang@Sun.COM cfga_flags_t flags)
9231258Smlf {
9241258Smlf int len;
9251258Smlf char *msg;
9261258Smlf nvlist_t *list = NULL;
9271258Smlf ap_ostate_t ostate;
9281258Smlf ap_rstate_t rstate;
9291258Smlf devctl_hdl_t hdl = NULL;
9301258Smlf cfga_sata_ret_t rv;
9311258Smlf char *str_p;
9321258Smlf size_t size;
9331258Smlf
9341258Smlf if ((rv = verify_params(ap_id, NULL, errstring)) != CFGA_SATA_OK) {
9351258Smlf (void) cfga_help(msgp, options, flags);
9361258Smlf return (sata_err_msg(errstring, rv, ap_id, errno));
9371258Smlf }
9381258Smlf
9391258Smlf /*
9401258Smlf * All subcommands which can change state of device require
9411258Smlf * root privileges.
9421258Smlf */
9431258Smlf if (geteuid() != 0) {
9441258Smlf rv = CFGA_SATA_PRIV;
9451258Smlf goto bailout;
9461258Smlf }
9471258Smlf
9481258Smlf if (func == NULL) {
9491258Smlf (void) printf("No valid option specified\n");
9501258Smlf rv = CFGA_SATA_OPTIONS;
9511258Smlf goto bailout;
9521258Smlf }
9531258Smlf
9541258Smlf if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &list, 0)) !=
9551258Smlf CFGA_SATA_OK) {
9561258Smlf goto bailout;
9571258Smlf }
9581258Smlf
9591258Smlf /* We do not care here about dynamic AP name component */
9601258Smlf if ((str_p = GET_DYN(ap_id)) != NULL) {
9611258Smlf *str_p = '\0';
9621258Smlf }
9631258Smlf
9641258Smlf rv = CFGA_SATA_OK;
9651258Smlf
9661258Smlf if (strcmp(func, SATA_RESET_PORT) == 0) {
9671258Smlf len = strlen(SATA_CONFIRM_PORT) +
9681258Smlf strlen(SATA_CONFIRM_DEVICE_ABORT) +
9691258Smlf strlen("Reset Port") + strlen(ap_id);
9701258Smlf
9711258Smlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
9721258Smlf (void) snprintf(msg, len +3, "Reset"
973*10318SXiao-Yu.Zhang@Sun.COM " %s%s\n%s",
974*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_PORT, ap_id,
975*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_DEVICE_ABORT);
9761258Smlf } else {
9771258Smlf rv = CFGA_SATA_NACK;
9781258Smlf goto bailout;
9791258Smlf }
9801258Smlf
9811258Smlf if (!sata_confirm(confp, msg)) {
9821258Smlf rv = CFGA_SATA_NACK;
9831258Smlf goto bailout;
9841258Smlf }
9851258Smlf
9861258Smlf rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_PORT, NULL,
987*10318SXiao-Yu.Zhang@Sun.COM (void **)&str_p, &size);
9881258Smlf
9891258Smlf } else if (strcmp(func, SATA_RESET_DEVICE) == 0) {
9901258Smlf if ((rv = port_state(hdl, list, &rstate, &ostate)) !=
9911258Smlf CFGA_SATA_OK)
9921258Smlf goto bailout;
9931258Smlf /*
9941258Smlf * Reset device function requires device to be connected
9951258Smlf */
9961258Smlf if (rstate != AP_RSTATE_CONNECTED) {
9971258Smlf rv = CFGA_SATA_NOT_CONNECTED;
9981258Smlf goto bailout;
9991258Smlf }
10001258Smlf
10011258Smlf len = strlen(SATA_CONFIRM_DEVICE) +
10021258Smlf strlen(SATA_CONFIRM_DEVICE_ABORT) +
10031258Smlf strlen("Reset Device") + strlen(ap_id);
10041258Smlf
10051258Smlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
10061258Smlf (void) snprintf(msg, len +3, "Reset"
1007*10318SXiao-Yu.Zhang@Sun.COM " %s%s\n%s",
1008*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_DEVICE, ap_id,
1009*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_DEVICE_ABORT);
10101258Smlf } else {
10111258Smlf rv = CFGA_SATA_NACK;
10121258Smlf goto bailout;
10131258Smlf }
10141258Smlf
10151258Smlf if (!sata_confirm(confp, msg)) {
10161258Smlf rv = CFGA_SATA_NACK;
10171258Smlf goto bailout;
10181258Smlf }
10191258Smlf
10201258Smlf rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_DEVICE, NULL,
10211258Smlf (void **)&str_p, &size);
10221258Smlf
10231258Smlf } else if (strcmp(func, SATA_RESET_ALL) == 0) {
10241258Smlf len = strlen(SATA_CONFIRM_CONTROLLER) +
10251258Smlf strlen(SATA_CONFIRM_CONTROLLER_ABORT) +
10261258Smlf strlen("Reset All") + strlen(ap_id);
10271258Smlf
10281258Smlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
10291258Smlf (void) snprintf(msg, len +3, "Reset"
1030*10318SXiao-Yu.Zhang@Sun.COM " %s%s\n%s",
1031*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_CONTROLLER, ap_id,
1032*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_CONTROLLER_ABORT);
10331258Smlf } else {
10341258Smlf rv = CFGA_SATA_NACK;
10351258Smlf goto bailout;
10361258Smlf }
10371258Smlf
10381258Smlf if (!sata_confirm(confp, msg)) {
10391258Smlf rv = CFGA_SATA_NACK;
10401258Smlf goto bailout;
10411258Smlf }
10421258Smlf rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_ALL, NULL,
1043*10318SXiao-Yu.Zhang@Sun.COM (void **)&str_p, &size);
10441258Smlf
10451258Smlf } else if (strcmp(func, SATA_PORT_DEACTIVATE) == 0) {
10461258Smlf len = strlen(SATA_CONFIRM_PORT) +
10471258Smlf strlen(SATA_CONFIRM_PORT_DISABLE) +
10481258Smlf strlen("Deactivate Port") + strlen(ap_id);
10491258Smlf
10501258Smlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
10511258Smlf (void) snprintf(msg, len +3, "Deactivate"
1052*10318SXiao-Yu.Zhang@Sun.COM " %s%s\n%s",
1053*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_PORT, ap_id,
1054*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_PORT_DISABLE);
10551258Smlf } else {
10561258Smlf rv = CFGA_SATA_NACK;
10571258Smlf goto bailout;
10581258Smlf }
10591258Smlf if (!sata_confirm(confp, msg)) {
10601258Smlf rv = CFGA_SATA_NACK;
10611258Smlf goto bailout;
10621258Smlf }
10631258Smlf
10641258Smlf rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_DEACTIVATE, NULL,
1065*10318SXiao-Yu.Zhang@Sun.COM (void **)&str_p, &size);
10661258Smlf
10671258Smlf } else if (strcmp(func, SATA_PORT_ACTIVATE) == 0) {
10681258Smlf len = strlen(SATA_CONFIRM_PORT) +
10691258Smlf strlen(SATA_CONFIRM_PORT_ENABLE) +
10701258Smlf strlen("Activate Port") + strlen(ap_id);
10711258Smlf
10721258Smlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
10731258Smlf (void) snprintf(msg, len +3, "Activate"
1074*10318SXiao-Yu.Zhang@Sun.COM " %s%s\n%s",
1075*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_PORT, ap_id,
1076*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_PORT_ENABLE);
10771258Smlf } else {
10781258Smlf rv = CFGA_SATA_NACK;
10791258Smlf goto bailout;
10801258Smlf }
10811258Smlf if (!sata_confirm(confp, msg)) {
10821258Smlf rv = CFGA_SATA_NACK;
10831258Smlf goto bailout;
10841258Smlf }
10851258Smlf
10861258Smlf rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_ACTIVATE,
10871258Smlf NULL, (void **)&str_p, &size);
1088*10318SXiao-Yu.Zhang@Sun.COM goto bailout;
10891258Smlf
10901258Smlf } else if (strcmp(func, SATA_PORT_SELF_TEST) == 0) {
10911258Smlf len = strlen(SATA_CONFIRM_PORT) +
10921258Smlf strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
10931258Smlf strlen("Self Test Port") + strlen(ap_id);
10941258Smlf
10951258Smlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
10961258Smlf (void) snprintf(msg, len +3, "Self Test"
1097*10318SXiao-Yu.Zhang@Sun.COM " %s%s\n%s",
1098*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_PORT, ap_id,
1099*10318SXiao-Yu.Zhang@Sun.COM SATA_CONFIRM_DEVICE_SUSPEND);
11001258Smlf } else {
11011258Smlf rv = CFGA_SATA_NACK;
11021258Smlf goto bailout;
11031258Smlf }
11041258Smlf if (!sata_confirm(confp, msg)) {
11051258Smlf rv = CFGA_SATA_NACK;
11061258Smlf goto bailout;
11071258Smlf }
11081258Smlf
11091258Smlf rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_SELF_TEST,
1110*10318SXiao-Yu.Zhang@Sun.COM NULL, (void **)&str_p, &size);
11111258Smlf } else {
11121258Smlf /* Unrecognized operation request */
11131258Smlf rv = CFGA_SATA_HWOPNOTSUPP;
11141258Smlf }
11151258Smlf
11161258Smlf bailout:
11171258Smlf cleanup_after_devctl_cmd(hdl, list);
11181258Smlf
11191258Smlf return (sata_err_msg(errstring, rv, ap_id, errno));
11201258Smlf
11211258Smlf }
11221258Smlf
11231258Smlf /* cfgadm entry point */
11241258Smlf /*ARGSUSED*/
11251258Smlf cfga_err_t
cfga_test(const char * ap_id,const char * options,struct cfga_msg * msgp,char ** errstring,cfga_flags_t flags)11261258Smlf cfga_test(
1127*10318SXiao-Yu.Zhang@Sun.COM const char *ap_id,
1128*10318SXiao-Yu.Zhang@Sun.COM const char *options,
1129*10318SXiao-Yu.Zhang@Sun.COM struct cfga_msg *msgp,
1130*10318SXiao-Yu.Zhang@Sun.COM char **errstring,
1131*10318SXiao-Yu.Zhang@Sun.COM cfga_flags_t flags)
11321258Smlf {
11331258Smlf /* Should call ioctl for self test - phase 2 */
11341258Smlf return (CFGA_OPNOTSUPP);
11351258Smlf }
11361258Smlf
11371258Smlf
11381258Smlf int
sata_check_target_node(di_node_t node,void * arg)11391258Smlf sata_check_target_node(di_node_t node, void *arg)
11401258Smlf {
11411258Smlf char *minorpath;
11421258Smlf char *cp;
11431258Smlf
11441258Smlf minorpath = di_devfs_minor_path(di_minor_next(node, DI_MINOR_NIL));
11451258Smlf if (minorpath != NULL) {
11461258Smlf if (strstr(minorpath, arg) != NULL) {
11471258Smlf cp = strrchr(minorpath, (int)*MINOR_SEP);
11481258Smlf if (cp != NULL) {
11491258Smlf (void) strcpy(arg, cp);
11501258Smlf }
11511258Smlf free(minorpath);
11521258Smlf return (DI_WALK_TERMINATE);
11531258Smlf }
11541258Smlf free(minorpath);
11551258Smlf }
11561258Smlf return (DI_WALK_CONTINUE);
11571258Smlf }
11581258Smlf
11594707Svikram struct chk_dev {
11604707Svikram int c_isblk;
11614707Svikram char *c_minor;
11624707Svikram };
11634707Svikram
11644707Svikram /*ARGSUSED*/
11654707Svikram static int
chk_dev_fcn(di_node_t node,di_minor_t minor,void * arg)11664707Svikram chk_dev_fcn(di_node_t node, di_minor_t minor, void *arg)
11674707Svikram {
11684707Svikram char *mn;
11694707Svikram struct chk_dev *chkp = (struct chk_dev *)arg;
11704707Svikram
11714707Svikram mn = di_minor_name(minor);
11724707Svikram if (mn == NULL)
11734707Svikram return (DI_WALK_CONTINUE);
11744707Svikram
11754707Svikram if (strcmp(mn, chkp->c_minor) != 0)
11764707Svikram return (DI_WALK_CONTINUE);
11774707Svikram
11784707Svikram chkp->c_isblk = di_minor_spectype(minor) == S_IFBLK ? 1 : 0;
11794707Svikram
11804707Svikram return (DI_WALK_TERMINATE);
11814707Svikram }
11824707Svikram
11834707Svikram /*
11844707Svikram * Don't use devfs if stat() in /devices fails. Use libdevinfo instead.
11854707Svikram * Retired devices don't show up in devfs.
11864707Svikram *
11874707Svikram * Returns:
11884707Svikram * 1 - minor exists and is of type BLK
11894707Svikram * 0 - minor does not exist or is not of type BLK.
11904707Svikram */
11914707Svikram static int
is_devinfo_blk(char * minor_path)11924707Svikram is_devinfo_blk(char *minor_path)
11934707Svikram {
11944707Svikram char *minor_portion;
11954707Svikram struct chk_dev chk_dev;
11964707Svikram di_node_t node;
11974707Svikram int rv;
11984707Svikram
11994707Svikram /*
12004707Svikram * prune minor path for di_init() - no /devices prefix and no minor name
12014707Svikram */
12024707Svikram if (strncmp(minor_path, "/devices/", strlen("/devices/")) != 0)
12034707Svikram return (0);
12044707Svikram
12054707Svikram minor_portion = strrchr(minor_path, *MINOR_SEP);
12064707Svikram if (minor_portion == NULL)
12074707Svikram return (0);
12084707Svikram
12094707Svikram *minor_portion = 0;
12104707Svikram
12114707Svikram node = di_init(minor_path + strlen("/devices"), DINFOMINOR);
12124707Svikram
12134707Svikram *minor_portion = *MINOR_SEP;
12144707Svikram
12154707Svikram if (node == DI_NODE_NIL)
12164707Svikram return (0);
12174707Svikram
12184707Svikram chk_dev.c_isblk = 0;
12194707Svikram chk_dev.c_minor = minor_portion + 1;
12204707Svikram
12214707Svikram rv = di_walk_minor(node, NULL, 0, &chk_dev, chk_dev_fcn);
12224707Svikram
12234707Svikram di_fini(node);
12244707Svikram
12254707Svikram if (rv == 0 && chk_dev.c_isblk)
12264707Svikram return (1);
12274707Svikram else
12284707Svikram return (0);
12294707Svikram }
12301258Smlf
12311258Smlf /*
12321258Smlf * The dynamic component buffer returned by this function has to be freed!
12331258Smlf */
12341258Smlf int
sata_make_dyncomp(const char * ap_id,char ** dyncomp,const char * type)12358010SYing.Tian@Sun.COM sata_make_dyncomp(const char *ap_id, char **dyncomp, const char *type)
12361258Smlf {
12372027Ssethg char *devpath = NULL;
12382027Ssethg char *cp = NULL;
12392027Ssethg int l_errno;
12402027Ssethg char minor_path[MAXPATHLEN];
12412027Ssethg char name_part[MAXNAMELEN];
12422027Ssethg char *devlink = NULL;
12432027Ssethg char *minor_portion = NULL;
12442027Ssethg int deplen;
12452027Ssethg int err;
12462027Ssethg DIR *dp = NULL;
12472027Ssethg struct stat sb;
12482027Ssethg struct dirent *dep = NULL;
12492027Ssethg struct dirent *newdep = NULL;
12502247Ssethg char *p;
12511258Smlf
12521258Smlf assert(dyncomp != NULL);
12531258Smlf
12541258Smlf /*
12551258Smlf * Get target node path
12561258Smlf */
12571258Smlf devpath = sata_get_devicepath(ap_id);
12581258Smlf if (devpath == NULL) {
12592027Ssethg
12601258Smlf (void) printf("cfga_list_ext: cannot locate target device\n");
12611258Smlf return (CFGA_SATA_DYNAMIC_AP);
12622027Ssethg
12631258Smlf } else {
12642027Ssethg
12652027Ssethg cp = strrchr(devpath, *PATH_SEP);
12662027Ssethg assert(cp != NULL);
12672027Ssethg *cp = 0; /* terminate path for opendir() */
12681258Smlf
12692027Ssethg (void) strncpy(name_part, cp + 1, MAXNAMELEN);
12701258Smlf
12712027Ssethg /*
12722027Ssethg * Using libdevinfo for this is overkill and kills
12732027Ssethg * performance when many consumers are using libcfgadm
12742027Ssethg * concurrently.
12752027Ssethg */
12762027Ssethg if ((dp = opendir(devpath)) == NULL) {
12771258Smlf goto bailout;
12781258Smlf }
12791258Smlf
12801258Smlf /*
12812027Ssethg * deplen is large enough to fit the largest path-
12822027Ssethg * struct dirent includes one byte (the terminator)
12832027Ssethg * so we don't add 1 to the calculation here.
12841258Smlf */
12853019Ssethg deplen = pathconf(devpath, _PC_NAME_MAX);
12863019Ssethg deplen = ((deplen <= 0) ? MAXNAMELEN : deplen) +
12872027Ssethg sizeof (struct dirent);
12882027Ssethg dep = (struct dirent *)malloc(deplen);
12892027Ssethg if (dep == NULL)
12902027Ssethg goto bailout;
12912027Ssethg
12922027Ssethg while ((err = readdir_r(dp, dep, &newdep)) == 0 &&
12932027Ssethg newdep != NULL) {
12942027Ssethg
12952027Ssethg assert(newdep == dep);
12961258Smlf
12972027Ssethg if (strcmp(dep->d_name, ".") == 0 ||
12982027Ssethg strcmp(dep->d_name, "..") == 0 ||
12992027Ssethg (minor_portion = strchr(dep->d_name,
13002027Ssethg *MINOR_SEP)) == NULL)
13012027Ssethg continue;
13022027Ssethg
13032027Ssethg *minor_portion = 0;
13042027Ssethg if (strcmp(dep->d_name, name_part) != 0)
13052027Ssethg continue;
13062027Ssethg *minor_portion = *MINOR_SEP;
13072027Ssethg
13082027Ssethg (void) snprintf(minor_path, MAXPATHLEN,
13092027Ssethg "%s/%s", devpath, dep->d_name);
13102027Ssethg
13114707Svikram /*
13128010SYing.Tian@Sun.COM * Break directly for tape device
13138010SYing.Tian@Sun.COM */
13148010SYing.Tian@Sun.COM if (strcmp(type, "tape") == 0)
13158010SYing.Tian@Sun.COM break;
13168010SYing.Tian@Sun.COM
13178010SYing.Tian@Sun.COM /*
13184707Svikram * If stat() fails, the device *may* be retired.
13194707Svikram * Check via libdevinfo if the device has a BLK minor.
13204707Svikram * We don't use libdevinfo all the time, since taking
13214707Svikram * a snapshot is slower than a stat().
13224707Svikram */
13234707Svikram if (stat(minor_path, &sb) < 0) {
13244707Svikram if (is_devinfo_blk(minor_path)) {
13254707Svikram break;
13264707Svikram } else {
13274707Svikram continue;
13284707Svikram }
13294707Svikram }
13302027Ssethg
13312027Ssethg if (S_ISBLK(sb.st_mode))
13322027Ssethg break;
13334707Svikram
13341258Smlf }
13351258Smlf
13362027Ssethg (void) closedir(dp);
13372027Ssethg free(dep);
13381258Smlf free(devpath);
13391258Smlf
13402027Ssethg dp = NULL;
13412027Ssethg dep = NULL;
13422027Ssethg devpath = NULL;
13432027Ssethg
13442027Ssethg /*
13452027Ssethg * If there was an error, or we didn't exit the loop
13462027Ssethg * by finding a block or character device, bail out.
13472027Ssethg */
13482027Ssethg if (err != 0 || newdep == NULL)
13492027Ssethg goto bailout;
13502027Ssethg
13512027Ssethg /*
13528010SYing.Tian@Sun.COM * Look for links to the physical path in /dev/dsk
13538010SYing.Tian@Sun.COM * and /dev/rmt. So far, sata modue supports disk,
13548010SYing.Tian@Sun.COM * dvd and tape devices, so we will first look for
13558010SYing.Tian@Sun.COM * BLOCK devices, and then look for tape devices.
13562027Ssethg */
13572027Ssethg (void) physpath_to_devlink("/dev/dsk",
13582027Ssethg minor_path, &devlink, &l_errno);
13591258Smlf
13601258Smlf /* postprocess and copy logical name here */
13611258Smlf if (devlink != NULL) {
13621258Smlf /*
13632247Ssethg * For disks, remove partition/slice info
13641258Smlf */
13652027Ssethg if ((cp = strstr(devlink, "dsk/")) != NULL) {
13662247Ssethg /* cXtYdZ[(s[0..15])|(p[0..X])] */
13672247Ssethg if ((p = strchr(cp + 4, 'd')) != NULL) {
13682247Ssethg p++; /* Skip the 'd' */
13692247Ssethg while (*p != 0 && isdigit(*p))
13702247Ssethg p++;
13712247Ssethg *p = 0;
13722247Ssethg }
13732027Ssethg *dyncomp = strdup(cp);
13741258Smlf }
13752027Ssethg
13761258Smlf free(devlink);
13778010SYing.Tian@Sun.COM } else if (strcmp(type, "tape") == 0) {
13788010SYing.Tian@Sun.COM
13798010SYing.Tian@Sun.COM /*
13808010SYing.Tian@Sun.COM * For tape device, logical name looks like
13818010SYing.Tian@Sun.COM * rmt/X
13828010SYing.Tian@Sun.COM */
13838010SYing.Tian@Sun.COM (void) physpath_to_devlink("/dev/rmt",
13848010SYing.Tian@Sun.COM minor_path, &devlink, &l_errno);
13858010SYing.Tian@Sun.COM
13868010SYing.Tian@Sun.COM if (devlink != NULL) {
13878010SYing.Tian@Sun.COM if ((cp = strstr(devlink, "rmt/")) != NULL) {
13888010SYing.Tian@Sun.COM *dyncomp = strdup(cp);
13898010SYing.Tian@Sun.COM }
13908010SYing.Tian@Sun.COM
13918010SYing.Tian@Sun.COM free(devlink);
13928010SYing.Tian@Sun.COM }
13931258Smlf }
13942027Ssethg
13951258Smlf return (SATA_CFGA_OK);
13961258Smlf }
13972027Ssethg
13981258Smlf bailout:
13992027Ssethg if (dp)
14002027Ssethg (void) closedir(dp);
14012027Ssethg if (devpath)
14021258Smlf free(devpath);
14032027Ssethg if (dep)
14042027Ssethg free(dep);
14051258Smlf return (CFGA_SATA_DYNAMIC_AP);
14061258Smlf }
14071258Smlf
14081258Smlf /* cfgadm entry point */
14091258Smlf /*ARGSUSED*/
14101258Smlf cfga_err_t
cfga_list_ext(const char * ap_id,cfga_list_data_t ** ap_id_list,int * nlistp,const char * options,const char * listopts,char ** errstring,cfga_flags_t flags)14111258Smlf cfga_list_ext(
1412*10318SXiao-Yu.Zhang@Sun.COM const char *ap_id,
1413*10318SXiao-Yu.Zhang@Sun.COM cfga_list_data_t **ap_id_list,
1414*10318SXiao-Yu.Zhang@Sun.COM int *nlistp,
1415*10318SXiao-Yu.Zhang@Sun.COM const char *options,
1416*10318SXiao-Yu.Zhang@Sun.COM const char *listopts,
1417*10318SXiao-Yu.Zhang@Sun.COM char **errstring,
1418*10318SXiao-Yu.Zhang@Sun.COM cfga_flags_t flags)
14191258Smlf {
14201258Smlf int l_errno;
14211258Smlf char *ap_id_log = NULL;
14221258Smlf size_t size;
14231258Smlf nvlist_t *user_nvlist = NULL;
14241258Smlf devctl_hdl_t devctl_hdl = NULL;
14251258Smlf cfga_sata_ret_t rv = CFGA_SATA_OK;
14261258Smlf devctl_ap_state_t devctl_ap_state;
14271258Smlf char *pdyn;
1428*10318SXiao-Yu.Zhang@Sun.COM boolean_t pmult = B_FALSE;
1429*10318SXiao-Yu.Zhang@Sun.COM uint32_t port;
14301258Smlf
14311258Smlf
14321258Smlf if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) {
14331258Smlf (void) cfga_help(NULL, options, flags);
14341258Smlf goto bailout;
14351258Smlf }
14361258Smlf /* We do not care here about dynamic AP name component */
14371258Smlf if ((pdyn = GET_DYN(ap_id)) != NULL) {
14381258Smlf *pdyn = '\0';
14391258Smlf }
14401258Smlf
14411258Smlf if (ap_id_list == NULL || nlistp == NULL) {
14421258Smlf rv = CFGA_SATA_DATA_ERROR;
14431258Smlf (void) cfga_help(NULL, options, flags);
14441258Smlf goto bailout;
14451258Smlf }
14461258Smlf
14471258Smlf /* Get ap status */
14481258Smlf if ((rv = setup_for_devctl_cmd(ap_id, &devctl_hdl, &user_nvlist,
14491258Smlf DC_RDONLY)) != CFGA_SATA_OK) {
14501258Smlf goto bailout;
14511258Smlf }
14521258Smlf
14531258Smlf /* will call dc_cmd to send IOCTL to kernel */
14541258Smlf if (devctl_ap_getstate(devctl_hdl, user_nvlist,
14551258Smlf &devctl_ap_state) == -1) {
14561258Smlf cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
14571258Smlf rv = CFGA_SATA_IOCTL;
14581258Smlf goto bailout;
14591258Smlf }
14601258Smlf
14611258Smlf cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
14621258Smlf
14631258Smlf /*
14641258Smlf * Create cfga_list_data_t struct.
14651258Smlf */
14661258Smlf if ((*ap_id_list =
14671258Smlf (cfga_list_data_t *)malloc(sizeof (**ap_id_list))) == NULL) {
14681258Smlf rv = CFGA_SATA_ALLOC_FAIL;
14691258Smlf goto bailout;
14701258Smlf }
14711258Smlf *nlistp = 1;
14721258Smlf
14731258Smlf /*
14741258Smlf * Rest of the code fills in the cfga_list_data_t struct.
14751258Smlf */
14761258Smlf
14771258Smlf /* Get /dev/cfg path to corresponding to the physical ap_id */
14781258Smlf /* Remember ap_id_log must be freed */
14792027Ssethg rv = physpath_to_devlink(CFGA_DEV_DIR, (char *)ap_id,
14802027Ssethg &ap_id_log, &l_errno);
14811258Smlf
14821258Smlf if (rv != 0) {
14831258Smlf rv = CFGA_SATA_DEVLINK;
14841258Smlf goto bailout;
14851258Smlf }
14861258Smlf
14871258Smlf /* Get logical ap_id corresponding to the physical */
14882033Ssethg if (ap_id_log == NULL || strstr(ap_id_log, CFGA_DEV_DIR) == NULL) {
14891258Smlf rv = CFGA_SATA_DEVLINK;
14901258Smlf goto bailout;
14911258Smlf }
14921258Smlf
14931258Smlf (void) strlcpy((*ap_id_list)->ap_log_id,
14941258Smlf /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR)+ 1,
14951258Smlf sizeof ((*ap_id_list)->ap_log_id));
14961258Smlf
14971258Smlf free(ap_id_log);
14981258Smlf ap_id_log = NULL;
14991258Smlf
15001258Smlf (void) strlcpy((*ap_id_list)->ap_phys_id, ap_id,
15011258Smlf sizeof ((*ap_id_list)->ap_phys_id));
15021258Smlf
15031258Smlf switch (devctl_ap_state.ap_rstate) {
1504*10318SXiao-Yu.Zhang@Sun.COM case AP_RSTATE_EMPTY:
1505*10318SXiao-Yu.Zhang@Sun.COM (*ap_id_list)->ap_r_state = CFGA_STAT_EMPTY;
1506*10318SXiao-Yu.Zhang@Sun.COM break;
15071258Smlf
1508*10318SXiao-Yu.Zhang@Sun.COM case AP_RSTATE_DISCONNECTED:
1509*10318SXiao-Yu.Zhang@Sun.COM (*ap_id_list)->ap_r_state = CFGA_STAT_DISCONNECTED;
1510*10318SXiao-Yu.Zhang@Sun.COM break;
15111258Smlf
1512*10318SXiao-Yu.Zhang@Sun.COM case AP_RSTATE_CONNECTED:
1513*10318SXiao-Yu.Zhang@Sun.COM (*ap_id_list)->ap_r_state = CFGA_STAT_CONNECTED;
1514*10318SXiao-Yu.Zhang@Sun.COM break;
15151258Smlf
1516*10318SXiao-Yu.Zhang@Sun.COM default:
1517*10318SXiao-Yu.Zhang@Sun.COM rv = CFGA_SATA_STATE;
1518*10318SXiao-Yu.Zhang@Sun.COM goto bailout;
15191258Smlf }
15201258Smlf
15211258Smlf switch (devctl_ap_state.ap_ostate) {
1522*10318SXiao-Yu.Zhang@Sun.COM case AP_OSTATE_CONFIGURED:
1523*10318SXiao-Yu.Zhang@Sun.COM (*ap_id_list)->ap_o_state = CFGA_STAT_CONFIGURED;
1524*10318SXiao-Yu.Zhang@Sun.COM break;
15251258Smlf
1526*10318SXiao-Yu.Zhang@Sun.COM case AP_OSTATE_UNCONFIGURED:
1527*10318SXiao-Yu.Zhang@Sun.COM (*ap_id_list)->ap_o_state = CFGA_STAT_UNCONFIGURED;
1528*10318SXiao-Yu.Zhang@Sun.COM break;
15291258Smlf
1530*10318SXiao-Yu.Zhang@Sun.COM default:
1531*10318SXiao-Yu.Zhang@Sun.COM rv = CFGA_SATA_STATE;
1532*10318SXiao-Yu.Zhang@Sun.COM goto bailout;
15331258Smlf }
15341258Smlf
15351258Smlf switch (devctl_ap_state.ap_condition) {
1536*10318SXiao-Yu.Zhang@Sun.COM case AP_COND_OK:
1537*10318SXiao-Yu.Zhang@Sun.COM (*ap_id_list)->ap_cond = CFGA_COND_OK;
1538*10318SXiao-Yu.Zhang@Sun.COM break;
15391258Smlf
1540*10318SXiao-Yu.Zhang@Sun.COM case AP_COND_FAILING:
1541*10318SXiao-Yu.Zhang@Sun.COM (*ap_id_list)->ap_cond = CFGA_COND_FAILING;
1542*10318SXiao-Yu.Zhang@Sun.COM break;
15431258Smlf
1544*10318SXiao-Yu.Zhang@Sun.COM case AP_COND_FAILED:
1545*10318SXiao-Yu.Zhang@Sun.COM (*ap_id_list)->ap_cond = CFGA_COND_FAILED;
1546*10318SXiao-Yu.Zhang@Sun.COM break;
15471258Smlf
1548*10318SXiao-Yu.Zhang@Sun.COM case AP_COND_UNUSABLE:
1549*10318SXiao-Yu.Zhang@Sun.COM (*ap_id_list)->ap_cond = CFGA_COND_UNUSABLE;
1550*10318SXiao-Yu.Zhang@Sun.COM break;
15511258Smlf
1552*10318SXiao-Yu.Zhang@Sun.COM case AP_COND_UNKNOWN:
1553*10318SXiao-Yu.Zhang@Sun.COM (*ap_id_list)->ap_cond = CFGA_COND_UNKNOWN;
1554*10318SXiao-Yu.Zhang@Sun.COM break;
15551258Smlf
1556*10318SXiao-Yu.Zhang@Sun.COM default:
1557*10318SXiao-Yu.Zhang@Sun.COM rv = CFGA_SATA_STATE;
1558*10318SXiao-Yu.Zhang@Sun.COM goto bailout;
15591258Smlf }
15601258Smlf
15611258Smlf (*ap_id_list)->ap_class[0] = '\0'; /* Filled by libcfgadm */
15621258Smlf (*ap_id_list)->ap_busy = devctl_ap_state.ap_in_transition;
15631258Smlf (*ap_id_list)->ap_status_time = devctl_ap_state.ap_last_change;
15641258Smlf (*ap_id_list)->ap_info[0] = NULL;
15651258Smlf
15661258Smlf if ((*ap_id_list)->ap_r_state == CFGA_STAT_CONNECTED) {
15671258Smlf char *str_p;
15681258Smlf int skip, i;
15691258Smlf
15701258Smlf /*
15711258Smlf * Fill in the 'Information' field for the -v option
15721258Smlf * Model (MOD:)
15731258Smlf */
15741258Smlf if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_MODEL_INFO,
15751258Smlf NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) {
15761258Smlf (void) printf(
1577*10318SXiao-Yu.Zhang@Sun.COM "SATA_CFGA_GET_MODULE_INFO ioctl failed\n");
15781258Smlf goto bailout;
15791258Smlf }
15801258Smlf /* drop leading and trailing spaces */
15811258Smlf skip = strspn(str_p, " ");
15821258Smlf for (i = size - 1; i >= 0; i--) {
15831258Smlf if (str_p[i] == '\040')
15841258Smlf str_p[i] = '\0';
15851258Smlf else if (str_p[i] != '\0')
15861258Smlf break;
15871258Smlf }
15881258Smlf
15891258Smlf (void) strlcpy((*ap_id_list)->ap_info, "Mod: ",
1590*10318SXiao-Yu.Zhang@Sun.COM sizeof ((*ap_id_list)->ap_info));
15911258Smlf (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
1592*10318SXiao-Yu.Zhang@Sun.COM sizeof ((*ap_id_list)->ap_info));
15931258Smlf
15941258Smlf free(str_p);
15951258Smlf
15961258Smlf /*
15971258Smlf * Fill in the 'Information' field for the -v option
15981258Smlf * Firmware revision (FREV:)
15991258Smlf */
16001258Smlf if ((rv = do_control_ioctl(ap_id,
16011258Smlf SATA_CFGA_GET_REVFIRMWARE_INFO,
16021258Smlf NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) {
16031258Smlf (void) printf(
16041258Smlf "SATA_CFGA_GET_REVFIRMWARE_INFO ioctl failed\n");
16051258Smlf goto bailout;
16061258Smlf }
16071258Smlf /* drop leading and trailing spaces */
16081258Smlf skip = strspn(str_p, " ");
16091258Smlf for (i = size - 1; i >= 0; i--) {
16101258Smlf if (str_p[i] == '\040')
16111258Smlf str_p[i] = '\0';
16121258Smlf else if (str_p[i] != '\0')
16131258Smlf break;
16141258Smlf }
16151258Smlf (void) strlcat((*ap_id_list)->ap_info, " FRev: ",
1616*10318SXiao-Yu.Zhang@Sun.COM sizeof ((*ap_id_list)->ap_info));
16171258Smlf (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
1618*10318SXiao-Yu.Zhang@Sun.COM sizeof ((*ap_id_list)->ap_info));
16191258Smlf
16201258Smlf free(str_p);
16211258Smlf
16221258Smlf
16231258Smlf /*
16241258Smlf * Fill in the 'Information' field for the -v option
16251258Smlf * Serial Number (SN:)
16261258Smlf */
16271258Smlf if ((rv = do_control_ioctl(ap_id,
16281258Smlf SATA_CFGA_GET_SERIALNUMBER_INFO,
16291258Smlf NULL, (void **)&str_p, &size)) != CFGA_SATA_OK) {
16301258Smlf (void) printf(
16311258Smlf "SATA_CFGA_GET_SERIALNUMBER_INFO ioctl failed\n");
16321258Smlf goto bailout;
16331258Smlf }
16341258Smlf /* drop leading and trailing spaces */
16351258Smlf skip = strspn(str_p, " ");
16361258Smlf for (i = size - 1; i >= 0; i--) {
16371258Smlf if (str_p[i] == '\040')
16381258Smlf str_p[i] = '\0';
16391258Smlf else if (str_p[i] != '\0')
16401258Smlf break;
16411258Smlf }
16421258Smlf (void) strlcat((*ap_id_list)->ap_info, " SN: ",
1643*10318SXiao-Yu.Zhang@Sun.COM sizeof ((*ap_id_list)->ap_info));
16441258Smlf (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
1645*10318SXiao-Yu.Zhang@Sun.COM sizeof ((*ap_id_list)->ap_info));
16461258Smlf
16471258Smlf free(str_p);
16481258Smlf
16491258Smlf
16501258Smlf
16511258Smlf /* Fill in ap_type which is collected from HBA driver */
16521258Smlf /* call do_control_ioctl TBD */
16531258Smlf if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, NULL,
16541258Smlf (void **)&str_p, &size)) != CFGA_SATA_OK) {
16551258Smlf (void) printf(
1656*10318SXiao-Yu.Zhang@Sun.COM "SATA_CFGA_GET_AP_TYPE ioctl failed\n");
16571258Smlf goto bailout;
16581258Smlf }
16591258Smlf
16601258Smlf (void) strlcpy((*ap_id_list)->ap_type, str_p,
1661*10318SXiao-Yu.Zhang@Sun.COM sizeof ((*ap_id_list)->ap_type));
16621258Smlf
16631258Smlf free(str_p);
16641258Smlf
1665*10318SXiao-Yu.Zhang@Sun.COM /*
1666*10318SXiao-Yu.Zhang@Sun.COM * Checking device type. Port multiplier has no dynamic
1667*10318SXiao-Yu.Zhang@Sun.COM * suffix.
1668*10318SXiao-Yu.Zhang@Sun.COM */
1669*10318SXiao-Yu.Zhang@Sun.COM if (strncmp((*ap_id_list)->ap_type, "sata-pmult",
1670*10318SXiao-Yu.Zhang@Sun.COM sizeof ("sata-pmult")) == 0)
1671*10318SXiao-Yu.Zhang@Sun.COM pmult = B_TRUE;
1672*10318SXiao-Yu.Zhang@Sun.COM
1673*10318SXiao-Yu.Zhang@Sun.COM if ((*ap_id_list)->ap_o_state == CFGA_STAT_CONFIGURED &&
1674*10318SXiao-Yu.Zhang@Sun.COM pmult == B_FALSE) {
16751258Smlf
16761258Smlf char *dyncomp = NULL;
16771258Smlf
16781258Smlf /*
16791258Smlf * This is the case where we need to generate
16801258Smlf * a dynamic component of the ap_id, i.e. device.
16811258Smlf */
16828010SYing.Tian@Sun.COM rv = sata_make_dyncomp(ap_id, &dyncomp,
16838010SYing.Tian@Sun.COM (*ap_id_list)->ap_type);
16841258Smlf if (rv != CFGA_SATA_OK)
16851258Smlf goto bailout;
16861258Smlf if (dyncomp != NULL) {
16871258Smlf (void) strcat((*ap_id_list)->ap_log_id,
1688*10318SXiao-Yu.Zhang@Sun.COM DYN_SEP);
16891258Smlf (void) strlcat((*ap_id_list)->ap_log_id,
1690*10318SXiao-Yu.Zhang@Sun.COM dyncomp,
1691*10318SXiao-Yu.Zhang@Sun.COM sizeof ((*ap_id_list)->ap_log_id));
16921258Smlf free(dyncomp);
16931258Smlf }
16941258Smlf }
16951258Smlf
16961258Smlf } else {
1697*10318SXiao-Yu.Zhang@Sun.COM /* This is an empty port */
1698*10318SXiao-Yu.Zhang@Sun.COM if (get_port_num(ap_id, &port) != SATA_CFGA_OK) {
1699*10318SXiao-Yu.Zhang@Sun.COM goto bailout;
1700*10318SXiao-Yu.Zhang@Sun.COM }
1701*10318SXiao-Yu.Zhang@Sun.COM
1702*10318SXiao-Yu.Zhang@Sun.COM if (port & SATA_CFGA_PMPORT_QUAL) {
1703*10318SXiao-Yu.Zhang@Sun.COM (void) strlcpy((*ap_id_list)->ap_type, "pmult-port",
1704*10318SXiao-Yu.Zhang@Sun.COM sizeof ((*ap_id_list)->ap_type));
1705*10318SXiao-Yu.Zhang@Sun.COM } else {
1706*10318SXiao-Yu.Zhang@Sun.COM (void) strlcpy((*ap_id_list)->ap_type, "sata-port",
1707*10318SXiao-Yu.Zhang@Sun.COM sizeof ((*ap_id_list)->ap_type));
1708*10318SXiao-Yu.Zhang@Sun.COM }
17091258Smlf }
17101258Smlf
17111258Smlf return (sata_err_msg(errstring, rv, ap_id, errno));
17121258Smlf
17131258Smlf bailout:
17141258Smlf if (*ap_id_list != NULL) {
17151258Smlf free(*ap_id_list);
17161258Smlf }
17171258Smlf if (ap_id_log != NULL) {
17181258Smlf free(ap_id_log);
17191258Smlf }
17201258Smlf
17211258Smlf return (sata_err_msg(errstring, rv, ap_id, errno));
17221258Smlf }
17231258Smlf /*
17241258Smlf * This routine accepts a string adn prints it using
17251258Smlf * the message print routine argument.
17261258Smlf */
17271258Smlf static void
cfga_msg(struct cfga_msg * msgp,const char * str)17281258Smlf cfga_msg(struct cfga_msg *msgp, const char *str)
17291258Smlf {
17301258Smlf int len;
17311258Smlf char *q;
17321258Smlf
17331258Smlf if (msgp == NULL || msgp->message_routine == NULL) {
17341258Smlf (void) printf("cfga_msg: NULL msgp\n");
17351258Smlf return;
17361258Smlf }
17371258Smlf
17381258Smlf if ((len = strlen(str)) == 0) {
17391258Smlf (void) printf("cfga_msg: null str\n");
17401258Smlf return;
17411258Smlf }
17421258Smlf
17431258Smlf if ((q = (char *)calloc(len + 1, 1)) == NULL) {
1744*10318SXiao-Yu.Zhang@Sun.COM perror("cfga_msg");
17451258Smlf return;
17461258Smlf }
17471258Smlf
17481258Smlf (void) strcpy(q, str);
17491258Smlf (*msgp->message_routine)(msgp->appdata_ptr, q);
17501258Smlf
17511258Smlf free(q);
17521258Smlf }
17531258Smlf
17541258Smlf /* cfgadm entry point */
17551258Smlf /* ARGSUSED */
17561258Smlf cfga_err_t
cfga_help(struct cfga_msg * msgp,const char * options,cfga_flags_t flags)17571258Smlf cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
17581258Smlf {
17591258Smlf if (options != NULL) {
17601258Smlf cfga_msg(msgp, dgettext(TEXT_DOMAIN, sata_help[HELP_UNKNOWN]));
17611258Smlf cfga_msg(msgp, options);
17621258Smlf }
17631258Smlf cfga_msg(msgp, dgettext(TEXT_DOMAIN, sata_help[HELP_HEADER]));
17641258Smlf cfga_msg(msgp, sata_help[HELP_CONFIG]);
17651258Smlf cfga_msg(msgp, sata_help[HELP_RESET_PORT]);
17661258Smlf cfga_msg(msgp, sata_help[HELP_RESET_DEVICE]);
17671258Smlf cfga_msg(msgp, sata_help[HELP_RESET_ALL]);
17681258Smlf cfga_msg(msgp, sata_help[HELP_PORT_ACTIVATE]);
17691258Smlf cfga_msg(msgp, sata_help[HELP_PORT_DEACTIVATE]);
17701258Smlf cfga_msg(msgp, sata_help[HELP_PORT_SELF_TEST]);
17711258Smlf cfga_msg(msgp, sata_help[HELP_CNTRL_SELF_TEST]);
17721258Smlf
17731258Smlf return (CFGA_OK);
17741258Smlf }
17751258Smlf
17761258Smlf
17771258Smlf /*
17781258Smlf * Ensure the ap_id passed is in the correct (physical ap_id) form:
17791258Smlf * path/device:xx[.xx]
17801258Smlf * where xx is a one or two-digit number.
17811258Smlf *
17821258Smlf * Note the library always calls the plugin with a physical ap_id.
17831258Smlf */
17841258Smlf static int
verify_valid_apid(const char * ap_id)17851258Smlf verify_valid_apid(const char *ap_id)
17861258Smlf {
17871258Smlf char *l_ap_id;
17881258Smlf
17891258Smlf if (ap_id == NULL)
17901258Smlf return (-1);
17911258Smlf
17921258Smlf l_ap_id = strrchr(ap_id, (int)*MINOR_SEP);
17931258Smlf l_ap_id++;
17941258Smlf
17951258Smlf if (strspn(l_ap_id, "0123456789.") != strlen(l_ap_id)) {
17961258Smlf /* Bad characters in the ap_id */
17971258Smlf return (-1);
17981258Smlf }
17991258Smlf
18001258Smlf if (strstr(l_ap_id, "..") != NULL) {
18011258Smlf /* ap_id has 1..2 or more than 2 dots */
18021258Smlf return (-1);
18031258Smlf }
18041258Smlf
18051258Smlf return (0);
18061258Smlf }
18071258Smlf
18081258Smlf
18091258Smlf
18101258Smlf /*
18111258Smlf * Verify the params passed in are valid.
18121258Smlf */
18131258Smlf static cfga_sata_ret_t
verify_params(const char * ap_id,const char * options,char ** errstring)18141258Smlf verify_params(
1815*10318SXiao-Yu.Zhang@Sun.COM const char *ap_id,
1816*10318SXiao-Yu.Zhang@Sun.COM const char *options,
1817*10318SXiao-Yu.Zhang@Sun.COM char **errstring)
18181258Smlf {
18191258Smlf char *pdyn, *lap_id;
18201258Smlf int rv;
18211258Smlf
18221258Smlf if (errstring != NULL) {
18231258Smlf *errstring = NULL;
18241258Smlf }
18251258Smlf
18261258Smlf if (options != NULL) {
18271258Smlf return (CFGA_SATA_OPTIONS);
18281258Smlf }
18291258Smlf
18301258Smlf /* Strip dynamic AP name component if it is present. */
18311258Smlf lap_id = strdup(ap_id);
18321258Smlf if (lap_id == NULL) {
18331258Smlf return (CFGA_SATA_ALLOC_FAIL);
18341258Smlf }
18351258Smlf if ((pdyn = GET_DYN(lap_id)) != NULL) {
18361258Smlf *pdyn = '\0';
18371258Smlf }
18381258Smlf
18391258Smlf if (verify_valid_apid(lap_id) != 0) {
18401258Smlf rv = CFGA_SATA_AP;
18411258Smlf } else {
18421258Smlf rv = CFGA_SATA_OK;
18431258Smlf }
18441258Smlf free(lap_id);
18451258Smlf
18461258Smlf return (rv);
18471258Smlf }
18481258Smlf
18491258Smlf /*
18501258Smlf * Takes a validated ap_id and extracts the port number.
1851*10318SXiao-Yu.Zhang@Sun.COM * Port multiplier is supported now.
18521258Smlf */
18531258Smlf static cfga_sata_ret_t
get_port_num(const char * ap_id,uint32_t * port)18541258Smlf get_port_num(const char *ap_id, uint32_t *port)
18551258Smlf {
1856*10318SXiao-Yu.Zhang@Sun.COM uint32_t cport, pmport = 0, qual = 0;
1857*10318SXiao-Yu.Zhang@Sun.COM char *cport_str, *pmport_str;
18581258Smlf
1859*10318SXiao-Yu.Zhang@Sun.COM /* Get the cport number */
1860*10318SXiao-Yu.Zhang@Sun.COM cport_str = strrchr(ap_id, (int)*MINOR_SEP) + strlen(MINOR_SEP);
1861*10318SXiao-Yu.Zhang@Sun.COM
1862*10318SXiao-Yu.Zhang@Sun.COM errno = 0;
1863*10318SXiao-Yu.Zhang@Sun.COM cport = strtol(cport_str, NULL, 10);
1864*10318SXiao-Yu.Zhang@Sun.COM if ((cport & ~SATA_CFGA_CPORT_MASK) != 0 || errno != 0) {
1865*10318SXiao-Yu.Zhang@Sun.COM return (CFGA_SATA_PORT);
18661258Smlf }
18671258Smlf
1868*10318SXiao-Yu.Zhang@Sun.COM /* Get pmport number if there is a PORT_SEPARATOR */
18691258Smlf errno = 0;
1870*10318SXiao-Yu.Zhang@Sun.COM if ((pmport_str = strrchr(ap_id, (int)*PORT_SEPARATOR)) != 0) {
1871*10318SXiao-Yu.Zhang@Sun.COM pmport_str += strlen(PORT_SEPARATOR);
1872*10318SXiao-Yu.Zhang@Sun.COM pmport = strtol(pmport_str, NULL, 10);
1873*10318SXiao-Yu.Zhang@Sun.COM qual = SATA_CFGA_PMPORT_QUAL;
1874*10318SXiao-Yu.Zhang@Sun.COM if ((pmport & ~SATA_CFGA_PMPORT_MASK) != 0 || errno != 0) {
1875*10318SXiao-Yu.Zhang@Sun.COM return (CFGA_SATA_PORT);
1876*10318SXiao-Yu.Zhang@Sun.COM }
1877*10318SXiao-Yu.Zhang@Sun.COM }
18781258Smlf
1879*10318SXiao-Yu.Zhang@Sun.COM *port = cport | (pmport << SATA_CFGA_PMPORT_SHIFT) | qual;
18801258Smlf return (CFGA_SATA_OK);
18811258Smlf }
18821258Smlf
18831258Smlf /*
18841258Smlf * Pair of routines to set up for/clean up after a devctl_ap_* lib call.
18851258Smlf */
18861258Smlf static void
cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl,nvlist_t * user_nvlist)18871258Smlf cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist)
18881258Smlf {
18891258Smlf if (user_nvlist != NULL) {
18901258Smlf nvlist_free(user_nvlist);
18911258Smlf }
18921258Smlf if (devctl_hdl != NULL) {
18931258Smlf devctl_release(devctl_hdl);
18941258Smlf }
18951258Smlf }
18961258Smlf
18971258Smlf static cfga_sata_ret_t
setup_for_devctl_cmd(const char * ap_id,devctl_hdl_t * devctl_hdl,nvlist_t ** user_nvlistp,uint_t oflag)18981258Smlf setup_for_devctl_cmd(
1899*10318SXiao-Yu.Zhang@Sun.COM const char *ap_id,
1900*10318SXiao-Yu.Zhang@Sun.COM devctl_hdl_t *devctl_hdl,
1901*10318SXiao-Yu.Zhang@Sun.COM nvlist_t **user_nvlistp,
1902*10318SXiao-Yu.Zhang@Sun.COM uint_t oflag)
19031258Smlf {
19041258Smlf
19051258Smlf uint_t port;
19061258Smlf cfga_sata_ret_t rv = CFGA_SATA_OK;
19071258Smlf char *lap_id, *pdyn;
19081258Smlf
19091258Smlf lap_id = strdup(ap_id);
19101258Smlf if (lap_id == NULL)
19111258Smlf return (CFGA_SATA_ALLOC_FAIL);
19121258Smlf if ((pdyn = GET_DYN(lap_id)) != NULL) {
19131258Smlf *pdyn = '\0';
19141258Smlf }
19151258Smlf
19161258Smlf /* Get a devctl handle to pass to the devctl_ap_XXX functions */
19171258Smlf if ((*devctl_hdl = devctl_ap_acquire((char *)lap_id, oflag)) == NULL) {
19182027Ssethg (void) fprintf(stderr, "[libcfgadm:sata] "
19192027Ssethg "setup_for_devctl_cmd: devctl_ap_acquire failed: %s\n",
19202027Ssethg strerror(errno));
19211258Smlf rv = CFGA_SATA_DEVCTL;
19221258Smlf goto bailout;
19231258Smlf }
19241258Smlf
19251258Smlf /* Set up nvlist to pass the port number down to the driver */
19261258Smlf if (nvlist_alloc(user_nvlistp, NV_UNIQUE_NAME_TYPE, NULL) != 0) {
19271258Smlf *user_nvlistp = NULL;
19281258Smlf rv = CFGA_SATA_NVLIST;
19291258Smlf (void) printf("nvlist_alloc failed\n");
19301258Smlf goto bailout;
19311258Smlf }
19321258Smlf
19331258Smlf /*
19341258Smlf * Get port id, for Port Multiplier port, things could be a little bit
19351258Smlf * complicated because of "port.port" format in ap_id, thus for
19361258Smlf * port multiplier port, port number should be coded as 32bit int
19371258Smlf * with the sig 16 bit as sata channel number, least 16 bit as
19381258Smlf * the port number of sata port multiplier port.
19391258Smlf */
19401258Smlf if ((rv = get_port_num(lap_id, &port)) != CFGA_SATA_OK) {
19411258Smlf (void) printf(
1942*10318SXiao-Yu.Zhang@Sun.COM "setup_for_devctl_cmd: get_port_num, errno: %d\n",
1943*10318SXiao-Yu.Zhang@Sun.COM errno);
19441258Smlf goto bailout;
19451258Smlf }
19461258Smlf
19471258Smlf /* Creates an int32_t entry */
19481258Smlf if (nvlist_add_int32(*user_nvlistp, PORT, port) == -1) {
19491258Smlf (void) printf("nvlist_add_int32 failed\n");
19501258Smlf rv = CFGA_SATA_NVLIST;
19511258Smlf goto bailout;
19521258Smlf }
19531258Smlf
19542027Ssethg free(lap_id);
19551258Smlf return (rv);
19561258Smlf
19571258Smlf bailout:
19581258Smlf free(lap_id);
19591258Smlf (void) cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
19601258Smlf
19611258Smlf return (rv);
19621258Smlf }
19631258Smlf
19641258Smlf
19651258Smlf static cfga_sata_ret_t
port_state(devctl_hdl_t hdl,nvlist_t * list,ap_rstate_t * rstate,ap_ostate_t * ostate)19661258Smlf port_state(devctl_hdl_t hdl, nvlist_t *list,
1967*10318SXiao-Yu.Zhang@Sun.COM ap_rstate_t *rstate, ap_ostate_t *ostate)
19681258Smlf {
19691258Smlf devctl_ap_state_t devctl_ap_state;
19701258Smlf
19711258Smlf if (devctl_ap_getstate(hdl, list, &devctl_ap_state) == -1) {
19721258Smlf (void) printf("devctl_ap_getstate failed, errno: %d\n", errno);
19731258Smlf return (CFGA_SATA_IOCTL);
19741258Smlf }
19751258Smlf *rstate = devctl_ap_state.ap_rstate;
19761258Smlf *ostate = devctl_ap_state.ap_ostate;
19771258Smlf return (CFGA_SATA_OK);
19781258Smlf }
19791258Smlf
19801258Smlf
19811258Smlf /*
19821258Smlf * Given a subcommand to the DEVCTL_AP_CONTROL ioctl, rquest the size of
19831258Smlf * the data to be returned, allocate a buffer, then get the data.
19841258Smlf * Returns *descrp (which must be freed) and size.
19851258Smlf *
19861258Smlf * Note SATA_DESCR_TYPE_STRING returns an ASCII NULL-terminated string,
19871258Smlf * not a string descr.
19881258Smlf */
19891258Smlf cfga_sata_ret_t
do_control_ioctl(const char * ap_id,sata_cfga_apctl_t subcommand,uint_t arg,void ** descrp,size_t * sizep)19901258Smlf do_control_ioctl(const char *ap_id, sata_cfga_apctl_t subcommand, uint_t arg,
1991*10318SXiao-Yu.Zhang@Sun.COM void **descrp, size_t *sizep)
19921258Smlf {
19931258Smlf int fd = -1;
19941258Smlf uint_t port;
19951258Smlf uint32_t local_size;
19961258Smlf cfga_sata_ret_t rv = CFGA_SATA_OK;
19971258Smlf struct sata_ioctl_data ioctl_data;
19981258Smlf
19991258Smlf assert(descrp != NULL);
20001258Smlf *descrp = NULL;
20011258Smlf assert(sizep != NULL);
20021258Smlf
20031258Smlf if ((rv = get_port_num(ap_id, &port)) != CFGA_SATA_OK) {
20041258Smlf goto bailout;
20051258Smlf }
20061258Smlf
20071258Smlf if ((fd = open(ap_id, O_RDONLY)) == -1) {
20081258Smlf (void) printf("do_control_ioctl: open failed: errno:%d\n",
2009*10318SXiao-Yu.Zhang@Sun.COM errno);
20101258Smlf rv = CFGA_SATA_OPEN;
20111258Smlf if (errno == EBUSY) {
20121258Smlf rv = CFGA_SATA_BUSY;
20131258Smlf }
20141258Smlf goto bailout;
20151258Smlf }
20161258Smlf
20171258Smlf ioctl_data.cmd = subcommand;
20181258Smlf ioctl_data.port = port;
20191258Smlf ioctl_data.misc_arg = (uint_t)arg;
20201258Smlf
20211258Smlf /*
20221258Smlf * Find out how large a buf we need to get the data.
20231258Smlf * Note the ioctls only accept/return a 32-bit int for a get_size
20241258Smlf * to avoid 32/64 and BE/LE issues.
20251258Smlf */
20261258Smlf if ((subcommand == SATA_CFGA_GET_AP_TYPE) ||
20271258Smlf (subcommand == SATA_CFGA_GET_DEVICE_PATH) ||
20281258Smlf (subcommand == SATA_CFGA_GET_MODEL_INFO) ||
20291258Smlf (subcommand == SATA_CFGA_GET_REVFIRMWARE_INFO) ||
20301258Smlf (subcommand == SATA_CFGA_GET_SERIALNUMBER_INFO)) {
20311258Smlf ioctl_data.get_size = B_TRUE;
20321258Smlf ioctl_data.buf = (caddr_t)&local_size;
20331258Smlf ioctl_data.bufsiz = sizeof (local_size);
20341258Smlf
20351258Smlf if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
20361258Smlf perror("ioctl failed (size)");
20371258Smlf rv = CFGA_SATA_IOCTL;
20381258Smlf goto bailout;
20391258Smlf }
20401258Smlf *sizep = local_size;
20411258Smlf
20421258Smlf if (local_size == 0) {
20431258Smlf (void) printf("zero length data\n");
20441258Smlf rv = CFGA_SATA_ZEROLEN;
20451258Smlf goto bailout;
20461258Smlf }
20471258Smlf if ((*descrp = malloc(*sizep)) == NULL) {
20481258Smlf (void) printf("do_control_ioctl: malloc failed\n");
20491258Smlf rv = CFGA_SATA_ALLOC_FAIL;
20501258Smlf goto bailout;
20511258Smlf }
20521258Smlf } else {
20531258Smlf *sizep = 0;
20541258Smlf }
20551258Smlf ioctl_data.get_size = B_FALSE;
20561258Smlf ioctl_data.buf = *descrp;
20571258Smlf ioctl_data.bufsiz = *sizep;
20581258Smlf
20591258Smlf /* Execute IOCTL */
20601258Smlf
20611258Smlf if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
20621258Smlf rv = CFGA_SATA_IOCTL;
20631258Smlf goto bailout;
20641258Smlf }
20651258Smlf
20661258Smlf (void) close(fd);
20671258Smlf
20681258Smlf return (rv);
20691258Smlf
20701258Smlf bailout:
20711258Smlf if (fd != -1) {
20721258Smlf (void) close(fd);
20731258Smlf }
20741258Smlf if (*descrp != NULL) {
20751258Smlf free(*descrp);
20761258Smlf *descrp = NULL;
20771258Smlf }
20781258Smlf
20791258Smlf if (rv == CFGA_SATA_IOCTL && errno == EBUSY) {
20801258Smlf rv = CFGA_SATA_BUSY;
20811258Smlf }
20821258Smlf
20831258Smlf return (rv);
20841258Smlf }
20851258Smlf
20861258Smlf
20871258Smlf static int
sata_confirm(struct cfga_confirm * confp,char * msg)20881258Smlf sata_confirm(struct cfga_confirm *confp, char *msg)
20891258Smlf {
20901258Smlf int rval;
20911258Smlf
20921258Smlf if (confp == NULL || confp->confirm == NULL) {
20931258Smlf return (0);
20941258Smlf }
20951258Smlf rval = (*confp->confirm)(confp->appdata_ptr, msg);
20961258Smlf
20971258Smlf return (rval);
20981258Smlf }
20991258Smlf
21001258Smlf
21011258Smlf static char *
sata_get_devicepath(const char * ap_id)21021258Smlf sata_get_devicepath(const char *ap_id)
21031258Smlf {
21041258Smlf char *devpath = NULL;
21051258Smlf size_t size;
21061258Smlf cfga_sata_ret_t rv;
21071258Smlf
21081258Smlf rv = do_control_ioctl(ap_id, SATA_CFGA_GET_DEVICE_PATH, NULL,
21091258Smlf (void **)&devpath, &size);
21101258Smlf
21111258Smlf if (rv == CFGA_SATA_OK) {
21121258Smlf return (devpath);
21131258Smlf } else {
21141258Smlf return ((char *)NULL);
21151258Smlf }
21161258Smlf
21171258Smlf }
2118