mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-17 02:31:27 +00:00
- 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:
@@ -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(¶ms, 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,
|
||||
¶ms);
|
||||
}
|
||||
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,
|
||||
¶ms);
|
||||
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,
|
||||
¶ms);
|
||||
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,
|
||||
¶ms);
|
||||
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,
|
||||
¶ms);
|
||||
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,
|
||||
¶ms);
|
||||
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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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(¶ms, 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, ¶ms);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(¶ms, 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, ¶ms);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user