]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
RDMA/srp: Handle large SCSI CDBs correctly
authorBart Van Assche <bvanassche@acm.org>
Mon, 17 Dec 2018 21:20:35 +0000 (13:20 -0800)
committerDoug Ledford <dledford@redhat.com>
Wed, 19 Dec 2018 20:07:25 +0000 (15:07 -0500)
Reserve additional space for CDBs that contain more than sixteen bytes
and set the add_cdb_len field for such CDBs as required. From the SRP
standard: "The ADDITIONAL CDB LENGTH field contains the length in
dwords of the ADDITIONAL CDB field."

Cc: Sergey Gorenko <sergeygo@mellanox.com>
Cc: Max Gurtovoy <maxg@mellanox.com>
Cc: Laurence Oberman <loberman@redhat.com>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/ulp/srp/ib_srp.c
drivers/infiniband/ulp/srp/ib_srp.h

index fbf701c0a514ea306918c7afd33aefd21f47ac99..ef8d55dca13643757993370838f9f4e04f05605a 100644 (file)
@@ -1782,7 +1782,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
        u8 fmt;
 
        if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE)
-               return sizeof (struct srp_cmd);
+               return sizeof(struct srp_cmd) + cmd->add_cdb_len;
 
        if (scmnd->sc_data_direction != DMA_FROM_DEVICE &&
            scmnd->sc_data_direction != DMA_TO_DEVICE) {
@@ -1803,7 +1803,8 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
                return -EIO;
 
        fmt = SRP_DATA_DESC_DIRECT;
-       len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf);
+       len = sizeof(struct srp_cmd) + cmd->add_cdb_len +
+               sizeof(struct srp_direct_buf);
 
        if (count == 1 && target->global_rkey) {
                /*
@@ -1812,8 +1813,9 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
                 * single entry.  So a direct descriptor along with
                 * the DMA MR suffices.
                 */
-               struct srp_direct_buf *buf = (void *) cmd->add_data;
+               struct srp_direct_buf *buf;
 
+               buf = (void *)cmd->add_data + cmd->add_cdb_len;
                buf->va  = cpu_to_be64(ib_sg_dma_address(ibdev, scat));
                buf->key = cpu_to_be32(target->global_rkey);
                buf->len = cpu_to_be32(ib_sg_dma_len(ibdev, scat));
@@ -1826,7 +1828,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
         * We have more than one scatter/gather entry, so build our indirect
         * descriptor table, trying to merge as many entries as we can.
         */
-       indirect_hdr = (void *) cmd->add_data;
+       indirect_hdr = (void *)cmd->add_data + cmd->add_cdb_len;
 
        ib_dma_sync_single_for_cpu(ibdev, req->indirect_dma_addr,
                                   target->indirect_size, DMA_TO_DEVICE);
@@ -1861,8 +1863,9 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
                 * Memory registration collapsed the sg-list into one entry,
                 * so use a direct descriptor.
                 */
-               struct srp_direct_buf *buf = (void *) cmd->add_data;
+               struct srp_direct_buf *buf;
 
+               buf = (void *)cmd->add_data + cmd->add_cdb_len;
                *buf = req->indirect_desc[0];
                goto map_complete;
        }
@@ -1880,7 +1883,8 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
        idb_len = sizeof(struct srp_indirect_buf) + table_len;
 
        fmt = SRP_DATA_DESC_INDIRECT;
-       len = sizeof(struct srp_cmd) + sizeof (struct srp_indirect_buf);
+       len = sizeof(struct srp_cmd) + cmd->add_cdb_len +
+               sizeof(struct srp_indirect_buf);
        len += count * sizeof (struct srp_direct_buf);
 
        memcpy(indirect_hdr->desc_list, req->indirect_desc,
@@ -2324,6 +2328,12 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
        int_to_scsilun(scmnd->device->lun, &cmd->lun);
        cmd->tag    = tag;
        memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len);
+       if (unlikely(scmnd->cmd_len > sizeof(cmd->cdb))) {
+               cmd->add_cdb_len = round_up(scmnd->cmd_len - sizeof(cmd->cdb),
+                                           4);
+               if (WARN_ON_ONCE(cmd->add_cdb_len > SRP_MAX_ADD_CDB_LEN))
+                       goto err_iu;
+       }
 
        req->scmnd    = scmnd;
        req->cmd      = iu;
@@ -3829,6 +3839,7 @@ static ssize_t srp_create_target(struct device *dev,
        target->indirect_size = target->sg_tablesize *
                                sizeof (struct srp_direct_buf);
        target->max_iu_len = sizeof (struct srp_cmd) +
+                            SRP_MAX_ADD_CDB_LEN +
                             sizeof (struct srp_indirect_buf) +
                             target->cmd_sg_cnt * sizeof (struct srp_direct_buf);
 
index a2706086b9c7d4e55acea759f8d96d6a9c2b2dd9..d6c116a53d5e817cb6b651c84d79ab16cbecd355 100644 (file)
@@ -67,6 +67,8 @@ enum {
        SRP_TAG_TSK_MGMT        = 1U << 31,
 
        SRP_MAX_PAGES_PER_MR    = 512,
+
+       SRP_MAX_ADD_CDB_LEN     = 16,
 };
 
 enum srp_target_state {