summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_transport_fc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/scsi_transport_fc.c')
-rw-r--r--drivers/scsi/scsi_transport_fc.c50
1 files changed, 33 insertions, 17 deletions
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 653f22a8deb..1d5b72173dd 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -475,7 +475,8 @@ MODULE_PARM_DESC(dev_loss_tmo,
"Maximum number of seconds that the FC transport should"
" insulate the loss of a remote port. Once this value is"
" exceeded, the scsi target is removed. Value should be"
- " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT.");
+ " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT if"
+ " fast_io_fail_tmo is not set.");
/*
* Netlink Infrastructure
@@ -842,9 +843,17 @@ store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr,
(rport->port_state == FC_PORTSTATE_NOTPRESENT))
return -EBUSY;
val = simple_strtoul(buf, &cp, 0);
- if ((*cp && (*cp != '\n')) ||
- (val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT))
+ if ((*cp && (*cp != '\n')) || (val < 0))
return -EINVAL;
+
+ /*
+ * If fast_io_fail is off we have to cap
+ * dev_loss_tmo at SCSI_DEVICE_BLOCK_MAX_TIMEOUT
+ */
+ if (rport->fast_io_fail_tmo == -1 &&
+ val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
+ return -EINVAL;
+
i->f->set_rport_dev_loss_tmo(rport, val);
return count;
}
@@ -925,9 +934,16 @@ store_fc_rport_fast_io_fail_tmo(struct device *dev,
rport->fast_io_fail_tmo = -1;
else {
val = simple_strtoul(buf, &cp, 0);
- if ((*cp && (*cp != '\n')) ||
- (val < 0) || (val >= rport->dev_loss_tmo))
+ if ((*cp && (*cp != '\n')) || (val < 0))
+ return -EINVAL;
+ /*
+ * Cap fast_io_fail by dev_loss_tmo or
+ * SCSI_DEVICE_BLOCK_MAX_TIMEOUT.
+ */
+ if ((val >= rport->dev_loss_tmo) ||
+ (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT))
return -EINVAL;
+
rport->fast_io_fail_tmo = val;
}
return count;
@@ -1216,6 +1232,15 @@ store_fc_vport_delete(struct device *dev, struct device_attribute *attr,
{
struct fc_vport *vport = transport_class_to_vport(dev);
struct Scsi_Host *shost = vport_to_shost(vport);
+ unsigned long flags;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) {
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ return -EBUSY;
+ }
+ vport->flags |= FC_VPORT_DELETING;
+ spin_unlock_irqrestore(shost->host_lock, flags);
fc_queue_work(shost, &vport->vport_delete_work);
return count;
@@ -1805,6 +1830,9 @@ store_fc_host_vport_delete(struct device *dev, struct device_attribute *attr,
list_for_each_entry(vport, &fc_host->vports, peers) {
if ((vport->channel == 0) &&
(vport->port_name == wwpn) && (vport->node_name == wwnn)) {
+ if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING))
+ break;
+ vport->flags |= FC_VPORT_DELETING;
match = 1;
break;
}
@@ -3354,18 +3382,6 @@ fc_vport_terminate(struct fc_vport *vport)
unsigned long flags;
int stat;
- spin_lock_irqsave(shost->host_lock, flags);
- if (vport->flags & FC_VPORT_CREATING) {
- spin_unlock_irqrestore(shost->host_lock, flags);
- return -EBUSY;
- }
- if (vport->flags & (FC_VPORT_DEL)) {
- spin_unlock_irqrestore(shost->host_lock, flags);
- return -EALREADY;
- }
- vport->flags |= FC_VPORT_DELETING;
- spin_unlock_irqrestore(shost->host_lock, flags);
-
if (i->f->vport_delete)
stat = i->f->vport_delete(vport);
else