- Fixed several iSCSI RFC violations in TM area, added necessary support in the...
authorvlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Tue, 28 Aug 2007 17:32:31 +0000 (17:32 +0000)
committervlnb <vlnb@d57e44dd-8a1f-0410-8b47-8ef2f437770f>
Tue, 28 Aug 2007 17:32:31 +0000 (17:32 +0000)
 - Some minor TM handling improvements
 - Some cleanups

git-svn-id: https://scst.svn.sourceforge.net/svnroot/scst/trunk@173 d57e44dd-8a1f-0410-8b47-8ef2f437770f

iscsi-scst/kernel/iscsi.c
iscsi-scst/kernel/iscsi.h
iscsi-scst/kernel/iscsi_hdr.h
scst/include/scsi_tgt.h
scst/src/scst_main.c
scst/src/scst_priv.h
scst/src/scst_targ.c

index 1abbae2..1efc5b9 100644 (file)
@@ -937,7 +937,7 @@ static void send_r2t(struct iscsi_cmnd *req)
                rsp_hdr = (struct iscsi_r2t_hdr *)&rsp->pdu.bhs;
                rsp_hdr->opcode = ISCSI_OP_R2T;
                rsp_hdr->flags = ISCSI_FLG_FINAL;
-               memcpy(rsp_hdr->lun, cmnd_hdr(req)->lun, 8);
+               rsp_hdr->lun = cmnd_hdr(req)->lun;
                rsp_hdr->itt = cmnd_hdr(req)->itt;
                rsp_hdr->r2t_sn = cpu_to_be32(req->r2t_sn++);
                rsp_hdr->buffer_offset = cpu_to_be32(offset);
@@ -1130,7 +1130,7 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
        TRACE_DBG("scsi command: %02x", req_hdr->scb[0]);
 
        scst_cmd = scst_rx_cmd(session->scst_sess,
-               (uint8_t*)req_hdr->lun, sizeof(req_hdr->lun),
+               (uint8_t*)&req_hdr->lun, sizeof(req_hdr->lun),
                req_hdr->scb, sizeof(req_hdr->scb), SCST_NON_ATOMIC);
        if (scst_cmd == NULL) {
                create_status_rsp(req, SAM_STAT_BUSY, NULL, 0);
@@ -1176,6 +1176,9 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req)
                break;
        }
 
+       /* cmd_sn is already in CPU format converted in check_cmd_sn() */
+       scst_cmd_set_tgt_sn(scst_cmd, req_hdr->cmd_sn);
+
        TRACE_DBG("START Command (tag %d, queue_type %d)",
                req_hdr->itt, scst_cmd->queue_type);
        req->scst_state = ISCSI_CMD_STATE_RX_CMD;
@@ -1411,27 +1414,57 @@ static inline int __cmnd_abort(struct iscsi_cmnd *cmnd)
        return res;
 }
 
-static int cmnd_abort(struct iscsi_session *session, u32 itt)
+static int cmnd_abort(struct iscsi_cmnd *req)
 {
+       struct iscsi_session *session = req->conn->session;
+       struct iscsi_task_mgt_hdr *req_hdr =
+               (struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
        struct iscsi_cmnd *cmnd;
        int err;
 
-       if ((cmnd = cmnd_find_hash_get(session, itt, ISCSI_RESERVED_TAG))) {
+       if ((cmnd = cmnd_find_hash_get(session, req_hdr->rtt, ISCSI_RESERVED_TAG))) {
                struct iscsi_conn *conn = cmnd->conn;
+               struct iscsi_scsi_cmd_hdr *hdr = cmnd_hdr(cmnd);
+
+               if (req_hdr->lun != hdr->lun) {
+                        PRINT_ERROR_PR("ABORT TASK: LUN mismatch: req LUN "
+                               "%Lx, cmd LUN %Lx, rtt %u", req_hdr->lun,
+                               hdr->lun, req_hdr->rtt);
+                       err = ISCSI_RESPONSE_FUNCTION_REJECTED;
+                       goto out_put;
+               }
+
+               if (before(req_hdr->cmd_sn, hdr->cmd_sn) ||
+                   (req_hdr->cmd_sn == hdr->cmd_sn)) {
+                       PRINT_ERROR_PR("ABORT TASK: SN mismatch: req SN %x, "
+                               "cmd SN %x, rtt %u", req_hdr->cmd_sn,
+                               hdr->cmd_sn, req_hdr->rtt);
+                       err = ISCSI_RESPONSE_FUNCTION_REJECTED;
+                       goto out_put;
+               }
+
                spin_lock_bh(&conn->cmd_list_lock);
                __cmnd_abort(cmnd);
                spin_unlock_bh(&conn->cmd_list_lock);
+
                cmnd_put(cmnd);
                err = 0;
        } else
                err = ISCSI_RESPONSE_UNKNOWN_TASK;
 
+out:
        return err;
+
+out_put:
+       cmnd_put(cmnd);
+       goto out;
 }
 
-static int target_abort(struct iscsi_cmnd *req, u16 *lun, int all)
+static int target_abort(struct iscsi_cmnd *req, int all)
 {
        struct iscsi_target *target = req->conn->session->target;
+       struct iscsi_task_mgt_hdr *req_hdr =
+               (struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
        struct iscsi_session *session;
        struct iscsi_conn *conn;
        struct iscsi_cmnd *cmnd;
@@ -1448,8 +1481,7 @@ again:
                                        continue;
                                if (all)
                                        again = __cmnd_abort(cmnd);
-                               else if (memcmp(lun, &cmnd_hdr(cmnd)->lun,
-                                               sizeof(cmnd_hdr(cmnd)->lun)) == 0)
+                               else if (req_hdr->lun == cmnd_hdr(cmnd)->lun)
                                        again = __cmnd_abort(cmnd);
                                if (again)
                                        goto again;
@@ -1465,6 +1497,8 @@ again:
 static void task_set_abort(struct iscsi_cmnd *req)
 {
        struct iscsi_session *session = req->conn->session;
+       struct iscsi_task_mgt_hdr *req_hdr =
+               (struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
        struct iscsi_target *target = session->target;
        struct iscsi_conn *conn;
        struct iscsi_cmnd *cmnd;
@@ -1475,9 +1509,16 @@ static void task_set_abort(struct iscsi_cmnd *req)
                spin_lock_bh(&conn->cmd_list_lock);
 again:
                list_for_each_entry(cmnd, &conn->cmd_list, cmd_list_entry) {
-                       if (cmnd != req)
-                               if (__cmnd_abort(cmnd))
-                                       goto again;
+                       struct iscsi_scsi_cmd_hdr *hdr = cmnd_hdr(cmnd);
+                       if (cmnd == req)
+                               continue;
+                       if (req_hdr->lun != hdr->lun)
+                               continue;
+                       if (before(req_hdr->cmd_sn, hdr->cmd_sn) ||
+                           req_hdr->cmd_sn == hdr->cmd_sn)
+                               continue;
+                       if (__cmnd_abort(cmnd))
+                               goto again;
                }
                spin_unlock_bh(&conn->cmd_list_lock);
        }
@@ -1504,61 +1545,91 @@ again:
 static void execute_task_management(struct iscsi_cmnd *req)
 {
        struct iscsi_conn *conn = req->conn;
-       struct iscsi_task_mgt_hdr *req_hdr = (struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
+       struct iscsi_task_mgt_hdr *req_hdr =
+               (struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
        int err = 0, function = req_hdr->function & ISCSI_FUNCTION_MASK;
+       struct scst_rx_mgmt_params params;
 
        TRACE(TRACE_MGMT, "TM cmd: req %p, itt %x, fn %d, rtt %x", req, cmnd_itt(req),
                function, req_hdr->rtt);
 
-       /* 
-        * ToDo: relevant TM functions shall affect only commands with
-        * CmdSN lower req_hdr->cmd_sn (see RFC 3720 section 10.5).
-        * 
-        * I suppose, iscsi_session_push_cmnd() should be updated to keep
-        * commands with higher CmdSN in the session->pending_list until
-        * executing TM command finished. Although, if higher CmdSN commands
-        * might be already sent to SCST for execution, it could get much more
-        * complicated and should be implemented on SCST level.
-        */
+       memset(&params, 0, sizeof(params));
+       params.atomic = SCST_NON_ATOMIC;
+       params.tgt_priv = req;
+       
+       if ((function != ISCSI_FUNCTION_ABORT_TASK) &&
+           (req_hdr->rtt != ISCSI_RESERVED_TAG)) {
+               PRINT_ERROR_PR("Invalid RTT %x (TM fn %x)", req_hdr->rtt,
+                       function);
+               err = -1;
+               goto reject;
+       }
+
+       /* cmd_sn is already in CPU format converted in check_cmd_sn() */
 
        switch (function) {
        case ISCSI_FUNCTION_ABORT_TASK:
-               err = cmnd_abort(conn->session, req_hdr->rtt);
+               err = cmnd_abort(req);
                if (err == 0) {
-                       err = scst_rx_mgmt_fn_tag(conn->session->scst_sess,
-                               SCST_ABORT_TASK, req_hdr->rtt, SCST_NON_ATOMIC,
-                               req);
+                       params.fn = SCST_ABORT_TASK;
+                       params.tag = req_hdr->rtt;
+                       params.tag_set = 1;
+                       params.lun = (uint8_t *)&req_hdr->lun;
+                       params.lun_len = sizeof(req_hdr->lun);
+                       params.lun_set = 1;
+                       params.cmd_sn = req_hdr->cmd_sn;
+                       params.cmd_sn_set = 1;
+                       err = scst_rx_mgmt_fn(conn->session->scst_sess,
+                               &params);
                }
                break;
        case ISCSI_FUNCTION_ABORT_TASK_SET:
                task_set_abort(req);
-               err = scst_rx_mgmt_fn_lun(conn->session->scst_sess,
-                       SCST_ABORT_TASK_SET, (uint8_t *)req_hdr->lun,
-                       sizeof(req_hdr->lun), SCST_NON_ATOMIC, req);
+               params.fn = SCST_ABORT_TASK_SET;
+               params.lun = (uint8_t *)&req_hdr->lun;
+               params.lun_len = sizeof(req_hdr->lun);
+               params.lun_set = 1;
+               params.cmd_sn = req_hdr->cmd_sn;
+               params.cmd_sn_set = 1;
+               err = scst_rx_mgmt_fn(conn->session->scst_sess,
+                       &params);
                break;
        case ISCSI_FUNCTION_CLEAR_TASK_SET:
                task_set_abort(req);
-               err = scst_rx_mgmt_fn_lun(conn->session->scst_sess,
-                       SCST_CLEAR_TASK_SET, (uint8_t *)req_hdr->lun,
-                       sizeof(req_hdr->lun), SCST_NON_ATOMIC, req);
+               params.fn = SCST_CLEAR_TASK_SET;
+               params.lun = (uint8_t *)&req_hdr->lun;
+               params.lun_len = sizeof(req_hdr->lun);
+               params.lun_set = 1;
+               params.cmd_sn = req_hdr->cmd_sn;
+               params.cmd_sn_set = 1;
+               err = scst_rx_mgmt_fn(conn->session->scst_sess,
+                       &params);
                break;
        case ISCSI_FUNCTION_CLEAR_ACA:
-               err = scst_rx_mgmt_fn_lun(conn->session->scst_sess,
-                       SCST_CLEAR_ACA, (uint8_t *)req_hdr->lun,
-                       sizeof(req_hdr->lun), SCST_NON_ATOMIC, req);
+               params.fn = SCST_CLEAR_ACA;
+               params.lun = (uint8_t *)&req_hdr->lun;
+               params.lun_len = sizeof(req_hdr->lun);
+               params.lun_set = 1;
+               params.cmd_sn = req_hdr->cmd_sn;
+               params.cmd_sn_set = 1;
+               err = scst_rx_mgmt_fn(conn->session->scst_sess,
+                       &params);
                break;
        case ISCSI_FUNCTION_TARGET_COLD_RESET:
        case ISCSI_FUNCTION_TARGET_WARM_RESET:
-               target_abort(req, 0, 1);
-               err = scst_rx_mgmt_fn_lun(conn->session->scst_sess,
-                       SCST_TARGET_RESET, (uint8_t *)req_hdr->lun,
-                       sizeof(req_hdr->lun), SCST_NON_ATOMIC, req);
+               target_abort(req, 1);
+               params.fn = SCST_TARGET_RESET;
+               err = scst_rx_mgmt_fn(conn->session->scst_sess,
+                       &params);
                break;
        case ISCSI_FUNCTION_LOGICAL_UNIT_RESET:
-               target_abort(req, req_hdr->lun, 0);
-               err = scst_rx_mgmt_fn_lun(conn->session->scst_sess,
-                       SCST_LUN_RESET, (uint8_t *)req_hdr->lun,
-                       sizeof(req_hdr->lun), SCST_NON_ATOMIC, req);
+               target_abort(req, 0);
+               params.fn = SCST_LUN_RESET;
+               params.lun = (uint8_t *)&req_hdr->lun;
+               params.lun_len = sizeof(req_hdr->lun);
+               params.lun_set = 1;
+               err = scst_rx_mgmt_fn(conn->session->scst_sess,
+                       &params);
                break;
        case ISCSI_FUNCTION_TASK_REASSIGN:
                iscsi_send_task_mgmt_resp(req, 
@@ -1570,6 +1641,7 @@ static void execute_task_management(struct iscsi_cmnd *req)
                break;
        }
 
+reject:
        if (err != 0) {
                iscsi_send_task_mgmt_resp(req,
                        ISCSI_RESPONSE_FUNCTION_REJECTED);
index 1bd9039..1d0f85f 100644 (file)
@@ -407,12 +407,6 @@ static inline void iscsi_cmnd_set_length(struct iscsi_pdu *pdu)
 #endif
 }
 
-#define cmnd_hdr(cmnd) ((struct iscsi_scsi_cmd_hdr *) (&((cmnd)->pdu.bhs)))
-#define cmnd_ttt(cmnd) cpu_to_be32((cmnd)->pdu.bhs.ttt)
-#define cmnd_itt(cmnd) cpu_to_be32((cmnd)->pdu.bhs.itt)
-#define cmnd_opcode(cmnd) ((cmnd)->pdu.bhs.opcode & ISCSI_OPCODE_MASK)
-#define cmnd_scsicode(cmnd) cmnd_hdr(cmnd)->scb[0]
-
 extern struct scst_tgt_template iscsi_template;
 
 static inline void cmnd_get(struct iscsi_cmnd *cmnd)
index 6d5a168..99f694d 100644 (file)
@@ -38,7 +38,7 @@ struct iscsi_hdr {
 #elif defined(__LITTLE_ENDIAN_BITFIELD)
        u32 length;                     /* 4 */
 #endif
-       u16 lun[4];                     /* 8 */
+       u64 lun;                        /* 8 */
        u32 itt;                        /* 16 */
        u32 ttt;                        /* 20 */
        u32 sn;                         /* 24 */
@@ -101,7 +101,7 @@ struct iscsi_scsi_cmd_hdr {
        u16 rsvd1;
        u8  ahslength;
        u8  datalength[3];
-       u16 lun[4];
+       u64 lun;
        u32 itt;
        u32 data_length;
        u32 cmd_sn;
@@ -170,7 +170,7 @@ struct iscsi_task_mgt_hdr {
        u16 rsvd1;
        u8  ahslength;
        u8  datalength[3];
-       u16 lun[4];
+       u64 lun;
        u32 itt;
        u32 rtt;
        u32 cmd_sn;
@@ -222,7 +222,7 @@ struct iscsi_data_out_hdr {
        u16 rsvd1;
        u8  ahslength;
        u8  datalength[3];
-       u16 lun[4];
+       u64 lun;
        u32 itt;
        u32 ttt;
        u32 rsvd2;
@@ -259,7 +259,7 @@ struct iscsi_r2t_hdr {
        u16 rsvd1;
        u8  ahslength;
        u8  datalength[3];
-       u16 lun[4];
+       u64 lun;
        u32 itt;
        u32 ttt;
        u32 stat_sn;
@@ -276,7 +276,7 @@ struct iscsi_async_msg_hdr {
        u16 rsvd1;
        u8  ahslength;
        u8  datalength[3];
-       u16 lun[4];
+       u64 lun;
        u32 ffffffff;
        u32 rsvd2;
        u32 stat_sn;
@@ -491,7 +491,7 @@ struct iscsi_nop_out_hdr {
        u16 rsvd1;
        u8  ahslength;
        u8  datalength[3];
-       u16 lun[4];
+       u64 lun;
        u32 itt;
        u32 ttt;
        u32 cmd_sn;
@@ -505,7 +505,7 @@ struct iscsi_nop_in_hdr {
        u16 rsvd1;
        u8  ahslength;
        u8  datalength[3];
-       u16 lun[4];
+       u64 lun;
        u32 itt;
        u32 ttt;
        u32 stat_sn;
@@ -516,4 +516,11 @@ struct iscsi_nop_in_hdr {
 
 #define ISCSI_RESERVED_TAG     (0xffffffffU)
 
+#define cmnd_hdr(cmnd) ((struct iscsi_scsi_cmd_hdr *) (&((cmnd)->pdu.bhs)))
+#define cmnd_ttt(cmnd) cpu_to_be32((cmnd)->pdu.bhs.ttt)
+#define cmnd_itt(cmnd) cpu_to_be32((cmnd)->pdu.bhs.itt)
+#define cmnd_opcode(cmnd) ((cmnd)->pdu.bhs.opcode & ISCSI_OPCODE_MASK)
+#define cmnd_scsicode(cmnd) cmnd_hdr(cmnd)->scb[0]
+
+
 #endif /* __ISCSI_HDR_H__ */
index 6a0dfc2..a77cf85 100644 (file)
@@ -1056,7 +1056,10 @@ struct scst_cmd
         * Set if inc expected_sn in cmd->scst_cmd_done() (to 
         * save extra dereferences)
         */
-       unsigned inc_expected_sn_on_done:1; 
+       unsigned int inc_expected_sn_on_done:1; 
+
+       /* Set if tgt_sn field is valid */
+       unsigned int tgt_sn_set:1;
 
        /**************************************************************/
 
@@ -1095,6 +1098,8 @@ struct scst_cmd
         */
        uint64_t tag;
 
+       uint32_t tgt_sn; /* SN set by target driver (for TM purposes) */
+
        /* CDB and its len */
        uint8_t cdb[SCST_MAX_CDB_SIZE];
        int cdb_len;
@@ -1167,6 +1172,20 @@ struct scst_cmd
        struct scst_cmd *orig_cmd; /* Used to issue REQUEST SENSE */
 };
 
+struct scst_rx_mgmt_params
+{
+       int fn;
+       uint64_t tag;
+       const uint8_t *lun;
+       int lun_len;
+       uint32_t cmd_sn;
+       int atomic;
+       void *tgt_priv;
+       unsigned char tag_set;
+       unsigned char lun_set;
+       unsigned char cmd_sn_set;
+};
+
 struct scst_mgmt_cmd
 {
        /* List entry for *_mgmt_cmd_list */
@@ -1181,6 +1200,10 @@ struct scst_mgmt_cmd
 
        unsigned int completed:1;       /* set, if the mcmd is completed */
        unsigned int active:1;          /* set, if the mcmd is active */
+       /* Set if device(s) should be unblocked after mcmd's finish */
+       unsigned int needs_unblocking:1;
+       unsigned int lun_set:1;         /* set, if lun field is valid */
+       unsigned int cmd_sn_set:1;      /* set, if cmd_sn field is valid */
 
        /*
         * Number of commands to complete before sending response,
@@ -1192,9 +1215,11 @@ struct scst_mgmt_cmd
        int completed_cmd_count;
 
        lun_t lun;      /* LUN for this mgmt cmd */
-       /* or */
+       /* or (and for iSCSI) */
        uint64_t tag;   /* tag of the corresponding cmd */
 
+       uint32_t cmd_sn; /* affected command's highest SN */
+
        /* corresponding cmd (to be aborted, found by tag) */
        struct scst_cmd *cmd_to_abort;
 
@@ -1590,7 +1615,7 @@ void scst_unregister_virtual_dev_driver(struct scst_dev_type *dev_type);
 
 /* 
  * Creates and sends new command to SCST.
- * Must not been called in parallel with scst_unregister_session() for the
+ * Must not be called in parallel with scst_unregister_session() for the
  * same sess. Returns the command on success or NULL otherwise
  */
 struct scst_cmd *scst_rx_cmd(struct scst_session *sess,
@@ -1661,24 +1686,62 @@ void scst_rx_data(struct scst_cmd *cmd, int status, int pref_context);
  */
 void scst_tgt_cmd_done(struct scst_cmd *cmd);
 
+/* 
+ * Creates new management command sends it for execution.
+ * Must not be called in parallel with scst_unregister_session() for the 
+ * same sess. Returns 0 for success, error code otherwise.
+ */
+int scst_rx_mgmt_fn(struct scst_session *sess,
+       const struct scst_rx_mgmt_params *params);
+
 /* 
  * Creates new management command using tag and sends it for execution.
  * Can be used for SCST_ABORT_TASK only.
- * Must not been called in parallel with scst_unregister_session() for the 
+ * Must not be called in parallel with scst_unregister_session() for the 
  * same sess. Returns 0 for success, error code otherwise.
+ *
+ * Obsolete in favor of scst_rx_mgmt_fn()
  */
-int scst_rx_mgmt_fn_tag(struct scst_session *sess, int fn, uint64_t tag,
-                      int atomic, void *tgt_priv);
+static inline int scst_rx_mgmt_fn_tag(struct scst_session *sess, int fn,
+       uint64_t tag, int atomic, void *tgt_priv)
+{
+       struct scst_rx_mgmt_params params;
+
+       BUG_ON(fn != SCST_ABORT_TASK);
+
+       memset(&params, 0, sizeof(params));
+       params.fn = fn;
+       params.tag = tag;
+       params.tag_set = 1;
+       params.atomic = atomic;
+       params.tgt_priv = tgt_priv;
+       return scst_rx_mgmt_fn(sess, &params);
+}
 
 /* 
  * Creates new management command using LUN and sends it for execution.
  * Currently can be used for any fn, except SCST_ABORT_TASK.
- * Must not been called in parallel with scst_unregister_session() for the 
+ * Must not be called in parallel with scst_unregister_session() for the 
  * same sess. Returns 0 for success, error code otherwise.
+ *
+ * Obsolete in favor of scst_rx_mgmt_fn()
  */
-int scst_rx_mgmt_fn_lun(struct scst_session *sess, int fn,
-                       const uint8_t *lun, int lun_len,
-                       int atomic, void *tgt_priv);
+static inline int scst_rx_mgmt_fn_lun(struct scst_session *sess, int fn,
+       const uint8_t *lun, int lun_len, int atomic, void *tgt_priv)
+{
+       struct scst_rx_mgmt_params params;
+
+       BUG_ON(fn == SCST_ABORT_TASK);
+
+       memset(&params, 0, sizeof(params));
+       params.fn = fn;
+       params.lun = lun;
+       params.lun_len = lun_len;
+       params.lun_set = 1;
+       params.atomic = atomic;
+       params.tgt_priv = tgt_priv;
+       return scst_rx_mgmt_fn(sess, &params);
+}
 
 /*
  * Provides various CDB info
@@ -1991,6 +2054,22 @@ static inline void scst_cmd_set_no_sgv(struct scst_cmd *cmd)
        cmd->no_sgv = 1;
 }
 
+/*
+ * Get/Set functions for tgt_sn
+ */
+static inline int scst_cmd_get_tgt_sn(struct scst_cmd *cmd)
+{
+       BUG_ON(!cmd->tgt_sn_set);
+       return cmd->tgt_sn;
+}
+
+static inline void scst_cmd_set_tgt_sn(struct scst_cmd *cmd, uint32_t tgt_sn)
+{
+       cmd->tgt_sn_set = 1;
+       cmd->tgt_sn = tgt_sn;
+}
+
+
 /*
  * Returns 1 if the cmd was aborted, so its status is invalid and no
  * reply shall be sent to the remote initiator. A target driver should
index 3168e2b..b55a9a1 100644 (file)
@@ -1633,8 +1633,7 @@ EXPORT_SYMBOL(scst_tgt_cmd_done);
 EXPORT_SYMBOL(scst_restart_cmd);
 EXPORT_SYMBOL(scst_rx_cmd);
 EXPORT_SYMBOL(scst_rx_data);
-EXPORT_SYMBOL(scst_rx_mgmt_fn_tag);
-EXPORT_SYMBOL(scst_rx_mgmt_fn_lun);
+EXPORT_SYMBOL(scst_rx_mgmt_fn);
 
 EXPORT_SYMBOL(scst_find_cmd);
 EXPORT_SYMBOL(scst_find_cmd_by_tag);
index cbc3f98..d6c2fd1 100644 (file)
@@ -558,4 +558,13 @@ void scst_check_debug_sn(struct scst_cmd *cmd);
 static inline void scst_check_debug_sn(struct scst_cmd *cmd) {}
 #endif
 
+/*
+ * It deals with comparing 32 bit unsigned ints and worry about wraparound
+ * (automatic with unsigned arithmetic). Borrowed from net/tcp.h.
+ */
+static inline int scst_sn_before(__u32 seq1, __u32 seq2)
+{
+        return (__s32)(seq1-seq2) < 0;
+}
+
 #endif /* __SCST_PRIV_H */
index da97b9f..5a17620 100644 (file)
@@ -49,7 +49,7 @@ static inline void scst_schedule_tasklet(struct scst_cmd *cmd)
 }
 
 /* 
- * Must not been called in parallel with scst_unregister_session() for the 
+ * Must not be called in parallel with scst_unregister_session() for the 
  * same sess
  */
 struct scst_cmd *scst_rx_cmd(struct scst_session *sess,
@@ -3397,8 +3397,15 @@ static void __scst_abort_task_set(struct scst_mgmt_cmd *mcmd,
                        search_cmd_list_entry) {
                if ((cmd->tgt_dev == tgt_dev) ||
                    ((cmd->tgt_dev == NULL) && 
-                    (cmd->lun == tgt_dev->lun)))
+                    (cmd->lun == tgt_dev->lun))) {
+                       if (mcmd->cmd_sn_set) {
+                               sBUG_ON(!cmd->tgt_sn_set);
+                               if (scst_sn_before(mcmd->cmd_sn, cmd->tgt_sn) ||
+                                   (mcmd->cmd_sn == cmd->tgt_sn))
+                                       continue;
+                       }
                        scst_abort_cmd(cmd, mcmd, other_ini, 0);
+               }
        }
        spin_unlock_irq(&sess->sess_list_lock);
 
@@ -3418,6 +3425,8 @@ static int scst_abort_task_set(struct scst_mgmt_cmd *mcmd)
        TRACE(TRACE_MGMT, "Aborting task set (lun=%Ld, mcmd=%p)",
                tgt_dev->lun, mcmd);
 
+       mcmd->needs_unblocking = 1;
+
        spin_lock_bh(&dev->dev_lock);
        __scst_block_dev(dev);
        spin_unlock_bh(&dev->dev_lock);
@@ -3452,7 +3461,7 @@ static int scst_check_delay_mgmt_cmd(struct scst_mgmt_cmd *mcmd)
  * >0, if it should be requeued, <0 otherwise */
 static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
 {
-       int res = 0;
+       int res = 0, rc;
 
        TRACE_ENTRY();
 
@@ -3460,7 +3469,11 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
        if (res != 0)
                goto out;
 
-       if (mcmd->fn == SCST_ABORT_TASK) {
+       mcmd->state = SCST_MGMT_CMD_STATE_READY;
+
+       switch (mcmd->fn) {
+       case SCST_ABORT_TASK:
+       {
                struct scst_session *sess = mcmd->sess;
                struct scst_cmd *cmd;
 
@@ -3479,23 +3492,43 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
                TRACE(TRACE_MGMT, "Cmd %p for tag %llu (sn %ld) found, "
                        "aborting it", cmd, mcmd->tag, cmd->sn);
                mcmd->cmd_to_abort = cmd;
-               scst_abort_cmd(cmd, mcmd, 0, 1);
-               scst_unblock_aborted_cmds(0);
+               if (mcmd->lun_set && (mcmd->lun != cmd->lun)) {
+                       PRINT_ERROR_PR("ABORT TASK: LUN mismatch: mcmd LUN %Lx, "
+                               "cmd LUN %Lx, cmd tag %Lu", mcmd->lun, cmd->lun,
+                               mcmd->tag);
+                       mcmd->status = SCST_MGMT_STATUS_REJECTED;
+               } else if (mcmd->cmd_sn_set && 
+                          (scst_sn_before(mcmd->cmd_sn, cmd->tgt_sn) ||
+                           (mcmd->cmd_sn == cmd->tgt_sn))) {
+                       PRINT_ERROR_PR("ABORT TASK: SN mismatch: mcmd SN %x, "
+                               "cmd SN %x, cmd tag %Lu", mcmd->cmd_sn,
+                               cmd->tgt_sn, mcmd->tag);
+                       mcmd->status = SCST_MGMT_STATUS_REJECTED;
+               } else {
+                       scst_abort_cmd(cmd, mcmd, 0, 1);
+                       scst_unblock_aborted_cmds(0);
+               }
                res = scst_set_mcmd_next_state(mcmd);
                mcmd->cmd_to_abort = NULL; /* just in case */
                scst_cmd_put(cmd);
-       } else {
-               int rc;
+               break;
+       }
+
+       case SCST_TARGET_RESET:
+       case SCST_ABORT_ALL_TASKS:
+       case SCST_NEXUS_LOSS:
+               break;
+
+       default:
                rc = scst_mgmt_translate_lun(mcmd);
                if (rc < 0) {
                        PRINT_ERROR_PR("Corresponding device for lun %Ld not "
                                "found", (uint64_t)mcmd->lun);
                        mcmd->status = SCST_MGMT_STATUS_LUN_NOT_EXIST;
                        mcmd->state = SCST_MGMT_CMD_STATE_DONE;
-               } else if (rc == 0)
-                       mcmd->state = SCST_MGMT_CMD_STATE_READY;
-               else
+               } else if (rc != 0)
                        res = rc;
+               break;
        }
 
 out:
@@ -3517,6 +3550,8 @@ static int scst_target_reset(struct scst_mgmt_cmd *mcmd)
        TRACE(TRACE_MGMT, "Target reset (mcmd %p, cmd count %d)",
                mcmd, atomic_read(&mcmd->sess->sess_cmd_count));
 
+       mcmd->needs_unblocking = 1;
+
        mutex_lock(&scst_mutex);
 
        list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
@@ -3603,6 +3638,8 @@ static int scst_lun_reset(struct scst_mgmt_cmd *mcmd)
 
        TRACE(TRACE_MGMT, "Resetting lun %Ld (mcmd %p)", tgt_dev->lun, mcmd);
 
+       mcmd->needs_unblocking = 1;
+
        spin_lock_bh(&dev->dev_lock);
        __scst_block_dev(dev);
        scst_process_reset(dev, mcmd->sess, NULL, mcmd);
@@ -3648,6 +3685,8 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
                        mcmd);
        }
 
+       mcmd->needs_unblocking = 1;
+
        mutex_lock(&scst_mutex);
        for(i = 0; i < TGT_DEV_HASH_SIZE; i++) {
                struct list_head *sess_tgt_dev_list_head =
@@ -3699,6 +3738,8 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd,
                        mcmd);
        }
 
+       mcmd->needs_unblocking = 1;
+
        mutex_lock(&scst_mutex);
 
        list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
@@ -3828,7 +3869,7 @@ static void scst_mgmt_cmd_send_done(struct scst_mgmt_cmd *mcmd)
                      mcmd->sess->tgt->tgtt->name);
        }
 
-       if (mcmd->mcmd_tgt_dev != NULL) {
+       if (mcmd->needs_unblocking) {
                switch (mcmd->fn) {
                case SCST_ABORT_TASK_SET:
                case SCST_CLEAR_TASK_SET:
@@ -3864,8 +3905,8 @@ static void scst_mgmt_cmd_send_done(struct scst_mgmt_cmd *mcmd)
 
                        break;
                }
-               case SCST_CLEAR_ACA:
                default:
+                       sBUG();
                        break;
                }
        }
@@ -4085,74 +4126,51 @@ out_unlock:
 }
 
 /* 
- * Must not been called in parallel with scst_unregister_session() for the 
+ * Must not be called in parallel with scst_unregister_session() for the 
  * same sess
  */
-int scst_rx_mgmt_fn_lun(struct scst_session *sess, int fn,
-                       const uint8_t *lun, int lun_len, int atomic,
-                       void *tgt_priv)
+int scst_rx_mgmt_fn(struct scst_session *sess,
+       const struct scst_rx_mgmt_params *params)
 {
        int res = -EFAULT;
        struct scst_mgmt_cmd *mcmd = NULL;
 
        TRACE_ENTRY();
 
-       if (unlikely(fn == SCST_ABORT_TASK)) {
-               PRINT_ERROR_PR("%s() for ABORT TASK called", __FUNCTION__);
-               res = -EINVAL;
-               goto out;
+       switch (params->fn) {
+       case SCST_ABORT_TASK:
+               sBUG_ON(!params->tag_set);
+               break;
+       case SCST_TARGET_RESET:
+       case SCST_ABORT_ALL_TASKS:
+       case SCST_NEXUS_LOSS:
+               break;
+       default:
+               sBUG_ON(!params->lun_set);
        }
 
-       mcmd = scst_pre_rx_mgmt_cmd(sess, fn, atomic, tgt_priv);
+       mcmd = scst_pre_rx_mgmt_cmd(sess, params->fn, params->atomic,
+               params->tgt_priv);
        if (mcmd == NULL)
                goto out;
 
-       mcmd->lun = scst_unpack_lun(lun, lun_len);
-       if (mcmd->lun == (lun_t)-1)
-               goto out_free;
-
-       TRACE(TRACE_MGMT, "sess=%p, lun=%Ld", sess, (uint64_t)mcmd->lun);
-
-       if (scst_post_rx_mgmt_cmd(sess, mcmd) != 0)
-               goto out_free;
-
-       res = 0;
-
-out:
-       TRACE_EXIT_RES(res);
-       return res;
-
-out_free:
-       scst_free_mgmt_cmd(mcmd);
-       mcmd = NULL;
-       goto out;
-}
-
-/* 
- * Must not been called in parallel with scst_unregister_session() for the 
- * same sess
- */
-int scst_rx_mgmt_fn_tag(struct scst_session *sess, int fn, uint64_t tag,
-                      int atomic, void *tgt_priv)
-{
-       int res = -EFAULT;
-       struct scst_mgmt_cmd *mcmd = NULL;
-
-       TRACE_ENTRY();
-
-       if (unlikely(fn != SCST_ABORT_TASK)) {
-               PRINT_ERROR_PR("%s(%d) called", __FUNCTION__, fn);
-               res = -EINVAL;
-               goto out;
+       if (params->lun_set) {
+               mcmd->lun = scst_unpack_lun(params->lun, params->lun_len);
+               if (mcmd->lun == (lun_t)-1)
+                       goto out_free;
+               mcmd->lun_set = 1;
        }
 
-       mcmd = scst_pre_rx_mgmt_cmd(sess, fn, atomic, tgt_priv);
-       if (mcmd == NULL)
-               goto out;
+       if (params->tag_set)
+               mcmd->tag = params->tag;
 
-       mcmd->tag = tag;
+       mcmd->cmd_sn_set = params->cmd_sn_set;
+       mcmd->cmd_sn = params->cmd_sn;
 
-       TRACE(TRACE_MGMT, "sess=%p, tag=%llu", sess, mcmd->tag);
+       TRACE(TRACE_MGMT, "sess=%p, fn %x, tag_set %d, tag %Ld, lun_set %d, "
+               "lun=%Ld, cmd_sn_set %d, cmd_sn %x", sess, params->fn,
+               params->tag_set, params->tag, params->lun_set,
+               (uint64_t)mcmd->lun, params->cmd_sn_set, params->cmd_sn);
 
        if (scst_post_rx_mgmt_cmd(sess, mcmd) != 0)
                goto out_free;
@@ -4354,7 +4372,7 @@ out_free:
 }
 
 /* 
- * Must not been called in parallel with scst_rx_cmd() or 
+ * Must not be called in parallel with scst_rx_cmd() or 
  * scst_rx_mgmt_fn_*() for the same sess
  */
 void scst_unregister_session(struct scst_session *sess, int wait,