📄 i2o_core.c
字号:
/* * Core I2O structure management * * (C) Copyright 1999 Red Hat Software * * Written by Alan Cox, Building Number Three Ltd * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * A lot of the I2O message side code from this is taken from the * Red Creek RCPCI45 adapter driver by Red Creek Communications * * Fixes by: * Philipp Rumpf * Juha Siev鋘en <Juha.Sievanen@cs.Helsinki.FI> * Auvo H鋕kinen <Auvo.Hakkinen@cs.Helsinki.FI> * Deepak Saxena <deepak@plexity.net> * Boji T Kannanthanam <boji.t.kannanthanam@intel.com> * */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/pci.h>#include <linux/i2o.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/spinlock.h>#include <linux/smp_lock.h>#include <linux/bitops.h>#include <linux/wait.h>#include <linux/delay.h>#include <linux/timer.h>#include <linux/tqueue.h>#include <linux/interrupt.h>#include <linux/sched.h>#include <asm/semaphore.h>#include <linux/completion.h>#include <asm/io.h>#include <linux/reboot.h>#include "i2o_lan.h"//#define DRIVERDEBUG#ifdef DRIVERDEBUG#define dprintk(s, args...) printk(s, ## args)#else#define dprintk(s, args...)#endif/* OSM table */static struct i2o_handler *i2o_handlers[MAX_I2O_MODULES];/* Controller list */static struct i2o_controller *i2o_controllers[MAX_I2O_CONTROLLERS];struct i2o_controller *i2o_controller_chain;int i2o_num_controllers;/* Initiator Context for Core message */static int core_context;/* Initialization && shutdown functions */static void i2o_sys_init(void);static void i2o_sys_shutdown(void);static int i2o_reset_controller(struct i2o_controller *);static int i2o_reboot_event(struct notifier_block *, unsigned long , void *);static int i2o_online_controller(struct i2o_controller *);static int i2o_init_outbound_q(struct i2o_controller *);static int i2o_post_outbound_messages(struct i2o_controller *);/* Reply handler */static void i2o_core_reply(struct i2o_handler *, struct i2o_controller *, struct i2o_message *);/* Various helper functions */static int i2o_lct_get(struct i2o_controller *);static int i2o_lct_notify(struct i2o_controller *);static int i2o_hrt_get(struct i2o_controller *);static int i2o_build_sys_table(void);static int i2o_systab_send(struct i2o_controller *c);/* I2O core event handler */static int i2o_core_evt(void *);static int evt_pid;static int evt_running;/* Dynamic LCT update handler */static int i2o_dyn_lct(void *);void i2o_report_controller_unit(struct i2o_controller *, struct i2o_device *);/* * I2O System Table. Contains information about * all the IOPs in the system. Used to inform IOPs * about each other's existence. * * sys_tbl_ver is the CurrentChangeIndicator that is * used by IOPs to track changes. */static struct i2o_sys_tbl *sys_tbl;static int sys_tbl_ind;static int sys_tbl_len;/* * This spin lock is used to keep a device from being * added and deleted concurrently across CPUs or interrupts. * This can occur when a user creates a device and immediatelly * deletes it before the new_dev_notify() handler is called. */static spinlock_t i2o_dev_lock = SPIN_LOCK_UNLOCKED;#ifdef MODULE/* * Function table to send to bus specific layers * See <include/linux/i2o.h> for explanation of this */static struct i2o_core_func_table i2o_core_functions ={ i2o_install_controller, i2o_activate_controller, i2o_find_controller, i2o_unlock_controller, i2o_run_queue, i2o_delete_controller};#ifdef CONFIG_I2O_PCI_MODULEextern int i2o_pci_core_attach(struct i2o_core_func_table *);extern void i2o_pci_core_detach(void);#endif /* CONFIG_I2O_PCI_MODULE */#endif /* MODULE *//* * Structures and definitions for synchronous message posting. * See i2o_post_wait() for description. */ struct i2o_post_wait_data{ int *status; /* Pointer to status block on caller stack */ int *complete; /* Pointer to completion flag on caller stack */ u32 id; /* Unique identifier */ wait_queue_head_t *wq; /* Wake up for caller (NULL for dead) */ struct i2o_post_wait_data *next; /* Chain */ void *mem[2]; /* Memory blocks to recover on failure path */};static struct i2o_post_wait_data *post_wait_queue;static u32 post_wait_id; // Unique ID for each post_waitstatic spinlock_t post_wait_lock = SPIN_LOCK_UNLOCKED;static void i2o_post_wait_complete(u32, int);/* OSM descriptor handler */ static struct i2o_handler i2o_core_handler ={ (void *)i2o_core_reply, NULL, NULL, NULL, "I2O core layer", 0, I2O_CLASS_EXECUTIVE};/* * Used when queueing a reply to be handled later */ struct reply_info{ struct i2o_controller *iop; u32 msg[MSG_FRAME_SIZE];};static struct reply_info evt_reply;static struct reply_info events[I2O_EVT_Q_LEN];static int evt_in;static int evt_out;static int evt_q_len;#define MODINC(x,y) ((x) = ((x) + 1) % (y))/* * I2O configuration spinlock. This isnt a big deal for contention * so we have one only */static DECLARE_MUTEX(i2o_configuration_lock);/* * Event spinlock. Used to keep event queue sane and from * handling multiple events simultaneously. */static spinlock_t i2o_evt_lock = SPIN_LOCK_UNLOCKED;/* * Semaphore used to synchronize event handling thread with * interrupt handler. */ static DECLARE_MUTEX(evt_sem);static DECLARE_COMPLETION(evt_dead);static DECLARE_WAIT_QUEUE_HEAD(evt_wait);static struct notifier_block i2o_reboot_notifier ={ i2o_reboot_event, NULL, 0};/* * Config options */static int verbose;MODULE_PARM(verbose, "i");/* * I2O Core reply handler */static void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m){ u32 *msg=(u32 *)m; u32 status; u32 context = msg[2]; if (msg[0] & MSG_FAIL) // Fail bit is set { u32 *preserved_msg = (u32*)(c->mem_offset + msg[7]); i2o_report_status(KERN_INFO, "i2o_core", msg); i2o_dump_message(preserved_msg); /* If the failed request needs special treatment, * it should be done here. */ /* Release the preserved msg by resubmitting it as a NOP */ preserved_msg[0] = cpu_to_le32(THREE_WORD_MSG_SIZE | SGL_OFFSET_0); preserved_msg[1] = cpu_to_le32(I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0); preserved_msg[2] = 0; i2o_post_message(c, msg[7]); /* If reply to i2o_post_wait failed, return causes a timeout */ return; } #ifdef DRIVERDEBUG i2o_report_status(KERN_INFO, "i2o_core", msg);#endif if(msg[2]&0x80000000) // Post wait message { if (msg[4] >> 24) status = (msg[4] & 0xFFFF); else status = I2O_POST_WAIT_OK; i2o_post_wait_complete(context, status); return; } if(m->function == I2O_CMD_UTIL_EVT_REGISTER) { memcpy(events[evt_in].msg, msg, (msg[0]>>16)<<2); events[evt_in].iop = c; spin_lock(&i2o_evt_lock); MODINC(evt_in, I2O_EVT_Q_LEN); if(evt_q_len == I2O_EVT_Q_LEN) MODINC(evt_out, I2O_EVT_Q_LEN); else evt_q_len++; spin_unlock(&i2o_evt_lock); up(&evt_sem); wake_up_interruptible(&evt_wait); return; } if(m->function == I2O_CMD_LCT_NOTIFY) { up(&c->lct_sem); return; } /* * If this happens, we want to dump the message to the syslog so * it can be sent back to the card manufacturer by the end user * to aid in debugging. * */ printk(KERN_WARNING "%s: Unsolicited message reply sent to core!" "Message dumped to syslog\n", c->name); i2o_dump_message(msg); return;}/** * i2o_install_handler - install a message handler * @h: Handler structure * * Install an I2O handler - these handle the asynchronous messaging * from the card once it has initialised. If the table of handlers is * full then -ENOSPC is returned. On a success 0 is returned and the * context field is set by the function. The structure is part of the * system from this time onwards. It must not be freed until it has * been uninstalled */ int i2o_install_handler(struct i2o_handler *h){ int i; down(&i2o_configuration_lock); for(i=0;i<MAX_I2O_MODULES;i++) { if(i2o_handlers[i]==NULL) { h->context = i; i2o_handlers[i]=h; up(&i2o_configuration_lock); return 0; } } up(&i2o_configuration_lock); return -ENOSPC;}/** * i2o_remove_handler - remove an i2o message handler * @h: handler * * Remove a message handler previously installed with i2o_install_handler. * After this function returns the handler object can be freed or re-used */ int i2o_remove_handler(struct i2o_handler *h){ i2o_handlers[h->context]=NULL; return 0;} /* * Each I2O controller has a chain of devices on it. * Each device has a pointer to it's LCT entry to be used * for fun purposes. *//** * i2o_install_device - attach a device to a controller * @c: controller * @d: device * * Add a new device to an i2o controller. This can be called from * non interrupt contexts only. It adds the device and marks it as * unclaimed. The device memory becomes part of the kernel and must * be uninstalled before being freed or reused. Zero is returned * on success. */ int i2o_install_device(struct i2o_controller *c, struct i2o_device *d){ int i; down(&i2o_configuration_lock); d->controller=c; d->owner=NULL; d->next=c->devices; d->prev=NULL; if (c->devices != NULL) c->devices->prev=d; c->devices=d; *d->dev_name = 0; for(i = 0; i < I2O_MAX_MANAGERS; i++) d->managers[i] = NULL; up(&i2o_configuration_lock); return 0;}/* we need this version to call out of i2o_delete_controller */int __i2o_delete_device(struct i2o_device *d){ struct i2o_device **p; int i; p=&(d->controller->devices); /* * Hey we have a driver! * Check to see if the driver wants us to notify it of * device deletion. If it doesn't we assume that it * is unsafe to delete a device with an owner and * fail. */ if(d->owner) { if(d->owner->dev_del_notify) { dprintk(KERN_INFO "Device has owner, notifying\n"); d->owner->dev_del_notify(d->controller, d); if(d->owner) { printk(KERN_WARNING "Driver \"%s\" did not release device!\n", d->owner->name); return -EBUSY; } } else return -EBUSY; } /* * Tell any other users who are talking to this device * that it's going away. We assume that everything works. */ for(i=0; i < I2O_MAX_MANAGERS; i++) { if(d->managers[i] && d->managers[i]->dev_del_notify) d->managers[i]->dev_del_notify(d->controller, d); } while(*p!=NULL) { if(*p==d) { /* * Destroy */ *p=d->next; kfree(d); return 0; } p=&((*p)->next); } printk(KERN_ERR "i2o_delete_device: passed invalid device.\n"); return -EINVAL;}/** * i2o_delete_device - remove an i2o device * @d: device to remove * * This function unhooks a device from a controller. The device * will not be unhooked if it has an owner who does not wish to free * it, or if the owner lacks a dev_del_notify function. In that case * -EBUSY is returned. On success 0 is returned. Other errors cause * negative errno values to be returned */ int i2o_delete_device(struct i2o_device *d){ int ret; down(&i2o_configuration_lock); /* * Seek, locate */ ret = __i2o_delete_device(d); up(&i2o_configuration_lock); return ret;}/** * i2o_install_controller - attach a controller * @c: controller * * Add a new controller to the i2o layer. This can be called from * non interrupt contexts only. It adds the controller and marks it as * unused with no devices. If the tables are full or memory allocations * fail then a negative errno code is returned. On success zero is * returned and the controller is bound to the system. The structure * must not be freed or reused until being uninstalled. */ int i2o_install_controller(struct i2o_controller *c){ int i; down(&i2o_configuration_lock); for(i=0;i<MAX_I2O_CONTROLLERS;i++) { if(i2o_controllers[i]==NULL) { c->dlct = (i2o_lct*)kmalloc(8192, GFP_KERNEL); if(c->dlct==NULL) { up(&i2o_configuration_lock); return -ENOMEM; } i2o_controllers[i]=c; c->devices = NULL; c->next=i2o_controller_chain; i2o_controller_chain=c; c->unit = i; c->page_frame = NULL; c->hrt = NULL; c->lct = NULL; c->status_block = NULL; sprintf(c->name, "i2o/iop%d", i); i2o_num_controllers++; init_MUTEX_LOCKED(&c->lct_sem); up(&i2o_configuration_lock); return 0; } } printk(KERN_ERR "No free i2o controller slots.\n"); up(&i2o_configuration_lock); return -EBUSY;}/** * i2o_delete_controller - delete a controller * @c: controller * * Remove an i2o controller from the system. If the controller or its * devices are busy then -EBUSY is returned. On a failure a negative * errno code is returned. On success zero is returned. */ int i2o_delete_controller(struct i2o_controller *c){ struct i2o_controller **p; int users; char name[16]; int stat; dprintk(KERN_INFO "Deleting controller %s\n", c->name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -