Simple bugfix for concurrent work of several targets, which eventually turned out in a massive cleanup and fixes.

Particularly:
 - Added ability for target drivers to set result of command's status delvery to initiator (see scst_set_delivery_status())
 - Added ability for user space devices set some mode page parameters to make SCST core behave correspondingly
 - TM improvements
 - Few possible crashes fixed
 - Logging improvements
 - Performance improvements
 - Docs updates


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@227 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2007-12-07 17:00:42 +00:00
parent 8555992770
commit d33edb6ba3
31 changed files with 1486 additions and 684 deletions
+22 -1
View File
@@ -2,7 +2,7 @@
USER SPACE INTERFACE DESCRIPTION.
Version 0.9.6/1
Version 0.9.6/2
I. Description.
@@ -62,6 +62,7 @@ struct scst_user_dev_desc
{
uint8_t version;
uint8_t type;
uint8_t has_own_order_mgmt;
struct scst_user_opt opt;
uint32_t block_size;
char name[SCST_MAX_NAME];
@@ -73,6 +74,10 @@ where:
- type - SCSI type of the device
- has_own_order_mgmt - set it in non-zero, if device implements own
ORDERED commands management, i.e. guarantees commands execution order
requirements, specified by SAM.
- opt - device options, see SCST_USER_SET_OPTIONS/SCST_USER_GET_OPTIONS below
- block_size - block size, shall be divisible by 512 for block devices
@@ -101,6 +106,11 @@ struct scst_user_opt
uint8_t prio_queue_type;
uint8_t partial_transfers_type;
uint32_t partial_len;
uint8_t tst;
uint8_t queue_alg;
uint8_t tas;
uint8_t swp;
},
where:
@@ -181,6 +191,9 @@ where:
* SCST_USER_PARTIAL_TRANSFERS_SUPPORTED - the partial data transfers
are supported without limitations.
- tst, queue_alg, tas and swp - set values for TST, QUEUE ALGORITHM MODIFIER,
TAS and SWP fields from control mode page correspondingly, see SPC.
Flags parse_type and on_free_cmd_type are designed to improve
performance by eliminating context switches to the user space handler,
when processing of the corresponding events isn't needed.
@@ -572,6 +585,7 @@ struct scst_user_scsi_on_free_cmd
uint8_t buffer_cached;
uint8_t aborted;
uint8_t status;
uint8_t delivery_status;
},
where:
@@ -586,7 +600,14 @@ where:
- aborted - true, if command was aborted
- status - SAM status of the commands execution
- delivery_status - status of cmd's status/data delivery to remote
initiator. Can be:
* SCST_CMD_DELIVERY_SUCCESS - delivery succeeded
* SCST_CMD_DELIVERY_FAILED - delivery failed
The user space handler should reply using the corresponding reply
command. No error code is needed.
+8 -4
View File
@@ -721,7 +721,8 @@ static struct iscsi_cmnd *cmnd_find_hash_get(struct iscsi_session *session,
spin_lock(&session->cmnd_hash_lock);
cmnd = __cmnd_find_hash(session, itt, ttt);
cmnd_get(cmnd);
if (cmnd)
cmnd_get(cmnd);
spin_unlock(&session->cmnd_hash_lock);
return cmnd;
@@ -1296,7 +1297,7 @@ static int data_out_start(struct iscsi_conn *conn, struct iscsi_cmnd *cmnd)
cmnd->cmd_req = req = cmnd_find_hash(conn->session, req_hdr->itt,
req_hdr->ttt);
if (!req) {
PRINT_ERROR("unable to find scsi task %x %x",
PRINT_ERROR("Unable to find scsi task %x %x",
cmnd_itt(cmnd), cmnd_ttt(cmnd));
goto skip_pdu;
}
@@ -1583,7 +1584,8 @@ static void execute_task_management(struct iscsi_cmnd *req)
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),
TRACE((function == ISCSI_FUNCTION_ABORT_TASK) ? TRACE_MGMT_MINOR : TRACE_MGMT,
"TM cmd: req %p, itt %x, fn %d, rtt %x", req, cmnd_itt(req),
function, req_hdr->rtt);
memset(&params, 0, sizeof(params));
@@ -2318,7 +2320,9 @@ static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status)
(struct iscsi_task_mgt_hdr *)&req->pdu.bhs;
struct iscsi_task_rsp_hdr *rsp_hdr;
TRACE(TRACE_MGMT, "TM req %p finished, status %d", req, status);
TRACE((req_hdr->function == ISCSI_FUNCTION_ABORT_TASK) ?
TRACE_MGMT_MINOR : TRACE_MGMT,
"TM req %p finished, status %d", req, status);
rsp = iscsi_cmnd_create_rsp_cmnd(req);
rsp_hdr = (struct iscsi_task_rsp_hdr *)&rsp->pdu.bhs;
+1 -1
View File
@@ -34,7 +34,7 @@
#ifdef DEBUG
#define ISCSI_DEFAULT_LOG_FLAGS (TRACE_FUNCTION | TRACE_LINE | TRACE_PID | \
TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_DEBUG | \
TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_MINOR | TRACE_MGMT_DEBUG | \
TRACE_MINOR | TRACE_SPECIAL | TRACE_CONN_OC)
#else
#define ISCSI_DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | \
+3
View File
@@ -817,6 +817,9 @@ err:
(unsigned long long)conn->session->sid, conn->cid,
conn->write_cmnd);
}
if (ref_cmd->scst_cmd != NULL)
scst_set_delivery_status(ref_cmd->scst_cmd,
SCST_CMD_DELIVERY_FAILED);
return res;
}
+7 -2
View File
@@ -65,8 +65,8 @@ static char *mpt_state_string[] = {
#ifdef DEBUG
#define SCST_DEFAULT_MPT_LOG_FLAGS (TRACE_FUNCTION | TRACE_PID | \
TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_DEBUG | \
TRACE_MINOR | TRACE_SPECIAL)
TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_MINOR | \
TRACE_MGMT_DEBUG | TRACE_MINOR | TRACE_SPECIAL)
#else
# ifdef TRACING
#define SCST_DEFAULT_MPT_LOG_FLAGS (TRACE_FUNCTION | TRACE_PID | \
@@ -803,6 +803,7 @@ stm_tgt_reply(MPT_ADAPTER *ioc, u32 reply_word)
case MPT_STATUS_SENSE_ATTEMPT:
atomic_set(&priv->pending_sense[init_index],
MPT_STATUS_SENSE_IDLE);
/* ToDo: check and set scst_set_delivery_status(), if necessary */
scst_tgt_cmd_done(scst_cmd);
break;
@@ -813,6 +814,7 @@ stm_tgt_reply(MPT_ADAPTER *ioc, u32 reply_word)
case MPT_STATUS_SENSE_NOT_SENT:
atomic_set(&priv->pending_sense[init_index],
MPT_STATUS_SENSE_HANDLE_RQ);
/* ToDo: check and set scst_set_delivery_status(), if necessary */
scst_tgt_cmd_done(scst_cmd);
break;
@@ -831,10 +833,12 @@ stm_tgt_reply(MPT_ADAPTER *ioc, u32 reply_word)
default:
/* nothing much to do here, we aren't
* handling cached sense/status */
/* ToDo: check and set scst_set_delivery_status(), if necessary */
scst_tgt_cmd_done(scst_cmd);
break;
}
} else {
/* ToDo: check and set scst_set_delivery_status(), if necessary */
scst_tgt_cmd_done(scst_cmd);
}
@@ -1674,6 +1678,7 @@ mpt_xmit_response(struct scst_cmd *scst_cmd)
return res;
out_tgt_free:
/* ToDo: check and set scst_set_delivery_status(), if necessary */
scst_tgt_cmd_done(scst_cmd);
goto out;
}
+9 -10
View File
@@ -49,8 +49,8 @@
#ifdef DEBUG
#define Q2T_DEFAULT_LOG_FLAGS (TRACE_FUNCTION | TRACE_PID | \
TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_DEBUG | \
TRACE_MINOR | TRACE_SPECIAL)
TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_MINOR | \
TRACE_MGMT_DEBUG | TRACE_MINOR | TRACE_SPECIAL)
#else
# ifdef TRACING
#define Q2T_DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MINOR | \
@@ -689,7 +689,7 @@ static int q2t_xmit_response(struct scst_cmd *scst_cmd)
if (unlikely(scst_cmd_aborted(scst_cmd))) {
scsi_qla_host_t *ha = sess->tgt->ha;
TRACE(TRACE_MGMT, "qla2x00tgt(%ld): terminating exchange "
TRACE(TRACE_MGMT_MINOR, "qla2x00tgt(%ld): terminating exchange "
"for aborted scst_cmd=%p (tag=%Ld)",
ha->instance, scst_cmd, scst_cmd_get_tag(scst_cmd));
@@ -1004,13 +1004,13 @@ static void q2t_do_ctio_completion(scsi_qla_host_t *ha,
handle &= ~CTIO_COMPLETION_HANDLE_MARK;
if (status != CTIO_SUCCESS) {
err = 1;
switch (status) {
case CTIO_LIP_RESET:
case CTIO_TARGET_RESET:
case CTIO_ABORTED:
case CTIO_TIMEOUT:
case CTIO_INVALID_RX_ID:
err = 1;
/* they are OK */
TRACE_MGMT_DBG("qla2x00tgt(%ld): CTIO with status %#x "
"received (LIP_RESET=e, ABORTED=2, "
@@ -1020,14 +1020,12 @@ static void q2t_do_ctio_completion(scsi_qla_host_t *ha,
case CTIO_PORT_LOGGED_OUT:
case CTIO_PORT_UNAVAILABLE:
err = 1;
PRINT_INFO("qla2x00tgt(%ld): CTIO with PORT LOGGED "
"OUT (29) or PORT UNAVAILABLE (28) status %x "
"received", ha->instance, status);
break;
default:
err = 1;
PRINT_ERROR("qla2x00tgt(%ld): CTIO with error status "
"0x%x received", ha->instance, status);
break;
@@ -1133,6 +1131,7 @@ out:
out_free:
if (unlikely(err)) {
TRACE_MGMT_DBG("%s", "Finishing failed CTIO");
scst_set_delivery_status(scst_cmd, SCST_CMD_DELIVERY_FAILED);
}
scst_tgt_cmd_done(scst_cmd);
goto out;
@@ -1360,7 +1359,6 @@ static int q2t_send_cmd_to_scst(scsi_qla_host_t *ha, atio_entry_t *atio)
/* le64_to_cpu(*(uint64_t *)(((char *)atio)+0x2c))); */
/*le32_to_cpu(*(uint32_t *)atio->initiator_port_name)); */
if (tgt->tgt_shutdown) {
TRACE_MGMT_DBG("New command while device %p is shutting "
"down", tgt);
@@ -1606,8 +1604,9 @@ static void q2t_task_mgmt_fn_done(struct scst_mgmt_cmd *scst_mcmd)
TRACE_ENTRY();
TRACE(TRACE_MGMT, "scst_mcmd (%p) status %#x state %#x", scst_mcmd,
scst_mcmd->status, scst_mcmd->state);
TRACE((scst_mcmd->fn == SCST_ABORT_TASK) ? TRACE_MGMT_MINOR : TRACE_MGMT,
"scst_mcmd (%p) status %#x state %#x", scst_mcmd,
scst_mcmd->status, scst_mcmd->state);
mcmd = scst_mgmt_cmd_get_tgt_priv(scst_mcmd);
if (unlikely(mcmd == NULL)) {
@@ -1671,7 +1670,7 @@ static void q2t_handle_imm_notify(scsi_qla_host_t *ha, notify_entry_t *iocb)
break;
case IMM_NTFY_ABORT_TASK:
TRACE(TRACE_MGMT, "Abort Task (S %04x I %#x -> L %#x)",
TRACE(TRACE_MGMT_MINOR, "Abort Task (S %04x I %#x -> L %#x)",
le16_to_cpu(iocb->seq_id), loop_id,
le16_to_cpu(iocb->lun));
if (q2t_abort_task(ha, iocb) == 0)
+3
View File
@@ -547,6 +547,7 @@ scsi_target_done_cmd(tmd_cmd_t *tmd, int from_intr)
xfr->td_hflags &= ~TDFH_DATA_MASK;
xfr->td_xfrlen = 0;
}
/* ToDo: check and set scst_set_delivery_status(), if necessary */
scst_tgt_cmd_done(scst_cmd);
return;
}
@@ -561,6 +562,7 @@ scsi_target_done_cmd(tmd_cmd_t *tmd, int from_intr)
}
scst_rx_data(scst_cmd, SCST_RX_STATUS_SUCCESS, SCST_CONTEXT_TASKLET);
} else {
/* ToDo: check and set scst_set_delivery_status(), if necessary */
scst_tgt_cmd_done(scst_cmd);
}
} else {
@@ -569,6 +571,7 @@ scsi_target_done_cmd(tmd_cmd_t *tmd, int from_intr)
} else if (xfr->td_hflags & TDFH_DATA_IN) {
xfr->td_hflags &= ~TDFH_DATA_MASK;
xfr->td_xfrlen = 0;
/* ToDo: check and set scst_set_delivery_status(), if necessary */
scst_tgt_cmd_done(scst_cmd);
}
}
+36 -18
View File
@@ -465,9 +465,19 @@ IMPORTANT: By default for performance reasons VDISK FILEIO devices use write
usually it turned off by default and the status of barriers
usage isn't reported anywhere in the system logs as well as
there is no way to know it on the mounted file system (at
least no known one). Also note that on some real-life
workloads write through caching might perform better, than
write back one with the barrier protection turned on.
least no known one). Windows and, AFAIK, other UNIX'es don't
need any special explicit options and do necessary barrier
actions on write-back caching devices by default. Also note
that on some real-life workloads write through caching might
perform better, than write back one with the barrier
protection turned on.
Also you should realize that Linux doesn't provide a
guarantee that after sync()/fsync() all written data really
hit permanent storage, they can be then in the cache of your
backstorage device and lost on power failure event. Thus,
ever with write-through cache mode, you still need a good UPS
to protect yourself from your data loss (note, data loss, not
the file system integrity).
IMPORTANT: Some disk and partition table management utilities don't support
========= block sizes >512 bytes, therefore make sure that your favorite one
@@ -598,10 +608,10 @@ If you use SCST version taken directly from the SVN repository, you can
set the above options, except ALLOW_PASSTHROUGH_IO_SUBMIT_IN_SIRQ, using
debug2perf Makefile target.
4. For kernel:
4. For other target and initiator software parts:
- Don't enable debug/hacking features, i.e. use them as they are by
default.
- Don't enable debug/hacking features in the kernel, i.e. use them as
they are by default.
- The default kernel read-ahead and queuing settings are optimized
for locally attached disks, therefore they are not optimal if they
@@ -639,23 +649,31 @@ debug2perf Makefile target.
directory, they also affect performance. If you find the best values,
please share them with us.
- Use on the target deadline IO scheduler with read_expire and
write_expire increased on all exported devices to 5000 and 20000
correspondingly.
- On the target deadline IO scheduler with read_expire and
write_expire increased on all exported devices to 5000 and 15000
correspondingly used to be the fastest, but currently seems CFQ often
outperforms it. So, try on your load and use the best one.
- It is recommended to turn the kernel preemption off, i.e. set
the kernel preemption model to "No Forced Preemption (Server)".
5. For hardware.
- Looks like XFS is the best filesystem on the target to store device
files, because it allows considerably better linear write throughput,
than ext3.
- Make sure that your target hardware (e.g. target FC card) and underlaying
IO hardware (e.g. IO card, like SATA, SCSI or RAID to which your
disks connected) stay on different PCI buses. They have to work in
parallel, so it will be better if they don't compete for the bus. The
problem is not only in the bandwidth, which they have to share, but
also in the interaction between cards during that competition. In
some cases it could lead up to 5-10 times less performance, than
expected.
5. For hardware on target.
- Make sure that your target hardware (e.g. target FC or network card)
and underlaying IO hardware (e.g. IO card, like SATA, SCSI or RAID to
which your disks connected) don't share the same PCI bus. They have
to work in parallel, so it will be better if they don't compete for
the bus. The problem is not only in the bandwidth, which they have to
share, but also in the interaction between cards during that
competition. This is very important, because in some cases if target
and backend storage controllers share the same PCI bus, it could lead
up to 5-10 times less performance, than expected. If you have no
choice, but PCI bus sharing, set in the BIOS PCI latency as low as
possible.
IMPORTANT: If you use on initiator some versions of Windows (at least W2K)
========= you can't get good write performance for VDISK FILEIO devices with
+112 -66
View File
@@ -39,74 +39,92 @@
/* Version numbers, the same as for the kernel */
#define SCST_VERSION_CODE 0x000906
#define SCST_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
#define SCST_VERSION_STRING "0.9.6-pre3"
#define SCST_VERSION_STRING "0.9.6-rc1"
/*************************************************************
** States of command processing state machine
** States of command processing state machine. At first,
** "active" states, then - "passive" ones. This is to have
** more efficient generated code of the corresponding
** "switch" statements.
*************************************************************/
/* A cmd is created, but scst_cmd_init_done() not called */
#define SCST_CMD_STATE_INIT_WAIT 1
/* LUN translation (cmd->tgt_dev assignment) */
#define SCST_CMD_STATE_INIT 2
/* Internal parsing */
#define SCST_CMD_STATE_PRE_PARSE 0
/* Dev handler's parse() is going to be called */
#define SCST_CMD_STATE_DEV_PARSE 4
#define SCST_CMD_STATE_DEV_PARSE 1
/* Allocation of the cmd's data buffer */
#define SCST_CMD_STATE_PREPARE_SPACE 5
/* Allocation of the cmd's data buffer */
#define SCST_CMD_STATE_PREPROCESS_DONE 6
#define SCST_CMD_STATE_PREPARE_SPACE 2
/* Target driver's rdy_to_xfer() is going to be called */
#define SCST_CMD_STATE_RDY_TO_XFER 7
/* Waiting for data from the initiator (until scst_rx_data() called) */
#define SCST_CMD_STATE_DATA_WAIT 8
#define SCST_CMD_STATE_RDY_TO_XFER 3
/* Target driver's pre_exec() is going to be called */
#define SCST_CMD_STATE_PRE_EXEC 9
#define SCST_CMD_STATE_TGT_PRE_EXEC 4
/* CDB is going to be sent to SCSI mid-level for execution */
#define SCST_CMD_STATE_SEND_TO_MIDLEV 10
#define SCST_CMD_STATE_SEND_TO_MIDLEV 5
/* Waiting for CDB's execution finish */
#define SCST_CMD_STATE_EXECUTING 11
/* Internal pos-exec checks */
#define SCST_CMD_STATE_PRE_DEV_DONE 6
/* Internal MODE SELECT pages related checks */
#define SCST_CMD_STATE_MODE_SELECT_CHECKS 7
/* Dev handler's dev_done() is going to be called */
#define SCST_CMD_STATE_DEV_DONE 12
#define SCST_CMD_STATE_DEV_DONE 8
/* Target driver's xmit_response() is going to be called */
#define SCST_CMD_STATE_XMIT_RESP 13
#define SCST_CMD_STATE_PRE_XMIT_RESP 9
/* Waiting for response's transmission finish */
#define SCST_CMD_STATE_XMIT_WAIT 14
/* Target driver's xmit_response() is going to be called */
#define SCST_CMD_STATE_XMIT_RESP 10
/* The cmd finished */
#define SCST_CMD_STATE_FINISHED 15
#define SCST_CMD_STATE_FINISHED 11
#define SCST_CMD_STATE_LAST_ACTIVE (SCST_CMD_STATE_FINISHED+100)
/* A cmd is created, but scst_cmd_init_done() not called */
#define SCST_CMD_STATE_INIT_WAIT (SCST_CMD_STATE_LAST_ACTIVE+1)
/* LUN translation (cmd->tgt_dev assignment) */
#define SCST_CMD_STATE_INIT (SCST_CMD_STATE_LAST_ACTIVE+2)
/* Allocation of the cmd's data buffer */
#define SCST_CMD_STATE_PREPROCESS_DONE (SCST_CMD_STATE_LAST_ACTIVE+3)
/* Waiting for data from the initiator (until scst_rx_data() called) */
#define SCST_CMD_STATE_DATA_WAIT (SCST_CMD_STATE_LAST_ACTIVE+4)
/* Waiting for CDB's execution finish */
#define SCST_CMD_STATE_EXECUTING (SCST_CMD_STATE_LAST_ACTIVE+5)
/* Waiting for response's transmission finish */
#define SCST_CMD_STATE_XMIT_WAIT (SCST_CMD_STATE_LAST_ACTIVE+6)
/*************************************************************
** Can be retuned instead of cmd's state by dev handlers'
** functions, if the command's state should be set by default
* Can be retuned instead of cmd's state by dev handlers'
* functions, if the command's state should be set by default
*************************************************************/
#define SCST_CMD_STATE_DEFAULT 0
#define SCST_CMD_STATE_DEFAULT 500
/*************************************************************
** Can be retuned instead of cmd's state by dev handlers'
** functions, if it is impossible to complete requested
** task in atomic context. The cmd will be restarted in thread
** context.
* Can be retuned instead of cmd's state by dev handlers'
* functions, if it is impossible to complete requested
* task in atomic context. The cmd will be restarted in thread
* context.
*************************************************************/
#define SCST_CMD_STATE_NEED_THREAD_CTX 100
#define SCST_CMD_STATE_NEED_THREAD_CTX 1000
/*************************************************************
** Can be retuned instead of cmd's state by dev handlers'
** parse function, if the cmd processing should be stopped
** for now. The cmd will be restarted by dev handlers itself.
* Can be retuned instead of cmd's state by dev handlers'
* parse function, if the cmd processing should be stopped
* for now. The cmd will be restarted by dev handlers itself.
*************************************************************/
#define SCST_CMD_STATE_STOP 101
#define SCST_CMD_STATE_STOP 1001
/*************************************************************
** States of mgmt command processing state machine
@@ -206,6 +224,9 @@
*/
#define SCST_PREPROCESS_STATUS_ERROR_FATAL 3
/* Thread context requested */
#define SCST_PREPROCESS_STATUS_NEED_THREAD 4
/*************************************************************
** Allowed return codes for xmit_response(), rdy_to_xfer(),
** report_aen()
@@ -314,22 +335,8 @@
/* Set if no response should be sent to the target about this cmd */
#define SCST_CMD_NO_RESP 2
/*
* Set if the cmd is being executed. Needed to guarantee that
* "no further responses from the task are sent to
* the SCSI initiator port" after response from the TM function is
* sent (SAM) as well as correct ABORT TASK status code
*/
#define SCST_CMD_EXECUTING 3
/*
* Set if the cmd status/data are being xmitted. The purpose is the
* same as for SCST_CMD_EXECUTING
*/
#define SCST_CMD_XMITTING 4
/* Set if the cmd is dead and can be destroyed at any time */
#define SCST_CMD_CAN_BE_DESTROYED 5
#define SCST_CMD_CAN_BE_DESTROYED 3
/*************************************************************
** Tgt_dev's flags (tgt_dev_flags)
@@ -664,9 +671,6 @@ struct scst_dev_type
/* Set, if no /proc files should be automatically created by SCST */
unsigned no_proc:1;
/* Set if increment expected_sn in cmd->scst_cmd_done() */
unsigned inc_expected_sn_on_done:1;
/*
* Called to parse CDB from the cmd and initialize
* cmd->bufflen and cmd->data_direction (both - REQUIRED).
@@ -964,6 +968,9 @@ struct scst_cmd
*/
unsigned int sent_to_midlev:1;
/* Set if scst_local_exec() was already called for this cmd */
unsigned int local_exec_done:1;
/* Set if the cmd's action is completed */
unsigned int completed:1;
@@ -1058,9 +1065,6 @@ struct scst_cmd
/* Set if the cmd is deferred HEAD OF QUEUE */
unsigned int hq_deferred:1;
/* Set if the internal parse should be skipped */
unsigned int skip_parse:1;
/*
* Set if increment expected_sn in cmd->scst_cmd_done() (to save
* extra dereferences)
@@ -1074,14 +1078,17 @@ struct scst_cmd
unsigned long cmd_flags; /* cmd's async flags */
/* Keeps status of cmd's status/data delivery to remote initiator */
int delivery_status;
struct scst_tgt_template *tgtt; /* to save extra dereferences */
struct scst_tgt *tgt; /* to save extra dereferences */
struct scst_device *dev; /* to save extra dereferences */
lun_t lun; /* LUN for this cmd */
struct scst_tgt_dev *tgt_dev; /* corresponding device for this cmd */
lun_t lun; /* LUN for this cmd */
/* The corresponding mgmt cmd, if any, protected by sess_list_lock */
struct scst_mgmt_cmd *mgmt_cmnd;
@@ -1276,6 +1283,26 @@ struct scst_device
/**************************************************************/
/*************************************************************
** Dev's control mode page related values. Updates serialized
** by scst_block_dev(). It's long to not interfere with the
** above flags.
*************************************************************/
unsigned long queue_alg:4;
unsigned long tst:3;
unsigned long tas:1;
unsigned long swp:1;
/*
* Set if device implements own ordered commands management.
* Particularly, if set, expected_sn will be incremented immediately
* after exec() returned.
*/
unsigned long has_own_order_mgmt:1;
/**************************************************************/
spinlock_t dev_lock; /* device lock */
/*
@@ -1304,8 +1331,8 @@ struct scst_device
/* Used to wait for requested amount of "on_dev" commands */
wait_queue_head_t on_dev_waitQ;
/* A list entry used during RESETs, protected by scst_mutex */
struct list_head reset_dev_list_entry;
/* A list entry used during TM, protected by scst_mutex */
struct list_head tm_dev_list_entry;
/* Virtual device internal ID */
int virt_id;
@@ -1411,8 +1438,6 @@ struct scst_tgt_dev
/* internal tmp list entry */
struct list_head extra_tgt_dev_list_entry;
};
/*
@@ -1692,7 +1717,9 @@ void scst_rx_data(struct scst_cmd *cmd, int status, int pref_context);
/*
* Notifies SCST that the driver sent the response and the command
* can be freed now.
* can be freed now. Don't forget to set the delivery status, if it
* isn't success, using scst_set_delivery_status() before calling
* this function.
*/
void scst_tgt_cmd_done(struct scst_cmd *cmd);
@@ -2134,6 +2161,22 @@ static inline void scst_clear_may_need_dma_sync(struct scst_cmd *cmd)
cmd->may_need_dma_sync = 0;
}
/*
* Get/clear functions for cmd's delivery_status. It is one of
* SCST_CMD_DELIVERY_* constants, it specifies the status of the
* command's delivery to initiator.
*/
static inline int scst_get_delivery_status(struct scst_cmd *cmd)
{
return cmd->delivery_status;
}
static inline void scst_set_delivery_status(struct scst_cmd *cmd,
int delivery_status)
{
cmd->delivery_status = delivery_status;
}
/*
* Get/Set function for mgmt cmd's target private data
*/
@@ -2314,6 +2357,9 @@ struct proc_dir_entry *scst_create_proc_entry(struct proc_dir_entry * root,
int scst_add_cmd_threads(int num);
void scst_del_cmd_threads(int num);
void scst_set_sense(uint8_t *buffer, int len, int key,
int asc, int ascq);
void scst_set_cmd_error_sense(struct scst_cmd *cmd, uint8_t *sense,
unsigned int len);
@@ -2334,7 +2380,7 @@ void scst_set_resp_data_len(struct scst_cmd *cmd, int resp_data_len);
* Checks if total memory allocated by commands is less, than defined
* limit (scst_cur_max_cmd_mem) and returns 0, if it is so. Otherwise,
* returnes 1 and sets on cmd QUEUE FULL or BUSY status as well as
* SCST_CMD_STATE_XMIT_RESP state. Target drivers and dev handlers are
* SCST_CMD_STATE_PRE_XMIT_RESP state. Target drivers and dev handlers are
* required to call this function if they allocate data buffers on their
* own.
*/
+30 -3
View File
@@ -3,7 +3,7 @@
*
* Copyright (C) 2004-2007 Vladislav Bolkhovitin <vst@vlnb.net>
*
* Contains macroses for execution tracing and error reporting
* Contains common SCST constants.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -29,6 +29,13 @@
/* Max size of sense */
#define SCST_SENSE_BUFFERSIZE 96
/*************************************************************
** Allowed delivery statuses for cmd's delivery_status
*************************************************************/
#define SCST_CMD_DELIVERY_SUCCESS 0
#define SCST_CMD_DELIVERY_FAILED -1
/*************************************************************
** Values for task management functions
*************************************************************/
@@ -48,7 +55,7 @@
*/
#define SCST_NEXUS_LOSS_SESS 6
/* Aborts all tasks in the corresponding session with TASK_ABORTED status */
/* Aborts all tasks in the corresponding session */
#define SCST_ABORT_ALL_TASKS_SESS 7
/*
@@ -58,7 +65,7 @@
*/
#define SCST_NEXUS_LOSS 8
/* Aborts all tasks in all sessions of the tgt with TASK_ABORTED status */
/* Aborts all tasks in all sessions of the tgt */
#define SCST_ABORT_ALL_TASKS 9
/*************************************************************
@@ -100,6 +107,11 @@ enum scst_cmd_queue_type
#define SCST_NO_SENSE(sense) (((uint8_t *)(sense))[2] == 0)
static inline int scst_is_ua_sense(const uint8_t *sense)
{
return SCST_SENSE_VALID(sense) && (sense[2] == UNIT_ATTENTION);
}
/*************************************************************
** Sense data for the appropriate errors. Can be used with
** scst_set_cmd_error()
@@ -122,6 +134,9 @@ enum scst_cmd_queue_type
#define scst_sense_write_error MEDIUM_ERROR, 0x03, 0
#define scst_sense_not_ready NOT_READY, 0x04, 0x10
#define scst_sense_invalid_message ILLEGAL_REQUEST, 0x49, 0
#define scst_sense_cleared_by_another_ini_UA UNIT_ATTENTION, 0x2F, 0
#define SCST_STANDARD_SENSE_LEN 14
/*************************************************************
* SCSI opcodes not listed anywhere else
@@ -231,6 +246,18 @@ enum scst_cmd_queue_type
#define LONG_BIT 2
#define BT_BIT 1
/*************************************************************
** Values for the control mode page TST field
*************************************************************/
#define SCST_CONTR_MODE_ONE_TASK_SET 0
#define SCST_CONTR_MODE_SEP_TASK_SETS 1
/*******************************************************************
** Values for the control mode page QUEUE ALGORITHM MODIFIER field
*******************************************************************/
#define SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER 0
#define SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER 1
/*************************************************************
** Misc SCSI constants
*************************************************************/
+43 -38
View File
@@ -116,9 +116,10 @@
#define TRACE_OUT_OF_MEM 0x00000100
#define TRACE_MINOR 0x00000200 /* less important events */
#define TRACE_MGMT 0x00000400
#define TRACE_MGMT_DEBUG 0x00000800
#define TRACE_SCSI 0x00001000
#define TRACE_SPECIAL 0x00002000 /* filtering debug, etc */
#define TRACE_MGMT_MINOR 0x00000800
#define TRACE_MGMT_DEBUG 0x00001000
#define TRACE_SCSI 0x00002000
#define TRACE_SPECIAL 0x00004000 /* filtering debug, etc */
#define TRACE_ALL 0xffffffff
/* Flags 0xXXXX0000 are local for users */
@@ -151,26 +152,12 @@ do { \
} \
} while(0)
#define TRACE_LOG_FLAG(log_flag, trace, format, args...) \
do { \
char *__tflag = log_flag; \
if (trace_flag & (trace)) \
{ \
if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
__LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
} \
} \
PRINT(NO_FLAG, "%s" format, __tflag, args); \
} while(0)
#define TRACE_BUFFER(message, buff, len) \
do { \
if (trace_flag & TRACE_BUFF) \
{ \
char *__tflag = LOG_FLAG; \
if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
if (debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
__LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
@@ -185,7 +172,7 @@ do { \
if (trace_flag & (flag)) \
{ \
char *__tflag = LOG_FLAG; \
if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
if (debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
__LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
@@ -195,11 +182,18 @@ do { \
} \
} while(0)
#define PRINT_BUFFER(message, buff, len) \
do { \
PRINT(NO_FLAG, "%s:", message); \
debug_print_buffer(buff, len); \
} while(0)
#else /* DEBUG || TRACING */
#define TRACE(trace, args...) {}
#define TRACE_BUFFER(message, buff, len) {}
#define TRACE_BUFF_FLAG(flag, message, buff, len) {}
#define PRINT_BUFFER(message, buff, len) {}
#endif /* DEBUG || TRACING */
@@ -210,7 +204,7 @@ do { \
if (trace_flag & TRACE_MEMORY) \
{ \
char *__tflag = LOG_FLAG; \
if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
if (debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
__LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
@@ -224,7 +218,7 @@ do { \
if (trace_flag & TRACE_DEBUG) \
{ \
char *__tflag = LOG_FLAG; \
if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
if (debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
__LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
@@ -238,7 +232,7 @@ do { \
if (trace_flag & (TRACE_DEBUG|TRACE_SPECIAL)) \
{ \
char *__tflag = LOG_FLAG; \
if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
if (debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
__LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
@@ -252,7 +246,7 @@ do { \
if (trace_flag & TRACE_MGMT_DEBUG) \
{ \
char *__tflag = LOG_FLAG; \
if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
if (debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
__LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
@@ -266,7 +260,7 @@ do { \
if (trace_flag & (TRACE_MGMT_DEBUG|TRACE_SPECIAL)) \
{ \
char *__tflag = LOG_FLAG; \
if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
if (debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
__LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
@@ -275,22 +269,33 @@ do { \
} \
} while(0)
#define PRINT_ERROR(format, args...) \
do { \
if (ERROR_FLAG != LOG_FLAG) \
{ \
TRACE_LOG_FLAG(LOG_FLAG, trace_flag, "***ERROR*** " format, args); \
} \
TRACE_LOG_FLAG(ERROR_FLAG, trace_flag, "***ERROR*** " format, args); \
#define PRINT_LOG_FLAG(log_flag, format, args...) \
do { \
char *__tflag = log_flag; \
if (debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
__LINE__) > 0) \
{ \
__tflag = NO_FLAG; \
} \
PRINT(NO_FLAG, "%s" format, __tflag, args); \
} while(0)
#define PRINT_INFO(format, args...) \
do { \
if (INFO_FLAG != LOG_FLAG) \
{ \
TRACE_LOG_FLAG(LOG_FLAG, trace_flag, format, args); \
} \
TRACE_LOG_FLAG(INFO_FLAG, trace_flag, format, args); \
#define PRINT_ERROR(format, args...) \
do { \
if (ERROR_FLAG != LOG_FLAG) \
{ \
PRINT_LOG_FLAG(LOG_FLAG, "***ERROR*** " format, args); \
} \
PRINT_LOG_FLAG(ERROR_FLAG, "***ERROR*** " format, args); \
} while(0)
#define PRINT_INFO(format, args...) \
do { \
if (INFO_FLAG != LOG_FLAG) \
{ \
PRINT_LOG_FLAG(LOG_FLAG, format, args); \
} \
PRINT_LOG_FLAG(INFO_FLAG, format, args); \
} while(0)
#define TRACE_ENTRY() \
+13 -2
View File
@@ -3,7 +3,9 @@
*
* Copyright (C) 2007 Vladislav Bolkhovitin <vst@vlnb.net>
*
* Contains macroses for execution tracing and error reporting
* Contains constants and data structures for scst_user module.
* See http://scst.sourceforge.net/doc/scst_user_spec.txt or
* scst_user_spec.txt for description.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -23,7 +25,7 @@
#define DEV_USER_NAME "scst_user"
#define DEV_USER_PATH "/dev/"
#define DEV_USER_VERSION 961
#define DEV_USER_VERSION 962
/*
* Chosen so sizeof(scst_user_sess) <= sizeof(scst_user_scsi_cmd_exec)
@@ -91,6 +93,14 @@ struct scst_user_opt
uint8_t prio_queue_type;
uint8_t partial_transfers_type;
int32_t partial_len;
/* SCSI control mode page parameters, see SPC */
uint8_t tst;
uint8_t queue_alg;
uint8_t tas;
uint8_t swp;
uint8_t has_own_order_mgmt;
};
struct scst_user_dev_desc
@@ -170,6 +180,7 @@ struct scst_user_scsi_on_free_cmd
uint8_t buffer_cached;
uint8_t aborted;
uint8_t status;
uint8_t delivery_status;
};
struct scst_user_on_cached_mem_free
+2 -1
View File
@@ -18,6 +18,7 @@
*/
#include <linux/cdrom.h>
#include <scsi/scsi_host.h>
#define LOG_PREFIX "dev_cdrom"
@@ -210,7 +211,7 @@ int cdrom_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
scst_cdrom_generic_parse(cmd, info_cdb, cdrom_get_block_shift);
cmd->retries = 1;
cmd->retries = SCST_PASSTHROUGH_RETRIES;
if (info_cdb->flags & SCST_SMALL_TIMEOUT) {
cmd->timeout = CDROM_SMALL_TIMEOUT;
+3 -1
View File
@@ -17,6 +17,8 @@
* GNU General Public License for more details.
*/
#include <scsi/scsi_host.h>
#define LOG_PREFIX "dev_changer"
#include "scsi_tgt.h"
@@ -130,7 +132,7 @@ int changer_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
scst_changer_generic_parse(cmd, info_cdb, 0);
cmd->retries = 1;
cmd->retries = SCST_PASSTHROUGH_RETRIES;
if (info_cdb->flags & SCST_LONG_TIMEOUT) {
cmd->timeout = CHANGER_LONG_TIMEOUT;
+4 -2
View File
@@ -15,8 +15,8 @@
#ifdef DEBUG
#define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_PID | \
TRACE_LINE | TRACE_FUNCTION | TRACE_MGMT | TRACE_MINOR | \
TRACE_MGMT_DEBUG | TRACE_SPECIAL)
TRACE_LINE | TRACE_FUNCTION | TRACE_MGMT | TRACE_MGMT_MINOR | \
TRACE_MINOR | TRACE_MGMT_DEBUG | TRACE_SPECIAL)
#else
#define SCST_DEFAULT_DEV_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | \
TRACE_MINOR | TRACE_SPECIAL)
@@ -29,6 +29,8 @@ static unsigned long dh_trace_flag = SCST_DEFAULT_DEV_LOG_FLAGS;
#define trace_log_tbl NULL
#endif
#define SCST_PASSTHROUGH_RETRIES 0
static struct scst_proc_data dev_handler_log_proc_data;
static int dev_handler_log_info_show(struct seq_file *seq, void *v)
+2 -1
View File
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <scsi/scsi_host.h>
#define LOG_PREFIX "dev_disk"
@@ -282,7 +283,7 @@ int disk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
scst_sbc_generic_parse(cmd, info_cdb, disk_get_block_shift);
cmd->retries = 1;
cmd->retries = SCST_PASSTHROUGH_RETRIES;
if (info_cdb->flags & SCST_SMALL_TIMEOUT) {
cmd->timeout = DISK_SMALL_TIMEOUT;
+2 -1
View File
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <scsi/scsi_host.h>
#define LOG_PREFIX "dev_modisk"
@@ -297,7 +298,7 @@ int modisk_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
scst_modisk_generic_parse(cmd, info_cdb, modisk_get_block_shift);
cmd->retries = 1;
cmd->retries = SCST_PASSTHROUGH_RETRIES;
if (info_cdb->flags & SCST_SMALL_TIMEOUT) {
cmd->timeout = MODISK_SMALL_TIMEOUT;
+3 -1
View File
@@ -17,6 +17,8 @@
* GNU General Public License for more details.
*/
#include <scsi/scsi_host.h>
#define LOG_PREFIX "dev_processor"
#include "scsi_tgt.h"
@@ -130,7 +132,7 @@ int processor_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
scst_processor_generic_parse(cmd, info_cdb, 0);
cmd->retries = 1;
cmd->retries = SCST_PASSTHROUGH_RETRIES;
if (info_cdb->flags & SCST_LONG_TIMEOUT) {
cmd->timeout = PROCESSOR_LONG_TIMEOUT;
+5 -3
View File
@@ -19,6 +19,8 @@
#define LOG_PREFIX "dev_raid"
#include <scsi/scsi_host.h>
#include "scsi_tgt.h"
#include "scst_dev_handler.h"
@@ -30,9 +32,9 @@
parse_atomic: 1, \
/* dev_done_atomic: 1,*/ \
attach: raid_attach, \
/* detach: raid_detach,*/ \
/* detach: raid_detach,*/ \
parse: raid_parse, \
/* dev_done: raid_done*/ \
/* dev_done: raid_done*/ \
}
#define RAID_RETRIES 2
@@ -130,7 +132,7 @@ int raid_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
scst_raid_generic_parse(cmd, info_cdb, 0);
cmd->retries = 1;
cmd->retries = SCST_PASSTHROUGH_RETRIES;
if (info_cdb->flags & SCST_LONG_TIMEOUT) {
cmd->timeout = RAID_LONG_TIMEOUT;
+2 -1
View File
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <scsi/scsi_host.h>
#define LOG_PREFIX "dev_tape"
@@ -285,7 +286,7 @@ int tape_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
scst_tape_generic_parse(cmd, info_cdb, tape_get_block_size);
cmd->retries = 1;
cmd->retries = SCST_PASSTHROUGH_RETRIES;
if (info_cdb->flags & SCST_SMALL_TIMEOUT) {
cmd->timeout = TAPE_SMALL_TIMEOUT;
+61 -12
View File
@@ -59,6 +59,12 @@ struct scst_user_dev
unsigned short internal_reset_active:1;
unsigned short pre_unreg_sess_active:1; /* just a small optimization */
unsigned short tst:3;
unsigned short queue_alg:4;
unsigned short tas:1;
unsigned short swp:1;
unsigned short has_own_order_mgmt:1;
unsigned short detach_cmd_count;
int (*generic_parse)(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb,
@@ -82,6 +88,8 @@ struct scst_user_dev
unsigned int handle_counter;
struct list_head ucmd_hash[1<<DEV_USER_CMD_HASH_ORDER];
struct scst_device *sdev;
int virt_id;
struct list_head dev_list_entry;
char name[SCST_MAX_NAME];
@@ -552,6 +560,14 @@ static int dev_user_alloc_space(struct scst_user_cmd *ucmd)
TRACE_ENTRY();
if (unlikely(ucmd->cmd->data_buf_tgt_alloc)) {
PRINT_ERROR("Target driver %s requested own memory "
"allocation", ucmd->cmd->tgtt->name);
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
res = SCST_CMD_STATE_PRE_XMIT_RESP;
goto out;
}
ucmd->state = UCMD_STATE_BUF_ALLOCING;
cmd->data_buf_alloced = 1;
@@ -560,7 +576,7 @@ static int dev_user_alloc_space(struct scst_user_cmd *ucmd)
goto out;
else if (rc < 0) {
scst_set_busy(cmd);
res = SCST_CMD_STATE_XMIT_RESP;
res = SCST_CMD_STATE_PRE_XMIT_RESP;
goto out;
}
@@ -671,16 +687,14 @@ static int dev_user_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
rc = dev->generic_parse(cmd, info_cdb, dev_user_get_block);
if ((rc != 0) || (info_cdb->flags & SCST_INFO_INVALID))
goto out_invalid;
ucmd->cmd->skip_parse = 1;
break;
case SCST_USER_PARSE_EXCEPTION:
TRACE_DBG("PARSE EXCEPTION: ucmd %p", ucmd);
rc = dev->generic_parse(cmd, info_cdb, dev_user_get_block);
if ((rc == 0) && (!(info_cdb->flags & SCST_INFO_INVALID))) {
ucmd->cmd->skip_parse = 1;
if ((rc == 0) && (!(info_cdb->flags & SCST_INFO_INVALID)))
break;
} else if (rc == SCST_CMD_STATE_NEED_THREAD_CTX) {
else if (rc == SCST_CMD_STATE_NEED_THREAD_CTX) {
TRACE_MEM("Restarting PARSE to thread context "
"(ucmd %p)", ucmd);
res = SCST_CMD_STATE_NEED_THREAD_CTX;
@@ -691,7 +705,6 @@ static int dev_user_parse(struct scst_cmd *cmd, struct scst_info_cdb *info_cdb)
case SCST_USER_PARSE_CALL:
TRACE_DBG("Preparing PARSE for user space (ucmd=%p, h=%d, "
"bufflen %d)", ucmd, ucmd->h, cmd->bufflen);
ucmd->cmd->skip_parse = 1;
ucmd->user_cmd.cmd_h = ucmd->h;
ucmd->user_cmd.subcode = SCST_USER_PARSE;
ucmd->user_cmd.parse_cmd.sess_h = (unsigned long)cmd->tgt_dev;
@@ -733,7 +746,7 @@ out_invalid:
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode));
out_error:
res = SCST_CMD_STATE_XMIT_RESP;
res = SCST_CMD_STATE_PRE_XMIT_RESP;
goto out;
}
@@ -850,6 +863,7 @@ static void dev_user_on_free_cmd(struct scst_cmd *cmd)
ucmd->user_cmd.on_free_cmd.buffer_cached = ucmd->buff_cached;
ucmd->user_cmd.on_free_cmd.aborted = ucmd->aborted;
ucmd->user_cmd.on_free_cmd.status = cmd->status;
ucmd->user_cmd.on_free_cmd.delivery_status = cmd->delivery_status;
ucmd->state = UCMD_STATE_ON_FREEING;
@@ -1043,7 +1057,7 @@ out_nomem:
/* go through */
out_err:
ucmd->cmd->state = SCST_CMD_STATE_XMIT_RESP;
ucmd->cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
goto out;
out_unmap:
@@ -1084,7 +1098,7 @@ static int dev_user_process_reply_alloc(struct scst_user_cmd *ucmd,
res = dev_user_map_buf(ucmd, reply->alloc_reply.pbuf, pages);
} else {
scst_set_busy(ucmd->cmd);
ucmd->cmd->state = SCST_CMD_STATE_XMIT_RESP;
ucmd->cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP;
}
out_process:
@@ -1868,7 +1882,6 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
if (test_bit(SCST_CMD_ABORTED, &ucmd->cmd->cmd_flags))
ucmd->aborted = 1;
else {
ucmd->cmd->completed = 1;
if (busy)
scst_set_busy(ucmd->cmd);
else
@@ -2202,8 +2215,14 @@ static int dev_user_attach(struct scst_device *sdev)
}
sdev->p_cmd_lists = &dev->cmd_lists;
sdev->dh_priv = dev;
sdev->tst = dev->tst;
sdev->queue_alg = dev->queue_alg;
sdev->swp = dev->swp;
sdev->tas = dev->tas;
sdev->has_own_order_mgmt = dev->has_own_order_mgmt;
dev->sdev = sdev;
PRINT_INFO("Attached user space SCSI target virtual device \"%s\"",
dev->name);
@@ -2226,6 +2245,7 @@ static void dev_user_detach(struct scst_device *sdev)
/* dev will be freed by the caller */
sdev->dh_priv = NULL;
dev->sdev = NULL;
TRACE_EXIT();
return;
@@ -2610,7 +2630,6 @@ static int dev_user_register_dev(struct file *file,
dev->devtype.exec_atomic = 0; /* no point to make it 1 */
dev->devtype.dev_done_atomic = 1;
dev->devtype.no_proc = 1;
dev->devtype.inc_expected_sn_on_done = 1;
dev->devtype.attach = dev_user_attach;
dev->devtype.detach = dev_user_detach;
dev->devtype.attach_tgt = dev_user_attach_tgt;
@@ -2714,6 +2733,18 @@ static int __dev_user_set_opt(struct scst_user_dev *dev,
goto out;
}
if (((opt->tst != SCST_CONTR_MODE_ONE_TASK_SET) &&
(opt->tst != SCST_CONTR_MODE_SEP_TASK_SETS)) ||
((opt->queue_alg != SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER) &&
(opt->queue_alg != SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER)) ||
(opt->swp > 1) || (opt->tas > 1) || (opt->has_own_order_mgmt > 1)) {
PRINT_ERROR("Invalid SCSI option (tst %x, queue_alg %x, swp %x, "
"tas %x, has_own_order_mgmt %x)", opt->tst,
opt->queue_alg, opt->swp, opt->tas, opt->has_own_order_mgmt);
res = -EINVAL;
goto out;
}
if ((dev->prio_queue_type != opt->prio_queue_type) &&
(opt->prio_queue_type == SCST_USER_PRIO_QUEUE_SINGLE)) {
struct scst_user_cmd *u, *t;
@@ -2732,6 +2763,19 @@ static int __dev_user_set_opt(struct scst_user_dev *dev,
dev->partial_transfers_type = opt->partial_transfers_type;
dev->partial_len = opt->partial_len;
dev->tst = opt->tst;
dev->queue_alg = opt->queue_alg;
dev->swp = opt->swp;
dev->tas = opt->tas;
dev->has_own_order_mgmt = opt->has_own_order_mgmt;
if (dev->sdev != NULL) {
dev->sdev->tst = opt->tst;
dev->sdev->queue_alg = opt->queue_alg;
dev->sdev->swp = opt->swp;
dev->sdev->tas = opt->tas;
dev->sdev->has_own_order_mgmt = opt->has_own_order_mgmt;
}
dev_user_setup_functions(dev);
out:
@@ -2791,6 +2835,11 @@ static int dev_user_get_opt(struct file *file, void *arg)
opt.prio_queue_type = dev->prio_queue_type;
opt.partial_transfers_type = dev->partial_transfers_type;
opt.partial_len = dev->partial_len;
opt.tst = dev->tst;
opt.queue_alg = dev->queue_alg;
opt.tas = dev->tas;
opt.swp = dev->swp;
opt.has_own_order_mgmt = dev->has_own_order_mgmt;
TRACE_DBG("parse_type %x, on_free_cmd_type %x, memory_reuse_type %x, "
"partial_transfers_type %x, partial_len %d", opt.parse_type,
+133 -11
View File
@@ -88,6 +88,16 @@ static struct scst_proc_log vdisk_proc_local_trace_tbl[] =
#define VDISK_NAME "vdisk"
#define VCDROM_NAME "vcdrom"
#define DEF_TST SCST_CONTR_MODE_SEP_TASK_SETS
/*
* Since we can't control backstorage device's reordering, we have to always
* report unrestricted reordering.
*/
#define DEF_QUEUE_ALG_WT SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER
#define DEF_QUEUE_ALG SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER
#define DEF_SWP 0
#define DEF_TAS 0
#define VDISK_PROC_HELP "help"
static unsigned int random_values[256] = {
@@ -188,7 +198,8 @@ struct scst_vdisk_dev {
struct scst_vdisk_tgt_dev {
/*
* Used without locking since SCST core ensures that only commands
* of the same type per tgt_dev can be processed simultaneously
* with the same ORDERED type per tgt_dev can be processed
* simultaneously.
*/
enum scst_cmd_queue_type last_write_cmd_queue_type;
};
@@ -223,6 +234,7 @@ static void vdisk_exec_verify(struct scst_cmd *cmd,
static void vdisk_exec_read_capacity(struct scst_cmd *cmd);
static void vdisk_exec_read_capacity16(struct scst_cmd *cmd);
static void vdisk_exec_inquiry(struct scst_cmd *cmd);
static void vdisk_exec_request_sense(struct scst_cmd *cmd);
static void vdisk_exec_mode_sense(struct scst_cmd *cmd);
static void vdisk_exec_mode_select(struct scst_cmd *cmd);
static void vdisk_exec_log(struct scst_cmd *cmd);
@@ -236,6 +248,8 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset,
static int vcdrom_read_proc(struct seq_file *seq, struct scst_dev_type *dev_type);
static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_dev_type *dev_type);
static int vdisk_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev);
#define VDISK_TYPE { \
name: VDISK_NAME, \
@@ -252,6 +266,7 @@ static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
exec: vdisk_do_job, \
read_proc: vdisk_read_proc, \
write_proc: vdisk_write_proc, \
task_mgmt_fn: vdisk_task_mgmt_fn, \
}
#define VDISK_BLK_TYPE { \
@@ -262,13 +277,13 @@ static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
exec_atomic: 0, \
dev_done_atomic: 1, \
no_proc: 1, \
inc_expected_sn_on_done: 1, \
attach: vdisk_attach, \
detach: vdisk_detach, \
attach_tgt: vdisk_attach_tgt, \
detach_tgt: vdisk_detach_tgt, \
parse: vdisk_parse, \
exec: vdisk_do_job, \
task_mgmt_fn: vdisk_task_mgmt_fn, \
}
#define VCDROM_TYPE { \
@@ -286,6 +301,7 @@ static int vcdrom_write_proc(char *buffer, char **start, off_t offset,
exec: vcdrom_exec, \
read_proc: vcdrom_read_proc, \
write_proc: vcdrom_write_proc, \
task_mgmt_fn: vdisk_task_mgmt_fn, \
}
static DEFINE_MUTEX(scst_vdisk_mutex);
@@ -469,6 +485,14 @@ static int vdisk_attach(struct scst_device *dev)
dev->dh_priv = virt_dev;
dev->tst = DEF_TST;
if (virt_dev->wt_flag)
dev->queue_alg = DEF_QUEUE_ALG_WT;
else
dev->queue_alg = DEF_QUEUE_ALG;
dev->swp = DEF_SWP;
dev->tas = DEF_TAS;
out:
TRACE_EXIT();
return res;
@@ -823,7 +847,7 @@ static int vdisk_do_job(struct scst_cmd *cmd)
/* ToDo: BLOCKIO VERIFY */
vdisk_exec_write(cmd, thr, loff);
/* O_SYNC flag is used for WT devices */
if (cmd->status == 0)
if (scsi_status_is_good(cmd->status))
vdisk_exec_verify(cmd, thr, loff);
else if (do_fsync)
vdisk_fsync(thr, loff, data_len, cmd);
@@ -890,6 +914,9 @@ static int vdisk_do_job(struct scst_cmd *cmd)
case INQUIRY:
vdisk_exec_inquiry(cmd);
break;
case REQUEST_SENSE:
vdisk_exec_request_sense(cmd);
break;
case READ_CAPACITY:
vdisk_exec_read_capacity(cmd);
break;
@@ -989,7 +1016,7 @@ static int vcdrom_exec(struct scst_cmd *cmd)
TRACE_DBG("%s", "CDROM empty");
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_not_ready));
goto out_complete;
goto out_done;
}
if (virt_dev->media_changed && (cmd->cdb[0] != INQUIRY) &&
@@ -1001,7 +1028,7 @@ static int vcdrom_exec(struct scst_cmd *cmd)
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_medium_changed_UA));
spin_unlock(&virt_dev->flags_lock);
goto out_complete;
goto out_done;
}
spin_unlock(&virt_dev->flags_lock);
}
@@ -1012,8 +1039,7 @@ out:
TRACE_EXIT();
return SCST_EXEC_COMPLETED;
out_complete:
cmd->completed = 1;
out_done:
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT);
goto out;
}
@@ -1193,6 +1219,36 @@ out:
return;
}
static void vdisk_exec_request_sense(struct scst_cmd *cmd)
{
int32_t length;
uint8_t *address;
TRACE_ENTRY();
length = scst_get_buf_first(cmd, &address);
TRACE_DBG("length %d", length);
if (unlikely(length < SCST_STANDARD_SENSE_LEN)) {
PRINT_ERROR("scst_get_buf_first() failed or too small "
"requested buffer (returned %d)", length);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_invalid_field_in_parm_list));
if (length > 0)
goto out_put;
else
goto out;
}
scst_set_sense(address, length, SCST_LOAD_SENSE(scst_sense_no_sense));
out_put:
scst_put_buf(cmd, address);
out:
TRACE_EXIT();
return;
}
/*
* <<Following mode pages info copied from ST318451LW with some corrections>>
*
@@ -1256,14 +1312,38 @@ static int vdisk_caching_pg(unsigned char *p, int pcontrol,
static int vdisk_ctrl_m_pg(unsigned char *p, int pcontrol,
struct scst_vdisk_dev *virt_dev)
{ /* Control mode page for mode_sense */
const unsigned char ctrl_m_pg[] = {0xa, 0xa, 0x20, 0, 0, 0x40, 0, 0,
const unsigned char ctrl_m_pg[] = {0xa, 0xa, 0, 0, 0, 0, 0, 0,
0, 0, 0x2, 0x4b};
memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
if (!virt_dev->wt_flag && !virt_dev->nv_cache)
p[3] |= 0x10; /* Enable unrestricted reordering */
if (1 == pcontrol)
switch(pcontrol) {
case 0:
p[2] |= virt_dev->dev->tst << 5;
p[3] |= virt_dev->dev->queue_alg << 4;
p[4] |= virt_dev->dev->swp << 3;
p[5] |= virt_dev->dev->tas << 6;
break;
case 1:
memset(p + 2, 0, sizeof(ctrl_m_pg) - 2);
#if 0 /* Too early, see corresponding comment in vdisk_exec_mode_select() */
p[2] |= 7 << 5;
p[3] |= 0xF << 4;
p[4] |= 1 << 3;
p[5] |= 1 << 6;
#endif
break;
case 2:
p[2] |= DEF_TST << 5;
if (virt_dev->wt_flag)
p[3] |= DEF_QUEUE_ALG_WT << 4;
else
p[3] |= DEF_QUEUE_ALG << 4;
p[4] |= DEF_SWP << 3;
p[5] |= DEF_TAS << 6;
break;
default:
sBUG();
}
return sizeof(ctrl_m_pg);
}
@@ -1519,6 +1599,25 @@ static void vdisk_exec_mode_select(struct scst_cmd *cmd)
goto out_put;
}
break;
#if 0 /*
* It's too early to implement it, since we can't control the backstorage
* device parameters. ToDo
*/
} else if ((address[offset] & 0x3f) == 0xA) { /* Control page */
if (address[offset + 1] != 0xA) {
PRINT_ERROR("%s", "MODE SELECT: Invalid "
"control page request");
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(
scst_sense_invalid_field_in_parm_list));
goto out_put;
}
#endif
} else {
PRINT_ERROR("MODE SELECT: Invalid request %x",
address[offset] & 0x3f);
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(
scst_sense_invalid_field_in_parm_list));
goto out_put;
}
offset += address[offset + 1];
}
@@ -2366,6 +2465,29 @@ out:
return dev;
}
static int vdisk_task_mgmt_fn(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev)
{
TRACE_ENTRY();
if ((mcmd->fn == SCST_LUN_RESET) || (mcmd->fn == SCST_TARGET_RESET)) {
/* Restore default values */
struct scst_device *dev = tgt_dev->dev;
struct scst_vdisk_dev *virt_dev =
(struct scst_vdisk_dev *)dev->dh_priv;
dev->tst = DEF_TST;
if (virt_dev->wt_flag)
dev->queue_alg = DEF_QUEUE_ALG_WT;
else
dev->queue_alg = DEF_QUEUE_ALG;
dev->swp = DEF_SWP;
dev->tas = DEF_TAS;
}
TRACE_EXIT();
return SCST_DEV_TM_NOT_COMPLETED;
}
/*
* Called when a file in the /proc/VDISK_NAME/VDISK_NAME is read
*/
+323 -93
View File
@@ -38,6 +38,8 @@
#include "scst_cdbprobe.h"
static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev);
int scst_check_internal_sense(struct scst_device *dev, int result,
uint8_t *sense, int sense_len);
void scst_set_cmd_error_status(struct scst_cmd *cmd, int status)
{
@@ -50,6 +52,8 @@ void scst_set_cmd_error_status(struct scst_cmd *cmd, int status)
cmd->tgt_resp_flags = SCST_TSC_FLAG_STATUS;
cmd->resp_data_len = 0;
cmd->completed = 1;
TRACE_EXIT();
return;
}
@@ -67,6 +71,19 @@ void scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq)
return;
}
void scst_set_sense(uint8_t *buffer, int len, int key,
int asc, int ascq)
{
memset(buffer, 0, len);
buffer[0] = 0x70; /* Error Code */
buffer[2] = key; /* Sense Key */
buffer[7] = 0x0a; /* Additional Sense Length */
buffer[12] = asc; /* ASC */
buffer[13] = ascq; /* ASCQ */
TRACE_BUFFER("Sense set", buffer, len);
return;
}
void scst_set_cmd_error_sense(struct scst_cmd *cmd, uint8_t *sense,
unsigned int len)
{
@@ -91,15 +108,15 @@ void scst_set_busy(struct scst_cmd *cmd)
if ((c <= 1) || (cmd->sess->init_phase != SCST_SESS_IPH_READY)) {
scst_set_cmd_error_status(cmd, SAM_STAT_BUSY);
TRACE_MGMT_DBG("Sending BUSY status to initiator %s "
TRACE(TRACE_MGMT_MINOR, "Sending BUSY status to initiator %s "
"(cmds count %d, queue_type %x, sess->init_phase %d)",
cmd->sess->initiator_name, c,
cmd->queue_type, cmd->sess->init_phase);
} else {
scst_set_cmd_error_status(cmd, SAM_STAT_TASK_SET_FULL);
TRACE_MGMT_DBG("Sending QUEUE_FULL status to initiator %s "
"(cmds count %d, queue_type %x, sess->init_phase %d)",
cmd->sess->initiator_name, c,
TRACE(TRACE_MGMT_MINOR, "Sending QUEUE_FULL status to "
"initiator %s (cmds count %d, queue_type %x, "
"sess->init_phase %d)", cmd->sess->initiator_name, c,
cmd->queue_type, cmd->sess->init_phase);
}
@@ -297,9 +314,8 @@ int scst_destroy_acg(struct scst_acg *acg)
{
struct scst_tgt_dev *tgt_dev, *tt;
list_for_each_entry_safe(tgt_dev, tt,
&acg_dev->dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry)
{
&acg_dev->dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry) {
if (tgt_dev->acg_dev == acg_dev)
scst_free_tgt_dev(tgt_dev);
}
@@ -436,7 +452,7 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess,
spin_lock_bh(&scst_temp_UA_lock);
scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
SCST_LOAD_SENSE(scst_sense_reset_UA));
scst_alloc_set_UA(tgt_dev, scst_temp_UA, sizeof(scst_temp_UA));
scst_alloc_set_UA(tgt_dev, scst_temp_UA, sizeof(scst_temp_UA), 0);
spin_unlock_bh(&scst_temp_UA_lock);
tm_dbg_init_tgt_dev(tgt_dev, acg_dev);
@@ -489,42 +505,31 @@ out_free:
goto out;
}
static void scst_send_release(struct scst_tgt_dev *tgt_dev);
static void scst_clear_reservation(struct scst_tgt_dev *tgt_dev);
/*
* No locks supposed to be held, scst_mutex - held.
* The activity is suspended.
*/
void scst_reset_tgt_dev(struct scst_tgt_dev *tgt_dev, int nexus_loss)
void scst_nexus_loss(struct scst_tgt_dev *tgt_dev)
{
struct scst_device *dev = tgt_dev->dev;
TRACE_ENTRY();
if (dev->dev_reserved &&
!test_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags))
{
/* This is one who holds the reservation */
struct scst_tgt_dev *tgt_dev_tmp;
list_for_each_entry(tgt_dev_tmp, &dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry)
{
clear_bit(SCST_TGT_DEV_RESERVED,
&tgt_dev_tmp->tgt_dev_flags);
}
dev->dev_reserved = 0;
scst_clear_reservation(tgt_dev);
scst_send_release(tgt_dev);
}
/* With activity suspended the lock isn't needed, but let's be safe */
spin_lock_bh(&tgt_dev->tgt_dev_lock);
scst_free_all_UA(tgt_dev);
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
spin_lock_bh(&scst_temp_UA_lock);
if (nexus_loss) {
scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
SCST_LOAD_SENSE(scst_sense_nexus_loss_UA));
} else {
scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
SCST_LOAD_SENSE(scst_sense_reset_UA));
}
scst_check_set_UA(tgt_dev, scst_temp_UA, sizeof(scst_temp_UA));
scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
SCST_LOAD_SENSE(scst_sense_nexus_loss_UA));
scst_check_set_UA(tgt_dev, scst_temp_UA, sizeof(scst_temp_UA), 0);
spin_unlock_bh(&scst_temp_UA_lock);
TRACE_EXIT();
return;
}
/*
@@ -543,7 +548,7 @@ static void scst_free_tgt_dev(struct scst_tgt_dev *tgt_dev)
list_del(&tgt_dev->dev_tgt_dev_list_entry);
list_del(&tgt_dev->sess_tgt_dev_list_entry);
scst_reset_tgt_dev(tgt_dev, 0);
scst_clear_reservation(tgt_dev);
scst_free_all_UA(tgt_dev);
if (dev->handler && dev->handler->detach_tgt) {
@@ -713,8 +718,7 @@ int scst_acg_remove_dev(struct scst_acg *acg, struct scst_device *dev)
}
list_for_each_entry_safe(tgt_dev, tt, &dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry)
{
dev_tgt_dev_list_entry) {
if (tgt_dev->acg_dev == acg_dev)
scst_free_tgt_dev(tgt_dev);
}
@@ -882,7 +886,7 @@ int scst_prepare_request_sense(struct scst_cmd *orig_cmd)
rs_cmd->cdb_len = sizeof(request_sense);
rs_cmd->data_direction = SCST_DATA_READ;
TRACE(TRACE_RETRY, "Adding REQUEST SENSE cmd %p to head of active "
TRACE(TRACE_MGMT_MINOR, "Adding REQUEST SENSE cmd %p to head of active "
"cmd list ", rs_cmd);
spin_lock_irq(&rs_cmd->cmd_lists->cmd_list_lock);
list_add(&rs_cmd->cmd_list_entry, &rs_cmd->cmd_lists->active_cmd_list);
@@ -919,8 +923,8 @@ struct scst_cmd *scst_complete_request_sense(struct scst_cmd *cmd)
len = scst_get_buf_first(cmd, &buf);
if ((cmd->status == 0) && (len > 0) && SCST_SENSE_VALID(buf) &&
(!SCST_NO_SENSE(buf)))
if (scsi_status_is_good(cmd->status) && (len > 0) &&
SCST_SENSE_VALID(buf) && (!SCST_NO_SENSE(buf)))
{
TRACE_BUFF_FLAG(TRACE_SCSI, "REQUEST SENSE returned",
buf, len);
@@ -930,7 +934,8 @@ struct scst_cmd *scst_complete_request_sense(struct scst_cmd *cmd)
} else {
PRINT_ERROR("%s", "Unable to get the sense via "
"REQUEST SENSE, returning HARDWARE ERROR");
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
scst_set_cmd_error(orig_cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
}
if (len > 0)
@@ -1011,7 +1016,7 @@ static void scst_send_release(struct scst_tgt_dev *tgt_dev)
struct scsi_device *scsi_dev;
unsigned char cdb[6];
unsigned char *sense;
int rc;
int rc, i;
TRACE_ENTRY();
@@ -1019,25 +1024,36 @@ static void scst_send_release(struct scst_tgt_dev *tgt_dev)
goto out;
/* We can't afford missing RELEASE due to memory shortage */
sense = kzalloc(SCST_SENSE_BUFFERSIZE, GFP_KERNEL|__GFP_NOFAIL);
sense = kmalloc(SCST_SENSE_BUFFERSIZE, GFP_KERNEL|__GFP_NOFAIL);
scsi_dev = tgt_dev->dev->scsi_dev;
memset(cdb, 0, sizeof(cdb));
cdb[0] = RELEASE;
cdb[1] = (scsi_dev->scsi_level <= SCSI_2) ?
((scsi_dev->lun << 5) & 0xe0) : 0;
for(i = 0; i < 5; i++) {
memset(cdb, 0, sizeof(cdb));
cdb[0] = RELEASE;
cdb[1] = (scsi_dev->scsi_level <= SCSI_2) ?
((scsi_dev->lun << 5) & 0xe0) : 0;
TRACE(TRACE_DEBUG | TRACE_SCSI, "%s", "Sending RELEASE req to SCSI "
"mid-level");
rc = scsi_execute(scsi_dev, cdb, SCST_DATA_NONE, NULL, 0,
sense, SCST_DEFAULT_TIMEOUT, 3, GFP_KERNEL);
if (rc) {
PRINT_INFO("scsi_execute() failed: %d", rc);
goto out_free;
memset(sense, 0, SCST_SENSE_BUFFERSIZE);
TRACE(TRACE_DEBUG | TRACE_SCSI, "%s", "Sending RELEASE req to "
"SCSI mid-level");
rc = scsi_execute(scsi_dev, cdb, SCST_DATA_NONE, NULL, 0,
sense, SCST_DEFAULT_TIMEOUT, 0, GFP_KERNEL);
TRACE_DBG("MODE_SENSE done: %x", rc);
if (scsi_status_is_good(rc)) {
break;
} else {
PRINT_ERROR("RELEASE failed: %d", rc);
TRACE_BUFFER("RELEASE sense", sense,
SCST_SENSE_BUFFERSIZE);
if (scst_check_internal_sense(tgt_dev->dev, rc,
sense, SCST_SENSE_BUFFERSIZE) != 0)
break;
}
}
out_free:
kfree(sense);
out:
@@ -1046,6 +1062,31 @@ out:
}
#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) */
static void scst_clear_reservation(struct scst_tgt_dev *tgt_dev)
{
struct scst_device *dev = tgt_dev->dev;
TRACE_ENTRY();
if (dev->dev_reserved &&
!test_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags))
{
/* This is one who holds the reservation */
struct scst_tgt_dev *tgt_dev_tmp;
list_for_each_entry(tgt_dev_tmp, &dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry) {
clear_bit(SCST_TGT_DEV_RESERVED,
&tgt_dev_tmp->tgt_dev_flags);
}
dev->dev_reserved = 0;
scst_send_release(tgt_dev);
}
TRACE_EXIT();
return;
}
struct scst_session *scst_alloc_session(struct scst_tgt *tgt, int gfp_mask,
const char *initiator_name)
{
@@ -1190,11 +1231,12 @@ struct scst_cmd *scst_alloc_cmd(int gfp_mask)
memset(cmd, 0, sizeof(*cmd));
#endif
cmd->state = SCST_CMD_STATE_INIT_WAIT;
atomic_set(&cmd->cmd_ref, 1);
cmd->cmd_lists = &scst_main_cmd_lists;
cmd->queue_type = SCST_CMD_QUEUE_SIMPLE;
cmd->timeout = SCST_DEFAULT_TIMEOUT;
cmd->retries = 1;
cmd->retries = 0;
cmd->data_len = -1;
cmd->tgt_resp_flags = SCST_TSC_FLAG_STATUS;
cmd->resp_data_len = -1;
@@ -2191,6 +2233,101 @@ out:
return res;
}
int scst_check_internal_sense(struct scst_device *dev, int result,
uint8_t *sense, int sense_len)
{
TRACE_ENTRY();
if (host_byte(result) == DID_RESET) {
scst_set_sense(sense, sense_len,
SCST_LOAD_SENSE(scst_sense_reset_UA));
scst_dev_check_set_UA(dev, NULL, sense, sense_len);
} else if (SCST_SENSE_VALID(sense) && scst_is_ua_sense(sense))
scst_dev_check_set_UA(dev, NULL, sense, sense_len);
TRACE_EXIT();
return 0;
}
int scst_obtain_device_parameters(struct scst_device *dev)
{
int res = 0, i;
uint8_t cmd[16];
uint8_t buffer[4+0x0A];
uint8_t sense_buffer[SCST_SENSE_BUFFERSIZE];
TRACE_ENTRY();
sBUG_ON(in_interrupt() || in_atomic());
EXTRACHECKS_BUG_ON(dev->scsi_dev == NULL);
for(i = 0; i < 5; i++) {
/* Get control mode page */
memset(cmd, 0, sizeof(cmd));
cmd[0] = MODE_SENSE;
cmd[1] = 8; /* DBD */
cmd[2] = 0x0A;
cmd[4] = sizeof(buffer);
memset(buffer, 0, sizeof(buffer));
memset(sense_buffer, 0, sizeof(sense_buffer));
TRACE_DBG("%s", "Doing MODE_SENSE");
res = scsi_execute(dev->scsi_dev, cmd, SCST_DATA_READ, buffer,
sizeof(buffer), sense_buffer, SCST_DEFAULT_TIMEOUT,
0, GFP_KERNEL);
TRACE_DBG("MODE_SENSE done: %x", res);
if (scsi_status_is_good(res)) {
int q;
TRACE_BUFFER("Returned control mode page data", buffer,
sizeof(buffer));
dev->tst = buffer[4+2] >> 5;
q = buffer[4+3] >> 4;
if (q > SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER) {
PRINT_ERROR("Too big QUEUE ALG %x, dev "
"%d:%d:%d:%d", dev->queue_alg,
dev->scsi_dev->host->host_no, dev->scsi_dev->channel,
dev->scsi_dev->id, dev->scsi_dev->lun);
}
dev->queue_alg = q;
dev->swp = (buffer[4+4] & 0x8) >> 3;
dev->tas = (buffer[4+5] & 0x40) >> 6;
/*
* Unfortunately, SCSI ML doesn't provide a way to
* specify commands task attribute, so we can rely on
* device's restricted reordering only.
*/
dev->has_own_order_mgmt = !dev->queue_alg;
TRACE(TRACE_MGMT_MINOR, "Device %d:%d:%d:%d: TST %x, "
"QUEUE ALG %x, SWP %x, TAS %x, has_own_order_mgmt "
"%d", dev->scsi_dev->host->host_no,
dev->scsi_dev->channel, dev->scsi_dev->id,
dev->scsi_dev->lun, dev->tst, dev->queue_alg,
dev->swp, dev->tas, dev->has_own_order_mgmt);
goto out;
} else {
PRINT_ERROR("Internal MODE_SENSE failed: %d", res);
TRACE_BUFFER("MODE_SENSE sense", sense_buffer,
sizeof(sense_buffer));
if (scst_check_internal_sense(dev, res, sense_buffer,
sizeof(sense_buffer)) != 0)
break;
}
}
res = -ENODEV;
out:
TRACE_EXIT_RES(res);
return res;
}
/* Called under dev_lock and BH off */
void scst_process_reset(struct scst_device *dev,
struct scst_session *originator, struct scst_cmd *exclude_cmd,
@@ -2205,8 +2342,7 @@ void scst_process_reset(struct scst_device *dev,
if (dev->dev_reserved) {
/* Either scst_mutex held or exclude_cmd non-NULL */
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry)
{
dev_tgt_dev_list_entry) {
TRACE(TRACE_MGMT, "Clearing RESERVE'ation for tgt_dev "
"lun %Ld", tgt_dev->lun);
clear_bit(SCST_TGT_DEV_RESERVED,
@@ -2215,26 +2351,22 @@ void scst_process_reset(struct scst_device *dev,
dev->dev_reserved = 0;
/*
* There is no need to send RELEASE, since the device is going
* to be resetted
* to be resetted. Actually, since we can be in RESET TM
* function, it might be dangerous.
*/
}
dev->dev_double_ua_possible = 1;
dev->dev_serialized = 1;
/* BH already off */
spin_lock(&scst_temp_UA_lock);
scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
SCST_LOAD_SENSE(scst_sense_reset_UA));
__scst_process_UA(dev, exclude_cmd, scst_temp_UA, sizeof(scst_temp_UA),
1);
spin_unlock(&scst_temp_UA_lock);
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry)
{
dev_tgt_dev_list_entry) {
struct scst_session *sess = tgt_dev->sess;
spin_lock_bh(&tgt_dev->tgt_dev_lock);
scst_free_all_UA(tgt_dev);
spin_unlock_bh(&tgt_dev->tgt_dev_lock);
spin_lock_irq(&sess->sess_list_lock);
TRACE_DBG("Searching in search cmd list (sess=%p)", sess);
@@ -2245,8 +2377,8 @@ void scst_process_reset(struct scst_device *dev,
if ((cmd->tgt_dev == tgt_dev) ||
((cmd->tgt_dev == NULL) &&
(cmd->lun == tgt_dev->lun))) {
scst_abort_cmd(cmd, mcmd,
(tgt_dev->sess != originator), 0);
scst_abort_cmd(cmd, mcmd,
(tgt_dev->sess != originator), 0);
}
}
spin_unlock_irq(&sess->sess_list_lock);
@@ -2266,6 +2398,14 @@ void scst_process_reset(struct scst_device *dev,
}
}
/* BH already off */
spin_lock(&scst_temp_UA_lock);
scst_set_sense(scst_temp_UA, sizeof(scst_temp_UA),
SCST_LOAD_SENSE(scst_sense_reset_UA));
scst_dev_check_set_local_UA(dev, exclude_cmd, scst_temp_UA,
sizeof(scst_temp_UA));
spin_unlock(&scst_temp_UA_lock);
TRACE_EXIT();
return;
}
@@ -2322,7 +2462,7 @@ out_unlock:
/* Called under dev_lock, tgt_dev_lock and BH off */
void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev,
const uint8_t *sense, int sense_len)
const uint8_t *sense, int sense_len, int head)
{
struct scst_tgt_dev_UA *UA_entry = NULL;
@@ -2342,16 +2482,21 @@ void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev,
memcpy(UA_entry->UA_sense_buffer, sense, sense_len);
set_bit(SCST_TGT_DEV_UA_PENDING, &tgt_dev->tgt_dev_flags);
smp_mb__after_set_bit();
list_add_tail(&UA_entry->UA_list_entry, &tgt_dev->UA_list);
TRACE_MGMT_DBG("Adding new UA to tgt_dev %p", tgt_dev);
if (head)
list_add(&UA_entry->UA_list_entry, &tgt_dev->UA_list);
else
list_add_tail(&UA_entry->UA_list_entry, &tgt_dev->UA_list);
out:
TRACE_EXIT();
return;
}
/* Called under dev_lock and BH off */
void scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
const uint8_t *sense, int sense_len)
const uint8_t *sense, int sense_len, int head)
{
int skip_UA = 0;
struct scst_tgt_dev_UA *UA_entry_tmp;
@@ -2361,16 +2506,16 @@ void scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
spin_lock(&tgt_dev->tgt_dev_lock);
list_for_each_entry(UA_entry_tmp, &tgt_dev->UA_list,
UA_list_entry)
{
if (sense[12] == UA_entry_tmp->UA_sense_buffer[12]) {
UA_list_entry) {
if (memcmp(sense, UA_entry_tmp->UA_sense_buffer, sense_len) == 0) {
TRACE_MGMT_DBG("%s", "UA already exists");
skip_UA = 1;
break;
}
}
if (skip_UA == 0)
scst_alloc_set_UA(tgt_dev, sense, sense_len);
scst_alloc_set_UA(tgt_dev, sense, sense_len, head);
spin_unlock(&tgt_dev->tgt_dev_lock);
@@ -2378,31 +2523,41 @@ void scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
return;
}
/* Called under dev_lock and BH off */
void __scst_process_UA(struct scst_device *dev,
struct scst_cmd *exclude, const uint8_t *sense, int sense_len,
int internal)
/* No locks, but the activity must not get suspended while inside this function */
void scst_dev_check_set_local_UA(struct scst_device *dev,
struct scst_cmd *exclude, const uint8_t *sense, int sense_len)
{
struct scst_tgt_dev *tgt_dev, *exclude_tgt_dev = NULL;
TRACE_ENTRY();
TRACE(TRACE_MGMT, "Processing UA dev %p", dev);
if (exclude != NULL)
exclude_tgt_dev = exclude->tgt_dev;
/* Check for reset UA */
if (!internal && (sense[12] == SCST_SENSE_ASC_UA_RESET)) {
scst_process_reset(dev, (exclude != NULL) ? exclude->sess : NULL,
exclude, NULL);
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry) {
if (tgt_dev != exclude_tgt_dev)
scst_check_set_UA(tgt_dev, sense, sense_len, 0);
}
list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list,
dev_tgt_dev_list_entry) {
if (tgt_dev != exclude_tgt_dev)
scst_check_set_UA(tgt_dev, sense, sense_len);
}
TRACE_EXIT();
return;
}
/* Called under dev_lock and BH off */
void __scst_dev_check_set_UA(struct scst_device *dev,
struct scst_cmd *exclude, const uint8_t *sense, int sense_len)
{
TRACE_ENTRY();
TRACE(TRACE_MGMT, "Processing UA dev %p", dev);
/* Check for reset UA */
if (sense[12] == SCST_SENSE_ASC_UA_RESET)
scst_process_reset(dev, (exclude != NULL) ? exclude->sess : NULL,
exclude, NULL);
scst_dev_check_set_local_UA(dev, exclude, sense, sense_len);
TRACE_EXIT();
return;
@@ -2817,6 +2972,72 @@ out:
return;
}
void scst_on_hq_cmd_response(struct scst_cmd *cmd)
{
struct scst_tgt_dev *tgt_dev = cmd->tgt_dev;
TRACE_ENTRY();
spin_lock_irq(&tgt_dev->sn_lock);
tgt_dev->hq_cmd_count--;
spin_unlock_irq(&tgt_dev->sn_lock);
EXTRACHECKS_BUG_ON(tgt_dev->hq_cmd_count < 0);
/*
* There is no problem in checking hq_cmd_count in the
* non-locked state. In the worst case we will only have
* unneeded run of the deferred commands.
*/
if (tgt_dev->hq_cmd_count == 0) {
struct scst_cmd *c =
scst_check_deferred_commands(tgt_dev);
if (c != NULL) {
spin_lock_irq(&c->cmd_lists->cmd_list_lock);
TRACE_SN("Adding cmd %p to active cmd list", c);
list_add_tail(&c->cmd_list_entry,
&c->cmd_lists->active_cmd_list);
wake_up(&c->cmd_lists->cmd_list_waitQ);
spin_unlock_irq(&c->cmd_lists->cmd_list_lock);
}
}
TRACE_EXIT();
return;
}
void scst_xmit_process_aborted_cmd(struct scst_cmd *cmd)
{
TRACE_ENTRY();
if (test_bit(SCST_CMD_ABORTED_OTHER, &cmd->cmd_flags)) {
if (cmd->completed) {
/* It's completed and it's OK to return its result */
goto out;
}
TRACE_MGMT_DBG("Flag ABORTED OTHER set for cmd %p (tag %llu)",
cmd, cmd->tag);
if (cmd->dev->tas) {
scst_set_cmd_error_status(cmd, SAM_STAT_TASK_ABORTED);
} else {
/* Abort without delivery or notification */
clear_bit(SCST_CMD_ABORTED_OTHER,
&cmd->cmd_flags);
}
} else {
if ((cmd->tgt_dev != NULL) &&
scst_is_ua_sense(cmd->sense_buffer)) {
/* This UA delivery is going to fail, so requeue it */
scst_check_set_UA(cmd->tgt_dev, cmd->sense_buffer,
sizeof(cmd->sense_buffer), 1);
}
}
out:
TRACE_EXIT();
return;
}
void __init scst_scsi_op_list_init(void)
{
int i;
@@ -3095,6 +3316,15 @@ void tm_dbg_release_cmd(struct scst_cmd *cmd)
"delayed cmd %p (tag=%llu), moving it to "
"active cmd list (delayed_cmds_count=%d)",
c, c->tag, tm_dbg_delayed_cmds_count);
if (!test_bit(SCST_CMD_ABORTED_OTHER, &cmd->cmd_flags)) {
if (((scst_random() % 10) == 5)) {
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
/* It's completed now */
}
}
spin_lock(&cmd->cmd_lists->cmd_list_lock);
list_move(&c->cmd_list_entry,
&c->cmd_lists->active_cmd_list);
+8 -2
View File
@@ -509,6 +509,10 @@ static int scst_register_device(struct scsi_device *scsidp)
dev->scsi_dev = scsidp;
list_add_tail(&dev->dev_list_entry, &scst_dev_list);
res = scst_obtain_device_parameters(dev);
if (res != 0)
goto out_free;
list_for_each_entry(dt, &scst_dev_type_list, dev_type_list_entry) {
if (dt->type == scsidp->type) {
@@ -710,12 +714,12 @@ void scst_unregister_virtual_device(int id)
list_for_each_entry(d, &scst_dev_list, dev_list_entry) {
if (d->virt_id == id) {
dev = d;
TRACE_DBG("Target device %p found", dev);
TRACE_DBG("Target device %p (id %d) found", dev, id);
break;
}
}
if (dev == NULL) {
PRINT_ERROR("%s", "Target device not found");
PRINT_ERROR("Target virtual device (id %d) not found", id);
goto out_unblock;
}
@@ -1672,6 +1676,8 @@ EXPORT_SYMBOL(scst_set_busy);
EXPORT_SYMBOL(scst_set_cmd_error_status);
EXPORT_SYMBOL(scst_set_cmd_error);
EXPORT_SYMBOL(scst_set_resp_data_len);
EXPORT_SYMBOL(scst_set_sense);
EXPORT_SYMBOL(scst_set_cmd_error_sense);
EXPORT_SYMBOL(scst_process_active_cmd);
+21 -27
View File
@@ -56,7 +56,7 @@ extern unsigned long scst_trace_flag;
*/
#define SCST_DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | TRACE_PID | \
TRACE_LINE | TRACE_FUNCTION | TRACE_SPECIAL | TRACE_MGMT | \
TRACE_MGMT_DEBUG | TRACE_RETRY)
TRACE_MGMT_MINOR | TRACE_MGMT_DEBUG | TRACE_RETRY)
#define TRACE_SN(args...) TRACE(TRACE_SCSI_SERIALIZING, args)
@@ -103,7 +103,7 @@ extern unsigned long scst_trace_flag;
** Maximum count of uncompleted commands that an initiator could
** queue on any device. Then it will start getting TASK QUEUE FULL status.
**/
#define SCST_MAX_TGT_DEV_COMMANDS 64
#define SCST_MAX_TGT_DEV_COMMANDS 32
/**
** Maximum count of uncompleted commands that could be queued on any device.
@@ -115,7 +115,8 @@ extern unsigned long scst_trace_flag;
#define SCST_TGT_RETRY_TIMEOUT (3/2*HZ)
#define SCST_CMD_MEM_TIMEOUT (120*HZ)
static inline int scst_get_context(void) {
static inline int scst_get_context(void)
{
if (in_irq())
return SCST_CONTEXT_TASKLET;
if (irqs_disabled())
@@ -234,6 +235,9 @@ int scst_check_hq_cmd(struct scst_cmd *cmd);
void scst_unblock_deferred(struct scst_tgt_dev *tgt_dev,
struct scst_cmd *cmd_sn);
void scst_on_hq_cmd_response(struct scst_cmd *cmd);
void scst_xmit_process_aborted_cmd(struct scst_cmd *cmd);
int scst_cmd_thread(void *arg);
void scst_cmd_tasklet(long p);
int scst_init_cmd_thread(void *arg);
@@ -254,7 +258,7 @@ void scst_proc_del_acg_tree(struct proc_dir_entry *acg_proc_root,
int scst_sess_alloc_tgt_devs(struct scst_session *sess);
void scst_sess_free_tgt_devs(struct scst_session *sess);
void scst_reset_tgt_dev(struct scst_tgt_dev *tgt_dev, int nexus_loss);
void scst_nexus_loss(struct scst_tgt_dev *tgt_dev);
int scst_acg_add_dev(struct scst_acg *acg, struct scst_device *dev, lun_t lun,
int read_only);
@@ -350,23 +354,26 @@ void scst_cleanup_proc_dev_handler_dir_entries(struct scst_dev_type *dev_type);
int scst_get_cdb_len(const uint8_t *cdb);
void __scst_process_UA(struct scst_device *dev, struct scst_cmd *exclude,
const uint8_t *sense, int sense_len, int internal);
static inline void scst_process_UA(struct scst_device *dev,
struct scst_cmd *exclude, const uint8_t *sense, int sense_len,
int internal)
int scst_obtain_device_parameters(struct scst_device *dev);
void __scst_dev_check_set_UA(struct scst_device *dev, struct scst_cmd *exclude,
const uint8_t *sense, int sense_len);
static inline void scst_dev_check_set_UA(struct scst_device *dev,
struct scst_cmd *exclude, const uint8_t *sense, int sense_len)
{
spin_lock_bh(&dev->dev_lock);
__scst_process_UA(dev, exclude, sense, sense_len, internal);
__scst_dev_check_set_UA(dev, exclude, sense, sense_len);
spin_unlock_bh(&dev->dev_lock);
return;
}
void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev, const uint8_t *sense,
int sense_len);
void scst_dev_check_set_local_UA(struct scst_device *dev,
struct scst_cmd *exclude, const uint8_t *sense, int sense_len);
void scst_check_set_UA(struct scst_tgt_dev *tgt_dev,
const uint8_t *sense, int sense_len);
int scst_set_pending_UA(struct scst_cmd *cmd);
const uint8_t *sense, int sense_len, int head);
void scst_alloc_set_UA(struct scst_tgt_dev *tgt_dev, const uint8_t *sense,
int sense_len, int head);
void scst_free_all_UA(struct scst_tgt_dev *tgt_dev);
int scst_set_pending_UA(struct scst_cmd *cmd);
void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
int other_ini, int call_dev_task_mgmt_fn);
@@ -487,19 +494,6 @@ static inline void scst_cmd_put(struct scst_cmd *cmd)
extern void scst_throttle_cmd(struct scst_cmd *cmd);
extern void scst_unthrottle_cmd(struct scst_cmd *cmd);
static inline void scst_set_sense(uint8_t *buffer, int len, int key,
int asc, int ascq)
{
memset(buffer, 0, len);
buffer[0] = 0x70; /* Error Code */
buffer[2] = key; /* Sense Key */
buffer[7] = 0x0a; /* Additional Sense Length */
buffer[12] = asc; /* ASC */
buffer[13] = ascq; /* ASCQ */
TRACE_BUFFER("Sense set", buffer, len);
return;
}
static inline void scst_check_restore_sg_buff(struct scst_cmd *cmd)
{
if (cmd->sg_buff_modified) {
+1
View File
@@ -101,6 +101,7 @@ static struct scst_proc_log scst_proc_trace_tbl[] =
{ TRACE_SPECIAL, "special" },
{ TRACE_SCSI, "scsi" },
{ TRACE_MGMT, "mgmt" },
{ TRACE_MGMT_MINOR, "mgmt_minor" },
{ TRACE_MGMT_DEBUG, "mgmt_dbg" },
{ 0, NULL }
};
+558 -362
View File
File diff suppressed because it is too large Load Diff
+37 -2
View File
@@ -32,6 +32,7 @@
#include "common.h"
static void exec_inquiry(struct vdisk_cmd *vcmd);
static void exec_request_sense(struct vdisk_cmd *vcmd);
static void exec_mode_sense(struct vdisk_cmd *vcmd);
static void exec_mode_select(struct vdisk_cmd *vcmd);
static void exec_read_capacity(struct vdisk_cmd *vcmd);
@@ -445,6 +446,9 @@ static int do_exec(struct vdisk_cmd *vcmd)
case INQUIRY:
exec_inquiry(vcmd);
break;
case REQUEST_SENSE:
exec_request_sense(vcmd);
break;
case READ_CAPACITY:
exec_read_capacity(vcmd);
break;
@@ -533,6 +537,11 @@ static int do_on_free_cmd(struct vdisk_cmd *vcmd)
TRACE_ENTRY();
TRACE_DBG("On free cmd (cmd %d, resp_data_len %d, aborted %d, "
"status %d, delivery_status %d)", cmd->cmd_h,
cmd->on_free_cmd.resp_data_len, cmd->on_free_cmd.aborted,
cmd->on_free_cmd.status, cmd->on_free_cmd.delivery_status);
TRACE_MEM("On free cmd (cmd %d, buf %Lx, buffer_cached %d)", cmd->cmd_h,
cmd->on_free_cmd.pbuf, cmd->on_free_cmd.buffer_cached);
@@ -557,8 +566,9 @@ static int do_tm(struct vdisk_cmd *vcmd)
TRACE_ENTRY();
TRACE(TRACE_MGMT, "TM fn %d (sess_h %Lx, cmd_h_to_abort %d)",
cmd->tm_cmd.fn, cmd->tm_cmd.sess_h, cmd->tm_cmd.cmd_h_to_abort);
TRACE((cmd->tm_cmd.fn == SCST_ABORT_TASK) ? TRACE_MGMT_MINOR : TRACE_MGMT,
"TM fn %d (sess_h %Lx, cmd_h_to_abort %d)", cmd->tm_cmd.fn,
cmd->tm_cmd.sess_h, cmd->tm_cmd.cmd_h_to_abort);
memset(reply, 0, sizeof(*reply));
reply->cmd_h = cmd->cmd_h;
@@ -1026,6 +1036,31 @@ out:
return;
}
static void exec_request_sense(struct vdisk_cmd *vcmd)
{
struct scst_user_scsi_cmd_exec *cmd = &vcmd->cmd->exec_cmd;
struct scst_user_scsi_cmd_reply_exec *reply = &vcmd->reply->exec_reply;
int length = cmd->bufflen;
uint8_t *address = (uint8_t*)(unsigned long)cmd->pbuf;
TRACE_ENTRY();
if (length < SCST_STANDARD_SENSE_LEN) {
PRINT_ERROR("too small requested buffer for REQUEST SENSE "
"(len %d)", length);
set_cmd_error(vcmd,
SCST_LOAD_SENSE(scst_sense_invalid_field_in_parm_list));
goto out;
}
set_sense(address, length, SCST_LOAD_SENSE(scst_sense_no_sense));
reply->resp_data_len = length;
out:
TRACE_EXIT();
return;
}
/*
* <<Following mode pages info copied from ST318451LW with some corrections>>
*
+3 -3
View File
@@ -45,9 +45,9 @@
struct vdisk_tgt_dev {
uint64_t sess_h;
/*
* last_write_cmd_queue_type accessed without protection since we are
* guaranteed that only commands of the same type per tgt_dev can be
* processed simultaneously
* Used without protection since we are guaranteed by SCST core
* that only commands with the same ORDERED type per tgt_dev can
* be processed simultaneously.
*/
int last_write_cmd_queue_type;
};
+24 -12
View File
@@ -47,11 +47,12 @@ extern pid_t gettid(void);
#define TRACE_OUT_OF_MEM 0x00000100
#define TRACE_MINOR 0x00000200 /* less important events */
#define TRACE_MGMT 0x00000400
#define TRACE_MGMT_DEBUG 0x00000800
#define TRACE_SCSI 0x00001000
#define TRACE_SPECIAL 0x00002000 /* filtering debug, etc */
#define TRACE_TIME 0x00004000
#define TRACE_ORDER 0x00008000
#define TRACE_MGMT_MINOR 0x00000800
#define TRACE_MGMT_DEBUG 0x00001000
#define TRACE_SCSI 0x00002000
#define TRACE_SPECIAL 0x00004000 /* filtering debug, etc */
#define TRACE_TIME 0x00008000
#define TRACE_ORDER 0x00010000
#define TRACE_ALL 0xffffffff
#define PRINT(format, args...) fprintf(stdout, format "\n", ## args);
@@ -91,7 +92,7 @@ do { \
do { \
if (trace_flag & TRACE_BUFF) \
{ \
debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
__LINE__); \
PRINT("%s:", message); \
debug_print_buffer(buff, len); \
@@ -102,18 +103,25 @@ do { \
do { \
if (trace_flag & (flag)) \
{ \
debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
__LINE__); \
PRINT("%s:", message); \
debug_print_buffer(buff, len); \
} \
} while(0)
#define PRINT_BUFFER(message, buff, len) \
do { \
PRINT("%s:", message); \
debug_print_buffer(buff, len); \
} while(0)
#else /* DEBUG || TRACING */
#define TRACE(trace, args...) {}
#define TRACE_BUFFER(message, buff, len) {}
#define TRACE_BUFF_FLAG(flag, message, buff, len) {}
#define PRINT_BUFFER(message, buff, len) {}
static inline int debug_init(void) { return 0; }
static inline void debug_done(void) {}
@@ -128,7 +136,7 @@ static inline void debug_done(void) {}
do { \
if (trace_flag & TRACE_MEMORY) \
{ \
debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
__LINE__); \
PRINT(format, args); \
} \
@@ -138,7 +146,7 @@ do { \
do { \
if (trace_flag & TRACE_DEBUG) \
{ \
debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
__LINE__); \
PRINT(format, args); \
} \
@@ -148,7 +156,7 @@ do { \
do { \
if (trace_flag & TRACE_MGMT_DEBUG) \
{ \
debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
debug_print_prefix(trace_flag, NULL, __FUNCTION__, \
__LINE__); \
PRINT(format, args); \
} \
@@ -156,12 +164,16 @@ do { \
#define PRINT_ERROR(format, args...) \
do { \
TRACE(trace_flag, "***ERROR*** " format, args); \
debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
__LINE__); \
PRINT("***ERROR*** " format, args); \
} while(0)
#define PRINT_INFO(format, args...) \
do { \
TRACE(trace_flag, format, args); \
debug_print_prefix(trace_flag, __LOG_PREFIX, __FUNCTION__, \
__LINE__); \
PRINT(format, args); \
} while(0)
#define TRACE_ENTRY() \
+7 -4
View File
@@ -45,15 +45,15 @@ char *app_name;
~TRACE_SCSI & ~TRACE_SCSI_SERIALIZING & ~TRACE_DEBUG)
*/
#define DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | TRACE_PID | \
TRACE_FUNCTION | TRACE_SPECIAL | TRACE_MGMT | TRACE_MGMT_DEBUG | \
TRACE_TIME)
TRACE_FUNCTION | TRACE_SPECIAL | TRACE_MGMT | TRACE_MGMT_MINOR | \
TRACE_MGMT_DEBUG | TRACE_TIME)
#define TRACE_SN(args...) TRACE(TRACE_SCSI_SERIALIZING, args)
#else /* DEBUG */
# ifdef TRACING
#define DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | \
#define DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | TRACE_MGMT \
TRACE_TIME | TRACE_SPECIAL)
# else
#define DEFAULT_LOG_FLAGS 0
@@ -388,6 +388,9 @@ int main(int argc, char **argv)
else
desc.opt.prio_queue_type = SCST_USER_PRIO_QUEUE_SINGLE;
desc.opt.tst = SCST_CONTR_MODE_SEP_TASK_SETS;
desc.opt.queue_alg = SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER;
res = ioctl(dev.scst_usr_fd, SCST_USER_REGISTER_DEVICE, &desc);
if (res != 0) {
res = errno;
@@ -418,7 +421,7 @@ int main(int argc, char **argv)
res = ioctl(dev.scst_usr_fd, SCST_USER_SET_OPTIONS, &opt);
if (res != 0) {
res = errno;
PRINT_ERROR("Unable to get options: %s", strerror(res));
PRINT_ERROR("Unable to set options: %s", strerror(res));
goto out_close;
}
}