From: John Meneghini Refactor and fc_rport_set_marginal_state smp safe by holding `shost->host_lock` around all `rport->port_state` accesses. Call nvme_fc_modify_rport_fpin_state() when FC_PORTSTATE_MARGINAL is set or cleared. This allows the user to quickly set or clear the NVME_CTRL_MARGINAL state from sysfs. E.g.: echo "Marginal" > /sys/class/fc_remote_ports/rport-13:0-5/port_state echo "Online" > /sys/class/fc_remote_ports/rport-13:0-5/port_state Note: nvme_fc_modify_rport_fpin_state() will only affect rports that have FC_PORT_ROLE_NVME_TARGET set. Signed-off-by: John Meneghini --- V10 -> V11: - No change --- drivers/scsi/scsi_transport_fc.c | 42 +++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index df1edf3c23fa..af309a7bdc22 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -1251,34 +1251,58 @@ static ssize_t fc_rport_set_marginal_state(struct device *dev, const char *buf, size_t count) { struct fc_rport *rport = transport_class_to_rport(dev); + struct Scsi_Host *shost = rport_to_shost(rport); + struct fc_internal *i = to_fc_internal(shost->transportt); enum fc_port_state port_state; int ret = 0; + unsigned long flags; ret = get_fc_port_state_match(buf, &port_state); if (ret) return -EINVAL; - if (port_state == FC_PORTSTATE_MARGINAL) { + + spin_lock_irqsave(shost->host_lock, flags); + + switch (port_state) { + case FC_PORTSTATE_MARGINAL: /* * Change the state to Marginal only if the * current rport state is Online * Allow only Online->Marginal */ - if (rport->port_state == FC_PORTSTATE_ONLINE) + if (rport->port_state == FC_PORTSTATE_ONLINE) { rport->port_state = port_state; - else if (port_state != rport->port_state) - return -EINVAL; - } else if (port_state == FC_PORTSTATE_ONLINE) { + spin_unlock_irqrestore(shost->host_lock, flags); + if (i->f->set_rport_marginal) + i->f->set_rport_marginal(rport, true); + return count; + } + break; + + case FC_PORTSTATE_ONLINE: /* * Change the state to Online only if the * current rport state is Marginal * Allow only Marginal->Online */ - if (rport->port_state == FC_PORTSTATE_MARGINAL) + if (rport->port_state == FC_PORTSTATE_MARGINAL) { rport->port_state = port_state; - else if (port_state != rport->port_state) - return -EINVAL; - } else + spin_unlock_irqrestore(shost->host_lock, flags); + if (i->f->set_rport_marginal) + i->f->set_rport_marginal(rport, false); + return count; + } + break; + default: + break; + } + + if (port_state != rport->port_state) { + spin_unlock_irqrestore(shost->host_lock, flags); return -EINVAL; + } + + spin_unlock_irqrestore(shost->host_lock, flags); return count; } -- 2.54.0