diff options
author | Markus Lidel <Markus.Lidel@shadowconnect.com> | 2005-06-23 22:02:16 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-24 00:05:28 -0700 |
commit | f10378fff658f61307496e0ae00095041725cf07 (patch) | |
tree | 0c0413649317677771fa325dded94f1e12a6a0b7 /drivers/message/i2o | |
parent | f88e119c4b824a5017456fa094950d0f4092d96c (diff) |
[PATCH] I2O: new sysfs attributes and Adaptec specific block device access and 64-bit DMA support
Changes:
- Added Bus-OSM which could be used by user space programs to reset a
channel on the controller
- Make ioctl's in Config-OSM obsolete in prefer for sysfs attributes and
move those to its own file
- Added sysfs attribute for firmware read and write access for I2O
controllers
- Added special handling of firmware read and write access for Adaptec
controllers
- Added vendor id and product id as sysfs-attribute to Executive classes
- Added automatic notification of LCT change handling to Exec-OSM
- Added flushing function to Block-OSM for later barrier implementation
- Use PRIVATE messages for Block access on Adaptec controllers, which are
faster then BLOCK class access
- Cleaned up support for Promise controller
- New messages are now detected using the IRQ status register as
suggested by the I2O spec
- Added i2o_dma_high() and i2o_dma_low() functions
- Added facility for SG tablesize calculation when using 32-bit and
64-bit DMA addresses
- Added i2o_dma_map_single() and i2o_dma_map_sg() which could build the
SG list for 32-bit as well as 64-bit DMA addresses
Signed-off-by: Markus Lidel <Markus.Lidel@shadowconnect.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/message/i2o')
-rw-r--r-- | drivers/message/i2o/Kconfig | 18 | ||||
-rw-r--r-- | drivers/message/i2o/Makefile | 3 | ||||
-rw-r--r-- | drivers/message/i2o/bus-osm.c | 164 | ||||
-rw-r--r-- | drivers/message/i2o/config-osm.c | 579 | ||||
-rw-r--r-- | drivers/message/i2o/driver.c | 12 | ||||
-rw-r--r-- | drivers/message/i2o/exec-osm.c | 74 | ||||
-rw-r--r-- | drivers/message/i2o/i2o_block.c | 277 | ||||
-rw-r--r-- | drivers/message/i2o/i2o_block.h | 4 | ||||
-rw-r--r-- | drivers/message/i2o/i2o_config.c | 156 | ||||
-rw-r--r-- | drivers/message/i2o/i2o_proc.c | 4 | ||||
-rw-r--r-- | drivers/message/i2o/i2o_scsi.c | 30 | ||||
-rw-r--r-- | drivers/message/i2o/iop.c | 263 | ||||
-rw-r--r-- | drivers/message/i2o/pci.c | 67 |
13 files changed, 1176 insertions, 475 deletions
diff --git a/drivers/message/i2o/Kconfig b/drivers/message/i2o/Kconfig index 8d132b0d6b12..ce278e060aca 100644 --- a/drivers/message/i2o/Kconfig +++ b/drivers/message/i2o/Kconfig @@ -35,6 +35,24 @@ config I2O_CONFIG To compile this support as a module, choose M here: the module will be called i2o_config. +config I2O_CONFIG_OLD_IOCTL + bool "Enable ioctls (OBSOLETE)" + depends on I2O_CONFIG + default y + ---help--- + Enables old ioctls. + +config I2O_BUS + tristate "I2O Bus Adapter OSM" + depends on I2O + ---help--- + Include support for the I2O Bus Adapter OSM. The Bus Adapter OSM + provides access to the busses on the I2O controller. The main purpose + is to rescan the bus to find new devices. + + To compile this support as a module, choose M here: the + module will be called i2o_bus. + config I2O_BLOCK tristate "I2O Block OSM" depends on I2O diff --git a/drivers/message/i2o/Makefile b/drivers/message/i2o/Makefile index aabc6cdc3fce..2c2e39aa1efa 100644 --- a/drivers/message/i2o/Makefile +++ b/drivers/message/i2o/Makefile @@ -6,8 +6,11 @@ # i2o_core-y += iop.o driver.o device.o debug.o pci.o exec-osm.o +i2o_bus-y += bus-osm.o +i2o_config-y += config-osm.o obj-$(CONFIG_I2O) += i2o_core.o obj-$(CONFIG_I2O_CONFIG)+= i2o_config.o +obj-$(CONFIG_I2O_BUS) += i2o_bus.o obj-$(CONFIG_I2O_BLOCK) += i2o_block.o obj-$(CONFIG_I2O_SCSI) += i2o_scsi.o obj-$(CONFIG_I2O_PROC) += i2o_proc.o diff --git a/drivers/message/i2o/bus-osm.c b/drivers/message/i2o/bus-osm.c new file mode 100644 index 000000000000..d43c35894ae9 --- /dev/null +++ b/drivers/message/i2o/bus-osm.c @@ -0,0 +1,164 @@ +/* + * Bus Adapter OSM + * + * Copyright (C) 2005 Markus Lidel <Markus.Lidel@shadowconnect.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Fixes/additions: + * Markus Lidel <Markus.Lidel@shadowconnect.com> + * initial version. + */ + +#include <linux/module.h> +#include <linux/i2o.h> + +#define OSM_NAME "bus-osm" +#define OSM_VERSION "$Rev$" +#define OSM_DESCRIPTION "I2O Bus Adapter OSM" + +static struct i2o_driver i2o_bus_driver; + +/* Bus OSM class handling definition */ +static struct i2o_class_id i2o_bus_class_id[] = { + {I2O_CLASS_BUS_ADAPTER}, + {I2O_CLASS_END} +}; + +/** + * i2o_bus_scan - Scan the bus for new devices + * @dev: I2O device of the bus, which should be scanned + * + * Scans the bus dev for new / removed devices. After the scan a new LCT + * will be fetched automatically. + * + * Returns 0 on success or negative error code on failure. + */ +static int i2o_bus_scan(struct i2o_device *dev) +{ + struct i2o_message __iomem *msg; + u32 m; + + m = i2o_msg_get_wait(dev->iop, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -ETIMEDOUT; + + writel(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); + writel(I2O_CMD_BUS_SCAN << 24 | HOST_TID << 12 | dev->lct_data.tid, + &msg->u.head[1]); + + return i2o_msg_post_wait(dev->iop, m, 60); +}; + +/** + * i2o_bus_store_scan - Scan the I2O Bus Adapter + * @d: device which should be scanned + * + * Returns count. + */ +static ssize_t i2o_bus_store_scan(struct device *d, const char *buf, + size_t count) +{ + struct i2o_device *i2o_dev = to_i2o_device(d); + int rc; + + if ((rc = i2o_bus_scan(i2o_dev))) + osm_warn("bus scan failed %d\n", rc); + + return count; +} + +/* Bus Adapter OSM device attributes */ +static DEVICE_ATTR(scan, S_IWUSR, NULL, i2o_bus_store_scan); + +/** + * i2o_bus_probe - verify if dev is a I2O Bus Adapter device and install it + * @dev: device to verify if it is a I2O Bus Adapter device + * + * Because we want all Bus Adapters always return 0. + * + * Returns 0. + */ +static int i2o_bus_probe(struct device *dev) +{ + struct i2o_device *i2o_dev = to_i2o_device(get_device(dev)); + + device_create_file(dev, &dev_attr_scan); + + osm_info("device added (TID: %03x)\n", i2o_dev->lct_data.tid); + + return 0; +}; + +/** + * i2o_bus_remove - remove the I2O Bus Adapter device from the system again + * @dev: I2O Bus Adapter device which should be removed + * + * Always returns 0. + */ +static int i2o_bus_remove(struct device *dev) +{ + struct i2o_device *i2o_dev = to_i2o_device(dev); + + device_remove_file(dev, &dev_attr_scan); + + put_device(dev); + + osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid); + + return 0; +}; + +/* Bus Adapter OSM driver struct */ +static struct i2o_driver i2o_bus_driver = { + .name = OSM_NAME, + .classes = i2o_bus_class_id, + .driver = { + .probe = i2o_bus_probe, + .remove = i2o_bus_remove, + }, +}; + +/** + * i2o_bus_init - Bus Adapter OSM initialization function + * + * Only register the Bus Adapter OSM in the I2O core. + * + * Returns 0 on success or negative error code on failure. + */ +static int __init i2o_bus_init(void) +{ + int rc; + + printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n"); + + /* Register Bus Adapter OSM into I2O core */ + rc = i2o_driver_register(&i2o_bus_driver); + if (rc) { + osm_err("Could not register Bus Adapter OSM\n"); + return rc; + } + + return 0; +}; + +/** + * i2o_bus_exit - Bus Adapter OSM exit function + * + * Unregisters Bus Adapter OSM from I2O core. + */ +static void __exit i2o_bus_exit(void) +{ + i2o_driver_unregister(&i2o_bus_driver); +}; + +MODULE_AUTHOR("Markus Lidel <Markus.Lidel@shadowconnect.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(OSM_DESCRIPTION); +MODULE_VERSION(OSM_VERSION); + +module_init(i2o_bus_init); +module_exit(i2o_bus_exit); diff --git a/drivers/message/i2o/config-osm.c b/drivers/message/i2o/config-osm.c new file mode 100644 index 000000000000..d0267609a949 --- /dev/null +++ b/drivers/message/i2o/config-osm.c @@ -0,0 +1,579 @@ +/* + * Configuration OSM + * + * Copyright (C) 2005 Markus Lidel <Markus.Lidel@shadowconnect.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Fixes/additions: + * Markus Lidel <Markus.Lidel@shadowconnect.com> + * initial version. + */ + +#include <linux/module.h> +#include <linux/i2o.h> +#include <linux/namei.h> + +#include <asm/uaccess.h> + +#define OSM_NAME "config-osm" +#define OSM_VERSION "1.248" +#define OSM_DESCRIPTION "I2O Configuration OSM" + +/* access mode user rw */ +#define S_IWRSR (S_IRUSR | S_IWUSR) + +static struct i2o_driver i2o_config_driver; + +/* Special file operations for sysfs */ +struct fops_attribute { + struct bin_attribute bin; + struct file_operations fops; +}; + +/** + * sysfs_read_dummy + */ +static ssize_t sysfs_read_dummy(struct kobject *kobj, char *buf, loff_t offset, + size_t count) +{ + return 0; +}; + +/** + * sysfs_write_dummy + */ +static ssize_t sysfs_write_dummy(struct kobject *kobj, char *buf, loff_t offset, + size_t count) +{ + return 0; +}; + +/** + * sysfs_create_fops_file - Creates attribute with special file operations + * @kobj: kobject which should contains the attribute + * @attr: attributes which should be used to create file + * + * First creates attribute @attr in kobject @kobj. If it is the first time + * this function is called, merge old fops from sysfs with new one and + * write it back. Afterwords the new fops will be set for the created + * attribute. + * + * Returns 0 on success or negative error code on failure. + */ +static int sysfs_create_fops_file(struct kobject *kobj, + struct fops_attribute *attr) +{ + struct file_operations tmp, *fops; + struct dentry *d; + struct qstr qstr; + int rc; + + fops = &attr->fops; + + if (fops->read) + attr->bin.read = sysfs_read_dummy; + + if (fops->write) + attr->bin.write = sysfs_write_dummy; + + if ((rc = sysfs_create_bin_file(kobj, &attr->bin))) + return rc; + + qstr.name = attr->bin.attr.name; + qstr.len = strlen(qstr.name); + qstr.hash = full_name_hash(qstr.name, qstr.len); + + if ((d = lookup_hash(&qstr, kobj->dentry))) { + if (!fops->owner) { + memcpy(&tmp, d->d_inode->i_fop, sizeof(tmp)); + if (fops->read) + tmp.read = fops->read; + if (fops->write) + tmp.write = fops->write; + memcpy(fops, &tmp, sizeof(tmp)); + } + + d->d_inode->i_fop = fops; + } else + sysfs_remove_bin_file(kobj, &attr->bin); + + return -ENOENT; +}; + +/** + * sysfs_remove_fops_file - Remove attribute with special file operations + * @kobj: kobject which contains the attribute + * @attr: attributes which are used to create file + * + * Only wrapper arround sysfs_remove_bin_file() + * + * Returns 0 on success or negative error code on failure. + */ +static inline int sysfs_remove_fops_file(struct kobject *kobj, + struct fops_attribute *attr) +{ + return sysfs_remove_bin_file(kobj, &attr->bin); +}; + +/** + * i2o_config_read_hrt - Returns the HRT of the controller + * @kob: kernel object handle + * @buf: buffer into which the HRT should be copied + * @off: file offset + * @count: number of bytes to read + * + * Put @count bytes starting at @off into @buf from the HRT of the I2O + * controller corresponding to @kobj. + * + * Returns number of bytes copied into buffer. + */ +static ssize_t i2o_config_read_hrt(struct kobject *kobj, char *buf, + loff_t offset, size_t count) +{ + struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop; + i2o_hrt *hrt = c->hrt.virt; + + u32 size = (hrt->num_entries * hrt->entry_len + 2) * 4; + + if (offset > size) + return 0; + + if (offset + count > size) + count = size - offset; + + memcpy(buf, (u8 *) hrt + offset, count); + + return count; +}; + +/** + * i2o_config_read_lct - Returns the LCT of the controller + * @kob: kernel object handle + * @buf: buffer into which the LCT should be copied + * @off: file offset + * @count: number of bytes to read + * + * Put @count bytes starting at @off into @buf from the LCT of the I2O + * controller corresponding to @kobj. + * + * Returns number of bytes copied into buffer. + */ +static ssize_t i2o_config_read_lct(struct kobject *kobj, char *buf, + loff_t offset, size_t count) +{ + struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop; + u32 size = c->lct->table_size * 4; + + if (offset > size) + return 0; + + if (offset + count > size) + count = size - offset; + + memcpy(buf, (u8 *) c->lct + offset, count); + + return count; +}; + +#define I2O_CONFIG_SW_ATTR(_name,_mode,_type,_swid) \ +static ssize_t i2o_config_##_name##_read(struct file *file, char __user *buf, size_t count, loff_t * offset) { \ + return i2o_config_sw_read(file, buf, count, offset, _type, _swid); \ +};\ +\ +static ssize_t i2o_config_##_name##_write(struct file *file, const char __user *buf, size_t count, loff_t * offset) { \ + return i2o_config_sw_write(file, buf, count, offset, _type, _swid); \ +}; \ +\ +static struct fops_attribute i2o_config_attr_##_name = { \ + .bin = { .attr = { .name = __stringify(_name), .mode = _mode, \ + .owner = THIS_MODULE }, \ + .size = 0, }, \ + .fops = { .write = i2o_config_##_name##_write, \ + .read = i2o_config_##_name##_read} \ +}; + +#ifdef CONFIG_I2O_EXT_ADAPTEC + +/** + * i2o_config_dpt_reagion - Converts type and id to flash region + * @swtype: type of software module reading + * @swid: id of software which should be read + * + * Converts type and id from I2O spec to the matching region for DPT / + * Adaptec controllers. + * + * Returns region which match type and id or -1 on error. + */ +static u32 i2o_config_dpt_region(u8 swtype, u8 swid) +{ + switch (swtype) { + case I2O_SOFTWARE_MODULE_IRTOS: + /* + * content: operation firmware + * region size: + * 0xbc000 for 2554, 3754, 2564, 3757 + * 0x170000 for 2865 + * 0x17c000 for 3966 + */ + if (!swid) + return 0; + + break; + + case I2O_SOFTWARE_MODULE_IOP_PRIVATE: + /* + * content: BIOS and SMOR + * BIOS size: first 0x8000 bytes + * region size: + * 0x40000 for 2554, 3754, 2564, 3757 + * 0x80000 for 2865, 3966 + */ + if (!swid) + return 1; + + break; + + case I2O_SOFTWARE_MODULE_IOP_CONFIG: + switch (swid) { + case 0: + /* + * content: NVRAM defaults + * region size: 0x2000 bytes + */ + return 2; + case 1: + /* + * content: serial number + * region size: 0x2000 bytes + */ + return 3; + } + break; + } + + return -1; +}; + +#endif + +/** + * i2o_config_sw_read - Read a software module from controller + * @file: file pointer + * @buf: buffer into which the data should be copied + * @count: number of bytes to read + * @off: file offset + * @swtype: type of software module reading + * @swid: id of software which should be read + * + * Transfers @count bytes at offset @offset from IOP into buffer using + * type @swtype and id @swid as described in I2O spec. + * + * Returns number of bytes copied into buffer or error code on failure. + */ +static ssize_t i2o_config_sw_read(struct file *file, char __user * buf, + size_t count, loff_t * offset, u8 swtype, + u32 swid) +{ + struct sysfs_dirent *sd = file->f_dentry->d_parent->d_fsdata; + struct kobject *kobj = sd->s_element; + struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop; + u32 m, function = I2O_CMD_SW_UPLOAD; + struct i2o_dma buffer; + struct i2o_message __iomem *msg; + u32 __iomem *mptr; + int rc, status; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -EBUSY; + + mptr = &msg->body[3]; + + if ((rc = i2o_dma_alloc(&c->pdev->dev, &buffer, count, GFP_KERNEL))) { + i2o_msg_nop(c, m); + return rc; + } +#ifdef CONFIG_I2O_EXT_ADAPTEC + if (c->adaptec) { + mptr = &msg->body[4]; + function = I2O_CMD_PRIVATE; + + writel(TEN_WORD_MSG_SIZE | SGL_OFFSET_8, &msg->u.head[0]); + + writel(I2O_VENDOR_DPT << 16 | I2O_DPT_FLASH_READ, + &msg->body[0]); + writel(i2o_config_dpt_region(swtype, swid), &msg->body[1]); + writel(*offset, &msg->body[2]); + writel(count, &msg->body[3]); + } else +#endif + writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]); + + writel(0xD0000000 | count, mptr++); + writel(buffer.phys, mptr); + + writel(function << 24 | HOST_TID << 12 | ADAPTER_TID, &msg->u.head[1]); + writel(i2o_config_driver.context, &msg->u.head[2]); + writel(0, &msg->u.head[3]); + +#ifdef CONFIG_I2O_EXT_ADAPTEC + if (!c->adaptec) +#endif + { + writel((u32) swtype << 16 | (u32) 1 << 8, &msg->body[0]); + writel(0, &msg->body[1]); + writel(swid, &msg->body[2]); + } + + status = i2o_msg_post_wait_mem(c, m, 60, &buffer); + + if (status == I2O_POST_WAIT_OK) { + if (!(rc = copy_to_user(buf, buffer.virt, count))) { + rc = count; + *offset += count; + } + } else + rc = -EIO; + + if (status != -ETIMEDOUT) + i2o_dma_free(&c->pdev->dev, &buffer); + + return rc; +}; + +/** + * i2o_config_sw_write - Write a software module to controller + * @file: file pointer + * @buf: buffer into which the data should be copied + * @count: number of bytes to read + * @off: file offset + * @swtype: type of software module writing + * @swid: id of software which should be written + * + * Transfers @count bytes at offset @offset from buffer to IOP using + * type @swtype and id @swid as described in I2O spec. + * + * Returns number of bytes copied from buffer or error code on failure. + */ +static ssize_t i2o_config_sw_write(struct file *file, const char __user * buf, + size_t count, loff_t * offset, u8 swtype, + u32 swid) +{ + struct sysfs_dirent *sd = file->f_dentry->d_parent->d_fsdata; + struct kobject *kobj = sd->s_element; + struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop; + u32 m, function = I2O_CMD_SW_DOWNLOAD; + struct i2o_dma buffer; + struct i2o_message __iomem *msg; + u32 __iomem *mptr; + int rc, status; + + m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); + if (m == I2O_QUEUE_EMPTY) + return -EBUSY; + + mptr = &msg->body[3]; + + if ((rc = i2o_dma_alloc(&c->pdev->dev, &buffer, count, GFP_KERNEL))) + goto nop_msg; + + if ((rc = copy_from_user(buffer.virt, buf, count))) + goto free_buffer; + +#ifdef CONFIG_I2O_EXT_ADAPTEC + if (c->adaptec) { + mptr = &msg->body[4]; + function = I2O_CMD_PRIVATE; + + writel(TEN_WORD_MSG_SIZE | SGL_OFFSET_8, &msg->u.head[0]); + + writel(I2O_VENDOR_DPT << 16 | I2O_DPT_FLASH_WRITE, + &msg->body[0]); + writel(i2o_config_dpt_region(swtype, swid), &msg->body[1]); + writel(*offset, &msg->body[2]); + writel(count, &msg->body[3]); + } else +#endif + writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]); + + writel(0xD4000000 | count, mptr++); + writel(buffer.phys, mptr); + + writel(function << 24 | HOST_TID << 12 | ADAPTER_TID, &msg->u.head[1]); + writel(i2o_config_driver.context, &msg->u.head[2]); + writel(0, &msg->u.head[3]); + +#ifdef CONFIG_I2O_EXT_ADAPTEC + if (!c->adaptec) +#endif + { + writel((u32) swtype << 16 | (u32) 1 << 8, &msg->body[0]); + writel(0, &msg->body[1]); + writel(swid, &msg->body[2]); + } + + status = i2o_msg_post_wait_mem(c, m, 60, &buffer); + + if (status != -ETIMEDOUT) + i2o_dma_free(&c->pdev->dev, &buffer); + + if (status != I2O_POST_WAIT_OK) + return -EIO; + + *offset += count; + + return count; + + free_buffer: + i2o_dma_free(&c->pdev->dev, &buffer); + + nop_msg: + i2o_msg_nop(c, m); + + return rc; +}; + +/* attribute for HRT in sysfs */ +static struct bin_attribute i2o_config_hrt_attr = { + .attr = { + .name = "hrt", + .mode = S_IRUGO, + .owner = THIS_MODULE}, + .size = 0, + .read = i2o_config_read_hrt +}; + +/* attribute for LCT in sysfs */ +static struct bin_attribute i2o_config_lct_attr = { + .attr = { + .name = "lct", + .mode = S_IRUGO, + .owner = THIS_MODULE}, + .size = 0, + .read = i2o_config_read_lct +}; + +/* IRTOS firmware access */ +I2O_CONFIG_SW_ATTR(irtos, S_IWRSR, I2O_SOFTWARE_MODULE_IRTOS, 0); + +#ifdef CONFIG_I2O_EXT_ADAPTEC + +/* + * attribute for BIOS / SMOR, nvram and serial number access on DPT / Adaptec + * controllers + */ +I2O_CONFIG_SW_ATTR(bios, S_IWRSR, I2O_SOFTWARE_MODULE_IOP_PRIVATE, 0); +I2O_CONFIG_SW_ATTR(nvram, S_IWRSR, I2O_SOFTWARE_MODULE_IOP_CONFIG, 0); +I2O_CONFIG_SW_ATTR(serial, S_IWRSR, I2O_SOFTWARE_MODULE_IOP_CONFIG, 1); + +#endif + +/** + * i2o_config_notify_controller_add - Notify of added controller + * @c: the controller which was added + * + * If a I2O controller is added, we catch the notification to add sysfs + * entries. + */ +static void i2o_config_notify_controller_add(struct i2o_controller *c) +{ + struct kobject *kobj = &c->exec->device.kobj; + + sysfs_create_bin_file(kobj, &i2o_config_hrt_attr); + sysfs_create_bin_file(kobj, &i2o_config_lct_attr); + + sysfs_create_fops_file(kobj, &i2o_config_attr_irtos); +#ifdef CONFIG_I2O_EXT_ADAPTEC + if (c->adaptec) { + sysfs_create_fops_file(kobj, &i2o_config_attr_bios); + sysfs_create_fops_file(kobj, &i2o_config_attr_nvram); + sysfs_create_fops_file(kobj, &i2o_config_attr_serial); + } +#endif +}; + +/** + * i2o_config_notify_controller_remove - Notify of removed controller + * @c: the controller which was removed + * + * If a I2O controller is removed, we catch the notification to remove the + * sysfs entries. + */ +static void i2o_config_notify_controller_remove(struct i2o_controller *c) +{ + struct kobject *kobj = &c->exec->device.kobj; + +#ifdef CONFIG_I2O_EXT_ADAPTEC + if (c->adaptec) { + sysfs_remove_fops_file(kobj, &i2o_config_attr_serial); + sysfs_remove_fops_file(kobj, &i2o_config_attr_nvram); + sysfs_remove_fops_file(kobj, &i2o_config_attr_bios); + } +#endif + sysfs_remove_fops_file(kobj, &i2o_config_attr_irtos); + + sysfs_remove_bin_file(kobj, &i2o_config_lct_attr); + sysfs_remove_bin_file(kobj, &i2o_config_hrt_attr); +}; + +/* Config OSM driver struct */ +static struct i2o_driver i2o_config_driver = { + .name = OSM_NAME, + .notify_controller_add = i2o_config_notify_controller_add, + .notify_controller_remove = i2o_config_notify_controller_remove +}; + +#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL +#include "i2o_config.c" +#endif + +/** + * i2o_config_init - Configuration OSM initialization function + * + * Registers Configuration OSM in the I2O core and if old ioctl's are + * compiled in initialize them. + * + * Returns 0 on success or negative error code on failure. + */ +static int __init i2o_config_init(void) +{ + printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n"); + + if (i2o_driver_register(&i2o_config_driver)) { + osm_err("handler register failed.\n"); + return -EBUSY; + } +#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL + if (i2o_config_old_init()) + i2o_driver_unregister(&i2o_config_driver); +#endif + + return 0; +} + +/** + * i2o_config_exit - Configuration OSM exit function + * + * If old ioctl's are compiled in exit remove them and unregisters + * Configuration OSM from I2O core. + */ +static void i2o_config_exit(void) +{ +#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL + i2o_config_old_exit(); +#endif + + i2o_driver_unregister(&i2o_config_driver); +} + +MODULE_AUTHOR("Markus Lidel <Markus.Lidel@shadowconnect.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(OSM_DESCRIPTION); +MODULE_VERSION(OSM_VERSION); + +module_init(i2o_config_init); +module_exit(i2o_config_exit); diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c index bebdd509b5d8..393be8e2914c 100644 --- a/drivers/message/i2o/driver.c +++ b/drivers/message/i2o/driver.c @@ -180,7 +180,13 @@ int i2o_driver_dispatch(struct i2o_controller *c, u32 m) { struct i2o_driver *drv; struct i2o_message __iomem *msg = i2o_msg_out_to_virt(c, m); - u32 context = readl(&msg->u.s.icntxt); + u32 context; + unsigned long flags; + + if(unlikely(!msg)) + return -EIO; + + context = readl(&msg->u.s.icntxt); if (unlikely(context >= i2o_max_drivers)) { osm_warn("%s: Spurious reply to unknown driver %d\n", c->name, @@ -188,9 +194,9 @@ int i2o_driver_dispatch(struct i2o_controller *c, u32 m) return -EIO; } - spin_lock(&i2o_drivers_lock); + spin_lock_irqsave(&i2o_drivers_lock, flags); drv = i2o_drivers[context]; - spin_unlock(&i2o_drivers_lock); + spin_unlock_irqrestore(&i2o_drivers_lock, flags); if (unlikely(!drv)) { osm_warn("%s: Spurious reply to unknown driver %d\n", c->name, diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index 5581344fbba6..0160221c802a 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -206,6 +206,7 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, u32 context) { struct i2o_exec_wait *wait, *tmp; + unsigned long flags; static spinlock_t lock = SPIN_LOCK_UNLOCKED; int rc = 1; @@ -216,11 +217,13 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, * already expired. Not much we can do about that except log it for * debug purposes, increase timeout, and recompile. */ - spin_lock(&lock); + spin_lock_irqsave(&lock, flags); list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) { if (wait->tcntxt == context) { list_del(&wait->list); + spin_unlock_irqrestore(&lock, flags); + wait->m = m; wait->msg = msg; wait->complete = 1; @@ -242,13 +245,11 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, rc = -1; } - spin_unlock(&lock); - return rc; } } - spin_unlock(&lock); + spin_unlock_irqrestore(&lock, flags); osm_warn("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name, context); @@ -257,6 +258,50 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, }; /** + * i2o_exec_show_vendor_id - Displays Vendor ID of controller + * @d: device of which the Vendor ID should be displayed + * @buf: buffer into which the Vendor ID should be printed + * + * Returns number of bytes printed into buffer. + */ +static ssize_t i2o_exec_show_vendor_id(struct device *d, char *buf) +{ + struct i2o_device *dev = to_i2o_device(d); + u16 id; + + if (i2o_parm_field_get(dev, 0x0000, 0, &id, 2)) { + sprintf(buf, "0x%04x", id); + return strlen(buf) + 1; + } + + return 0; +}; + +/** + * i2o_exec_show_product_id - Displays Product ID of controller + * @d: device of which the Product ID should be displayed + * @buf: buffer into which the Product ID should be printed + * + * Returns number of bytes printed into buffer. + */ +static ssize_t i2o_exec_show_product_id(struct device *d, char *buf) +{ + struct i2o_device *dev = to_i2o_device(d); + u16 id; + + if (i2o_parm_field_get(dev, 0x0000, 1, &id, 2)) { + sprintf(buf, "0x%04x", id); + return strlen(buf) + 1; + } + + return 0; +}; + +/* Exec-OSM device attributes */ +static DEVICE_ATTR(vendor_id, S_IRUGO, i2o_exec_show_vendor_id, NULL); +static DEVICE_ATTR(product_id, S_IRUGO, i2o_exec_show_product_id, NULL); + +/** * i2o_exec_probe - Called if a new I2O device (executive class) appears * @dev: I2O device which should be probed * @@ -268,10 +313,16 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, static int i2o_exec_probe(struct device *dev) { struct i2o_device *i2o_dev = to_i2o_device(dev); + struct i2o_controller *c = i2o_dev->iop; i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff); - i2o_dev->iop->exec = i2o_dev; + c->exec = i2o_dev; + + i2o_exec_lct_notify(c, c->lct->change_ind + 1); + + device_create_file(dev, &dev_attr_vendor_id); + device_create_file(dev, &dev_attr_product_id); return 0; }; @@ -286,6 +337,9 @@ static int i2o_exec_probe(struct device *dev) */ static int i2o_exec_remove(struct device *dev) { + device_remove_file(dev, &dev_attr_product_id); + device_remove_file(dev, &dev_attr_vendor_id); + i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0); return 0; @@ -297,12 +351,16 @@ static int i2o_exec_remove(struct device *dev) * * This function handles asynchronus LCT NOTIFY replies. It parses the * new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY - * again. + * again, otherwise send LCT NOTIFY to get informed on next LCT change. */ static void i2o_exec_lct_modified(struct i2o_controller *c) { - if (i2o_device_parse_lct(c) == -EAGAIN) - i2o_exec_lct_notify(c, 0); + u32 change_ind = 0; + + if (i2o_device_parse_lct(c) != -EAGAIN) + change_ind = c->lct->change_ind + 1; + + i2o_exec_lct_notify(c, change_ind); }; /** diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index e69421e36ac5..1dd2b9dad50e 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -147,6 +147,29 @@ static int i2o_block_device_flush(struct i2o_device *dev) }; /** + * i2o_block_issue_flush - device-flush interface for block-layer + * @queue: the request queue of the device which should be flushed + * @disk: gendisk + * @error_sector: error offset + * + * Helper function to provide flush functionality to block-layer. + * + * Returns 0 on success or negative error code on failure. + */ + +static int i2o_block_issue_flush(request_queue_t * queue, struct gendisk *disk, + sector_t * error_sector) +{ + struct i2o_block_device *i2o_blk_dev = queue->queuedata; + int rc = -ENODEV; + + if (likely(i2o_blk_dev)) + rc = i2o_block_device_flush(i2o_blk_dev->i2o_dev); + + return rc; +} + +/** * i2o_block_device_mount - Mount (load) the media of device dev * @dev: I2O device which should receive the mount request * @media_id: Media Identifier @@ -299,28 +322,31 @@ static inline void i2o_block_request_free(struct i2o_block_request *ireq) /** * i2o_block_sglist_alloc - Allocate the SG list and map it + * @c: I2O controller to which the request belongs * @ireq: I2O block request * - * Builds the SG list and map it into to be accessable by the controller. + * Builds the SG list and map it to be accessable by the controller. * - * Returns the number of elements in the SG list or 0 on failure. + * Returns 0 on failure or 1 on success. */ -static inline int i2o_block_sglist_alloc(struct i2o_block_request *ireq) +static inline int i2o_block_sglist_alloc(struct i2o_controller *c, + struct i2o_block_request *ireq, + u32 __iomem ** mptr) { - struct device *dev = &ireq->i2o_blk_dev->i2o_dev->iop->pdev->dev; int nents; + enum dma_data_direction direction; + ireq->dev = &c->pdev-> |