aoe: user can ask driver to forget previously detected devices
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / block / aoe / aoedev.c
blobe26f6f4a28a2992203508b93ead845dfd26162e7
1 /* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
2 /*
3 * aoedev.c
4 * AoE device utility functions; maintains device list.
5 */
7 #include <linux/hdreg.h>
8 #include <linux/blkdev.h>
9 #include <linux/netdevice.h>
10 #include "aoe.h"
12 static void dummy_timer(ulong);
13 static void aoedev_freedev(struct aoedev *);
14 static void freetgt(struct aoetgt *t);
16 static struct aoedev *devlist;
17 static spinlock_t devlist_lock;
19 int
20 aoedev_isbusy(struct aoedev *d)
22 struct aoetgt **t, **te;
23 struct frame *f, *e;
25 t = d->targets;
26 te = t + NTARGETS;
27 for (; t < te && *t; t++) {
28 f = (*t)->frames;
29 e = f + (*t)->nframes;
30 for (; f < e; f++)
31 if (f->tag != FREETAG)
32 return 1;
34 return 0;
37 struct aoedev *
38 aoedev_by_aoeaddr(int maj, int min)
40 struct aoedev *d;
41 ulong flags;
43 spin_lock_irqsave(&devlist_lock, flags);
45 for (d=devlist; d; d=d->next)
46 if (d->aoemajor == maj && d->aoeminor == min)
47 break;
49 spin_unlock_irqrestore(&devlist_lock, flags);
50 return d;
53 static void
54 dummy_timer(ulong vp)
56 struct aoedev *d;
58 d = (struct aoedev *)vp;
59 if (d->flags & DEVFL_TKILL)
60 return;
61 d->timer.expires = jiffies + HZ;
62 add_timer(&d->timer);
65 void
66 aoedev_downdev(struct aoedev *d)
68 struct aoetgt **t, **te;
69 struct frame *f, *e;
70 struct buf *buf;
71 struct bio *bio;
73 t = d->targets;
74 te = t + NTARGETS;
75 for (; t < te && *t; t++) {
76 f = (*t)->frames;
77 e = f + (*t)->nframes;
78 for (; f < e; f->tag = FREETAG, f->buf = NULL, f++) {
79 if (f->tag == FREETAG || f->buf == NULL)
80 continue;
81 buf = f->buf;
82 bio = buf->bio;
83 if (--buf->nframesout == 0
84 && buf != d->inprocess) {
85 mempool_free(buf, d->bufpool);
86 bio_endio(bio, -EIO);
89 (*t)->maxout = (*t)->nframes;
90 (*t)->nout = 0;
92 buf = d->inprocess;
93 if (buf) {
94 bio = buf->bio;
95 mempool_free(buf, d->bufpool);
96 bio_endio(bio, -EIO);
98 d->inprocess = NULL;
99 d->htgt = NULL;
101 while (!list_empty(&d->bufq)) {
102 buf = container_of(d->bufq.next, struct buf, bufs);
103 list_del(d->bufq.next);
104 bio = buf->bio;
105 mempool_free(buf, d->bufpool);
106 bio_endio(bio, -EIO);
109 if (d->gd)
110 d->gd->capacity = 0;
112 d->flags &= ~DEVFL_UP;
115 static void
116 aoedev_freedev(struct aoedev *d)
118 struct aoetgt **t, **e;
120 if (d->gd) {
121 aoedisk_rm_sysfs(d);
122 del_gendisk(d->gd);
123 put_disk(d->gd);
125 t = d->targets;
126 e = t + NTARGETS;
127 for (; t < e && *t; t++)
128 freetgt(*t);
129 if (d->bufpool)
130 mempool_destroy(d->bufpool);
131 kfree(d);
135 aoedev_flush(const char __user *str, size_t cnt)
137 ulong flags;
138 struct aoedev *d, **dd;
139 struct aoedev *rmd = NULL;
140 char buf[16];
141 int all = 0;
143 if (cnt >= 3) {
144 if (cnt > sizeof buf)
145 cnt = sizeof buf;
146 if (copy_from_user(buf, str, cnt))
147 return -EFAULT;
148 all = !strncmp(buf, "all", 3);
151 flush_scheduled_work();
152 spin_lock_irqsave(&devlist_lock, flags);
153 dd = &devlist;
154 while ((d = *dd)) {
155 spin_lock(&d->lock);
156 if ((!all && (d->flags & DEVFL_UP))
157 || (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE))
158 || d->nopen) {
159 spin_unlock(&d->lock);
160 dd = &d->next;
161 continue;
163 *dd = d->next;
164 aoedev_downdev(d);
165 d->flags |= DEVFL_TKILL;
166 spin_unlock(&d->lock);
167 d->next = rmd;
168 rmd = d;
170 spin_unlock_irqrestore(&devlist_lock, flags);
171 while ((d = rmd)) {
172 rmd = d->next;
173 del_timer_sync(&d->timer);
174 aoedev_freedev(d); /* must be able to sleep */
176 return 0;
179 /* find it or malloc it */
180 struct aoedev *
181 aoedev_by_sysminor_m(ulong sysminor)
183 struct aoedev *d;
184 ulong flags;
186 spin_lock_irqsave(&devlist_lock, flags);
188 for (d=devlist; d; d=d->next)
189 if (d->sysminor == sysminor)
190 break;
191 if (d)
192 goto out;
193 d = kcalloc(1, sizeof *d, GFP_ATOMIC);
194 if (!d)
195 goto out;
196 INIT_WORK(&d->work, aoecmd_sleepwork);
197 spin_lock_init(&d->lock);
198 init_timer(&d->timer);
199 d->timer.data = (ulong) d;
200 d->timer.function = dummy_timer;
201 d->timer.expires = jiffies + HZ;
202 add_timer(&d->timer);
203 d->bufpool = NULL; /* defer to aoeblk_gdalloc */
204 d->tgt = d->targets;
205 INIT_LIST_HEAD(&d->bufq);
206 d->sysminor = sysminor;
207 d->aoemajor = AOEMAJOR(sysminor);
208 d->aoeminor = AOEMINOR(sysminor);
209 d->mintimer = MINTIMER;
210 d->next = devlist;
211 devlist = d;
212 out:
213 spin_unlock_irqrestore(&devlist_lock, flags);
214 return d;
217 static void
218 freetgt(struct aoetgt *t)
220 struct frame *f, *e;
222 f = t->frames;
223 e = f + t->nframes;
224 for (; f < e; f++) {
225 skb_shinfo(f->skb)->nr_frags = 0;
226 dev_kfree_skb(f->skb);
228 kfree(t->frames);
229 kfree(t);
232 void
233 aoedev_exit(void)
235 struct aoedev *d;
236 ulong flags;
238 flush_scheduled_work();
240 while ((d = devlist)) {
241 devlist = d->next;
243 spin_lock_irqsave(&d->lock, flags);
244 aoedev_downdev(d);
245 d->flags |= DEVFL_TKILL;
246 spin_unlock_irqrestore(&d->lock, flags);
248 del_timer_sync(&d->timer);
249 aoedev_freedev(d);
253 int __init
254 aoedev_init(void)
256 spin_lock_init(&devlist_lock);
257 return 0;