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 268