1/* Copyright (c) 2012 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 <linux/completion.h>
10#include <linux/delay.h>
11#include <linux/slab.h>
12#include <linux/mutex.h>
13#include <linux/skbuff.h>
14#include <linux/export.h>
15#include "aoe.h"
16
17enum {
18	//MINOR_STAT = 1, (moved to sysfs)
19	MINOR_ERR = 2,
20	MINOR_DISCOVER,
21	MINOR_INTERFACES,
22	MINOR_REVALIDATE,
23	MINOR_FLUSH,
24	MSGSZ = 2048,
25	NMSG = 100,		/* message backlog to retain */
26};
27
28struct aoe_chardev {
29	ulong minor;
30	char name[32];
31};
32
33enum { EMFL_VALID = 1 };
34
35struct ErrMsg {
36	short flags;
37	short len;
38	char *msg;
39};
40
41static DEFINE_MUTEX(aoechr_mutex);
42
43/* A ring buffer of error messages, to be read through
44 * "/dev/etherd/err".  When no messages are present,
45 * readers will block waiting for messages to appear.
46 */
47static struct ErrMsg emsgs[NMSG];
48static int emsgs_head_idx, emsgs_tail_idx;
49static struct completion emsgs_comp;
50static spinlock_t emsgs_lock;
51static int nblocked_emsgs_readers;
52
53static struct aoe_chardev chardevs[] = {
54	{ MINOR_ERR, "err" },
55	{ MINOR_DISCOVER, "discover" },
56	{ MINOR_INTERFACES, "interfaces" },
57	{ MINOR_REVALIDATE, "revalidate" },
58	{ MINOR_FLUSH, "flush" },
59};
60
61static char *aoe_devnode(const struct device *dev, umode_t *mode)
62{
63	return kasprintf(GFP_KERNEL, "etherd/%s", dev_name(dev));
64}
65
66static const struct class aoe_class = {
67	.name = "aoe",
68	.devnode = aoe_devnode,
69};
70
71static int
72discover(void)
73{
74	aoecmd_cfg(0xffff, 0xff);
75	return 0;
76}
77
78static int
79interfaces(const char __user *str, size_t size)
80{
81	if (set_aoe_iflist(str, size)) {
82		printk(KERN_ERR
83			"aoe: could not set interface list: too many interfaces\n");
84		return -EINVAL;
85	}
86	return 0;
87}
88
89static int
90revalidate(const char __user *str, size_t size)
91{
92	int major, minor, n;
93	ulong flags;
94	struct aoedev *d;
95	struct sk_buff *skb;
96	char buf[16];
97
98	if (size >= sizeof buf)
99		return -EINVAL;
100	buf[sizeof buf - 1] = '\0';
101	if (copy_from_user(buf, str, size))
102		return -EFAULT;
103
104	n = sscanf(buf, "e%d.%d", &major, &minor);
105	if (n != 2) {
106		pr_err("aoe: invalid device specification %s\n", buf);
107		return -EINVAL;
108	}
109	d = aoedev_by_aoeaddr(major, minor, 0);
110	if (!d)
111		return -EINVAL;
112	spin_lock_irqsave(&d->lock, flags);
113	aoecmd_cleanslate(d);
114	aoecmd_cfg(major, minor);
115loop:
116	skb = aoecmd_ata_id(d);
117	spin_unlock_irqrestore(&d->lock, flags);
118	/* try again if we are able to sleep a bit,
119	 * otherwise give up this revalidation
120	 */
121	if (!skb && !msleep_interruptible(250)) {
122		spin_lock_irqsave(&d->lock, flags);
123		goto loop;
124	}
125	aoedev_put(d);
126	if (skb) {
127		struct sk_buff_head queue;
128		__skb_queue_head_init(&queue);
129		__skb_queue_tail(&queue, skb);
130		aoenet_xmit(&queue);
131	}
132	return 0;
133}
134
135void
136aoechr_error(char *msg)
137{
138	struct ErrMsg *em;
139	char *mp;
140	ulong flags, n;
141
142	n = strlen(msg);
143
144	spin_lock_irqsave(&emsgs_lock, flags);
145
146	em = emsgs + emsgs_tail_idx;
147	if ((em->flags & EMFL_VALID)) {
148bail:		spin_unlock_irqrestore(&emsgs_lock, flags);
149		return;
150	}
151
152	mp = kmemdup(msg, n, GFP_ATOMIC);
153	if (!mp)
154		goto bail;
155
156	em->msg = mp;
157	em->flags |= EMFL_VALID;
158	em->len = n;
159
160	emsgs_tail_idx++;
161	emsgs_tail_idx %= ARRAY_SIZE(emsgs);
162
163	spin_unlock_irqrestore(&emsgs_lock, flags);
164
165	if (nblocked_emsgs_readers)
166		complete(&emsgs_comp);
167}
168
169static ssize_t
170aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp)
171{
172	int ret = -EINVAL;
173
174	switch ((unsigned long) filp->private_data) {
175	default:
176		printk(KERN_INFO "aoe: can't write to that file.\n");
177		break;
178	case MINOR_DISCOVER:
179		ret = discover();
180		break;
181	case MINOR_INTERFACES:
182		ret = interfaces(buf, cnt);
183		break;
184	case MINOR_REVALIDATE:
185		ret = revalidate(buf, cnt);
186		break;
187	case MINOR_FLUSH:
188		ret = aoedev_flush(buf, cnt);
189		break;
190	}
191	if (ret == 0)
192		ret = cnt;
193	return ret;
194}
195
196static int
197aoechr_open(struct inode *inode, struct file *filp)
198{
199	int n, i;
200
201	mutex_lock(&aoechr_mutex);
202	n = iminor(inode);
203	filp->private_data = (void *) (unsigned long) n;
204
205	for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
206		if (chardevs[i].minor == n) {
207			mutex_unlock(&aoechr_mutex);
208			return 0;
209		}
210	mutex_unlock(&aoechr_mutex);
211	return -EINVAL;
212}
213
214static int
215aoechr_rel(struct inode *inode, struct file *filp)
216{
217	return 0;
218}
219
220static ssize_t
221aoechr_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
222{
223	unsigned long n;
224	char *mp;
225	struct ErrMsg *em;
226	ssize_t len;
227	ulong flags;
228
229	n = (unsigned long) filp->private_data;
230	if (n != MINOR_ERR)
231		return -EFAULT;
232
233	spin_lock_irqsave(&emsgs_lock, flags);
234
235	for (;;) {
236		em = emsgs + emsgs_head_idx;
237		if ((em->flags & EMFL_VALID) != 0)
238			break;
239		if (filp->f_flags & O_NDELAY) {
240			spin_unlock_irqrestore(&emsgs_lock, flags);
241			return -EAGAIN;
242		}
243		nblocked_emsgs_readers++;
244
245		spin_unlock_irqrestore(&emsgs_lock, flags);
246
247		n = wait_for_completion_interruptible(&emsgs_comp);
248
249		spin_lock_irqsave(&emsgs_lock, flags);
250
251		nblocked_emsgs_readers--;
252
253		if (n) {
254			spin_unlock_irqrestore(&emsgs_lock, flags);
255			return -ERESTARTSYS;
256		}
257	}
258	if (em->len > cnt) {
259		spin_unlock_irqrestore(&emsgs_lock, flags);
260		return -EAGAIN;
261	}
262	mp = em->msg;
263	len = em->len;
264	em->msg = NULL;
265	em->flags &= ~EMFL_VALID;
266
267	emsgs_head_idx++;
268	emsgs_head_idx %= ARRAY_SIZE(emsgs);
269
270	spin_unlock_irqrestore(&emsgs_lock, flags);
271
272	n = copy_to_user(buf, mp, len);
273	kfree(mp);
274	return n == 0 ? len : -EFAULT;
275}
276
277static const struct file_operations aoe_fops = {
278	.write = aoechr_write,
279	.read = aoechr_read,
280	.open = aoechr_open,
281	.release = aoechr_rel,
282	.owner = THIS_MODULE,
283	.llseek = noop_llseek,
284};
285
286int __init
287aoechr_init(void)
288{
289	int n, i;
290
291	n = register_chrdev(AOE_MAJOR, "aoechr", &aoe_fops);
292	if (n < 0) {
293		printk(KERN_ERR "aoe: can't register char device\n");
294		return n;
295	}
296	init_completion(&emsgs_comp);
297	spin_lock_init(&emsgs_lock);
298	n = class_register(&aoe_class);
299	if (n) {
300		unregister_chrdev(AOE_MAJOR, "aoechr");
301		return n;
302	}
303
304	for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
305		device_create(&aoe_class, NULL,
306			      MKDEV(AOE_MAJOR, chardevs[i].minor), NULL,
307			      chardevs[i].name);
308
309	return 0;
310}
311
312void
313aoechr_exit(void)
314{
315	int i;
316
317	for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
318		device_destroy(&aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
319	class_unregister(&aoe_class);
320	unregister_chrdev(AOE_MAJOR, "aoechr");
321}
322
323