| From 176ddd89171ddcf661862d90c5d257877f7326d6 Mon Sep 17 00:00:00 2001 |
| From: Jolly Shah <jollys@google.com> |
| Date: Thu, 18 Mar 2021 15:56:32 -0700 |
| Subject: scsi: libsas: Reset num_scatter if libata marks qc as NODATA |
| |
| From: Jolly Shah <jollys@google.com> |
| |
| commit 176ddd89171ddcf661862d90c5d257877f7326d6 upstream. |
| |
| When the cache_type for the SCSI device is changed, the SCSI layer issues a |
| MODE_SELECT command. The caching mode details are communicated via a |
| request buffer associated with the SCSI command with data direction set as |
| DMA_TO_DEVICE (scsi_mode_select()). When this command reaches the libata |
| layer, as a part of generic initial setup, libata layer sets up the |
| scatterlist for the command using the SCSI command (ata_scsi_qc_new()). |
| This command is then translated by the libata layer into |
| ATA_CMD_SET_FEATURES (ata_scsi_mode_select_xlat()). The libata layer treats |
| this as a non-data command (ata_mselect_caching()), since it only needs an |
| ATA taskfile to pass the caching on/off information to the device. It does |
| not need the scatterlist that has been setup, so it does not perform |
| dma_map_sg() on the scatterlist (ata_qc_issue()). Unfortunately, when this |
| command reaches the libsas layer (sas_ata_qc_issue()), libsas layer sees it |
| as a non-data command with a scatterlist. It cannot extract the correct DMA |
| length since the scatterlist has not been mapped with dma_map_sg() for a |
| DMA operation. When this partially constructed SAS task reaches pm80xx |
| LLDD, it results in the following warning: |
| |
| "pm80xx_chip_sata_req 6058: The sg list address |
| start_addr=0x0000000000000000 data_len=0x0end_addr_high=0xffffffff |
| end_addr_low=0xffffffff has crossed 4G boundary" |
| |
| Update libsas to handle ATA non-data commands separately so num_scatter and |
| total_xfer_len remain 0. |
| |
| Link: https://lore.kernel.org/r/20210318225632.2481291-1-jollys@google.com |
| Fixes: 53de092f47ff ("scsi: libsas: Set data_dir as DMA_NONE if libata marks qc as NODATA") |
| Tested-by: Luo Jiaxing <luojiaxing@huawei.com> |
| Reviewed-by: John Garry <john.garry@huawei.com> |
| Signed-off-by: Jolly Shah <jollys@google.com> |
| Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/scsi/libsas/sas_ata.c | 9 ++++----- |
| 1 file changed, 4 insertions(+), 5 deletions(-) |
| |
| --- a/drivers/scsi/libsas/sas_ata.c |
| +++ b/drivers/scsi/libsas/sas_ata.c |
| @@ -216,18 +216,17 @@ static unsigned int sas_ata_qc_issue(str |
| memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len); |
| task->total_xfer_len = qc->nbytes; |
| task->num_scatter = qc->n_elem; |
| + task->data_dir = qc->dma_dir; |
| + } else if (qc->tf.protocol == ATA_PROT_NODATA) { |
| + task->data_dir = DMA_NONE; |
| } else { |
| for_each_sg(qc->sg, sg, qc->n_elem, si) |
| xfer += sg_dma_len(sg); |
| |
| task->total_xfer_len = xfer; |
| task->num_scatter = si; |
| - } |
| - |
| - if (qc->tf.protocol == ATA_PROT_NODATA) |
| - task->data_dir = DMA_NONE; |
| - else |
| task->data_dir = qc->dma_dir; |
| + } |
| task->scatter = qc->sg; |
| task->ata_task.retry_count = 1; |
| task->task_state_flags = SAS_TASK_STATE_PENDING; |