* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <scsi/scsi_cmnd.h>
 #include "isci.h"
 #include "task.h"
 #include "request.h"
        task_context->response_iu_lower = lower_32_bits(dma_addr);
 }
 
+static u8 scu_bg_blk_size(struct scsi_device *sdp)
+{
+       switch (sdp->sector_size) {
+       case 512:
+               return 0;
+       case 1024:
+               return 1;
+       case 4096:
+               return 3;
+       default:
+               return 0xff;
+       }
+}
+
+static u32 scu_dif_bytes(u32 len, u32 sector_size)
+{
+       return (len >> ilog2(sector_size)) * 8;
+}
+
+static void scu_ssp_ireq_dif_insert(struct isci_request *ireq, u8 type, u8 op)
+{
+       struct scu_task_context *tc = ireq->tc;
+       struct scsi_cmnd *scmd = ireq->ttype_ptr.io_task_ptr->uldd_task;
+       u8 blk_sz = scu_bg_blk_size(scmd->device);
+
+       tc->block_guard_enable = 1;
+       tc->blk_prot_en = 1;
+       tc->blk_sz = blk_sz;
+       /* DIF write insert */
+       tc->blk_prot_func = 0x2;
+
+       tc->transfer_length_bytes += scu_dif_bytes(tc->transfer_length_bytes,
+                                                  scmd->device->sector_size);
+
+       /* always init to 0, used by hw */
+       tc->interm_crc_val = 0;
+
+       tc->init_crc_seed = 0;
+       tc->app_tag_verify = 0;
+       tc->app_tag_gen = 0;
+       tc->ref_tag_seed_verify = 0;
+
+       /* always init to same as bg_blk_sz */
+       tc->UD_bytes_immed_val = scmd->device->sector_size;
+
+       tc->reserved_DC_0 = 0;
+
+       /* always init to 8 */
+       tc->DIF_bytes_immed_val = 8;
+
+       tc->reserved_DC_1 = 0;
+       tc->bgc_blk_sz = scmd->device->sector_size;
+       tc->reserved_E0_0 = 0;
+       tc->app_tag_gen_mask = 0;
+
+       /** setup block guard control **/
+       tc->bgctl = 0;
+
+       /* DIF write insert */
+       tc->bgctl_f.op = 0x2;
+
+       tc->app_tag_verify_mask = 0;
+
+       /* must init to 0 for hw */
+       tc->blk_guard_err = 0;
+
+       tc->reserved_E8_0 = 0;
+
+       if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2))
+               tc->ref_tag_seed_gen = scsi_get_lba(scmd) & 0xffffffff;
+       else if (type & SCSI_PROT_DIF_TYPE3)
+               tc->ref_tag_seed_gen = 0;
+}
+
+static void scu_ssp_ireq_dif_strip(struct isci_request *ireq, u8 type, u8 op)
+{
+       struct scu_task_context *tc = ireq->tc;
+       struct scsi_cmnd *scmd = ireq->ttype_ptr.io_task_ptr->uldd_task;
+       u8 blk_sz = scu_bg_blk_size(scmd->device);
+
+       tc->block_guard_enable = 1;
+       tc->blk_prot_en = 1;
+       tc->blk_sz = blk_sz;
+       /* DIF read strip */
+       tc->blk_prot_func = 0x1;
+
+       tc->transfer_length_bytes += scu_dif_bytes(tc->transfer_length_bytes,
+                                                  scmd->device->sector_size);
+
+       /* always init to 0, used by hw */
+       tc->interm_crc_val = 0;
+
+       tc->init_crc_seed = 0;
+       tc->app_tag_verify = 0;
+       tc->app_tag_gen = 0;
+
+       if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2))
+               tc->ref_tag_seed_verify = scsi_get_lba(scmd) & 0xffffffff;
+       else if (type & SCSI_PROT_DIF_TYPE3)
+               tc->ref_tag_seed_verify = 0;
+
+       /* always init to same as bg_blk_sz */
+       tc->UD_bytes_immed_val = scmd->device->sector_size;
+
+       tc->reserved_DC_0 = 0;
+
+       /* always init to 8 */
+       tc->DIF_bytes_immed_val = 8;
+
+       tc->reserved_DC_1 = 0;
+       tc->bgc_blk_sz = scmd->device->sector_size;
+       tc->reserved_E0_0 = 0;
+       tc->app_tag_gen_mask = 0;
+
+       /** setup block guard control **/
+       tc->bgctl = 0;
+
+       /* DIF read strip */
+       tc->bgctl_f.crc_verify = 1;
+       tc->bgctl_f.op = 0x1;
+       if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2)) {
+               tc->bgctl_f.ref_tag_chk = 1;
+               tc->bgctl_f.app_f_detect = 1;
+       } else if (type & SCSI_PROT_DIF_TYPE3)
+               tc->bgctl_f.app_ref_f_detect = 1;
+
+       tc->app_tag_verify_mask = 0;
+
+       /* must init to 0 for hw */
+       tc->blk_guard_err = 0;
+
+       tc->reserved_E8_0 = 0;
+       tc->ref_tag_seed_gen = 0;
+}
+
 /**
  * This method is will fill in the SCU Task Context for a SSP IO request.
  * @sci_req:
                                                      u32 len)
 {
        struct scu_task_context *task_context = ireq->tc;
+       struct sas_task *sas_task = ireq->ttype_ptr.io_task_ptr;
+       struct scsi_cmnd *scmd = sas_task->uldd_task;
+       u8 prot_type = scsi_get_prot_type(scmd);
+       u8 prot_op = scsi_get_prot_op(scmd);
 
        scu_ssp_reqeust_construct_task_context(ireq, task_context);
 
 
        if (task_context->transfer_length_bytes > 0)
                sci_request_build_sgl(ireq);
+
+       if (prot_type != SCSI_PROT_DIF_TYPE0) {
+               if (prot_op == SCSI_PROT_READ_STRIP)
+                       scu_ssp_ireq_dif_strip(ireq, prot_type, prot_op);
+               else if (prot_op == SCSI_PROT_WRITE_INSERT)
+                       scu_ssp_ireq_dif_insert(ireq, prot_type, prot_op);
+       }
 }
 
 /**
 
        struct transport_snapshot snapshot; /* read only set to 0 */
 
        /* OFFSET 0x5C */
