# 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); }