Commit 1b2ed5b7 authored by Jens Axboe's avatar Jens Axboe Committed by Linus Torvalds

[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.
parent 48a6c2a9
...@@ -646,6 +646,80 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space) ...@@ -646,6 +646,80 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)
return 0; 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) static int cdrom_media_erasable(struct cdrom_device_info *cdi)
{ {
disc_information di; disc_information di;
...@@ -729,6 +803,23 @@ static int mo_open_write(struct cdrom_device_info *cdi) ...@@ -729,6 +803,23 @@ static int mo_open_write(struct cdrom_device_info *cdi)
return buffer[3] & 0x80; 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 * 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) ...@@ -740,6 +831,9 @@ static int cdrom_open_write(struct cdrom_device_info *cdi)
ret = cdrom_mrw_open_write(cdi); ret = cdrom_mrw_open_write(cdi);
else if (CDROM_CAN(CDC_DVD_RAM)) else if (CDROM_CAN(CDC_DVD_RAM))
ret = cdrom_dvdram_open_write(cdi); 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)) else if (CDROM_CAN(CDC_MO_DRIVE))
ret = mo_open_write(cdi); ret = mo_open_write(cdi);
...@@ -2785,6 +2879,7 @@ EXPORT_SYMBOL(cdrom_mode_sense); ...@@ -2785,6 +2879,7 @@ EXPORT_SYMBOL(cdrom_mode_sense);
EXPORT_SYMBOL(init_cdrom_command); EXPORT_SYMBOL(init_cdrom_command);
EXPORT_SYMBOL(cdrom_get_media_event); EXPORT_SYMBOL(cdrom_get_media_event);
EXPORT_SYMBOL(cdrom_is_mrw); EXPORT_SYMBOL(cdrom_is_mrw);
EXPORT_SYMBOL(cdrom_is_random_writable);
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
...@@ -2889,6 +2984,10 @@ int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, ...@@ -2889,6 +2984,10 @@ int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp,
for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW_W) != 0); 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"); strcpy(info+pos,"\n\n");
return proc_dostring(ctl, write, filp, buffer, lenp); return proc_dostring(ctl, write, filp, buffer, lenp);
......
...@@ -2883,6 +2883,8 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots) ...@@ -2883,6 +2883,8 @@ static int ide_cdrom_register (ide_drive_t *drive, int nslots)
devinfo->mask |= CDC_MRW; devinfo->mask |= CDC_MRW;
if (!CDROM_CONFIG_FLAGS(drive)->mrw_w) if (!CDROM_CONFIG_FLAGS(drive)->mrw_w)
devinfo->mask |= CDC_MRW_W; devinfo->mask |= CDC_MRW_W;
if (!CDROM_CONFIG_FLAGS(drive)->ram)
devinfo->mask |= CDC_RAM;
devinfo->disk = drive->disk; devinfo->disk = drive->disk;
return register_cdrom(devinfo); return register_cdrom(devinfo);
...@@ -2919,7 +2921,7 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) ...@@ -2919,7 +2921,7 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
struct cdrom_info *info = drive->driver_data; struct cdrom_info *info = drive->driver_data;
struct cdrom_device_info *cdi = &info->devinfo; struct cdrom_device_info *cdi = &info->devinfo;
struct atapi_capabilities_page cap; 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) { if (drive->media == ide_optical) {
CDROM_CONFIG_FLAGS(drive)->mo_drive = 1; CDROM_CONFIG_FLAGS(drive)->mo_drive = 1;
...@@ -2955,6 +2957,9 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive) ...@@ -2955,6 +2957,9 @@ int ide_cdrom_probe_capabilities (ide_drive_t *drive)
CDROM_CONFIG_FLAGS(drive)->ram = 1; 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) if (cap.lock == 0)
CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1; CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
......
...@@ -698,7 +698,7 @@ static void get_sectorsize(struct scsi_cd *cd) ...@@ -698,7 +698,7 @@ static void get_sectorsize(struct scsi_cd *cd)
static void get_capabilities(struct scsi_cd *cd) static void get_capabilities(struct scsi_cd *cd)
{ {
unsigned char *buffer; 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_mode_data data;
struct scsi_request *SRpnt; struct scsi_request *SRpnt;
unsigned char cmd[MAX_COMMAND_SIZE]; unsigned char cmd[MAX_COMMAND_SIZE];
...@@ -783,6 +783,11 @@ static void get_capabilities(struct scsi_cd *cd) ...@@ -783,6 +783,11 @@ static void get_capabilities(struct scsi_cd *cd)
if (!mrw_write) if (!mrw_write)
cd->cdi.mask |= CDC_MRW_W; 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; n = data.header_length + data.block_descriptor_length;
cd->cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176; cd->cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176;
cd->readcd_known = 1; cd->readcd_known = 1;
...@@ -832,8 +837,8 @@ static void get_capabilities(struct scsi_cd *cd) ...@@ -832,8 +837,8 @@ static void get_capabilities(struct scsi_cd *cd)
/* /*
* if DVD-RAM of MRW-W, we are randomly writeable * if DVD-RAM of MRW-W, we are randomly writeable
*/ */
if ((cd->cdi.mask & (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_DVD_RAM | CDC_MRW_W | CDC_RAM)) {
cd->device->writeable = 1; cd->device->writeable = 1;
set_disk_ro(cd->disk, 0); set_disk_ro(cd->disk, 0);
} }
......
...@@ -722,7 +722,9 @@ struct request_sense { ...@@ -722,7 +722,9 @@ struct request_sense {
/* /*
* feature profile * 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 * media status bits
...@@ -771,6 +773,34 @@ struct mrw_feature_desc { ...@@ -771,6 +773,34 @@ struct mrw_feature_desc {
__u8 reserved5; __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 { typedef struct {
__u16 disc_information_length; __u16 disc_information_length;
#if defined(__BIG_ENDIAN_BITFIELD) #if defined(__BIG_ENDIAN_BITFIELD)
...@@ -1140,6 +1170,7 @@ struct media_event_desc { ...@@ -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_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_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 */ #endif /* End of kernel only stuff */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment