166f9d5cbSmlf /*
266f9d5cbSmlf * CDDL HEADER START
366f9d5cbSmlf *
466f9d5cbSmlf * The contents of this file are subject to the terms of the
566f9d5cbSmlf * Common Development and Distribution License (the "License").
666f9d5cbSmlf * You may not use this file except in compliance with the License.
766f9d5cbSmlf *
866f9d5cbSmlf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
966f9d5cbSmlf * or http://www.opensolaris.org/os/licensing.
1066f9d5cbSmlf * See the License for the specific language governing permissions
1166f9d5cbSmlf * and limitations under the License.
1266f9d5cbSmlf *
1366f9d5cbSmlf * When distributing Covered Code, include this CDDL HEADER in each
1466f9d5cbSmlf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1566f9d5cbSmlf * If applicable, add the following below this CDDL HEADER, with the
1666f9d5cbSmlf * fields enclosed by brackets "[]" replaced with your own identifying
1766f9d5cbSmlf * information: Portions Copyright [yyyy] [name of copyright owner]
1866f9d5cbSmlf *
1966f9d5cbSmlf * CDDL HEADER END
2066f9d5cbSmlf */
2166f9d5cbSmlf
2266f9d5cbSmlf /*
238aa6aadbSXiao-Yu Zhang * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2466f9d5cbSmlf * Use is subject to license terms.
25cf252232SAndy Fiddaman * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
2661233e71SJohn Levon * Copyright (c) 2018, Joyent, Inc.
2766f9d5cbSmlf */
2866f9d5cbSmlf
29724365f7Ssethg #include <sys/param.h>
30724365f7Ssethg #include <sys/stat.h>
31724365f7Ssethg #include <errno.h>
32724365f7Ssethg #include <string.h>
33724365f7Ssethg #include <dirent.h>
3466f9d5cbSmlf #include "cfga_sata.h"
3566f9d5cbSmlf
3666f9d5cbSmlf /*
3766f9d5cbSmlf * This file contains the entry points to the plug-in as defined in the
38*bbf21555SRichard Lowe * config_admin(3CFGADM) man page.
3966f9d5cbSmlf */
4066f9d5cbSmlf
4166f9d5cbSmlf /*
4266f9d5cbSmlf * Set the version number for the cfgadm library's use.
4366f9d5cbSmlf */
4466f9d5cbSmlf int cfga_version = CFGA_HSL_V2;
4566f9d5cbSmlf
4666f9d5cbSmlf enum {
4766f9d5cbSmlf HELP_HEADER = 1,
4866f9d5cbSmlf HELP_CONFIG,
4966f9d5cbSmlf HELP_RESET_PORT,
5066f9d5cbSmlf HELP_RESET_DEVICE,
5166f9d5cbSmlf HELP_RESET_ALL,
5266f9d5cbSmlf HELP_PORT_DEACTIVATE,
5366f9d5cbSmlf HELP_PORT_ACTIVATE,
5466f9d5cbSmlf HELP_PORT_SELF_TEST,
5566f9d5cbSmlf HELP_CNTRL_SELF_TEST,
5666f9d5cbSmlf HELP_UNKNOWN
5766f9d5cbSmlf };
5866f9d5cbSmlf
5966f9d5cbSmlf /* SATA specific help messages */
6066f9d5cbSmlf static char *sata_help[] = {
6166f9d5cbSmlf NULL,
6266f9d5cbSmlf "SATA specific commands:\n",
6366f9d5cbSmlf " cfgadm -c [configure|unconfigure|disconnect|connect] ap_id "
6466f9d5cbSmlf "[ap_id...]\n",
6566f9d5cbSmlf " cfgadm -x sata_reset_port ap_id [ap_id...]\n",
6666f9d5cbSmlf " cfgadm -x sata_reset_device ap_id [ap_id...]\n",
6766f9d5cbSmlf " cfgadm -x sata_reset_all ap_id\n",
6866f9d5cbSmlf " cfgadm -x sata_port_deactivate ap_id [ap_id...]\n",
6966f9d5cbSmlf " cfgadm -x sata_port_activate ap_id [ap_id...]\n",
7066f9d5cbSmlf " cfgadm -x sata_port_self_test ap_id [ap_id...]\n",
7166f9d5cbSmlf " cfgadm -t ap_id\n",
7266f9d5cbSmlf "\tunknown command or option:\n",
7366f9d5cbSmlf NULL
7466f9d5cbSmlf }; /* End help messages */
7566f9d5cbSmlf
7666f9d5cbSmlf
7766f9d5cbSmlf /*
7866f9d5cbSmlf * Messages.
7966f9d5cbSmlf */
8066f9d5cbSmlf static msgcvt_t sata_msgs[] = {
8166f9d5cbSmlf /* CFGA_SATA_OK */
8266f9d5cbSmlf { CVT, CFGA_OK, "" },
8366f9d5cbSmlf
8466f9d5cbSmlf /* CFGA_SATA_NACK */
8566f9d5cbSmlf { CVT, CFGA_NACK, "" },
8666f9d5cbSmlf
8766f9d5cbSmlf /* CFGA_SATA_DEVICE_UNCONFIGURED */
8866f9d5cbSmlf { CVT, CFGA_OK, "Device unconfigured prior to disconnect" },
8966f9d5cbSmlf
9066f9d5cbSmlf /* CFGA_SATA_UNKNOWN / CFGA_LIB_ERROR -> "Library error" */
9166f9d5cbSmlf { CVT, CFGA_LIB_ERROR, "Unknown message; internal error" },
9266f9d5cbSmlf
9366f9d5cbSmlf /* CFGA_SATA_INTERNAL_ERROR / CFGA_LIB_ERROR -> "Library error" */
9466f9d5cbSmlf { CVT, CFGA_LIB_ERROR, "Internal error" },
9566f9d5cbSmlf
9666f9d5cbSmlf /* CFGA_SATA_DATA_ERROR / CFGA_DATA_ERROR -> "Data error" */
9766f9d5cbSmlf { CVT, CFGA_DATA_ERROR, "cfgadm data error" },
9866f9d5cbSmlf
9966f9d5cbSmlf /* CFGA_SATA_OPTIONS / CFGA_ERROR -> "Hardware specific failure" */
10066f9d5cbSmlf { CVT, CFGA_ERROR, "Hardware specific option not supported" },
10166f9d5cbSmlf
10266f9d5cbSmlf /* CFGA_SATA_HWOPNOTSUPP / CFGA_ERROR -> "Hardware specific failure" */
10366f9d5cbSmlf { CVT, CFGA_ERROR, "Hardware specific operation not supported" },
10466f9d5cbSmlf
10566f9d5cbSmlf /*
10666f9d5cbSmlf * CFGA_SATA_DYNAMIC_AP /
10766f9d5cbSmlf * CFGA_LIB_ERROR -> "Configuration operation invalid"
10866f9d5cbSmlf */
10966f9d5cbSmlf { CVT, CFGA_INVAL, "Cannot identify attached device" },
11066f9d5cbSmlf
11166f9d5cbSmlf /* CFGA_SATA_AP / CFGA_APID_NOEXIST -> "Attachment point not found" */
11266f9d5cbSmlf { CVT, CFGA_APID_NOEXIST, "" },
11366f9d5cbSmlf
11466f9d5cbSmlf /* CFGA_SATA_PORT / CFGA_LIB_ERROR -> "Library error" */
11566f9d5cbSmlf { CVT, CFGA_LIB_ERROR, "Cannot determine sata port number for " },
11666f9d5cbSmlf
11766f9d5cbSmlf /* CFGA_SATA_DEVCTL / CFGA_LIB_ERROR -> "Library error" */
11866f9d5cbSmlf { CVT, CFGA_LIB_ERROR, "Internal error: "
11966f9d5cbSmlf "Cannot allocate devctl handle " },
12066f9d5cbSmlf
12166f9d5cbSmlf /*
12266f9d5cbSmlf * CFGA_SATA_DEV_CONFIGURE /
12366f9d5cbSmlf * CFGA_ERROR -> "Hardware specific failure"
12466f9d5cbSmlf */
12566f9d5cbSmlf { CVT, CFGA_ERROR, "Failed to config device at " },
12666f9d5cbSmlf
12766f9d5cbSmlf /*
12866f9d5cbSmlf * CFGA_SATA_DEV_UNCONFIGURE /
12966f9d5cbSmlf * CFGA_ERROR -> "Hardware specific failure"
13066f9d5cbSmlf */
13166f9d5cbSmlf { CVT, CFGA_ERROR, "Failed to unconfig device at " },
13266f9d5cbSmlf
13366f9d5cbSmlf /*
13466f9d5cbSmlf * CFGA_SATA_DISCONNECTED
13566f9d5cbSmlf * CFGA_INVAL -> "Configuration operation invalid"
13666f9d5cbSmlf */
13766f9d5cbSmlf { CVT, CFGA_INVAL, "Port already disconnected " },
13866f9d5cbSmlf
13966f9d5cbSmlf /*
14066f9d5cbSmlf * CFGA_SATA_NOT_CONNECTED
14166f9d5cbSmlf * CFGA_INVAL -> "Configuration operation invalid"
14266f9d5cbSmlf */
14366f9d5cbSmlf { CVT, CFGA_INVAL, "No device connected to " },
14466f9d5cbSmlf
14566f9d5cbSmlf /*
14666f9d5cbSmlf * CFGA_SATA_NOT_CONFIGURED /
14766f9d5cbSmlf * CFGA_INVAL -> "Configuration operation invalid"
14866f9d5cbSmlf */
14966f9d5cbSmlf { CVT, CFGA_INVAL, "No device configured at " },
15066f9d5cbSmlf
15166f9d5cbSmlf /*
15266f9d5cbSmlf * CFGA_SATA_ALREADY_CONNECTED /
15366f9d5cbSmlf * CFGA_INVAL -> "Configuration operation invalid"
15466f9d5cbSmlf */
15566f9d5cbSmlf { CVT, CFGA_INVAL, "Device already connected to " },
15666f9d5cbSmlf
15766f9d5cbSmlf /*
15866f9d5cbSmlf * CFGA_SATA_ALREADY_CONFIGURED /
15966f9d5cbSmlf * CFGA_INVAL -> "Configuration operation invalid"
16066f9d5cbSmlf */
16166f9d5cbSmlf { CVT, CFGA_INVAL, "Device already configured at " },
16266f9d5cbSmlf
16366f9d5cbSmlf /*
16466f9d5cbSmlf * CFGA_SATA_INVALID_DEVNAME /
16566f9d5cbSmlf * CFGA_INVAL -> "Configuration operation invalid"
16666f9d5cbSmlf */
16766f9d5cbSmlf { CVT, CFGA_INVAL, "Cannot specify device name" },
16866f9d5cbSmlf
16966f9d5cbSmlf /* CFGA_SATA_OPEN / CFGA_LIB_ERROR -> "Library error" */
17066f9d5cbSmlf { CVT, CFGA_LIB_ERROR, "Cannot open " },
17166f9d5cbSmlf
17266f9d5cbSmlf /* CFGA_SATA_IOCTL / CFGA_ERROR -> "Hardware specific failure" */
17366f9d5cbSmlf { CVT, CFGA_ERROR, "Driver ioctl failed " },
17466f9d5cbSmlf
17566f9d5cbSmlf /*
17666f9d5cbSmlf * CFGA_SATA_BUSY /
17766f9d5cbSmlf * CFGA_SYSTEM_BUSY -> "System is busy, try again"
17866f9d5cbSmlf */
17966f9d5cbSmlf { CVT, CFGA_SYSTEM_BUSY, "" },
18066f9d5cbSmlf
18166f9d5cbSmlf /* CFGA_SATA_ALLOC_FAIL / CFGA_LIB_ERROR -> "Library error" */
18266f9d5cbSmlf { CVT, CFGA_LIB_ERROR, "Memory allocation failure" },
18366f9d5cbSmlf
18466f9d5cbSmlf /*
18566f9d5cbSmlf * CFGA_SATA_OPNOTSUPP /
18666f9d5cbSmlf * CFGA_OPNOTSUPP -> "Configuration operation not supported"
18766f9d5cbSmlf */
18866f9d5cbSmlf { CVT, CFGA_OPNOTSUPP, "Operation not supported" },
18966f9d5cbSmlf
19066f9d5cbSmlf /* CFGA_SATA_DEVLINK / CFGA_LIB_ERROR -> "Library error" */
19166f9d5cbSmlf { CVT, CFGA_LIB_ERROR, "Could not find /dev/cfg link for " },
19266f9d5cbSmlf
19366f9d5cbSmlf /* CFGA_SATA_STATE / CFGA_LIB_ERROR -> "Library error" */
19466f9d5cbSmlf { CVT, CFGA_LIB_ERROR, "Internal error: Unrecognized ap state" },
19566f9d5cbSmlf
19666f9d5cbSmlf /* CFGA_SATA_PRIV / CFGA_PRIV -> "Insufficient privileges" */
19766f9d5cbSmlf { CVT, CFGA_PRIV, "" },
19866f9d5cbSmlf
19966f9d5cbSmlf /* CFGA_SATA_NVLIST / CFGA_ERROR -> "Hardware specific failure" */
20066f9d5cbSmlf { CVT, CFGA_ERROR, "Internal error (nvlist)" },
20166f9d5cbSmlf
20266f9d5cbSmlf /* CFGA_SATA_ZEROLEN / CFGA_ERROR -> "Hardware specific failure" */
20366f9d5cbSmlf { CVT, CFGA_ERROR, "Internal error (zerolength string)" },
20466f9d5cbSmlf
20566f9d5cbSmlf /* CFGA_SATA_RCM_HANDLE / CFGA_ERROR -> "Hardware specific failure" */
20666f9d5cbSmlf { CVT, CFGA_ERROR, "cannot get RCM handle"},
20766f9d5cbSmlf
20866f9d5cbSmlf /*
20966f9d5cbSmlf * CFGA_SATA_RCM_ONLINE /
21066f9d5cbSmlf * CFGA_SYSTEM_BUSY -> "System is busy, try again"
21166f9d5cbSmlf */
21266f9d5cbSmlf { CVT, CFGA_SYSTEM_BUSY, "failed to online: "},
21366f9d5cbSmlf
21466f9d5cbSmlf /*
21566f9d5cbSmlf * CFGA_SATA_RCM_OFFLINE /
21666f9d5cbSmlf * CFGA_SYSTEM_BUSY -> "System is busy, try again"
21766f9d5cbSmlf */
21866f9d5cbSmlf { CVT, CFGA_SYSTEM_BUSY, "failed to offline: "},
21966f9d5cbSmlf
22066f9d5cbSmlf /* CFGA_SATA_RCM_INFO / CFGA_ERROR -> "Hardware specific failure" */
22166f9d5cbSmlf { CVT, CFGA_ERROR, "failed to query: "}
22266f9d5cbSmlf
22366f9d5cbSmlf }; /* End error messages */
22466f9d5cbSmlf
22566f9d5cbSmlf static cfga_sata_ret_t
22666f9d5cbSmlf verify_params(const char *ap_id, const char *options, char **errstring);
22766f9d5cbSmlf
22866f9d5cbSmlf
22966f9d5cbSmlf static cfga_sata_ret_t
23066f9d5cbSmlf setup_for_devctl_cmd(const char *ap_id, devctl_hdl_t *devctl_hdl,
23166f9d5cbSmlf nvlist_t **user_nvlistp, uint_t oflag);
23266f9d5cbSmlf
23366f9d5cbSmlf static cfga_sata_ret_t
23466f9d5cbSmlf port_state(devctl_hdl_t hdl, nvlist_t *list,
23566f9d5cbSmlf ap_rstate_t *rstate, ap_ostate_t *ostate);
23666f9d5cbSmlf
23766f9d5cbSmlf static cfga_sata_ret_t
23866f9d5cbSmlf do_control_ioctl(const char *ap_id, sata_cfga_apctl_t subcommand, uint_t arg,
23966f9d5cbSmlf void **descrp, size_t *sizep);
24066f9d5cbSmlf
24166f9d5cbSmlf static void
24266f9d5cbSmlf cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist);
24366f9d5cbSmlf
24466f9d5cbSmlf static char *
24566f9d5cbSmlf sata_get_devicepath(const char *ap_id);
24666f9d5cbSmlf
24766f9d5cbSmlf static int
24866f9d5cbSmlf sata_confirm(struct cfga_confirm *confp, char *msg);
24966f9d5cbSmlf
2508aa6aadbSXiao-Yu Zhang static cfga_sata_ret_t
2518aa6aadbSXiao-Yu Zhang get_port_num(const char *ap_id, uint32_t *port);
25266f9d5cbSmlf
25366f9d5cbSmlf /* Utilities */
25466f9d5cbSmlf
255724365f7Ssethg static cfga_sata_ret_t
physpath_to_devlink(const char * basedir,const char * node_path,char ** logpp,int * l_errnop)256724365f7Ssethg physpath_to_devlink(const char *basedir, const char *node_path,
257724365f7Ssethg char **logpp, int *l_errnop)
25866f9d5cbSmlf {
259724365f7Ssethg char *linkpath;
260724365f7Ssethg char *buf;
261724365f7Ssethg char *real_path;
262724365f7Ssethg DIR *dp;
263724365f7Ssethg struct dirent *dep, *newdep;
264724365f7Ssethg int deplen;
265724365f7Ssethg boolean_t found = B_FALSE;
266724365f7Ssethg int err = 0;
267724365f7Ssethg struct stat sb;
268724365f7Ssethg char *p;
269724365f7Ssethg cfga_sata_ret_t rv = CFGA_SATA_INTERNAL_ERROR;
27066f9d5cbSmlf
27166f9d5cbSmlf /*
272724365f7Ssethg * Using libdevinfo for this is overkill and kills performance
273724365f7Ssethg * when multiple consumers of libcfgadm are executing
274724365f7Ssethg * concurrently.
27566f9d5cbSmlf */
276724365f7Ssethg if ((dp = opendir(basedir)) == NULL) {
27766f9d5cbSmlf *l_errnop = errno;
278724365f7Ssethg return (CFGA_SATA_INTERNAL_ERROR);
279724365f7Ssethg }
280724365f7Ssethg
281724365f7Ssethg linkpath = malloc(PATH_MAX);
282724365f7Ssethg buf = malloc(PATH_MAX);
283724365f7Ssethg real_path = malloc(PATH_MAX);
284724365f7Ssethg
285d3080269Ssethg deplen = pathconf(basedir, _PC_NAME_MAX);
286d3080269Ssethg deplen = (deplen <= 0 ? MAXNAMELEN : deplen) +
287724365f7Ssethg sizeof (struct dirent);
288724365f7Ssethg dep = (struct dirent *)malloc(deplen);
289724365f7Ssethg
290724365f7Ssethg if (dep == NULL || linkpath == NULL || buf == NULL ||
291724365f7Ssethg real_path == NULL) {
292724365f7Ssethg *l_errnop = ENOMEM;
293724365f7Ssethg rv = CFGA_SATA_ALLOC_FAIL;
294724365f7Ssethg goto pp_cleanup;
29566f9d5cbSmlf }
29666f9d5cbSmlf
29766f9d5cbSmlf *logpp = NULL;
298724365f7Ssethg
299724365f7Ssethg while (!found && (err = readdir_r(dp, dep, &newdep)) == 0 &&
300724365f7Ssethg newdep != NULL) {
301724365f7Ssethg
302724365f7Ssethg assert(newdep == dep);
303724365f7Ssethg
304724365f7Ssethg if (strcmp(dep->d_name, ".") == 0 ||
305724365f7Ssethg strcmp(dep->d_name, "..") == 0)
306724365f7Ssethg continue;
307724365f7Ssethg
308724365f7Ssethg (void) snprintf(linkpath, MAXPATHLEN,
309724365f7Ssethg "%s/%s", basedir, dep->d_name);
310724365f7Ssethg
311724365f7Ssethg if (lstat(linkpath, &sb) < 0)
312724365f7Ssethg continue;
313724365f7Ssethg
314724365f7Ssethg if (S_ISDIR(sb.st_mode)) {
315724365f7Ssethg
316724365f7Ssethg if ((rv = physpath_to_devlink(linkpath, node_path,
317724365f7Ssethg logpp, l_errnop)) != CFGA_SATA_OK) {
318724365f7Ssethg
319724365f7Ssethg goto pp_cleanup;
32066f9d5cbSmlf }
32166f9d5cbSmlf
322724365f7Ssethg if (*logpp != NULL)
323724365f7Ssethg found = B_TRUE;
32466f9d5cbSmlf
325724365f7Ssethg } else if (S_ISLNK(sb.st_mode)) {
326724365f7Ssethg
327724365f7Ssethg bzero(buf, PATH_MAX);
328724365f7Ssethg if (readlink(linkpath, buf, PATH_MAX) < 0)
329724365f7Ssethg continue;
330724365f7Ssethg
331724365f7Ssethg
332724365f7Ssethg /*
333724365f7Ssethg * realpath() is too darn slow, so fake
334724365f7Ssethg * it, by using what we know about /dev
335724365f7Ssethg * links: they are always of the form:
336724365f7Ssethg * <"../">+/devices/<path>
337724365f7Ssethg */
338724365f7Ssethg p = buf;
339724365f7Ssethg while (strncmp(p, "../", 3) == 0)
340724365f7Ssethg p += 3;
341724365f7Ssethg
342724365f7Ssethg if (p != buf)
343724365f7Ssethg p--; /* back up to get a slash */
344724365f7Ssethg
345724365f7Ssethg assert (*p == '/');
346724365f7Ssethg
347724365f7Ssethg if (strcmp(p, node_path) == 0) {
348724365f7Ssethg *logpp = strdup(linkpath);
34966f9d5cbSmlf if (*logpp == NULL) {
350724365f7Ssethg
351724365f7Ssethg rv = CFGA_SATA_ALLOC_FAIL;
352724365f7Ssethg goto pp_cleanup;
35366f9d5cbSmlf }
35466f9d5cbSmlf
355724365f7Ssethg found = B_TRUE;
356724365f7Ssethg }
357724365f7Ssethg }
358724365f7Ssethg }
359724365f7Ssethg
360724365f7Ssethg free(linkpath);
361724365f7Ssethg free(buf);
362724365f7Ssethg free(real_path);
363724365f7Ssethg free(dep);
364724365f7Ssethg (void) closedir(dp);
365724365f7Ssethg
366724365f7Ssethg if (err != 0) {
367724365f7Ssethg *l_errnop = err;
368724365f7Ssethg return (CFGA_SATA_INTERNAL_ERROR);
369724365f7Ssethg }
370724365f7Ssethg
371724365f7Ssethg return (CFGA_SATA_OK);
372724365f7Ssethg
373724365f7Ssethg pp_cleanup:
374724365f7Ssethg
375724365f7Ssethg if (dp)
376724365f7Ssethg (void) closedir(dp);
377724365f7Ssethg if (dep)
378724365f7Ssethg free(dep);
379724365f7Ssethg if (linkpath)
380724365f7Ssethg free(linkpath);
381724365f7Ssethg if (buf)
382724365f7Ssethg free(buf);
383724365f7Ssethg if (real_path)
384724365f7Ssethg free(real_path);
385724365f7Ssethg if (*logpp) {
386724365f7Ssethg free(*logpp);
387724365f7Ssethg *logpp = NULL;
388724365f7Ssethg }
389724365f7Ssethg return (rv);
39066f9d5cbSmlf }
39166f9d5cbSmlf
39266f9d5cbSmlf
39366f9d5cbSmlf /*
39466f9d5cbSmlf * Given the index into a table (msgcvt_t) of messages, get the message
39566f9d5cbSmlf * string, converting it to the proper locale if necessary.
39666f9d5cbSmlf * NOTE: Indexes are defined in cfga_sata.h
39766f9d5cbSmlf */
39866f9d5cbSmlf static const char *
get_msg(uint_t msg_index,msgcvt_t * msg_tbl,uint_t tbl_size)39966f9d5cbSmlf get_msg(uint_t msg_index, msgcvt_t *msg_tbl, uint_t tbl_size)
40066f9d5cbSmlf {
40166f9d5cbSmlf if (msg_index >= tbl_size) {
40266f9d5cbSmlf msg_index = CFGA_SATA_UNKNOWN;
40366f9d5cbSmlf }
40466f9d5cbSmlf
40566f9d5cbSmlf return ((msg_tbl[msg_index].intl) ?
40666f9d5cbSmlf dgettext(TEXT_DOMAIN, msg_tbl[msg_index].msgstr) :
40766f9d5cbSmlf msg_tbl[msg_index].msgstr);
40866f9d5cbSmlf }
40966f9d5cbSmlf
41066f9d5cbSmlf /*
41166f9d5cbSmlf * Allocates and creates a message string (in *ret_str),
41266f9d5cbSmlf * by concatenating all the (char *) args together, in order.
41366f9d5cbSmlf * Last arg MUST be NULL.
41466f9d5cbSmlf */
41566f9d5cbSmlf static void
set_msg(char ** ret_str,...)41666f9d5cbSmlf set_msg(char **ret_str, ...)
41766f9d5cbSmlf {
41866f9d5cbSmlf char *str;
41966f9d5cbSmlf size_t total_len;
42066f9d5cbSmlf va_list valist;
42166f9d5cbSmlf
42266f9d5cbSmlf va_start(valist, ret_str);
42366f9d5cbSmlf
42466f9d5cbSmlf total_len = (*ret_str == NULL) ? 0 : strlen(*ret_str);
42566f9d5cbSmlf
42666f9d5cbSmlf while ((str = va_arg(valist, char *)) != NULL) {
42766f9d5cbSmlf size_t len = strlen(str);
42866f9d5cbSmlf char *old_str = *ret_str;
42966f9d5cbSmlf
43066f9d5cbSmlf *ret_str = (char *)realloc(*ret_str, total_len + len + 1);
43166f9d5cbSmlf if (*ret_str == NULL) {
43266f9d5cbSmlf /* We're screwed */
43366f9d5cbSmlf free(old_str);
43466f9d5cbSmlf va_end(valist);
43566f9d5cbSmlf return;
43666f9d5cbSmlf }
43766f9d5cbSmlf
43866f9d5cbSmlf (void) strcpy(*ret_str + total_len, str);
43966f9d5cbSmlf total_len += len;
44066f9d5cbSmlf }
44166f9d5cbSmlf
44266f9d5cbSmlf va_end(valist);
44366f9d5cbSmlf }
44466f9d5cbSmlf
44566f9d5cbSmlf /*
44666f9d5cbSmlf * Error message handling.
44766f9d5cbSmlf * For the rv passed in, looks up the corresponding error message string(s),
44866f9d5cbSmlf * internationalized if necessary, and concatenates it into a new
44966f9d5cbSmlf * memory buffer, and points *errstring to it.
45066f9d5cbSmlf * Note not all rvs will result in an error message return, as not all
45166f9d5cbSmlf * error conditions warrant a SATA-specific error message - for those
45266f9d5cbSmlf * conditions the cfgadm generic messages are sufficient.
45366f9d5cbSmlf *
45466f9d5cbSmlf * Some messages may display ap_id or errno, which is why they are passed
45566f9d5cbSmlf * in.
45666f9d5cbSmlf */
45766f9d5cbSmlf
45866f9d5cbSmlf cfga_err_t
sata_err_msg(char ** errstring,cfga_sata_ret_t rv,const char * ap_id,int l_errno)45966f9d5cbSmlf sata_err_msg(
46066f9d5cbSmlf char **errstring,
46166f9d5cbSmlf cfga_sata_ret_t rv,
46266f9d5cbSmlf const char *ap_id,
46366f9d5cbSmlf int l_errno)
46466f9d5cbSmlf {
46566f9d5cbSmlf if (errstring == NULL) {
46666f9d5cbSmlf return (sata_msgs[rv].cfga_err);
46766f9d5cbSmlf }
46866f9d5cbSmlf
46966f9d5cbSmlf /*
47066f9d5cbSmlf * Generate the appropriate SATA-specific error message(s) (if any).
47166f9d5cbSmlf */
47266f9d5cbSmlf switch (rv) {
47366f9d5cbSmlf case CFGA_SATA_OK:
47466f9d5cbSmlf case CFGA_NACK:
47566f9d5cbSmlf /* Special case - do nothing. */
47666f9d5cbSmlf break;
47766f9d5cbSmlf
47866f9d5cbSmlf case CFGA_SATA_UNKNOWN:
47966f9d5cbSmlf case CFGA_SATA_DYNAMIC_AP:
48066f9d5cbSmlf case CFGA_SATA_INTERNAL_ERROR:
48166f9d5cbSmlf case CFGA_SATA_OPTIONS:
48266f9d5cbSmlf case CFGA_SATA_ALLOC_FAIL:
48366f9d5cbSmlf case CFGA_SATA_STATE:
48466f9d5cbSmlf case CFGA_SATA_PRIV:
48566f9d5cbSmlf case CFGA_SATA_OPNOTSUPP:
48666f9d5cbSmlf case CFGA_SATA_DATA_ERROR:
48766f9d5cbSmlf /* These messages require no additional strings passed. */
48866f9d5cbSmlf set_msg(errstring, ERR_STR(rv), NULL);
48966f9d5cbSmlf break;
49066f9d5cbSmlf
49166f9d5cbSmlf case CFGA_SATA_HWOPNOTSUPP:
49266f9d5cbSmlf /* hardware-specific help needed */
49366f9d5cbSmlf set_msg(errstring, ERR_STR(rv), NULL);
49466f9d5cbSmlf set_msg(errstring, "\n",
49566f9d5cbSmlf dgettext(TEXT_DOMAIN, sata_help[HELP_HEADER]), NULL);
49666f9d5cbSmlf set_msg(errstring, sata_help[HELP_RESET_PORT], NULL);
49766f9d5cbSmlf set_msg(errstring, sata_help[HELP_RESET_DEVICE], NULL);
49866f9d5cbSmlf set_msg(errstring, sata_help[HELP_RESET_ALL], NULL);
49966f9d5cbSmlf set_msg(errstring, sata_help[HELP_PORT_ACTIVATE], NULL);
50066f9d5cbSmlf set_msg(errstring, sata_help[HELP_PORT_DEACTIVATE], NULL);
50166f9d5cbSmlf set_msg(errstring, sata_help[HELP_PORT_SELF_TEST], NULL);
50266f9d5cbSmlf set_msg(errstring, sata_help[HELP_CNTRL_SELF_TEST], NULL);
50366f9d5cbSmlf break;
50466f9d5cbSmlf
50566f9d5cbSmlf case CFGA_SATA_AP:
50666f9d5cbSmlf case CFGA_SATA_PORT:
50766f9d5cbSmlf case CFGA_SATA_NOT_CONNECTED:
50866f9d5cbSmlf case CFGA_SATA_NOT_CONFIGURED:
50966f9d5cbSmlf case CFGA_SATA_ALREADY_CONNECTED:
51066f9d5cbSmlf case CFGA_SATA_ALREADY_CONFIGURED:
51166f9d5cbSmlf case CFGA_SATA_BUSY:
51266f9d5cbSmlf case CFGA_SATA_DEVLINK:
51366f9d5cbSmlf case CFGA_SATA_RCM_HANDLE:
51466f9d5cbSmlf case CFGA_SATA_RCM_ONLINE:
51566f9d5cbSmlf case CFGA_SATA_RCM_OFFLINE:
51666f9d5cbSmlf case CFGA_SATA_RCM_INFO:
51766f9d5cbSmlf case CFGA_SATA_DEV_CONFIGURE:
51866f9d5cbSmlf case CFGA_SATA_DEV_UNCONFIGURE:
51966f9d5cbSmlf case CFGA_SATA_DISCONNECTED:
52066f9d5cbSmlf /* These messages also print ap_id. */
52166f9d5cbSmlf set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "", NULL);
52266f9d5cbSmlf break;
52366f9d5cbSmlf
52466f9d5cbSmlf
52566f9d5cbSmlf case CFGA_SATA_IOCTL:
52666f9d5cbSmlf case CFGA_SATA_NVLIST:
52766f9d5cbSmlf /* These messages also print errno. */
52866f9d5cbSmlf {
52966f9d5cbSmlf char *errno_str = l_errno ? strerror(l_errno) : "";
53066f9d5cbSmlf
53166f9d5cbSmlf set_msg(errstring, ERR_STR(rv), errno_str,
53266f9d5cbSmlf l_errno ? "\n" : "", NULL);
53366f9d5cbSmlf break;
53466f9d5cbSmlf }
53566f9d5cbSmlf
53666f9d5cbSmlf case CFGA_SATA_OPEN:
53766f9d5cbSmlf /* These messages also apid and errno. */
53866f9d5cbSmlf {
53966f9d5cbSmlf char *errno_str = l_errno ? strerror(l_errno) : "";
54066f9d5cbSmlf
54166f9d5cbSmlf set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "\n",
54266f9d5cbSmlf errno_str, l_errno ? "\n" : "", NULL);
54366f9d5cbSmlf break;
54466f9d5cbSmlf }
54566f9d5cbSmlf
54666f9d5cbSmlf default:
54766f9d5cbSmlf set_msg(errstring, ERR_STR(CFGA_SATA_INTERNAL_ERROR), NULL);
54866f9d5cbSmlf
54966f9d5cbSmlf } /* end switch */
55066f9d5cbSmlf
55166f9d5cbSmlf
55266f9d5cbSmlf /*
55366f9d5cbSmlf * Determine the proper error code to send back to the cfgadm library.
55466f9d5cbSmlf */
55566f9d5cbSmlf return (sata_msgs[rv].cfga_err);
55666f9d5cbSmlf }
55766f9d5cbSmlf
55866f9d5cbSmlf
55966f9d5cbSmlf /*
56066f9d5cbSmlf * Entry points
56166f9d5cbSmlf */
56266f9d5cbSmlf /* cfgadm entry point */
56366f9d5cbSmlf /*ARGSUSED*/
56466f9d5cbSmlf 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)56566f9d5cbSmlf cfga_change_state(
56666f9d5cbSmlf cfga_cmd_t state_change_cmd,
56766f9d5cbSmlf const char *ap_id,
56866f9d5cbSmlf const char *options,
56966f9d5cbSmlf struct cfga_confirm *confp,
57066f9d5cbSmlf struct cfga_msg *msgp,
57166f9d5cbSmlf char **errstring,
57266f9d5cbSmlf cfga_flags_t flags)
57366f9d5cbSmlf {
57466f9d5cbSmlf int ret;
57566f9d5cbSmlf int len;
57666f9d5cbSmlf char *msg;
57766f9d5cbSmlf char *devpath;
57866f9d5cbSmlf nvlist_t *nvl = NULL;
57966f9d5cbSmlf ap_rstate_t rstate;
58066f9d5cbSmlf ap_ostate_t ostate;
58166f9d5cbSmlf devctl_hdl_t hdl = NULL;
58266f9d5cbSmlf cfga_sata_ret_t rv = CFGA_SATA_OK;
58366f9d5cbSmlf char *pdyn;
5848aa6aadbSXiao-Yu Zhang char *str_type;
5858aa6aadbSXiao-Yu Zhang size_t size;
5868aa6aadbSXiao-Yu Zhang boolean_t pmult = B_FALSE;
58766f9d5cbSmlf
58866f9d5cbSmlf /*
58966f9d5cbSmlf * All sub-commands which can change state of device require
59066f9d5cbSmlf * root privileges.
59166f9d5cbSmlf */
59266f9d5cbSmlf if (geteuid() != 0) {
59366f9d5cbSmlf rv = CFGA_SATA_PRIV;
59466f9d5cbSmlf goto bailout;
59566f9d5cbSmlf }
59666f9d5cbSmlf
59766f9d5cbSmlf if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) {
59866f9d5cbSmlf (void) cfga_help(msgp, options, flags);
59966f9d5cbSmlf goto bailout;
60066f9d5cbSmlf }
60166f9d5cbSmlf
60266f9d5cbSmlf if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &nvl,
60366f9d5cbSmlf DC_RDONLY)) != CFGA_SATA_OK) {
60466f9d5cbSmlf goto bailout;
60566f9d5cbSmlf }
60666f9d5cbSmlf
6078aa6aadbSXiao-Yu Zhang /*
6088aa6aadbSXiao-Yu Zhang * Checking device type. A port multiplier is not configurable - it is
6098aa6aadbSXiao-Yu Zhang * already configured as soon as it is connected.
6108aa6aadbSXiao-Yu Zhang */
61121f023dfSToomas Soome if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, 0,
6128aa6aadbSXiao-Yu Zhang (void **)&str_type, &size)) != CFGA_SATA_OK) {
6138aa6aadbSXiao-Yu Zhang /* no such deivce */
6148aa6aadbSXiao-Yu Zhang goto bailout;
6158aa6aadbSXiao-Yu Zhang }
6168aa6aadbSXiao-Yu Zhang if (strncmp(str_type, "sata-pmult", sizeof ("sata-pmult")) == 0) {
6178aa6aadbSXiao-Yu Zhang pmult = B_TRUE;
6188aa6aadbSXiao-Yu Zhang }
6198aa6aadbSXiao-Yu Zhang
62066f9d5cbSmlf switch (state_change_cmd) {
62166f9d5cbSmlf case CFGA_CMD_CONFIGURE:
6228aa6aadbSXiao-Yu Zhang if (pmult == B_TRUE) {
6238aa6aadbSXiao-Yu Zhang rv = CFGA_SATA_HWOPNOTSUPP;
6248aa6aadbSXiao-Yu Zhang goto bailout;
6258aa6aadbSXiao-Yu Zhang }
6268aa6aadbSXiao-Yu Zhang
62766f9d5cbSmlf if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
62866f9d5cbSmlf CFGA_SATA_OK)
62966f9d5cbSmlf goto bailout;
63066f9d5cbSmlf
63166f9d5cbSmlf if (ostate == AP_OSTATE_CONFIGURED) {
63266f9d5cbSmlf rv = CFGA_SATA_ALREADY_CONFIGURED;
63366f9d5cbSmlf goto bailout;
63466f9d5cbSmlf }
63566f9d5cbSmlf /* Disallow dynamic AP name component */
63666f9d5cbSmlf if (GET_DYN(ap_id) != NULL) {
63766f9d5cbSmlf rv = CFGA_SATA_INVALID_DEVNAME;
63866f9d5cbSmlf goto bailout;
63966f9d5cbSmlf }
64066f9d5cbSmlf
64166f9d5cbSmlf if (rstate == AP_RSTATE_EMPTY) {
64266f9d5cbSmlf rv = CFGA_SATA_NOT_CONNECTED;
64366f9d5cbSmlf goto bailout;
64466f9d5cbSmlf }
64566f9d5cbSmlf rv = CFGA_SATA_OK;
64666f9d5cbSmlf
64766f9d5cbSmlf if (devctl_ap_configure(hdl, nvl) != 0) {
64866f9d5cbSmlf rv = CFGA_SATA_DEV_CONFIGURE;
64966f9d5cbSmlf goto bailout;
65066f9d5cbSmlf }
65166f9d5cbSmlf
65266f9d5cbSmlf devpath = sata_get_devicepath(ap_id);
65366f9d5cbSmlf if (devpath == NULL) {
65466f9d5cbSmlf int i;
65566f9d5cbSmlf /*
65666f9d5cbSmlf * Try for some time as SATA hotplug thread
65766f9d5cbSmlf * takes a while to create the path then
65866f9d5cbSmlf * eventually give up.
65966f9d5cbSmlf */
66066f9d5cbSmlf for (i = 0; i < 12 && (devpath == NULL); i++) {
66166f9d5cbSmlf (void) sleep(6);
66266f9d5cbSmlf devpath = sata_get_devicepath(ap_id);
66366f9d5cbSmlf }
66466f9d5cbSmlf
66566f9d5cbSmlf if (devpath == NULL) {
66666f9d5cbSmlf rv = CFGA_SATA_DEV_CONFIGURE;
66766f9d5cbSmlf break;
66866f9d5cbSmlf }
66966f9d5cbSmlf }
67066f9d5cbSmlf
67166f9d5cbSmlf S_FREE(devpath);
67266f9d5cbSmlf break;
67366f9d5cbSmlf
67466f9d5cbSmlf case CFGA_CMD_UNCONFIGURE:
6758aa6aadbSXiao-Yu Zhang if (pmult == B_TRUE) {
6768aa6aadbSXiao-Yu Zhang rv = CFGA_SATA_HWOPNOTSUPP;
6778aa6aadbSXiao-Yu Zhang goto bailout;
6788aa6aadbSXiao-Yu Zhang }
6798aa6aadbSXiao-Yu Zhang
68066f9d5cbSmlf if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
68166f9d5cbSmlf CFGA_SATA_OK)
68266f9d5cbSmlf goto bailout;
68366f9d5cbSmlf
68466f9d5cbSmlf if (rstate != AP_RSTATE_CONNECTED) {
68566f9d5cbSmlf rv = CFGA_SATA_NOT_CONNECTED;
68666f9d5cbSmlf goto bailout;
68766f9d5cbSmlf }
68866f9d5cbSmlf
68966f9d5cbSmlf if (ostate != AP_OSTATE_CONFIGURED) {
69066f9d5cbSmlf rv = CFGA_SATA_NOT_CONFIGURED;
69166f9d5cbSmlf goto bailout;
69266f9d5cbSmlf }
69366f9d5cbSmlf /* Strip off AP name dynamic component, if present */
69466f9d5cbSmlf if ((pdyn = GET_DYN(ap_id)) != NULL) {
69566f9d5cbSmlf *pdyn = '\0';
69666f9d5cbSmlf }
69766f9d5cbSmlf
69866f9d5cbSmlf rv = CFGA_SATA_OK;
69966f9d5cbSmlf
70066f9d5cbSmlf len = strlen(SATA_CONFIRM_DEVICE) +
70166f9d5cbSmlf strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
70266f9d5cbSmlf strlen("Unconfigure") + strlen(ap_id);
70366f9d5cbSmlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
70466f9d5cbSmlf (void) snprintf(msg, len + 3, "Unconfigure"
70566f9d5cbSmlf " %s%s\n%s",
70666f9d5cbSmlf SATA_CONFIRM_DEVICE, ap_id,
70766f9d5cbSmlf SATA_CONFIRM_DEVICE_SUSPEND);
70866f9d5cbSmlf }
70966f9d5cbSmlf
71066f9d5cbSmlf if (!sata_confirm(confp, msg)) {
71166f9d5cbSmlf free(msg);
71266f9d5cbSmlf rv = CFGA_SATA_NACK;
71366f9d5cbSmlf break;
71466f9d5cbSmlf }
71566f9d5cbSmlf free(msg);
71666f9d5cbSmlf
71766f9d5cbSmlf devpath = sata_get_devicepath(ap_id);
71866f9d5cbSmlf if (devpath == NULL) {
71966f9d5cbSmlf (void) printf(
72066f9d5cbSmlf "cfga_change_state: get device path failed\n");
72166f9d5cbSmlf rv = CFGA_SATA_DEV_UNCONFIGURE;
72266f9d5cbSmlf break;
72366f9d5cbSmlf }
72466f9d5cbSmlf
72566f9d5cbSmlf if ((rv = sata_rcm_offline(ap_id, errstring, devpath, flags))
72666f9d5cbSmlf != CFGA_SATA_OK) {
72766f9d5cbSmlf break;
72866f9d5cbSmlf }
72966f9d5cbSmlf
73066f9d5cbSmlf ret = devctl_ap_unconfigure(hdl, nvl);
73166f9d5cbSmlf
73266f9d5cbSmlf if (ret != 0) {
73366f9d5cbSmlf rv = CFGA_SATA_DEV_UNCONFIGURE;
73466f9d5cbSmlf if (errno == EBUSY) {
73566f9d5cbSmlf rv = CFGA_SATA_BUSY;
73666f9d5cbSmlf }
73766f9d5cbSmlf (void) sata_rcm_online(ap_id, errstring, devpath,
73866f9d5cbSmlf flags);
73966f9d5cbSmlf } else {
74066f9d5cbSmlf (void) sata_rcm_remove(ap_id, errstring, devpath,
74166f9d5cbSmlf flags);
74266f9d5cbSmlf
74366f9d5cbSmlf }
74466f9d5cbSmlf S_FREE(devpath);
74566f9d5cbSmlf
74666f9d5cbSmlf break;
74766f9d5cbSmlf
74866f9d5cbSmlf case CFGA_CMD_DISCONNECT:
74966f9d5cbSmlf if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
75066f9d5cbSmlf CFGA_SATA_OK)
75166f9d5cbSmlf goto bailout;
75266f9d5cbSmlf
75366f9d5cbSmlf if (rstate == AP_RSTATE_DISCONNECTED) {
75466f9d5cbSmlf rv = CFGA_SATA_DISCONNECTED;
75566f9d5cbSmlf goto bailout;
75666f9d5cbSmlf }
75766f9d5cbSmlf
75866f9d5cbSmlf /* Strip off AP name dynamic component, if present */
75966f9d5cbSmlf if ((pdyn = GET_DYN(ap_id)) != NULL) {
76066f9d5cbSmlf *pdyn = '\0';
76166f9d5cbSmlf }
76266f9d5cbSmlf
76366f9d5cbSmlf
76466f9d5cbSmlf rv = CFGA_SATA_OK; /* other statuses don't matter */
76566f9d5cbSmlf
76666f9d5cbSmlf /*
76766f9d5cbSmlf * If the port originally with device attached and was
76866f9d5cbSmlf * unconfigured already, the devicepath for the sd will be
76966f9d5cbSmlf * removed. sata_get_devicepath in this case is not necessary.
77066f9d5cbSmlf */
77166f9d5cbSmlf /* only call rcm_offline if the state was CONFIGURED */
7728aa6aadbSXiao-Yu Zhang if (ostate == AP_OSTATE_CONFIGURED &&
7738aa6aadbSXiao-Yu Zhang pmult == B_FALSE) {
77466f9d5cbSmlf devpath = sata_get_devicepath(ap_id);
77566f9d5cbSmlf if (devpath == NULL) {
77666f9d5cbSmlf (void) printf(
77766f9d5cbSmlf "cfga_change_state: get path failed\n");
77866f9d5cbSmlf rv = CFGA_SATA_DEV_UNCONFIGURE;
77966f9d5cbSmlf break;
78066f9d5cbSmlf }
78166f9d5cbSmlf
78266f9d5cbSmlf len = strlen(SATA_CONFIRM_DEVICE) +
78366f9d5cbSmlf strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
78466f9d5cbSmlf strlen("Disconnect") + strlen(ap_id);
78566f9d5cbSmlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
78666f9d5cbSmlf (void) snprintf(msg, len + 3,
78766f9d5cbSmlf "Disconnect"
78866f9d5cbSmlf " %s%s\n%s",
78966f9d5cbSmlf SATA_CONFIRM_DEVICE, ap_id,
79066f9d5cbSmlf SATA_CONFIRM_DEVICE_SUSPEND);
79166f9d5cbSmlf }
79266f9d5cbSmlf if (!sata_confirm(confp, msg)) {
79366f9d5cbSmlf free(msg);
79466f9d5cbSmlf rv = CFGA_SATA_NACK;
79566f9d5cbSmlf break;
79666f9d5cbSmlf }
79766f9d5cbSmlf free(msg);
79866f9d5cbSmlf
79966f9d5cbSmlf if ((rv = sata_rcm_offline(ap_id, errstring,
80066f9d5cbSmlf devpath, flags)) != CFGA_SATA_OK) {
80166f9d5cbSmlf break;
80266f9d5cbSmlf }
80366f9d5cbSmlf
80466f9d5cbSmlf ret = devctl_ap_unconfigure(hdl, nvl);
80566f9d5cbSmlf if (ret != 0) {
80666f9d5cbSmlf (void) printf(
80766f9d5cbSmlf "devctl_ap_unconfigure failed\n");
80866f9d5cbSmlf rv = CFGA_SATA_DEV_UNCONFIGURE;
80966f9d5cbSmlf if (errno == EBUSY)
81066f9d5cbSmlf rv = CFGA_SATA_BUSY;
81166f9d5cbSmlf (void) sata_rcm_online(ap_id, errstring,
81266f9d5cbSmlf devpath, flags);
81366f9d5cbSmlf S_FREE(devpath);
81466f9d5cbSmlf
81566f9d5cbSmlf /*
81666f9d5cbSmlf * The current policy is that if unconfigure
81766f9d5cbSmlf * failed, do not continue with disconnect.
81866f9d5cbSmlf * If the port needs to be forced into the
81966f9d5cbSmlf * disconnect (shutdown) state,
82066f9d5cbSmlf * the -x sata_port_poweroff command should be
82166f9d5cbSmlf * used instead of -c disconnect
82266f9d5cbSmlf */
82366f9d5cbSmlf break;
82466f9d5cbSmlf } else {
82566f9d5cbSmlf (void) printf("%s\n",
82666f9d5cbSmlf ERR_STR(CFGA_SATA_DEVICE_UNCONFIGURED));
82766f9d5cbSmlf (void) sata_rcm_remove(ap_id, errstring,
82866f9d5cbSmlf devpath, flags);
82966f9d5cbSmlf }
83066f9d5cbSmlf S_FREE(devpath);
83166f9d5cbSmlf } else if (rstate == AP_RSTATE_CONNECTED ||
83266f9d5cbSmlf rstate == AP_RSTATE_EMPTY) {
83366f9d5cbSmlf len = strlen(SATA_CONFIRM_PORT) +
83466f9d5cbSmlf strlen(SATA_CONFIRM_PORT_DISABLE) +
83566f9d5cbSmlf strlen("Deactivate Port") + strlen(ap_id);
83666f9d5cbSmlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
83766f9d5cbSmlf (void) snprintf(msg, len +3,
83866f9d5cbSmlf "Disconnect"
83966f9d5cbSmlf " %s%s\n%s",
84066f9d5cbSmlf SATA_CONFIRM_PORT, ap_id,
84166f9d5cbSmlf SATA_CONFIRM_PORT_DISABLE);
84266f9d5cbSmlf }
84366f9d5cbSmlf if (!sata_confirm(confp, msg)) {
84466f9d5cbSmlf free(msg);
84566f9d5cbSmlf rv = CFGA_SATA_NACK;
84666f9d5cbSmlf break;
84766f9d5cbSmlf }
84866f9d5cbSmlf }
84966f9d5cbSmlf ret = devctl_ap_disconnect(hdl, nvl);
85066f9d5cbSmlf if (ret != 0) {
85166f9d5cbSmlf rv = CFGA_SATA_IOCTL;
85266f9d5cbSmlf if (errno == EBUSY) {
85366f9d5cbSmlf rv = CFGA_SATA_BUSY;
85466f9d5cbSmlf }
85566f9d5cbSmlf }
85666f9d5cbSmlf break;
85766f9d5cbSmlf
85866f9d5cbSmlf case CFGA_CMD_CONNECT:
85966f9d5cbSmlf if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
86066f9d5cbSmlf CFGA_SATA_OK)
86166f9d5cbSmlf goto bailout;
86266f9d5cbSmlf
86366f9d5cbSmlf if (rstate == AP_RSTATE_CONNECTED) {
86466f9d5cbSmlf rv = CFGA_SATA_ALREADY_CONNECTED;
86566f9d5cbSmlf goto bailout;
86666f9d5cbSmlf }
86766f9d5cbSmlf
86866f9d5cbSmlf len = strlen(SATA_CONFIRM_PORT) +
86966f9d5cbSmlf strlen(SATA_CONFIRM_PORT_ENABLE) +
87066f9d5cbSmlf strlen("Activate Port") + strlen(ap_id);
87166f9d5cbSmlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
87266f9d5cbSmlf (void) snprintf(msg, len +3, "Activate"
87366f9d5cbSmlf " %s%s\n%s",
87466f9d5cbSmlf SATA_CONFIRM_PORT, ap_id,
87566f9d5cbSmlf SATA_CONFIRM_PORT_ENABLE);
87666f9d5cbSmlf }
87766f9d5cbSmlf if (!sata_confirm(confp, msg)) {
87866f9d5cbSmlf rv = CFGA_SATA_NACK;
87966f9d5cbSmlf break;
88066f9d5cbSmlf }
88166f9d5cbSmlf
88266f9d5cbSmlf /* Disallow dynamic AP name component */
88366f9d5cbSmlf if (GET_DYN(ap_id) != NULL) {
88466f9d5cbSmlf rv = CFGA_SATA_INVALID_DEVNAME;
88566f9d5cbSmlf goto bailout;
88666f9d5cbSmlf }
88766f9d5cbSmlf
88866f9d5cbSmlf ret = devctl_ap_connect(hdl, nvl);
88966f9d5cbSmlf if (ret != 0) {
89066f9d5cbSmlf rv = CFGA_SATA_IOCTL;
89166f9d5cbSmlf } else {
89266f9d5cbSmlf rv = CFGA_SATA_OK;
89366f9d5cbSmlf }
89466f9d5cbSmlf
89566f9d5cbSmlf break;
89666f9d5cbSmlf
89766f9d5cbSmlf case CFGA_CMD_LOAD:
89866f9d5cbSmlf case CFGA_CMD_UNLOAD:
89966f9d5cbSmlf (void) cfga_help(msgp, options, flags);
90066f9d5cbSmlf rv = CFGA_SATA_OPNOTSUPP;
90166f9d5cbSmlf break;
90266f9d5cbSmlf
90366f9d5cbSmlf case CFGA_CMD_NONE:
90466f9d5cbSmlf default:
90566f9d5cbSmlf (void) cfga_help(msgp, options, flags);
90666f9d5cbSmlf rv = CFGA_SATA_INTERNAL_ERROR;
90766f9d5cbSmlf }
90866f9d5cbSmlf
90966f9d5cbSmlf bailout:
91066f9d5cbSmlf cleanup_after_devctl_cmd(hdl, nvl);
91166f9d5cbSmlf
91266f9d5cbSmlf return (sata_err_msg(errstring, rv, ap_id, errno));
91366f9d5cbSmlf }
91466f9d5cbSmlf
91566f9d5cbSmlf /* cfgadm entry point */
91666f9d5cbSmlf 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)91766f9d5cbSmlf cfga_private_func(
91866f9d5cbSmlf const char *func,
91966f9d5cbSmlf const char *ap_id,
92066f9d5cbSmlf const char *options,
92166f9d5cbSmlf struct cfga_confirm *confp,
92266f9d5cbSmlf struct cfga_msg *msgp,
92366f9d5cbSmlf char **errstring,
92466f9d5cbSmlf cfga_flags_t flags)
92566f9d5cbSmlf {
92666f9d5cbSmlf int len;
92766f9d5cbSmlf char *msg;
92866f9d5cbSmlf nvlist_t *list = NULL;
92966f9d5cbSmlf ap_ostate_t ostate;
93066f9d5cbSmlf ap_rstate_t rstate;
93166f9d5cbSmlf devctl_hdl_t hdl = NULL;
93266f9d5cbSmlf cfga_sata_ret_t rv;
93366f9d5cbSmlf char *str_p;
93466f9d5cbSmlf size_t size;
93566f9d5cbSmlf
93666f9d5cbSmlf if ((rv = verify_params(ap_id, NULL, errstring)) != CFGA_SATA_OK) {
93766f9d5cbSmlf (void) cfga_help(msgp, options, flags);
93866f9d5cbSmlf return (sata_err_msg(errstring, rv, ap_id, errno));
93966f9d5cbSmlf }
94066f9d5cbSmlf
94166f9d5cbSmlf /*
94266f9d5cbSmlf * All subcommands which can change state of device require
94366f9d5cbSmlf * root privileges.
94466f9d5cbSmlf */
94566f9d5cbSmlf if (geteuid() != 0) {
94666f9d5cbSmlf rv = CFGA_SATA_PRIV;
94766f9d5cbSmlf goto bailout;
94866f9d5cbSmlf }
94966f9d5cbSmlf
95066f9d5cbSmlf if (func == NULL) {
95166f9d5cbSmlf (void) printf("No valid option specified\n");
95266f9d5cbSmlf rv = CFGA_SATA_OPTIONS;
95366f9d5cbSmlf goto bailout;
95466f9d5cbSmlf }
95566f9d5cbSmlf
95666f9d5cbSmlf if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &list, 0)) !=
95766f9d5cbSmlf CFGA_SATA_OK) {
95866f9d5cbSmlf goto bailout;
95966f9d5cbSmlf }
96066f9d5cbSmlf
96166f9d5cbSmlf /* We do not care here about dynamic AP name component */
96266f9d5cbSmlf if ((str_p = GET_DYN(ap_id)) != NULL) {
96366f9d5cbSmlf *str_p = '\0';
96466f9d5cbSmlf }
96566f9d5cbSmlf
96666f9d5cbSmlf rv = CFGA_SATA_OK;
96766f9d5cbSmlf
96866f9d5cbSmlf if (strcmp(func, SATA_RESET_PORT) == 0) {
96966f9d5cbSmlf len = strlen(SATA_CONFIRM_PORT) +
97066f9d5cbSmlf strlen(SATA_CONFIRM_DEVICE_ABORT) +
97166f9d5cbSmlf strlen("Reset Port") + strlen(ap_id);
97266f9d5cbSmlf
97366f9d5cbSmlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
97466f9d5cbSmlf (void) snprintf(msg, len +3, "Reset"
97566f9d5cbSmlf " %s%s\n%s",
97666f9d5cbSmlf SATA_CONFIRM_PORT, ap_id,
97766f9d5cbSmlf SATA_CONFIRM_DEVICE_ABORT);
97866f9d5cbSmlf } else {
97966f9d5cbSmlf rv = CFGA_SATA_NACK;
98066f9d5cbSmlf goto bailout;
98166f9d5cbSmlf }
98266f9d5cbSmlf
98366f9d5cbSmlf if (!sata_confirm(confp, msg)) {
98466f9d5cbSmlf rv = CFGA_SATA_NACK;
98566f9d5cbSmlf goto bailout;
98666f9d5cbSmlf }
98766f9d5cbSmlf
98821f023dfSToomas Soome rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_PORT, 0,
98966f9d5cbSmlf (void **)&str_p, &size);
99066f9d5cbSmlf
99166f9d5cbSmlf } else if (strcmp(func, SATA_RESET_DEVICE) == 0) {
99266f9d5cbSmlf if ((rv = port_state(hdl, list, &rstate, &ostate)) !=
99366f9d5cbSmlf CFGA_SATA_OK)
99466f9d5cbSmlf goto bailout;
99566f9d5cbSmlf /*
99666f9d5cbSmlf * Reset device function requires device to be connected
99766f9d5cbSmlf */
99866f9d5cbSmlf if (rstate != AP_RSTATE_CONNECTED) {
99966f9d5cbSmlf rv = CFGA_SATA_NOT_CONNECTED;
100066f9d5cbSmlf goto bailout;
100166f9d5cbSmlf }
100266f9d5cbSmlf
100366f9d5cbSmlf len = strlen(SATA_CONFIRM_DEVICE) +
100466f9d5cbSmlf strlen(SATA_CONFIRM_DEVICE_ABORT) +
100566f9d5cbSmlf strlen("Reset Device") + strlen(ap_id);
100666f9d5cbSmlf
100766f9d5cbSmlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
100866f9d5cbSmlf (void) snprintf(msg, len +3, "Reset"
100966f9d5cbSmlf " %s%s\n%s",
101066f9d5cbSmlf SATA_CONFIRM_DEVICE, ap_id,
101166f9d5cbSmlf SATA_CONFIRM_DEVICE_ABORT);
101266f9d5cbSmlf } else {
101366f9d5cbSmlf rv = CFGA_SATA_NACK;
101466f9d5cbSmlf goto bailout;
101566f9d5cbSmlf }
101666f9d5cbSmlf
101766f9d5cbSmlf if (!sata_confirm(confp, msg)) {
101866f9d5cbSmlf rv = CFGA_SATA_NACK;
101966f9d5cbSmlf goto bailout;
102066f9d5cbSmlf }
102166f9d5cbSmlf
102221f023dfSToomas Soome rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_DEVICE, 0,
102366f9d5cbSmlf (void **)&str_p, &size);
102466f9d5cbSmlf
102566f9d5cbSmlf } else if (strcmp(func, SATA_RESET_ALL) == 0) {
102666f9d5cbSmlf len = strlen(SATA_CONFIRM_CONTROLLER) +
102766f9d5cbSmlf strlen(SATA_CONFIRM_CONTROLLER_ABORT) +
102866f9d5cbSmlf strlen("Reset All") + strlen(ap_id);
102966f9d5cbSmlf
103066f9d5cbSmlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
103166f9d5cbSmlf (void) snprintf(msg, len +3, "Reset"
103266f9d5cbSmlf " %s%s\n%s",
103366f9d5cbSmlf SATA_CONFIRM_CONTROLLER, ap_id,
103466f9d5cbSmlf SATA_CONFIRM_CONTROLLER_ABORT);
103566f9d5cbSmlf } else {
103666f9d5cbSmlf rv = CFGA_SATA_NACK;
103766f9d5cbSmlf goto bailout;
103866f9d5cbSmlf }
103966f9d5cbSmlf
104066f9d5cbSmlf if (!sata_confirm(confp, msg)) {
104166f9d5cbSmlf rv = CFGA_SATA_NACK;
104266f9d5cbSmlf goto bailout;
104366f9d5cbSmlf }
104421f023dfSToomas Soome rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_ALL, 0,
104566f9d5cbSmlf (void **)&str_p, &size);
104666f9d5cbSmlf
104766f9d5cbSmlf } else if (strcmp(func, SATA_PORT_DEACTIVATE) == 0) {
104866f9d5cbSmlf len = strlen(SATA_CONFIRM_PORT) +
104966f9d5cbSmlf strlen(SATA_CONFIRM_PORT_DISABLE) +
105066f9d5cbSmlf strlen("Deactivate Port") + strlen(ap_id);
105166f9d5cbSmlf
105266f9d5cbSmlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
105366f9d5cbSmlf (void) snprintf(msg, len +3, "Deactivate"
105466f9d5cbSmlf " %s%s\n%s",
105566f9d5cbSmlf SATA_CONFIRM_PORT, ap_id,
105666f9d5cbSmlf SATA_CONFIRM_PORT_DISABLE);
105766f9d5cbSmlf } else {
105866f9d5cbSmlf rv = CFGA_SATA_NACK;
105966f9d5cbSmlf goto bailout;
106066f9d5cbSmlf }
106166f9d5cbSmlf if (!sata_confirm(confp, msg)) {
106266f9d5cbSmlf rv = CFGA_SATA_NACK;
106366f9d5cbSmlf goto bailout;
106466f9d5cbSmlf }
106566f9d5cbSmlf
106621f023dfSToomas Soome rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_DEACTIVATE, 0,
106766f9d5cbSmlf (void **)&str_p, &size);
106866f9d5cbSmlf
106966f9d5cbSmlf } else if (strcmp(func, SATA_PORT_ACTIVATE) == 0) {
107066f9d5cbSmlf len = strlen(SATA_CONFIRM_PORT) +
107166f9d5cbSmlf strlen(SATA_CONFIRM_PORT_ENABLE) +
107266f9d5cbSmlf strlen("Activate Port") + strlen(ap_id);
107366f9d5cbSmlf
107466f9d5cbSmlf if ((msg = (char *)calloc(len +3, 1)) != NULL) {
107566f9d5cbSmlf (void) snprintf(msg, len +3, "Activate"
107666f9d5cbSmlf " %s%s\n%s",
107766f9d5cbSmlf SATA_CONFIRM_PORT, ap_id,
107866f9d5cbSmlf SATA_CONFIRM_PORT_ENABLE);
107966f9d5cbSmlf } else {
108066f9d5cbSmlf rv = CFGA_SATA_NACK;
108166f9d5cbSmlf goto bailout;
108266f9d5cbSmlf }
108366f9d5cbSmlf if (!sata_confirm(confp, msg)) {
108466f9d5cbSmlf rv = CFGA_SATA_NACK;
108566f9d5cbSmlf goto bailout;
108666f9d5cbSmlf }
108766f9d5cbSmlf
108866f9d5cbSmlf rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_ACTIVATE,
108921f023dfSToomas Soome 0, (void **)&str_p, &size);
109066f9d5cbSmlf goto bailout;
109166f9d5cbSmlf
109266f9d5cbSmlf } else if (strcmp(func, SATA_PORT_SELF_TEST) == 0) {
109366f9d5cbSmlf len = strlen(SATA_CONFIRM_PORT) +
109466f9d5cbSmlf strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
109566f9d5cbSmlf strlen("Self Test Port") + strlen(ap_id);
109666f9d5cbSmlf
109721f023dfSToomas Soome if ((msg = calloc(len +3, 1)) != NULL) {
109866f9d5cbSmlf (void) snprintf(msg, len +3, "Self Test"
109966f9d5cbSmlf " %s%s\n%s",
110066f9d5cbSmlf SATA_CONFIRM_PORT, ap_id,
110166f9d5cbSmlf SATA_CONFIRM_DEVICE_SUSPEND);
110266f9d5cbSmlf } else {
110366f9d5cbSmlf rv = CFGA_SATA_NACK;
110466f9d5cbSmlf goto bailout;
110566f9d5cbSmlf }
110666f9d5cbSmlf if (!sata_confirm(confp, msg)) {
110766f9d5cbSmlf rv = CFGA_SATA_NACK;
110866f9d5cbSmlf goto bailout;
110966f9d5cbSmlf }
111066f9d5cbSmlf
111166f9d5cbSmlf rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_SELF_TEST,
111221f023dfSToomas Soome 0, (void **)&str_p, &size);
111366f9d5cbSmlf } else {
111466f9d5cbSmlf /* Unrecognized operation request */
111566f9d5cbSmlf rv = CFGA_SATA_HWOPNOTSUPP;
111666f9d5cbSmlf }
111766f9d5cbSmlf
111866f9d5cbSmlf bailout:
111966f9d5cbSmlf cleanup_after_devctl_cmd(hdl, list);
112066f9d5cbSmlf
112166f9d5cbSmlf return (sata_err_msg(errstring, rv, ap_id, errno));
112266f9d5cbSmlf
112366f9d5cbSmlf }
112466f9d5cbSmlf
112566f9d5cbSmlf /* cfgadm entry point */
112666f9d5cbSmlf /*ARGSUSED*/
112766f9d5cbSmlf cfga_err_t
cfga_test(const char * ap_id,const char * options,struct cfga_msg * msgp,char ** errstring,cfga_flags_t flags)112866f9d5cbSmlf cfga_test(
112966f9d5cbSmlf const char *ap_id,
113066f9d5cbSmlf const char *options,
113166f9d5cbSmlf struct cfga_msg *msgp,
113266f9d5cbSmlf char **errstring,
113366f9d5cbSmlf cfga_flags_t flags)
113466f9d5cbSmlf {
113566f9d5cbSmlf /* Should call ioctl for self test - phase 2 */
113666f9d5cbSmlf return (CFGA_OPNOTSUPP);
113766f9d5cbSmlf }
113866f9d5cbSmlf
113966f9d5cbSmlf
114066f9d5cbSmlf int
sata_check_target_node(di_node_t node,void * arg)114166f9d5cbSmlf sata_check_target_node(di_node_t node, void *arg)
114266f9d5cbSmlf {
114366f9d5cbSmlf char *minorpath;
114466f9d5cbSmlf char *cp;
114566f9d5cbSmlf
114666f9d5cbSmlf minorpath = di_devfs_minor_path(di_minor_next(node, DI_MINOR_NIL));
114766f9d5cbSmlf if (minorpath != NULL) {
114866f9d5cbSmlf if (strstr(minorpath, arg) != NULL) {
114966f9d5cbSmlf cp = strrchr(minorpath, (int)*MINOR_SEP);
115066f9d5cbSmlf if (cp != NULL) {
115166f9d5cbSmlf (void) strcpy(arg, cp);
115266f9d5cbSmlf }
115366f9d5cbSmlf free(minorpath);
115466f9d5cbSmlf return (DI_WALK_TERMINATE);
115566f9d5cbSmlf }
115666f9d5cbSmlf free(minorpath);
115766f9d5cbSmlf }
115866f9d5cbSmlf return (DI_WALK_CONTINUE);
115966f9d5cbSmlf }
116066f9d5cbSmlf
1161d7b0e458Svikram struct chk_dev {
1162d7b0e458Svikram int c_isblk;
1163d7b0e458Svikram char *c_minor;
1164d7b0e458Svikram };
1165d7b0e458Svikram
1166d7b0e458Svikram /*ARGSUSED*/
1167d7b0e458Svikram static int
chk_dev_fcn(di_node_t node,di_minor_t minor,void * arg)1168d7b0e458Svikram chk_dev_fcn(di_node_t node, di_minor_t minor, void *arg)
1169d7b0e458Svikram {
1170d7b0e458Svikram char *mn;
1171d7b0e458Svikram struct chk_dev *chkp = (struct chk_dev *)arg;
1172d7b0e458Svikram
1173d7b0e458Svikram mn = di_minor_name(minor);
1174d7b0e458Svikram if (mn == NULL)
1175d7b0e458Svikram return (DI_WALK_CONTINUE);
1176d7b0e458Svikram
1177d7b0e458Svikram if (strcmp(mn, chkp->c_minor) != 0)
1178d7b0e458Svikram return (DI_WALK_CONTINUE);
1179d7b0e458Svikram
1180d7b0e458Svikram chkp->c_isblk = di_minor_spectype(minor) == S_IFBLK ? 1 : 0;
1181d7b0e458Svikram
1182d7b0e458Svikram return (DI_WALK_TERMINATE);
1183d7b0e458Svikram }
1184d7b0e458Svikram
1185d7b0e458Svikram /*
1186d7b0e458Svikram * Don't use devfs if stat() in /devices fails. Use libdevinfo instead.
1187d7b0e458Svikram * Retired devices don't show up in devfs.
1188d7b0e458Svikram *
1189d7b0e458Svikram * Returns:
1190d7b0e458Svikram * 1 - minor exists and is of type BLK
1191d7b0e458Svikram * 0 - minor does not exist or is not of type BLK.
1192d7b0e458Svikram */
1193d7b0e458Svikram static int
is_devinfo_blk(char * minor_path)1194d7b0e458Svikram is_devinfo_blk(char *minor_path)
1195d7b0e458Svikram {
1196d7b0e458Svikram char *minor_portion;
1197d7b0e458Svikram struct chk_dev chk_dev;
1198d7b0e458Svikram di_node_t node;
1199d7b0e458Svikram int rv;
1200d7b0e458Svikram
1201d7b0e458Svikram /*
1202d7b0e458Svikram * prune minor path for di_init() - no /devices prefix and no minor name
1203d7b0e458Svikram */
1204d7b0e458Svikram if (strncmp(minor_path, "/devices/", strlen("/devices/")) != 0)
1205d7b0e458Svikram return (0);
1206d7b0e458Svikram
1207d7b0e458Svikram minor_portion = strrchr(minor_path, *MINOR_SEP);
1208d7b0e458Svikram if (minor_portion == NULL)
1209d7b0e458Svikram return (0);
1210d7b0e458Svikram
1211d7b0e458Svikram *minor_portion = 0;
1212d7b0e458Svikram
1213d7b0e458Svikram node = di_init(minor_path + strlen("/devices"), DINFOMINOR);
1214d7b0e458Svikram
1215d7b0e458Svikram *minor_portion = *MINOR_SEP;
1216d7b0e458Svikram
1217d7b0e458Svikram if (node == DI_NODE_NIL)
1218d7b0e458Svikram return (0);
1219d7b0e458Svikram
1220d7b0e458Svikram chk_dev.c_isblk = 0;
1221d7b0e458Svikram chk_dev.c_minor = minor_portion + 1;
1222d7b0e458Svikram
1223d7b0e458Svikram rv = di_walk_minor(node, NULL, 0, &chk_dev, chk_dev_fcn);
1224d7b0e458Svikram
1225d7b0e458Svikram di_fini(node);
1226d7b0e458Svikram
1227d7b0e458Svikram if (rv == 0 && chk_dev.c_isblk)
1228d7b0e458Svikram return (1);
1229d7b0e458Svikram else
1230d7b0e458Svikram return (0);
1231d7b0e458Svikram }
123266f9d5cbSmlf
123366f9d5cbSmlf /*
123466f9d5cbSmlf * The dynamic component buffer returned by this function has to be freed!
123566f9d5cbSmlf */
123666f9d5cbSmlf int
sata_make_dyncomp(const char * ap_id,char ** dyncomp,const char * type)123738547057Sying tian - Beijing China sata_make_dyncomp(const char *ap_id, char **dyncomp, const char *type)
123866f9d5cbSmlf {
123966f9d5cbSmlf char *devpath = NULL;
124066f9d5cbSmlf char *cp = NULL;
124166f9d5cbSmlf int l_errno;
1242724365f7Ssethg char minor_path[MAXPATHLEN];
1243724365f7Ssethg char name_part[MAXNAMELEN];
1244724365f7Ssethg char *devlink = NULL;
1245724365f7Ssethg char *minor_portion = NULL;
1246724365f7Ssethg int deplen;
1247724365f7Ssethg int err;
1248724365f7Ssethg DIR *dp = NULL;
1249724365f7Ssethg struct stat sb;
1250724365f7Ssethg struct dirent *dep = NULL;
1251724365f7Ssethg struct dirent *newdep = NULL;
1252545e5dadSsethg char *p;
125366f9d5cbSmlf
125466f9d5cbSmlf assert(dyncomp != NULL);
125566f9d5cbSmlf
125666f9d5cbSmlf /*
125766f9d5cbSmlf * Get target node path
125866f9d5cbSmlf */
125966f9d5cbSmlf devpath = sata_get_devicepath(ap_id);
126066f9d5cbSmlf if (devpath == NULL) {
1261724365f7Ssethg
126266f9d5cbSmlf (void) printf("cfga_list_ext: cannot locate target device\n");
126366f9d5cbSmlf return (CFGA_SATA_DYNAMIC_AP);
1264724365f7Ssethg
126566f9d5cbSmlf } else {
126666f9d5cbSmlf
1267724365f7Ssethg cp = strrchr(devpath, *PATH_SEP);
1268724365f7Ssethg assert(cp != NULL);
1269724365f7Ssethg *cp = 0; /* terminate path for opendir() */
127066f9d5cbSmlf
1271724365f7Ssethg (void) strncpy(name_part, cp + 1, MAXNAMELEN);
1272724365f7Ssethg
1273724365f7Ssethg /*
1274724365f7Ssethg * Using libdevinfo for this is overkill and kills
1275724365f7Ssethg * performance when many consumers are using libcfgadm
1276724365f7Ssethg * concurrently.
1277724365f7Ssethg */
1278724365f7Ssethg if ((dp = opendir(devpath)) == NULL) {
127966f9d5cbSmlf goto bailout;
128066f9d5cbSmlf }
128166f9d5cbSmlf
128266f9d5cbSmlf /*
1283724365f7Ssethg * deplen is large enough to fit the largest path-
1284724365f7Ssethg * struct dirent includes one byte (the terminator)
1285724365f7Ssethg * so we don't add 1 to the calculation here.
128666f9d5cbSmlf */
1287d3080269Ssethg deplen = pathconf(devpath, _PC_NAME_MAX);
1288d3080269Ssethg deplen = ((deplen <= 0) ? MAXNAMELEN : deplen) +
1289724365f7Ssethg sizeof (struct dirent);
1290724365f7Ssethg dep = (struct dirent *)malloc(deplen);
1291724365f7Ssethg if (dep == NULL)
129266f9d5cbSmlf goto bailout;
1293724365f7Ssethg
1294724365f7Ssethg while ((err = readdir_r(dp, dep, &newdep)) == 0 &&
1295724365f7Ssethg newdep != NULL) {
1296724365f7Ssethg
1297724365f7Ssethg assert(newdep == dep);
1298724365f7Ssethg
1299724365f7Ssethg if (strcmp(dep->d_name, ".") == 0 ||
1300724365f7Ssethg strcmp(dep->d_name, "..") == 0 ||
1301724365f7Ssethg (minor_portion = strchr(dep->d_name,
1302724365f7Ssethg *MINOR_SEP)) == NULL)
1303724365f7Ssethg continue;
1304724365f7Ssethg
1305724365f7Ssethg *minor_portion = 0;
1306724365f7Ssethg if (strcmp(dep->d_name, name_part) != 0)
1307724365f7Ssethg continue;
1308724365f7Ssethg *minor_portion = *MINOR_SEP;
1309724365f7Ssethg
1310724365f7Ssethg (void) snprintf(minor_path, MAXPATHLEN,
1311724365f7Ssethg "%s/%s", devpath, dep->d_name);
1312724365f7Ssethg
1313d7b0e458Svikram /*
131438547057Sying tian - Beijing China * Break directly for tape device
131538547057Sying tian - Beijing China */
131638547057Sying tian - Beijing China if (strcmp(type, "tape") == 0)
131738547057Sying tian - Beijing China break;
131838547057Sying tian - Beijing China
131938547057Sying tian - Beijing China /*
1320d7b0e458Svikram * If stat() fails, the device *may* be retired.
1321d7b0e458Svikram * Check via libdevinfo if the device has a BLK minor.
1322d7b0e458Svikram * We don't use libdevinfo all the time, since taking
1323d7b0e458Svikram * a snapshot is slower than a stat().
1324d7b0e458Svikram */
1325d7b0e458Svikram if (stat(minor_path, &sb) < 0) {
1326d7b0e458Svikram if (is_devinfo_blk(minor_path)) {
1327d7b0e458Svikram break;
1328d7b0e458Svikram } else {
1329724365f7Ssethg continue;
1330d7b0e458Svikram }
1331d7b0e458Svikram }
1332724365f7Ssethg
1333724365f7Ssethg if (S_ISBLK(sb.st_mode))
1334724365f7Ssethg break;
1335d7b0e458Svikram
133666f9d5cbSmlf }
133766f9d5cbSmlf
1338724365f7Ssethg (void) closedir(dp);
1339724365f7Ssethg free(dep);
134066f9d5cbSmlf free(devpath);
134166f9d5cbSmlf
1342724365f7Ssethg dp = NULL;
1343724365f7Ssethg dep = NULL;
1344724365f7Ssethg devpath = NULL;
1345724365f7Ssethg
1346724365f7Ssethg /*
1347724365f7Ssethg * If there was an error, or we didn't exit the loop
1348724365f7Ssethg * by finding a block or character device, bail out.
1349724365f7Ssethg */
1350724365f7Ssethg if (err != 0 || newdep == NULL)
1351724365f7Ssethg goto bailout;
1352724365f7Ssethg
1353724365f7Ssethg /*
135438547057Sying tian - Beijing China * Look for links to the physical path in /dev/dsk
135538547057Sying tian - Beijing China * and /dev/rmt. So far, sata modue supports disk,
135638547057Sying tian - Beijing China * dvd and tape devices, so we will first look for
135738547057Sying tian - Beijing China * BLOCK devices, and then look for tape devices.
1358724365f7Ssethg */
1359724365f7Ssethg (void) physpath_to_devlink("/dev/dsk",
1360724365f7Ssethg minor_path, &devlink, &l_errno);
136166f9d5cbSmlf
136266f9d5cbSmlf /* postprocess and copy logical name here */
136366f9d5cbSmlf if (devlink != NULL) {
136466f9d5cbSmlf /*
1365545e5dadSsethg * For disks, remove partition/slice info
136666f9d5cbSmlf */
1367724365f7Ssethg if ((cp = strstr(devlink, "dsk/")) != NULL) {
1368545e5dadSsethg /* cXtYdZ[(s[0..15])|(p[0..X])] */
1369545e5dadSsethg if ((p = strchr(cp + 4, 'd')) != NULL) {
1370545e5dadSsethg p++; /* Skip the 'd' */
1371545e5dadSsethg while (*p != 0 && isdigit(*p))
1372545e5dadSsethg p++;
1373545e5dadSsethg *p = 0;
1374545e5dadSsethg }
137566f9d5cbSmlf *dyncomp = strdup(cp);
1376724365f7Ssethg }
1377724365f7Ssethg
137866f9d5cbSmlf free(devlink);
137938547057Sying tian - Beijing China } else if (strcmp(type, "tape") == 0) {
138038547057Sying tian - Beijing China
138138547057Sying tian - Beijing China /*
138238547057Sying tian - Beijing China * For tape device, logical name looks like
138338547057Sying tian - Beijing China * rmt/X
138438547057Sying tian - Beijing China */
138538547057Sying tian - Beijing China (void) physpath_to_devlink("/dev/rmt",
138638547057Sying tian - Beijing China minor_path, &devlink, &l_errno);
138738547057Sying tian - Beijing China
138838547057Sying tian - Beijing China if (devlink != NULL) {
138938547057Sying tian - Beijing China if ((cp = strstr(devlink, "rmt/")) != NULL) {
139038547057Sying tian - Beijing China *dyncomp = strdup(cp);
139138547057Sying tian - Beijing China }
139238547057Sying tian - Beijing China
139338547057Sying tian - Beijing China free(devlink);
139438547057Sying tian - Beijing China }
139566f9d5cbSmlf }
1396724365f7Ssethg
139766f9d5cbSmlf return (SATA_CFGA_OK);
139866f9d5cbSmlf }
1399724365f7Ssethg
140066f9d5cbSmlf bailout:
1401724365f7Ssethg if (dp)
1402724365f7Ssethg (void) closedir(dp);
1403724365f7Ssethg if (devpath)
140466f9d5cbSmlf free(devpath);
1405724365f7Ssethg if (dep)
1406724365f7Ssethg free(dep);
140766f9d5cbSmlf return (CFGA_SATA_DYNAMIC_AP);
140866f9d5cbSmlf }
140966f9d5cbSmlf
141066f9d5cbSmlf /* cfgadm entry point */
141166f9d5cbSmlf /*ARGSUSED*/
141266f9d5cbSmlf 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)141366f9d5cbSmlf cfga_list_ext(
141466f9d5cbSmlf const char *ap_id,
141566f9d5cbSmlf cfga_list_data_t **ap_id_list,
141666f9d5cbSmlf int *nlistp,
141766f9d5cbSmlf const char *options,
141866f9d5cbSmlf const char *listopts,
141966f9d5cbSmlf char **errstring,
142066f9d5cbSmlf cfga_flags_t flags)
142166f9d5cbSmlf {
142266f9d5cbSmlf int l_errno;
142366f9d5cbSmlf char *ap_id_log = NULL;
142466f9d5cbSmlf size_t size;
142566f9d5cbSmlf nvlist_t *user_nvlist = NULL;
142666f9d5cbSmlf devctl_hdl_t devctl_hdl = NULL;
142766f9d5cbSmlf cfga_sata_ret_t rv = CFGA_SATA_OK;
142866f9d5cbSmlf devctl_ap_state_t devctl_ap_state;
142966f9d5cbSmlf char *pdyn;
14308aa6aadbSXiao-Yu Zhang boolean_t pmult = B_FALSE;
14318aa6aadbSXiao-Yu Zhang uint32_t port;
143266f9d5cbSmlf
143366f9d5cbSmlf
143466f9d5cbSmlf if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) {
143566f9d5cbSmlf goto bailout;
143666f9d5cbSmlf }
143766f9d5cbSmlf /* We do not care here about dynamic AP name component */
143866f9d5cbSmlf if ((pdyn = GET_DYN(ap_id)) != NULL) {
143966f9d5cbSmlf *pdyn = '\0';
144066f9d5cbSmlf }
144166f9d5cbSmlf
144266f9d5cbSmlf if (ap_id_list == NULL || nlistp == NULL) {
144366f9d5cbSmlf rv = CFGA_SATA_DATA_ERROR;
144466f9d5cbSmlf goto bailout;
144566f9d5cbSmlf }
144666f9d5cbSmlf
144766f9d5cbSmlf /* Get ap status */
144866f9d5cbSmlf if ((rv = setup_for_devctl_cmd(ap_id, &devctl_hdl, &user_nvlist,
144966f9d5cbSmlf DC_RDONLY)) != CFGA_SATA_OK) {
145066f9d5cbSmlf goto bailout;
145166f9d5cbSmlf }
145266f9d5cbSmlf
145366f9d5cbSmlf /* will call dc_cmd to send IOCTL to kernel */
145466f9d5cbSmlf if (devctl_ap_getstate(devctl_hdl, user_nvlist,
145566f9d5cbSmlf &devctl_ap_state) == -1) {
145666f9d5cbSmlf cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
145766f9d5cbSmlf rv = CFGA_SATA_IOCTL;
145866f9d5cbSmlf goto bailout;
145966f9d5cbSmlf }
146066f9d5cbSmlf
146166f9d5cbSmlf cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
146266f9d5cbSmlf
146366f9d5cbSmlf /*
146466f9d5cbSmlf * Create cfga_list_data_t struct.
146566f9d5cbSmlf */
146666f9d5cbSmlf if ((*ap_id_list =
146766f9d5cbSmlf (cfga_list_data_t *)malloc(sizeof (**ap_id_list))) == NULL) {
146866f9d5cbSmlf rv = CFGA_SATA_ALLOC_FAIL;
146966f9d5cbSmlf goto bailout;
147066f9d5cbSmlf }
147166f9d5cbSmlf *nlistp = 1;
147266f9d5cbSmlf
147366f9d5cbSmlf /*
147466f9d5cbSmlf * Rest of the code fills in the cfga_list_data_t struct.
147566f9d5cbSmlf */
147666f9d5cbSmlf
147766f9d5cbSmlf /* Get /dev/cfg path to corresponding to the physical ap_id */
147866f9d5cbSmlf /* Remember ap_id_log must be freed */
1479724365f7Ssethg rv = physpath_to_devlink(CFGA_DEV_DIR, (char *)ap_id,
1480724365f7Ssethg &ap_id_log, &l_errno);
148166f9d5cbSmlf
148266f9d5cbSmlf if (rv != 0) {
148366f9d5cbSmlf rv = CFGA_SATA_DEVLINK;
148466f9d5cbSmlf goto bailout;
148566f9d5cbSmlf }
148666f9d5cbSmlf
148766f9d5cbSmlf /* Get logical ap_id corresponding to the physical */
148820e7b521Ssethg if (ap_id_log == NULL || strstr(ap_id_log, CFGA_DEV_DIR) == NULL) {
148966f9d5cbSmlf rv = CFGA_SATA_DEVLINK;
149066f9d5cbSmlf goto bailout;
149166f9d5cbSmlf }
149266f9d5cbSmlf
149366f9d5cbSmlf (void) strlcpy((*ap_id_list)->ap_log_id,
149466f9d5cbSmlf /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR)+ 1,
149566f9d5cbSmlf sizeof ((*ap_id_list)->ap_log_id));
149666f9d5cbSmlf
149766f9d5cbSmlf free(ap_id_log);
149866f9d5cbSmlf ap_id_log = NULL;
149966f9d5cbSmlf
150066f9d5cbSmlf (void) strlcpy((*ap_id_list)->ap_phys_id, ap_id,
150166f9d5cbSmlf sizeof ((*ap_id_list)->ap_phys_id));
150266f9d5cbSmlf
150366f9d5cbSmlf switch (devctl_ap_state.ap_rstate) {
150466f9d5cbSmlf case AP_RSTATE_EMPTY:
150566f9d5cbSmlf (*ap_id_list)->ap_r_state = CFGA_STAT_EMPTY;
150666f9d5cbSmlf break;
150766f9d5cbSmlf
150866f9d5cbSmlf case AP_RSTATE_DISCONNECTED:
150966f9d5cbSmlf (*ap_id_list)->ap_r_state = CFGA_STAT_DISCONNECTED;
151066f9d5cbSmlf break;
151166f9d5cbSmlf
151266f9d5cbSmlf case AP_RSTATE_CONNECTED:
151366f9d5cbSmlf (*ap_id_list)->ap_r_state = CFGA_STAT_CONNECTED;
151466f9d5cbSmlf break;
151566f9d5cbSmlf
151666f9d5cbSmlf default:
151766f9d5cbSmlf rv = CFGA_SATA_STATE;
151866f9d5cbSmlf goto bailout;
151966f9d5cbSmlf }
152066f9d5cbSmlf
152166f9d5cbSmlf switch (devctl_ap_state.ap_ostate) {
152266f9d5cbSmlf case AP_OSTATE_CONFIGURED:
152366f9d5cbSmlf (*ap_id_list)->ap_o_state = CFGA_STAT_CONFIGURED;
152466f9d5cbSmlf break;
152566f9d5cbSmlf
152666f9d5cbSmlf case AP_OSTATE_UNCONFIGURED:
152766f9d5cbSmlf (*ap_id_list)->ap_o_state = CFGA_STAT_UNCONFIGURED;
152866f9d5cbSmlf break;
152966f9d5cbSmlf
153066f9d5cbSmlf default:
153166f9d5cbSmlf rv = CFGA_SATA_STATE;
153266f9d5cbSmlf goto bailout;
153366f9d5cbSmlf }
153466f9d5cbSmlf
153566f9d5cbSmlf switch (devctl_ap_state.ap_condition) {
153666f9d5cbSmlf case AP_COND_OK:
153766f9d5cbSmlf (*ap_id_list)->ap_cond = CFGA_COND_OK;
153866f9d5cbSmlf break;
153966f9d5cbSmlf
154066f9d5cbSmlf case AP_COND_FAILING:
154166f9d5cbSmlf (*ap_id_list)->ap_cond = CFGA_COND_FAILING;
154266f9d5cbSmlf break;
154366f9d5cbSmlf
154466f9d5cbSmlf case AP_COND_FAILED:
154566f9d5cbSmlf (*ap_id_list)->ap_cond = CFGA_COND_FAILED;
154666f9d5cbSmlf break;
154766f9d5cbSmlf
154866f9d5cbSmlf case AP_COND_UNUSABLE:
154966f9d5cbSmlf (*ap_id_list)->ap_cond = CFGA_COND_UNUSABLE;
155066f9d5cbSmlf break;
155166f9d5cbSmlf
155266f9d5cbSmlf case AP_COND_UNKNOWN:
155366f9d5cbSmlf (*ap_id_list)->ap_cond = CFGA_COND_UNKNOWN;
155466f9d5cbSmlf break;
155566f9d5cbSmlf
155666f9d5cbSmlf default:
155766f9d5cbSmlf rv = CFGA_SATA_STATE;
155866f9d5cbSmlf goto bailout;
155966f9d5cbSmlf }
156066f9d5cbSmlf
156166f9d5cbSmlf (*ap_id_list)->ap_class[0] = '\0'; /* Filled by libcfgadm */
156266f9d5cbSmlf (*ap_id_list)->ap_busy = devctl_ap_state.ap_in_transition;
156366f9d5cbSmlf (*ap_id_list)->ap_status_time = devctl_ap_state.ap_last_change;
156421f023dfSToomas Soome (*ap_id_list)->ap_info[0] = '\0';
156566f9d5cbSmlf
156666f9d5cbSmlf if ((*ap_id_list)->ap_r_state == CFGA_STAT_CONNECTED) {
156766f9d5cbSmlf char *str_p;
156866f9d5cbSmlf int skip, i;
156966f9d5cbSmlf
157066f9d5cbSmlf /*
157166f9d5cbSmlf * Fill in the 'Information' field for the -v option
157266f9d5cbSmlf * Model (MOD:)
157366f9d5cbSmlf */
157466f9d5cbSmlf if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_MODEL_INFO,
157521f023dfSToomas Soome 0, (void **)&str_p, &size)) != CFGA_SATA_OK) {
157666f9d5cbSmlf (void) printf(
157766f9d5cbSmlf "SATA_CFGA_GET_MODULE_INFO ioctl failed\n");
157866f9d5cbSmlf goto bailout;
157966f9d5cbSmlf }
158066f9d5cbSmlf /* drop leading and trailing spaces */
158166f9d5cbSmlf skip = strspn(str_p, " ");
158266f9d5cbSmlf for (i = size - 1; i >= 0; i--) {
158366f9d5cbSmlf if (str_p[i] == '\040')
158466f9d5cbSmlf str_p[i] = '\0';
158566f9d5cbSmlf else if (str_p[i] != '\0')
158666f9d5cbSmlf break;
158766f9d5cbSmlf }
158866f9d5cbSmlf
158966f9d5cbSmlf (void) strlcpy((*ap_id_list)->ap_info, "Mod: ",
159066f9d5cbSmlf sizeof ((*ap_id_list)->ap_info));
159166f9d5cbSmlf (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
159266f9d5cbSmlf sizeof ((*ap_id_list)->ap_info));
159366f9d5cbSmlf
159466f9d5cbSmlf free(str_p);
159566f9d5cbSmlf
159666f9d5cbSmlf /*
159766f9d5cbSmlf * Fill in the 'Information' field for the -v option
159866f9d5cbSmlf * Firmware revision (FREV:)
159966f9d5cbSmlf */
160066f9d5cbSmlf if ((rv = do_control_ioctl(ap_id,
160166f9d5cbSmlf SATA_CFGA_GET_REVFIRMWARE_INFO,
160221f023dfSToomas Soome 0, (void **)&str_p, &size)) != CFGA_SATA_OK) {
160366f9d5cbSmlf (void) printf(
160466f9d5cbSmlf "SATA_CFGA_GET_REVFIRMWARE_INFO ioctl failed\n");
160566f9d5cbSmlf goto bailout;
160666f9d5cbSmlf }
160766f9d5cbSmlf /* drop leading and trailing spaces */
160866f9d5cbSmlf skip = strspn(str_p, " ");
160966f9d5cbSmlf for (i = size - 1; i >= 0; i--) {
161066f9d5cbSmlf if (str_p[i] == '\040')
161166f9d5cbSmlf str_p[i] = '\0';
161266f9d5cbSmlf else if (str_p[i] != '\0')
161366f9d5cbSmlf break;
161466f9d5cbSmlf }
161566f9d5cbSmlf (void) strlcat((*ap_id_list)->ap_info, " FRev: ",
161666f9d5cbSmlf sizeof ((*ap_id_list)->ap_info));
161766f9d5cbSmlf (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
161866f9d5cbSmlf sizeof ((*ap_id_list)->ap_info));
161966f9d5cbSmlf
162066f9d5cbSmlf free(str_p);
162166f9d5cbSmlf
162266f9d5cbSmlf
162366f9d5cbSmlf /*
162466f9d5cbSmlf * Fill in the 'Information' field for the -v option
162566f9d5cbSmlf * Serial Number (SN:)
162666f9d5cbSmlf */
162766f9d5cbSmlf if ((rv = do_control_ioctl(ap_id,
162866f9d5cbSmlf SATA_CFGA_GET_SERIALNUMBER_INFO,
162921f023dfSToomas Soome 0, (void **)&str_p, &size)) != CFGA_SATA_OK) {
163066f9d5cbSmlf (void) printf(
163166f9d5cbSmlf "SATA_CFGA_GET_SERIALNUMBER_INFO ioctl failed\n");
163266f9d5cbSmlf goto bailout;
163366f9d5cbSmlf }
163466f9d5cbSmlf /* drop leading and trailing spaces */
163566f9d5cbSmlf skip = strspn(str_p, " ");
163666f9d5cbSmlf for (i = size - 1; i >= 0; i--) {
163766f9d5cbSmlf if (str_p[i] == '\040')
163866f9d5cbSmlf str_p[i] = '\0';
163966f9d5cbSmlf else if (str_p[i] != '\0')
164066f9d5cbSmlf break;
164166f9d5cbSmlf }
164266f9d5cbSmlf (void) strlcat((*ap_id_list)->ap_info, " SN: ",
164366f9d5cbSmlf sizeof ((*ap_id_list)->ap_info));
164466f9d5cbSmlf (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
164566f9d5cbSmlf sizeof ((*ap_id_list)->ap_info));
164666f9d5cbSmlf
164766f9d5cbSmlf free(str_p);
164866f9d5cbSmlf
164966f9d5cbSmlf
165066f9d5cbSmlf
165166f9d5cbSmlf /* Fill in ap_type which is collected from HBA driver */
165266f9d5cbSmlf /* call do_control_ioctl TBD */
165321f023dfSToomas Soome if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, 0,
165466f9d5cbSmlf (void **)&str_p, &size)) != CFGA_SATA_OK) {
165566f9d5cbSmlf (void) printf(
165666f9d5cbSmlf "SATA_CFGA_GET_AP_TYPE ioctl failed\n");
165766f9d5cbSmlf goto bailout;
165866f9d5cbSmlf }
165966f9d5cbSmlf
166066f9d5cbSmlf (void) strlcpy((*ap_id_list)->ap_type, str_p,
166166f9d5cbSmlf sizeof ((*ap_id_list)->ap_type));
166266f9d5cbSmlf
166366f9d5cbSmlf free(str_p);
166466f9d5cbSmlf
16658aa6aadbSXiao-Yu Zhang /*
16668aa6aadbSXiao-Yu Zhang * Checking device type. Port multiplier has no dynamic
16678aa6aadbSXiao-Yu Zhang * suffix.
16688aa6aadbSXiao-Yu Zhang */
16698aa6aadbSXiao-Yu Zhang if (strncmp((*ap_id_list)->ap_type, "sata-pmult",
16708aa6aadbSXiao-Yu Zhang sizeof ("sata-pmult")) == 0)
16718aa6aadbSXiao-Yu Zhang pmult = B_TRUE;
16728aa6aadbSXiao-Yu Zhang
16738aa6aadbSXiao-Yu Zhang if ((*ap_id_list)->ap_o_state == CFGA_STAT_CONFIGURED &&
16748aa6aadbSXiao-Yu Zhang pmult == B_FALSE) {
167566f9d5cbSmlf
167666f9d5cbSmlf char *dyncomp = NULL;
167766f9d5cbSmlf
167866f9d5cbSmlf /*
167966f9d5cbSmlf * This is the case where we need to generate
168066f9d5cbSmlf * a dynamic component of the ap_id, i.e. device.
168166f9d5cbSmlf */
168238547057Sying tian - Beijing China rv = sata_make_dyncomp(ap_id, &dyncomp,
168338547057Sying tian - Beijing China (*ap_id_list)->ap_type);
168466f9d5cbSmlf if (rv != CFGA_SATA_OK)
168566f9d5cbSmlf goto bailout;
168666f9d5cbSmlf if (dyncomp != NULL) {
168766f9d5cbSmlf (void) strcat((*ap_id_list)->ap_log_id,
168866f9d5cbSmlf DYN_SEP);
168966f9d5cbSmlf (void) strlcat((*ap_id_list)->ap_log_id,
169066f9d5cbSmlf dyncomp,
169166f9d5cbSmlf sizeof ((*ap_id_list)->ap_log_id));
169266f9d5cbSmlf free(dyncomp);
169366f9d5cbSmlf }
169466f9d5cbSmlf }
169566f9d5cbSmlf
169666f9d5cbSmlf } else {
16978aa6aadbSXiao-Yu Zhang /* This is an empty port */
16982c2d21e9SRichard Lowe if (get_port_num(ap_id, &port) != CFGA_SATA_OK) {
16998aa6aadbSXiao-Yu Zhang goto bailout;
17008aa6aadbSXiao-Yu Zhang }
17018aa6aadbSXiao-Yu Zhang
17028aa6aadbSXiao-Yu Zhang if (port & SATA_CFGA_PMPORT_QUAL) {
17038aa6aadbSXiao-Yu Zhang (void) strlcpy((*ap_id_list)->ap_type, "pmult-port",
17048aa6aadbSXiao-Yu Zhang sizeof ((*ap_id_list)->ap_type));
17058aa6aadbSXiao-Yu Zhang } else {
170666f9d5cbSmlf (void) strlcpy((*ap_id_list)->ap_type, "sata-port",
170766f9d5cbSmlf sizeof ((*ap_id_list)->ap_type));
170866f9d5cbSmlf }
17098aa6aadbSXiao-Yu Zhang }
171066f9d5cbSmlf
171166f9d5cbSmlf return (sata_err_msg(errstring, rv, ap_id, errno));
171266f9d5cbSmlf
171366f9d5cbSmlf bailout:
171466f9d5cbSmlf if (*ap_id_list != NULL) {
171566f9d5cbSmlf free(*ap_id_list);
171666f9d5cbSmlf }
171766f9d5cbSmlf if (ap_id_log != NULL) {
171866f9d5cbSmlf free(ap_id_log);
171966f9d5cbSmlf }
172066f9d5cbSmlf
172166f9d5cbSmlf return (sata_err_msg(errstring, rv, ap_id, errno));
172266f9d5cbSmlf }
172366f9d5cbSmlf /*
172466f9d5cbSmlf * This routine accepts a string adn prints it using
172566f9d5cbSmlf * the message print routine argument.
172666f9d5cbSmlf */
172766f9d5cbSmlf static void
cfga_msg(struct cfga_msg * msgp,const char * str)172866f9d5cbSmlf cfga_msg(struct cfga_msg *msgp, const char *str)
172966f9d5cbSmlf {
173066f9d5cbSmlf int len;
173166f9d5cbSmlf char *q;
173266f9d5cbSmlf
173366f9d5cbSmlf if (msgp == NULL || msgp->message_routine == NULL) {
173466f9d5cbSmlf (void) printf("cfga_msg: NULL msgp\n");
173566f9d5cbSmlf return;
173666f9d5cbSmlf }
173766f9d5cbSmlf
173866f9d5cbSmlf if ((len = strlen(str)) == 0) {
173966f9d5cbSmlf (void) printf("cfga_msg: null str\n");
174066f9d5cbSmlf return;
174166f9d5cbSmlf }
174266f9d5cbSmlf
174366f9d5cbSmlf if ((q = (char *)calloc(len + 1, 1)) == NULL) {
17448aa6aadbSXiao-Yu Zhang perror("cfga_msg");
174566f9d5cbSmlf return;
174666f9d5cbSmlf }
174766f9d5cbSmlf
174866f9d5cbSmlf (void) strcpy(q, str);
174961233e71SJohn Levon (void) (*msgp->message_routine)(msgp->appdata_ptr, q);
175066f9d5cbSmlf
175166f9d5cbSmlf free(q);
175266f9d5cbSmlf }
175366f9d5cbSmlf
175466f9d5cbSmlf /* cfgadm entry point */
175566f9d5cbSmlf /* ARGSUSED */
175666f9d5cbSmlf cfga_err_t
cfga_help(struct cfga_msg * msgp,const char * options,cfga_flags_t flags)175766f9d5cbSmlf cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
175866f9d5cbSmlf {
175966f9d5cbSmlf if (options != NULL) {
176066f9d5cbSmlf cfga_msg(msgp, dgettext(TEXT_DOMAIN, sata_help[HELP_UNKNOWN]));
176166f9d5cbSmlf cfga_msg(msgp, options);
176266f9d5cbSmlf }
176366f9d5cbSmlf cfga_msg(msgp, dgettext(TEXT_DOMAIN, sata_help[HELP_HEADER]));
176466f9d5cbSmlf cfga_msg(msgp, sata_help[HELP_CONFIG]);
176566f9d5cbSmlf cfga_msg(msgp, sata_help[HELP_RESET_PORT]);
176666f9d5cbSmlf cfga_msg(msgp, sata_help[HELP_RESET_DEVICE]);
176766f9d5cbSmlf cfga_msg(msgp, sata_help[HELP_RESET_ALL]);
176866f9d5cbSmlf cfga_msg(msgp, sata_help[HELP_PORT_ACTIVATE]);
176966f9d5cbSmlf cfga_msg(msgp, sata_help[HELP_PORT_DEACTIVATE]);
177066f9d5cbSmlf cfga_msg(msgp, sata_help[HELP_PORT_SELF_TEST]);
177166f9d5cbSmlf cfga_msg(msgp, sata_help[HELP_CNTRL_SELF_TEST]);
177266f9d5cbSmlf
177366f9d5cbSmlf return (CFGA_OK);
177466f9d5cbSmlf }
177566f9d5cbSmlf
177666f9d5cbSmlf
177766f9d5cbSmlf /*
177866f9d5cbSmlf * Ensure the ap_id passed is in the correct (physical ap_id) form:
177966f9d5cbSmlf * path/device:xx[.xx]
178066f9d5cbSmlf * where xx is a one or two-digit number.
178166f9d5cbSmlf *
178266f9d5cbSmlf * Note the library always calls the plugin with a physical ap_id.
178366f9d5cbSmlf */
178466f9d5cbSmlf static int
verify_valid_apid(const char * ap_id)178566f9d5cbSmlf verify_valid_apid(const char *ap_id)
178666f9d5cbSmlf {
178766f9d5cbSmlf char *l_ap_id;
178866f9d5cbSmlf
178966f9d5cbSmlf if (ap_id == NULL)
179066f9d5cbSmlf return (-1);
179166f9d5cbSmlf
179266f9d5cbSmlf l_ap_id = strrchr(ap_id, (int)*MINOR_SEP);
179366f9d5cbSmlf l_ap_id++;
179466f9d5cbSmlf
179566f9d5cbSmlf if (strspn(l_ap_id, "0123456789.") != strlen(l_ap_id)) {
179666f9d5cbSmlf /* Bad characters in the ap_id */
179766f9d5cbSmlf return (-1);
179866f9d5cbSmlf }
179966f9d5cbSmlf
180066f9d5cbSmlf if (strstr(l_ap_id, "..") != NULL) {
180166f9d5cbSmlf /* ap_id has 1..2 or more than 2 dots */
180266f9d5cbSmlf return (-1);
180366f9d5cbSmlf }
180466f9d5cbSmlf
180566f9d5cbSmlf return (0);
180666f9d5cbSmlf }
180766f9d5cbSmlf
180866f9d5cbSmlf
180966f9d5cbSmlf
181066f9d5cbSmlf /*
181166f9d5cbSmlf * Verify the params passed in are valid.
181266f9d5cbSmlf */
181366f9d5cbSmlf static cfga_sata_ret_t
verify_params(const char * ap_id,const char * options,char ** errstring)181466f9d5cbSmlf verify_params(
181566f9d5cbSmlf const char *ap_id,
181666f9d5cbSmlf const char *options,
181766f9d5cbSmlf char **errstring)
181866f9d5cbSmlf {
181966f9d5cbSmlf char *pdyn, *lap_id;
182066f9d5cbSmlf int rv;
182166f9d5cbSmlf
182266f9d5cbSmlf if (errstring != NULL) {
182366f9d5cbSmlf *errstring = NULL;
182466f9d5cbSmlf }
182566f9d5cbSmlf
182666f9d5cbSmlf if (options != NULL) {
182766f9d5cbSmlf return (CFGA_SATA_OPTIONS);
182866f9d5cbSmlf }
182966f9d5cbSmlf
183066f9d5cbSmlf /* Strip dynamic AP name component if it is present. */
183166f9d5cbSmlf lap_id = strdup(ap_id);
183266f9d5cbSmlf if (lap_id == NULL) {
183366f9d5cbSmlf return (CFGA_SATA_ALLOC_FAIL);
183466f9d5cbSmlf }
183566f9d5cbSmlf if ((pdyn = GET_DYN(lap_id)) != NULL) {
183666f9d5cbSmlf *pdyn = '\0';
183766f9d5cbSmlf }
183866f9d5cbSmlf
183966f9d5cbSmlf if (verify_valid_apid(lap_id) != 0) {
184066f9d5cbSmlf rv = CFGA_SATA_AP;
184166f9d5cbSmlf } else {
184266f9d5cbSmlf rv = CFGA_SATA_OK;
184366f9d5cbSmlf }
184466f9d5cbSmlf free(lap_id);
184566f9d5cbSmlf
184666f9d5cbSmlf return (rv);
184766f9d5cbSmlf }
184866f9d5cbSmlf
184966f9d5cbSmlf /*
185066f9d5cbSmlf * Takes a validated ap_id and extracts the port number.
18518aa6aadbSXiao-Yu Zhang * Port multiplier is supported now.
185266f9d5cbSmlf */
185366f9d5cbSmlf static cfga_sata_ret_t
get_port_num(const char * ap_id,uint32_t * port)185466f9d5cbSmlf get_port_num(const char *ap_id, uint32_t *port)
185566f9d5cbSmlf {
18568aa6aadbSXiao-Yu Zhang uint32_t cport, pmport = 0, qual = 0;
18578aa6aadbSXiao-Yu Zhang char *cport_str, *pmport_str;
185866f9d5cbSmlf
18598aa6aadbSXiao-Yu Zhang /* Get the cport number */
18608aa6aadbSXiao-Yu Zhang cport_str = strrchr(ap_id, (int)*MINOR_SEP) + strlen(MINOR_SEP);
186166f9d5cbSmlf
186266f9d5cbSmlf errno = 0;
18638aa6aadbSXiao-Yu Zhang cport = strtol(cport_str, NULL, 10);
18648aa6aadbSXiao-Yu Zhang if ((cport & ~SATA_CFGA_CPORT_MASK) != 0 || errno != 0) {
186566f9d5cbSmlf return (CFGA_SATA_PORT);
18668aa6aadbSXiao-Yu Zhang }
186766f9d5cbSmlf
18688aa6aadbSXiao-Yu Zhang /* Get pmport number if there is a PORT_SEPARATOR */
18698aa6aadbSXiao-Yu Zhang errno = 0;
18708aa6aadbSXiao-Yu Zhang if ((pmport_str = strrchr(ap_id, (int)*PORT_SEPARATOR)) != 0) {
18718aa6aadbSXiao-Yu Zhang pmport_str += strlen(PORT_SEPARATOR);
18728aa6aadbSXiao-Yu Zhang pmport = strtol(pmport_str, NULL, 10);
18738aa6aadbSXiao-Yu Zhang qual = SATA_CFGA_PMPORT_QUAL;
18748aa6aadbSXiao-Yu Zhang if ((pmport & ~SATA_CFGA_PMPORT_MASK) != 0 || errno != 0) {
18758aa6aadbSXiao-Yu Zhang return (CFGA_SATA_PORT);
18768aa6aadbSXiao-Yu Zhang }
18778aa6aadbSXiao-Yu Zhang }
187866f9d5cbSmlf
18798aa6aadbSXiao-Yu Zhang *port = cport | (pmport << SATA_CFGA_PMPORT_SHIFT) | qual;
188066f9d5cbSmlf return (CFGA_SATA_OK);
188166f9d5cbSmlf }
188266f9d5cbSmlf
188366f9d5cbSmlf /*
188466f9d5cbSmlf * Pair of routines to set up for/clean up after a devctl_ap_* lib call.
188566f9d5cbSmlf */
188666f9d5cbSmlf static void
cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl,nvlist_t * user_nvlist)188766f9d5cbSmlf cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist)
188866f9d5cbSmlf {
188966f9d5cbSmlf if (user_nvlist != NULL) {
189066f9d5cbSmlf nvlist_free(user_nvlist);
189166f9d5cbSmlf }
189266f9d5cbSmlf if (devctl_hdl != NULL) {
189366f9d5cbSmlf devctl_release(devctl_hdl);
189466f9d5cbSmlf }
189566f9d5cbSmlf }
189666f9d5cbSmlf
189766f9d5cbSmlf 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)189866f9d5cbSmlf setup_for_devctl_cmd(
189966f9d5cbSmlf const char *ap_id,
190066f9d5cbSmlf devctl_hdl_t *devctl_hdl,
190166f9d5cbSmlf nvlist_t **user_nvlistp,
190266f9d5cbSmlf uint_t oflag)
190366f9d5cbSmlf {
190466f9d5cbSmlf
190566f9d5cbSmlf uint_t port;
190666f9d5cbSmlf cfga_sata_ret_t rv = CFGA_SATA_OK;
190766f9d5cbSmlf char *lap_id, *pdyn;
190866f9d5cbSmlf
190966f9d5cbSmlf lap_id = strdup(ap_id);
191066f9d5cbSmlf if (lap_id == NULL)
191166f9d5cbSmlf return (CFGA_SATA_ALLOC_FAIL);
191266f9d5cbSmlf if ((pdyn = GET_DYN(lap_id)) != NULL) {
191366f9d5cbSmlf *pdyn = '\0';
191466f9d5cbSmlf }
191566f9d5cbSmlf
191666f9d5cbSmlf /* Get a devctl handle to pass to the devctl_ap_XXX functions */
191766f9d5cbSmlf if ((*devctl_hdl = devctl_ap_acquire((char *)lap_id, oflag)) == NULL) {
1918724365f7Ssethg (void) fprintf(stderr, "[libcfgadm:sata] "
1919724365f7Ssethg "setup_for_devctl_cmd: devctl_ap_acquire failed: %s\n",
1920724365f7Ssethg strerror(errno));
192166f9d5cbSmlf rv = CFGA_SATA_DEVCTL;
192266f9d5cbSmlf goto bailout;
192366f9d5cbSmlf }
192466f9d5cbSmlf
192566f9d5cbSmlf /* Set up nvlist to pass the port number down to the driver */
192621f023dfSToomas Soome if (nvlist_alloc(user_nvlistp, NV_UNIQUE_NAME_TYPE, 0) != 0) {
192766f9d5cbSmlf *user_nvlistp = NULL;
192866f9d5cbSmlf rv = CFGA_SATA_NVLIST;
192966f9d5cbSmlf (void) printf("nvlist_alloc failed\n");
193066f9d5cbSmlf goto bailout;
193166f9d5cbSmlf }
193266f9d5cbSmlf
193366f9d5cbSmlf /*
193466f9d5cbSmlf * Get port id, for Port Multiplier port, things could be a little bit
193566f9d5cbSmlf * complicated because of "port.port" format in ap_id, thus for
193666f9d5cbSmlf * port multiplier port, port number should be coded as 32bit int
193766f9d5cbSmlf * with the sig 16 bit as sata channel number, least 16 bit as
193866f9d5cbSmlf * the port number of sata port multiplier port.
193966f9d5cbSmlf */
194066f9d5cbSmlf if ((rv = get_port_num(lap_id, &port)) != CFGA_SATA_OK) {
194166f9d5cbSmlf (void) printf(
194266f9d5cbSmlf "setup_for_devctl_cmd: get_port_num, errno: %d\n",
194366f9d5cbSmlf errno);
194466f9d5cbSmlf goto bailout;
194566f9d5cbSmlf }
194666f9d5cbSmlf
194766f9d5cbSmlf /* Creates an int32_t entry */
194866f9d5cbSmlf if (nvlist_add_int32(*user_nvlistp, PORT, port) == -1) {
194966f9d5cbSmlf (void) printf("nvlist_add_int32 failed\n");
195066f9d5cbSmlf rv = CFGA_SATA_NVLIST;
195166f9d5cbSmlf goto bailout;
195266f9d5cbSmlf }
195366f9d5cbSmlf
1954724365f7Ssethg free(lap_id);
195566f9d5cbSmlf return (rv);
195666f9d5cbSmlf
195766f9d5cbSmlf bailout:
195866f9d5cbSmlf free(lap_id);
195966f9d5cbSmlf (void) cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
196066f9d5cbSmlf
196166f9d5cbSmlf return (rv);
196266f9d5cbSmlf }
196366f9d5cbSmlf
196466f9d5cbSmlf
196566f9d5cbSmlf static cfga_sata_ret_t
port_state(devctl_hdl_t hdl,nvlist_t * list,ap_rstate_t * rstate,ap_ostate_t * ostate)196666f9d5cbSmlf port_state(devctl_hdl_t hdl, nvlist_t *list,
196766f9d5cbSmlf ap_rstate_t *rstate, ap_ostate_t *ostate)
196866f9d5cbSmlf {
196966f9d5cbSmlf devctl_ap_state_t devctl_ap_state;
197066f9d5cbSmlf
197166f9d5cbSmlf if (devctl_ap_getstate(hdl, list, &devctl_ap_state) == -1) {
197266f9d5cbSmlf (void) printf("devctl_ap_getstate failed, errno: %d\n", errno);
197366f9d5cbSmlf return (CFGA_SATA_IOCTL);
197466f9d5cbSmlf }
197566f9d5cbSmlf *rstate = devctl_ap_state.ap_rstate;
197666f9d5cbSmlf *ostate = devctl_ap_state.ap_ostate;
197766f9d5cbSmlf return (CFGA_SATA_OK);
197866f9d5cbSmlf }
197966f9d5cbSmlf
198066f9d5cbSmlf
198166f9d5cbSmlf /*
198266f9d5cbSmlf * Given a subcommand to the DEVCTL_AP_CONTROL ioctl, rquest the size of
198366f9d5cbSmlf * the data to be returned, allocate a buffer, then get the data.
198466f9d5cbSmlf * Returns *descrp (which must be freed) and size.
198566f9d5cbSmlf *
198666f9d5cbSmlf * Note SATA_DESCR_TYPE_STRING returns an ASCII NULL-terminated string,
198766f9d5cbSmlf * not a string descr.
198866f9d5cbSmlf */
198966f9d5cbSmlf cfga_sata_ret_t
do_control_ioctl(const char * ap_id,sata_cfga_apctl_t subcommand,uint_t arg,void ** descrp,size_t * sizep)199066f9d5cbSmlf do_control_ioctl(const char *ap_id, sata_cfga_apctl_t subcommand, uint_t arg,
199166f9d5cbSmlf void **descrp, size_t *sizep)
199266f9d5cbSmlf {
199366f9d5cbSmlf int fd = -1;
199466f9d5cbSmlf uint_t port;
199566f9d5cbSmlf uint32_t local_size;
199666f9d5cbSmlf cfga_sata_ret_t rv = CFGA_SATA_OK;
199766f9d5cbSmlf struct sata_ioctl_data ioctl_data;
199866f9d5cbSmlf
199966f9d5cbSmlf assert(descrp != NULL);
200066f9d5cbSmlf *descrp = NULL;
200166f9d5cbSmlf assert(sizep != NULL);
200266f9d5cbSmlf
200366f9d5cbSmlf if ((rv = get_port_num(ap_id, &port)) != CFGA_SATA_OK) {
200466f9d5cbSmlf goto bailout;
200566f9d5cbSmlf }
200666f9d5cbSmlf
200766f9d5cbSmlf if ((fd = open(ap_id, O_RDONLY)) == -1) {
200866f9d5cbSmlf (void) printf("do_control_ioctl: open failed: errno:%d\n",
200966f9d5cbSmlf errno);
201066f9d5cbSmlf rv = CFGA_SATA_OPEN;
201166f9d5cbSmlf if (errno == EBUSY) {
201266f9d5cbSmlf rv = CFGA_SATA_BUSY;
201366f9d5cbSmlf }
201466f9d5cbSmlf goto bailout;
201566f9d5cbSmlf }
201666f9d5cbSmlf
201766f9d5cbSmlf ioctl_data.cmd = subcommand;
201866f9d5cbSmlf ioctl_data.port = port;
201966f9d5cbSmlf ioctl_data.misc_arg = (uint_t)arg;
202066f9d5cbSmlf
202166f9d5cbSmlf /*
202266f9d5cbSmlf * Find out how large a buf we need to get the data.
202366f9d5cbSmlf * Note the ioctls only accept/return a 32-bit int for a get_size
202466f9d5cbSmlf * to avoid 32/64 and BE/LE issues.
202566f9d5cbSmlf */
202666f9d5cbSmlf if ((subcommand == SATA_CFGA_GET_AP_TYPE) ||
202766f9d5cbSmlf (subcommand == SATA_CFGA_GET_DEVICE_PATH) ||
202866f9d5cbSmlf (subcommand == SATA_CFGA_GET_MODEL_INFO) ||
202966f9d5cbSmlf (subcommand == SATA_CFGA_GET_REVFIRMWARE_INFO) ||
203066f9d5cbSmlf (subcommand == SATA_CFGA_GET_SERIALNUMBER_INFO)) {
203166f9d5cbSmlf ioctl_data.get_size = B_TRUE;
203266f9d5cbSmlf ioctl_data.buf = (caddr_t)&local_size;
203366f9d5cbSmlf ioctl_data.bufsiz = sizeof (local_size);
203466f9d5cbSmlf
203566f9d5cbSmlf if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
203666f9d5cbSmlf perror("ioctl failed (size)");
203766f9d5cbSmlf rv = CFGA_SATA_IOCTL;
203866f9d5cbSmlf goto bailout;
203966f9d5cbSmlf }
204066f9d5cbSmlf *sizep = local_size;
204166f9d5cbSmlf
204266f9d5cbSmlf if (local_size == 0) {
204366f9d5cbSmlf (void) printf("zero length data\n");
204466f9d5cbSmlf rv = CFGA_SATA_ZEROLEN;
204566f9d5cbSmlf goto bailout;
204666f9d5cbSmlf }
204766f9d5cbSmlf if ((*descrp = malloc(*sizep)) == NULL) {
204866f9d5cbSmlf (void) printf("do_control_ioctl: malloc failed\n");
204966f9d5cbSmlf rv = CFGA_SATA_ALLOC_FAIL;
205066f9d5cbSmlf goto bailout;
205166f9d5cbSmlf }
205266f9d5cbSmlf } else {
205366f9d5cbSmlf *sizep = 0;
205466f9d5cbSmlf }
205566f9d5cbSmlf ioctl_data.get_size = B_FALSE;
205666f9d5cbSmlf ioctl_data.buf = *descrp;
205766f9d5cbSmlf ioctl_data.bufsiz = *sizep;
205866f9d5cbSmlf
205966f9d5cbSmlf /* Execute IOCTL */
206066f9d5cbSmlf
206166f9d5cbSmlf if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
206266f9d5cbSmlf rv = CFGA_SATA_IOCTL;
206366f9d5cbSmlf goto bailout;
206466f9d5cbSmlf }
206566f9d5cbSmlf
206666f9d5cbSmlf (void) close(fd);
206766f9d5cbSmlf
206866f9d5cbSmlf return (rv);
206966f9d5cbSmlf
207066f9d5cbSmlf bailout:
207166f9d5cbSmlf if (fd != -1) {
207266f9d5cbSmlf (void) close(fd);
207366f9d5cbSmlf }
207466f9d5cbSmlf if (*descrp != NULL) {
207566f9d5cbSmlf free(*descrp);
207666f9d5cbSmlf *descrp = NULL;
207766f9d5cbSmlf }
207866f9d5cbSmlf
207966f9d5cbSmlf if (rv == CFGA_SATA_IOCTL && errno == EBUSY) {
208066f9d5cbSmlf rv = CFGA_SATA_BUSY;
208166f9d5cbSmlf }
208266f9d5cbSmlf
208366f9d5cbSmlf return (rv);
208466f9d5cbSmlf }
208566f9d5cbSmlf
208666f9d5cbSmlf
208766f9d5cbSmlf static int
sata_confirm(struct cfga_confirm * confp,char * msg)208866f9d5cbSmlf sata_confirm(struct cfga_confirm *confp, char *msg)
208966f9d5cbSmlf {
209066f9d5cbSmlf int rval;
209166f9d5cbSmlf
209266f9d5cbSmlf if (confp == NULL || confp->confirm == NULL) {
209366f9d5cbSmlf return (0);
209466f9d5cbSmlf }
209566f9d5cbSmlf rval = (*confp->confirm)(confp->appdata_ptr, msg);
209666f9d5cbSmlf
209766f9d5cbSmlf return (rval);
209866f9d5cbSmlf }
209966f9d5cbSmlf
210066f9d5cbSmlf
210166f9d5cbSmlf static char *
sata_get_devicepath(const char * ap_id)210266f9d5cbSmlf sata_get_devicepath(const char *ap_id)
210366f9d5cbSmlf {
210466f9d5cbSmlf char *devpath = NULL;
210566f9d5cbSmlf size_t size;
210666f9d5cbSmlf cfga_sata_ret_t rv;
210766f9d5cbSmlf
210821f023dfSToomas Soome rv = do_control_ioctl(ap_id, SATA_CFGA_GET_DEVICE_PATH, 0,
210966f9d5cbSmlf (void **)&devpath, &size);
211066f9d5cbSmlf
211166f9d5cbSmlf if (rv == CFGA_SATA_OK) {
211266f9d5cbSmlf return (devpath);
211366f9d5cbSmlf } else {
211466f9d5cbSmlf return ((char *)NULL);
211566f9d5cbSmlf }
211666f9d5cbSmlf
211766f9d5cbSmlf }
2118