mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-18 05:06:31 +00:00
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:
+22
-1
@@ -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.
|
||||
|
||||
|
||||
@@ -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(¶ms, 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;
|
||||
|
||||
@@ -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 | \
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
@@ -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() \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+37
-2
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user