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