Commit | Line | Data |
---|---|---|
2611464d | 1 | /* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ |
1da177e4 LT |
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 | ||
3ae1c24e EC |
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 { | |
463c2c12 | 23 | if (f->tag != FREETAG) |
3ae1c24e | 24 | return 1; |
3ae1c24e EC |
25 | } while (++f < e); |
26 | ||
27 | return 0; | |
28 | } | |
29 | ||
1da177e4 | 30 | struct aoedev * |
32465c65 | 31 | aoedev_by_aoeaddr(int maj, int min) |
1da177e4 LT |
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) | |
32465c65 | 39 | if (d->aoemajor == maj && d->aoeminor == min) |
1da177e4 LT |
40 | break; |
41 | ||
42 | spin_unlock_irqrestore(&devlist_lock, flags); | |
43 | return d; | |
44 | } | |
45 | ||
3ae1c24e EC |
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 | ||
1da177e4 LT |
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 | ||
82ca76b6 | 65 | d = kzalloc(sizeof *d, GFP_ATOMIC); |
1da177e4 LT |
66 | if (d == NULL) |
67 | return NULL; | |
68 | f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); | |
69 | if (f == NULL) { | |
70 | kfree(d); | |
71 | return NULL; | |
72 | } | |
73 | ||
3ae1c24e EC |
74 | INIT_WORK(&d->work, aoecmd_sleepwork, d); |
75 | ||
1da177e4 LT |
76 | d->nframes = nframes; |
77 | d->frames = f; | |
78 | e = f + nframes; | |
79 | for (; f<e; f++) | |
80 | f->tag = FREETAG; | |
81 | ||
82 | spin_lock_init(&d->lock); | |
83 | init_timer(&d->timer); | |
3ae1c24e EC |
84 | d->timer.data = (ulong) d; |
85 | d->timer.function = dummy_timer; | |
86 | d->timer.expires = jiffies + HZ; | |
87 | add_timer(&d->timer); | |
1da177e4 LT |
88 | d->bufpool = NULL; /* defer to aoeblk_gdalloc */ |
89 | INIT_LIST_HEAD(&d->bufq); | |
90 | d->next = devlist; | |
91 | devlist = d; | |
92 | ||
93 | return d; | |
94 | } | |
95 | ||
96 | void | |
97 | aoedev_downdev(struct aoedev *d) | |
98 | { | |
99 | struct frame *f, *e; | |
100 | struct buf *buf; | |
101 | struct bio *bio; | |
102 | ||
1da177e4 LT |
103 | f = d->frames; |
104 | e = f + d->nframes; | |
105 | for (; f<e; f->tag = FREETAG, f->buf = NULL, f++) { | |
106 | if (f->tag == FREETAG || f->buf == NULL) | |
107 | continue; | |
108 | buf = f->buf; | |
109 | bio = buf->bio; | |
110 | if (--buf->nframesout == 0) { | |
111 | mempool_free(buf, d->bufpool); | |
112 | bio_endio(bio, bio->bi_size, -EIO); | |
113 | } | |
114 | } | |
115 | d->inprocess = NULL; | |
116 | ||
117 | while (!list_empty(&d->bufq)) { | |
118 | buf = container_of(d->bufq.next, struct buf, bufs); | |
119 | list_del(d->bufq.next); | |
120 | bio = buf->bio; | |
121 | mempool_free(buf, d->bufpool); | |
122 | bio_endio(bio, bio->bi_size, -EIO); | |
123 | } | |
124 | ||
1da177e4 LT |
125 | if (d->gd) |
126 | d->gd->capacity = 0; | |
127 | ||
3ae1c24e | 128 | d->flags &= ~(DEVFL_UP | DEVFL_PAUSE); |
1da177e4 LT |
129 | } |
130 | ||
3ae1c24e | 131 | /* find it or malloc it */ |
1da177e4 | 132 | struct aoedev * |
3ae1c24e | 133 | aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt) |
1da177e4 LT |
134 | { |
135 | struct aoedev *d; | |
136 | ulong flags; | |
137 | ||
138 | spin_lock_irqsave(&devlist_lock, flags); | |
139 | ||
140 | for (d=devlist; d; d=d->next) | |
93d489fc | 141 | if (d->sysminor == sysminor) |
1da177e4 LT |
142 | break; |
143 | ||
3ae1c24e EC |
144 | if (d == NULL) { |
145 | d = aoedev_newdev(bufcnt); | |
146 | if (d == NULL) { | |
147 | spin_unlock_irqrestore(&devlist_lock, flags); | |
148 | printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n"); | |
149 | return NULL; | |
150 | } | |
1da177e4 LT |
151 | d->sysminor = sysminor; |
152 | d->aoemajor = AOEMAJOR(sysminor); | |
153 | d->aoeminor = AOEMINOR(sysminor); | |
154 | } | |
155 | ||
3ae1c24e | 156 | spin_unlock_irqrestore(&devlist_lock, flags); |
1da177e4 LT |
157 | return d; |
158 | } | |
159 | ||
160 | static void | |
161 | aoedev_freedev(struct aoedev *d) | |
162 | { | |
163 | if (d->gd) { | |
164 | aoedisk_rm_sysfs(d); | |
165 | del_gendisk(d->gd); | |
166 | put_disk(d->gd); | |
167 | } | |
168 | kfree(d->frames); | |
03347936 | 169 | if (d->bufpool) |
170 | mempool_destroy(d->bufpool); | |
1da177e4 LT |
171 | kfree(d); |
172 | } | |
173 | ||
174 | void | |
175 | aoedev_exit(void) | |
176 | { | |
177 | struct aoedev *d; | |
178 | ulong flags; | |
179 | ||
180 | flush_scheduled_work(); | |
181 | ||
182 | while ((d = devlist)) { | |
183 | devlist = d->next; | |
184 | ||
185 | spin_lock_irqsave(&d->lock, flags); | |
186 | aoedev_downdev(d); | |
3ae1c24e | 187 | d->flags |= DEVFL_TKILL; |
1da177e4 LT |
188 | spin_unlock_irqrestore(&d->lock, flags); |
189 | ||
190 | del_timer_sync(&d->timer); | |
191 | aoedev_freedev(d); | |
192 | } | |
193 | } | |
194 | ||
195 | int __init | |
196 | aoedev_init(void) | |
197 | { | |
198 | spin_lock_init(&devlist_lock); | |
199 | return 0; | |
200 | } | |
201 |