Merge branches 'irq-core-for-linus' and 'core-locking-for-linus' of git://git.kernel...
[deliverable/linux.git] / drivers / block / aoe / aoeblk.c
CommitLineData
52e112b3 1/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */
1da177e4
LT
2/*
3 * aoeblk.c
4 * block device routines
5 */
6
027b180d 7#include <linux/kernel.h>
1da177e4
LT
8#include <linux/hdreg.h>
9#include <linux/blkdev.h>
43cbe2cb 10#include <linux/backing-dev.h>
1da177e4
LT
11#include <linux/fs.h>
12#include <linux/ioctl.h>
5a0e3ad6 13#include <linux/slab.h>
027b180d 14#include <linux/ratelimit.h>
1da177e4
LT
15#include <linux/genhd.h>
16#include <linux/netdevice.h>
2a48fc0a 17#include <linux/mutex.h>
1da177e4
LT
18#include "aoe.h"
19
2a48fc0a 20static DEFINE_MUTEX(aoeblk_mutex);
e18b890b 21static struct kmem_cache *buf_pool_cache;
1da177e4 22
edfaa7c3
KS
23static ssize_t aoedisk_show_state(struct device *dev,
24 struct device_attribute *attr, char *page)
1da177e4 25{
edfaa7c3 26 struct gendisk *disk = dev_to_disk(dev);
1da177e4
LT
27 struct aoedev *d = disk->private_data;
28
29 return snprintf(page, PAGE_SIZE,
30 "%s%s\n",
31 (d->flags & DEVFL_UP) ? "up" : "down",
68e0d42f 32 (d->flags & DEVFL_KICKME) ? ",kickme" :
3ae1c24e
EC
33 (d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : "");
34 /* I'd rather see nopen exported so we can ditch closewait */
1da177e4 35}
edfaa7c3
KS
36static ssize_t aoedisk_show_mac(struct device *dev,
37 struct device_attribute *attr, char *page)
1da177e4 38{
edfaa7c3 39 struct gendisk *disk = dev_to_disk(dev);
1da177e4 40 struct aoedev *d = disk->private_data;
68e0d42f 41 struct aoetgt *t = d->targets[0];
1da177e4 42
68e0d42f
EC
43 if (t == NULL)
44 return snprintf(page, PAGE_SIZE, "none\n");
411c41ee 45 return snprintf(page, PAGE_SIZE, "%pm\n", t->addr);
1da177e4 46}
edfaa7c3
KS
47static ssize_t aoedisk_show_netif(struct device *dev,
48 struct device_attribute *attr, char *page)
1da177e4 49{
edfaa7c3 50 struct gendisk *disk = dev_to_disk(dev);
1da177e4 51 struct aoedev *d = disk->private_data;
68e0d42f
EC
52 struct net_device *nds[8], **nd, **nnd, **ne;
53 struct aoetgt **t, **te;
54 struct aoeif *ifp, *e;
55 char *p;
56
57 memset(nds, 0, sizeof nds);
58 nd = nds;
59 ne = nd + ARRAY_SIZE(nds);
60 t = d->targets;
61 te = t + NTARGETS;
62 for (; t < te && *t; t++) {
63 ifp = (*t)->ifs;
64 e = ifp + NAOEIFS;
65 for (; ifp < e && ifp->nd; ifp++) {
66 for (nnd = nds; nnd < nd; nnd++)
67 if (*nnd == ifp->nd)
68 break;
69 if (nnd == nd && nd != ne)
70 *nd++ = ifp->nd;
71 }
72 }
1da177e4 73
68e0d42f
EC
74 ne = nd;
75 nd = nds;
76 if (*nd == NULL)
77 return snprintf(page, PAGE_SIZE, "none\n");
78 for (p = page; nd < ne; nd++)
79 p += snprintf(p, PAGE_SIZE - (p-page), "%s%s",
80 p == page ? "" : ",", (*nd)->name);
81 p += snprintf(p, PAGE_SIZE - (p-page), "\n");
82 return p-page;
1da177e4 83}
4613ed27 84/* firmware version */
edfaa7c3
KS
85static ssize_t aoedisk_show_fwver(struct device *dev,
86 struct device_attribute *attr, char *page)
4613ed27 87{
edfaa7c3 88 struct gendisk *disk = dev_to_disk(dev);
4613ed27
EC
89 struct aoedev *d = disk->private_data;
90
91 return snprintf(page, PAGE_SIZE, "0x%04x\n", (unsigned int) d->fw_ver);
92}
1da177e4 93
edfaa7c3
KS
94static DEVICE_ATTR(state, S_IRUGO, aoedisk_show_state, NULL);
95static DEVICE_ATTR(mac, S_IRUGO, aoedisk_show_mac, NULL);
96static DEVICE_ATTR(netif, S_IRUGO, aoedisk_show_netif, NULL);
97static struct device_attribute dev_attr_firmware_version = {
01e8ef11 98 .attr = { .name = "firmware-version", .mode = S_IRUGO },
edfaa7c3 99 .show = aoedisk_show_fwver,
4613ed27 100};
1da177e4 101
4ca5224f 102static struct attribute *aoe_attrs[] = {
edfaa7c3
KS
103 &dev_attr_state.attr,
104 &dev_attr_mac.attr,
105 &dev_attr_netif.attr,
106 &dev_attr_firmware_version.attr,
107 NULL,
4ca5224f
GKH
108};
109
110static const struct attribute_group attr_group = {
111 .attrs = aoe_attrs,
112};
113
114static int
1da177e4
LT
115aoedisk_add_sysfs(struct aoedev *d)
116{
ed9e1982 117 return sysfs_create_group(&disk_to_dev(d->gd)->kobj, &attr_group);
1da177e4
LT
118}
119void
120aoedisk_rm_sysfs(struct aoedev *d)
121{
ed9e1982 122 sysfs_remove_group(&disk_to_dev(d->gd)->kobj, &attr_group);
1da177e4
LT
123}
124
125static int
94562c17 126aoeblk_open(struct block_device *bdev, fmode_t mode)
1da177e4 127{
94562c17 128 struct aoedev *d = bdev->bd_disk->private_data;
1da177e4
LT
129 ulong flags;
130
2a48fc0a 131 mutex_lock(&aoeblk_mutex);
1da177e4
LT
132 spin_lock_irqsave(&d->lock, flags);
133 if (d->flags & DEVFL_UP) {
134 d->nopen++;
135 spin_unlock_irqrestore(&d->lock, flags);
2a48fc0a 136 mutex_unlock(&aoeblk_mutex);
1da177e4
LT
137 return 0;
138 }
139 spin_unlock_irqrestore(&d->lock, flags);
2a48fc0a 140 mutex_unlock(&aoeblk_mutex);
1da177e4
LT
141 return -ENODEV;
142}
143
144static int
94562c17 145aoeblk_release(struct gendisk *disk, fmode_t mode)
1da177e4 146{
94562c17 147 struct aoedev *d = disk->private_data;
1da177e4
LT
148 ulong flags;
149
1da177e4
LT
150 spin_lock_irqsave(&d->lock, flags);
151
5f7702fd 152 if (--d->nopen == 0) {
1da177e4
LT
153 spin_unlock_irqrestore(&d->lock, flags);
154 aoecmd_cfg(d->aoemajor, d->aoeminor);
155 return 0;
156 }
157 spin_unlock_irqrestore(&d->lock, flags);
158
159 return 0;
160}
161
162static int
165125e1 163aoeblk_make_request(struct request_queue *q, struct bio *bio)
1da177e4 164{
e9bb8fb0 165 struct sk_buff_head queue;
1da177e4
LT
166 struct aoedev *d;
167 struct buf *buf;
1da177e4
LT
168 ulong flags;
169
170 blk_queue_bounce(q, &bio);
171
68e0d42f
EC
172 if (bio == NULL) {
173 printk(KERN_ERR "aoe: bio is NULL\n");
174 BUG();
175 return 0;
176 }
1da177e4 177 d = bio->bi_bdev->bd_disk->private_data;
68e0d42f
EC
178 if (d == NULL) {
179 printk(KERN_ERR "aoe: bd_disk->private_data is NULL\n");
180 BUG();
181 bio_endio(bio, -ENXIO);
182 return 0;
7b6d91da 183 } else if (bio->bi_rw & REQ_HARDBARRIER) {
18d8217b
EC
184 bio_endio(bio, -EOPNOTSUPP);
185 return 0;
68e0d42f
EC
186 } else if (bio->bi_io_vec == NULL) {
187 printk(KERN_ERR "aoe: bi_io_vec is NULL\n");
188 BUG();
189 bio_endio(bio, -ENXIO);
190 return 0;
191 }
1da177e4
LT
192 buf = mempool_alloc(d->bufpool, GFP_NOIO);
193 if (buf == NULL) {
a12c93f0 194 printk(KERN_INFO "aoe: buf allocation failure\n");
6712ecf8 195 bio_endio(bio, -ENOMEM);
1da177e4
LT
196 return 0;
197 }
198 memset(buf, 0, sizeof(*buf));
199 INIT_LIST_HEAD(&buf->bufs);
68e0d42f 200 buf->stime = jiffies;
1da177e4
LT
201 buf->bio = bio;
202 buf->resid = bio->bi_size;
203 buf->sector = bio->bi_sector;
392e4845 204 buf->bv = &bio->bi_io_vec[bio->bi_idx];
1da177e4 205 buf->bv_resid = buf->bv->bv_len;
68e0d42f
EC
206 WARN_ON(buf->bv_resid == 0);
207 buf->bv_off = buf->bv->bv_offset;
1da177e4
LT
208
209 spin_lock_irqsave(&d->lock, flags);
210
211 if ((d->flags & DEVFL_UP) == 0) {
027b180d 212 pr_info_ratelimited("aoe: device %ld.%d is not up\n",
a12c93f0 213 d->aoemajor, d->aoeminor);
1da177e4
LT
214 spin_unlock_irqrestore(&d->lock, flags);
215 mempool_free(buf, d->bufpool);
6712ecf8 216 bio_endio(bio, -ENXIO);
1da177e4
LT
217 return 0;
218 }
219
220 list_add_tail(&buf->bufs, &d->bufq);
1da177e4 221
3ae1c24e 222 aoecmd_work(d);
e9bb8fb0
DM
223 __skb_queue_head_init(&queue);
224 skb_queue_splice_init(&d->sendq, &queue);
1da177e4
LT
225
226 spin_unlock_irqrestore(&d->lock, flags);
e9bb8fb0 227 aoenet_xmit(&queue);
3ae1c24e 228
1da177e4
LT
229 return 0;
230}
231
1da177e4 232static int
a885c8c4 233aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1da177e4 234{
a885c8c4 235 struct aoedev *d = bdev->bd_disk->private_data;
1da177e4 236
1da177e4 237 if ((d->flags & DEVFL_UP) == 0) {
a12c93f0 238 printk(KERN_ERR "aoe: disk not up\n");
1da177e4
LT
239 return -ENODEV;
240 }
241
a885c8c4
CH
242 geo->cylinders = d->geo.cylinders;
243 geo->heads = d->geo.heads;
244 geo->sectors = d->geo.sectors;
245 return 0;
1da177e4
LT
246}
247
83d5cde4 248static const struct block_device_operations aoe_bdops = {
94562c17
AV
249 .open = aoeblk_open,
250 .release = aoeblk_release,
a885c8c4 251 .getgeo = aoeblk_getgeo,
1da177e4
LT
252 .owner = THIS_MODULE,
253};
254
255/* alloc_disk and add_disk can sleep */
256void
257aoeblk_gdalloc(void *vp)
258{
259 struct aoedev *d = vp;
260 struct gendisk *gd;
261 ulong flags;
262
263 gd = alloc_disk(AOE_PARTITIONS);
264 if (gd == NULL) {
1d75981a
EC
265 printk(KERN_ERR
266 "aoe: cannot allocate disk structure for %ld.%d\n",
6bb6285f 267 d->aoemajor, d->aoeminor);
43cbe2cb 268 goto err;
1da177e4
LT
269 }
270
93d2341c 271 d->bufpool = mempool_create_slab_pool(MIN_BUFS, buf_pool_cache);
1da177e4 272 if (d->bufpool == NULL) {
1d75981a 273 printk(KERN_ERR "aoe: cannot allocate bufpool for %ld.%d\n",
6bb6285f 274 d->aoemajor, d->aoeminor);
43cbe2cb 275 goto err_disk;
1da177e4
LT
276 }
277
7135a71b
EC
278 d->blkq = blk_alloc_queue(GFP_KERNEL);
279 if (!d->blkq)
43cbe2cb 280 goto err_mempool;
7135a71b 281 blk_queue_make_request(d->blkq, aoeblk_make_request);
d993831f 282 d->blkq->backing_dev_info.name = "aoe";
7135a71b
EC
283 if (bdi_init(&d->blkq->backing_dev_info))
284 goto err_blkq;
43cbe2cb 285 spin_lock_irqsave(&d->lock, flags);
1da177e4
LT
286 gd->major = AOE_MAJOR;
287 gd->first_minor = d->sysminor * AOE_PARTITIONS;
288 gd->fops = &aoe_bdops;
289 gd->private_data = d;
80795aef 290 set_capacity(gd, d->ssize);
68e0d42f 291 snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d",
1da177e4
LT
292 d->aoemajor, d->aoeminor);
293
7135a71b 294 gd->queue = d->blkq;
1da177e4 295 d->gd = gd;
3ae1c24e 296 d->flags &= ~DEVFL_GDALLOC;
1da177e4
LT
297 d->flags |= DEVFL_UP;
298
299 spin_unlock_irqrestore(&d->lock, flags);
300
301 add_disk(gd);
302 aoedisk_add_sysfs(d);
43cbe2cb
AM
303 return;
304
7135a71b
EC
305err_blkq:
306 blk_cleanup_queue(d->blkq);
307 d->blkq = NULL;
43cbe2cb
AM
308err_mempool:
309 mempool_destroy(d->bufpool);
310err_disk:
311 put_disk(gd);
312err:
313 spin_lock_irqsave(&d->lock, flags);
314 d->flags &= ~DEVFL_GDALLOC;
315 spin_unlock_irqrestore(&d->lock, flags);
1da177e4
LT
316}
317
318void
319aoeblk_exit(void)
320{
321 kmem_cache_destroy(buf_pool_cache);
322}
323
324int __init
325aoeblk_init(void)
326{
20c2df83 327 buf_pool_cache = kmem_cache_create("aoe_bufs",
1da177e4 328 sizeof(struct buf),
20c2df83 329 0, 0, NULL);
1da177e4
LT
330 if (buf_pool_cache == NULL)
331 return -ENOMEM;
332
333 return 0;
334}
335
This page took 0.550934 seconds and 5 git commands to generate.