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

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libdevinfo/devinfo_retire.c
          +++ new/usr/src/lib/libdevinfo/devinfo_retire.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright (c) 2013, Nexenta Systemc, Inc.  All rights reserved.
  24   25   */
  25   26  
  26   27  #include <libdevinfo.h>
  27   28  #include <sys/modctl.h>
  28   29  #include <sys/stat.h>
  29   30  #include <string.h>
  30   31  #include <librcm.h>
  31   32  #include <dlfcn.h>
       33 +#include <sys/scsi/scsi_address.h>
       34 +#include <limits.h>
       35 +#include <errno.h>
  32   36  
  33   37  #undef  NDEBUG
  34   38  #include <assert.h>
  35   39  
  36   40  typedef struct rio_path {
  37   41          char            rpt_path[PATH_MAX];
  38   42          struct rio_path *rpt_next;
  39   43  } rio_path_t;
  40   44  
  41   45  typedef struct rcm_arg {
↓ open down ↓ 617 lines elided ↑ open up ↑
 659  663          dp->rt_debug(dp->rt_hdl, "[INFO]: constraint str = %p\n", plistp);
 660  664  
 661  665          *pp = plistp;
 662  666          *clen = len;
 663  667  
 664  668          rp->rcm_retcode = RCM_SUCCESS;
 665  669  out:
 666  670          return (rp->rcm_retcode);
 667  671  }
 668  672  
 669      -
 670  673  /*ARGSUSED*/
 671      -int
 672      -di_retire_device(char *devpath, di_retire_t *dp, int flags)
      674 +static int
      675 +do_di_retire_device(char *devpath, di_retire_t *dp, int flags)
 673  676  {
 674  677          char path[PATH_MAX];
 675  678          struct stat sb;
 676  679          int retval = EINVAL;
 677  680          char *constraint = NULL;
 678  681          size_t clen;
 679  682          void *librcm_hdl;
 680  683          rcm_arg_t rarg = {0};
 681  684          int (*librcm_alloc_handle)();
 682  685          int (*librcm_free_handle)();
↓ open down ↓ 140 lines elided ↑ open up ↑
 823  826  
 824  827          free(constraint);
 825  828  
 826  829          if (rarg.rcm_node != DI_NODE_NIL)
 827  830                  di_fini(rarg.rcm_node);
 828  831  
 829  832          return (retval);
 830  833  }
 831  834  
 832  835  /*ARGSUSED*/
 833      -int
 834      -di_unretire_device(char *devpath, di_retire_t *dp)
      836 +static int
      837 +do_di_unretire_device(char *devpath, di_retire_t *dp)
 835  838  {
 836  839          if (dp == NULL || dp->rt_debug == NULL || dp->rt_hdl == NULL)
 837  840                  return (EINVAL);
 838  841  
 839  842          if (devpath == NULL || devpath[0] == '\0') {
 840  843                  dp->rt_debug(dp->rt_hdl, "[ERROR]: NULL devpath\n");
 841  844                  return (EINVAL);
 842  845          }
 843  846  
 844  847          if (devpath[0] != '/' || strlen(devpath) >= PATH_MAX ||
↓ open down ↓ 8 lines elided ↑ open up ↑
 853  856                  int err = errno;
 854  857                  dp->rt_debug(dp->rt_hdl, "[ERROR]: unretire modctl() failed: "
 855  858                      "%s: %s\n", devpath, strerror(err));
 856  859                  return (err);
 857  860          }
 858  861  
 859  862          dp->rt_debug(dp->rt_hdl, "[INFO]: unretire modctl() done: %s\n",
 860  863              devpath);
 861  864  
 862  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));
 863 1014  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX