ide: add generic ATA/ATAPI disk driver

* Add struct ide_disk_ops containing protocol specific methods.

* Add 'struct ide_disk_ops *' to ide_drive_t.

* Convert ide-{disk,floppy} drivers to use struct ide_disk_ops.

* Merge ide-{disk,floppy} drivers into generic ide-gd driver.

While at it:
- ide_disk_init_capacity() -> ide_disk_get_capacity()

Acked-by: Borislav Petkov <petkovbb@gmail.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
This commit is contained in:
Bartlomiej Zolnierkiewicz 2008-10-17 18:09:14 +02:00
parent 79cb380397
commit 806f80a6fc
13 changed files with 304 additions and 456 deletions

View file

@ -84,21 +84,40 @@ config BLK_DEV_IDE_SATA
If unsure, say N. If unsure, say N.
config BLK_DEV_IDEDISK config IDE_GD
tristate "Include IDE/ATA-2 DISK support" tristate "generic ATA/ATAPI disk support"
---help--- default y
This will include enhanced support for MFM/RLL/IDE hard disks. If help
you have a MFM/RLL/IDE disk, and there is no special reason to use Support for ATA/ATAPI disks (including ATAPI floppy drives).
the old hard disk driver instead, say Y. If you have an SCSI-only
system, you can say N here.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here.
module will be called ide-disk. The module will be called ide-gd_mod.
Do not compile this driver as a module if your root file system
(the one containing the directory /) is located on the IDE disk.
If unsure, say Y. If unsure, say Y.
config IDE_GD_ATA
bool "ATA disk support"
depends on IDE_GD
default y
help
This will include support for ATA hard disks.
If unsure, say Y.
config IDE_GD_ATAPI
bool "ATAPI floppy support"
depends on IDE_GD
select IDE_ATAPI
help
This will include support for ATAPI floppy drives
(i.e. Iomega ZIP or MKE LS-120).
For information about jumper settings and the question
of when a ZIP drive uses a partition table, see
<http://www.win.tue.nl/~aeb/linux/zip/zip-1.html>.
If unsure, say N.
config BLK_DEV_IDECS config BLK_DEV_IDECS
tristate "PCMCIA IDE support" tristate "PCMCIA IDE support"
depends on PCMCIA depends on PCMCIA
@ -163,29 +182,6 @@ config BLK_DEV_IDETAPE
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called ide-tape. module will be called ide-tape.
config BLK_DEV_IDEFLOPPY
tristate "Include IDE/ATAPI FLOPPY support"
select IDE_ATAPI
---help---
If you have an IDE floppy drive which uses the ATAPI protocol,
answer Y. ATAPI is a newer protocol used by IDE CD-ROM/tape/floppy
drives, similar to the SCSI protocol.
The LS-120 and the IDE/ATAPI Iomega ZIP drive are also supported by
this driver. For information about jumper settings and the question
of when a ZIP drive uses a partition table, see
<http://www.win.tue.nl/~aeb/linux/zip/zip-1.html>.
(ATAPI PD-CD/CDR drives are not supported by this driver; support
for PD-CD/CDR drives is available if you answer Y to
"SCSI emulation support", below).
If you say Y here, the FLOPPY drive will be identified along with
other IDE devices, as "hdb" or "hdc", or something similar (check
the boot messages with dmesg).
To compile this driver as a module, choose M here: the
module will be called ide-floppy.
config BLK_DEV_IDESCSI config BLK_DEV_IDESCSI
tristate "SCSI emulation support (DEPRECATED)" tristate "SCSI emulation support (DEPRECATED)"
depends on SCSI depends on SCSI

View file

@ -37,18 +37,25 @@ obj-$(CONFIG_IDE_H8300) += h8300/
obj-$(CONFIG_IDE_GENERIC) += ide-generic.o obj-$(CONFIG_IDE_GENERIC) += ide-generic.o
obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
ide-disk_mod-y += ide-gd.o ide-disk.o ide-disk_ioctl.o ide-gd_mod-y += ide-gd.o
ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o ide-cd_mod-y += ide-cd.o ide-cd_ioctl.o ide-cd_verbose.o
ide-floppy_mod-y += ide-gd-floppy.o ide-floppy.o ide-floppy_ioctl.o
ifeq ($(CONFIG_IDE_GD_ATA), y)
ide-gd_mod-y += ide-disk.o ide-disk_ioctl.o
ifeq ($(CONFIG_IDE_PROC_FS), y) ifeq ($(CONFIG_IDE_PROC_FS), y)
ide-disk_mod-y += ide-disk_proc.o ide-gd_mod-y += ide-disk_proc.o
ide-floppy_mod-y += ide-floppy_proc.o endif
endif endif
obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk_mod.o ifeq ($(CONFIG_IDE_GD_ATAPI), y)
ide-gd_mod-y += ide-floppy.o ide-floppy_ioctl.o
ifeq ($(CONFIG_IDE_PROC_FS), y)
ide-gd_mod-y += ide-floppy_proc.o
endif
endif
obj-$(CONFIG_IDE_GD) += ide-gd_mod.o
obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd_mod.o obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd_mod.o
obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy_mod.o
obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o
ifeq ($(CONFIG_BLK_DEV_IDECS), y) ifeq ($(CONFIG_BLK_DEV_IDECS), y)

