[dm-devel] [PATCH 5/6] libmultipath: Implement sysfs_set_fc_rport_state()

Hannes Reinecke hare at suse.de
Thu Mar 14 14:08:47 UTC 2013


In a faulty fabric FC HBAs might not be able to update the status
of the remote ports, resulting in I/O to be stuck as the normal
'fast_io_fail' mechanism it never invoked.

To handle these cases I've implemented a function
sysfs_set_fc_rport_state() which allows multipath to
forcibly set the rport state to 'blocked', causing the
fast_io_fail mechanism to be invoked, which eventually
will abort all stuck I/O.

This patch relies on the patch
scsi_transport_fc: Make 'port_state' writeable
posted to linux-scsi.

Signed-off-by: Hannes Reinecke <hare at suse.de>
---
 libmultipath/discovery.c |   60 ++++++++++++++++++++++++++++++++++++++++++++++
 libmultipath/discovery.h |    1 +
 2 files changed, 61 insertions(+)

diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
index 58ce533..3b60125 100644
--- a/libmultipath/discovery.c
+++ b/libmultipath/discovery.c
@@ -476,6 +476,66 @@ sysfs_set_scsi_tmo (struct multipath *mpp)
 }
 
 int
+sysfs_set_fc_rport_state (struct path *pp, int blocked)
+{
+	struct udev_device *rport_dev = NULL;
+	char rport_id[32];
+	char value[NAME_SIZE];
+	int retval = 0;
+
+	if (pp->bus != SYSFS_BUS_SCSI) {
+		condlog(4, "%s: no FC settings on non-SCSI device", pp->dev);
+		return 0;
+	}
+
+	sprintf(rport_id, "rport-%d:%d-%d",
+		pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
+	rport_dev = udev_device_new_from_subsystem_sysname(conf->udev,
+				"fc_remote_ports", rport_id);
+	if (!rport_dev) {
+		condlog(1, "%s: No fc_remote_port device for '%s'", pp->dev,
+			rport_id);
+		return 0;
+	}
+
+	if (sysfs_attr_get_value(rport_dev, "port_state",
+				 value, 16) <= 0) {
+		condlog(1, "%s: failed to read rport state from '%s'",
+			pp->dev, rport_id);
+		retval = EBADF;
+		goto out;
+	}
+	condlog(3, "%s: rport state '%s'", pp->dev, value);
+	if (blocked) {
+		/* Can only transition Online -> Blocked */
+		if (strncmp(value, "Online", 6)) {
+			retval = EAGAIN;
+			goto out;
+		}
+		sprintf(value, "Blocked");
+	} else {
+		/* Can only transition Blocked -> Online */
+		if (strncmp(value, "Blocked", 7)) {
+			retval = EAGAIN;
+			goto out;
+		}
+
+		sprintf(value, "Online");
+	}
+
+	if (sysfs_attr_set_value(rport_dev, "port_state",
+				 value, strlen(value)) <= 0) {
+		condlog(1, "%s: failed to set rport to '%s', error %d",
+			pp->dev, value, errno);
+		retval = ENXIO;
+	}
+out:
+	udev_device_unref(rport_dev);
+
+	return retval;
+}
+
+int
 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
        void *resp, int mx_resp_len)
 {
diff --git a/libmultipath/discovery.h b/libmultipath/discovery.h
index 1a614ee..38b61dc 100644
--- a/libmultipath/discovery.h
+++ b/libmultipath/discovery.h
@@ -38,6 +38,7 @@ int store_pathinfo (vector pathvec, vector hwtable,
 		    struct path **pp_ptr);
 int sysfs_set_scsi_tmo (struct multipath *mpp);
 int sysfs_get_timeout(struct path *pp, unsigned int *timeout);
+int sysfs_set_fc_rport_state(struct path *pp, int blocked);
 
 /*
  * discovery bitmask
-- 
1.7.10.4




More information about the dm-devel mailing list