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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/param.h>
32 #include "cfga_sata.h"
35 * This file contains the entry points to the plug-in as defined in the
36 * config_admin(3X) man page.
40 * Set the version number for the cfgadm library's use.
42 int cfga_version
= CFGA_HSL_V2
;
57 /* SATA specific help messages */
58 static char *sata_help
[] = {
60 "SATA specific commands:\n",
61 " cfgadm -c [configure|unconfigure|disconnect|connect] ap_id "
63 " cfgadm -x sata_reset_port ap_id [ap_id...]\n",
64 " cfgadm -x sata_reset_device ap_id [ap_id...]\n",
65 " cfgadm -x sata_reset_all ap_id\n",
66 " cfgadm -x sata_port_deactivate ap_id [ap_id...]\n",
67 " cfgadm -x sata_port_activate ap_id [ap_id...]\n",
68 " cfgadm -x sata_port_self_test ap_id [ap_id...]\n",
70 "\tunknown command or option:\n",
72 }; /* End help messages */
78 static msgcvt_t sata_msgs
[] = {
83 { CVT
, CFGA_NACK
, "" },
85 /* CFGA_SATA_DEVICE_UNCONFIGURED */
86 { CVT
, CFGA_OK
, "Device unconfigured prior to disconnect" },
88 /* CFGA_SATA_UNKNOWN / CFGA_LIB_ERROR -> "Library error" */
89 { CVT
, CFGA_LIB_ERROR
, "Unknown message; internal error" },
91 /* CFGA_SATA_INTERNAL_ERROR / CFGA_LIB_ERROR -> "Library error" */
92 { CVT
, CFGA_LIB_ERROR
, "Internal error" },
94 /* CFGA_SATA_DATA_ERROR / CFGA_DATA_ERROR -> "Data error" */
95 { CVT
, CFGA_DATA_ERROR
, "cfgadm data error" },
97 /* CFGA_SATA_OPTIONS / CFGA_ERROR -> "Hardware specific failure" */
98 { CVT
, CFGA_ERROR
, "Hardware specific option not supported" },
100 /* CFGA_SATA_HWOPNOTSUPP / CFGA_ERROR -> "Hardware specific failure" */
101 { CVT
, CFGA_ERROR
, "Hardware specific operation not supported" },
104 * CFGA_SATA_DYNAMIC_AP /
105 * CFGA_LIB_ERROR -> "Configuration operation invalid"
107 { CVT
, CFGA_INVAL
, "Cannot identify attached device" },
109 /* CFGA_SATA_AP / CFGA_APID_NOEXIST -> "Attachment point not found" */
110 { CVT
, CFGA_APID_NOEXIST
, "" },
112 /* CFGA_SATA_PORT / CFGA_LIB_ERROR -> "Library error" */
113 { CVT
, CFGA_LIB_ERROR
, "Cannot determine sata port number for " },
115 /* CFGA_SATA_DEVCTL / CFGA_LIB_ERROR -> "Library error" */
116 { CVT
, CFGA_LIB_ERROR
, "Internal error: "
117 "Cannot allocate devctl handle " },
120 * CFGA_SATA_DEV_CONFIGURE /
121 * CFGA_ERROR -> "Hardware specific failure"
123 { CVT
, CFGA_ERROR
, "Failed to config device at " },
126 * CFGA_SATA_DEV_UNCONFIGURE /
127 * CFGA_ERROR -> "Hardware specific failure"
129 { CVT
, CFGA_ERROR
, "Failed to unconfig device at " },
132 * CFGA_SATA_DISCONNECTED
133 * CFGA_INVAL -> "Configuration operation invalid"
135 { CVT
, CFGA_INVAL
, "Port already disconnected " },
138 * CFGA_SATA_NOT_CONNECTED
139 * CFGA_INVAL -> "Configuration operation invalid"
141 { CVT
, CFGA_INVAL
, "No device connected to " },
144 * CFGA_SATA_NOT_CONFIGURED /
145 * CFGA_INVAL -> "Configuration operation invalid"
147 { CVT
, CFGA_INVAL
, "No device configured at " },
150 * CFGA_SATA_ALREADY_CONNECTED /
151 * CFGA_INVAL -> "Configuration operation invalid"
153 { CVT
, CFGA_INVAL
, "Device already connected to " },
156 * CFGA_SATA_ALREADY_CONFIGURED /
157 * CFGA_INVAL -> "Configuration operation invalid"
159 { CVT
, CFGA_INVAL
, "Device already configured at " },
162 * CFGA_SATA_INVALID_DEVNAME /
163 * CFGA_INVAL -> "Configuration operation invalid"
165 { CVT
, CFGA_INVAL
, "Cannot specify device name" },
167 /* CFGA_SATA_OPEN / CFGA_LIB_ERROR -> "Library error" */
168 { CVT
, CFGA_LIB_ERROR
, "Cannot open " },
170 /* CFGA_SATA_IOCTL / CFGA_ERROR -> "Hardware specific failure" */
171 { CVT
, CFGA_ERROR
, "Driver ioctl failed " },
175 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
177 { CVT
, CFGA_SYSTEM_BUSY
, "" },
179 /* CFGA_SATA_ALLOC_FAIL / CFGA_LIB_ERROR -> "Library error" */
180 { CVT
, CFGA_LIB_ERROR
, "Memory allocation failure" },
183 * CFGA_SATA_OPNOTSUPP /
184 * CFGA_OPNOTSUPP -> "Configuration operation not supported"
186 { CVT
, CFGA_OPNOTSUPP
, "Operation not supported" },
188 /* CFGA_SATA_DEVLINK / CFGA_LIB_ERROR -> "Library error" */
189 { CVT
, CFGA_LIB_ERROR
, "Could not find /dev/cfg link for " },
191 /* CFGA_SATA_STATE / CFGA_LIB_ERROR -> "Library error" */
192 { CVT
, CFGA_LIB_ERROR
, "Internal error: Unrecognized ap state" },
194 /* CFGA_SATA_PRIV / CFGA_PRIV -> "Insufficient privileges" */
195 { CVT
, CFGA_PRIV
, "" },
197 /* CFGA_SATA_NVLIST / CFGA_ERROR -> "Hardware specific failure" */
198 { CVT
, CFGA_ERROR
, "Internal error (nvlist)" },
200 /* CFGA_SATA_ZEROLEN / CFGA_ERROR -> "Hardware specific failure" */
201 { CVT
, CFGA_ERROR
, "Internal error (zerolength string)" },
203 /* CFGA_SATA_RCM_HANDLE / CFGA_ERROR -> "Hardware specific failure" */
204 { CVT
, CFGA_ERROR
, "cannot get RCM handle"},
207 * CFGA_SATA_RCM_ONLINE /
208 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
210 { CVT
, CFGA_SYSTEM_BUSY
, "failed to online: "},
213 * CFGA_SATA_RCM_OFFLINE /
214 * CFGA_SYSTEM_BUSY -> "System is busy, try again"
216 { CVT
, CFGA_SYSTEM_BUSY
, "failed to offline: "},
218 /* CFGA_SATA_RCM_INFO / CFGA_ERROR -> "Hardware specific failure" */
219 { CVT
, CFGA_ERROR
, "failed to query: "}
221 }; /* End error messages */
223 static cfga_sata_ret_t
224 verify_params(const char *ap_id
, const char *options
, char **errstring
);
227 static cfga_sata_ret_t
228 setup_for_devctl_cmd(const char *ap_id
, devctl_hdl_t
*devctl_hdl
,
229 nvlist_t
**user_nvlistp
, uint_t oflag
);
231 static cfga_sata_ret_t
232 port_state(devctl_hdl_t hdl
, nvlist_t
*list
,
233 ap_rstate_t
*rstate
, ap_ostate_t
*ostate
);
235 static cfga_sata_ret_t
236 do_control_ioctl(const char *ap_id
, sata_cfga_apctl_t subcommand
, uint_t arg
,
237 void **descrp
, size_t *sizep
);
240 cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl
, nvlist_t
*user_nvlist
);
243 sata_get_devicepath(const char *ap_id
);
246 sata_confirm(struct cfga_confirm
*confp
, char *msg
);
248 static cfga_sata_ret_t
249 get_port_num(const char *ap_id
, uint32_t *port
);
253 static cfga_sata_ret_t
254 physpath_to_devlink(const char *basedir
, const char *node_path
,
255 char **logpp
, int *l_errnop
)
261 struct dirent
*dep
, *newdep
;
263 boolean_t found
= B_FALSE
;
267 cfga_sata_ret_t rv
= CFGA_SATA_INTERNAL_ERROR
;
270 * Using libdevinfo for this is overkill and kills performance
271 * when multiple consumers of libcfgadm are executing
274 if ((dp
= opendir(basedir
)) == NULL
) {
276 return (CFGA_SATA_INTERNAL_ERROR
);
279 linkpath
= malloc(PATH_MAX
);
280 buf
= malloc(PATH_MAX
);
281 real_path
= malloc(PATH_MAX
);
283 deplen
= pathconf(basedir
, _PC_NAME_MAX
);
284 deplen
= (deplen
<= 0 ? MAXNAMELEN
: deplen
) +
285 sizeof (struct dirent
);
286 dep
= (struct dirent
*)malloc(deplen
);
288 if (dep
== NULL
|| linkpath
== NULL
|| buf
== NULL
||
291 rv
= CFGA_SATA_ALLOC_FAIL
;
297 while (!found
&& (err
= readdir_r(dp
, dep
, &newdep
)) == 0 &&
300 assert(newdep
== dep
);
302 if (strcmp(dep
->d_name
, ".") == 0 ||
303 strcmp(dep
->d_name
, "..") == 0)
306 (void) snprintf(linkpath
, MAXPATHLEN
,
307 "%s/%s", basedir
, dep
->d_name
);
309 if (lstat(linkpath
, &sb
) < 0)
312 if (S_ISDIR(sb
.st_mode
)) {
314 if ((rv
= physpath_to_devlink(linkpath
, node_path
,
315 logpp
, l_errnop
)) != CFGA_SATA_OK
) {
323 } else if (S_ISLNK(sb
.st_mode
)) {
325 bzero(buf
, PATH_MAX
);
326 if (readlink(linkpath
, buf
, PATH_MAX
) < 0)
331 * realpath() is too darn slow, so fake
332 * it, by using what we know about /dev
333 * links: they are always of the form:
334 * <"../">+/devices/<path>
337 while (strncmp(p
, "../", 3) == 0)
341 p
--; /* back up to get a slash */
345 if (strcmp(p
, node_path
) == 0) {
346 *logpp
= strdup(linkpath
);
347 if (*logpp
== NULL
) {
349 rv
= CFGA_SATA_ALLOC_FAIL
;
366 return (CFGA_SATA_INTERNAL_ERROR
);
369 return (CFGA_SATA_OK
);
392 * Given the index into a table (msgcvt_t) of messages, get the message
393 * string, converting it to the proper locale if necessary.
394 * NOTE: Indexes are defined in cfga_sata.h
397 get_msg(uint_t msg_index
, msgcvt_t
*msg_tbl
, uint_t tbl_size
)
399 if (msg_index
>= tbl_size
) {
400 msg_index
= CFGA_SATA_UNKNOWN
;
403 return ((msg_tbl
[msg_index
].intl
) ?
404 dgettext(TEXT_DOMAIN
, msg_tbl
[msg_index
].msgstr
) :
405 msg_tbl
[msg_index
].msgstr
);
409 * Allocates and creates a message string (in *ret_str),
410 * by concatenating all the (char *) args together, in order.
411 * Last arg MUST be NULL.
414 set_msg(char **ret_str
, ...)
420 va_start(valist
, ret_str
);
422 total_len
= (*ret_str
== NULL
) ? 0 : strlen(*ret_str
);
424 while ((str
= va_arg(valist
, char *)) != NULL
) {
425 size_t len
= strlen(str
);
426 char *old_str
= *ret_str
;
428 *ret_str
= (char *)realloc(*ret_str
, total_len
+ len
+ 1);
429 if (*ret_str
== NULL
) {
436 (void) strcpy(*ret_str
+ total_len
, str
);
444 * Error message handling.
445 * For the rv passed in, looks up the corresponding error message string(s),
446 * internationalized if necessary, and concatenates it into a new
447 * memory buffer, and points *errstring to it.
448 * Note not all rvs will result in an error message return, as not all
449 * error conditions warrant a SATA-specific error message - for those
450 * conditions the cfgadm generic messages are sufficient.
452 * Some messages may display ap_id or errno, which is why they are passed
463 if (errstring
== NULL
) {
464 return (sata_msgs
[rv
].cfga_err
);
468 * Generate the appropriate SATA-specific error message(s) (if any).
473 /* Special case - do nothing. */
476 case CFGA_SATA_UNKNOWN
:
477 case CFGA_SATA_DYNAMIC_AP
:
478 case CFGA_SATA_INTERNAL_ERROR
:
479 case CFGA_SATA_OPTIONS
:
480 case CFGA_SATA_ALLOC_FAIL
:
481 case CFGA_SATA_STATE
:
483 case CFGA_SATA_OPNOTSUPP
:
484 case CFGA_SATA_DATA_ERROR
:
485 /* These messages require no additional strings passed. */
486 set_msg(errstring
, ERR_STR(rv
), NULL
);
489 case CFGA_SATA_HWOPNOTSUPP
:
490 /* hardware-specific help needed */
491 set_msg(errstring
, ERR_STR(rv
), NULL
);
492 set_msg(errstring
, "\n",
493 dgettext(TEXT_DOMAIN
, sata_help
[HELP_HEADER
]), NULL
);
494 set_msg(errstring
, sata_help
[HELP_RESET_PORT
], NULL
);
495 set_msg(errstring
, sata_help
[HELP_RESET_DEVICE
], NULL
);
496 set_msg(errstring
, sata_help
[HELP_RESET_ALL
], NULL
);
497 set_msg(errstring
, sata_help
[HELP_PORT_ACTIVATE
], NULL
);
498 set_msg(errstring
, sata_help
[HELP_PORT_DEACTIVATE
], NULL
);
499 set_msg(errstring
, sata_help
[HELP_PORT_SELF_TEST
], NULL
);
500 set_msg(errstring
, sata_help
[HELP_CNTRL_SELF_TEST
], NULL
);
505 case CFGA_SATA_NOT_CONNECTED
:
506 case CFGA_SATA_NOT_CONFIGURED
:
507 case CFGA_SATA_ALREADY_CONNECTED
:
508 case CFGA_SATA_ALREADY_CONFIGURED
:
510 case CFGA_SATA_DEVLINK
:
511 case CFGA_SATA_RCM_HANDLE
:
512 case CFGA_SATA_RCM_ONLINE
:
513 case CFGA_SATA_RCM_OFFLINE
:
514 case CFGA_SATA_RCM_INFO
:
515 case CFGA_SATA_DEV_CONFIGURE
:
516 case CFGA_SATA_DEV_UNCONFIGURE
:
517 case CFGA_SATA_DISCONNECTED
:
518 /* These messages also print ap_id. */
519 set_msg(errstring
, ERR_STR(rv
), "ap_id: ", ap_id
, "", NULL
);
523 case CFGA_SATA_IOCTL
:
524 case CFGA_SATA_NVLIST
:
525 /* These messages also print errno. */
527 char *errno_str
= l_errno
? strerror(l_errno
) : "";
529 set_msg(errstring
, ERR_STR(rv
), errno_str
,
530 l_errno
? "\n" : "", NULL
);
535 /* These messages also apid and errno. */
537 char *errno_str
= l_errno
? strerror(l_errno
) : "";
539 set_msg(errstring
, ERR_STR(rv
), "ap_id: ", ap_id
, "\n",
540 errno_str
, l_errno
? "\n" : "", NULL
);
545 set_msg(errstring
, ERR_STR(CFGA_SATA_INTERNAL_ERROR
), NULL
);
551 * Determine the proper error code to send back to the cfgadm library.
553 return (sata_msgs
[rv
].cfga_err
);
560 /* cfgadm entry point */
564 cfga_cmd_t state_change_cmd
,
567 struct cfga_confirm
*confp
,
568 struct cfga_msg
*msgp
,
576 nvlist_t
*nvl
= NULL
;
579 devctl_hdl_t hdl
= NULL
;
580 cfga_sata_ret_t rv
= CFGA_SATA_OK
;
584 boolean_t pmult
= B_FALSE
;
587 * All sub-commands which can change state of device require
590 if (geteuid() != 0) {
595 if ((rv
= verify_params(ap_id
, options
, errstring
)) != CFGA_SATA_OK
) {
596 (void) cfga_help(msgp
, options
, flags
);
600 if ((rv
= setup_for_devctl_cmd(ap_id
, &hdl
, &nvl
,
601 DC_RDONLY
)) != CFGA_SATA_OK
) {
606 * Checking device type. A port multiplier is not configurable - it is
607 * already configured as soon as it is connected.
609 if ((rv
= do_control_ioctl(ap_id
, SATA_CFGA_GET_AP_TYPE
, NULL
,
610 (void **)&str_type
, &size
)) != CFGA_SATA_OK
) {
614 if (strncmp(str_type
, "sata-pmult", sizeof ("sata-pmult")) == 0) {
618 switch (state_change_cmd
) {
619 case CFGA_CMD_CONFIGURE
:
620 if (pmult
== B_TRUE
) {
621 rv
= CFGA_SATA_HWOPNOTSUPP
;
625 if ((rv
= port_state(hdl
, nvl
, &rstate
, &ostate
)) !=
629 if (ostate
== AP_OSTATE_CONFIGURED
) {
630 rv
= CFGA_SATA_ALREADY_CONFIGURED
;
633 /* Disallow dynamic AP name component */
634 if (GET_DYN(ap_id
) != NULL
) {
635 rv
= CFGA_SATA_INVALID_DEVNAME
;
639 if (rstate
== AP_RSTATE_EMPTY
) {
640 rv
= CFGA_SATA_NOT_CONNECTED
;
645 if (devctl_ap_configure(hdl
, nvl
) != 0) {
646 rv
= CFGA_SATA_DEV_CONFIGURE
;
650 devpath
= sata_get_devicepath(ap_id
);
651 if (devpath
== NULL
) {
654 * Try for some time as SATA hotplug thread
655 * takes a while to create the path then
656 * eventually give up.
658 for (i
= 0; i
< 12 && (devpath
== NULL
); i
++) {
660 devpath
= sata_get_devicepath(ap_id
);
663 if (devpath
== NULL
) {
664 rv
= CFGA_SATA_DEV_CONFIGURE
;
672 case CFGA_CMD_UNCONFIGURE
:
673 if (pmult
== B_TRUE
) {
674 rv
= CFGA_SATA_HWOPNOTSUPP
;
678 if ((rv
= port_state(hdl
, nvl
, &rstate
, &ostate
)) !=
682 if (rstate
!= AP_RSTATE_CONNECTED
) {
683 rv
= CFGA_SATA_NOT_CONNECTED
;
687 if (ostate
!= AP_OSTATE_CONFIGURED
) {
688 rv
= CFGA_SATA_NOT_CONFIGURED
;
691 /* Strip off AP name dynamic component, if present */
692 if ((pdyn
= GET_DYN(ap_id
)) != NULL
) {
698 len
= strlen(SATA_CONFIRM_DEVICE
) +
699 strlen(SATA_CONFIRM_DEVICE_SUSPEND
) +
700 strlen("Unconfigure") + strlen(ap_id
);
701 if ((msg
= (char *)calloc(len
+3, 1)) != NULL
) {
702 (void) snprintf(msg
, len
+ 3, "Unconfigure"
704 SATA_CONFIRM_DEVICE
, ap_id
,
705 SATA_CONFIRM_DEVICE_SUSPEND
);
708 if (!sata_confirm(confp
, msg
)) {
715 devpath
= sata_get_devicepath(ap_id
);
716 if (devpath
== NULL
) {
718 "cfga_change_state: get device path failed\n");
719 rv
= CFGA_SATA_DEV_UNCONFIGURE
;
723 if ((rv
= sata_rcm_offline(ap_id
, errstring
, devpath
, flags
))
728 ret
= devctl_ap_unconfigure(hdl
, nvl
);
731 rv
= CFGA_SATA_DEV_UNCONFIGURE
;
732 if (errno
== EBUSY
) {
735 (void) sata_rcm_online(ap_id
, errstring
, devpath
,
738 (void) sata_rcm_remove(ap_id
, errstring
, devpath
,
746 case CFGA_CMD_DISCONNECT
:
747 if ((rv
= port_state(hdl
, nvl
, &rstate
, &ostate
)) !=
751 if (rstate
== AP_RSTATE_DISCONNECTED
) {
752 rv
= CFGA_SATA_DISCONNECTED
;
756 /* Strip off AP name dynamic component, if present */
757 if ((pdyn
= GET_DYN(ap_id
)) != NULL
) {
762 rv
= CFGA_SATA_OK
; /* other statuses don't matter */
765 * If the port originally with device attached and was
766 * unconfigured already, the devicepath for the sd will be
767 * removed. sata_get_devicepath in this case is not necessary.
769 /* only call rcm_offline if the state was CONFIGURED */
770 if (ostate
== AP_OSTATE_CONFIGURED
&&
772 devpath
= sata_get_devicepath(ap_id
);
773 if (devpath
== NULL
) {
775 "cfga_change_state: get path failed\n");
776 rv
= CFGA_SATA_DEV_UNCONFIGURE
;
780 len
= strlen(SATA_CONFIRM_DEVICE
) +
781 strlen(SATA_CONFIRM_DEVICE_SUSPEND
) +
782 strlen("Disconnect") + strlen(ap_id
);
783 if ((msg
= (char *)calloc(len
+3, 1)) != NULL
) {
784 (void) snprintf(msg
, len
+ 3,
787 SATA_CONFIRM_DEVICE
, ap_id
,
788 SATA_CONFIRM_DEVICE_SUSPEND
);
790 if (!sata_confirm(confp
, msg
)) {
797 if ((rv
= sata_rcm_offline(ap_id
, errstring
,
798 devpath
, flags
)) != CFGA_SATA_OK
) {
802 ret
= devctl_ap_unconfigure(hdl
, nvl
);
805 "devctl_ap_unconfigure failed\n");
806 rv
= CFGA_SATA_DEV_UNCONFIGURE
;
809 (void) sata_rcm_online(ap_id
, errstring
,
814 * The current policy is that if unconfigure
815 * failed, do not continue with disconnect.
816 * If the port needs to be forced into the
817 * disconnect (shutdown) state,
818 * the -x sata_port_poweroff command should be
819 * used instead of -c disconnect
823 (void) printf("%s\n",
824 ERR_STR(CFGA_SATA_DEVICE_UNCONFIGURED
));
825 (void) sata_rcm_remove(ap_id
, errstring
,
829 } else if (rstate
== AP_RSTATE_CONNECTED
||
830 rstate
== AP_RSTATE_EMPTY
) {
831 len
= strlen(SATA_CONFIRM_PORT
) +
832 strlen(SATA_CONFIRM_PORT_DISABLE
) +
833 strlen("Deactivate Port") + strlen(ap_id
);
834 if ((msg
= (char *)calloc(len
+3, 1)) != NULL
) {
835 (void) snprintf(msg
, len
+3,
838 SATA_CONFIRM_PORT
, ap_id
,
839 SATA_CONFIRM_PORT_DISABLE
);
841 if (!sata_confirm(confp
, msg
)) {
847 ret
= devctl_ap_disconnect(hdl
, nvl
);
849 rv
= CFGA_SATA_IOCTL
;
850 if (errno
== EBUSY
) {
856 case CFGA_CMD_CONNECT
:
857 if ((rv
= port_state(hdl
, nvl
, &rstate
, &ostate
)) !=
861 if (rstate
== AP_RSTATE_CONNECTED
) {
862 rv
= CFGA_SATA_ALREADY_CONNECTED
;
866 len
= strlen(SATA_CONFIRM_PORT
) +
867 strlen(SATA_CONFIRM_PORT_ENABLE
) +
868 strlen("Activate Port") + strlen(ap_id
);
869 if ((msg
= (char *)calloc(len
+3, 1)) != NULL
) {
870 (void) snprintf(msg
, len
+3, "Activate"
872 SATA_CONFIRM_PORT
, ap_id
,
873 SATA_CONFIRM_PORT_ENABLE
);
875 if (!sata_confirm(confp
, msg
)) {
880 /* Disallow dynamic AP name component */
881 if (GET_DYN(ap_id
) != NULL
) {
882 rv
= CFGA_SATA_INVALID_DEVNAME
;
886 ret
= devctl_ap_connect(hdl
, nvl
);
888 rv
= CFGA_SATA_IOCTL
;
896 case CFGA_CMD_UNLOAD
:
897 (void) cfga_help(msgp
, options
, flags
);
898 rv
= CFGA_SATA_OPNOTSUPP
;
903 (void) cfga_help(msgp
, options
, flags
);
904 rv
= CFGA_SATA_INTERNAL_ERROR
;
908 cleanup_after_devctl_cmd(hdl
, nvl
);
910 return (sata_err_msg(errstring
, rv
, ap_id
, errno
));
913 /* cfgadm entry point */
919 struct cfga_confirm
*confp
,
920 struct cfga_msg
*msgp
,
926 nvlist_t
*list
= NULL
;
929 devctl_hdl_t hdl
= NULL
;
934 if ((rv
= verify_params(ap_id
, NULL
, errstring
)) != CFGA_SATA_OK
) {
935 (void) cfga_help(msgp
, options
, flags
);
936 return (sata_err_msg(errstring
, rv
, ap_id
, errno
));
940 * All subcommands which can change state of device require
943 if (geteuid() != 0) {
949 (void) printf("No valid option specified\n");
950 rv
= CFGA_SATA_OPTIONS
;
954 if ((rv
= setup_for_devctl_cmd(ap_id
, &hdl
, &list
, 0)) !=
959 /* We do not care here about dynamic AP name component */
960 if ((str_p
= GET_DYN(ap_id
)) != NULL
) {
966 if (strcmp(func
, SATA_RESET_PORT
) == 0) {
967 len
= strlen(SATA_CONFIRM_PORT
) +
968 strlen(SATA_CONFIRM_DEVICE_ABORT
) +
969 strlen("Reset Port") + strlen(ap_id
);
971 if ((msg
= (char *)calloc(len
+3, 1)) != NULL
) {
972 (void) snprintf(msg
, len
+3, "Reset"
974 SATA_CONFIRM_PORT
, ap_id
,
975 SATA_CONFIRM_DEVICE_ABORT
);
981 if (!sata_confirm(confp
, msg
)) {
986 rv
= do_control_ioctl(ap_id
, SATA_CFGA_RESET_PORT
, NULL
,
987 (void **)&str_p
, &size
);
989 } else if (strcmp(func
, SATA_RESET_DEVICE
) == 0) {
990 if ((rv
= port_state(hdl
, list
, &rstate
, &ostate
)) !=
994 * Reset device function requires device to be connected
996 if (rstate
!= AP_RSTATE_CONNECTED
) {
997 rv
= CFGA_SATA_NOT_CONNECTED
;
1001 len
= strlen(SATA_CONFIRM_DEVICE
) +
1002 strlen(SATA_CONFIRM_DEVICE_ABORT
) +
1003 strlen("Reset Device") + strlen(ap_id
);
1005 if ((msg
= (char *)calloc(len
+3, 1)) != NULL
) {
1006 (void) snprintf(msg
, len
+3, "Reset"
1008 SATA_CONFIRM_DEVICE
, ap_id
,
1009 SATA_CONFIRM_DEVICE_ABORT
);
1011 rv
= CFGA_SATA_NACK
;
1015 if (!sata_confirm(confp
, msg
)) {
1016 rv
= CFGA_SATA_NACK
;
1020 rv
= do_control_ioctl(ap_id
, SATA_CFGA_RESET_DEVICE
, NULL
,
1021 (void **)&str_p
, &size
);
1023 } else if (strcmp(func
, SATA_RESET_ALL
) == 0) {
1024 len
= strlen(SATA_CONFIRM_CONTROLLER
) +
1025 strlen(SATA_CONFIRM_CONTROLLER_ABORT
) +
1026 strlen("Reset All") + strlen(ap_id
);
1028 if ((msg
= (char *)calloc(len
+3, 1)) != NULL
) {
1029 (void) snprintf(msg
, len
+3, "Reset"
1031 SATA_CONFIRM_CONTROLLER
, ap_id
,
1032 SATA_CONFIRM_CONTROLLER_ABORT
);
1034 rv
= CFGA_SATA_NACK
;
1038 if (!sata_confirm(confp
, msg
)) {
1039 rv
= CFGA_SATA_NACK
;
1042 rv
= do_control_ioctl(ap_id
, SATA_CFGA_RESET_ALL
, NULL
,
1043 (void **)&str_p
, &size
);
1045 } else if (strcmp(func
, SATA_PORT_DEACTIVATE
) == 0) {
1046 len
= strlen(SATA_CONFIRM_PORT
) +
1047 strlen(SATA_CONFIRM_PORT_DISABLE
) +
1048 strlen("Deactivate Port") + strlen(ap_id
);
1050 if ((msg
= (char *)calloc(len
+3, 1)) != NULL
) {
1051 (void) snprintf(msg
, len
+3, "Deactivate"
1053 SATA_CONFIRM_PORT
, ap_id
,
1054 SATA_CONFIRM_PORT_DISABLE
);
1056 rv
= CFGA_SATA_NACK
;
1059 if (!sata_confirm(confp
, msg
)) {
1060 rv
= CFGA_SATA_NACK
;
1064 rv
= do_control_ioctl(ap_id
, SATA_CFGA_PORT_DEACTIVATE
, NULL
,
1065 (void **)&str_p
, &size
);
1067 } else if (strcmp(func
, SATA_PORT_ACTIVATE
) == 0) {
1068 len
= strlen(SATA_CONFIRM_PORT
) +
1069 strlen(SATA_CONFIRM_PORT_ENABLE
) +
1070 strlen("Activate Port") + strlen(ap_id
);
1072 if ((msg
= (char *)calloc(len
+3, 1)) != NULL
) {
1073 (void) snprintf(msg
, len
+3, "Activate"
1075 SATA_CONFIRM_PORT
, ap_id
,
1076 SATA_CONFIRM_PORT_ENABLE
);
1078 rv
= CFGA_SATA_NACK
;
1081 if (!sata_confirm(confp
, msg
)) {
1082 rv
= CFGA_SATA_NACK
;
1086 rv
= do_control_ioctl(ap_id
, SATA_CFGA_PORT_ACTIVATE
,
1087 NULL
, (void **)&str_p
, &size
);
1090 } else if (strcmp(func
, SATA_PORT_SELF_TEST
) == 0) {
1091 len
= strlen(SATA_CONFIRM_PORT
) +
1092 strlen(SATA_CONFIRM_DEVICE_SUSPEND
) +
1093 strlen("Self Test Port") + strlen(ap_id
);
1095 if ((msg
= (char *)calloc(len
+3, 1)) != NULL
) {
1096 (void) snprintf(msg
, len
+3, "Self Test"
1098 SATA_CONFIRM_PORT
, ap_id
,
1099 SATA_CONFIRM_DEVICE_SUSPEND
);
1101 rv
= CFGA_SATA_NACK
;
1104 if (!sata_confirm(confp
, msg
)) {
1105 rv
= CFGA_SATA_NACK
;
1109 rv
= do_control_ioctl(ap_id
, SATA_CFGA_PORT_SELF_TEST
,
1110 NULL
, (void **)&str_p
, &size
);
1112 /* Unrecognized operation request */
1113 rv
= CFGA_SATA_HWOPNOTSUPP
;
1117 cleanup_after_devctl_cmd(hdl
, list
);
1119 return (sata_err_msg(errstring
, rv
, ap_id
, errno
));
1123 /* cfgadm entry point */
1128 const char *options
,
1129 struct cfga_msg
*msgp
,
1133 /* Should call ioctl for self test - phase 2 */
1134 return (CFGA_OPNOTSUPP
);
1139 sata_check_target_node(di_node_t node
, void *arg
)
1144 minorpath
= di_devfs_minor_path(di_minor_next(node
, DI_MINOR_NIL
));
1145 if (minorpath
!= NULL
) {
1146 if (strstr(minorpath
, arg
) != NULL
) {
1147 cp
= strrchr(minorpath
, (int)*MINOR_SEP
);
1149 (void) strcpy(arg
, cp
);
1152 return (DI_WALK_TERMINATE
);
1156 return (DI_WALK_CONTINUE
);
1166 chk_dev_fcn(di_node_t node
, di_minor_t minor
, void *arg
)
1169 struct chk_dev
*chkp
= (struct chk_dev
*)arg
;
1171 mn
= di_minor_name(minor
);
1173 return (DI_WALK_CONTINUE
);
1175 if (strcmp(mn
, chkp
->c_minor
) != 0)
1176 return (DI_WALK_CONTINUE
);
1178 chkp
->c_isblk
= di_minor_spectype(minor
) == S_IFBLK
? 1 : 0;
1180 return (DI_WALK_TERMINATE
);
1184 * Don't use devfs if stat() in /devices fails. Use libdevinfo instead.
1185 * Retired devices don't show up in devfs.
1188 * 1 - minor exists and is of type BLK
1189 * 0 - minor does not exist or is not of type BLK.
1192 is_devinfo_blk(char *minor_path
)
1194 char *minor_portion
;
1195 struct chk_dev chk_dev
;
1200 * prune minor path for di_init() - no /devices prefix and no minor name
1202 if (strncmp(minor_path
, "/devices/", strlen("/devices/")) != 0)
1205 minor_portion
= strrchr(minor_path
, *MINOR_SEP
);
1206 if (minor_portion
== NULL
)
1211 node
= di_init(minor_path
+ strlen("/devices"), DINFOMINOR
);
1213 *minor_portion
= *MINOR_SEP
;
1215 if (node
== DI_NODE_NIL
)
1218 chk_dev
.c_isblk
= 0;
1219 chk_dev
.c_minor
= minor_portion
+ 1;
1221 rv
= di_walk_minor(node
, NULL
, 0, &chk_dev
, chk_dev_fcn
);
1225 if (rv
== 0 && chk_dev
.c_isblk
)
1232 * The dynamic component buffer returned by this function has to be freed!
1235 sata_make_dyncomp(const char *ap_id
, char **dyncomp
, const char *type
)
1237 char *devpath
= NULL
;
1240 char minor_path
[MAXPATHLEN
];
1241 char name_part
[MAXNAMELEN
];
1242 char *devlink
= NULL
;
1243 char *minor_portion
= NULL
;
1248 struct dirent
*dep
= NULL
;
1249 struct dirent
*newdep
= NULL
;
1252 assert(dyncomp
!= NULL
);
1255 * Get target node path
1257 devpath
= sata_get_devicepath(ap_id
);
1258 if (devpath
== NULL
) {
1260 (void) printf("cfga_list_ext: cannot locate target device\n");
1261 return (CFGA_SATA_DYNAMIC_AP
);
1265 cp
= strrchr(devpath
, *PATH_SEP
);
1267 *cp
= 0; /* terminate path for opendir() */
1269 (void) strncpy(name_part
, cp
+ 1, MAXNAMELEN
);
1272 * Using libdevinfo for this is overkill and kills
1273 * performance when many consumers are using libcfgadm
1276 if ((dp
= opendir(devpath
)) == NULL
) {
1281 * deplen is large enough to fit the largest path-
1282 * struct dirent includes one byte (the terminator)
1283 * so we don't add 1 to the calculation here.
1285 deplen
= pathconf(devpath
, _PC_NAME_MAX
);
1286 deplen
= ((deplen
<= 0) ? MAXNAMELEN
: deplen
) +
1287 sizeof (struct dirent
);
1288 dep
= (struct dirent
*)malloc(deplen
);
1292 while ((err
= readdir_r(dp
, dep
, &newdep
)) == 0 &&
1295 assert(newdep
== dep
);
1297 if (strcmp(dep
->d_name
, ".") == 0 ||
1298 strcmp(dep
->d_name
, "..") == 0 ||
1299 (minor_portion
= strchr(dep
->d_name
,
1300 *MINOR_SEP
)) == NULL
)
1304 if (strcmp(dep
->d_name
, name_part
) != 0)
1306 *minor_portion
= *MINOR_SEP
;
1308 (void) snprintf(minor_path
, MAXPATHLEN
,
1309 "%s/%s", devpath
, dep
->d_name
);
1312 * Break directly for tape device
1314 if (strcmp(type
, "tape") == 0)
1318 * If stat() fails, the device *may* be retired.
1319 * Check via libdevinfo if the device has a BLK minor.
1320 * We don't use libdevinfo all the time, since taking
1321 * a snapshot is slower than a stat().
1323 if (stat(minor_path
, &sb
) < 0) {
1324 if (is_devinfo_blk(minor_path
)) {
1331 if (S_ISBLK(sb
.st_mode
))
1336 (void) closedir(dp
);
1345 * If there was an error, or we didn't exit the loop
1346 * by finding a block or character device, bail out.
1348 if (err
!= 0 || newdep
== NULL
)
1352 * Look for links to the physical path in /dev/dsk
1353 * and /dev/rmt. So far, sata modue supports disk,
1354 * dvd and tape devices, so we will first look for
1355 * BLOCK devices, and then look for tape devices.
1357 (void) physpath_to_devlink("/dev/dsk",
1358 minor_path
, &devlink
, &l_errno
);
1360 /* postprocess and copy logical name here */
1361 if (devlink
!= NULL
) {
1363 * For disks, remove partition/slice info
1365 if ((cp
= strstr(devlink
, "dsk/")) != NULL
) {
1366 /* cXtYdZ[(s[0..15])|(p[0..X])] */
1367 if ((p
= strchr(cp
+ 4, 'd')) != NULL
) {
1368 p
++; /* Skip the 'd' */
1369 while (*p
!= 0 && isdigit(*p
))
1373 *dyncomp
= strdup(cp
);
1377 } else if (strcmp(type
, "tape") == 0) {
1380 * For tape device, logical name looks like
1383 (void) physpath_to_devlink("/dev/rmt",
1384 minor_path
, &devlink
, &l_errno
);
1386 if (devlink
!= NULL
) {
1387 if ((cp
= strstr(devlink
, "rmt/")) != NULL
) {
1388 *dyncomp
= strdup(cp
);
1395 return (SATA_CFGA_OK
);
1400 (void) closedir(dp
);
1405 return (CFGA_SATA_DYNAMIC_AP
);
1408 /* cfgadm entry point */
1413 cfga_list_data_t
**ap_id_list
,
1415 const char *options
,
1416 const char *listopts
,
1421 char *ap_id_log
= NULL
;
1423 nvlist_t
*user_nvlist
= NULL
;
1424 devctl_hdl_t devctl_hdl
= NULL
;
1425 cfga_sata_ret_t rv
= CFGA_SATA_OK
;
1426 devctl_ap_state_t devctl_ap_state
;
1428 boolean_t pmult
= B_FALSE
;
1432 if ((rv
= verify_params(ap_id
, options
, errstring
)) != CFGA_SATA_OK
) {
1433 (void) cfga_help(NULL
, options
, flags
);
1436 /* We do not care here about dynamic AP name component */
1437 if ((pdyn
= GET_DYN(ap_id
)) != NULL
) {
1441 if (ap_id_list
== NULL
|| nlistp
== NULL
) {
1442 rv
= CFGA_SATA_DATA_ERROR
;
1443 (void) cfga_help(NULL
, options
, flags
);
1448 if ((rv
= setup_for_devctl_cmd(ap_id
, &devctl_hdl
, &user_nvlist
,
1449 DC_RDONLY
)) != CFGA_SATA_OK
) {
1453 /* will call dc_cmd to send IOCTL to kernel */
1454 if (devctl_ap_getstate(devctl_hdl
, user_nvlist
,
1455 &devctl_ap_state
) == -1) {
1456 cleanup_after_devctl_cmd(devctl_hdl
, user_nvlist
);
1457 rv
= CFGA_SATA_IOCTL
;
1461 cleanup_after_devctl_cmd(devctl_hdl
, user_nvlist
);
1464 * Create cfga_list_data_t struct.
1467 (cfga_list_data_t
*)malloc(sizeof (**ap_id_list
))) == NULL
) {
1468 rv
= CFGA_SATA_ALLOC_FAIL
;
1474 * Rest of the code fills in the cfga_list_data_t struct.
1477 /* Get /dev/cfg path to corresponding to the physical ap_id */
1478 /* Remember ap_id_log must be freed */
1479 rv
= physpath_to_devlink(CFGA_DEV_DIR
, (char *)ap_id
,
1480 &ap_id_log
, &l_errno
);
1483 rv
= CFGA_SATA_DEVLINK
;
1487 /* Get logical ap_id corresponding to the physical */
1488 if (ap_id_log
== NULL
|| strstr(ap_id_log
, CFGA_DEV_DIR
) == NULL
) {
1489 rv
= CFGA_SATA_DEVLINK
;
1493 (void) strlcpy((*ap_id_list
)->ap_log_id
,
1494 /* Strip off /dev/cfg/ */ ap_id_log
+ strlen(CFGA_DEV_DIR
)+ 1,
1495 sizeof ((*ap_id_list
)->ap_log_id
));
1500 (void) strlcpy((*ap_id_list
)->ap_phys_id
, ap_id
,
1501 sizeof ((*ap_id_list
)->ap_phys_id
));
1503 switch (devctl_ap_state
.ap_rstate
) {
1504 case AP_RSTATE_EMPTY
:
1505 (*ap_id_list
)->ap_r_state
= CFGA_STAT_EMPTY
;
1508 case AP_RSTATE_DISCONNECTED
:
1509 (*ap_id_list
)->ap_r_state
= CFGA_STAT_DISCONNECTED
;
1512 case AP_RSTATE_CONNECTED
:
1513 (*ap_id_list
)->ap_r_state
= CFGA_STAT_CONNECTED
;
1517 rv
= CFGA_SATA_STATE
;
1521 switch (devctl_ap_state
.ap_ostate
) {
1522 case AP_OSTATE_CONFIGURED
:
1523 (*ap_id_list
)->ap_o_state
= CFGA_STAT_CONFIGURED
;
1526 case AP_OSTATE_UNCONFIGURED
:
1527 (*ap_id_list
)->ap_o_state
= CFGA_STAT_UNCONFIGURED
;
1531 rv
= CFGA_SATA_STATE
;
1535 switch (devctl_ap_state
.ap_condition
) {
1537 (*ap_id_list
)->ap_cond
= CFGA_COND_OK
;
1540 case AP_COND_FAILING
:
1541 (*ap_id_list
)->ap_cond
= CFGA_COND_FAILING
;
1544 case AP_COND_FAILED
:
1545 (*ap_id_list
)->ap_cond
= CFGA_COND_FAILED
;
1548 case AP_COND_UNUSABLE
:
1549 (*ap_id_list
)->ap_cond
= CFGA_COND_UNUSABLE
;
1552 case AP_COND_UNKNOWN
:
1553 (*ap_id_list
)->ap_cond
= CFGA_COND_UNKNOWN
;
1557 rv
= CFGA_SATA_STATE
;
1561 (*ap_id_list
)->ap_class
[0] = '\0'; /* Filled by libcfgadm */
1562 (*ap_id_list
)->ap_busy
= devctl_ap_state
.ap_in_transition
;
1563 (*ap_id_list
)->ap_status_time
= devctl_ap_state
.ap_last_change
;
1564 (*ap_id_list
)->ap_info
[0] = NULL
;
1566 if ((*ap_id_list
)->ap_r_state
== CFGA_STAT_CONNECTED
) {
1571 * Fill in the 'Information' field for the -v option
1574 if ((rv
= do_control_ioctl(ap_id
, SATA_CFGA_GET_MODEL_INFO
,
1575 NULL
, (void **)&str_p
, &size
)) != CFGA_SATA_OK
) {
1577 "SATA_CFGA_GET_MODULE_INFO ioctl failed\n");
1580 /* drop leading and trailing spaces */
1581 skip
= strspn(str_p
, " ");
1582 for (i
= size
- 1; i
>= 0; i
--) {
1583 if (str_p
[i
] == '\040')
1585 else if (str_p
[i
] != '\0')
1589 (void) strlcpy((*ap_id_list
)->ap_info
, "Mod: ",
1590 sizeof ((*ap_id_list
)->ap_info
));
1591 (void) strlcat((*ap_id_list
)->ap_info
, str_p
+ skip
,
1592 sizeof ((*ap_id_list
)->ap_info
));
1597 * Fill in the 'Information' field for the -v option
1598 * Firmware revision (FREV:)
1600 if ((rv
= do_control_ioctl(ap_id
,
1601 SATA_CFGA_GET_REVFIRMWARE_INFO
,
1602 NULL
, (void **)&str_p
, &size
)) != CFGA_SATA_OK
) {
1604 "SATA_CFGA_GET_REVFIRMWARE_INFO ioctl failed\n");
1607 /* drop leading and trailing spaces */
1608 skip
= strspn(str_p
, " ");
1609 for (i
= size
- 1; i
>= 0; i
--) {
1610 if (str_p
[i
] == '\040')
1612 else if (str_p
[i
] != '\0')
1615 (void) strlcat((*ap_id_list
)->ap_info
, " FRev: ",
1616 sizeof ((*ap_id_list
)->ap_info
));
1617 (void) strlcat((*ap_id_list
)->ap_info
, str_p
+ skip
,
1618 sizeof ((*ap_id_list
)->ap_info
));
1624 * Fill in the 'Information' field for the -v option
1625 * Serial Number (SN:)
1627 if ((rv
= do_control_ioctl(ap_id
,
1628 SATA_CFGA_GET_SERIALNUMBER_INFO
,
1629 NULL
, (void **)&str_p
, &size
)) != CFGA_SATA_OK
) {
1631 "SATA_CFGA_GET_SERIALNUMBER_INFO ioctl failed\n");
1634 /* drop leading and trailing spaces */
1635 skip
= strspn(str_p
, " ");
1636 for (i
= size
- 1; i
>= 0; i
--) {
1637 if (str_p
[i
] == '\040')
1639 else if (str_p
[i
] != '\0')
1642 (void) strlcat((*ap_id_list
)->ap_info
, " SN: ",
1643 sizeof ((*ap_id_list
)->ap_info
));
1644 (void) strlcat((*ap_id_list
)->ap_info
, str_p
+ skip
,
1645 sizeof ((*ap_id_list
)->ap_info
));
1651 /* Fill in ap_type which is collected from HBA driver */
1652 /* call do_control_ioctl TBD */
1653 if ((rv
= do_control_ioctl(ap_id
, SATA_CFGA_GET_AP_TYPE
, NULL
,
1654 (void **)&str_p
, &size
)) != CFGA_SATA_OK
) {
1656 "SATA_CFGA_GET_AP_TYPE ioctl failed\n");
1660 (void) strlcpy((*ap_id_list
)->ap_type
, str_p
,
1661 sizeof ((*ap_id_list
)->ap_type
));
1666 * Checking device type. Port multiplier has no dynamic
1669 if (strncmp((*ap_id_list
)->ap_type
, "sata-pmult",
1670 sizeof ("sata-pmult")) == 0)
1673 if ((*ap_id_list
)->ap_o_state
== CFGA_STAT_CONFIGURED
&&
1676 char *dyncomp
= NULL
;
1679 * This is the case where we need to generate
1680 * a dynamic component of the ap_id, i.e. device.
1682 rv
= sata_make_dyncomp(ap_id
, &dyncomp
,
1683 (*ap_id_list
)->ap_type
);
1684 if (rv
!= CFGA_SATA_OK
)
1686 if (dyncomp
!= NULL
) {
1687 (void) strcat((*ap_id_list
)->ap_log_id
,
1689 (void) strlcat((*ap_id_list
)->ap_log_id
,
1691 sizeof ((*ap_id_list
)->ap_log_id
));
1697 /* This is an empty port */
1698 if (get_port_num(ap_id
, &port
) != CFGA_SATA_OK
) {
1702 if (port
& SATA_CFGA_PMPORT_QUAL
) {
1703 (void) strlcpy((*ap_id_list
)->ap_type
, "pmult-port",
1704 sizeof ((*ap_id_list
)->ap_type
));
1706 (void) strlcpy((*ap_id_list
)->ap_type
, "sata-port",
1707 sizeof ((*ap_id_list
)->ap_type
));
1711 return (sata_err_msg(errstring
, rv
, ap_id
, errno
));
1714 if (*ap_id_list
!= NULL
) {
1717 if (ap_id_log
!= NULL
) {
1721 return (sata_err_msg(errstring
, rv
, ap_id
, errno
));
1724 * This routine accepts a string adn prints it using
1725 * the message print routine argument.
1728 cfga_msg(struct cfga_msg
*msgp
, const char *str
)
1733 if (msgp
== NULL
|| msgp
->message_routine
== NULL
) {
1734 (void) printf("cfga_msg: NULL msgp\n");
1738 if ((len
= strlen(str
)) == 0) {
1739 (void) printf("cfga_msg: null str\n");
1743 if ((q
= (char *)calloc(len
+ 1, 1)) == NULL
) {
1748 (void) strcpy(q
, str
);
1749 (*msgp
->message_routine
)(msgp
->appdata_ptr
, q
);
1754 /* cfgadm entry point */
1757 cfga_help(struct cfga_msg
*msgp
, const char *options
, cfga_flags_t flags
)
1759 if (options
!= NULL
) {
1760 cfga_msg(msgp
, dgettext(TEXT_DOMAIN
, sata_help
[HELP_UNKNOWN
]));
1761 cfga_msg(msgp
, options
);
1763 cfga_msg(msgp
, dgettext(TEXT_DOMAIN
, sata_help
[HELP_HEADER
]));
1764 cfga_msg(msgp
, sata_help
[HELP_CONFIG
]);
1765 cfga_msg(msgp
, sata_help
[HELP_RESET_PORT
]);
1766 cfga_msg(msgp
, sata_help
[HELP_RESET_DEVICE
]);
1767 cfga_msg(msgp
, sata_help
[HELP_RESET_ALL
]);
1768 cfga_msg(msgp
, sata_help
[HELP_PORT_ACTIVATE
]);
1769 cfga_msg(msgp
, sata_help
[HELP_PORT_DEACTIVATE
]);
1770 cfga_msg(msgp
, sata_help
[HELP_PORT_SELF_TEST
]);
1771 cfga_msg(msgp
, sata_help
[HELP_CNTRL_SELF_TEST
]);
1778 * Ensure the ap_id passed is in the correct (physical ap_id) form:
1779 * path/device:xx[.xx]
1780 * where xx is a one or two-digit number.
1782 * Note the library always calls the plugin with a physical ap_id.
1785 verify_valid_apid(const char *ap_id
)
1792 l_ap_id
= strrchr(ap_id
, (int)*MINOR_SEP
);
1795 if (strspn(l_ap_id
, "0123456789.") != strlen(l_ap_id
)) {
1796 /* Bad characters in the ap_id */
1800 if (strstr(l_ap_id
, "..") != NULL
) {
1801 /* ap_id has 1..2 or more than 2 dots */
1811 * Verify the params passed in are valid.
1813 static cfga_sata_ret_t
1816 const char *options
,
1819 char *pdyn
, *lap_id
;
1822 if (errstring
!= NULL
) {
1826 if (options
!= NULL
) {
1827 return (CFGA_SATA_OPTIONS
);
1830 /* Strip dynamic AP name component if it is present. */
1831 lap_id
= strdup(ap_id
);
1832 if (lap_id
== NULL
) {
1833 return (CFGA_SATA_ALLOC_FAIL
);
1835 if ((pdyn
= GET_DYN(lap_id
)) != NULL
) {
1839 if (verify_valid_apid(lap_id
) != 0) {
1850 * Takes a validated ap_id and extracts the port number.
1851 * Port multiplier is supported now.
1853 static cfga_sata_ret_t
1854 get_port_num(const char *ap_id
, uint32_t *port
)
1856 uint32_t cport
, pmport
= 0, qual
= 0;
1857 char *cport_str
, *pmport_str
;
1859 /* Get the cport number */
1860 cport_str
= strrchr(ap_id
, (int)*MINOR_SEP
) + strlen(MINOR_SEP
);
1863 cport
= strtol(cport_str
, NULL
, 10);
1864 if ((cport
& ~SATA_CFGA_CPORT_MASK
) != 0 || errno
!= 0) {
1865 return (CFGA_SATA_PORT
);
1868 /* Get pmport number if there is a PORT_SEPARATOR */
1870 if ((pmport_str
= strrchr(ap_id
, (int)*PORT_SEPARATOR
)) != 0) {
1871 pmport_str
+= strlen(PORT_SEPARATOR
);
1872 pmport
= strtol(pmport_str
, NULL
, 10);
1873 qual
= SATA_CFGA_PMPORT_QUAL
;
1874 if ((pmport
& ~SATA_CFGA_PMPORT_MASK
) != 0 || errno
!= 0) {
1875 return (CFGA_SATA_PORT
);
1879 *port
= cport
| (pmport
<< SATA_CFGA_PMPORT_SHIFT
) | qual
;
1880 return (CFGA_SATA_OK
);
1884 * Pair of routines to set up for/clean up after a devctl_ap_* lib call.
1887 cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl
, nvlist_t
*user_nvlist
)
1889 if (user_nvlist
!= NULL
) {
1890 nvlist_free(user_nvlist
);
1892 if (devctl_hdl
!= NULL
) {
1893 devctl_release(devctl_hdl
);
1897 static cfga_sata_ret_t
1898 setup_for_devctl_cmd(
1900 devctl_hdl_t
*devctl_hdl
,
1901 nvlist_t
**user_nvlistp
,
1906 cfga_sata_ret_t rv
= CFGA_SATA_OK
;
1907 char *lap_id
, *pdyn
;
1909 lap_id
= strdup(ap_id
);
1911 return (CFGA_SATA_ALLOC_FAIL
);
1912 if ((pdyn
= GET_DYN(lap_id
)) != NULL
) {
1916 /* Get a devctl handle to pass to the devctl_ap_XXX functions */
1917 if ((*devctl_hdl
= devctl_ap_acquire((char *)lap_id
, oflag
)) == NULL
) {
1918 (void) fprintf(stderr
, "[libcfgadm:sata] "
1919 "setup_for_devctl_cmd: devctl_ap_acquire failed: %s\n",
1921 rv
= CFGA_SATA_DEVCTL
;
1925 /* Set up nvlist to pass the port number down to the driver */
1926 if (nvlist_alloc(user_nvlistp
, NV_UNIQUE_NAME_TYPE
, NULL
) != 0) {
1927 *user_nvlistp
= NULL
;
1928 rv
= CFGA_SATA_NVLIST
;
1929 (void) printf("nvlist_alloc failed\n");
1934 * Get port id, for Port Multiplier port, things could be a little bit
1935 * complicated because of "port.port" format in ap_id, thus for
1936 * port multiplier port, port number should be coded as 32bit int
1937 * with the sig 16 bit as sata channel number, least 16 bit as
1938 * the port number of sata port multiplier port.
1940 if ((rv
= get_port_num(lap_id
, &port
)) != CFGA_SATA_OK
) {
1942 "setup_for_devctl_cmd: get_port_num, errno: %d\n",
1947 /* Creates an int32_t entry */
1948 if (nvlist_add_int32(*user_nvlistp
, PORT
, port
) == -1) {
1949 (void) printf("nvlist_add_int32 failed\n");
1950 rv
= CFGA_SATA_NVLIST
;
1959 (void) cleanup_after_devctl_cmd(*devctl_hdl
, *user_nvlistp
);
1965 static cfga_sata_ret_t
1966 port_state(devctl_hdl_t hdl
, nvlist_t
*list
,
1967 ap_rstate_t
*rstate
, ap_ostate_t
*ostate
)
1969 devctl_ap_state_t devctl_ap_state
;
1971 if (devctl_ap_getstate(hdl
, list
, &devctl_ap_state
) == -1) {
1972 (void) printf("devctl_ap_getstate failed, errno: %d\n", errno
);
1973 return (CFGA_SATA_IOCTL
);
1975 *rstate
= devctl_ap_state
.ap_rstate
;
1976 *ostate
= devctl_ap_state
.ap_ostate
;
1977 return (CFGA_SATA_OK
);
1982 * Given a subcommand to the DEVCTL_AP_CONTROL ioctl, rquest the size of
1983 * the data to be returned, allocate a buffer, then get the data.
1984 * Returns *descrp (which must be freed) and size.
1986 * Note SATA_DESCR_TYPE_STRING returns an ASCII NULL-terminated string,
1987 * not a string descr.
1990 do_control_ioctl(const char *ap_id
, sata_cfga_apctl_t subcommand
, uint_t arg
,
1991 void **descrp
, size_t *sizep
)
1995 uint32_t local_size
;
1996 cfga_sata_ret_t rv
= CFGA_SATA_OK
;
1997 struct sata_ioctl_data ioctl_data
;
1999 assert(descrp
!= NULL
);
2001 assert(sizep
!= NULL
);
2003 if ((rv
= get_port_num(ap_id
, &port
)) != CFGA_SATA_OK
) {
2007 if ((fd
= open(ap_id
, O_RDONLY
)) == -1) {
2008 (void) printf("do_control_ioctl: open failed: errno:%d\n",
2010 rv
= CFGA_SATA_OPEN
;
2011 if (errno
== EBUSY
) {
2012 rv
= CFGA_SATA_BUSY
;
2017 ioctl_data
.cmd
= subcommand
;
2018 ioctl_data
.port
= port
;
2019 ioctl_data
.misc_arg
= (uint_t
)arg
;
2022 * Find out how large a buf we need to get the data.
2023 * Note the ioctls only accept/return a 32-bit int for a get_size
2024 * to avoid 32/64 and BE/LE issues.
2026 if ((subcommand
== SATA_CFGA_GET_AP_TYPE
) ||
2027 (subcommand
== SATA_CFGA_GET_DEVICE_PATH
) ||
2028 (subcommand
== SATA_CFGA_GET_MODEL_INFO
) ||
2029 (subcommand
== SATA_CFGA_GET_REVFIRMWARE_INFO
) ||
2030 (subcommand
== SATA_CFGA_GET_SERIALNUMBER_INFO
)) {
2031 ioctl_data
.get_size
= B_TRUE
;
2032 ioctl_data
.buf
= (caddr_t
)&local_size
;
2033 ioctl_data
.bufsiz
= sizeof (local_size
);
2035 if (ioctl(fd
, DEVCTL_AP_CONTROL
, &ioctl_data
) != 0) {
2036 perror("ioctl failed (size)");
2037 rv
= CFGA_SATA_IOCTL
;
2040 *sizep
= local_size
;
2042 if (local_size
== 0) {
2043 (void) printf("zero length data\n");
2044 rv
= CFGA_SATA_ZEROLEN
;
2047 if ((*descrp
= malloc(*sizep
)) == NULL
) {
2048 (void) printf("do_control_ioctl: malloc failed\n");
2049 rv
= CFGA_SATA_ALLOC_FAIL
;
2055 ioctl_data
.get_size
= B_FALSE
;
2056 ioctl_data
.buf
= *descrp
;
2057 ioctl_data
.bufsiz
= *sizep
;
2061 if (ioctl(fd
, DEVCTL_AP_CONTROL
, &ioctl_data
) != 0) {
2062 rv
= CFGA_SATA_IOCTL
;
2074 if (*descrp
!= NULL
) {
2079 if (rv
== CFGA_SATA_IOCTL
&& errno
== EBUSY
) {
2080 rv
= CFGA_SATA_BUSY
;
2088 sata_confirm(struct cfga_confirm
*confp
, char *msg
)
2092 if (confp
== NULL
|| confp
->confirm
== NULL
) {
2095 rval
= (*confp
->confirm
)(confp
->appdata_ptr
, msg
);
2102 sata_get_devicepath(const char *ap_id
)
2104 char *devpath
= NULL
;
2108 rv
= do_control_ioctl(ap_id
, SATA_CFGA_GET_DEVICE_PATH
, NULL
,
2109 (void **)&devpath
, &size
);
2111 if (rv
== CFGA_SATA_OK
) {
2114 return ((char *)NULL
);