}
 
 /*
- * compare @cmp_len bytes of @read_sgl with @cmp_sgl. On miscompare return
- * TCM_MISCOMPARE_VERIFY.
+ * compare @cmp_len bytes of @read_sgl with @cmp_sgl. On miscompare, fill
+ * @miscmp_off and return TCM_MISCOMPARE_VERIFY.
  */
 static sense_reason_t
 compare_and_write_do_cmp(struct scatterlist *read_sgl, unsigned int read_nents,
                         struct scatterlist *cmp_sgl, unsigned int cmp_nents,
-                        unsigned int cmp_len)
+                        unsigned int cmp_len, unsigned int *miscmp_off)
 {
        unsigned char *buf = NULL;
        struct scatterlist *sg;
         * Compare SCSI READ payload against verify payload
         */
        offset = 0;
+       ret = TCM_NO_SENSE;
        for_each_sg(read_sgl, sg, read_nents, i) {
                unsigned int len = min(sg->length, cmp_len);
                unsigned char *addr = kmap_atomic(sg_page(sg));
 
                if (memcmp(addr, buf + offset, len)) {
-                       pr_warn("Detected MISCOMPARE for addr: %p buf: %p\n",
-                               addr, buf + offset);
-                       kunmap_atomic(addr);
+                       unsigned int i;
+
+                       for (i = 0; i < len && addr[i] == buf[offset + i]; i++)
+                               ;
+                       *miscmp_off = offset + i;
+                       pr_warn("Detected MISCOMPARE at offset %u\n",
+                               *miscmp_off);
                        ret = TCM_MISCOMPARE_VERIFY;
-                       goto out;
                }
                kunmap_atomic(addr);
+               if (ret != TCM_NO_SENSE)
+                       goto out;
 
                offset += len;
                cmp_len -= len;
                        break;
        }
        pr_debug("COMPARE AND WRITE read data matches compare data\n");
-       ret = TCM_NO_SENSE;
 out:
        kfree(buf);
        return ret;
        unsigned int len;
        unsigned int block_size = dev->dev_attrib.block_size;
        unsigned int compare_len = (cmd->t_task_nolb * block_size);
+       unsigned int miscmp_off = 0;
        sense_reason_t ret = TCM_NO_SENSE;
        int i;
 
                                       cmd->t_bidi_data_nents,
                                       cmd->t_data_sg,
                                       cmd->t_data_nents,
-                                      compare_len);
-       if (ret)
+                                      compare_len,
+                                      &miscmp_off);
+       if (ret == TCM_MISCOMPARE_VERIFY) {
+               /*
+                * SBC-4 r15: 5.3 COMPARE AND WRITE command
+                * In the sense data (see 4.18 and SPC-5) the offset from the
+                * start of the Data-Out Buffer to the first byte of data that
+                * was not equal shall be reported in the INFORMATION field.
+                */
+               cmd->sense_info = miscmp_off;
+               goto out;
+       } else if (ret)
                goto out;
 
        if (sg_alloc_table(&write_tbl, cmd->t_data_nents, GFP_KERNEL) < 0) {