module_param(atapi_dmadir, int, 0444);
 MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
 
+int atapi_passthru16 = 1;
+module_param(atapi_passthru16, int, 0444);
+MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices; on by default (0=off, 1=on)");
+
 int libata_fua = 0;
 module_param_named(fua, libata_fua, int, 0444);
 MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
 
                                      void (*done)(struct scsi_cmnd *),
                                      struct ata_device *dev)
 {
+       u8 scsi_op = scmd->cmnd[0];
+       ata_xlat_func_t xlat_func;
        int rc = 0;
 
-       if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) {
-               DPRINTK("bad CDB len=%u, max=%u\n",
-                       scmd->cmd_len, dev->cdb_len);
-               scmd->result = DID_ERROR << 16;
-               done(scmd);
-               return 0;
-       }
-
        if (dev->class == ATA_DEV_ATA) {
-               ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
-                                                             scmd->cmnd[0]);
+               if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len))
+                       goto bad_cdb_len;
 
-               if (xlat_func)
-                       rc = ata_scsi_translate(dev, scmd, done, xlat_func);
-               else
-                       ata_scsi_simulate(dev, scmd, done);
-       } else
-               rc = ata_scsi_translate(dev, scmd, done, atapi_xlat);
+               xlat_func = ata_get_xlat_func(dev, scsi_op);
+       } else {
+               if (unlikely(!scmd->cmd_len))
+                       goto bad_cdb_len;
+
+               xlat_func = NULL;
+               if (likely((scsi_op != ATA_16) || !atapi_passthru16)) {
+                       /* relay SCSI command to ATAPI device */
+                       if (unlikely(scmd->cmd_len > dev->cdb_len))
+                               goto bad_cdb_len;
+
+                       xlat_func = atapi_xlat;
+               } else {
+                       /* ATA_16 passthru, treat as an ATA command */
+                       if (unlikely(scmd->cmd_len > 16))
+                               goto bad_cdb_len;
+
+                       xlat_func = ata_get_xlat_func(dev, scsi_op);
+               }
+       }
+
+       if (xlat_func)
+               rc = ata_scsi_translate(dev, scmd, done, xlat_func);
+       else
+               ata_scsi_simulate(dev, scmd, done);
 
        return rc;
+
+ bad_cdb_len:
+       DPRINTK("bad CDB len=%u, scsi_op=0x%02x, max=%u\n",
+               scmd->cmd_len, scsi_op, dev->cdb_len);
+       scmd->result = DID_ERROR << 16;
+       done(scmd);
+       return 0;
 }
 
 /**