Merge branch 'for-linville' of git://github.com/kvalo/ath
[firefly-linux-kernel-4.4.55.git] / drivers / target / target_core_transport.c
index 51a375453d9b89b204990b714733f92b74bad4c4..d4b98690a73680244676b6e608ede6c85ff724cb 100644 (file)
@@ -235,7 +235,7 @@ void transport_subsystem_check_init(void)
        sub_api_initialized = 1;
 }
 
-struct se_session *transport_init_session(void)
+struct se_session *transport_init_session(enum target_prot_op sup_prot_ops)
 {
        struct se_session *se_sess;
 
@@ -251,6 +251,7 @@ struct se_session *transport_init_session(void)
        INIT_LIST_HEAD(&se_sess->sess_wait_list);
        spin_lock_init(&se_sess->sess_cmd_lock);
        kref_init(&se_sess->sess_kref);
+       se_sess->sup_prot_ops = sup_prot_ops;
 
        return se_sess;
 }
@@ -288,12 +289,13 @@ int transport_alloc_session_tags(struct se_session *se_sess,
 EXPORT_SYMBOL(transport_alloc_session_tags);
 
 struct se_session *transport_init_session_tags(unsigned int tag_num,
-                                              unsigned int tag_size)
+                                              unsigned int tag_size,
+                                              enum target_prot_op sup_prot_ops)
 {
        struct se_session *se_sess;
        int rc;
 
-       se_sess = transport_init_session();
+       se_sess = transport_init_session(sup_prot_ops);
        if (IS_ERR(se_sess))
                return se_sess;
 
@@ -605,6 +607,12 @@ void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
 {
        if (cmd->se_cmd_flags & SCF_SE_LUN_CMD)
                transport_lun_remove_cmd(cmd);
+       /*
+        * Allow the fabric driver to unmap any resources before
+        * releasing the descriptor via TFO->release_cmd()
+        */
+       if (remove)
+               cmd->se_tfo->aborted_task(cmd);
 
        if (transport_cmd_check_stop_to_fabric(cmd))
                return;
@@ -1759,6 +1767,15 @@ void target_execute_cmd(struct se_cmd *cmd)
        cmd->t_state = TRANSPORT_PROCESSING;
        cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
        spin_unlock_irq(&cmd->t_state_lock);
+       /*
+        * Perform WRITE_INSERT of PI using software emulation when backend
+        * device has PI enabled, if the transport has not already generated
+        * PI using hardware WRITE_INSERT offload.
+        */
+       if (cmd->prot_op == TARGET_PROT_DOUT_INSERT) {
+               if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DOUT_INSERT))
+                       sbc_dif_generate(cmd);
+       }
 
        if (target_handle_task_attr(cmd)) {
                spin_lock_irq(&cmd->t_state_lock);
@@ -1888,6 +1905,21 @@ static void transport_handle_queue_full(
        schedule_work(&cmd->se_dev->qf_work_queue);
 }
 
+static bool target_check_read_strip(struct se_cmd *cmd)
+{
+       sense_reason_t rc;
+
+       if (!(cmd->se_sess->sup_prot_ops & TARGET_PROT_DIN_STRIP)) {
+               rc = sbc_dif_read_strip(cmd);
+               if (rc) {
+                       cmd->pi_err = rc;
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 static void target_complete_ok_work(struct work_struct *work)
 {
        struct se_cmd *cmd = container_of(work, struct se_cmd, work);
@@ -1952,6 +1984,22 @@ static void target_complete_ok_work(struct work_struct *work)
                                        cmd->data_length;
                }
                spin_unlock(&cmd->se_lun->lun_sep_lock);
+               /*
+                * Perform READ_STRIP of PI using software emulation when
+                * backend had PI enabled, if the transport will not be
+                * performing hardware READ_STRIP offload.
+                */
+               if (cmd->prot_op == TARGET_PROT_DIN_STRIP &&
+                   target_check_read_strip(cmd)) {
+                       ret = transport_send_check_condition_and_sense(cmd,
+                                               cmd->pi_err, 0);
+                       if (ret == -EAGAIN || ret == -ENOMEM)
+                               goto queue_full;
+
+                       transport_lun_remove_cmd(cmd);
+                       transport_cmd_check_stop_to_fabric(cmd);
+                       return;
+               }
 
                trace_target_cmd_complete(cmd);
                ret = cmd->se_tfo->queue_data_in(cmd);