aoeblk.c revision 52e112b3ab6b2b35a144565c8ea3bdda1e2845f2
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, "%012llx\n", mac_addr(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, .owner = THIS_MODULE },
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(&d->gd->dev.kobj, &attr_group);
113}
114void
115aoedisk_rm_sysfs(struct aoedev *d)
116{
117	sysfs_remove_group(&d->gd->dev.kobj, &attr_group);
118}
119
120static int
121aoeblk_open(struct inode *inode, struct file *filp)
122{
123	struct aoedev *d;
124	ulong flags;
125
126	d = inode->i_bdev->bd_disk->private_data;
127
128	spin_lock_irqsave(&d->lock, flags);
129	if (d->flags & DEVFL_UP) {
130		d->nopen++;
131		spin_unlock_irqrestore(&d->lock, flags);
132		return 0;
133	}
134	spin_unlock_irqrestore(&d->lock, flags);
135	return -ENODEV;
136}
137
138static int
139aoeblk_release(struct inode *inode, struct file *filp)
140{
141	struct aoedev *d;
142	ulong flags;
143
144	d = inode->i_bdev->bd_disk->private_data;
145
146	spin_lock_irqsave(&d->lock, flags);
147
148	if (--d->nopen == 0) {
149		spin_unlock_irqrestore(&d->lock, flags);
150		aoecmd_cfg(d->aoemajor, d->aoeminor);
151		return 0;
152	}
153	spin_unlock_irqrestore(&d->lock, flags);
154
155	return 0;
156}
157
158static int
159aoeblk_make_request(struct request_queue *q, struct bio *bio)
160{
161	struct aoedev *d;
162	struct buf *buf;
163	struct sk_buff *sl;
164	ulong flags;
165
166	blk_queue_bounce(q, &bio);
167
168	if (bio == NULL) {
169		printk(KERN_ERR "aoe: bio is NULL\n");
170		BUG();
171		return 0;
172	}
173	d = bio->bi_bdev->bd_disk->private_data;
174	if (d == NULL) {
175		printk(KERN_ERR "aoe: bd_disk->private_data is NULL\n");
176		BUG();
177		bio_endio(bio, -ENXIO);
178		return 0;
179	} else if (bio->bi_io_vec == NULL) {
180		printk(KERN_ERR "aoe: bi_io_vec is NULL\n");
181		BUG();
182		bio_endio(bio, -ENXIO);
183		return 0;
184	}
185	buf = mempool_alloc(d->bufpool, GFP_NOIO);
186	if (buf == NULL) {
187		printk(KERN_INFO "aoe: buf allocation failure\n");
188		bio_endio(bio, -ENOMEM);
189		return 0;
190	}
191	memset(buf, 0, sizeof(*buf));
192	INIT_LIST_HEAD(&buf->bufs);
193	buf->stime = jiffies;
194	buf->bio = bio;
195	buf->resid = bio->bi_size;
196	buf->sector = bio->bi_sector;
197	buf->bv = &bio->bi_io_vec[bio->bi_idx];
198	buf->bv_resid = buf->bv->bv_len;
199	WARN_ON(buf->bv_resid == 0);
200	buf->bv_off = buf->bv->bv_offset;
201
202	spin_lock_irqsave(&d->lock, flags);
203
204	if ((d->flags & DEVFL_UP) == 0) {
205		printk(KERN_INFO "aoe: device %ld.%d is not up\n",
206			d->aoemajor, d->aoeminor);
207		spin_unlock_irqrestore(&d->lock, flags);
208		mempool_free(buf, d->bufpool);
209		bio_endio(bio, -ENXIO);
210		return 0;
211	}
212
213	list_add_tail(&buf->bufs, &d->bufq);
214
215	aoecmd_work(d);
216	sl = d->sendq_hd;
217	d->sendq_hd = d->sendq_tl = NULL;
218
219	spin_unlock_irqrestore(&d->lock, flags);
220	aoenet_xmit(sl);
221
222	return 0;
223}
224
225static int
226aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
227{
228	struct aoedev *d = bdev->bd_disk->private_data;
229
230	if ((d->flags & DEVFL_UP) == 0) {
231		printk(KERN_ERR "aoe: disk not up\n");
232		return -ENODEV;
233	}
234
235	geo->cylinders = d->geo.cylinders;
236	geo->heads = d->geo.heads;
237	geo->sectors = d->geo.sectors;
238	return 0;
239}
240
241static struct block_device_operations aoe_bdops = {
242	.open = aoeblk_open,
243	.release = aoeblk_release,
244	.getgeo = aoeblk_getgeo,
245	.owner = THIS_MODULE,
246};
247
248/* alloc_disk and add_disk can sleep */
249void
250aoeblk_gdalloc(void *vp)
251{
252	struct aoedev *d = vp;
253	struct gendisk *gd;
254	ulong flags;
255
256	gd = alloc_disk(AOE_PARTITIONS);
257	if (gd == NULL) {
258		printk(KERN_ERR
259			"aoe: cannot allocate disk structure for %ld.%d\n",
260			d->aoemajor, d->aoeminor);
261		goto err;
262	}
263
264	d->bufpool = mempool_create_slab_pool(MIN_BUFS, buf_pool_cache);
265	if (d->bufpool == NULL) {
266		printk(KERN_ERR "aoe: cannot allocate bufpool for %ld.%d\n",
267			d->aoemajor, d->aoeminor);
268		goto err_disk;
269	}
270
271	blk_queue_make_request(&d->blkq, aoeblk_make_request);
272	if (bdi_init(&d->blkq.backing_dev_info))
273		goto err_mempool;
274	spin_lock_irqsave(&d->lock, flags);
275	gd->major = AOE_MAJOR;
276	gd->first_minor = d->sysminor * AOE_PARTITIONS;
277	gd->fops = &aoe_bdops;
278	gd->private_data = d;
279	gd->capacity = d->ssize;
280	snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d",
281		d->aoemajor, d->aoeminor);
282
283	gd->queue = &d->blkq;
284	d->gd = gd;
285	d->flags &= ~DEVFL_GDALLOC;
286	d->flags |= DEVFL_UP;
287
288	spin_unlock_irqrestore(&d->lock, flags);
289
290	add_disk(gd);
291	aoedisk_add_sysfs(d);
292	return;
293
294err_mempool:
295	mempool_destroy(d->bufpool);
296err_disk:
297	put_disk(gd);
298err:
299	spin_lock_irqsave(&d->lock, flags);
300	d->flags &= ~DEVFL_GDALLOC;
301	spin_unlock_irqrestore(&d->lock, flags);
302}
303
304void
305aoeblk_exit(void)
306{
307	kmem_cache_destroy(buf_pool_cache);
308}
309
310int __init
311aoeblk_init(void)
312{
313	buf_pool_cache = kmem_cache_create("aoe_bufs",
314					   sizeof(struct buf),
315					   0, 0, NULL);
316	if (buf_pool_cache == NULL)
317		return -ENOMEM;
318
319	return 0;
320}
321
322