From 635237f09be38ca3d9b365e57999f7a4dc69ee20 Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <hare@suse.de>
Date: Mon, 14 Jan 2019 10:15:16 +0100
Subject: [PATCH] nvme_fc: add auto-connect scripts

References: bsc#1103354

Here's a set of script to enable FC-NVMe autoconnect, based on
the initial posting from James Smart.
FC-NVMe already generates an uevent whenever a new FC-NVMe remote
port is registered, so we can create an udev rule to parse this
event and start connecting to it.

The problem here is that the 'nvme connect' call might be taking
some time or might even stall altogether, so we cannot call it
directly from the udev rule. Rather, the udev rule starts a systemd
service, which then calls 'nvme connect' as a 'oneshot' program.
With this approach we are insulated from any stalls in udev rules.
Additionally we can implement a boot service to restart any missed
connections attempts.

Cc: James Smart <james.smart@broadcom.com>
Signed-off-by: Hannes Reinecke <hare@suse.com>

Add: nvmefc-connect.target to bundle all nvmefc-connect@ services

This allows to stop all parameterized services by stopping the target.
This can then be used in RPM macros to avoid errors like the ones
reported in bsc#1127076.

For a more detailed explanation, visit:
https://nordisch.org/posts/hooking-up-instantiated-services-with-rpm/

nvmefc-connect@.service requires the nvmefc-connect.target so that the
target automatically gets started when a (parameterized) service gets
started. This is necessary to stop the (then obsolete) services on a
package upgrade, because the rpm macros only stop _active_ systemd
units.

Also remove the [Install] section of the nvmefc-connect@.service
because the service shouldn't be enabled.

Change nvmefc-connect@.service to type `simple`

The idea is that udevd calls systemd for the nvme connect-all calls so
that it doesn't have to wait for it to return. But systemd waits for
services of type `oneshot` when called with systemctl start until the
process specified in the service file terminates.

Instead use type `simple`: systemd will return immediately after
starting the service, regardless of how long the nvme connect-all call
takes.

nvme-cli: Check for sysfs interface before NVMe discovery

This prevents an unnecessary error message in the case that the nvme-fc
kernel module is not loaded and the
/sys/class/fc/fc_udev_device/nvme_discovery handle is not available.

Signed-off-by: Simon Schricker <sschricker@suse.de>
---
 nvme-fc-autoconnect/70-nvmefc-autoconnect.conf      |  1 +
 nvme-fc-autoconnect/70-nvmefc-autoconnect.rules     |  8 ++++++++
 nvme-fc-autoconnect/nvmefc-boot-connections.service | 10 ++++++++++
 nvme-fc-autoconnect/nvmefc-connect.target           |  2 ++
 nvme-fc-autoconnect/nvmefc-connect@.service         | 13 +++++++++++++
 5 files changed, 34 insertions(+)
 create mode 100644 nvme-fc-autoconnect/70-nvmefc-autoconnect.conf
 create mode 100644 nvme-fc-autoconnect/70-nvmefc-autoconnect.rules
 create mode 100644 nvme-fc-autoconnect/nvmefc-boot-connections.service
 create mode 100644 nvme-fc-autoconnect/nvmefc-connect.target
 create mode 100644 nvme-fc-autoconnect/nvmefc-connect@.service

diff --git a/nvme-fc-autoconnect/70-nvmefc-autoconnect.conf b/nvme-fc-autoconnect/70-nvmefc-autoconnect.conf
new file mode 100644
index 0000000..b92d94f
--- /dev/null
+++ b/nvme-fc-autoconnect/70-nvmefc-autoconnect.conf
@@ -0,0 +1 @@
+install_items+="/usr/lib/udev/rules.d/70-nvmefc-autoconnect.rules"
diff --git a/nvme-fc-autoconnect/70-nvmefc-autoconnect.rules b/nvme-fc-autoconnect/70-nvmefc-autoconnect.rules
new file mode 100644
index 0000000..aa4f9bf
--- /dev/null
+++ b/nvme-fc-autoconnect/70-nvmefc-autoconnect.rules
@@ -0,0 +1,8 @@
+#
+# nvme_fc: udev event to automatically scan (via discovery controller)
+#   new FC nvme remote ports and auto-connect to the subsystems they report.
+#
+
+ACTION=="change", SUBSYSTEM=="fc", ENV{FC_EVENT}=="nvmediscovery", \
+  ENV{NVMEFC_HOST_TRADDR}=="*",  ENV{NVMEFC_TRADDR}=="*", \
+  RUN+="/usr/bin/systemctl --no-block start nvmefc-connect@--host-traddr=$env{NVMEFC_HOST_TRADDR}\\x20--traddr=$env{NVMEFC_TRADDR}.service"
diff --git a/nvme-fc-autoconnect/nvmefc-boot-connections.service b/nvme-fc-autoconnect/nvmefc-boot-connections.service
new file mode 100644
index 0000000..ffa7087
--- /dev/null
+++ b/nvme-fc-autoconnect/nvmefc-boot-connections.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Auto-connect to subsystems on FC-NVME devices during boot
+ConditionPathExists=/sys/class/fc/fc_udev_device/nvme_discovery
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -c "echo add > /sys/class/fc/fc_udev_device/nvme_discovery"
+
+[Install]
+WantedBy=default.target
diff --git a/nvme-fc-autoconnect/nvmefc-connect.target b/nvme-fc-autoconnect/nvmefc-connect.target
new file mode 100644
index 0000000..953c0b7
--- /dev/null
+++ b/nvme-fc-autoconnect/nvmefc-connect.target
@@ -0,0 +1,2 @@
+[Unit]
+Description=All instances of nvme-fc-autoconnect daemon
diff --git a/nvme-fc-autoconnect/nvmefc-connect@.service b/nvme-fc-autoconnect/nvmefc-connect@.service
new file mode 100644
index 0000000..a8ff271
--- /dev/null
+++ b/nvme-fc-autoconnect/nvmefc-connect@.service
@@ -0,0 +1,13 @@
+#
+# Unit file used by 70-nvmefc-autoconnect.rules.
+#
+
+[Unit]
+Description=Auto-connect to subsystems on FC-NVME devices
+After=syslog.target
+PartOf=nvmefc-connect.target
+Requires=nvmefc-connect.target
+
+[Service]
+Type=simple
+ExecStart=/bin/sh -c "/usr/sbin/nvme connect-all --transport=fc `/usr/bin/echo -e '%i'`"
-- 
2.22.0

