]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] allow random write to cdrom devices with profile 2 (removable disk)
authorJens Axboe <axboe@suse.de>
Mon, 15 Mar 2004 23:51:27 +0000 (15:51 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 15 Mar 2004 23:51:27 +0000 (15:51 -0800)
This patch is from Iomega, and it allows random write opens of CDROM's
that support the feature.

drivers/cdrom/cdrom.c
drivers/ide/ide-cd.c
drivers/scsi/sr.c
include/linux/cdrom.h

index 11bbaffdc9f2f0a9fadc00b273f093a2cb775d13..7b3fbd6901cde9a7ea02c5c0733c36019e73216c 100644 (file)
@@ -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);
index 6015ff37b8b89225cac7ccc62d89c2ee4b73b861..28edf46f40cdfb743aa6d6d49c08200116eb1b10 100644 (file)
@@ -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;
index 809e42316326b72f6c687b73f17d5a5bf58179f9..4e9b0fdf64634343cde1e6dfe79e3c3d1654d714 100644 (file)
@@ -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);
        }
index a4e851d4a335247cb8319c7262264a6cc72c8900..8fcf9bc9cf2bde8d6605c753e1e94e43c6bcd4c7 100644 (file)
@@ -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 */