-       u32 block_protection_enable:1;
-       u32 block_size:2;
-       u32 block_protection_function:2;
+       u32 blk_prot_en:1;
+       u32 blk_sz:2;
+       u32 blk_prot_func:2;
        u32 reserved_5C_0:9;
        u32 active_sgl_element:2;  /* read only set to 0 */
        u32 sgl_exhausted:1;  /* read only set to 0 */
        u32 reserved_C4_CC[3];
 
        /* OFFSET 0xD0 */
-       u32 intermediate_crc_value:16;
-       u32 initial_crc_seed:16;
+       u32 interm_crc_val:16;
+       u32 init_crc_seed:16;
 
        /* OFFSET 0xD4 */
-       u32 application_tag_for_verify:16;
-       u32 application_tag_for_generate:16;
+       u32 app_tag_verify:16;
+       u32 app_tag_gen:16;
 
        /* OFFSET 0xD8 */
-       u32 reference_tag_seed_for_verify_function;
+       u32 ref_tag_seed_verify;
 
        /* OFFSET 0xDC */
-       u32 reserved_DC;
+       u32 UD_bytes_immed_val:13;
+       u32 reserved_DC_0:3;
+       u32 DIF_bytes_immed_val:4;
+       u32 reserved_DC_1:12;
 
        /* OFFSET 0xE0 */
-       u32 reserved_E0_0:16;
-       u32 application_tag_mask_for_generate:16;
+       u32 bgc_blk_sz:13;
+       u32 reserved_E0_0:3;
+       u32 app_tag_gen_mask:16;
 
        /* OFFSET 0xE4 */
-       u32 block_protection_control:16;
-       u32 application_tag_mask_for_verify:16;
+       union {
+               u16 bgctl;
+               struct {
+                       u16 crc_verify:1;
+                       u16 app_tag_chk:1;
+                       u16 ref_tag_chk:1;
+                       u16 op:2;
+                       u16 legacy:1;
+                       u16 invert_crc_seed:1;
+                       u16 ref_tag_gen:1;
+                       u16 fixed_ref_tag:1;
+                       u16 invert_crc:1;
+                       u16 app_ref_f_detect:1;
+                       u16 uninit_dif_check_err:1;
+                       u16 uninit_dif_bypass:1;
+                       u16 app_f_detect:1;
+                       u16 reserved_0:2;
+               } bgctl_f;
+       };
+
+       u16 app_tag_verify_mask;
 
        /* OFFSET 0xE8 */
-       u32 block_protection_error:8;
+       u32 blk_guard_err:8;
        u32 reserved_E8_0:24;
 
        /* OFFSET 0xEC */
-       u32 reference_tag_seed_for_verify;
+       u32 ref_tag_seed_gen;
 
        /* OFFSET 0xF0 */
        u32 intermediate_crc_valid_snapshot:16;
        /* OFFSET 0xFC */
        u32 reference_tag_seed_for_generate_function_snapshot;
 
-};
+} __packed;
 
 #endif /* _SCU_TASK_CONTEXT_H_ */