Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/nvme/host/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -5074,6 +5074,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);
clear_bit(NVME_CTRL_MARGINAL, &ctrl->flags);
spin_lock_init(&ctrl->lock);
mutex_init(&ctrl->namespaces_lock);

Expand Down
80 changes: 80 additions & 0 deletions drivers/nvme/host/fc.c
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,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 */
clear_bit(NVME_CTRL_MARGINAL, &ctrl->flags);

nvme_reset_ctrl(&ctrl->ctrl);
}

Expand Down Expand Up @@ -3726,6 +3730,82 @@ static struct nvmf_transport_ops nvme_fc_transport = {
.create_ctrl = nvme_fc_create_ctrl,
};

static struct nvme_fc_rport *nvme_fc_rport_from_wwpn(struct nvme_fc_lport *lport,
u64 rport_wwpn)
{
struct nvme_fc_rport *rport;
unsigned long flags;

spin_lock_irqsave(&nvme_fc_lock, flags);
list_for_each_entry(rport, &lport->endp_list, endp_list) {
if (!nvme_fc_rport_get(rport))
continue;
if (rport->remoteport.port_name == rport_wwpn &&
rport->remoteport.port_role & FC_PORT_ROLE_NVME_TARGET) {
spin_unlock_irqrestore(&nvme_fc_lock, flags);
return rport;
}
nvme_fc_rport_put(rport);
}
spin_unlock_irqrestore(&nvme_fc_lock, flags);
return NULL;
}

static struct nvme_fc_lport *
nvme_fc_lport_from_wwpn(u64 wwpn)
{
struct nvme_fc_lport *lport;
unsigned long flags;

spin_lock_irqsave(&nvme_fc_lock, flags);
list_for_each_entry(lport, &nvme_fc_lport_list, port_list) {
if (lport->localport.port_name == wwpn &&
lport->localport.port_state == FC_OBJSTATE_ONLINE) {
if (nvme_fc_lport_get(lport)) {
spin_unlock_irqrestore(&nvme_fc_lock, flags);
return lport;
}
}
}
spin_unlock_irqrestore(&nvme_fc_lock, flags);
return NULL;
}

static void
nvme_fc_fpin_set_state(struct nvme_fc_lport *lport, u64 wwpn, bool marginal)
{
struct nvme_fc_rport *rport;
struct nvme_fc_ctrl *ctrl;

rport = nvme_fc_rport_from_wwpn(lport, wwpn);
if (!rport)
return;

spin_lock_irq(&rport->lock);
list_for_each_entry(ctrl, &rport->ctrl_list, ctrl_list) {
if (marginal)
set_bit(NVME_CTRL_MARGINAL, &ctrl->ctrl.flags);
else
clear_bit(NVME_CTRL_MARGINAL, &ctrl->ctrl.flags);
}
spin_unlock_irq(&rport->lock);
nvme_fc_rport_put(rport);
}

void
nvme_fc_modify_rport_fpin_state(u64 local_wwpn, u64 remote_wwpn, bool marginal)
{
struct nvme_fc_lport *lport;

lport = nvme_fc_lport_from_wwpn(local_wwpn);
if (!lport)
return;

nvme_fc_fpin_set_state(lport, remote_wwpn, marginal);
nvme_fc_lport_put(lport);
}
EXPORT_SYMBOL_GPL(nvme_fc_modify_rport_fpin_state);

/* Arbitrary successive failures max. With lots of subsystems could be high */
#define DISCOVERY_MAX_FAIL 20

Expand Down
24 changes: 17 additions & 7 deletions drivers/nvme/host/multipath.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,11 +324,14 @@ static struct nvme_ns *__nvme_find_path(struct nvme_ns_head *head, int node)

switch (ns->ana_state) {
case NVME_ANA_OPTIMIZED:
if (distance < found_distance) {
found_distance = distance;
found = ns;
if (!nvme_ctrl_is_marginal(ns->ctrl)) {
if (distance < found_distance) {
found_distance = distance;
found = ns;
}
break;
}
break;
fallthrough;
case NVME_ANA_NONOPTIMIZED:
if (distance < fallback_distance) {
fallback_distance = distance;
Expand Down Expand Up @@ -381,7 +384,8 @@ static struct nvme_ns *nvme_round_robin_path(struct nvme_ns_head *head)

if (ns->ana_state == NVME_ANA_OPTIMIZED) {
found = ns;
goto out;
if (!nvme_ctrl_is_marginal(ns->ctrl))
goto out;
}
if (ns->ana_state == NVME_ANA_NONOPTIMIZED)
found = ns;
Expand Down Expand Up @@ -416,6 +420,9 @@ static struct nvme_ns *nvme_queue_depth_path(struct nvme_ns_head *head)
if (nvme_path_is_disabled(ns))
continue;

if (nvme_ctrl_is_marginal(ns->ctrl))
continue;

depth = atomic_read(&ns->ctrl->nr_active);

switch (ns->ana_state) {
Expand All @@ -439,13 +446,16 @@ static struct nvme_ns *nvme_queue_depth_path(struct nvme_ns_head *head)
return best_opt;
}

return best_opt ? best_opt : best_nonopt;
best_opt = (best_opt) ? best_opt : best_nonopt;

return best_opt ? best_opt : __nvme_find_path(head, numa_node_id());
}

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)
Expand Down
6 changes: 6 additions & 0 deletions drivers/nvme/host/nvme.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,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 {
Expand Down Expand Up @@ -417,6 +418,11 @@ 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);
}

enum nvme_iopolicy {
NVME_IOPOLICY_NUMA,
NVME_IOPOLICY_RR,
Expand Down
4 changes: 3 additions & 1 deletion drivers/nvme/host/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,9 @@ static ssize_t nvme_sysfs_show_state(struct device *dev,
};

if (state < ARRAY_SIZE(state_name) && state_name[state])
return sysfs_emit(buf, "%s\n", state_name[state]);
return sysfs_emit(buf, "%s\n",
(nvme_ctrl_is_marginal(ctrl)) ? "marginal" :
state_name[state]);

return sysfs_emit(buf, "unknown state\n");
}
Expand Down
Loading