Print this page
OS-66 Retired devices may still get attached leading to ndi_devi_online errors


   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 }