pcmcia: use dynamic debug infrastructure, deprecate CS_CHECK (ide)
[safe/jmp/linux-2.6] / drivers / block / aoe / aoechr.c
index f112466..62141ec 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2006 Coraid, Inc.  See COPYING for GPL terms. */
+/* Copyright (c) 2007 Coraid, Inc.  See COPYING for GPL terms. */
 /*
  * aoechr.c
  * AoE character device driver
@@ -6,7 +6,10 @@
 
 #include <linux/hdreg.h>
 #include <linux/blkdev.h>
+#include <linux/completion.h>
 #include <linux/delay.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
 #include "aoe.h"
 
 enum {
@@ -15,6 +18,7 @@ enum {
        MINOR_DISCOVER,
        MINOR_INTERFACES,
        MINOR_REVALIDATE,
+       MINOR_FLUSH,
        MSGSZ = 2048,
        NMSG = 100,             /* message backlog to retain */
 };
@@ -34,7 +38,7 @@ struct ErrMsg {
 
 static struct ErrMsg emsgs[NMSG];
 static int emsgs_head_idx, emsgs_tail_idx;
-static struct semaphore emsgs_sema;
+static struct completion emsgs_comp;
 static spinlock_t emsgs_lock;
 static int nblocked_emsgs_readers;
 static struct class *aoe_class;
@@ -43,6 +47,7 @@ static struct aoe_chardev chardevs[] = {
        { MINOR_DISCOVER, "discover" },
        { MINOR_INTERFACES, "interfaces" },
        { MINOR_REVALIDATE, "revalidate" },
+       { MINOR_FLUSH, "flush" },
 };
 
 static int
@@ -99,7 +104,12 @@ loop:
                spin_lock_irqsave(&d->lock, flags);
                goto loop;
        }
-       aoenet_xmit(skb);
+       if (skb) {
+               struct sk_buff_head queue;
+               __skb_queue_head_init(&queue);
+               __skb_queue_tail(&queue, skb);
+               aoenet_xmit(&queue);
+       }
        aoecmd_cfg(major, minor);
        return 0;
 }
@@ -138,7 +148,7 @@ bail:               spin_unlock_irqrestore(&emsgs_lock, flags);
        spin_unlock_irqrestore(&emsgs_lock, flags);
 
        if (nblocked_emsgs_readers)
-               up(&emsgs_sema);
+               complete(&emsgs_comp);
 }
 
 static ssize_t
@@ -158,6 +168,9 @@ aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp
                break;
        case MINOR_REVALIDATE:
                ret = revalidate(buf, cnt);
+               break;
+       case MINOR_FLUSH:
+               ret = aoedev_flush(buf, cnt);
        }
        if (ret == 0)
                ret = cnt;
@@ -169,12 +182,16 @@ aoechr_open(struct inode *inode, struct file *filp)
 {
        int n, i;
 
+       lock_kernel();
        n = iminor(inode);
        filp->private_data = (void *) (unsigned long) n;
 
        for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
-               if (chardevs[i].minor == n)
+               if (chardevs[i].minor == n) {
+                       unlock_kernel();
                        return 0;
+               }
+       unlock_kernel();
        return -EINVAL;
 }
 
@@ -211,7 +228,7 @@ aoechr_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
 
                spin_unlock_irqrestore(&emsgs_lock, flags);
 
-               n = down_interruptible(&emsgs_sema);
+               n = wait_for_completion_interruptible(&emsgs_comp);
 
                spin_lock_irqsave(&emsgs_lock, flags);
 
@@ -249,6 +266,11 @@ static const struct file_operations aoe_fops = {
        .owner = THIS_MODULE,
 };
 
+static char *aoe_devnode(struct device *dev, mode_t *mode)
+{
+       return kasprintf(GFP_KERNEL, "etherd/%s", dev_name(dev));
+}
+
 int __init
 aoechr_init(void)
 {
@@ -259,16 +281,19 @@ aoechr_init(void)
                printk(KERN_ERR "aoe: can't register char device\n");
                return n;
        }
-       sema_init(&emsgs_sema, 0);
+       init_completion(&emsgs_comp);
        spin_lock_init(&emsgs_lock);
        aoe_class = class_create(THIS_MODULE, "aoe");
        if (IS_ERR(aoe_class)) {
                unregister_chrdev(AOE_MAJOR, "aoechr");
                return PTR_ERR(aoe_class);
        }
+       aoe_class->devnode = aoe_devnode;
+
        for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
                device_create(aoe_class, NULL,
-                             MKDEV(AOE_MAJOR, chardevs[i].minor), chardevs[i].name);
+                             MKDEV(AOE_MAJOR, chardevs[i].minor), NULL,
+                             chardevs[i].name);
 
        return 0;
 }