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