View file

@ -184,8 +184,8 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
* 1073741822 == 549756 MB or 48bit addressing fake drive * 1073741822 == 549756 MB or 48bit addressing fake drive
*/ */
ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq,
sector_t block) sector_t block)
{ {
ide_hwif_t *hwif = HWIF(drive); ide_hwif_t *hwif = HWIF(drive);
@ -333,7 +333,7 @@ static void idedisk_check_hpa(ide_drive_t *drive)
} }
} }
void ide_disk_init_capacity(ide_drive_t *drive) static int ide_disk_get_capacity(ide_drive_t *drive)
{ {
u16 *id = drive->id; u16 *id = drive->id;
int lba; int lba;
@ -382,6 +382,8 @@ void ide_disk_init_capacity(ide_drive_t *drive)
} else } else
drive->dev_flags &= ~IDE_DFLAG_LBA48; drive->dev_flags &= ~IDE_DFLAG_LBA48;
} }
return 0;
} }
static void idedisk_prepare_flush(struct request_queue *q, struct request *rq) static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
@ -590,7 +592,12 @@ ide_ext_devset_rw(wcache, wcache);
ide_ext_devset_rw_sync(nowerr, nowerr); ide_ext_devset_rw_sync(nowerr, nowerr);
void ide_disk_setup(ide_drive_t *drive) static int ide_disk_check(ide_drive_t *drive, const char *s)
{
return 1;
}
static void ide_disk_setup(ide_drive_t *drive)
{ {
struct ide_disk_obj *idkp = drive->driver_data; struct ide_disk_obj *idkp = drive->driver_data;
ide_hwif_t *hwif = drive->hwif; ide_hwif_t *hwif = drive->hwif;
@ -626,7 +633,7 @@ void ide_disk_setup(ide_drive_t *drive)
drive->queue->max_sectors / 2); drive->queue->max_sectors / 2);
/* calculate drive capacity, and select LBA if possible */ /* calculate drive capacity, and select LBA if possible */
ide_disk_init_capacity(drive); ide_disk_get_capacity(drive);
/* /*
* if possible, give fdisk access to more of the drive, * if possible, give fdisk access to more of the drive,
@ -682,7 +689,7 @@ void ide_disk_setup(ide_drive_t *drive)
drive->dev_flags |= IDE_DFLAG_ATTACH; drive->dev_flags |= IDE_DFLAG_ATTACH;
} }
void ide_disk_flush(ide_drive_t *drive) static void ide_disk_flush(ide_drive_t *drive)
{ {
if (ata_id_flush_enabled(drive->id) == 0 || if (ata_id_flush_enabled(drive->id) == 0 ||
(drive->dev_flags & IDE_DFLAG_WCACHE) == 0) (drive->dev_flags & IDE_DFLAG_WCACHE) == 0)
@ -692,7 +699,13 @@ void ide_disk_flush(ide_drive_t *drive)
printk(KERN_INFO "%s: wcache flush failed!\n", drive->name); printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);
} }
int ide_disk_set_doorlock(ide_drive_t *drive, int on) static int ide_disk_init_media(ide_drive_t *drive, struct gendisk *disk)
{
return 0;
}
static int ide_disk_set_doorlock(ide_drive_t *drive, struct gendisk *disk,
int on)
{ {
ide_task_t task; ide_task_t task;
int ret; int ret;
@ -711,3 +724,15 @@ int ide_disk_set_doorlock(ide_drive_t *drive, int on)
return ret; return ret;
} }
const struct ide_disk_ops ide_ata_disk_ops = {
.check = ide_disk_check,
.get_capacity = ide_disk_get_capacity,
.setup = ide_disk_setup,
.flush = ide_disk_flush,
.init_media = ide_disk_init_media,
.set_doorlock = ide_disk_set_doorlock,
.do_request = ide_do_rw_disk,
.end_request = ide_end_request,
.ioctl = ide_disk_ioctl,
};

View file

@ -1,22 +1,11 @@
#ifndef __IDE_DISK_H #ifndef __IDE_DISK_H
#define __IDE_DISK_H #define __IDE_DISK_H
struct ide_disk_obj { #include "ide-gd.h"
ide_drive_t *drive;
ide_driver_t *driver;
struct gendisk *disk;
struct kref kref;
unsigned int openers; /* protected by BKL for now */
};
sector_t ide_gd_capacity(ide_drive_t *);
#ifdef CONFIG_IDE_GD_ATA
/* ide-disk.c */ /* ide-disk.c */
void ide_disk_init_capacity(ide_drive_t *); extern const struct ide_disk_ops ide_ata_disk_ops;
void ide_disk_setup(ide_drive_t *);
void ide_disk_flush(ide_drive_t *);
int ide_disk_set_doorlock(ide_drive_t *, int);
ide_startstop_t ide_do_rw_disk(ide_drive_t *, struct request *, sector_t);
ide_decl_devset(address); ide_decl_devset(address);
ide_decl_devset(multcount); ide_decl_devset(multcount);
ide_decl_devset(nowerr); ide_decl_devset(nowerr);
@ -24,12 +13,17 @@ ide_decl_devset(wcache);
ide_decl_devset(acoustic); ide_decl_devset(acoustic);
/* ide-disk_ioctl.c */ /* ide-disk_ioctl.c */
int ide_disk_ioctl(struct inode *, struct file *, unsigned int, unsigned long); int ide_disk_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int,
unsigned long);
#ifdef CONFIG_IDE_PROC_FS #ifdef CONFIG_IDE_PROC_FS
/* ide-disk_proc.c */ /* ide-disk_proc.c */
extern ide_proc_entry_t ide_disk_proc[]; extern ide_proc_entry_t ide_disk_proc[];
extern const struct ide_proc_devset ide_disk_settings[]; extern const struct ide_proc_devset ide_disk_settings[];
#endif #endif
#else
#define ide_disk_proc NULL
#define ide_disk_settings NULL
#endif
#endif /* __IDE_DISK_H */ #endif /* __IDE_DISK_H */

