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_by_aoeaddr(int maj, int min) 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 (d->aoemajor == maj && d->aoeminor == min) 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 = kzalloc(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 break; 114 115 if (d == NULL && (d = aoedev_newdev(bufcnt)) == NULL) { 116 spin_unlock_irqrestore(&devlist_lock, flags); 117 printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n"); 118 return NULL; 119 } /* if newdev, (d->flags & DEVFL_UP) == 0 for below */ 120 121 spin_unlock_irqrestore(&devlist_lock, flags); 122 spin_lock_irqsave(&d->lock, flags); 123 124 d->ifp = ifp; 125 memcpy(d->addr, addr, sizeof d->addr); 126 if ((d->flags & DEVFL_UP) == 0) { 127 aoedev_downdev(d); /* flushes outstanding frames */ 128 d->sysminor = sysminor; 129 d->aoemajor = AOEMAJOR(sysminor); 130 d->aoeminor = AOEMINOR(sysminor); 131 } 132 133 spin_unlock_irqrestore(&d->lock, flags); 134 return d; 135 } 136 137 static void 138 aoedev_freedev(struct aoedev *d) 139 { 140 if (d->gd) { 141 aoedisk_rm_sysfs(d); 142 del_gendisk(d->gd); 143 put_disk(d->gd); 144 } 145 kfree(d->frames); 146 if (d->bufpool) 147 mempool_destroy(d->bufpool); 148 kfree(d); 149 } 150 151 void 152 aoedev_exit(void) 153 { 154 struct aoedev *d; 155 ulong flags; 156 157 flush_scheduled_work(); 158 159 while ((d = devlist)) { 160 devlist = d->next; 161 162 spin_lock_irqsave(&d->lock, flags); 163 aoedev_downdev(d); 164 spin_unlock_irqrestore(&d->lock, flags); 165 166 del_timer_sync(&d->timer); 167 aoedev_freedev(d); 168 } 169 } 170 171 int __init 172 aoedev_init(void) 173 { 174 spin_lock_init(&devlist_lock); 175 return 0; 176 } 177 178