summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Axboe <axboe@suse.de>2004-03-15 15:51:27 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-03-15 15:51:27 -0800
commit1b2ed5b74904b6d1540efdd0bd08022765dc292a (patch)
treede74110dfb43c3fc33edf20b1d30c906bf495f84
parent48a6c2a947c15b9b8289f1e3092ce064d0e21b50 (diff)
[PATCH] allow random write to cdrom devices with profile 2 (removable disk)
This patch is from Iomega, and it allows random write opens of CDROM's that support the feature.
-rw-r--r--drivers/cdrom/cdrom.c99
-rw-r--r--drivers/ide/ide-cd.c7
-rw-r--r--drivers/scsi/sr.c11
-rw-r--r--include/linux/cdrom.h33
4 files changed, 145 insertions, 5 deletions
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 11bbaffdc9f2..7b3fbd6901cd 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -646,6 +646,80 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)
return 0;
}
+int cdrom_get_random_writable(struct cdrom_device_info *cdi,
+ struct rwrt_feature_desc *rfd)
+{
+ struct cdrom_generic_command cgc;
+ char buffer[24];
+ struct feature_header *fh;
+ int ret;
+
+ init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+
+ cgc.cmd[0] = GPCMD_GET_CONFIGURATION; /* often 0x46 */
+ cgc.cmd[3] = CDF_RWRT; /* often 0x0020 */
+ cgc.cmd[8] = sizeof(buffer); /* often 0x18 */
+ cgc.quiet = 1;
+
+ if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
+ return ret;
+
+ fh = (struct feature_header *)&buffer[0];
+ if (be32_to_cpu(fh->data_len) >= (sizeof(struct feature_header)+
+ sizeof(struct rwrt_feature_desc)))
+ memcpy(rfd, &buffer[sizeof(struct feature_header)],
+ sizeof (*rfd));
+ else
+ memset(rfd, 0, sizeof(*rfd));
+
+ return 0;
+}
+
+int cdrom_has_defect_mgt(struct cdrom_device_info *cdi)
+{
+ struct cdrom_generic_command cgc;
+ char buffer[16];
+ struct feature_header *fh;
+ __u16 *feature_code;
+ int ret;
+
+ init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+
+ cgc.cmd[0] = GPCMD_GET_CONFIGURATION; /* often 0x46 */
+ cgc.cmd[3] = CDF_HWDM; /* often 0x0024 */
+ cgc.cmd[8] = sizeof(buffer); /* often 0x10 */
+ cgc.quiet = 1;
+
+ if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
+ return ret;
+
+ fh = (struct feature_header *)&buffer[0];
+ ret = 1;
+ if (be32_to_cpu(fh->data_len) >= (sizeof(struct feature_header)+8)) {
+ feature_code = (__u16 *)&buffer[sizeof(struct feature_header)];
+ if (CDF_HWDM == be16_to_cpu(*feature_code))
+ ret = 0;
+ }
+ return ret;
+}
+
+
+int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write)
+{
+ struct rwrt_feature_desc rfd;
+ int ret;
+
+ *write = 0;
+
+ if ((ret = cdrom_get_random_writable(cdi, &rfd)))
+ return ret;
+
+ if (CDF_RWRT == be16_to_cpu(rfd.feature_code))
+ *write = 1;
+
+ return 0;
+}
+
static int cdrom_media_erasable(struct cdrom_device_info *cdi)
{
disc_information di;
@@ -729,6 +803,23 @@ static int mo_open_write(struct cdrom_device_info *cdi)
return buffer[3] & 0x80;
}
+static int cdrom_ram_open_write(struct cdrom_device_info *cdi)
+{
+ struct rwrt_feature_desc rfd;
+ int ret;
+
+ if ((ret = cdrom_has_defect_mgt(cdi)))
+ return ret;
+
+ if ((ret = cdrom_get_random_writable(cdi, &rfd)))
+ return ret;
+ else if (CDF_RWRT == be16_to_cpu(rfd.feature_code))
+ ret = !rfd.curr;
+
+ cdinfo(CD_OPEN, "can open for random write\n");
+ return ret;
+}
+
/*
* returns 0 for ok to open write, non-0 to disallow
*/
@@ -740,6 +831,9 @@ static int cdrom_open_write(struct cdrom_device_info *cdi)
ret = cdrom_mrw_open_write(cdi);
else if (CDROM_CAN(CDC_DVD_RAM))
ret = cdrom_dvdram_open_write(cdi);
+ else if (CDROM_CAN(CDC_RAM) &&
+ !CDROM_CAN(CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_MRW))
+ ret = cdrom_ram_open_write(cdi);
else if (CDROM_CAN(CDC_MO_DRIVE))
ret = mo_open_write(cdi);
@@ -2785,6 +2879,7 @@ EXPORT_SYMBOL(cdrom_mode_sense);
EXPORT_SYMBOL(init_cdrom_command);
EXPORT_SYMBOL(cdrom_get_media_event);
EXPORT_SYMBOL(cdrom_is_mrw);
+EXPORT_SYMBOL(cdrom_is_random_writable);
#ifdef CONFIG_SYSCTL
@@ -2889,6 +2984,10 @@ int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp,
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW_W) != 0);
+ pos += sprintf(info+pos, "\nCan write RAM:\t");
+ for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
+ pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_RAM) != 0);
+
strcpy(info+pos,"\n\n");
return proc_dostring(ctl, write, filp, buffer, lenp);
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 6015ff37b8b8..28edf46f40cd 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -2883,6 +2883,8 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
devinfo->mask |= CDC_MRW;
if (!CDROM_CONFIG_FLAGS(drive)->mrw_w)
devinfo->mask |= CDC_MRW_W;
+ if (!CDROM_CONFIG_FLAGS(drive)->ram)
+ devinfo->mask |= CDC_RAM;
devinfo->disk = drive->disk;
return register_cdrom(devinfo);
@@ -2919,7 +2921,7 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
struct cdrom_info *info = drive->driver_data;
struct cdrom_device_info *cdi = &info->devinfo;
struct atapi_capabilities_page cap;
- int nslots = 1, mrw_write = 0;
+ int nslots = 1, mrw_write = 0, ram_write = 0;
if (drive->media == ide_optical) {
CDROM_CONFIG_FLAGS(drive)->mo_drive = 1;
@@ -2955,6 +2957,9 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
CDROM_CONFIG_FLAGS(drive)->ram = 1;
}
}
+ if (!cdrom_is_random_writable(cdi, &ram_write))
+ if (ram_write)
+ CDROM_CONFIG_FLAGS(drive)->ram = 1;
if (cap.lock == 0)
CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 809e42316326..4e9b0fdf6463 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -698,7 +698,7 @@ Enomem:
static void get_capabilities(struct scsi_cd *cd)
{
unsigned char *buffer;
- int rc, n, mrw_write = 0, mrw = 1;
+ int rc, n, mrw_write = 0, mrw = 1,ram_write=0;
struct scsi_mode_data data;
struct scsi_request *SRpnt;
unsigned char cmd[MAX_COMMAND_SIZE];
@@ -783,6 +783,11 @@ static void get_capabilities(struct scsi_cd *cd)
if (!mrw_write)
cd->cdi.mask |= CDC_MRW_W;
+ if (cdrom_is_random_writable(&cd->cdi, &ram_write))
+ cd->cdi.mask |= CDC_RAM;
+ if (!ram_write)
+ cd->cdi.mask |= CDC_RAM;
+
n = data.header_length + data.block_descriptor_length;
cd->cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176;
cd->readcd_known = 1;
@@ -832,8 +837,8 @@ static void get_capabilities(struct scsi_cd *cd)
/*
* if DVD-RAM of MRW-W, we are randomly writeable
*/
- if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W)) !=
- (CDC_DVD_RAM | CDC_MRW_W)) {
+ if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM)) !=
+ (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM)) {
cd->device->writeable = 1;
set_disk_ro(cd->disk, 0);
}
diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h
index a4e851d4a335..8fcf9bc9cf2b 100644
--- a/include/linux/cdrom.h
+++ b/include/linux/cdrom.h
@@ -722,7 +722,9 @@ struct request_sense {
/*
* feature profile
*/
-#define CDF_MRW 0x28
+#define CDF_RWRT 0x0020 /* "Random Writable" */
+#define CDF_HWDM 0x0024 /* "Hardware Defect Management" */
+#define CDF_MRW 0x0028
/*
* media status bits
@@ -771,6 +773,34 @@ struct mrw_feature_desc {
__u8 reserved5;
};
+/* cf. mmc4r02g.pdf 5.3.10 Random Writable Feature (0020h) pg 197 of 635 */
+struct rwrt_feature_desc {
+ __u16 feature_code;
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 reserved1 : 2;
+ __u8 feature_version : 4;
+ __u8 persistent : 1;
+ __u8 curr : 1;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 curr : 1;
+ __u8 persistent : 1;
+ __u8 feature_version : 4;
+ __u8 reserved1 : 2;
+#endif
+ __u8 add_len;
+ __u32 last_lba;
+ __u32 block_size;
+ __u16 blocking;
+#if defined(__BIG_ENDIAN_BITFIELD)
+ __u8 reserved2 : 7;
+ __u8 page_present : 1;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ __u8 page_present : 1;
+ __u8 reserved2 : 7;
+#endif
+ __u8 reserved3;
+};
+
typedef struct {
__u16 disc_information_length;
#if defined(__BIG_ENDIAN_BITFIELD)
@@ -1140,6 +1170,7 @@ struct media_event_desc {
extern int cdrom_get_media_event(struct cdrom_device_info *cdi, struct media_event_desc *med);
extern int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write);
+extern int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write);
#endif /* End of kernel only stuff */