Make the two block layer operations most frequently used (REQ_OP_READ
and REQ_OP_WRITE) bypass the switch statements in the submission and
response paths. Assume these two enums are 0 and 1 which allows a
single comparison to select both of them. Check that assumption
at driver start-up.

Signed-off-by: Douglas Gilbert <dgilb...@interlog.com>
---
 drivers/scsi/sd.c | 82 +++++++++++++++++++++++++++++++----------------
 1 file changed, 55 insertions(+), 27 deletions(-)

diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 4b1402633c36..9f047fd3c92d 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1227,6 +1227,14 @@ static int sd_init_command(struct scsi_cmnd *cmd)
 {
        struct request *rq = cmd->request;
 
+       /*
+        * Assumption that REQ_OP_READ and REQ_OP_WRITE are 0 and 1 is
+        * checked in init_sd(). The following "if" is done to dispatch
+        * REQ_OP_READ and REQ_OP_WRITE quickly.
+        */
+       if (likely(req_op(rq) < 2))
+               return sd_setup_read_write_cmnd(cmd);
+
        switch (req_op(rq)) {
        case REQ_OP_DISCARD:
                switch (scsi_disk(rq->rq_disk)->provisioning_mode) {
@@ -1247,9 +1255,6 @@ static int sd_init_command(struct scsi_cmnd *cmd)
                return sd_setup_write_same_cmnd(cmd);
        case REQ_OP_FLUSH:
                return sd_setup_flush_cmnd(cmd);
-       case REQ_OP_READ:
-       case REQ_OP_WRITE:
-               return sd_setup_read_write_cmnd(cmd);
        case REQ_OP_ZONE_REPORT:
                return sd_zbc_setup_report_cmnd(cmd);
        case REQ_OP_ZONE_RESET:
@@ -1973,30 +1978,12 @@ static int sd_done(struct scsi_cmnd *SCpnt)
        int sense_valid = 0;
        int sense_deferred = 0;
 
-       switch (req_op(req)) {
-       case REQ_OP_DISCARD:
-       case REQ_OP_WRITE_ZEROES:
-       case REQ_OP_WRITE_SAME:
-       case REQ_OP_ZONE_RESET:
-               if (!result) {
-                       good_bytes = blk_rq_bytes(req);
-                       scsi_set_resid(SCpnt, 0);
-               } else {
-                       good_bytes = 0;
-                       scsi_set_resid(SCpnt, blk_rq_bytes(req));
-               }
-               break;
-       case REQ_OP_ZONE_REPORT:
-               if (!result) {
-                       good_bytes = scsi_bufflen(SCpnt)
-                               - scsi_get_resid(SCpnt);
-                       scsi_set_resid(SCpnt, 0);
-               } else {
-                       good_bytes = 0;
-                       scsi_set_resid(SCpnt, blk_rq_bytes(req));
-               }
-               break;
-       default:
+       /*
+        * Assumption that REQ_OP_READ and REQ_OP_WRITE are 0 and 1 is
+        * checked in init_sd(). The following "if" is done to expedite
+        * REQ_OP_READ and REQ_OP_WRITE.
+        */
+       if (likely(req_op(req) < 2)) {
                /*
                 * In case of bogus fw or device, we could end up having
                 * an unaligned partial completion. Check this here and force
@@ -2011,6 +1998,36 @@ static int sd_done(struct scsi_cmnd *SCpnt)
                                    round_up(resid, sector_size));
                        scsi_set_resid(SCpnt, resid);
                }
+       } else {
+               switch (req_op(req)) {
+               case REQ_OP_DISCARD:
+               case REQ_OP_WRITE_ZEROES:
+               case REQ_OP_WRITE_SAME:
+               case REQ_OP_ZONE_RESET:
+                       if (!result) {
+                               good_bytes = blk_rq_bytes(req);
+                               scsi_set_resid(SCpnt, 0);
+                       } else {
+                               good_bytes = 0;
+                               scsi_set_resid(SCpnt, blk_rq_bytes(req));
+                       }
+                       break;
+               case REQ_OP_ZONE_REPORT:
+                       if (!result) {
+                               good_bytes = scsi_bufflen(SCpnt)
+                                       - scsi_get_resid(SCpnt);
+                               scsi_set_resid(SCpnt, 0);
+                       } else {
+                               good_bytes = 0;
+                               scsi_set_resid(SCpnt, blk_rq_bytes(req));
+                       }
+                       break;
+               default:
+                       sd_printk(KERN_NOTICE, sdkp, "unexpected REQ_OP=%u\n",
+                                 (unsigned int)req_op(req));
+                       WARN_ON_ONCE(true);
+                       break;
+               }
        }
 
        if (result) {
@@ -3597,6 +3614,17 @@ static int __init init_sd(void)
        int majors = 0, i, err;
 
        SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
+       /*
+        * The sd_init_command() and sd_done() assume REQ_OP_READ and
+        * REQ_OP_WRITE are 0 and 1 and will fail if they are not. If they
+        * are not, would prefer a compile failure but the preprocessor can't
+        * use enum constants. Place check here because only need to check
+        * early and once.
+        */
+       if (REQ_OP_READ + REQ_OP_WRITE > 1)
+               pr_err("%s: REQ_OP_READ=%d REQ_OP_WRITE=%d %s.\n", __func__,
+                      REQ_OP_READ, REQ_OP_WRITE,
+                      "expected 0 and 1. Logic ERROR");
 
        for (i = 0; i < SD_MAJORS; i++) {
                if (register_blkdev(sd_major(i), "sd") != 0)
-- 
2.17.1

Reply via email to