📄 iop.c
字号:
i2o_iop_enable_all(); 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){ volatile 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(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 | 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]); /* Outbound msg frame size in words and Initcode */ 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]); 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; } schedule_timeout_uninterruptible(1); } m = c->out_queue.phys; /* Post frames */ for (i = 0; i < I2O_MAX_OUTBOUND_MSG_FRAMES; i++) { i2o_flush_reply(c, m); udelay(1); /* Promise */ m += I2O_OUTBOUND_MSG_FRAME_SIZE * sizeof(u32); } return 0;}/** * i2o_iop_reset - reset an I2O controller * @c: controller to reset * * Reset the IOP into INIT state and wait until IOP gets into RESET state. * Terminate all external operations, clear IOP's inbound and outbound * queues, terminate all DDMs, and reload the IOP's operating environment * and all local DDMs. The IOP rebuilds its LCT. */static int i2o_iop_reset(struct i2o_controller *c){ 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; 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(c->status_block.virt, 0, 8); /* Quiesce all IOPs first */ i2o_iop_quiesce_all(); writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]); writel(I2O_CMD_ADAPTER_RESET << 24 | HOST_TID << 12 | ADAPTER_TID, &msg->u.head[1]); writel(i2o_exec_driver.context, &msg->u.s.icntxt); writel(0, &msg->u.s.tcntxt); //FIXME: use reasonable transaction context writel(0, &msg->body[0]); writel(0, &msg->body[1]); 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)) break; schedule_timeout_uninterruptible(1); } 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. */ osm_debug("%s: Reset in progress, waiting for reboot...\n", c->name); m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_RESET); while (m == I2O_QUEUE_EMPTY) { if (time_after(jiffies, timeout)) { osm_err("%s: IOP reset timeout.\n", c->name); rc = -ETIMEDOUT; goto exit; } schedule_timeout_uninterruptible(1); 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; } exit: /* Enable all IOPs */ i2o_iop_enable_all(); return rc;};/** * i2o_iop_activate - Bring controller up to HOLD * @c: controller * * This function brings an I2O controller into HOLD state. The adapter * is reset if necessary and then the queues and resource table are read. * * Returns 0 on success or negative error code on failure. */static int i2o_iop_activate(struct i2o_controller *c){ i2o_status_block *sb = c->status_block.virt; int rc; int state; /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */ /* In READY state, Get status */ rc = i2o_status_get(c); if (rc) { osm_info("%s: Unable to obtain status, attempting a reset.\n", c->name); rc = i2o_iop_reset(c); if (rc) return rc; } if (sb->i2o_version > I2OVER15) { osm_err("%s: Not running version 1.5 of the I2O Specification." "\n", c->name); return -ENODEV; } switch (sb->iop_state) { case ADAPTER_STATE_FAULTED: osm_err("%s: hardware fault\n", c->name); return -EFAULT; case ADAPTER_STATE_READY: case ADAPTER_STATE_OPERATIONAL: case ADAPTER_STATE_HOLD: case ADAPTER_STATE_FAILED: osm_debug("%s: already running, trying to reset...\n", c->name); 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 adapter was not in RESET state clear now */ if (state != ADAPTER_STATE_RESET) i2o_iop_clear(c); i2o_status_get(c); if (sb->iop_state != ADAPTER_STATE_HOLD) { osm_err("%s: failed to bring IOP into HOLD state\n", c->name); return -EIO; } return i2o_hrt_get(c);};/** * i2o_iop_systab_set - Set the I2O System Table of the specified IOP * @c: I2O controller to which the system table should be send * * Before the systab could be set i2o_systab_build() must be called. * * Returns 0 on success or negative error code on failure. */static int i2o_iop_systab_set(struct i2o_controller *c){ struct i2o_message __iomem *msg; u32 m; i2o_status_block *sb = c->status_block.virt; struct device *dev = &c->pdev->dev; struct resource *root; int rc; if (sb->current_mem_size < sb->desired_mem_size) { struct resource *res = &c->mem_resource; res->name = c->pdev->bus->name; res->flags = IORESOURCE_MEM; res->start = 0; res->end = 0; osm_info("%s: requires private memory resources.\n", c->name); root = pci_find_parent_resource(c->pdev, res); if (root == NULL) osm_warn("%s: Can't find parent resource!\n", c->name); if (root && allocate_resource(root, res, sb->desired_mem_size, sb->desired_mem_size, sb->desired_mem_size, 1 << 20, /* Unspecified, so use 1Mb and play safe */ NULL, NULL) >= 0) { c->mem_alloc = 1; sb->current_mem_size = 1 + res->end - res->start; sb->current_mem_base = res->start; osm_info("%s: allocated %ld bytes of PCI memory at " "0x%08lX.\n", c->name, 1 + res->end - res->start, res->start); } } if (sb->current_io_size < sb->desired_io_size) { struct resource *res = &c->io_resource; res->name = c->pdev->bus->name; res->flags = IORESOURCE_IO; res->start = 0; res->end = 0; osm_info("%s: requires private memory resources.\n", c->name); root = pci_find_parent_resource(c->pdev, res); if (root == NULL) osm_warn("%s: Can't find parent resource!\n", c->name); if (root && allocate_resource(root, res, sb->desired_io_size, sb->desired_io_size, sb->desired_io_size, 1 << 20, /* Unspecified, so use 1Mb and play safe */ NULL, NULL) >= 0) { c->io_alloc = 1; sb->current_io_size = 1 + res->end - res->start; sb->current_mem_base = res->start; osm_info("%s: allocated %ld bytes of PCI I/O at 0x%08lX" ".\n", c->name, 1 + res->end - res->start, res->start); } } m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); if (m == I2O_QUEUE_EMPTY) return -ETIMEDOUT; i2o_systab.phys = dma_map_single(dev, i2o_systab.virt, i2o_systab.len, PCI_DMA_TODEVICE); if (!i2o_systab.phys) { i2o_msg_nop(c, m); return -ENOMEM; } writel(I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6, &msg->u.head[0]); writel(I2O_CMD_SYS_TAB_SET << 24 | HOST_TID << 12 | ADAPTER_TID, &msg->u.head[1]); /* * Provide three SGL-elements: * System table (SysTab), Private memory space declaration and * Private i/o space declaration * * FIXME: is this still true? * Nasty one here. We can't use dma_alloc_coherent to send the * same table to everyone. We have to go remap it for them all */ writel(c->unit + 2, &msg->body[0]); writel(0, &msg->body[1]); writel(0x54000000 | i2o_systab.len, &msg->body[2]); writel(i2o_systab.phys, &msg->body[3]); writel(0x54000000 | sb->current_mem_size, &msg->body[4]); writel(sb->current_mem_base, &msg->body[5]); writel(0xd4000000 | sb->current_io_size, &msg->body[6]); writel(sb->current_io_base, &msg->body[6]); rc = i2o_msg_post_wait(c, m, 120); dma_unmap_single(dev, i2o_systab.phys, i2o_systab.len, PCI_DMA_TODEVICE); if (rc < 0) osm_err("%s: Unable to set SysTab (status=%#x).\n", c->name, -rc); else osm_debug("%s: SysTab set.\n", c->name); i2o_status_get(c); // Entered READY state return rc;}/** * i2o_iop_online - Bring a controller online into OPERATIONAL state. * @c: I2O controller * * Send the system table and enable the I2O controller. * * Returns 0 on success or negativer error code on failure. */static int i2o_iop_online(struct i2o_controller *c){ int rc; rc = i2o_iop_systab_set(c); if (rc) return rc; /* In READY state */ osm_debug("%s: Attempting to enable...\n", c->name); rc = i2o_iop_enable(c); if (rc) return rc; return 0;};/** * i2o_iop_remove - Remove the I2O controller from the I2O core * @c: I2O controller * * Remove the I2O controller from the I2O core. If devices are attached to * the controller remove these also and finally reset the controller. */void i2o_iop_remove(struct i2o_controller *c){ struct i2o_device *dev, *tmp; osm_debug("%s: deleting controller\n", c->name); i2o_driver_notify_controller_remove_all(c); list_del(&c->list); list_for_each_entry_safe(dev, tmp, &c->devices, list) i2o_device_remove(dev); class_device_unregister(c->classdev); device_del(&c->device); /* Ask the IOP to switch to RESET state */ i2o_iop_reset(c); put_device(&c->device);}/** * i2o_systab_build - Build system table * * The system table contains information about all the IOPs in the system * (duh) and is used by the Executives on the IOPs to establish peer2peer * connections. We're not supporting peer2peer at the moment, but this * will be needed down the road for things like lan2lan forwarding. * * Returns 0 on success or negative error code on failure. */static int i2o_systab_build(void){ struct i2o_controller *c, *tmp; int num_controllers = 0; u32 change_ind = 0; int count = 0; struct i2o_sys_tbl *systab = i2o_systab.virt; list_for_each_entry_safe(c, tmp, &i2o_controllers, list) num_controllers++; if (systab) { change_ind = systab->change_ind; kfree(i2o_systab.virt); } /* Header + IOPs */ i2o_systab.len = sizeof(struct i2o_sys_tbl) + num_controllers * sizeof(struct i2o_sys_tbl_entry); systab = i2o_systab.virt = kmalloc(i2o_systab.len, GFP_KERNEL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -