aoe: handle multiple network paths to AoE device
[safe/jmp/linux-2.6] / drivers / block / aoe / aoedev.c
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 aoetgt **t, **te;
19         struct frame *f, *e;
20
21         t = d->targets;
22         te = t + NTARGETS;
23         for (; t < te && *t; t++) {
24                 f = (*t)->frames;
25                 e = f + (*t)->nframes;
26                 for (; f < e; f++)
27                         if (f->tag != FREETAG)
28                                 return 1;
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 void
62 aoedev_downdev(struct aoedev *d)
63 {
64         struct aoetgt **t, **te;
65         struct frame *f, *e;
66         struct buf *buf;
67         struct bio *bio;
68
69         t = d->targets;
70         te = t + NTARGETS;
71         for (; t < te && *t; t++) {
72                 f = (*t)->frames;
73                 e = f + (*t)->nframes;
74                 for (; f < e; f->tag = FREETAG, f->buf = NULL, f++) {
75                         if (f->tag == FREETAG || f->buf == NULL)
76                                 continue;
77                         buf = f->buf;
78                         bio = buf->bio;
79                         if (--buf->nframesout == 0
80                         && buf != d->inprocess) {
81                                 mempool_free(buf, d->bufpool);
82                                 bio_endio(bio, -EIO);
83                         }
84                 }
85                 (*t)->maxout = (*t)->nframes;
86                 (*t)->nout = 0;
87         }
88         buf = d->inprocess;
89         if (buf) {
90                 bio = buf->bio;
91                 mempool_free(buf, d->bufpool);
92                 bio_endio(bio, -EIO);
93         }
94         d->inprocess = NULL;
95         d->htgt = NULL;
96
97         while (!list_empty(&d->bufq)) {
98                 buf = container_of(d->bufq.next, struct buf, bufs);
99                 list_del(d->bufq.next);
100                 bio = buf->bio;
101                 mempool_free(buf, d->bufpool);
102                 bio_endio(bio, -EIO);
103         }
104
105         if (d->gd)
106                 d->gd->capacity = 0;
107
108         d->flags &= ~DEVFL_UP;
109 }
110
111 /* find it or malloc it */
112 struct aoedev *
113 aoedev_by_sysminor_m(ulong sysminor)
114 {
115         struct aoedev *d;
116         ulong flags;
117
118         spin_lock_irqsave(&devlist_lock, flags);
119
120         for (d=devlist; d; d=d->next)
121                 if (d->sysminor == sysminor)
122                         break;
123         if (d)
124                 goto out;
125         d = kcalloc(1, sizeof *d, GFP_ATOMIC);
126         if (!d)
127                 goto out;
128         INIT_WORK(&d->work, aoecmd_sleepwork);
129         spin_lock_init(&d->lock);
130         init_timer(&d->timer);
131         d->timer.data = (ulong) d;
132         d->timer.function = dummy_timer;
133         d->timer.expires = jiffies + HZ;
134         add_timer(&d->timer);
135         d->bufpool = NULL;      /* defer to aoeblk_gdalloc */
136         d->tgt = d->targets;
137         INIT_LIST_HEAD(&d->bufq);
138         d->sysminor = sysminor;
139         d->aoemajor = AOEMAJOR(sysminor);
140         d->aoeminor = AOEMINOR(sysminor);
141         d->mintimer = MINTIMER;
142         d->next = devlist;
143         devlist = d;
144  out:
145         spin_unlock_irqrestore(&devlist_lock, flags);
146         return d;
147 }
148
149 static void
150 freetgt(struct aoetgt *t)
151 {
152         struct frame *f, *e;
153
154         f = t->frames;
155         e = f + t->nframes;
156         for (; f < e; f++) {
157                 skb_shinfo(f->skb)->nr_frags = 0;
158                 dev_kfree_skb(f->skb);
159         }
160         kfree(t->frames);
161         kfree(t);
162 }
163
164 static void
165 aoedev_freedev(struct aoedev *d)
166 {
167         struct aoetgt **t, **e;
168
169         if (d->gd) {
170                 aoedisk_rm_sysfs(d);
171                 del_gendisk(d->gd);
172                 put_disk(d->gd);
173         }
174         t = d->targets;
175         e = t + NTARGETS;
176         for (; t < e && *t; t++)
177                 freetgt(*t);
178         if (d->bufpool)
179                 mempool_destroy(d->bufpool);
180         kfree(d);
181 }
182
183 void
184 aoedev_exit(void)
185 {
186         struct aoedev *d;
187         ulong flags;
188
189         flush_scheduled_work();
190
191         while ((d = devlist)) {
192                 devlist = d->next;
193
194                 spin_lock_irqsave(&d->lock, flags);
195                 aoedev_downdev(d);
196                 d->flags |= DEVFL_TKILL;
197                 spin_unlock_irqrestore(&d->lock, flags);
198
199                 del_timer_sync(&d->timer);
200                 aoedev_freedev(d);
201         }
202 }
203
204 int __init
205 aoedev_init(void)
206 {
207         spin_lock_init(&devlist_lock);
208         return 0;
209 }
210