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/ata/libata-scsi.c | |
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/ata/libata-scsi.c')
-rw-r--r-- | drivers/ata/libata-scsi.c | 52 |
1 files changed, 36 insertions, 16 deletions
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 | /** |