- Fixed several iSCSI RFC violations in TM area, added necessary support in the SCST core

- Some minor TM handling improvements
 - Some cleanups


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@173 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2007-08-28 17:32:31 +00:00
parent fd6744d33e
commit ef588acdf3
7 changed files with 313 additions and 135 deletions

View 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);

View 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)

View 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__ */

View 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,
@@ -1662,23 +1687,61 @@ 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 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
* 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_tag(struct scst_session *sess, int fn, uint64_t tag,
int atomic, void *tgt_priv);
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 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()
*/
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

View 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);

View 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 */

View 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,