x86/smpboot: Init apic mapping before usage
[cascardo/linux.git] / drivers / target / target_core_transport.c
index 5ab3967..7dfefd6 100644 (file)
@@ -1303,23 +1303,6 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
 
        trace_target_sequencer_start(cmd);
 
-       /*
-        * Check for an existing UNIT ATTENTION condition
-        */
-       ret = target_scsi3_ua_check(cmd);
-       if (ret)
-               return ret;
-
-       ret = target_alua_state_check(cmd);
-       if (ret)
-               return ret;
-
-       ret = target_check_reservation(cmd);
-       if (ret) {
-               cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
-               return ret;
-       }
-
        ret = dev->transport->parse_cdb(cmd);
        if (ret == TCM_UNSUPPORTED_SCSI_OPCODE)
                pr_warn_ratelimited("%s/%s: Unsupported SCSI Opcode 0x%02x, sending CHECK_CONDITION.\n",
@@ -1709,6 +1692,7 @@ void transport_generic_request_failure(struct se_cmd *cmd,
        case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED:
        case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
        case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
+       case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE:
                break;
        case TCM_OUT_OF_RESOURCES:
                sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
@@ -1761,20 +1745,45 @@ queue_full:
 }
 EXPORT_SYMBOL(transport_generic_request_failure);
 
-void __target_execute_cmd(struct se_cmd *cmd)
+void __target_execute_cmd(struct se_cmd *cmd, bool do_checks)
 {
        sense_reason_t ret;
 
-       if (cmd->execute_cmd) {
-               ret = cmd->execute_cmd(cmd);
-               if (ret) {
-                       spin_lock_irq(&cmd->t_state_lock);
-                       cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT);
-                       spin_unlock_irq(&cmd->t_state_lock);
+       if (!cmd->execute_cmd) {
+               ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+               goto err;
+       }
+       if (do_checks) {
+               /*
+                * Check for an existing UNIT ATTENTION condition after
+                * target_handle_task_attr() has done SAM task attr
+                * checking, and possibly have already defered execution
+                * out to target_restart_delayed_cmds() context.
+                */
+               ret = target_scsi3_ua_check(cmd);
+               if (ret)
+                       goto err;
 
-                       transport_generic_request_failure(cmd, ret);
+               ret = target_alua_state_check(cmd);
+               if (ret)
+                       goto err;
+
+               ret = target_check_reservation(cmd);
+               if (ret) {
+                       cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
+                       goto err;
                }
        }
+
+       ret = cmd->execute_cmd(cmd);
+       if (!ret)
+               return;
+err:
+       spin_lock_irq(&cmd->t_state_lock);
+       cmd->transport_state &= ~(CMD_T_BUSY|CMD_T_SENT);
+       spin_unlock_irq(&cmd->t_state_lock);
+
+       transport_generic_request_failure(cmd, ret);
 }
 
 static int target_write_prot_action(struct se_cmd *cmd)
@@ -1819,6 +1828,8 @@ static bool target_handle_task_attr(struct se_cmd *cmd)
        if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return false;
 
+       cmd->se_cmd_flags |= SCF_TASK_ATTR_SET;
+
        /*
         * Check for the existence of HEAD_OF_QUEUE, and if true return 1
         * to allow the passed struct se_cmd list of tasks to the front of the list.
@@ -1899,7 +1910,7 @@ void target_execute_cmd(struct se_cmd *cmd)
                return;
        }
 
-       __target_execute_cmd(cmd);
+       __target_execute_cmd(cmd, true);
 }
 EXPORT_SYMBOL(target_execute_cmd);
 
@@ -1923,7 +1934,7 @@ static void target_restart_delayed_cmds(struct se_device *dev)
                list_del(&cmd->se_delayed_node);
                spin_unlock(&dev->delayed_cmd_lock);
 
-               __target_execute_cmd(cmd);
+               __target_execute_cmd(cmd, true);
 
                if (cmd->sam_task_attr == TCM_ORDERED_TAG)
                        break;
@@ -1941,6 +1952,9 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
        if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
                return;
 
+       if (!(cmd->se_cmd_flags & SCF_TASK_ATTR_SET))
+               goto restart;
+
        if (cmd->sam_task_attr == TCM_SIMPLE_TAG) {
                atomic_dec_mb(&dev->simple_cmds);
                dev->dev_cur_ordered_id++;
@@ -1957,7 +1971,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd)
                pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED\n",
                         dev->dev_cur_ordered_id);
        }
-
+restart:
        target_restart_delayed_cmds(dev);
 }
 
@@ -2520,8 +2534,12 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref)
         * fabric acknowledgement that requires two target_put_sess_cmd()
         * invocations before se_cmd descriptor release.
         */
-       if (ack_kref)
-               kref_get(&se_cmd->cmd_kref);
+       if (ack_kref) {
+               if (!kref_get_unless_zero(&se_cmd->cmd_kref))
+                       return -EINVAL;
+
+               se_cmd->se_cmd_flags |= SCF_ACK_KREF;
+       }
 
        spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
        if (se_sess->sess_tearing_down) {
@@ -2557,15 +2575,10 @@ static void target_release_cmd_kref(struct kref *kref)
        bool fabric_stop;
 
        spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
-       if (list_empty(&se_cmd->se_cmd_list)) {
-               spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
-               target_free_cmd_mem(se_cmd);
-               se_cmd->se_tfo->release_cmd(se_cmd);
-               return;
-       }
 
        spin_lock(&se_cmd->t_state_lock);
-       fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP);
+       fabric_stop = (se_cmd->transport_state & CMD_T_FABRIC_STOP) &&
+                     (se_cmd->transport_state & CMD_T_ABORTED);
        spin_unlock(&se_cmd->t_state_lock);
 
        if (se_cmd->cmd_wait_set || fabric_stop) {
@@ -2605,7 +2618,7 @@ EXPORT_SYMBOL(target_put_sess_cmd);
  */
 void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
 {
-       struct se_cmd *se_cmd;
+       struct se_cmd *se_cmd, *tmp_cmd;
        unsigned long flags;
        int rc;
 
@@ -2617,14 +2630,16 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
        se_sess->sess_tearing_down = 1;
        list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list);
 
-       list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list) {
+       list_for_each_entry_safe(se_cmd, tmp_cmd,
+                                &se_sess->sess_wait_list, se_cmd_list) {
                rc = kref_get_unless_zero(&se_cmd->cmd_kref);
                if (rc) {
                        se_cmd->cmd_wait_set = 1;
                        spin_lock(&se_cmd->t_state_lock);
                        se_cmd->transport_state |= CMD_T_FABRIC_STOP;
                        spin_unlock(&se_cmd->t_state_lock);
-               }
+               } else
+                       list_del_init(&se_cmd->se_cmd_list);
        }
 
        spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
@@ -2849,6 +2864,12 @@ static const struct sense_info sense_info_table[] = {
                .ascq = 0x03, /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */
                .add_sector_info = true,
        },
+       [TCM_COPY_TARGET_DEVICE_NOT_REACHABLE] = {
+               .key = COPY_ABORTED,
+               .asc = 0x0d,
+               .ascq = 0x02, /* COPY TARGET DEVICE NOT REACHABLE */
+
+       },
        [TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE] = {
                /*
                 * Returning ILLEGAL REQUEST would cause immediate IO errors on