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