blob: a4d625aefeaaf1baa1d8a72505d29cd1b2a8ca14 [file] [log] [blame]
Ed L. Cashin26114642006-09-20 14:36:48 -04001/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
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
12static struct aoedev *devlist;
13static spinlock_t devlist_lock;
14
Ed L. Cashin3ae1c242006-01-19 13:46:19 -050015int
16aoedev_isbusy(struct aoedev *d)
17{
Ed L. Cashin68e0d422008-02-08 04:20:00 -080018 struct aoetgt **t, **te;
Ed L. Cashin3ae1c242006-01-19 13:46:19 -050019 struct frame *f, *e;
20
Ed L. Cashin68e0d422008-02-08 04:20:00 -080021 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 }
Ed L. Cashin3ae1c242006-01-19 13:46:19 -050030 return 0;
31}
32
Linus Torvalds1da177e2005-04-16 15:20:36 -070033struct aoedev *
ecashin@coraid.com32465c62005-04-18 22:00:18 -070034aoedev_by_aoeaddr(int maj, int min)
Linus Torvalds1da177e2005-04-16 15:20:36 -070035{
36 struct aoedev *d;
37 ulong flags;
38
39 spin_lock_irqsave(&devlist_lock, flags);
40
41 for (d=devlist; d; d=d->next)
ecashin@coraid.com32465c62005-04-18 22:00:18 -070042 if (d->aoemajor == maj && d->aoeminor == min)
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 break;
44
45 spin_unlock_irqrestore(&devlist_lock, flags);
46 return d;
47}
48
Ed L. Cashin3ae1c242006-01-19 13:46:19 -050049static void
50dummy_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
Linus Torvalds1da177e2005-04-16 15:20:36 -070061void
62aoedev_downdev(struct aoedev *d)
63{
Ed L. Cashin68e0d422008-02-08 04:20:00 -080064 struct aoetgt **t, **te;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 struct frame *f, *e;
66 struct buf *buf;
67 struct bio *bio;
68
Ed L. Cashin68e0d422008-02-08 04:20:00 -080069 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -080085 (*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);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 }
94 d->inprocess = NULL;
Ed L. Cashin68e0d422008-02-08 04:20:00 -080095 d->htgt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
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);
NeilBrown6712ecf2007-09-27 12:47:43 +0200102 bio_endio(bio, -EIO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 }
104
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 if (d->gd)
106 d->gd->capacity = 0;
107
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800108 d->flags &= ~DEVFL_UP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109}
110
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500111/* find it or malloc it */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112struct aoedev *
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800113aoedev_by_sysminor_m(ulong sysminor)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
115 struct aoedev *d;
116 ulong flags;
117
118 spin_lock_irqsave(&devlist_lock, flags);
119
120 for (d=devlist; d; d=d->next)
Ed L Cashin93d489f2005-04-29 10:24:22 -0400121 if (d->sysminor == sysminor)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 break;
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800123 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:
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500145 spin_unlock_irqrestore(&devlist_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return d;
147}
148
149static void
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800150freetgt(struct aoetgt *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151{
Ed L. Cashine407a7f2006-09-20 14:36:49 -0400152 struct frame *f, *e;
153
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800154 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
164static void
165aoedev_freedev(struct aoedev *d)
166{
167 struct aoetgt **t, **e;
168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 if (d->gd) {
170 aoedisk_rm_sysfs(d);
171 del_gendisk(d->gd);
172 put_disk(d->gd);
173 }
Ed L. Cashin68e0d422008-02-08 04:20:00 -0800174 t = d->targets;
175 e = t + NTARGETS;
176 for (; t < e && *t; t++)
177 freetgt(*t);
ecashin@coraid.com03347932005-04-18 22:00:19 -0700178 if (d->bufpool)
179 mempool_destroy(d->bufpool);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 kfree(d);
181}
182
183void
184aoedev_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);
Ed L. Cashin3ae1c242006-01-19 13:46:19 -0500196 d->flags |= DEVFL_TKILL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 spin_unlock_irqrestore(&d->lock, flags);
198
199 del_timer_sync(&d->timer);
200 aoedev_freedev(d);
201 }
202}
203
204int __init
205aoedev_init(void)
206{
207 spin_lock_init(&devlist_lock);
208 return 0;
209}
210