diff options
| author | James Bottomley <jejb@mulgrave.(none)> | 2004-12-23 01:01:49 -0600 |
|---|---|---|
| committer | James Bottomley <jejb@mulgrave.(none)> | 2004-12-23 01:01:49 -0600 |
| commit | f5cf12230f9b850ef9d74bba6edefc734fe4f232 (patch) | |
| tree | b68317bbf4b1a73e5431b2f25644b662a1ac5b79 | |
| parent | 3e54f826a3c33510595ac9153f103508a3a6ce6b (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.c | 57 | ||||
| -rw-r--r-- | include/scsi/scsi_host.h | 14 | ||||
| -rw-r--r-- | include/scsi/scsi_tcq.h | 52 |
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; |
