--- /dev/null
+/*
+ * I2O core internal declarations
+ *
+ * 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.
+ */
+
+/* Exec-OSM */
+extern struct bus_type i2o_bus_type;
+
+extern struct i2o_driver i2o_exec_driver;
+extern int i2o_exec_lct_get(struct i2o_controller *);
+
+extern int __init i2o_exec_init(void);
+extern void __exit i2o_exec_exit(void);
+
+/* driver */
+extern int i2o_driver_dispatch(struct i2o_controller *, u32);
+
+extern int __init i2o_driver_init(void);
+extern void __exit i2o_driver_exit(void);
+
+/* PCI */
+extern int __init i2o_pci_init(void);
+extern void __exit i2o_pci_exit(void);
+
+/* device */
+extern void i2o_device_remove(struct i2o_device *);
+extern int i2o_device_parse_lct(struct i2o_controller *);
+
+extern int i2o_device_init(void);
+extern void i2o_device_exit(void);
+
+/* IOP */
+extern struct i2o_controller *i2o_iop_alloc(void);
+extern void i2o_iop_free(struct i2o_controller *);
+
+extern int i2o_iop_add(struct i2o_controller *);
+extern void i2o_iop_remove(struct i2o_controller *);
+
+/* control registers relative to c->base */
+#define I2O_IRQ_STATUS 0x30
+#define I2O_IRQ_MASK 0x34
+#define I2O_IN_PORT 0x40
+#define I2O_OUT_PORT 0x44
+
+#define I2O_IRQ_OUTBOUND_POST 0x00000008
#include <linux/pci.h>
#include <linux/i2o.h>
-extern struct i2o_driver **i2o_drivers;
-extern unsigned int i2o_max_drivers;
static void i2o_report_util_cmd(u8 cmd);
static void i2o_report_exec_cmd(u8 cmd);
static void i2o_report_fail_status(u8 req_status, u32 * msg);
u8 cmd = (msg[1] >> 24) & 0xFF;
u8 req_status = (msg[4] >> 24) & 0xFF;
u16 detailed_status = msg[4] & 0xFFFF;
- //struct i2o_driver *h = i2o_drivers[msg[2] & (i2o_max_drivers-1)];
if (cmd == I2O_CMD_UTIL_EVT_REGISTER)
return; // No status in this reply
#include <linux/module.h>
#include <linux/i2o.h>
#include <linux/delay.h>
-
-/* Exec OSM functions */
-extern struct bus_type i2o_bus_type;
+#include "core.h"
/**
* i2o_device_issue_claim - claim or release a device
}
if (lct->table_size * 4 > c->dlct.len) {
- memcpy_fromio(c->lct, c->dlct.virt, c->dlct.len);
+ memcpy(c->lct, c->dlct.virt, c->dlct.len);
up(&c->lct_lock);
return -EAGAIN;
}
- memcpy_fromio(c->lct, c->dlct.virt, lct->table_size * 4);
+ memcpy(c->lct, c->dlct.virt, lct->table_size * 4);
lct = c->lct;
{
struct i2o_device *dev = to_i2o_device(cd->dev);
- sprintf(buf, "%03x\n", dev->lct_data.class_id);
+ sprintf(buf, "0x%03x\n", dev->lct_data.class_id);
return strlen(buf) + 1;
};
{
struct i2o_device *dev = to_i2o_device(cd->dev);
- sprintf(buf, "%03x\n", dev->lct_data.tid);
+ sprintf(buf, "0x%03x\n", dev->lct_data.tid);
return strlen(buf) + 1;
};
if (rc == -ETIMEDOUT)
return rc;
- memcpy_fromio(reslist, res.virt, res.len);
+ memcpy(reslist, res.virt, res.len);
i2o_dma_free(dev, &res);
/* Query failed */
void *buf, int buflen)
{
u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
- u8 resblk[8 + buflen]; /* 8 bytes for header */
+ u8 *resblk; /* 8 bytes for header */
int size;
if (field == -1) /* whole group */
opblk[4] = -1;
+ resblk = kmalloc(buflen + 8, GFP_KERNEL | GFP_ATOMIC);
+ if (!resblk)
+ return -ENOMEM;
+
size = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
sizeof(opblk), resblk, buflen + 8);
memcpy(buf, resblk + 8, buflen); /* cut off header */
+ kfree(resblk);
+
if (size > buflen)
return buflen;
#include <linux/module.h>
#include <linux/rwsem.h>
#include <linux/i2o.h>
+#include "core.h"
#define OSM_NAME "i2o"
/* max_drivers - Maximum I2O drivers (OSMs) which could be registered */
-unsigned int i2o_max_drivers = I2O_MAX_DRIVERS;
+static unsigned int i2o_max_drivers = I2O_MAX_DRIVERS;
module_param_named(max_drivers, i2o_max_drivers, uint, 0);
MODULE_PARM_DESC(max_drivers, "maximum number of OSM's to support");
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;
+ struct i2o_message *msg = i2o_msg_out_to_virt(c, m);
+ u32 context = le32_to_cpu(msg->u.s.icntxt);
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,
context);
return -EIO;
}
- if ((readl(&msg->u.head[1]) >> 24) == I2O_CMD_UTIL_EVT_REGISTER) {
+ if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_UTIL_EVT_REGISTER) {
struct i2o_device *dev, *tmp;
struct i2o_event *evt;
u16 size;
- u16 tid = readl(&msg->u.head[1]) & 0xfff;
+ u16 tid = le32_to_cpu(msg->u.head[1]) & 0xfff;
osm_debug("event received from device %d\n", tid);
return -EIO;
/* cut of header from message size (in 32-bit words) */
- size = (readl(&msg->u.head[0]) >> 16) - 5;
+ size = (le32_to_cpu(msg->u.head[0]) >> 16) - 5;
evt = kmalloc(size * 4 + sizeof(*evt), GFP_ATOMIC | __GFP_ZERO);
if (!evt)
return -ENOMEM;
evt->size = size;
- evt->tcntxt = readl(&msg->u.s.tcntxt);
- evt->event_indicator = readl(&msg->body[0]);
- memcpy_fromio(&evt->tcntxt, &msg->u.s.tcntxt, size * 4);
+ evt->tcntxt = le32_to_cpu(msg->u.s.tcntxt);
+ evt->event_indicator = le32_to_cpu(msg->body[0]);
+ memcpy(&evt->tcntxt, &msg->u.s.tcntxt, size * 4);
list_for_each_entry_safe(dev, tmp, &c->devices, list)
if (dev->lct_data.tid == tid) {
#include <linux/module.h>
#include <linux/i2o.h>
#include <linux/delay.h>
+#include "core.h"
#define OSM_NAME "exec-osm"
static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind);
-/* Module internal functions from other sources */
-extern int i2o_device_parse_lct(struct i2o_controller *);
-
/* global wait list for POST WAIT */
static LIST_HEAD(i2o_exec_wait_list);
u32 tcntxt; /* transaction context from reply */
int complete; /* 1 if reply received otherwise 0 */
u32 m; /* message id */
- struct i2o_message __iomem *msg; /* pointer to the reply message */
+ struct i2o_message *msg; /* pointer to the reply message */
struct list_head list; /* node in global wait list */
};
barrier();
if (wait->complete) {
- rc = readl(&wait->msg->body[0]) >> 24;
+ rc = le32_to_cpu(wait->msg->body[0]) >> 24;
i2o_flush_reply(c, wait->m);
i2o_exec_wait_free(wait);
} else {
* message must also be given back to the controller.
*/
static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
- struct i2o_message __iomem *msg,
- u32 context)
+ struct i2o_message *msg, u32 context)
{
struct i2o_exec_wait *wait, *tmp;
unsigned long flags;
* code on failure and if the reply should be flushed.
*/
static int i2o_exec_reply(struct i2o_controller *c, u32 m,
- struct i2o_message __iomem *msg)
+ struct i2o_message *msg)
{
u32 context;
- if (readl(&msg->u.head[0]) & MSG_FAIL) {
+ if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) {
/*
* If Fail bit is set we must take the transaction context of
* the preserved message to find the right request again.
struct i2o_message __iomem *pmsg;
u32 pm;
- pm = readl(&msg->body[3]);
+ pm = le32_to_cpu(msg->body[3]);
pmsg = i2o_msg_in_to_virt(c, pm);
/* Release the preserved msg */
i2o_msg_nop(c, pm);
} else
- context = readl(&msg->u.s.tcntxt);
+ context = le32_to_cpu(msg->u.s.tcntxt);
if (context & 0x80000000)
return i2o_msg_post_wait_complete(c, m, msg, context);
- if ((readl(&msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) {
+ if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) {
struct work_struct *work;
pr_debug("%s: LCT notify received\n", c->name);
*/
static void i2o_exec_event(struct i2o_event *evt)
{
- if(likely(evt->i2o_dev))
- osm_info("Event received from device: %d\n",
- evt->i2o_dev->lct_data.tid);
+ if (likely(evt->i2o_dev))
+ osm_debug("Event received from device: %d\n",
+ evt->i2o_dev->lct_data.tid);
kfree(evt);
};
#include "i2o_block.h"
#define OSM_NAME "block-osm"
-#define OSM_VERSION "$Rev$"
+#define OSM_VERSION "1.287"
#define OSM_DESCRIPTION "I2O Block Device OSM"
static struct i2o_driver i2o_block_driver;
static void i2o_block_event(struct i2o_event *evt)
{
- osm_info("event received\n");
+ osm_debug("event received\n");
kfree(evt);
};
#include <asm/uaccess.h>
+#define SG_TABLESIZE 30
+
extern int i2o_parm_issue(struct i2o_device *, int, void *, int, void *, int);
static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
goto sg_list_cleanup;
if (sg_offset) {
- u32 msg[MSG_FRAME_SIZE];
+ u32 msg[I2O_OUTBOUND_MSG_FRAME_SIZE];
/* Copy back the Scatter Gather buffers back to user space */
u32 j;
// TODO 64bit fix
int sg_size;
// re-acquire the original message to handle correctly the sg copy operation
- memset(&msg, 0, MSG_FRAME_SIZE * 4);
+ memset(&msg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);
// get user msg size in u32s
if (get_user(size, &user_msg[0])) {
rcode = -EFAULT;
int sg_size;
// re-acquire the original message to handle correctly the sg copy operation
- memset(&msg, 0, MSG_FRAME_SIZE * 4);
+ memset(&msg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);
// get user msg size in u32s
if (get_user(size, &user_msg[0])) {
rcode = -EFAULT;
* Fix the resource management problems.
*/
-#define DEBUG 1
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
struct i2o_message *msg)
{
struct scsi_cmnd *cmd;
+ u32 error;
struct device *dev;
- u8 as, ds, st;
cmd = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
-
- if (msg->u.head[0] & (1 << 13)) {
- struct i2o_message __iomem *pmsg; /* preserved message */
- u32 pm;
- int err = DID_ERROR;
-
- pm = le32_to_cpu(msg->body[3]);
-
- pmsg = i2o_msg_in_to_virt(c, pm);
-
- osm_err("IOP fail.\n");
- osm_err("From %d To %d Cmd %d.\n",
- (msg->u.head[1] >> 12) & 0xFFF,
- msg->u.head[1] & 0xFFF, msg->u.head[1] >> 24);
- osm_err("Failure Code %d.\n", msg->body[0] >> 24);
- if (msg->body[0] & (1 << 16))
- osm_err("Format error.\n");
- if (msg->body[0] & (1 << 17))
- osm_err("Path error.\n");
- if (msg->body[0] & (1 << 18))
- osm_err("Path State.\n");
- if (msg->body[0] & (1 << 18))
- {
- osm_err("Congestion.\n");
- err = DID_BUS_BUSY;
- }
-
- osm_debug("Failing message is %p.\n", pmsg);
-
- cmd = i2o_cntxt_list_get(c, readl(&pmsg->u.s.tcntxt));
- if (!cmd)
- return 1;
-
- cmd->result = err << 16;
- cmd->scsi_done(cmd);
-
- /* Now flush the message by making it a NOP */
- i2o_msg_nop(c, pm);
-
- return 1;
+ if (unlikely(!cmd)) {
+ osm_err("NULL reply received!\n");
+ return -1;
}
/*
* Low byte is device status, next is adapter status,
* (then one byte reserved), then request status.
*/
- ds = (u8) le32_to_cpu(msg->body[0]);
- as = (u8) (le32_to_cpu(msg->body[0]) >> 8);
- st = (u8) (le32_to_cpu(msg->body[0]) >> 24);
+ error = le32_to_cpu(msg->body[0]);
+ osm_debug("Completed %ld\n", cmd->serial_number);
+
+ cmd->result = error & 0xff;
/*
- * Is this a control request coming back - eg an abort ?
+ * if DeviceStatus is not SCSI_SUCCESS copy over the sense data and let
+ * the SCSI layer handle the error
*/
+ if (cmd->result)
+ memcpy(cmd->sense_buffer, &msg->body[3],
+ min(sizeof(cmd->sense_buffer), (size_t) 40));
- if (!cmd) {
- if (st)
- osm_warn("SCSI abort: %08X", le32_to_cpu(msg->body[0]));
- osm_info("SCSI abort completed.\n");
- return -EFAULT;
- }
+ /* only output error code if AdapterStatus is not HBA_SUCCESS */
+ if ((error >> 8) & 0xff)
+ osm_err("SCSI error %08x\n", error);
- osm_debug("Completed %ld\n", cmd->serial_number);
+ dev = &c->pdev->dev;
+ if (cmd->use_sg)
+ dma_unmap_sg(dev, cmd->request_buffer, cmd->use_sg,
+ cmd->sc_data_direction);
+ else if (cmd->SCp.dma_handle)
+ dma_unmap_single(dev, cmd->SCp.dma_handle, cmd->request_bufflen,
+ cmd->sc_data_direction);
- if (st) {
- u32 count, error;
- /* An error has occurred */
-
- switch (st) {
- case 0x06:
- count = le32_to_cpu(msg->body[1]);
- if (count < cmd->underflow) {
- int i;
-
- osm_err("SCSI underflow 0x%08X 0x%08X\n", count,
- cmd->underflow);
- osm_debug("Cmd: ");
- for (i = 0; i < 15; i++)
- pr_debug("%02X ", cmd->cmnd[i]);
- pr_debug(".\n");
- cmd->result = (DID_ERROR << 16);
- }
- break;
+ cmd->scsi_done(cmd);
- default:
- error = le32_to_cpu(msg->body[0]);
-
- osm_err("SCSI error %08x\n", error);
-
- if ((error & 0xff) == 0x02 /*CHECK_CONDITION */ ) {
- int i;
- u32 len = sizeof(cmd->sense_buffer);
- len = (len > 40) ? 40 : len;
- // Copy over the sense data
- memcpy(cmd->sense_buffer, (void *)&msg->body[3],
- len);
- for (i = 0; i <= len; i++)
- osm_info("%02x\n",
- cmd->sense_buffer[i]);
- if (cmd->sense_buffer[0] == 0x70
- && cmd->sense_buffer[2] == DATA_PROTECT) {
- /* This is to handle an array failed */
- cmd->result = (DID_TIME_OUT << 16);
- printk(KERN_WARNING "%s: SCSI Data "
- "Protect-Device (%d,%d,%d) "
- "hba_status=0x%x, dev_status="
- "0x%x, cmd=0x%x\n", c->name,
- (u32) cmd->device->channel,
- (u32) cmd->device->id,
- (u32) cmd->device->lun,
- (error >> 8) & 0xff,
- error & 0xff, cmd->cmnd[0]);
- } else
- cmd->result = (DID_ERROR << 16);
-
- break;
- }
-
- switch (as) {
- case 0x0E:
- /* SCSI Reset */
- cmd->result = DID_RESET << 16;
- break;
-
- case 0x0F:
- cmd->result = DID_PARITY << 16;
- break;
-
- default:
- cmd->result = DID_ERROR << 16;
- break;
- }
+ return 1;
+};
- break;
- }
+/**
+ * i2o_scsi_notify_device_add - Retrieve notifications of added devices
+ * @i2o_dev: the I2O device which was added
+ *
+ * If a I2O device is added we catch the notification, because I2O classes
+ * other then SCSI peripheral will not be received through
+ * i2o_scsi_probe().
+ */
+static void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev)
+{
+ switch (i2o_dev->lct_data.class_id) {
+ case I2O_CLASS_EXECUTIVE:
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ i2o_scsi_probe(&i2o_dev->device);
+ break;
- cmd->scsi_done(cmd);
- return 1;
+ default:
+ break;
}
+};
- cmd->result = DID_OK << 16 | ds;
-
- dev = &c->pdev->dev;
- if (cmd->use_sg)
- dma_unmap_sg(dev, (struct scatterlist *)cmd->buffer,
- cmd->use_sg, cmd->sc_data_direction);
- else if (cmd->request_bufflen)
- dma_unmap_single(dev, (dma_addr_t) ((long)cmd->SCp.ptr),
- cmd->request_bufflen, cmd->sc_data_direction);
-
- cmd->scsi_done(cmd);
+/**
+ * i2o_scsi_notify_device_remove - Retrieve notifications of removed
+ * devices
+ * @i2o_dev: the I2O device which was removed
+ *
+ * If a I2O device is removed, we catch the notification to remove the
+ * corresponding SCSI device.
+ */
+static void i2o_scsi_notify_device_remove(struct i2o_device *i2o_dev)
+{
+ switch (i2o_dev->lct_data.class_id) {
+ case I2O_CLASS_EXECUTIVE:
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ i2o_scsi_remove(&i2o_dev->device);
+ break;
- return 1;
+ default:
+ break;
+ }
};
/**
.name = OSM_NAME,
.reply = i2o_scsi_reply,
.classes = i2o_scsi_class_id,
+ .notify_device_add = i2o_scsi_notify_device_add,
+ .notify_device_remove = i2o_scsi_notify_device_remove,
.notify_controller_add = i2o_scsi_notify_controller_add,
.notify_controller_remove = i2o_scsi_notify_controller_remove,
.driver = {
*/
/* Attach tags to the devices */
- /*
+ /* FIXME: implement
if(SCpnt->device->tagged_supported) {
if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
scsi_flags |= 0x01000000;
#include <linux/module.h>
#include <linux/i2o.h>
#include <linux/delay.h>
+#include "core.h"
-#define OSM_VERSION "$Rev$"
+#define OSM_NAME "i2o"
+#define OSM_VERSION "1.288"
#define OSM_DESCRIPTION "I2O subsystem"
/* global I2O controller list */
static int i2o_hrt_get(struct i2o_controller *c);
-/* Module internal functions from other sources */
-extern struct i2o_driver i2o_exec_driver;
-extern int i2o_exec_lct_get(struct i2o_controller *);
-extern void i2o_device_remove(struct i2o_device *);
-
-extern int __init i2o_driver_init(void);
-extern void __exit i2o_driver_exit(void);
-extern int __init i2o_exec_init(void);
-extern void __exit i2o_exec_exit(void);
-extern int __init i2o_pci_init(void);
-extern void __exit i2o_pci_exit(void);
-extern int i2o_device_init(void);
-extern void i2o_device_exit(void);
-
/**
* i2o_msg_nop - Returns a message which is not used
* @c: I2O controller from which the message was created
* address from the read port (see the i2o spec). If no message is
* available returns I2O_QUEUE_EMPTY and msg is leaved untouched.
*/
-u32 i2o_msg_get_wait(struct i2o_controller *c, struct i2o_message __iomem **msg,
- int wait)
+u32 i2o_msg_get_wait(struct i2o_controller *c,
+ struct i2o_message __iomem ** msg, int wait)
{
unsigned long timeout = jiffies + wait * HZ;
u32 m;
while ((m = i2o_msg_get(c, msg)) == I2O_QUEUE_EMPTY) {
if (time_after(jiffies, timeout)) {
- pr_debug("%s: Timeout waiting for message frame.\n",
- c->name);
+ osm_debug("%s: Timeout waiting for message frame.\n",
+ c->name);
return I2O_QUEUE_EMPTY;
}
set_current_state(TASK_UNINTERRUPTIBLE);
*/
static int i2o_iop_init_outbound_queue(struct i2o_controller *c)
{
- u8 *status = c->status.virt;
+ volatile u8 *status = c->status.virt;
u32 m;
struct i2o_message __iomem *msg;
ulong timeout;
osm_debug("%s: Initializing Outbound Queue...\n", c->name);
- memset(status, 0, 4);
+ memset(c->status.virt, 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(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(0x0106, &msg->u.s.tcntxt); /* FIXME: why 0x0106, maybe in
- Spec? */
+ writel(0x00000000, &msg->u.s.tcntxt);
writel(PAGE_SIZE, &msg->body[0]);
/* Outbound msg frame size in words and Initcode */
- writel(MSG_FRAME_SIZE << 16 | 0x80, &msg->body[1]);
+ writel(I2O_OUTBOUND_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]);
}
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
-
- rmb();
}
m = c->out_queue.phys;
/* Post frames */
- for (i = 0; i < NMBR_MSG_FRAMES; i++) {
+ for (i = 0; i < I2O_MAX_OUTBOUND_MSG_FRAMES; i++) {
i2o_flush_reply(c, m);
udelay(1); /* Promise */
- m += MSG_FRAME_SIZE * 4;
+ m += I2O_OUTBOUND_MSG_FRAME_SIZE * sizeof(u32);
}
return 0;
*/
static int i2o_iop_reset(struct i2o_controller *c)
{
- u8 *status = c->status.virt;
+ volatile u8 *status = c->status.virt;
struct i2o_message __iomem *msg;
u32 m;
unsigned long timeout;
i2o_status_block *sb = c->status_block.virt;
int rc = 0;
- pr_debug("%s: Resetting controller\n", c->name);
+ osm_debug("%s: Resetting controller\n", c->name);
m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
if (m == I2O_QUEUE_EMPTY)
return -ETIMEDOUT;
- memset(status, 0, 8);
+ memset(c->status_block.virt, 0, 8);
/* Quiesce all IOPs first */
i2o_iop_quiesce_all();
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
-
- rmb();
}
switch (*status) {
{
struct i2o_message __iomem *msg;
u32 m;
- u8 *status_block;
+ volatile u8 *status_block;
unsigned long timeout;
status_block = (u8 *) c->status_block.virt;
- memset(status_block, 0, sizeof(i2o_status_block));
+ memset(c->status_block.virt, 0, sizeof(i2o_status_block));
m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
if (m == I2O_QUEUE_EMPTY)
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
-
- rmb();
}
#ifdef DEBUG
i2o_iop_free(c);
};
+/* I2O controller class */
+static struct class i2o_controller_class = {
+ .name = "i2o_controller",
+};
+
/**
* i2o_iop_alloc - Allocate and initialize a i2o_controller struct
*
sprintf(c->name, "iop%d", c->unit);
device_initialize(&c->device);
+ class_device_initialize(&c->classdev);
+
c->device.release = &i2o_iop_release;
+ c->classdev.class = &i2o_controller_class;
+ c->classdev.dev = &c->device;
+
snprintf(c->device.bus_id, BUS_ID_SIZE, "iop%d", c->unit);
+ snprintf(c->classdev.class_id, BUS_ID_SIZE, "iop%d", c->unit);
#if BITS_PER_LONG == 64
spin_lock_init(&c->context_list_lock);
{
int rc;
- if((rc = device_add(&c->device))) {
- printk(KERN_ERR "%s: could not register controller\n", c->name);
+ if ((rc = device_add(&c->device))) {
+ osm_err("%s: could not add controller\n", c->name);
goto iop_reset;
}
- printk(KERN_INFO "%s: Activating I2O controller...\n", c->name);
- printk(KERN_INFO "%s: This may take a few minutes if there are many "
- "devices\n", c->name);
+ if ((rc = class_device_add(&c->classdev))) {
+ osm_err("%s: could not add controller class\n", c->name);
+ goto device_del;
+ }
+
+ osm_info("%s: Activating I2O controller...\n", c->name);
+ osm_info("%s: This may take a few minutes if there are many devices\n",
+ c->name);
if ((rc = i2o_iop_activate(c))) {
- printk(KERN_ERR "%s: could not activate controller\n",
- c->name);
- goto iop_reset;
+ osm_err("%s: could not activate controller\n", c->name);
+ goto class_del;
}
- pr_debug("%s: building sys table...\n", c->name);
+ osm_debug("%s: building sys table...\n", c->name);
if ((rc = i2o_systab_build()))
- goto iop_reset;
+ goto class_del;
- pr_debug("%s: online controller...\n", c->name);
+ osm_debug("%s: online controller...\n", c->name);
if ((rc = i2o_iop_online(c)))
- goto iop_reset;
+ goto class_del;
- pr_debug("%s: getting LCT...\n", c->name);
+ osm_debug("%s: getting LCT...\n", c->name);
if ((rc = i2o_exec_lct_get(c)))
- goto iop_reset;
+ goto class_del;
list_add(&c->list, &i2o_controllers);
i2o_driver_notify_controller_add_all(c);
- printk(KERN_INFO "%s: Controller added\n", c->name);
+ osm_info("%s: Controller added\n", c->name);
return 0;
-iop_reset:
+ class_del:
+ class_device_del(&c->classdev);
+
+ device_del:
+ device_del(&c->device);
+
+ iop_reset:
i2o_iop_reset(c);
return rc;
if (rc)
goto exit;
- rc = i2o_driver_init();
- if (rc)
+ if ((rc = class_register(&i2o_controller_class))) {
+ osm_err("can't register class i2o_controller\n");
goto device_exit;
+ }
- rc = i2o_exec_init();
- if (rc)
+ if ((rc = i2o_driver_init()))
+ goto class_exit;
+
+ if ((rc = i2o_exec_init()))
goto driver_exit;
- rc = i2o_pci_init();
- if (rc < 0)
+ if ((rc = i2o_pci_init()))
goto exec_exit;
return 0;
driver_exit:
i2o_driver_exit();
+ class_exit:
+ class_unregister(&i2o_controller_class);
+
device_exit:
i2o_device_exit();
i2o_pci_exit();
i2o_exec_exit();
i2o_driver_exit();
+ class_unregister(&i2o_controller_class);
i2o_device_exit();
};
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/i2o.h>
-
-/* Module internal functions from other sources */
-extern struct i2o_controller *i2o_iop_alloc(void);
-extern void i2o_iop_free(struct i2o_controller *);
-
-extern int i2o_iop_add(struct i2o_controller *);
-extern void i2o_iop_remove(struct i2o_controller *);
-
-extern int i2o_driver_dispatch(struct i2o_controller *, u32);
+#include "core.h"
/* PCI device id table for all I2O controllers */
static struct pci_device_id __devinitdata i2o_pci_ids[] = {
struct pci_dev *pdev = c->pdev;
int rc;
- wmb();
writel(0xffffffff, c->irq_mask);
- wmb();
if (pdev->irq) {
rc = request_irq(pdev->irq, i2o_pci_interrupt, SA_SHIRQ,
}
writel(0x00000000, c->irq_mask);
- wmb();
printk(KERN_INFO "%s: Installed at IRQ %d\n", c->name, pdev->irq);
*/
static void i2o_pci_irq_disable(struct i2o_controller *c)
{
- wmb();
writel(0xffffffff, c->irq_mask);
- wmb();
if (c->pdev->irq > 0)
free_irq(c->pdev->irq, c);
if ((rc = i2o_iop_add(c)))
goto uninstall;
+ get_device(&c->device);
+
if (i960)
pci_write_config_word(i960, 0x42, 0x03ff);
- get_device(&c->device);
-
return 0;
uninstall:
{
pci_unregister_driver(&i2o_pci_driver);
};
-
-EXPORT_SYMBOL(i2o_dma_realloc);
MODULE_DEVICE_TABLE(pci, i2o_pci_ids);
#endif /* __KERNEL__ */
-/*
- * Software module types
- */
-#define I2O_SOFTWARE_MODULE_IRTOS 0x11
-#define I2O_SOFTWARE_MODULE_IOP_PRIVATE 0x22
-#define I2O_SOFTWARE_MODULE_IOP_CONFIG 0x23
-
-/*
- * Vendors
- */
-#define I2O_VENDOR_DPT 0x001b
-
/*
* I2O Control IOCTLs and structures
*/
#define ADAPTER_STATE_FAILED 0x10
#define ADAPTER_STATE_FAULTED 0x11
+/*
+ * Software module types
+ */
+#define I2O_SOFTWARE_MODULE_IRTOS 0x11
+#define I2O_SOFTWARE_MODULE_IOP_PRIVATE 0x22
+#define I2O_SOFTWARE_MODULE_IOP_CONFIG 0x23
+
+/*
+ * Vendors
+ */
+#define I2O_VENDOR_DPT 0x001b
/*
* DPT / Adaptec specific values for i2o_sg_io_hdr flags.
};
/*
- * Contains all information which are necessary for DMA operations
+ * Contains DMA mapped address information
*/
struct i2o_dma {
void *virt;
dma_addr_t phys;
- u32 len;
+ size_t len;
+};
+
+/*
+ * Contains IO mapped address information
+ */
+struct i2o_io {
+ void __iomem *virt;
+ unsigned long phys;
+ unsigned long len;
};
/*
struct semaphore lct_lock; /* Lock for LCT updates */
struct i2o_dma status_block; /* IOP status block */
- struct i2o_dma base; /* controller messaging unit */
- struct i2o_dma in_queue; /* inbound message queue Host->IOP */
+ struct i2o_io base; /* controller messaging unit */
+ struct i2o_io in_queue; /* inbound message queue Host->IOP */
struct i2o_dma out_queue; /* outbound message queue IOP->Host */
unsigned int battery:1; /* Has a battery backup */
struct resource mem_resource; /* Mem resource allocated to the IOP */
struct device device;
+ struct class_device classdev; /* I2O controller class */
struct i2o_device *exec; /* Executive */
#if BITS_PER_LONG == 64
spinlock_t context_list_lock; /* lock for context_list */
extern struct list_head i2o_controllers;
/* Message functions */
-static inline u32 i2o_msg_get(struct i2o_controller *, struct i2o_message __iomem **);
-extern u32 i2o_msg_get_wait(struct i2o_controller *, struct i2o_message __iomem **,
- int);
+static inline u32 i2o_msg_get(struct i2o_controller *,
+ struct i2o_message __iomem **);
+extern u32 i2o_msg_get_wait(struct i2o_controller *,
+ struct i2o_message __iomem **, int);
static inline void i2o_msg_post(struct i2o_controller *, u32);
static inline int i2o_msg_post_wait(struct i2o_controller *, u32,
unsigned long);
* available returns I2O_QUEUE_EMPTY and msg is leaved untouched.
*/
static inline u32 i2o_msg_get(struct i2o_controller *c,
- struct i2o_message __iomem **msg)
+ struct i2o_message __iomem ** msg)
{
u32 m = readl(c->in_port);
- if (m != I2O_QUEUE_EMPTY) {
+ if (m != I2O_QUEUE_EMPTY)
*msg = c->in_queue.virt + m;
- rmb();
- }
return m;
};
*/
static inline void i2o_msg_post(struct i2o_controller *c, u32 m)
{
- wmb();
writel(m, c->in_port);
};
* work for sender side messages as they are ioremap objects
* provided by the I2O controller.
*/
-static inline struct i2o_message __iomem *i2o_msg_out_to_virt(struct
- i2o_controller *c,
- u32 m)
+static inline struct i2o_message *i2o_msg_out_to_virt(struct i2o_controller *c,
+ u32 m)
{
- if (unlikely
- (m < c->out_queue.phys
- || m >= c->out_queue.phys + c->out_queue.len))
- return NULL;
+ BUG_ON(m < c->out_queue.phys
+ || m >= c->out_queue.phys + c->out_queue.len);
return c->out_queue.virt + (m - c->out_queue.phys);
};
* work for receive side messages as they are kmalloc objects
* in a different pool.
*/
-static inline struct i2o_message __iomem *i2o_msg_in_to_virt(struct i2o_controller *c,
- u32 m)
+static inline struct i2o_message __iomem *i2o_msg_in_to_virt(struct
+ i2o_controller *c,
+ u32 m)
{
return c->in_queue.virt + m;
};
-/**
- * i2o_dma_alloc - Allocate DMA memory
- * @dev: struct device pointer to the PCI device of the I2O controller
- * @addr: i2o_dma struct which should get the DMA buffer
- * @len: length of the new DMA memory
- * @gfp_mask: GFP mask
- *
- * Allocate a coherent DMA memory and write the pointers into addr.
- *
- * Returns 0 on success or -ENOMEM on failure.
- */
-static inline int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr,
- size_t len, unsigned int gfp_mask)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- int dma_64 = 0;
-
- if ((sizeof(dma_addr_t) > 4) && (pdev->dma_mask == DMA_64BIT_MASK)) {
- dma_64 = 1;
- if(pci_set_dma_mask(pdev, DMA_32BIT_MASK))
- return -ENOMEM;
- }
-
- addr->virt = dma_alloc_coherent(dev, len, &addr->phys, gfp_mask);
-
- if ((sizeof(dma_addr_t) > 4) && dma_64)
- if(pci_set_dma_mask(pdev, DMA_64BIT_MASK))
- printk(KERN_WARNING "i2o: unable to set 64-bit DMA");
-
- if (!addr->virt)
- return -ENOMEM;
-
- memset(addr->virt, 0, len);
- addr->len = len;
-
- return 0;
-};
-
-/**
- * i2o_dma_free - Free DMA memory
- * @dev: struct device pointer to the PCI device of the I2O controller
- * @addr: i2o_dma struct which contains the DMA buffer
- *
- * Free a coherent DMA memory and set virtual address of addr to NULL.
- */
-static inline void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
-{
- if (addr->virt) {
- if (addr->phys)
- dma_free_coherent(dev, addr->len, addr->virt,
- addr->phys);
- else
- kfree(addr->virt);
- addr->virt = NULL;
- }
-};
-
/*
* Endian handling wrapped into the macro - keeps the core code
* cleaner.
#define ELEVEN_WORD_MSG_SIZE 0x000B0000
#define I2O_MESSAGE_SIZE(x) ((x)<<16)
-/* Special TID Assignments */
-
+/* special TID assignments */
#define ADAPTER_TID 0
#define HOST_TID 1
-#define MSG_FRAME_SIZE 128 /* i2o_scsi assumes >= 32 */
-#define SG_TABLESIZE 30
-#define NMBR_MSG_FRAMES 128
-
-#define MSG_POOL_SIZE (MSG_FRAME_SIZE*NMBR_MSG_FRAMES*sizeof(u32))
+/* outbound queue defines */
+#define I2O_MAX_OUTBOUND_MSG_FRAMES 128
+#define I2O_OUTBOUND_MSG_FRAME_SIZE 128 /* in 32-bit words */
#define I2O_POST_WAIT_OK 0
#define I2O_POST_WAIT_TIMEOUT -ETIMEDOUT