📄 i2o_core.c
字号:
/* * Clear event registration as this can cause weird behavior */ if(c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL) i2o_event_register(c, core_context, 0, 0, 0); down(&i2o_configuration_lock); if((users=atomic_read(&c->users))) { dprintk(KERN_INFO "I2O: %d users for controller %s\n", users, c->name); up(&i2o_configuration_lock); return -EBUSY; } while(c->devices) { if(__i2o_delete_device(c->devices)<0) { /* Shouldnt happen */ c->bus_disable(c); up(&i2o_configuration_lock); return -EBUSY; } } /* * If this is shutdown time, the thread's already been killed */ if(c->lct_running) { stat = kill_proc(c->lct_pid, SIGTERM, 1); if(!stat) { int count = 10 * 100; while(c->lct_running && --count) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); } if(!count) printk(KERN_ERR "%s: LCT thread still running!\n", c->name); } } p=&i2o_controller_chain; while(*p) { if(*p==c) { /* Ask the IOP to switch to RESET state */ i2o_reset_controller(c); /* Release IRQ */ c->destructor(c); *p=c->next; up(&i2o_configuration_lock); if(c->page_frame) { pci_unmap_single(c->pdev, c->page_frame_map, MSG_POOL_SIZE, PCI_DMA_FROMDEVICE); kfree(c->page_frame); } if(c->hrt) kfree(c->hrt); if(c->lct) kfree(c->lct); if(c->status_block) kfree(c->status_block); if(c->dlct) kfree(c->dlct); i2o_controllers[c->unit]=NULL; memcpy(name, c->name, strlen(c->name)+1); kfree(c); dprintk(KERN_INFO "%s: Deleted from controller chain.\n", name); i2o_num_controllers--; return 0; } p=&((*p)->next); } up(&i2o_configuration_lock); printk(KERN_ERR "i2o_delete_controller: bad pointer!\n"); return -ENOENT;}/** * i2o_unlock_controller - unlock a controller * @c: controller to unlock * * Take a lock on an i2o controller. This prevents it being deleted. * i2o controllers are not refcounted so a deletion of an in use device * will fail, not take affect on the last dereference. */ void i2o_unlock_controller(struct i2o_controller *c){ atomic_dec(&c->users);}/** * i2o_find_controller - return a locked controller * @n: controller number * * Returns a pointer to the controller object. The controller is locked * on return. NULL is returned if the controller is not found. */ struct i2o_controller *i2o_find_controller(int n){ struct i2o_controller *c; if(n<0 || n>=MAX_I2O_CONTROLLERS) return NULL; down(&i2o_configuration_lock); c=i2o_controllers[n]; if(c!=NULL) atomic_inc(&c->users); up(&i2o_configuration_lock); return c;}/** * i2o_issue_claim - claim or release a device * @cmd: command * @c: controller to claim for * @tid: i2o task id * @type: type of claim * * Issue I2O UTIL_CLAIM and UTIL_RELEASE messages. The message to be sent * is set by cmd. The tid is the task id of the object to claim and the * type is the claim type (see the i2o standard) * * Zero is returned on success. */ static int i2o_issue_claim(u32 cmd, struct i2o_controller *c, int tid, u32 type){ u32 msg[5]; msg[0] = FIVE_WORD_MSG_SIZE | SGL_OFFSET_0; msg[1] = cmd << 24 | HOST_TID<<12 | tid; msg[3] = 0; msg[4] = type; return i2o_post_wait(c, msg, sizeof(msg), 60);}/* * i2o_claim_device - claim a device for use by an OSM * @d: device to claim * @h: handler for this device * * Do the leg work to assign a device to a given OSM on Linux. The * kernel updates the internal handler data for the device and then * performs an I2O claim for the device, attempting to claim the * device as primary. If the attempt fails a negative errno code * is returned. On success zero is returned. */ int i2o_claim_device(struct i2o_device *d, struct i2o_handler *h){ down(&i2o_configuration_lock); if (d->owner) { printk(KERN_INFO "Device claim called, but dev already owned by %s!", h->name); up(&i2o_configuration_lock); return -EBUSY; } d->owner=h; if(i2o_issue_claim(I2O_CMD_UTIL_CLAIM ,d->controller,d->lct_data.tid, I2O_CLAIM_PRIMARY)) { d->owner = NULL; return -EBUSY; } up(&i2o_configuration_lock); return 0;}/** * i2o_release_device - release a device that the OSM is using * @d: device to claim * @h: handler for this device * * Drop a claim by an OSM on a given I2O device. The handler is cleared * and 0 is returned on success. * * AC - some devices seem to want to refuse an unclaim until they have * finished internal processing. It makes sense since you don't want a * new device to go reconfiguring the entire system until you are done. * Thus we are prepared to wait briefly. */int i2o_release_device(struct i2o_device *d, struct i2o_handler *h){ int err = 0; int tries; down(&i2o_configuration_lock); if (d->owner != h) { printk(KERN_INFO "Claim release called, but not owned by %s!\n", h->name); up(&i2o_configuration_lock); return -ENOENT; } for(tries=0;tries<10;tries++) { d->owner = NULL; /* * If the controller takes a nonblocking approach to * releases we have to sleep/poll for a few times. */ if((err=i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, I2O_CLAIM_PRIMARY)) ) { err = -ENXIO; current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(HZ); } else { err=0; break; } } up(&i2o_configuration_lock); return err;}/** * i2o_device_notify_on - Enable deletion notifiers * @d: device for notification * @h: handler to install * * Called by OSMs to let the core know that they want to be * notified if the given device is deleted from the system. */int i2o_device_notify_on(struct i2o_device *d, struct i2o_handler *h){ int i; if(d->num_managers == I2O_MAX_MANAGERS) return -ENOSPC; for(i = 0; i < I2O_MAX_MANAGERS; i++) { if(!d->managers[i]) { d->managers[i] = h; break; } } d->num_managers++; return 0;}/** * i2o_device_notify_off - Remove deletion notifiers * @d: device for notification * @h: handler to remove * * Called by OSMs to let the core know that they no longer * are interested in the fate of the given device. */int i2o_device_notify_off(struct i2o_device *d, struct i2o_handler *h){ int i; for(i=0; i < I2O_MAX_MANAGERS; i++) { if(d->managers[i] == h) { d->managers[i] = NULL; d->num_managers--; return 0; } } return -ENOENT;}/** * i2o_event_register - register interest in an event * @c: Controller to register interest with * @tid: I2O task id * @init_context: initiator context to use with this notifier * @tr_context: transaction context to use with this notifier * @evt_mask: mask of events * * Create and posts an event registration message to the task. No reply * is waited for, or expected. Errors in posting will be reported. */ int i2o_event_register(struct i2o_controller *c, u32 tid, u32 init_context, u32 tr_context, u32 evt_mask){ u32 msg[5]; // Not performance critical, so we just // i2o_post_this it instead of building it // in IOP memory msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1] = I2O_CMD_UTIL_EVT_REGISTER<<24 | HOST_TID<<12 | tid; msg[2] = init_context; msg[3] = tr_context; msg[4] = evt_mask; return i2o_post_this(c, msg, sizeof(msg));}/* * i2o_event_ack - acknowledge an event * @c: controller * @msg: pointer to the UTIL_EVENT_REGISTER reply we received * * We just take a pointer to the original UTIL_EVENT_REGISTER reply * message and change the function code since that's what spec * describes an EventAck message looking like. */ int i2o_event_ack(struct i2o_controller *c, u32 *msg){ struct i2o_message *m = (struct i2o_message *)msg; m->function = I2O_CMD_UTIL_EVT_ACK; return i2o_post_wait(c, msg, m->size * 4, 2);}/* * Core event handler. Runs as a separate thread and is woken * up whenever there is an Executive class event. */static int i2o_core_evt(void *reply_data){ struct reply_info *reply = (struct reply_info *) reply_data; u32 *msg = reply->msg; struct i2o_controller *c = NULL; unsigned long flags; lock_kernel(); daemonize(); unlock_kernel(); strcpy(current->comm, "i2oevtd"); evt_running = 1; while(1) { if(down_interruptible(&evt_sem)) { dprintk(KERN_INFO "I2O event thread dead\n"); printk("exiting..."); evt_running = 0; complete_and_exit(&evt_dead, 0); } /* * Copy the data out of the queue so that we don't have to lock * around the whole function and just around the qlen update */ spin_lock_irqsave(&i2o_evt_lock, flags); memcpy(reply, &events[evt_out], sizeof(struct reply_info)); MODINC(evt_out, I2O_EVT_Q_LEN); evt_q_len--; spin_unlock_irqrestore(&i2o_evt_lock, flags); c = reply->iop; dprintk(KERN_INFO "I2O IRTOS EVENT: iop%d, event %#10x\n", c->unit, msg[4]); /* * We do not attempt to delete/quiesce/etc. the controller if * some sort of error indidication occurs. We may want to do * so in the future, but for now we just let the user deal with * it. One reason for this is that what to do with an error * or when to send what 鎟ror is not really agreed on, so * we get errors that may not be fatal but just look like they * are...so let the user deal with it. */ switch(msg[4]) { case I2O_EVT_IND_EXEC_RESOURCE_LIMITS: printk(KERN_ERR "%s: Out of resources\n", c->name); break; case I2O_EVT_IND_EXEC_POWER_FAIL: printk(KERN_ERR "%s: Power failure\n", c->name); break; case I2O_EVT_IND_EXEC_HW_FAIL: { char *fail[] = { "Unknown Error", "Power Lost", "Code Violation", "Parity Error", "Code Execution Exception", "Watchdog Timer Expired" }; if(msg[5] <= 6) printk(KERN_ERR "%s: Hardware Failure: %s\n", c->name, fail[msg[5]]); else printk(KERN_ERR "%s: Unknown Hardware Failure\n", c->name); break; } /* * New device created * - Create a new i2o_device entry * - Inform all interested drivers about this device's existence */ case I2O_EVT_IND_EXEC_NEW_LCT_ENTRY: { struct i2o_device *d = (struct i2o_device *) kmalloc(sizeof(struct i2o_device), GFP_KERNEL); int i; if (d == NULL) { printk(KERN_EMERG "i2oevtd: out of memory\n"); break; } memcpy(&d->lct_data, &msg[5], sizeof(i2o_lct_entry)); d->next = NULL; d->controller = c; d->flags = 0; i2o_report_controller_unit(c, d); i2o_install_device(c,d); for(i = 0; i < MAX_I2O_MODULES; i++) { if(i2o_handlers[i] && i2o_handlers[i]->new_dev_notify && (i2o_handlers[i]->class&d->lct_data.class_id)) { spin_lock(&i2o_dev_lock); i2o_handlers[i]->new_dev_notify(c,d); spin_unlock(&i2o_dev_lock); } } break; } /* * LCT entry for a device has been modified, so update it * internally. */ case I2O_EVT_IND_EXEC_MODIFIED_LCT: { struct i2o_device *d; i2o_lct_entry *new_lct = (i2o_lct_entry *)&msg[5]; for(d = c->devices; d; d = d->next) { if(d->lct_data.tid == new_lct->tid) { memcpy(&d->lct_data, new_lct, sizeof(i2o_lct_entry)); break; } } break; } case I2O_EVT_IND_CONFIGURATION_FLAG: printk(KERN_WARNING "%s requires user configuration\n", c->name); break; case I2O_EVT_IND_GENERAL_WARNING: printk(KERN_WARNING "%s: Warning notification received!" "Check configuration for errors!\n", c->name); break; case I2O_EVT_IND_EVT_MASK_MODIFIED: /* Well I guess that was us hey .. */ break; default: printk(KERN_WARNING "%s: No handler for event (0x%08x)\n", c->name, msg[4]); break; } } return 0;}/* * Dynamic LCT update. This compares the LCT with the currently * installed devices to check for device deletions..this needed b/c there * is no DELETED_LCT_ENTRY EventIndicator for the Executive class so * we can't just have the event handler do this...annoying * * This is a hole in the spec that will hopefully be fixed someday. */static int i2o_dyn_lct(void *foo){ struct i2o_controller *c = (struct i2o_controller *)foo; struct i2o_device *d = NULL; struct i2o_device *d1 = NULL; int i = 0; int found = 0; int entries; void *tmp; char name[16]; lock_kernel(); daemonize(); unlock_kernel(); sprintf(name, "iop%d_lctd", c->unit); strcpy(current->comm, name); c->lct_running = 1; while(1) { down_interruptible(&c->lct_sem); if(signal_pending(current)) { dprintk(KERN_ERR "%s: LCT thread dead\n", c->name); c->lct_running = 0; return 0; } entries = c->dlct->table_size; entries -= 3; entries /= 9; dprintk(KERN_INFO "%s: Dynamic LCT Update\n",c->name); dprintk(KERN_INFO "%s: Dynamic LCT contains %d entries\n", c->name, entries); if(!entries) { printk(KERN_INFO "%s: Empty LCT???\n", c->name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -