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