[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>
This commit is contained in:
Markus Lidel
2005-06-23 22:02:16 -07:00
committed by Linus Torvalds
vanhempi f88e119c4b
commit f10378fff6
15 muutettua tiedostoa jossa 1473 lisäystä ja 559 poistoa

Näytä tiedosto

@@ -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,20 +604,27 @@ 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;
/* verify if controller is in state RESET */
i2o_status_get(c);
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;
}
/* from here all quiesce commands are safe */
c->no_quiesce = 0;
/* If IopReset was rejected or didn't perform reset, try IopClear */
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);
exit:
/* Enable all IOPs */
i2o_iop_enable_all();
@@ -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);