iop.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,259 行 · 第 1/3 页

C
1,259
字号
	u32 m;	int rc;	m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);	if (m == I2O_QUEUE_EMPTY)		return -ETIMEDOUT;	/* Quiesce all IOPs first */	i2o_iop_quiesce_all();	writel(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);	writel(I2O_CMD_ADAPTER_CLEAR << 24 | HOST_TID << 12 | ADAPTER_TID,	       &msg->u.head[1]);	if ((rc = i2o_msg_post_wait(c, m, 30)))		printk(KERN_INFO "%s: Unable to clear (status=%#x).\n",		       c->name, -rc);	else		pr_debug("%s: Cleared.\n", c->name);	/* Enable all IOPs */	i2o_iop_enable_all();	i2o_status_get(c);	return rc;}/** *	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){	u8 *status = c->status.virt;	struct i2o_message *msg;	u32 m;	unsigned long timeout;	i2o_status_block *sb = c->status_block.virt;	int rc = 0;	pr_debug("Resetting controller\n");	m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);	if (m == I2O_QUEUE_EMPTY)		return -ETIMEDOUT;	memset(status, 0, 4);	/* 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_ptr_low((void *)c->status.phys), &msg->body[2]);	writel(i2o_ptr_high((void *)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 "IOP reset timeout.\n");			rc = -ETIMEDOUT;			goto exit;		}		set_current_state(TASK_UNINTERRUPTIBLE);		schedule_timeout(1);		rmb();	}	if (*status == 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.		 */		pr_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)) {				printk(KERN_ERR "IOP reset timeout.\n");				rc = -ETIMEDOUT;				goto exit;			}			set_current_state(TASK_UNINTERRUPTIBLE);			schedule_timeout(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;	/* 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();	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. */int i2o_iop_init_outbound_queue(struct i2o_controller *c){	u8 *status = c->status.virt;	u32 m;	struct i2o_message *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 | 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]);	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);		m += MSG_FRAME_SIZE * 4;	}	return 0;}/** *	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;	/* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */	/* In READY state, Get status */	rc = i2o_status_get(c);	if (rc) {		printk(KERN_INFO "Unable to obtain status of %s, "		       "attempting a reset.\n", c->name);		if (i2o_iop_reset(c))			return rc;	}	if (sb->i2o_version > I2OVER15) {		printk(KERN_ERR "%s: Not running vrs. 1.5. of the I2O "		       "Specification.\n", c->name);		return -ENODEV;	}	switch (sb->iop_state) {	case ADAPTER_STATE_FAULTED:		printk(KERN_CRIT "%s: hardware fault\n", c->name);		return -ENODEV;	case ADAPTER_STATE_READY:	case ADAPTER_STATE_OPERATIONAL:	case ADAPTER_STATE_HOLD:	case ADAPTER_STATE_FAILED:		pr_debug("already running, trying to reset...\n");		if (i2o_iop_reset(c))			return -ENODEV;	}	rc = i2o_iop_init_outbound_queue(c);	if (rc)		return rc;	/* In HOLD state */	rc = i2o_hrt_get(c);	if (rc)		return rc;	return 0;};/** *	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 *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;		printk("%s: requires private memory resources.\n", c->name);		root = pci_find_parent_resource(c->pdev, res);		if (root == NULL)			printk("Can't find parent resource!\n");		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;			printk(KERN_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;		printk("%s: requires private memory resources.\n", c->name);		root = pci_find_parent_resource(c->pdev, res);		if (root == NULL)			printk("Can't find parent resource!\n");		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;			printk(KERN_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.phys, &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)		printk(KERN_ERR "%s: Unable to set SysTab (status=%#x).\n",		       c->name, -rc);	else		pr_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 */	pr_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;	pr_debug("Deleting controller %s\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);	/* Ask the IOP to switch to RESET state */	i2o_iop_reset(c);}/** *	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){

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?