target: pass the se_task to the CDB emulation callback
[deliverable/linux.git] / drivers / target / target_core_pr.c
index 7fd3a161f7cc61cb8b95b6aca9f6af76972ba44c..09e1e3e896c6c1259b848ba3417bfa01a15c4220 100644 (file)
@@ -25,7 +25,6 @@
  *
  ******************************************************************************/
 
-#include <linux/version.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
@@ -117,14 +116,100 @@ static int core_scsi2_reservation_check(struct se_cmd *cmd, u32 *pr_reg_type)
        return ret;
 }
 
-static int core_scsi2_reservation_release(struct se_cmd *cmd)
+static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *,
+                                       struct se_node_acl *, struct se_session *);
+static void core_scsi3_put_pr_reg(struct t10_pr_registration *);
+
+static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret)
+{
+       struct se_session *se_sess = cmd->se_sess;
+       struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
+       struct t10_pr_registration *pr_reg;
+       struct t10_reservation *pr_tmpl = &su_dev->t10_pr;
+       int crh = (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS);
+       int conflict = 0;
+
+       if (!crh)
+               return false;
+
+       pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl,
+                       se_sess);
+       if (pr_reg) {
+               /*
+                * From spc4r17 5.7.3 Exceptions to SPC-2 RESERVE and RELEASE
+                * behavior
+                *
+                * A RESERVE(6) or RESERVE(10) command shall complete with GOOD
+                * status, but no reservation shall be established and the
+                * persistent reservation shall not be changed, if the command
+                * is received from a) and b) below.
+                *
+                * A RELEASE(6) or RELEASE(10) command shall complete with GOOD
+                * status, but the persistent reservation shall not be released,
+                * if the command is received from a) and b)
+                *
+                * a) An I_T nexus that is a persistent reservation holder; or
+                * b) An I_T nexus that is registered if a registrants only or
+                *    all registrants type persistent reservation is present.
+                *
+                * In all other cases, a RESERVE(6) command, RESERVE(10) command,
+                * RELEASE(6) command, or RELEASE(10) command shall be processed
+                * as defined in SPC-2.
+                */
+               if (pr_reg->pr_res_holder) {
+                       core_scsi3_put_pr_reg(pr_reg);
+                       *ret = 0;
+                       return false;
+               }
+               if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) ||
+                   (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) ||
+                   (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
+                   (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
+                       core_scsi3_put_pr_reg(pr_reg);
+                       *ret = 0;
+                       return true;
+               }
+               core_scsi3_put_pr_reg(pr_reg);
+               conflict = 1;
+       } else {
+               /*
+                * Following spc2r20 5.5.1 Reservations overview:
+                *
+                * If a logical unit has executed a PERSISTENT RESERVE OUT
+                * command with the REGISTER or the REGISTER AND IGNORE
+                * EXISTING KEY service action and is still registered by any
+                * initiator, all RESERVE commands and all RELEASE commands
+                * regardless of initiator shall conflict and shall terminate
+                * with a RESERVATION CONFLICT status.
+                */
+               spin_lock(&pr_tmpl->registration_lock);
+               conflict = (list_empty(&pr_tmpl->registration_list)) ? 0 : 1;
+               spin_unlock(&pr_tmpl->registration_lock);
+       }
+
+       if (conflict) {
+               pr_err("Received legacy SPC-2 RESERVE/RELEASE"
+                       " while active SPC-3 registrations exist,"
+                       " returning RESERVATION_CONFLICT\n");
+               *ret = PYX_TRANSPORT_RESERVATION_CONFLICT;
+               return true;
+       }
+
+       return false;
+}
+
+int target_scsi2_reservation_release(struct se_task *task)
 {
+       struct se_cmd *cmd = task->task_se_cmd;
        struct se_device *dev = cmd->se_dev;
        struct se_session *sess = cmd->se_sess;
        struct se_portal_group *tpg = sess->se_tpg;
+       int ret;
 
        if (!sess || !tpg)
                return 0;
+       if (target_check_scsi2_reservation_conflict(cmd, &ret))
+               return ret;
 
        spin_lock(&dev->dev_reservation_lock);
        if (!dev->dev_reserved_node_acl || !sess) {
@@ -151,11 +236,13 @@ static int core_scsi2_reservation_release(struct se_cmd *cmd)
        return 0;
 }
 
-static int core_scsi2_reservation_reserve(struct se_cmd *cmd)
+int target_scsi2_reservation_reserve(struct se_task *task)
 {
+       struct se_cmd *cmd = task->task_se_cmd;
        struct se_device *dev = cmd->se_dev;
        struct se_session *sess = cmd->se_sess;
        struct se_portal_group *tpg = sess->se_tpg;
+       int ret;
 
        if ((cmd->t_task_cdb[1] & 0x01) &&
            (cmd->t_task_cdb[1] & 0x02)) {
@@ -169,6 +256,8 @@ static int core_scsi2_reservation_reserve(struct se_cmd *cmd)
         */
        if (!sess || !tpg)
                return 0;
+       if (target_check_scsi2_reservation_conflict(cmd, &ret))
+               return ret;
 
        spin_lock(&dev->dev_reservation_lock);
        if (dev->dev_reserved_node_acl &&
@@ -201,99 +290,6 @@ static int core_scsi2_reservation_reserve(struct se_cmd *cmd)
        return 0;
 }
 
-static struct t10_pr_registration *core_scsi3_locate_pr_reg(struct se_device *,
-                                       struct se_node_acl *, struct se_session *);
-static void core_scsi3_put_pr_reg(struct t10_pr_registration *);
-
-/*
- * Setup in target_core_transport.c:transport_generic_cmd_sequencer()
- * and called via struct se_cmd->transport_emulate_cdb() in TCM processing
- * thread context.
- */
-int core_scsi2_emulate_crh(struct se_cmd *cmd)
-{
-       struct se_session *se_sess = cmd->se_sess;
-       struct se_subsystem_dev *su_dev = cmd->se_dev->se_sub_dev;
-       struct t10_pr_registration *pr_reg;
-       struct t10_reservation *pr_tmpl = &su_dev->t10_pr;
-       unsigned char *cdb = &cmd->t_task_cdb[0];
-       int crh = (su_dev->t10_pr.res_type == SPC3_PERSISTENT_RESERVATIONS);
-       int conflict = 0;
-
-       if (!se_sess)
-               return 0;
-
-       if (!crh)
-               goto after_crh;
-
-       pr_reg = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl,
-                       se_sess);
-       if (pr_reg) {
-               /*
-                * From spc4r17 5.7.3 Exceptions to SPC-2 RESERVE and RELEASE
-                * behavior
-                *
-                * A RESERVE(6) or RESERVE(10) command shall complete with GOOD
-                * status, but no reservation shall be established and the
-                * persistent reservation shall not be changed, if the command
-                * is received from a) and b) below.
-                *
-                * A RELEASE(6) or RELEASE(10) command shall complete with GOOD
-                * status, but the persistent reservation shall not be released,
-                * if the command is received from a) and b)
-                *
-                * a) An I_T nexus that is a persistent reservation holder; or
-                * b) An I_T nexus that is registered if a registrants only or
-                *    all registrants type persistent reservation is present.
-                *
-                * In all other cases, a RESERVE(6) command, RESERVE(10) command,
-                * RELEASE(6) command, or RELEASE(10) command shall be processed
-                * as defined in SPC-2.
-                */
-               if (pr_reg->pr_res_holder) {
-                       core_scsi3_put_pr_reg(pr_reg);
-                       return 0;
-               }
-               if ((pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY) ||
-                   (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY) ||
-                   (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) ||
-                   (pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) {
-                       core_scsi3_put_pr_reg(pr_reg);
-                       return 0;
-               }
-               core_scsi3_put_pr_reg(pr_reg);
-               conflict = 1;
-       } else {
-               /*
-                * Following spc2r20 5.5.1 Reservations overview:
-                *
-                * If a logical unit has executed a PERSISTENT RESERVE OUT
-                * command with the REGISTER or the REGISTER AND IGNORE
-                * EXISTING KEY service action and is still registered by any
-                * initiator, all RESERVE commands and all RELEASE commands
-                * regardless of initiator shall conflict and shall terminate
-                * with a RESERVATION CONFLICT status.
-                */
-               spin_lock(&pr_tmpl->registration_lock);
-               conflict = (list_empty(&pr_tmpl->registration_list)) ? 0 : 1;
-               spin_unlock(&pr_tmpl->registration_lock);
-       }
-
-       if (conflict) {
-               pr_err("Received legacy SPC-2 RESERVE/RELEASE"
-                       " while active SPC-3 registrations exist,"
-                       " returning RESERVATION_CONFLICT\n");
-               return PYX_TRANSPORT_RESERVATION_CONFLICT;
-       }
-
-after_crh:
-       if ((cdb[0] == RESERVE) || (cdb[0] == RESERVE_10))
-               return core_scsi2_reservation_reserve(cmd);
-       else if ((cdb[0] == RELEASE) || (cdb[0] == RELEASE_10))
-               return core_scsi2_reservation_release(cmd);
-       else
-               return PYX_TRANSPORT_INVALID_CDB_FIELD;
-}
 
 /*
  * Begin SPC-3/SPC-4 Persistent Reservations emulation support
@@ -419,12 +415,12 @@ static int core_scsi3_pr_seq_non_holder(
                break;
        case RELEASE:
        case RELEASE_10:
-               /* Handled by CRH=1 in core_scsi2_emulate_crh() */
+               /* Handled by CRH=1 in target_scsi2_reservation_release() */
                ret = 0;
                break;
        case RESERVE:
        case RESERVE_10:
-               /* Handled by CRH=1 in core_scsi2_emulate_crh() */
+               /* Handled by CRH=1 in target_scsi2_reservation_reserve() */
                ret = 0;
                break;
        case TEST_UNIT_READY:
@@ -3740,12 +3736,31 @@ static unsigned long long core_scsi3_extract_reservation_key(unsigned char *cdb)
 /*
  * See spc4r17 section 6.14 Table 170
  */
-static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb)
+int target_scsi3_emulate_pr_out(struct se_task *task)
 {
+       struct se_cmd *cmd = task->task_se_cmd;
+       unsigned char *cdb = &cmd->t_task_cdb[0];
        unsigned char *buf;
        u64 res_key, sa_res_key;
        int sa, scope, type, aptpl;
        int spec_i_pt = 0, all_tg_pt = 0, unreg = 0;
+
+       /*
+        * Following spc2r20 5.5.1 Reservations overview:
+        *
+        * If a logical unit has been reserved by any RESERVE command and is
+        * still reserved by any initiator, all PERSISTENT RESERVE IN and all
+        * PERSISTENT RESERVE OUT commands shall conflict regardless of
+        * initiator or service action and shall terminate with a RESERVATION
+        * CONFLICT status.
+        */
+       if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) {
+               pr_err("Received PERSISTENT_RESERVE CDB while legacy"
+                       " SPC-2 reservation is held, returning"
+                       " RESERVATION_CONFLICT\n");
+               return PYX_TRANSPORT_RESERVATION_CONFLICT;
+       }
+
        /*
         * FIXME: A NULL struct se_session pointer means an this is not coming from
         * a $FABRIC_MOD's nexus, but from internal passthrough ops.
@@ -4191,29 +4206,10 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd)
        return 0;
 }
 
-static int core_scsi3_emulate_pr_in(struct se_cmd *cmd, unsigned char *cdb)
+int target_scsi3_emulate_pr_in(struct se_task *task)
 {
-       switch (cdb[1] & 0x1f) {
-       case PRI_READ_KEYS:
-               return core_scsi3_pri_read_keys(cmd);
-       case PRI_READ_RESERVATION:
-               return core_scsi3_pri_read_reservation(cmd);
-       case PRI_REPORT_CAPABILITIES:
-               return core_scsi3_pri_report_capabilities(cmd);
-       case PRI_READ_FULL_STATUS:
-               return core_scsi3_pri_read_full_status(cmd);
-       default:
-               pr_err("Unknown PERSISTENT_RESERVE_IN service"
-                       " action: 0x%02x\n", cdb[1] & 0x1f);
-               return PYX_TRANSPORT_INVALID_CDB_FIELD;
-       }
-
-}
+       struct se_cmd *cmd = task->task_se_cmd;
 
-int core_scsi3_emulate_pr(struct se_cmd *cmd)
-{
-       unsigned char *cdb = &cmd->t_task_cdb[0];
-       struct se_device *dev = cmd->se_dev;
        /*
         * Following spc2r20 5.5.1 Reservations overview:
         *
@@ -4223,16 +4219,27 @@ int core_scsi3_emulate_pr(struct se_cmd *cmd)
         * initiator or service action and shall terminate with a RESERVATION
         * CONFLICT status.
         */
-       if (dev->dev_flags & DF_SPC2_RESERVATIONS) {
+       if (cmd->se_dev->dev_flags & DF_SPC2_RESERVATIONS) {
                pr_err("Received PERSISTENT_RESERVE CDB while legacy"
                        " SPC-2 reservation is held, returning"
                        " RESERVATION_CONFLICT\n");
                return PYX_TRANSPORT_RESERVATION_CONFLICT;
        }
 
-       return (cdb[0] == PERSISTENT_RESERVE_OUT) ?
-              core_scsi3_emulate_pr_out(cmd, cdb) :
-              core_scsi3_emulate_pr_in(cmd, cdb);
+       switch (cmd->t_task_cdb[1] & 0x1f) {
+       case PRI_READ_KEYS:
+               return core_scsi3_pri_read_keys(cmd);
+       case PRI_READ_RESERVATION:
+               return core_scsi3_pri_read_reservation(cmd);
+       case PRI_REPORT_CAPABILITIES:
+               return core_scsi3_pri_report_capabilities(cmd);
+       case PRI_READ_FULL_STATUS:
+               return core_scsi3_pri_read_full_status(cmd);
+       default:
+               pr_err("Unknown PERSISTENT_RESERVE_IN service"
+                       " action: 0x%02x\n", cmd->t_task_cdb[1] & 0x1f);
+               return PYX_TRANSPORT_INVALID_CDB_FIELD;
+       }
 }
 
 static int core_pt_reservation_check(struct se_cmd *cmd, u32 *pr_res_type)
This page took 0.039981 seconds and 5 git commands to generate.