Merge commit 'b1e7e97d3b60469b243b3b2e22c7d8cbd11c7c90'
[unleashed.git] / usr / src / lib / cfgadm_plugins / sata / common / cfga_sata.c
blobb5297f275928583e63dc0b785c1d232ac5dae253
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
28 #include <sys/param.h>
29 #include <sys/stat.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <dirent.h>
33 #include "cfga_sata.h"
36 * This file contains the entry points to the plug-in as defined in the
37 * config_admin(3X) man page.
41 * Set the version number for the cfgadm library's use.
43 int cfga_version = CFGA_HSL_V2;
45 enum {
46 HELP_HEADER = 1,
47 HELP_CONFIG,
48 HELP_RESET_PORT,
49 HELP_RESET_DEVICE,
50 HELP_RESET_ALL,
51 HELP_PORT_DEACTIVATE,
52 HELP_PORT_ACTIVATE,
53 HELP_PORT_SELF_TEST,
54 HELP_CNTRL_SELF_TEST,
55 HELP_UNKNOWN
58 /* SATA specific help messages */
59 static char *sata_help[] = {
60 NULL,
61 "SATA specific commands:\n",
62 " cfgadm -c [configure|unconfigure|disconnect|connect] ap_id "
63 "[ap_id...]\n",
64 " cfgadm -x sata_reset_port ap_id [ap_id...]\n",
65 " cfgadm -x sata_reset_device ap_id [ap_id...]\n",
66 " cfgadm -x sata_reset_all ap_id\n",
67 " cfgadm -x sata_port_deactivate ap_id [ap_id...]\n",
68 " cfgadm -x sata_port_activate ap_id [ap_id...]\n",
69 " cfgadm -x sata_port_self_test ap_id [ap_id...]\n",
70 " cfgadm -t ap_id\n",
71 "\tunknown command or option:\n",
72 NULL
73 }; /* End help messages */
77 * Messages.
79 static msgcvt_t sata_msgs[] = {
80 /* CFGA_SATA_OK */
81 { CVT, CFGA_OK, "" },
83 /* CFGA_SATA_NACK */
84 { CVT, CFGA_NACK, "" },
86 /* CFGA_SATA_DEVICE_UNCONFIGURED */
87 { CVT, CFGA_OK, "Device unconfigured prior to disconnect" },
89 /* CFGA_SATA_UNKNOWN / CFGA_LIB_ERROR -> "Library error" */
90 { CVT, CFGA_LIB_ERROR, "Unknown message; internal error" },
92 /* CFGA_SATA_INTERNAL_ERROR / CFGA_LIB_ERROR -> "Library error" */
93 { CVT, CFGA_LIB_ERROR, "Internal error" },
95 /* CFGA_SATA_DATA_ERROR / CFGA_DATA_ERROR -> "Data error" */
96 { CVT, CFGA_DATA_ERROR, "cfgadm data error" },
98 /* CFGA_SATA_OPTIONS / CFGA_ERROR -> "Hardware specific failure" */
99 { CVT, CFGA_ERROR, "Hardware specific option not supported" },
101 /* CFGA_SATA_HWOPNOTSUPP / CFGA_ERROR -> "Hardware specific failure" */
102 { CVT, CFGA_ERROR, "Hardware specific operation not supported" },
105 * CFGA_SATA_DYNAMIC_AP /
106 * CFGA_LIB_ERROR -> "Configuration operation invalid"
108 { CVT, CFGA_INVAL, "Cannot identify attached device" },
110 /* CFGA_SATA_AP / CFGA_APID_NOEXIST -> "Attachment point not found" */
111 { CVT, CFGA_APID_NOEXIST, "" },
113 /* CFGA_SATA_PORT / CFGA_LIB_ERROR -> "Library error" */
114 { CVT, CFGA_LIB_ERROR, "Cannot determine sata port number for " },
116 /* CFGA_SATA_DEVCTL / CFGA_LIB_ERROR -> "Library error" */
117 { CVT, CFGA_LIB_ERROR, "Internal error: "
118 "Cannot allocate devctl handle " },
121 * CFGA_SATA_DEV_CONFIGURE /
122 * CFGA_ERROR -> "Hardware specific failure"
124 { CVT, CFGA_ERROR, "Failed to config device at " },
127 * CFGA_SATA_DEV_UNCONFIGURE /
128 * CFGA_ERROR -> "Hardware specific failure"
130 { CVT, CFGA_ERROR, "Failed to unconfig device at " },
133 * CFGA_SATA_DISCONNECTED
134 * CFGA_INVAL -> "Configuration operation invalid"
136 { CVT, CFGA_INVAL, "Port already disconnected " },
139 * CFGA_SATA_NOT_CONNECTED
140 * CFGA_INVAL -> "Configuration operation invalid"
142 { CVT, CFGA_INVAL, "No device connected to " },
145 * CFGA_SATA_NOT_CONFIGURED /
146 * CFGA_INVAL -> "Configuration operation invalid"
148 { CVT, CFGA_INVAL, "No device configured at " },
151 * CFGA_SATA_ALREADY_CONNECTED /
152 * CFGA_INVAL -> "Configuration operation invalid"
154 { CVT, CFGA_INVAL, "Device already connected to " },
157 * CFGA_SATA_ALREADY_CONFIGURED /
158 * CFGA_INVAL -> "Configuration operation invalid"
160 { CVT, CFGA_INVAL, "Device already configured at " },
163 * CFGA_SATA_INVALID_DEVNAME /
164 * CFGA_INVAL -> "Configuration operation invalid"
166 { CVT, CFGA_INVAL, "Cannot specify device name" },
168 /* CFGA_SATA_OPEN / CFGA_LIB_ERROR -> "Library error" */
169 { CVT, CFGA_LIB_ERROR, "Cannot open " },
171 /* CFGA_SATA_IOCTL / CFGA_ERROR -> "Hardware specific failure" */
172 { CVT, CFGA_ERROR, "Driver ioctl failed " },
175 * CFGA_SATA_BUSY /
176 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
178 { CVT, CFGA_SYSTEM_BUSY, "" },
180 /* CFGA_SATA_ALLOC_FAIL / CFGA_LIB_ERROR -> "Library error" */
181 { CVT, CFGA_LIB_ERROR, "Memory allocation failure" },
184 * CFGA_SATA_OPNOTSUPP /
185 * CFGA_OPNOTSUPP -> "Configuration operation not supported"
187 { CVT, CFGA_OPNOTSUPP, "Operation not supported" },
189 /* CFGA_SATA_DEVLINK / CFGA_LIB_ERROR -> "Library error" */
190 { CVT, CFGA_LIB_ERROR, "Could not find /dev/cfg link for " },
192 /* CFGA_SATA_STATE / CFGA_LIB_ERROR -> "Library error" */
193 { CVT, CFGA_LIB_ERROR, "Internal error: Unrecognized ap state" },
195 /* CFGA_SATA_PRIV / CFGA_PRIV -> "Insufficient privileges" */
196 { CVT, CFGA_PRIV, "" },
198 /* CFGA_SATA_NVLIST / CFGA_ERROR -> "Hardware specific failure" */
199 { CVT, CFGA_ERROR, "Internal error (nvlist)" },
201 /* CFGA_SATA_ZEROLEN / CFGA_ERROR -> "Hardware specific failure" */
202 { CVT, CFGA_ERROR, "Internal error (zerolength string)" },
204 /* CFGA_SATA_RCM_HANDLE / CFGA_ERROR -> "Hardware specific failure" */
205 { CVT, CFGA_ERROR, "cannot get RCM handle"},
208 * CFGA_SATA_RCM_ONLINE /
209 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
211 { CVT, CFGA_SYSTEM_BUSY, "failed to online: "},
214 * CFGA_SATA_RCM_OFFLINE /
215 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
217 { CVT, CFGA_SYSTEM_BUSY, "failed to offline: "},
219 /* CFGA_SATA_RCM_INFO / CFGA_ERROR -> "Hardware specific failure" */
220 { CVT, CFGA_ERROR, "failed to query: "}
222 }; /* End error messages */
224 static cfga_sata_ret_t
225 verify_params(const char *ap_id, const char *options, char **errstring);
228 static cfga_sata_ret_t
229 setup_for_devctl_cmd(const char *ap_id, devctl_hdl_t *devctl_hdl,
230 nvlist_t **user_nvlistp, uint_t oflag);
232 static cfga_sata_ret_t
233 port_state(devctl_hdl_t hdl, nvlist_t *list,
234 ap_rstate_t *rstate, ap_ostate_t *ostate);
236 static cfga_sata_ret_t
237 do_control_ioctl(const char *ap_id, sata_cfga_apctl_t subcommand, uint_t arg,
238 void **descrp, size_t *sizep);
240 static void
241 cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist);
243 static char *
244 sata_get_devicepath(const char *ap_id);
246 static int
247 sata_confirm(struct cfga_confirm *confp, char *msg);
249 static cfga_sata_ret_t
250 get_port_num(const char *ap_id, uint32_t *port);
252 /* Utilities */
254 static cfga_sata_ret_t
255 physpath_to_devlink(const char *basedir, const char *node_path,
256 char **logpp, int *l_errnop)
258 char *linkpath;
259 char *buf;
260 char *real_path;
261 DIR *dp;
262 struct dirent *dep, *newdep;
263 int deplen;
264 boolean_t found = B_FALSE;
265 int err = 0;
266 struct stat sb;
267 char *p;
268 cfga_sata_ret_t rv = CFGA_SATA_INTERNAL_ERROR;
271 * Using libdevinfo for this is overkill and kills performance
272 * when multiple consumers of libcfgadm are executing
273 * concurrently.
275 if ((dp = opendir(basedir)) == NULL) {
276 *l_errnop = errno;
277 return (CFGA_SATA_INTERNAL_ERROR);
280 linkpath = malloc(PATH_MAX);
281 buf = malloc(PATH_MAX);
282 real_path = malloc(PATH_MAX);
284 deplen = pathconf(basedir, _PC_NAME_MAX);
285 deplen = (deplen <= 0 ? MAXNAMELEN : deplen) +
286 sizeof (struct dirent);
287 dep = (struct dirent *)malloc(deplen);
289 if (dep == NULL || linkpath == NULL || buf == NULL ||
290 real_path == NULL) {
291 *l_errnop = ENOMEM;
292 rv = CFGA_SATA_ALLOC_FAIL;
293 goto pp_cleanup;
296 *logpp = NULL;
298 while (!found && (err = readdir_r(dp, dep, &newdep)) == 0 &&
299 newdep != NULL) {
301 assert(newdep == dep);
303 if (strcmp(dep->d_name, ".") == 0 ||
304 strcmp(dep->d_name, "..") == 0)
305 continue;
307 (void) snprintf(linkpath, MAXPATHLEN,
308 "%s/%s", basedir, dep->d_name);
310 if (lstat(linkpath, &sb) < 0)
311 continue;
313 if (S_ISDIR(sb.st_mode)) {
315 if ((rv = physpath_to_devlink(linkpath, node_path,
316 logpp, l_errnop)) != CFGA_SATA_OK) {
318 goto pp_cleanup;
321 if (*logpp != NULL)
322 found = B_TRUE;
324 } else if (S_ISLNK(sb.st_mode)) {
326 bzero(buf, PATH_MAX);
327 if (readlink(linkpath, buf, PATH_MAX) < 0)
328 continue;
332 * realpath() is too darn slow, so fake
333 * it, by using what we know about /dev
334 * links: they are always of the form:
335 * <"../">+/devices/<path>
337 p = buf;
338 while (strncmp(p, "../", 3) == 0)
339 p += 3;
341 if (p != buf)
342 p--; /* back up to get a slash */
344 assert (*p == '/');
346 if (strcmp(p, node_path) == 0) {
347 *logpp = strdup(linkpath);
348 if (*logpp == NULL) {
350 rv = CFGA_SATA_ALLOC_FAIL;
351 goto pp_cleanup;
354 found = B_TRUE;
359 free(linkpath);
360 free(buf);
361 free(real_path);
362 free(dep);
363 (void) closedir(dp);
365 if (err != 0) {
366 *l_errnop = err;
367 return (CFGA_SATA_INTERNAL_ERROR);
370 return (CFGA_SATA_OK);
372 pp_cleanup:
374 if (dp)
375 (void) closedir(dp);
376 free(dep);
377 free(linkpath);
378 free(buf);
379 free(real_path);
380 if (*logpp) {
381 free(*logpp);
382 *logpp = NULL;
384 return (rv);
389 * Given the index into a table (msgcvt_t) of messages, get the message
390 * string, converting it to the proper locale if necessary.
391 * NOTE: Indexes are defined in cfga_sata.h
393 static const char *
394 get_msg(uint_t msg_index, msgcvt_t *msg_tbl, uint_t tbl_size)
396 if (msg_index >= tbl_size) {
397 msg_index = CFGA_SATA_UNKNOWN;
400 return ((msg_tbl[msg_index].intl) ?
401 dgettext(TEXT_DOMAIN, msg_tbl[msg_index].msgstr) :
402 msg_tbl[msg_index].msgstr);
406 * Allocates and creates a message string (in *ret_str),
407 * by concatenating all the (char *) args together, in order.
408 * Last arg MUST be NULL.
410 static void
411 set_msg(char **ret_str, ...)
413 char *str;
414 size_t total_len;
415 va_list valist;
417 va_start(valist, ret_str);
419 total_len = (*ret_str == NULL) ? 0 : strlen(*ret_str);
421 while ((str = va_arg(valist, char *)) != NULL) {
422 size_t len = strlen(str);
423 char *old_str = *ret_str;
425 *ret_str = (char *)realloc(*ret_str, total_len + len + 1);
426 if (*ret_str == NULL) {
427 /* We're screwed */
428 free(old_str);
429 va_end(valist);
430 return;
433 (void) strcpy(*ret_str + total_len, str);
434 total_len += len;
437 va_end(valist);
441 * Error message handling.
442 * For the rv passed in, looks up the corresponding error message string(s),
443 * internationalized if necessary, and concatenates it into a new
444 * memory buffer, and points *errstring to it.
445 * Note not all rvs will result in an error message return, as not all
446 * error conditions warrant a SATA-specific error message - for those
447 * conditions the cfgadm generic messages are sufficient.
449 * Some messages may display ap_id or errno, which is why they are passed
450 * in.
453 cfga_err_t
454 sata_err_msg(
455 char **errstring,
456 cfga_sata_ret_t rv,
457 const char *ap_id,
458 int l_errno)
460 if (errstring == NULL) {
461 return (sata_msgs[rv].cfga_err);
465 * Generate the appropriate SATA-specific error message(s) (if any).
467 switch (rv) {
468 case CFGA_SATA_OK:
469 case CFGA_NACK:
470 /* Special case - do nothing. */
471 break;
473 case CFGA_SATA_UNKNOWN:
474 case CFGA_SATA_DYNAMIC_AP:
475 case CFGA_SATA_INTERNAL_ERROR:
476 case CFGA_SATA_OPTIONS:
477 case CFGA_SATA_ALLOC_FAIL:
478 case CFGA_SATA_STATE:
479 case CFGA_SATA_PRIV:
480 case CFGA_SATA_OPNOTSUPP:
481 case CFGA_SATA_DATA_ERROR:
482 /* These messages require no additional strings passed. */
483 set_msg(errstring, ERR_STR(rv), NULL);
484 break;
486 case CFGA_SATA_HWOPNOTSUPP:
487 /* hardware-specific help needed */
488 set_msg(errstring, ERR_STR(rv), NULL);
489 set_msg(errstring, "\n",
490 dgettext(TEXT_DOMAIN, sata_help[HELP_HEADER]), NULL);
491 set_msg(errstring, sata_help[HELP_RESET_PORT], NULL);
492 set_msg(errstring, sata_help[HELP_RESET_DEVICE], NULL);
493 set_msg(errstring, sata_help[HELP_RESET_ALL], NULL);
494 set_msg(errstring, sata_help[HELP_PORT_ACTIVATE], NULL);
495 set_msg(errstring, sata_help[HELP_PORT_DEACTIVATE], NULL);
496 set_msg(errstring, sata_help[HELP_PORT_SELF_TEST], NULL);
497 set_msg(errstring, sata_help[HELP_CNTRL_SELF_TEST], NULL);
498 break;
500 case CFGA_SATA_AP:
501 case CFGA_SATA_PORT:
502 case CFGA_SATA_NOT_CONNECTED:
503 case CFGA_SATA_NOT_CONFIGURED:
504 case CFGA_SATA_ALREADY_CONNECTED:
505 case CFGA_SATA_ALREADY_CONFIGURED:
506 case CFGA_SATA_BUSY:
507 case CFGA_SATA_DEVLINK:
508 case CFGA_SATA_RCM_HANDLE:
509 case CFGA_SATA_RCM_ONLINE:
510 case CFGA_SATA_RCM_OFFLINE:
511 case CFGA_SATA_RCM_INFO:
512 case CFGA_SATA_DEV_CONFIGURE:
513 case CFGA_SATA_DEV_UNCONFIGURE:
514 case CFGA_SATA_DISCONNECTED:
515 /* These messages also print ap_id. */
516 set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "", NULL);
517 break;
520 case CFGA_SATA_IOCTL:
521 case CFGA_SATA_NVLIST:
522 /* These messages also print errno. */
524 char *errno_str = l_errno ? strerror(l_errno) : "";
526 set_msg(errstring, ERR_STR(rv), errno_str,
527 l_errno ? "\n" : "", NULL);
528 break;
531 case CFGA_SATA_OPEN:
532 /* These messages also apid and errno. */
534 char *errno_str = l_errno ? strerror(l_errno) : "";
536 set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "\n",
537 errno_str, l_errno ? "\n" : "", NULL);
538 break;
541 default:
542 set_msg(errstring, ERR_STR(CFGA_SATA_INTERNAL_ERROR), NULL);
544 } /* end switch */
548 * Determine the proper error code to send back to the cfgadm library.
550 return (sata_msgs[rv].cfga_err);
555 * Entry points
557 /* cfgadm entry point */
558 /*ARGSUSED*/
559 cfga_err_t
560 cfga_change_state(
561 cfga_cmd_t state_change_cmd,
562 const char *ap_id,
563 const char *options,
564 struct cfga_confirm *confp,
565 struct cfga_msg *msgp,
566 char **errstring,
567 cfga_flags_t flags)
569 int ret;
570 int len;
571 char *msg;
572 char *devpath;
573 nvlist_t *nvl = NULL;
574 ap_rstate_t rstate;
575 ap_ostate_t ostate;
576 devctl_hdl_t hdl = NULL;
577 cfga_sata_ret_t rv = CFGA_SATA_OK;
578 char *pdyn;
579 char *str_type;
580 size_t size;
581 boolean_t pmult = B_FALSE;
584 * All sub-commands which can change state of device require
585 * root privileges.
587 if (geteuid() != 0) {
588 rv = CFGA_SATA_PRIV;
589 goto bailout;
592 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) {
593 (void) cfga_help(msgp, options, flags);
594 goto bailout;
597 if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &nvl,
598 DC_RDONLY)) != CFGA_SATA_OK) {
599 goto bailout;
603 * Checking device type. A port multiplier is not configurable - it is
604 * already configured as soon as it is connected.
606 if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, 0,
607 (void **)&str_type, &size)) != CFGA_SATA_OK) {
608 /* no such deivce */
609 goto bailout;
611 if (strncmp(str_type, "sata-pmult", sizeof ("sata-pmult")) == 0) {
612 pmult = B_TRUE;
615 switch (state_change_cmd) {
616 case CFGA_CMD_CONFIGURE:
617 if (pmult == B_TRUE) {
618 rv = CFGA_SATA_HWOPNOTSUPP;
619 goto bailout;
622 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
623 CFGA_SATA_OK)
624 goto bailout;
626 if (ostate == AP_OSTATE_CONFIGURED) {
627 rv = CFGA_SATA_ALREADY_CONFIGURED;
628 goto bailout;
630 /* Disallow dynamic AP name component */
631 if (GET_DYN(ap_id) != NULL) {
632 rv = CFGA_SATA_INVALID_DEVNAME;
633 goto bailout;
636 if (rstate == AP_RSTATE_EMPTY) {
637 rv = CFGA_SATA_NOT_CONNECTED;
638 goto bailout;
640 rv = CFGA_SATA_OK;
642 if (devctl_ap_configure(hdl, nvl) != 0) {
643 rv = CFGA_SATA_DEV_CONFIGURE;
644 goto bailout;
647 devpath = sata_get_devicepath(ap_id);
648 if (devpath == NULL) {
649 int i;
651 * Try for some time as SATA hotplug thread
652 * takes a while to create the path then
653 * eventually give up.
655 for (i = 0; i < 12 && (devpath == NULL); i++) {
656 (void) sleep(6);
657 devpath = sata_get_devicepath(ap_id);
660 if (devpath == NULL) {
661 rv = CFGA_SATA_DEV_CONFIGURE;
662 break;
666 S_FREE(devpath);
667 break;
669 case CFGA_CMD_UNCONFIGURE:
670 if (pmult == B_TRUE) {
671 rv = CFGA_SATA_HWOPNOTSUPP;
672 goto bailout;
675 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
676 CFGA_SATA_OK)
677 goto bailout;
679 if (rstate != AP_RSTATE_CONNECTED) {
680 rv = CFGA_SATA_NOT_CONNECTED;
681 goto bailout;
684 if (ostate != AP_OSTATE_CONFIGURED) {
685 rv = CFGA_SATA_NOT_CONFIGURED;
686 goto bailout;
688 /* Strip off AP name dynamic component, if present */
689 if ((pdyn = GET_DYN(ap_id)) != NULL) {
690 *pdyn = '\0';
693 rv = CFGA_SATA_OK;
695 len = strlen(SATA_CONFIRM_DEVICE) +
696 strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
697 strlen("Unconfigure") + strlen(ap_id);
698 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
699 (void) snprintf(msg, len + 3, "Unconfigure"
700 " %s%s\n%s",
701 SATA_CONFIRM_DEVICE, ap_id,
702 SATA_CONFIRM_DEVICE_SUSPEND);
705 if (!sata_confirm(confp, msg)) {
706 free(msg);
707 rv = CFGA_SATA_NACK;
708 break;
710 free(msg);
712 devpath = sata_get_devicepath(ap_id);
713 if (devpath == NULL) {
714 (void) printf(
715 "cfga_change_state: get device path failed\n");
716 rv = CFGA_SATA_DEV_UNCONFIGURE;
717 break;
720 if ((rv = sata_rcm_offline(ap_id, errstring, devpath, flags))
721 != CFGA_SATA_OK) {
722 break;
725 ret = devctl_ap_unconfigure(hdl, nvl);
727 if (ret != 0) {
728 rv = CFGA_SATA_DEV_UNCONFIGURE;
729 if (errno == EBUSY) {
730 rv = CFGA_SATA_BUSY;
732 (void) sata_rcm_online(ap_id, errstring, devpath,
733 flags);
734 } else {
735 (void) sata_rcm_remove(ap_id, errstring, devpath,
736 flags);
739 S_FREE(devpath);
741 break;
743 case CFGA_CMD_DISCONNECT:
744 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
745 CFGA_SATA_OK)
746 goto bailout;
748 if (rstate == AP_RSTATE_DISCONNECTED) {
749 rv = CFGA_SATA_DISCONNECTED;
750 goto bailout;
753 /* Strip off AP name dynamic component, if present */
754 if ((pdyn = GET_DYN(ap_id)) != NULL) {
755 *pdyn = '\0';
759 rv = CFGA_SATA_OK; /* other statuses don't matter */
762 * If the port originally with device attached and was
763 * unconfigured already, the devicepath for the sd will be
764 * removed. sata_get_devicepath in this case is not necessary.
766 /* only call rcm_offline if the state was CONFIGURED */
767 if (ostate == AP_OSTATE_CONFIGURED &&
768 pmult == B_FALSE) {
769 devpath = sata_get_devicepath(ap_id);
770 if (devpath == NULL) {
771 (void) printf(
772 "cfga_change_state: get path failed\n");
773 rv = CFGA_SATA_DEV_UNCONFIGURE;
774 break;
777 len = strlen(SATA_CONFIRM_DEVICE) +
778 strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
779 strlen("Disconnect") + strlen(ap_id);
780 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
781 (void) snprintf(msg, len + 3,
782 "Disconnect"
783 " %s%s\n%s",
784 SATA_CONFIRM_DEVICE, ap_id,
785 SATA_CONFIRM_DEVICE_SUSPEND);
787 if (!sata_confirm(confp, msg)) {
788 free(msg);
789 rv = CFGA_SATA_NACK;
790 break;
792 free(msg);
794 if ((rv = sata_rcm_offline(ap_id, errstring,
795 devpath, flags)) != CFGA_SATA_OK) {
796 break;
799 ret = devctl_ap_unconfigure(hdl, nvl);
800 if (ret != 0) {
801 (void) printf(
802 "devctl_ap_unconfigure failed\n");
803 rv = CFGA_SATA_DEV_UNCONFIGURE;
804 if (errno == EBUSY)
805 rv = CFGA_SATA_BUSY;
806 (void) sata_rcm_online(ap_id, errstring,
807 devpath, flags);
808 S_FREE(devpath);
811 * The current policy is that if unconfigure
812 * failed, do not continue with disconnect.
813 * If the port needs to be forced into the
814 * disconnect (shutdown) state,
815 * the -x sata_port_poweroff command should be
816 * used instead of -c disconnect
818 break;
819 } else {
820 (void) printf("%s\n",
821 ERR_STR(CFGA_SATA_DEVICE_UNCONFIGURED));
822 (void) sata_rcm_remove(ap_id, errstring,
823 devpath, flags);
825 S_FREE(devpath);
826 } else if (rstate == AP_RSTATE_CONNECTED ||
827 rstate == AP_RSTATE_EMPTY) {
828 len = strlen(SATA_CONFIRM_PORT) +
829 strlen(SATA_CONFIRM_PORT_DISABLE) +
830 strlen("Deactivate Port") + strlen(ap_id);
831 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
832 (void) snprintf(msg, len +3,
833 "Disconnect"
834 " %s%s\n%s",
835 SATA_CONFIRM_PORT, ap_id,
836 SATA_CONFIRM_PORT_DISABLE);
838 if (!sata_confirm(confp, msg)) {
839 free(msg);
840 rv = CFGA_SATA_NACK;
841 break;
844 ret = devctl_ap_disconnect(hdl, nvl);
845 if (ret != 0) {
846 rv = CFGA_SATA_IOCTL;
847 if (errno == EBUSY) {
848 rv = CFGA_SATA_BUSY;
851 break;
853 case CFGA_CMD_CONNECT:
854 if ((rv = port_state(hdl, nvl, &rstate, &ostate)) !=
855 CFGA_SATA_OK)
856 goto bailout;
858 if (rstate == AP_RSTATE_CONNECTED) {
859 rv = CFGA_SATA_ALREADY_CONNECTED;
860 goto bailout;
863 len = strlen(SATA_CONFIRM_PORT) +
864 strlen(SATA_CONFIRM_PORT_ENABLE) +
865 strlen("Activate Port") + strlen(ap_id);
866 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
867 (void) snprintf(msg, len +3, "Activate"
868 " %s%s\n%s",
869 SATA_CONFIRM_PORT, ap_id,
870 SATA_CONFIRM_PORT_ENABLE);
872 if (!sata_confirm(confp, msg)) {
873 rv = CFGA_SATA_NACK;
874 break;
877 /* Disallow dynamic AP name component */
878 if (GET_DYN(ap_id) != NULL) {
879 rv = CFGA_SATA_INVALID_DEVNAME;
880 goto bailout;
883 ret = devctl_ap_connect(hdl, nvl);
884 if (ret != 0) {
885 rv = CFGA_SATA_IOCTL;
886 } else {
887 rv = CFGA_SATA_OK;
890 break;
892 case CFGA_CMD_LOAD:
893 case CFGA_CMD_UNLOAD:
894 (void) cfga_help(msgp, options, flags);
895 rv = CFGA_SATA_OPNOTSUPP;
896 break;
898 case CFGA_CMD_NONE:
899 default:
900 (void) cfga_help(msgp, options, flags);
901 rv = CFGA_SATA_INTERNAL_ERROR;
904 bailout:
905 cleanup_after_devctl_cmd(hdl, nvl);
907 return (sata_err_msg(errstring, rv, ap_id, errno));
910 /* cfgadm entry point */
911 cfga_err_t
912 cfga_private_func(
913 const char *func,
914 const char *ap_id,
915 const char *options,
916 struct cfga_confirm *confp,
917 struct cfga_msg *msgp,
918 char **errstring,
919 cfga_flags_t flags)
921 int len;
922 char *msg;
923 nvlist_t *list = NULL;
924 ap_ostate_t ostate;
925 ap_rstate_t rstate;
926 devctl_hdl_t hdl = NULL;
927 cfga_sata_ret_t rv;
928 char *str_p;
929 size_t size;
931 if ((rv = verify_params(ap_id, NULL, errstring)) != CFGA_SATA_OK) {
932 (void) cfga_help(msgp, options, flags);
933 return (sata_err_msg(errstring, rv, ap_id, errno));
937 * All subcommands which can change state of device require
938 * root privileges.
940 if (geteuid() != 0) {
941 rv = CFGA_SATA_PRIV;
942 goto bailout;
945 if (func == NULL) {
946 (void) printf("No valid option specified\n");
947 rv = CFGA_SATA_OPTIONS;
948 goto bailout;
951 if ((rv = setup_for_devctl_cmd(ap_id, &hdl, &list, 0)) !=
952 CFGA_SATA_OK) {
953 goto bailout;
956 /* We do not care here about dynamic AP name component */
957 if ((str_p = GET_DYN(ap_id)) != NULL) {
958 *str_p = '\0';
961 rv = CFGA_SATA_OK;
963 if (strcmp(func, SATA_RESET_PORT) == 0) {
964 len = strlen(SATA_CONFIRM_PORT) +
965 strlen(SATA_CONFIRM_DEVICE_ABORT) +
966 strlen("Reset Port") + strlen(ap_id);
968 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
969 (void) snprintf(msg, len +3, "Reset"
970 " %s%s\n%s",
971 SATA_CONFIRM_PORT, ap_id,
972 SATA_CONFIRM_DEVICE_ABORT);
973 } else {
974 rv = CFGA_SATA_NACK;
975 goto bailout;
978 if (!sata_confirm(confp, msg)) {
979 rv = CFGA_SATA_NACK;
980 goto bailout;
983 rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_PORT, 0,
984 (void **)&str_p, &size);
986 } else if (strcmp(func, SATA_RESET_DEVICE) == 0) {
987 if ((rv = port_state(hdl, list, &rstate, &ostate)) !=
988 CFGA_SATA_OK)
989 goto bailout;
991 * Reset device function requires device to be connected
993 if (rstate != AP_RSTATE_CONNECTED) {
994 rv = CFGA_SATA_NOT_CONNECTED;
995 goto bailout;
998 len = strlen(SATA_CONFIRM_DEVICE) +
999 strlen(SATA_CONFIRM_DEVICE_ABORT) +
1000 strlen("Reset Device") + strlen(ap_id);
1002 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1003 (void) snprintf(msg, len +3, "Reset"
1004 " %s%s\n%s",
1005 SATA_CONFIRM_DEVICE, ap_id,
1006 SATA_CONFIRM_DEVICE_ABORT);
1007 } else {
1008 rv = CFGA_SATA_NACK;
1009 goto bailout;
1012 if (!sata_confirm(confp, msg)) {
1013 rv = CFGA_SATA_NACK;
1014 goto bailout;
1017 rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_DEVICE, 0,
1018 (void **)&str_p, &size);
1020 } else if (strcmp(func, SATA_RESET_ALL) == 0) {
1021 len = strlen(SATA_CONFIRM_CONTROLLER) +
1022 strlen(SATA_CONFIRM_CONTROLLER_ABORT) +
1023 strlen("Reset All") + strlen(ap_id);
1025 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1026 (void) snprintf(msg, len +3, "Reset"
1027 " %s%s\n%s",
1028 SATA_CONFIRM_CONTROLLER, ap_id,
1029 SATA_CONFIRM_CONTROLLER_ABORT);
1030 } else {
1031 rv = CFGA_SATA_NACK;
1032 goto bailout;
1035 if (!sata_confirm(confp, msg)) {
1036 rv = CFGA_SATA_NACK;
1037 goto bailout;
1039 rv = do_control_ioctl(ap_id, SATA_CFGA_RESET_ALL, 0,
1040 (void **)&str_p, &size);
1042 } else if (strcmp(func, SATA_PORT_DEACTIVATE) == 0) {
1043 len = strlen(SATA_CONFIRM_PORT) +
1044 strlen(SATA_CONFIRM_PORT_DISABLE) +
1045 strlen("Deactivate Port") + strlen(ap_id);
1047 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1048 (void) snprintf(msg, len +3, "Deactivate"
1049 " %s%s\n%s",
1050 SATA_CONFIRM_PORT, ap_id,
1051 SATA_CONFIRM_PORT_DISABLE);
1052 } else {
1053 rv = CFGA_SATA_NACK;
1054 goto bailout;
1056 if (!sata_confirm(confp, msg)) {
1057 rv = CFGA_SATA_NACK;
1058 goto bailout;
1061 rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_DEACTIVATE, 0,
1062 (void **)&str_p, &size);
1064 } else if (strcmp(func, SATA_PORT_ACTIVATE) == 0) {
1065 len = strlen(SATA_CONFIRM_PORT) +
1066 strlen(SATA_CONFIRM_PORT_ENABLE) +
1067 strlen("Activate Port") + strlen(ap_id);
1069 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1070 (void) snprintf(msg, len +3, "Activate"
1071 " %s%s\n%s",
1072 SATA_CONFIRM_PORT, ap_id,
1073 SATA_CONFIRM_PORT_ENABLE);
1074 } else {
1075 rv = CFGA_SATA_NACK;
1076 goto bailout;
1078 if (!sata_confirm(confp, msg)) {
1079 rv = CFGA_SATA_NACK;
1080 goto bailout;
1083 rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_ACTIVATE,
1084 0, (void **)&str_p, &size);
1085 goto bailout;
1087 } else if (strcmp(func, SATA_PORT_SELF_TEST) == 0) {
1088 len = strlen(SATA_CONFIRM_PORT) +
1089 strlen(SATA_CONFIRM_DEVICE_SUSPEND) +
1090 strlen("Self Test Port") + strlen(ap_id);
1092 if ((msg = (char *)calloc(len +3, 1)) != NULL) {
1093 (void) snprintf(msg, len +3, "Self Test"
1094 " %s%s\n%s",
1095 SATA_CONFIRM_PORT, ap_id,
1096 SATA_CONFIRM_DEVICE_SUSPEND);
1097 } else {
1098 rv = CFGA_SATA_NACK;
1099 goto bailout;
1101 if (!sata_confirm(confp, msg)) {
1102 rv = CFGA_SATA_NACK;
1103 goto bailout;
1106 rv = do_control_ioctl(ap_id, SATA_CFGA_PORT_SELF_TEST,
1107 0, (void **)&str_p, &size);
1108 } else {
1109 /* Unrecognized operation request */
1110 rv = CFGA_SATA_HWOPNOTSUPP;
1113 bailout:
1114 cleanup_after_devctl_cmd(hdl, list);
1116 return (sata_err_msg(errstring, rv, ap_id, errno));
1120 /* cfgadm entry point */
1121 /*ARGSUSED*/
1122 cfga_err_t
1123 cfga_test(
1124 const char *ap_id,
1125 const char *options,
1126 struct cfga_msg *msgp,
1127 char **errstring,
1128 cfga_flags_t flags)
1130 /* Should call ioctl for self test - phase 2 */
1131 return (CFGA_OPNOTSUPP);
1136 sata_check_target_node(di_node_t node, void *arg)
1138 char *minorpath;
1139 char *cp;
1141 minorpath = di_devfs_minor_path(di_minor_next(node, DI_MINOR_NIL));
1142 if (minorpath != NULL) {
1143 if (strstr(minorpath, arg) != NULL) {
1144 cp = strrchr(minorpath, (int)*MINOR_SEP);
1145 if (cp != NULL) {
1146 (void) strcpy(arg, cp);
1148 free(minorpath);
1149 return (DI_WALK_TERMINATE);
1151 free(minorpath);
1153 return (DI_WALK_CONTINUE);
1156 struct chk_dev {
1157 int c_isblk;
1158 char *c_minor;
1161 /*ARGSUSED*/
1162 static int
1163 chk_dev_fcn(di_node_t node, di_minor_t minor, void *arg)
1165 char *mn;
1166 struct chk_dev *chkp = (struct chk_dev *)arg;
1168 mn = di_minor_name(minor);
1169 if (mn == NULL)
1170 return (DI_WALK_CONTINUE);
1172 if (strcmp(mn, chkp->c_minor) != 0)
1173 return (DI_WALK_CONTINUE);
1175 chkp->c_isblk = di_minor_spectype(minor) == S_IFBLK ? 1 : 0;
1177 return (DI_WALK_TERMINATE);
1181 * Don't use devfs if stat() in /devices fails. Use libdevinfo instead.
1182 * Retired devices don't show up in devfs.
1184 * Returns:
1185 * 1 - minor exists and is of type BLK
1186 * 0 - minor does not exist or is not of type BLK.
1188 static int
1189 is_devinfo_blk(char *minor_path)
1191 char *minor_portion;
1192 struct chk_dev chk_dev;
1193 di_node_t node;
1194 int rv;
1197 * prune minor path for di_init() - no /devices prefix and no minor name
1199 if (strncmp(minor_path, "/devices/", strlen("/devices/")) != 0)
1200 return (0);
1202 minor_portion = strrchr(minor_path, *MINOR_SEP);
1203 if (minor_portion == NULL)
1204 return (0);
1206 *minor_portion = 0;
1208 node = di_init(minor_path + strlen("/devices"), DINFOMINOR);
1210 *minor_portion = *MINOR_SEP;
1212 if (node == DI_NODE_NIL)
1213 return (0);
1215 chk_dev.c_isblk = 0;
1216 chk_dev.c_minor = minor_portion + 1;
1218 rv = di_walk_minor(node, NULL, 0, &chk_dev, chk_dev_fcn);
1220 di_fini(node);
1222 if (rv == 0 && chk_dev.c_isblk)
1223 return (1);
1224 else
1225 return (0);
1229 * The dynamic component buffer returned by this function has to be freed!
1232 sata_make_dyncomp(const char *ap_id, char **dyncomp, const char *type)
1234 char *devpath = NULL;
1235 char *cp = NULL;
1236 int l_errno;
1237 char minor_path[MAXPATHLEN];
1238 char name_part[MAXNAMELEN];
1239 char *devlink = NULL;
1240 char *minor_portion = NULL;
1241 int deplen;
1242 int err;
1243 DIR *dp = NULL;
1244 struct stat sb;
1245 struct dirent *dep = NULL;
1246 struct dirent *newdep = NULL;
1247 char *p;
1249 assert(dyncomp != NULL);
1252 * Get target node path
1254 devpath = sata_get_devicepath(ap_id);
1255 if (devpath == NULL) {
1257 (void) printf("cfga_list_ext: cannot locate target device\n");
1258 return (CFGA_SATA_DYNAMIC_AP);
1260 } else {
1262 cp = strrchr(devpath, *PATH_SEP);
1263 assert(cp != NULL);
1264 *cp = 0; /* terminate path for opendir() */
1266 (void) strncpy(name_part, cp + 1, MAXNAMELEN);
1269 * Using libdevinfo for this is overkill and kills
1270 * performance when many consumers are using libcfgadm
1271 * concurrently.
1273 if ((dp = opendir(devpath)) == NULL) {
1274 goto bailout;
1278 * deplen is large enough to fit the largest path-
1279 * struct dirent includes one byte (the terminator)
1280 * so we don't add 1 to the calculation here.
1282 deplen = pathconf(devpath, _PC_NAME_MAX);
1283 deplen = ((deplen <= 0) ? MAXNAMELEN : deplen) +
1284 sizeof (struct dirent);
1285 dep = (struct dirent *)malloc(deplen);
1286 if (dep == NULL)
1287 goto bailout;
1289 while ((err = readdir_r(dp, dep, &newdep)) == 0 &&
1290 newdep != NULL) {
1292 assert(newdep == dep);
1294 if (strcmp(dep->d_name, ".") == 0 ||
1295 strcmp(dep->d_name, "..") == 0 ||
1296 (minor_portion = strchr(dep->d_name,
1297 *MINOR_SEP)) == NULL)
1298 continue;
1300 *minor_portion = 0;
1301 if (strcmp(dep->d_name, name_part) != 0)
1302 continue;
1303 *minor_portion = *MINOR_SEP;
1305 (void) snprintf(minor_path, MAXPATHLEN,
1306 "%s/%s", devpath, dep->d_name);
1309 * Break directly for tape device
1311 if (strcmp(type, "tape") == 0)
1312 break;
1315 * If stat() fails, the device *may* be retired.
1316 * Check via libdevinfo if the device has a BLK minor.
1317 * We don't use libdevinfo all the time, since taking
1318 * a snapshot is slower than a stat().
1320 if (stat(minor_path, &sb) < 0) {
1321 if (is_devinfo_blk(minor_path)) {
1322 break;
1323 } else {
1324 continue;
1328 if (S_ISBLK(sb.st_mode))
1329 break;
1333 (void) closedir(dp);
1334 free(dep);
1335 free(devpath);
1337 dp = NULL;
1338 dep = NULL;
1339 devpath = NULL;
1342 * If there was an error, or we didn't exit the loop
1343 * by finding a block or character device, bail out.
1345 if (err != 0 || newdep == NULL)
1346 goto bailout;
1349 * Look for links to the physical path in /dev/dsk
1350 * and /dev/rmt. So far, sata modue supports disk,
1351 * dvd and tape devices, so we will first look for
1352 * BLOCK devices, and then look for tape devices.
1354 (void) physpath_to_devlink("/dev/dsk",
1355 minor_path, &devlink, &l_errno);
1357 /* postprocess and copy logical name here */
1358 if (devlink != NULL) {
1360 * For disks, remove partition/slice info
1362 if ((cp = strstr(devlink, "dsk/")) != NULL) {
1363 /* cXtYdZ[(s[0..15])|(p[0..X])] */
1364 if ((p = strchr(cp + 4, 'd')) != NULL) {
1365 p++; /* Skip the 'd' */
1366 while (*p != 0 && isdigit(*p))
1367 p++;
1368 *p = 0;
1370 *dyncomp = strdup(cp);
1373 free(devlink);
1374 } else if (strcmp(type, "tape") == 0) {
1377 * For tape device, logical name looks like
1378 * rmt/X
1380 (void) physpath_to_devlink("/dev/rmt",
1381 minor_path, &devlink, &l_errno);
1383 if (devlink != NULL) {
1384 if ((cp = strstr(devlink, "rmt/")) != NULL) {
1385 *dyncomp = strdup(cp);
1388 free(devlink);
1392 return (SATA_CFGA_OK);
1395 bailout:
1396 if (dp)
1397 (void) closedir(dp);
1398 free(devpath);
1399 free(dep);
1400 return (CFGA_SATA_DYNAMIC_AP);
1403 /* cfgadm entry point */
1404 /*ARGSUSED*/
1405 cfga_err_t
1406 cfga_list_ext(
1407 const char *ap_id,
1408 cfga_list_data_t **ap_id_list,
1409 int *nlistp,
1410 const char *options,
1411 const char *listopts,
1412 char **errstring,
1413 cfga_flags_t flags)
1415 int l_errno;
1416 char *ap_id_log = NULL;
1417 size_t size;
1418 nvlist_t *user_nvlist = NULL;
1419 devctl_hdl_t devctl_hdl = NULL;
1420 cfga_sata_ret_t rv = CFGA_SATA_OK;
1421 devctl_ap_state_t devctl_ap_state;
1422 char *pdyn;
1423 boolean_t pmult = B_FALSE;
1424 uint32_t port;
1427 if ((rv = verify_params(ap_id, options, errstring)) != CFGA_SATA_OK) {
1428 goto bailout;
1430 /* We do not care here about dynamic AP name component */
1431 if ((pdyn = GET_DYN(ap_id)) != NULL) {
1432 *pdyn = '\0';
1435 if (ap_id_list == NULL || nlistp == NULL) {
1436 rv = CFGA_SATA_DATA_ERROR;
1437 goto bailout;
1440 /* Get ap status */
1441 if ((rv = setup_for_devctl_cmd(ap_id, &devctl_hdl, &user_nvlist,
1442 DC_RDONLY)) != CFGA_SATA_OK) {
1443 goto bailout;
1446 /* will call dc_cmd to send IOCTL to kernel */
1447 if (devctl_ap_getstate(devctl_hdl, user_nvlist,
1448 &devctl_ap_state) == -1) {
1449 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
1450 rv = CFGA_SATA_IOCTL;
1451 goto bailout;
1454 cleanup_after_devctl_cmd(devctl_hdl, user_nvlist);
1457 * Create cfga_list_data_t struct.
1459 if ((*ap_id_list =
1460 (cfga_list_data_t *)malloc(sizeof (**ap_id_list))) == NULL) {
1461 rv = CFGA_SATA_ALLOC_FAIL;
1462 goto bailout;
1464 *nlistp = 1;
1467 * Rest of the code fills in the cfga_list_data_t struct.
1470 /* Get /dev/cfg path to corresponding to the physical ap_id */
1471 /* Remember ap_id_log must be freed */
1472 rv = physpath_to_devlink(CFGA_DEV_DIR, (char *)ap_id,
1473 &ap_id_log, &l_errno);
1475 if (rv != 0) {
1476 rv = CFGA_SATA_DEVLINK;
1477 goto bailout;
1480 /* Get logical ap_id corresponding to the physical */
1481 if (ap_id_log == NULL || strstr(ap_id_log, CFGA_DEV_DIR) == NULL) {
1482 rv = CFGA_SATA_DEVLINK;
1483 goto bailout;
1486 (void) strlcpy((*ap_id_list)->ap_log_id,
1487 /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR)+ 1,
1488 sizeof ((*ap_id_list)->ap_log_id));
1490 free(ap_id_log);
1491 ap_id_log = NULL;
1493 (void) strlcpy((*ap_id_list)->ap_phys_id, ap_id,
1494 sizeof ((*ap_id_list)->ap_phys_id));
1496 switch (devctl_ap_state.ap_rstate) {
1497 case AP_RSTATE_EMPTY:
1498 (*ap_id_list)->ap_r_state = CFGA_STAT_EMPTY;
1499 break;
1501 case AP_RSTATE_DISCONNECTED:
1502 (*ap_id_list)->ap_r_state = CFGA_STAT_DISCONNECTED;
1503 break;
1505 case AP_RSTATE_CONNECTED:
1506 (*ap_id_list)->ap_r_state = CFGA_STAT_CONNECTED;
1507 break;
1509 default:
1510 rv = CFGA_SATA_STATE;
1511 goto bailout;
1514 switch (devctl_ap_state.ap_ostate) {
1515 case AP_OSTATE_CONFIGURED:
1516 (*ap_id_list)->ap_o_state = CFGA_STAT_CONFIGURED;
1517 break;
1519 case AP_OSTATE_UNCONFIGURED:
1520 (*ap_id_list)->ap_o_state = CFGA_STAT_UNCONFIGURED;
1521 break;
1523 default:
1524 rv = CFGA_SATA_STATE;
1525 goto bailout;
1528 switch (devctl_ap_state.ap_condition) {
1529 case AP_COND_OK:
1530 (*ap_id_list)->ap_cond = CFGA_COND_OK;
1531 break;
1533 case AP_COND_FAILING:
1534 (*ap_id_list)->ap_cond = CFGA_COND_FAILING;
1535 break;
1537 case AP_COND_FAILED:
1538 (*ap_id_list)->ap_cond = CFGA_COND_FAILED;
1539 break;
1541 case AP_COND_UNUSABLE:
1542 (*ap_id_list)->ap_cond = CFGA_COND_UNUSABLE;
1543 break;
1545 case AP_COND_UNKNOWN:
1546 (*ap_id_list)->ap_cond = CFGA_COND_UNKNOWN;
1547 break;
1549 default:
1550 rv = CFGA_SATA_STATE;
1551 goto bailout;
1554 (*ap_id_list)->ap_class[0] = '\0'; /* Filled by libcfgadm */
1555 (*ap_id_list)->ap_busy = devctl_ap_state.ap_in_transition;
1556 (*ap_id_list)->ap_status_time = devctl_ap_state.ap_last_change;
1557 (*ap_id_list)->ap_info[0] = '\0';
1559 if ((*ap_id_list)->ap_r_state == CFGA_STAT_CONNECTED) {
1560 char *str_p;
1561 int skip, i;
1564 * Fill in the 'Information' field for the -v option
1565 * Model (MOD:)
1567 if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_MODEL_INFO,
1568 0, (void **)&str_p, &size)) != CFGA_SATA_OK) {
1569 (void) printf(
1570 "SATA_CFGA_GET_MODULE_INFO ioctl failed\n");
1571 goto bailout;
1573 /* drop leading and trailing spaces */
1574 skip = strspn(str_p, " ");
1575 for (i = size - 1; i >= 0; i--) {
1576 if (str_p[i] == '\040')
1577 str_p[i] = '\0';
1578 else if (str_p[i] != '\0')
1579 break;
1582 (void) strlcpy((*ap_id_list)->ap_info, "Mod: ",
1583 sizeof ((*ap_id_list)->ap_info));
1584 (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
1585 sizeof ((*ap_id_list)->ap_info));
1587 free(str_p);
1590 * Fill in the 'Information' field for the -v option
1591 * Firmware revision (FREV:)
1593 if ((rv = do_control_ioctl(ap_id,
1594 SATA_CFGA_GET_REVFIRMWARE_INFO,
1595 0, (void **)&str_p, &size)) != CFGA_SATA_OK) {
1596 (void) printf(
1597 "SATA_CFGA_GET_REVFIRMWARE_INFO ioctl failed\n");
1598 goto bailout;
1600 /* drop leading and trailing spaces */
1601 skip = strspn(str_p, " ");
1602 for (i = size - 1; i >= 0; i--) {
1603 if (str_p[i] == '\040')
1604 str_p[i] = '\0';
1605 else if (str_p[i] != '\0')
1606 break;
1608 (void) strlcat((*ap_id_list)->ap_info, " FRev: ",
1609 sizeof ((*ap_id_list)->ap_info));
1610 (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
1611 sizeof ((*ap_id_list)->ap_info));
1613 free(str_p);
1617 * Fill in the 'Information' field for the -v option
1618 * Serial Number (SN:)
1620 if ((rv = do_control_ioctl(ap_id,
1621 SATA_CFGA_GET_SERIALNUMBER_INFO,
1622 0, (void **)&str_p, &size)) != CFGA_SATA_OK) {
1623 (void) printf(
1624 "SATA_CFGA_GET_SERIALNUMBER_INFO ioctl failed\n");
1625 goto bailout;
1627 /* drop leading and trailing spaces */
1628 skip = strspn(str_p, " ");
1629 for (i = size - 1; i >= 0; i--) {
1630 if (str_p[i] == '\040')
1631 str_p[i] = '\0';
1632 else if (str_p[i] != '\0')
1633 break;
1635 (void) strlcat((*ap_id_list)->ap_info, " SN: ",
1636 sizeof ((*ap_id_list)->ap_info));
1637 (void) strlcat((*ap_id_list)->ap_info, str_p + skip,
1638 sizeof ((*ap_id_list)->ap_info));
1640 free(str_p);
1644 /* Fill in ap_type which is collected from HBA driver */
1645 /* call do_control_ioctl TBD */
1646 if ((rv = do_control_ioctl(ap_id, SATA_CFGA_GET_AP_TYPE, 0,
1647 (void **)&str_p, &size)) != CFGA_SATA_OK) {
1648 (void) printf(
1649 "SATA_CFGA_GET_AP_TYPE ioctl failed\n");
1650 goto bailout;
1653 (void) strlcpy((*ap_id_list)->ap_type, str_p,
1654 sizeof ((*ap_id_list)->ap_type));
1656 free(str_p);
1659 * Checking device type. Port multiplier has no dynamic
1660 * suffix.
1662 if (strncmp((*ap_id_list)->ap_type, "sata-pmult",
1663 sizeof ("sata-pmult")) == 0)
1664 pmult = B_TRUE;
1666 if ((*ap_id_list)->ap_o_state == CFGA_STAT_CONFIGURED &&
1667 pmult == B_FALSE) {
1669 char *dyncomp = NULL;
1672 * This is the case where we need to generate
1673 * a dynamic component of the ap_id, i.e. device.
1675 rv = sata_make_dyncomp(ap_id, &dyncomp,
1676 (*ap_id_list)->ap_type);
1677 if (rv != CFGA_SATA_OK)
1678 goto bailout;
1679 if (dyncomp != NULL) {
1680 (void) strcat((*ap_id_list)->ap_log_id,
1681 DYN_SEP);
1682 (void) strlcat((*ap_id_list)->ap_log_id,
1683 dyncomp,
1684 sizeof ((*ap_id_list)->ap_log_id));
1685 free(dyncomp);
1689 } else {
1690 /* This is an empty port */
1691 if (get_port_num(ap_id, &port) != CFGA_SATA_OK) {
1692 goto bailout;
1695 if (port & SATA_CFGA_PMPORT_QUAL) {
1696 (void) strlcpy((*ap_id_list)->ap_type, "pmult-port",
1697 sizeof ((*ap_id_list)->ap_type));
1698 } else {
1699 (void) strlcpy((*ap_id_list)->ap_type, "sata-port",
1700 sizeof ((*ap_id_list)->ap_type));
1704 return (sata_err_msg(errstring, rv, ap_id, errno));
1706 bailout:
1707 if (*ap_id_list != NULL) {
1708 free(*ap_id_list);
1710 if (ap_id_log != NULL) {
1711 free(ap_id_log);
1714 return (sata_err_msg(errstring, rv, ap_id, errno));
1717 * This routine accepts a string adn prints it using
1718 * the message print routine argument.
1720 static void
1721 cfga_msg(struct cfga_msg *msgp, const char *str)
1723 int len;
1724 char *q;
1726 if (msgp == NULL || msgp->message_routine == NULL) {
1727 (void) printf("cfga_msg: NULL msgp\n");
1728 return;
1731 if ((len = strlen(str)) == 0) {
1732 (void) printf("cfga_msg: null str\n");
1733 return;
1736 if ((q = (char *)calloc(len + 1, 1)) == NULL) {
1737 perror("cfga_msg");
1738 return;
1741 (void) strcpy(q, str);
1742 (*msgp->message_routine)(msgp->appdata_ptr, q);
1744 free(q);
1747 /* cfgadm entry point */
1748 /* ARGSUSED */
1749 cfga_err_t
1750 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
1752 if (options != NULL) {
1753 cfga_msg(msgp, dgettext(TEXT_DOMAIN, sata_help[HELP_UNKNOWN]));
1754 cfga_msg(msgp, options);
1756 cfga_msg(msgp, dgettext(TEXT_DOMAIN, sata_help[HELP_HEADER]));
1757 cfga_msg(msgp, sata_help[HELP_CONFIG]);
1758 cfga_msg(msgp, sata_help[HELP_RESET_PORT]);
1759 cfga_msg(msgp, sata_help[HELP_RESET_DEVICE]);
1760 cfga_msg(msgp, sata_help[HELP_RESET_ALL]);
1761 cfga_msg(msgp, sata_help[HELP_PORT_ACTIVATE]);
1762 cfga_msg(msgp, sata_help[HELP_PORT_DEACTIVATE]);
1763 cfga_msg(msgp, sata_help[HELP_PORT_SELF_TEST]);
1764 cfga_msg(msgp, sata_help[HELP_CNTRL_SELF_TEST]);
1766 return (CFGA_OK);
1771 * Ensure the ap_id passed is in the correct (physical ap_id) form:
1772 * path/device:xx[.xx]
1773 * where xx is a one or two-digit number.
1775 * Note the library always calls the plugin with a physical ap_id.
1777 static int
1778 verify_valid_apid(const char *ap_id)
1780 char *l_ap_id;
1782 if (ap_id == NULL)
1783 return (-1);
1785 l_ap_id = strrchr(ap_id, (int)*MINOR_SEP);
1786 l_ap_id++;
1788 if (strspn(l_ap_id, "0123456789.") != strlen(l_ap_id)) {
1789 /* Bad characters in the ap_id */
1790 return (-1);
1793 if (strstr(l_ap_id, "..") != NULL) {
1794 /* ap_id has 1..2 or more than 2 dots */
1795 return (-1);
1798 return (0);
1804 * Verify the params passed in are valid.
1806 static cfga_sata_ret_t
1807 verify_params(
1808 const char *ap_id,
1809 const char *options,
1810 char **errstring)
1812 char *pdyn, *lap_id;
1813 int rv;
1815 if (errstring != NULL) {
1816 *errstring = NULL;
1819 if (options != NULL) {
1820 return (CFGA_SATA_OPTIONS);
1823 /* Strip dynamic AP name component if it is present. */
1824 lap_id = strdup(ap_id);
1825 if (lap_id == NULL) {
1826 return (CFGA_SATA_ALLOC_FAIL);
1828 if ((pdyn = GET_DYN(lap_id)) != NULL) {
1829 *pdyn = '\0';
1832 if (verify_valid_apid(lap_id) != 0) {
1833 rv = CFGA_SATA_AP;
1834 } else {
1835 rv = CFGA_SATA_OK;
1837 free(lap_id);
1839 return (rv);
1843 * Takes a validated ap_id and extracts the port number.
1844 * Port multiplier is supported now.
1846 static cfga_sata_ret_t
1847 get_port_num(const char *ap_id, uint32_t *port)
1849 uint32_t cport, pmport = 0, qual = 0;
1850 char *cport_str, *pmport_str;
1852 /* Get the cport number */
1853 cport_str = strrchr(ap_id, (int)*MINOR_SEP) + strlen(MINOR_SEP);
1855 errno = 0;
1856 cport = strtol(cport_str, NULL, 10);
1857 if ((cport & ~SATA_CFGA_CPORT_MASK) != 0 || errno != 0) {
1858 return (CFGA_SATA_PORT);
1861 /* Get pmport number if there is a PORT_SEPARATOR */
1862 errno = 0;
1863 if ((pmport_str = strrchr(ap_id, (int)*PORT_SEPARATOR)) != 0) {
1864 pmport_str += strlen(PORT_SEPARATOR);
1865 pmport = strtol(pmport_str, NULL, 10);
1866 qual = SATA_CFGA_PMPORT_QUAL;
1867 if ((pmport & ~SATA_CFGA_PMPORT_MASK) != 0 || errno != 0) {
1868 return (CFGA_SATA_PORT);
1872 *port = cport | (pmport << SATA_CFGA_PMPORT_SHIFT) | qual;
1873 return (CFGA_SATA_OK);
1877 * Pair of routines to set up for/clean up after a devctl_ap_* lib call.
1879 static void
1880 cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist)
1882 nvlist_free(user_nvlist);
1883 devctl_release(devctl_hdl);
1886 static cfga_sata_ret_t
1887 setup_for_devctl_cmd(
1888 const char *ap_id,
1889 devctl_hdl_t *devctl_hdl,
1890 nvlist_t **user_nvlistp,
1891 uint_t oflag)
1894 uint_t port;
1895 cfga_sata_ret_t rv = CFGA_SATA_OK;
1896 char *lap_id, *pdyn;
1898 lap_id = strdup(ap_id);
1899 if (lap_id == NULL)
1900 return (CFGA_SATA_ALLOC_FAIL);
1901 if ((pdyn = GET_DYN(lap_id)) != NULL) {
1902 *pdyn = '\0';
1905 /* Get a devctl handle to pass to the devctl_ap_XXX functions */
1906 if ((*devctl_hdl = devctl_ap_acquire((char *)lap_id, oflag)) == NULL) {
1907 (void) fprintf(stderr, "[libcfgadm:sata] "
1908 "setup_for_devctl_cmd: devctl_ap_acquire failed: %s\n",
1909 strerror(errno));
1910 rv = CFGA_SATA_DEVCTL;
1911 goto bailout;
1914 /* Set up nvlist to pass the port number down to the driver */
1915 if (nvlist_alloc(user_nvlistp, NV_UNIQUE_NAME_TYPE, 0) != 0) {
1916 *user_nvlistp = NULL;
1917 rv = CFGA_SATA_NVLIST;
1918 (void) printf("nvlist_alloc failed\n");
1919 goto bailout;
1923 * Get port id, for Port Multiplier port, things could be a little bit
1924 * complicated because of "port.port" format in ap_id, thus for
1925 * port multiplier port, port number should be coded as 32bit int
1926 * with the sig 16 bit as sata channel number, least 16 bit as
1927 * the port number of sata port multiplier port.
1929 if ((rv = get_port_num(lap_id, &port)) != CFGA_SATA_OK) {
1930 (void) printf(
1931 "setup_for_devctl_cmd: get_port_num, errno: %d\n",
1932 errno);
1933 goto bailout;
1936 /* Creates an int32_t entry */
1937 if (nvlist_add_int32(*user_nvlistp, PORT, port) == -1) {
1938 (void) printf("nvlist_add_int32 failed\n");
1939 rv = CFGA_SATA_NVLIST;
1940 goto bailout;
1943 free(lap_id);
1944 return (rv);
1946 bailout:
1947 free(lap_id);
1948 (void) cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
1950 return (rv);
1954 static cfga_sata_ret_t
1955 port_state(devctl_hdl_t hdl, nvlist_t *list,
1956 ap_rstate_t *rstate, ap_ostate_t *ostate)
1958 devctl_ap_state_t devctl_ap_state;
1960 if (devctl_ap_getstate(hdl, list, &devctl_ap_state) == -1) {
1961 (void) printf("devctl_ap_getstate failed, errno: %d\n", errno);
1962 return (CFGA_SATA_IOCTL);
1964 *rstate = devctl_ap_state.ap_rstate;
1965 *ostate = devctl_ap_state.ap_ostate;
1966 return (CFGA_SATA_OK);
1971 * Given a subcommand to the DEVCTL_AP_CONTROL ioctl, rquest the size of
1972 * the data to be returned, allocate a buffer, then get the data.
1973 * Returns *descrp (which must be freed) and size.
1975 * Note SATA_DESCR_TYPE_STRING returns an ASCII NULL-terminated string,
1976 * not a string descr.
1978 cfga_sata_ret_t
1979 do_control_ioctl(const char *ap_id, sata_cfga_apctl_t subcommand, uint_t arg,
1980 void **descrp, size_t *sizep)
1982 int fd = -1;
1983 uint_t port;
1984 uint32_t local_size;
1985 cfga_sata_ret_t rv = CFGA_SATA_OK;
1986 struct sata_ioctl_data ioctl_data;
1988 assert(descrp != NULL);
1989 *descrp = NULL;
1990 assert(sizep != NULL);
1992 if ((rv = get_port_num(ap_id, &port)) != CFGA_SATA_OK) {
1993 goto bailout;
1996 if ((fd = open(ap_id, O_RDONLY)) == -1) {
1997 (void) printf("do_control_ioctl: open failed: errno:%d\n",
1998 errno);
1999 rv = CFGA_SATA_OPEN;
2000 if (errno == EBUSY) {
2001 rv = CFGA_SATA_BUSY;
2003 goto bailout;
2006 ioctl_data.cmd = subcommand;
2007 ioctl_data.port = port;
2008 ioctl_data.misc_arg = (uint_t)arg;
2011 * Find out how large a buf we need to get the data.
2012 * Note the ioctls only accept/return a 32-bit int for a get_size
2013 * to avoid 32/64 and BE/LE issues.
2015 if ((subcommand == SATA_CFGA_GET_AP_TYPE) ||
2016 (subcommand == SATA_CFGA_GET_DEVICE_PATH) ||
2017 (subcommand == SATA_CFGA_GET_MODEL_INFO) ||
2018 (subcommand == SATA_CFGA_GET_REVFIRMWARE_INFO) ||
2019 (subcommand == SATA_CFGA_GET_SERIALNUMBER_INFO)) {
2020 ioctl_data.get_size = B_TRUE;
2021 ioctl_data.buf = (caddr_t)&local_size;
2022 ioctl_data.bufsiz = sizeof (local_size);
2024 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
2025 perror("ioctl failed (size)");
2026 rv = CFGA_SATA_IOCTL;
2027 goto bailout;
2029 *sizep = local_size;
2031 if (local_size == 0) {
2032 (void) printf("zero length data\n");
2033 rv = CFGA_SATA_ZEROLEN;
2034 goto bailout;
2036 if ((*descrp = malloc(*sizep)) == NULL) {
2037 (void) printf("do_control_ioctl: malloc failed\n");
2038 rv = CFGA_SATA_ALLOC_FAIL;
2039 goto bailout;
2041 } else {
2042 *sizep = 0;
2044 ioctl_data.get_size = B_FALSE;
2045 ioctl_data.buf = *descrp;
2046 ioctl_data.bufsiz = *sizep;
2048 /* Execute IOCTL */
2050 if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
2051 rv = CFGA_SATA_IOCTL;
2052 goto bailout;
2055 (void) close(fd);
2057 return (rv);
2059 bailout:
2060 if (fd != -1) {
2061 (void) close(fd);
2063 if (*descrp != NULL) {
2064 free(*descrp);
2065 *descrp = NULL;
2068 if (rv == CFGA_SATA_IOCTL && errno == EBUSY) {
2069 rv = CFGA_SATA_BUSY;
2072 return (rv);
2076 static int
2077 sata_confirm(struct cfga_confirm *confp, char *msg)
2079 int rval;
2081 if (confp == NULL || confp->confirm == NULL) {
2082 return (0);
2084 rval = (*confp->confirm)(confp->appdata_ptr, msg);
2086 return (rval);
2090 static char *
2091 sata_get_devicepath(const char *ap_id)
2093 char *devpath = NULL;
2094 size_t size;
2095 cfga_sata_ret_t rv;
2097 rv = do_control_ioctl(ap_id, SATA_CFGA_GET_DEVICE_PATH, 0,
2098 (void **)&devpath, &size);
2100 if (rv == CFGA_SATA_OK) {
2101 return (devpath);
2102 } else {
2103 return (NULL);