2005-04-16 15:20:36 -07:00
/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
/*
* aoeblk . c
* block device routines
*/
# include <linux/hdreg.h>
# include <linux/blkdev.h>
# include <linux/fs.h>
# include <linux/ioctl.h>
# include <linux/genhd.h>
# include <linux/netdevice.h>
# include "aoe.h"
static kmem_cache_t * buf_pool_cache ;
/* add attributes for our block devices in sysfs */
static ssize_t aoedisk_show_state ( struct gendisk * disk , char * page )
{
struct aoedev * d = disk - > private_data ;
return snprintf ( page , PAGE_SIZE ,
" %s%s \n " ,
( d - > flags & DEVFL_UP ) ? " up " : " down " ,
2006-01-19 13:46:19 -05:00
( d - > flags & DEVFL_PAUSE ) ? " ,paused " :
( d - > nopen & & ! ( d - > flags & DEVFL_UP ) ) ? " ,closewait " : " " ) ;
/* I'd rather see nopen exported so we can ditch closewait */
2005-04-16 15:20:36 -07:00
}
static ssize_t aoedisk_show_mac ( struct gendisk * disk , char * page )
{
struct aoedev * d = disk - > private_data ;
return snprintf ( page , PAGE_SIZE , " %012llx \n " ,
( unsigned long long ) mac_addr ( d - > addr ) ) ;
}
static ssize_t aoedisk_show_netif ( struct gendisk * disk , char * page )
{
struct aoedev * d = disk - > private_data ;
return snprintf ( page , PAGE_SIZE , " %s \n " , d - > ifp - > name ) ;
}
2005-04-29 10:24:25 -04:00
/* firmware version */
static ssize_t aoedisk_show_fwver ( struct gendisk * disk , char * page )
{
struct aoedev * d = disk - > private_data ;
return snprintf ( page , PAGE_SIZE , " 0x%04x \n " , ( unsigned int ) d - > fw_ver ) ;
}
2005-04-16 15:20:36 -07:00
static struct disk_attribute disk_attr_state = {
. attr = { . name = " state " , . mode = S_IRUGO } ,
. show = aoedisk_show_state
} ;
static struct disk_attribute disk_attr_mac = {
. attr = { . name = " mac " , . mode = S_IRUGO } ,
. show = aoedisk_show_mac
} ;
static struct disk_attribute disk_attr_netif = {
. attr = { . name = " netif " , . mode = S_IRUGO } ,
. show = aoedisk_show_netif
} ;
2005-04-29 10:24:25 -04:00
static struct disk_attribute disk_attr_fwver = {
. attr = { . name = " firmware-version " , . mode = S_IRUGO } ,
. show = aoedisk_show_fwver
} ;
2005-04-16 15:20:36 -07:00
static void
aoedisk_add_sysfs ( struct aoedev * d )
{
sysfs_create_file ( & d - > gd - > kobj , & disk_attr_state . attr ) ;
sysfs_create_file ( & d - > gd - > kobj , & disk_attr_mac . attr ) ;
sysfs_create_file ( & d - > gd - > kobj , & disk_attr_netif . attr ) ;
2005-04-29 10:24:25 -04:00
sysfs_create_file ( & d - > gd - > kobj , & disk_attr_fwver . attr ) ;
2005-04-16 15:20:36 -07:00
}
void
aoedisk_rm_sysfs ( struct aoedev * d )
{
sysfs_remove_link ( & d - > gd - > kobj , " state " ) ;
sysfs_remove_link ( & d - > gd - > kobj , " mac " ) ;
sysfs_remove_link ( & d - > gd - > kobj , " netif " ) ;
2005-04-29 10:24:25 -04:00
sysfs_remove_link ( & d - > gd - > kobj , " firmware-version " ) ;
2005-04-16 15:20:36 -07:00
}
static int
aoeblk_open ( struct inode * inode , struct file * filp )
{
struct aoedev * d ;
ulong flags ;
d = inode - > i_bdev - > bd_disk - > private_data ;
spin_lock_irqsave ( & d - > lock , flags ) ;
if ( d - > flags & DEVFL_UP ) {
d - > nopen + + ;
spin_unlock_irqrestore ( & d - > lock , flags ) ;
return 0 ;
}
spin_unlock_irqrestore ( & d - > lock , flags ) ;
return - ENODEV ;
}
static int
aoeblk_release ( struct inode * inode , struct file * filp )
{
struct aoedev * d ;
ulong flags ;
d = inode - > i_bdev - > bd_disk - > private_data ;
spin_lock_irqsave ( & d - > lock , flags ) ;
2006-01-19 13:46:27 -05:00
if ( - - d - > nopen = = 0 ) {
2005-04-16 15:20:36 -07:00
spin_unlock_irqrestore ( & d - > lock , flags ) ;
aoecmd_cfg ( d - > aoemajor , d - > aoeminor ) ;
return 0 ;
}
spin_unlock_irqrestore ( & d - > lock , flags ) ;
return 0 ;
}
static int
aoeblk_make_request ( request_queue_t * q , struct bio * bio )
{
struct aoedev * d ;
struct buf * buf ;
struct sk_buff * sl ;
ulong flags ;
blk_queue_bounce ( q , & bio ) ;
d = bio - > bi_bdev - > bd_disk - > private_data ;
buf = mempool_alloc ( d - > bufpool , GFP_NOIO ) ;
if ( buf = = NULL ) {
printk ( KERN_INFO " aoe: aoeblk_make_request: buf allocation "
" failure \n " ) ;
bio_endio ( bio , bio - > bi_size , - ENOMEM ) ;
return 0 ;
}
memset ( buf , 0 , sizeof ( * buf ) ) ;
INIT_LIST_HEAD ( & buf - > bufs ) ;
2005-04-18 22:00:22 -07:00
buf - > start_time = jiffies ;
2005-04-16 15:20:36 -07:00
buf - > bio = bio ;
buf - > resid = bio - > bi_size ;
buf - > sector = bio - > bi_sector ;
buf - > bv = buf - > bio - > bi_io_vec ;
buf - > bv_resid = buf - > bv - > bv_len ;
buf - > bufaddr = page_address ( buf - > bv - > bv_page ) + buf - > bv - > bv_offset ;
spin_lock_irqsave ( & d - > lock , flags ) ;
if ( ( d - > flags & DEVFL_UP ) = = 0 ) {
printk ( KERN_INFO " aoe: aoeblk_make_request: device %ld.%ld is not up \n " ,
d - > aoemajor , d - > aoeminor ) ;
spin_unlock_irqrestore ( & d - > lock , flags ) ;
mempool_free ( buf , d - > bufpool ) ;
bio_endio ( bio , bio - > bi_size , - ENXIO ) ;
return 0 ;
}
list_add_tail ( & buf - > bufs , & d - > bufq ) ;
2006-01-19 13:46:19 -05:00
aoecmd_work ( d ) ;
2005-04-18 22:00:22 -07:00
sl = d - > sendq_hd ;
d - > sendq_hd = d - > sendq_tl = NULL ;
2005-04-16 15:20:36 -07:00
spin_unlock_irqrestore ( & d - > lock , flags ) ;
aoenet_xmit ( sl ) ;
2006-01-19 13:46:19 -05:00
2005-04-16 15:20:36 -07:00
return 0 ;
}
static int
2006-01-08 01:02:50 -08:00
aoeblk_getgeo ( struct block_device * bdev , struct hd_geometry * geo )
2005-04-16 15:20:36 -07:00
{
2006-01-08 01:02:50 -08:00
struct aoedev * d = bdev - > bd_disk - > private_data ;
2005-04-16 15:20:36 -07:00
if ( ( d - > flags & DEVFL_UP ) = = 0 ) {
printk ( KERN_ERR " aoe: aoeblk_ioctl: disk not up \n " ) ;
return - ENODEV ;
}
2006-01-08 01:02:50 -08:00
geo - > cylinders = d - > geo . cylinders ;
geo - > heads = d - > geo . heads ;
geo - > sectors = d - > geo . sectors ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
static struct block_device_operations aoe_bdops = {
. open = aoeblk_open ,
. release = aoeblk_release ,
2006-01-08 01:02:50 -08:00
. getgeo = aoeblk_getgeo ,
2005-04-16 15:20:36 -07:00
. owner = THIS_MODULE ,
} ;
/* alloc_disk and add_disk can sleep */
void
aoeblk_gdalloc ( void * vp )
{
struct aoedev * d = vp ;
struct gendisk * gd ;
ulong flags ;
gd = alloc_disk ( AOE_PARTITIONS ) ;
if ( gd = = NULL ) {
printk ( KERN_ERR " aoe: aoeblk_gdalloc: cannot allocate disk "
" structure for %ld.%ld \n " , d - > aoemajor , d - > aoeminor ) ;
spin_lock_irqsave ( & d - > lock , flags ) ;
2006-01-19 13:46:19 -05:00
d - > flags & = ~ DEVFL_GDALLOC ;
2005-04-16 15:20:36 -07:00
spin_unlock_irqrestore ( & d - > lock , flags ) ;
return ;
}
d - > bufpool = mempool_create ( MIN_BUFS ,
mempool_alloc_slab , mempool_free_slab ,
buf_pool_cache ) ;
if ( d - > bufpool = = NULL ) {
printk ( KERN_ERR " aoe: aoeblk_gdalloc: cannot allocate bufpool "
" for %ld.%ld \n " , d - > aoemajor , d - > aoeminor ) ;
put_disk ( gd ) ;
spin_lock_irqsave ( & d - > lock , flags ) ;
2006-01-19 13:46:19 -05:00
d - > flags & = ~ DEVFL_GDALLOC ;
2005-04-16 15:20:36 -07:00
spin_unlock_irqrestore ( & d - > lock , flags ) ;
return ;
}
spin_lock_irqsave ( & d - > lock , flags ) ;
blk_queue_make_request ( & d - > blkq , aoeblk_make_request ) ;
gd - > major = AOE_MAJOR ;
gd - > first_minor = d - > sysminor * AOE_PARTITIONS ;
gd - > fops = & aoe_bdops ;
gd - > private_data = d ;
gd - > capacity = d - > ssize ;
snprintf ( gd - > disk_name , sizeof gd - > disk_name , " etherd/e%ld.%ld " ,
d - > aoemajor , d - > aoeminor ) ;
gd - > queue = & d - > blkq ;
d - > gd = gd ;
2006-01-19 13:46:19 -05:00
d - > flags & = ~ DEVFL_GDALLOC ;
2005-04-16 15:20:36 -07:00
d - > flags | = DEVFL_UP ;
spin_unlock_irqrestore ( & d - > lock , flags ) ;
add_disk ( gd ) ;
aoedisk_add_sysfs ( d ) ;
}
void
aoeblk_exit ( void )
{
kmem_cache_destroy ( buf_pool_cache ) ;
}
int __init
aoeblk_init ( void )
{
buf_pool_cache = kmem_cache_create ( " aoe_bufs " ,
sizeof ( struct buf ) ,
0 , 0 , NULL , NULL ) ;
if ( buf_pool_cache = = NULL )
return - ENOMEM ;
return 0 ;
}