Commit f10378ff authored by Markus Lidel's avatar Markus Lidel Committed by Linus Torvalds

[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: default avatarMarkus Lidel <Markus.Lidel@shadowconnect.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f88e119c
......@@ -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
......
......@@ -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
/*
* 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);
This diff is collapsed.
......@@ -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,
......
......@@ -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);
......@@ -256,6 +257,50 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
return -1;
};
/**
* 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);
};
/**
......
This diff is collapsed.
......@@ -84,9 +84,9 @@ struct i2o_block_request
struct list_head queue;
struct request *req; /* corresponding request */
struct i2o_block_device *i2o_blk_dev; /* I2O block device */
int sg_dma_direction; /* direction of DMA buffer read/write */
struct device *dev; /* device used for DMA */
int sg_nents; /* number of SG elements */
struct scatterlist sg_table[I2O_MAX_SEGMENTS]; /* SG table */
struct scatterlist sg_table[I2O_MAX_PHYS_SEGMENTS]; /* SG table */
};
/* I2O Block device delayed request */
......
......@@ -30,27 +30,11 @@
* 2 of the License, or (at your option) any later version.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/i2o.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
#include <linux/spinlock.h>
#include <linux/smp_lock.h>
#include <linux/ioctl32.h>
#include <linux/compat.h>
#include <linux/syscalls.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define OSM_NAME "config-osm"
#define OSM_VERSION "$Rev$"
#define OSM_DESCRIPTION "I2O Configuration OSM"
extern int i2o_parm_issue(struct i2o_device *, int, void *, int, void *, int);
......@@ -80,125 +64,6 @@ struct i2o_cfg_info {
static struct i2o_cfg_info *open_files = NULL;
static ulong i2o_cfg_info_id = 0;
/**
* 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 = to_i2o_controller(container_of(kobj,
struct device,
kobj));
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 = to_i2o_controller(container_of(kobj,
struct device,
kobj));
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;
};
/* 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
};
/**
* 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)
{
sysfs_create_bin_file(&(c->device.kobj), &i2o_config_hrt_attr);
sysfs_create_bin_file(&(c->device.kobj), &i2o_config_lct_attr);
};
/**
* 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)
{
sysfs_remove_bin_file(&c->device.kobj, &i2o_config_lct_attr);
sysfs_remove_bin_file(&c->device.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
};
static int i2o_cfg_getiops(unsigned long arg)
{
struct i2o_controller *c;
......@@ -1257,37 +1122,20 @@ static struct miscdevice i2o_miscdev = {
&config_fops
};
static int __init i2o_config_init(void)
static int __init i2o_config_old_init(void)
{
printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
spin_lock_init(&i2o_config_lock);
if (misc_register(&i2o_miscdev) < 0) {
osm_err("can't register device.\n");
return -EBUSY;
}
/*
* Install our handler
*/
if (i2o_driver_register(&i2o_config_driver)) {
osm_err("handler register failed.\n");
misc_deregister(&i2o_miscdev);
return -EBUSY;
}
return 0;
}
static void i2o_config_exit(void)
static void i2o_config_old_exit(void)
{
misc_deregister(&i2o_miscdev);
i2o_driver_unregister(&i2o_config_driver);
}
MODULE_AUTHOR("Red Hat Software");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(OSM_DESCRIPTION);
MODULE_VERSION(OSM_VERSION);
module_init(i2o_config_init);
module_exit(i2o_config_exit);
......@@ -228,7 +228,7 @@ static const char *i2o_get_class_name(int class)
case I2O_CLASS_FLOPPY_DEVICE:
idx = 12;
break;
case I2O_CLASS_BUS_ADAPTER_PORT:
case I2O_CLASS_BUS_ADAPTER:
idx = 13;
break;
case I2O_CLASS_PEER_TRANSPORT_AGENT:
......@@ -490,7 +490,7 @@ static int i2o_seq_show_lct(struct seq_file *seq, void *v)
seq_printf(seq, ", Unknown Device Type");
break;
case I2O_CLASS_BUS_ADAPTER_PORT:
case I2O_CLASS_BUS_ADAPTER:
if (lct->lct_entry[i].sub_class < BUS_TABLE_SIZE)
seq_printf(seq, ", %s",
bus_ports[lct->lct_entry[i].
......
......@@ -103,7 +103,7 @@ static struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c)
i2o_status_block *sb;
list_for_each_entry(i2o_dev, &c->devices, list)
if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER_PORT) {
if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
&& (type == 0x01)) /* SCSI bus */
max_channel++;
......@@ -139,7 +139,7 @@ static struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c)
i = 0;
list_for_each_entry(i2o_dev, &c->devices, list)
if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER_PORT) {
if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1) || (type == 1)) /* only SCSI bus */
i2o_shost->channel[i++] = i2o_dev;
......@@ -186,6 +186,7 @@ static int i2o_scsi_remove(struct device *dev)
shost_for_each_device(scsi_dev, i2o_shost->scsi_host)
if (scsi_dev->hostdata == i2o_dev) {
sysfs_remove_link(&i2o_dev->device.kobj, "scsi");
scsi_remove_device(scsi_dev);
scsi_device_put(scsi_dev);
break;
......@@ -259,12 +260,14 @@ static int i2o_scsi_probe(struct device *dev)
scsi_dev =
__scsi_add_device(i2o_shost->scsi_host, channel, id, lun, i2o_dev);
if (!scsi_dev) {
if (IS_ERR(scsi_dev)) {
osm_warn("can not add SCSI device %03x\n",
i2o_dev->lct_data.tid);
return -EFAULT;
return PTR_ERR(scsi_dev);
}
sysfs_create_link(&i2o_dev->device.kobj, &scsi_dev->sdev_gendev.kobj, "scsi");
osm_info("device added (TID: %03x) channel: %d, id: %d, lun: %d\n",
i2o_dev->lct_data.tid, channel, id, (unsigned int)lun);
......@@ -545,7 +548,13 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
int tid;
struct i2o_message __iomem *msg;
u32 m;
u32 scsi_flags, sg_flags;
/*
* ENABLE_DISCONNECT
* SIMPLE_TAG
* RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
*/
u32 scsi_flags = 0x20a00000;
u32 sg_flags;
u32 __iomem *mptr;
u32 __iomem *lenptr;
u32 len;
......@@ -591,17 +600,19 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
switch (SCpnt->sc_data_direction) {
case PCI_DMA_NONE:
scsi_flags = 0x00000000; // DATA NO XFER
/* DATA NO XFER */
sg_flags = 0x00000000;
break;
case PCI_DMA_TODEVICE:
scsi_flags = 0x80000000; // DATA OUT (iop-->dev)
/* DATA OUT (iop-->dev) */
scsi_flags |= 0x80000000;
sg_flags = 0x14000000;
break;
case PCI_DMA_FROMDEVICE:
scsi_flags = 0x40000000; // DATA IN (iop<--dev)
/* DATA IN (iop<--dev) */
scsi_flags |= 0x40000000;
sg_flags = 0x10000000;
break;
......@@ -639,8 +650,7 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
}
*/
/* Direction, disconnect ok, tag, CDBLen */
writel(scsi_flags | 0x20200000 | SCpnt->cmd_len, mptr ++);
writel(scsi_flags | SCpnt->cmd_len, mptr++);
/* Write SCSI command into the message - always 16 byte block */
memcpy_toio(mptr, SCpnt->cmnd, 16);
......
......@@ -455,6 +455,70 @@ static int i2o_iop_clear(struct i2o_controller *c)
return rc;
}
/**
* i2o_iop_init_outbound_queue - setup the outbound message queue
* @c: I2O controller
*
* Clear and (re)initialize IOP's outbound queue and post the message
* frames to the IOP.
*
* Returns 0 on success or a negative errno code on failure.
*/
static int i2o_iop_init_outbound_queue(struct i2o_controller *c)
{
u8 *status = c->status.virt;
u32 m;
struct i2o_message __iomem *msg;
ulong timeout;
int i;
osm_debug("%s: Initializing Outbound Queue...\n", c->name);
memset(status, 0, 4);
m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
if (m == I2O_QUEUE_EMPTY)
return -ETIMEDOUT;
writel(EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6, &msg->u.head[0]);
writel(I2O_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 | ADAPTER_TID,
&msg->u.head[1]);
writel(i2o_exec_driver.context, &msg->u.s.icntxt);
writel(0x0106, &msg->u.s.tcntxt); /* FIXME: why 0x0106, maybe in
Spec? */
writel(PAGE_SIZE, &msg->body[0]);
/* Outbound msg frame size in words and Initcode */
writel(MSG_FRAME_SIZE << 16 | 0x80, &msg->body[1]);
writel(0xd0000004, &msg->body[2]);
writel(i2o_dma_low(c->status.phys), &msg->body[3]);
writel(i2o_dma_high(c->status.phys), &msg->body[4]);
i2o_msg_post(c, m);
timeout = jiffies + I2O_TIMEOUT_INIT_OUTBOUND_QUEUE * HZ;
while (*status <= I2O_CMD_IN_PROGRESS) {
if (time_after(jiffies, timeout)) {
osm_warn("%s: Timeout Initializing\n", c->name);
return -ETIMEDOUT;
}
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
rmb();
}
m = c->out_queue.phys;
/* Post frames */
for (i = 0; i < NMBR_MSG_FRAMES; i++) {
i2o_flush_reply(c, m);
udelay(1); /* Promise */
m += MSG_FRAME_SIZE * 4;
}
return 0;
}
/**
* i2o_iop_reset - reset an I2O controller
* @c: controller to reset
......@@ -491,25 +555,16 @@ static int i2o_iop_reset(struct i2o_controller *c)
writel(0, &msg->u.s.tcntxt); //FIXME: use reasonable transaction context
writel(0, &msg->body[0]);
writel(0, &msg->body[1]);
writel(i2o_ptr_low((void *)c->status.phys), &msg->body[2]);
writel(i2o_ptr_high((void *)c->status.phys), &msg->body[3]);
writel(i2o_dma_low(c->status.phys), &msg->body[2]);
writel(i2o_dma_high(c->status.phys), &msg->body[3]);
i2o_msg_post(c, m);
/* Wait for a reply */
timeout = jiffies + I2O_TIMEOUT_RESET * HZ;
while (!*status) {
if (time_after(jiffies, timeout)) {
printk(KERN_ERR "%s: IOP reset timeout.\n", c->name);
rc = -ETIMEDOUT;
goto exit;
}
/* Promise bug */
if (status[1] || status[4]) {
*status = 0;
if (time_after(jiffies, timeout))
break;
}
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
......@@ -517,14 +572,20 @@ static int i2o_iop_reset(struct i2o_controller *c)
rmb();
}
if (*status == I2O_CMD_IN_PROGRESS) {
switch (*status) {
case I2O_CMD_REJECTED:
osm_warn("%s: IOP reset rejected\n", c->name);
rc = -EPERM;
break;
case I2O_CMD_IN_PROGRESS:
/*
* Once the reset is sent, the IOP goes into the INIT state
* which is indeterminate. We need to wait until the IOP
* has rebooted before we can let the system talk to
* it. We read the inbound Free_List until a message is
* available. If we can't read one in the given ammount of
* time, we assume the IOP could not reboot properly.
* which is indeterminate. We need to wait until the IOP has
* rebooted before we can let the system talk to it. We read
* the inbound Free_List until a message is available. If we
* can't read one in the given ammount of time, we assume the
* IOP could not reboot properly.
*/
pr_debug("%s: Reset in progress, waiting for reboot...\n",
c->name);
......@@ -543,19 +604,26 @@ static int i2o_iop_reset(struct i2o_controller *c)
m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_RESET);
}
i2o_msg_nop(c, m);
}
/* from here all quiesce commands are safe */
c->no_quiesce = 0;
/* If IopReset was rejected or didn't perform reset, try IopClear */
/* verify if controller is in state RESET */
i2o_status_get(c);
if (*status == I2O_CMD_REJECTED || sb->iop_state != ADAPTER_STATE_RESET) {
printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",
c->name);
i2o_iop_clear(c);
} else
pr_debug("%s: Reset completed.\n", c->name);
if (!c->promise && (sb->iop_state != ADAPTER_STATE_RESET))
osm_warn("%s: reset completed, but adapter not in RESET"
" state.\n", c->name);
else
osm_debug("%s: reset completed.\n", c->name);
break;
default:
osm_err("%s: IOP reset timeout.\n", c->name);
rc = -ETIMEDOUT;
break;
}
exit:
/* Enable all IOPs */
......@@ -564,87 +632,6 @@ static int i2o_iop_reset(struct i2o_controller *c)
return rc;
};
/**
* i2o_iop_init_outbound_queue - setup the outbound message queue
* @c: I2O controller
*
* Clear and (re)initialize IOP's outbound queue and post the message
* frames to the IOP.
*
* Returns 0 on success or a negative errno code on failure.
*/
static int i2o_iop_init_outbound_queue(struct i2o_controller *c)
{
u8 *status = c->status.virt;
u32 m;
struct i2o_message __iomem *msg;
ulong timeout;
int i;
pr_debug("%s: Initializing Outbound Queue...\n", c->name);
memset(status, 0, 4);
m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
if (m == I2O_QUEUE_EMPTY)
return -ETIMEDOUT;
writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]);
writel(I2O_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 | ADAPTER_TID,
&msg->u.head[1]);
writel(i2o_exec_driver.context, &msg->u.s.icntxt);
writel(0x00000000, &msg->u.s.tcntxt);
writel(PAGE_SIZE, &msg->body[0]);
writel(MSG_FRAME_SIZE << 16 | 0x80, &msg->body[1]); /* Outbound msg frame
size in words and Initcode */
writel(0xd0000004, &msg->body[2]);
writel(i2o_ptr_low((void *)c->status.phys), &msg->body[3]);
writel(i2o_ptr_high((void *)c->status.phys), &msg->body[4]);
i2o_msg_post(c, m);
timeout = jiffies + I2O_TIMEOUT_INIT_OUTBOUND_QUEUE * HZ;
while (*status <= I2O_CMD_IN_PROGRESS) {
if (time_after(jiffies, timeout)) {
printk(KERN_WARNING "%s: Timeout Initializing\n",
c->name);
return -ETIMEDOUT;
}
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
rmb();
}
m = c->out_queue.phys;
/* Post frames */
for (i = 0; i < NMBR_MSG_FRAMES; i++) {
i2o_flush_reply(c, m);
udelay(1); /* Promise */
m += MSG_FRAME_SIZE * 4;
}
return 0;
}
/**
* i2o_iop_send_nop - send a core NOP message
* @c: controller
*
* Send a no-operation message with a reply set to cause no
* action either. Needed for bringing up promise controllers.
*/
static int i2o_iop_send_nop(struct i2o_controller *c)
{
struct i2o_message __iomem *msg;
u32 m = i2o_msg_get_wait(c, &msg, HZ);
if (m == I2O_QUEUE_EMPTY)
return -ETIMEDOUT;
i2o_msg_nop(c, m);
return 0;
}
/**
* i2o_iop_activate - Bring controller up to HOLD
* @c: controller
......@@ -656,26 +643,9 @@ static int i2o_iop_send_nop(struct i2o_controller *c)
*/
static int i2o_iop_activate(struct i2o_controller *c)
{
struct pci_dev *i960 = NULL;
i2o_status_block *sb = c->status_block.virt;
int rc;
if (c->promise) {
/* Beat up the hardware first of all */
i960 =
pci_find_slot(c->pdev->bus->number,
PCI_DEVFN(PCI_SLOT(c->pdev->devfn), 0));
if (i960)
pci_write_config_word(i960, 0x42, 0);
/* Follow this sequence precisely or the controller
ceases to perform useful functions until reboot */
if ((rc = i2o_iop_send_nop(c)))
return rc;
if ((rc = i2o_iop_reset(c)))
return rc;
}
int state;
/* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */
/* In READY state, Get status */
......@@ -684,7 +654,8 @@ static int i2o_iop_activate(struct i2o_controller *c)
if (rc) {
printk(KERN_INFO "%s: Unable to obtain status, "
"attempting a reset.\n", c->name);
if (i2o_iop_reset(c))
rc = i2o_iop_reset(c);
if (rc)
return rc;
}
......@@ -697,37 +668,37 @@ static int i2o_iop_activate(struct i2o_controller *c)
switch (sb->iop_state) {
case ADAPTER_STATE_FAULTED:
printk(KERN_CRIT "%s: hardware fault\n", c->name);
return -ENODEV;
return -EFAULT;
case ADAPTER_STATE_READY:
case ADAPTER_STATE_OPERATIONAL:
case ADAPTER_STATE_HOLD:
case ADAPTER_STATE_FAILED:
pr_debug("%s: already running, trying to reset...\n", c->name);
if (i2o_iop_reset(c))
return -ENODEV;
rc = i2o_iop_reset(c);
if (rc)
return rc;
}
/* preserve state */
state = sb->iop_state;
rc = i2o_iop_init_outbound_queue(c);
if (rc)
return rc;
if (c->promise) {
if ((rc = i2o_iop_send_nop(c)))
return rc;
/* if adapter was not in RESET state clear now */
if (state != ADAPTER_STATE_RESET)
i2o_iop_clear(c);
if ((rc = i2o_status_get(c)))
return rc;
i2o_status_get(c);
if (i960)
pci_write_config_word(i960, 0x42, 0x3FF);
if (sb->iop_state != ADAPTER_STATE_HOLD) {
osm_err("%s: failed to bring IOP into HOLD state\n", c->name);
return -EIO;
}
/* In HOLD state */
rc = i2o_hrt_get(c);
return rc;
return i2o_hrt_get(c);
};
/**
......@@ -1030,8 +1001,8 @@ int i2o_status_get(struct i2o_controller *c)
writel(0, &msg->u.s.tcntxt); // FIXME: use resonable transaction context
writel(0, &msg->body[0]);
writel(0, &msg->body[1]);
writel(i2o_ptr_low((void *)c->status_block.phys), &msg->body[2]);
writel(i2o_ptr_high((void *)c->status_block.phys), &msg->body[3]);
writel(i2o_dma_low(c->status_block.phys), &msg->body[2]);
writel(i2o_dma_high(c->status_block.phys), &msg->body[3]);
writel(sizeof(i2o_status_block), &msg->body[4]); /* always 88 bytes */
i2o_msg_post(c, m);
......
......@@ -49,30 +49,6 @@ static struct pci_device_id __devinitdata i2o_pci_ids[] = {
{0}
};
/**
* i2o_dma_realloc - Realloc DMA memory
* @dev: struct device pointer to the PCI device of the I2O controller
* @addr: pointer to a i2o_dma struct DMA buffer
* @len: new length of memory
* @gfp_mask: GFP mask
*
* If there was something allocated in the addr, free it first. If len > 0
* than try to allocate it and write the addresses back to the addr
* structure. If len == 0 set the virtual address to NULL.
*
* Returns the 0 on success or negative error code on failure.
*/
int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr, size_t len,
unsigned int gfp_mask)
{
i2o_dma_free(dev, addr);
if (len)
return i2o_dma_alloc(dev, addr, len, gfp_mask);
return 0;
};
/**
* i2o_pci_free - Frees the DMA memory for the I2O controller
* @c: I2O controller to free
......@@ -185,6 +161,7 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
} else
c->in_queue = c->base;
c->irq_status = c->base.virt + I2O_IRQ_STATUS;
c->irq_mask = c->base.virt + I2O_IRQ_MASK;
c->in_port = c->base.virt + I2O_IN_PORT;
c->out_port = c->base.virt + I2O_OUT_PORT;
......@@ -232,36 +209,30 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r)
{
struct i2o_controller *c = dev_id;
struct device *dev = &c->pdev->dev;
u32 mv = readl(c->out_port);
u32 m;
irqreturn_t rc = IRQ_NONE;
while (readl(c->irq_status) & I2O_IRQ_OUTBOUND_POST) {
m = readl(c->out_port);
if (m == I2O_QUEUE_EMPTY) {
/*
* Old 960 steppings had a bug in the I2O unit that caused
* the queue to appear empty when it wasn't.
* Old 960 steppings had a bug in the I2O unit that
* caused the queue to appear empty when it wasn't.
*/
if (mv == I2O_QUEUE_EMPTY) {
mv = readl(c->out_port);
if (unlikely(mv == I2O_QUEUE_EMPTY))
return IRQ_NONE;
else
pr_debug("%s: 960 bug detected\n", c->name);
m = readl(c->out_port);
if (unlikely(m == I2O_QUEUE_EMPTY))
break;
}
while (mv != I2O_QUEUE_EMPTY) {
/* dispatch it */
if (i2o_driver_dispatch(c, mv))
if (i2o_driver_dispatch(c, m))
/* flush it if result != 0 */
i2o_flush_reply(c, mv);
i2o_flush_reply(c, m);
/*
* That 960 bug again...
*/
mv = readl(c->out_port);
if (mv == I2O_QUEUE_EMPTY)
mv = readl(c->out_port);
rc = IRQ_HANDLED;
}
return IRQ_HANDLED;
return rc;
}
/**
......
......@@ -32,6 +32,10 @@ typedef unsigned int u32;
#endif /* __KERNEL__ */
/*
* Vendors
*/
#define I2O_VENDOR_DPT 0x001b
/*
* I2O Control IOCTLs and structures
......@@ -333,7 +337,7 @@ typedef struct _i2o_status_block {
#define I2O_CLASS_ATE_PERIPHERAL 0x061
#define I2O_CLASS_FLOPPY_CONTROLLER 0x070
#define I2O_CLASS_FLOPPY_DEVICE 0x071
#define I2O_CLASS_BUS_ADAPTER_PORT 0x080
#define I2O_CLASS_BUS_ADAPTER 0x080
#define I2O_CLASS_PEER_TRANSPORT_AGENT 0x090
#define I2O_CLASS_PEER_TRANSPORT 0x091
#define I2O_CLASS_END 0xfff
......
This diff is collapsed.
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