[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