[v6] sd: Check for unaligned partial completion
diff mbox

Message ID 20170301082700.20413-1-damien.lemoal@wdc.com
State Accepted, archived
Headers show

Commit Message

Damien Le Moal March 1, 2017, 8:27 a.m. UTC
Commit <f2e767bb5d6e> ("mpt3sas: Force request partial completion
alignment") was not considering the case of commands not operating on
logical block size units (e.g. REQ_OP_ZONE_REPORT and its 64B aligned
partial replies). In this case, forcing alignment of resid to the
device logical block size can break the command result, e.g. in the
case of REQ_OP_ZONE_REPORT, the exact number of zone reported by the
device.

Move the partial completion alignement check of mpt3sas to a generic
implementation in sd_done(). The check is added within the default
section of the initial req_op() switch case so that the report and
reset zone commands are ignored. In addition, as sd_done() is not
called for passthrough requests, resid corrections are not done as
intended by the initial mpt3sas patch.

Fixes: f2e767bb5d6e ("mpt3sas: Force request partial completion alignment")
Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>
---
 drivers/scsi/mpt3sas/mpt3sas_scsih.c | 15 ---------------
 drivers/scsi/sd.c                    | 17 +++++++++++++++++
 2 files changed, 17 insertions(+), 15 deletions(-)

Comments

Christoph Hellwig March 1, 2017, 2:51 p.m. UTC | #1
I much prefer this version:

Acked-by: Christoph Hellwig <hch@lst.de>
Bart Van Assche March 1, 2017, 4:16 p.m. UTC | #2
On Wed, 2017-03-01 at 17:27 +0900, Damien Le Moal wrote:
> Commit <f2e767bb5d6e> ("mpt3sas: Force request partial completion
> alignment") was not considering the case of commands not operating on
> logical block size units (e.g. REQ_OP_ZONE_REPORT and its 64B aligned
> partial replies). In this case, forcing alignment of resid to the
> device logical block size can break the command result, e.g. in the
> case of REQ_OP_ZONE_REPORT, the exact number of zone reported by the
> device.
> 
> Move the partial completion alignement check of mpt3sas to a generic
> implementation in sd_done(). The check is added within the default
> section of the initial req_op() switch case so that the report and
> reset zone commands are ignored. In addition, as sd_done() is not
> called for passthrough requests, resid corrections are not done as
> intended by the initial mpt3sas patch.
> 
> Fixes: f2e767bb5d6e ("mpt3sas: Force request partial completion alignment")
> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com>

We want this patch to be included in the v4.10.x stable kernels so I think
that a "Cc: <stable@vger.kernel.org>" tag is needed. Otherwise this patch
looks fine to me. Hence:

Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
Martin K. Petersen March 2, 2017, 2:48 a.m. UTC | #3
>>>>> "Damien" == Damien Le Moal <damien.lemoal@wdc.com> writes:

Damien,

Damien> Move the partial completion alignement check of mpt3sas to a
Damien> generic implementation in sd_done(). The check is added within
Damien> the default section of the initial req_op() switch case so that
Damien> the report and reset zone commands are ignored. In addition, as
Damien> sd_done() is not called for passthrough requests, resid
Damien> corrections are not done as intended by the initial mpt3sas
Damien> patch.

Thanks! Applied to 4.11/scsi-fixes with a Cc: to stable.

Patch
diff mbox

diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 46e866c..69c29c5 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -4677,7 +4677,6 @@  _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
 	struct MPT3SAS_DEVICE *sas_device_priv_data;
 	u32 response_code = 0;
 	unsigned long flags;
-	unsigned int sector_sz;
 
 	mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
 
@@ -4742,20 +4741,6 @@  _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
 	}
 
 	xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
-
-	/* In case of bogus fw or device, we could end up having
-	 * unaligned partial completion. We can force alignment here,
-	 * then scsi-ml does not need to handle this misbehavior.
-	 */
-	sector_sz = scmd->device->sector_size;
-	if (unlikely(!blk_rq_is_passthrough(scmd->request) && sector_sz &&
-		     xfer_cnt % sector_sz)) {
-		sdev_printk(KERN_INFO, scmd->device,
-		    "unaligned partial completion avoided (xfer_cnt=%u, sector_sz=%u)\n",
-			    xfer_cnt, sector_sz);
-		xfer_cnt = round_down(xfer_cnt, sector_sz);
-	}
-
 	scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
 	if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
 		log_info =  le32_to_cpu(mpi_reply->IOCLogInfo);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index c7839f6..fb9b4d2 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1783,6 +1783,8 @@  static int sd_done(struct scsi_cmnd *SCpnt)
 {
 	int result = SCpnt->result;
 	unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt);
+	unsigned int sector_size = SCpnt->device->sector_size;
+	unsigned int resid;
 	struct scsi_sense_hdr sshdr;
 	struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk);
 	struct request *req = SCpnt->request;
@@ -1813,6 +1815,21 @@  static int sd_done(struct scsi_cmnd *SCpnt)
 			scsi_set_resid(SCpnt, blk_rq_bytes(req));
 		}
 		break;
+	default:
+		/*
+		 * In case of bogus fw or device, we could end up having
+		 * an unaligned partial completion. Check this here and force
+		 * alignment.
+		 */
+		resid = scsi_get_resid(SCpnt);
+		if (resid & (sector_size - 1)) {
+			sd_printk(KERN_INFO, sdkp,
+				"Unaligned partial completion (resid=%u, sector_sz=%u)\n",
+				resid, sector_size);
+			resid = min(scsi_bufflen(SCpnt),
+				    round_up(resid, sector_size));
+			scsi_set_resid(SCpnt, resid);
+		}
 	}
 
 	if (result) {