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