Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux.git] / drivers / target / target_core_sbc.c
index 62daef5c0c8f18b6552a9e01216d09514e563716..e0229592ec5509656aed292970af719be1f9111d 100644 (file)
@@ -89,6 +89,7 @@ static sense_reason_t
 sbc_emulate_readcapacity_16(struct se_cmd *cmd)
 {
        struct se_device *dev = cmd->se_dev;
+       struct se_session *sess = cmd->se_sess;
        unsigned char *rbuf;
        unsigned char buf[32];
        unsigned long long blocks = dev->transport->get_blocks(dev);
@@ -109,8 +110,10 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
        /*
         * Set P_TYPE and PROT_EN bits for DIF support
         */
-       if (dev->dev_attrib.pi_prot_type)
-               buf[12] = (dev->dev_attrib.pi_prot_type - 1) << 1 | 0x1;
+       if (sess->sup_prot_ops & (TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS)) {
+               if (dev->dev_attrib.pi_prot_type)
+                       buf[12] = (dev->dev_attrib.pi_prot_type - 1) << 1 | 0x1;
+       }
 
        if (dev->transport->get_lbppbe)
                buf[13] = dev->transport->get_lbppbe(dev) & 0x0f;
@@ -425,13 +428,14 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd)
                goto out;
        }
 
-       write_sg = kzalloc(sizeof(struct scatterlist) * cmd->t_data_nents,
+       write_sg = kmalloc(sizeof(struct scatterlist) * cmd->t_data_nents,
                           GFP_KERNEL);
        if (!write_sg) {
                pr_err("Unable to allocate compare_and_write sg\n");
                ret = TCM_OUT_OF_RESOURCES;
                goto out;
        }
+       sg_init_table(write_sg, cmd->t_data_nents);
        /*
         * Setup verify and write data payloads from total NumberLBAs.
         */
@@ -1092,6 +1096,50 @@ err:
 }
 EXPORT_SYMBOL(sbc_execute_unmap);
 
+void
+sbc_dif_generate(struct se_cmd *cmd)
+{
+       struct se_device *dev = cmd->se_dev;
+       struct se_dif_v1_tuple *sdt;
+       struct scatterlist *dsg, *psg = cmd->t_prot_sg;
+       sector_t sector = cmd->t_task_lba;
+       void *daddr, *paddr;
+       int i, j, offset = 0;
+
+       for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) {
+               daddr = kmap_atomic(sg_page(dsg)) + dsg->offset;
+               paddr = kmap_atomic(sg_page(psg)) + psg->offset;
+
+               for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) {
+
+                       if (offset >= psg->length) {
+                               kunmap_atomic(paddr);
+                               psg = sg_next(psg);
+                               paddr = kmap_atomic(sg_page(psg)) + psg->offset;
+                               offset = 0;
+                       }
+
+                       sdt = paddr + offset;
+                       sdt->guard_tag = cpu_to_be16(crc_t10dif(daddr + j,
+                                               dev->dev_attrib.block_size));
+                       if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT)
+                               sdt->ref_tag = cpu_to_be32(sector & 0xffffffff);
+                       sdt->app_tag = 0;
+
+                       pr_debug("DIF WRITE INSERT sector: %llu guard_tag: 0x%04x"
+                                " app_tag: 0x%04x ref_tag: %u\n",
+                                (unsigned long long)sector, sdt->guard_tag,
+                                sdt->app_tag, be32_to_cpu(sdt->ref_tag));
+
+                       sector++;
+                       offset += sizeof(struct se_dif_v1_tuple);
+               }
+
+               kunmap_atomic(paddr);
+               kunmap_atomic(daddr);
+       }
+}
+
 static sense_reason_t
 sbc_dif_v1_verify(struct se_device *dev, struct se_dif_v1_tuple *sdt,
                  const void *p, sector_t sector, unsigned int ei_lba)
@@ -1223,9 +1271,9 @@ sbc_dif_verify_write(struct se_cmd *cmd, sector_t start, unsigned int sectors,
 }
 EXPORT_SYMBOL(sbc_dif_verify_write);
 
-sense_reason_t
-sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
-                   unsigned int ei_lba, struct scatterlist *sg, int sg_off)
+static sense_reason_t
+__sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
+                     unsigned int ei_lba, struct scatterlist *sg, int sg_off)
 {
        struct se_device *dev = cmd->se_dev;
        struct se_dif_v1_tuple *sdt;
@@ -1278,8 +1326,31 @@ sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
                kunmap_atomic(paddr);
                kunmap_atomic(daddr);
        }
-       sbc_dif_copy_prot(cmd, sectors, true, sg, sg_off);
 
        return 0;
 }
+
+sense_reason_t
+sbc_dif_read_strip(struct se_cmd *cmd)
+{
+       struct se_device *dev = cmd->se_dev;
+       u32 sectors = cmd->prot_length / dev->prot_length;
+
+       return __sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, 0,
+                                    cmd->t_prot_sg, 0);
+}
+
+sense_reason_t
+sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
+                   unsigned int ei_lba, struct scatterlist *sg, int sg_off)
+{
+       sense_reason_t rc;
+
+       rc = __sbc_dif_verify_read(cmd, start, sectors, ei_lba, sg, sg_off);
+       if (rc)
+               return rc;
+
+       sbc_dif_copy_prot(cmd, sectors, true, sg, sg_off);
+       return 0;
+}
 EXPORT_SYMBOL(sbc_dif_verify_read);