📄 i2o_core.c
字号:
if (iop != c) i2o_enable_controller(iop); return ret;}/** * i2o_reset_controller - reset an IOP * @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_reset_controller(struct i2o_controller *c){ struct i2o_controller *iop; u32 m; u8 *status; u32 *msg; long time; /* Quiesce all IOPs first */ for (iop = i2o_controller_chain; iop; iop = iop->next) { if(iop->type != I2O_TYPE_PCI || !iop->bus.pci.dpt) i2o_quiesce_controller(iop); } m=i2o_wait_message(c, "AdapterReset"); if(m==0xFFFFFFFF) return -ETIMEDOUT; msg=(u32 *)(c->mem_offset+m); status=(void *)kmalloc(4, GFP_KERNEL); if(status==NULL) { printk(KERN_ERR "IOP reset failed - no free memory.\n"); return -ENOMEM; } memset(status, 0, 4); msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID; msg[2]=core_context; msg[3]=0; msg[4]=0; msg[5]=0; msg[6]=virt_to_bus(status); msg[7]=0; /* 64bit host FIXME */ i2o_post_message(c,m); /* Wait for a reply */ time=jiffies; while(*status==0) { if((jiffies-time)>=20*HZ) { printk(KERN_ERR "IOP reset timeout.\n"); // Better to leak this for safety: kfree(status); return -ETIMEDOUT; } schedule(); barrier(); } 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. */ dprintk(KERN_INFO "%s: Reset in progress, waiting for reboot...\n", c->name); time = jiffies; m = I2O_POST_READ32(c); while(m == 0XFFFFFFFF) { if((jiffies-time) >= 30*HZ) { printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n", c->name); return -ETIMEDOUT; } schedule(); barrier(); m = I2O_POST_READ32(c); } i2o_flush_reply(c,m); } /* If IopReset was rejected or didn't perform reset, try IopClear */ i2o_status_get(c); if (status[0] == I2O_CMD_REJECTED || c->status_block->iop_state != ADAPTER_STATE_RESET) { printk(KERN_WARNING "%s: Reset rejected, trying to clear\n",c->name); i2o_clear_controller(c); } else dprintk(KERN_INFO "%s: Reset completed.\n", c->name); /* Enable other IOPs */ for (iop = i2o_controller_chain; iop; iop = iop->next) if (iop != c) i2o_enable_controller(iop); kfree(status); return 0;}/** * i2o_status_get - get the status block for the IOP * @c: controller * * Issue a status query on the controller. This updates the * attached status_block. If the controller fails to reply or an * error occurs then a negative errno code is returned. On success * zero is returned and the status_blok is updated. */ int i2o_status_get(struct i2o_controller *c){ long time; u32 m; u32 *msg; u8 *status_block; if (c->status_block == NULL) { c->status_block = (i2o_status_block *) kmalloc(sizeof(i2o_status_block),GFP_KERNEL); if (c->status_block == NULL) { printk(KERN_CRIT "%s: Get Status Block failed; Out of memory.\n", c->name); return -ENOMEM; } } status_block = (u8*)c->status_block; memset(c->status_block,0,sizeof(i2o_status_block)); m=i2o_wait_message(c, "StatusGet"); if(m==0xFFFFFFFF) return -ETIMEDOUT; msg=(u32 *)(c->mem_offset+m); msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID; msg[2]=core_context; msg[3]=0; msg[4]=0; msg[5]=0; msg[6]=virt_to_bus(c->status_block); msg[7]=0; /* 64bit host FIXME */ msg[8]=sizeof(i2o_status_block); /* always 88 bytes */ i2o_post_message(c,m); /* Wait for a reply */ time=jiffies; while(status_block[87]!=0xFF) { if((jiffies-time)>=5*HZ) { printk(KERN_ERR "%s: Get status timeout.\n",c->name); return -ETIMEDOUT; } schedule(); barrier(); }#ifdef DRIVERDEBUG printk(KERN_INFO "%s: State = ", c->name); switch (c->status_block->iop_state) { case 0x01: printk("INIT\n"); break; case 0x02: printk("RESET\n"); break; case 0x04: printk("HOLD\n"); break; case 0x05: printk("READY\n"); break; case 0x08: printk("OPERATIONAL\n"); break; case 0x10: printk("FAILED\n"); break; case 0x11: printk("FAULTED\n"); break; default: printk("%x (unknown !!)\n",c->status_block->iop_state);} #endif return 0;}/* * Get the Hardware Resource Table for the device. * The HRT contains information about possible hidden devices * but is mostly useless to us */int i2o_hrt_get(struct i2o_controller *c){ u32 msg[6]; int ret, size = sizeof(i2o_hrt); /* First read just the header to figure out the real size */ do { if (c->hrt == NULL) { c->hrt=kmalloc(size, GFP_KERNEL); if (c->hrt == NULL) { printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", c->name); return -ENOMEM; } } msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; msg[3]= 0; msg[4]= (0xD0000000 | size); /* Simple transaction */ msg[5]= virt_to_bus(c->hrt); /* Dump it here */ ret = i2o_post_wait_mem(c, msg, sizeof(msg), 20, c->hrt, NULL); if(ret == -ETIMEDOUT) { /* The HRT block we used is in limbo somewhere. When the iop wakes up we will recover it */ c->hrt = NULL; return ret; } if(ret<0) { printk(KERN_ERR "%s: Unable to get HRT (status=%#x)\n", c->name, -ret); return ret; } if (c->hrt->num_entries * c->hrt->entry_len << 2 > size) { size = c->hrt->num_entries * c->hrt->entry_len << 2; kfree(c->hrt); c->hrt = NULL; } } while (c->hrt == NULL); i2o_parse_hrt(c); // just for debugging return 0;}/* * Send the I2O System Table to the specified IOP * * The system table contains information about all the IOPs in the * system. It is build and then sent to each IOP so that IOPs can * establish connections between each other. * */static int i2o_systab_send(struct i2o_controller *iop){ u32 msg[12]; int ret; u32 *privbuf = kmalloc(16, GFP_KERNEL); if(privbuf == NULL) return -ENOMEM; if(iop->type == I2O_TYPE_PCI) { struct resource *root; if(iop->status_block->current_mem_size < iop->status_block->desired_mem_size) { struct resource *res = &iop->mem_resource; res->name = iop->pdev->bus->name; res->flags = IORESOURCE_MEM; res->start = 0; res->end = 0; printk("%s: requires private memory resources.\n", iop->name); root = pci_find_parent_resource(iop->pdev, res); if(root==NULL) printk("Can't find parent resource!\n"); if(root && allocate_resource(root, res, iop->status_block->desired_mem_size, iop->status_block->desired_mem_size, iop->status_block->desired_mem_size, 1<<20, /* Unspecified, so use 1Mb and play safe */ NULL, NULL)>=0) { iop->mem_alloc = 1; iop->status_block->current_mem_size = 1 + res->end - res->start; iop->status_block->current_mem_base = res->start; printk(KERN_INFO "%s: allocated %ld bytes of PCI memory at 0x%08lX.\n", iop->name, 1+res->end-res->start, res->start); } } if(iop->status_block->current_io_size < iop->status_block->desired_io_size) { struct resource *res = &iop->io_resource; res->name = iop->pdev->bus->name; res->flags = IORESOURCE_IO; res->start = 0; res->end = 0; printk("%s: requires private memory resources.\n", iop->name); root = pci_find_parent_resource(iop->pdev, res); if(root==NULL) printk("Can't find parent resource!\n"); if(root && allocate_resource(root, res, iop->status_block->desired_io_size, iop->status_block->desired_io_size, iop->status_block->desired_io_size, 1<<20, /* Unspecified, so use 1Mb and play safe */ NULL, NULL)>=0) { iop->io_alloc = 1; iop->status_block->current_io_size = 1 + res->end - res->start; iop->status_block->current_mem_base = res->start; printk(KERN_INFO "%s: allocated %ld bytes of PCI I/O at 0x%08lX.\n", iop->name, 1+res->end-res->start, res->start); } } } else { privbuf[0] = iop->status_block->current_mem_base; privbuf[1] = iop->status_block->current_mem_size; privbuf[2] = iop->status_block->current_io_base; privbuf[3] = iop->status_block->current_io_size; } msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6; msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; msg[3] = 0; msg[4] = (0<<16) | ((iop->unit+2) ); /* Host 0 IOP ID (unit + 2) */ msg[5] = 0; /* Segment 0 */ /* * Provide three SGL-elements: * System table (SysTab), Private memory space declaration and * Private i/o space declaration * * FIXME: provide these for controllers needing them */ msg[6] = 0x54000000 | sys_tbl_len; msg[7] = virt_to_bus(sys_tbl); msg[8] = 0x54000000 | 8; msg[9] = virt_to_bus(privbuf); msg[10] = 0xD4000000 | 8; msg[11] = virt_to_bus(privbuf+2); ret=i2o_post_wait_mem(iop, msg, sizeof(msg), 120, privbuf, NULL); if(ret==-ETIMEDOUT) { printk(KERN_ERR "%s: SysTab setup timed out.\n", iop->name); } else if(ret<0) { printk(KERN_ERR "%s: Unable to set SysTab (status=%#x).\n", iop->name, -ret); kfree(privbuf); } else { dprintk(KERN_INFO "%s: SysTab set.\n", iop->name); kfree(privbuf); } i2o_status_get(iop); // Entered READY state return ret; }/* * Initialize I2O subsystem. */static void __init i2o_sys_init(void){ struct i2o_controller *iop, *niop = NULL; printk(KERN_INFO "Activating I2O controllers...\n"); printk(KERN_INFO "This may take a few minutes if there are many devices\n"); /* In INIT state, Activate IOPs */ for (iop = i2o_controller_chain; iop; iop = niop) { dprintk(KERN_INFO "Calling i2o_activate_controller for %s...\n", iop->name); niop = iop->next; if (i2o_activate_controller(iop) < 0) i2o_delete_controller(iop); } /* Active IOPs in HOLD state */rebuild_sys_tab: if (i2o_controller_chain == NULL) return; /* * If build_sys_table fails, we kill everything and bail * as we can't init the IOPs w/o a system table */ dprintk(KERN_INFO "i2o_core: Calling i2o_build_sys_table...\n"); if (i2o_build_sys_table() < 0) { i2o_sys_shutdown(); return; } /* If IOP don't get online, we need to rebuild the System table */ for (iop = i2o_controller_chain; iop; iop = niop) { niop = iop->next; dprintk(KERN_INFO "Calling i2o_online_controller for %s...\n", iop->name); if (i2o_online_controller(iop) < 0) { i2o_delete_controller(iop); goto rebuild_sys_tab; } } /* Active IOPs now in OPERATIONAL state */ /* * Register for status updates from all IOPs */ for(iop = i2o_controller_chain; iop; iop=iop->next) { /* Create a kernel thread to deal with dynamic LCT updates */ iop->lct_pid = kernel_thread(i2o_dyn_lct, iop, CLONE_SIGHAND); /* Update change ind on DLCT */ iop->dlct->change_ind = iop->lct->change_ind; /* Start dynamic LCT updates */ i2o_lct_notify(iop); /* Register for all events from IRTOS */ i2o_event_register(iop, core_context, 0, 0, 0xFFFFFFFF); }}/** * i2o_sys_shutdown - shutdown I2O system * * Bring down each i2o controller and then return. Each controller * is taken through an orderly shutdown */ static void i2o_sys_shutdown(void){ struct i2o_controller *iop, *niop; /* Delete all IOPs from the controller chain */ /* that will reset all IOPs too */ for (iop = i2o_controller_chain; iop; iop = niop) { niop = iop->next; i2o_delete_controller(iop); }}/** * i2o_activate_controller - bring controller up to HOLD * @iop: controller * * This function brings an I2O controller into HOLD state. The adapter * is reset if neccessary and then the queues and resource table * are read. -1 is returned on a failure, 0 on success. * */ int i2o_activate_controller(struct i2o_controller *iop){ /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */ /* In READY state, Get status */ if (i2o_status_get(iop) < 0) { printk(KERN_INFO "Unable to obtain status of %s, " "attempting a reset.\n", iop->name); if (i2o_reset_controller(iop) < 0) return -1; } if(iop->status_block->iop_state == ADAPTER_STATE_FAULTED) { printk(KERN_CRIT "%s: hardware fault\n", iop->name); return -1; } if (iop->status_block->i2o_version > I2OVER15) { printk(KERN_ERR "%s: Not running vrs. 1.5. of the I2O Specification.\n", iop->name); return -1; } if (iop->status_block->iop_state == ADAPTER_STATE_READY || iop->status_block->iop_state == ADAPTER_STATE_OPERATIONAL || iop->status_block->iop_state == ADAPTER_STATE_HOLD || iop->status_block->iop_state == ADAPTER_STATE_FAILED) { dprintk(KERN_INFO "%s: Already running, trying to reset...\n", iop->name); if (i2o_reset_controller(iop) < 0) return -1; } if (i2o_init_outbound_q(iop) < 0) return -1; if (i2o_post_outbound_messages(iop)) return -1; /* In HOLD state */ if (i2o_hrt_get(iop) < 0) return -1; return 0;}/** * i2o_init_outbound_queue - setup the outbound queue * @c: controller *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -