Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[pandora-kernel.git] / drivers / block / aoe / aoeblk.c
1 /* Copyright (c) 2006 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
16 static struct kmem_cache *buf_pool_cache;
17
18 static 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_PAUSE) ? ",paused" :
28                         (d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : "");
29         /* I'd rather see nopen exported so we can ditch closewait */
30 }
31 static 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
37         return snprintf(page, PAGE_SIZE, "%012llx\n",
38                         (unsigned long long)mac_addr(d->addr));
39 }
40 static ssize_t aoedisk_show_netif(struct device *dev,
41                                   struct device_attribute *attr, char *page)
42 {
43         struct gendisk *disk = dev_to_disk(dev);
44         struct aoedev *d = disk->private_data;
45
46         return snprintf(page, PAGE_SIZE, "%s\n", d->ifp->name);
47 }
48 /* firmware version */
49 static ssize_t aoedisk_show_fwver(struct device *dev,
50                                   struct device_attribute *attr, char *page)
51 {
52         struct gendisk *disk = dev_to_disk(dev);
53         struct aoedev *d = disk->private_data;
54
55         return snprintf(page, PAGE_SIZE, "0x%04x\n", (unsigned int) d->fw_ver);
56 }
57
58 static DEVICE_ATTR(state, S_IRUGO, aoedisk_show_state, NULL);
59 static DEVICE_ATTR(mac, S_IRUGO, aoedisk_show_mac, NULL);
60 static DEVICE_ATTR(netif, S_IRUGO, aoedisk_show_netif, NULL);
61 static struct device_attribute dev_attr_firmware_version = {
62         .attr = { .name = "firmware-version", .mode = S_IRUGO, .owner = THIS_MODULE },
63         .show = aoedisk_show_fwver,
64 };
65
66 static struct attribute *aoe_attrs[] = {
67         &dev_attr_state.attr,
68         &dev_attr_mac.attr,
69         &dev_attr_netif.attr,
70         &dev_attr_firmware_version.attr,
71         NULL,
72 };
73
74 static const struct attribute_group attr_group = {
75         .attrs = aoe_attrs,
76 };
77
78 static int
79 aoedisk_add_sysfs(struct aoedev *d)
80 {
81         return sysfs_create_group(&d->gd->dev.kobj, &attr_group);
82 }
83 void
84 aoedisk_rm_sysfs(struct aoedev *d)
85 {
86         sysfs_remove_group(&d->gd->dev.kobj, &attr_group);
87 }
88
89 static int
90 aoeblk_open(struct inode *inode, struct file *filp)
91 {
92         struct aoedev *d;
93         ulong flags;
94
95         d = inode->i_bdev->bd_disk->private_data;
96
97         spin_lock_irqsave(&d->lock, flags);
98         if (d->flags & DEVFL_UP) {
99                 d->nopen++;
100                 spin_unlock_irqrestore(&d->lock, flags);
101                 return 0;
102         }
103         spin_unlock_irqrestore(&d->lock, flags);
104         return -ENODEV;
105 }
106
107 static int
108 aoeblk_release(struct inode *inode, struct file *filp)
109 {
110         struct aoedev *d;
111         ulong flags;
112
113         d = inode->i_bdev->bd_disk->private_data;
114
115         spin_lock_irqsave(&d->lock, flags);
116
117         if (--d->nopen == 0) {
118                 spin_unlock_irqrestore(&d->lock, flags);
119                 aoecmd_cfg(d->aoemajor, d->aoeminor);
120                 return 0;
121         }
122         spin_unlock_irqrestore(&d->lock, flags);
123
124         return 0;
125 }
126
127 static int
128 aoeblk_make_request(struct request_queue *q, struct bio *bio)
129 {
130         struct aoedev *d;
131         struct buf *buf;
132         struct sk_buff *sl;
133         ulong flags;
134
135         blk_queue_bounce(q, &bio);
136
137         d = bio->bi_bdev->bd_disk->private_data;
138         buf = mempool_alloc(d->bufpool, GFP_NOIO);
139         if (buf == NULL) {
140                 printk(KERN_INFO "aoe: buf allocation failure\n");
141                 bio_endio(bio, -ENOMEM);
142                 return 0;
143         }
144         memset(buf, 0, sizeof(*buf));
145         INIT_LIST_HEAD(&buf->bufs);
146         buf->start_time = jiffies;
147         buf->bio = bio;
148         buf->resid = bio->bi_size;
149         buf->sector = bio->bi_sector;
150         buf->bv = &bio->bi_io_vec[bio->bi_idx];
151         WARN_ON(buf->bv->bv_len == 0);
152         buf->bv_resid = buf->bv->bv_len;
153         buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset;
154
155         spin_lock_irqsave(&d->lock, flags);
156
157         if ((d->flags & DEVFL_UP) == 0) {
158                 printk(KERN_INFO "aoe: device %ld.%ld is not up\n",
159                         d->aoemajor, d->aoeminor);
160                 spin_unlock_irqrestore(&d->lock, flags);
161                 mempool_free(buf, d->bufpool);
162                 bio_endio(bio, -ENXIO);
163                 return 0;
164         }
165
166         list_add_tail(&buf->bufs, &d->bufq);
167
168         aoecmd_work(d);
169         sl = d->sendq_hd;
170         d->sendq_hd = d->sendq_tl = NULL;
171
172         spin_unlock_irqrestore(&d->lock, flags);
173         aoenet_xmit(sl);
174
175         return 0;
176 }
177
178 static int
179 aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
180 {
181         struct aoedev *d = bdev->bd_disk->private_data;
182
183         if ((d->flags & DEVFL_UP) == 0) {
184                 printk(KERN_ERR "aoe: disk not up\n");
185                 return -ENODEV;
186         }
187
188         geo->cylinders = d->geo.cylinders;
189         geo->heads = d->geo.heads;
190         geo->sectors = d->geo.sectors;
191         return 0;
192 }
193
194 static struct block_device_operations aoe_bdops = {
195         .open = aoeblk_open,
196         .release = aoeblk_release,
197         .getgeo = aoeblk_getgeo,
198         .owner = THIS_MODULE,
199 };
200
201 /* alloc_disk and add_disk can sleep */
202 void
203 aoeblk_gdalloc(void *vp)
204 {
205         struct aoedev *d = vp;
206         struct gendisk *gd;
207         ulong flags;
208
209         gd = alloc_disk(AOE_PARTITIONS);
210         if (gd == NULL) {
211                 printk(KERN_ERR "aoe: cannot allocate disk structure for %ld.%ld\n",
212                         d->aoemajor, d->aoeminor);
213                 goto err;
214         }
215
216         d->bufpool = mempool_create_slab_pool(MIN_BUFS, buf_pool_cache);
217         if (d->bufpool == NULL) {
218                 printk(KERN_ERR "aoe: cannot allocate bufpool for %ld.%ld\n",
219                         d->aoemajor, d->aoeminor);
220                 goto err_disk;
221         }
222
223         blk_queue_make_request(&d->blkq, aoeblk_make_request);
224         if (bdi_init(&d->blkq.backing_dev_info))
225                 goto err_mempool;
226         spin_lock_irqsave(&d->lock, flags);
227         gd->major = AOE_MAJOR;
228         gd->first_minor = d->sysminor * AOE_PARTITIONS;
229         gd->fops = &aoe_bdops;
230         gd->private_data = d;
231         gd->capacity = d->ssize;
232         snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%ld",
233                 d->aoemajor, d->aoeminor);
234
235         gd->queue = &d->blkq;
236         d->gd = gd;
237         d->flags &= ~DEVFL_GDALLOC;
238         d->flags |= DEVFL_UP;
239
240         spin_unlock_irqrestore(&d->lock, flags);
241
242         add_disk(gd);
243         aoedisk_add_sysfs(d);
244         return;
245
246 err_mempool:
247         mempool_destroy(d->bufpool);
248 err_disk:
249         put_disk(gd);
250 err:
251         spin_lock_irqsave(&d->lock, flags);
252         d->flags &= ~DEVFL_GDALLOC;
253         spin_unlock_irqrestore(&d->lock, flags);
254 }
255
256 void
257 aoeblk_exit(void)
258 {
259         kmem_cache_destroy(buf_pool_cache);
260 }
261
262 int __init
263 aoeblk_init(void)
264 {
265         buf_pool_cache = kmem_cache_create("aoe_bufs",
266                                            sizeof(struct buf),
267                                            0, 0, NULL);
268         if (buf_pool_cache == NULL)
269                 return -ENOMEM;
270
271         return 0;
272 }
273