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