diff options
Diffstat (limited to 'drivers/scsi/sr_ioctl.c')
| -rw-r--r-- | drivers/scsi/sr_ioctl.c | 89 |
1 files changed, 52 insertions, 37 deletions
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 5d02ff4db6c..a3911c39ea5 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -1,13 +1,14 @@ #include <linux/kernel.h> -#include <linux/sched.h> #include <linux/mm.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/blkdev.h> +#include <linux/module.h> #include <linux/blkpg.h> #include <linux/cdrom.h> #include <linux/delay.h> +#include <linux/slab.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -192,7 +193,7 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) SDev = cd->device; if (!sense) { - sense = kmalloc(sizeof(*sense), GFP_KERNEL); + sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); if (!sense) { err = -ENOMEM; goto out; @@ -208,7 +209,7 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) memset(sense, 0, sizeof(*sense)); result = scsi_execute(SDev, cgc->cmd, cgc->data_direction, cgc->buffer, cgc->buflen, (char *)sense, - cgc->timeout, IOCTL_RETRIES, 0); + cgc->timeout, IOCTL_RETRIES, 0, NULL); scsi_normalize_sense((char *)sense, sizeof(*sense), &sshdr); @@ -276,18 +277,6 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) /* ---------------------------------------------------------------------- */ /* interface to cdrom.c */ -static int test_unit_ready(Scsi_CD *cd) -{ - struct packet_command cgc; - - memset(&cgc, 0, sizeof(struct packet_command)); - cgc.cmd[0] = GPCMD_TEST_UNIT_READY; - cgc.quiet = 1; - cgc.data_direction = DMA_NONE; - cgc.timeout = IOCTL_TIMEOUT; - return sr_do_ioctl(cd, &cgc); -} - int sr_tray_move(struct cdrom_device_info *cdi, int pos) { Scsi_CD *cd = cdi->handle; @@ -311,14 +300,59 @@ int sr_lock_door(struct cdrom_device_info *cdi, int lock) int sr_drive_status(struct cdrom_device_info *cdi, int slot) { + struct scsi_cd *cd = cdi->handle; + struct scsi_sense_hdr sshdr; + struct media_event_desc med; + if (CDSL_CURRENT != slot) { /* we have no changer support */ return -EINVAL; } - if (0 == test_unit_ready(cdi->handle)) + if (!scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) + return CDS_DISC_OK; + + /* SK/ASC/ASCQ of 2/4/1 means "unit is becoming ready" */ + if (scsi_sense_valid(&sshdr) && sshdr.sense_key == NOT_READY + && sshdr.asc == 0x04 && sshdr.ascq == 0x01) + return CDS_DRIVE_NOT_READY; + + if (!cdrom_get_media_event(cdi, &med)) { + if (med.media_present) + return CDS_DISC_OK; + else if (med.door_open) + return CDS_TRAY_OPEN; + else + return CDS_NO_DISC; + } + + /* + * SK/ASC/ASCQ of 2/4/2 means "initialization required" + * Using CD_TRAY_OPEN results in an START_STOP_UNIT to close + * the tray, which resolves the initialization requirement. + */ + if (scsi_sense_valid(&sshdr) && sshdr.sense_key == NOT_READY + && sshdr.asc == 0x04 && sshdr.ascq == 0x02) + return CDS_TRAY_OPEN; + + /* + * 0x04 is format in progress .. but there must be a disc present! + */ + if (sshdr.sense_key == NOT_READY && sshdr.asc == 0x04) return CDS_DISC_OK; - return CDS_TRAY_OPEN; + /* + * If not using Mt Fuji extended media tray reports, + * just return TRAY_OPEN since ATAPI doesn't provide + * any other way to detect this... + */ + if (scsi_sense_valid(&sshdr) && + /* 0x3a is medium not present */ + sshdr.asc == 0x3a) + return CDS_NO_DISC; + else + return CDS_TRAY_OPEN; + + return CDS_DRIVE_NOT_READY; } int sr_disk_status(struct cdrom_device_info *cdi) @@ -546,7 +580,7 @@ int sr_is_xa(Scsi_CD *cd) if (!xa_test) return 0; - raw_sector = (unsigned char *) kmalloc(2048, GFP_KERNEL | SR_GFP_DMA(cd)); + raw_sector = kmalloc(2048, GFP_KERNEL | SR_GFP_DMA(cd)); if (!raw_sector) return -ENOMEM; if (0 == sr_read_sector(cd, cd->ms_offset + 16, @@ -562,22 +596,3 @@ int sr_is_xa(Scsi_CD *cd) #endif return is_xa; } - -int sr_dev_ioctl(struct cdrom_device_info *cdi, - unsigned int cmd, unsigned long arg) -{ - Scsi_CD *cd = cdi->handle; - int ret; - - ret = scsi_nonblockable_ioctl(cd->device, cmd, - (void __user *)arg, NULL); - /* - * ENODEV means that we didn't recognise the ioctl, or that we - * cannot execute it in the current device state. In either - * case fall through to scsi_ioctl, which will return ENDOEV again - * if it doesn't recognise the ioctl - */ - if (ret != -ENODEV) - return ret; - return scsi_ioctl(cd->device, cmd, (void __user *)arg); -} |
