#define IDECD_VERSION "4.61"
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/cdrom.h>
#include <linux/ide.h>
#include <linux/completion.h>
-#include <linux/mutex.h>
#include <scsi/scsi.h> /* For SCSI -> ATAPI command conversion */
#include "ide-cd.h"
-static DEFINE_MUTEX(idecd_ref_mutex);
+static DECLARE_MUTEX(idecd_ref_sem);
#define to_ide_cd(obj) container_of(obj, struct cdrom_info, kref)
{
struct cdrom_info *cd = NULL;
- mutex_lock(&idecd_ref_mutex);
+ down(&idecd_ref_sem);
cd = ide_cd_g(disk);
if (cd)
kref_get(&cd->kref);
- mutex_unlock(&idecd_ref_mutex);
+ up(&idecd_ref_sem);
return cd;
}
static void ide_cd_put(struct cdrom_info *cd)
{
- mutex_lock(&idecd_ref_mutex);
+ down(&idecd_ref_sem);
kref_put(&cd->kref, ide_cd_release);
- mutex_unlock(&idecd_ref_mutex);
+ up(&idecd_ref_sem);
}
/****************************************************************************
* we cannot reliably check if drive can auto-close
*/
if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
- break;
- log = 1;
+ log = 0;
break;
case UNIT_ATTENTION:
/*
struct request *failed_command,
struct request_sense *sense)
{
- 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 (sense->sense_key == 0x05 && sense->asc == 0x24)
return;
- if (sense->error_code == 0x70) { /* Current Error */
- switch(sense->sense_key) {
- case MEDIUM_ERROR:
- case VOLUME_OVERFLOW:
- case ILLEGAL_REQUEST:
- if (!sense->valid)
- break;
- if (failed_command == NULL ||
- !blk_fs_request(failed_command))
- break;
- sector = (sense->information[0] << 24) |
- (sense->information[1] << 16) |
- (sense->information[2] << 8) |
- (sense->information[3]);
-
- bio_sectors = bio_sectors(failed_command->bio);
- if (bio_sectors < 4)
- bio_sectors = 4;
- if (drive->queue->hardsect_size == 2048)
- sector <<= 2; /* Device sector size is 2K */
- sector &= ~(bio_sectors -1);
- valid = (sector - failed_command->sector) << 9;
-
- if (valid < 0)
- valid = 0;
- if (sector < get_capacity(info->disk) &&
- drive->probed_capacity - sector < 4 * 75) {
- set_capacity(info->disk, sector);
- }
- }
- }
#if VERBOSE_IDE_CD_ERRORS
{
int i;
sense = failed->sense;
failed->sense_len = rq->sense_len;
}
- cdrom_analyze_sense_data(drive, failed, sense);
+
/*
* now end failed request
*/
- if (blk_fs_request(failed)) {
- if (ide_end_dequeued_request(drive, failed, 0,
- failed->hard_nr_sectors))
- BUG();
- } else {
- spin_lock_irqsave(&ide_lock, flags);
- end_that_request_chunk(failed, 0,
- failed->data_len);
- end_that_request_last(failed, 0);
- spin_unlock_irqrestore(&ide_lock, flags);
- }
- } else
- cdrom_analyze_sense_data(drive, NULL, sense);
+ spin_lock_irqsave(&ide_lock, flags);
+ end_that_request_chunk(failed, 0, failed->data_len);
+ end_that_request_last(failed, 0);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ }
+
+ cdrom_analyze_sense_data(drive, failed, sense);
}
if (!rq->current_nr_sectors && blk_fs_request(rq))
ide_end_request(drive, uptodate, nsectors);
}
-static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 stat)
-{
- if (stat & 0x80)
- return;
- ide_dump_status(drive, msg, stat);
-}
-
/* Returns 0 if the request should be continued.
Returns 1 if the request was ended. */
static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
sense_key == DATA_PROTECT) {
/* No point in retrying after an illegal
request or data protect error.*/
- ide_dump_status_no_sense (drive, "command error", stat);
+ ide_dump_status (drive, "command error", stat);
do_end_request = 1;
} else if (sense_key == MEDIUM_ERROR) {
/* No point in re-trying a zillion times on a bad
* sector... If we got here the error is not correctable */
- ide_dump_status_no_sense (drive, "media error (bad sector)", stat);
+ ide_dump_status (drive, "media error (bad sector)", stat);
do_end_request = 1;
} else if (sense_key == BLANK_CHECK) {
/* Disk appears blank ?? */
- ide_dump_status_no_sense (drive, "media error (blank)", stat);
+ ide_dump_status (drive, "media error (blank)", stat);
do_end_request = 1;
} else if ((err & ~ABRT_ERR) != 0) {
/* Go to the default handler
do_end_request = 1;
}
- /* End a request through request sense analysis when we have
- sense data. We need this in order to perform end of media
- processing */
-
- if (do_end_request) {
- if (stat & ERR_STAT) {
- unsigned long flags;
- spin_lock_irqsave(&ide_lock, flags);
- blkdev_dequeue_request(rq);
- HWGROUP(drive)->rq = NULL;
- spin_unlock_irqrestore(&ide_lock, flags);
-
- cdrom_queue_request_sense(drive, rq->sense, rq);
- } else
- cdrom_end_request(drive, 0);
- } else {
- /* If we got a CHECK_CONDITION status,
- queue a request sense command. */
- if (stat & ERR_STAT)
- cdrom_queue_request_sense(drive, NULL, NULL);
- }
+ if (do_end_request)
+ cdrom_end_request(drive, 0);
+
+ /* If we got a CHECK_CONDITION status,
+ queue a request sense command. */
+ if ((stat & ERR_STAT) != 0)
+ cdrom_queue_request_sense(drive, NULL, NULL);
} else {
blk_dump_rq_flags(rq, "ide-cd: bad rq");
cdrom_end_request(drive, 0);
} else {
confused:
printk (KERN_ERR "%s: cdrom_pc_intr: The drive "
- "appears confused (ireason = 0x%02x). "
- "Trying to recover by ending request.\n",
+ "appears confused (ireason = 0x%02x)\n",
drive->name, ireason);
rq->flags |= REQ_FAILED;
- cdrom_end_request(drive, 0);
- return ide_stopped;
}
/* Now we wait for another interrupt. */
}
-static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
+static
+int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
{
struct request_sense sense;
int retries = 10;
}
}
- BUG_ON(HWGROUP(drive)->handler != NULL);
+ if (HWGROUP(drive)->handler != NULL)
+ BUG();
ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, NULL);
return ide_started;
req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
req.data = (char *)&capbuf;
req.data_len = sizeof(capbuf);
- req.flags |= REQ_QUIET;
stat = cdrom_queue_packet_command(drive, &req);
if (stat == 0) {
toc->capacity = 0x1fffff;
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;
-
blk_queue_hardsect_size(drive->queue,
sectors_per_frame << SECTOR_BITS);
if (!stat && (last_written > toc->capacity)) {
toc->capacity = last_written;
set_capacity(info->disk, toc->capacity * sectors_per_frame);
- drive->probed_capacity = toc->capacity * sectors_per_frame;
}
/* Remember that we've read this stuff. */
return cgc->stat;
}
+static
+int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi,
+ unsigned int cmd, unsigned long arg)
+{
+ struct packet_command cgc;
+ char buffer[16];
+ int stat;
+
+ init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
+
+ /* These will be moved into the Uniform layer shortly... */
+ switch (cmd) {
+ case CDROMSETSPINDOWN: {
+ char spindown;
+
+ if (copy_from_user(&spindown, (void __user *) arg, sizeof(char)))
+ return -EFAULT;
+
+ if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0)))
+ return stat;
+
+ buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f);
+
+ return cdrom_mode_select(cdi, &cgc);
+ }
+
+ case CDROMGETSPINDOWN: {
+ char spindown;
+
+ if ((stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0)))
+ return stat;
+
+ spindown = buffer[11] & 0x0f;
+
+ if (copy_to_user((void __user *) arg, &spindown, sizeof (char)))
+ return -EFAULT;
+
+ return 0;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+}
+
static
int ide_cdrom_audio_ioctl (struct cdrom_device_info *cdi,
unsigned int cmd, void *arg)
* any other way to detect this...
*/
if (sense.sense_key == NOT_READY) {
- if (sense.asc == 0x3a && sense.ascq == 1)
- return CDS_NO_DISC;
- else
- return CDS_TRAY_OPEN;
+ if (sense.asc == 0x3a) {
+ if (sense.ascq == 1)
+ return CDS_NO_DISC;
+ else if (sense.ascq == 0 || sense.ascq == 2)
+ return CDS_TRAY_OPEN;
+ }
}
+
return CDS_DRIVE_NOT_READY;
}
.get_mcn = ide_cdrom_get_mcn,
.reset = ide_cdrom_reset,
.audio_ioctl = ide_cdrom_audio_ioctl,
+ .dev_ioctl = ide_cdrom_dev_ioctl,
.capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK |
CDC_SELECT_SPEED | CDC_SELECT_DISC |
CDC_MULTI_SESSION | CDC_MCN |
CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET |
- CDC_DRIVE_STATUS | CDC_CD_R |
+ CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_CD_R |
CDC_CD_RW | CDC_DVD | CDC_DVD_R| CDC_DVD_RAM |
CDC_GENERIC_PACKET | CDC_MO_DRIVE | CDC_MRW |
CDC_MRW_W | CDC_RAM,
return 0;
}
-static int idecd_set_spindown(struct cdrom_device_info *cdi, unsigned long arg)
-{
- struct packet_command cgc;
- char buffer[16];
- int stat;
- char spindown;
-
- if (copy_from_user(&spindown, (void __user *)arg, sizeof(char)))
- return -EFAULT;
-
- init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
-
- stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0);
- if (stat)
- return stat;
-
- buffer[11] = (buffer[11] & 0xf0) | (spindown & 0x0f);
- return cdrom_mode_select(cdi, &cgc);
-}
-
-static int idecd_get_spindown(struct cdrom_device_info *cdi, unsigned long arg)
-{
- struct packet_command cgc;
- char buffer[16];
- int stat;
- char spindown;
-
- init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_UNKNOWN);
-
- stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CDROM_PAGE, 0);
- if (stat)
- return stat;
-
- spindown = buffer[11] & 0x0f;
- if (copy_to_user((void __user *)arg, &spindown, sizeof (char)))
- return -EFAULT;
- return 0;
-}
-
static int idecd_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct cdrom_info *info = ide_cd_g(bdev->bd_disk);
int err;
- switch (cmd) {
- case CDROMSETSPINDOWN:
- return idecd_set_spindown(&info->devinfo, arg);
- case CDROMGETSPINDOWN:
- return idecd_get_spindown(&info->devinfo, arg);
- default:
- break;
- }
-
- err = generic_ide_ioctl(info->drive, file, bdev, cmd, arg);
+ err = generic_ide_ioctl(info->drive, file, bdev, cmd, arg);
if (err == -EINVAL)
err = cdrom_ioctl(file, &info->devinfo, inode, cmd, arg);
drive->driver_data = info;
g->minors = 1;
+ snprintf(g->devfs_name, sizeof(g->devfs_name),
+ "%s/cd", drive->devfs_name);
g->driverfs_dev = &drive->gendev;
g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
if (ide_cdrom_setup(drive)) {