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:
Vladislav Bolkhovitin
2014-04-26 01:56:36 +00:00
parent c0be3de584
commit 34f682c19e
9 changed files with 503 additions and 69 deletions

View File

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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

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

View File

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

View File

@@ -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:

View File

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