X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmessage%2Fi2o%2Fexec-osm.c;fp=drivers%2Fmessage%2Fi2o%2Fexec-osm.c;h=7bd4d85d0b42db6af28def4072cbd11fbadbec86;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=79c1cbfb8f44a7dd0cc381206637525769420deb;hpb=cee37fe97739d85991964371c1f3a745c00dd236;p=linux-2.6.git diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index 79c1cbfb8..7bd4d85d0 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -30,6 +30,12 @@ #include #include #include +#include +#include +#include +#include /* wait_event_interruptible_timeout() needs this */ +#include /* HZ */ +#include "core.h" #define OSM_NAME "exec-osm" @@ -37,9 +43,6 @@ struct i2o_driver i2o_exec_driver; static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind); -/* Module internal functions from other sources */ -extern int i2o_device_parse_lct(struct i2o_controller *); - /* global wait list for POST WAIT */ static LIST_HEAD(i2o_exec_wait_list); @@ -50,8 +53,16 @@ struct i2o_exec_wait { u32 tcntxt; /* transaction context from reply */ int complete; /* 1 if reply received otherwise 0 */ u32 m; /* message id */ - struct i2o_message __iomem *msg; /* pointer to the reply message */ + struct i2o_message *msg; /* pointer to the reply message */ struct list_head list; /* node in global wait list */ + spinlock_t lock; /* lock before modifying */ +}; + +/* Work struct needed to handle LCT NOTIFY replies */ +struct i2o_exec_lct_notify_work { + struct work_struct work; /* work struct */ + struct i2o_controller *c; /* controller on which the LCT NOTIFY + was received */ }; /* Exec OSM class handling definition */ @@ -72,13 +83,12 @@ static struct i2o_exec_wait *i2o_exec_wait_alloc(void) { struct i2o_exec_wait *wait; - wait = kmalloc(sizeof(*wait), GFP_KERNEL); + wait = kzalloc(sizeof(*wait), GFP_KERNEL); if (!wait) - return ERR_PTR(-ENOMEM); - - memset(wait, 0, sizeof(*wait)); + return NULL; INIT_LIST_HEAD(&wait->list); + spin_lock_init(&wait->lock); return wait; }; @@ -108,15 +118,16 @@ static void i2o_exec_wait_free(struct i2o_exec_wait *wait) * buffer must not be freed. Instead the event completion will free them * for you. In all other cases the buffer are your problem. * - * Returns 0 on success or negative error code on failure. + * Returns 0 on success, negative error code on timeout or positive error + * code from reply. */ -int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long - timeout, struct i2o_dma *dma) +int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg, + unsigned long timeout, struct i2o_dma *dma) { DECLARE_WAIT_QUEUE_HEAD(wq); struct i2o_exec_wait *wait; static u32 tcntxt = 0x80000000; - struct i2o_message __iomem *msg = c->in_queue.virt + m; + long flags; int rc = 0; wait = i2o_exec_wait_alloc(); @@ -134,38 +145,32 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long * We will only use transaction contexts >= 0x80000000 for POST WAIT, * so we could find a POST WAIT reply easier in the reply handler. */ - writel(i2o_exec_driver.context, &msg->u.s.icntxt); + msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context); wait->tcntxt = tcntxt++; - writel(wait->tcntxt, &msg->u.s.tcntxt); + msg->u.s.tcntxt = cpu_to_le32(wait->tcntxt); + + wait->wq = &wq; + /* + * we add elements to the head, because if a entry in the list will + * never be removed, we have to iterate over it every time + */ + list_add(&wait->list, &i2o_exec_wait_list); /* * Post the message to the controller. At some point later it will * return. If we time out before it returns then complete will be zero. */ - i2o_msg_post(c, m); - - if (!wait->complete) { - wait->wq = &wq; - /* - * we add elements add the head, because if a entry in the list - * will never be removed, we have to iterate over it every time - */ - list_add(&wait->list, &i2o_exec_wait_list); + i2o_msg_post(c, msg); - wait_event_interruptible_timeout(wq, wait->complete, - timeout * HZ); + wait_event_interruptible_timeout(wq, wait->complete, timeout * HZ); - wait->wq = NULL; - } + spin_lock_irqsave(&wait->lock, flags); - barrier(); + wait->wq = NULL; - if (wait->complete) { - if (readl(&wait->msg->body[0]) >> 24) - rc = readl(&wait->msg->body[0]) & 0xff; - i2o_flush_reply(c, wait->m); - i2o_exec_wait_free(wait); - } else { + if (wait->complete) + rc = le32_to_cpu(wait->msg->body[0]) >> 24; + else { /* * We cannot remove it now. This is important. When it does * terminate (which it must do if the controller has not @@ -179,6 +184,13 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long rc = -ETIMEDOUT; } + spin_unlock_irqrestore(&wait->lock, flags); + + if (rc != -ETIMEDOUT) { + i2o_flush_reply(c, wait->m); + i2o_exec_wait_free(wait); + } + return rc; }; @@ -187,6 +199,7 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long * @c: I2O controller which answers * @m: message id * @msg: pointer to the I2O reply message + * @context: transaction context of request * * This function is called in interrupt context only. If the reply reached * before the timeout, the i2o_exec_wait struct is filled with the message @@ -201,16 +214,11 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long * message must also be given back to the controller. */ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, - struct i2o_message __iomem *msg) + struct i2o_message *msg, u32 context) { struct i2o_exec_wait *wait, *tmp; - static spinlock_t lock; + unsigned long flags; int rc = 1; - u32 context; - - spin_lock_init(&lock); - - context = readl(&msg->u.s.tcntxt); /* * We need to search through the i2o_exec_wait_list to see if the given @@ -219,21 +227,24 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, * already expired. Not much we can do about that except log it for * debug purposes, increase timeout, and recompile. */ - spin_lock(&lock); list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) { if (wait->tcntxt == context) { + spin_lock_irqsave(&wait->lock, flags); + list_del(&wait->list); wait->m = m; wait->msg = msg; wait->complete = 1; - barrier(); - - if (wait->wq) { - wake_up_interruptible(wait->wq); + if (wait->wq) rc = 0; - } else { + else + rc = -1; + + spin_unlock_irqrestore(&wait->lock, flags); + + if (rc) { struct device *dev; dev = &c->pdev->dev; @@ -242,23 +253,66 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m, c->name); i2o_dma_free(dev, &wait->dma); i2o_exec_wait_free(wait); - rc = -1; - } - - spin_unlock(&lock); + } else + wake_up_interruptible(wait->wq); return rc; } } - spin_unlock(&lock); - - pr_debug("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name, + osm_warn("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name, context); return -1; }; +/** + * i2o_exec_show_vendor_id - Displays Vendor ID of controller + * @d: device of which the Vendor ID should be displayed + * @buf: buffer into which the Vendor ID should be printed + * + * Returns number of bytes printed into buffer. + */ +static ssize_t i2o_exec_show_vendor_id(struct device *d, + struct device_attribute *attr, char *buf) +{ + struct i2o_device *dev = to_i2o_device(d); + u16 id; + + if (!i2o_parm_field_get(dev, 0x0000, 0, &id, 2)) { + sprintf(buf, "0x%04x", le16_to_cpu(id)); + return strlen(buf) + 1; + } + + return 0; +}; + +/** + * i2o_exec_show_product_id - Displays Product ID of controller + * @d: device of which the Product ID should be displayed + * @buf: buffer into which the Product ID should be printed + * + * Returns number of bytes printed into buffer. + */ +static ssize_t i2o_exec_show_product_id(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct i2o_device *dev = to_i2o_device(d); + u16 id; + + if (!i2o_parm_field_get(dev, 0x0000, 1, &id, 2)) { + sprintf(buf, "0x%04x", le16_to_cpu(id)); + return strlen(buf) + 1; + } + + return 0; +}; + +/* Exec-OSM device attributes */ +static DEVICE_ATTR(vendor_id, S_IRUGO, i2o_exec_show_vendor_id, NULL); +static DEVICE_ATTR(product_id, S_IRUGO, i2o_exec_show_product_id, NULL); + /** * i2o_exec_probe - Called if a new I2O device (executive class) appears * @dev: I2O device which should be probed @@ -274,7 +328,8 @@ static int i2o_exec_probe(struct device *dev) i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff); - i2o_dev->iop->exec = i2o_dev; + device_create_file(dev, &dev_attr_vendor_id); + device_create_file(dev, &dev_attr_product_id); return 0; }; @@ -289,6 +344,9 @@ static int i2o_exec_probe(struct device *dev) */ static int i2o_exec_remove(struct device *dev) { + device_remove_file(dev, &dev_attr_product_id); + device_remove_file(dev, &dev_attr_vendor_id); + i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0); return 0; @@ -300,12 +358,21 @@ static int i2o_exec_remove(struct device *dev) * * This function handles asynchronus LCT NOTIFY replies. It parses the * new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY - * again. + * again, otherwise send LCT NOTIFY to get informed on next LCT change. */ -static void i2o_exec_lct_modified(struct i2o_controller *c) +static void i2o_exec_lct_modified(struct i2o_exec_lct_notify_work *work) { - if (i2o_device_parse_lct(c) == -EAGAIN) - i2o_exec_lct_notify(c, 0); + u32 change_ind = 0; + struct i2o_controller *c = work->c; + + kfree(work); + + if (i2o_device_parse_lct(c) != -EAGAIN) + change_ind = c->lct->change_ind + 1; + +#ifdef CONFIG_I2O_LCT_NOTIFY_ON_CHANGES + i2o_exec_lct_notify(c, change_ind); +#endif }; /** @@ -325,28 +392,33 @@ static void i2o_exec_lct_modified(struct i2o_controller *c) static int i2o_exec_reply(struct i2o_controller *c, u32 m, struct i2o_message *msg) { - if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) { // Fail bit is set - struct i2o_message __iomem *pmsg; /* preserved message */ + u32 context; + + if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) { + struct i2o_message __iomem *pmsg; u32 pm; - pm = le32_to_cpu(msg->body[3]); + /* + * If Fail bit is set we must take the transaction context of + * the preserved message to find the right request again. + */ + pm = le32_to_cpu(msg->body[3]); pmsg = i2o_msg_in_to_virt(c, pm); + context = readl(&pmsg->u.s.tcntxt); i2o_report_status(KERN_INFO, "i2o_core", msg); - /* Release the preserved msg by resubmitting it as a NOP */ - i2o_msg_nop(c, pm); - - /* If reply to i2o_post_wait failed, return causes a timeout */ - return -1; - } + /* Release the preserved msg */ + i2o_msg_nop_mfa(c, pm); + } else + context = le32_to_cpu(msg->u.s.tcntxt); - if (le32_to_cpu(msg->u.s.tcntxt) & 0x80000000) - return i2o_msg_post_wait_complete(c, m, msg); + if (context & 0x80000000) + return i2o_msg_post_wait_complete(c, m, msg, context); if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) { - struct work_struct *work; + struct i2o_exec_lct_notify_work *work; pr_debug("%s: LCT notify received\n", c->name); @@ -354,8 +426,11 @@ static int i2o_exec_reply(struct i2o_controller *c, u32 m, if (!work) return -ENOMEM; - INIT_WORK(work, (void (*)(void *))i2o_exec_lct_modified, c); - queue_work(i2o_exec_driver.event_queue, work); + work->c = c; + + INIT_WORK(&work->work, (void (*)(void *))i2o_exec_lct_modified, + work); + queue_work(i2o_exec_driver.event_queue, &work->work); return 1; } @@ -381,8 +456,9 @@ static int i2o_exec_reply(struct i2o_controller *c, u32 m, */ static void i2o_exec_event(struct i2o_event *evt) { - osm_info("Event received from device: %d\n", - evt->i2o_dev->lct_data.tid); + if (likely(evt->i2o_dev)) + osm_debug("Event received from device: %d\n", + evt->i2o_dev->lct_data.tid); kfree(evt); }; @@ -398,25 +474,26 @@ static void i2o_exec_event(struct i2o_event *evt) */ int i2o_exec_lct_get(struct i2o_controller *c) { - struct i2o_message __iomem *msg; - u32 m; + struct i2o_message *msg; int i = 0; int rc = -EAGAIN; for (i = 1; i <= I2O_LCT_GET_TRIES; i++) { - m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); - if (m == I2O_QUEUE_EMPTY) - return -ETIMEDOUT; - - writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]); - writel(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 | ADAPTER_TID, - &msg->u.head[1]); - writel(0xffffffff, &msg->body[0]); - writel(0x00000000, &msg->body[1]); - writel(0xd0000000 | c->dlct.len, &msg->body[2]); - writel(c->dlct.phys, &msg->body[3]); - - rc = i2o_msg_post_wait(c, m, I2O_TIMEOUT_LCT_GET); + msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET); + if (IS_ERR(msg)) + return PTR_ERR(msg); + + msg->u.head[0] = + cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6); + msg->u.head[1] = + cpu_to_le32(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 | + ADAPTER_TID); + msg->body[0] = cpu_to_le32(0xffffffff); + msg->body[1] = cpu_to_le32(0x00000000); + msg->body[2] = cpu_to_le32(0xd0000000 | c->dlct.len); + msg->body[3] = cpu_to_le32(c->dlct.phys); + + rc = i2o_msg_post_wait(c, msg, I2O_TIMEOUT_LCT_GET); if (rc < 0) break; @@ -442,29 +519,33 @@ static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind) { i2o_status_block *sb = c->status_block.virt; struct device *dev; - struct i2o_message __iomem *msg; - u32 m; + struct i2o_message *msg; + + down(&c->lct_lock); dev = &c->pdev->dev; - if (i2o_dma_realloc(dev, &c->dlct, sb->expected_lct_size, GFP_KERNEL)) + if (i2o_dma_realloc + (dev, &c->dlct, le32_to_cpu(sb->expected_lct_size), GFP_KERNEL)) return -ENOMEM; - m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); - if (m == I2O_QUEUE_EMPTY) - return -ETIMEDOUT; - - writel(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6, &msg->u.head[0]); - writel(I2O_CMD_LCT_NOTIFY << 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 */ - writel(0xffffffff, &msg->body[0]); - writel(change_ind, &msg->body[1]); - writel(0xd0000000 | c->dlct.len, &msg->body[2]); - writel(c->dlct.phys, &msg->body[3]); - - i2o_msg_post(c, m); + msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET); + if (IS_ERR(msg)) + return PTR_ERR(msg); + + msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6); + msg->u.head[1] = cpu_to_le32(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 | + ADAPTER_TID); + msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context); + msg->u.s.tcntxt = cpu_to_le32(0x00000000); + msg->body[0] = cpu_to_le32(0xffffffff); + msg->body[1] = cpu_to_le32(change_ind); + msg->body[2] = cpu_to_le32(0xd0000000 | c->dlct.len); + msg->body[3] = cpu_to_le32(c->dlct.phys); + + i2o_msg_post(c, msg); + + up(&c->lct_lock); return 0; };