View file

@ -13,12 +13,10 @@ static const struct ide_ioctl_devset ide_disk_ioctl_settings[] = {
{ 0 } { 0 }
}; };
int ide_disk_ioctl(struct inode *inode, struct file *file, int ide_disk_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct block_device *bdev = inode->i_bdev; struct block_device *bdev = inode->i_bdev;
struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
ide_drive_t *drive = idkp->drive;
int err; int err;
err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings); err = ide_setting_ioctl(drive, bdev, cmd, arg, ide_disk_ioctl_settings);

View file

@ -68,7 +68,7 @@
* Used to finish servicing a request. For read/write requests, we will call * Used to finish servicing a request. For read/write requests, we will call
* ide_end_request to pass to the next buffer. * ide_end_request to pass to the next buffer.
*/ */
int ide_floppy_end_request(ide_drive_t *drive, int uptodate, int nsecs) static int ide_floppy_end_request(ide_drive_t *drive, int uptodate, int nsecs)
{ {
idefloppy_floppy_t *floppy = drive->driver_data; idefloppy_floppy_t *floppy = drive->driver_data;
struct request *rq = HWGROUP(drive)->rq; struct request *rq = HWGROUP(drive)->rq;
@ -280,13 +280,12 @@ static void idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy,
pc->req_xfer = pc->buf_size = rq->data_len; pc->req_xfer = pc->buf_size = rq->data_len;
} }
ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, struct request *rq, static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
sector_t block_s) struct request *rq, sector_t block)
{ {
idefloppy_floppy_t *floppy = drive->driver_data; idefloppy_floppy_t *floppy = drive->driver_data;
ide_hwif_t *hwif = drive->hwif; ide_hwif_t *hwif = drive->hwif;
struct ide_atapi_pc *pc; struct ide_atapi_pc *pc;
unsigned long block = (unsigned long)block_s;
ide_debug_log(IDE_DBG_FUNC, "%s: dev: %s, cmd: 0x%x, cmd_type: %x, " ide_debug_log(IDE_DBG_FUNC, "%s: dev: %s, cmd: 0x%x, cmd_type: %x, "
"errors: %d\n", "errors: %d\n",
@ -316,7 +315,7 @@ ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, struct request *rq,
return ide_stopped; return ide_stopped;
} }
pc = &floppy->queued_pc; pc = &floppy->queued_pc;
idefloppy_create_rw_cmd(drive, pc, rq, block); idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block);
} else if (blk_special_request(rq)) { } else if (blk_special_request(rq)) {
pc = (struct ide_atapi_pc *) rq->buffer; pc = (struct ide_atapi_pc *) rq->buffer;
} else if (blk_pc_request(rq)) { } else if (blk_pc_request(rq)) {
@ -406,7 +405,7 @@ static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
* Determine if a media is present in the floppy drive, and if so, its LBA * Determine if a media is present in the floppy drive, and if so, its LBA
* capacity. * capacity.
*/ */
int ide_floppy_get_capacity(ide_drive_t *drive) static int ide_floppy_get_capacity(ide_drive_t *drive)
{ {
idefloppy_floppy_t *floppy = drive->driver_data; idefloppy_floppy_t *floppy = drive->driver_data;
struct gendisk *disk = floppy->disk; struct gendisk *disk = floppy->disk;
@ -505,9 +504,9 @@ int ide_floppy_get_capacity(ide_drive_t *drive)
return rc; return rc;
} }
void ide_floppy_setup(ide_drive_t *drive) static void ide_floppy_setup(ide_drive_t *drive)
{ {
struct ide_floppy_obj *floppy = drive->driver_data; struct ide_disk_obj *floppy = drive->driver_data;
u16 *id = drive->id; u16 *id = drive->id;
drive->pc_callback = ide_floppy_callback; drive->pc_callback = ide_floppy_callback;
@ -547,3 +546,33 @@ void ide_floppy_setup(ide_drive_t *drive)
drive->dev_flags |= IDE_DFLAG_ATTACH; drive->dev_flags |= IDE_DFLAG_ATTACH;
} }
static void ide_floppy_flush(ide_drive_t *drive)
{
}
static int ide_floppy_init_media(ide_drive_t *drive, struct gendisk *disk)
{
int ret = 0;
if (ide_do_test_unit_ready(drive, disk))
ide_do_start_stop(drive, disk, 1);
ret = ide_floppy_get_capacity(drive);
set_capacity(disk, ide_gd_capacity(drive));
return ret;
}
const struct ide_disk_ops ide_atapi_disk_ops = {
.check = ide_check_atapi_device,
.get_capacity = ide_floppy_get_capacity,
.setup = ide_floppy_setup,
.flush = ide_floppy_flush,
.init_media = ide_floppy_init_media,
.set_doorlock = ide_set_media_lock,
.do_request = ide_floppy_do_request,
.end_request = ide_floppy_end_request,
.ioctl = ide_floppy_ioctl,
};

View file

@ -1,48 +1,10 @@
#ifndef __IDE_FLOPPY_H #ifndef __IDE_FLOPPY_H
#define __IDE_FLOPPY_H #define __IDE_FLOPPY_H
#define DRV_NAME "ide-floppy" #include "ide-gd.h"
#define PFX DRV_NAME ": "
/* define to see debug info */ #ifdef CONFIG_IDE_GD_ATAPI
#define IDEFLOPPY_DEBUG_LOG 0 typedef struct ide_disk_obj idefloppy_floppy_t;
#if IDEFLOPPY_DEBUG_LOG
#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args)
#else
#define ide_debug_log(lvl, fmt, args...) do {} while (0)
#endif
/*
* Most of our global data which we need to save even as we leave the driver
* due to an interrupt or a timer event is stored in a variable of type
* idefloppy_floppy_t, defined below.
*/
typedef struct ide_floppy_obj {
ide_drive_t *drive;
ide_driver_t *driver;
struct gendisk *disk;
struct kref kref;
unsigned int openers; /* protected by BKL for now */
/* Last failed packet command */
struct ide_atapi_pc *failed_pc;
/* used for blk_{fs,pc}_request() requests */
struct ide_atapi_pc queued_pc;
/* Last error information */
u8 sense_key, asc, ascq;
int progress_indication;
/* Device information */
/* Current format */
int blocks, block_size, bs_factor;
/* Last format capacity descriptor */
u8 cap_desc[8];
/* Copy of the flexible disk page */
u8 flexible_disk_page[32];
} idefloppy_floppy_t;
/* /*
* Pages of the SELECT SENSE / MODE SENSE packet commands. * Pages of the SELECT SENSE / MODE SENSE packet commands.
@ -57,23 +19,23 @@ typedef struct ide_floppy_obj {
#define IDEFLOPPY_IOCTL_FORMAT_START 0x4602 #define IDEFLOPPY_IOCTL_FORMAT_START 0x4602
#define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS 0x4603 #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS 0x4603
sector_t ide_gd_capacity(ide_drive_t *);
/* ide-floppy.c */ /* ide-floppy.c */
extern const struct ide_disk_ops ide_atapi_disk_ops;
void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *, u8); void ide_floppy_create_mode_sense_cmd(struct ide_atapi_pc *, u8);
void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *); void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *);
int ide_floppy_get_capacity(ide_drive_t *);
void ide_floppy_setup(ide_drive_t *);
ide_startstop_t ide_floppy_do_request(ide_drive_t *, struct request *, sector_t);
int ide_floppy_end_request(ide_drive_t *, int, int);
/* ide-floppy_ioctl.c */ /* ide-floppy_ioctl.c */
int ide_floppy_ioctl(struct inode *, struct file *, unsigned, unsigned long); int ide_floppy_ioctl(ide_drive_t *, struct inode *, struct file *, unsigned int,
unsigned long);
#ifdef CONFIG_IDE_PROC_FS #ifdef CONFIG_IDE_PROC_FS
/* ide-floppy_proc.c */ /* ide-floppy_proc.c */
extern ide_proc_entry_t ide_floppy_proc[]; extern ide_proc_entry_t ide_floppy_proc[];
extern const struct ide_proc_devset ide_floppy_settings[]; extern const struct ide_proc_devset ide_floppy_settings[];
#endif #endif
#else
#define ide_floppy_proc NULL
#define ide_floppy_settings NULL
#endif
#endif /*__IDE_FLOPPY_H */ #endif /*__IDE_FLOPPY_H */

