linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / drivers / ide / ide-cd.c
index 654d4cd..3325660 100644 (file)
  
 #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) 
 
@@ -335,11 +335,11 @@ static struct cdrom_info *ide_cd_get(struct gendisk *disk)
 {
        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;
 }
 
@@ -347,9 +347,9 @@ static void ide_cd_release(struct kref *);
 
 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);
 }
 
 /****************************************************************************
@@ -394,8 +394,7 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
                         * 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:
                        /*
@@ -417,11 +416,6 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
                              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;
 
@@ -434,37 +428,6 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
                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;
@@ -645,23 +608,17 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
                                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))
@@ -675,13 +632,6 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
        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)
@@ -810,16 +760,16 @@ 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
@@ -831,27 +781,13 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
                        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);
@@ -1514,12 +1450,9 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
        } 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. */
@@ -1554,7 +1487,8 @@ static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
 }
 
 
-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;
@@ -1787,7 +1721,8 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
                }
        }
 
-       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;
@@ -2207,7 +2142,6 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
        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) {
@@ -2282,9 +2216,6 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
                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);
 
@@ -2407,7 +2338,6 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
        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. */
@@ -2540,6 +2470,52 @@ static int ide_cdrom_packet(struct cdrom_device_info *cdi,
        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)
@@ -2764,11 +2740,14 @@ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
         * 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;
 }
 
@@ -2873,11 +2852,12 @@ static struct cdrom_device_ops ide_cdrom_dops = {
        .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,
@@ -3387,45 +3367,6 @@ static int idecd_release(struct inode * inode, struct file * file)
        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)
 {
@@ -3433,16 +3374,7 @@ static int idecd_ioctl (struct inode *inode, struct file *file,
        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);
 
@@ -3526,6 +3458,8 @@ static int ide_cd_probe(ide_drive_t *drive)
        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)) {