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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.