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 int 16 aoedev_isbusy(struct aoedev *d) 17 { 18 struct frame *f, *e; 19 20 f = d->frames; 21 e = f + d->nframes; 22 do { 23 if (f->tag != FREETAG) { 24 printk(KERN_DEBUG "aoe: %ld.%ld isbusy\n", 25 d->aoemajor, d->aoeminor); 26 return 1; 27 } 28 } while (++f < e); 29 30 return 0; 31 } 32 33 struct aoedev * 34 aoedev_by_aoeaddr(int maj, int min) 35 { 36 struct aoedev *d; 37 ulong flags; 38 39 spin_lock_irqsave(&devlist_lock, flags); 40 41 for (d=devlist; d; d=d->next) 42 if (d->aoemajor == maj && d->aoeminor == min) 43 break; 44 45 spin_unlock_irqrestore(&devlist_lock, flags); 46 return d; 47 } 48 49 static void 50 dummy_timer(ulong vp) 51 { 52 struct aoedev *d; 53 54 d = (struct aoedev *)vp; 55 if (d->flags & DEVFL_TKILL) 56 return; 57 d->timer.expires = jiffies + HZ; 58 add_timer(&d->timer); 59 } 60 61 /* called with devlist lock held */ 62 static struct aoedev * 63 aoedev_newdev(ulong nframes) 64 { 65 struct aoedev *d; 66 struct frame *f, *e; 67 68 d = kzalloc(sizeof *d, GFP_ATOMIC); 69 if (d == NULL) 70 return NULL; 71 f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); 72 if (f == NULL) { 73 kfree(d); 74 return NULL; 75 } 76 77 INIT_WORK(&d->work, aoecmd_sleepwork, d); 78 79 d->nframes = nframes; 80 d->frames = f; 81 e = f + nframes; 82 for (; f<e; f++) 83 f->tag = FREETAG; 84 85 spin_lock_init(&d->lock); 86 init_timer(&d->timer); 87 d->timer.data = (ulong) d; 88 d->timer.function = dummy_timer; 89 d->timer.expires = jiffies + HZ; 90 add_timer(&d->timer); 91 d->bufpool = NULL; /* defer to aoeblk_gdalloc */ 92 INIT_LIST_HEAD(&d->bufq); 93 d->next = devlist; 94 devlist = d; 95 96 return d; 97 } 98 99 void 100 aoedev_downdev(struct aoedev *d) 101 { 102 struct frame *f, *e; 103 struct buf *buf; 104 struct bio *bio; 105 106 f = d->frames; 107 e = f + d->nframes; 108 for (; f<e; f->tag = FREETAG, f->buf = NULL, f++) { 109 if (f->tag == FREETAG || f->buf == NULL) 110 continue; 111 buf = f->buf; 112 bio = buf->bio; 113 if (--buf->nframesout == 0) { 114 mempool_free(buf, d->bufpool); 115 bio_endio(bio, bio->bi_size, -EIO); 116 } 117 } 118 d->inprocess = NULL; 119 120 while (!list_empty(&d->bufq)) { 121 buf = container_of(d->bufq.next, struct buf, bufs); 122 list_del(d->bufq.next); 123 bio = buf->bio; 124 mempool_free(buf, d->bufpool); 125 bio_endio(bio, bio->bi_size, -EIO); 126 } 127 128 if (d->gd) 129 d->gd->capacity = 0; 130 131 d->flags &= ~(DEVFL_UP | DEVFL_PAUSE); 132 } 133 134 /* find it or malloc it */ 135 struct aoedev * 136 aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt) 137 { 138 struct aoedev *d; 139 ulong flags; 140 141 spin_lock_irqsave(&devlist_lock, flags); 142 143 for (d=devlist; d; d=d->next) 144 if (d->sysminor == sysminor) 145 break; 146 147 if (d == NULL) { 148 d = aoedev_newdev(bufcnt); 149 if (d == NULL) { 150 spin_unlock_irqrestore(&devlist_lock, flags); 151 printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n"); 152 return NULL; 153 } 154 d->sysminor = sysminor; 155 d->aoemajor = AOEMAJOR(sysminor); 156 d->aoeminor = AOEMINOR(sysminor); 157 } 158 159 spin_unlock_irqrestore(&devlist_lock, flags); 160 return d; 161 } 162 163 static void 164 aoedev_freedev(struct aoedev *d) 165 { 166 if (d->gd) { 167 aoedisk_rm_sysfs(d); 168 del_gendisk(d->gd); 169 put_disk(d->gd); 170 } 171 kfree(d->frames); 172 if (d->bufpool) 173 mempool_destroy(d->bufpool); 174 kfree(d); 175 } 176 177 void 178 aoedev_exit(void) 179 { 180 struct aoedev *d; 181 ulong flags; 182 183 flush_scheduled_work(); 184 185 while ((d = devlist)) { 186 devlist = d->next; 187 188 spin_lock_irqsave(&d->lock, flags); 189 aoedev_downdev(d); 190 d->flags |= DEVFL_TKILL; 191 spin_unlock_irqrestore(&d->lock, flags); 192 193 del_timer_sync(&d->timer); 194 aoedev_freedev(d); 195 } 196 } 197 198 int __init 199 aoedev_init(void) 200 { 201 spin_lock_init(&devlist_lock); 202 return 0; 203 } 204 205