View file

@ -33,7 +33,7 @@
static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg) static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
{ {
struct ide_floppy_obj *floppy = drive->driver_data; struct ide_disk_obj *floppy = drive->driver_data;
struct ide_atapi_pc pc; struct ide_atapi_pc pc;
u8 header_len, desc_cnt; u8 header_len, desc_cnt;
int i, blocks, length, u_array_size, u_index; int i, blocks, length, u_array_size, u_index;
@ -260,13 +260,10 @@ static int ide_floppy_format_ioctl(ide_drive_t *drive, struct file *file,
} }
} }
int ide_floppy_ioctl(struct inode *inode, struct file *file, int ide_floppy_ioctl(ide_drive_t *drive, struct inode *inode,
unsigned int cmd, unsigned long arg) struct file *file, unsigned int cmd, unsigned long arg)
{ {
struct block_device *bdev = inode->i_bdev; struct block_device *bdev = inode->i_bdev;
struct ide_floppy_obj *floppy = ide_drv_g(bdev->bd_disk,
ide_floppy_obj);
ide_drive_t *drive = floppy->drive;
struct ide_atapi_pc pc; struct ide_atapi_pc pc;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int err; int err;

View file

@ -1,309 +0,0 @@
#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>
#include "ide-floppy.h"
#define IDEFLOPPY_VERSION "1.00"
/* module parameters */
static unsigned long debug_mask;
module_param(debug_mask, ulong, 0644);
static DEFINE_MUTEX(ide_disk_ref_mutex);
static void ide_disk_release(struct kref *);
static struct ide_floppy_obj *ide_disk_get(struct gendisk *disk)
{
struct ide_floppy_obj *idkp = NULL;
mutex_lock(&ide_disk_ref_mutex);
idkp = ide_drv_g(disk, ide_floppy_obj);
if (idkp) {
if (ide_device_get(idkp->drive))
idkp = NULL;
else
kref_get(&idkp->kref);
}
mutex_unlock(&ide_disk_ref_mutex);
return idkp;
}
static void ide_disk_put(struct ide_floppy_obj *idkp)
{
ide_drive_t *drive = idkp->drive;
mutex_lock(&ide_disk_ref_mutex);
kref_put(&idkp->kref, ide_disk_release);
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_floppy_obj *idkp = drive->driver_data;
struct gendisk *g = idkp->disk;
ide_proc_unregister_driver(drive, idkp->driver);
del_gendisk(g);
ide_disk_put(idkp);
}
static void ide_disk_release(struct kref *kref)
{
struct ide_floppy_obj *idkp = to_ide_drv(kref, ide_floppy_obj);
ide_drive_t *drive = idkp->drive;
struct gendisk *g = idkp->disk;
drive->driver_data = NULL;
g->private_data = NULL;
put_disk(g);
kfree(idkp);
}
#ifdef CONFIG_IDE_PROC_FS
static ide_proc_entry_t *ide_floppy_proc_entries(ide_drive_t *drive)
{
return ide_floppy_proc;
}
static const struct ide_proc_devset *ide_floppy_proc_devsets(ide_drive_t *drive)
{
return ide_floppy_settings;
}
#endif
static ide_driver_t ide_gd_driver = {
.gen_driver = {
.owner = THIS_MODULE,
.name = "ide-floppy",
.bus = &ide_bus_type,
},
.probe = ide_gd_probe,
.remove = ide_gd_remove,
.version = IDEFLOPPY_VERSION,
.do_request = ide_floppy_do_request,
.end_request = ide_floppy_end_request,
.error = __ide_error,
#ifdef CONFIG_IDE_PROC_FS
.proc_entries = ide_floppy_proc_entries,
.proc_devsets = ide_floppy_proc_devsets,
#endif
};
static int ide_gd_open(struct inode *inode, struct file *filp)
{
struct gendisk *disk = inode->i_bdev->bd_disk;
struct ide_floppy_obj *idkp;
ide_drive_t *drive;
int ret = 0;
idkp = ide_disk_get(disk);
if (idkp == NULL)
return -ENXIO;
drive = idkp->drive;
ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
idkp->openers++;
if (idkp->openers == 1) {
drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
/* Just in case */
if (ide_do_test_unit_ready(drive, disk))
ide_do_start_stop(drive, disk, 1);
ret = ide_floppy_get_capacity(drive);
set_capacity(disk, ide_gd_capacity(drive));
if (ret && (filp->f_flags & O_NDELAY) == 0) {
/*
* 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
*/
ret = -EIO;
goto out_put_idkp;
}
if ((drive->dev_flags & IDE_DFLAG_WP) && (filp->f_mode & 2)) {
ret = -EROFS;
goto out_put_idkp;
}
ide_set_media_lock(drive, disk, 1);
drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
check_disk_change(inode->i_bdev);
} else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) {
ret = -EBUSY;
goto out_put_idkp;
}
return 0;
out_put_idkp:
idkp->openers--;
ide_disk_put(idkp);
return ret;
}
static int ide_gd_release(struct inode *inode, struct file *filp)
{
struct gendisk *disk = inode->i_bdev->bd_disk;
struct ide_floppy_obj *idkp = ide_drv_g(disk, ide_floppy_obj);
ide_drive_t *drive = idkp->drive;
ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
if (idkp->openers == 1) {
ide_set_media_lock(drive, disk, 0);
drive->dev_flags &= ~IDE_DFLAG_FORMAT_IN_PROGRESS;
}
idkp->openers--;
ide_disk_put(idkp);
return 0;
}
static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
struct ide_floppy_obj *idkp = ide_drv_g(bdev->bd_disk, ide_floppy_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_floppy_obj *idkp = ide_drv_g(disk, ide_floppy_obj);
ide_drive_t *drive = idkp->drive;
int ret;
/* 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;
}
ret = !!(drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED);
drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED;
return ret;
}
static int ide_gd_revalidate_disk(struct gendisk *disk)
{
struct ide_floppy_obj *idkp = ide_drv_g(disk, ide_floppy_obj);
set_capacity(disk, ide_gd_capacity(idkp->drive));
return 0;
}
static struct block_device_operations ide_gd_ops = {
.owner = THIS_MODULE,
.open = ide_gd_open,
.release = ide_gd_release,
.ioctl = ide_floppy_ioctl,
.getgeo = ide_gd_getgeo,
.media_changed = ide_gd_media_changed,
.revalidate_disk = ide_gd_revalidate_disk
};
static int ide_gd_probe(ide_drive_t *drive)
{
struct ide_floppy_obj *idkp;
struct gendisk *g;
if (!strstr("ide-floppy", drive->driver_req))
goto failed;
if (drive->media != ide_floppy)
goto failed;
if (!ide_check_atapi_device(drive, DRV_NAME)) {
printk(KERN_ERR PFX "%s: not supported by this version of "
DRV_NAME "\n", drive->name);
goto failed;
}
idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
if (!idkp) {
printk(KERN_ERR PFX "%s: Can't allocate a floppy structure\n",
drive->name);
goto failed;
}
g = alloc_disk_node(1 << PARTN_BITS, hwif_to_node(drive->hwif));
if (!g)
goto out_free_idkp;
ide_init_disk(g, drive);
kref_init(&idkp->kref);
idkp->drive = drive;
idkp->driver = &ide_gd_driver;
idkp->disk = g;
g->private_data = &idkp->driver;
drive->driver_data = idkp;
drive->debug_mask = debug_mask;
ide_floppy_setup(drive);
set_capacity(g, ide_gd_capacity(drive));
g->minors = 1 << PARTN_BITS;
g->driverfs_dev = &drive->gendev;
if (drive->dev_flags & IDE_DFLAG_REMOVABLE)
g->flags = GENHD_FL_REMOVABLE;
g->fops = &ide_gd_ops;
add_disk(g);
return 0;
out_free_idkp:
kfree(idkp);
failed:
return -ENODEV;
}
static int __init ide_gd_init(void)
{
printk(KERN_INFO DRV_NAME " driver " IDEFLOPPY_VERSION "\n");
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-floppy*");
MODULE_ALIAS("ide-floppy");
module_init(ide_gd_init);
module_exit(ide_gd_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ATAPI FLOPPY Driver");

View file

@ -15,9 +15,14 @@
#endif #endif
#include "ide-disk.h" #include "ide-disk.h"
#include "ide-floppy.h"
#define IDE_GD_VERSION "1.18" #define IDE_GD_VERSION "1.18"
/* module parameters */
static unsigned long debug_mask;
module_param(debug_mask, ulong, 0644);
static DEFINE_MUTEX(ide_disk_ref_mutex); static DEFINE_MUTEX(ide_disk_ref_mutex);
static void ide_disk_release(struct kref *); static void ide_disk_release(struct kref *);
@ -64,7 +69,7 @@ static void ide_gd_remove(ide_drive_t *drive)
del_gendisk(g); del_gendisk(g);
ide_disk_flush(drive); drive->disk_ops->flush(drive);
ide_disk_put(idkp); ide_disk_put(idkp);
} }
@ -75,6 +80,7 @@ static void ide_disk_release(struct kref *kref)
ide_drive_t *drive = idkp->drive; ide_drive_t *drive = idkp->drive;
struct gendisk *g = idkp->disk; struct gendisk *g = idkp->disk;
drive->disk_ops = NULL;
drive->driver_data = NULL; drive->driver_data = NULL;
g->private_data = NULL; g->private_data = NULL;
put_disk(g); put_disk(g);
@ -89,7 +95,7 @@ static void ide_disk_release(struct kref *kref)
static void ide_gd_resume(ide_drive_t *drive) static void ide_gd_resume(ide_drive_t *drive)
{ {
if (ata_id_hpa_enabled(drive->id)) if (ata_id_hpa_enabled(drive->id))
ide_disk_init_capacity(drive); (void)drive->disk_ops->get_capacity(drive);
} }
static void ide_gd_shutdown(ide_drive_t *drive) static void ide_gd_shutdown(ide_drive_t *drive)
@ -110,7 +116,7 @@ static void ide_gd_shutdown(ide_drive_t *drive)
#else #else
if (system_state == SYSTEM_RESTART) { if (system_state == SYSTEM_RESTART) {
#endif #endif
ide_disk_flush(drive); drive->disk_ops->flush(drive);
return; return;
} }
@ -122,19 +128,31 @@ static void ide_gd_shutdown(ide_drive_t *drive)
#ifdef CONFIG_IDE_PROC_FS #ifdef CONFIG_IDE_PROC_FS
static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive) static ide_proc_entry_t *ide_disk_proc_entries(ide_drive_t *drive)
{ {
return ide_disk_proc; return (drive->media == ide_disk) ? ide_disk_proc : ide_floppy_proc;
} }
static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive) static const struct ide_proc_devset *ide_disk_proc_devsets(ide_drive_t *drive)
{ {
return ide_disk_settings; return (drive->media == ide_disk) ? ide_disk_settings
: ide_floppy_settings;
} }
#endif #endif
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);
}
static int ide_gd_end_request(ide_drive_t *drive, int uptodate, int nrsecs)
{
return drive->disk_ops->end_request(drive, uptodate, nrsecs);
}
static ide_driver_t ide_gd_driver = { static ide_driver_t ide_gd_driver = {
.gen_driver = { .gen_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "ide-disk", .name = "ide-gd",
.bus = &ide_bus_type, .bus = &ide_bus_type,
}, },
.probe = ide_gd_probe, .probe = ide_gd_probe,
@ -142,8 +160,8 @@ static ide_driver_t ide_gd_driver = {
.resume = ide_gd_resume, .resume = ide_gd_resume,
.shutdown = ide_gd_shutdown, .shutdown = ide_gd_shutdown,
.version = IDE_GD_VERSION, .version = IDE_GD_VERSION,
.do_request = ide_do_rw_disk, .do_request = ide_gd_do_request,
.end_request = ide_end_request, .end_request = ide_gd_end_request,
.error = __ide_error, .error = __ide_error,
#ifdef CONFIG_IDE_PROC_FS #ifdef CONFIG_IDE_PROC_FS
.proc_entries = ide_disk_proc_entries, .proc_entries = ide_disk_proc_entries,
@ -156,6 +174,7 @@ static int ide_gd_open(struct inode *inode, struct file *filp)
struct gendisk *disk = inode->i_bdev->bd_disk; struct gendisk *disk = inode->i_bdev->bd_disk;
struct ide_disk_obj *idkp; struct ide_disk_obj *idkp;
ide_drive_t *drive; ide_drive_t *drive;
int ret = 0;
idkp = ide_disk_get(disk); idkp = ide_disk_get(disk);
if (idkp == NULL) if (idkp == NULL)
@ -163,19 +182,49 @@ static int ide_gd_open(struct inode *inode, struct file *filp)
drive = idkp->drive; drive = idkp->drive;
ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
idkp->openers++; idkp->openers++;
if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) { if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) {
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
*/
if (ret && (filp->f_flags & O_NDELAY) == 0) {
ret = -EIO;
goto out_put_idkp;
}
if ((drive->dev_flags & IDE_DFLAG_WP) && (filp->f_mode & 2)) {
ret = -EROFS;
goto out_put_idkp;
}
/* /*
* Ignore the return code from door_lock, * Ignore the return code from door_lock,
* since the open() has already succeeded, * since the open() has already succeeded,
* and the door_lock is irrelevant at this point. * and the door_lock is irrelevant at this point.
*/ */
ide_disk_set_doorlock(drive, 1); drive->disk_ops->set_doorlock(drive, disk, 1);
drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED; drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED;
check_disk_change(inode->i_bdev); check_disk_change(inode->i_bdev);
} else if (drive->dev_flags & IDE_DFLAG_FORMAT_IN_PROGRESS) {
ret = -EBUSY;
goto out_put_idkp;
} }
return 0; return 0;
out_put_idkp:
idkp->openers--;
ide_disk_put(idkp);
return ret;
} }
static int ide_gd_release(struct inode *inode, struct file *filp) static int ide_gd_release(struct inode *inode, struct file *filp)
@ -184,11 +233,15 @@ static int ide_gd_release(struct inode *inode, struct file *filp)
struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj);
ide_drive_t *drive = idkp->drive; ide_drive_t *drive = idkp->drive;
if (idkp->openers == 1) ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
ide_disk_flush(drive);
if ((drive->dev_flags & IDE_DFLAG_REMOVABLE) && idkp->openers == 1) if (idkp->openers == 1)
ide_disk_set_doorlock(drive, 0); drive->disk_ops->flush(drive);
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;
}
idkp->openers--; idkp->openers--;
@ -233,11 +286,21 @@ static int ide_gd_revalidate_disk(struct gendisk *disk)
return 0; return 0;
} }
static int ide_gd_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct block_device *bdev = inode->i_bdev;
struct ide_disk_obj *idkp = ide_drv_g(bdev->bd_disk, ide_disk_obj);
ide_drive_t *drive = idkp->drive;
return drive->disk_ops->ioctl(drive, inode, file, cmd, arg);
}
static struct block_device_operations ide_gd_ops = { static struct block_device_operations ide_gd_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = ide_gd_open, .open = ide_gd_open,
.release = ide_gd_release, .release = ide_gd_release,
.ioctl = ide_disk_ioctl, .ioctl = ide_gd_ioctl,
.getgeo = ide_gd_getgeo, .getgeo = ide_gd_getgeo,
.media_changed = ide_gd_media_changed, .media_changed = ide_gd_media_changed,
.revalidate_disk = ide_gd_revalidate_disk .revalidate_disk = ide_gd_revalidate_disk
@ -245,19 +308,37 @@ static struct block_device_operations ide_gd_ops = {
static int ide_gd_probe(ide_drive_t *drive) static int ide_gd_probe(ide_drive_t *drive)
{ {
const struct ide_disk_ops *disk_ops = NULL;
struct ide_disk_obj *idkp; struct ide_disk_obj *idkp;
struct gendisk *g; struct gendisk *g;
/* strstr("foo", "") is non-NULL */ /* strstr("foo", "") is non-NULL */
if (!strstr("ide-disk", drive->driver_req)) if (!strstr("ide-gd", drive->driver_req))
goto failed; goto failed;
if (drive->media != ide_disk) #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)
goto failed; goto failed;
if (disk_ops->check(drive, DRV_NAME) == 0) {
printk(KERN_ERR PFX "%s: not supported by this driver\n",
drive->name);
goto failed;
}
idkp = kzalloc(sizeof(*idkp), GFP_KERNEL); idkp = kzalloc(sizeof(*idkp), GFP_KERNEL);
if (!idkp) if (!idkp) {
printk(KERN_ERR PFX "%s: can't allocate a disk structure\n",
drive->name);
goto failed; goto failed;
}
g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif)); g = alloc_disk_node(IDE_DISK_MINORS, hwif_to_node(drive->hwif));
if (!g) if (!g)
@ -274,8 +355,10 @@ static int ide_gd_probe(ide_drive_t *drive)
g->private_data = &idkp->driver; g->private_data = &idkp->driver;
drive->driver_data = idkp; drive->driver_data = idkp;
drive->debug_mask = debug_mask;
drive->disk_ops = disk_ops;
ide_disk_setup(drive); disk_ops->setup(drive);
set_capacity(g, ide_gd_capacity(drive)); set_capacity(g, ide_gd_capacity(drive));
@ -296,6 +379,7 @@ static int ide_gd_probe(ide_drive_t *drive)
static int __init ide_gd_init(void) static int __init ide_gd_init(void)
{ {
printk(KERN_INFO DRV_NAME " driver " IDE_GD_VERSION "\n");
return driver_register(&ide_gd_driver.gen_driver); return driver_register(&ide_gd_driver.gen_driver);
} }
@ -306,7 +390,9 @@ static void __exit ide_gd_exit(void)
MODULE_ALIAS("ide:*m-disk*"); MODULE_ALIAS("ide:*m-disk*");
MODULE_ALIAS("ide-disk"); MODULE_ALIAS("ide-disk");
MODULE_ALIAS("ide:*m-floppy*");
MODULE_ALIAS("ide-floppy");
module_init(ide_gd_init); module_init(ide_gd_init);
module_exit(ide_gd_exit); module_exit(ide_gd_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ATA DISK Driver"); MODULE_DESCRIPTION("generic ATA/ATAPI disk driver");

44
drivers/ide/ide-gd.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef __IDE_GD_H
#define __IDE_GD_H
#define DRV_NAME "ide-gd"
#define PFX DRV_NAME ": "
/* define to see debug info */
#define IDE_GD_DEBUG_LOG 0
#if IDE_GD_DEBUG_LOG
#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args)
#else
#define ide_debug_log(lvl, fmt, args...) do {} while (0)
#endif
struct ide_disk_obj {
ide_drive_t *drive;
ide_driver_t *driver;
struct gendisk *disk;
struct kref kref;
unsigned int openers; /* protected by BKL for now */
/* Last failed packet command */
struct ide_atapi_pc *failed_pc;
/* used for blk_{fs,pc}_request() requests */
struct ide_atapi_pc queued_pc;
/* Last error information */
u8 sense_key, asc, ascq;
int progress_indication;
/* Device information */
/* Current format */
int blocks, block_size, bs_factor;
/* Last format capacity descriptor */
u8 cap_desc[8];
/* Copy of the flexible disk page */
u8 flexible_disk_page[32];
};
sector_t ide_gd_capacity(ide_drive_t *);
#endif /* __IDE_GD_H */

View file

@ -179,7 +179,7 @@ config LEDS_TRIGGER_TIMER
config LEDS_TRIGGER_IDE_DISK config LEDS_TRIGGER_IDE_DISK
bool "LED IDE Disk Trigger" bool "LED IDE Disk Trigger"
depends on LEDS_TRIGGERS && BLK_DEV_IDEDISK depends on LEDS_TRIGGERS && IDE_GD_ATA
help help
This allows LEDs to be controlled by IDE disk activity. This allows LEDs to be controlled by IDE disk activity.
If unsure, say Y. If unsure, say Y.

View file

@ -461,6 +461,23 @@ struct ide_acpi_drive_link;
struct ide_acpi_hwif_link; struct ide_acpi_hwif_link;
#endif #endif
struct ide_drive_s;
struct ide_disk_ops {
int (*check)(struct ide_drive_s *, const char *);
int (*get_capacity)(struct ide_drive_s *);
void (*setup)(struct ide_drive_s *);
void (*flush)(struct ide_drive_s *);
int (*init_media)(struct ide_drive_s *, struct gendisk *);
int (*set_doorlock)(struct ide_drive_s *, struct gendisk *,
int);
ide_startstop_t (*do_request)(struct ide_drive_s *, struct request *,
sector_t);
int (*end_request)(struct ide_drive_s *, int, int);
int (*ioctl)(struct ide_drive_s *, struct inode *,
struct file *, unsigned int, unsigned long);
};
/* ATAPI device flags */ /* ATAPI device flags */
enum { enum {
IDE_AFLAG_DRQ_INTERRUPT = (1 << 0), IDE_AFLAG_DRQ_INTERRUPT = (1 << 0),
@ -594,6 +611,8 @@ struct ide_drive_s {
#endif #endif
struct hwif_s *hwif; /* actually (ide_hwif_t *) */ struct hwif_s *hwif; /* actually (ide_hwif_t *) */
const struct ide_disk_ops *disk_ops;
unsigned long dev_flags; unsigned long dev_flags;
unsigned long sleep; /* sleep until this time */ unsigned long sleep; /* sleep until this time */