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