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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 #include <libdevinfo.h>
27 #include <sys/modctl.h>
28 #include <sys/stat.h>
29 #include <string.h>
30 #include <librcm.h>
31 #include <dlfcn.h>
32
33 #undef NDEBUG
34 #include <assert.h>
35
36 typedef struct rio_path {
37 char rpt_path[PATH_MAX];
38 struct rio_path *rpt_next;
39 } rio_path_t;
40
41 typedef struct rcm_arg {
42 char *rcm_root;
43 di_node_t rcm_node;
44 int rcm_supp;
45 rcm_handle_t *rcm_handle;
46 int rcm_retcode;
47 di_retire_t *rcm_dp;
48 rio_path_t *rcm_cons_nodes;
49 rio_path_t *rcm_rsrc_minors;
50 int (*rcm_offline)();
51 int (*rcm_online)();
649 p = tmp->rpt_next;
650 (void) strcpy(s, tmp->rpt_path);
651 s += strlen(s) + 1;
652 RIO_ASSERT(dp, s - plistp < len);
653 free(tmp);
654 }
655 rp->rcm_cons_nodes = NULL;
656 RIO_ASSERT(dp, s - plistp == len - 1);
657 *s = '\0';
658
659 dp->rt_debug(dp->rt_hdl, "[INFO]: constraint str = %p\n", plistp);
660
661 *pp = plistp;
662 *clen = len;
663
664 rp->rcm_retcode = RCM_SUCCESS;
665 out:
666 return (rp->rcm_retcode);
667 }
668
669
670 /*ARGSUSED*/
671 int
672 di_retire_device(char *devpath, di_retire_t *dp, int flags)
673 {
674 char path[PATH_MAX];
675 struct stat sb;
676 int retval = EINVAL;
677 char *constraint = NULL;
678 size_t clen;
679 void *librcm_hdl;
680 rcm_arg_t rarg = {0};
681 int (*librcm_alloc_handle)();
682 int (*librcm_free_handle)();
683
684 if (dp == NULL || dp->rt_debug == NULL || dp->rt_hdl == NULL)
685 return (EINVAL);
686
687 if (devpath == NULL || devpath[0] == '\0') {
688 dp->rt_debug(dp->rt_hdl, "[ERROR]: NULL argument(s)\n");
689 return (EINVAL);
690 }
691
692 if (devpath[0] != '/' || strlen(devpath) >= PATH_MAX ||
813 retval = 0;
814
815 out:
816 if (rarg.rcm_handle)
817 (void) librcm_free_handle(rarg.rcm_handle);
818
819 RIO_ASSERT(dp, rarg.rcm_cons_nodes == NULL);
820 RIO_ASSERT(dp, rarg.rcm_rsrc_minors == NULL);
821
822 (void) dlclose(librcm_hdl);
823
824 free(constraint);
825
826 if (rarg.rcm_node != DI_NODE_NIL)
827 di_fini(rarg.rcm_node);
828
829 return (retval);
830 }
831
832 /*ARGSUSED*/
833 int
834 di_unretire_device(char *devpath, di_retire_t *dp)
835 {
836 if (dp == NULL || dp->rt_debug == NULL || dp->rt_hdl == NULL)
837 return (EINVAL);
838
839 if (devpath == NULL || devpath[0] == '\0') {
840 dp->rt_debug(dp->rt_hdl, "[ERROR]: NULL devpath\n");
841 return (EINVAL);
842 }
843
844 if (devpath[0] != '/' || strlen(devpath) >= PATH_MAX ||
845 strncmp(devpath, "/devices/", strlen("/devices/")) == 0 ||
846 strstr(devpath, "../devices/") || strrchr(devpath, ':')) {
847 dp->rt_debug(dp->rt_hdl, "[ERROR]: invalid devpath: %s\n",
848 devpath);
849 return (EINVAL);
850 }
851
852 if (modctl(MODUNRETIRE, devpath) != 0) {
853 int err = errno;
854 dp->rt_debug(dp->rt_hdl, "[ERROR]: unretire modctl() failed: "
855 "%s: %s\n", devpath, strerror(err));
856 return (err);
857 }
858
859 dp->rt_debug(dp->rt_hdl, "[INFO]: unretire modctl() done: %s\n",
860 devpath);
861
862 return (0);
863 }
|
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2013, Nexenta Systemc, Inc. All rights reserved.
25 */
26
27 #include <libdevinfo.h>
28 #include <sys/modctl.h>
29 #include <sys/stat.h>
30 #include <string.h>
31 #include <librcm.h>
32 #include <dlfcn.h>
33 #include <sys/scsi/scsi_address.h>
34 #include <limits.h>
35 #include <errno.h>
36
37 #undef NDEBUG
38 #include <assert.h>
39
40 typedef struct rio_path {
41 char rpt_path[PATH_MAX];
42 struct rio_path *rpt_next;
43 } rio_path_t;
44
45 typedef struct rcm_arg {
46 char *rcm_root;
47 di_node_t rcm_node;
48 int rcm_supp;
49 rcm_handle_t *rcm_handle;
50 int rcm_retcode;
51 di_retire_t *rcm_dp;
52 rio_path_t *rcm_cons_nodes;
53 rio_path_t *rcm_rsrc_minors;
54 int (*rcm_offline)();
55 int (*rcm_online)();
653 p = tmp->rpt_next;
654 (void) strcpy(s, tmp->rpt_path);
655 s += strlen(s) + 1;
656 RIO_ASSERT(dp, s - plistp < len);
657 free(tmp);
658 }
659 rp->rcm_cons_nodes = NULL;
660 RIO_ASSERT(dp, s - plistp == len - 1);
661 *s = '\0';
662
663 dp->rt_debug(dp->rt_hdl, "[INFO]: constraint str = %p\n", plistp);
664
665 *pp = plistp;
666 *clen = len;
667
668 rp->rcm_retcode = RCM_SUCCESS;
669 out:
670 return (rp->rcm_retcode);
671 }
672
673 /*ARGSUSED*/
674 static int
675 do_di_retire_device(char *devpath, di_retire_t *dp, int flags)
676 {
677 char path[PATH_MAX];
678 struct stat sb;
679 int retval = EINVAL;
680 char *constraint = NULL;
681 size_t clen;
682 void *librcm_hdl;
683 rcm_arg_t rarg = {0};
684 int (*librcm_alloc_handle)();
685 int (*librcm_free_handle)();
686
687 if (dp == NULL || dp->rt_debug == NULL || dp->rt_hdl == NULL)
688 return (EINVAL);
689
690 if (devpath == NULL || devpath[0] == '\0') {
691 dp->rt_debug(dp->rt_hdl, "[ERROR]: NULL argument(s)\n");
692 return (EINVAL);
693 }
694
695 if (devpath[0] != '/' || strlen(devpath) >= PATH_MAX ||
816 retval = 0;
817
818 out:
819 if (rarg.rcm_handle)
820 (void) librcm_free_handle(rarg.rcm_handle);
821
822 RIO_ASSERT(dp, rarg.rcm_cons_nodes == NULL);
823 RIO_ASSERT(dp, rarg.rcm_rsrc_minors == NULL);
824
825 (void) dlclose(librcm_hdl);
826
827 free(constraint);
828
829 if (rarg.rcm_node != DI_NODE_NIL)
830 di_fini(rarg.rcm_node);
831
832 return (retval);
833 }
834
835 /*ARGSUSED*/
836 static int
837 do_di_unretire_device(char *devpath, di_retire_t *dp)
838 {
839 if (dp == NULL || dp->rt_debug == NULL || dp->rt_hdl == NULL)
840 return (EINVAL);
841
842 if (devpath == NULL || devpath[0] == '\0') {
843 dp->rt_debug(dp->rt_hdl, "[ERROR]: NULL devpath\n");
844 return (EINVAL);
845 }
846
847 if (devpath[0] != '/' || strlen(devpath) >= PATH_MAX ||
848 strncmp(devpath, "/devices/", strlen("/devices/")) == 0 ||
849 strstr(devpath, "../devices/") || strrchr(devpath, ':')) {
850 dp->rt_debug(dp->rt_hdl, "[ERROR]: invalid devpath: %s\n",
851 devpath);
852 return (EINVAL);
853 }
854
855 if (modctl(MODUNRETIRE, devpath) != 0) {
856 int err = errno;
857 dp->rt_debug(dp->rt_hdl, "[ERROR]: unretire modctl() failed: "
858 "%s: %s\n", devpath, strerror(err));
859 return (err);
860 }
861
862 dp->rt_debug(dp->rt_hdl, "[INFO]: unretire modctl() done: %s\n",
863 devpath);
864
865 return (0);
866 }
867
868 /* Structure that holds physical path instance. */
869 struct retire_mpath_info {
870 char *pathname;
871 struct retire_mpath_info *next;
872 char nodename[PATH_MAX];
873 };
874
875 static int
876 retire_walk_nodes(di_node_t node, void *arg)
877 {
878 char *dn = NULL;
879 struct retire_mpath_info **mpinfo = (struct retire_mpath_info **)arg;
880 di_node_t pnode;
881 char *baddr;
882 di_path_t path;
883
884 if (node == NULL || ((baddr = di_bus_addr(node)) == NULL) ||
885 baddr[0] == '\0') {
886 return (DI_WALK_CONTINUE);
887 }
888
889 if (((dn = strstr((*mpinfo)->pathname, baddr)) == NULL) ||
890 /* Make sure bus address matches completely. */
891 (strlen(dn) != strlen(baddr))) {
892 return (DI_WALK_CONTINUE);
893 }
894
895 if ((path = di_path_client_next_path(node, DI_PATH_NIL)) == NULL) {
896 return (DI_WALK_CONTINUE);
897 }
898
899 for (; path != NULL; path = di_path_client_next_path(node, path)) {
900 struct retire_mpath_info *ri, *prev;
901 char *port_id = NULL;
902 char *p;
903
904 if ((pnode = di_path_phci_node(path)) == DI_NODE_NIL) {
905 continue;
906 }
907
908 if ((p = di_devfs_path(pnode)) == NULL) {
909 continue;
910 }
911
912 if (di_path_prop_lookup_strings(path,
913 SCSI_ADDR_PROP_TARGET_PORT, &port_id) == 1) {
914
915 ri = malloc(sizeof (*ri) + PATH_MAX);
916 if (ri != NULL) {
917 prev = *mpinfo;
918
919 ri->next = prev;
920
921 /* Preserve nodename */
922 ri->pathname = prev->pathname;
923 (void) snprintf(&ri->nodename[0], PATH_MAX,
924 "%s/disk@%s,0", p, port_id);
925
926 *mpinfo = ri;
927 }
928 }
929
930 di_devfs_path_free(p);
931 }
932
933 return (DI_WALK_CONTINUE);
934 }
935
936 int
937 do_di_retire_device_mp(char *devpath, di_retire_t *dp, int flags,
938 boolean_t retire)
939 {
940 int err = 0;
941 struct retire_mpath_info mpinfo, *pmpinfo, *pcurr;
942 char *path;
943 di_node_t root_node;
944
945 /* First, retire the device itself. */
946 err = retire ?
947 do_di_retire_device(devpath, dp, flags) :
948 do_di_unretire_device(devpath, dp);
949
950 if (err != 0) {
951 dp->rt_debug(dp->rt_hdl, "di_%sretire_device failed to"
952 " %sretire device: %d %s", retire ? "" : "un",
953 retire ? "" : "un", err, devpath);
954 return (err);
955 }
956
957 /* Next, try to retire all physical paths, if possible. */
958 root_node = di_init("/", DINFOCPYALL | DINFOPATH | DINFOLYR);
959 if (root_node == DI_NODE_NIL) {
960 dp->rt_debug(dp->rt_hdl, "di_%sretire_device can't access"
961 " device tree, MPxIO checks ignored for %s",
962 retire ? "" : "un", devpath);
963 return (0);
964 }
965
966 /* Obtain multipath information. */
967 (void) memset(&mpinfo, 0, sizeof (mpinfo));
968 mpinfo.pathname = devpath;
969
970 pmpinfo = &mpinfo;
971
972 (void) di_walk_node(root_node, DI_WALK_CLDFIRST, &pmpinfo,
973 retire_walk_nodes);
974
975 /* Next, retire all possible physical paths. */
976 for (; err == 0 && pmpinfo != &mpinfo; ) {
977 pcurr = pmpinfo;
978 pmpinfo = pmpinfo->next;
979
980 path = &pcurr->nodename[0];
981
982 dp->rt_debug(dp->rt_hdl,
983 "di_%sretire_device %sretiring physical path %s\n",
984 retire ? "" : "un", retire ? "" : "un", path);
985
986 err = retire ?
987 do_di_retire_device(path, dp, flags) :
988 do_di_unretire_device(path, dp);
989
990 if (err != 0)
991 dp->rt_debug(dp->rt_hdl,
992 "di_%sretire_device failed to %sretire physical"
993 " path %s, %d\n", retire ? "" : "un",
994 retire ? "" : "un", path, err);
995
996 free(pcurr);
997 }
998
999 return (0);
1000 }
1001
1002 /*ARGSUSED*/
1003 int
1004 di_retire_device(char *devpath, di_retire_t *dp, int flags)
1005 {
1006 return (do_di_retire_device_mp(devpath, dp, flags, B_TRUE));
1007 }
1008
1009 /*ARGSUSED*/
1010 int
1011 di_unretire_device(char *devpath, di_retire_t *dp)
1012 {
1013 return (do_di_retire_device_mp(devpath, dp, 0, B_FALSE));
1014 }
|