Signed-off-by: Douglas Gilbert <dgilbert@xxxxxxxxxxxx>
---
No speed up here, just a clean up. There could possibly be a speed
improvement (not observed in tests) from lessening the cache footprint
of the sd_done() function which is on the fast path.
drivers/scsi/sd.c | 112 ++++++++++++++++++++++++----------------------
1 file changed, 59 insertions(+), 53 deletions(-)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index b17b8c66881d..4b1402633c36 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1898,6 +1898,62 @@ static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
return min(good_bytes, transferred);
}
+/* Helper for scsi_done() when there is a sense buffer */
+static int sd_done_sense(struct scsi_cmnd *SCpnt, unsigned int good_bytes,
+ struct scsi_sense_hdr *sshdrp)
+{
+ struct request *req = SCpnt->request;
+ struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk);
+
+ switch (sshdrp->sense_key) {
+ case HARDWARE_ERROR:
+ case MEDIUM_ERROR:
+ return sd_completed_bytes(SCpnt);
+ case RECOVERED_ERROR:
+ return scsi_bufflen(SCpnt);
+ case NO_SENSE:
+ /* This indicates a false check condition, so ignore it. An
+ * unknown amount of data was transferred so treat it as an
+ * error.
+ */
+ SCpnt->result = 0;
+ memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ break;
+ case ABORTED_COMMAND:
+ if (sshdrp->asc == 0x10) /* DIF: Target detected corruption */
+ good_bytes = sd_completed_bytes(SCpnt);
+ break;
+ case ILLEGAL_REQUEST:
+ switch (sshdrp->asc) {
+ case 0x10: /* DIX: Host detected corruption */
+ good_bytes = sd_completed_bytes(SCpnt);
+ break;
+ case 0x20: /* INVALID COMMAND OPCODE */
+ case 0x24: /* INVALID FIELD IN CDB */
+ switch (SCpnt->cmnd[0]) {
+ case UNMAP:
+ sd_config_discard(sdkp, SD_LBP_DISABLE);
+ break;
+ case WRITE_SAME_16:
+ case WRITE_SAME:
+ if (SCpnt->cmnd[1] & 8) { /* UNMAP */
+ sd_config_discard(sdkp, SD_LBP_DISABLE);
+ } else {
+ sdkp->device->no_write_same = 1;
+ sd_config_write_same(sdkp);
+ req->__data_len = blk_rq_bytes(req);
+ req->rq_flags |= RQF_QUIET;
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return good_bytes;
+}
+
/**
* sd_done - bottom half handler: called when the lower level
* driver has completed (successfully or otherwise) a scsi command.
@@ -1964,60 +2020,10 @@ static int sd_done(struct scsi_cmnd *SCpnt)
}
sdkp->medium_access_timed_out = 0;
- if (driver_byte(result) != DRIVER_SENSE &&
- (!sense_valid || sense_deferred))
- goto out;
+ if (unlikely(driver_byte(result) == DRIVER_SENSE ||
+ (sense_valid && !sense_deferred)))
+ good_bytes = sd_done_sense(SCpnt, good_bytes, &sshdr);
- switch (sshdr.sense_key) {
- case HARDWARE_ERROR:
- case MEDIUM_ERROR:
- good_bytes = sd_completed_bytes(SCpnt);
- break;
- case RECOVERED_ERROR:
- good_bytes = scsi_bufflen(SCpnt);
- break;
- case NO_SENSE:
- /* This indicates a false check condition, so ignore it. An
- * unknown amount of data was transferred so treat it as an
- * error.
- */
- SCpnt->result = 0;
- memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- break;
- case ABORTED_COMMAND:
- if (sshdr.asc == 0x10) /* DIF: Target detected corruption */
- good_bytes = sd_completed_bytes(SCpnt);
- break;
- case ILLEGAL_REQUEST:
- switch (sshdr.asc) {
- case 0x10: /* DIX: Host detected corruption */
- good_bytes = sd_completed_bytes(SCpnt);
- break;
- case 0x20: /* INVALID COMMAND OPCODE */
- case 0x24: /* INVALID FIELD IN CDB */
- switch (SCpnt->cmnd[0]) {
- case UNMAP:
- sd_config_discard(sdkp, SD_LBP_DISABLE);
- break;
- case WRITE_SAME_16:
- case WRITE_SAME:
- if (SCpnt->cmnd[1] & 8) { /* UNMAP */
- sd_config_discard(sdkp, SD_LBP_DISABLE);
- } else {
- sdkp->device->no_write_same = 1;
- sd_config_write_same(sdkp);
- req->__data_len = blk_rq_bytes(req);
- req->rq_flags |= RQF_QUIET;
- }
- break;
- }
- }
- break;
- default:
- break;
- }
-
- out:
if (sd_is_zoned(sdkp))
sd_zbc_complete(SCpnt, good_bytes, &sshdr);