diff options
Diffstat (limited to 'drivers/block/aoe/aoeblk.c')
-rw-r--r-- | drivers/block/aoe/aoeblk.c | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c new file mode 100644 index 000000000000..63561b280bc5 --- /dev/null +++ b/drivers/block/aoe/aoeblk.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* Copyright (c) 2004 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/fs.h> | ||
10 | #include <linux/ioctl.h> | ||
11 | #include <linux/genhd.h> | ||
12 | #include <linux/netdevice.h> | ||
13 | #include "aoe.h" | ||
14 | |||
15 | static kmem_cache_t *buf_pool_cache; | ||
16 | |||
17 | /* add attributes for our block devices in sysfs */ | ||
18 | static ssize_t aoedisk_show_state(struct gendisk * disk, char *page) | ||
19 | { | ||
20 | struct aoedev *d = disk->private_data; | ||
21 | |||
22 | return snprintf(page, PAGE_SIZE, | ||
23 | "%s%s\n", | ||
24 | (d->flags & DEVFL_UP) ? "up" : "down", | ||
25 | (d->flags & DEVFL_CLOSEWAIT) ? ",closewait" : ""); | ||
26 | } | ||
27 | static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page) | ||
28 | { | ||
29 | struct aoedev *d = disk->private_data; | ||
30 | |||
31 | return snprintf(page, PAGE_SIZE, "%012llx\n", | ||
32 | (unsigned long long)mac_addr(d->addr)); | ||
33 | } | ||
34 | static ssize_t aoedisk_show_netif(struct gendisk * disk, char *page) | ||
35 | { | ||
36 | struct aoedev *d = disk->private_data; | ||
37 | |||
38 | return snprintf(page, PAGE_SIZE, "%s\n", d->ifp->name); | ||
39 | } | ||
40 | |||
41 | static struct disk_attribute disk_attr_state = { | ||
42 | .attr = {.name = "state", .mode = S_IRUGO }, | ||
43 | .show = aoedisk_show_state | ||
44 | }; | ||
45 | static struct disk_attribute disk_attr_mac = { | ||
46 | .attr = {.name = "mac", .mode = S_IRUGO }, | ||
47 | .show = aoedisk_show_mac | ||
48 | }; | ||
49 | static struct disk_attribute disk_attr_netif = { | ||
50 | .attr = {.name = "netif", .mode = S_IRUGO }, | ||
51 | .show = aoedisk_show_netif | ||
52 | }; | ||
53 | |||
54 | static void | ||
55 | aoedisk_add_sysfs(struct aoedev *d) | ||
56 | { | ||
57 | sysfs_create_file(&d->gd->kobj, &disk_attr_state.attr); | ||
58 | sysfs_create_file(&d->gd->kobj, &disk_attr_mac.attr); | ||
59 | sysfs_create_file(&d->gd->kobj, &disk_attr_netif.attr); | ||
60 | } | ||
61 | void | ||
62 | aoedisk_rm_sysfs(struct aoedev *d) | ||
63 | { | ||
64 | sysfs_remove_link(&d->gd->kobj, "state"); | ||
65 | sysfs_remove_link(&d->gd->kobj, "mac"); | ||
66 | sysfs_remove_link(&d->gd->kobj, "netif"); | ||
67 | } | ||
68 | |||
69 | static int | ||
70 | aoeblk_open(struct inode *inode, struct file *filp) | ||
71 | { | ||
72 | struct aoedev *d; | ||
73 | ulong flags; | ||
74 | |||
75 | d = inode->i_bdev->bd_disk->private_data; | ||
76 | |||
77 | spin_lock_irqsave(&d->lock, flags); | ||
78 | if (d->flags & DEVFL_UP) { | ||
79 | d->nopen++; | ||
80 | spin_unlock_irqrestore(&d->lock, flags); | ||
81 | return 0; | ||
82 | } | ||
83 | spin_unlock_irqrestore(&d->lock, flags); | ||
84 | return -ENODEV; | ||
85 | } | ||
86 | |||
87 | static int | ||
88 | aoeblk_release(struct inode *inode, struct file *filp) | ||
89 | { | ||
90 | struct aoedev *d; | ||
91 | ulong flags; | ||
92 | |||
93 | d = inode->i_bdev->bd_disk->private_data; | ||
94 | |||
95 | spin_lock_irqsave(&d->lock, flags); | ||
96 | |||
97 | if (--d->nopen == 0 && (d->flags & DEVFL_CLOSEWAIT)) { | ||
98 | d->flags &= ~DEVFL_CLOSEWAIT; | ||
99 | spin_unlock_irqrestore(&d->lock, flags); | ||
100 | aoecmd_cfg(d->aoemajor, d->aoeminor); | ||
101 | return 0; | ||
102 | } | ||
103 | spin_unlock_irqrestore(&d->lock, flags); | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int | ||
109 | aoeblk_make_request(request_queue_t *q, struct bio *bio) | ||
110 | { | ||
111 | struct aoedev *d; | ||
112 | struct buf *buf; | ||
113 | struct sk_buff *sl; | ||
114 | ulong flags; | ||
115 | |||
116 | blk_queue_bounce(q, &bio); | ||
117 | |||
118 | d = bio->bi_bdev->bd_disk->private_data; | ||
119 | buf = mempool_alloc(d->bufpool, GFP_NOIO); | ||
120 | if (buf == NULL) { | ||
121 | printk(KERN_INFO "aoe: aoeblk_make_request: buf allocation " | ||
122 | "failure\n"); | ||
123 | bio_endio(bio, bio->bi_size, -ENOMEM); | ||
124 | return 0; | ||
125 | } | ||
126 | memset(buf, 0, sizeof(*buf)); | ||
127 | INIT_LIST_HEAD(&buf->bufs); | ||
128 | buf->bio = bio; | ||
129 | buf->resid = bio->bi_size; | ||
130 | buf->sector = bio->bi_sector; | ||
131 | buf->bv = buf->bio->bi_io_vec; | ||
132 | buf->bv_resid = buf->bv->bv_len; | ||
133 | buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset; | ||
134 | |||
135 | spin_lock_irqsave(&d->lock, flags); | ||
136 | |||
137 | if ((d->flags & DEVFL_UP) == 0) { | ||
138 | printk(KERN_INFO "aoe: aoeblk_make_request: device %ld.%ld is not up\n", | ||
139 | d->aoemajor, d->aoeminor); | ||
140 | spin_unlock_irqrestore(&d->lock, flags); | ||
141 | mempool_free(buf, d->bufpool); | ||
142 | bio_endio(bio, bio->bi_size, -ENXIO); | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | list_add_tail(&buf->bufs, &d->bufq); | ||
147 | aoecmd_work(d); | ||
148 | |||
149 | sl = d->skblist; | ||
150 | d->skblist = NULL; | ||
151 | |||
152 | spin_unlock_irqrestore(&d->lock, flags); | ||
153 | |||
154 | aoenet_xmit(sl); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | /* This ioctl implementation expects userland to have the device node | ||
159 | * permissions set so that only priviledged users can open an aoe | ||
160 | * block device directly. | ||
161 | */ | ||
162 | static int | ||
163 | aoeblk_ioctl(struct inode *inode, struct file *filp, uint cmd, ulong arg) | ||
164 | { | ||
165 | struct aoedev *d; | ||
166 | |||
167 | if (!arg) | ||
168 | return -EINVAL; | ||
169 | |||
170 | d = inode->i_bdev->bd_disk->private_data; | ||
171 | if ((d->flags & DEVFL_UP) == 0) { | ||
172 | printk(KERN_ERR "aoe: aoeblk_ioctl: disk not up\n"); | ||
173 | return -ENODEV; | ||
174 | } | ||
175 | |||
176 | if (cmd == HDIO_GETGEO) { | ||
177 | d->geo.start = get_start_sect(inode->i_bdev); | ||
178 | if (!copy_to_user((void __user *) arg, &d->geo, sizeof d->geo)) | ||
179 | return 0; | ||
180 | return -EFAULT; | ||
181 | } | ||
182 | printk(KERN_INFO "aoe: aoeblk_ioctl: unknown ioctl %d\n", cmd); | ||
183 | return -EINVAL; | ||
184 | } | ||
185 | |||
186 | static struct block_device_operations aoe_bdops = { | ||
187 | .open = aoeblk_open, | ||
188 | .release = aoeblk_release, | ||
189 | .ioctl = aoeblk_ioctl, | ||
190 | .owner = THIS_MODULE, | ||
191 | }; | ||
192 | |||
193 | /* alloc_disk and add_disk can sleep */ | ||
194 | void | ||
195 | aoeblk_gdalloc(void *vp) | ||
196 | { | ||
197 | struct aoedev *d = vp; | ||
198 | struct gendisk *gd; | ||
199 | ulong flags; | ||
200 | |||
201 | gd = alloc_disk(AOE_PARTITIONS); | ||
202 | if (gd == NULL) { | ||
203 | printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate disk " | ||
204 | "structure for %ld.%ld\n", d->aoemajor, d->aoeminor); | ||
205 | spin_lock_irqsave(&d->lock, flags); | ||
206 | d->flags &= ~DEVFL_WORKON; | ||
207 | spin_unlock_irqrestore(&d->lock, flags); | ||
208 | return; | ||
209 | } | ||
210 | |||
211 | d->bufpool = mempool_create(MIN_BUFS, | ||
212 | mempool_alloc_slab, mempool_free_slab, | ||
213 | buf_pool_cache); | ||
214 | if (d->bufpool == NULL) { | ||
215 | printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate bufpool " | ||
216 | "for %ld.%ld\n", d->aoemajor, d->aoeminor); | ||
217 | put_disk(gd); | ||
218 | spin_lock_irqsave(&d->lock, flags); | ||
219 | d->flags &= ~DEVFL_WORKON; | ||
220 | spin_unlock_irqrestore(&d->lock, flags); | ||
221 | return; | ||
222 | } | ||
223 | |||
224 | spin_lock_irqsave(&d->lock, flags); | ||
225 | blk_queue_make_request(&d->blkq, aoeblk_make_request); | ||
226 | gd->major = AOE_MAJOR; | ||
227 | gd->first_minor = d->sysminor * AOE_PARTITIONS; | ||
228 | gd->fops = &aoe_bdops; | ||
229 | gd->private_data = d; | ||
230 | gd->capacity = d->ssize; | ||
231 | snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%ld", | ||
232 | d->aoemajor, d->aoeminor); | ||
233 | |||
234 | gd->queue = &d->blkq; | ||
235 | d->gd = gd; | ||
236 | d->flags &= ~DEVFL_WORKON; | ||
237 | d->flags |= DEVFL_UP; | ||
238 | |||
239 | spin_unlock_irqrestore(&d->lock, flags); | ||
240 | |||
241 | add_disk(gd); | ||
242 | aoedisk_add_sysfs(d); | ||
243 | |||
244 | printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu " | ||
245 | "sectors\n", (unsigned long long)mac_addr(d->addr), | ||
246 | d->aoemajor, d->aoeminor, | ||
247 | d->fw_ver, (long long)d->ssize); | ||
248 | } | ||
249 | |||
250 | void | ||
251 | aoeblk_exit(void) | ||
252 | { | ||
253 | kmem_cache_destroy(buf_pool_cache); | ||
254 | } | ||
255 | |||
256 | int __init | ||
257 | aoeblk_init(void) | ||
258 | { | ||
259 | buf_pool_cache = kmem_cache_create("aoe_bufs", | ||
260 | sizeof(struct buf), | ||
261 | 0, 0, NULL, NULL); | ||
262 | if (buf_pool_cache == NULL) | ||
263 | return -ENOMEM; | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||