mirror of
https://github.com/SCST-project/scst.git
synced 2026-07-20 15:02:18 +00:00
Merged revisions 5456-5485,5487-5508 via svnmerge from
svn+ssh://yanb123@svn.code.sf.net/p/scst/svn/trunk
........
r5456 | bvassche | 2014-04-23 08:15:57 +0300 (Wed, 23 Apr 2014) | 1 line
scst/README: Update implicit ALUA section
........
r5457 | bvassche | 2014-04-23 11:57:17 +0300 (Wed, 23 Apr 2014) | 1 line
ib_srpt: RHEL 5.9 build fix
........
r5458 | bvassche | 2014-04-23 11:59:18 +0300 (Wed, 23 Apr 2014) | 1 line
ib_srpt: Clean up the CM event handling code
........
r5459 | bvassche | 2014-04-23 12:02:29 +0300 (Wed, 23 Apr 2014) | 1 line
ib_srpt: Clean up the CM event handling code (part 2)
........
r5460 | bvassche | 2014-04-23 12:04:15 +0300 (Wed, 23 Apr 2014) | 1 line
ib_srpt, RDMA/CM: Avoid hanging sessions due to a cable pull
........
r5461 | bvassche | 2014-04-23 12:20:52 +0300 (Wed, 23 Apr 2014) | 1 line
ib_srpt: RHEL 5.9 build fix (part 2)
........
r5462 | bvassche | 2014-04-23 16:38:54 +0300 (Wed, 23 Apr 2014) | 1 line
ib_srpt: Clean up the CM event handling messages (part 3)
........
r5463 | vlnb | 2014-04-24 03:07:22 +0300 (Thu, 24 Apr 2014) | 3 lines
Cleanups
........
r5464 | vlnb | 2014-04-24 05:30:52 +0300 (Thu, 24 Apr 2014) | 35 lines
scst_lib: Avoid integer overflows
This patch fixes the following kernel oops:
[3696]: scst: scst_parse_cmd:826:Warning: expected transfer length 522240 for opcode 0x08 (handler vcdrom, target iscsi) doesn't match decoded value -2048
[3696]: scst_parse_cmd:828:Suspicious CDB:
(h)___0__1__2__3__4__5__6__7__8__9__A__B__C__D__E__F
0: 08 1f ff ff ff 00 ......
BUG: unable to handle kernel paging request at ffff88283597f0c8
IP: [<ffffffff8135c3af>] sg_init_table+0x5f/0x90
Call Trace:
[<ffffffffa021eb48>] sgv_pool_alloc+0x3b8/0xbf0 [scst]
[<ffffffffa0204c16>] scst_alloc_space+0xb6/0x290 [scst]
[<ffffffffa01e2d28>] scst_prepare_space+0x3b8/0x6e0 [scst]
[<ffffffffa01ef4a5>] scst_process_active_cmd+0x455/0x7e0 [scst]
[<ffffffffa01efb22>] scst_cmd_init_done+0x2f2/0x5c0 [scst]
[<ffffffffa0156ac2>] scst_cmd_init_stage1_done.constprop.37+0x12/0x20 [iscsi_scst]
[<ffffffffa015d9fa>] scsi_cmnd_start+0x25a/0x550 [iscsi_scst]
[<ffffffffa015e4b8>] cmnd_rx_start+0x148/0x1a0 [iscsi_scst]
[<ffffffffa0161598>] process_read_io+0x3b8/0x800 [iscsi_scst]
[<ffffffffa0161aa7>] scst_do_job_rd+0xc7/0x220 [iscsi_scst]
[<ffffffffa016208d>] istrd+0x16d/0x2e0 [iscsi_scst]
[<ffffffff81075bad>] kthread+0xed/0x110
[<ffffffff816dd5bc>] ret_from_fork+0x7c/0xb0
and causes the following message to be reported instead:
[11269]: scst: scst_generic_parse:7402:***WARNING***: bufflen 16777215, data_len 16777215 or out_bufflen 0 too large for device disk12 (block size 2048)
scst_generic_parse:CDB:
(h)___0__1__2__3__4__5__6__7__8__9__A__B__C__D__E__F
0: 08 1f ff ff ff 00 ......
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5465 | vlnb | 2014-04-24 05:33:07 +0300 (Thu, 24 Apr 2014) | 5 lines
scst_targ: Clarify a comment
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5466 | vlnb | 2014-04-24 05:39:05 +0300 (Thu, 24 Apr 2014) | 12 lines
scst: Avoid that smatch complains about dead code
The panic() function that implements BUG() has been declared with attribute
noreturn in some RHEL 5 kernel headers and also in the RHEL 6 kernel headers.
Smatch warns about dead code if any code follows a function that has been
declared with attribute noreturn. Hence add a few preprocessor statements to
suppress the smatch warning when building against an upstream kernel or when
building against RHEL 6 or later.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5467 | vlnb | 2014-04-24 06:15:12 +0300 (Thu, 24 Apr 2014) | 3 lines
Fix queuing of UA for aborted by PREEMPT AND ABORT, if TAS is 0, + some clarifications
........
r5468 | vlnb | 2014-04-24 07:03:51 +0300 (Thu, 24 Apr 2014) | 6 lines
Fix for TARGET RESET race
It can happen, when a device added after blocking, so unblocking then
will make dev->block_count of the new device negative.
........
r5469 | bvassche | 2014-04-24 11:41:15 +0300 (Thu, 24 Apr 2014) | 1 line
scst/README: Update multipathd information in implicit ALUA section
........
r5470 | bvassche | 2014-04-24 13:37:58 +0300 (Thu, 24 Apr 2014) | 1 line
ib_srpt: OFED 3.12 build fix
........
r5471 | bvassche | 2014-04-24 13:38:37 +0300 (Thu, 24 Apr 2014) | 1 line
ib_srpt: Add support in the Makefile for MLNX OFED and for OFED 3.x
........
r5472 | bvassche | 2014-04-24 14:11:26 +0300 (Thu, 24 Apr 2014) | 1 line
ib_srpt: Make srpt_disconnect_ch() close sessions properly that have not yet reached the connected state
........
r5473 | bvassche | 2014-04-24 15:27:00 +0300 (Thu, 24 Apr 2014) | 1 line
ib_srpt, Makefile: Introduce the OFED_KERNEL_DIR variable
........
r5474 | bvassche | 2014-04-24 21:43:41 +0300 (Thu, 24 Apr 2014) | 1 line
ib_srpt: Unload properly with RDMA/CM disabled
........
r5475 | bvassche | 2014-04-24 21:45:23 +0300 (Thu, 24 Apr 2014) | 1 line
scstadmin, regression tests: Follow-up for r5409
........
r5476 | bvassche | 2014-04-24 21:49:52 +0300 (Thu, 24 Apr 2014) | 16 lines
scst: Avoid that reassigning a session triggers a kernel crash
This patch fixes the following kernel bug:
BUG: unable to handle kernel NULL pointer dereference at 0000000000000064
IP: [<ffffffffa069e59c>] scst_alloc_add_tgt_dev+0x9c/0x540 [scst]
Call Trace:
[<ffffffffa06a1b57>] scst_check_reassign_sessions+0x367/0x3b0 [scst]
[<ffffffffa06a1cb7>] scst_acg_add_acn+0x117/0x1a0 [scst]
[<ffffffffa06a5e42>] scst_acg_ini_mgmt_store_work_fn+0x152/0x370 [scst]
[<ffffffffa06a93a6>] sysfs_work_thread_fn+0xa6/0x2f0 [scst]
[<ffffffff8108dd72>] kthread+0xd2/0xf0
[<ffffffff816912bc>] ret_from_fork+0x7c/0xb0
Reported-by: Zhen Xu <zhenxu.zj@gmail.com>
........
r5477 | vlnb | 2014-04-25 02:07:58 +0300 (Fri, 25 Apr 2014) | 3 lines
Minor logging cleanup
........
r5478 | vlnb | 2014-04-25 02:44:25 +0300 (Fri, 25 Apr 2014) | 3 lines
Cleanup
........
r5479 | vlnb | 2014-04-25 05:03:04 +0300 (Fri, 25 Apr 2014) | 3 lines
Saved mode pages added
........
r5480 | vlnb | 2014-04-25 05:47:31 +0300 (Fri, 25 Apr 2014) | 3 lines
Follow up for the previous commit
........
r5481 | vlnb | 2014-04-26 04:56:36 +0300 (Sat, 26 Apr 2014) | 3 lines
Processing of QErr and TMF_ONLY added
........
r5482 | vlnb | 2014-04-26 05:12:17 +0300 (Sat, 26 Apr 2014) | 3 lines
Cleanups
........
r5483 | bvassche | 2014-04-26 09:32:32 +0300 (Sat, 26 Apr 2014) | 7 lines
scst: Fix recently introduced checkpatch complaints about whitespace
Fix two instances of the following checkpatch errors:
ERROR: code indent should use tabs where possible
ERROR: spaces required around that ':' (ctx:VxW)
........
r5484 | bvassche | 2014-04-27 09:26:29 +0300 (Sun, 27 Apr 2014) | 6 lines
scst_const.h: Fix a checkpatch complaint about whitespace
Avoid that checkpatch reports the following warning message:
WARNING: please, no space before tabs
........
r5485 | bvassche | 2014-04-28 12:29:25 +0300 (Mon, 28 Apr 2014) | 5 lines
scst: Export scst_path_put()
This patch makes the code that was added via r5479 build against kernel
version 2.6.38 and before.
........
r5487 | vlnb | 2014-04-28 23:31:14 +0300 (Mon, 28 Apr 2014) | 3 lines
Cleanups
........
r5488 | vlnb | 2014-04-29 00:38:22 +0300 (Tue, 29 Apr 2014) | 3 lines
Returned sense cleanups
........
r5489 | vlnb | 2014-04-29 01:30:03 +0300 (Tue, 29 Apr 2014) | 3 lines
Let REPORT SUPPORTED OPERATION CODES be handled by dev handler as well
........
r5490 | vlnb | 2014-04-29 03:13:24 +0300 (Tue, 29 Apr 2014) | 6 lines
It's wrong to clean reservation on failed RESERVE commands
With multiple outstanding commands it can open a race window leading to
loose of a valid reservation
........
r5491 | vlnb | 2014-04-29 04:32:13 +0300 (Tue, 29 Apr 2014) | 3 lines
SCSI logging improvements
........
r5492 | vlnb | 2014-04-29 04:45:43 +0300 (Tue, 29 Apr 2014) | 3 lines
Missed hunk in the previous commit
........
r5493 | vlnb | 2014-04-29 05:09:29 +0300 (Tue, 29 Apr 2014) | 3 lines
Minor logging improvement
........
r5494 | bvassche | 2014-04-29 15:35:41 +0300 (Tue, 29 Apr 2014) | 1 line
ib_srpt, README: Fix RDMA/CM login instructions
........
r5495 | bvassche | 2014-04-29 15:39:50 +0300 (Tue, 29 Apr 2014) | 4 lines
ib_srpt: Make LUN masking work again
This patch fixes a regression that was introduced in r5425.
........
r5496 | vlnb | 2014-04-30 04:04:27 +0300 (Wed, 30 Apr 2014) | 3 lines
Extended INQUIRY page added
........
r5497 | vlnb | 2014-04-30 04:07:41 +0300 (Wed, 30 Apr 2014) | 3 lines
Cleanup
........
r5498 | bvassche | 2014-04-30 08:30:45 +0300 (Wed, 30 Apr 2014) | 1 line
ib_srpt: Fix two recently introduced checkpatch complaints about whitespace
........
r5499 | bvassche | 2014-04-30 09:01:17 +0300 (Wed, 30 Apr 2014) | 1 line
nightly build: Update kernel versions
........
r5500 | vlnb | 2014-05-02 05:50:12 +0300 (Fri, 02 May 2014) | 3 lines
Fix CDROM empty case
........
r5501 | vlnb | 2014-05-02 05:50:34 +0300 (Fri, 02 May 2014) | 3 lines
Cleanups
........
r5502 | vlnb | 2014-05-02 05:56:19 +0300 (Fri, 02 May 2014) | 9 lines
scst_sysfs: Save the value of the 'preferred' attribute only if it has been set
The default value of the 'preferred' attribute is 0 (disabled). Hence
it is only necessary that scstadmin saves the value of that attribute
if it is not zero.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
r5503 | vlnb | 2014-05-07 02:22:32 +0300 (Wed, 07 May 2014) | 3 lines
Cleanups and logging improvements
........
r5504 | vlnb | 2014-05-07 05:13:11 +0300 (Wed, 07 May 2014) | 5 lines
Fix COMMAND DATA LENGTH in All_commands parameter data of REPORT SUPPORTED OPERATION CODES
Reported by Sebastian Herbszt <herbszt@gmx.de>
........
r5505 | bvassche | 2014-05-07 11:38:47 +0300 (Wed, 07 May 2014) | 5 lines
scst: Fix the procfs build
Move the definition of scst_get_opcode_name() up such that it occurs
outside #ifndef CONFIG_SCST_PROC / #endif. See also r5491.
........
r5506 | bvassche | 2014-05-07 11:57:04 +0300 (Wed, 07 May 2014) | 4 lines
scst_vdisk: Build fix for kernel versions < 2.6.37
See also r5420 / r5479.
........
r5507 | bvassche | 2014-05-07 16:42:56 +0300 (Wed, 07 May 2014) | 1 line
nightly build: Update kernel versions
........
r5508 | vlnb | 2014-05-08 05:28:49 +0300 (Thu, 08 May 2014) | 7 lines
Avoid that the code for dumping the PR state triggers a race condition
Callers of scst_pr_dump_prs() must hold dev_pr_mutex.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/iser@5509 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -1457,9 +1457,10 @@ static void cmnd_prepare_get_rejected_immed_data(struct iscsi_cmnd *cmnd)
|
||||
|
||||
TRACE_DBG_FLAG(iscsi_get_flow_ctrl_or_mgmt_dbg_log_flag(cmnd),
|
||||
"Skipping (cmnd %p, ITT %x, op %x, cmd op %x, "
|
||||
"datasize %u, scst_cmd %p, scst state %d)", cmnd,
|
||||
"datasize %u, scst_cmd %p, scst state %d, status %d)", cmnd,
|
||||
cmnd->pdu.bhs.itt, cmnd_opcode(cmnd), cmnd_hdr(cmnd)->scb[0],
|
||||
cmnd->pdu.datasize, cmnd->scst_cmd, cmnd->scst_state);
|
||||
cmnd->pdu.datasize, cmnd->scst_cmd, cmnd->scst_state,
|
||||
cmnd->scst_cmd ? cmnd->scst_cmd->status : -1);
|
||||
|
||||
iscsi_extracheck_is_rd_thread(conn);
|
||||
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
ABT_DETAILS="x86_64"
|
||||
ABT_JOBS=5
|
||||
ABT_KERNELS=" \
|
||||
3.14.1 \
|
||||
3.14.3 \
|
||||
3.13.10 \
|
||||
3.12.17-nc \
|
||||
3.11.10-nc \
|
||||
3.10.37-nc \
|
||||
3.10.39-nc \
|
||||
3.9.11-nc \
|
||||
3.8.14-nc \
|
||||
3.7.10-nc \
|
||||
3.6.11-nc \
|
||||
3.5.7-nc \
|
||||
3.4.87-nc \
|
||||
3.4.89-nc \
|
||||
3.3.8-nc \
|
||||
3.2.57-nc \
|
||||
3.1.10-nc \
|
||||
|
||||
@@ -2623,16 +2623,16 @@ static int q2t_pre_xmit_response(struct q2t_cmd *cmd,
|
||||
if (unlikely(scst_get_resid(scst_cmd, &prm->residual, NULL))) {
|
||||
if (prm->residual > 0) {
|
||||
TRACE_DBG("Residual underflow: %d (tag %lld, "
|
||||
"op %x, bufflen %d, rq_result %x)",
|
||||
"op %s, bufflen %d, rq_result %x)",
|
||||
prm->residual, scst_cmd->tag,
|
||||
scst_cmd->cdb[0], cmd->bufflen,
|
||||
scst_get_opcode_name(scst_cmd), cmd->bufflen,
|
||||
prm->rq_result);
|
||||
prm->rq_result |= SS_RESIDUAL_UNDER;
|
||||
} else if (prm->residual < 0) {
|
||||
TRACE_DBG("Residual overflow: %d (tag %lld, "
|
||||
"op %x, bufflen %d, rq_result %x)",
|
||||
"op %s, bufflen %d, rq_result %x)",
|
||||
prm->residual, scst_cmd->tag,
|
||||
scst_cmd->cdb[0], cmd->bufflen,
|
||||
scst_get_opcode_name(scst_cmd), cmd->bufflen,
|
||||
prm->rq_result);
|
||||
prm->rq_result |= SS_RESIDUAL_OVER;
|
||||
prm->residual = -prm->residual;
|
||||
@@ -3591,18 +3591,18 @@ static void q2t_do_ctio_completion(scsi_qla_host_t *ha, uint32_t handle,
|
||||
TRACE(TRACE_MINOR_AND_MGMT_DBG,
|
||||
"qla2x00t(%ld): CTIO with "
|
||||
"status %#x received, state %x, scst_cmd %p, "
|
||||
"op %x (LIP_RESET=e, ABORTED=2, TARGET_RESET=17, "
|
||||
"op %s (LIP_RESET=e, ABORTED=2, TARGET_RESET=17, "
|
||||
"TIMEOUT=b, INVALID_RX_ID=8)", ha->instance,
|
||||
status, cmd->state, scst_cmd, scst_cmd->cdb[0]);
|
||||
status, cmd->state, scst_cmd, scst_get_opcode_name(scst_cmd));
|
||||
break;
|
||||
|
||||
case CTIO_PORT_LOGGED_OUT:
|
||||
case CTIO_PORT_UNAVAILABLE:
|
||||
PRINT_INFO("qla2x00t(%ld): CTIO with PORT LOGGED "
|
||||
"OUT (29) or PORT UNAVAILABLE (28) status %x "
|
||||
"received (state %x, scst_cmd %p, op %x)",
|
||||
"received (state %x, scst_cmd %p, op %s)",
|
||||
ha->instance, status, cmd->state, scst_cmd,
|
||||
scst_cmd->cdb[0]);
|
||||
scst_get_opcode_name(scst_cmd));
|
||||
break;
|
||||
|
||||
case CTIO_SRR_RECEIVED:
|
||||
@@ -3613,9 +3613,9 @@ static void q2t_do_ctio_completion(scsi_qla_host_t *ha, uint32_t handle,
|
||||
|
||||
default:
|
||||
PRINT_ERROR("qla2x00t(%ld): CTIO with error status "
|
||||
"0x%x received (state %x, scst_cmd %p, op %x)",
|
||||
"0x%x received (state %x, scst_cmd %p, op %s)",
|
||||
ha->instance, status, cmd->state, scst_cmd,
|
||||
scst_cmd->cdb[0]);
|
||||
scst_get_opcode_name(scst_cmd));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4652,10 +4652,10 @@ restart:
|
||||
cmd->sg = scst_cmd_get_sg(&cmd->scst_cmd);
|
||||
cmd->sg_cnt = scst_cmd_get_sg_cnt(&cmd->scst_cmd);
|
||||
|
||||
TRACE_MGMT_DBG("SRR cmd %p (scst_cmd %p, tag %d, op %x), "
|
||||
TRACE_MGMT_DBG("SRR cmd %p (scst_cmd %p, tag %d, op %s), "
|
||||
"sg_cnt=%d, offset=%d", cmd, &cmd->scst_cmd,
|
||||
cmd->tag, cmd->scst_cmd.cdb[0], cmd->sg_cnt,
|
||||
cmd->offset);
|
||||
cmd->tag, scst_get_opcode_name(&cmd->scst_cmd),
|
||||
cmd->sg_cnt, cmd->offset);
|
||||
|
||||
if (IS_FWI2_CAPABLE(ha))
|
||||
q24_handle_srr(ha, sctio, imm);
|
||||
|
||||
+108
-76
@@ -949,6 +949,11 @@ cache. The following parameters possible for vdisk_fileio:
|
||||
initiators can unmap blocks of storage, if they don't need them
|
||||
anymore. Backend storage also must support this facility.
|
||||
|
||||
- tst - allows to specify TST control mode page field. It specifies
|
||||
the type of task set in the device. Possible values are: 0 - the
|
||||
device maintains one task set for all I_T nexuses and 1 - the device
|
||||
maintains separate task sets for each I_T nexus. Default - 1.
|
||||
|
||||
- removable - with this flag set the device is reported to remote
|
||||
initiators as removable.
|
||||
|
||||
@@ -965,16 +970,17 @@ storage HBAs and for applications that either do not need caching
|
||||
between application and disk or need the large block throughput. See
|
||||
below for more info.
|
||||
|
||||
The following parameters possible for vdisk_blockio: filename,
|
||||
blocksize, nv_cache, read_only, removable, rotational, thin_provisioned.
|
||||
See vdisk_fileio above for description of those parameters.
|
||||
The following common with vdisk_fileio parameters are possible for
|
||||
vdisk_blockio: filename, blocksize, nv_cache, write_through, read_only,
|
||||
removable, rotational, thin_provisioned, tst. See vdisk_fileio above for
|
||||
description of those parameters.
|
||||
|
||||
Handler vdisk_nullio provides NULLIO mode to create virtual devices. In
|
||||
this mode no real I/O is done, but success returned to initiators.
|
||||
Intended to be used for performance measurements at the same way as
|
||||
"*_perf" handlers. The following parameters possible for vdisk_nullio:
|
||||
blocksize, read_only, removable. See vdisk_fileio above for description
|
||||
of those parameters.
|
||||
blocksize, read_only, removable, tst. See vdisk_fileio above for
|
||||
description of those parameters.
|
||||
|
||||
vdisk_nullio also has extra attribute:
|
||||
|
||||
@@ -986,7 +992,7 @@ vdisk_nullio also has extra attribute:
|
||||
"dummy" placeholder on LUN 0, if LUN 0 is not desired.
|
||||
|
||||
Handler vcdrom allows emulation of a virtual CDROM device using an ISO
|
||||
file as backend. It doesn't have any parameters.
|
||||
file as backend. It has only single parameter: tst.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -1025,6 +1031,9 @@ Each vdisk_fileio's device has the following attributes in
|
||||
SCST device belongs to (in SCSI terminology all SCST devices called
|
||||
Logical Units). See SPC for more info.
|
||||
|
||||
- tst - contains TST field of SCSI Control mode page. See SPC-4 for
|
||||
more details about this field.
|
||||
|
||||
- thin_provisioned - contains thin provisioning status of this virtual
|
||||
device.
|
||||
|
||||
@@ -1087,6 +1096,7 @@ For example:
|
||||
|-- thin_provisioned
|
||||
|-- threads_num
|
||||
|-- threads_pool_type
|
||||
|-- tst
|
||||
|-- type
|
||||
|-- usn
|
||||
`-- write_through
|
||||
@@ -1094,17 +1104,17 @@ For example:
|
||||
Each vdisk_blockio's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: blocksize, filename, nv_cache,
|
||||
read_only, removable, resync_size, rotational, size_mb, t10_dev_id,
|
||||
thin_provisioned, threads_num, threads_pool_type, type, usn. See above
|
||||
description of those parameters.
|
||||
thin_provisioned, threads_num, threads_pool_type, tst, type, usn. See
|
||||
above description of those parameters.
|
||||
|
||||
Each vdisk_nullio's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: blocksize, read_only,
|
||||
removable, size_mb, t10_dev_id, threads_num, threads_pool_type, type,
|
||||
usn, dummy. See above description of those parameters.
|
||||
tst, usn, dummy. See above description of those parameters.
|
||||
|
||||
Each vcdrom's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: filename, size_mb,
|
||||
t10_dev_id, threads_num, threads_pool_type, type, usn. See above
|
||||
t10_dev_id, threads_num, threads_pool_type, type, usn, tst. See above
|
||||
description of those parameters. Exception is filename attribute. For
|
||||
vcdrom it is writable. Writing to it allows to virtually insert or
|
||||
change virtual CD media in the virtual CDROM device. For example:
|
||||
@@ -1352,70 +1362,48 @@ The steps involved in configuring ALUA are:
|
||||
|
||||
As an example, in a H.A. setup with two systems each having one InfiniBand
|
||||
HCA controlled by the ib_srpt driver and where each system exports two LUNs
|
||||
could be configured as follows:
|
||||
the following configuration can be used in scst.conf on both systems:
|
||||
|
||||
own_tgt_id=1
|
||||
other_tgt_id=2
|
||||
cd /sys/kernel/scst_tgt/device_groups
|
||||
echo del dgroup1 >mgmt
|
||||
echo del dgroup2 >mgmt
|
||||
echo create dgroup1 >mgmt
|
||||
echo add disk01 >dgroup1/devices/mgmt
|
||||
echo create tgroup1 >dgroup1/target_groups/mgmt
|
||||
echo ${own_tgt_id} >dgroup1/target_groups/tgroup1/group_id
|
||||
echo add ib_srpt_0 >dgroup1/target_groups/tgroup1/mgmt
|
||||
echo ${own_tgt_id} >dgroup1/target_groups/tgroup1/ib_srpt_0/rel_tgt_id
|
||||
if [ ${own_tgt_id} = 1 ]; then
|
||||
echo 1 >dgroup1/target_groups/tgroup1/preferred
|
||||
fi
|
||||
echo create tgroup2 >dgroup1/target_groups/mgmt
|
||||
echo ${other_tgt_id} >dgroup1/target_groups/tgroup2/group_id
|
||||
echo add ib_srpt_0-other >dgroup1/target_groups/tgroup2/mgmt
|
||||
echo ${other_tgt_id} >dgroup1/target_groups/tgroup2/ib_srpt_0-other/rel_tgt_id
|
||||
if [ ${other_tgt_id} = 1 ]; then
|
||||
echo 1 >dgroup1/target_groups/tgroup2/preferred
|
||||
fi
|
||||
echo create dgroup2 >mgmt
|
||||
echo add disk02 >dgroup2/devices/mgmt
|
||||
echo create tgroup1 >dgroup2/target_groups/mgmt
|
||||
echo ${own_tgt_id} >dgroup2/target_groups/tgroup1/group_id
|
||||
echo add ib_srpt_0 >dgroup2/target_groups/tgroup1/mgmt
|
||||
echo ${own_tgt_id} >dgroup2/target_groups/tgroup1/ib_srpt_0/rel_tgt_id
|
||||
if [ ${own_tgt_id} = 2 ]; then
|
||||
echo 1 >dgroup2/target_groups/tgroup1/preferred
|
||||
fi
|
||||
echo create tgroup2 >dgroup2/target_groups/mgmt
|
||||
echo ${other_tgt_id} >dgroup2/target_groups/tgroup2/group_id
|
||||
echo add ib_srpt_0-other >dgroup2/target_groups/tgroup2/mgmt
|
||||
echo ${other_tgt_id} >dgroup2/target_groups/tgroup2/ib_srpt_0-other/rel_tgt_id
|
||||
if [ ${other_tgt_id} = 2 ]; then
|
||||
echo 1 >dgroup2/target_groups/tgroup2/preferred
|
||||
fi
|
||||
DEVICE_GROUP dgroup1 {
|
||||
DEVICE disk01
|
||||
|
||||
The second system in the same H.A. setup can be configured with the same
|
||||
commands but with the values of ${own_rel_tgt_id} and ${other_rel_tgt_id}
|
||||
swapped.
|
||||
TARGET_GROUP tgroup1 {
|
||||
group_id 256
|
||||
preferred 1
|
||||
state active
|
||||
TARGET fe80:0000:0000:0000:0002:c903:00fa:b7e1 {
|
||||
rel_tgt_id 1
|
||||
}
|
||||
}
|
||||
TARGET_GROUP tgroup2 {
|
||||
group_id 257
|
||||
state standby
|
||||
TARGET fe80:0000:0000:0000:0002:c903:00fa:b7f2 {
|
||||
rel_tgt_id 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
The result of the above commands is:
|
||||
DEVICE_GROUP dgroup2 {
|
||||
DEVICE disk02
|
||||
|
||||
TARGET_GROUP tgroup1 {
|
||||
group_id 256
|
||||
state standby
|
||||
TARGET fe80:0000:0000:0000:0002:c903:00fa:b7e1 {
|
||||
rel_tgt_id 1
|
||||
}
|
||||
}
|
||||
TARGET_GROUP tgroup2 {
|
||||
group_id 257
|
||||
preferred 1
|
||||
state active
|
||||
TARGET fe80:0000:0000:0000:0002:c903:00fa:b7f2 {
|
||||
rel_tgt_id 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ find -type f | grep -v '/mgmt$' | cut -c3- | sort | \
|
||||
while read f; do echo $f = $(head -n 1 $f); done
|
||||
dgroup1/target_groups/tgroup1/group_id = 1
|
||||
dgroup1/target_groups/tgroup1/ib_srpt_0/rel_tgt_id = 1
|
||||
dgroup1/target_groups/tgroup1/preferred = 1
|
||||
dgroup1/target_groups/tgroup1/state = active
|
||||
dgroup1/target_groups/tgroup2/group_id = 2
|
||||
dgroup1/target_groups/tgroup2/ib_srpt_0-other/rel_tgt_id = 2
|
||||
dgroup1/target_groups/tgroup2/preferred = 0
|
||||
dgroup1/target_groups/tgroup2/state = active
|
||||
dgroup2/target_groups/tgroup1/group_id = 1
|
||||
dgroup2/target_groups/tgroup1/ib_srpt_0/rel_tgt_id = 1
|
||||
dgroup2/target_groups/tgroup1/preferred = 1
|
||||
dgroup2/target_groups/tgroup1/state = active
|
||||
dgroup2/target_groups/tgroup2/group_id = 2
|
||||
dgroup2/target_groups/tgroup2/ib_srpt_0-other/rel_tgt_id = 2
|
||||
dgroup2/target_groups/tgroup2/preferred = 0
|
||||
dgroup2/target_groups/tgroup2/state = active
|
||||
|
||||
Checking the Target Configuration
|
||||
.................................
|
||||
@@ -1446,7 +1434,7 @@ configured on the target:
|
||||
|
||||
# sg_rtpg /dev/sdb
|
||||
Report target port groups:
|
||||
target port group id : 0x1 , Pref=1
|
||||
target port group id : 0x100 , Pref=1
|
||||
target port group asymmetric access state : 0x00
|
||||
T_SUP : 0, O_SUP : 0, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
|
||||
status code : 0x02
|
||||
@@ -1454,7 +1442,7 @@ Report target port groups:
|
||||
target port count : 01
|
||||
Relative target port ids:
|
||||
0x01
|
||||
target port group id : 0x2 , Pref=0
|
||||
target port group id : 0x101 , Pref=0
|
||||
target port group asymmetric access state : 0x00
|
||||
T_SUP : 0, O_SUP : 0, LBD_SUP : 0, U_SUP : 1, S_SUP : 1, AN_SUP : 1, AO_SUP : 1
|
||||
status code : 0x02
|
||||
@@ -1463,6 +1451,24 @@ Report target port groups:
|
||||
Relative target port ids:
|
||||
0x02
|
||||
|
||||
The relative target port ID and the target port group ID for a certain path
|
||||
can be queried e.g. as follows:
|
||||
|
||||
# sg_vpd -p di /dev/sdb
|
||||
Device Identification VPD page:
|
||||
Addressed logical unit:
|
||||
designator type: T10 vendor identification, code set: ASCII
|
||||
vendor id: SCST_FIO
|
||||
vendor specific: 27cddc71-disk01
|
||||
designator type: EUI-64 based, code set: Binary
|
||||
0x3237636464633731
|
||||
Target port:
|
||||
designator type: Relative target port, code set: Binary
|
||||
Relative target port: 0x1
|
||||
designator type: Target port group, code set: Binary
|
||||
Target port group: 0x100
|
||||
|
||||
|
||||
Initiator Support
|
||||
.................
|
||||
|
||||
@@ -1472,14 +1478,40 @@ modify at least the following in /etc/multipath.conf to enable implicit ALUA:
|
||||
* hardware_handler "1 alua"
|
||||
* prio alua
|
||||
* path_grouping_policy group_by_prio
|
||||
* path_checker tur
|
||||
|
||||
Note: newer versions of multipathd support a parameter called
|
||||
"detect_prio". It can be more convenient to enable this parameter instead of
|
||||
setting the parameter "prio" to "alua" for only those LUNs that support ALUA.
|
||||
Notes:
|
||||
- Newer versions of multipathd support a parameter called
|
||||
"detect_prio". It can be more convenient to enable this parameter instead of
|
||||
setting the parameter "prio" to "alua" for only those LUNs that support ALUA.
|
||||
- Older versions of multipathd (e.g. RHEL 5 and SLES 10 SP1) need
|
||||
'prio_callout "/sbin/mpath_prio_alua /dev/%n"' instead of 'prio alua'.
|
||||
|
||||
# multipath -ll
|
||||
23237636464633731 dm-3 SCST_FIO,disk01
|
||||
size=1.0G features='3 queue_if_no_path pg_init_retries 50' hwhandler='1 alua' wp=rw
|
||||
|-+- policy='service-time 0' prio=1 status=active
|
||||
| `- 10:0:0:0 sdd 8:48 active ready running
|
||||
`-+- policy='service-time 0' prio=130 status=enabled
|
||||
`- 11:0:0:0 sde 8:64 active ready running
|
||||
23133326137346538 dm-4 SCST_FIO,disk02
|
||||
size=1.0G features='3 queue_if_no_path pg_init_retries 50' hwhandler='1 alua' wp=rw
|
||||
|-+- policy='service-time 0' prio=130 status=active
|
||||
| `- 10:0:0:2 sdn 8:208 active ready running
|
||||
`-+- policy='service-time 0' prio=1 status=enabled
|
||||
`- 11:0:0:2 sdp 8:240 active ready running
|
||||
|
||||
The following information can be derived from the above output:
|
||||
* That the hardware handler (hw_handler) has been set to "1 alua".
|
||||
* That multipathd created two priority groups - one with priority 1 and one
|
||||
with priority 130.
|
||||
* That the SRP path with SCSI host number 10 will be used for communication
|
||||
with LUN "disk01" and that the SRP path with SCSI host number 11 will be used
|
||||
for communication with LUN "disk02".
|
||||
|
||||
More information about how to configure the device mapper and the scsi_dh_alua
|
||||
driver can be found in the manual of your Linux distribution ("man
|
||||
multipath.conf").
|
||||
multipath.conf", "man multipath" and "man multipathd").
|
||||
|
||||
Windows initiator systems support ALUA from Windows Server 2008 on. For more
|
||||
information about ALUA support in Windows Server, see also:
|
||||
|
||||
+20
-10
@@ -807,6 +807,11 @@ cache. The following parameters possible for vdisk_fileio:
|
||||
initiators can unmap blocks of storage, if they don't need them
|
||||
anymore. Backend storage also must support this facility.
|
||||
|
||||
- tst - allows to specify TST control mode page field. It specifies
|
||||
the type of task set in the device. Possible values are: 0 - the
|
||||
device maintains one task set for all I_T nexuses and 1 - the device
|
||||
maintains separate task sets for each I_T nexus. Default - 1.
|
||||
|
||||
- removable - with this flag set the device is reported to remote
|
||||
initiators as removable.
|
||||
|
||||
@@ -823,16 +828,17 @@ storage HBAs and for applications that either do not need caching
|
||||
between application and disk or need the large block throughput. See
|
||||
below for more info.
|
||||
|
||||
The following parameters possible for vdisk_blockio: filename,
|
||||
blocksize, nv_cache, read_only, removable, rotational, thin_provisioned.
|
||||
See vdisk_fileio above for description of those parameters.
|
||||
The following common with vdisk_fileio parameters are possible for
|
||||
vdisk_blockio: filename, blocksize, nv_cache, write_through, read_only,
|
||||
removable, rotational, thin_provisioned, tst. See vdisk_fileio above for
|
||||
description of those parameters.
|
||||
|
||||
Handler vdisk_nullio provides NULLIO mode to create virtual devices. In
|
||||
this mode no real I/O is done, but success returned to initiators.
|
||||
Intended to be used for performance measurements at the same way as
|
||||
"*_perf" handlers. The following parameters possible for vdisk_nullio:
|
||||
blocksize, read_only, removable. See vdisk_fileio above for description
|
||||
of those parameters.
|
||||
blocksize, read_only, removable, tst. See vdisk_fileio above for
|
||||
description of those parameters.
|
||||
|
||||
vdisk_nullio also has extra attribute:
|
||||
|
||||
@@ -844,7 +850,7 @@ vdisk_nullio also has extra attribute:
|
||||
"dummy" placeholder on LUN 0, if LUN 0 is not desired.
|
||||
|
||||
Handler vcdrom allows emulation of a virtual CDROM device using an ISO
|
||||
file as backend. It doesn't have any parameters.
|
||||
file as backend. It has only single parameter: tst.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -883,6 +889,9 @@ Each vdisk_fileio's device has the following attributes in
|
||||
SCST device belongs to (in SCSI terminology all SCST devices called
|
||||
Logical Units). See SPC for more info.
|
||||
|
||||
- tst - contains TST field of SCSI Control mode page. See SPC-4 for
|
||||
more details about this field.
|
||||
|
||||
- thin_provisioned - contains thin provisioning status of this virtual
|
||||
device.
|
||||
|
||||
@@ -939,6 +948,7 @@ For example:
|
||||
|-- thin_provisioned
|
||||
|-- threads_num
|
||||
|-- threads_pool_type
|
||||
|-- tst
|
||||
|-- type
|
||||
|-- usn
|
||||
`-- write_through
|
||||
@@ -946,17 +956,17 @@ For example:
|
||||
Each vdisk_blockio's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: blocksize, filename, nv_cache,
|
||||
read_only, removable, resync_size, rotational, size_mb, t10_dev_id,
|
||||
thin_provisioned, threads_num, threads_pool_type, type, usn. See above
|
||||
description of those parameters.
|
||||
thin_provisioned, threads_num, threads_pool_type, tst, type, usn. See
|
||||
above description of those parameters.
|
||||
|
||||
Each vdisk_nullio's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: blocksize, read_only,
|
||||
removable, size_mb, t10_dev_id, threads_num, threads_pool_type, type,
|
||||
usn, dummy. See above description of those parameters.
|
||||
tst, usn, dummy. See above description of those parameters.
|
||||
|
||||
Each vcdrom's device has the following attributes in
|
||||
/sys/kernel/scst_tgt/devices/device_name: filename, size_mb,
|
||||
t10_dev_id, threads_num, threads_pool_type, type, usn. See above
|
||||
t10_dev_id, threads_num, threads_pool_type, type, usn, tst. See above
|
||||
description of those parameters. Exception is filename attribute. For
|
||||
vcdrom it is writable. Writing to it allows to virtually insert or
|
||||
change virtual CD media in the virtual CDROM device. For example:
|
||||
|
||||
+83
-9
@@ -225,6 +225,8 @@ static inline bool list_entry_in_list(const struct list_head *entry)
|
||||
** !! as well!
|
||||
*************************************************************/
|
||||
enum {
|
||||
/** Active states **/
|
||||
|
||||
/* Dev handler's parse() is going to be called */
|
||||
SCST_CMD_STATE_PARSE = 0,
|
||||
|
||||
@@ -258,6 +260,12 @@ enum {
|
||||
/* Checks before target driver's xmit_response() is called */
|
||||
SCST_CMD_STATE_PRE_XMIT_RESP,
|
||||
|
||||
/* Checks 1 before target driver's xmit_response() is called */
|
||||
SCST_CMD_STATE_PRE_XMIT_RESP1,
|
||||
|
||||
/* Checks 2 before target driver's xmit_response() is called */
|
||||
SCST_CMD_STATE_PRE_XMIT_RESP2,
|
||||
|
||||
/* Target driver's xmit_response() is going to be called */
|
||||
SCST_CMD_STATE_XMIT_RESP,
|
||||
|
||||
@@ -269,6 +277,8 @@ enum {
|
||||
|
||||
SCST_CMD_STATE_LAST_ACTIVE = (SCST_CMD_STATE_FINISHED_INTERNAL+100),
|
||||
|
||||
/** Passive states **/
|
||||
|
||||
/* A cmd is created, but scst_cmd_init_done() not called */
|
||||
SCST_CMD_STATE_INIT_WAIT,
|
||||
|
||||
@@ -568,7 +578,11 @@ enum scst_exec_context {
|
||||
/* Set if the cmd is aborted by other initiator */
|
||||
#define SCST_CMD_ABORTED_OTHER 1
|
||||
|
||||
/* Set if no response should be sent to the target about this cmd */
|
||||
/*
|
||||
* Set if no response should be sent to the target about this cmd.
|
||||
* Must be set together with SCST_CMD_ABORTED for better processing
|
||||
* in scst_pre_xmit_response2().
|
||||
*/
|
||||
#define SCST_CMD_NO_RESP 2
|
||||
|
||||
/* Set if the cmd is dead and can be destroyed at any time */
|
||||
@@ -2078,8 +2092,8 @@ struct scst_cmd {
|
||||
|
||||
unsigned long start_time;
|
||||
|
||||
/* List entry for tgt_dev's SN related lists */
|
||||
struct list_head sn_cmd_list_entry;
|
||||
/* List entry for tgt_dev's deferred (SN, etc.) lists */
|
||||
struct list_head deferred_cmd_list_entry;
|
||||
|
||||
/* Cmd's serial number, used to execute cmd's in order of arrival */
|
||||
unsigned int sn;
|
||||
@@ -2243,6 +2257,10 @@ struct scst_cmd {
|
||||
void *cmd_data_descriptors;
|
||||
int cmd_data_descriptors_cnt;
|
||||
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
char not_parsed_op_name[8];
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCST_MEASURE_LATENCY
|
||||
uint64_t start, curr_start, parse_time, alloc_buf_time;
|
||||
uint64_t restart_waiting_time, rdy_to_xfer_time;
|
||||
@@ -2311,6 +2329,7 @@ struct scst_mgmt_cmd {
|
||||
unsigned int needs_unblocking:1;
|
||||
unsigned int lun_set:1; /* set, if lun field is valid */
|
||||
unsigned int cmd_sn_set:1; /* set, if cmd_sn field is valid */
|
||||
unsigned int scst_get_called:1; /* set, if scst_get() was called */
|
||||
/* Set if dev handler's task_mgmt_fn_received was called */
|
||||
unsigned int task_mgmt_fn_received_called:1;
|
||||
unsigned int mcmd_dropped:1; /* set if mcmd was dropped */
|
||||
@@ -2403,20 +2422,51 @@ struct scst_device {
|
||||
|
||||
/*************************************************************
|
||||
** Dev's control mode page related values. Updates serialized
|
||||
** by scst_block_dev(). Modified independently to the above
|
||||
** fields, hence the alignment.
|
||||
** by device blocking. Since device blocking protects only
|
||||
** commands on the execution stage, in all other read cases
|
||||
** use ACCESS_ONCE(), if necessary. Modified independently
|
||||
** to the above fields, hence the alignment.
|
||||
*************************************************************/
|
||||
|
||||
unsigned int queue_alg:4 __aligned(sizeof(long));
|
||||
unsigned int tst:3;
|
||||
unsigned int qerr:2;
|
||||
unsigned int tmf_only:1;
|
||||
unsigned int tas:1;
|
||||
unsigned int swp:1;
|
||||
unsigned int d_sense:1;
|
||||
|
||||
/**
|
||||
** Saved and default versions of them, which supported. TST is not
|
||||
** among them, because it's hard to switch curr_order_data on the
|
||||
** fly. To ensure that no commands lost, we need to flush the previous
|
||||
** curr_order_data at first and with one being active command (MODE
|
||||
** SELECT), we don't have facility for that at the moment. Suspending
|
||||
** activities will hang waiting for the active MODE SELECT. ToDo.
|
||||
**/
|
||||
|
||||
unsigned int queue_alg_saved:4;
|
||||
unsigned int queue_alg_default:4;
|
||||
|
||||
unsigned int tmf_only_saved:1;
|
||||
unsigned int tmf_only_default:1;
|
||||
|
||||
unsigned int qerr_saved:2;
|
||||
unsigned int qerr_default:2;
|
||||
|
||||
unsigned int tas_saved:1;
|
||||
unsigned int tas_default:1;
|
||||
|
||||
unsigned int swp_saved:1;
|
||||
unsigned int swp_default:1;
|
||||
|
||||
unsigned int d_sense_saved:1;
|
||||
unsigned int d_sense_default:1;
|
||||
|
||||
/*
|
||||
* Set if device implements own ordered commands management. If not set
|
||||
* and queue_alg is SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER,
|
||||
* expected_sn will be incremented only after commands finished.
|
||||
* and queue_alg is SCST_QUEUE_ALG_0_RESTRICTED_REORDER, expected_sn
|
||||
* will be incremented only after commands finished.
|
||||
*/
|
||||
unsigned int has_own_order_mgmt:1;
|
||||
|
||||
@@ -2884,7 +2934,6 @@ struct scst_tg_tgt {
|
||||
uint16_t rel_tgt_id;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Used to store per-session UNIT ATTENTIONs
|
||||
*/
|
||||
@@ -4260,7 +4309,7 @@ static inline int scst_check_local_events(struct scst_cmd *cmd)
|
||||
return __scst_check_local_events(cmd, true);
|
||||
}
|
||||
|
||||
int scst_get_cmd_abnormal_done_state(const struct scst_cmd *cmd);
|
||||
int scst_get_cmd_abnormal_done_state(struct scst_cmd *cmd);
|
||||
void scst_set_cmd_abnormal_done_state(struct scst_cmd *cmd);
|
||||
|
||||
struct scst_trace_log {
|
||||
@@ -4559,6 +4608,15 @@ static inline void put_unaligned_be24(const uint32_t v, uint8_t *const p)
|
||||
p[2] = v >> 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
const char *scst_get_opcode_name(struct scst_cmd *cmd);
|
||||
#else
|
||||
static inline const char *scst_get_opcode_name(struct scst_cmd *cmd)
|
||||
{
|
||||
return cmd->op_name;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SCST_PROC
|
||||
|
||||
/*
|
||||
@@ -4593,6 +4651,7 @@ int scst_wait_info_completion(struct scst_sysfs_user_info *info,
|
||||
|
||||
unsigned int scst_get_setup_id(void);
|
||||
|
||||
|
||||
/*
|
||||
* Needed to avoid potential circular locking dependency between scst_mutex
|
||||
* and internal sysfs locking (s_active). It could be since most sysfs entries
|
||||
@@ -4694,4 +4753,19 @@ void scst_write_same(struct scst_cmd *cmd);
|
||||
__be64 scst_pack_lun(const uint64_t lun, enum scst_lun_addr_method addr_method);
|
||||
uint64_t scst_unpack_lun(const uint8_t *lun, int len);
|
||||
|
||||
int scst_save_global_mode_pages(const struct scst_device *dev,
|
||||
uint8_t *buf, int size);
|
||||
int scst_restore_global_mode_pages(struct scst_device *dev, char *params,
|
||||
char **last_param);
|
||||
|
||||
int scst_read_file_transactional(const char *name, const char *name1,
|
||||
const char *signature, int signature_len, uint8_t *buf, int size);
|
||||
int scst_write_file_transactional(const char *name, const char *name1,
|
||||
const char *signature, int signature_len, const uint8_t *buf, int size);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
|
||||
void scst_path_put(struct nameidata *nd);
|
||||
#endif
|
||||
int scst_remove_file(const char *name);
|
||||
|
||||
#endif /* __SCST_H */
|
||||
|
||||
@@ -495,20 +495,28 @@ enum {
|
||||
/*************************************************************
|
||||
** Values for the control mode page TST field
|
||||
*************************************************************/
|
||||
#define SCST_CONTR_MODE_ONE_TASK_SET 0
|
||||
#define SCST_CONTR_MODE_SEP_TASK_SETS 1
|
||||
#define SCST_TST_0_SINGLE_TASK_SET 0
|
||||
#define SCST_TST_1_SEP_TASK_SETS 1
|
||||
|
||||
/*******************************************************************
|
||||
** Values for the control mode page QUEUE ALGORITHM MODIFIER field
|
||||
*******************************************************************/
|
||||
#define SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER 0
|
||||
#define SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER 1
|
||||
#define SCST_QUEUE_ALG_0_RESTRICTED_REORDER 0
|
||||
#define SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER 1
|
||||
|
||||
/*************************************************************
|
||||
** Values for the control mode page D_SENSE field
|
||||
*************************************************************/
|
||||
#define SCST_CONTR_MODE_FIXED_SENSE 0
|
||||
#define SCST_CONTR_MODE_DESCR_SENSE 1
|
||||
#define SCST_D_SENSE_0_FIXED_SENSE 0
|
||||
#define SCST_D_SENSE_1_DESCR_SENSE 1
|
||||
|
||||
/*************************************************************
|
||||
** Values for the control mode page QErr field
|
||||
*************************************************************/
|
||||
#define SCST_QERR_0_ALL_RESUME 0
|
||||
#define SCST_QERR_1_ABORT_ALL 1
|
||||
#define SCST_QERR_2_RESERVED 2
|
||||
#define SCST_QERR_3_ABORT_THIS_NEXUS_ONLY 3
|
||||
|
||||
/*************************************************************
|
||||
** TransportID protocol identifiers
|
||||
|
||||
@@ -88,7 +88,9 @@ struct scst_user_opt {
|
||||
|
||||
/* SCSI control mode page parameters, see SPC */
|
||||
uint8_t tst;
|
||||
uint8_t tmf_only;
|
||||
uint8_t queue_alg;
|
||||
uint8_t qerr;
|
||||
uint8_t tas;
|
||||
uint8_t swp;
|
||||
uint8_t d_sense;
|
||||
|
||||
+1
-1
@@ -116,7 +116,7 @@ endif
|
||||
@echo "*!! target drivers, custom dev handlers and necessary user !!*"
|
||||
@echo "*!! space applications. Otherwise, because of the versions !!*"
|
||||
@echo "*!! mismatch, you could have many problems and crashes. !!*"
|
||||
@echo "*!! See IMPORTANT note in the \"Installation\" section of !!*"
|
||||
@echo "*!! See IMPORTANT note in the \"Installation\" section of !!*"
|
||||
@echo "*!! SCST's README file for more info. !!*"
|
||||
@echo "*!! !!*"
|
||||
@echo "*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*"
|
||||
|
||||
@@ -71,6 +71,7 @@ all:
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)
|
||||
|
||||
install: all
|
||||
mkdir -p $(DESTDIR)/var/lib/scst/vdev_mode_pages
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) \
|
||||
modules_install
|
||||
|
||||
|
||||
@@ -406,8 +406,9 @@ static int disk_exec(struct scst_cmd *cmd)
|
||||
if (unlikely((cmd->bufflen >> block_shift) > max_sectors)) {
|
||||
if ((cmd->out_bufflen >> block_shift) > max_sectors) {
|
||||
PRINT_ERROR("Too limited max_sectors %d for "
|
||||
"bidirectional cmd %x (out_bufflen %d)",
|
||||
max_sectors, cmd->cdb[0], cmd->out_bufflen);
|
||||
"bidirectional cmd %p (op %s, out_bufflen %d)",
|
||||
max_sectors, cmd, scst_get_opcode_name(cmd),
|
||||
cmd->out_bufflen);
|
||||
/* Let lower level handle it */
|
||||
res = SCST_EXEC_NOT_COMPLETED;
|
||||
goto out;
|
||||
|
||||
@@ -62,7 +62,9 @@ struct scst_user_dev {
|
||||
unsigned int blocking:1;
|
||||
unsigned int cleanup_done:1;
|
||||
unsigned int tst:3;
|
||||
unsigned int tmf_only:1;
|
||||
unsigned int queue_alg:4;
|
||||
unsigned int qerr:2;
|
||||
unsigned int tas:1;
|
||||
unsigned int swp:1;
|
||||
unsigned int d_sense:1;
|
||||
@@ -1368,8 +1370,8 @@ out_process:
|
||||
return res;
|
||||
|
||||
out_inval:
|
||||
PRINT_ERROR("Invalid parse_reply parameters (LUN %lld, op %x, cmd %p)",
|
||||
(long long unsigned int)cmd->lun, cmd->cdb[0], cmd);
|
||||
PRINT_ERROR("Invalid parse_reply parameters (LUN %lld, op %s, cmd %p)",
|
||||
(long long unsigned int)cmd->lun, scst_get_opcode_name(cmd), cmd);
|
||||
PRINT_BUFFER("Invalid parse_reply", reply, sizeof(*reply));
|
||||
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
res = -EINVAL;
|
||||
@@ -1554,8 +1556,8 @@ out:
|
||||
return res;
|
||||
|
||||
out_inval:
|
||||
PRINT_ERROR("Invalid exec_reply parameters (LUN %lld, op %x, cmd %p)",
|
||||
(long long unsigned int)cmd->lun, cmd->cdb[0], cmd);
|
||||
PRINT_ERROR("Invalid exec_reply parameters (LUN %lld, op %s, cmd %p)",
|
||||
(long long unsigned int)cmd->lun, scst_get_opcode_name(cmd), cmd);
|
||||
PRINT_BUFFER("Invalid exec_reply", reply, sizeof(*reply));
|
||||
|
||||
out_hwerr:
|
||||
@@ -2618,10 +2620,22 @@ static int dev_user_attach(struct scst_device *sdev)
|
||||
|
||||
sdev->dh_priv = dev;
|
||||
sdev->tst = dev->tst;
|
||||
sdev->tmf_only = dev->tmf_only;
|
||||
sdev->tmf_only_saved = dev->tmf_only;
|
||||
sdev->tmf_only_default = dev->tmf_only;
|
||||
sdev->queue_alg = dev->queue_alg;
|
||||
sdev->qerr = dev->qerr;
|
||||
sdev->qerr_saved = dev->qerr;
|
||||
sdev->qerr_default = dev->qerr;
|
||||
sdev->swp = dev->swp;
|
||||
sdev->swp_saved = dev->swp;
|
||||
sdev->swp_default = dev->swp;
|
||||
sdev->tas = dev->tas;
|
||||
sdev->tas_saved = dev->tas;
|
||||
sdev->tas_default = dev->tas;
|
||||
sdev->d_sense = dev->d_sense;
|
||||
sdev->d_sense_saved = dev->d_sense;
|
||||
sdev->d_sense_default = dev->d_sense;
|
||||
sdev->has_own_order_mgmt = dev->has_own_order_mgmt;
|
||||
|
||||
dev->sdev = sdev;
|
||||
@@ -3350,20 +3364,34 @@ 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)) ||
|
||||
if (((opt->tst != SCST_TST_0_SINGLE_TASK_SET) &&
|
||||
(opt->tst != SCST_TST_1_SEP_TASK_SETS)) ||
|
||||
(opt->tmf_only > 1) ||
|
||||
((opt->queue_alg != SCST_QUEUE_ALG_0_RESTRICTED_REORDER) &&
|
||||
(opt->queue_alg != SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER)) ||
|
||||
((opt->qerr == SCST_QERR_2_RESERVED) ||
|
||||
(opt->qerr > SCST_QERR_3_ABORT_THIS_NEXUS_ONLY)) ||
|
||||
(opt->swp > 1) || (opt->tas > 1) || (opt->has_own_order_mgmt > 1) ||
|
||||
(opt->d_sense > 1)) {
|
||||
PRINT_ERROR("Invalid SCSI option (tst %x, queue_alg %x, swp %x,"
|
||||
" tas %x, d_sense %d, has_own_order_mgmt %x)", opt->tst,
|
||||
opt->queue_alg, opt->swp, opt->tas, opt->d_sense,
|
||||
opt->has_own_order_mgmt);
|
||||
PRINT_ERROR("Invalid SCSI option (tst %x, tmf_only %x, "
|
||||
"queue_alg %x, qerr %x, swp %x, tas %x, d_sense %d, "
|
||||
"has_own_order_mgmt %x)",
|
||||
opt->tst, opt->tmf_only, opt->queue_alg, opt->qerr,
|
||||
opt->swp, opt->tas, opt->d_sense, opt->has_own_order_mgmt);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if 1
|
||||
if ((dev->tst != opt->tst) && (dev->sdev != NULL) &&
|
||||
!list_empty(&dev->sdev->dev_tgt_dev_list)) {
|
||||
PRINT_ERROR("On the fly setting of TST not supported. "
|
||||
"See comment in struct scst_device.");
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
dev->parse_type = opt->parse_type;
|
||||
dev->on_free_cmd_type = opt->on_free_cmd_type;
|
||||
dev->memory_reuse_type = opt->memory_reuse_type;
|
||||
@@ -3371,14 +3399,18 @@ static int __dev_user_set_opt(struct scst_user_dev *dev,
|
||||
dev->partial_len = opt->partial_len;
|
||||
|
||||
dev->tst = opt->tst;
|
||||
dev->tmf_only = opt->tmf_only;
|
||||
dev->queue_alg = opt->queue_alg;
|
||||
dev->qerr = opt->qerr;
|
||||
dev->swp = opt->swp;
|
||||
dev->tas = opt->tas;
|
||||
dev->d_sense = opt->d_sense;
|
||||
dev->has_own_order_mgmt = opt->has_own_order_mgmt;
|
||||
if (dev->sdev != NULL) {
|
||||
dev->sdev->tst = opt->tst;
|
||||
dev->sdev->tmf_only = opt->tmf_only;
|
||||
dev->sdev->queue_alg = opt->queue_alg;
|
||||
dev->sdev->qerr = opt->qerr;
|
||||
dev->sdev->swp = opt->swp;
|
||||
dev->sdev->tas = opt->tas;
|
||||
dev->sdev->d_sense = opt->d_sense;
|
||||
@@ -3449,7 +3481,9 @@ static int dev_user_get_opt(struct file *file, void __user *arg)
|
||||
opt.partial_transfers_type = dev->partial_transfers_type;
|
||||
opt.partial_len = dev->partial_len;
|
||||
opt.tst = dev->tst;
|
||||
opt.tmf_only = dev->tmf_only;
|
||||
opt.queue_alg = dev->queue_alg;
|
||||
opt.qerr = dev->qerr;
|
||||
opt.tas = dev->tas;
|
||||
opt.swp = dev->swp;
|
||||
opt.d_sense = dev->d_sense;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+801
-79
File diff suppressed because it is too large
Load Diff
@@ -960,8 +960,8 @@ int scst_suspend_activity(unsigned long timeout)
|
||||
set_bit(SCST_FLAG_SUSPENDED, &scst_flags);
|
||||
/*
|
||||
* Assignment of SCST_FLAG_SUSPENDING and SCST_FLAG_SUSPENDED must be
|
||||
* ordered with cpu_cmd_count in scst_get(). Otherwise lockless logic in
|
||||
* scst_translate_lun() and scst_mgmt_translate_lun() won't work.
|
||||
* ordered with cpu_cmd_count in scst_get(). Otherwise, lockless logic
|
||||
* of scst_get() users won't work.
|
||||
*/
|
||||
smp_mb__after_set_bit();
|
||||
|
||||
|
||||
+40
-19
@@ -565,6 +565,27 @@ static void scst_pr_abort_reg(struct scst_device *dev,
|
||||
*/
|
||||
PRINT_ERROR("SCST_PR_ABORT_ALL failed %d (sess %p)",
|
||||
rc, sess);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((reg->tgt_dev != pr_cmd->tgt_dev) && !dev->tas) {
|
||||
uint8_t sense_buffer[SCST_STANDARD_SENSE_LEN];
|
||||
int sl;
|
||||
sl = scst_set_sense(sense_buffer, sizeof(sense_buffer),
|
||||
dev->d_sense,
|
||||
SCST_LOAD_SENSE(scst_sense_cleared_by_another_ini_UA));
|
||||
/*
|
||||
* Potentially, setting UA here, when the aborted commands are
|
||||
* still running, can lead to a situation that one of them could
|
||||
* take it, then that would be detected and the UA requeued.
|
||||
* But, meanwhile, one or more subsequent, i.e. not aborted,
|
||||
* commands can "leak" executed normally. So, as result, the
|
||||
* UA would be delivered one or more commands "later". However,
|
||||
* that should be OK, because, if multiple commands are being
|
||||
* executed in parallel, you can't control exact order of UA
|
||||
* delivery anyway.
|
||||
*/
|
||||
scst_check_set_UA(reg->tgt_dev, sense_buffer, sl, 0);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -1559,8 +1580,8 @@ void scst_pr_register(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
|
||||
}
|
||||
if (spec_i_pt) {
|
||||
TRACE_PR("%s", "spec_i_pt must be zero in this case");
|
||||
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(
|
||||
scst_sense_invalid_field_in_cdb));
|
||||
scst_set_invalid_field_in_parm_list(cmd, 20,
|
||||
SCST_INVAL_FIELD_BIT_OFFS_VALID | 3);
|
||||
goto out;
|
||||
}
|
||||
if (action_key == 0) {
|
||||
@@ -1700,8 +1721,7 @@ void scst_pr_register_and_move(struct scst_cmd *cmd, uint8_t *buffer,
|
||||
|
||||
if (tid_buffer_size < 24) {
|
||||
TRACE_PR("%s", "Transport id buffer too small");
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_field_in_parm_list));
|
||||
scst_set_invalid_field_in_parm_list(cmd, 20, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1730,9 +1750,8 @@ void scst_pr_register_and_move(struct scst_cmd *cmd, uint8_t *buffer,
|
||||
*/
|
||||
if (!scst_pr_is_holder(dev, reg)) {
|
||||
TRACE_PR("Registrant %s/%d (%p) is not a holder (tgt_dev %p)",
|
||||
debug_transport_id_to_initiator_name(
|
||||
reg->transport_id), reg->rel_tgt_id,
|
||||
reg, tgt_dev);
|
||||
debug_transport_id_to_initiator_name(reg->transport_id),
|
||||
reg->rel_tgt_id, reg, tgt_dev);
|
||||
scst_set_cmd_error_status(cmd, SAM_STAT_RESERVATION_CONFLICT);
|
||||
goto out;
|
||||
}
|
||||
@@ -2267,8 +2286,9 @@ bool scst_pr_crh_case(struct scst_cmd *cmd)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_DBG("Test if there is a CRH case for command %s (0x%x) from "
|
||||
"%s", cmd->op_name, cmd->cdb[0], cmd->sess->initiator_name);
|
||||
TRACE_DBG("Test if there is a CRH case for command %s (%s) from "
|
||||
"%s", cmd->op_name, scst_get_opcode_name(cmd),
|
||||
cmd->sess->initiator_name);
|
||||
|
||||
if (!dev->pr_is_set) {
|
||||
TRACE_PR("%s", "PR not set");
|
||||
@@ -2303,12 +2323,12 @@ bool scst_pr_crh_case(struct scst_cmd *cmd)
|
||||
}
|
||||
|
||||
if (!allowed)
|
||||
TRACE_PR("Command %s (0x%x) from %s rejected due to not CRH "
|
||||
"reservation", cmd->op_name, cmd->cdb[0],
|
||||
TRACE_PR("Command %s (%s) from %s rejected due to not CRH "
|
||||
"reservation", cmd->op_name, scst_get_opcode_name(cmd),
|
||||
cmd->sess->initiator_name);
|
||||
else
|
||||
TRACE_DBG("Command %s (0x%x) from %s is allowed to execute "
|
||||
"due to CRH", cmd->op_name, cmd->cdb[0],
|
||||
TRACE_DBG("Command %s (%s) from %s is allowed to execute "
|
||||
"due to CRH", cmd->op_name, scst_get_opcode_name(cmd),
|
||||
cmd->sess->initiator_name);
|
||||
|
||||
out:
|
||||
@@ -2330,8 +2350,8 @@ bool scst_pr_is_cmd_allowed(struct scst_cmd *cmd)
|
||||
|
||||
scst_pr_read_lock(dev);
|
||||
|
||||
TRACE_DBG("Testing if command %s (0x%x) from %s allowed to execute",
|
||||
cmd->op_name, cmd->cdb[0], cmd->sess->initiator_name);
|
||||
TRACE_DBG("Testing if command %s (%s) from %s allowed to execute",
|
||||
cmd->op_name, scst_get_opcode_name(cmd), cmd->sess->initiator_name);
|
||||
|
||||
/* Recheck, because it can change while we were waiting for the lock */
|
||||
if (unlikely(!dev->pr_is_set)) {
|
||||
@@ -2380,12 +2400,13 @@ bool scst_pr_is_cmd_allowed(struct scst_cmd *cmd)
|
||||
}
|
||||
|
||||
if (!allowed)
|
||||
TRACE_PR("Command %s (0x%x) from %s rejected due "
|
||||
"to PR", cmd->op_name, cmd->cdb[0],
|
||||
TRACE_PR("Command %s (%s) from %s rejected due "
|
||||
"to PR", cmd->op_name, scst_get_opcode_name(cmd),
|
||||
cmd->sess->initiator_name);
|
||||
else
|
||||
TRACE_DBG("Command %s (0x%x) from %s is allowed to execute",
|
||||
cmd->op_name, cmd->cdb[0], cmd->sess->initiator_name);
|
||||
TRACE_DBG("Command %s (%s) from %s is allowed to execute",
|
||||
cmd->op_name, scst_get_opcode_name(cmd),
|
||||
cmd->sess->initiator_name);
|
||||
|
||||
out_unlock:
|
||||
scst_pr_read_unlock(dev);
|
||||
|
||||
@@ -375,6 +375,8 @@ int scst_set_cmd_error_sense(struct scst_cmd *cmd, uint8_t *sense,
|
||||
unsigned int len);
|
||||
void scst_store_sense(struct scst_cmd *cmd);
|
||||
|
||||
int scst_process_check_condition(struct scst_cmd *cmd);
|
||||
|
||||
int scst_assign_dev_handler(struct scst_device *dev,
|
||||
struct scst_dev_type *handler);
|
||||
|
||||
@@ -770,16 +772,11 @@ void scst_vfs_unlink_and_put(struct nameidata *nd);
|
||||
void scst_vfs_unlink_and_put(struct path *path);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
|
||||
void scst_path_put(struct nameidata *nd);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
|
||||
int scst_vfs_fsync(struct file *file, loff_t loff, loff_t len);
|
||||
#endif
|
||||
|
||||
int scst_copy_file(const char *src, const char *dest);
|
||||
int scst_remove_file(const char *name);
|
||||
|
||||
#ifdef CONFIG_SCST_DEBUG_TM
|
||||
extern void tm_dbg_check_released_cmds(void);
|
||||
|
||||
@@ -397,7 +397,12 @@ int scst_proc_log_entry_write(struct file *file, const char __user *buf,
|
||||
|
||||
list_for_each_entry(dev, &scst_dev_list, dev_list_entry) {
|
||||
if (strcmp(dev->virt_name, p) == 0) {
|
||||
scst_pr_dump_prs(dev, true);
|
||||
if (mutex_lock_interruptible(&dev->dev_pr_mutex) == 0) {
|
||||
scst_pr_dump_prs(dev, true);
|
||||
mutex_unlock(&dev->dev_pr_mutex);
|
||||
} else {
|
||||
res = -EINTR;
|
||||
}
|
||||
goto out_up;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-4
@@ -2762,15 +2762,23 @@ static ssize_t scst_dev_sysfs_dump_prs(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct scst_device *dev;
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
|
||||
res = mutex_lock_interruptible(&dev->dev_pr_mutex);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
scst_pr_dump_prs(dev, true);
|
||||
mutex_unlock(&dev->dev_pr_mutex);
|
||||
|
||||
TRACE_EXIT_RES(count);
|
||||
return count;
|
||||
res = count;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct kobj_attribute dev_dump_prs_attr =
|
||||
@@ -5414,8 +5422,8 @@ static ssize_t scst_tg_preferred_show(struct kobject *kobj,
|
||||
struct scst_target_group *tg;
|
||||
|
||||
tg = container_of(kobj, struct scst_target_group, kobj);
|
||||
return scnprintf(buf, PAGE_SIZE, "%u\n%s",
|
||||
tg->preferred, SCST_SYSFS_KEY_MARK "\n");
|
||||
return scnprintf(buf, PAGE_SIZE, "%u\n%s", tg->preferred,
|
||||
tg->preferred ? SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
}
|
||||
|
||||
static int scst_tg_preferred_store_work_fn(struct scst_sysfs_work_item *w)
|
||||
|
||||
+259
-174
@@ -413,12 +413,12 @@ void scst_cmd_init_done(struct scst_cmd *cmd,
|
||||
scst_set_start_time(cmd);
|
||||
|
||||
TRACE_DBG("Preferred context: %d (cmd %p)", pref_context, cmd);
|
||||
TRACE(TRACE_SCSI, "lun=%lld, initiator %s, target %s, CDB len=%d, "
|
||||
"queue_type=%x, tag=%llu (cmd %p, sess %p)",
|
||||
(long long unsigned int)cmd->lun, cmd->sess->initiator_name,
|
||||
cmd->tgt->tgt_name, cmd->cdb_len, cmd->queue_type,
|
||||
TRACE(TRACE_SCSI, "NEW CDB: len %d, lun %lld, initiator %s, "
|
||||
"target %s, queue_type %x, tag %llu (cmd %p, sess %p)",
|
||||
cmd->cdb_len, (long long unsigned int)cmd->lun,
|
||||
cmd->sess->initiator_name, cmd->tgt->tgt_name, cmd->queue_type,
|
||||
(long long unsigned int)cmd->tag, cmd, sess);
|
||||
PRINT_BUFF_FLAG(TRACE_SCSI, "Receiving CDB", cmd->cdb, cmd->cdb_len);
|
||||
PRINT_BUFF_FLAG(TRACE_SCSI, "CDB", cmd->cdb, cmd->cdb_len);
|
||||
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
if (unlikely((in_irq() || irqs_disabled())) &&
|
||||
@@ -570,19 +570,19 @@ int scst_pre_parse(struct scst_cmd *cmd)
|
||||
#else
|
||||
cmd->inc_expected_sn_on_done = devt->exec_sync ||
|
||||
(!dev->has_own_order_mgmt &&
|
||||
(dev->queue_alg == SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER ||
|
||||
(dev->queue_alg == SCST_QUEUE_ALG_0_RESTRICTED_REORDER ||
|
||||
cmd->queue_type == SCST_CMD_QUEUE_ORDERED));
|
||||
#endif
|
||||
|
||||
TRACE_DBG("op_name <%s> (cmd %p), direction=%d "
|
||||
"(expected %d, set %s), lba %lld, bufflen=%d, data_len %lld, "
|
||||
"out_bufflen=%d (expected len %d, out expected len %d), "
|
||||
"flags=0x%x", cmd->op_name, cmd, cmd->data_direction,
|
||||
"flags=0x%x, naca %d", cmd->op_name, cmd, cmd->data_direction,
|
||||
cmd->expected_data_direction,
|
||||
scst_cmd_is_expected_set(cmd) ? "yes" : "no",
|
||||
(long long)cmd->lba, cmd->bufflen, (long long)cmd->data_len,
|
||||
cmd->out_bufflen, cmd->expected_transfer_len,
|
||||
cmd->expected_out_transfer_len, cmd->op_flags);
|
||||
cmd->expected_out_transfer_len, cmd->op_flags, cmd->cmd_naca);
|
||||
|
||||
res = 0;
|
||||
|
||||
@@ -700,8 +700,8 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
|
||||
if (unlikely(cmd->cdb_len == 0)) {
|
||||
PRINT_ERROR("Unable to get CDB length for "
|
||||
"opcode 0x%02x. Returning INVALID "
|
||||
"OPCODE", cmd->cdb[0]);
|
||||
"opcode %s. Returning INVALID "
|
||||
"OPCODE", scst_get_opcode_name(cmd));
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_opcode));
|
||||
goto out_done;
|
||||
@@ -726,8 +726,9 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
} else {
|
||||
if (cmd->bufflen == 0) {
|
||||
PRINT_ERROR("Unknown data transfer length for opcode "
|
||||
"0x%x (handler %s, target %s)", cmd->cdb[0],
|
||||
devt->name, cmd->tgtt->name);
|
||||
"%s (handler %s, target %s)",
|
||||
scst_get_opcode_name(cmd), devt->name,
|
||||
cmd->tgtt->name);
|
||||
PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_message));
|
||||
@@ -747,7 +748,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
|
||||
if (unlikely(cmd->cmd_linked)) {
|
||||
PRINT_ERROR("Linked commands are not supported "
|
||||
"(opcode 0x%02x)", cmd->cdb[0]);
|
||||
"(opcode %s)", scst_get_opcode_name(cmd));
|
||||
scst_set_invalid_field_in_cdb(cmd, cmd->cdb_len-1,
|
||||
SCST_INVAL_FIELD_BIT_OFFS_VALID | 0);
|
||||
goto out_done;
|
||||
@@ -768,9 +769,9 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
((cmd->sg == NULL) && (state > SCST_CMD_STATE_PREPARE_SPACE)))) {
|
||||
PRINT_ERROR("Dev handler %s parse() returned "
|
||||
"invalid cmd data_direction %d, bufflen %d, state %d "
|
||||
"or sg %p (opcode 0x%x)", devt->name,
|
||||
"or sg %p (opcode %s)", devt->name,
|
||||
cmd->data_direction, cmd->bufflen, state, cmd->sg,
|
||||
cmd->cdb[0]);
|
||||
scst_get_opcode_name(cmd));
|
||||
PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len);
|
||||
goto out_hw_error;
|
||||
}
|
||||
@@ -805,10 +806,10 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
(cmd->bufflen != 0)) &&
|
||||
!scst_is_allowed_to_mismatch_cmd(cmd)) {
|
||||
PRINT_ERROR("Expected data direction %d for "
|
||||
"opcode 0x%02x (handler %s, target %s) "
|
||||
"opcode %s (handler %s, target %s) "
|
||||
"doesn't match decoded value %d",
|
||||
cmd->expected_data_direction,
|
||||
cmd->cdb[0], devt->name,
|
||||
scst_get_opcode_name(cmd), devt->name,
|
||||
cmd->tgtt->name, cmd->data_direction);
|
||||
PRINT_BUFFER("Failed CDB", cmd->cdb,
|
||||
cmd->cdb_len);
|
||||
@@ -819,10 +820,10 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
}
|
||||
if (unlikely(cmd->bufflen != cmd->expected_transfer_len)) {
|
||||
TRACE(TRACE_MINOR, "Warning: expected "
|
||||
"transfer length %d for opcode 0x%02x "
|
||||
"transfer length %d for opcode %s "
|
||||
"(handler %s, target %s) doesn't match "
|
||||
"decoded value %d",
|
||||
cmd->expected_transfer_len, cmd->cdb[0],
|
||||
cmd->expected_transfer_len, scst_get_opcode_name(cmd),
|
||||
devt->name, cmd->tgtt->name, cmd->bufflen);
|
||||
PRINT_BUFF_FLAG(TRACE_MINOR, "Suspicious CDB",
|
||||
cmd->cdb, cmd->cdb_len);
|
||||
@@ -832,12 +833,12 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
}
|
||||
if (unlikely(cmd->out_bufflen != cmd->expected_out_transfer_len)) {
|
||||
TRACE(TRACE_MINOR, "Warning: expected bidirectional OUT "
|
||||
"transfer length %d for opcode 0x%02x "
|
||||
"transfer length %d for opcode %s "
|
||||
"(handler %s, target %s) doesn't match "
|
||||
"decoded value %d",
|
||||
cmd->expected_out_transfer_len, cmd->cdb[0],
|
||||
devt->name, cmd->tgtt->name,
|
||||
cmd->out_bufflen);
|
||||
cmd->expected_out_transfer_len,
|
||||
scst_get_opcode_name(cmd), devt->name,
|
||||
cmd->tgtt->name, cmd->out_bufflen);
|
||||
PRINT_BUFF_FLAG(TRACE_MINOR, "Suspicious CDB",
|
||||
cmd->cdb, cmd->cdb_len);
|
||||
cmd->resid_possible = 1;
|
||||
@@ -846,16 +847,17 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
}
|
||||
|
||||
if (unlikely(cmd->data_direction == SCST_DATA_UNKNOWN)) {
|
||||
PRINT_ERROR("Unknown data direction. Opcode 0x%x, handler %s, "
|
||||
"target %s", cmd->cdb[0], devt->name,
|
||||
PRINT_ERROR("Unknown data direction (opcode %s, handler %s, "
|
||||
"target %s)", scst_get_opcode_name(cmd), devt->name,
|
||||
cmd->tgtt->name);
|
||||
PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len);
|
||||
goto out_hw_error;
|
||||
}
|
||||
|
||||
if (unlikely(cmd->op_flags & SCST_UNKNOWN_LBA)) {
|
||||
PRINT_ERROR("Unknown LBA (opcode 0x%x, handler %s, "
|
||||
"target %s)", cmd->cdb[0], devt->name, cmd->tgtt->name);
|
||||
PRINT_ERROR("Unknown LBA (opcode %s, handler %s, "
|
||||
"target %s)", scst_get_opcode_name(cmd), devt->name,
|
||||
cmd->tgtt->name);
|
||||
PRINT_BUFFER("Failed CDB", cmd->cdb, cmd->cdb_len);
|
||||
goto out_hw_error;
|
||||
}
|
||||
@@ -872,13 +874,13 @@ set_res:
|
||||
TRACE(TRACE_SCSI, "op_name <%s> (cmd %p), direction=%d "
|
||||
"(expected %d, set %s), lba=%lld, bufflen=%d, data len %lld, "
|
||||
"out_bufflen=%d, (expected len %d, out expected len %d), "
|
||||
"flags=0x%x, internal %d", cmd->op_name, cmd,
|
||||
"flags=0x%x, internal %d, naca %d", cmd->op_name, cmd,
|
||||
cmd->data_direction, cmd->expected_data_direction,
|
||||
scst_cmd_is_expected_set(cmd) ? "yes" : "no",
|
||||
(unsigned long long)cmd->lba,
|
||||
cmd->bufflen, (long long)cmd->data_len, cmd->out_bufflen,
|
||||
cmd->expected_transfer_len, cmd->expected_out_transfer_len,
|
||||
cmd->op_flags, cmd->internal);
|
||||
cmd->op_flags, cmd->internal, cmd->cmd_naca);
|
||||
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
switch (state) {
|
||||
@@ -893,7 +895,8 @@ set_res:
|
||||
case SCST_CMD_STATE_REAL_EXEC:
|
||||
case SCST_CMD_STATE_PRE_DEV_DONE:
|
||||
case SCST_CMD_STATE_DEV_DONE:
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP:
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP1:
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP2:
|
||||
case SCST_CMD_STATE_XMIT_RESP:
|
||||
case SCST_CMD_STATE_FINISHED:
|
||||
case SCST_CMD_STATE_FINISHED_INTERNAL:
|
||||
@@ -906,12 +909,12 @@ set_res:
|
||||
default:
|
||||
if (state >= 0) {
|
||||
PRINT_ERROR("Dev handler %s parse() returned "
|
||||
"invalid cmd state %d (opcode %d)",
|
||||
devt->name, state, cmd->cdb[0]);
|
||||
"invalid cmd state %d (opcode %s)",
|
||||
devt->name, state, scst_get_opcode_name(cmd));
|
||||
} else {
|
||||
PRINT_ERROR("Dev handler %s parse() returned "
|
||||
"error %d (opcode %d)", devt->name,
|
||||
state, cmd->cdb[0]);
|
||||
"error %d (opcode %s)", devt->name,
|
||||
state, scst_get_opcode_name(cmd));
|
||||
}
|
||||
goto out_hw_error;
|
||||
}
|
||||
@@ -989,12 +992,10 @@ out:
|
||||
break;
|
||||
}
|
||||
if (abort) {
|
||||
TRACE_MGMT_DBG("Black hole: aborting cmd %p (op %x, "
|
||||
"initiator %s)", cmd, cmd->cdb[0],
|
||||
TRACE_MGMT_DBG("Black hole: aborting cmd %p (op %s, "
|
||||
"initiator %s)", cmd, scst_get_opcode_name(cmd),
|
||||
sess->initiator_name);
|
||||
spin_lock_irq(&sess->sess_list_lock);
|
||||
scst_abort_cmd(cmd, NULL, false, false);
|
||||
spin_unlock_irq(&sess->sess_list_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1304,7 +1305,9 @@ void scst_restart_cmd(struct scst_cmd *cmd, int status,
|
||||
break;
|
||||
|
||||
case SCST_PREPROCESS_STATUS_ERROR_FATAL:
|
||||
set_bit(SCST_CMD_ABORTED, &cmd->cmd_flags);
|
||||
set_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags);
|
||||
cmd->delivery_status = SCST_CMD_DELIVERY_FAILED;
|
||||
/* go through */
|
||||
case SCST_PREPROCESS_STATUS_ERROR:
|
||||
if (cmd->sense != NULL)
|
||||
@@ -1515,7 +1518,6 @@ void scst_rx_data(struct scst_cmd *cmd, int status,
|
||||
scst_set_rdy_to_xfer_time(cmd);
|
||||
|
||||
TRACE_DBG("Preferred context: %d", pref_context);
|
||||
TRACE(TRACE_SCSI, "cmd %p, status %#x", cmd, status);
|
||||
|
||||
cmd->cmd_hw_pending = 0;
|
||||
|
||||
@@ -1540,7 +1542,10 @@ void scst_rx_data(struct scst_cmd *cmd, int status,
|
||||
break;
|
||||
#endif
|
||||
|
||||
/* Small context optimization */
|
||||
/*
|
||||
* Make sure that the exec phase runs in thread context since
|
||||
* invoking I/O functions from atomic context is not allowed.
|
||||
*/
|
||||
if ((pref_context == SCST_CONTEXT_TASKLET) ||
|
||||
(pref_context == SCST_CONTEXT_DIRECT_ATOMIC) ||
|
||||
((pref_context == SCST_CONTEXT_SAME) &&
|
||||
@@ -1549,6 +1554,7 @@ void scst_rx_data(struct scst_cmd *cmd, int status,
|
||||
break;
|
||||
|
||||
case SCST_RX_STATUS_ERROR_SENSE_SET:
|
||||
TRACE(TRACE_SCSI, "cmd %p, RX data error status %#x", cmd, status);
|
||||
if (!cmd->write_not_received_set)
|
||||
scst_cmd_set_write_no_data_received(cmd);
|
||||
scst_set_cmd_abnormal_done_state(cmd);
|
||||
@@ -1556,9 +1562,12 @@ void scst_rx_data(struct scst_cmd *cmd, int status,
|
||||
break;
|
||||
|
||||
case SCST_RX_STATUS_ERROR_FATAL:
|
||||
set_bit(SCST_CMD_ABORTED, &cmd->cmd_flags);
|
||||
set_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags);
|
||||
cmd->delivery_status = SCST_CMD_DELIVERY_FAILED;
|
||||
/* go through */
|
||||
case SCST_RX_STATUS_ERROR:
|
||||
TRACE(TRACE_SCSI, "cmd %p, RX data error status %#x", cmd, status);
|
||||
if (!cmd->write_not_received_set)
|
||||
scst_cmd_set_write_no_data_received(cmd);
|
||||
scst_set_cmd_error(cmd,
|
||||
@@ -1676,7 +1685,9 @@ static int scst_tgt_pre_exec(struct scst_cmd *cmd)
|
||||
scst_set_cmd_abnormal_done_state(cmd);
|
||||
goto out;
|
||||
case SCST_PREPROCESS_STATUS_ERROR_FATAL:
|
||||
set_bit(SCST_CMD_ABORTED, &cmd->cmd_flags);
|
||||
set_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags);
|
||||
cmd->delivery_status = SCST_CMD_DELIVERY_FAILED;
|
||||
/* go through */
|
||||
case SCST_PREPROCESS_STATUS_ERROR:
|
||||
scst_set_cmd_error(cmd,
|
||||
@@ -1718,7 +1729,7 @@ static void scst_do_cmd_done(struct scst_cmd *cmd, int result,
|
||||
scst_set_resp_data_len(cmd, cmd->resp_data_len - resid);
|
||||
/*
|
||||
* We ignore write direction residue, because from the
|
||||
* initiator's POV we already transferred all the data.
|
||||
* initiator's POV we have already transferred all the data.
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -1805,11 +1816,12 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state,
|
||||
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
if ((next_state != SCST_CMD_STATE_PRE_DEV_DONE) &&
|
||||
(next_state != SCST_CMD_STATE_PRE_XMIT_RESP) &&
|
||||
(next_state != SCST_CMD_STATE_PRE_XMIT_RESP1) &&
|
||||
(next_state != SCST_CMD_STATE_PRE_XMIT_RESP2) &&
|
||||
(next_state != SCST_CMD_STATE_FINISHED) &&
|
||||
(next_state != SCST_CMD_STATE_FINISHED_INTERNAL)) {
|
||||
PRINT_ERROR("%s() received invalid cmd state %d (opcode %d)",
|
||||
__func__, next_state, cmd->cdb[0]);
|
||||
PRINT_ERROR("%s() received invalid cmd state %d (opcode %s)",
|
||||
__func__, next_state, scst_get_opcode_name(cmd));
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
scst_set_cmd_abnormal_done_state(cmd);
|
||||
@@ -1842,15 +1854,18 @@ static int scst_report_luns_local(struct scst_cmd *cmd)
|
||||
if ((cmd->cdb[2] != 0) && (cmd->cdb[2] != 2)) {
|
||||
PRINT_ERROR("Unsupported SELECT REPORT value %x in REPORT "
|
||||
"LUNS command", cmd->cdb[2]);
|
||||
goto out_err;
|
||||
scst_set_invalid_field_in_cdb(cmd, 2, 0);
|
||||
goto out_compl;
|
||||
}
|
||||
|
||||
buffer_size = scst_get_buf_full_sense(cmd, &buffer);
|
||||
if (unlikely(buffer_size <= 0))
|
||||
goto out_compl;
|
||||
|
||||
if (buffer_size < 16)
|
||||
if (buffer_size < 16) {
|
||||
scst_set_invalid_field_in_cdb(cmd, 6, 0);
|
||||
goto out_put_err;
|
||||
}
|
||||
|
||||
memset(buffer, 0, buffer_size);
|
||||
offs = 8;
|
||||
@@ -1928,10 +1943,6 @@ out_compl:
|
||||
|
||||
out_put_err:
|
||||
scst_put_buf_full(cmd, buffer);
|
||||
|
||||
out_err:
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
|
||||
goto out_compl;
|
||||
}
|
||||
|
||||
@@ -2025,8 +2036,8 @@ static int scst_request_sense_local(struct scst_cmd *cmd)
|
||||
sl = tgt_dev->tgt_dev_valid_sense_len;
|
||||
else {
|
||||
sl = buffer_size;
|
||||
TRACE(TRACE_MINOR, "%s: Being returned sense truncated "
|
||||
"to size %d (needed %d)", cmd->op_name,
|
||||
TRACE(TRACE_SCSI|TRACE_MINOR, "%s: Being returned sense "
|
||||
"truncated to size %d (needed %d)", cmd->op_name,
|
||||
buffer_size, tgt_dev->tgt_dev_valid_sense_len);
|
||||
}
|
||||
memcpy(buffer, tgt_dev->tgt_dev_sense, sl);
|
||||
@@ -2124,20 +2135,15 @@ static int scst_report_supported_opcodes(struct scst_cmd *cmd)
|
||||
int req_sa = get_unaligned_be16(&cmd->cdb[4]);
|
||||
const struct scst_opcode_descriptor *op = NULL;
|
||||
const struct scst_opcode_descriptor **supp_opcodes = NULL;
|
||||
int supp_opcodes_cnt;
|
||||
int supp_opcodes_cnt, rc;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (cmd->devt->get_supported_opcodes == NULL) {
|
||||
TRACE(TRACE_MINOR, "Unknown opcode 0x%02x", cmd->cdb[0]);
|
||||
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode));
|
||||
/* get_cdb_info_min() ensures that get_supported_opcodes is not NULL here */
|
||||
|
||||
rc = cmd->devt->get_supported_opcodes(cmd, &supp_opcodes, &supp_opcodes_cnt);
|
||||
if (rc != 0)
|
||||
goto out_compl;
|
||||
} else {
|
||||
int rc = cmd->devt->get_supported_opcodes(cmd, &supp_opcodes,
|
||||
&supp_opcodes_cnt);
|
||||
if (rc != 0)
|
||||
goto out_compl;
|
||||
}
|
||||
|
||||
TRACE_DBG("cmd %p, options %d, req_opcode %x, req_sa %x, rctd %d",
|
||||
cmd, options, req_opcode, req_sa, rctd);
|
||||
@@ -2243,7 +2249,7 @@ static int scst_report_supported_opcodes(struct scst_cmd *cmd)
|
||||
|
||||
switch (options) {
|
||||
case 0: /* all */
|
||||
put_unaligned_be32(buf_len - 3, &buf[0]);
|
||||
put_unaligned_be32(buf_len - 4, &buf[0]);
|
||||
offs = 4;
|
||||
for (i = 0; i < supp_opcodes_cnt; i++) {
|
||||
op = supp_opcodes[i];
|
||||
@@ -2354,7 +2360,7 @@ static int scst_reserve_local(struct scst_cmd *cmd)
|
||||
|
||||
/*
|
||||
* There's no need to block this device, even for
|
||||
* SCST_CONTR_MODE_ONE_TASK_SET, or anyhow else protect reservations
|
||||
* SCST_TST_0_SINGLE_TASK_SET, or anyhow else protect reservations
|
||||
* changes, because:
|
||||
*
|
||||
* 1. The reservation changes are (rather) atomic, i.e., in contrast
|
||||
@@ -2363,7 +2369,7 @@ static int scst_reserve_local(struct scst_cmd *cmd)
|
||||
*
|
||||
* 2. It's a duty of initiators to ensure order of regular commands
|
||||
* around the reservation command either by ORDERED attribute, or by
|
||||
* queue draining, or etc. For case of SCST_CONTR_MODE_ONE_TASK_SET
|
||||
* queue draining, or etc. For case of SCST_TST_0_SINGLE_TASK_SET
|
||||
* there are no target drivers which can ensure even for ORDERED
|
||||
* commands order of their delivery, so, because initiators know
|
||||
* it, also there's no point to do any extra protection actions.
|
||||
@@ -2487,9 +2493,10 @@ static int scst_persistent_reserve_in_local(struct scst_cmd *cmd)
|
||||
session = cmd->sess;
|
||||
|
||||
if (unlikely(dev->not_pr_supporting_tgt_devs_num != 0)) {
|
||||
PRINT_WARNING("Persistent Reservation command %x refused for "
|
||||
PRINT_WARNING("Persistent Reservation command %s refused for "
|
||||
"device %s, because the device has not supporting PR "
|
||||
"transports connected", cmd->cdb[0], dev->virt_name);
|
||||
"transports connected", scst_get_opcode_name(cmd),
|
||||
dev->virt_name);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_opcode));
|
||||
goto out_done;
|
||||
@@ -2524,8 +2531,8 @@ static int scst_persistent_reserve_in_local(struct scst_cmd *cmd)
|
||||
|
||||
action = cmd->cdb[1] & 0x1f;
|
||||
|
||||
TRACE(TRACE_SCSI, "PR action %x for '%s' (LUN %llx) from '%s'", action,
|
||||
dev->virt_name, tgt_dev->lun, session->initiator_name);
|
||||
TRACE(TRACE_SCSI, "PR IN action %x for '%s' (LUN %llx) from '%s'",
|
||||
action, dev->virt_name, tgt_dev->lun, session->initiator_name);
|
||||
|
||||
switch (action) {
|
||||
case PR_READ_KEYS:
|
||||
@@ -2586,18 +2593,18 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd)
|
||||
session = cmd->sess;
|
||||
|
||||
if (unlikely(dev->not_pr_supporting_tgt_devs_num != 0)) {
|
||||
PRINT_WARNING("Persistent Reservation command %x refused for "
|
||||
PRINT_WARNING("Persistent Reservation command %s refused for "
|
||||
"device %s, because the device has not supporting PR "
|
||||
"transports connected", cmd->cdb[0], dev->virt_name);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_opcode));
|
||||
"transports connected", scst_get_opcode_name(cmd),
|
||||
dev->virt_name);
|
||||
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode));
|
||||
goto out_done;
|
||||
}
|
||||
|
||||
action = cmd->cdb[1] & 0x1f;
|
||||
|
||||
TRACE(TRACE_SCSI, "PR action %x for '%s' (LUN %llx) from '%s'", action,
|
||||
dev->virt_name, tgt_dev->lun, session->initiator_name);
|
||||
TRACE(TRACE_SCSI, "PR OUT action %x for '%s' (LUN %llx) from '%s'",
|
||||
action, dev->virt_name, tgt_dev->lun, session->initiator_name);
|
||||
|
||||
if (scst_dev_reserved(dev)) {
|
||||
TRACE_PR("PR command rejected, because device %s holds regular "
|
||||
@@ -2630,8 +2637,8 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd)
|
||||
if ((action != PR_REGISTER) && (action != PR_REGISTER_AND_IGNORE) &&
|
||||
(action != PR_CLEAR) && (cmd->cdb[2] >> 4) != SCOPE_LU) {
|
||||
TRACE_PR("Scope must be SCOPE_LU for action %x", action);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
|
||||
scst_set_invalid_field_in_cdb(cmd, 2,
|
||||
SCST_INVAL_FIELD_BIT_OFFS_VALID | 4);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
@@ -2639,8 +2646,8 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd)
|
||||
if ((action != PR_REGISTER) && (action != PR_REGISTER_AND_MOVE) &&
|
||||
((buffer[20] >> 3) & 0x01)) {
|
||||
TRACE_PR("SPEC_I_PT must be zero for action %x", action);
|
||||
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(
|
||||
scst_sense_invalid_field_in_cdb));
|
||||
scst_set_invalid_field_in_parm_list(cmd, 20,
|
||||
SCST_INVAL_FIELD_BIT_OFFS_VALID | 3);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
@@ -2648,8 +2655,8 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd)
|
||||
if ((action != PR_REGISTER) && (action != PR_REGISTER_AND_IGNORE) &&
|
||||
(action != PR_REGISTER_AND_MOVE) && ((buffer[20] >> 2) & 0x01)) {
|
||||
TRACE_PR("ALL_TG_PT must be zero for action %x", action);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb));
|
||||
scst_set_invalid_field_in_parm_list(cmd, 20,
|
||||
SCST_INVAL_FIELD_BIT_OFFS_VALID | 2);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
@@ -3000,10 +3007,11 @@ static int scst_do_real_exec(struct scst_cmd *cmd)
|
||||
if (rc == -EINVAL &&
|
||||
(cmd->bufflen >> 9) > queue_max_hw_sectors(scsi_dev->request_queue))
|
||||
PRINT_ERROR("Too low max_hw_sectors %d sectors on %s "
|
||||
"to serve command %#x with bufflen %d bytes."
|
||||
"to serve command %s with bufflen %d bytes."
|
||||
"See README for more details.",
|
||||
queue_max_hw_sectors(scsi_dev->request_queue),
|
||||
dev->virt_name, cmd->cdb[0], cmd->bufflen);
|
||||
dev->virt_name, scst_get_opcode_name(cmd),
|
||||
cmd->bufflen);
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
@@ -3090,8 +3098,9 @@ static int scst_do_local_exec(struct scst_cmd *cmd)
|
||||
if ((cmd->op_flags & SCST_WRITE_MEDIUM) &&
|
||||
(tgt_dev->tgt_dev_rd_only || cmd->dev->swp)) {
|
||||
PRINT_WARNING("Attempt of write access to read-only device: "
|
||||
"initiator %s, LUN %lld, op %x",
|
||||
cmd->sess->initiator_name, cmd->lun, cmd->cdb[0]);
|
||||
"initiator %s, LUN %lld, op %s",
|
||||
cmd->sess->initiator_name, cmd->lun,
|
||||
scst_get_opcode_name(cmd));
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_data_protect));
|
||||
goto out_done;
|
||||
@@ -3294,7 +3303,7 @@ static int scst_exec_check_sn(struct scst_cmd **active_cmd)
|
||||
if (unlikely(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE))
|
||||
goto exec;
|
||||
|
||||
sBUG_ON(!cmd->sn_set);
|
||||
EXTRACHECKS_BUG_ON(!cmd->sn_set);
|
||||
|
||||
expected_sn = ACCESS_ONCE(order_data->expected_sn);
|
||||
/* Optimized for lockless fast path */
|
||||
@@ -3330,7 +3339,7 @@ static int scst_exec_check_sn(struct scst_cmd **active_cmd)
|
||||
TRACE_SN("Deferring cmd %p (sn=%d, set %d, "
|
||||
"expected_sn=%d)", cmd, cmd->sn,
|
||||
cmd->sn_set, expected_sn);
|
||||
list_add_tail(&cmd->sn_cmd_list_entry,
|
||||
list_add_tail(&cmd->deferred_cmd_list_entry,
|
||||
&order_data->deferred_cmd_list);
|
||||
res = SCST_CMD_STATE_RES_CONT_NEXT;
|
||||
}
|
||||
@@ -3360,8 +3369,11 @@ static int scst_check_sense(struct scst_cmd *cmd)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (unlikely(cmd->ua_ignore))
|
||||
if (unlikely(cmd->ua_ignore)) {
|
||||
PRINT_BUFF_FLAG(TRACE_SCSI, "Local UA sense", cmd->sense,
|
||||
cmd->sense_valid_len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If we had internal bus reset behind us, set the command error UA */
|
||||
if ((dev->scsi_dev != NULL) &&
|
||||
@@ -3466,8 +3478,8 @@ static bool scst_check_auto_sense(struct scst_cmd *cmd)
|
||||
} else {
|
||||
TRACE(TRACE_SCSI|TRACE_MINOR_AND_MGMT_DBG, "Host "
|
||||
"status 0x%x received, returning HARDWARE ERROR "
|
||||
"instead (cmd %p, op 0x%x, target %s, device "
|
||||
"%s)", cmd->host_status, cmd, cmd->cdb[0],
|
||||
"instead (cmd %p, op %s, target %s, device "
|
||||
"%s)", cmd->host_status, cmd, scst_get_opcode_name(cmd),
|
||||
cmd->tgt->tgt_name, cmd->dev->virt_name);
|
||||
scst_set_cmd_error(cmd,
|
||||
SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
@@ -3484,10 +3496,11 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (unlikely(scst_check_auto_sense(cmd))) {
|
||||
rc = scst_check_auto_sense(cmd);
|
||||
if (unlikely(rc)) {
|
||||
PRINT_INFO("Command finished with CHECK CONDITION, but "
|
||||
"without sense data (opcode 0x%x), issuing "
|
||||
"REQUEST SENSE", cmd->cdb[0]);
|
||||
"without sense data (opcode %s), issuing "
|
||||
"REQUEST SENSE", scst_get_opcode_name(cmd));
|
||||
rc = scst_prepare_request_sense(cmd);
|
||||
if (rc == 0)
|
||||
res = SCST_CMD_STATE_RES_CONT_NEXT;
|
||||
@@ -3498,7 +3511,10 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
|
||||
SCST_LOAD_SENSE(scst_sense_hardw_error));
|
||||
}
|
||||
goto out;
|
||||
} else if (unlikely(scst_check_sense(cmd))) {
|
||||
}
|
||||
|
||||
rc = scst_check_sense(cmd);
|
||||
if (unlikely(rc)) {
|
||||
/*
|
||||
* We can't allow atomic command on the exec stages, so
|
||||
* restart to the thread
|
||||
@@ -3507,7 +3523,8 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (likely(scsi_status_is_good(cmd->status))) {
|
||||
rc = scsi_status_is_good(cmd->status);
|
||||
if (likely(rc)) {
|
||||
unsigned char type = cmd->dev->type;
|
||||
if (unlikely((cmd->cdb[0] == MODE_SENSE ||
|
||||
cmd->cdb[0] == MODE_SENSE_10)) &&
|
||||
@@ -3580,33 +3597,12 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
|
||||
if (unlikely((cmd->cdb[0] == MODE_SELECT) ||
|
||||
(cmd->cdb[0] == MODE_SELECT_10) ||
|
||||
(cmd->cdb[0] == LOG_SELECT))) {
|
||||
TRACE(TRACE_SCSI,
|
||||
"MODE/LOG SELECT succeeded (LUN %lld)",
|
||||
TRACE(TRACE_SCSI, "MODE/LOG SELECT succeeded (LUN %lld)",
|
||||
(long long unsigned int)cmd->lun);
|
||||
cmd->state = SCST_CMD_STATE_MODE_SELECT_CHECKS;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
TRACE(TRACE_SCSI, "cmd %p not succeeded with status %x",
|
||||
cmd, cmd->status);
|
||||
|
||||
if ((cmd->cdb[0] == RESERVE) || (cmd->cdb[0] == RESERVE_10)) {
|
||||
struct scst_device *dev = cmd->dev;
|
||||
|
||||
if (scst_is_reservation_holder(dev, cmd->sess)) {
|
||||
TRACE(TRACE_SCSI, "RESERVE failed lun=%lld, "
|
||||
"status=%x",
|
||||
(long long unsigned int)cmd->lun,
|
||||
cmd->status);
|
||||
PRINT_BUFF_FLAG(TRACE_SCSI, "Sense", cmd->sense,
|
||||
cmd->sense_valid_len);
|
||||
|
||||
spin_lock_bh(&dev->dev_lock);
|
||||
scst_clear_dev_reservation(dev);
|
||||
spin_unlock_bh(&dev->dev_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for MODE PARAMETERS CHANGED UA */
|
||||
if ((cmd->dev->scsi_dev != NULL) &&
|
||||
(cmd->status == SAM_STAT_CHECK_CONDITION) &&
|
||||
@@ -3719,7 +3715,7 @@ static int scst_dev_done(struct scst_cmd *cmd)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
state = SCST_CMD_STATE_PRE_XMIT_RESP;
|
||||
state = SCST_CMD_STATE_PRE_XMIT_RESP1;
|
||||
|
||||
if (likely((cmd->op_flags & SCST_FULLY_LOCAL_CMD) == 0) &&
|
||||
likely(devt->dev_done != NULL)) {
|
||||
@@ -3750,7 +3746,8 @@ static int scst_dev_done(struct scst_cmd *cmd)
|
||||
|
||||
switch (state) {
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP:
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP1:
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP2:
|
||||
case SCST_CMD_STATE_PARSE:
|
||||
case SCST_CMD_STATE_PREPARE_SPACE:
|
||||
case SCST_CMD_STATE_RDY_TO_XFER:
|
||||
@@ -3805,7 +3802,8 @@ static int scst_dev_done(struct scst_cmd *cmd)
|
||||
cmd->state = SCST_CMD_STATE_FINISHED_INTERNAL;
|
||||
|
||||
#ifndef CONFIG_SCST_TEST_IO_IN_SIRQ
|
||||
if (cmd->state != SCST_CMD_STATE_PRE_XMIT_RESP) {
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
if (cmd->state != SCST_CMD_STATE_PRE_XMIT_RESP1) {
|
||||
/* We can't allow atomic command on the exec stages */
|
||||
if (scst_cmd_atomic(cmd)) {
|
||||
switch (state) {
|
||||
@@ -3822,13 +3820,58 @@ static int scst_dev_done(struct scst_cmd *cmd)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
out:
|
||||
TRACE_EXIT_HRES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int scst_pre_xmit_response(struct scst_cmd *cmd)
|
||||
static int scst_pre_xmit_response2(struct scst_cmd *cmd)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
again:
|
||||
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)))
|
||||
scst_xmit_process_aborted_cmd(cmd);
|
||||
else if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION)) {
|
||||
if (cmd->tgt_dev != NULL) {
|
||||
int rc = scst_process_check_condition(cmd);
|
||||
/* !! At this point cmd can be already dead !! */
|
||||
if (rc == -1) {
|
||||
res = SCST_CMD_STATE_RES_CONT_NEXT;
|
||||
goto out;
|
||||
} else if (rc == 1)
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(test_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags))) {
|
||||
EXTRACHECKS_BUG_ON(!test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags));
|
||||
TRACE_MGMT_DBG("Flag NO_RESP set for cmd %p (tag %llu), "
|
||||
"skipping", cmd, (long long unsigned int)cmd->tag);
|
||||
cmd->state = SCST_CMD_STATE_FINISHED;
|
||||
goto out_same;
|
||||
}
|
||||
|
||||
if (unlikely(cmd->resid_possible))
|
||||
scst_adjust_resp_data_len(cmd);
|
||||
else
|
||||
cmd->adjusted_resp_data_len = cmd->resp_data_len;
|
||||
|
||||
cmd->state = SCST_CMD_STATE_XMIT_RESP;
|
||||
|
||||
out_same:
|
||||
res = SCST_CMD_STATE_RES_CONT_SAME;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int scst_pre_xmit_response1(struct scst_cmd *cmd)
|
||||
{
|
||||
int res;
|
||||
|
||||
@@ -3838,7 +3881,7 @@ static int scst_pre_xmit_response(struct scst_cmd *cmd)
|
||||
|
||||
#ifdef CONFIG_SCST_DEBUG_TM
|
||||
if (cmd->tm_dbg_delayed &&
|
||||
!test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) {
|
||||
!test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)) {
|
||||
if (scst_cmd_atomic(cmd)) {
|
||||
TRACE_MGMT_DBG("%s",
|
||||
"DEBUG_TM delayed cmd needs a thread");
|
||||
@@ -3876,29 +3919,10 @@ static int scst_pre_xmit_response(struct scst_cmd *cmd)
|
||||
cmd->done = 1;
|
||||
smp_mb(); /* to sync with scst_abort_cmd() */
|
||||
|
||||
if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)))
|
||||
scst_xmit_process_aborted_cmd(cmd);
|
||||
else if (unlikely(cmd->status == SAM_STAT_CHECK_CONDITION))
|
||||
scst_store_sense(cmd);
|
||||
cmd->state = SCST_CMD_STATE_PRE_XMIT_RESP2;
|
||||
res = scst_pre_xmit_response2(cmd);
|
||||
|
||||
if (unlikely(test_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags))) {
|
||||
TRACE_MGMT_DBG("Flag NO_RESP set for cmd %p (tag %llu), "
|
||||
"skipping", cmd, (long long unsigned int)cmd->tag);
|
||||
cmd->state = SCST_CMD_STATE_FINISHED;
|
||||
res = SCST_CMD_STATE_RES_CONT_SAME;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(cmd->resid_possible))
|
||||
scst_adjust_resp_data_len(cmd);
|
||||
else
|
||||
cmd->adjusted_resp_data_len = cmd->resp_data_len;
|
||||
|
||||
cmd->state = SCST_CMD_STATE_XMIT_RESP;
|
||||
res = SCST_CMD_STATE_RES_CONT_SAME;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_HRES(res);
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -4069,6 +4093,7 @@ static int scst_finish_cmd(struct scst_cmd *cmd)
|
||||
|
||||
if (unlikely(cmd->delivery_status != SCST_CMD_DELIVERY_SUCCESS)) {
|
||||
if ((cmd->tgt_dev != NULL) &&
|
||||
(cmd->status == SAM_STAT_CHECK_CONDITION) &&
|
||||
scst_is_ua_sense(cmd->sense, cmd->sense_valid_len)) {
|
||||
/* This UA delivery failed, so we need to requeue it */
|
||||
if (scst_cmd_atomic(cmd) &&
|
||||
@@ -4173,7 +4198,7 @@ static void scst_cmd_set_sn(struct scst_cmd *cmd)
|
||||
cmd->queue_type = SCST_CMD_QUEUE_ORDERED;
|
||||
#endif
|
||||
|
||||
if (cmd->dev->queue_alg == SCST_CONTR_MODE_QUEUE_ALG_RESTRICTED_REORDER) {
|
||||
if (cmd->dev->queue_alg == SCST_QUEUE_ALG_0_RESTRICTED_REORDER) {
|
||||
if (likely(cmd->queue_type != SCST_CMD_QUEUE_HEAD_OF_QUEUE)) {
|
||||
/*
|
||||
* Not the best way, but good enough until there is a
|
||||
@@ -4228,7 +4253,7 @@ again:
|
||||
goto again;
|
||||
|
||||
case SCST_CMD_QUEUE_ORDERED:
|
||||
TRACE_SN("ORDERED cmd %p (op %x)", cmd, cmd->cdb[0]);
|
||||
TRACE_SN("ORDERED cmd %p (op %s)", cmd, scst_get_opcode_name(cmd));
|
||||
ordered:
|
||||
order_data->curr_sn++;
|
||||
TRACE_SN("Incremented curr_sn %d", order_data->curr_sn);
|
||||
@@ -4271,7 +4296,7 @@ ordered:
|
||||
break;
|
||||
|
||||
case SCST_CMD_QUEUE_HEAD_OF_QUEUE:
|
||||
TRACE_SN("HQ cmd %p (op %x)", cmd, cmd->cdb[0]);
|
||||
TRACE_SN("HQ cmd %p (op %s)", cmd, scst_get_opcode_name(cmd));
|
||||
spin_lock_irqsave(&order_data->sn_lock, flags);
|
||||
order_data->hq_cmd_count++;
|
||||
spin_unlock_irqrestore(&order_data->sn_lock, flags);
|
||||
@@ -4762,10 +4787,14 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic)
|
||||
res = scst_dev_done(cmd);
|
||||
break;
|
||||
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP:
|
||||
res = scst_pre_xmit_response(cmd);
|
||||
EXTRACHECKS_BUG_ON(res ==
|
||||
SCST_CMD_STATE_RES_NEED_THREAD);
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP1:
|
||||
res = scst_pre_xmit_response1(cmd);
|
||||
EXTRACHECKS_BUG_ON(res == SCST_CMD_STATE_RES_NEED_THREAD);
|
||||
break;
|
||||
|
||||
case SCST_CMD_STATE_PRE_XMIT_RESP2:
|
||||
res = scst_pre_xmit_response2(cmd);
|
||||
EXTRACHECKS_BUG_ON(res == SCST_CMD_STATE_RES_NEED_THREAD);
|
||||
break;
|
||||
|
||||
case SCST_CMD_STATE_XMIT_RESP:
|
||||
@@ -4784,8 +4813,11 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic)
|
||||
PRINT_CRIT_ERROR("cmd (%p) in state %d, but shouldn't "
|
||||
"be", cmd, cmd->state);
|
||||
sBUG();
|
||||
#if defined(RHEL_MAJOR) && RHEL_MAJOR -0 < 6
|
||||
/* For suppressing a gcc compiler warning */
|
||||
res = SCST_CMD_STATE_RES_CONT_NEXT;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
} while (res == SCST_CMD_STATE_RES_CONT_SAME);
|
||||
|
||||
@@ -4817,8 +4849,10 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic)
|
||||
cmd->state);
|
||||
spin_unlock_irq(&cmd->cmd_threads->cmd_list_lock);
|
||||
sBUG();
|
||||
#if defined(RHEL_MAJOR) && RHEL_MAJOR -0 < 6
|
||||
spin_lock_irq(&cmd->cmd_threads->cmd_list_lock);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
wake_up(&cmd->cmd_threads->cmd_list_waitQ);
|
||||
@@ -4918,21 +4952,16 @@ void scst_cmd_tasklet(long p)
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 0 on success, < 0 if there is no device handler or
|
||||
* > 0 if SCST_FLAG_SUSPENDED set and SCST_FLAG_SUSPENDING - not.
|
||||
* No locks, protection is done by the suspended activity.
|
||||
* Returns 0 on success, or > 0 if SCST_FLAG_SUSPENDED set and
|
||||
* SCST_FLAG_SUSPENDING - not. No locks, protection is done by the
|
||||
* suspended activity.
|
||||
*/
|
||||
static int scst_mgmt_translate_lun(struct scst_mgmt_cmd *mcmd)
|
||||
static int scst_get_mgmt(struct scst_mgmt_cmd *mcmd)
|
||||
{
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
struct list_head *head;
|
||||
int res = -1;
|
||||
int res = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_DBG("Finding tgt_dev for mgmt cmd %p (lun %lld)", mcmd,
|
||||
(long long unsigned int)mcmd->lun);
|
||||
|
||||
mcmd->cpu_cmd_counter = scst_get();
|
||||
|
||||
if (unlikely(test_bit(SCST_FLAG_SUSPENDED, &scst_flags) &&
|
||||
@@ -4943,6 +4972,33 @@ static int scst_mgmt_translate_lun(struct scst_mgmt_cmd *mcmd)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT_HRES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 0 on success, < 0 if there is no device handler or
|
||||
* > 0 if SCST_FLAG_SUSPENDED set and SCST_FLAG_SUSPENDING - not.
|
||||
* No locks, protection is done by the suspended activity.
|
||||
*/
|
||||
static int scst_mgmt_translate_lun(struct scst_mgmt_cmd *mcmd)
|
||||
{
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
struct list_head *head;
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
TRACE_DBG("Finding tgt_dev for mgmt cmd %p (lun %lld)", mcmd,
|
||||
(long long unsigned int)mcmd->lun);
|
||||
|
||||
res = scst_get_mgmt(mcmd);
|
||||
if (unlikely(res != 0))
|
||||
goto out;
|
||||
|
||||
res = -1;
|
||||
|
||||
head = &mcmd->sess->sess_tgt_dev_list[SESS_TGT_DEV_LIST_HASH_FN(mcmd->lun)];
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
if (tgt_dev->lun == mcmd->lun) {
|
||||
@@ -5208,8 +5264,8 @@ static inline int scst_is_strict_mgmt_fn(int mgmt_fn)
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be called under sess_list_lock to sync with finished flag assignment in
|
||||
* scst_finish_cmd()
|
||||
* If mcmd != NULL, must be called under sess_list_lock to sync with "finished"
|
||||
* flag assignment in scst_finish_cmd()
|
||||
*/
|
||||
void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
|
||||
bool other_ini, bool call_dev_task_mgmt_fn_received)
|
||||
@@ -5226,8 +5282,8 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
|
||||
if (call_dev_task_mgmt_fn_received)
|
||||
EXTRACHECKS_BUG_ON(!mcmd);
|
||||
|
||||
TRACE(TRACE_SCSI|TRACE_MGMT_DEBUG, "Aborting cmd %p (tag %llu, op %x)",
|
||||
cmd, (long long unsigned int)cmd->tag, cmd->cdb[0]);
|
||||
TRACE(TRACE_SCSI|TRACE_MGMT_DEBUG, "Aborting cmd %p (tag %llu, op %s)",
|
||||
cmd, (long long unsigned int)cmd->tag, scst_get_opcode_name(cmd));
|
||||
|
||||
/* To protect from concurrent aborts */
|
||||
spin_lock_irqsave(&other_ini_lock, flags);
|
||||
@@ -5331,12 +5387,12 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
|
||||
t = TRACE_MGMT_DEBUG;
|
||||
TRACE(t, "cmd %p (tag %llu, "
|
||||
"sn %u) being executed/xmitted (state %d, "
|
||||
"op %x, proc time %ld sec., timeout %d sec.), "
|
||||
"op %s, proc time %ld sec., timeout %d sec.), "
|
||||
"deferring ABORT (cmd_done_wait_count %d, "
|
||||
"cmd_finish_wait_count %d, internal %d, mcmd "
|
||||
"fn %d (mcmd %p))", cmd,
|
||||
(long long unsigned int)cmd->tag,
|
||||
cmd->sn, cmd->state, cmd->cdb[0],
|
||||
cmd->sn, cmd->state, scst_get_opcode_name(cmd),
|
||||
(long)(jiffies - cmd->start_time) / HZ,
|
||||
cmd->timeout / HZ, mcmd->cmd_done_wait_count,
|
||||
mcmd->cmd_finish_wait_count, cmd->internal,
|
||||
@@ -5484,7 +5540,7 @@ void scst_unblock_aborted_cmds(const struct scst_tgt *tgt,
|
||||
spin_lock(&order_data->sn_lock);
|
||||
list_for_each_entry_safe(cmd, tcmd,
|
||||
&order_data->deferred_cmd_list,
|
||||
sn_cmd_list_entry) {
|
||||
deferred_cmd_list_entry) {
|
||||
|
||||
if ((tgt != NULL) && (tgt != cmd->tgt))
|
||||
continue;
|
||||
@@ -5492,7 +5548,7 @@ void scst_unblock_aborted_cmds(const struct scst_tgt *tgt,
|
||||
continue;
|
||||
|
||||
if (__scst_check_unblock_aborted_cmd(cmd,
|
||||
&cmd->sn_cmd_list_entry)) {
|
||||
&cmd->deferred_cmd_list_entry)) {
|
||||
TRACE_MGMT_DBG("Unblocked aborted SN "
|
||||
"cmd %p (sn %u)", cmd, cmd->sn);
|
||||
order_data->def_cmd_count--;
|
||||
@@ -5679,6 +5735,18 @@ static int scst_clear_task_set(struct scst_mgmt_cmd *mcmd)
|
||||
|
||||
list_for_each_entry(tgt_dev, &UA_tgt_devs,
|
||||
extra_tgt_dev_list_entry) {
|
||||
/*
|
||||
* Potentially, setting UA here, when the aborted
|
||||
* commands are still running, can lead to a situation
|
||||
* that one of them could take it, then that would be
|
||||
* detected and the UA requeued. But, meanwhile, one or
|
||||
* more subsequent, i.e. not aborted, commands can
|
||||
* "leak" executed normally. So, as result, the
|
||||
* UA would be delivered one or more commands "later".
|
||||
* However, that should be OK, because, if multiple
|
||||
* commands are being executed in parallel, you can't
|
||||
* control exact order of UA delivery anyway.
|
||||
*/
|
||||
scst_check_set_UA(tgt_dev, sense_buffer, sl, 0);
|
||||
}
|
||||
}
|
||||
@@ -5742,6 +5810,21 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
|
||||
}
|
||||
|
||||
case SCST_TARGET_RESET:
|
||||
/*
|
||||
* Needed to protect against race, when a device added after
|
||||
* blocking, so unblocking then will make dev->block_count
|
||||
* of the new device negative.
|
||||
*/
|
||||
rc = scst_get_mgmt(mcmd);
|
||||
if (rc == 0) {
|
||||
mcmd->state = SCST_MCMD_STATE_EXEC;
|
||||
mcmd->scst_get_called = 1;
|
||||
} else {
|
||||
EXTRACHECKS_BUG_ON(rc < 0);
|
||||
res = rc;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCST_NEXUS_LOSS_SESS:
|
||||
case SCST_ABORT_ALL_TASKS_SESS:
|
||||
case SCST_NEXUS_LOSS:
|
||||
@@ -5950,7 +6033,7 @@ static void scst_do_nexus_loss_sess(struct scst_mgmt_cmd *mcmd)
|
||||
|
||||
/* Returns 0 if the command processing should be continued, <0 otherwise */
|
||||
static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
|
||||
int nexus_loss)
|
||||
int nexus_loss_unreg_sess)
|
||||
{
|
||||
int res;
|
||||
int i;
|
||||
@@ -5959,8 +6042,8 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd,
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
if (nexus_loss) {
|
||||
TRACE_MGMT_DBG("Nexus loss for sess %p (mcmd %p)",
|
||||
if (nexus_loss_unreg_sess) {
|
||||
TRACE_MGMT_DBG("Nexus loss or UNREG SESS for sess %p (mcmd %p)",
|
||||
sess, mcmd);
|
||||
} else {
|
||||
TRACE_MGMT_DBG("Aborting all from sess %p (mcmd %p)",
|
||||
@@ -6125,8 +6208,7 @@ static int scst_mgmt_cmd_exec(struct scst_mgmt_cmd *mcmd)
|
||||
break;
|
||||
|
||||
case SCST_CLEAR_TASK_SET:
|
||||
if (mcmd->mcmd_tgt_dev->dev->tst ==
|
||||
SCST_CONTR_MODE_SEP_TASK_SETS)
|
||||
if (mcmd->mcmd_tgt_dev->dev->tst == SCST_TST_1_SEP_TASK_SETS)
|
||||
res = scst_abort_task_set(mcmd);
|
||||
else
|
||||
res = scst_clear_task_set(mcmd);
|
||||
@@ -6416,8 +6498,11 @@ static int scst_process_mgmt_cmd(struct scst_mgmt_cmd *mcmd)
|
||||
mcmd->cmd_finish_wait_count,
|
||||
mcmd->cmd_done_wait_count);
|
||||
sBUG();
|
||||
#if defined(RHEL_MAJOR) && RHEL_MAJOR -0 < 6
|
||||
/* For suppressing a gcc compiler warning */
|
||||
res = -1;
|
||||
goto out;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -274,10 +274,10 @@ sub lunTest {
|
||||
Dumper(undef, "luns(): Target 'no-such-target' is not available"));
|
||||
ok(Dumper($SCST->luns('scst_local', 'local1')),
|
||||
Dumper({ '0' => 'disk01', '1' => 'disk02', '2' => 'disk01',
|
||||
'3' => 'disk02' }, undef));
|
||||
'3' => 'disk02' }));
|
||||
ok(Dumper($SCST->luns('scst_local', 'local1', 'group1')),
|
||||
Dumper({ '0' => 'disk01', '2' => 'disk02', '4' => 'disk01',
|
||||
'6' => 'disk02' }, undef));
|
||||
'6' => 'disk02' }));
|
||||
|
||||
ok(lunReadOnly($SCST, 'scst_local', 'local1', 0), '0');
|
||||
ok($SCST->setLunAttribute(), $SCST->SCST_C_LUN_SETATTR_FAIL);
|
||||
@@ -302,11 +302,11 @@ sub lunTest {
|
||||
ok($SCST->replaceLun('scst_local', 'local1', 0, 'disk02', {}), 0);
|
||||
ok(Dumper($SCST->luns('scst_local', 'local1')),
|
||||
Dumper({ '0' => 'disk02', '1' => 'disk02', '2' => 'disk01',
|
||||
'3' => 'disk02' }, undef));
|
||||
'3' => 'disk02' }));
|
||||
ok($SCST->replaceLun('scst_local', 'local1', 0, 'disk01', {}), 0);
|
||||
ok(Dumper($SCST->luns('scst_local', 'local1')),
|
||||
Dumper({ '0' => 'disk01', '1' => 'disk02', '2' => 'disk01',
|
||||
'3' => 'disk02' }, undef));
|
||||
'3' => 'disk02' }));
|
||||
|
||||
ok($SCST->clearLuns(undef, undef), $SCST->SCST_C_TGT_CLR_LUN_FAIL);
|
||||
ok($SCST->clearLuns(undef, undef, 'group1'),
|
||||
@@ -322,16 +322,16 @@ sub lunTest {
|
||||
ok($SCST->removeLun('scst_local', 'local1', '8', 'group1'),
|
||||
$SCST->SCST_C_GRP_NO_LUN);
|
||||
ok($SCST->clearLuns('scst_local', 'local1'), 0);
|
||||
ok(Dumper($SCST->luns('scst_local', 'local1')), Dumper({ }, undef));
|
||||
ok(Dumper($SCST->luns('scst_local', 'local1')), Dumper({ }));
|
||||
ok(Dumper($SCST->luns('scst_local', 'local1', 'group1')),
|
||||
Dumper({ '0' => 'disk01', '2' => 'disk02', '4' => 'disk01',
|
||||
'6' => 'disk02' }, undef));
|
||||
'6' => 'disk02' }));
|
||||
ok($SCST->removeLun('scst_local', 'local1', '4', 'group1'), 0);
|
||||
ok(Dumper($SCST->luns('scst_local', 'local1', 'group1')),
|
||||
Dumper({ '0' => 'disk01', '2' => 'disk02', '6' => 'disk02' }, undef));
|
||||
Dumper({ '0' => 'disk01', '2' => 'disk02', '6' => 'disk02' }));
|
||||
ok($SCST->clearLuns('scst_local', 'local1', 'group1'), 0);
|
||||
ok(Dumper($SCST->luns('scst_local', 'local1', 'group1')),
|
||||
Dumper({ }, undef));
|
||||
Dumper({ }));
|
||||
|
||||
ok($SCST->removeInitiator('scst_local', 'local1', 'group1', 'ini1'), 0);
|
||||
ok($SCST->removeGroup('scst_local', 'local1', 'group1'), 0);
|
||||
|
||||
+33
-20
@@ -47,19 +47,30 @@ SRC_FILES=$(wildcard */*.[ch])
|
||||
MODULE_SYMVERS:=$(shell if [ -e $(KDIR)/Module.symvers ]; then \
|
||||
echo Module.symvers; else echo Modules.symvers; fi)
|
||||
|
||||
# Whether or not the OFED kernel modules have been installed.
|
||||
OFED_KERNEL_IB_RPM_INSTALLED:=$(shell if rpm -q kernel-ib 2>/dev/null | grep -q $$(uname -r | sed 's/-/_/g'); then echo true; else echo false; fi)
|
||||
# Name of the OFED kernel RPM.
|
||||
OFED_KERNEL_IB_RPM:=$(shell for r in kernel-ib mlnx-ofa_kernel compat-rdma; do rpm -q $$r 2>/dev/null | grep -q "^$$r" && echo $$r && break; done)
|
||||
|
||||
# Whether or not the OFED kernel-ib-devel RPM has been installed.
|
||||
OFED_KERNEL_IB_DEVEL_RPM_INSTALLED:=$(shell if rpm -q kernel-ib-devel 2>/dev/null | grep -q $$(uname -r | sed 's/-/_/g'); then echo true; else echo false; fi)
|
||||
# Name of the OFED kernel development RPM.
|
||||
OFED_KERNEL_IB_DEVEL_RPM:=$(shell for r in kernel-ib-devel mlnx-ofa_kernel-devel compat-rdma-devel; do rpm -q $$r 2>/dev/null | grep -q "^$$r" && echo $$r && break; done)
|
||||
|
||||
ifeq ($(OFED_KERNEL_IB_DEVEL_RPM_INSTALLED),true)
|
||||
# Read OFED's config.mk, which contains the definition of the variable
|
||||
ifeq ($(OFED_KERNEL_IB_RPM),kernel-ib)
|
||||
OFED_KERNEL_DIR:=/usr/src/ofa_kernel
|
||||
# Read OFED 1.x's config.mk, which contains the definition of the variable
|
||||
# BACKPORT_INCLUDES.
|
||||
include /usr/src/ofa_kernel/config.mk
|
||||
include $(OFED_KERNEL_DIR)/config.mk
|
||||
OFED_CFLAGS:=$(BACKPORT_INCLUDES) -I$(OFED_KERNEL_DIR)/include
|
||||
endif
|
||||
ifeq ($(OFED_KERNEL_IB_RPM),mlnx-ofa_kernel)
|
||||
OFED_KERNEL_DIR:=/usr/src/ofa_kernel/default
|
||||
OFED_CFLAGS:=-I$(OFED_KERNEL_DIR)/default/include
|
||||
endif
|
||||
ifeq ($(OFED_KERNEL_IB_RPM),compat-rdma)
|
||||
OFED_KERNEL_DIR:=/usr/src/compat-rdma
|
||||
OFED_CFLAGS:=-I$(OFED_KERNEL_DIR)/include
|
||||
endif
|
||||
ifneq ($(OFED_KERNEL_IB_RPM),)
|
||||
OFED_MODULE_SYMVERS:=$(OFED_KERNEL_DIR)/Module.symvers
|
||||
endif
|
||||
|
||||
OFED_CFLAGS:=$(shell if $(OFED_KERNEL_IB_DEVEL_RPM_INSTALLED); then echo $(BACKPORT_INCLUDES) -I/usr/src/ofa_kernel/include; fi)
|
||||
|
||||
# Path of the OFED ib_srpt.ko kernel module.
|
||||
OFED_SRPT_PATH:=/lib/modules/$(KVER)/updates/kernel/drivers/infiniband/ulp/srpt/ib_srpt.ko
|
||||
@@ -82,14 +93,15 @@ uninstall:
|
||||
-/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER)
|
||||
|
||||
src/Module.symvers src/Modules.symvers: $(SCST_SYMVERS_DIR)/$(MODULE_SYMVERS)
|
||||
@if $(OFED_KERNEL_IB_RPM_INSTALLED); then \
|
||||
if ! $(OFED_KERNEL_IB_DEVEL_RPM_INSTALLED); then \
|
||||
echo "Error: the OFED package kernel-ib-devel has not yet been" \
|
||||
"installed."; \
|
||||
@if [ -n "$(OFED_KERNEL_IB_RPM)" ]; then \
|
||||
if [ -z "$(OFED_KERNEL_IB_DEVEL_RPM)" ]; then \
|
||||
echo "Error: the OFED package $(OFED_KERNEL_IB_RPM)-devel has" \
|
||||
"not yet been installed."; \
|
||||
false; \
|
||||
elif [ -e /lib/modules/$(KVER)/kernel/drivers/infiniband ]; then \
|
||||
echo "Error: the distro-provided InfiniBand kernel drivers" \
|
||||
"must be removed first."; \
|
||||
"must be removed first" \
|
||||
" (/lib/modules/$(KVER)/kernel/drivers/infiniband)."; \
|
||||
false; \
|
||||
elif $(OFED_SRPT_INSTALLED); then \
|
||||
echo "Error: OFED has been built with srpt=y in ofed.conf."; \
|
||||
@@ -97,21 +109,22 @@ src/Module.symvers src/Modules.symvers: $(SCST_SYMVERS_DIR)/$(MODULE_SYMVERS)
|
||||
false; \
|
||||
elif [ -e $(KDIR)/scripts/Makefile.lib ] \
|
||||
&& ! grep -wq '^c_flags .*PRE_CFLAGS' \
|
||||
$(KDIR)/scripts/Makefile.lib \
|
||||
$(KDIR)/scripts/Makefile.lib \
|
||||
&& ! grep -wq '^LINUXINCLUDE .*PRE_CFLAGS' \
|
||||
$(KDIR)/Makefile; then \
|
||||
$(KDIR)/Makefile; then \
|
||||
echo "Error: the kernel build system has not yet been patched.";\
|
||||
false; \
|
||||
else \
|
||||
echo " Building against OFED InfiniBand kernel headers."; \
|
||||
echo " Building against $(OFED_KERNEL_IB_RPM) InfiniBand" \
|
||||
"kernel headers."; \
|
||||
( \
|
||||
grep -v drivers/infiniband/ $<; \
|
||||
cat /usr/src/ofa_kernel/Module.symvers \
|
||||
cat $(OFED_MODULE_SYMVERS) \
|
||||
) >$@; \
|
||||
fi \
|
||||
else \
|
||||
if $(OFED_KERNEL_IB_DEVEL_RPM_INSTALLED); then \
|
||||
echo "Error: the OFED package kernel-ib has not yet been" \
|
||||
if [ -n "$(OFED_KERNEL_IB_DEVEL_RPM)" ]; then \
|
||||
echo "Error: the OFED kernel package has not yet been" \
|
||||
"installed."; \
|
||||
false; \
|
||||
else \
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ When using RoCE or iWARP, log in to the target system to determine the id_ext
|
||||
and ioc_guid parameters and use these to log in. An example:
|
||||
|
||||
[ target system ]
|
||||
# sed 's/,\(pkey\|dgid\|ioc_guid\)=[^,]*//g' $(find /sys/kernel/scst_tgt/targets/ib_srpt -name login_info) | uniq
|
||||
# sed 's/,\(pkey\|dgid\|service_id\)=[^,]*//g' $(find /sys/kernel/scst_tgt/targets/ib_srpt -name login_info) | uniq
|
||||
id_ext=0002c90300a34270,ioc_guid=0002c90300a34270
|
||||
|
||||
[ initiator system ]
|
||||
|
||||
+134
-72
@@ -335,6 +335,8 @@ static const char *get_ch_state_name(enum rdma_ch_state s)
|
||||
return "live";
|
||||
case CH_DISCONNECTING:
|
||||
return "disconnecting";
|
||||
case CH_DRAINING:
|
||||
return "draining";
|
||||
case CH_DISCONNECTED:
|
||||
return "disconnected";
|
||||
}
|
||||
@@ -2175,10 +2177,57 @@ static void srpt_destroy_ch_ib(struct srpt_rdma_ch *ch)
|
||||
ib_destroy_cq(ch->cq);
|
||||
}
|
||||
|
||||
/**
|
||||
* srpt_close_ch() - Close an RDMA channel.
|
||||
*
|
||||
* Make sure all resources associated with the channel will be deallocated at
|
||||
* an appropriate time.
|
||||
*
|
||||
* Returns true if and only if the channel state has been modified into
|
||||
* CH_DRAINING.
|
||||
*/
|
||||
static bool srpt_close_ch(struct srpt_rdma_ch *ch)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!srpt_set_ch_state(ch, CH_DRAINING))
|
||||
return false;
|
||||
|
||||
kref_get(&ch->kref);
|
||||
|
||||
ret = srpt_ch_qp_err(ch);
|
||||
if (ret < 0)
|
||||
PRINT_ERROR("%s: changing queue pair into error state"
|
||||
" failed: %d", ch->sess_name, ret);
|
||||
|
||||
ret = srpt_zerolength_write(ch);
|
||||
if (ret < 0) {
|
||||
PRINT_ERROR("%s: queuing zero-length write failed: %d",
|
||||
ch->sess_name, ret);
|
||||
WARN_ON_ONCE(!srpt_set_ch_state(ch, CH_DISCONNECTED));
|
||||
}
|
||||
|
||||
kref_put(&ch->kref, srpt_free_ch);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the channel state into CH_DISCONNECTING. If a channel has not yet
|
||||
* reached the connected state, close it. If a channel is in the connected
|
||||
* state, send a DREQ. If a DREQ has been received, send a DREP. Note: it is
|
||||
* the responsibility of the caller to ensure that this function is not
|
||||
* invoked concurrently with the code that accepts a connection. This means
|
||||
* that this function must either be invoked from inside a CM callback
|
||||
* function or that it must be invoked with the srpt_tgt.mutex held.
|
||||
*/
|
||||
static int srpt_disconnect_ch(struct srpt_rdma_ch *ch)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!srpt_set_ch_state(ch, CH_DISCONNECTING))
|
||||
return -ENOTCONN;
|
||||
|
||||
if (ch->using_rdma_cm) {
|
||||
ret = rdma_disconnect(ch->rdma_cm.cm_id);
|
||||
} else {
|
||||
@@ -2187,45 +2236,12 @@ static int srpt_disconnect_ch(struct srpt_rdma_ch *ch)
|
||||
ret = ib_send_cm_drep(ch->ib_cm.cm_id, NULL, 0);
|
||||
}
|
||||
|
||||
if (ret < 0 && srpt_close_ch(ch))
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* srpt_close_ch() - Close an RDMA channel.
|
||||
*
|
||||
* Make sure all resources associated with the channel will be deallocated at
|
||||
* an appropriate time.
|
||||
*
|
||||
* Returns true if and only if the channel state has been modified from
|
||||
* CH_CONNECTING or CH_LIVE into CH_DISCONNECTING.
|
||||
*/
|
||||
static bool srpt_close_ch(struct srpt_rdma_ch *ch)
|
||||
{
|
||||
int ret;
|
||||
bool was_live;
|
||||
|
||||
was_live = srpt_set_ch_state(ch, CH_DISCONNECTING);
|
||||
if (was_live) {
|
||||
kref_get(&ch->kref);
|
||||
|
||||
ret = srpt_ch_qp_err(ch);
|
||||
if (ret < 0)
|
||||
PRINT_ERROR("%s: changing queue pair into error state"
|
||||
" failed: %d", ch->sess_name, ret);
|
||||
|
||||
ret = srpt_zerolength_write(ch);
|
||||
if (ret < 0) {
|
||||
PRINT_ERROR("%s: queuing zero-length write failed: %d",
|
||||
ch->sess_name, ret);
|
||||
WARN_ON_ONCE(!srpt_set_ch_state(ch, CH_DISCONNECTED));
|
||||
}
|
||||
|
||||
kref_put(&ch->kref, srpt_free_ch);
|
||||
}
|
||||
|
||||
return was_live;
|
||||
}
|
||||
|
||||
static void __srpt_close_all_ch(struct srpt_tgt *srpt_tgt)
|
||||
{
|
||||
struct srpt_nexus *nexus;
|
||||
@@ -2354,7 +2370,8 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
|
||||
struct ib_cm_id *ib_cm_id,
|
||||
struct rdma_cm_id *rdma_cm_id,
|
||||
u8 port_num, __be16 pkey,
|
||||
const struct srp_login_req *req)
|
||||
const struct srp_login_req *req,
|
||||
const char *src_addr)
|
||||
{
|
||||
struct srpt_port *const sport = &sdev->port[port_num - 1];
|
||||
const __be16 *const raw_port_gid = (__be16 *)sport->gid.raw;
|
||||
@@ -2514,16 +2531,7 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
|
||||
}
|
||||
|
||||
if (one_target_per_port) {
|
||||
snprintf(ch->sess_name, sizeof(ch->sess_name),
|
||||
"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
|
||||
be16_to_cpu(raw_port_gid[0]),
|
||||
be16_to_cpu(raw_port_gid[1]),
|
||||
be16_to_cpu(raw_port_gid[2]),
|
||||
be16_to_cpu(raw_port_gid[3]),
|
||||
be16_to_cpu(raw_port_gid[4]),
|
||||
be16_to_cpu(raw_port_gid[5]),
|
||||
be16_to_cpu(raw_port_gid[6]),
|
||||
be16_to_cpu(raw_port_gid[7]));
|
||||
strlcpy(ch->sess_name, src_addr, sizeof(ch->sess_name));
|
||||
} else if (use_port_guid_in_session_name) {
|
||||
/*
|
||||
* If the kernel module parameter use_port_guid_in_session_name
|
||||
@@ -2644,10 +2652,20 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
|
||||
rep_param->ib_cm.initiator_depth = 4;
|
||||
}
|
||||
|
||||
if (ch->using_rdma_cm)
|
||||
ret = rdma_accept(rdma_cm_id, &rep_param->rdma_cm);
|
||||
else
|
||||
ret = ib_send_cm_rep(ib_cm_id, &rep_param->ib_cm);
|
||||
/*
|
||||
* Hold the srpt_tgt mutex while accepting a connection to avoid that
|
||||
* srpt_disconnect_ch() is invoked concurrently with this code.
|
||||
*/
|
||||
mutex_lock(&srpt_tgt->mutex);
|
||||
if (srpt_tgt->enabled && ch->state == CH_CONNECTING) {
|
||||
if (ch->using_rdma_cm)
|
||||
ret = rdma_accept(rdma_cm_id, &rep_param->rdma_cm);
|
||||
else
|
||||
ret = ib_send_cm_rep(ib_cm_id, &rep_param->ib_cm);
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
mutex_unlock(&srpt_tgt->mutex);
|
||||
|
||||
switch (ret) {
|
||||
case 0:
|
||||
@@ -2717,9 +2735,36 @@ static int srpt_ib_cm_req_recv(struct ib_cm_id *cm_id,
|
||||
struct ib_cm_req_event_param *param,
|
||||
void *private_data)
|
||||
{
|
||||
__be16 *const raw_sgid = (__be16 *)param->primary_path->dgid.raw;
|
||||
char sgid[40];
|
||||
|
||||
scnprintf(sgid, sizeof(sgid), "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
|
||||
be16_to_cpu(raw_sgid[0]), be16_to_cpu(raw_sgid[1]),
|
||||
be16_to_cpu(raw_sgid[2]), be16_to_cpu(raw_sgid[3]),
|
||||
be16_to_cpu(raw_sgid[4]), be16_to_cpu(raw_sgid[5]),
|
||||
be16_to_cpu(raw_sgid[6]), be16_to_cpu(raw_sgid[7]));
|
||||
|
||||
return srpt_cm_req_recv(cm_id->context, cm_id, NULL, param->port,
|
||||
param->primary_path->pkey,
|
||||
private_data);
|
||||
private_data, sgid);
|
||||
}
|
||||
|
||||
static const char *inet_ntop(const void *sa, char *dst, unsigned size)
|
||||
{
|
||||
switch (((struct sockaddr *)sa)->sa_family) {
|
||||
case AF_INET:
|
||||
snprintf(dst, size, "%pI4",
|
||||
&((struct sockaddr_in *)sa)->sin_addr);
|
||||
break;
|
||||
case AF_INET6:
|
||||
snprintf(dst, size, "%pI6",
|
||||
&((struct sockaddr_in6 *)sa)->sin6_addr);
|
||||
break;
|
||||
default:
|
||||
snprintf(dst, size, "???");
|
||||
break;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static int srpt_rdma_cm_req_recv(struct rdma_cm_id *cm_id,
|
||||
@@ -2728,6 +2773,7 @@ static int srpt_rdma_cm_req_recv(struct rdma_cm_id *cm_id,
|
||||
struct srpt_device *sdev;
|
||||
struct srp_login_req req;
|
||||
const struct srp_login_req_rdma *req_rdma;
|
||||
char src_addr[40];
|
||||
|
||||
sdev = ib_get_client_data(cm_id->device, &srpt_client);
|
||||
if (!sdev)
|
||||
@@ -2747,13 +2793,15 @@ static int srpt_rdma_cm_req_recv(struct rdma_cm_id *cm_id,
|
||||
memcpy(req.initiator_port_id, req_rdma->initiator_port_id, 16);
|
||||
memcpy(req.target_port_id, req_rdma->target_port_id, 16);
|
||||
|
||||
inet_ntop(&cm_id->route.addr.src_addr, src_addr, sizeof(src_addr));
|
||||
|
||||
return srpt_cm_req_recv(sdev, NULL, cm_id, cm_id->port_num,
|
||||
cm_id->route.path_rec->pkey, &req);
|
||||
cm_id->route.path_rec->pkey, &req, src_addr);
|
||||
}
|
||||
|
||||
static void srpt_cm_rej_recv(struct ib_cm_id *cm_id)
|
||||
static void srpt_cm_rej_recv(struct srpt_rdma_ch *ch)
|
||||
{
|
||||
PRINT_INFO("Received InfiniBand REJ packet for cm_id %p.", cm_id);
|
||||
PRINT_INFO("Received CM REJ for ch %s.", ch->sess_name);
|
||||
}
|
||||
|
||||
static void srpt_check_timeout(struct srpt_rdma_ch *ch)
|
||||
@@ -2825,13 +2873,13 @@ static void srpt_cm_rtu_recv(struct srpt_rdma_ch *ch)
|
||||
|
||||
static void srpt_cm_timewait_exit(struct srpt_rdma_ch *ch)
|
||||
{
|
||||
PRINT_INFO("Received InfiniBand TimeWait exit for ch %p.", ch);
|
||||
PRINT_INFO("Received CM TimeWait exit for ch %s.", ch->sess_name);
|
||||
srpt_close_ch(ch);
|
||||
}
|
||||
|
||||
static void srpt_cm_rep_error(struct ib_cm_id *cm_id)
|
||||
static void srpt_cm_rep_error(struct srpt_rdma_ch *ch)
|
||||
{
|
||||
PRINT_INFO("Received InfiniBand REP error for cm_id %p.", cm_id);
|
||||
PRINT_INFO("Received CM REP error for ch %s.", ch->sess_name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2848,7 +2896,7 @@ static int srpt_cm_dreq_recv(struct srpt_rdma_ch *ch)
|
||||
*/
|
||||
static void srpt_cm_drep_recv(struct srpt_rdma_ch *ch)
|
||||
{
|
||||
PRINT_INFO("Received InfiniBand DREP message for ch %p.", ch);
|
||||
PRINT_INFO("Received CM DREP message for ch %s.", ch->sess_name);
|
||||
srpt_close_ch(ch);
|
||||
}
|
||||
|
||||
@@ -2864,6 +2912,7 @@ static void srpt_cm_drep_recv(struct srpt_rdma_ch *ch)
|
||||
*/
|
||||
static int srpt_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
|
||||
{
|
||||
struct srpt_rdma_ch *ch = cm_id->context;
|
||||
int ret;
|
||||
|
||||
BUG_ON(!cm_id->context);
|
||||
@@ -2875,29 +2924,29 @@ static int srpt_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
|
||||
event->private_data);
|
||||
break;
|
||||
case IB_CM_REJ_RECEIVED:
|
||||
srpt_cm_rej_recv(cm_id);
|
||||
srpt_cm_rej_recv(ch);
|
||||
break;
|
||||
case IB_CM_RTU_RECEIVED:
|
||||
case IB_CM_USER_ESTABLISHED:
|
||||
srpt_cm_rtu_recv((struct srpt_rdma_ch *)cm_id->context);
|
||||
srpt_cm_rtu_recv(ch);
|
||||
break;
|
||||
case IB_CM_DREQ_RECEIVED:
|
||||
ret = srpt_cm_dreq_recv((struct srpt_rdma_ch *)cm_id->context);
|
||||
ret = srpt_cm_dreq_recv(ch);
|
||||
break;
|
||||
case IB_CM_DREP_RECEIVED:
|
||||
srpt_cm_drep_recv((struct srpt_rdma_ch *)cm_id->context);
|
||||
srpt_cm_drep_recv(ch);
|
||||
break;
|
||||
case IB_CM_TIMEWAIT_EXIT:
|
||||
srpt_cm_timewait_exit((struct srpt_rdma_ch *)cm_id->context);
|
||||
srpt_cm_timewait_exit(ch);
|
||||
break;
|
||||
case IB_CM_REP_ERROR:
|
||||
srpt_cm_rep_error(cm_id);
|
||||
srpt_cm_rep_error(ch);
|
||||
break;
|
||||
case IB_CM_DREQ_ERROR:
|
||||
PRINT_INFO("Received IB DREQ ERROR event.");
|
||||
PRINT_INFO("Received CM DREQ ERROR event.");
|
||||
break;
|
||||
case IB_CM_MRA_RECEIVED:
|
||||
PRINT_INFO("Received IB MRA event");
|
||||
PRINT_INFO("Received CM MRA event");
|
||||
break;
|
||||
default:
|
||||
PRINT_ERROR("received unrecognized IB CM event %d",
|
||||
@@ -2911,23 +2960,32 @@ static int srpt_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
|
||||
static int srpt_rdma_cm_handler(struct rdma_cm_id *cm_id,
|
||||
struct rdma_cm_event *event)
|
||||
{
|
||||
struct srpt_rdma_ch *ch = cm_id->context;
|
||||
int ret = 0;
|
||||
|
||||
switch (event->event) {
|
||||
case RDMA_CM_EVENT_CONNECT_REQUEST:
|
||||
ret = srpt_rdma_cm_req_recv(cm_id, event);
|
||||
break;
|
||||
case RDMA_CM_EVENT_REJECTED:
|
||||
srpt_cm_rej_recv(ch);
|
||||
break;
|
||||
case RDMA_CM_EVENT_ESTABLISHED:
|
||||
srpt_cm_rtu_recv(cm_id->context);
|
||||
srpt_cm_rtu_recv(ch);
|
||||
break;
|
||||
case RDMA_CM_EVENT_DISCONNECTED:
|
||||
srpt_cm_dreq_recv(cm_id->context);
|
||||
if (ch->state < CH_DISCONNECTING)
|
||||
srpt_cm_dreq_recv(ch);
|
||||
else
|
||||
srpt_cm_drep_recv(ch);
|
||||
break;
|
||||
case RDMA_CM_EVENT_TIMEWAIT_EXIT:
|
||||
srpt_cm_timewait_exit(cm_id->context);
|
||||
srpt_cm_timewait_exit(ch);
|
||||
break;
|
||||
case RDMA_CM_EVENT_UNREACHABLE:
|
||||
srpt_cm_rep_error(ch);
|
||||
break;
|
||||
case RDMA_CM_EVENT_DEVICE_REMOVAL:
|
||||
break;
|
||||
case RDMA_CM_EVENT_ADDR_CHANGE:
|
||||
break;
|
||||
default:
|
||||
@@ -3579,8 +3637,11 @@ static int srpt_detect(struct scst_tgt_template *tp)
|
||||
static int srpt_close_session(struct scst_session *sess)
|
||||
{
|
||||
struct srpt_rdma_ch *ch = scst_sess_get_tgt_priv(sess);
|
||||
struct srpt_tgt *srpt_tgt = ch->srpt_tgt;
|
||||
|
||||
mutex_lock(&srpt_tgt->mutex);
|
||||
srpt_disconnect_ch(ch);
|
||||
mutex_unlock(&srpt_tgt->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4339,7 +4400,8 @@ static void __exit srpt_cleanup_module(void)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
rdma_destroy_id(rdma_cm_id);
|
||||
if (rdma_cm_id)
|
||||
rdma_destroy_id(rdma_cm_id);
|
||||
ib_unregister_client(&srpt_client);
|
||||
#ifdef CONFIG_SCST_PROC
|
||||
srpt_unregister_procfs_entry(&srpt_template);
|
||||
|
||||
+16
-6
@@ -41,7 +41,6 @@
|
||||
#include <rdma/ib_verbs.h>
|
||||
#include <rdma/ib_sa.h>
|
||||
#include <rdma/ib_cm.h>
|
||||
#include <rdma/rdma_cm.h>
|
||||
#include <scsi/srp.h>
|
||||
#if defined(INSIDE_KERNEL_TREE)
|
||||
#include <scst/scst.h>
|
||||
@@ -49,6 +48,14 @@
|
||||
#include <linux/version.h>
|
||||
#include <scst.h>
|
||||
#endif
|
||||
#if defined(RHEL_MAJOR) && RHEL_MAJOR -0 == 5
|
||||
#define vlan_dev_vlan_id(dev) (panic("RHEL 5 misses vlan_dev_vlan_id()"),0)
|
||||
#endif
|
||||
#if defined(RHEL_MAJOR)
|
||||
#define __ethtool_get_settings(dev, cmd) (panic("RHEL misses __ethtool_get_settings()"),0)
|
||||
#endif
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <rdma/rdma_cm.h>
|
||||
#include "ib_dm_mad.h"
|
||||
|
||||
/*
|
||||
@@ -139,7 +146,8 @@ enum {
|
||||
LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 76)) && \
|
||||
!(defined(RHEL_MAJOR) && \
|
||||
(RHEL_MAJOR -0 > 6 || \
|
||||
RHEL_MAJOR -0 == 6 && RHEL_MINOR -0 >= 5))
|
||||
RHEL_MAJOR -0 == 6 && RHEL_MINOR -0 >= 5 || \
|
||||
RHEL_MAJOR -0 == 5 && RHEL_MINOR -0 >= 9))
|
||||
/* See also patch "IB/core: Add GID change event" (commit 761d90ed4). */
|
||||
enum { IB_EVENT_GID_CHANGE = 18 };
|
||||
#endif
|
||||
@@ -284,15 +292,17 @@ struct srpt_send_ioctx {
|
||||
* enum rdma_ch_state - SRP channel state.
|
||||
* @CH_CONNECTING: QP is in RTR state; waiting for RTU.
|
||||
* @CH_LIVE: QP is in RTS state.
|
||||
* @CH_DISCONNECTING: DREQ has been received and waiting for DREP or DREQ has
|
||||
* been sent and waiting for DREP or channel is being closed
|
||||
* for another reason.
|
||||
* @CH_DISCONNECTED: Last WQE has been received.
|
||||
* @CH_DISCONNECTING: DREQ has been sent and waiting for DREP or DREQ has
|
||||
* been received.
|
||||
* @CH_DRAINING: DREP has been received or waiting for DREP timed out
|
||||
* and last work request has been queued.
|
||||
* @CH_DISCONNECTED: Last completion has been received.
|
||||
*/
|
||||
enum rdma_ch_state {
|
||||
CH_CONNECTING,
|
||||
CH_LIVE,
|
||||
CH_DISCONNECTING,
|
||||
CH_DRAINING,
|
||||
CH_DISCONNECTED,
|
||||
};
|
||||
|
||||
|
||||
+5
-3
@@ -383,9 +383,11 @@ int start(int argc, char **argv)
|
||||
desc.opt.on_free_cmd_type = on_free_cmd_type;
|
||||
desc.opt.memory_reuse_type = memory_reuse_type;
|
||||
|
||||
desc.opt.tst = SCST_CONTR_MODE_SEP_TASK_SETS;
|
||||
desc.opt.queue_alg = SCST_CONTR_MODE_QUEUE_ALG_UNRESTRICTED_REORDER;
|
||||
desc.opt.d_sense = SCST_CONTR_MODE_FIXED_SENSE;
|
||||
desc.opt.tst = SCST_TST_1_SEP_TASK_SETS;
|
||||
desc.opt.tmf_only = 0;
|
||||
desc.opt.queue_alg = SCST_QUEUE_ALG_1_UNRESTRICTED_REORDER;
|
||||
desc.opt.qerr = SCST_QERR_0_ALL_RESUME;
|
||||
desc.opt.d_sense = SCST_D_SENSE_0_FIXED_SENSE;
|
||||
|
||||
res = ioctl(devs[i].scst_usr_fd, SCST_USER_REGISTER_DEVICE, &desc);
|
||||
if (res != 0) {
|
||||
|
||||
Reference in New Issue
Block a user