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