diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-06-16 23:00:36 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-06-16 23:00:36 +0000 |
commit | 14dd2ec093cfabda3ae7efeeaf0e23c66ebaccc0 (patch) | |
tree | 9a9ce5cff6ef92faa6e07a82785b9a6d6838f7e4 /drivers/i2o | |
parent | 847290510f811c572cc2aa80c1f02a04721410b1 (diff) |
Merge with 2.4.0-test1.
Diffstat (limited to 'drivers/i2o')
-rw-r--r-- | drivers/i2o/i2o_core.c | 328 |
1 files changed, 253 insertions, 75 deletions
diff --git a/drivers/i2o/i2o_core.c b/drivers/i2o/i2o_core.c index 80d001468..d8cc9b2c0 100644 --- a/drivers/i2o/i2o_core.c +++ b/drivers/i2o/i2o_core.c @@ -189,7 +189,7 @@ static int evt_q_len = 0; * I2O configuration spinlock. This isnt a big deal for contention * so we have one only */ -static spinlock_t i2o_configuration_lock = SPIN_LOCK_UNLOCKED; +static struct semaphore i2o_configuration_lock; /* * Event spinlock. Used to keep event queue sane and from @@ -215,7 +215,7 @@ static struct notifier_block i2o_reboot_notifier = /* * I2O Core reply handler */ -void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, +static void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *m) { u32 *msg=(u32 *)m; @@ -297,29 +297,44 @@ void i2o_core_reply(struct i2o_handler *h, struct i2o_controller *c, 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. + * 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; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); for(i=0;i<MAX_I2O_MODULES;i++) { if(i2o_handlers[i]==NULL) { h->context = i; i2o_handlers[i]=h; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } } - spin_unlock(&i2o_configuration_lock); + 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; @@ -332,12 +347,24 @@ int i2o_remove_handler(struct i2o_handler *h) * 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; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); d->controller=c; d->owner=NULL; d->next=c->devices; @@ -347,7 +374,7 @@ int i2o_install_device(struct i2o_controller *c, struct i2o_device *d) for(i = 0; i < I2O_MAX_MANAGERS; i++) d->managers[i] = NULL; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } @@ -411,11 +438,22 @@ int __i2o_delete_device(struct i2o_device *d) 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; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); /* * Seek, locate @@ -423,23 +461,37 @@ int i2o_delete_device(struct i2o_device *d) ret = __i2o_delete_device(d); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return ret; } -/* - * Add and remove controllers from the I2O controller list +/** + * 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; - spin_lock(&i2o_configuration_lock); + 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; @@ -448,20 +500,28 @@ int i2o_install_controller(struct i2o_controller *c) c->page_frame = NULL; c->hrt = NULL; c->lct = NULL; - c->dlct = (i2o_lct*)kmalloc(8192, GFP_KERNEL); c->status_block = NULL; sprintf(c->name, "i2o/iop%d", i); i2o_num_controllers++; init_MUTEX_LOCKED(&c->lct_sem); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } } printk(KERN_ERR "No free i2o controller slots.\n"); - spin_unlock(&i2o_configuration_lock); + 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; @@ -477,12 +537,12 @@ int i2o_delete_controller(struct i2o_controller *c) if(c->status_block->iop_state == ADAPTER_STATE_OPERATIONAL) i2o_event_register(c, core_context, 0, 0, 0); - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); if((users=atomic_read(&c->users))) { dprintk(KERN_INFO "I2O: %d users for controller %s\n", users, c->name); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } while(c->devices) @@ -491,7 +551,7 @@ int i2o_delete_controller(struct i2o_controller *c) { /* Shouldnt happen */ c->bus_disable(c); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -EBUSY; } } @@ -528,7 +588,7 @@ int i2o_delete_controller(struct i2o_controller *c) c->destructor(c); *p=c->next; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); if(c->page_frame) kfree(c->page_frame); @@ -551,16 +611,33 @@ int i2o_delete_controller(struct i2o_controller *c) } p=&((*p)->next); } - spin_unlock(&i2o_configuration_lock); + 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; @@ -568,17 +645,28 @@ struct i2o_controller *i2o_find_controller(int n) if(n<0 || n>=MAX_I2O_CONTROLLERS) return NULL; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); c=i2o_controllers[n]; if(c!=NULL) atomic_inc(&c->users); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return c; } -/* - * Issue UTIL_CLAIM or UTIL_RELEASE message +/** + * 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]; @@ -592,54 +680,70 @@ static int i2o_issue_claim(u32 cmd, struct i2o_controller *c, int tid, u32 type) } /* - * Claim a device for use by an OSM + * 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) { - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); if (d->owner) { printk(KERN_INFO "Device claim called, but dev allready owned by %s!", h->name); - spin_unlock(&i2o_configuration_lock); + 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)) { - spin_unlock(&i2o_configuration_lock); + d->owner = NULL; return -EBUSY; } - - d->owner=h; - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return 0; } -/* - * Release a device that the OSM is using +/** + * 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. + * */ + int i2o_release_device(struct i2o_device *d, struct i2o_handler *h) { int err = 0; - spin_lock(&i2o_configuration_lock); + down(&i2o_configuration_lock); if (d->owner != h) { printk(KERN_INFO "Claim release called, but not owned by %s!", h->name); - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return -ENOENT; } + d->owner = NULL; + if(i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, I2O_CLAIM_PRIMARY)) { err = -ENXIO; + d->owner = h; } - d->owner = NULL; - - spin_unlock(&i2o_configuration_lock); + up(&i2o_configuration_lock); return err; } @@ -994,7 +1098,10 @@ static int i2o_dyn_lct(void *foo) return 0; } -/* +/** + * i2o_run_queue - process pending events on a controller + * @c: controller to process + * * This is called by the bus specific driver layer when an interrupt * or poll of this card interface is desired. */ @@ -1046,9 +1153,13 @@ void i2o_run_queue(struct i2o_controller *c) } -/* - * Do i2o class name lookup +/** + * i2o_get_class_name - do i2o class name lookup + * @class: class number + * + * Return a descriptive string for an i2o class */ + const char *i2o_get_class_name(int class) { int idx = 16; @@ -1112,8 +1223,18 @@ const char *i2o_get_class_name(int class) } -/* - * Wait up to 5 seconds for a message slot to be available. +/** + * i2o_wait_message + * @c: controller + * @why: explanation + * + * This function waits up to 5 seconds for a message slot to be + * available. If no message is available it prints an error message + * that is expected to be what the message will be used for (eg + * "get_status"). 0xFFFFFFFF is returned on a failure. + * + * On a success the message is returned. This is the physical page + * frame offset address from the read port. (See the i2o spec) */ u32 i2o_wait_message(struct i2o_controller *c, char *why) @@ -1134,8 +1255,14 @@ u32 i2o_wait_message(struct i2o_controller *c, char *why) return m; } -/* - * Dump the information block associated with a given unit (TID) +/** + * i2o_report_controller_unit - print information about a tid + * @c: controller + * @d: device + * + * Dump an information block associated with a given unit (TID). The + * tables are read and a block of text is output to printk that is + * formatted intended for the user. */ void i2o_report_controller_unit(struct i2o_controller *c, struct i2o_device *d) @@ -1341,10 +1468,14 @@ static int i2o_parse_lct(struct i2o_controller *c) } -/* - * Quiesce IOP. Causes IOP to make external operation quiescend. - * Internal operation of the IOP continues normally. +/** + * i2o_quiesce_controller - quiesce controller + * @c: controller + * + * Quiesce an IOP. Causes IOP to make external operation quiescent + * (i2o 'READY' state). Internal operation of the IOP continues normally. */ + int i2o_quiesce_controller(struct i2o_controller *c) { u32 msg[4]; @@ -1373,14 +1504,18 @@ int i2o_quiesce_controller(struct i2o_controller *c) dprintk(KERN_INFO "%s: Quiesced.\n", c->name); i2o_status_get(c); // Entered READY state - - return ret; - + return ret; } -/* - * Enable IOP. Allows the IOP to resume external operations. +/** + * i2o_enable_controller - move controller from ready to operational + * @c: controller + * + * Enable IOP. This allows the IOP to resume external operations and + * reverses the effect of a quiesce. In the event of an error a negative + * errno code is returned. */ + int i2o_enable_controller(struct i2o_controller *c) { u32 msg[4]; @@ -1395,7 +1530,7 @@ int i2o_enable_controller(struct i2o_controller *c) msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID; - /* How long of a timeout do we need? */ + /* How long of a timeout do we need? */ if ((ret = i2o_post_wait(c, msg, sizeof(msg), 240))) printk(KERN_ERR "%s: Could not enable (status=%#x).\n", @@ -1408,12 +1543,16 @@ int i2o_enable_controller(struct i2o_controller *c) return ret; } -/* - * Clear an IOP to HOLD state, ie. terminate external operations, clear all - * input queues and prepare for a system restart. IOP's internal operation - * continues normally and the outbound queue is alive. - * IOP is not expected to rebuild its LCT. +/** + * i2o_clear_controller - clear a controller + * @c: controller + * + * Clear an IOP to HOLD state, ie. terminate external operations, clear all + * input queues and prepare for a system restart. IOP's internal operation + * continues normally and the outbound queue is alive. + * The IOP is not expected to rebuild its LCT. */ + int i2o_clear_controller(struct i2o_controller *c) { struct i2o_controller *iop; @@ -1447,12 +1586,16 @@ int i2o_clear_controller(struct i2o_controller *c) } -/* - * 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. IOP rebuilds its LCT. +/** + * i2o_reset_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_reset_controller(struct i2o_controller *c) { struct i2o_controller *iop; @@ -1556,9 +1699,16 @@ static int i2o_reset_controller(struct i2o_controller *c) } -/* - * Get the status block for the IOP +/** + * 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; @@ -1743,7 +1893,7 @@ static int i2o_systab_send(struct i2o_controller *iop) /* * Initialize I2O subsystem. */ -static void __init i2o_sys_init() +static void __init i2o_sys_init(void) { struct i2o_controller *iop, *niop = NULL; @@ -1806,9 +1956,13 @@ rebuild_sys_tab: } } -/* - * Shutdown I2O system +/** + * 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; @@ -1822,9 +1976,16 @@ static void i2o_sys_shutdown(void) } } -/* - * Bring an I2O controller into HOLD state. See the spec. +/** + * 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) */ @@ -1872,9 +2033,14 @@ int i2o_activate_controller(struct i2o_controller *iop) } -/* - * Clear and (re)initialize IOP's outbound queue +/** + * i2o_init_outbound_queue - setup the outbound queue + * @c: controller + * + * Clear and (re)initialize IOP's outbound queue. Returns 0 on + * success or a negative errno code on a failure. */ + int i2o_init_outbound_q(struct i2o_controller *c) { u8 *status; @@ -1938,6 +2104,15 @@ int i2o_init_outbound_q(struct i2o_controller *c) return 0; } +/** + * i2o_post_outbound_messages - fill message queue + * @c: controller + * + * Allocate a message frame and load the messages into the IOP. The + * function returns zero on success or a negative errno code on + * failure. + */ + int i2o_post_outbound_messages(struct i2o_controller *c) { int i; @@ -3071,6 +3246,9 @@ extern int i2o_scsi_init(void); int __init i2o_init(void) { printk(KERN_INFO "Loading I2O Core - (c) Copyright 1999 Red Hat Software\n"); + + init_MUTEX(&i2o_configuration_lock); + if (i2o_install_handler(&i2o_core_handler) < 0) { printk(KERN_ERR |