2008-10-17 18:09:12 +02:00
# include <linux/module.h>
# include <linux/types.h>
# include <linux/string.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/genhd.h>
# include <linux/mutex.h>
# include <linux/ide.h>
# include <linux/hdreg.h>
2009-04-22 20:33:41 +02:00
# include <linux/dmi.h>
2008-10-17 18:09:12 +02:00
# if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT)
# define IDE_DISK_MINORS (1 << PARTN_BITS)
# else
# define IDE_DISK_MINORS 0
# endif
# include "ide-disk.h"
2008-10-17 18:09:14 +02:00
# include "ide-floppy.h"
2008-10-17 18:09:12 +02:00
# define IDE_GD_VERSION "1.18"
2008-10-17 18:09:14 +02:00
/* module parameters */
static unsigned long debug_mask ;
module_param ( debug_mask , ulong , 0644 ) ;
2008-10-17 18:09:12 +02:00
static DEFINE_MUTEX ( ide_disk_ref_mutex ) ;
2009-02-25 20:28:24 +01:00
static void ide_disk_release ( struct device * ) ;
2008-10-17 18:09:12 +02:00
static struct ide_disk_obj * ide_disk_get ( struct gendisk * disk )
{
struct ide_disk_obj * idkp = NULL ;
mutex_lock ( & ide_disk_ref_mutex ) ;
idkp = ide_drv_g ( disk , ide_disk_obj ) ;
if ( idkp ) {
if ( ide_device_get ( idkp - > drive ) )
idkp = NULL ;
else
2009-02-25 20:28:24 +01:00
get_device ( & idkp - > dev ) ;
2008-10-17 18:09:12 +02:00
}
mutex_unlock ( & ide_disk_ref_mutex ) ;
return idkp ;
}
static void ide_disk_put ( struct ide_disk_obj * idkp )
{
ide_drive_t * drive = idkp - > drive ;
mutex_lock ( & ide_disk_ref_mutex ) ;
2009-02-25 20:28:24 +01:00
put_device ( & idkp - > dev ) ;
2008-10-17 18:09:12 +02:00
ide_device_put ( drive ) ;
mutex_unlock ( & ide_disk_ref_mutex ) ;
}
sector_t ide_gd_capacity ( ide_drive_t * drive )
{
return drive - > capacity64 ;
}
static int ide_gd_probe ( ide_drive_t * ) ;
static void ide_gd_remove ( ide_drive_t * drive )
{
struct ide_disk_obj * idkp = drive - > driver_data ;
struct gendisk * g = idkp - > disk ;
ide_proc_unregister_driver ( drive , idkp - > driver ) ;
2009-02-25 20:28:24 +01:00
device_del ( & idkp - > dev ) ;
2008-10-17 18:09:12 +02:00
del_gendisk ( g ) ;
2008-10-17 18:09:14 +02:00
drive - > disk_ops - > flush ( drive ) ;
2008-10-17 18:09:12 +02:00
2009-02-25 20:28:24 +01:00
mutex_lock ( & ide_disk_ref_mutex ) ;
put_device ( & idkp - > dev ) ;
mutex_unlock ( & ide_disk_ref_mutex ) ;
2008-10-17 18:09:12 +02:00
}
2009-02-25 20:28:24 +01:00
static void ide_disk_release ( struct device * dev )
2008-10-17 18:09:12 +02:00
{
2009-02-25 20:28:24 +01:00
struct ide_disk_obj * idkp = to_ide_drv ( dev , ide_disk_obj ) ;
2008-10-17 18:09:12 +02:00
ide_drive_t * drive = idkp - > drive ;
struct gendisk * g = idkp - > disk ;
2008-10-17 18:09:14 +02:00
drive - > disk_ops = NULL ;
2008-10-17 18:09:12 +02:00
drive - > driver_data = NULL ;
g - > private_data = NULL ;
put_disk ( g ) ;
kfree ( idkp ) ;
}
/*
* On HPA drives the capacity needs to be
* reinitilized on resume otherwise the disk
* can not be used and a hard reset is required
*/
static void ide_gd_resume ( ide_drive_t * drive )
{
if ( ata_id_hpa_enabled ( drive - > id ) )
2008-10-17 18:09:14 +02:00
( void ) drive - > disk_ops - > get_capacity ( drive ) ;
2008-10-17 18:09:12 +02:00
}
2009-04-22 20:33:41 +02:00
static const struct dmi_system_id ide_coldreboot_table [ ] = {
{
/* Acer TravelMate 66x cuts power during reboot */
. ident = " Acer TravelMate 660 " ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " Acer " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " TravelMate 660 " ) ,
} ,
} ,
{ } /* terminate list */
} ;
2008-10-17 18:09:12 +02:00
static void ide_gd_shutdown ( ide_drive_t * drive )
{
# ifdef CONFIG_ALPHA
/* On Alpha, halt(8) doesn't actually turn the machine off,
it puts you into the sort of firmware monitor . Typically ,
it ' s used to boot another kernel image , so it ' s not much
different from reboot ( 8 ) . Therefore , we don ' t need to
spin down the disk in this case , especially since Alpha
firmware doesn ' t handle disks in standby mode properly .
On the other hand , it ' s reasonably safe to turn the power
off when the shutdown process reaches the firmware prompt ,
as the firmware initialization takes rather long time -
at least 10 seconds , which should be sufficient for
the disk to expire its write cache . */
if ( system_state ! = SYSTEM_POWER_OFF ) {
# else
2009-04-22 20:33:41 +02:00
if ( system_state = = SYSTEM_RESTART & &
! dmi_check_system ( ide_coldreboot_table ) ) {
2008-10-17 18:09:12 +02:00
# endif
2008-10-17 18:09:14 +02:00
drive - > disk_ops - > flush ( drive ) ;
2008-10-17 18:09:12 +02:00
return ;
}
printk ( KERN_INFO " Shutdown: %s \n " , drive - > name ) ;
drive - > gendev . bus - > suspend ( & drive - > gendev , PMSG_SUSPEND ) ;
}
2008-10-17 18:09:13 +02:00
# ifdef CONFIG_IDE_PROC_FS
static ide_proc_entry_t * ide_disk_proc_entries ( ide_drive_t * drive )
{
2008-10-17 18:09:14 +02:00
return ( drive - > media = = ide_disk ) ? ide_disk_proc : ide_floppy_proc ;
2008-10-17 18:09:13 +02:00
}
static const struct ide_proc_devset * ide_disk_proc_devsets ( ide_drive_t * drive )
{
2008-10-17 18:09:14 +02:00
return ( drive - > media = = ide_disk ) ? ide_disk_settings
: ide_floppy_settings ;
2008-10-17 18:09:13 +02:00
}
# endif
2008-10-17 18:09:14 +02:00
static ide_startstop_t ide_gd_do_request ( ide_drive_t * drive ,
struct request * rq , sector_t sector )
{
return drive - > disk_ops - > do_request ( drive , rq , sector ) ;
}
2009-01-06 17:20:53 +01:00
static struct ide_driver ide_gd_driver = {
2008-10-17 18:09:12 +02:00
. gen_driver = {
. owner = THIS_MODULE ,
2008-10-17 18:09:14 +02:00
. name = " ide-gd " ,
2008-10-17 18:09:12 +02:00
. bus = & ide_bus_type ,
} ,
. probe = ide_gd_probe ,
. remove = ide_gd_remove ,
. resume = ide_gd_resume ,
. shutdown = ide_gd_shutdown ,
. version = IDE_GD_VERSION ,
2008-10-17 18:09:14 +02:00
. do_request = ide_gd_do_request ,
2008-10-17 18:09:12 +02:00
# ifdef CONFIG_IDE_PROC_FS
2008-10-17 18:09:13 +02:00
. proc_entries = ide_disk_proc_entries ,
. proc_devsets = ide_disk_proc_devsets ,
2008-10-17 18:09:12 +02:00
# endif
} ;
2008-10-16 10:34:00 -04:00
static int ide_gd_open ( struct block_device * bdev , fmode_t mode )
2008-10-17 18:09:12 +02:00
{
2008-10-16 10:34:00 -04:00
struct gendisk * disk = bdev - > bd_disk ;
2008-10-17 18:09:12 +02:00
struct ide_disk_obj * idkp ;
ide_drive_t * drive ;
2008-10-17 18:09:14 +02:00
int ret = 0 ;
2008-10-17 18:09:12 +02:00
idkp = ide_disk_get ( disk ) ;
if ( idkp = = NULL )
return - ENXIO ;
drive = idkp - > drive ;
2009-01-02 13:34:47 +01:00
ide_debug_log ( IDE_DBG_FUNC , " enter " ) ;
2008-10-17 18:09:14 +02:00
2008-10-17 18:09:12 +02:00
idkp - > openers + + ;
if ( ( drive - > dev_flags & IDE_DFLAG_REMOVABLE ) & & idkp - > openers = = 1 ) {
2008-10-17 18:09:14 +02:00
drive - > dev_flags & = ~ IDE_DFLAG_FORMAT_IN_PROGRESS ;
/* Just in case */
ret = drive - > disk_ops - > init_media ( drive , disk ) ;
/*
* Allow O_NDELAY to open a drive without a disk , or with an
* unreadable disk , so that we can get the format capacity
* of the drive or begin the format - Sam
*/
2008-10-16 10:34:00 -04:00
if ( ret & & ( mode & FMODE_NDELAY ) = = 0 ) {
2008-10-17 18:09:14 +02:00
ret = - EIO ;
goto out_put_idkp ;
}
2008-10-16 10:34:00 -04:00
if ( ( drive - > dev_flags & IDE_DFLAG_WP ) & & ( mode & FMODE_WRITE ) ) {
2008-10-17 18:09:14 +02:00
ret = - EROFS ;
goto out_put_idkp ;
}
2008-10-17 18:09:12 +02:00
/*
* Ignore the return code from door_lock ,
* since the open ( ) has already succeeded ,
* and the door_lock is irrelevant at this point .
*/
2008-10-17 18:09:14 +02:00
drive - > disk_ops - > set_doorlock ( drive , disk , 1 ) ;
2008-10-17 18:09:12 +02:00
drive - > dev_flags | = IDE_DFLAG_MEDIA_CHANGED ;
2008-10-16 10:34:00 -04:00
check_disk_change ( bdev ) ;
2008-10-17 18:09:14 +02:00
} else if ( drive - > dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS ) {
ret = - EBUSY ;
goto out_put_idkp ;
2008-10-17 18:09:12 +02:00
}
return 0 ;
2008-10-17 18:09:14 +02:00
out_put_idkp :
idkp - > openers - - ;
ide_disk_put ( idkp ) ;
return ret ;
2008-10-17 18:09:12 +02:00
}
2008-10-16 10:34:00 -04:00
static int ide_gd_release ( struct gendisk * disk , fmode_t mode )
2008-10-17 18:09:12 +02:00
{
struct ide_disk_obj * idkp = ide_drv_g ( disk , ide_disk_obj ) ;
ide_drive_t * drive = idkp - > drive ;
2009-01-02 13:34:47 +01:00
ide_debug_log ( IDE_DBG_FUNC , " enter " ) ;
2008-10-17 18:09:14 +02:00
2008-10-17 18:09:12 +02:00
if ( idkp - > openers = = 1 )
2008-10-17 18:09:14 +02:00
drive - > disk_ops - > flush ( drive ) ;
2008-10-17 18:09:12 +02:00
2008-10-17 18:09:14 +02:00
if ( ( drive - > dev_flags & IDE_DFLAG_REMOVABLE ) & & idkp - > openers = = 1 ) {
drive - > disk_ops - > set_doorlock ( drive , disk , 0 ) ;
drive - > dev_flags & = ~ IDE_DFLAG_FORMAT_IN_PROGRESS ;
}
2008-10-17 18:09:12 +02:00
idkp - > openers - - ;
ide_disk_put ( idkp ) ;
return 0 ;
}
static int ide_gd_getgeo ( struct block_device * bdev , struct hd_geometry * geo )
{
struct ide_disk_obj * idkp = ide_drv_g ( bdev - > bd_disk , ide_disk_obj ) ;
ide_drive_t * drive = idkp - > drive ;
geo - > heads = drive - > bios_head ;
geo - > sectors = drive - > bios_sect ;
geo - > cylinders = ( u16 ) drive - > bios_cyl ; /* truncate */
return 0 ;
}
static int ide_gd_media_changed ( struct gendisk * disk )
{
struct ide_disk_obj * idkp = ide_drv_g ( disk , ide_disk_obj ) ;
ide_drive_t * drive = idkp - > drive ;
2008-10-17 18:09:12 +02:00
int ret ;
2008-10-17 18:09:12 +02:00
/* do not scan partitions twice if this is a removable device */
if ( drive - > dev_flags & IDE_DFLAG_ATTACH ) {
drive - > dev_flags & = ~ IDE_DFLAG_ATTACH ;
return 0 ;
}
2008-10-17 18:09:12 +02:00
ret = ! ! ( drive - > dev_flags & IDE_DFLAG_MEDIA_CHANGED ) ;
drive - > dev_flags & = ~ IDE_DFLAG_MEDIA_CHANGED ;
return ret ;
2008-10-17 18:09:12 +02:00
}
2009-06-07 13:52:52 +02:00
static unsigned long long ide_gd_set_capacity ( struct gendisk * disk ,
unsigned long long capacity )
{
struct ide_disk_obj * idkp = ide_drv_g ( disk , ide_disk_obj ) ;
ide_drive_t * drive = idkp - > drive ;
const struct ide_disk_ops * disk_ops = drive - > disk_ops ;
if ( disk_ops - > set_capacity )
return disk_ops - > set_capacity ( drive , capacity ) ;
return drive - > capacity64 ;
}
2008-10-17 18:09:12 +02:00
static int ide_gd_revalidate_disk ( struct gendisk * disk )
{
struct ide_disk_obj * idkp = ide_drv_g ( disk , ide_disk_obj ) ;
2008-11-02 21:40:10 +01:00
ide_drive_t * drive = idkp - > drive ;
if ( ide_gd_media_changed ( disk ) )
drive - > disk_ops - > get_capacity ( drive ) ;
set_capacity ( disk , ide_gd_capacity ( drive ) ) ;
2008-10-17 18:09:12 +02:00
return 0 ;
}
2008-10-16 10:34:00 -04:00
static int ide_gd_ioctl ( struct block_device * bdev , fmode_t mode ,
2008-10-17 18:09:14 +02:00
unsigned int cmd , unsigned long arg )
{
struct ide_disk_obj * idkp = ide_drv_g ( bdev - > bd_disk , ide_disk_obj ) ;
ide_drive_t * drive = idkp - > drive ;
2008-10-16 10:34:00 -04:00
return drive - > disk_ops - > ioctl ( drive , bdev , mode , cmd , arg ) ;
2008-10-17 18:09:14 +02:00
}
2009-09-21 17:01:13 -07:00
static const struct block_device_operations ide_gd_ops = {
2008-10-17 18:09:12 +02:00
. owner = THIS_MODULE ,
2008-10-16 10:34:00 -04:00
. open = ide_gd_open ,
. release = ide_gd_release ,
. locked_ioctl = ide_gd_ioctl ,
2008-10-17 18:09:12 +02:00
. getgeo = ide_gd_getgeo ,
. media_changed = ide_gd_media_changed ,
2009-06-07 13:52:52 +02:00
. set_capacity = ide_gd_set_capacity ,
2008-10-17 18:09:12 +02:00
. revalidate_disk = ide_gd_revalidate_disk
} ;
static int ide_gd_probe ( ide_drive_t * drive )
{
2008-10-17 18:09:14 +02:00
const struct ide_disk_ops * disk_ops = NULL ;
2008-10-17 18:09:12 +02:00
struct ide_disk_obj * idkp ;
struct gendisk * g ;
/* strstr("foo", "") is non-NULL */
2008-10-17 18:09:14 +02:00
if ( ! strstr ( " ide-gd " , drive - > driver_req ) )
goto failed ;
# ifdef CONFIG_IDE_GD_ATA
if ( drive - > media = = ide_disk )
disk_ops = & ide_ata_disk_ops ;
# endif
# ifdef CONFIG_IDE_GD_ATAPI
if ( drive - > media = = ide_floppy )
disk_ops = & ide_atapi_disk_ops ;
# endif
if ( disk_ops = = NULL )
2008-10-17 18:09:12 +02:00
goto failed ;
2008-10-17 18:09:14 +02:00
if ( disk_ops - > check ( drive , DRV_NAME ) = = 0 ) {
printk ( KERN_ERR PFX " %s: not supported by this driver \n " ,
drive - > name ) ;
2008-10-17 18:09:12 +02:00
goto failed ;
2008-10-17 18:09:14 +02:00
}
2008-10-17 18:09:12 +02:00
idkp = kzalloc ( sizeof ( * idkp ) , GFP_KERNEL ) ;
2008-10-17 18:09:14 +02:00
if ( ! idkp ) {
printk ( KERN_ERR PFX " %s: can't allocate a disk structure \n " ,
drive - > name ) ;
2008-10-17 18:09:12 +02:00
goto failed ;
2008-10-17 18:09:14 +02:00
}
2008-10-17 18:09:12 +02:00
g = alloc_disk_node ( IDE_DISK_MINORS , hwif_to_node ( drive - > hwif ) ) ;
if ( ! g )
goto out_free_idkp ;
ide_init_disk ( g , drive ) ;
2009-02-25 20:28:24 +01:00
idkp - > dev . parent = & drive - > gendev ;
idkp - > dev . release = ide_disk_release ;
dev_set_name ( & idkp - > dev , dev_name ( & drive - > gendev ) ) ;
if ( device_register ( & idkp - > dev ) )
goto out_free_disk ;
2008-10-17 18:09:12 +02:00
idkp - > drive = drive ;
idkp - > driver = & ide_gd_driver ;
idkp - > disk = g ;
g - > private_data = & idkp - > driver ;
drive - > driver_data = idkp ;
2008-10-17 18:09:14 +02:00
drive - > debug_mask = debug_mask ;
drive - > disk_ops = disk_ops ;
2008-10-17 18:09:12 +02:00
2008-10-17 18:09:14 +02:00
disk_ops - > setup ( drive ) ;
2008-10-17 18:09:12 +02:00
set_capacity ( g , ide_gd_capacity ( drive ) ) ;
g - > minors = IDE_DISK_MINORS ;
g - > driverfs_dev = & drive - > gendev ;
g - > flags | = GENHD_FL_EXT_DEVT ;
if ( drive - > dev_flags & IDE_DFLAG_REMOVABLE )
g - > flags = GENHD_FL_REMOVABLE ;
g - > fops = & ide_gd_ops ;
add_disk ( g ) ;
return 0 ;
2009-02-25 20:28:24 +01:00
out_free_disk :
put_disk ( g ) ;
2008-10-17 18:09:12 +02:00
out_free_idkp :
kfree ( idkp ) ;
failed :
return - ENODEV ;
}
static int __init ide_gd_init ( void )
{
2008-10-17 18:09:14 +02:00
printk ( KERN_INFO DRV_NAME " driver " IDE_GD_VERSION " \n " ) ;
2008-10-17 18:09:12 +02:00
return driver_register ( & ide_gd_driver . gen_driver ) ;
}
static void __exit ide_gd_exit ( void )
{
driver_unregister ( & ide_gd_driver . gen_driver ) ;
}
MODULE_ALIAS ( " ide:*m-disk* " ) ;
MODULE_ALIAS ( " ide-disk " ) ;
2008-10-17 18:09:14 +02:00
MODULE_ALIAS ( " ide:*m-floppy* " ) ;
MODULE_ALIAS ( " ide-floppy " ) ;
2008-10-17 18:09:12 +02:00
module_init ( ide_gd_init ) ;
module_exit ( ide_gd_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
2008-10-17 18:09:14 +02:00
MODULE_DESCRIPTION ( " generic ATA/ATAPI disk driver " ) ;