From: James Bottomley <James.Bottomley@steeleye.com>
To: SCSI Mailing List <linux-scsi@vger.kernel.org>,
Patrick Mochel <mochel@osdl.org>, Greg KH <greg@kroah.com>,
Mike Anderson <andmike@us.ibm.com>
Subject: Re: [RFC] support for sysfs string based properties for SCSI (2/3)
Date: 03 May 2003 14:25:35 -0500 [thread overview]
Message-ID: <1051989937.2308.21.camel@mulgrave> (raw)
In-Reply-To: <1051989565.2036.14.camel@mulgrave>
[-- Attachment #1: Type: text/plain, Size: 259 bytes --]
This implements a generic host and device based show/store using
property attributes in SCSI.
I've done it for both LLDs and ULDs, but I'm not convinced that the ULD
one is needed: I think it will probably get subsumed by the driver class
changes.
James
[-- Attachment #2: tmp.diff --]
[-- Type: text/plain, Size: 13949 bytes --]
# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.1197 -> 1.1198
# drivers/scsi/scsi_sysfs.c 1.11 -> 1.12
# drivers/scsi/hosts.h 1.60 -> 1.61
# drivers/scsi/scsi.c 1.109 -> 1.110
# drivers/scsi/scsi_priv.h 1.1 -> 1.2
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/05/03 jejb@raven.il.steeleye.com 1.1198
# SCSI: add ULD and LLD device/host property show/store
#
# This implements a property show/store method for arbitrary string
# based properties which can be exposed through the sysfs interface.
#
# The essential problem to be solved here is that properties can be
# read easily enough in the mid-layer but they require co-operation
# from the LLD to set them
# --------------------------------------------
#
diff -Nru a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
--- a/drivers/scsi/hosts.h Sat May 3 14:24:25 2003
+++ b/drivers/scsi/hosts.h Sat May 3 14:24:25 2003
@@ -266,6 +266,22 @@
int (* bios_param)(struct scsi_device *, struct block_device *,
sector_t, int []);
+ /*
+ * Used to show/store generic ASCII properties
+ *
+ * If filled in, it will be called before the generic SCSI driver
+ * processes the properties.
+ */
+ ssize_t (* host_property_show)(struct Scsi_Host *, char *,
+ struct attribute *);
+ ssize_t (* host_property_store)(struct Scsi_Host *, const char *,
+ size_t, struct attribute *);
+ ssize_t (* device_property_show)(struct scsi_device *, char *,
+ struct attribute *);
+ ssize_t (* device_property_store)(struct scsi_device *, const char *,
+ size_t, struct attribute *);
+
+
/*
* This determines if we will use a non-interrupt driven
* or an interrupt driven scheme, It is set to the maximum number
@@ -538,6 +554,10 @@
int (*init_command)(Scsi_Cmnd *); /* Used by new queueing code.
Selects command for blkdevs */
void (*rescan)(Scsi_Device *);
+ ssize_t (* device_property_show)(struct scsi_device *, char *,
+ struct attribute *);
+ ssize_t (* device_property_store)(struct scsi_device *, const char *,
+ size_t, struct attribute *);
struct device_driver scsi_driverfs_driver;
};
diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c Sat May 3 14:24:25 2003
+++ b/drivers/scsi/scsi.c Sat May 3 14:24:25 2003
@@ -89,7 +89,7 @@
* List of all highlevel drivers.
*/
LIST_HEAD(scsi_devicelist);
-static DECLARE_RWSEM(scsi_devicelist_mutex);
+DECLARE_RWSEM(scsi_devicelist_mutex);
/*
* Note - the initial logging level can be set here to log events at boot time.
diff -Nru a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
--- a/drivers/scsi/scsi_priv.h Sat May 3 14:24:25 2003
+++ b/drivers/scsi/scsi_priv.h Sat May 3 14:24:25 2003
@@ -143,4 +143,7 @@
extern struct list_head scsi_dev_info_list;
extern int scsi_dev_info_list_add_str(char *);
+extern struct list_head scsi_devicelist;
+extern struct rw_semaphore scsi_devicelist_mutex;
+
#endif /* _SCSI_PRIV_H */
diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c Sat May 3 14:24:25 2003
+++ b/drivers/scsi/scsi_sysfs.c Sat May 3 14:24:25 2003
@@ -16,41 +16,20 @@
#include "scsi_priv.h"
-/*
- * shost_show_function: macro to create an attr function that can be used to
- * show a non-bit field.
- */
-#define shost_show_function(field, format_string) \
-static ssize_t \
-show_##field (struct device *dev, char *buf) \
-{ \
- struct Scsi_Host *shost = to_scsi_host(dev); \
- return snprintf (buf, 20, format_string, shost->field); \
-}
-
-/*
- * shost_rd_attr: macro to create a function and attribute variable for a
- * read only field.
- */
-#define shost_rd_attr(field, format_string) \
- shost_show_function(field, format_string) \
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
-
-/*
- * Create the actual show/store functions and data structures.
- */
-shost_rd_attr(unique_id, "%u\n");
-shost_rd_attr(host_busy, "%hu\n");
-shost_rd_attr(cmd_per_lun, "%hd\n");
-shost_rd_attr(sg_tablesize, "%hu\n");
-shost_rd_attr(unchecked_isa_dma, "%d\n");
-
-static struct device_attribute *const shost_attrs[] = {
- &dev_attr_unique_id,
- &dev_attr_host_busy,
- &dev_attr_cmd_per_lun,
- &dev_attr_sg_tablesize,
- &dev_attr_unchecked_isa_dma,
+/* FIXME: need generic attributes for the host */
+
+/* generic attributes to appear in device directory */
+struct device_attribute sdev_attrs[] = {
+ { .attr = { .name = "device_blocked", .mode = S_IRUGO }, },
+ { .attr = { .name = "queue_depth", .mode = S_IRUGO | S_IWUSR }, },
+ { .attr = { .name = "type", .mode = S_IRUGO }, },
+ { .attr = { .name = "scsi_level", .mode = S_IRUGO }, },
+ { .attr = { .name = "access_count", .mode = S_IRUGO }, },
+ { .attr = { .name = "vendor", .mode = S_IRUGO }, },
+ { .attr = { .name = "model", .mode = S_IRUGO }, },
+ { .attr = { .name = "rev", .mode = S_IRUGO }, },
+ { .attr = { .name = "online", .mode = S_IRUGO }, },
+ { .attr = { .name = "rescan", .mode = S_IRUGO | S_IWUSR }, },
};
/**
@@ -105,10 +84,154 @@
return 0;
}
+#define SCSI_SYSFS_MAX_BUF 20
+
+static ssize_t scsi_sysfs_device_show(struct device * dev, char * buf,
+ struct attribute *attr)
+{
+ char *name = attr->name;
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct Scsi_Device_Template *tpnt;
+ int ret = 0;
+
+ /* process any host based overrides */
+
+ if(sdev->host->hostt->device_property_show) {
+ ret = sdev->host->hostt->device_property_show(sdev, buf, attr);
+ if(ret != 0)
+ return ret;
+ }
+
+ /* pass to every upper level driver. ULDs must check to see
+ * if they're interested in the device type *before* doing
+ * anything with the property */
+
+ down_read(&scsi_devicelist_mutex);
+ list_for_each_entry(tpnt, &scsi_devicelist, list) {
+ if(tpnt->device_property_show) {
+ ret = tpnt->device_property_show(sdev, buf, attr);
+
+ if(ret != 0) {
+ up_read(&scsi_devicelist_mutex);
+ return ret;
+ }
+ }
+
+ }
+ up_read(&scsi_devicelist_mutex);
+
+ /* generic processing */
+
+ if (strcmp(name, "device_blocked") == 0) {
+ ret = snprintf(buf, SCSI_SYSFS_MAX_BUF, "%d\n",
+ sdev->device_blocked);
+ } else if (strcmp(name, "queue_depth") == 0) {
+ ret = snprintf(buf, SCSI_SYSFS_MAX_BUF, "%d\n",
+ sdev->queue_depth);
+ } else if (strcmp(name, "type") == 0) {
+ ret = snprintf(buf, SCSI_SYSFS_MAX_BUF, "%d\n",
+ sdev->type);
+ } else if (strcmp(name, "scsi_level") == 0) {
+ ret = snprintf(buf, SCSI_SYSFS_MAX_BUF, "%d\n",
+ sdev->scsi_level);
+ } else if (strcmp(name, "access_count") == 0) {
+ ret = snprintf(buf, SCSI_SYSFS_MAX_BUF, "%d\n",
+ sdev->access_count);
+ } else if (strcmp(name, "vendor") == 0) {
+ ret = snprintf(buf, SCSI_SYSFS_MAX_BUF, "%.8s\n",
+ sdev->vendor);
+ } else if (strcmp(name, "model") == 0) {
+ ret = snprintf(buf, SCSI_SYSFS_MAX_BUF, "%.16s\n",
+ sdev->model);
+ } else if (strcmp(name, "rev") == 0) {
+ ret = snprintf(buf, SCSI_SYSFS_MAX_BUF, "%.4s\n",
+ sdev->rev);
+ } else if (strcmp(name, "online") == 0) {
+ ret = snprintf(buf, SCSI_SYSFS_MAX_BUF, "%d\n",
+ sdev->online);
+ }
+
+ return ret;
+}
+
+static size_t scsi_sysfs_device_store(struct device * dev, const char * buf,
+ size_t count, struct attribute *attr)
+{
+ char *name = attr->name;
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct Scsi_Device_Template *tpnt;
+ int ret = 0;
+
+ /* process any host based overrides */
+
+ if(sdev->host->hostt->device_property_store) {
+ ret = sdev->host->hostt->device_property_store(sdev, buf,
+ count, attr);
+ if(ret < 0)
+ return ret;
+
+ }
+ /* pass to every upper level driver. ULDs must check to see
+ * if they're interested in the device type *before* doing
+ * anything with the property */
+
+ down_read(&scsi_devicelist_mutex);
+ list_for_each_entry(tpnt, &scsi_devicelist, list) {
+ if(tpnt->device_property_store) {
+ ret = tpnt->device_property_store(sdev, buf,
+ count, attr);
+
+ if(ret < 0) {
+ up_read(&scsi_devicelist_mutex);
+ return ret;
+ }
+ }
+
+ }
+ up_read(&scsi_devicelist_mutex);
+
+ /* generic processing */
+
+ if (strcmp(name, "rescan") == 0) {
+ ret = count;
+ scsi_rescan_device(sdev);
+ } else if (strcmp(name, "online") == 0) {
+ /* FIXME: will do online/offline here when available */
+ }
+
+ return ret;
+}
+
+static ssize_t scsi_sysfs_show(struct device * dev, char * buf,
+ struct attribute *attr)
+{
+ /* FIXME: If we actually had a device type corresponding to a
+ * host, we'd check for it here and then do host stuff
+ if(0)
+ return scsi_sysfs_host_show(dev, buf, attr);
+ else
+ */
+ return scsi_sysfs_device_show(dev, buf, attr);
+}
+
+static ssize_t scsi_sysfs_store(struct device * dev, const char * buf,
+ size_t count, struct attribute *attr)
+{
+ /* FIXME: If we actually had a device type corresponding to a
+ * host, we'd check for it here and then do host stuff
+ if(0)
+ return scsi_sysfs_host_store(dev, buf, count, attr);
+ else
+ */
+ return scsi_sysfs_device_store(dev, buf, count, attr);
+}
+
static struct bus_type scsi_bus_type = {
.name = "scsi",
.match = scsi_bus_match,
+ .show = scsi_sysfs_show,
+ .store = scsi_sysfs_store,
};
@@ -154,125 +277,6 @@
}
-/*
- * sdev_show_function: macro to create an attr function that can be used to
- * show a non-bit field.
- */
-#define sdev_show_function(field, format_string) \
-static ssize_t \
-show_##field (struct device *dev, char *buf) \
-{ \
- struct scsi_device *sdev; \
- sdev = to_scsi_device(dev); \
- return snprintf (buf, 20, format_string, sdev->field); \
-} \
-
-/*
- * sdev_rd_attr: macro to create a function and attribute variable for a
- * read only field.
- */
-#define sdev_rd_attr(field, format_string) \
- sdev_show_function(field, format_string) \
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
-
-
-/*
- * sdev_rd_attr: create a function and attribute variable for a
- * read/write field.
- */
-#define sdev_rw_attr(field, format_string) \
- sdev_show_function(field, format_string) \
- \
-static ssize_t \
-sdev_store_##field (struct device *dev, const char *buf, size_t count) \
-{ \
- struct scsi_device *sdev; \
- sdev = to_scsi_device(dev); \
- snscanf (buf, 20, format_string, &sdev->field); \
- return count; \
-} \
-static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, show_##field, sdev_store_##field)
-
-/*
- * sdev_rd_attr: create a function and attribute variable for a
- * read/write bit field.
- */
-#define sdev_rw_attr_bit(field) \
- sdev_show_function(field, "%d\n") \
- \
-static ssize_t \
-sdev_store_##field (struct device *dev, const char *buf, size_t count) \
-{ \
- int ret; \
- struct scsi_device *sdev; \
- ret = scsi_sdev_check_buf_bit(buf); \
- if (ret >= 0) { \
- sdev = to_scsi_device(dev); \
- sdev->field = ret; \
- ret = count; \
- } \
- return ret; \
-} \
-static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, show_##field, sdev_store_##field)
-
-/*
- * scsi_sdev_check_buf_bit: return 0 if buf is "0", return 1 if buf is "1",
- * else return -EINVAL.
- */
-static int scsi_sdev_check_buf_bit(const char *buf)
-{
- if ((buf[1] == '\0') || ((buf[1] == '\n') && (buf[2] == '\0'))) {
- if (buf[0] == '1')
- return 1;
- else if (buf[0] == '0')
- return 0;
- else
- return -EINVAL;
- } else
- return -EINVAL;
-}
-
-/*
- * Create the actual show/store functions and data structures.
- */
-sdev_rd_attr (device_blocked, "%d\n");
-sdev_rd_attr (queue_depth, "%d\n");
-sdev_rd_attr (type, "%d\n");
-sdev_rd_attr (scsi_level, "%d\n");
-sdev_rd_attr (access_count, "%d\n");
-sdev_rd_attr (vendor, "%.8s\n");
-sdev_rd_attr (model, "%.16s\n");
-sdev_rd_attr (rev, "%.4s\n");
-sdev_rw_attr_bit (online);
-
-static ssize_t
-show_rescan_field (struct device *dev, char *buf)
-{
- return 0;
-}
-
-static ssize_t
-store_rescan_field (struct device *dev, const char *buf, size_t count)
-{
- scsi_rescan_device(to_scsi_device(dev));
- return 0;
-}
-
-static DEVICE_ATTR(rescan, S_IRUGO | S_IWUSR, show_rescan_field, store_rescan_field)
-
-static struct device_attribute * const sdev_attrs[] = {
- &dev_attr_device_blocked,
- &dev_attr_queue_depth,
- &dev_attr_type,
- &dev_attr_scsi_level,
- &dev_attr_access_count,
- &dev_attr_vendor,
- &dev_attr_model,
- &dev_attr_rev,
- &dev_attr_online,
- &dev_attr_rescan,
-};
-
/**
* scsi_device_register - register a scsi device with the scsi bus
* @sdev: scsi_device to register
@@ -295,7 +299,7 @@
for (i = 0; !error && i < ARRAY_SIZE(sdev_attrs); i++)
error = device_create_file(&sdev->sdev_driverfs_dev,
- sdev_attrs[i]);
+ &sdev_attrs[i]);
if (error)
scsi_device_unregister(sdev);
@@ -312,6 +316,6 @@
int i;
for (i = 0; i < ARRAY_SIZE(sdev_attrs); i++)
- device_remove_file(&sdev->sdev_driverfs_dev, sdev_attrs[i]);
+ device_remove_file(&sdev->sdev_driverfs_dev, &sdev_attrs[i]);
device_unregister(&sdev->sdev_driverfs_dev);
}
next prev parent reply other threads:[~2003-05-03 19:13 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-05-03 19:11 [RFC] support for sysfs string based properties for SCSI (1/3) James Bottomley
2003-05-03 19:19 ` James Bottomley
2003-05-03 19:25 ` James Bottomley [this message]
2003-05-03 19:30 ` [RFC] support for sysfs string based properties for SCSI (3/3) James Bottomley
2003-05-05 17:02 ` [RFC] support for sysfs string based properties for SCSI (1/3) Greg KH
2003-05-05 17:08 ` James Bottomley
2003-05-05 17:17 ` Greg KH
2003-05-05 20:08 ` Mike Anderson
2003-05-06 0:05 ` James Bottomley
2003-05-13 21:02 ` Patrick Mochel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1051989937.2308.21.camel@mulgrave \
--to=james.bottomley@steeleye.com \
--cc=andmike@us.ibm.com \
--cc=greg@kroah.com \
--cc=linux-scsi@vger.kernel.org \
--cc=mochel@osdl.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox