diff options
| author | Jens Axboe <axboe@suse.de> | 2004-03-15 15:51:27 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-03-15 15:51:27 -0800 |
| commit | 1b2ed5b74904b6d1540efdd0bd08022765dc292a (patch) | |
| tree | de74110dfb43c3fc33edf20b1d30c906bf495f84 | |
| parent | 48a6c2a947c15b9b8289f1e3092ce064d0e21b50 (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.c | 99 | ||||
| -rw-r--r-- | drivers/ide/ide-cd.c | 7 | ||||
| -rw-r--r-- | drivers/scsi/sr.c | 11 | ||||
| -rw-r--r-- | include/linux/cdrom.h | 33 |
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 */ |
