summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Bottomley <jejb@mulgrave.(none)>2004-12-23 01:01:49 -0600
committerJames Bottomley <jejb@mulgrave.(none)>2004-12-23 01:01:49 -0600
commitf5cf12230f9b850ef9d74bba6edefc734fe4f232 (patch)
treeb68317bbf4b1a73e5431b2f25644b662a1ac5b79
parent3e54f826a3c33510595ac9153f103508a3a6ce6b (diff)
SCSI: add queue_type entry in sysfs
This adds an extra attribute to tell you what type of queueing the driver is using: none, simple or ordered. If the driver supplies the change_queue_type API, you can also alter this (which would allow the turning on or off of TCQ). I also fixed the change_queue_depth not to allow the user to go below one. Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/scsi_sysfs.c57
-rw-r--r--include/scsi/scsi_host.h14
-rw-r--r--include/scsi/scsi_tcq.h52
3 files changed, 115 insertions, 8 deletions
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index fb1bb4bc2590..1fc2962ee10e 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -15,6 +15,7 @@
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport.h>
#include "scsi_priv.h"
@@ -393,11 +394,28 @@ show_state_field(struct device *dev, char *buf)
static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_state_field, store_state_field);
+static ssize_t
+show_queue_type_field(struct device *dev, char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ const char *name = "none";
+
+ if (sdev->ordered_tags)
+ name = "ordered";
+ else if (sdev->simple_tags)
+ name = "simple";
+
+ return snprintf(buf, 20, "%s\n", name);
+}
+
+static DEVICE_ATTR(queue_type, S_IRUGO, show_queue_type_field, NULL);
+
/* Default template for device attributes. May NOT be modified */
static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
&dev_attr_device_blocked,
&dev_attr_queue_depth,
+ &dev_attr_queue_type,
&dev_attr_type,
&dev_attr_scsi_level,
&dev_attr_vendor,
@@ -421,6 +439,10 @@ static ssize_t sdev_store_queue_depth_rw(struct device *dev, const char *buf,
return -EINVAL;
depth = simple_strtoul(buf, NULL, 0);
+
+ if (depth < 1)
+ return -EINVAL;
+
retval = sht->change_queue_depth(sdev, depth);
if (retval < 0)
return retval;
@@ -432,6 +454,38 @@ static struct device_attribute sdev_attr_queue_depth_rw =
__ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,
sdev_store_queue_depth_rw);
+static ssize_t sdev_store_queue_type_rw(struct device *dev, const char *buf,
+ size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct scsi_host_template *sht = sdev->host->hostt;
+ int tag_type = 0, retval;
+ int prev_tag_type = scsi_get_tag_type(sdev);
+
+ if (!sdev->tagged_supported || !sht->change_queue_type)
+ return -EINVAL;
+
+ if (strncmp(buf, "ordered", 7) == 0)
+ tag_type = MSG_ORDERED_TAG;
+ else if (strncmp(buf, "simple", 6) == 0)
+ tag_type = MSG_SIMPLE_TAG;
+ else if (strncmp(buf, "none", 4) != 0)
+ return -EINVAL;
+
+ if (tag_type == prev_tag_type)
+ return count;
+
+ retval = sht->change_queue_type(sdev, tag_type);
+ if (retval < 0)
+ return retval;
+
+ return count;
+}
+
+static struct device_attribute sdev_attr_queue_type_rw =
+ __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
+ sdev_store_queue_type_rw);
+
static struct device_attribute *attr_changed_internally(
struct Scsi_Host *shost,
struct device_attribute * attr)
@@ -439,6 +493,9 @@ static struct device_attribute *attr_changed_internally(
if (!strcmp("queue_depth", attr->attr.name)
&& shost->hostt->change_queue_depth)
return &sdev_attr_queue_depth_rw;
+ else if (!strcmp("queue_type", attr->attr.name)
+ && shost->hostt->change_queue_type)
+ return &sdev_attr_queue_type_rw;
return attr;
}
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 59c7e45d3409..a22a274fbd7a 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -228,13 +228,23 @@ struct scsi_host_template {
int (* change_queue_depth)(struct scsi_device *, int);
/*
+ * fill in this function to allow the changing of tag types
+ * (this also allows the enabling/disabling of tag command
+ * queueing). An error should only be returned if something
+ * went wrong in the driver while trying to set the tag type.
+ * If the driver doesn't support the requested tag type, then
+ * it should set the closest type it does support without
+ * returning an error. Returns the actual tag type set.
+ */
+ int (* change_queue_type)(struct scsi_device *, int);
+
+ /*
* This function determines the bios parameters for a given
* harddisk. These tend to be numbers that are made up by
* the host adapter. Parameters:
* size, device, list (heads, sectors, cylinders)
*
- * Status: OPTIONAL
- */
+ * Status: OPTIONAL */
int (* bios_param)(struct scsi_device *, struct block_device *,
sector_t, int []);
diff --git a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h
index 78039d0f1a57..e47e36a4ef49 100644
--- a/include/scsi/scsi_tcq.h
+++ b/include/scsi/scsi_tcq.h
@@ -13,6 +13,43 @@
#define SCSI_NO_TAG (-1) /* identify no tag in use */
+
+/**
+ * scsi_get_tag_type - get the type of tag the device supports
+ * @sdev: the scsi device
+ *
+ * Notes:
+ * If the drive only supports simple tags, returns MSG_SIMPLE_TAG
+ * if it supports all tag types, returns MSG_ORDERED_TAG.
+ */
+static inline int scsi_get_tag_type(struct scsi_device *sdev)
+{
+ if (!sdev->tagged_supported)
+ return 0;
+ if (sdev->ordered_tags)
+ return MSG_ORDERED_TAG;
+ if (sdev->simple_tags)
+ return MSG_SIMPLE_TAG;
+ return 0;
+}
+
+static inline void scsi_set_tag_type(struct scsi_device *sdev, int tag)
+{
+ switch (tag) {
+ case MSG_ORDERED_TAG:
+ sdev->ordered_tags = 1;
+ /* fall through */
+ case MSG_SIMPLE_TAG:
+ sdev->simple_tags = 1;
+ break;
+ case 0:
+ /* fall through */
+ default:
+ sdev->ordered_tags = 0;
+ sdev->simple_tags = 0;
+ break;
+ }
+}
/**
* scsi_activate_tcq - turn on tag command queueing
* @SDpnt: device to turn on TCQ for
@@ -25,11 +62,13 @@
**/
static inline void scsi_activate_tcq(struct scsi_device *sdev, int depth)
{
- if (sdev->tagged_supported) {
- if (!blk_queue_tagged(sdev->request_queue))
- blk_queue_init_tags(sdev->request_queue, depth, NULL);
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth);
- }
+ if (!sdev->tagged_supported)
+ return;
+
+ if (!blk_queue_tagged(sdev->request_queue))
+ blk_queue_init_tags(sdev->request_queue, depth, NULL);
+
+ scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
}
/**
@@ -56,9 +95,10 @@ static inline void scsi_deactivate_tcq(struct scsi_device *sdev, int depth)
static inline int scsi_populate_tag_msg(struct scsi_cmnd *cmd, char *msg)
{
struct request *req = cmd->request;
+ struct scsi_device *sdev = cmd->device;
if (blk_rq_tagged(req)) {
- if (req->flags & REQ_HARDBARRIER)
+ if (sdev->ordered_tags && req->flags & REQ_HARDBARRIER)
*msg++ = MSG_ORDERED_TAG;
else
*msg++ = MSG_SIMPLE_TAG;