summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index f0152b043e18..b95f187297ae 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -1973,12 +1973,23 @@ megasas_set_nvme_device_properties(struct scsi_device *sdev,
{
struct megasas_instance *instance;
u32 mr_nvme_pg_size;
+ u64 max_prp_io;
instance = (struct megasas_instance *)sdev->host->hostdata;
mr_nvme_pg_size = max_t(u32, instance->nvme_page_size,
MR_DEFAULT_NVME_PAGE_SIZE);
- lim->max_hw_sectors = max_io_size / 512;
+ /*
+ * megasas_make_prp_nvme() builds the PRP list in cmd->sg_frame without
+ * bounding it against that buffer, and spends one entry per page of
+ * it on the chain pointer. Cap the transfer at what the buffer holds,
+ * less one page for lists that start off a page boundary.
+ */
+ max_prp_io = (u64)((instance->max_chain_frame_sz / sizeof(u64)) -
+ (instance->max_chain_frame_sz / mr_nvme_pg_size) - 1) *
+ mr_nvme_pg_size;
+
+ lim->max_hw_sectors = min_t(u64, max_io_size, max_prp_io) >> SECTOR_SHIFT;
lim->virt_boundary_mask = mr_nvme_pg_size - 1;
}