diff options
author | Sreekanth Reddy <sreekanth.reddy@avagotech.com> | 2014-09-12 14:05:21 +0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-09-16 20:14:15 +0400 |
commit | daeaa9df92bd742f4e6d4d6039d689277a8e31bd (patch) | |
tree | 712a7a2df69c28e69b9e0308e54c3836deb8fbe3 /drivers/scsi | |
parent | 49563e1e4b202436a36409f365b0a96796db5aad (diff) | |
download | linux-daeaa9df92bd742f4e6d4d6039d689277a8e31bd.tar.xz |
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>
Diffstat (limited to 'drivers/scsi')
-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 @@ #include <linux/raid_class.h> #include <linux/slab.h> +#include <asm/unaligned.h> + #include "mpt2sas_base.h" MODULE_AUTHOR(MPT2SAS_AUTHOR); @@ -3858,85 +3860,46 @@ _scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, u16 smid) { - u32 v_lba, p_lba, stripe_off, stripe_unit, column, io_size; + sector_t v_lba, p_lba, stripe_off, stripe_unit, column, io_size; u32 stripe_sz, stripe_exp; - u8 num_pds, *cdb_ptr, i; - u8 cdb0 = scmd->cmnd[0]; - u64 v_llba; + u8 num_pds, cmd = scmd->cmnd[0]; - /* - * Try Direct I/O to RAID memeber disks - */ - if (cdb0 == READ_16 || cdb0 == READ_10 || - cdb0 == WRITE_16 || cdb0 == WRITE_10) { - cdb_ptr = mpi_request->CDB.CDB32; - - if ((cdb0 < READ_16) || !(cdb_ptr[2] | cdb_ptr[3] | cdb_ptr[4] - | cdb_ptr[5])) { - io_size = scsi_bufflen(scmd) >> - raid_device->block_exponent; - i = (cdb0 < READ_16) ? 2 : 6; - /* get virtual lba */ - v_lba = be32_to_cpu(*(__be32 *)(&cdb_ptr[i])); - - if (((u64)v_lba + (u64)io_size - 1) <= - (u32)raid_device->max_lba) { - stripe_sz = raid_device->stripe_sz; - stripe_exp = raid_device->stripe_exponent; - stripe_off = v_lba & (stripe_sz - 1); - - /* Check whether IO falls within a stripe */ - if ((stripe_off + io_size) <= stripe_sz) { - num_pds = raid_device->num_pds; - p_lba = v_lba >> stripe_exp; - stripe_unit = p_lba / num_pds; - column = p_lba % num_pds; - p_lba = (stripe_unit << stripe_exp) + - stripe_off; - mpi_request->DevHandle = - cpu_to_le16(raid_device-> - pd_handle[column]); - (*(__be32 *)(&cdb_ptr[i])) = - cpu_to_be32(p_lba); - /* - * WD: To indicate this I/O is directI/O - */ - _scsih_scsi_direct_io_set(ioc, smid, 1); - } - } - } else { - io_size = scsi_bufflen(scmd) >> - raid_device->block_exponent; - /* get virtual lba */ - v_llba = be64_to_cpu(*(__be64 *)(&cdb_ptr[2])); - - if ((v_llba + (u64)io_size - 1) <= - raid_device->max_lba) { - stripe_sz = raid_device->stripe_sz; - stripe_exp = raid_device->stripe_exponent; - stripe_off = (u32) (v_llba & (stripe_sz - 1)); - - /* Check whether IO falls within a stripe */ - if ((stripe_off + io_size) <= stripe_sz) { - num_pds = raid_device->num_pds; - p_lba = (u32)(v_llba >> stripe_exp); - stripe_unit = p_lba / num_pds; - column = p_lba % num_pds; - p_lba = (stripe_unit << stripe_exp) + - stripe_off; - mpi_request->DevHandle = - cpu_to_le16(raid_device-> - pd_handle[column]); - (*(__be64 *)(&cdb_ptr[2])) = - cpu_to_be64((u64)p_lba); - /* - * WD: To indicate this I/O is directI/O - */ - _scsih_scsi_direct_io_set(ioc, smid, 1); - } - } - } - } + if (cmd != READ_10 && cmd != WRITE_10 && + cmd != READ_16 && cmd != WRITE_16) + return; + + if (cmd == READ_10 || cmd == WRITE_10) + v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]); + else + v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]); + + io_size = scsi_bufflen(scmd) >> raid_device->block_exponent; + + if (v_lba + io_size - 1 > raid_device->max_lba) + return; + + stripe_sz = raid_device->stripe_sz; + stripe_exp = raid_device->stripe_exponent; + stripe_off = v_lba & (stripe_sz - 1); + + /* Return unless IO falls within a stripe */ + if (stripe_off + io_size > stripe_sz) + return; + + num_pds = raid_device->num_pds; + p_lba = v_lba >> stripe_exp; + stripe_unit = p_lba / num_pds; + column = p_lba % num_pds; + p_lba = (stripe_unit << stripe_exp) + stripe_off; + mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]); + + if (cmd == READ_10 || cmd == WRITE_10) + put_unaligned_be32(lower_32_bits(p_lba), + &mpi_request->CDB.CDB32[2]); + else + put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]); + + _scsih_scsi_direct_io_set(ioc, smid, 1); } /** |