#include "ide-cd.h"
+static DECLARE_MUTEX(idecd_ref_sem);
+
+#define to_ide_cd(obj) container_of(obj, struct cdrom_info, kref)
+
+#define ide_cd_g(disk) \
+ container_of((disk)->private_data, struct cdrom_info, driver)
+
+static struct cdrom_info *ide_cd_get(struct gendisk *disk)
+{
+ struct cdrom_info *cd = NULL;
+
+ down(&idecd_ref_sem);
+ cd = ide_cd_g(disk);
+ if (cd)
+ kref_get(&cd->kref);
+ up(&idecd_ref_sem);
+ return cd;
+}
+
+static void ide_cd_release(struct kref *);
+
+static void ide_cd_put(struct cdrom_info *cd)
+{
+ down(&idecd_ref_sem);
+ kref_put(&cd->kref, ide_cd_release);
+ up(&idecd_ref_sem);
+}
+
/****************************************************************************
* Generic packet command support and error handling routines.
*/
unsigned long sector;
unsigned long bio_sectors;
unsigned long valid;
+ struct cdrom_info *info = drive->driver_data;
if (!cdrom_log_sense(drive, failed_command, sense))
return;
if(valid < 0)
valid = 0;
- if(sector < get_capacity(drive->disk) &&
+ if(sector < get_capacity(info->disk) &&
drive->probed_capacity - sector < 4 * 75) {
- set_capacity(drive->disk, sector);
+ set_capacity(info->disk, sector);
}
}
}
(sense->sense_key == NOT_READY && (sense->asc == 4 ||
sense->asc == 0x3a)))
return;
-
+
printk(KERN_ERR "%s: error code: 0x%02x sense_key: 0x%02x asc: 0x%02x ascq: 0x%02x\n",
drive->name,
sense->error_code, sense->sense_key,
/*
* Initialize a ide-cd packet command request
*/
-static void cdrom_prepare_request(struct request *rq)
+static void cdrom_prepare_request(ide_drive_t *drive, struct request *rq)
{
+ struct cdrom_info *cd = drive->driver_data;
+
ide_init_drive_cmd(rq);
rq->flags = REQ_PC;
+ rq->rq_disk = cd->disk;
}
static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
sense = &info->sense_data;
/* stuff the sense request in front of our current request */
- cdrom_prepare_request(rq);
+ cdrom_prepare_request(drive, rq);
rq->data = sense;
rq->cmd[0] = GPCMD_REQUEST_SENSE;
(void) ide_do_drive_cmd(drive, rq, ide_preempt);
}
-/*
- * ide_error() takes action based on the error returned by the drive.
- */
-static ide_startstop_t ide_cdrom_error (ide_drive_t *drive, const char *msg, byte stat)
-{
- struct request *rq;
- byte err;
-
- err = ide_dump_atapi_status(drive, msg, stat);
- if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
- return ide_stopped;
- /* retry only "normal" I/O: */
- if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) {
- rq->errors = 1;
- ide_end_drive_cmd(drive, stat, err);
- return ide_stopped;
- }
-
- if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
- /* other bits are useless when BUSY */
- rq->errors |= ERROR_RESET;
- } else {
- /* add decoding error stuff */
- }
- if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
- /* force an abort */
- HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
- if (rq->errors >= ERROR_MAX) {
- DRIVER(drive)->end_request(drive, 0, 0);
- } else {
- if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
- ++rq->errors;
- return ide_do_reset(drive);
- }
- ++rq->errors;
- }
- return ide_stopped;
-}
-
-static ide_startstop_t ide_cdrom_abort (ide_drive_t *drive, const char *msg)
-{
- struct request *rq;
-
- if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
- return ide_stopped;
- /* retry only "normal" I/O: */
- if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) {
- rq->errors = 1;
- ide_end_drive_cmd(drive, BUSY_STAT, 0);
- return ide_stopped;
- }
- rq->errors |= ERROR_RESET;
- DRIVER(drive)->end_request(drive, 0, 0);
- return ide_stopped;
-}
-
static void cdrom_end_request (ide_drive_t *drive, int uptodate)
{
struct request *rq = HWGROUP(drive)->rq;
rq->flags |= REQ_FAILED;
cdrom_end_request(drive, 0);
- DRIVER(drive)->error(drive, "request sense failure", stat);
+ ide_error(drive, "request sense failure", stat);
return 1;
} else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) {
} else if ((err & ~ABRT_ERR) != 0) {
/* Go to the default handler
for other errors. */
- DRIVER(drive)->error(drive, "cdrom_decode_status",stat);
+ ide_error(drive, "cdrom_decode_status", stat);
return 1;
} else if ((++rq->errors > ERROR_MAX)) {
/* We've racked up too many retries. Abort. */
return startstop;
if (info->dma)
- info->dma = !hwif->ide_dma_setup(drive);
+ info->dma = !hwif->dma_setup(drive);
/* Set up the controller registers. */
/* FIXME: for Virtual DMA we must check harder */
/* Start the DMA if need be */
if (info->dma)
- hwif->ide_dma_start(drive);
+ hwif->dma_start(drive);
return ide_started;
}
ide_end_request(drive, 1, rq->nr_sectors);
return ide_stopped;
} else
- return DRIVER(drive)->error(drive, "dma error", stat);
+ return ide_error(drive, "dma error", stat);
}
/* Read the interrupt reason and the transfer length. */
/* The drive is in the process of loading
a disk. Retry, but wait a little to give
the drive time to complete the load. */
- msleep(2000);
+ ssleep(2);
} else {
/* Otherwise, don't retry. */
retries = 0;
if (dma_error) {
printk(KERN_ERR "ide-cd: dma error\n");
__ide_dma_off(drive);
- return DRIVER(drive)->error(drive, "dma error", stat);
+ return ide_error(drive, "dma error", stat);
}
end_that_request_chunk(rq, 1, rq->data_len);
*/
if (dma) {
if (dma_error)
- return DRIVER(drive)->error(drive, "dma error", stat);
+ return ide_error(drive, "dma error", stat);
ide_end_request(drive, 1, rq->nr_sectors);
return ide_stopped;
static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
{
struct cdrom_info *info = drive->driver_data;
- struct gendisk *g = drive->disk;
+ struct gendisk *g = info->disk;
unsigned short sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;
/*
/*
* check if dma is safe
+ *
+ * NOTE! The "len" and "addr" checks should possibly have
+ * separate masks.
*/
- if ((rq->data_len & mask) || (addr & mask))
+ if ((rq->data_len & 15) || (addr & mask))
info->dma = 0;
}
struct cdrom_info *info = drive->driver_data;
struct cdrom_device_info *cdi = &info->devinfo;
- cdrom_prepare_request(&req);
+ cdrom_prepare_request(drive, &req);
req.sense = sense;
req.cmd[0] = GPCMD_TEST_UNIT_READY;
if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) {
stat = 0;
} else {
- cdrom_prepare_request(&req);
+ cdrom_prepare_request(drive, &req);
req.sense = sense;
req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
req.cmd[4] = lockflag ? 1 : 0;
if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
return 0;
- cdrom_prepare_request(&req);
+ cdrom_prepare_request(drive, &req);
/* only tell drive to close tray if open, if it can do that */
if (ejectflag && !CDROM_CONFIG_FLAGS(drive)->close_tray)
int stat;
struct request req;
- cdrom_prepare_request(&req);
+ cdrom_prepare_request(drive, &req);
req.sense = sense;
req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
{
struct request req;
- cdrom_prepare_request(&req);
+ cdrom_prepare_request(drive, &req);
req.sense = sense;
req.data = buf;
if (stat)
toc->capacity = 0x1fffff;
- set_capacity(drive->disk, toc->capacity * sectors_per_frame);
+ set_capacity(info->disk, toc->capacity * sectors_per_frame);
/* Save a private copy of te TOC capacity for error handling */
drive->probed_capacity = toc->capacity * sectors_per_frame;
stat = cdrom_get_last_written(cdi, &last_written);
if (!stat && (last_written > toc->capacity)) {
toc->capacity = last_written;
- set_capacity(drive->disk, toc->capacity * sectors_per_frame);
+ set_capacity(info->disk, toc->capacity * sectors_per_frame);
drive->probed_capacity = toc->capacity * sectors_per_frame;
}
{
struct request req;
- cdrom_prepare_request(&req);
+ cdrom_prepare_request(drive, &req);
req.sense = sense;
req.data = buf;
struct request_sense *sense)
{
struct request req;
- cdrom_prepare_request(&req);
+ cdrom_prepare_request(drive, &req);
req.sense = sense;
if (speed == 0)
struct request_sense sense;
struct request req;
- cdrom_prepare_request(&req);
+ cdrom_prepare_request(drive, &req);
req.sense = &sense;
req.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
/* here we queue the commands from the uniform CD-ROM
layer. the packet must be complete, as we do not
touch it at all. */
- cdrom_prepare_request(&req);
+ cdrom_prepare_request(drive, &req);
memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE);
if (cgc->sense)
memset(cgc->sense, 0, sizeof(struct request_sense));
struct request req;
int ret;
- cdrom_prepare_request(&req);
+ cdrom_prepare_request(drive, &req);
req.flags = REQ_SPECIAL | REQ_QUIET;
ret = ide_do_drive_cmd(drive, &req, ide_wait);
else
return CDS_TRAY_OPEN;
}
-
return CDS_DRIVE_NOT_READY;
}
devinfo->mask |= CDC_CLOSE_TRAY;
if (!CDROM_CONFIG_FLAGS(drive)->mo_drive)
devinfo->mask |= CDC_MO_DRIVE;
-
- devinfo->disk = drive->disk;
+
+ devinfo->disk = info->disk;
return register_cdrom(devinfo);
}
drive->queue->unplug_delay = 1;
drive->special.all = 0;
- drive->ready_stat = 0;
CDROM_STATE_FLAGS(drive)->media_changed = 1;
CDROM_STATE_FLAGS(drive)->toc_valid = 0;
*/
blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE);
+ if (drive->autotune == IDE_TUNE_DEFAULT ||
+ drive->autotune == IDE_TUNE_AUTO)
+ drive->dsc_overlap = (drive->next != drive);
#if 0
drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1;
if (HWIF(drive)->no_dsc) {
return capacity * sectors_per_frame;
}
-static
-int ide_cdrom_cleanup(ide_drive_t *drive)
+static int ide_cd_remove(struct device *dev)
{
+ ide_drive_t *drive = to_ide_device(dev);
struct cdrom_info *info = drive->driver_data;
+
+ ide_unregister_subdriver(drive, info->driver);
+
+ del_gendisk(info->disk);
+
+ ide_cd_put(info);
+
+ return 0;
+}
+
+static void ide_cd_release(struct kref *kref)
+{
+ struct cdrom_info *info = to_ide_cd(kref);
struct cdrom_device_info *devinfo = &info->devinfo;
- struct gendisk *g = drive->disk;
+ ide_drive_t *drive = info->drive;
+ struct gendisk *g = info->disk;
- if (ide_unregister_subdriver(drive)) {
- printk(KERN_ERR "%s: %s: failed to ide_unregister_subdriver\n",
- __FUNCTION__, drive->name);
- return 1;
- }
if (info->buffer != NULL)
kfree(info->buffer);
if (info->toc != NULL)
if (info->changer_info != NULL)
kfree(info->changer_info);
if (devinfo->handle == drive && unregister_cdrom(devinfo))
- printk(KERN_ERR "%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
- kfree(info);
+ printk(KERN_ERR "%s: %s failed to unregister device from the cdrom "
+ "driver.\n", __FUNCTION__, drive->name);
+ drive->dsc_overlap = 0;
drive->driver_data = NULL;
blk_queue_prep_rq(drive->queue, NULL);
- del_gendisk(g);
- g->fops = ide_fops;
- return 0;
+ g->private_data = NULL;
+ put_disk(g);
+ kfree(info);
}
-static int ide_cdrom_attach (ide_drive_t *drive);
-
-/*
- * Power Management state machine.
- *
- * We don't do much for CDs right now.
- */
-
-static void ide_cdrom_complete_power_step (ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
-{
-}
+static int ide_cd_probe(struct device *);
-static ide_startstop_t ide_cdrom_start_power_step (ide_drive_t *drive, struct request *rq)
+#ifdef CONFIG_PROC_FS
+static int proc_idecd_read_capacity
+ (char *page, char **start, off_t off, int count, int *eof, void *data)
{
- ide_task_t *args = rq->special;
-
- memset(args, 0, sizeof(*args));
-
- switch (rq->pm->pm_step) {
- case ide_pm_state_start_suspend:
- break;
+ ide_drive_t*drive = (ide_drive_t *)data;
+ int len;
- case ide_pm_state_start_resume: /* Resume step 1 (restore DMA) */
- /*
- * Right now, all we do is call hwif->ide_dma_check(drive),
- * we could be smarter and check for current xfer_speed
- * in struct drive etc...
- * Also, this step could be implemented as a generic helper
- * as most subdrivers will use it.
- */
- if ((drive->id->capability & 1) == 0)
- break;
- if (HWIF(drive)->ide_dma_check == NULL)
- break;
- HWIF(drive)->ide_dma_check(drive);
- break;
- }
- rq->pm->pm_step = ide_pm_state_completed;
- return ide_stopped;
+ len = sprintf(page,"%llu\n", (long long)ide_cdrom_capacity(drive));
+ PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
}
+static ide_proc_entry_t idecd_proc[] = {
+ { "capacity", S_IFREG|S_IRUGO, proc_idecd_read_capacity, NULL },
+ { NULL, 0, NULL, NULL }
+};
+#else
+# define idecd_proc NULL
+#endif
+
static ide_driver_t ide_cdrom_driver = {
.owner = THIS_MODULE,
- .name = "ide-cdrom",
+ .gen_driver = {
+ .name = "ide-cdrom",
+ .bus = &ide_bus_type,
+ .probe = ide_cd_probe,
+ .remove = ide_cd_remove,
+ },
.version = IDECD_VERSION,
.media = ide_cdrom,
- .busy = 0,
.supports_dsc_overlap = 1,
- .cleanup = ide_cdrom_cleanup,
.do_request = ide_do_rw_cdrom,
- .sense = ide_dump_atapi_status,
- .error = ide_cdrom_error,
- .abort = ide_cdrom_abort,
- .capacity = ide_cdrom_capacity,
- .attach = ide_cdrom_attach,
- .drives = LIST_HEAD_INIT(ide_cdrom_driver.drives),
- .start_power_step = ide_cdrom_start_power_step,
- .complete_power_step = ide_cdrom_complete_power_step,
+ .end_request = ide_end_request,
+ .error = __ide_error,
+ .abort = __ide_abort,
+ .proc = idecd_proc,
};
static int idecd_open(struct inode * inode, struct file * file)
{
- ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
- struct cdrom_info *info = drive->driver_data;
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct cdrom_info *info;
+ ide_drive_t *drive;
int rc = -ENOMEM;
+
+ if (!(info = ide_cd_get(disk)))
+ return -ENXIO;
+
+ drive = info->drive;
+
drive->usage++;
if (!info->buffer)
GFP_KERNEL|__GFP_REPEAT);
if (!info->buffer || (rc = cdrom_open(&info->devinfo, inode, file)))
drive->usage--;
+
+ if (rc < 0)
+ ide_cd_put(info);
+
return rc;
}
static int idecd_release(struct inode * inode, struct file * file)
{
- ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;
- struct cdrom_info *info = drive->driver_data;
+ struct gendisk *disk = inode->i_bdev->bd_disk;
+ struct cdrom_info *info = ide_cd_g(disk);
+ ide_drive_t *drive = info->drive;
cdrom_release (&info->devinfo, file);
drive->usage--;
+
+ ide_cd_put(info);
+
return 0;
}
unsigned int cmd, unsigned long arg)
{
struct block_device *bdev = inode->i_bdev;
- ide_drive_t *drive = bdev->bd_disk->private_data;
- int err = generic_ide_ioctl(file, bdev, cmd, arg);
- if (err == -EINVAL) {
- struct cdrom_info *info = drive->driver_data;
+ struct cdrom_info *info = ide_cd_g(bdev->bd_disk);
+ int err;
+
+ err = generic_ide_ioctl(info->drive, file, bdev, cmd, arg);
+ if (err == -EINVAL)
err = cdrom_ioctl(file, &info->devinfo, inode, cmd, arg);
- }
+
return err;
}
static int idecd_media_changed(struct gendisk *disk)
{
- ide_drive_t *drive = disk->private_data;
- struct cdrom_info *info = drive->driver_data;
+ struct cdrom_info *info = ide_cd_g(disk);
return cdrom_media_changed(&info->devinfo);
}
static int idecd_revalidate_disk(struct gendisk *disk)
{
- ide_drive_t *drive = disk->private_data;
+ struct cdrom_info *info = ide_cd_g(disk);
struct request_sense sense;
- cdrom_read_toc(drive, &sense);
+ cdrom_read_toc(info->drive, &sense);
return 0;
}
module_param(ignore, charp, 0400);
MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
-static int ide_cdrom_attach (ide_drive_t *drive)
+static int ide_cd_probe(struct device *dev)
{
+ ide_drive_t *drive = to_ide_device(dev);
struct cdrom_info *info;
- struct gendisk *g = drive->disk;
+ struct gendisk *g;
struct request_sense sense;
if (!strstr("ide-cdrom", drive->driver_req))
printk(KERN_ERR "%s: Can't allocate a cdrom structure\n", drive->name);
goto failed;
}
- if (ide_register_subdriver(drive, &ide_cdrom_driver)) {
- printk(KERN_ERR "%s: Failed to register the driver with ide.c\n",
- drive->name);
- kfree(info);
- goto failed;
- }
+
+ g = alloc_disk(1 << PARTN_BITS);
+ if (!g)
+ goto out_free_cd;
+
+ ide_init_disk(g, drive);
+
+ ide_register_subdriver(drive, &ide_cdrom_driver);
+
memset(info, 0, sizeof (struct cdrom_info));
+
+ kref_init(&info->kref);
+
+ info->drive = drive;
+ info->driver = &ide_cdrom_driver;
+ info->disk = g;
+
+ g->private_data = &info->driver;
+
drive->driver_data = info;
- DRIVER(drive)->busy++;
+
g->minors = 1;
snprintf(g->devfs_name, sizeof(g->devfs_name),
"%s/cd", drive->devfs_name);
g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
if (ide_cdrom_setup(drive)) {
struct cdrom_device_info *devinfo = &info->devinfo;
- DRIVER(drive)->busy--;
- ide_unregister_subdriver(drive);
+ ide_unregister_subdriver(drive, &ide_cdrom_driver);
if (info->buffer != NULL)
kfree(info->buffer);
if (info->toc != NULL)
drive->driver_data = NULL;
goto failed;
}
- DRIVER(drive)->busy--;
cdrom_read_toc(drive, &sense);
g->fops = &idecd_ops;
g->flags |= GENHD_FL_REMOVABLE;
add_disk(g);
return 0;
+
+out_free_cd:
+ kfree(info);
failed:
- return 1;
+ return -ENODEV;
}
static void __exit ide_cdrom_exit(void)
{
- ide_unregister_driver(&ide_cdrom_driver);
+ driver_unregister(&ide_cdrom_driver.gen_driver);
}
static int ide_cdrom_init(void)
{
- ide_register_driver(&ide_cdrom_driver);
- return 0;
+ return driver_register(&ide_cdrom_driver.gen_driver);
}
module_init(ide_cdrom_init);