152e112b3ab6b2b35a144565c8ea3bdda1e2845f2Ed L. Cashin/* Copyright (c) 2007 Coraid, Inc.  See COPYING for GPL terms. */
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * aoeblk.c
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * block device routines
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7027b180d7405f2b2df25e2a8b1b796b00f3773cfAndrew Morton#include <linux/kernel.h>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hdreg.h>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h>
1043cbe2cbdd5320f1ac785c6f016923609831effeAndrew Morton#include <linux/backing-dev.h>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioctl.h>
135a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
14027b180d7405f2b2df25e2a8b1b796b00f3773cfAndrew Morton#include <linux/ratelimit.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/genhd.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
172a48fc0ab24241755dc93bfd4f01d68efab47f5aArnd Bergmann#include <linux/mutex.h>
18d5decd3b9512e35c87492312a72443192eebdda9Paul Gortmaker#include <linux/export.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "aoe.h"
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
212a48fc0ab24241755dc93bfd4f01d68efab47f5aArnd Bergmannstatic DEFINE_MUTEX(aoeblk_mutex);
22e18b890bb0881bbab6f4f1a6cd20d9c60d66b003Christoph Lameterstatic struct kmem_cache *buf_pool_cache;
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sieversstatic ssize_t aoedisk_show_state(struct device *dev,
25edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers				  struct device_attribute *attr, char *page)
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
27edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers	struct gendisk *disk = dev_to_disk(dev);
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct aoedev *d = disk->private_data;
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return snprintf(page, PAGE_SIZE,
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"%s%s\n",
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(d->flags & DEVFL_UP) ? "up" : "down",
3368e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin			(d->flags & DEVFL_KICKME) ? ",kickme" :
343ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin			(d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : "");
353ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin	/* I'd rather see nopen exported so we can ditch closewait */
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
37edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sieversstatic ssize_t aoedisk_show_mac(struct device *dev,
38edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers				struct device_attribute *attr, char *page)
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
40edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers	struct gendisk *disk = dev_to_disk(dev);
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct aoedev *d = disk->private_data;
4268e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	struct aoetgt *t = d->targets[0];
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4468e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	if (t == NULL)
4568e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		return snprintf(page, PAGE_SIZE, "none\n");
46411c41eea58bd3500cf897e2c27dd5330935a3a8Harvey Harrison	return snprintf(page, PAGE_SIZE, "%pm\n", t->addr);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
48edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sieversstatic ssize_t aoedisk_show_netif(struct device *dev,
49edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers				  struct device_attribute *attr, char *page)
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
51edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers	struct gendisk *disk = dev_to_disk(dev);
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct aoedev *d = disk->private_data;
5368e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	struct net_device *nds[8], **nd, **nnd, **ne;
5468e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	struct aoetgt **t, **te;
5568e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	struct aoeif *ifp, *e;
5668e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	char *p;
5768e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin
5868e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	memset(nds, 0, sizeof nds);
5968e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	nd = nds;
6068e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	ne = nd + ARRAY_SIZE(nds);
6168e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	t = d->targets;
6268e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	te = t + NTARGETS;
6368e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	for (; t < te && *t; t++) {
6468e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		ifp = (*t)->ifs;
6568e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		e = ifp + NAOEIFS;
6668e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		for (; ifp < e && ifp->nd; ifp++) {
6768e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin			for (nnd = nds; nnd < nd; nnd++)
6868e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin				if (*nnd == ifp->nd)
6968e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin					break;
7068e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin			if (nnd == nd && nd != ne)
7168e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin				*nd++ = ifp->nd;
7268e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		}
7368e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	}
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7568e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	ne = nd;
7668e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	nd = nds;
7768e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	if (*nd == NULL)
7868e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		return snprintf(page, PAGE_SIZE, "none\n");
7968e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	for (p = page; nd < ne; nd++)
8068e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		p += snprintf(p, PAGE_SIZE - (p-page), "%s%s",
8168e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin			p == page ? "" : ",", (*nd)->name);
8268e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	p += snprintf(p, PAGE_SIZE - (p-page), "\n");
8368e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	return p-page;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
854613ed277ab8a41640434181898ef4649cc7301eEd L. Cashin/* firmware version */
86edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sieversstatic ssize_t aoedisk_show_fwver(struct device *dev,
87edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers				  struct device_attribute *attr, char *page)
884613ed277ab8a41640434181898ef4649cc7301eEd L. Cashin{
89edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers	struct gendisk *disk = dev_to_disk(dev);
904613ed277ab8a41640434181898ef4649cc7301eEd L. Cashin	struct aoedev *d = disk->private_data;
914613ed277ab8a41640434181898ef4649cc7301eEd L. Cashin
924613ed277ab8a41640434181898ef4649cc7301eEd L. Cashin	return snprintf(page, PAGE_SIZE, "0x%04x\n", (unsigned int) d->fw_ver);
934613ed277ab8a41640434181898ef4649cc7301eEd L. Cashin}
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
95edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sieversstatic DEVICE_ATTR(state, S_IRUGO, aoedisk_show_state, NULL);
96edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sieversstatic DEVICE_ATTR(mac, S_IRUGO, aoedisk_show_mac, NULL);
97edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sieversstatic DEVICE_ATTR(netif, S_IRUGO, aoedisk_show_netif, NULL);
98edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sieversstatic struct device_attribute dev_attr_firmware_version = {
9901e8ef11bc1a74e65678ed55795f59266d4add01Parag Warudkar	.attr = { .name = "firmware-version", .mode = S_IRUGO },
100edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers	.show = aoedisk_show_fwver,
1014613ed277ab8a41640434181898ef4649cc7301eEd L. Cashin};
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1034ca5224f3ea4779054d96e885ca9b3980801ce13Greg Kroah-Hartmanstatic struct attribute *aoe_attrs[] = {
104edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers	&dev_attr_state.attr,
105edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers	&dev_attr_mac.attr,
106edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers	&dev_attr_netif.attr,
107edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers	&dev_attr_firmware_version.attr,
108edfaa7c36574f1bf09c65ad602412db9da5f96bfKay Sievers	NULL,
1094ca5224f3ea4779054d96e885ca9b3980801ce13Greg Kroah-Hartman};
1104ca5224f3ea4779054d96e885ca9b3980801ce13Greg Kroah-Hartman
1114ca5224f3ea4779054d96e885ca9b3980801ce13Greg Kroah-Hartmanstatic const struct attribute_group attr_group = {
1124ca5224f3ea4779054d96e885ca9b3980801ce13Greg Kroah-Hartman	.attrs = aoe_attrs,
1134ca5224f3ea4779054d96e885ca9b3980801ce13Greg Kroah-Hartman};
1144ca5224f3ea4779054d96e885ca9b3980801ce13Greg Kroah-Hartman
1154ca5224f3ea4779054d96e885ca9b3980801ce13Greg Kroah-Hartmanstatic int
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoedisk_add_sysfs(struct aoedev *d)
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
118ed9e1982347b36573cd622ee5f4e2a7ccd79b3fdTejun Heo	return sysfs_create_group(&disk_to_dev(d->gd)->kobj, &attr_group);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoedisk_rm_sysfs(struct aoedev *d)
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
123ed9e1982347b36573cd622ee5f4e2a7ccd79b3fdTejun Heo	sysfs_remove_group(&disk_to_dev(d->gd)->kobj, &attr_group);
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
12794562c175113cf91204a77269eabeea32e1f38dbAl Viroaoeblk_open(struct block_device *bdev, fmode_t mode)
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12994562c175113cf91204a77269eabeea32e1f38dbAl Viro	struct aoedev *d = bdev->bd_disk->private_data;
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong flags;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1322a48fc0ab24241755dc93bfd4f01d68efab47f5aArnd Bergmann	mutex_lock(&aoeblk_mutex);
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&d->lock, flags);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (d->flags & DEVFL_UP) {
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d->nopen++;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&d->lock, flags);
1372a48fc0ab24241755dc93bfd4f01d68efab47f5aArnd Bergmann		mutex_unlock(&aoeblk_mutex);
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&d->lock, flags);
1412a48fc0ab24241755dc93bfd4f01d68efab47f5aArnd Bergmann	mutex_unlock(&aoeblk_mutex);
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENODEV;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
14694562c175113cf91204a77269eabeea32e1f38dbAl Viroaoeblk_release(struct gendisk *disk, fmode_t mode)
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
14894562c175113cf91204a77269eabeea32e1f38dbAl Viro	struct aoedev *d = disk->private_data;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong flags;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&d->lock, flags);
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1535f7702fd737d14de3ed06a94a1655be9d43f7e35Ed L. Cashin	if (--d->nopen == 0) {
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&d->lock, flags);
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		aoecmd_cfg(d->aoemajor, d->aoeminor);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&d->lock, flags);
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1635a7bbad27a410350e64a2d7f5ec18fc73836c14fChristoph Hellwigstatic void
164165125e1e480f9510a5ffcfbfee4e3ee38c05f23Jens Axboeaoeblk_make_request(struct request_queue *q, struct bio *bio)
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
166e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Miller	struct sk_buff_head queue;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct aoedev *d;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct buf *buf;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong flags;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	blk_queue_bounce(q, &bio);
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
17368e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	if (bio == NULL) {
17468e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		printk(KERN_ERR "aoe: bio is NULL\n");
17568e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		BUG();
1765a7bbad27a410350e64a2d7f5ec18fc73836c14fChristoph Hellwig		return;
17768e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	}
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d = bio->bi_bdev->bd_disk->private_data;
17968e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	if (d == NULL) {
18068e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		printk(KERN_ERR "aoe: bd_disk->private_data is NULL\n");
18168e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		BUG();
18268e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		bio_endio(bio, -ENXIO);
1835a7bbad27a410350e64a2d7f5ec18fc73836c14fChristoph Hellwig		return;
18468e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	} else if (bio->bi_io_vec == NULL) {
18568e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		printk(KERN_ERR "aoe: bi_io_vec is NULL\n");
18668e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		BUG();
18768e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin		bio_endio(bio, -ENXIO);
1885a7bbad27a410350e64a2d7f5ec18fc73836c14fChristoph Hellwig		return;
18968e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	}
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf = mempool_alloc(d->bufpool, GFP_NOIO);
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (buf == NULL) {
192a12c93f08b8fc83b7fcdabaf92b1adcea7489f5eEd L. Cashin		printk(KERN_INFO "aoe: buf allocation failure\n");
1936712ecf8f648118c3363c142196418f89a510b90NeilBrown		bio_endio(bio, -ENOMEM);
1945a7bbad27a410350e64a2d7f5ec18fc73836c14fChristoph Hellwig		return;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(buf, 0, sizeof(*buf));
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	INIT_LIST_HEAD(&buf->bufs);
19868e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	buf->stime = jiffies;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->bio = bio;
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->resid = bio->bi_size;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->sector = bio->bi_sector;
202392e4845f9728114f7ffa8d7612683397fd4d441Ed L. Cashin	buf->bv = &bio->bi_io_vec[bio->bi_idx];
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	buf->bv_resid = buf->bv->bv_len;
20468e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	WARN_ON(buf->bv_resid == 0);
20568e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	buf->bv_off = buf->bv->bv_offset;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&d->lock, flags);
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((d->flags & DEVFL_UP) == 0) {
210027b180d7405f2b2df25e2a8b1b796b00f3773cfAndrew Morton		pr_info_ratelimited("aoe: device %ld.%d is not up\n",
211a12c93f08b8fc83b7fcdabaf92b1adcea7489f5eEd L. Cashin			d->aoemajor, d->aoeminor);
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&d->lock, flags);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mempool_free(buf, d->bufpool);
2146712ecf8f648118c3363c142196418f89a510b90NeilBrown		bio_endio(bio, -ENXIO);
2155a7bbad27a410350e64a2d7f5ec18fc73836c14fChristoph Hellwig		return;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	list_add_tail(&buf->bufs, &d->bufq);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2203ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin	aoecmd_work(d);
221e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Miller	__skb_queue_head_init(&queue);
222e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Miller	skb_queue_splice_init(&d->sendq, &queue);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&d->lock, flags);
225e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Miller	aoenet_xmit(&queue);
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
229a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwigaoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
231a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig	struct aoedev *d = bdev->bd_disk->private_data;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((d->flags & DEVFL_UP) == 0) {
234a12c93f08b8fc83b7fcdabaf92b1adcea7489f5eEd L. Cashin		printk(KERN_ERR "aoe: disk not up\n");
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
238a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig	geo->cylinders = d->geo.cylinders;
239a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig	geo->heads = d->geo.heads;
240a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig	geo->sectors = d->geo.sectors;
241a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig	return 0;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
24483d5cde47dedf01b6a4a4331882cbc0a7eea3c2eAlexey Dobriyanstatic const struct block_device_operations aoe_bdops = {
24594562c175113cf91204a77269eabeea32e1f38dbAl Viro	.open = aoeblk_open,
24694562c175113cf91204a77269eabeea32e1f38dbAl Viro	.release = aoeblk_release,
247a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig	.getgeo = aoeblk_getgeo,
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner = THIS_MODULE,
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* alloc_disk and add_disk can sleep */
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoeblk_gdalloc(void *vp)
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct aoedev *d = vp;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gendisk *gd;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong flags;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gd = alloc_disk(AOE_PARTITIONS);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (gd == NULL) {
2611d75981a8094e9f84fae65a6a83b361e3893b971Ed L. Cashin		printk(KERN_ERR
2621d75981a8094e9f84fae65a6a83b361e3893b971Ed L. Cashin			"aoe: cannot allocate disk structure for %ld.%d\n",
2636bb6285fdb948cedee586c6bebc9ebc5e32a5c35Ed L. Cashin			d->aoemajor, d->aoeminor);
26443cbe2cbdd5320f1ac785c6f016923609831effeAndrew Morton		goto err;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26793d2341c750cda0df48a6cc67b35fe25f1ec47dfMatthew Dobson	d->bufpool = mempool_create_slab_pool(MIN_BUFS, buf_pool_cache);
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (d->bufpool == NULL) {
2691d75981a8094e9f84fae65a6a83b361e3893b971Ed L. Cashin		printk(KERN_ERR "aoe: cannot allocate bufpool for %ld.%d\n",
2706bb6285fdb948cedee586c6bebc9ebc5e32a5c35Ed L. Cashin			d->aoemajor, d->aoeminor);
27143cbe2cbdd5320f1ac785c6f016923609831effeAndrew Morton		goto err_disk;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2747135a71b19be1faf48b7148d77844d03bc0717d6Ed L. Cashin	d->blkq = blk_alloc_queue(GFP_KERNEL);
2757135a71b19be1faf48b7148d77844d03bc0717d6Ed L. Cashin	if (!d->blkq)
27643cbe2cbdd5320f1ac785c6f016923609831effeAndrew Morton		goto err_mempool;
2777135a71b19be1faf48b7148d77844d03bc0717d6Ed L. Cashin	blk_queue_make_request(d->blkq, aoeblk_make_request);
278d993831fa7ffeb89e994f046f93eeb09ec91df08Jens Axboe	d->blkq->backing_dev_info.name = "aoe";
2797135a71b19be1faf48b7148d77844d03bc0717d6Ed L. Cashin	if (bdi_init(&d->blkq->backing_dev_info))
2807135a71b19be1faf48b7148d77844d03bc0717d6Ed L. Cashin		goto err_blkq;
28143cbe2cbdd5320f1ac785c6f016923609831effeAndrew Morton	spin_lock_irqsave(&d->lock, flags);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gd->major = AOE_MAJOR;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gd->first_minor = d->sysminor * AOE_PARTITIONS;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gd->fops = &aoe_bdops;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	gd->private_data = d;
28680795aefb76d10c5d698e60c7e7750b5330787daTejun Heo	set_capacity(gd, d->ssize);
28768e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d",
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d->aoemajor, d->aoeminor);
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2907135a71b19be1faf48b7148d77844d03bc0717d6Ed L. Cashin	gd->queue = d->blkq;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d->gd = gd;
2923ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin	d->flags &= ~DEVFL_GDALLOC;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d->flags |= DEVFL_UP;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&d->lock, flags);
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_disk(gd);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	aoedisk_add_sysfs(d);
29943cbe2cbdd5320f1ac785c6f016923609831effeAndrew Morton	return;
30043cbe2cbdd5320f1ac785c6f016923609831effeAndrew Morton
3017135a71b19be1faf48b7148d77844d03bc0717d6Ed L. Cashinerr_blkq:
3027135a71b19be1faf48b7148d77844d03bc0717d6Ed L. Cashin	blk_cleanup_queue(d->blkq);
3037135a71b19be1faf48b7148d77844d03bc0717d6Ed L. Cashin	d->blkq = NULL;
30443cbe2cbdd5320f1ac785c6f016923609831effeAndrew Mortonerr_mempool:
30543cbe2cbdd5320f1ac785c6f016923609831effeAndrew Morton	mempool_destroy(d->bufpool);
30643cbe2cbdd5320f1ac785c6f016923609831effeAndrew Mortonerr_disk:
30743cbe2cbdd5320f1ac785c6f016923609831effeAndrew Morton	put_disk(gd);
30843cbe2cbdd5320f1ac785c6f016923609831effeAndrew Mortonerr:
30943cbe2cbdd5320f1ac785c6f016923609831effeAndrew Morton	spin_lock_irqsave(&d->lock, flags);
31043cbe2cbdd5320f1ac785c6f016923609831effeAndrew Morton	d->flags &= ~DEVFL_GDALLOC;
31143cbe2cbdd5320f1ac785c6f016923609831effeAndrew Morton	spin_unlock_irqrestore(&d->lock, flags);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoeblk_exit(void)
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kmem_cache_destroy(buf_pool_cache);
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsaoeblk_init(void)
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
32320c2df83d25c6a95affe6157a4c9cac4cf5ffaacPaul Mundt	buf_pool_cache = kmem_cache_create("aoe_bufs",
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					   sizeof(struct buf),
32520c2df83d25c6a95affe6157a4c9cac4cf5ffaacPaul Mundt					   0, 0, NULL);
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (buf_pool_cache == NULL)
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
332