aoe: remove unused NARGS enum
[linux-2.6.git] / drivers / block / aoe / aoechr.c
1 /* Copyright (c) 2006 Coraid, Inc.  See COPYING for GPL terms. */
2 /*
3  * aoechr.c
4  * AoE character device driver
5  */
6
7 #include <linux/hdreg.h>
8 #include <linux/blkdev.h>
9 #include "aoe.h"
10
11 enum {
12         //MINOR_STAT = 1, (moved to sysfs)
13         MINOR_ERR = 2,
14         MINOR_DISCOVER,
15         MINOR_INTERFACES,
16         MINOR_REVALIDATE,
17         MSGSZ = 2048,
18         NMSG = 100,             /* message backlog to retain */
19 };
20
21 struct aoe_chardev {
22         ulong minor;
23         char name[32];
24 };
25
26 enum { EMFL_VALID = 1 };
27
28 struct ErrMsg {
29         short flags;
30         short len;
31         char *msg;
32 };
33
34 static struct ErrMsg emsgs[NMSG];
35 static int emsgs_head_idx, emsgs_tail_idx;
36 static struct semaphore emsgs_sema;
37 static spinlock_t emsgs_lock;
38 static int nblocked_emsgs_readers;
39 static struct class *aoe_class;
40 static struct aoe_chardev chardevs[] = {
41         { MINOR_ERR, "err" },
42         { MINOR_DISCOVER, "discover" },
43         { MINOR_INTERFACES, "interfaces" },
44         { MINOR_REVALIDATE, "revalidate" },
45 };
46
47 static int
48 discover(void)
49 {
50         aoecmd_cfg(0xffff, 0xff);
51         return 0;
52 }
53
54 static int
55 interfaces(const char __user *str, size_t size)
56 {
57         if (set_aoe_iflist(str, size)) {
58                 printk(KERN_CRIT
59                        "%s: could not set interface list: %s\n",
60                        __FUNCTION__, "too many interfaces");
61                 return -EINVAL;
62         }
63         return 0;
64 }
65
66 static int
67 revalidate(const char __user *str, size_t size)
68 {
69         int major, minor, n;
70         ulong flags;
71         struct aoedev *d;
72         char buf[16];
73
74         if (size >= sizeof buf)
75                 return -EINVAL;
76         buf[sizeof buf - 1] = '\0';
77         if (copy_from_user(buf, str, size))
78                 return -EFAULT;
79
80         /* should be e%d.%d format */
81         n = sscanf(buf, "e%d.%d", &major, &minor);
82         if (n != 2) {
83                 printk(KERN_ERR "aoe: %s: invalid device specification\n",
84                         __FUNCTION__);
85                 return -EINVAL;
86         }
87         d = aoedev_by_aoeaddr(major, minor);
88         if (!d)
89                 return -EINVAL;
90
91         spin_lock_irqsave(&d->lock, flags);
92         d->flags |= DEVFL_PAUSE;
93         spin_unlock_irqrestore(&d->lock, flags);
94         aoecmd_cfg(major, minor);
95
96         return 0;
97 }
98
99 void
100 aoechr_error(char *msg)
101 {
102         struct ErrMsg *em;
103         char *mp;
104         ulong flags, n;
105
106         n = strlen(msg);
107
108         spin_lock_irqsave(&emsgs_lock, flags);
109
110         em = emsgs + emsgs_tail_idx;
111         if ((em->flags & EMFL_VALID)) {
112 bail:           spin_unlock_irqrestore(&emsgs_lock, flags);
113                 return;
114         }
115
116         mp = kmalloc(n, GFP_ATOMIC);
117         if (mp == NULL) {
118                 printk(KERN_CRIT "aoe: aoechr_error: allocation failure, len=%ld\n", n);
119                 goto bail;
120         }
121
122         memcpy(mp, msg, n);
123         em->msg = mp;
124         em->flags |= EMFL_VALID;
125         em->len = n;
126
127         emsgs_tail_idx++;
128         emsgs_tail_idx %= ARRAY_SIZE(emsgs);
129
130         spin_unlock_irqrestore(&emsgs_lock, flags);
131
132         if (nblocked_emsgs_readers)
133                 up(&emsgs_sema);
134 }
135
136 static ssize_t
137 aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp)
138 {
139         int ret = -EINVAL;
140
141         switch ((unsigned long) filp->private_data) {
142         default:
143                 printk(KERN_INFO "aoe: aoechr_write: can't write to that file.\n");
144                 break;
145         case MINOR_DISCOVER:
146                 ret = discover();
147                 break;
148         case MINOR_INTERFACES:
149                 ret = interfaces(buf, cnt);
150                 break;
151         case MINOR_REVALIDATE:
152                 ret = revalidate(buf, cnt);
153         }
154         if (ret == 0)
155                 ret = cnt;
156         return ret;
157 }
158
159 static int
160 aoechr_open(struct inode *inode, struct file *filp)
161 {
162         int n, i;
163
164         n = iminor(inode);
165         filp->private_data = (void *) (unsigned long) n;
166
167         for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
168                 if (chardevs[i].minor == n)
169                         return 0;
170         return -EINVAL;
171 }
172
173 static int
174 aoechr_rel(struct inode *inode, struct file *filp)
175 {
176         return 0;
177 }
178
179 static ssize_t
180 aoechr_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
181 {
182         unsigned long n;
183         char *mp;
184         struct ErrMsg *em;
185         ssize_t len;
186         ulong flags;
187
188         n = (unsigned long) filp->private_data;
189         switch (n) {
190         case MINOR_ERR:
191                 spin_lock_irqsave(&emsgs_lock, flags);
192 loop:
193                 em = emsgs + emsgs_head_idx;
194                 if ((em->flags & EMFL_VALID) == 0) {
195                         if (filp->f_flags & O_NDELAY) {
196                                 spin_unlock_irqrestore(&emsgs_lock, flags);
197                                 return -EAGAIN;
198                         }
199                         nblocked_emsgs_readers++;
200
201                         spin_unlock_irqrestore(&emsgs_lock, flags);
202
203                         n = down_interruptible(&emsgs_sema);
204
205                         spin_lock_irqsave(&emsgs_lock, flags);
206
207                         nblocked_emsgs_readers--;
208
209                         if (n) {
210                                 spin_unlock_irqrestore(&emsgs_lock, flags);
211                                 return -ERESTARTSYS;
212                         }
213                         goto loop;
214                 }
215                 if (em->len > cnt) {
216                         spin_unlock_irqrestore(&emsgs_lock, flags);
217                         return -EAGAIN;
218                 }
219                 mp = em->msg;
220                 len = em->len;
221                 em->msg = NULL;
222                 em->flags &= ~EMFL_VALID;
223
224                 emsgs_head_idx++;
225                 emsgs_head_idx %= ARRAY_SIZE(emsgs);
226
227                 spin_unlock_irqrestore(&emsgs_lock, flags);
228
229                 n = copy_to_user(buf, mp, len);
230                 kfree(mp);
231                 return n == 0 ? len : -EFAULT;
232         default:
233                 return -EFAULT;
234         }
235 }
236
237 static struct file_operations aoe_fops = {
238         .write = aoechr_write,
239         .read = aoechr_read,
240         .open = aoechr_open,
241         .release = aoechr_rel,
242         .owner = THIS_MODULE,
243 };
244
245 int __init
246 aoechr_init(void)
247 {
248         int n, i;
249
250         n = register_chrdev(AOE_MAJOR, "aoechr", &aoe_fops);
251         if (n < 0) { 
252                 printk(KERN_ERR "aoe: aoechr_init: can't register char device\n");
253                 return n;
254         }
255         sema_init(&emsgs_sema, 0);
256         spin_lock_init(&emsgs_lock);
257         aoe_class = class_create(THIS_MODULE, "aoe");
258         if (IS_ERR(aoe_class)) {
259                 unregister_chrdev(AOE_MAJOR, "aoechr");
260                 return PTR_ERR(aoe_class);
261         }
262         for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
263                 class_device_create(aoe_class, NULL,
264                                         MKDEV(AOE_MAJOR, chardevs[i].minor),
265                                         NULL, chardevs[i].name);
266
267         return 0;
268 }
269
270 void
271 aoechr_exit(void)
272 {
273         int i;
274
275         for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
276                 class_device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
277         class_destroy(aoe_class);
278         unregister_chrdev(AOE_MAJOR, "aoechr");
279 }
280