]>
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 | 66 | f = kcalloc(nframes, sizeof *f, GFP_ATOMIC); |
e407a7f6 EC |
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); | |
1da177e4 LT |
89 | return NULL; |
90 | } | |
3ae1c24e | 91 | INIT_WORK(&d->work, aoecmd_sleepwork, d); |
1da177e4 LT |
92 | spin_lock_init(&d->lock); |
93 | init_timer(&d->timer); | |
3ae1c24e EC |
94 | d->timer.data = (ulong) d; |
95 | d->timer.function = dummy_timer; | |
96 | d->timer.expires = jiffies + HZ; | |
97 | add_timer(&d->timer); | |
1da177e4 LT |
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 | ||
1da177e4 LT |
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, bio->bi_size, -EIO); | |
123 | } | |
4f51dc5e | 124 | skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0; |
1da177e4 LT |
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, bio->bi_size, -EIO); | |
134 | } | |
135 | ||
1da177e4 LT |
136 | if (d->gd) |
137 | d->gd->capacity = 0; | |
138 | ||
3ae1c24e | 139 | d->flags &= ~(DEVFL_UP | DEVFL_PAUSE); |
1da177e4 LT |
140 | } |
141 | ||
3ae1c24e | 142 | /* find it or malloc it */ |
1da177e4 | 143 | struct aoedev * |
3ae1c24e | 144 | aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt) |
1da177e4 LT |
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) | |
93d489fc | 152 | if (d->sysminor == sysminor) |
1da177e4 LT |
153 | break; |
154 | ||
3ae1c24e EC |
155 | if (d == NULL) { |
156 | d = aoedev_newdev(bufcnt); | |
157 | if (d == NULL) { | |
158 | spin_unlock_irqrestore(&devlist_lock, flags); | |
a12c93f0 | 159 | printk(KERN_INFO "aoe: aoedev_newdev failure.\n"); |
3ae1c24e EC |
160 | return NULL; |
161 | } | |
1da177e4 LT |
162 | d->sysminor = sysminor; |
163 | d->aoemajor = AOEMAJOR(sysminor); | |
164 | d->aoeminor = AOEMINOR(sysminor); | |
165 | } | |
166 | ||
3ae1c24e | 167 | spin_unlock_irqrestore(&devlist_lock, flags); |
1da177e4 LT |
168 | return d; |
169 | } | |
170 | ||
171 | static void | |
172 | aoedev_freedev(struct aoedev *d) | |
173 | { | |
e407a7f6 EC |
174 | struct frame *f, *e; |
175 | ||
1da177e4 LT |
176 | if (d->gd) { |
177 | aoedisk_rm_sysfs(d); | |
178 | del_gendisk(d->gd); | |
179 | put_disk(d->gd); | |
180 | } | |
e407a7f6 EC |
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 | } | |
1da177e4 | 187 | kfree(d->frames); |
03347936 EC |
188 | if (d->bufpool) |
189 | mempool_destroy(d->bufpool); | |
1da177e4 LT |
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); | |
3ae1c24e | 206 | d->flags |= DEVFL_TKILL; |
1da177e4 LT |
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 |