summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/scsi_transport_sas.c43
-rw-r--r--include/scsi/scsi_transport_sas.h1
2 files changed, 42 insertions, 2 deletions
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index f5618c1116f4..0cc766a9aa65 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -34,7 +34,7 @@
#define SAS_HOST_ATTRS 0
-#define SAS_PORT_ATTRS 15
+#define SAS_PORT_ATTRS 17
#define SAS_RPORT_ATTRS 5
struct sas_internal {
@@ -289,9 +289,39 @@ show_sas_device_type(struct class_device *cdev, char *buf)
return snprintf(buf, 20, "none\n");
return get_sas_device_type_names(phy->identify.device_type, buf);
}
-
static CLASS_DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);
+static ssize_t do_sas_phy_reset(struct class_device *cdev,
+ size_t count, int hard_reset)
+{
+ struct sas_phy *phy = transport_class_to_phy(cdev);
+ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+ struct sas_internal *i = to_sas_internal(shost->transportt);
+ int error;
+
+ if (!phy->local_attached)
+ return -EINVAL;
+
+ error = i->f->phy_reset(phy, hard_reset);
+ if (error)
+ return error;
+ return count;
+};
+
+static ssize_t store_sas_link_reset(struct class_device *cdev,
+ const char *buf, size_t count)
+{
+ return do_sas_phy_reset(cdev, count, 0);
+}
+static CLASS_DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset);
+
+static ssize_t store_sas_hard_reset(struct class_device *cdev,
+ const char *buf, size_t count)
+{
+ return do_sas_phy_reset(cdev, count, 1);
+}
+static CLASS_DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset);
+
sas_phy_protocol_attr(identify.initiator_port_protocols,
initiator_port_protocols);
sas_phy_protocol_attr(identify.target_port_protocols,
@@ -725,6 +755,13 @@ static struct device *sas_target_parent(struct Scsi_Host *shost,
i->phy_attrs[count] = &i->private_phy_attrs[count]; \
count++
+#define SETUP_PORT_ATTRIBUTE_WRONLY(field) \
+ i->private_phy_attrs[count] = class_device_attr_##field; \
+ i->private_phy_attrs[count].attr.mode = S_IWUGO; \
+ i->private_phy_attrs[count].show = NULL; \
+ i->phy_attrs[count] = &i->private_phy_attrs[count]; \
+ count++
+
/**
* sas_attach_transport -- instantiate SAS transport template
@@ -781,6 +818,8 @@ sas_attach_transport(struct sas_function_template *ft)
SETUP_PORT_ATTRIBUTE(running_disparity_error_count);
SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count);
SETUP_PORT_ATTRIBUTE(phy_reset_problem_count);
+ SETUP_PORT_ATTRIBUTE_WRONLY(link_reset);
+ SETUP_PORT_ATTRIBUTE_WRONLY(hard_reset);
i->phy_attrs[count] = NULL;
count = 0;
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
index 57eb68c6e9a7..b91400bfb02a 100644
--- a/include/scsi/scsi_transport_sas.h
+++ b/include/scsi/scsi_transport_sas.h
@@ -94,6 +94,7 @@ struct sas_rphy {
/* The functions by which the transport class and the driver communicate */
struct sas_function_template {
int (*get_linkerrors)(struct sas_phy *);
+ int (*phy_reset)(struct sas_phy *, int);
};