Commit 1419b854 authored by James Bottomley's avatar James Bottomley

Merge ssh://linux-scsi@linux-scsi.bkbits.net/scsi-misc-2.5

into raven.il.steeleye.com:/home/jejb/BK/scsi-misc-2.5
parents 7614478d 064bbf11
......@@ -124,6 +124,7 @@
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <asm/dma.h>
#include <asm/system.h>
......@@ -173,6 +174,8 @@ STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
STATIC int NCR_700_slave_configure(Scsi_Device *SDpnt);
STATIC void NCR_700_slave_destroy(Scsi_Device *SDpnt);
static struct device_attribute **NCR_700_dev_attrs = NULL;
static char *NCR_700_phase[] = {
"",
"after selection",
......@@ -247,6 +250,9 @@ NCR_700_detect(Scsi_Host_Template *tpnt,
static int banner = 0;
int j;
if(tpnt->sdev_attrs == NULL)
tpnt->sdev_attrs = NCR_700_dev_attrs;
memory = dma_alloc_noncoherent(hostdata->dev, TOTAL_MEM_SIZE,
&pScript, GFP_KERNEL);
if(memory == NULL) {
......@@ -2015,6 +2021,56 @@ NCR_700_slave_destroy(Scsi_Device *SDp)
/* to do here: deallocate memory */
}
static ssize_t
NCR_700_store_queue_depth(struct device *dev, const char *buf, size_t count)
{
int depth;
struct scsi_device *SDp = to_scsi_device(dev);
depth = simple_strtoul(buf, NULL, 0);
if(depth > NCR_700_MAX_TAGS)
return -EINVAL;
scsi_adjust_queue_depth(SDp, MSG_ORDERED_TAG, depth);
return count;
}
static ssize_t
NCR_700_show_active_tags(struct device *dev, char *buf)
{
struct scsi_device *SDp = to_scsi_device(dev);
return snprintf(buf, 20, "%d\n", NCR_700_get_depth(SDp));
}
static struct device_attribute NCR_700_queue_depth_attr = {
.attr = {
.name = "queue_depth",
.mode = S_IWUSR,
},
.store = NCR_700_store_queue_depth,
};
static struct device_attribute NCR_700_active_tags_attr = {
.attr = {
.name = "active_tags",
.mode = S_IRUGO,
},
.show = NCR_700_show_active_tags,
};
STATIC int __init
NCR_700_init(void)
{
scsi_sysfs_modify_sdev_attribute(&NCR_700_dev_attrs,
&NCR_700_queue_depth_attr);
scsi_sysfs_modify_sdev_attribute(&NCR_700_dev_attrs,
&NCR_700_active_tags_attr);
return 0;
}
EXPORT_SYMBOL(NCR_700_detect);
EXPORT_SYMBOL(NCR_700_release);
EXPORT_SYMBOL(NCR_700_intr);
module_init(NCR_700_init);
......@@ -385,6 +385,7 @@ static int __init NCR_D700_init(void)
static void __exit NCR_D700_exit(void)
{
mca_unregister_driver(&NCR_D700_driver);
scsi_sysfs_release_attributes();
}
module_init(NCR_D700_init);
......
......@@ -321,7 +321,12 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
shost_tp->eh_host_reset_handler == NULL) {
printk(KERN_ERR "ERROR: SCSI host `%s' has no error handling\nERROR: This is not a safe way to run your SCSI host\nERROR: The error handling must be added to this driver\n", shost_tp->proc_name);
dump_stack();
}
}
if(shost_tp->shost_attrs == NULL)
/* if its not set in the template, use the default */
shost_tp->shost_attrs = scsi_sysfs_shost_attrs;
if(shost_tp->sdev_attrs == NULL)
shost_tp->sdev_attrs = scsi_sysfs_sdev_attrs;
gfp_mask = GFP_KERNEL;
if (shost_tp->unchecked_isa_dma && xtr_bytes)
gfp_mask |= __GFP_DMA;
......
......@@ -356,6 +356,16 @@ typedef struct SHT
* FIXME: This should probably be a value in the template */
#define SCSI_DEFAULT_HOST_BLOCKED 7
/*
* pointer to the sysfs class properties for this host
*/
struct class_device_attribute **shost_attrs;
/*
* Pointer to the SCSI device properties for this host
*/
struct device_attribute **sdev_attrs;
} Scsi_Host_Template;
/*
......@@ -588,4 +598,6 @@ static inline Scsi_Device *scsi_find_device(struct Scsi_Host *shost,
return NULL;
}
extern void scsi_sysfs_release_attributes(struct SHT *hostt);
#endif
......@@ -682,4 +682,9 @@ static inline Scsi_Cmnd *scsi_find_tag(Scsi_Device *SDpnt, int tag) {
int scsi_set_medium_removal(Scsi_Device *dev, char state);
extern int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs,
struct device_attribute *attr);
extern int scsi_sysfs_modify_shost_attribute(struct class_device_attribute ***class_attrs,
struct class_device_attribute *attr);
#endif /* _SCSI_H */
......@@ -131,4 +131,9 @@ extern void scsi_sysfs_remove_host(struct Scsi_Host *);
extern int scsi_sysfs_register(void);
extern void scsi_sysfs_unregister(void);
/* definitions for the linker default sections covering the host
* class and device attributes */
extern struct class_device_attribute *scsi_sysfs_shost_attrs[];
extern struct device_attribute *scsi_sysfs_sdev_attrs[];
#endif /* _SCSI_PRIV_H */
......@@ -45,12 +45,13 @@ 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 class_device_attribute *const shost_attrs[] = {
struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
&class_device_attr_unique_id,
&class_device_attr_host_busy,
&class_device_attr_cmd_per_lun,
&class_device_attr_sg_tablesize,
&class_device_attr_unchecked_isa_dma,
NULL
};
static struct class shost_class = {
......@@ -243,7 +244,8 @@ store_rescan_field (struct device *dev, const char *buf, size_t count)
static DEVICE_ATTR(rescan, S_IRUGO | S_IWUSR, show_rescan_field, store_rescan_field)
static struct device_attribute * const sdev_attrs[] = {
/* Default template for device attributes. May NOT be modified */
struct device_attribute *scsi_sysfs_sdev_attrs[] = {
&dev_attr_device_blocked,
&dev_attr_queue_depth,
&dev_attr_type,
......@@ -254,6 +256,7 @@ static struct device_attribute * const sdev_attrs[] = {
&dev_attr_rev,
&dev_attr_online,
&dev_attr_rescan,
NULL
};
static void scsi_device_release(struct device *dev)
......@@ -287,9 +290,9 @@ int scsi_device_register(struct scsi_device *sdev)
if (error)
return error;
for (i = 0; !error && i < ARRAY_SIZE(sdev_attrs); i++)
for (i = 0; !error && sdev->host->hostt->sdev_attrs[i] != NULL; i++)
error = device_create_file(&sdev->sdev_driverfs_dev,
sdev_attrs[i]);
sdev->host->hostt->sdev_attrs[i]);
if (error)
scsi_device_unregister(sdev);
......@@ -305,8 +308,8 @@ void scsi_device_unregister(struct scsi_device *sdev)
{
int i;
for (i = 0; i < ARRAY_SIZE(sdev_attrs); i++)
device_remove_file(&sdev->sdev_driverfs_dev, sdev_attrs[i]);
for (i = 0; sdev->host->hostt->sdev_attrs[i] != NULL; i++)
device_remove_file(&sdev->sdev_driverfs_dev, sdev->host->hostt->sdev_attrs[i]);
device_unregister(&sdev->sdev_driverfs_dev);
}
......@@ -357,9 +360,9 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost, struct device *dev)
if (error)
goto clean_device;
for (i = 0; !error && i < ARRAY_SIZE(shost_attrs); i++)
for (i = 0; !error && shost->hostt->shost_attrs[i] != NULL; i++)
error = class_device_create_file(&shost->class_dev,
shost_attrs[i]);
shost->hostt->shost_attrs[i]);
if (error)
goto clean_class;
......@@ -383,3 +386,118 @@ void scsi_sysfs_remove_host(struct Scsi_Host *shost)
device_del(&shost->host_gendev);
}
/** scsi_sysfs_modify_shost_attribute - modify or add a host class attribute
*
* @class_attrs:host class attribute list to be added to or modified
* @attr: individual attribute to change or added
*
* returns zero if successful or error if not
**/
int scsi_sysfs_modify_shost_attribute(struct class_device_attribute ***class_attrs,
struct class_device_attribute *attr)
{
int modify = 0;
int num_attrs;
if(*class_attrs == NULL)
*class_attrs = scsi_sysfs_shost_attrs;
for(num_attrs=0; (*class_attrs)[num_attrs] != NULL; num_attrs++)
if(strcmp((*class_attrs)[num_attrs]->attr.name, attr->attr.name) == 0)
modify = num_attrs;
if(*class_attrs == scsi_sysfs_shost_attrs || !modify) {
/* note: need space for null at the end as well */
struct class_device_attribute **tmp_attrs = kmalloc(sizeof(struct class_device_attribute)*(num_attrs + (modify ? 1 : 2)), GFP_KERNEL);
if(tmp_attrs == NULL)
return -ENOMEM;
memcpy(tmp_attrs, *class_attrs, sizeof(struct class_device_attribute)*num_attrs);
if(*class_attrs != scsi_sysfs_shost_attrs)
kfree(*class_attrs);
*class_attrs = tmp_attrs;
}
if(modify) {
/* spare the caller from having to copy things it's
* not interested in */
struct class_device_attribute *old_attr =
(*class_attrs)[modify];
/* extend permissions */
attr->attr.mode |= old_attr->attr.mode;
/* override null show/store with default */
if(attr->show == NULL)
attr->show = old_attr->show;
if(attr->store == NULL)
attr->store = old_attr->store;
(*class_attrs)[modify] = attr;
} else {
(*class_attrs)[num_attrs++] = attr;
(*class_attrs)[num_attrs] = NULL;
}
return 0;
}
EXPORT_SYMBOL(scsi_sysfs_modify_shost_attribute);
/** scsi_sysfs_modify_sdev_attribute - modify or add a host device attribute
*
* @dev_attrs: pointer to the attribute list to be added to or modified
* @attr: individual attribute to change or added
*
* returns zero if successful or error if not
**/
int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs,
struct device_attribute *attr)
{
int modify = 0;
int num_attrs;
if(*dev_attrs == NULL)
*dev_attrs = scsi_sysfs_sdev_attrs;
for(num_attrs=0; (*dev_attrs)[num_attrs] != NULL; num_attrs++)
if(strcmp((*dev_attrs)[num_attrs]->attr.name, attr->attr.name) == 0)
modify = num_attrs;
if(*dev_attrs == scsi_sysfs_sdev_attrs || !modify) {
/* note: need space for null at the end as well */
struct device_attribute **tmp_attrs = kmalloc(sizeof(struct device_attribute)*(num_attrs + (modify ? 1 : 2)), GFP_KERNEL);
if(tmp_attrs == NULL)
return -ENOMEM;
memcpy(tmp_attrs, *dev_attrs, sizeof(struct device_attribute)*num_attrs);
if(*dev_attrs != scsi_sysfs_sdev_attrs)
kfree(*dev_attrs);
*dev_attrs = tmp_attrs;
}
if(modify) {
/* spare the caller from having to copy things it's
* not interested in */
struct device_attribute *old_attr =
(*dev_attrs)[modify];
/* extend permissions */
attr->attr.mode |= old_attr->attr.mode;
/* override null show/store with default */
if(attr->show == NULL)
attr->show = old_attr->show;
if(attr->store == NULL)
attr->store = old_attr->store;
(*dev_attrs)[modify] = attr;
} else {
(*dev_attrs)[num_attrs++] = attr;
(*dev_attrs)[num_attrs] = NULL;
}
return 0;
}
EXPORT_SYMBOL(scsi_sysfs_modify_sdev_attribute);
void scsi_sysfs_release_attributes(struct SHT *hostt)
{
if(hostt->sdev_attrs != scsi_sysfs_sdev_attrs)
kfree(hostt->sdev_attrs);
if(hostt->shost_attrs != scsi_sysfs_shost_attrs)
kfree(hostt->shost_attrs);
}
EXPORT_SYMBOL(scsi_sysfs_release_attributes);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment