* [PATCH v2 0/7] nvme-fc: FPIN link integrity handling
@ 2026-09-02 20:05 Jesse Taube
2026-09-02 20:05 ` [PATCH v2 1/7] nvme: add NVME_CTRL_MARGINAL flag Jesse Taube
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Jesse Taube @ 2026-09-02 20:05 UTC (permalink / raw)
To: linux-nvme
Cc: linux-scsi, Jonathan Corbet, Shuah Khan, Keith Busch, Jens Axboe,
Christoph Hellwig, Sagi Grimberg, Justin Tee, Naresh Gottumukkala,
Paul Ely, Chaitanya Kulkarni, James E.J. Bottomley,
Martin K. Petersen, Nilesh Javali, GR-QLogic-Storage-Upstream,
Hannes Reinecke, Jesse Taube, Gustavo A. R. Silva, John Meneghini,
Bryan Gurney, Chris Leech, Ewan D . Milne, shinichiro.kawasaki,
linux-doc, linux-kernel, linux-block
This set has been split into an NVMe set which adds marginal path
handling and a SCSI set which handles decoding FPIN LI events and
setting the marginal flag. The NVMe set, this one, can be tested and
used independently of the SCSI set.
FPIN LI (link integrity) messages are received when the attached fabric
detects hardware errors. In response, I/O should be directed away from
the affected ports. This series adds a new controller flag
'NVME_CTRL_MARGINAL' which is checked during multipath path selection,
causing the path to be de-prioritized. If no other paths are available
the marginal paths are still used.
Testing was performed by Jesse Taube and John Meneghini using blktests
with the fcloop driver.
Controllers on the affected port show the NVME_CTRL_MARGINAL flag:
\
+- nvme4 fc traddr=c,host_traddr=e live optimized
+- nvme5 fc traddr=8,host_traddr=e live non-optimized
+- nvme8 fc traddr=e,host_traddr=f marginal optimized
+- nvme9 fc traddr=a,host_traddr=f marginal non-optimized
All multipath io-policies were verified: numa, round-robin, and
queue-depth. Scenarios included optimized, non-optimized, and
inaccessible, and marginal paths. When all paths are
marginal, I/O continues based on the multipath policy.
Original work on this set was presented at the LSFMM 2024 conference:
Link: https://people.redhat.com/jmeneghi/LSFMM_2024/LSFMM_2024_NVMe_Cancel_and_FPIN.pdf
To test path handling use:
https://github.com/linux-blktests/blktests/pull/264
or
https://lore.kernel.org/linux-nvme/20260828153029.853768-1-jtaubepe@redhat.com/T/
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220329
Previously posted as a combined NVMe+SCSI series (v1-v11).
V1 -> V2:
- Changed flag name to 'marginal'
- Do not block marginal path; influence path selection instead
to de-prioritize marginal paths
V2 -> V3:
- Split off driver-specific modifications
- Introduce 'union fc_tlv_desc' to avoid casts
V3 -> V4:
- Include reviews from Justin Tee
- Split marginal path handling patch
V4 -> V5:
- Change 'u8' to '__u8' on fc_tlv_desc to fix a failure to build
- Print 'marginal' instead of 'live' in the state of controllers
when they are marginal
V5 -> V6:
- Minor spelling corrections to patch descriptions
V6 -> V7:
- No code changes; added note about additional testing
V7 -> V8:
- Split nvme core marginal flag addition into its own patch
- Add patch for queue_depth marginal path support
V8 -> V9:
- Rebased patch series to nvme-6.17.
- Added patch from Gustavo Silva, "scsi: qla2xxx: Fix memcpy field-spanning
write issue", which resolves the field-spanning write issue
- We decided to leave the "marginal" state as is, because the transport
driver uses the term "marginal".
V9 -> V10:
- Rebased patch series to nvme-6.18.
- Refactor and fix a patch from Gustavo Silva, "scsi: qla2xxx: Fix 2 memcpy
field-spanning write issue", which resolves the field-spanning write
issue.
This new version of Gustavo's patch fixes a bug found in testing.
- Refactored original implementation
New functions added:
nvme_fc_lport_from_wwpn() - Find local port by WWPN
nvme_fc_fpin_set_state() - Set marginal state on controllers
nvme_fc_modify_rport_fpin_state() - Main API function
Functions removed:
nvme_fc_fpin_li_lport_update() - FPIN processing logic
nvme_fc_fpin_rcv() - Direct FPIN message processing
Functions modified:
fc_rport_set_marginal_state - allows administrative control
V10 -> V1:
- Rebase onto 7.2-rc1
- Add marginal support to fcloop driver (new patch)
- Rewrite multipath handling ("nvme-fc: marginal path handling") and
("nvme-multipath: queue-depth support for marginal paths") replacing
them with ("nvme-multipath: round-robin...")
("nvme-fc: marginal path handling...") and
("nvme-multipath: queue-depth support")
- New patch ("scsi: scsi_transport_fc: Add set_rport_marginal to ")
replaces ("scsi: scsi_transport_fc: add fc_host_fpin_set_nvme").
Uses existing function template to add a new callback for setting
the marginal state on a remote port, similar to the existing
set_rport_dev_loss_tmo() callback.
- Replace `nvme_fc_modify_rport_fpin_state` with
`nvme_fc_set_remoteport_fpin` which takes
`struct nvme_fc_remote_port` instead of wwpn and wwnn
- Rewrite the "enable FPIN notification for NVMe" patches
to use the new callback methods.
V1 -> V2 (split):
- Split SCSI and NVME parts.
- Rewrite path handling code.
Bryan Gurney (2):
nvme: add NVME_CTRL_MARGINAL flag
nvme: sysfs: emit the marginal path state in show_state()
Jesse Taube (4):
nvme-multipath: numa support for marginal paths
nvme-multipath: round-robin support for marginal paths
nvme-fc: add nvme_fc_set_remoteport_fpin()
nvme: fcloop: Add set_marginal_rport to sysfs
John Meneghini (1):
nvme-multipath: queue-depth support for marginal paths
drivers/nvme/host/core.c | 1 +
drivers/nvme/host/fc.c | 17 +++++++++
drivers/nvme/host/multipath.c | 70 ++++++++++++++++++++++++++++++----
drivers/nvme/host/nvme.h | 11 ++++++
drivers/nvme/host/sysfs.c | 3 ++
drivers/nvme/target/fcloop.c | 50 ++++++++++++++++++++++++
include/linux/nvme-fc-driver.h | 2 +
7 files changed, 146 insertions(+), 8 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 1/7] nvme: add NVME_CTRL_MARGINAL flag
2026-09-02 20:05 [PATCH v2 0/7] nvme-fc: FPIN link integrity handling Jesse Taube
@ 2026-09-02 20:05 ` Jesse Taube
2026-09-02 20:05 ` [PATCH v2 2/7] nvme-multipath: numa support for marginal paths Jesse Taube
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Jesse Taube @ 2026-09-02 20:05 UTC (permalink / raw)
To: linux-nvme
Cc: linux-scsi, Jonathan Corbet, Shuah Khan, Keith Busch, Jens Axboe,
Christoph Hellwig, Sagi Grimberg, Justin Tee, Naresh Gottumukkala,
Paul Ely, Chaitanya Kulkarni, James E.J. Bottomley,
Martin K. Petersen, Nilesh Javali, GR-QLogic-Storage-Upstream,
Hannes Reinecke, Jesse Taube, Gustavo A. R. Silva, John Meneghini,
Bryan Gurney, Chris Leech, Ewan D . Milne, shinichiro.kawasaki,
linux-doc, linux-kernel, linux-block
From: Bryan Gurney <bgurney@redhat.com>
Add a new controller flag, NVME_CTRL_MARGINAL, to help multipath I/O
policies to react to a path that is set to a "marginal" state.
The "marginal" flag is initialized to false in `nvme_init_ctrl` and
cleared in `nvme_fc_ctrl_connectivity_loss` before re-association.
It is only cleared there, not in the generic `nvme_reset_ctrl` path,
because the marginal condition reflects a physical link problem.
An arbitrary controller reset does not signal that a hardware fault has
been resolved. Calling `nvme_fc_ctrl_connectivity_loss` means the FC
association has failed and will be re-established, so the prior link
quality state is no longer meaningful.
Signed-off-by: Bryan Gurney <bgurney@redhat.com>
---
V10 -> V1:
- No change
V1 -> V2:
- Add nvme_ctrl_assign_marginal
- Fix nvme_fc_ctrl_connectivity_loss clearing wrong bit.
- Update commit message
---
drivers/nvme/host/core.c | 1 +
drivers/nvme/host/fc.c | 4 ++++
drivers/nvme/host/nvme.h | 11 +++++++++++
3 files changed, 16 insertions(+)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 453c1f0b2dd0..4ce3c0573707 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -5165,6 +5165,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
WRITE_ONCE(ctrl->state, NVME_CTRL_NEW);
ctrl->passthru_err_log_enabled = false;
clear_bit(NVME_CTRL_FAILFAST_EXPIRED, &ctrl->flags);
+ nvme_ctrl_assign_marginal(ctrl, false);
spin_lock_init(&ctrl->lock);
mutex_init(&ctrl->namespaces_lock);
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 04363b9c4489..7886c0dcc626 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -788,6 +788,10 @@ nvme_fc_ctrl_connectivity_loss(struct nvme_fc_ctrl *ctrl)
"Reconnect", ctrl->cnum);
set_bit(ASSOC_FAILED, &ctrl->flags);
+
+ /* clear 'marginal' flag as controller will be reset */
+ nvme_ctrl_assign_marginal(&ctrl->ctrl, false);
+
nvme_reset_ctrl(&ctrl->ctrl);
}
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 824651cc898d..640cb4747ba2 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -329,6 +329,7 @@ enum nvme_ctrl_flags {
NVME_CTRL_SKIP_ID_CNS_CS = 4,
NVME_CTRL_DIRTY_CAPABILITY = 5,
NVME_CTRL_FROZEN = 6,
+ NVME_CTRL_MARGINAL = 7,
};
struct nvme_ctrl {
@@ -479,6 +480,16 @@ static inline enum nvme_ctrl_state nvme_ctrl_state(struct nvme_ctrl *ctrl)
return READ_ONCE(ctrl->state);
}
+static inline bool nvme_ctrl_is_marginal(struct nvme_ctrl *ctrl)
+{
+ return test_bit(NVME_CTRL_MARGINAL, &ctrl->flags);
+}
+
+static inline void nvme_ctrl_assign_marginal(struct nvme_ctrl *ctrl, bool marginal)
+{
+ assign_bit(NVME_CTRL_MARGINAL, &ctrl->flags, marginal);
+}
+
enum nvme_iopolicy {
NVME_IOPOLICY_NUMA,
NVME_IOPOLICY_RR,
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 2/7] nvme-multipath: numa support for marginal paths
2026-09-02 20:05 [PATCH v2 0/7] nvme-fc: FPIN link integrity handling Jesse Taube
2026-09-02 20:05 ` [PATCH v2 1/7] nvme: add NVME_CTRL_MARGINAL flag Jesse Taube
@ 2026-09-02 20:05 ` Jesse Taube
2026-09-02 20:05 ` [PATCH v2 3/7] nvme-multipath: queue-depth " Jesse Taube
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Jesse Taube @ 2026-09-02 20:05 UTC (permalink / raw)
To: linux-nvme
Cc: linux-scsi, Jonathan Corbet, Shuah Khan, Keith Busch, Jens Axboe,
Christoph Hellwig, Sagi Grimberg, Justin Tee, Naresh Gottumukkala,
Paul Ely, Chaitanya Kulkarni, James E.J. Bottomley,
Martin K. Petersen, Nilesh Javali, GR-QLogic-Storage-Upstream,
Hannes Reinecke, Jesse Taube, Gustavo A. R. Silva, John Meneghini,
Bryan Gurney, Chris Leech, Ewan D . Milne, shinichiro.kawasaki,
linux-doc, linux-kernel, linux-block
FPIN LI (link integrity) messages are received when the attached
fabric detects hardware errors. In response to these messages I/O
should be directed away from the affected ports, and only used
if no other non-marginal paths are available.
To handle this a new controller flag 'NVME_CTRL_MARGINAL' is added
which will cause the multipath scheduler to skip these paths when
checking for 'optimized' paths.
Signed-off-by: Jesse Taube <jtaubepe@redhat.com>
---
This is a distinct change from the previous commit
which treated marginal paths as non-optimized but still usable.
This changes the priority of marginal paths to be lower than
non-optimized paths.
V10 -> V1:
- New commit
V1 -> V2:
- Rewrite
---
drivers/nvme/host/multipath.c | 33 ++++++++++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 9b9a657fa330..dbf09cdda815 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -305,16 +305,45 @@ static bool nvme_path_is_disabled(struct nvme_ns *ns)
return false;
}
+static bool nvme_path_is_usable(struct nvme_ns *ns)
+{
+ /* Only NVME_ANA_OPTIMIZED and NVME_ANA_NONOPTIMIZED are usable */
+ return !nvme_path_is_disabled(ns) &&
+ (ns->ana_state == NVME_ANA_OPTIMIZED ||
+ ns->ana_state == NVME_ANA_NONOPTIMIZED);
+}
+
+static bool nvme_all_paths_marginal(struct nvme_ns_head *head)
+{
+ struct nvme_ns *ns;
+
+ list_for_each_entry_srcu(ns, &head->list, siblings,
+ srcu_read_lock_held(&head->srcu)) {
+ /* skip paths which can not be used */
+ if (!nvme_path_is_usable(ns))
+ continue;
+ if (!nvme_ctrl_is_marginal(ns->ctrl))
+ return false;
+ }
+
+ return true;
+}
+
static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head, int node)
{
int found_distance = INT_MAX, fallback_distance = INT_MAX, distance;
struct nvme_ns *found = NULL, *fallback = NULL, *ns;
+ bool need_marginal = nvme_all_paths_marginal(head);
list_for_each_entry_srcu(ns, &head->list, siblings,
srcu_read_lock_held(&head->srcu)) {
if (nvme_path_is_disabled(ns))
continue;
+ /* Skip marginal paths unless we need to use them */
+ if (!need_marginal && nvme_ctrl_is_marginal(ns->ctrl))
+ continue;
+
if (ns->ctrl->numa_node != NUMA_NO_NODE &&
READ_ONCE(head->subsys->iopolicy) == NVME_IOPOLICY_NUMA)
distance = node_distance(node, ns->ctrl->numa_node);
@@ -339,6 +368,7 @@ static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head, int node)
}
}
+ /* No optimized path found, use the fallback */
if (!found)
found = fallback;
if (found)
@@ -444,7 +474,8 @@ static struct nvme_ns *nvme_queue_depth_path(struct nvme_ns_head *head)
static inline bool nvme_path_is_optimized(struct nvme_ns *ns)
{
return nvme_ctrl_state(ns->ctrl) == NVME_CTRL_LIVE &&
- ns->ana_state == NVME_ANA_OPTIMIZED;
+ ns->ana_state == NVME_ANA_OPTIMIZED &&
+ !nvme_ctrl_is_marginal(ns->ctrl);
}
static struct nvme_ns *nvme_numa_path(struct nvme_ns_head *head)
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 3/7] nvme-multipath: queue-depth support for marginal paths
2026-09-02 20:05 [PATCH v2 0/7] nvme-fc: FPIN link integrity handling Jesse Taube
2026-09-02 20:05 ` [PATCH v2 1/7] nvme: add NVME_CTRL_MARGINAL flag Jesse Taube
2026-09-02 20:05 ` [PATCH v2 2/7] nvme-multipath: numa support for marginal paths Jesse Taube
@ 2026-09-02 20:05 ` Jesse Taube
2026-09-02 20:05 ` [PATCH v2 4/7] nvme-multipath: round-robin " Jesse Taube
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Jesse Taube @ 2026-09-02 20:05 UTC (permalink / raw)
To: linux-nvme
Cc: linux-scsi, Jonathan Corbet, Shuah Khan, Keith Busch, Jens Axboe,
Christoph Hellwig, Sagi Grimberg, Justin Tee, Naresh Gottumukkala,
Paul Ely, Chaitanya Kulkarni, James E.J. Bottomley,
Martin K. Petersen, Nilesh Javali, GR-QLogic-Storage-Upstream,
Hannes Reinecke, Jesse Taube, Gustavo A. R. Silva, John Meneghini,
Bryan Gurney, Chris Leech, Ewan D . Milne, shinichiro.kawasaki,
linux-doc, linux-kernel, linux-block
From: John Meneghini <jmeneghi@redhat.com>
Exclude marginal paths from queue-depth io policy. In the case where all
paths are marginal and no optimized or non-optimized path is found, we
fall back and select the best marginal path.
Signed-off-by: Jesse Taube <jtaubepe@redhat.com>
Signed-off-by: John Meneghini <jmeneghi@redhat.com>
---
V10 -> V1:
- New commit
V1 -> V2:
- Rewrite
---
drivers/nvme/host/multipath.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index dbf09cdda815..f28797deab68 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -439,12 +439,17 @@ static struct nvme_ns *nvme_queue_depth_path(struct nvme_ns_head *head)
struct nvme_ns *best_opt = NULL, *best_nonopt = NULL, *ns;
unsigned int min_depth_opt = UINT_MAX, min_depth_nonopt = UINT_MAX;
unsigned int depth;
+ bool need_marginal = nvme_all_paths_marginal(head);
list_for_each_entry_srcu(ns, &head->list, siblings,
srcu_read_lock_held(&head->srcu)) {
if (nvme_path_is_disabled(ns))
continue;
+ /* Skip marginal paths unless we need to use them */
+ if (!need_marginal && nvme_ctrl_is_marginal(ns->ctrl))
+ continue;
+
depth = atomic_read(&ns->ctrl->nr_active);
switch (ns->ana_state) {
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 4/7] nvme-multipath: round-robin support for marginal paths
2026-09-02 20:05 [PATCH v2 0/7] nvme-fc: FPIN link integrity handling Jesse Taube
` (2 preceding siblings ...)
2026-09-02 20:05 ` [PATCH v2 3/7] nvme-multipath: queue-depth " Jesse Taube
@ 2026-09-02 20:05 ` Jesse Taube
2026-09-02 20:05 ` [PATCH v2 5/7] nvme: sysfs: emit the marginal path state in show_state() Jesse Taube
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Jesse Taube @ 2026-09-02 20:05 UTC (permalink / raw)
To: linux-nvme
Cc: linux-scsi, Jonathan Corbet, Shuah Khan, Keith Busch, Jens Axboe,
Christoph Hellwig, Sagi Grimberg, Justin Tee, Naresh Gottumukkala,
Paul Ely, Chaitanya Kulkarni, James E.J. Bottomley,
Martin K. Petersen, Nilesh Javali, GR-QLogic-Storage-Upstream,
Hannes Reinecke, Jesse Taube, Gustavo A. R. Silva, John Meneghini,
Bryan Gurney, Chris Leech, Ewan D . Milne, shinichiro.kawasaki,
linux-doc, linux-kernel, linux-block
Exclude marginal paths from round-robin io policy. In the case where all
paths are marginal and no optimized or non-optimized path is found, we
fall back and perform round-robin on the marginal paths.
Signed-off-by: Jesse Taube <jtaubepe@redhat.com>
---
V10 -> V1:
- New commit
V1 -> V2:
- Rewrite
---
drivers/nvme/host/multipath.c | 32 +++++++++++++++++++++++++-------
1 file changed, 25 insertions(+), 7 deletions(-)
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index f28797deab68..738e3c742b74 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -392,22 +392,29 @@ static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head)
int node = numa_node_id();
struct nvme_ns *old = srcu_dereference(head->current_path[node],
&head->srcu);
+ bool need_marginal;
if (unlikely(!old))
return __nvme_find_path(head, node);
if (list_is_singular(&head->list)) {
- if (nvme_path_is_disabled(old))
- return NULL;
- return old;
+ if (nvme_path_is_usable(old))
+ return old;
+ return NULL;
}
+ need_marginal = nvme_all_paths_marginal(head);
+
for (ns = nvme_next_ns(head, old);
ns && ns != old;
ns = nvme_next_ns(head, ns)) {
if (nvme_path_is_disabled(ns))
continue;
+ /* Skip marginal paths unless we need to use them */
+ if (!need_marginal && nvme_ctrl_is_marginal(ns->ctrl))
+ continue;
+
if (ns->ana_state == NVME_ANA_OPTIMIZED) {
found = ns;
goto out;
@@ -419,12 +426,23 @@ static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head)
/*
* The loop above skips the current path for round-robin semantics.
* Fall back to the current path if either:
- * - no other optimized path found and current is optimized,
+ * - no other optimized path found and current is,
+ * optimized and not marginal.
+ * - no other non-marginal path found and current is,
+ * optimized and marginal.
* - no other usable path found and current is usable.
*/
- if (!nvme_path_is_disabled(old) &&
- (old->ana_state == NVME_ANA_OPTIMIZED ||
- (!found && old->ana_state == NVME_ANA_NONOPTIMIZED)))
+ /* no other usable path found and current is usable. */
+ if (nvme_path_is_usable(old) && !found)
+ return old;
+ /*
+ * - no other optimized path found and current is,
+ * optimized and not marginal.
+ * - no other non-marginal path found and current is,
+ * optimized and marginal.
+ */
+ if (nvme_path_is_usable(old) && old->ana_state == NVME_ANA_OPTIMIZED &&
+ (!nvme_ctrl_is_marginal(old->ctrl) || need_marginal))
return old;
if (!found)
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 5/7] nvme: sysfs: emit the marginal path state in show_state()
2026-09-02 20:05 [PATCH v2 0/7] nvme-fc: FPIN link integrity handling Jesse Taube
` (3 preceding siblings ...)
2026-09-02 20:05 ` [PATCH v2 4/7] nvme-multipath: round-robin " Jesse Taube
@ 2026-09-02 20:05 ` Jesse Taube
2026-09-02 20:05 ` [PATCH v2 6/7] nvme-fc: add nvme_fc_set_remoteport_fpin() Jesse Taube
2026-09-02 20:05 ` [PATCH v2 7/7] nvme: fcloop: Add set_marginal_rport to sysfs Jesse Taube
6 siblings, 0 replies; 8+ messages in thread
From: Jesse Taube @ 2026-09-02 20:05 UTC (permalink / raw)
To: linux-nvme
Cc: linux-scsi, Jonathan Corbet, Shuah Khan, Keith Busch, Jens Axboe,
Christoph Hellwig, Sagi Grimberg, Justin Tee, Naresh Gottumukkala,
Paul Ely, Chaitanya Kulkarni, James E.J. Bottomley,
Martin K. Petersen, Nilesh Javali, GR-QLogic-Storage-Upstream,
Hannes Reinecke, Jesse Taube, Gustavo A. R. Silva, John Meneghini,
Bryan Gurney, Chris Leech, Ewan D . Milne, shinichiro.kawasaki,
linux-doc, linux-kernel, linux-block, Muneendra Kumar
From: Bryan Gurney <bgurney@redhat.com>
If a controller has received a link integrity or congestion event, and
has the NVME_CTRL_MARGINAL flag set, emit "marginal" in the state
instead of "live", to identify the marginal paths.
Co-developed-by: John Meneghini <jmeneghi@redhat.com>
Signed-off-by: John Meneghini <jmeneghi@redhat.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Tested-by: Muneendra Kumar <muneendra.kumar@broadcom.com>
Signed-off-by: Bryan Gurney <bgurney@redhat.com>
---
V10 -> V1:
- No change
V1 -> V2:
- Only emit "marginal" if port is "live"
---
drivers/nvme/host/sysfs.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/nvme/host/sysfs.c b/drivers/nvme/host/sysfs.c
index 75b2d69b5957..9ede6b37f27a 100644
--- a/drivers/nvme/host/sysfs.c
+++ b/drivers/nvme/host/sysfs.c
@@ -526,6 +526,9 @@ static ssize_t nvme_sysfs_show_state(struct device *dev,
[NVME_CTRL_DEAD] = "dead",
};
+ if (state == NVME_CTRL_LIVE && nvme_ctrl_is_marginal(ctrl))
+ return sysfs_emit(buf, "%s\n", "marginal");
+
if (state < ARRAY_SIZE(state_name) && state_name[state])
return sysfs_emit(buf, "%s\n", state_name[state]);
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 6/7] nvme-fc: add nvme_fc_set_remoteport_fpin()
2026-09-02 20:05 [PATCH v2 0/7] nvme-fc: FPIN link integrity handling Jesse Taube
` (4 preceding siblings ...)
2026-09-02 20:05 ` [PATCH v2 5/7] nvme: sysfs: emit the marginal path state in show_state() Jesse Taube
@ 2026-09-02 20:05 ` Jesse Taube
2026-09-02 20:05 ` [PATCH v2 7/7] nvme: fcloop: Add set_marginal_rport to sysfs Jesse Taube
6 siblings, 0 replies; 8+ messages in thread
From: Jesse Taube @ 2026-09-02 20:05 UTC (permalink / raw)
To: linux-nvme
Cc: linux-scsi, Jonathan Corbet, Shuah Khan, Keith Busch, Jens Axboe,
Christoph Hellwig, Sagi Grimberg, Justin Tee, Naresh Gottumukkala,
Paul Ely, Chaitanya Kulkarni, James E.J. Bottomley,
Martin K. Petersen, Nilesh Javali, GR-QLogic-Storage-Upstream,
Hannes Reinecke, Jesse Taube, Gustavo A. R. Silva, John Meneghini,
Bryan Gurney, Chris Leech, Ewan D . Milne, shinichiro.kawasaki,
linux-doc, linux-kernel, linux-block, Hannes Reinecke
Add nvme_fc_set_remoteport_fpin() and supporting functions. This
function is called by the SCSI FC transport and driver layer to set or
clear the 'marginal' path status for a specific rport.
Co-developed-by: Hannes Reinecke <hare@kernel.org>
Signed-off-by: Hannes Reinecke <hare@kernel.org>
Signed-off-by: John Meneghini <jmeneghi@redhat.com>
Signed-off-by: Jesse Taube <jtaubepe@redhat.com>
---
V10 -> V1:
- Remove nvme_fc_modify_rport_fpin_state
- Use struct nvme_fc_remote_port instead of wwpn and wwnn
V1 -> V2:
- Use nvme_ctrl_assign_marginal over set/clear_bit
---
drivers/nvme/host/fc.c | 13 +++++++++++++
include/linux/nvme-fc-driver.h | 2 ++
2 files changed, 15 insertions(+)
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c
index 7886c0dcc626..c4810d048b87 100644
--- a/drivers/nvme/host/fc.c
+++ b/drivers/nvme/host/fc.c
@@ -895,6 +895,19 @@ nvme_fc_set_remoteport_devloss(struct nvme_fc_remote_port *portptr,
}
EXPORT_SYMBOL_GPL(nvme_fc_set_remoteport_devloss);
+void
+nvme_fc_set_remoteport_fpin(struct nvme_fc_remote_port *portptr, bool marginal)
+{
+ struct nvme_fc_rport *rport = remoteport_to_rport(portptr);
+ struct nvme_fc_ctrl *ctrl;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rport->lock, flags);
+ list_for_each_entry(ctrl, &rport->ctrl_list, ctrl_list)
+ nvme_ctrl_assign_marginal(&ctrl->ctrl, marginal);
+ spin_unlock_irqrestore(&rport->lock, flags);
+}
+EXPORT_SYMBOL_GPL(nvme_fc_set_remoteport_fpin);
/* *********************** FC-NVME DMA Handling **************************** */
diff --git a/include/linux/nvme-fc-driver.h b/include/linux/nvme-fc-driver.h
index 9f6acadfe0c8..95d79386d126 100644
--- a/include/linux/nvme-fc-driver.h
+++ b/include/linux/nvme-fc-driver.h
@@ -536,6 +536,8 @@ void nvme_fc_rescan_remoteport(struct nvme_fc_remote_port *remoteport);
int nvme_fc_set_remoteport_devloss(struct nvme_fc_remote_port *remoteport,
u32 dev_loss_tmo);
+void nvme_fc_set_remoteport_fpin(struct nvme_fc_remote_port *portptr, bool marginal);
+
/*
* Routine called to pass a NVME-FC LS request, received by the lldd,
* to the nvme-fc transport.
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 7/7] nvme: fcloop: Add set_marginal_rport to sysfs
2026-09-02 20:05 [PATCH v2 0/7] nvme-fc: FPIN link integrity handling Jesse Taube
` (5 preceding siblings ...)
2026-09-02 20:05 ` [PATCH v2 6/7] nvme-fc: add nvme_fc_set_remoteport_fpin() Jesse Taube
@ 2026-09-02 20:05 ` Jesse Taube
6 siblings, 0 replies; 8+ messages in thread
From: Jesse Taube @ 2026-09-02 20:05 UTC (permalink / raw)
To: linux-nvme
Cc: linux-scsi, Jonathan Corbet, Shuah Khan, Keith Busch, Jens Axboe,
Christoph Hellwig, Sagi Grimberg, Justin Tee, Naresh Gottumukkala,
Paul Ely, Chaitanya Kulkarni, James E.J. Bottomley,
Martin K. Petersen, Nilesh Javali, GR-QLogic-Storage-Upstream,
Hannes Reinecke, Jesse Taube, Gustavo A. R. Silva, John Meneghini,
Bryan Gurney, Chris Leech, Ewan D . Milne, shinichiro.kawasaki,
linux-doc, linux-kernel, linux-block
To allow testing of multipath failover, add a sysfs attribute to set a
remote port as marginal. This will allow the fcloop LLDD to set the
marginal flag on a remote port, simulating a marginal link.
Example:
Turn on marginal for a remote port matching wwnn and wwpn:
`echo 'wwnn=0x200000109b5f2956,wwpn=0x100000109b5f2956,marginal=1' >
/sys/class/fcloop/ctl/set_marginal_rport`
Turn off marginal for a remote port matching wwnn and wwpn:
`echo 'wwnn=0x200000109b5f2956,wwpn=0x100000109b5f2956,marginal=0' >
/sys/class/fcloop/ctl/set_marginal_rport`
Suggested-by: John Meneghini <jmeneghi@redhat.com>
Signed-off-by: Jesse Taube <jtaubepe@redhat.com>
V10 -> V1:
- New patch
V1 -> V2:
- Fix reference count leak in error path
---
drivers/nvme/target/fcloop.c | 50 ++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c
index b63af3b643a6..9977c2a71bd5 100644
--- a/drivers/nvme/target/fcloop.c
+++ b/drivers/nvme/target/fcloop.c
@@ -6,6 +6,7 @@
#include <linux/module.h>
#include <linux/parser.h>
#include <uapi/scsi/fc/fc_fs.h>
+#include <uapi/scsi/fc/fc_els.h>
#include "../host/nvme.h"
#include "../target/nvmet.h"
@@ -21,6 +22,7 @@ enum {
NVMF_OPT_FCADDR = 1 << 3,
NVMF_OPT_LPWWNN = 1 << 4,
NVMF_OPT_LPWWPN = 1 << 5,
+ NVMF_OPT_MARGINAL = 1 << 6,
};
struct fcloop_ctrl_options {
@@ -31,6 +33,7 @@ struct fcloop_ctrl_options {
u32 fcaddr;
u64 lpwwnn;
u64 lpwwpn;
+ u32 marginal;
};
static const match_table_t opt_tokens = {
@@ -40,6 +43,7 @@ static const match_table_t opt_tokens = {
{ NVMF_OPT_FCADDR, "fcaddr=%x" },
{ NVMF_OPT_LPWWNN, "lpwwnn=%s" },
{ NVMF_OPT_LPWWPN, "lpwwpn=%s" },
+ { NVMF_OPT_MARGINAL, "marginal=%d" },
{ NVMF_OPT_ERR, NULL }
};
@@ -120,6 +124,13 @@ fcloop_parse_options(struct fcloop_ctrl_options *opts,
}
opts->lpwwpn = token64;
break;
+ case NVMF_OPT_MARGINAL:
+ if (match_int(args, &token)) {
+ ret = -EINVAL;
+ goto out_free_options;
+ }
+ opts->marginal = token;
+ break;
default:
pr_warn("unknown parameter or missing value '%s'\n", p);
ret = -EINVAL;
@@ -199,6 +210,9 @@ fcloop_parse_nm_options(struct device *dev, u64 *nname, u64 *pname,
#define TGTPORT_OPTS (NVMF_OPT_WWNN | NVMF_OPT_WWPN)
+#define MARGINAL_OPTS (NVMF_OPT_WWNN | NVMF_OPT_WWPN | \
+ NVMF_OPT_MARGINAL)
+
static DEFINE_SPINLOCK(fcloop_lock);
static LIST_HEAD(fcloop_lports);
@@ -1663,6 +1677,40 @@ fcloop_set_cmd_drop(struct device *dev, struct device_attribute *attr,
return count;
}
+static ssize_t
+fcloop_set_marginal_rport(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fcloop_nport *nport;
+ struct fcloop_ctrl_options opts = {};
+ unsigned long flags;
+ int ret;
+
+ ret = fcloop_parse_options(&opts, buf);
+ if (ret)
+ return ret;
+
+ /* everything there ? */
+ if ((opts.mask & MARGINAL_OPTS) != MARGINAL_OPTS)
+ return -EINVAL;
+
+ nport = fcloop_nport_lookup(opts.wwnn, opts.wwpn);
+ if (!nport)
+ return -ENOENT;
+
+ spin_lock_irqsave(&fcloop_lock, flags);
+ if (!nport->rport || !nport->rport->remoteport) {
+ spin_unlock_irqrestore(&fcloop_lock, flags);
+ fcloop_nport_put(nport);
+ return -ENOENT;
+ }
+
+ nvme_fc_set_remoteport_fpin(nport->rport->remoteport, opts.marginal);
+ spin_unlock_irqrestore(&fcloop_lock, flags);
+ fcloop_nport_put(nport);
+
+ return count;
+}
static DEVICE_ATTR(add_local_port, 0200, NULL, fcloop_create_local_port);
static DEVICE_ATTR(del_local_port, 0200, NULL, fcloop_delete_local_port);
@@ -1671,6 +1719,7 @@ static DEVICE_ATTR(del_remote_port, 0200, NULL, fcloop_delete_remote_port);
static DEVICE_ATTR(add_target_port, 0200, NULL, fcloop_create_target_port);
static DEVICE_ATTR(del_target_port, 0200, NULL, fcloop_delete_target_port);
static DEVICE_ATTR(set_cmd_drop, 0200, NULL, fcloop_set_cmd_drop);
+static DEVICE_ATTR(set_marginal_rport, 0200, NULL, fcloop_set_marginal_rport);
static struct attribute *fcloop_dev_attrs[] = {
&dev_attr_add_local_port.attr,
@@ -1680,6 +1729,7 @@ static struct attribute *fcloop_dev_attrs[] = {
&dev_attr_add_target_port.attr,
&dev_attr_del_target_port.attr,
&dev_attr_set_cmd_drop.attr,
+ &dev_attr_set_marginal_rport.attr,
NULL
};
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-09-02 20:06 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-02 20:05 [PATCH v2 0/7] nvme-fc: FPIN link integrity handling Jesse Taube
2026-09-02 20:05 ` [PATCH v2 1/7] nvme: add NVME_CTRL_MARGINAL flag Jesse Taube
2026-09-02 20:05 ` [PATCH v2 2/7] nvme-multipath: numa support for marginal paths Jesse Taube
2026-09-02 20:05 ` [PATCH v2 3/7] nvme-multipath: queue-depth " Jesse Taube
2026-09-02 20:05 ` [PATCH v2 4/7] nvme-multipath: round-robin " Jesse Taube
2026-09-02 20:05 ` [PATCH v2 5/7] nvme: sysfs: emit the marginal path state in show_state() Jesse Taube
2026-09-02 20:05 ` [PATCH v2 6/7] nvme-fc: add nvme_fc_set_remoteport_fpin() Jesse Taube
2026-09-02 20:05 ` [PATCH v2 7/7] nvme: fcloop: Add set_marginal_rport to sysfs Jesse Taube
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox