152e112b3ab6b2b35a144565c8ea3bdda1e2845f2Ed L. Cashin/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * aoechr.c 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * AoE character device driver 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hdreg.h> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h> 924879a8e3e68f146d4d85528cc0b5dea712b77c5Matthias Kaehlcke#include <linux/completion.h> 1068e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin#include <linux/delay.h> 115a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 122a48fc0ab24241755dc93bfd4f01d68efab47f5aArnd Bergmann#include <linux/mutex.h> 13e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Miller#include <linux/skbuff.h> 14d5decd3b9512e35c87492312a72443192eebdda9Paul Gortmaker#include <linux/export.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "aoe.h" 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum { 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds //MINOR_STAT = 1, (moved to sysfs) 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MINOR_ERR = 2, 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MINOR_DISCOVER, 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MINOR_INTERFACES, 223ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin MINOR_REVALIDATE, 23262bf54144ebcb78cd0d057d2705dc5fb7bba7acEd L. Cashin MINOR_FLUSH, 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MSGSZ = 2048, 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NMSG = 100, /* message backlog to retain */ 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct aoe_chardev { 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ulong minor; 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char name[32]; 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum { EMFL_VALID = 1 }; 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ErrMsg { 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short flags; 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short len; 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *msg; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 412a48fc0ab24241755dc93bfd4f01d68efab47f5aArnd Bergmannstatic DEFINE_MUTEX(aoechr_mutex); 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct ErrMsg emsgs[NMSG]; 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int emsgs_head_idx, emsgs_tail_idx; 4424879a8e3e68f146d4d85528cc0b5dea712b77c5Matthias Kaehlckestatic struct completion emsgs_comp; 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic spinlock_t emsgs_lock; 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int nblocked_emsgs_readers; 47deb3697037a7d362d13468a73643e09cbc1615a8Greg Kroah-Hartmanstatic struct class *aoe_class; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct aoe_chardev chardevs[] = { 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { MINOR_ERR, "err" }, 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { MINOR_DISCOVER, "discover" }, 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { MINOR_INTERFACES, "interfaces" }, 523ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin { MINOR_REVALIDATE, "revalidate" }, 53262bf54144ebcb78cd0d057d2705dc5fb7bba7acEd L. Cashin { MINOR_FLUSH, "flush" }, 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdiscover(void) 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds aoecmd_cfg(0xffff, 0xff); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsinterfaces(const char __user *str, size_t size) 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (set_aoe_iflist(str, size)) { 67a12c93f08b8fc83b7fcdabaf92b1adcea7489f5eEd L. Cashin printk(KERN_ERR 68a12c93f08b8fc83b7fcdabaf92b1adcea7489f5eEd L. Cashin "aoe: could not set interface list: too many interfaces\n"); 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 743ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashinstatic int 753ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashinrevalidate(const char __user *str, size_t size) 763ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin{ 773ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin int major, minor, n; 783ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin ulong flags; 793ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin struct aoedev *d; 8068e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin struct sk_buff *skb; 813ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin char buf[16]; 823ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin 833ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin if (size >= sizeof buf) 843ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin return -EINVAL; 853ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin buf[sizeof buf - 1] = '\0'; 863ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin if (copy_from_user(buf, str, size)) 873ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin return -EFAULT; 883ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin 893ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin /* should be e%d.%d format */ 903ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin n = sscanf(buf, "e%d.%d", &major, &minor); 913ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin if (n != 2) { 92a12c93f08b8fc83b7fcdabaf92b1adcea7489f5eEd L. Cashin printk(KERN_ERR "aoe: invalid device specification\n"); 933ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin return -EINVAL; 943ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin } 953ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin d = aoedev_by_aoeaddr(major, minor); 963ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin if (!d) 973ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin return -EINVAL; 983ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin spin_lock_irqsave(&d->lock, flags); 9968e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin aoecmd_cleanslate(d); 10068e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashinloop: 10168e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin skb = aoecmd_ata_id(d); 1023ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin spin_unlock_irqrestore(&d->lock, flags); 10368e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin /* try again if we are able to sleep a bit, 10468e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin * otherwise give up this revalidation 10568e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin */ 10668e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin if (!skb && !msleep_interruptible(200)) { 10768e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin spin_lock_irqsave(&d->lock, flags); 10868e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin goto loop; 10968e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin } 110e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Miller if (skb) { 111e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Miller struct sk_buff_head queue; 112e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Miller __skb_queue_head_init(&queue); 113e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Miller __skb_queue_tail(&queue, skb); 114e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Miller aoenet_xmit(&queue); 115e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Miller } 1163ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin aoecmd_cfg(major, minor); 1173ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin return 0; 1183ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin} 1193ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoechr_error(char *msg) 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ErrMsg *em; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *mp; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ulong flags, n; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = strlen(msg); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&emsgs_lock, flags); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds em = emsgs + emsgs_tail_idx; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((em->flags & EMFL_VALID)) { 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsbail: spin_unlock_irqrestore(&emsgs_lock, flags); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mp = kmalloc(n, GFP_ATOMIC); 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mp == NULL) { 139a12c93f08b8fc83b7fcdabaf92b1adcea7489f5eEd L. Cashin printk(KERN_ERR "aoe: allocation failure, len=%ld\n", n); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto bail; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(mp, msg, n); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds em->msg = mp; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds em->flags |= EMFL_VALID; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds em->len = n; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds emsgs_tail_idx++; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds emsgs_tail_idx %= ARRAY_SIZE(emsgs); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&emsgs_lock, flags); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nblocked_emsgs_readers) 15424879a8e3e68f146d4d85528cc0b5dea712b77c5Matthias Kaehlcke complete(&emsgs_comp); 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp) 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -EINVAL; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch ((unsigned long) filp->private_data) { 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 164a12c93f08b8fc83b7fcdabaf92b1adcea7489f5eEd L. Cashin printk(KERN_INFO "aoe: can't write to that file.\n"); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MINOR_DISCOVER: 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = discover(); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case MINOR_INTERFACES: 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = interfaces(buf, cnt); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1723ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin case MINOR_REVALIDATE: 1733ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin ret = revalidate(buf, cnt); 174262bf54144ebcb78cd0d057d2705dc5fb7bba7acEd L. Cashin break; 175262bf54144ebcb78cd0d057d2705dc5fb7bba7acEd L. Cashin case MINOR_FLUSH: 176262bf54144ebcb78cd0d057d2705dc5fb7bba7acEd L. Cashin ret = aoedev_flush(buf, cnt); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret == 0) 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = cnt; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoechr_open(struct inode *inode, struct file *filp) 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int n, i; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1882a48fc0ab24241755dc93bfd4f01d68efab47f5aArnd Bergmann mutex_lock(&aoechr_mutex); 1892017b376c01a54bf7d26ad4f461abe9b5f9064feEric Sesterhenn n = iminor(inode); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds filp->private_data = (void *) (unsigned long) n; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(chardevs); ++i) 193579174a55f491edeaccb8f5d3dc7ad69a17f5423Jonathan Corbet if (chardevs[i].minor == n) { 1942a48fc0ab24241755dc93bfd4f01d68efab47f5aArnd Bergmann mutex_unlock(&aoechr_mutex); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 196579174a55f491edeaccb8f5d3dc7ad69a17f5423Jonathan Corbet } 1972a48fc0ab24241755dc93bfd4f01d68efab47f5aArnd Bergmann mutex_unlock(&aoechr_mutex); 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoechr_rel(struct inode *inode, struct file *filp) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoechr_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off) 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long n; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *mp; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ErrMsg *em; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ssize_t len; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ulong flags; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = (unsigned long) filp->private_data; 217cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin if (n != MINOR_ERR) 218cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin return -EFAULT; 219cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin 220cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin spin_lock_irqsave(&emsgs_lock, flags); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 222cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin for (;;) { 223cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin em = emsgs + emsgs_head_idx; 224cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin if ((em->flags & EMFL_VALID) != 0) 225cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin break; 226cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin if (filp->f_flags & O_NDELAY) { 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&emsgs_lock, flags); 228cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin return -EAGAIN; 229cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin } 230cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin nblocked_emsgs_readers++; 231cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin 232cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin spin_unlock_irqrestore(&emsgs_lock, flags); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23424879a8e3e68f146d4d85528cc0b5dea712b77c5Matthias Kaehlcke n = wait_for_completion_interruptible(&emsgs_comp); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 236cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin spin_lock_irqsave(&emsgs_lock, flags); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 238cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin nblocked_emsgs_readers--; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 240cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin if (n) { 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&emsgs_lock, flags); 242cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin return -ERESTARTSYS; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 244cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin } 245cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin if (em->len > cnt) { 246cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin spin_unlock_irqrestore(&emsgs_lock, flags); 247cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin return -EAGAIN; 248cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin } 249cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin mp = em->msg; 250cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin len = em->len; 251cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin em->msg = NULL; 252cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin em->flags &= ~EMFL_VALID; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 254cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin emsgs_head_idx++; 255cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin emsgs_head_idx %= ARRAY_SIZE(emsgs); 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 257cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin spin_unlock_irqrestore(&emsgs_lock, flags); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 259cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin n = copy_to_user(buf, mp, len); 260cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin kfree(mp); 261cf446f0dbafb5428a551da1c0df8f56316831df8Ed L. Cashin return n == 0 ? len : -EFAULT; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2642b8693c0617e972fc0b2fd1ebf8de97e15b656c3Arjan van de Venstatic const struct file_operations aoe_fops = { 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = aoechr_write, 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read = aoechr_read, 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = aoechr_open, 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = aoechr_rel, 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 2706038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann .llseek = noop_llseek, 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2732c9ede55ecec58099b72e4bb8eab719f32f72c31Al Virostatic char *aoe_devnode(struct device *dev, umode_t *mode) 2741ce8a0d396288f28070483a8190843c23b8282f4Kay Sievers{ 2751ce8a0d396288f28070483a8190843c23b8282f4Kay Sievers return kasprintf(GFP_KERNEL, "etherd/%s", dev_name(dev)); 2761ce8a0d396288f28070483a8190843c23b8282f4Kay Sievers} 2771ce8a0d396288f28070483a8190843c23b8282f4Kay Sievers 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoechr_init(void) 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int n, i; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = register_chrdev(AOE_MAJOR, "aoechr", &aoe_fops); 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n < 0) { 285a12c93f08b8fc83b7fcdabaf92b1adcea7489f5eEd L. Cashin printk(KERN_ERR "aoe: can't register char device\n"); 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return n; 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28824879a8e3e68f146d4d85528cc0b5dea712b77c5Matthias Kaehlcke init_completion(&emsgs_comp); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&emsgs_lock); 290deb3697037a7d362d13468a73643e09cbc1615a8Greg Kroah-Hartman aoe_class = class_create(THIS_MODULE, "aoe"); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(aoe_class)) { 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_chrdev(AOE_MAJOR, "aoechr"); 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PTR_ERR(aoe_class); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 295e454cea20bdcff10ee698d11b8882662a0153a47Kay Sievers aoe_class->devnode = aoe_devnode; 2961ce8a0d396288f28070483a8190843c23b8282f4Kay Sievers 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(chardevs); ++i) 2981ff9f542e5f87c299226557ce5e67a402ed4b502Greg Kroah-Hartman device_create(aoe_class, NULL, 2991ff9f542e5f87c299226557ce5e67a402ed4b502Greg Kroah-Hartman MKDEV(AOE_MAJOR, chardevs[i].minor), NULL, 3001ff9f542e5f87c299226557ce5e67a402ed4b502Greg Kroah-Hartman chardevs[i].name); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoechr_exit(void) 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(chardevs); ++i) 3117ea7ed01ff741918532978b30f6f226ed6f78476Tony Jones device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor)); 312deb3697037a7d362d13468a73643e09cbc1615a8Greg Kroah-Hartman class_destroy(aoe_class); 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_chrdev(AOE_MAJOR, "aoechr"); 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 316