diff options
author | Mark Lord <liml@rtr.ca> | 2007-08-07 12:08:45 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-10-12 14:55:32 -0400 |
commit | baf4fdfaaf5cb9f4fb1c341c8cef60a64e580582 (patch) | |
tree | f26293a36958a6813bf1353cb07afd3d6be6aa0d /drivers | |
parent | 4cc980b34b2a25f600576dcd11de388bc44e1ebd (diff) |
libata: add support for ATA_16 on ATAPI
Add support for issuing ATA_16 passthru commands to ATAPI devices
managed by libata. It requires the previous CDB length fix patch.
A boot/module parameter, "atapi_passthru16=0" can be used to globally
disable this feature, if ever desired.
tj: restructured __ata_scsi_queuecmd() according to Jeff's suggestion.
Signed-off-by: Mark Lord <liml@rtr.ca>
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/libata-core.c | 4 | ||||
-rw-r--r-- | drivers/ata/libata-scsi.c | 52 | ||||
-rw-r--r-- | drivers/ata/libata.h | 1 |
3 files changed, 41 insertions, 16 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index fc0679370638..75ccf46972d8 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -86,6 +86,10 @@ int atapi_dmadir = 0; | |||
86 | module_param(atapi_dmadir, int, 0444); | 86 | module_param(atapi_dmadir, int, 0444); |
87 | MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)"); | 87 | MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)"); |
88 | 88 | ||
89 | int atapi_passthru16 = 1; | ||
90 | module_param(atapi_passthru16, int, 0444); | ||
91 | MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices; on by default (0=off, 1=on)"); | ||
92 | |||
89 | int libata_fua = 0; | 93 | int libata_fua = 0; |
90 | module_param_named(fua, libata_fua, int, 0444); | 94 | module_param_named(fua, libata_fua, int, 0444); |
91 | MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)"); | 95 | MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)"); |
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 58051ee40f1a..7d66c986a54c 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -2761,28 +2761,48 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, | |||
2761 | void (*done)(struct scsi_cmnd *), | 2761 | void (*done)(struct scsi_cmnd *), |
2762 | struct ata_device *dev) | 2762 | struct ata_device *dev) |
2763 | { | 2763 | { |
2764 | u8 scsi_op = scmd->cmnd[0]; | ||
2765 | ata_xlat_func_t xlat_func; | ||
2764 | int rc = 0; | 2766 | int rc = 0; |
2765 | 2767 | ||
2766 | if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) { | ||
2767 | DPRINTK("bad CDB len=%u, max=%u\n", | ||
2768 | scmd->cmd_len, dev->cdb_len); | ||
2769 | scmd->result = DID_ERROR << 16; | ||
2770 | done(scmd); | ||
2771 | return 0; | ||
2772 | } | ||
2773 | |||
2774 | if (dev->class == ATA_DEV_ATA) { | 2768 | if (dev->class == ATA_DEV_ATA) { |
2775 | ata_xlat_func_t xlat_func = ata_get_xlat_func(dev, | 2769 | if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) |
2776 | scmd->cmnd[0]); | 2770 | goto bad_cdb_len; |
2777 | 2771 | ||
2778 | if (xlat_func) | 2772 | xlat_func = ata_get_xlat_func(dev, scsi_op); |
2779 | rc = ata_scsi_translate(dev, scmd, done, xlat_func); | 2773 | } else { |
2780 | else | 2774 | if (unlikely(!scmd->cmd_len)) |
2781 | ata_scsi_simulate(dev, scmd, done); | 2775 | goto bad_cdb_len; |
2782 | } else | 2776 | |
2783 | rc = ata_scsi_translate(dev, scmd, done, atapi_xlat); | 2777 | xlat_func = NULL; |
2778 | if (likely((scsi_op != ATA_16) || !atapi_passthru16)) { | ||
2779 | /* relay SCSI command to ATAPI device */ | ||
2780 | if (unlikely(scmd->cmd_len > dev->cdb_len)) | ||
2781 | goto bad_cdb_len; | ||
2782 | |||
2783 | xlat_func = atapi_xlat; | ||
2784 | } else { | ||
2785 | /* ATA_16 passthru, treat as an ATA command */ | ||
2786 | if (unlikely(scmd->cmd_len > 16)) | ||
2787 | goto bad_cdb_len; | ||
2788 | |||
2789 | xlat_func = ata_get_xlat_func(dev, scsi_op); | ||
2790 | } | ||
2791 | } | ||
2792 | |||
2793 | if (xlat_func) | ||
2794 | rc = ata_scsi_translate(dev, scmd, done, xlat_func); | ||
2795 | else | ||
2796 | ata_scsi_simulate(dev, scmd, done); | ||
2784 | 2797 | ||
2785 | return rc; | 2798 | return rc; |
2799 | |||
2800 | bad_cdb_len: | ||
2801 | DPRINTK("bad CDB len=%u, scsi_op=0x%02x, max=%u\n", | ||
2802 | scmd->cmd_len, scsi_op, dev->cdb_len); | ||
2803 | scmd->result = DID_ERROR << 16; | ||
2804 | done(scmd); | ||
2805 | return 0; | ||
2786 | } | 2806 | } |
2787 | 2807 | ||
2788 | /** | 2808 | /** |
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 6d85edefa7c6..11f64a43b38a 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h | |||
@@ -56,6 +56,7 @@ extern unsigned int ata_print_id; | |||
56 | extern struct workqueue_struct *ata_aux_wq; | 56 | extern struct workqueue_struct *ata_aux_wq; |
57 | extern int atapi_enabled; | 57 | extern int atapi_enabled; |
58 | extern int atapi_dmadir; | 58 | extern int atapi_dmadir; |
59 | extern int atapi_passthru16; | ||
59 | extern int libata_fua; | 60 | extern int libata_fua; |
60 | extern int libata_noacpi; | 61 | extern int libata_noacpi; |
61 | extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); | 62 | extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); |