mirror of
https://github.com/SCST-project/scst.git
synced 2026-05-14 09:11:27 +00:00
Processing of QErr and TMF_ONLY added
git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5481 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -225,6 +225,8 @@ static inline bool list_entry_in_list(const struct list_head *entry)
|
||||
** !! as well!
|
||||
*************************************************************/
|
||||
enum {
|
||||
/** Active states **/
|
||||
|
||||
/* Dev handler's parse() is going to be called */
|
||||
SCST_CMD_STATE_PARSE = 0,
|
||||
|
||||
@@ -258,6 +260,12 @@ enum {
|
||||
/* Checks before target driver's xmit_response() is called */
|
||||
SCST_CMD_STATE_PRE_XMIT_RESP,
|
||||
|
||||
/* Checks 1 before target driver's xmit_response() is called */
|
||||
SCST_CMD_STATE_PRE_XMIT_RESP1,
|
||||
|
||||
/* Checks 2 before target driver's xmit_response() is called */
|
||||
SCST_CMD_STATE_PRE_XMIT_RESP2,
|
||||
|
||||
/* Target driver's xmit_response() is going to be called */
|
||||
SCST_CMD_STATE_XMIT_RESP,
|
||||
|
||||
@@ -269,6 +277,8 @@ enum {
|
||||
|
||||
SCST_CMD_STATE_LAST_ACTIVE = (SCST_CMD_STATE_FINISHED_INTERNAL+100),
|
||||
|
||||
/** Passive states **/
|
||||
|
||||
/* A cmd is created, but scst_cmd_init_done() not called */
|
||||
SCST_CMD_STATE_INIT_WAIT,
|
||||
|
||||
@@ -568,7 +578,11 @@ enum scst_exec_context {
|
||||
/* Set if the cmd is aborted by other initiator */
|
||||
#define SCST_CMD_ABORTED_OTHER 1
|
||||
|
||||
/* Set if no response should be sent to the target about this cmd */
|
||||
/*
|
||||
* Set if no response should be sent to the target about this cmd.
|
||||
* Must be set together with SCST_CMD_ABORTED for better processing
|
||||
* in scst_pre_xmit_response2().
|
||||
*/
|
||||
#define SCST_CMD_NO_RESP 2
|
||||
|
||||
/* Set if the cmd is dead and can be destroyed at any time */
|
||||
@@ -2403,13 +2417,17 @@ struct scst_device {
|
||||
/**************************************************************/
|
||||
|
||||
/*************************************************************
|
||||
** Dev's control mode page related values. Updates serialized
|
||||
** by scst_block_dev(). Modified independently to the above
|
||||
** fields, hence the alignment.
|
||||
*************************************************************/
|
||||
** Dev's control mode page related values. Updates serialized
|
||||
** by device blocking. Since device blocking protects only
|
||||
** commands on the execution stage, in all other read cases
|
||||
** use ACCESS_ONCE(), if necessary. Modified independently
|
||||
** to the above fields, hence the alignment.
|
||||
*************************************************************/
|
||||
|
||||
unsigned int queue_alg:4 __aligned(sizeof(long));
|
||||
unsigned int tst:3;
|
||||
unsigned int qerr:2;
|
||||
unsigned int tmf_only:1;
|
||||
unsigned int tas:1;
|
||||
unsigned int swp:1;
|
||||
unsigned int d_sense:1;
|
||||
@@ -2426,6 +2444,12 @@ struct scst_device {
|
||||
unsigned int queue_alg_saved:4;
|
||||
unsigned int queue_alg_default:4;
|
||||
|
||||
unsigned int tmf_only_saved:1;
|
||||
unsigned int tmf_only_default:1;
|
||||
|
||||
unsigned int qerr_saved:2;
|
||||
unsigned int qerr_default:2;
|
||||
|
||||
unsigned int tas_saved:1;
|
||||
unsigned int tas_default:1;
|
||||
|
||||
@@ -2906,7 +2930,6 @@ struct scst_tg_tgt {
|
||||
uint16_t rel_tgt_id;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Used to store per-session UNIT ATTENTIONs
|
||||
*/
|
||||
|
||||
@@ -495,8 +495,8 @@ enum {
|
||||
/*************************************************************
|
||||
** Values for the control mode page TST field
|
||||
*************************************************************/
|
||||
#define SCST_TST_0_SINGLE_TASK_SET 0
|
||||
#define SCST_TST_1_SEP_TASK_SETS 1
|
||||
#define SCST_TST_0_SINGLE_TASK_SET 0
|
||||
#define SCST_TST_1_SEP_TASK_SETS 1
|
||||
|
||||
/*******************************************************************
|
||||
** Values for the control mode page QUEUE ALGORITHM MODIFIER field
|
||||
@@ -508,7 +508,15 @@ enum {
|
||||
** Values for the control mode page D_SENSE field
|
||||
*************************************************************/
|
||||
#define SCST_D_SENSE_0_FIXED_SENSE 0
|
||||
#define SCST_D_SENSE_1_DESCR_SENSE 1
|
||||
#define SCST_D_SENSE_1_DESCR_SENSE 1
|
||||
|
||||
/*************************************************************
|
||||
** Values for the control mode page QErr field
|
||||
*************************************************************/
|
||||
#define SCST_QERR_0_ALL_RESUME 0
|
||||
#define SCST_QERR_1_ABORT_ALL 1
|
||||
#define SCST_QERR_2_RESERVED 2
|
||||
#define SCST_QERR_3_ABORT_THIS_NEXUS_ONLY 3
|
||||
|
||||
/*************************************************************
|
||||
** TransportID protocol identifiers
|
||||
|
||||
@@ -88,7 +88,9 @@ struct scst_user_opt {
|
||||
|
||||
/* SCSI control mode page parameters, see SPC */
|
||||
uint8_t tst;
|
||||
uint8_t tmf_only;
|
||||
uint8_t queue_alg;
|
||||
uint8_t qerr;
|
||||
uint8_t tas;
|
||||
uint8_t swp;
|
||||
uint8_t d_sense;
|
||||
|
||||
@@ -62,7 +62,9 @@ struct scst_user_dev {
|
||||
unsigned int blocking:1;
|
||||
unsigned int cleanup_done:1;
|
||||
unsigned int tst:3;
|
||||
unsigned int tmf_only:1;
|
||||
unsigned int queue_alg:4;
|
||||
unsigned int qerr:2;
|
||||
unsigned int tas:1;
|
||||
unsigned int swp:1;
|
||||
unsigned int d_sense:1;
|
||||
@@ -2618,7 +2620,13 @@ static int dev_user_attach(struct scst_device *sdev)
|
||||
|
||||
sdev->dh_priv = dev;
|
||||
sdev->tst = dev->tst;
|
||||
sdev->tmf_only = dev->tmf_only;
|
||||
sdev->tmf_only_saved = dev->tmf_only;
|
||||
sdev->tmf_only_default = dev->tmf_only;
|
||||
sdev->queue_alg = dev->queue_alg;
|
||||
sdev->qerr = dev->qerr;
|
||||
sdev->qerr_saved = dev->qerr;
|
||||
sdev->qerr_default = dev->qerr;
|
||||
sdev->swp = dev->swp;
|
||||
sdev->swp_saved = dev->swp;
|
||||
sdev->swp_default = dev->swp;
|
||||
@@ -3370,6 +3378,22 @@ static int __dev_user_set_opt(struct scst_user_dev *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (((opt->tst != SCST_TST_0_SINGLE_TASK_SET) &&
|
||||
(opt->tst != SCST_TST_1_SEP_TASK_SETS)) ||
|
||||
(opt->tmf_only > 1) ||
|
||||
((opt->queue_alg != SCST_QUEUE_ALG_0_RESTRICTED_REORDER) &&
|
||||
(opt->queue_alg != SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER)) ||
|
||||
((opt->qerr == SCST_QERR_2_RESERVED) ||
|
||||
(opt->qerr > SCST_QERR_3_ABORT_THIS_NEXUS_ONLY)) ||
|
||||
(opt->swp > 1) || (opt->tas > 1) || (opt->has_own_order_mgmt > 1) ||
|
||||
(opt->d_sense > 1)) {
|
||||
PRINT_ERROR("Invalid SCSI option (tst %x, tmf_only %x, "
|
||||
"queue_alg %x, qerr %x, swp %x, tas %x, d_sense %d, "
|
||||
"has_own_order_mgmt %x)",
|
||||
opt->tst, opt->tmf_only, opt->queue_alg, opt->qerr,
|
||||
opt->swp, opt->tas, opt->d_sense, opt->has_own_order_mgmt);
|
||||
}
|
||||
|
||||
#if 1
|
||||
if ((dev->tst != opt->tst) && (dev->sdev != NULL) &&
|
||||
!list_empty(&dev->sdev->dev_tgt_dev_list)) {
|
||||
@@ -3387,14 +3411,18 @@ static int __dev_user_set_opt(struct scst_user_dev *dev,
|
||||
dev->partial_len = opt->partial_len;
|
||||
|
||||
dev->tst = opt->tst;
|
||||
dev->tmf_only = opt->tmf_only;
|
||||
dev->queue_alg = opt->queue_alg;
|
||||
dev->qerr = opt->qerr;
|
||||
dev->swp = opt->swp;
|
||||
dev->tas = opt->tas;
|
||||
dev->d_sense = opt->d_sense;
|
||||
dev->has_own_order_mgmt = opt->has_own_order_mgmt;
|
||||
if (dev->sdev != NULL) {
|
||||
dev->sdev->tst = opt->tst;
|
||||
dev->sdev->tmf_only = opt->tmf_only;
|
||||
dev->sdev->queue_alg = opt->queue_alg;
|
||||
dev->sdev->qerr = opt->qerr;
|
||||
dev->sdev->swp = opt->swp;
|
||||
dev->sdev->tas = opt->tas;
|
||||
dev->sdev->d_sense = opt->d_sense;
|
||||
@@ -3465,7 +3493,9 @@ static int dev_user_get_opt(struct file *file, void __user *arg)
|
||||
opt.partial_transfers_type = dev->partial_transfers_type;
|
||||
opt.partial_len = dev->partial_len;
|
||||
opt.tst = dev->tst;
|
||||
opt.tmf_only = dev->tmf_only;
|
||||
opt.queue_alg = dev->queue_alg;
|
||||
opt.qerr = dev->qerr;
|
||||
opt.tas = dev->tas;
|
||||
opt.swp = dev->swp;
|
||||
opt.d_sense = dev->d_sense;
|
||||
|
||||
@@ -116,6 +116,7 @@ static struct scst_trace_log vdisk_local_trace_tbl[] = {
|
||||
#define VDISK_NULLIO_SIZE (5LL*1024*1024*1024*1024/2)
|
||||
|
||||
#define DEF_TST SCST_TST_1_SEP_TASK_SETS
|
||||
#define DEF_TMF_ONLY 0
|
||||
|
||||
/*
|
||||
* Since we can't control backstorage device's reordering, we have to always
|
||||
@@ -123,9 +124,10 @@ static struct scst_trace_log vdisk_local_trace_tbl[] = {
|
||||
*/
|
||||
#define DEF_QUEUE_ALG_WT SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER
|
||||
#define DEF_QUEUE_ALG SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER
|
||||
|
||||
#define DEF_QERR SCST_QERR_0_ALL_RESUME
|
||||
#define DEF_SWP 0
|
||||
#define DEF_TAS 0
|
||||
|
||||
#define DEF_DSENSE SCST_D_SENSE_0_FIXED_SENSE
|
||||
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
@@ -1294,6 +1296,9 @@ static int vdisk_attach(struct scst_device *dev)
|
||||
dev->dh_priv = virt_dev;
|
||||
|
||||
dev->tst = virt_dev->tst;
|
||||
dev->tmf_only = DEF_TMF_ONLY;
|
||||
dev->tmf_only_saved = DEF_TMF_ONLY;
|
||||
dev->tmf_only_default = DEF_TMF_ONLY;
|
||||
dev->d_sense = DEF_DSENSE;
|
||||
dev->d_sense_saved = DEF_DSENSE;
|
||||
dev->d_sense_default = DEF_DSENSE;
|
||||
@@ -1303,6 +1308,9 @@ static int vdisk_attach(struct scst_device *dev)
|
||||
dev->queue_alg = DEF_QUEUE_ALG;
|
||||
dev->queue_alg_saved = dev->queue_alg;
|
||||
dev->queue_alg_default = dev->queue_alg;
|
||||
dev->qerr = DEF_QERR;
|
||||
dev->qerr_saved = DEF_QERR;
|
||||
dev->qerr_default = DEF_QERR;
|
||||
dev->swp = DEF_SWP;
|
||||
dev->swp_saved = DEF_SWP;
|
||||
dev->swp_default = DEF_SWP;
|
||||
@@ -3711,8 +3719,10 @@ static int vdisk_ctrl_m_pg(unsigned char *p, int pcontrol,
|
||||
switch (pcontrol) {
|
||||
case 0: /* current */
|
||||
p[2] |= virt_dev->dev->tst << 5;
|
||||
p[2] |= virt_dev->dev->tmf_only << 4;
|
||||
p[2] |= virt_dev->dev->d_sense << 2;
|
||||
p[3] |= virt_dev->dev->queue_alg << 4;
|
||||
p[3] |= virt_dev->dev->qerr << 1;
|
||||
p[4] |= virt_dev->dev->swp << 3;
|
||||
p[5] |= virt_dev->dev->tas << 6;
|
||||
break;
|
||||
@@ -3726,21 +3736,27 @@ static int vdisk_ctrl_m_pg(unsigned char *p, int pcontrol,
|
||||
p[2] |= 7 << 5; /* TST */
|
||||
#endif
|
||||
p[2] |= 1 << 2; /* D_SENSE */
|
||||
p[2] |= 1 << 4; /* TMF_ONLY */
|
||||
p[3] |= 0xF << 4; /* QUEUE ALGORITHM MODIFIER */
|
||||
p[3] |= 3 << 1; /* QErr */
|
||||
p[4] |= 1 << 3; /* SWP */
|
||||
p[5] |= 1 << 6; /* TAS */
|
||||
break;
|
||||
case 2: /* default */
|
||||
p[2] |= virt_dev->tst << 5;
|
||||
p[2] |= virt_dev->dev->d_sense_default << 2;
|
||||
p[2] |= virt_dev->dev->tmf_only_default << 4;
|
||||
p[3] |= virt_dev->dev->queue_alg_default << 4;
|
||||
p[3] |= virt_dev->dev->qerr_default << 1;
|
||||
p[4] |= virt_dev->dev->swp_default << 3;
|
||||
p[5] |= virt_dev->dev->tas_default << 6;
|
||||
break;
|
||||
case 3: /* saved */
|
||||
p[2] |= virt_dev->dev->tst << 5;
|
||||
p[2] |= virt_dev->dev->d_sense_saved << 2;
|
||||
p[2] |= virt_dev->dev->tmf_only_default << 4;
|
||||
p[3] |= virt_dev->dev->queue_alg_saved << 4;
|
||||
p[3] |= virt_dev->dev->qerr_saved << 1;
|
||||
p[4] |= virt_dev->dev->swp_saved << 3;
|
||||
p[5] |= virt_dev->dev->tas_saved << 6;
|
||||
break;
|
||||
@@ -3960,12 +3976,14 @@ out:
|
||||
}
|
||||
|
||||
static void vdisk_ctrl_m_pg_select(unsigned char *p,
|
||||
struct scst_vdisk_dev *virt_dev, struct scst_cmd *cmd, bool save)
|
||||
struct scst_vdisk_dev *virt_dev, struct scst_cmd *cmd, bool save,
|
||||
int param_offset)
|
||||
{
|
||||
struct scst_device *dev = virt_dev->dev;
|
||||
int old_swp = dev->swp, old_tas = dev->tas, old_dsense = dev->d_sense;
|
||||
int old_queue_alg = dev->queue_alg;
|
||||
int rc;
|
||||
int rc, old_tmf_only = dev->tmf_only, old_qerr = dev->qerr;
|
||||
int queue_alg, swp, tas, tmf_only, qerr, d_sense;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
@@ -3977,6 +3995,11 @@ static void vdisk_ctrl_m_pg_select(unsigned char *p,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* MODE SELECT is a strictly serialized cmd, so it is safe to
|
||||
* perform direct assignment here.
|
||||
*/
|
||||
|
||||
#if 0 /* Not implemented yet, see comment in struct scst_device */
|
||||
dev->tst = (p[2] >> 5) & 1;
|
||||
#else
|
||||
@@ -3988,13 +4011,79 @@ static void vdisk_ctrl_m_pg_select(unsigned char *p,
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
dev->queue_alg = p[3] >> 4;
|
||||
dev->swp = (p[4] & 0x8) >> 3;
|
||||
dev->tas = (p[5] & 0x40) >> 6;
|
||||
dev->d_sense = (p[2] & 0x4) >> 2;
|
||||
|
||||
queue_alg = p[3] >> 4;
|
||||
if ((queue_alg != SCST_QUEUE_ALG_0_RESTRICTED_REORDER) &&
|
||||
(queue_alg != SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER)) {
|
||||
PRINT_WARNING("Attempt to set invalid Control mode page QUEUE "
|
||||
"ALGORITHM MODIFIER value %d (initiator %s, dev %s)",
|
||||
queue_alg, cmd->sess->initiator_name, dev->virt_name);
|
||||
scst_set_invalid_field_in_parm_list(cmd, param_offset + 3,
|
||||
SCST_INVAL_FIELD_BIT_OFFS_VALID | 4);
|
||||
goto out;
|
||||
}
|
||||
|
||||
swp = (p[4] & 0x8) >> 3;
|
||||
if (swp > 1) {
|
||||
PRINT_WARNING("Attempt to set invalid Control mode page SWP "
|
||||
"value %d (initiator %s, dev %s)", swp,
|
||||
cmd->sess->initiator_name, dev->virt_name);
|
||||
scst_set_invalid_field_in_parm_list(cmd, param_offset + 4,
|
||||
SCST_INVAL_FIELD_BIT_OFFS_VALID | 3);
|
||||
goto out;
|
||||
}
|
||||
|
||||
tas = (p[5] & 0x40) >> 6;
|
||||
if (tas > 1) {
|
||||
PRINT_WARNING("Attempt to set invalid Control mode page TAS "
|
||||
"value %d (initiator %s, dev %s)", tas,
|
||||
cmd->sess->initiator_name, dev->virt_name);
|
||||
scst_set_invalid_field_in_parm_list(cmd, param_offset + 5,
|
||||
SCST_INVAL_FIELD_BIT_OFFS_VALID | 6);
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmf_only = (p[2] & 0x10) >> 4;
|
||||
if (tmf_only > 1) {
|
||||
PRINT_WARNING("Attempt to set invalid Control mode page "
|
||||
"TMF_ONLY value %d (initiator %s, dev %s)", tmf_only,
|
||||
cmd->sess->initiator_name, dev->virt_name);
|
||||
scst_set_invalid_field_in_parm_list(cmd, param_offset + 2,
|
||||
SCST_INVAL_FIELD_BIT_OFFS_VALID | 4);
|
||||
goto out;
|
||||
}
|
||||
|
||||
qerr = (p[3] & 0x6) >> 1;
|
||||
if ((qerr == SCST_QERR_2_RESERVED) ||
|
||||
(qerr > SCST_QERR_3_ABORT_THIS_NEXUS_ONLY)) {
|
||||
PRINT_WARNING("Attempt to set invalid Control mode page QErr "
|
||||
"value %d (initiator %s, dev %s)", qerr,
|
||||
cmd->sess->initiator_name, dev->virt_name);
|
||||
scst_set_invalid_field_in_parm_list(cmd, param_offset + 3,
|
||||
SCST_INVAL_FIELD_BIT_OFFS_VALID | 1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
d_sense = (p[2] & 0x4) >> 2;
|
||||
if (d_sense > 1) {
|
||||
PRINT_WARNING("Attempt to set invalid Control mode page D_SENSE "
|
||||
"value %d (initiator %s, dev %s)", d_sense,
|
||||
cmd->sess->initiator_name, dev->virt_name);
|
||||
scst_set_invalid_field_in_parm_list(cmd, param_offset + 2,
|
||||
SCST_INVAL_FIELD_BIT_OFFS_VALID | 2);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->queue_alg = queue_alg;
|
||||
dev->swp = swp;
|
||||
dev->tas = tas;
|
||||
dev->tmf_only = tmf_only;
|
||||
dev->qerr = qerr;
|
||||
dev->d_sense = d_sense;
|
||||
|
||||
if ((dev->swp == old_swp) && (dev->tas == old_tas) &&
|
||||
(dev->d_sense == old_dsense) && (dev->queue_alg == old_queue_alg))
|
||||
(dev->d_sense == old_dsense) && (dev->queue_alg == old_queue_alg) &&
|
||||
(dev->qerr == old_qerr) && dev->tmf_only == old_tmf_only)
|
||||
goto out;
|
||||
|
||||
if (!save)
|
||||
@@ -4006,6 +4095,8 @@ static void vdisk_ctrl_m_pg_select(unsigned char *p,
|
||||
dev->tas = old_tas;
|
||||
dev->d_sense = old_dsense;
|
||||
dev->queue_alg = old_queue_alg;
|
||||
dev->tmf_only = old_tmf_only;
|
||||
dev->qerr = old_qerr;
|
||||
/* Hopefully, the error is temporary */
|
||||
scst_set_busy(cmd);
|
||||
goto out;
|
||||
@@ -4015,13 +4106,16 @@ static void vdisk_ctrl_m_pg_select(unsigned char *p,
|
||||
dev->tas_saved = dev->tas;
|
||||
dev->d_sense_saved = dev->d_sense;
|
||||
dev->queue_alg_saved = dev->queue_alg;
|
||||
dev->tmf_only_saved = dev->tmf_only;
|
||||
dev->qerr_saved = dev->qerr;
|
||||
|
||||
out_ok:
|
||||
PRINT_INFO("Device %s: new control mode page parameters: SWP %x "
|
||||
"(was %x), TAS %x (was %x), D_SENSE %d (was %d), "
|
||||
"QUEUE ALG %d (was %d)", virt_dev->name, dev->swp,
|
||||
old_swp, dev->tas, old_tas, dev->d_sense, old_dsense,
|
||||
dev->queue_alg, old_queue_alg);
|
||||
"(was %x), TAS %x (was %x), TMF_ONLY %d (was %x), QErr %x "
|
||||
"(was %x), D_SENSE %d (was %d), QUEUE ALG %d (was %d)",
|
||||
virt_dev->name, dev->swp, old_swp, dev->tas, old_tas,
|
||||
dev->tmf_only, old_tmf_only, dev->qerr, old_qerr,
|
||||
dev->d_sense, old_dsense, dev->queue_alg, old_queue_alg);
|
||||
|
||||
out:
|
||||
TRACE_EXIT();
|
||||
@@ -4141,7 +4235,7 @@ static enum compl_status_e vdisk_exec_mode_select(struct vdisk_cmd_params *p)
|
||||
goto out_put;
|
||||
}
|
||||
vdisk_ctrl_m_pg_select(&address[offset], virt_dev, cmd,
|
||||
cmd->cdb[1] & SP);
|
||||
cmd->cdb[1] & SP, offset);
|
||||
} else {
|
||||
TRACE(TRACE_MINOR, "MODE SELECT: Invalid request %x",
|
||||
address[offset] & 0x3f);
|
||||
@@ -5617,10 +5711,12 @@ static void vdisk_task_mgmt_fn_done(struct scst_mgmt_cmd *mcmd,
|
||||
struct scst_vdisk_dev *virt_dev = dev->dh_priv;
|
||||
int rc;
|
||||
|
||||
dev->tmf_only = dev->tmf_only_saved;
|
||||
dev->d_sense = dev->d_sense_saved;
|
||||
dev->swp = dev->swp_saved;
|
||||
dev->tas = dev->tas_saved;
|
||||
dev->queue_alg = dev->queue_alg_saved;
|
||||
dev->qerr = dev->qerr_saved;
|
||||
|
||||
dev->tst = virt_dev->tst;
|
||||
|
||||
|
||||
@@ -2912,7 +2912,7 @@ int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd)
|
||||
if (cmd->internal)
|
||||
res = SCST_CMD_STATE_FINISHED_INTERNAL;
|
||||
else
|
||||
res = SCST_CMD_STATE_PRE_XMIT_RESP;
|
||||
res = SCST_CMD_STATE_PRE_XMIT_RESP1;
|
||||
break;
|
||||
|
||||
case SCST_CMD_STATE_PRE_DEV_DONE:
|
||||
@@ -2920,14 +2920,18 @@ int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd)
|
||||
res = SCST_CMD_STATE_DEV_DONE;
|
||||
break;
|
||||
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP:
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP1:
|
||||
res = SCST_CMD_STATE_PRE_XMIT_RESP2;
|
||||
break;
|
||||
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP2:
|
||||
res = SCST_CMD_STATE_XMIT_RESP;
|
||||
break;
|
||||
|
||||
case SCST_CMD_STATE_PREPROCESSING_DONE:
|
||||
case SCST_CMD_STATE_PREPROCESSING_DONE_CALLED:
|
||||
if (cmd->tgt_dev == NULL)
|
||||
res = SCST_CMD_STATE_PRE_XMIT_RESP;
|
||||
res = SCST_CMD_STATE_PRE_XMIT_RESP1;
|
||||
else
|
||||
res = SCST_CMD_STATE_PRE_DEV_DONE;
|
||||
break;
|
||||
@@ -3008,7 +3012,8 @@ void scst_set_cmd_abnormal_done_state(struct scst_cmd *cmd)
|
||||
case SCST_CMD_STATE_DEV_DONE:
|
||||
case SCST_CMD_STATE_PRE_DEV_DONE:
|
||||
case SCST_CMD_STATE_MODE_SELECT_CHECKS:
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP:
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP1:
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP2:
|
||||
case SCST_CMD_STATE_FINISHED_INTERNAL:
|
||||
break;
|
||||
default:
|
||||
@@ -3019,7 +3024,7 @@ void scst_set_cmd_abnormal_done_state(struct scst_cmd *cmd)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
if (((cmd->state != SCST_CMD_STATE_PRE_XMIT_RESP) &&
|
||||
if (((cmd->state != SCST_CMD_STATE_PRE_XMIT_RESP1) &&
|
||||
(cmd->state != SCST_CMD_STATE_PREPROCESSING_DONE)) &&
|
||||
(cmd->tgt_dev == NULL) && !cmd->internal) {
|
||||
PRINT_CRIT_ERROR("Wrong not inited cmd state %d (cmd %p, "
|
||||
@@ -8737,12 +8742,16 @@ int scst_obtain_device_parameters(struct scst_device *dev,
|
||||
"page data", buffer, sizeof(buffer));
|
||||
|
||||
dev->tst = buffer[4+2] >> 5;
|
||||
dev->tmf_only = (buffer[4+2] & 0x10) >> 4;
|
||||
q = buffer[4+3] >> 4;
|
||||
if (q > SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER) {
|
||||
PRINT_ERROR("Too big QUEUE ALG %x, dev %s",
|
||||
PRINT_ERROR("Too big QUEUE ALG %x, dev %s, "
|
||||
"using default: unrestricted reorder",
|
||||
dev->queue_alg, dev->virt_name);
|
||||
q = SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER;
|
||||
}
|
||||
dev->queue_alg = q;
|
||||
dev->qerr = (buffer[4+3] & 0x6) >> 1;
|
||||
dev->swp = (buffer[4+4] & 0x8) >> 3;
|
||||
dev->tas = (buffer[4+5] & 0x40) >> 6;
|
||||
dev->d_sense = (buffer[4+2] & 0x4) >> 2;
|
||||
@@ -8755,10 +8764,11 @@ int scst_obtain_device_parameters(struct scst_device *dev,
|
||||
*/
|
||||
dev->has_own_order_mgmt = !dev->queue_alg;
|
||||
|
||||
PRINT_INFO("Device %s: TST %x, QUEUE ALG %x, SWP %x, "
|
||||
"TAS %x, D_SENSE %d, has_own_order_mgmt %d",
|
||||
dev->virt_name, dev->tst, dev->queue_alg,
|
||||
dev->swp, dev->tas, dev->d_sense,
|
||||
PRINT_INFO("Device %s: TST %x, TMF_ONLY %x, QUEUE ALG %x, "
|
||||
"QErr %x, SWP %x, TAS %x, D_SENSE %d, "
|
||||
"has_own_order_mgmt %d", dev->virt_name,
|
||||
dev->tst, dev->tmf_only, dev->queue_alg,
|
||||
dev->qerr, dev->swp, dev->tas, dev->d_sense,
|
||||
dev->has_own_order_mgmt);
|
||||
|
||||
goto out;
|
||||
@@ -8820,9 +8830,10 @@ int scst_obtain_device_parameters(struct scst_device *dev,
|
||||
}
|
||||
brk:
|
||||
PRINT_WARNING("Unable to get device's %s control mode page, using "
|
||||
"existing values/defaults: TST %x, QUEUE ALG %x, SWP %x, "
|
||||
"TAS %x, D_SENSE %d, has_own_order_mgmt %d", dev->virt_name,
|
||||
dev->tst, dev->queue_alg, dev->swp, dev->tas, dev->d_sense,
|
||||
"existing values/defaults: TST %x, TMF_ONLY %x, QUEUE ALG %x, "
|
||||
"QErr %x, SWP %x, TAS %x, D_SENSE %d, has_own_order_mgmt %d",
|
||||
dev->virt_name, dev->tst, dev->tmf_only, dev->queue_alg,
|
||||
dev->qerr, dev->swp, dev->tas, dev->d_sense,
|
||||
dev->has_own_order_mgmt);
|
||||
|
||||
out:
|
||||
@@ -8890,6 +8901,152 @@ void scst_store_sense(struct scst_cmd *cmd)
|
||||
return;
|
||||
}
|
||||
|
||||
/* dev_lock supposed to be locked and BHs off */
|
||||
static void scst_abort_cmds_tgt_dev(struct scst_tgt_dev *tgt_dev,
|
||||
struct scst_cmd *exclude_cmd)
|
||||
{
|
||||
struct scst_session *sess = tgt_dev->sess;
|
||||
struct scst_cmd *cmd;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_MGMT_DBG("Aborting commands for tgt_dev %p (exclude_cmd %p)",
|
||||
tgt_dev, exclude_cmd);
|
||||
|
||||
/* IRQs supposed to be already locked */
|
||||
spin_lock(&sess->sess_list_lock);
|
||||
|
||||
list_for_each_entry(cmd, &sess->sess_cmd_list, sess_cmd_list_entry) {
|
||||
if (cmd == exclude_cmd)
|
||||
continue;
|
||||
if ((cmd->tgt_dev == tgt_dev) ||
|
||||
((cmd->tgt_dev == NULL) &&
|
||||
(cmd->lun == tgt_dev->lun))) {
|
||||
scst_abort_cmd(cmd, NULL, (tgt_dev != exclude_cmd->tgt_dev), 0);
|
||||
}
|
||||
}
|
||||
spin_unlock(&sess->sess_list_lock);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
/* dev_lock supposed to be locked and BHs off */
|
||||
static void scst_abort_cmds_dev(struct scst_device *dev,
|
||||
struct scst_cmd *exclude_cmd)
|
||||
{
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
|
||||
int sl = 0;
|
||||
bool set_ua = (dev->tas == 0);
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_MGMT_DBG("Aborting commands for dev %p (exclude_cmd %p, set_ua %d)",
|
||||
dev, exclude_cmd, set_ua);
|
||||
|
||||
if (set_ua)
|
||||
sl = scst_set_sense(sense_buffer, sizeof(sense_buffer), dev->d_sense,
|
||||
SCST_LOAD_SENSE(scst_sense_cleared_by_another_ini_UA));
|
||||
|
||||
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, dev_tgt_dev_list_entry) {
|
||||
scst_abort_cmds_tgt_dev(tgt_dev, exclude_cmd);
|
||||
/*
|
||||
* Potentially, setting UA here, when the aborted commands are
|
||||
* still running, can lead to a situation that one of them could
|
||||
* take it, then that would be detected and the UA requeued.
|
||||
* But, meanwhile, one or more subsequent, i.e. not aborted,
|
||||
* commands can "leak" executed normally. So, as result, the
|
||||
* UA would be delivered one or more commands "later". However,
|
||||
* that should be OK, because, if multiple commands are being
|
||||
* executed in parallel, you can't control exact order of UA
|
||||
* delivery anyway.
|
||||
*/
|
||||
if (set_ua && (tgt_dev != exclude_cmd->tgt_dev))
|
||||
scst_check_set_UA(tgt_dev, sense_buffer, sl, 0);
|
||||
}
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
/* No locks */
|
||||
static void scst_process_qerr(struct scst_cmd *cmd)
|
||||
{
|
||||
bool unblock = false;
|
||||
struct scst_device *dev = cmd->dev;
|
||||
unsigned int qerr, q;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
/* dev->qerr can be changed behind our back */
|
||||
q = dev->qerr;
|
||||
qerr = ACCESS_ONCE(q); /* ACCESS_ONCE doesn't work for bit bilds */
|
||||
|
||||
TRACE_DBG("Processing QErr %d for cmd %p", qerr, cmd);
|
||||
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
|
||||
switch (qerr) {
|
||||
case SCST_QERR_2_RESERVED:
|
||||
default:
|
||||
PRINT_WARNING("Invalid QErr value %x for device %s, process as "
|
||||
"0", qerr, dev->virt_name);
|
||||
/* go through */
|
||||
case SCST_QERR_0_ALL_RESUME:
|
||||
/* Nothing to do */
|
||||
break;
|
||||
case SCST_QERR_1_ABORT_ALL:
|
||||
if (dev->tst == SCST_TST_0_SINGLE_TASK_SET)
|
||||
scst_abort_cmds_dev(dev, cmd);
|
||||
else
|
||||
scst_abort_cmds_tgt_dev(cmd->tgt_dev, cmd);
|
||||
unblock = true;
|
||||
break;
|
||||
case SCST_QERR_3_ABORT_THIS_NEXUS_ONLY:
|
||||
scst_abort_cmds_tgt_dev(cmd->tgt_dev, cmd);
|
||||
unblock = true;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
|
||||
if (unblock)
|
||||
scst_unblock_aborted_cmds(cmd->tgt, cmd->sess, dev, false);
|
||||
|
||||
TRACE_EXIT();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* No locks. Returns -1, if processing should be switched to another cmd, 1
|
||||
* if cmd was aborted, 0 if cmd processing should continue.
|
||||
*/
|
||||
int scst_process_check_condition(struct scst_cmd *cmd)
|
||||
{
|
||||
int res;
|
||||
struct scst_order_data *order_data;
|
||||
struct scst_device *dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
EXTRACHECKS_BUG_ON(test_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags));
|
||||
|
||||
order_data = cmd->cur_order_data;
|
||||
dev = cmd->dev;
|
||||
|
||||
TRACE_DBG("CHECK CONDITION for cmd %p (tgt_dev %p)", cmd, cmd->tgt_dev);
|
||||
|
||||
scst_process_qerr(cmd);
|
||||
|
||||
scst_store_sense(cmd);
|
||||
|
||||
res = 0;
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void scst_xmit_process_aborted_cmd(struct scst_cmd *cmd)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
@@ -9273,6 +9430,8 @@ static void scst_free_descriptors(struct scst_cmd *cmd)
|
||||
**/
|
||||
|
||||
#define SCST_TAS_LABEL "TAS"
|
||||
#define SCST_QERR_LABEL "QERR"
|
||||
#define SCST_TMF_ONLY_LABEL "TMF_ONLY"
|
||||
#define SCST_SWP_LABEL "SWP"
|
||||
#define SCST_DSENSE_LABEL "D_SENSE"
|
||||
#define SCST_QUEUE_ALG_LABEL "QUEUE_ALG"
|
||||
@@ -9291,6 +9450,20 @@ int scst_save_global_mode_pages(const struct scst_device *dev,
|
||||
goto out_overflow;
|
||||
}
|
||||
|
||||
if (dev->qerr != dev->qerr_default) {
|
||||
res += scnprintf(&buf[res], size - res, "%s=%d\n",
|
||||
SCST_QERR_LABEL, dev->qerr);
|
||||
if (res >= size-1)
|
||||
goto out_overflow;
|
||||
}
|
||||
|
||||
if (dev->tmf_only != dev->tmf_only_default) {
|
||||
res += scnprintf(&buf[res], size - res, "%s=%d\n",
|
||||
SCST_TMF_ONLY_LABEL, dev->tmf_only);
|
||||
if (res >= size-1)
|
||||
goto out_overflow;
|
||||
}
|
||||
|
||||
if (dev->swp != dev->swp_default) {
|
||||
res += scnprintf(&buf[res], size - res, "%s=%d\n",
|
||||
SCST_SWP_LABEL, dev->swp);
|
||||
@@ -9349,6 +9522,59 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int scst_restore_qerr(struct scst_device *dev, unsigned int val)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if ((val == SCST_QERR_2_RESERVED) ||
|
||||
(val > SCST_QERR_3_ABORT_THIS_NEXUS_ONLY)) {
|
||||
PRINT_ERROR("Invalid value %d for parameter %s (device %s)",
|
||||
val, SCST_QERR_LABEL, dev->virt_name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->qerr = val;
|
||||
dev->qerr_saved = val;
|
||||
|
||||
PRINT_INFO("%s restored to %d for device %s", SCST_QERR_LABEL,
|
||||
dev->qerr, dev->virt_name);
|
||||
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int scst_restore_tmf_only(struct scst_device *dev, unsigned int val)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (val > 1) {
|
||||
PRINT_ERROR("Invalid value %d for parameter %s (device %s)",
|
||||
val, SCST_TMF_ONLY_LABEL, dev->virt_name);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->tmf_only = val;
|
||||
dev->tmf_only_saved = val;
|
||||
|
||||
PRINT_INFO("%s restored to %d for device %s", SCST_TMF_ONLY_LABEL,
|
||||
dev->tmf_only, dev->virt_name);
|
||||
|
||||
res = 0;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int scst_restore_swp(struct scst_device *dev, unsigned int val)
|
||||
{
|
||||
int res;
|
||||
@@ -9464,6 +9690,10 @@ int scst_restore_global_mode_pages(struct scst_device *dev, char *params,
|
||||
|
||||
if (strcasecmp(SCST_TAS_LABEL, p) == 0)
|
||||
res = scst_restore_tas(dev, val);
|
||||
else if (strcasecmp(SCST_QERR_LABEL, p) == 0)
|
||||
res = scst_restore_qerr(dev, val);
|
||||
else if (strcasecmp(SCST_TMF_ONLY_LABEL, p) == 0)
|
||||
res = scst_restore_tmf_only(dev, val);
|
||||
else if (strcasecmp(SCST_SWP_LABEL, p) == 0)
|
||||
res = scst_restore_swp(dev, val);
|
||||
else if (strcasecmp(SCST_DSENSE_LABEL, p) == 0)
|
||||
|
||||
@@ -375,6 +375,8 @@ int scst_set_cmd_error_sense(struct scst_cmd *cmd, uint8_t *sense,
|
||||
unsigned int len);
|
||||
void scst_store_sense(struct scst_cmd *cmd);
|
||||
|
||||
int scst_process_check_condition(struct scst_cmd *cmd);
|
||||
|
||||
int scst_assign_dev_handler(struct scst_device *dev,
|
||||
struct scst_dev_type *handler);
|
||||
|
||||
|
||||
@@ -577,12 +577,12 @@ int scst_pre_parse(struct scst_cmd *cmd)
|
||||
TRACE_DBG("op_name <%s> (cmd %p), direction=%d "
|
||||
"(expected %d, set %s), lba %lld, bufflen=%d, data_len %lld, "
|
||||
"out_bufflen=%d (expected len %d, out expected len %d), "
|
||||
"flags=0x%x", cmd->op_name, cmd, cmd->data_direction,
|
||||
"flags=0x%x, naca %d", cmd->op_name, cmd, cmd->data_direction,
|
||||
cmd->expected_data_direction,
|
||||
scst_cmd_is_expected_set(cmd) ? "yes" : "no",
|
||||
(long long)cmd->lba, cmd->bufflen, (long long)cmd->data_len,
|
||||
cmd->out_bufflen, cmd->expected_transfer_len,
|
||||
cmd->expected_out_transfer_len, cmd->op_flags);
|
||||
cmd->expected_out_transfer_len, cmd->op_flags, cmd->cmd_naca);
|
||||
|
||||
res = 0;
|
||||
|
||||
@@ -893,7 +893,8 @@ set_res:
|
||||
case SCST_CMD_STATE_REAL_EXEC:
|
||||
case SCST_CMD_STATE_PRE_DEV_DONE:
|
||||
case SCST_CMD_STATE_DEV_DONE:
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP:
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP1:
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP2:
|
||||
case SCST_CMD_STATE_XMIT_RESP:
|
||||
case SCST_CMD_STATE_FINISHED:
|
||||
case SCST_CMD_STATE_FINISHED_INTERNAL:
|
||||
@@ -1304,7 +1305,9 @@ void scst_restart_cmd(struct scst_cmd *cmd, int status,
|
||||
break;
|
||||
|
||||
case SCST_PREPROCESS_STATUS_ERROR_FATAL:
|
||||
set_bit(SCST_CMD_ABORTED, &cmd->cmd_flags);
|
||||
set_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags);
|
||||
cmd->delivery_status = SCST_CMD_DELIVERY_FAILED;
|
||||
/* go through */
|
||||
case SCST_PREPROCESS_STATUS_ERROR:
|
||||
if (cmd->sense != NULL)
|
||||
@@ -1559,7 +1562,9 @@ void scst_rx_data(struct scst_cmd *cmd, int status,
|
||||
break;
|
||||
|
||||
case SCST_RX_STATUS_ERROR_FATAL:
|
||||
set_bit(SCST_CMD_ABORTED, &cmd->cmd_flags);
|
||||
set_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags);
|
||||
cmd->delivery_status = SCST_CMD_DELIVERY_FAILED;
|
||||
/* go through */
|
||||
case SCST_RX_STATUS_ERROR:
|
||||
if (!cmd->write_not_received_set)
|
||||
@@ -1679,7 +1684,9 @@ static int scst_tgt_pre_exec(struct scst_cmd *cmd)
|
||||
scst_set_cmd_abnormal_done_state(cmd);
|
||||
goto out;
|
||||
case SCST_PREPROCESS_STATUS_ERROR_FATAL:
|
||||
set_bit(SCST_CMD_ABORTED, &cmd->cmd_flags);
|
||||
set_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags);
|
||||
cmd->delivery_status = SCST_CMD_DELIVERY_FAILED;
|
||||
/* go through */
|
||||
case SCST_PREPROCESS_STATUS_ERROR:
|
||||
scst_set_cmd_error(cmd,
|
||||
@@ -1808,7 +1815,8 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state,
|
||||
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
if ((next_state != SCST_CMD_STATE_PRE_DEV_DONE) &&
|
||||
(next_state != SCST_CMD_STATE_PRE_XMIT_RESP) &&
|
||||
(next_state != SCST_CMD_STATE_PRE_XMIT_RESP1) &&
|
||||
(next_state != SCST_CMD_STATE_PRE_XMIT_RESP2) &&
|
||||
(next_state != SCST_CMD_STATE_FINISHED) &&
|
||||
(next_state != SCST_CMD_STATE_FINISHED_INTERNAL)) {
|
||||
PRINT_ERROR("%s() received invalid cmd state %d (opcode %d)",
|
||||
@@ -3723,7 +3731,7 @@ static int scst_dev_done(struct scst_cmd *cmd)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
state = SCST_CMD_STATE_PRE_XMIT_RESP;
|
||||
state = SCST_CMD_STATE_PRE_XMIT_RESP1;
|
||||
|
||||
if (likely((cmd->op_flags & SCST_FULLY_LOCAL_CMD) == 0) &&
|
||||
likely(devt->dev_done != NULL)) {
|
||||
@@ -3754,7 +3762,8 @@ static int scst_dev_done(struct scst_cmd *cmd)
|
||||
|
||||
switch (state) {
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP:
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP1:
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP2:
|
||||
case SCST_CMD_STATE_PARSE:
|
||||
case SCST_CMD_STATE_PREPARE_SPACE:
|
||||
case SCST_CMD_STATE_RDY_TO_XFER:
|
||||
@@ -3809,7 +3818,8 @@ static int scst_dev_done(struct scst_cmd *cmd)
|
||||
cmd->state = SCST_CMD_STATE_FINISHED_INTERNAL;
|
||||
|
||||
#ifndef CONFIG_SCST_TEST_IO_IN_SIRQ
|
||||
if (cmd->state != SCST_CMD_STATE_PRE_XMIT_RESP) {
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
if (cmd->state != SCST_CMD_STATE_PRE_XMIT_RESP1) {
|
||||
/* We can't allow atomic command on the exec stages */
|
||||
if (scst_cmd_atomic(cmd)) {
|
||||
switch (state) {
|
||||
@@ -3826,13 +3836,58 @@ static int scst_dev_done(struct scst_cmd *cmd)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
out:
|
||||
TRACE_EXIT_HRES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int scst_pre_xmit_response(struct scst_cmd *cmd)
|
||||
static int scst_pre_xmit_response2(struct scst_cmd *cmd)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
again:
|
||||
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)))
|
||||
scst_xmit_process_aborted_cmd(cmd);
|
||||
else if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION)) {
|
||||
if (cmd->tgt_dev != NULL) {
|
||||
int rc = scst_process_check_condition(cmd);
|
||||
/* !! At this point cmd can be already dead !! */
|
||||
if (rc == -1) {
|
||||
res = SCST_CMD_STATE_RES_CONT_NEXT;
|
||||
goto out;
|
||||
} else if (rc == 1)
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(test_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags))) {
|
||||
EXTRACHECKS_BUG_ON(!test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags));
|
||||
TRACE_MGMT_DBG("Flag NO_RESP set for cmd %p (tag %llu), "
|
||||
"skipping", cmd, (long long unsigned int)cmd->tag);
|
||||
cmd->state = SCST_CMD_STATE_FINISHED;
|
||||
goto out_same;
|
||||
}
|
||||
|
||||
if (unlikely(cmd->resid_possible))
|
||||
scst_adjust_resp_data_len(cmd);
|
||||
else
|
||||
cmd->adjusted_resp_data_len = cmd->resp_data_len;
|
||||
|
||||
cmd->state = SCST_CMD_STATE_XMIT_RESP;
|
||||
|
||||
out_same:
|
||||
res = SCST_CMD_STATE_RES_CONT_SAME;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int scst_pre_xmit_response1(struct scst_cmd *cmd)
|
||||
{
|
||||
int res;
|
||||
|
||||
@@ -3880,29 +3935,10 @@ static int scst_pre_xmit_response(struct scst_cmd *cmd)
|
||||
cmd->done = 1;
|
||||
smp_mb(); /* to sync with scst_abort_cmd() */
|
||||
|
||||
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)))
|
||||
scst_xmit_process_aborted_cmd(cmd);
|
||||
else if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION))
|
||||
scst_store_sense(cmd);
|
||||
cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP2;
|
||||
res = scst_pre_xmit_response2(cmd);
|
||||
|
||||
if (unlikely(test_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags))) {
|
||||
TRACE_MGMT_DBG("Flag NO_RESP set for cmd %p (tag %llu), "
|
||||
"skipping", cmd, (long long unsigned int)cmd->tag);
|
||||
cmd->state = SCST_CMD_STATE_FINISHED;
|
||||
res = SCST_CMD_STATE_RES_CONT_SAME;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(cmd->resid_possible))
|
||||
scst_adjust_resp_data_len(cmd);
|
||||
else
|
||||
cmd->adjusted_resp_data_len = cmd->resp_data_len;
|
||||
|
||||
cmd->state = SCST_CMD_STATE_XMIT_RESP;
|
||||
res = SCST_CMD_STATE_RES_CONT_SAME;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_HRES(res);
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -4073,6 +4109,7 @@ static int scst_finish_cmd(struct scst_cmd *cmd)
|
||||
|
||||
if (unlikely(cmd->delivery_status != SCST_CMD_DELIVERY_SUCCESS)) {
|
||||
if ((cmd->tgt_dev != NULL) &&
|
||||
(cmd->status == SAM_STAT_CHECK_CONDITION) &&
|
||||
scst_is_ua_sense(cmd->sense, cmd->sense_valid_len)) {
|
||||
/* This UA delivery failed, so we need to requeue it */
|
||||
if (scst_cmd_atomic(cmd) &&
|
||||
@@ -4766,10 +4803,14 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic)
|
||||
res = scst_dev_done(cmd);
|
||||
break;
|
||||
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP:
|
||||
res = scst_pre_xmit_response(cmd);
|
||||
EXTRACHECKS_BUG_ON(res ==
|
||||
SCST_CMD_STATE_RES_NEED_THREAD);
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP1:
|
||||
res = scst_pre_xmit_response1(cmd);
|
||||
EXTRACHECKS_BUG_ON(res == SCST_CMD_STATE_RES_NEED_THREAD);
|
||||
break;
|
||||
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP2:
|
||||
res = scst_pre_xmit_response2(cmd);
|
||||
EXTRACHECKS_BUG_ON(res == SCST_CMD_STATE_RES_NEED_THREAD);
|
||||
break;
|
||||
|
||||
case SCST_CMD_STATE_XMIT_RESP:
|
||||
|
||||
@@ -384,7 +384,9 @@ int start(int argc, char **argv)
|
||||
desc.opt.memory_reuse_type = memory_reuse_type;
|
||||
|
||||
desc.opt.tst = SCST_TST_1_SEP_TASK_SETS;
|
||||
desc.opt.tmf_only = 0;
|
||||
desc.opt.queue_alg = SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER;
|
||||
desc.opt.qerr = 0;
|
||||
desc.opt.d_sense = SCST_D_SENSE_0_FIXED_SENSE;
|
||||
|
||||
res = ioctl(devs[i].scst_usr_fd, SCST_USER_REGISTER_DEVICE, &desc);
|
||||
|
||||
Reference in New Issue
Block a user