1 /* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */ 2 /* 3 * aoedev.c 4 * AoE device utility functions; maintains device list. 5 */ 6 7 #include <linux/hdreg.h> 8 #include <linux/blkdev.h> 9 #include <linux/netdevice.h> 10 #include "aoe.h" 11 12 static struct aoedev *devlist; 13 static spinlock_t devlist_lock; 14 15 struct aoedev * 16 aoedev_bymac(unsigned char *macaddr) 17 { 18 struct aoedev *d; 19 ulong flags; 20 21 spin_lock_irqsave(&devlist_lock, flags); 22 23 for (d=devlist; d; d=d->next) 24 if (!memcmp(d->addr, macaddr, 6)) 25 break; 26 27 spin_unlock_irqrestore(&devlist_lock, flags); 28 return d; 29 } 30 31 /* called with devlist lock held */ 32 static struct aoedev * 33 aoedev_newdev(ulong nframes) 34 { 35 struct aoedev *d; 36 struct frame *f, *e; 37 38 d = kcalloc(1, sizeof *d, GFP_ATOMIC); 39 if (d == NULL) 40 return NULL; 41 f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); 42 if (f == NULL) { 43 kfree(d); 44 return NULL; 45 } 46 47 d->nframes = nframes; 48 d->frames = f; 49 e = f + nframes; 50 for (; f<e; f++) 51 f->tag = FREETAG; 52 53 spin_lock_init(&d->lock); 54 init_timer(&d->timer); 55 d->bufpool = NULL; /* defer to aoeblk_gdalloc */ 56 INIT_LIST_HEAD(&d->bufq); 57 d->next = devlist; 58 devlist = d; 59 60 return d; 61 } 62 63 void 64 aoedev_downdev(struct aoedev *d) 65 { 66 struct frame *f, *e; 67 struct buf *buf; 68 struct bio *bio; 69 70 d->flags |= DEVFL_TKILL; 71 del_timer(&d->timer); 72 73 f = d->frames; 74 e = f + d->nframes; 75 for (; f<e; f->tag = FREETAG, f->buf = NULL, f++) { 76 if (f->tag == FREETAG || f->buf == NULL) 77 continue; 78 buf = f->buf; 79 bio = buf->bio; 80 if (--buf->nframesout == 0) { 81 mempool_free(buf, d->bufpool); 82 bio_endio(bio, bio->bi_size, -EIO); 83 } 84 } 85 d->inprocess = NULL; 86 87 while (!list_empty(&d->bufq)) { 88 buf = container_of(d->bufq.next, struct buf, bufs); 89 list_del(d->bufq.next); 90 bio = buf->bio; 91 mempool_free(buf, d->bufpool); 92 bio_endio(bio, bio->bi_size, -EIO); 93 } 94 95 if (d->nopen) 96 d->flags |= DEVFL_CLOSEWAIT; 97 if (d->gd) 98 d->gd->capacity = 0; 99 100 d->flags &= ~DEVFL_UP; 101 } 102 103 struct aoedev * 104 aoedev_set(ulong sysminor, unsigned char *addr, struct net_device *ifp, ulong bufcnt) 105 { 106 struct aoedev *d; 107 ulong flags; 108 109 spin_lock_irqsave(&devlist_lock, flags); 110 111 for (d=devlist; d; d=d->next) 112 if (d->sysminor == sysminor 113 || memcmp(d->addr, addr, sizeof d->addr) == 0) 114 break; 115 116 if (d == NULL && (d = aoedev_newdev(bufcnt)) == NULL) { 117 spin_unlock_irqrestore(&devlist_lock, flags); 118 printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n"); 119 return NULL; 120 } 121 122 spin_unlock_irqrestore(&devlist_lock, flags); 123 spin_lock_irqsave(&d->lock, flags); 124 125 d->ifp = ifp; 126 127 if (d->sysminor != sysminor 128 || memcmp(d->addr, addr, sizeof d->addr) 129 || (d->flags & DEVFL_UP) == 0) { 130 aoedev_downdev(d); /* flushes outstanding frames */ 131 memcpy(d->addr, addr, sizeof d->addr); 132 d->sysminor = sysminor; 133 d->aoemajor = AOEMAJOR(sysminor); 134 d->aoeminor = AOEMINOR(sysminor); 135 } 136 137 spin_unlock_irqrestore(&d->lock, flags); 138 return d; 139 } 140 141 static void 142 aoedev_freedev(struct aoedev *d) 143 { 144 if (d->gd) { 145 aoedisk_rm_sysfs(d); 146 del_gendisk(d->gd); 147 put_disk(d->gd); 148 } 149 kfree(d->frames); 150 mempool_destroy(d->bufpool); 151 kfree(d); 152 } 153 154 void 155 aoedev_exit(void) 156 { 157 struct aoedev *d; 158 ulong flags; 159 160 flush_scheduled_work(); 161 162 while ((d = devlist)) { 163 devlist = d->next; 164 165 spin_lock_irqsave(&d->lock, flags); 166 aoedev_downdev(d); 167 spin_unlock_irqrestore(&d->lock, flags); 168 169 del_timer_sync(&d->timer); 170 aoedev_freedev(d); 171 } 172 } 173 174 int __init 175 aoedev_init(void) 176 { 177 spin_lock_init(&devlist_lock); 178 return 0; 179 } 180 181