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  
17  enum {
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  
28  struct aoe_chardev {
29  	ulong minor;
30  	char name[32];
31  };
32  
33  enum { EMFL_VALID = 1 };
34  
35  struct ErrMsg {
36  	short flags;
37  	short len;
38  	char *msg;
39  };
40  
41  static 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   */
47  static struct ErrMsg emsgs[NMSG];
48  static int emsgs_head_idx, emsgs_tail_idx;
49  static struct completion emsgs_comp;
50  static spinlock_t emsgs_lock;
51  static int nblocked_emsgs_readers;
52  
53  static 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  
aoe_devnode(const struct device * dev,umode_t * mode)61  static char *aoe_devnode(const struct device *dev, umode_t *mode)
62  {
63  	return kasprintf(GFP_KERNEL, "etherd/%s", dev_name(dev));
64  }
65  
66  static const struct class aoe_class = {
67  	.name = "aoe",
68  	.devnode = aoe_devnode,
69  };
70  
71  static int
discover(void)72  discover(void)
73  {
74  	aoecmd_cfg(0xffff, 0xff);
75  	return 0;
76  }
77  
78  static int
interfaces(const char __user * str,size_t size)79  interfaces(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  
89  static int
revalidate(const char __user * str,size_t size)90  revalidate(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);
115  loop:
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  
135  void
aoechr_error(char * msg)136  aoechr_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)) {
148  bail:		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  
169  static ssize_t
aoechr_write(struct file * filp,const char __user * buf,size_t cnt,loff_t * offp)170  aoechr_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  
196  static int
aoechr_open(struct inode * inode,struct file * filp)197  aoechr_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  
214  static int
aoechr_rel(struct inode * inode,struct file * filp)215  aoechr_rel(struct inode *inode, struct file *filp)
216  {
217  	return 0;
218  }
219  
220  static ssize_t
aoechr_read(struct file * filp,char __user * buf,size_t cnt,loff_t * off)221  aoechr_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  
277  static 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  
286  int __init
aoechr_init(void)287  aoechr_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  
312  void
aoechr_exit(void)313  aoechr_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