diff options
author | Sreekanth Reddy <sreekanth.reddy@avagotech.com> | 2014-09-12 06:05:21 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-09-16 12:14:15 -0400 |
commit | daeaa9df92bd742f4e6d4d6039d689277a8e31bd (patch) | |
tree | 712a7a2df69c28e69b9e0308e54c3836deb8fbe3 | |
parent | 49563e1e4b202436a36409f365b0a96796db5aad (diff) |
mpt2sas: Avoid type casting for direct I/O commands
A type casting error caused the max volume LBA to be truncated from 64
to 32 bits. The virtual LBA would also get truncated to 32 bits in the
case of a 16-byte READ/WRITE command.
Rewrite entire function to get rid of code duplication and type casts.
Use get/put_unaligned wrappers to extract and replace the LBA field in
the MPI request CDB.
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Tested-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_scsih.c | 117 |
1 files changed, 40 insertions, 77 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index e7303edc3d8e..231ec34d8ea9 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c | |||
@@ -55,6 +55,8 @@ | |||
55 | #include <linux/raid_class.h> | 55 | #include <linux/raid_class.h> |
56 | #include <linux/slab.h> | 56 | #include <linux/slab.h> |
57 | 57 | ||
58 | #include <asm/unaligned.h> | ||
59 | |||
58 | #include "mpt2sas_base.h" | 60 | #include "mpt2sas_base.h" |
59 | 61 | ||
60 | MODULE_AUTHOR(MPT2SAS_AUTHOR); | 62 | MODULE_AUTHOR(MPT2SAS_AUTHOR); |
@@ -3858,85 +3860,46 @@ _scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, | |||
3858 | struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, | 3860 | struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, |
3859 | u16 smid) | 3861 | u16 smid) |
3860 | { | 3862 | { |
3861 | u32 v_lba, p_lba, stripe_off, stripe_unit, column, io_size; | 3863 | sector_t v_lba, p_lba, stripe_off, stripe_unit, column, io_size; |
3862 | u32 stripe_sz, stripe_exp; | 3864 | u32 stripe_sz, stripe_exp; |
3863 | u8 num_pds, *cdb_ptr, i; | 3865 | u8 num_pds, cmd = scmd->cmnd[0]; |
3864 | u8 cdb0 = scmd->cmnd[0]; | ||
3865 | u64 v_llba; | ||
3866 | 3866 | ||
3867 | /* | 3867 | if (cmd != READ_10 && cmd != WRITE_10 && |
3868 | * Try Direct I/O to RAID memeber disks | 3868 | cmd != READ_16 && cmd != WRITE_16) |
3869 | */ | 3869 | return; |
3870 | if (cdb0 == READ_16 || cdb0 == READ_10 || | 3870 | |
3871 | cdb0 == WRITE_16 || cdb0 == WRITE_10) { | 3871 | if (cmd == READ_10 || cmd == WRITE_10) |
3872 | cdb_ptr = mpi_request->CDB.CDB32; | 3872 | v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]); |
3873 | 3873 | else | |
3874 | if ((cdb0 < READ_16) || !(cdb_ptr[2] | cdb_ptr[3] | cdb_ptr[4] | 3874 | v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]); |
3875 | | cdb_ptr[5])) { | 3875 | |
3876 | io_size = scsi_bufflen(scmd) >> | 3876 | io_size = scsi_bufflen(scmd) >> raid_device->block_exponent; |
3877 | raid_device->block_exponent; | 3877 | |
3878 | i = (cdb0 < READ_16) ? 2 : 6; | 3878 | if (v_lba + io_size - 1 > raid_device->max_lba) |
3879 | /* get virtual lba */ | 3879 | return; |
3880 | v_lba = be32_to_cpu(*(__be32 *)(&cdb_ptr[i])); | 3880 | |
3881 | 3881 | stripe_sz = raid_device->stripe_sz; | |
3882 | if (((u64)v_lba + (u64)io_size - 1) <= | 3882 | stripe_exp = raid_device->stripe_exponent; |
3883 | (u32)raid_device->max_lba) { | 3883 | stripe_off = v_lba & (stripe_sz - 1); |
3884 | stripe_sz = raid_device->stripe_sz; | 3884 | |
3885 | stripe_exp = raid_device->stripe_exponent; | 3885 | /* Return unless IO falls within a stripe */ |
3886 | stripe_off = v_lba & (stripe_sz - 1); | 3886 | if (stripe_off + io_size > stripe_sz) |
3887 | 3887 | return; | |
3888 | /* Check whether IO falls within a stripe */ | 3888 | |
3889 | if ((stripe_off + io_size) <= stripe_sz) { | 3889 | num_pds = raid_device->num_pds; |
3890 | num_pds = raid_device->num_pds; | 3890 | p_lba = v_lba >> stripe_exp; |
3891 | p_lba = v_lba >> stripe_exp; | 3891 | stripe_unit = p_lba / num_pds; |
3892 | stripe_unit = p_lba / num_pds; | 3892 | column = p_lba % num_pds; |
3893 | column = p_lba % num_pds; | 3893 | p_lba = (stripe_unit << stripe_exp) + stripe_off; |
3894 | p_lba = (stripe_unit << stripe_exp) + | 3894 | mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]); |
3895 | stripe_off; | 3895 | |
3896 | mpi_request->DevHandle = | 3896 | if (cmd == READ_10 || cmd == WRITE_10) |
3897 | cpu_to_le16(raid_device-> | 3897 | put_unaligned_be32(lower_32_bits(p_lba), |
3898 | pd_handle[column]); | 3898 | &mpi_request->CDB.CDB32[2]); |
3899 | (*(__be32 *)(&cdb_ptr[i])) = | 3899 | else |
3900 | cpu_to_be32(p_lba); | 3900 | put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]); |
3901 | /* | 3901 | |
3902 | * WD: To indicate this I/O is directI/O | 3902 | _scsih_scsi_direct_io_set(ioc, smid, 1); |
3903 | */ | ||
3904 | _scsih_scsi_direct_io_set(ioc, smid, 1); | ||
3905 | } | ||
3906 | } | ||
3907 | } else { | ||
3908 | io_size = scsi_bufflen(scmd) >> | ||
3909 | raid_device->block_exponent; | ||
3910 | /* get virtual lba */ | ||
3911 | v_llba = be64_to_cpu(*(__be64 *)(&cdb_ptr[2])); | ||
3912 | |||
3913 | if ((v_llba + (u64)io_size - 1) <= | ||
3914 | raid_device->max_lba) { | ||
3915 | stripe_sz = raid_device->stripe_sz; | ||
3916 | stripe_exp = raid_device->stripe_exponent; | ||
3917 | stripe_off = (u32) (v_llba & (stripe_sz - 1)); | ||
3918 | |||
3919 | /* Check whether IO falls within a stripe */ | ||
3920 | if ((stripe_off + io_size) <= stripe_sz) { | ||
3921 | num_pds = raid_device->num_pds; | ||
3922 | p_lba = (u32)(v_llba >> stripe_exp); | ||
3923 | stripe_unit = p_lba / num_pds; | ||
3924 | column = p_lba % num_pds; | ||
3925 | p_lba = (stripe_unit << stripe_exp) + | ||
3926 | stripe_off; | ||
3927 | mpi_request->DevHandle = | ||
3928 | cpu_to_le16(raid_device-> | ||
3929 | pd_handle[column]); | ||
3930 | (*(__be64 *)(&cdb_ptr[2])) = | ||
3931 | cpu_to_be64((u64)p_lba); | ||
3932 | /* | ||
3933 | * WD: To indicate this I/O is directI/O | ||
3934 | */ | ||
3935 | _scsih_scsi_direct_io_set(ioc, smid, 1); | ||
3936 | } | ||
3937 | } | ||
3938 | } | ||
3939 | } | ||
3940 | } | 3903 | } |
3941 | 3904 | ||
3942 | /** | 3905 | /** |