scsi: ufs: Introduce a quirk to allow only page-aligned sg entries
authorKiwoong Kim <kwmad.kim@samsung.com>
Tue, 19 Jan 2021 03:33:41 +0000 (12:33 +0900)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 21 Jan 2021 02:53:44 +0000 (21:53 -0500)
Some SoCs require a single scatterlist entry for smaller than page size,
i.e. 4KB. When dispatching commands with more than one scatterlist entry
under 4KB in size the following behavior is observed:

A command to read a block range is dispatched with two scatterlist entries
that are named AAA and BBB. After dispatching, the host builds two PRDT
entries and during transmission, device sends just one DATA IN because
device doesn't care about host DMA. The host then transfers the combined
amount of data from start address of the area named AAA. As a consequence,
the area that follows AAA in memory would be corrupted.

    |<------------->|
    +-------+------------         +-------+
    +  AAA  + (corrupted)   ...   +  BBB  +
    +-------+------------         +-------+

To avoid this we need to enforce page size alignment for sg entries.

Link: https://lore.kernel.org/r/56dddef94f60bd9466fd77e69f64bbbd657ed2a1.1611026909.git.kwmad.kim@samsung.com
Signed-off-by: Kiwoong Kim <kwmad.kim@samsung.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h

index c22e751bb030ee0da0ccad7fde74b75ceade94a9..a4631caabf304e5f547731ba5582c18caaf9ff98 100644 (file)
@@ -4852,6 +4852,8 @@ static int ufshcd_slave_configure(struct scsi_device *sdev)
        struct request_queue *q = sdev->request_queue;
 
        blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1);
+       if (hba->quirks & UFSHCD_QUIRK_ALIGN_SG_WITH_PAGE_SIZE)
+               blk_queue_update_dma_alignment(q, PAGE_SIZE - 1);
 
        if (ufshcd_is_rpm_autosuspend_allowed(hba))
                sdev->rpm_autosuspend = 1;
index 5bbe4715d4e913eee69f6c79e427dd5d7b4bdafc..a5c6084c86156f88817854943821165e9539c441 100644 (file)
@@ -559,6 +559,10 @@ enum ufshcd_quirks {
         */
        UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING = 1 << 13,
 
+       /*
+        * This quirk allows only sg entries aligned with page size.
+        */
+       UFSHCD_QUIRK_ALIGN_SG_WITH_PAGE_SIZE            = 1 << 13,
 };
 
 enum ufshcd_caps {