0e8dd1
From 41bcd014886cfd2bc4415f2c78668008963934a9 Mon Sep 17 00:00:00 2001
0e8dd1
From: Maurizio Lombardi <mlombard@redhat.com>
0e8dd1
Date: Mon, 1 Feb 2016 14:44:22 +0100
0e8dd1
Subject: [PATCH] udev: fibre channel: fix NPIV support
0e8dd1
0e8dd1
When using NPIV, you can create multiple virtual HBAs on top of the
0e8dd1
physical one, this means that the physical N_Port can have multiple
0e8dd1
port IDs associated to it.
0e8dd1
Suppose a LUN is assigned to the physical HBA and to a virtual HBA,
0e8dd1
in both cases the original code uses the ID of the physical HBA
0e8dd1
to build the by-path link and udev will end up trying to create two by-path
0e8dd1
links with the same name.
0e8dd1
0e8dd1
This patch fixes the problem by using the port ID of the virtual HBA
0e8dd1
whenever it detects that the device belongs to a virtual HBA,
0e8dd1
otherwise it uses the port ID of the physical HBA.
0e8dd1
0e8dd1
(cherry-picked from 155a760bcedd11b7f3b430350a46f10736286895)
0e8dd1
0e8dd1
Resolves: #1266934
0e8dd1
---
0e8dd1
 src/udev/udev-builtin-path_id.c | 27 ++++++++++++++++++++++++---
0e8dd1
 1 file changed, 24 insertions(+), 3 deletions(-)
0e8dd1
0e8dd1
diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
0e8dd1
index 9ca6084..695ac7f 100644
0e8dd1
--- a/src/udev/udev-builtin-path_id.c
0e8dd1
+++ b/src/udev/udev-builtin-path_id.c
0e8dd1
@@ -92,6 +92,9 @@ static struct udev_device *skip_subsystem(struct udev_device *dev, const char *s
0e8dd1
 static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) {
0e8dd1
         struct udev *udev  = udev_device_get_udev(parent);
0e8dd1
         struct udev_device *targetdev;
0e8dd1
+        struct udev_device *rportdev;
0e8dd1
+        struct udev_device *hostdev;
0e8dd1
+        struct udev_device *vportdev;
0e8dd1
         struct udev_device *fcdev = NULL;
0e8dd1
         const char *port;
0e8dd1
         char *lun = NULL;
0e8dd1
@@ -100,9 +103,27 @@ static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent,
0e8dd1
         if (targetdev == NULL)
0e8dd1
                 return NULL;
0e8dd1
 
0e8dd1
-        fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev));
0e8dd1
-        if (fcdev == NULL)
0e8dd1
-                return NULL;
0e8dd1
+        rportdev = udev_device_get_parent(targetdev);
0e8dd1
+        if (rportdev == NULL)
0e8dd1
+                goto skip_npiv_check;
0e8dd1
+
0e8dd1
+        hostdev = udev_device_get_parent(rportdev);
0e8dd1
+        if (hostdev == NULL)
0e8dd1
+                goto skip_npiv_check;
0e8dd1
+
0e8dd1
+        vportdev = udev_device_get_parent(hostdev);
0e8dd1
+        if (vportdev == NULL)
0e8dd1
+                goto skip_npiv_check;
0e8dd1
+
0e8dd1
+        fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_vports", udev_device_get_sysname(vportdev));
0e8dd1
+
0e8dd1
+skip_npiv_check:
0e8dd1
+        if (fcdev == NULL) {
0e8dd1
+                fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev));
0e8dd1
+                if (fcdev == NULL)
0e8dd1
+                        return NULL;
0e8dd1
+        }
0e8dd1
+
0e8dd1
         port = udev_device_get_sysattr_value(fcdev, "port_name");
0e8dd1
         if (port == NULL) {
0e8dd1
                 parent = NULL;