Merged revisions 5322-5326,5329-5340,5344-5371,5382-5407 via svnmerge from

svn+ssh://yanb123@svn.code.sf.net/p/scst/svn/trunk

........
  r5322 | vlnb | 2014-03-05 05:27:21 +0200 (Wed, 05 Mar 2014) | 13 lines
  
  scst_vdisk: Make vdisk_nullio size configurable
  
  Keep the default size of vdisk_nullio devices at VDISK_NULLIO_SIZE. Add
  a sysfs attribute 'size' which is the size of a vdisk device in
  bytes. Make the size of vdisk_nullio devices configurable. Accept
  "size" and "size_mb" as creation parameters for vdisk_nullio
  devices. Generate a CAPACITY DATA HAS CHANGED unit attention after size
  changes. Refuse any attempt to change the size into a number that is
  not a multiple of the block size.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5323 | bvassche | 2014-03-06 09:29:00 +0200 (Thu, 06 Mar 2014) | 1 line
  
  scst_vdisk: Avoid that smatch complains about unreachable code
........
  r5324 | vlnb | 2014-03-07 06:02:39 +0200 (Fri, 07 Mar 2014) | 27 lines
  
  PERSISTENT RESERVE IN: Suppress a kernel warning for small output buffer sizes
  
  This patch suppresses the following error message and kernel warning:
  
  scst: ***ERROR***: Too big response data len 24 (max 8), limiting it to the max (dev iis)
  Call Trace:
   [<ffffffff818b1193>] ? dump_stack+0x41/0x56
   [<ffffffffa01c1a8f>] ? scst_set_resp_data_len+0x82/0xb1 [scst]
   [<ffffffffa01ca80f>] ? scst_pr_read_reservation+0xbf/0xc4 [scst]
   [<ffffffffa01b707b>] ? scst_persistent_reserve_in_local+0x140/0x1ce [scst]
   [<ffffffffa01b7cee>] ? scst_exec_check_blocking+0x57/0xf1 [scst]
   [<ffffffffa01b85f4>] ? scst_process_active_cmd+0x86c/0x136f [scst]
   [<ffffffffa01b913c>] ? scst_do_job_active+0x45/0x5b [scst]
   [<ffffffffa01b939c>] ? scst_cmd_thread+0x218/0x2b7 [scst]
   [<ffffffff8105292a>] ? wake_up_bit+0x23/0x23
   [<ffffffffa01b9184>] ? scst_cmd_tasklet+0x32/0x32 [scst]
   [<ffffffff81052355>] ? kthread_freezable_should_stop+0x51/0x51
   [<ffffffffa01b9184>] ? scst_cmd_tasklet+0x32/0x32 [scst]
   [<ffffffff81052400>] ? kthread+0xab/0xb3
   [<ffffffff81052355>] ? kthread_freezable_should_stop+0x51/0x51
   [<ffffffff818b4e3c>] ? ret_from_fork+0x7c/0xb0
   [<ffffffff81052355>] ? kthread_freezable_should_stop+0x51/0x51
  
  Reported-by: Roman Bogdanov <bogdanovr@gmail.com>
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5325 | bvassche | 2014-03-08 15:30:29 +0200 (Sat, 08 Mar 2014) | 1 line
  
  nightly build: Update kernel versions
........
  r5326 | vlnb | 2014-03-13 05:50:37 +0200 (Thu, 13 Mar 2014) | 3 lines
  
  Update link to Gentoo HOWTO from Jurie Botha
........
  r5329 | vlnb | 2014-03-15 03:38:06 +0200 (Sat, 15 Mar 2014) | 3 lines
  
  Cleanup
........
  r5330 | vlnb | 2014-03-15 03:38:37 +0200 (Sat, 15 Mar 2014) | 3 lines
  
  Implement REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS command
........
  r5331 | vlnb | 2014-03-15 03:40:57 +0200 (Sat, 15 Mar 2014) | 8 lines
  
  scst_vdisk: Remove an unused parameter from vdisk_fsync*()
  
  The "struct vdisk_cmd_params *p" parameter is neither used by vdisk_fsync(),
  vdisk_fsync_blockio() nor by vdisk_fsync_fileio() so remove it.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5332 | vlnb | 2014-03-15 03:42:06 +0200 (Sat, 15 Mar 2014) | 8 lines
  
  vdisk_blockio: Change default vendor name back to "SCST_BIO"
  
  In r5316 the default vendor name for vdisk_blockio devices was changed
  into "SCST_FIO". Change this back into "SCST_BIO".
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5333 | vlnb | 2014-03-15 03:44:35 +0200 (Sat, 15 Mar 2014) | 8 lines
  
  vdisk_blockio: Add VERIFY implementation
  
  There is already an implementation of the VERIFY command for vdisk_fileio
  devices. Add an implementation for vdisk_blockio devices.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5334 | vlnb | 2014-03-15 04:01:17 +0200 (Sat, 15 Mar 2014) | 8 lines
  
  scst_vdisk: Implement COMPARE AND WRITE
  
  Ensure that COMPARE AND WRITE is executed atomically by serializing
  all COMPARE AND WRITE commands per device (SCST_SERIALIZED).
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5335 | vlnb | 2014-03-15 04:09:17 +0200 (Sat, 15 Mar 2014) | 5 lines
  
  Fix URL to SCST website
  
  Signed-off-by: Steven J. Magnani <steve@digidescorp.com>
........
  r5336 | vlnb | 2014-03-15 04:13:58 +0200 (Sat, 15 Mar 2014) | 3 lines
  
  Cleanup
........
  r5337 | bvassche | 2014-03-15 08:47:26 +0200 (Sat, 15 Mar 2014) | 1 line
  
  scripts/kernel-functions: Kernel 3.13.6 build fix
........
  r5338 | bvassche | 2014-03-16 15:38:50 +0200 (Sun, 16 Mar 2014) | 1 line
  
  srpt: Minor buid process terminology change
........
  r5339 | bvassche | 2014-03-18 17:35:13 +0200 (Tue, 18 Mar 2014) | 1 line
  
  ib_srpt: Avoid that session logout hangs sporadically
........
  r5340 | vlnb | 2014-03-19 06:28:46 +0200 (Wed, 19 Mar 2014) | 8 lines
  
  scst/README: Show how to read SCST sysfs attributes
  
  Make the behavior of SCST sysfs attributes more clear by adding
  examples in scst/README of code for reading and writing these attributes.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5344 | bvassche | 2014-03-20 17:13:50 +0200 (Thu, 20 Mar 2014) | 1 line
  
  ib_srpt: Simplify srpt_handle_cmd()
........
  r5345 | bvassche | 2014-03-20 17:14:45 +0200 (Thu, 20 Mar 2014) | 5 lines
  
  ib_srpt: Micro-optimize I/O context state manipulation
      
  All ioctx->state manipulations are serialized per command so it is
  not necessary to use locking to protect these manipulations.
........
  r5346 | bvassche | 2014-03-20 17:15:54 +0200 (Thu, 20 Mar 2014) | 8 lines
  
  ib_srpt: Handle GID change events properly
      
  The mlx4_core driver generates a GID change event after a port has been
  changed from IB into Ethernet mode. Avoid that this causes the following
  error message to appear in the system log:
      
  ib_srpt: ***ERROR***: received unrecognized IB event 18
........
  r5347 | bvassche | 2014-03-20 17:16:27 +0200 (Thu, 20 Mar 2014) | 1 line
  
  ib_srpt/Makefile: Add kerneldoc target
........
  r5348 | bvassche | 2014-03-20 17:17:04 +0200 (Thu, 20 Mar 2014) | 1 line
  
  ib_srpt: Fix an error reported by the kerneldoc tool
........
  r5349 | bvassche | 2014-03-20 17:18:06 +0200 (Thu, 20 Mar 2014) | 5 lines
  
  ib_srpt: Avoid that cmd_wait_list processing triggers command reordering
  
  Although harmless for SCSI commands with SIMPLE ordering, avoid that commands
  received before RTU can get reordered.
........
  r5350 | bvassche | 2014-03-20 17:18:38 +0200 (Thu, 20 Mar 2014) | 2 lines
  
  ib_srpt: Micro-optimize SRP_CMD parsing
........
  r5351 | bvassche | 2014-03-20 17:19:05 +0200 (Thu, 20 Mar 2014) | 1 line
  
  ib_srpt: Sync information unit memory only once
........
  r5352 | bvassche | 2014-03-20 17:19:34 +0200 (Thu, 20 Mar 2014) | 2 lines
  
  ib_srpt: Introduce a temporary variable in srpt_handle_new_iu()
........
  r5353 | bvassche | 2014-03-20 17:20:55 +0200 (Thu, 20 Mar 2014) | 2 lines
  
  ib_srpt: Micro-optimize polling
........
  r5354 | bvassche | 2014-03-20 17:22:19 +0200 (Thu, 20 Mar 2014) | 5 lines
  
  ib_srpt: Rework multi-channel support
  
  Store initiator and target port ID's once per nexus instead of in each
  channel data structure.
........
  r5355 | bvassche | 2014-03-20 17:23:16 +0200 (Thu, 20 Mar 2014) | 2 lines
  
  ib_srpt: Simplify channel state management code
........
  r5356 | bvassche | 2014-03-20 17:24:18 +0200 (Thu, 20 Mar 2014) | 5 lines
  
  ib_srpt: Defer destroying the QP until the TimeWait state has been left
  
  This is necessary to avoid that a login gets rejected due to reusing a
  queue pair number that has not yet been freed by the target side.
........
  r5357 | bvassche | 2014-03-20 17:25:34 +0200 (Thu, 20 Mar 2014) | 5 lines
  
  ib_srpt: Rework waiting for last WQE
  
  After having changed the queue pair state into "error", queue an additional
  work request instead of waiting for the last WQE event.
........
  r5358 | bvassche | 2014-03-20 17:26:48 +0200 (Thu, 20 Mar 2014) | 1 line
  
  srpt/session-management.txt: Document how sessions are managed by the ib_srpt driver
........
  r5359 | bvassche | 2014-03-20 18:10:19 +0200 (Thu, 20 Mar 2014) | 1 line
  
  scst_const.h: Make COMPARE_AND_WRITE definition available for kernel versions 3.6..3.11
........
  r5360 | vlnb | 2014-03-21 03:58:13 +0200 (Fri, 21 Mar 2014) | 3 lines
  
  In VERIFY commands BYTCHK 1x is not supported (yet)
........
  r5361 | bvassche | 2014-03-21 18:29:26 +0200 (Fri, 21 Mar 2014) | 1 line
  
  srpt/Makefile: Avoid that the build process depends on source control tools
........
  r5362 | vlnb | 2014-03-22 01:12:42 +0200 (Sat, 22 Mar 2014) | 3 lines
  
  Fix error recovery of internal commands
........
  r5363 | bvassche | 2014-03-24 13:53:00 +0200 (Mon, 24 Mar 2014) | 1 line
  
  ib_srpt: Clarify a kernel-doc comment
........
  r5364 | bvassche | 2014-03-24 13:55:56 +0200 (Mon, 24 Mar 2014) | 1 line
  
  ib_srpt: Add newline at the end of kernel warning statements
........
  r5365 | bvassche | 2014-03-24 13:57:39 +0200 (Mon, 24 Mar 2014) | 5 lines
  
  ib_srpt: Change the severity level of a log message
  
  Make sure that target port state changes get logged even with
  debugging disabled.
........
  r5366 | bvassche | 2014-03-24 13:59:27 +0200 (Mon, 24 Mar 2014) | 5 lines
  
  ib_srpt: Clean up srpt_destroy_ch_ib()
  
  All callers guarantee that the completion queue is empty so it is
  not necessary to invoke ib_poll_cq() from inside this function.
........
  r5367 | bvassche | 2014-03-24 14:01:07 +0200 (Mon, 24 Mar 2014) | 5 lines
  
  ib_srpt: Micro-optimize srpt_adjust_srq_wr_avail()
  
  The overhead of atomic_add_return() is lower than that of a
  spin_lock() / spin_unlock() pair, hence switch to the former.
........
  r5368 | bvassche | 2014-03-24 14:03:09 +0200 (Mon, 24 Mar 2014) | 20 lines
  
  ib_srpt: Fix a kernel warning
  
  Avoid that the following (very rare) kernel warning is reported
  when an ib_srpt target port is disabled while I/O is ongoing:
  
  WARNING: CPU: 3 PID: 12259 at srpt/src/ib_srpt.c:3334 srpt_xmit_response+0x165/0x300 [ib_srpt]()
  Unexpected command state 6
  Call Trace:
   [<ffffffff814a15dc>] dump_stack+0x4e/0x7a
   [<ffffffff8104bc5d>] warn_slowpath_common+0x7d/0xa0
   [<ffffffff8104bccc>] warn_slowpath_fmt+0x4c/0x50
   [<ffffffffa0771525>] srpt_xmit_response+0x165/0x300 [ib_srpt]
   [<ffffffffa082aacc>] scst_xmit_response+0xbc/0x560 [scst]
   [<ffffffffa083123d>] scst_process_active_cmd+0x29d/0x7b0 [scst]
   [<ffffffffa0832bd9>] scst_do_job_active+0x89/0x1a0 [scst]
   [<ffffffffa0832e4f>] scst_cmd_thread+0x15f/0x350 [scst]
   [<ffffffff810766cd>] kthread+0xed/0x110
   [<ffffffff814b312c>] ret_from_fork+0x7c/0xb0
  ---[ end trace 591f7af7d006fc0e ]---
........
  r5369 | bvassche | 2014-03-24 14:04:44 +0200 (Mon, 24 Mar 2014) | 5 lines
  
  ib_srpt: Add a kernel warning
  
  Invoking srpt_zerolength_write() before the queue pair has reached
  the error state is a bug, so complain loudly if that happens.
........
  r5370 | bvassche | 2014-03-24 14:07:43 +0200 (Mon, 24 Mar 2014) | 7 lines
  
  ib_srpt: Avoid waiting for missing error completions
  
  Apparently with mlx4 firmware up to and including 2.30.8000 it is not
  guaranteed that for a QP associated with an SRQ error completions are
  generated for all pending work requests. Avoid triggering
  srpt_pending_cmd_timeout() for missing error completions.
........
  r5371 | bvassche | 2014-03-25 18:19:00 +0200 (Tue, 25 Mar 2014) | 1 line
  
  nightly build: Update kernel versions
........
  r5382 | vlnb | 2014-03-26 04:31:52 +0200 (Wed, 26 Mar 2014) | 6 lines
  
  Black hole functionality added
  
  Scst_mutex intentially used directly in the sysfs handler, because
  comming sysfs improvements will allow that.
........
  r5383 | vlnb | 2014-03-26 05:18:03 +0200 (Wed, 26 Mar 2014) | 5 lines
  
  documentation: Document SCST_SERIALIZED and SCST_STRICTLY_SERIALIZED
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5384 | vlnb | 2014-03-26 05:18:36 +0200 (Wed, 26 Mar 2014) | 3 lines
  
  Cleanup
........
  r5385 | vlnb | 2014-03-26 05:20:04 +0200 (Wed, 26 Mar 2014) | 9 lines
  
  scst_local: Remove two superfluous tests
  
  The to_scst_lcl_sess() macro is based on container_of() and hence never
  returns NULL. Hence remove the two tests that compare the result of that
  macro against NULL.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5386 | vlnb | 2014-03-26 05:21:25 +0200 (Wed, 26 Mar 2014) | 7 lines
  
  iscsi-scst: Introduce ARRAY_SIZE()
  
  This patch does not change any functionality.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5387 | vlnb | 2014-03-26 05:22:16 +0200 (Wed, 26 Mar 2014) | 8 lines
  
  scst: Clarify a comment
  
  The comment above scst_nexus_loss() is somewhat confusing so change
  it into something that is more clear.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5388 | vlnb | 2014-03-26 05:23:57 +0200 (Wed, 26 Mar 2014) | 9 lines
  
  scst_vdisk: Fix READ CAPACITY(10)
  
  SBC-2 defines the LBA as a 32-bit field that starts at offset 2 and
  not as a 64-bit field.
  
  Reported-by: Mike Christie <michaelc@cs.wisc.edu>
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5389 | bvassche | 2014-03-26 13:56:13 +0200 (Wed, 26 Mar 2014) | 4 lines
  
  ib_srpt: Clean up srpt_handle_rdma_comp()
  
  This patch does not change any functionality.
........
  r5390 | bvassche | 2014-03-26 13:56:59 +0200 (Wed, 26 Mar 2014) | 4 lines
  
  ib_srpt: Clean up srpt_handle_send_err_comp()
  
  This patch does not change any functionality.
........
  r5391 | bvassche | 2014-03-26 13:58:25 +0200 (Wed, 26 Mar 2014) | 4 lines
  
  ib_srpt: Clean up srpt_handle_rdma_err_comp()
  
  This patch does not change any functionality.
........
  r5392 | bvassche | 2014-03-26 13:59:37 +0200 (Wed, 26 Mar 2014) | 5 lines
  
  ib_srpt: Suppress superfluous error messages
  
  Only complain about a missing completion for I/O contexts that are
  in a state where the ib_srpt driver is waiting for the HCA.
........
  r5393 | bvassche | 2014-03-26 14:00:43 +0200 (Wed, 26 Mar 2014) | 5 lines
  
  ib_srpt: Make srpt_abort_cmd() state checks more strict
  
  Complain if srpt_abort_cmd() is called for an I/O context that is
  being processed by SCST and not by the HCA.
........
  r5394 | vlnb | 2014-03-27 00:16:16 +0200 (Thu, 27 Mar 2014) | 3 lines
  
  Cosmetics
........
  r5395 | vlnb | 2014-03-27 01:51:36 +0200 (Thu, 27 Mar 2014) | 3 lines
  
  Reimplement dropping of TM requests in a more reliable manner
........
  r5396 | vlnb | 2014-03-27 03:57:08 +0200 (Thu, 27 Mar 2014) | 3 lines
  
  Possibility to specify SCSI target device name added
........
  r5397 | bvassche | 2014-03-27 10:27:45 +0200 (Thu, 27 Mar 2014) | 6 lines
  
  Fix two checkpatch complaints about whitespace
  
  Avoid that checkpatch reports the following error message:
  
  ERROR: "(foo*)" should be "(foo *)"
........
  r5398 | bvassche | 2014-03-27 10:34:27 +0200 (Thu, 27 Mar 2014) | 6 lines
  
  Avoid that checkpatch complains that return is not a function
  
  Avoid that checkpatch reports the following error message:
  
  ERROR: return is not a function, parentheses are not required
........
  r5399 | bvassche | 2014-03-27 10:39:53 +0200 (Thu, 27 Mar 2014) | 1 line
  
  scripts/generate-kernel-patch: Fix for kernel versions 3.7, 3.10, 3.12 and 3.13
........
  r5400 | vlnb | 2014-03-29 04:07:22 +0300 (Sat, 29 Mar 2014) | 3 lines
  
  Cleanup
........
  r5401 | bvassche | 2014-04-01 20:46:36 +0300 (Tue, 01 Apr 2014) | 1 line
  
  vdisk_blockio: Temporarily disable COMPARE AND WRITE support
........
  r5402 | bvassche | 2014-04-02 00:05:31 +0300 (Wed, 02 Apr 2014) | 1 line
  
  vdisk_blockio: Fix the (recently enabled) VERIFY command
........
  r5403 | bvassche | 2014-04-03 18:58:16 +0300 (Thu, 03 Apr 2014) | 1 line
  
  ib_srpt: RHEL 6.5 build fix
........
  r5404 | vlnb | 2014-04-04 03:57:30 +0300 (Fri, 04 Apr 2014) | 3 lines
  
  Fix typo in scst_report_supported_tm_fns() reported by Steve Magnani <steve.magnani@digidescorp.com>
........
  r5405 | bvassche | 2014-04-04 07:38:33 +0300 (Fri, 04 Apr 2014) | 1 line
  
  scripts/specialize-patch: Handle numbers surrounded by parentheses properly
........
  r5406 | bvassche | 2014-04-04 08:50:52 +0300 (Fri, 04 Apr 2014) | 1 line
  
  scripts/specialize-patch: Rework r5405
........
  r5407 | bvassche | 2014-04-04 08:56:25 +0300 (Fri, 04 Apr 2014) | 1 line
  
  nightly build: Update kernel versions
........


git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/iser@5408 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Yan Burman
2014-04-06 08:13:25 +00:00
parent 4beae6794e
commit 799ddae085
27 changed files with 1635 additions and 548 deletions
+14 -1
View File
@@ -1272,7 +1272,20 @@ Where:
<item><bf/SCST_SMALL_TIMEOUT/ - set if CDB requires small timeout
<item><bf/SCST_LONG_TIMEOUT/ - set if CDB requires long timeout
<item><bf/SCST_SERIALIZED/ - set if a command requires serialization
against commands that are received later. If the flag SCST_SERIALIZED
has been set, execution of commands for the same device that are
received later will be postponed until execution of the serialized
command has finished.
<item><bf/SCST_STRICTLY_SERIALIZED/ - set if a command must not
be executed concurrently against any other command received for the
same device. Processing of a strictly serialized command only starts
after processing of all previously received commands has finished and
no new commands are started as long as execution of a strictly
serialized command is in progress.
</itemize>
<item><bf/direction/ - one of the <bf/SCST_DATA_*/ constants (see below)
+1 -1
View File
@@ -26,7 +26,7 @@ This document assumes that the reader is familiar with the SCST
architecture and the states through which SCSI commands go during
processing in SCST. Module scst_user basically only provides hooks to
them. Their description could be found on the SCST web page on
http://scst.st.net.
http://scst.sf.net.
<sect> User space API
+27 -7
View File
@@ -62,7 +62,8 @@ static struct page *dummy_page;
static struct scatterlist dummy_sg;
static void cmnd_remove_data_wait_hash(struct iscsi_cmnd *cmnd);
static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status);
static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status,
bool dropped);
static void iscsi_check_send_delayed_tm_resp(struct iscsi_session *sess);
static int cmnd_insert_data_wait_hash(struct iscsi_cmnd *cmnd);
static void iscsi_cmnd_init_write(struct iscsi_cmnd *rsp, int flags);
@@ -2721,7 +2722,7 @@ static void execute_task_management(struct iscsi_cmnd *req)
reject:
if (rc != 0)
iscsi_send_task_mgmt_resp(req, status);
iscsi_send_task_mgmt_resp(req, status, false);
return;
}
@@ -3610,7 +3611,8 @@ out:
return;
}
static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status)
static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status,
bool drop)
{
struct iscsi_cmnd *rsp;
struct iscsi_task_mgt_hdr *req_hdr =
@@ -3622,7 +3624,26 @@ static void iscsi_send_task_mgmt_resp(struct iscsi_cmnd *req, int status)
TRACE_ENTRY();
TRACE_MGMT_DBG("TM req %p finished", req);
TRACE(TRACE_MGMT, "iSCSI TM fn %d finished, status %d", fn, status);
TRACE(TRACE_MGMT, "iSCSI TM fn %d finished, status %d, dropped %d",
fn, status, drop);
if (drop) {
spin_lock(&sess->sn_lock);
sess->tm_active--;
spin_unlock(&sess->sn_lock);
if (fn == ISCSI_FUNCTION_TARGET_COLD_RESET) {
struct iscsi_target *target = req->conn->session->target;
PRINT_INFO("Closing all connections for target %x at "
"COLD RESET from initiator %s", target->tid,
req->conn->session->initiator_name);
mutex_lock(&target->target_mutex);
target_del_all_sess(target, 0);
mutex_unlock(&target->target_mutex);
}
goto out_release;
}
rsp = iscsi_alloc_rsp(req);
rsp_hdr = (struct iscsi_task_rsp_hdr *)&rsp->pdu.bhs;
@@ -3691,8 +3712,7 @@ static void iscsi_task_mgmt_fn_done(struct scst_mgmt_cmd *scst_mcmd)
int fn = scst_mgmt_cmd_get_fn(scst_mcmd);
struct iscsi_cmnd *req = (struct iscsi_cmnd *)
scst_mgmt_cmd_get_tgt_priv(scst_mcmd);
int status =
iscsi_get_mgmt_response(scst_mgmt_cmd_get_status(scst_mcmd));
int status = iscsi_get_mgmt_response(scst_mgmt_cmd_get_status(scst_mcmd));
if ((status == ISCSI_RESPONSE_UNKNOWN_TASK) &&
(fn == SCST_ABORT_TASK)) {
@@ -3714,7 +3734,7 @@ static void iscsi_task_mgmt_fn_done(struct scst_mgmt_cmd *scst_mcmd)
sBUG_ON(1);
break;
default:
iscsi_send_task_mgmt_resp(req, status);
iscsi_send_task_mgmt_resp(req, status, scst_mgmt_cmd_dropped(scst_mcmd));
scst_mgmt_cmd_set_tgt_priv(scst_mcmd, NULL);
break;
}
+4 -6
View File
@@ -1331,8 +1331,7 @@ static int write_data(struct iscsi_conn *conn)
loff_t off = 0;
int rest;
sBUG_ON(count > (signed)(sizeof(conn->write_iov) /
sizeof(conn->write_iov[0])));
sBUG_ON(count > ARRAY_SIZE(conn->write_iov));
retry:
oldfs = get_fs();
set_fs(KERNEL_DS);
@@ -1367,8 +1366,8 @@ retry:
break;
goto out_iov;
}
sBUG_ON(iop > conn->write_iov + sizeof(conn->write_iov)
/sizeof(conn->write_iov[0]));
sBUG_ON(iop >
conn->write_iov + ARRAY_SIZE(conn->write_iov));
iop->iov_base += rest;
iop->iov_len -= rest;
}
@@ -1626,8 +1625,7 @@ static void init_tx_hdigest(struct iscsi_cmnd *cmnd)
digest_tx_header(cmnd);
sBUG_ON(conn->write_iop_used >=
(signed)(sizeof(conn->write_iov)/sizeof(conn->write_iov[0])));
sBUG_ON(conn->write_iop_used >= ARRAY_SIZE(conn->write_iov));
iop = &conn->write_iop[conn->write_iop_used];
conn->write_iop_used++;
+3 -3
View File
@@ -3,16 +3,16 @@
ABT_DETAILS="x86_64"
ABT_JOBS=5
ABT_KERNELS=" \
3.13.5 \
3.13.9 \
3.12.13-nc \
3.11.10-nc \
3.10.32-nc \
3.10.36-nc \
3.9.11-nc \
3.8.13-nc \
3.7.10-nc \
3.6.11-nc \
3.5.7-nc \
3.4.81-nc \
3.4.86-nc \
3.3.8-nc \
3.2.53-nc \
3.1.10-nc \
+17 -17
View File
@@ -1235,25 +1235,25 @@ static struct q2t_sess *q2t_create_sess(scsi_qla_host_t *ha, fc_port_t *fcport,
spin_lock_irq(&pha->hardware_lock);
sess = q2t_find_sess_by_port_name_include_deleted(tgt, fcport->port_name);
if (sess != NULL) {
TRACE_MGMT_DBG("Double sess %p found (s_id %x:%x:%x, "
"loop_id %d), updating to d_id %x:%x:%x, "
"loop_id %d", sess, sess->s_id.b.domain,
sess->s_id.b.area, sess->s_id.b.al_pa,
sess->loop_id, fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa,
fcport->loop_id);
TRACE_MGMT_DBG("Double sess %p found (s_id %x:%x:%x, "
"loop_id %d), updating to d_id %x:%x:%x, "
"loop_id %d", sess, sess->s_id.b.domain,
sess->s_id.b.area, sess->s_id.b.al_pa,
sess->loop_id, fcport->d_id.b.domain,
fcport->d_id.b.area, fcport->d_id.b.al_pa,
fcport->loop_id);
if (sess->deleted)
q2t_undelete_sess(sess);
if (sess->deleted)
q2t_undelete_sess(sess);
q2t_sess_get(sess);
sess->s_id = fcport->d_id;
sess->loop_id = fcport->loop_id;
sess->conf_compl_supported = fcport->conf_compl_supported;
if (sess->local && !local)
sess->local = 0;
spin_unlock_irq(&pha->hardware_lock);
goto out;
q2t_sess_get(sess);
sess->s_id = fcport->d_id;
sess->loop_id = fcport->loop_id;
sess->conf_compl_supported = fcport->conf_compl_supported;
if (sess->local && !local)
sess->local = 0;
spin_unlock_irq(&pha->hardware_lock);
goto out;
}
spin_unlock_irq(&pha->hardware_lock);
+4 -4
View File
@@ -268,13 +268,13 @@ done
scsi_exec_req_fifo_defined=0
scst_io_context=0
for p in scst/kernel/*-${kver}.patch \
$(if [ ${kver} = 3.7 ] && [ "${1#3.7.}" -ge 10 ]; then
$(if [ "${1#3.7.}" != "$1" ] && [ "${1#3.7.}" -ge 10 ]; then
echo iscsi-scst/kernel/patches/*-3.7.10.patch;
elif [ ${kver} = 3.10 ] && [ "${1#3.10.}" -ge 30 ]; then
elif [ "${1#3.10.}" != "$1" ] && [ "${1#3.10.}" -ge 30 ]; then
echo iscsi-scst/kernel/patches/*-3.10.30.patch;
elif [ ${kver} = 3.12 ] && [ "${1#3.12.}" -ge 11 ]; then
elif [ "${1#3.12.}" != "$1" ] && [ "${1#3.12.}" -ge 11 ]; then
echo iscsi-scst/kernel/patches/*-3.12.11.patch;
elif [ ${kver} = 3.13 ] && [ "${1#3.13.}" -ge 3 ]; then
elif [ "${1#3.13.}" != "$1" ] && [ "${1#3.13.}" -ge 3 ]; then
echo iscsi-scst/kernel/patches/*-3.13.3.patch;
else
echo iscsi-scst/kernel/patches/*-${kver}.patch;
+3 -1
View File
@@ -175,7 +175,8 @@ Get rid of sparse errors on sk_buff.protocol.
EOF
fi
if [ "${1#3.13}" != "$1" ]; then
patch -f -s -p1 <<'EOF'
if [ "$1" = "3.13" ] || [ "${1#3.13.}" -lt 6 ]; then
patch -f -s -p1 <<'EOF'
From 7b4ec8dd7d4ac467e9eee4d49f2c9574d773efbb Mon Sep 17 00:00:00 2001
From: Johannes Berg <johannes.berg@intel.com>
Date: Thu, 16 Jan 2014 10:18:48 +1030
@@ -212,6 +213,7 @@ index 3f2793d..96e45ea 100644
__used \
__attribute__((section("___ksymtab" sec "+" #sym), unused)) \
EOF
fi
fi
)
rmdir "${tmpdir}"
+13 -1
View File
@@ -151,7 +151,13 @@ function evaluate(stmnt, pattern, arg, op, result) {
{
last_stmnt = stmnt
pattern = "![[:blank:]]*([0-9]+)"
pattern = "![[:blank:]]*(-*[0-9]+)"
while (match(stmnt, pattern, op) != 0)
{
sub(pattern, op[1] == 0, stmnt)
}
pattern = "![[:blank:]]*\\([[:blank:]]*(-*[0-9]+)[[:blank:]]*\\)"
while (match(stmnt, pattern, op) != 0)
{
sub(pattern, op[1] == 0, stmnt)
@@ -197,6 +203,12 @@ function evaluate(stmnt, pattern, arg, op, result) {
sub(pattern, result, stmnt)
}
pattern="(-*[0-9]+)[[:blank:]]*\\&\\&[[:blank:]]*\\([[:blank:]]*(-*[0-9]+)[[:blank:]]*\\)"
while (match(stmnt, pattern, op) != 0)
{
sub(pattern, (op[1] != 0) && (op[2] != 0), stmnt)
}
pattern="(-*[0-9]+)[[:blank:]]*\\&\\&[[:blank:]]*(-*[0-9]+)"
while (match(stmnt, pattern, op) != 0)
{
+63 -3
View File
@@ -460,7 +460,38 @@ following entries:
complete, an management tool should poll this file. If the operation
hasn't yet completed, it will also return EAGAIN. But after it's
completed, it will return the result of this operation (0 for success
or -errno for error).
or -errno for error). The following two shell functions show how to do
this:
# Read the SCST sysfs attribute $1. See also scst/README for more information.
scst_sysfs_read() {
local EAGAIN val
EAGAIN="Resource temporarily unavailable"
while true; do
if val="$(LC_ALL=C cat "$1" 2>&1)"; then
echo -n "${val%\[key\]}"
return 0
elif [ "${val/*: }" != "$EAGAIN" ]; then
return 1
fi
sleep 1
done
}
# Write $1 into the SCST sysfs attribute $2. See also scst/README for more
# information.
scst_sysfs_write() {
local EAGAIN status
EAGAIN="Resource temporarily unavailable"
if status="$(LC_ALL=C; (echo -n "$1" > "$2") 2>&1)"; then
return 0
elif [ "${status/*: }" != "$EAGAIN" ]; then
return 1
fi
scst_sysfs_read /sys/kernel/scst_tgt/last_sysfs_mgmt_res >/dev/null
}
"Devices" subdirectory contains subdirectories for each SCST devices.
@@ -549,7 +580,7 @@ Every target should have at least the following entries:
mapping to the corresponding hardware port. It isn't anyhow used by
SCST.
- enabled - using this attribute you can enable or disable this target/
- enabled - using this attribute you can enable or disable this target.
It allows to finish configuring it before it starts accepting new
connections. 0 by default.
@@ -561,6 +592,31 @@ Every target should have at least the following entries:
can assign the addressing method on per-initiator basis. See also the
"Logical unit addressing (LUN)" section in SAM-5 for more information.
- black_hole - if set, all LUNs in the corresponding initiator group,
default target group in this case, start "swallowing" requests from
initiators. Possible values are:
* 0 - disable black hole mode
* 1 - immediately abort all coming commands
* 2 - immediately abort all coming commands and drop all coming TM
commands
* 3 - immediately abort all coming data transfer commands.
* 4 - immediately abort all coming data transfer commands and drop all
coming TM commands
Modes 3 and 4 are the most evil ones, because they are not too well
handled by many initiator OS'es, including Linux, so they may never
recover from it.
Note, dropping TM commands, i.e. not sending response on them,
implemented not for all target drivers. If it's implemented for your
particular target driver or not, you can find out by checking traces
or the target driver's source code.
- cpu_mask - defines CPU affinity mask for threads serving this target.
For threads serving LUNs it is used only for devices with
threads_pool_type "per_initiator".
@@ -719,7 +775,7 @@ commands by looking inside this file.
Each security group's subdirectory contains 2 subdirectories: initiators
and luns as well as the following attributes: addr_method, cpu_mask and
io_grouping_type. See above description of them.
io_grouping_type, black_hole. See above description of them.
Each "initiators" subdirectory contains list of added to this groups
initiator as well as as well as file "mgmt". This file has the following
@@ -965,6 +1021,10 @@ Each vdisk_fileio's device has the following attributes in
- prod_rev_lvl - PRODUCT REVISION LEVEL as reported via the INQUIRY
response. The default value for this field is " 300".
- scsi_device_name - optional SCSI target device name to which this
SCST device belongs to (in SCSI terminology all SCST devices called
Logical Units). See SPC for more info.
- thin_provisioned - contains thin provisioning status of this virtual
device.
+63 -3
View File
@@ -322,7 +322,38 @@ following entries:
complete, an management tool should poll this file. If the operation
hasn't yet completed, it will also return EAGAIN. But after it's
completed, it will return the result of this operation (0 for success
or -errno for error).
or -errno for error). The following two shell functions show how to do
this:
# Read the SCST sysfs attribute $1. See also scst/README for more information.
scst_sysfs_read() {
local EAGAIN val
EAGAIN="Resource temporarily unavailable"
while true; do
if val="$(LC_ALL=C cat "$1" 2>&1)"; then
echo -n "${val%\[key\]}"
return 0
elif [ "${val/*: }" != "$EAGAIN" ]; then
return 1
fi
sleep 1
done
}
# Write $1 into the SCST sysfs attribute $2. See also scst/README for more
# information.
scst_sysfs_write() {
local EAGAIN status
EAGAIN="Resource temporarily unavailable"
if status="$(LC_ALL=C; (echo -n "$1" > "$2") 2>&1)"; then
return 0
elif [ "${status/*: }" != "$EAGAIN" ]; then
return 1
fi
scst_sysfs_read /sys/kernel/scst_tgt/last_sysfs_mgmt_res >/dev/null
}
"Devices" subdirectory contains subdirectories for each SCST devices.
@@ -411,7 +442,7 @@ Every target should have at least the following entries:
mapping to the corresponding hardware port. It isn't anyhow used by
SCST.
- enabled - using this attribute you can enable or disable this target/
- enabled - using this attribute you can enable or disable this target.
It allows to finish configuring it before it starts accepting new
connections. 0 by default.
@@ -423,6 +454,31 @@ Every target should have at least the following entries:
can assign the addressing method on per-initiator basis. See also the
"Logical unit addressing (LUN)" section in SAM-5 for more information.
- black_hole - if set, all LUNs in the corresponding initiator group,
default target group in this case, start "swallowing" requests from
initiators. Possible values are:
* 0 - disable black hole mode
* 1 - immediately abort all coming commands
* 2 - immediately abort all coming commands and drop all coming TM
commands
* 3 - immediately abort all coming data transfer commands.
* 4 - immediately abort all coming data transfer commands and drop all
coming TM commands
Modes 3 and 4 are the most evil ones, because they are not too well
handled by many initiator OS'es, including Linux, so they may never
recover from it.
Note, dropping TM commands, i.e. not sending response on them,
implemented not for all target drivers. If it's implemented for your
particular target driver or not, you can find out by checking traces
or the target driver's source code.
- cpu_mask - defines CPU affinity mask for threads serving this target.
For threads serving LUNs it is used only for devices with
threads_pool_type "per_initiator".
@@ -581,7 +637,7 @@ commands by looking inside this file.
Each security group's subdirectory contains 2 subdirectories: initiators
and luns as well as the following attributes: addr_method, cpu_mask and
io_grouping_type. See above description of them.
io_grouping_type, black_hole. See above description of them.
Each "initiators" subdirectory contains list of added to this groups
initiator as well as as well as file "mgmt". This file has the following
@@ -823,6 +879,10 @@ Each vdisk_fileio's device has the following attributes in
- prod_rev_lvl - PRODUCT REVISION LEVEL as reported via the INQUIRY
response. The default value for this field is " 300".
- scsi_device_name - optional SCSI target device name to which this
SCST device belongs to (in SCSI terminology all SCST devices called
Logical Units). See SPC for more info.
- thin_provisioned - contains thin provisioning status of this virtual
device.
+45 -6
View File
@@ -592,6 +592,9 @@ enum scst_exec_context {
/* Set if tgt_dev has Unit Attention sense */
#define SCST_TGT_DEV_UA_PENDING 0
/* Cache of acg->acg_black_hole_type */
#define SCST_TGT_DEV_BLACK_HOLE 1
/*************************************************************
** I/O grouping types. Changing them don't forget to change
** the corresponding *_STR values in scst_const.h!
@@ -2286,6 +2289,7 @@ struct scst_mgmt_cmd {
unsigned int cmd_sn_set:1; /* set, if cmd_sn field is valid */
/* 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 */
/*
* Number of commands to finish before sending response,
@@ -2727,6 +2731,33 @@ struct scst_acg {
unsigned int tgt_acg:1;
/* Not a black hole */
#define SCST_ACG_BLACK_HOLE_NONE 0
/* Immediately abort all coming commands */
#define SCST_ACG_BLACK_HOLE_CMD 1
/*
* Immediately abort all coming commands and drop all coming TM commands.
*
* CAUTION! With some target drivers it can cause internal resources
* leaks, so don't abuse this option!
*/
#define SCST_ACG_BLACK_HOLE_ALL 2
/* Immediately abort all coming data transfer commands */
#define SCST_ACG_BLACK_HOLE_DATA_CMD 3
/*
* Immediately abort all coming data transfer commands and drop all
* coming TM commands.
*
* CAUTION! With some target drivers it can cause internal resources
* leaks, so don't abuse this option!
*/
#define SCST_ACG_BLACK_HOLE_DATA_MCMD 4
volatile int acg_black_hole_type;
/* sysfs release completion */
struct completion *acg_kobj_release_cmpl;
@@ -3035,6 +3066,8 @@ int scst_get_cdb_info(struct scst_cmd *cmd);
int scst_set_cmd_error_status(struct scst_cmd *cmd, int status);
int scst_set_cmd_error(struct scst_cmd *cmd, int key, int asc, int ascq);
int scst_set_cmd_error_and_inf(struct scst_cmd *cmd, int key, int asc,
int ascq, uint64_t information);
void scst_set_busy(struct scst_cmd *cmd);
void scst_check_convert_sense(struct scst_cmd *cmd);
@@ -3685,12 +3718,6 @@ static inline int scst_mgmt_cmd_get_status(struct scst_mgmt_cmd *mcmd)
return mcmd->status;
}
/* Returns mgmt cmd's TM fn */
static inline int scst_mgmt_cmd_get_fn(struct scst_mgmt_cmd *mcmd)
{
return mcmd->fn;
}
static inline void scst_mgmt_cmd_set_status(struct scst_mgmt_cmd *mcmd,
int status)
{
@@ -3700,6 +3727,18 @@ static inline void scst_mgmt_cmd_set_status(struct scst_mgmt_cmd *mcmd,
mcmd->status = status;
}
/* Returns mgmt cmd's TM fn */
static inline int scst_mgmt_cmd_get_fn(struct scst_mgmt_cmd *mcmd)
{
return mcmd->fn;
}
/* Returns true if mgmt cmd should be dropped, i.e. response not sent */
static inline bool scst_mgmt_cmd_dropped(struct scst_mgmt_cmd *mcmd)
{
return mcmd->mcmd_dropped;
}
/*
* Called by dev handler's task_mgmt_fn_*() to notify SCST core that mcmd
* is going to complete asynchronously.
+12 -3
View File
@@ -264,12 +264,12 @@ enum scst_cdb_flags {
static inline int scst_sense_valid(const uint8_t *sense)
{
return ((sense != NULL) && ((sense[0] & 0x70) == 0x70));
return (sense != NULL) && ((sense[0] & 0x70) == 0x70);
}
static inline int scst_no_sense(const uint8_t *sense)
{
return ((sense != NULL) && (sense[2] == 0));
return (sense != NULL) && (sense[2] == 0);
}
static inline int scst_sense_response_code(const uint8_t *sense)
@@ -421,6 +421,16 @@ static inline int scst_sense_response_code(const uint8_t *sense)
#define UNMAP 0x42
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0)
/*
* From <scsi/scsi.h>. See also commit
* 1c68cc1626341665a8bd1d2c7dfffd7fc852a79c.
*/
#ifndef COMPARE_AND_WRITE
#define COMPARE_AND_WRITE 0x89
#endif
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
/*
* From <linux/fs.h>. See also commit
@@ -550,7 +560,6 @@ enum scst_tg_sup {
** Misc SCSI constants
*************************************************************/
#define SCST_SENSE_ASC_UA_RESET 0x29
#define BYTCHK 0x02
#define POSITION_LEN_SHORT 20
#define POSITION_LEN_LONG 32
+3 -3
View File
@@ -1,15 +1,15 @@
#
# SCSI target mid-level makefile
#
#
# Copyright (C) 2004 - 2014 Vladislav Bolkhovitin <vst@vlnb.net>
# Copyright (C) 2004 - 2005 Leonid Stoljar
# Copyright (C) 2007 - 2014 Fusion-io, Inc.
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, version 2
# of the License.
#
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+549 -90
View File
@@ -182,12 +182,14 @@ struct scst_vdisk_dev {
unsigned int vend_specific_id_set:1;
unsigned int prod_id_set:1; /* true if prod_id manually set */
unsigned int prod_rev_lvl_set:1; /* true if prod_rev_lvl manually set */
unsigned int scsi_device_name_set:1; /* true if scsi_device_name manually set */
unsigned int t10_dev_id_set:1; /* true if t10_dev_id manually set */
unsigned int usn_set:1; /* true if usn manually set */
char t10_vend_id[8 + 1];
char vend_specific_id[32 + 1];
char prod_id[16 + 1];
char prod_rev_lvl[4 + 1];
char scsi_device_name[256 + 1];
char t10_dev_id[16+8+2]; /* T10 device ID */
char usn[MAX_USN_LEN];
uint8_t inq_vend_specific[MAX_INQ_VEND_SPECIFIC_LEN];
@@ -259,8 +261,7 @@ static enum compl_status_e fileio_exec_write(struct vdisk_cmd_params *p);
static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua);
static int vdisk_blockio_flush(struct block_device *bdev, gfp_t gfp_mask,
bool report_error, struct scst_cmd *cmd, bool async);
static enum compl_status_e blockio_exec_verify(struct vdisk_cmd_params *p);
static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p);
static enum compl_status_e vdev_exec_verify(struct vdisk_cmd_params *p);
static enum compl_status_e blockio_exec_write_verify(struct vdisk_cmd_params *p);
static enum compl_status_e fileio_exec_write_verify(struct vdisk_cmd_params *p);
static enum compl_status_e nullio_exec_write_verify(struct vdisk_cmd_params *p);
@@ -277,7 +278,8 @@ static enum compl_status_e vdisk_exec_read_toc(struct vdisk_cmd_params *p);
static enum compl_status_e vdisk_exec_prevent_allow_medium_removal(struct vdisk_cmd_params *p);
static enum compl_status_e vdisk_exec_unmap(struct vdisk_cmd_params *p);
static enum compl_status_e vdisk_exec_write_same(struct vdisk_cmd_params *p);
static int vdisk_fsync(struct vdisk_cmd_params *p, loff_t loff,
static enum compl_status_e vdisk_exec_caw(struct vdisk_cmd_params *p);
static int vdisk_fsync(loff_t loff,
loff_t len, struct scst_device *dev, gfp_t gfp_flags,
struct scst_cmd *cmd, bool async);
#ifdef CONFIG_SCST_PROC
@@ -307,8 +309,14 @@ static int vdisk_unmap_range(struct scst_cmd *cmd,
#ifndef CONFIG_SCST_PROC
static ssize_t vdev_sysfs_size_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static ssize_t vdev_sysfs_size_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdev_sysfs_size_mb_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static ssize_t vdev_sysfs_size_mb_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdisk_sysfs_blocksize_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdisk_sysfs_rd_only_show(struct kobject *kobj,
@@ -347,6 +355,10 @@ static ssize_t vdev_sysfs_prod_rev_lvl_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static ssize_t vdev_sysfs_prod_rev_lvl_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdev_sysfs_scsi_device_name_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static ssize_t vdev_sysfs_scsi_device_name_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t vdev_sysfs_t10_dev_id_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static ssize_t vdev_sysfs_t10_dev_id_show(struct kobject *kobj,
@@ -365,8 +377,16 @@ static ssize_t vdev_zero_copy_show(struct kobject *kobj,
static ssize_t vcdrom_sysfs_filename_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static struct kobj_attribute vdev_size_attr =
__ATTR(size_mb, S_IRUGO, vdev_sysfs_size_show, NULL);
static struct kobj_attribute vdev_size_ro_attr =
__ATTR(size, S_IRUGO, vdev_sysfs_size_show, NULL);
static struct kobj_attribute vdev_size_rw_attr =
__ATTR(size, S_IWUSR|S_IRUGO, vdev_sysfs_size_show,
vdev_sysfs_size_store);
static struct kobj_attribute vdev_size_mb_ro_attr =
__ATTR(size_mb, S_IRUGO, vdev_sysfs_size_mb_show, NULL);
static struct kobj_attribute vdev_size_mb_rw_attr =
__ATTR(size_mb, S_IWUSR|S_IRUGO, vdev_sysfs_size_mb_show,
vdev_sysfs_size_mb_store);
static struct kobj_attribute vdisk_blocksize_attr =
__ATTR(blocksize, S_IRUGO, vdisk_sysfs_blocksize_show, NULL);
static struct kobj_attribute vdisk_rd_only_attr =
@@ -402,6 +422,9 @@ static struct kobj_attribute vdev_prod_id_attr =
static struct kobj_attribute vdev_prod_rev_lvl_attr =
__ATTR(prod_rev_lvl, S_IWUSR|S_IRUGO, vdev_sysfs_prod_rev_lvl_show,
vdev_sysfs_prod_rev_lvl_store);
static struct kobj_attribute vdev_scsi_device_name_attr =
__ATTR(scsi_device_name, S_IWUSR|S_IRUGO, vdev_sysfs_scsi_device_name_show,
vdev_sysfs_scsi_device_name_store);
static struct kobj_attribute vdev_t10_dev_id_attr =
__ATTR(t10_dev_id, S_IWUSR|S_IRUGO, vdev_sysfs_t10_dev_id_show,
vdev_sysfs_t10_dev_id_store);
@@ -419,7 +442,8 @@ static struct kobj_attribute vcdrom_filename_attr =
vcdrom_sysfs_filename_store);
static const struct attribute *vdisk_fileio_attrs[] = {
&vdev_size_attr.attr,
&vdev_size_ro_attr.attr,
&vdev_size_mb_ro_attr.attr,
&vdisk_blocksize_attr.attr,
&vdisk_rd_only_attr.attr,
&vdisk_wt_attr.attr,
@@ -434,6 +458,7 @@ static const struct attribute *vdisk_fileio_attrs[] = {
&vdev_vend_specific_id_attr.attr,
&vdev_prod_id_attr.attr,
&vdev_prod_rev_lvl_attr.attr,
&vdev_scsi_device_name_attr.attr,
&vdev_t10_dev_id_attr.attr,
&vdev_usn_attr.attr,
&vdev_inq_vend_specific_attr.attr,
@@ -442,7 +467,8 @@ static const struct attribute *vdisk_fileio_attrs[] = {
};
static const struct attribute *vdisk_blockio_attrs[] = {
&vdev_size_attr.attr,
&vdev_size_ro_attr.attr,
&vdev_size_mb_ro_attr.attr,
&vdisk_blocksize_attr.attr,
&vdisk_rd_only_attr.attr,
&vdisk_wt_attr.attr,
@@ -455,6 +481,7 @@ static const struct attribute *vdisk_blockio_attrs[] = {
&vdev_vend_specific_id_attr.attr,
&vdev_prod_id_attr.attr,
&vdev_prod_rev_lvl_attr.attr,
&vdev_scsi_device_name_attr.attr,
&vdev_t10_dev_id_attr.attr,
&vdev_usn_attr.attr,
&vdev_inq_vend_specific_attr.attr,
@@ -463,7 +490,8 @@ static const struct attribute *vdisk_blockio_attrs[] = {
};
static const struct attribute *vdisk_nullio_attrs[] = {
&vdev_size_attr.attr,
&vdev_size_rw_attr.attr,
&vdev_size_mb_rw_attr.attr,
&vdisk_blocksize_attr.attr,
&vdisk_rd_only_attr.attr,
&vdev_dummy_attr.attr,
@@ -472,6 +500,7 @@ static const struct attribute *vdisk_nullio_attrs[] = {
&vdev_vend_specific_id_attr.attr,
&vdev_prod_id_attr.attr,
&vdev_prod_rev_lvl_attr.attr,
&vdev_scsi_device_name_attr.attr,
&vdev_t10_dev_id_attr.attr,
&vdev_usn_attr.attr,
&vdev_inq_vend_specific_attr.attr,
@@ -480,12 +509,14 @@ static const struct attribute *vdisk_nullio_attrs[] = {
};
static const struct attribute *vcdrom_attrs[] = {
&vdev_size_attr.attr,
&vdev_size_ro_attr.attr,
&vdev_size_mb_ro_attr.attr,
&vcdrom_filename_attr.attr,
&vdev_t10_vend_id_attr.attr,
&vdev_vend_specific_id_attr.attr,
&vdev_prod_id_attr.attr,
&vdev_prod_rev_lvl_attr.attr,
&vdev_scsi_device_name_attr.attr,
&vdev_t10_dev_id_attr.attr,
&vdev_usn_attr.attr,
&vdev_inq_vend_specific_attr.attr,
@@ -499,7 +530,7 @@ static DEFINE_MUTEX(scst_vdisk_mutex);
/*
* Protects the device attributes t10_vend_id, vend_specific_id, prod_id,
* prod_rev_lvl, t10_dev_id, usn and inq_vend_specific.
* prod_rev_lvl, scsi_device_name, t10_dev_id, usn and inq_vend_specific.
*/
static DEFINE_RWLOCK(vdisk_serial_rwlock);
@@ -632,7 +663,9 @@ static struct scst_dev_type vdisk_null_devtype = {
"dummy, "
"read_only, "
"removable, "
"rotational",
"rotational, "
"size, "
"size_mb",
#endif
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
.default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
@@ -942,17 +975,15 @@ static int vdisk_attach(struct scst_device *dev)
dev->dev_rd_only = virt_dev->rd_only;
if (!virt_dev->cdrom_empty) {
if (virt_dev->nullio)
err = VDISK_NULLIO_SIZE;
else {
if (!virt_dev->nullio) {
res = vdisk_get_file_size(virt_dev->filename,
virt_dev->blockio, &err);
if (res != 0)
goto out;
}
virt_dev->file_size = err;
virt_dev->file_size = err;
TRACE_DBG("size of file: %lld", (long long unsigned int)err);
TRACE_DBG("size of file: %lld", err);
}
vdisk_blockio_check_flush_support(virt_dev);
vdisk_check_tp_support(virt_dev);
@@ -1123,12 +1154,12 @@ static enum compl_status_e vdisk_synchronize_cache(struct vdisk_cmd_params *p)
cmd->completed = 1;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT,
SCST_CONTEXT_SAME);
vdisk_fsync(p, loff, data_len, dev, cmd->cmd_gfp_mask, NULL, true);
vdisk_fsync(loff, data_len, dev, cmd->cmd_gfp_mask, NULL, true);
/* ToDo: vdisk_fsync() error processing */
scst_cmd_put(cmd);
res = RUNNING_ASYNC;
} else {
vdisk_fsync(p, loff, data_len, dev, cmd->cmd_gfp_mask, cmd, true);
vdisk_fsync(loff, data_len, dev, cmd->cmd_gfp_mask, cmd, true);
res = RUNNING_ASYNC;
}
@@ -1144,7 +1175,7 @@ static enum compl_status_e vdisk_exec_start_stop(struct vdisk_cmd_params *p)
TRACE_ENTRY();
vdisk_fsync(p, 0, virt_dev->file_size, dev, cmd->cmd_gfp_mask, cmd, false);
vdisk_fsync(0, virt_dev->file_size, dev, cmd->cmd_gfp_mask, cmd, false);
TRACE_EXIT();
return CMD_SUCCEEDED;
@@ -1405,9 +1436,9 @@ static vdisk_op_fn blockio_ops[256] = {
[WRITE_VERIFY] = blockio_exec_write_verify,
[WRITE_VERIFY_12] = blockio_exec_write_verify,
[WRITE_VERIFY_16] = blockio_exec_write_verify,
[VERIFY] = blockio_exec_verify,
[VERIFY_12] = blockio_exec_verify,
[VERIFY_16] = blockio_exec_verify,
[VERIFY] = vdev_exec_verify,
[VERIFY_12] = vdev_exec_verify,
[VERIFY_16] = vdev_exec_verify,
SHARED_OPS
};
@@ -1420,12 +1451,13 @@ static vdisk_op_fn fileio_ops[256] = {
[WRITE_10] = fileio_exec_write,
[WRITE_12] = fileio_exec_write,
[WRITE_16] = fileio_exec_write,
[COMPARE_AND_WRITE] = vdisk_exec_caw,
[WRITE_VERIFY] = fileio_exec_write_verify,
[WRITE_VERIFY_12] = fileio_exec_write_verify,
[WRITE_VERIFY_16] = fileio_exec_write_verify,
[VERIFY] = fileio_exec_verify,
[VERIFY_12] = fileio_exec_verify,
[VERIFY_16] = fileio_exec_verify,
[VERIFY] = vdev_exec_verify,
[VERIFY_12] = vdev_exec_verify,
[VERIFY_16] = vdev_exec_verify,
SHARED_OPS
};
@@ -1526,6 +1558,7 @@ static bool vdisk_parse_offset(struct vdisk_cmd_params *p, struct scst_cmd *cmd)
case WRITE_10:
case WRITE_12:
case WRITE_16:
case COMPARE_AND_WRITE:
fua = (cdb[1] & 0x8);
if (fua) {
TRACE(TRACE_ORDER, "FUA: loff=%lld, "
@@ -2536,6 +2569,23 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
int num = 4;
buf[1] = 0x83;
read_lock(&vdisk_serial_rwlock);
i = strlen(virt_dev->scsi_device_name);
if (i > 0) {
/* SCSI target device name */
buf[num + 0] = 0x3; /* ASCII */
buf[num + 1] = 0x20 | 0x8; /* Target device SCSI name */
i += 4 - i % 4; /* align to required 4 bytes */
scst_copy_and_fill_b(&buf[num + 4], virt_dev->scsi_device_name, i, '\0');
buf[num + 3] = i;
num += buf[num + 3];
num += 4;
}
read_unlock(&vdisk_serial_rwlock);
/* T10 vendor identifier field format (faked) */
buf[num + 0] = 0x2; /* ASCII */
buf[num + 1] = 0x1; /* Vendor ID */
@@ -2612,6 +2662,7 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
buf[1] = 0xB0;
buf[3] = 0x3C;
buf[4] = 1; /* WSNZ set */
buf[5] = 0xFF; /* No MAXIMUM COMPARE AND WRITE LENGTH limit */
/* Optimal transfer granuality is PAGE_SIZE */
put_unaligned_be16(max_t(int, PAGE_SIZE/dev->block_size, 1), &buf[6]);
@@ -3354,7 +3405,7 @@ static enum compl_status_e vdisk_exec_read_capacity(struct vdisk_cmd_params *p)
nblocks = virt_dev->nblocks;
if ((cmd->cdb[8] & 1) == 0) {
uint64_t lba = get_unaligned_be64(&cmd->cdb[2]);
uint32_t lba = get_unaligned_be32(&cmd->cdb[2]);
if (lba != 0) {
TRACE_DBG("PMI zero and LBA not zero (cmd %p)", cmd);
scst_set_cmd_error(cmd,
@@ -3623,7 +3674,7 @@ static enum compl_status_e vdisk_exec_prevent_allow_medium_removal(struct vdisk_
return CMD_SUCCEEDED;
}
static int vdisk_fsync_blockio(struct vdisk_cmd_params *p, loff_t loff,
static int vdisk_fsync_blockio(loff_t loff,
loff_t len, struct scst_device *dev, gfp_t gfp_flags,
struct scst_cmd *cmd, bool async)
{
@@ -3646,7 +3697,7 @@ static int vdisk_fsync_blockio(struct vdisk_cmd_params *p, loff_t loff,
return res;
}
static int vdisk_fsync_fileio(struct vdisk_cmd_params *p, loff_t loff,
static int vdisk_fsync_fileio(loff_t loff,
loff_t len, struct scst_device *dev, struct scst_cmd *cmd, bool async)
{
int res;
@@ -3697,7 +3748,7 @@ static int vdisk_fsync_fileio(struct vdisk_cmd_params *p, loff_t loff,
return res;
}
static int vdisk_fsync(struct vdisk_cmd_params *p, loff_t loff,
static int vdisk_fsync(loff_t loff,
loff_t len, struct scst_device *dev, gfp_t gfp_flags,
struct scst_cmd *cmd, bool async)
{
@@ -3722,10 +3773,12 @@ static int vdisk_fsync(struct vdisk_cmd_params *p, loff_t loff,
goto out;
}
if (virt_dev->blockio)
res = vdisk_fsync_blockio(p, loff, len, dev, gfp_flags, cmd, async);
if (virt_dev->nullio)
;
else if (virt_dev->blockio)
res = vdisk_fsync_blockio(loff, len, dev, gfp_flags, cmd, async);
else
res = vdisk_fsync_fileio(p, loff, len, dev, cmd, async);
res = vdisk_fsync_fileio(loff, len, dev, cmd, async);
out:
TRACE_EXIT_RES(res);
@@ -4016,7 +4069,7 @@ restart:
out_sync:
/* O_DSYNC flag is used for WT devices */
if (p->fua)
vdisk_fsync(p, loff, scst_cmd_get_data_len(cmd), cmd->dev,
vdisk_fsync(loff, scst_cmd_get_data_len(cmd), cmd->dev,
cmd->cmd_gfp_mask, cmd, false);
out:
TRACE_EXIT();
@@ -4382,65 +4435,198 @@ out:
return res;
}
static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
static int blockio_end_sync_io(struct bio *bio, unsigned int bytes_done,
int error)
#else
static void blockio_end_sync_io(struct bio *bio, int error)
#endif
{
struct completion *c = bio->bi_private;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
if (bio->bi_size)
return 1;
#endif
if (!bio_flagged(bio, BIO_UPTODATE) && error == 0) {
PRINT_ERROR("Not up to date bio with error 0; returning -EIO");
error = -EIO;
}
bio->bi_private = (void *)(unsigned long)error;
complete(c);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
return 0;
#else
return;
#endif
}
static ssize_t blockio_rw_sync(struct scst_vdisk_dev *virt_dev, void *buf,
size_t len, loff_t *loff, unsigned rw)
{
DECLARE_COMPLETION_ONSTACK(c);
struct block_device *bdev = virt_dev->bdev;
struct bio *bio;
void *p;
int max_nr_vecs, rc;
unsigned bytes, off;
ssize_t ret = -ENOMEM;
max_nr_vecs = min(bio_get_nr_vecs(bdev), BIO_MAX_PAGES);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
bio = bio_kmalloc(GFP_KERNEL, max_nr_vecs);
#else
bio = bio_alloc(GFP_KERNEL, max_nr_vecs);
#endif
if (!bio)
goto out;
bio->bi_rw = rw;
bio->bi_bdev = bdev;
bio->bi_end_io = blockio_end_sync_io;
bio->bi_private = &c;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0)
bio->bi_sector = *loff >> 9;
#else
bio->bi_iter.bi_sector = *loff >> 9;
#endif
for (p = buf; p < buf + len; p += bytes) {
off = offset_in_page(p);
bytes = PAGE_SIZE - off;
rc = bio_add_page(bio, virt_to_page(p), bytes, off);
if (WARN_ON_ONCE(rc < bytes))
goto free;
}
submit_bio(rw, bio);
wait_for_completion(&c);
ret = (unsigned long)bio->bi_private ? : len;
free:
bio_put(bio);
out:
return ret;
}
static ssize_t fileio_read_sync(struct file *fd, void *buf, size_t len,
loff_t *loff)
{
mm_segment_t old_fs;
ssize_t ret;
old_fs = get_fs();
set_fs(get_ds());
if (fd->f_op->llseek)
ret = fd->f_op->llseek(fd, *loff, 0/*SEEK_SET*/);
else
ret = default_llseek(fd, *loff, 0/*SEEK_SET*/);
if (ret < 0)
goto out;
ret = vfs_read(fd, (char __force __user *)buf, len, loff);
out:
set_fs(old_fs);
return ret;
}
static ssize_t fileio_write_sync(struct file *fd, void *buf, size_t len,
loff_t *loff)
{
mm_segment_t old_fs;
ssize_t ret;
old_fs = get_fs();
set_fs(get_ds());
if (fd->f_op->llseek)
ret = fd->f_op->llseek(fd, *loff, 0/*SEEK_SET*/);
else
ret = default_llseek(fd, *loff, 0/*SEEK_SET*/);
if (ret < 0)
goto out;
ret = vfs_write(fd, (char __force __user *)buf, len, loff);
out:
set_fs(old_fs);
return ret;
}
static ssize_t vdev_read_sync(struct scst_vdisk_dev *virt_dev, void *buf,
size_t len, loff_t *loff)
{
if (virt_dev->nullio)
return len;
else if (virt_dev->blockio)
return blockio_rw_sync(virt_dev, buf, len, loff, 0/*read*/);
else
return fileio_read_sync(virt_dev->fd, buf, len, loff);
}
static ssize_t vdev_write_sync(struct scst_vdisk_dev *virt_dev, void *buf,
size_t len, loff_t *loff)
{
int rw;
if (virt_dev->nullio) {
return len;
} else if (virt_dev->blockio) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
rw = REQ_WRITE;
#else
rw = 1 << BIO_RW;
#endif
return blockio_rw_sync(virt_dev, buf, len, loff, rw);
} else {
return fileio_write_sync(virt_dev->fd, buf, len, loff);
}
}
static enum compl_status_e vdev_exec_verify(struct vdisk_cmd_params *p)
{
struct scst_cmd *cmd = p->cmd;
loff_t loff = p->loff;
mm_segment_t old_fs;
loff_t err;
ssize_t length, len_mem = 0;
uint8_t *address_sav, *address = NULL;
int compare;
struct scst_vdisk_dev *virt_dev = cmd->dev->dh_priv;
struct file *fd = virt_dev->fd;
uint8_t *mem_verify = NULL;
int64_t data_len = scst_cmd_get_data_len(cmd);
TRACE_ENTRY();
sBUG_ON(virt_dev->blockio);
if (vdisk_fsync(p, loff, data_len, cmd->dev,
if (vdisk_fsync(loff, data_len, cmd->dev,
cmd->cmd_gfp_mask, cmd, false) != 0)
goto out;
/*
* Until the cache is cleared prior the verifying, there is not
* much point in this code. ToDo.
* For file I/O, unless the cache is cleared prior the verifying,
* there is not much point in this code. ToDo.
*
* Nevertherless, this code is valuable if the data have not been read
* from the file/disk yet.
*/
compare = scst_cmd_get_data_direction(cmd) == SCST_DATA_WRITE;
TRACE_DBG("VERIFY with BYTCHK=%d at offset %lld and len %lld\n",
TRACE_DBG("VERIFY with compare %d at offset %lld and len %lld\n",
compare, loff, (long long)data_len);
/* SEEK */
old_fs = get_fs();
set_fs(get_ds());
if (!virt_dev->nullio) {
if (fd->f_op->llseek)
err = fd->f_op->llseek(fd, loff, 0/*SEEK_SET*/);
else
err = default_llseek(fd, loff, 0/*SEEK_SET*/);
if (err != loff) {
PRINT_ERROR("lseek trouble %lld != %lld",
(long long unsigned int)err,
(long long unsigned int)loff);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_read_error));
goto out_set_fs;
}
}
mem_verify = vmalloc(LEN_MEM);
if (mem_verify == NULL) {
PRINT_ERROR("Unable to allocate memory %d for verify",
LEN_MEM);
scst_set_busy(cmd);
goto out_set_fs;
goto out;
}
if (compare) {
@@ -4453,11 +4639,7 @@ static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p)
len_mem = (length > LEN_MEM) ? LEN_MEM : length;
TRACE_DBG("Verify: length %zd - len_mem %zd", length, len_mem);
if (!virt_dev->nullio)
err = vfs_read(fd, (char __force __user *)mem_verify,
len_mem, &loff);
else
err = len_mem;
err = vdev_read_sync(virt_dev, mem_verify, len_mem, &loff);
if ((err < 0) || (err < len_mem)) {
PRINT_ERROR("verify() returned %lld from %zd",
(long long unsigned int)err, len_mem);
@@ -4469,14 +4651,14 @@ static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p)
}
if (compare)
scst_put_buf(cmd, address_sav);
goto out_set_fs;
goto out_free;
}
if (compare && memcmp(address, mem_verify, len_mem) != 0) {
TRACE_DBG("Verify: error memcmp length %zd", length);
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_miscompare_error));
scst_put_buf(cmd, address_sav);
goto out_set_fs;
goto out_free;
}
length -= len_mem;
if (compare)
@@ -4494,8 +4676,7 @@ static enum compl_status_e fileio_exec_verify(struct vdisk_cmd_params *p)
SCST_LOAD_SENSE(scst_sense_hardw_error));
}
out_set_fs:
set_fs(old_fs);
out_free:
if (mem_verify)
vfree(mem_verify);
@@ -4504,6 +4685,106 @@ out:
return CMD_SUCCEEDED;
}
/* COMPARE AND WRITE */
static enum compl_status_e vdisk_exec_caw(struct vdisk_cmd_params *p)
{
struct scst_cmd *cmd = p->cmd;
struct scst_device *dev = cmd->dev;
struct scst_vdisk_dev *virt_dev = dev->dh_priv;
uint32_t data_len = scst_cmd_get_data_len(cmd);
int length, i;
uint8_t *caw_buf = NULL, *read_buf = NULL;
loff_t loff, read, written;
if (unlikely(cmd->cdb[1] & 0xE0)) {
TRACE_DBG("%s", "WRPROTECT not supported");
scst_set_invalid_field_in_cdb(cmd, 1,
SCST_INVAL_FIELD_BIT_OFFS_VALID | 5);
goto out;
}
/*
* A NUMBER OF LOGICAL BLOCKS field set to zero specifies that no read
* operations shall be performed, no logical block data shall be
* transferred from the Data-Out Buffer, no compare operations shall
* be performed, and no write operations shall be performed. This
* condition shall not be considered an error.
*/
if (data_len == 0)
goto out;
length = scst_get_buf_full(cmd, &caw_buf);
read_buf = vmalloc(data_len);
if (length < 0 || !read_buf) {
PRINT_ERROR("scst_get_buf_full() failed: %d", length);
if (length == -ENOMEM || !read_buf)
scst_set_busy(cmd);
else
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_hardw_error));
goto out;
}
WARN_ON_ONCE(length != 2 * data_len);
loff = p->loff;
read = vdev_read_sync(virt_dev, read_buf, data_len, &loff);
if (read < data_len) {
PRINT_ERROR("COMPARE AND WRITE / READ returned %lld from %d",
read, data_len);
if (read == -EAGAIN)
scst_set_busy(cmd);
else
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_read_error));
goto out;
}
if (memcmp(caw_buf, read_buf, data_len) != 0) {
for (i = 0; i < data_len && caw_buf[i] == read_buf[i]; i++)
;
/*
* SBC-3 $5.2: if the compare operation does not indicate a
* match, then terminate the command with CHECK CONDITION
* status with the sense key set to MISCOMPARE and the
* additional sense code set to MISCOMPARE DURING VERIFY
* OPERATION. In the sense data (see 4.18 and SPC-4) the
* offset from the start of the Data-Out Buffer to the first
* byte of data that was not equal shall be reported in the
* INFORMATION field.
*/
scst_set_cmd_error_and_inf(cmd,
SCST_LOAD_SENSE(scst_sense_miscompare_error),
p->loff + i);
goto out;
}
loff = p->loff;
written = vdev_write_sync(virt_dev, caw_buf + data_len, data_len,
&loff);
if (written < data_len) {
PRINT_ERROR("COMPARE AND WRITE / WRITE wrote %lld / %d",
written, data_len);
if (written == -EAGAIN)
scst_set_busy(cmd);
else
scst_set_cmd_error(cmd,
SCST_LOAD_SENSE(scst_sense_write_error));
goto out;
}
if (p->fua)
vdisk_fsync(loff, scst_cmd_get_data_len(cmd), cmd->dev,
cmd->cmd_gfp_mask, cmd, false);
out:
if (read_buf)
vfree(read_buf);
if (caw_buf)
scst_put_buf_full(cmd, caw_buf);
return CMD_SUCCEEDED;
}
static enum compl_status_e blockio_exec_write_verify(struct vdisk_cmd_params *p)
{
/* Not yet implemented */
@@ -4511,18 +4792,12 @@ static enum compl_status_e blockio_exec_write_verify(struct vdisk_cmd_params *p)
return blockio_exec_write(p);
}
static enum compl_status_e blockio_exec_verify(struct vdisk_cmd_params *p)
{
/* Not yet implemented */
return CMD_SUCCEEDED;
}
static enum compl_status_e fileio_exec_write_verify(struct vdisk_cmd_params *p)
{
fileio_exec_write(p);
/* O_DSYNC flag is used for WT devices */
if (scsi_status_is_good(p->cmd->status))
fileio_exec_verify(p);
vdev_exec_verify(p);
return CMD_SUCCEEDED;
}
@@ -4723,8 +4998,7 @@ static int vdev_create(struct scst_dev_type *devt,
TRACE_DBG("t10_dev_id %s", virt_dev->t10_dev_id);
sprintf(virt_dev->t10_vend_id, "%.*s",
(int)(sizeof(virt_dev->t10_vend_id) - 1),
virt_dev->blockio ? SCST_BIO_VENDOR : SCST_FIO_VENDOR);
(int)sizeof(virt_dev->t10_vend_id) - 1, SCST_FIO_VENDOR);
sprintf(virt_dev->vend_specific_id, "%.*s",
(int)(sizeof(virt_dev->vend_specific_id) - 1),
@@ -4736,6 +5010,9 @@ static int vdev_create(struct scst_dev_type *devt,
sprintf(virt_dev->prod_rev_lvl, "%.*s",
(int)(sizeof(virt_dev->prod_rev_lvl) - 1), SCST_FIO_REV);
sprintf(virt_dev->scsi_device_name, "%.*s",
(int)(sizeof(virt_dev->scsi_device_name) - 1), "");
scnprintf(virt_dev->usn, sizeof(virt_dev->usn), "%llx", dev_id_num);
TRACE_DBG("usn %s", virt_dev->usn);
@@ -4898,6 +5175,10 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev,
virt_dev->thin_provisioned);
} else if (!strcasecmp("zero_copy", p)) {
virt_dev->zero_copy = !!val;
} else if (!strcasecmp("size", p)) {
virt_dev->file_size = val;
} else if (!strcasecmp("size_mb", p)) {
virt_dev->file_size = val * 1024 * 1024;
} else if (!strcasecmp("blocksize", p)) {
virt_dev->blk_shift = scst_calc_block_shift(val);
if (virt_dev->blk_shift < 9) {
@@ -4914,6 +5195,12 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev,
}
}
if (virt_dev->file_size % (1 << virt_dev->blk_shift) != 0) {
PRINT_ERROR("Device size %lld is not a multiple of the block"
" size %d", virt_dev->file_size,
1 << virt_dev->blk_shift);
res = -EINVAL;
}
out:
TRACE_EXIT_RES(res);
return res;
@@ -4999,6 +5286,8 @@ static int vdev_blockio_add_device(const char *device_name, char *params)
virt_dev->blockio = 1;
virt_dev->wt_flag = DEF_WRITE_THROUGH;
sprintf(virt_dev->t10_vend_id, "%.*s",
(int)sizeof(virt_dev->t10_vend_id) - 1, SCST_BIO_VENDOR);
res = vdev_parse_add_dev_params(virt_dev, params, allowed_params);
if (res != 0)
@@ -5042,7 +5331,7 @@ static int vdev_nullio_add_device(const char *device_name, char *params)
int res = 0;
static const char *const allowed_params[] = {
"read_only", "dummy", "removable", "blocksize", "rotational",
NULL
"size", "size_mb", NULL
};
struct scst_vdisk_dev *virt_dev;
@@ -5055,6 +5344,7 @@ static int vdev_nullio_add_device(const char *device_name, char *params)
virt_dev->command_set_version = 0x04C0; /* SBC-3 */
virt_dev->nullio = 1;
virt_dev->file_size = VDISK_NULLIO_SIZE;
res = vdev_parse_add_dev_params(virt_dev, params, allowed_params);
if (res != 0)
@@ -5492,22 +5782,128 @@ out_free:
goto out;
}
static ssize_t vdev_sysfs_size_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
static int vdev_size_process_store(struct scst_sysfs_work_item *work)
{
struct scst_device *dev = work->dev;
struct scst_vdisk_dev *virt_dev;
unsigned long long new_size;
int size_shift, res = -EINVAL;
if (sscanf(work->buf, "%d %lld", &size_shift, &new_size) != 2 ||
new_size > (ULONG_MAX >> size_shift))
goto put;
new_size <<= size_shift;
res = scst_suspend_activity(SCST_SUSPEND_TIMEOUT_USER);
if (res)
goto put;
/* To sync with detach*() functions */
res = mutex_lock_interruptible(&scst_mutex);
if (res)
goto resume;
virt_dev = dev->dh_priv;
if (!virt_dev->nullio) {
res = -EPERM;
sBUG();
} else if (new_size % (1 << virt_dev->blk_shift) == 0) {
virt_dev->file_size = new_size;
virt_dev->nblocks = virt_dev->file_size >> dev->block_shift;
} else {
res = -EINVAL;
}
mutex_unlock(&scst_mutex);
if (res == 0)
scst_capacity_data_changed(dev);
resume:
scst_resume_activity();
put:
kobject_put(&dev->dev_kobj);
return res;
}
static ssize_t vdev_size_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf,
size_t count, int size_shift)
{
struct scst_device *dev = container_of(kobj, struct scst_device,
dev_kobj);
struct scst_sysfs_work_item *work;
char *new_size;
int res = -ENOMEM;
new_size = kasprintf(GFP_KERNEL, "%d %.*s", size_shift, (int)count,
buf);
if (!new_size)
goto out;
res = scst_alloc_sysfs_work(vdev_size_process_store, false, &work);
if (res)
goto out_free;
work->buf = new_size;
work->dev = dev;
SCST_SET_DEP_MAP(work, &scst_dev_dep_map);
kobject_get(&dev->dev_kobj);
res = scst_sysfs_queue_wait_work(work);
if (res == 0)
res = count;
out:
return res;
out_free:
kfree(buf);
goto out;
}
static ssize_t vdev_sysfs_size_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
return vdev_size_store(kobj, attr, buf, count, 0);
}
static ssize_t vdev_size_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf, int size_shift)
{
int pos = 0;
struct scst_device *dev;
struct scst_vdisk_dev *virt_dev;
TRACE_ENTRY();
unsigned long long size;
dev = container_of(kobj, struct scst_device, dev_kobj);
virt_dev = dev->dh_priv;
size = ACCESS_ONCE(virt_dev->file_size);
pos = sprintf(buf, "%lld\n", virt_dev->file_size / 1024 / 1024);
return sprintf(buf, "%llu\n%s", size >> size_shift,
virt_dev->nullio && size != VDISK_NULLIO_SIZE ?
SCST_SYSFS_KEY_MARK "\n" : "");
}
TRACE_EXIT_RES(pos);
return pos;
static ssize_t vdev_sysfs_size_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return vdev_size_show(kobj, attr, buf, 0);
}
static ssize_t vdev_sysfs_size_mb_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
return vdev_size_store(kobj, attr, buf, count, 20);
}
static ssize_t vdev_sysfs_size_mb_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return vdev_size_show(kobj, attr, buf, 20);
}
static ssize_t vdisk_sysfs_blocksize_show(struct kobject *kobj,
@@ -6068,6 +6464,66 @@ static ssize_t vdev_sysfs_prod_rev_lvl_show(struct kobject *kobj,
return pos;
}
static ssize_t vdev_sysfs_scsi_device_name_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t count)
{
struct scst_device *dev;
struct scst_vdisk_dev *virt_dev;
char *p;
int res, len;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
virt_dev = dev->dh_priv;
p = memchr(buf, '\n', count);
len = p ? p - buf : count;
if (len >= sizeof(virt_dev->scsi_device_name)) {
PRINT_ERROR("SCSI device namel is too long (max %zd characters)",
sizeof(virt_dev->scsi_device_name));
res = -EINVAL;
goto out;
}
write_lock(&vdisk_serial_rwlock);
sprintf(virt_dev->scsi_device_name, "%.*s", len, buf);
if (strlen(virt_dev->scsi_device_name) > 0)
virt_dev->scsi_device_name_set = 1;
else
virt_dev->scsi_device_name_set = 0;
write_unlock(&vdisk_serial_rwlock);
res = count;
out:
TRACE_EXIT_RES(res);
return res;
}
static ssize_t vdev_sysfs_scsi_device_name_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
int pos;
struct scst_device *dev;
struct scst_vdisk_dev *virt_dev;
TRACE_ENTRY();
dev = container_of(kobj, struct scst_device, dev_kobj);
virt_dev = dev->dh_priv;
read_lock(&vdisk_serial_rwlock);
pos = sprintf(buf, "%s\n%s", virt_dev->scsi_device_name,
virt_dev->scsi_device_name_set ? SCST_SYSFS_KEY_MARK "\n" : "");
read_unlock(&vdisk_serial_rwlock);
TRACE_EXIT_RES(pos);
return pos;
}
static ssize_t vdev_sysfs_t10_dev_id_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
@@ -6502,6 +6958,9 @@ static int vdisk_write_proc(char *buffer, char **start, off_t offset,
virt_dev->blockio = 1;
/* Bad hack for anyway going out procfs */
virt_dev->vdev_devt = &vdisk_blk_devtype;
sprintf(virt_dev->t10_vend_id, "%.*s",
(int)sizeof(virt_dev->t10_vend_id) - 1,
SCST_BIO_VENDOR);
TRACE_DBG("%s", "BLOCKIO");
} else if (!strncmp("REMOVABLE", p, 9)) {
p += 9;
+114 -8
View File
@@ -150,6 +150,8 @@ static int get_cdb_info_write_same10(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops);
static int get_cdb_info_write_same16(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops);
static int get_cdb_info_compare_and_write(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops);
static int get_cdb_info_apt(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops);
static int get_cdb_info_min(struct scst_cmd *cmd,
@@ -966,6 +968,14 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
.info_lba_off = 2, .info_lba_len = 8,
.info_len_off = 10, .info_len_len = 4,
.get_cdb_info = get_cdb_info_lba_8_len_4},
{.ops = 0x89, .devkey = "O ",
.info_op_name = "COMPARE AND WRITE",
.info_data_direction = SCST_DATA_WRITE,
.info_op_flags = SCST_TRANSFER_LEN_TYPE_FIXED|SCST_WRITE_MEDIUM|
SCST_SERIALIZED,
.info_lba_off = 2, .info_lba_len = 8,
.info_len_off = 13, .info_len_len = 1,
.get_cdb_info = get_cdb_info_compare_and_write},
{.ops = 0x8A, .devkey = "O OO O ",
.info_op_name = "WRITE(16)",
.info_data_direction = SCST_DATA_WRITE,
@@ -1656,6 +1666,38 @@ out:
}
EXPORT_SYMBOL(scst_set_cmd_error);
int scst_set_cmd_error_and_inf(struct scst_cmd *cmd, int key, int asc,
int ascq, uint64_t information)
{
int res;
res = scst_set_cmd_error(cmd, key, asc, ascq);
if (res)
goto out;
switch (cmd->sense[0] & 0x7f) {
case 0x70:
/* Fixed format */
cmd->sense[0] |= 0x80; /* Information field is valid */
put_unaligned_be32(information, &cmd->sense[3]);
break;
case 0x72:
/* Descriptor format */
cmd->sense[7] = 12; /* additional sense length */
cmd->sense[8 + 0] = 0; /* descriptor type: Information */
cmd->sense[8 + 1] = 10; /* Additional length */
cmd->sense[8 + 2] = 0x80; /* VALID */
put_unaligned_be64(information, &cmd->sense[8 + 4]);
break;
default:
sBUG();
}
out:
return res;
}
EXPORT_SYMBOL(scst_set_cmd_error_and_inf);
static void scst_fill_field_pointer_sense(uint8_t *fp_sense, int field_offs,
int bit_offs, bool cdb)
{
@@ -3831,7 +3873,7 @@ found:
t->acg_dev->acg->acg_io_grouping_type);
} else {
res = t;
if (!*(volatile bool*)&res->active_cmd_threads->io_context_ready) {
if (!*(volatile bool *)&res->active_cmd_threads->io_context_ready) {
TRACE_DBG("IO context for t %p not yet "
"initialized, waiting...", t);
msleep(100);
@@ -4110,6 +4152,10 @@ static int scst_alloc_add_tgt_dev(struct scst_session *sess,
tgt_dev->tgt_dev_rd_only = acg_dev->acg_dev_rd_only || dev->dev_rd_only;
tgt_dev->sess = sess;
atomic_set(&tgt_dev->tgt_dev_cmd_count, 0);
if (sess->acg->acg_black_hole_type != SCST_ACG_BLACK_HOLE_NONE)
set_bit(SCST_TGT_DEV_BLACK_HOLE, &tgt_dev->tgt_dev_flags);
else
clear_bit(SCST_TGT_DEV_BLACK_HOLE, &tgt_dev->tgt_dev_flags);
scst_sgv_pool_use_norm(tgt_dev);
@@ -4233,7 +4279,7 @@ out_free:
goto out;
}
/* No locks supposed to be held, scst_mutex - held */
/* scst_mutex supposed to be held */
void scst_nexus_loss(struct scst_tgt_dev *tgt_dev, bool queue_UA)
{
TRACE_ENTRY();
@@ -4531,6 +4577,24 @@ out:
return res;
}
static void scst_prelim_finish_internal_cmd(struct scst_cmd *cmd)
{
unsigned long flags;
TRACE_ENTRY();
sBUG_ON(!cmd->internal);
spin_lock_irqsave(&cmd->sess->sess_list_lock, flags);
list_del(&cmd->sess_cmd_list_entry);
spin_unlock_irqrestore(&cmd->sess->sess_list_lock, flags);
__scst_cmd_put(cmd);
TRACE_EXIT();
return;
}
int scst_prepare_request_sense(struct scst_cmd *orig_cmd)
{
int res = 0;
@@ -4734,7 +4798,7 @@ out:
return res;
out_free_cmd:
__scst_cmd_put(cmd);
scst_prelim_finish_internal_cmd(cmd);
out_busy:
scst_set_busy(ws_cmd);
@@ -6436,8 +6500,16 @@ static int get_cdb_info_fmt(struct scst_cmd *cmd,
static int get_cdb_info_verify10(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops)
{
if (unlikely(cmd->cdb[1] & 4)) {
PRINT_ERROR("VERIFY(10): BYTCHK 1x not supported (dev %s)",
cmd->dev ? cmd->dev->virt_name : NULL);
scst_set_invalid_field_in_cdb(cmd, 1,
2 | SCST_INVAL_FIELD_BIT_OFFS_VALID);
return 1;
}
cmd->lba = get_unaligned_be32(cmd->cdb + sdbops->info_lba_off);
if (cmd->cdb[1] & BYTCHK) {
if (cmd->cdb[1] & 2) {
cmd->bufflen = get_unaligned_be16(cmd->cdb + sdbops->info_len_off);
cmd->data_len = cmd->bufflen;
cmd->data_direction = SCST_DATA_WRITE;
@@ -6455,7 +6527,15 @@ static int get_cdb_info_verify6(struct scst_cmd *cmd,
cmd->op_flags |= SCST_LBA_NOT_VALID;
cmd->lba = 0;
if (cmd->cdb[1] & BYTCHK) {
if (unlikely(cmd->cdb[1] & 4)) {
PRINT_ERROR("VERIFY(6): BYTCHK 1x not supported (dev %s)",
cmd->dev ? cmd->dev->virt_name : NULL);
scst_set_invalid_field_in_cdb(cmd, 1,
2 | SCST_INVAL_FIELD_BIT_OFFS_VALID);
return 1;
}
if (cmd->cdb[1] & 2) { /* BYTCHK 01 */
cmd->bufflen = get_unaligned_be24(cmd->cdb + sdbops->info_len_off);
cmd->data_len = cmd->bufflen;
cmd->data_direction = SCST_DATA_WRITE;
@@ -6470,8 +6550,16 @@ static int get_cdb_info_verify6(struct scst_cmd *cmd,
static int get_cdb_info_verify12(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops)
{
if (unlikely(cmd->cdb[1] & 4)) {
PRINT_ERROR("VERIFY(12): BYTCHK 1x not supported (dev %s)",
cmd->dev ? cmd->dev->virt_name : NULL);
scst_set_invalid_field_in_cdb(cmd, 1,
2 | SCST_INVAL_FIELD_BIT_OFFS_VALID);
return 1;
}
cmd->lba = get_unaligned_be32(cmd->cdb + sdbops->info_lba_off);
if (cmd->cdb[1] & BYTCHK) {
if (cmd->cdb[1] & 2) { /* BYTCHK 01 */
cmd->bufflen = get_unaligned_be32(cmd->cdb + sdbops->info_len_off);
if (unlikely(cmd->bufflen & SCST_MAX_VALID_BUFFLEN_MASK)) {
PRINT_ERROR("Too big bufflen %d (op %x)",
@@ -6492,8 +6580,16 @@ static int get_cdb_info_verify12(struct scst_cmd *cmd,
static int get_cdb_info_verify16(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops)
{
if (unlikely(cmd->cdb[1] & 4)) {
PRINT_ERROR("VERIFY(16): BYTCHK 1x not supported (dev %s)",
cmd->dev ? cmd->dev->virt_name : NULL);
scst_set_invalid_field_in_cdb(cmd, 1,
2 | SCST_INVAL_FIELD_BIT_OFFS_VALID);
return 1;
}
cmd->lba = get_unaligned_be64(cmd->cdb + sdbops->info_lba_off);
if (cmd->cdb[1] & BYTCHK) {
if (cmd->cdb[1] & 2) { /* BYTCHK 01 */
cmd->bufflen = get_unaligned_be32(cmd->cdb + sdbops->info_len_off);
if (unlikely(cmd->bufflen & SCST_MAX_VALID_BUFFLEN_MASK)) {
PRINT_ERROR("Too big bufflen %d (op %x)",
@@ -6684,6 +6780,15 @@ static int get_cdb_info_write_same16(struct scst_cmd *cmd,
return 0;
}
static int get_cdb_info_compare_and_write(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops)
{
cmd->lba = get_unaligned_be64(cmd->cdb + sdbops->info_lba_off);
cmd->data_len = cmd->cdb[sdbops->info_len_off];
cmd->bufflen = 2 * cmd->data_len;
return 0;
}
/**
* get_cdb_info_apt() - Parse ATA PASS-THROUGH CDB.
*
@@ -6799,7 +6904,8 @@ static int get_cdb_info_min(struct scst_cmd *cmd,
break;
case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS:
cmd->op_name = "REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS";
cmd->op_flags |= SCST_WRITE_EXCL_ALLOWED;
cmd->op_flags |= SCST_WRITE_EXCL_ALLOWED |
SCST_LOCAL_CMD | SCST_FULLY_LOCAL_CMD;
break;
default:
break;
+1 -1
View File
@@ -1925,7 +1925,7 @@ out_wait:
* Wait for io_context gets initialized to avoid possible races
* for it from the sharing it tgt_devs.
*/
while (!*(volatile bool*)&cmd_threads->io_context_ready) {
while (!*(volatile bool *)&cmd_threads->io_context_ready) {
TRACE_DBG("Waiting for io_context for cmd_threads %p "
"initialized", cmd_threads);
msleep(50);
+5 -5
View File
@@ -2457,7 +2457,7 @@ void scst_pr_read_reservation(struct scst_cmd *cmd, uint8_t *buffer,
if (buffer_size < 8) {
TRACE_PR("buffer_size too small: %d. expected >= 8 "
"(buffer %p)", buffer_size, buffer);
goto skip;
goto out;
}
memset(b, 0, sizeof(b));
@@ -2491,10 +2491,10 @@ void scst_pr_read_reservation(struct scst_cmd *cmd, uint8_t *buffer,
size = 24;
}
memset(buffer, 0, buffer_size);
memcpy(buffer, b, min(size, buffer_size));
skip:
out:
size = min(size, buffer_size);
memcpy(buffer, b, size);
memset(buffer + size, 0, buffer_size - size);
scst_set_resp_data_len(cmd, size);
TRACE_EXIT();
+159
View File
@@ -1756,6 +1756,124 @@ static struct kobj_attribute scst_tgt_io_grouping_type =
scst_tgt_io_grouping_type_show,
scst_tgt_io_grouping_type_store);
static ssize_t __scst_acg_black_hole_show(struct scst_acg *acg, char *buf)
{
int res, t = acg->acg_black_hole_type;
res = sprintf(buf, "%d\n", t);
return res;
}
static ssize_t __scst_acg_black_hole_store(struct scst_acg *acg,
const char *buf, size_t count)
{
int res = 0;
int prev, t;
struct scst_session *sess;
prev = acg->acg_black_hole_type;
if ((buf == NULL) || (count == 0)) {
res = 0;
goto out;
}
mutex_lock(&scst_mutex);
BUILD_BUG_ON((SCST_ACG_BLACK_HOLE_NONE != 0) ||
(SCST_ACG_BLACK_HOLE_CMD != 1) ||
(SCST_ACG_BLACK_HOLE_ALL != 2) ||
(SCST_ACG_BLACK_HOLE_DATA_CMD != 3) ||
(SCST_ACG_BLACK_HOLE_DATA_MCMD != 4));
switch (buf[0]) {
case '0':
acg->acg_black_hole_type = SCST_ACG_BLACK_HOLE_NONE;
break;
case '1':
acg->acg_black_hole_type = SCST_ACG_BLACK_HOLE_CMD;
break;
case '2':
acg->acg_black_hole_type = SCST_ACG_BLACK_HOLE_ALL;
break;
case '3':
acg->acg_black_hole_type = SCST_ACG_BLACK_HOLE_DATA_CMD;
break;
case '4':
acg->acg_black_hole_type = SCST_ACG_BLACK_HOLE_DATA_MCMD;
break;
default:
PRINT_ERROR("%s: Requested action not understood: %s",
__func__, buf);
res = -EINVAL;
goto out_unlock;
}
t = acg->acg_black_hole_type;
if (prev == t)
goto out_unlock;
list_for_each_entry(sess, &acg->acg_sess_list, acg_sess_list_entry) {
int i;
for (i = 0; i < SESS_TGT_DEV_LIST_HASH_SIZE; i++) {
struct list_head *head = &sess->sess_tgt_dev_list[i];
struct scst_tgt_dev *tgt_dev;
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
if (t != SCST_ACG_BLACK_HOLE_NONE)
set_bit(SCST_TGT_DEV_BLACK_HOLE, &tgt_dev->tgt_dev_flags);
else
clear_bit(SCST_TGT_DEV_BLACK_HOLE, &tgt_dev->tgt_dev_flags);
}
}
}
PRINT_INFO("Black hole set to %d for ACG %s", t, acg->acg_name);
out_unlock:
mutex_unlock(&scst_mutex);
out:
return res;
}
static ssize_t scst_tgt_black_hole_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct scst_acg *acg;
struct scst_tgt *tgt;
tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
acg = tgt->default_acg;
return __scst_acg_black_hole_show(acg, buf);
}
static ssize_t scst_tgt_black_hole_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
int res;
struct scst_acg *acg;
struct scst_tgt *tgt;
tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
acg = tgt->default_acg;
res = __scst_acg_black_hole_store(acg, buf, count);
if (res != 0)
goto out;
res = count;
out:
TRACE_EXIT_RES(res);
return res;
}
static struct kobj_attribute scst_tgt_black_hole =
__ATTR(black_hole, S_IRUGO | S_IWUSR,
scst_tgt_black_hole_show, scst_tgt_black_hole_store);
static ssize_t __scst_acg_cpu_mask_show(struct scst_acg *acg, char *buf)
{
int res;
@@ -2473,6 +2591,7 @@ static struct attribute *scst_tgt_attrs[] = {
&scst_tgt_comment.attr,
&scst_tgt_addr_method.attr,
&scst_tgt_io_grouping_type.attr,
&scst_tgt_black_hole.attr,
&scst_tgt_cpu_mask.attr,
&scst_tgt_unknown_cmd_count_attr.attr,
&scst_tgt_write_cmd_count_attr.attr,
@@ -4285,6 +4404,39 @@ static struct kobj_attribute scst_acg_io_grouping_type =
scst_acg_io_grouping_type_show,
scst_acg_io_grouping_type_store);
static ssize_t scst_acg_black_hole_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct scst_acg *acg;
acg = container_of(kobj, struct scst_acg, acg_kobj);
return __scst_acg_black_hole_show(acg, buf);
}
static ssize_t scst_acg_black_hole_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
int res;
struct scst_acg *acg;
acg = container_of(kobj, struct scst_acg, acg_kobj);
res = __scst_acg_black_hole_store(acg, buf, count);
if (res != 0)
goto out;
res = count;
out:
TRACE_EXIT_RES(res);
return res;
}
static struct kobj_attribute scst_acg_black_hole =
__ATTR(black_hole, S_IRUGO | S_IWUSR,
scst_acg_black_hole_show, scst_acg_black_hole_store);
static ssize_t scst_acg_cpu_mask_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
@@ -4408,6 +4560,13 @@ int scst_acg_sysfs_create(struct scst_tgt *tgt,
goto out_del;
}
res = sysfs_create_file(&acg->acg_kobj, &scst_acg_black_hole.attr);
if (res != 0) {
PRINT_ERROR("Can't add tgt attr %s for tgt %s",
scst_acg_black_hole.attr.name, tgt->tgt_name);
goto out_del;
}
res = sysfs_create_file(&acg->acg_kobj, &scst_acg_cpu_mask.attr);
if (res != 0) {
PRINT_ERROR("Can't add tgt attr %s for tgt %s",
+104 -1
View File
@@ -972,6 +972,32 @@ out:
}
#endif
if (unlikely(test_bit(SCST_TGT_DEV_BLACK_HOLE, &cmd->tgt_dev->tgt_dev_flags))) {
struct scst_session *sess = cmd->sess;
bool abort = false;
switch (sess->acg->acg_black_hole_type) {
case SCST_ACG_BLACK_HOLE_CMD:
case SCST_ACG_BLACK_HOLE_ALL:
abort = true;
break;
case SCST_ACG_BLACK_HOLE_DATA_CMD:
case SCST_ACG_BLACK_HOLE_DATA_MCMD:
if (cmd->data_direction != SCST_DATA_NONE)
abort = true;
break;
default:
break;
}
if (abort) {
TRACE_MGMT_DBG("Black hole: aborting cmd %p (op %x, "
"initiator %s)", cmd, cmd->cdb[0],
sess->initiator_name);
spin_lock_irq(&sess->sess_list_lock);
scst_abort_cmd(cmd, NULL, false, false);
spin_unlock_irq(&sess->sess_list_lock);
}
}
TRACE_EXIT_HRES(res);
return res;
@@ -2036,6 +2062,74 @@ out_unlock_put_not_completed:
goto out;
}
static int scst_report_supported_tm_fns(struct scst_cmd *cmd)
{
int res = SCST_EXEC_COMPLETED;
int length, resp_len = 0;
uint8_t *address;
uint8_t buf[16];
TRACE_ENTRY();
length = scst_get_buf_full_sense(cmd, &address);
TRACE_DBG("length %d", length);
if (unlikely(length <= 0))
goto out_compl;
memset(buf, 0, sizeof(buf));
buf[0] = 0xD8; /* ATS, ATSS, CTSS, LURS */
buf[1] = 0;
if ((cmd->cdb[2] & 0x80) == 0)
resp_len = 4;
else {
buf[3] = 0x0C;
#if 1
buf[4] = 1; /* TMFTMOV */
buf[6] = 0x80; /* ATTS */
put_unaligned_be32(300, &buf[8]); /* long timeout - 30 sec. */
put_unaligned_be32(150, &buf[12]); /* short timeout - 15 sec. */
#endif
resp_len = 16;
}
if (length > resp_len)
length = resp_len;
memcpy(address, buf, length);
scst_put_buf_full(cmd, address);
if (length < cmd->resp_data_len)
scst_set_resp_data_len(cmd, length);
out_compl:
cmd->completed = 1;
/* Report the result */
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME);
TRACE_EXIT_RES(res);
return res;
}
static int scst_maintenance_in(struct scst_cmd *cmd)
{
int res;
TRACE_ENTRY();
switch (cmd->cdb[1] & 0x1f) {
case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS:
res = scst_report_supported_tm_fns(cmd);
break;
default:
res = SCST_EXEC_NOT_COMPLETED;
break;
}
TRACE_EXIT_RES(res);
return res;
}
static int scst_reserve_local(struct scst_cmd *cmd)
{
int res = SCST_EXEC_NOT_COMPLETED;
@@ -2777,6 +2871,7 @@ static scst_local_exec_fn scst_local_fns[256] = {
[PERSISTENT_RESERVE_OUT] = scst_persistent_reserve_out_local,
[REPORT_LUNS] = scst_report_luns_local,
[REQUEST_SENSE] = scst_request_sense_local,
[MAINTENANCE_IN] = scst_maintenance_in,
};
static int scst_do_local_exec(struct scst_cmd *cmd)
@@ -5397,10 +5492,18 @@ static int scst_clear_task_set(struct scst_mgmt_cmd *mcmd)
* >0, if it should be requeued, <0 otherwise */
static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
{
int res = 0, rc;
int res = 0, rc, t;
TRACE_ENTRY();
t = mcmd->sess->acg->acg_black_hole_type;
if (unlikely((t == SCST_ACG_BLACK_HOLE_ALL) ||
(t == SCST_ACG_BLACK_HOLE_DATA_MCMD))) {
TRACE_MGMT_DBG("Dropping mcmd %p (fn %d, initiator %s)", mcmd,
mcmd->fn, mcmd->sess->initiator_name);
mcmd->mcmd_dropped = 1;
}
switch (mcmd->fn) {
case SCST_ABORT_TASK:
{
-8
View File
@@ -1657,11 +1657,6 @@ static int scst_local_driver_remove(struct device *dev)
TRACE_ENTRY();
sess = to_scst_lcl_sess(dev);
if (!sess) {
PRINT_ERROR("%s", "Unable to locate sess info");
return -ENODEV;
}
scsi_remove_host(sess->shost);
scsi_host_put(sess->shost);
@@ -1726,8 +1721,6 @@ static void scst_local_release_adapter(struct device *dev)
TRACE_ENTRY();
sess = to_scst_lcl_sess(dev);
if (sess == NULL)
goto out;
/*
* At this point the SCSI device is almost gone because the SCSI
@@ -1760,7 +1753,6 @@ static void scst_local_release_adapter(struct device *dev)
scst_unregister_session(sess->scst_sess, false, scst_local_free_sess);
out:
TRACE_EXIT();
return;
}
+6 -1
View File
@@ -40,6 +40,8 @@ INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra
set_var = $(shell { if [ -e "$(1)" ]; then grep -v '^$(2)=' "$(1)"; fi; echo "$(2)=$(3)"; } >/tmp/$(1)-$$$$.tmp && mv /tmp/$(1)-$$$$.tmp $(1))
SRC_FILES=$(wildcard */*.[ch])
# The file Modules.symvers has been renamed in the 2.6.18 kernel to
# Module.symvers. Find out which name to use by looking in $(KDIR).
MODULE_SYMVERS:=$(shell if [ -e $(KDIR)/Module.symvers ]; then \
@@ -113,7 +115,7 @@ src/Module.symvers src/Modules.symvers: $(SCST_SYMVERS_DIR)/$(MODULE_SYMVERS)
"installed."; \
false; \
else \
echo " Building against non-OFED InfiniBand kernel headers."; \
echo " Building against in-tree InfiniBand kernel headers."; \
cp $< $@; \
fi; \
fi
@@ -141,4 +143,7 @@ extraclean: clean
release-archive:
../scripts/generate-release-archive srpt "$$(sed -n 's/^#define[[:blank:]]DRV_VERSION[[:blank:]]*\"\([^\"]*\)\".*/\1/p' src/ib_srpt.c)"
kerneldoc.html: $(SRC_FILES)
$(KDIR)/scripts/kernel-doc -html $(SRC_FILES) >$@
.PHONY: all install clean extraclean 2debug 2release 2perf
+1 -1
View File
@@ -411,7 +411,7 @@ Q: Loading the kernel module ib_srpt triggers a kernel panic with a call trace
[<ffffffff81002e3b>] system_call_fastpath+0x16/0x1b
A: This means that you are using a system on which OFED has been installed but
that ib_srpt has been compiled against the non-OFED kernel headers instead
that ib_srpt has been compiled against the in-tree kernel headers instead
of the OFED kernel headers. You can fix this by rebuilding ib_srpt against
the OFED kernel headers. The ib_srpt makefile should detect the OFED kernel
headers automatically - at least if ib_srpt is built after OFED has been
+45
View File
@@ -0,0 +1,45 @@
ib_srpt and session management
==============================
The following actions related to SRP sessions can all occur concurrently:
* IB communication manager (CM) invokes srpt_cm_handler().
* HCA driver invokes the queue pair (QP) completion handler srpt_completion().
* HCA driver invokes the QP async event handler srpt_qp_event().
* HCA transfers data between initiator and target via RDMA.
* srpt_compl_thread() polls the QP.
* SCST core invokes one of the callback functions defined in srpt_template().
The actions that occur over the lifetime of a session are as follows:
- A REQ message is received from the initiator.
- srpt_cm_req_recv() is invoked and allocates a queue pair and creates a
completion thread.
- If the connection request is not accepted, a REJ message is sent and
srpt_close_ch() is invoked. The srpt_close_ch() call causes the completion
thread to stop and the allocated resources to be freed asynchronously.
- If the connection request is accepted a REP message is sent to the initiator.
- Once an RTU message is received from the initiator, srpt_cm_rtu_recv() is
invoked. That function changes the queue pair state into RTS, the channel
state into CH_LIVE and wakes up the completion thread.
- RDMA communication starts and continues until either a DREQ message is
received or sent. The function ib_send_cm_dreq() can get invoked
either because a target port is disabled or from inside the
srpt_close_session() function.
- After a DREQ has been sent either a DREP will be received
(srpt_cm_drep_recv()) or the TimeWait state will be reached and will be left
(srpt_cm_timewait_exit()).
- srpt_cm_dre[pq]_recv() and srpt_cm_timewait_exit() all invoke
srpt_close_ch().
- srpt_close_ch() changes the channel state into CH_DISCONNECTING, the
queue pair state into IB_QPS_ERR and queues a zero-length write.
- Upon receipt of the zero-length write completion the channel state is
changed into CH_DISCONNECTED. This is the last work completion so once the
channel state has reached CH_DISCONNECTED it is guaranteed that the queue
pair completion handler won't be invoked again and also that the completion
handler won't call wake_up_process(ch->thread) anymore.
- That channel state change causes the polling loop in the completion thread
to stop and also triggers a call of scst_unregister_session().
- Once scst_unregister_session() has finished srpt_unreg_sess() is invoked.
- srpt_unreg_sess() destroys the CM ID and decrements the channel refcount.
- Once the channel refcount drops to zero srpt_free_ch() is invoked which
frees the queue pair and other IB resources.
+337 -354
View File
File diff suppressed because it is too large Load Diff
+41 -19
View File
@@ -56,6 +56,7 @@
*/
#define SRP_SERVICE_NAME_PREFIX "SRP.T10:"
struct srpt_nexus;
struct srpt_tgt;
enum {
@@ -132,6 +133,16 @@ enum {
RDMA_COMPL_TIMEOUT_S = 80,
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0) && \
!(defined(CONFIG_SUSE_KERNEL) && \
LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 76)) && \
!(defined(RHEL_MAJOR) && \
(RHEL_MAJOR -0 > 6 || \
RHEL_MAJOR -0 == 6 && RHEL_MINOR -0 >= 5))
/* See also patch "IB/core: Add GID change event" (commit 761d90ed4). */
enum { IB_EVENT_GID_CHANGE = 18 };
#endif
enum srpt_opcode {
SRPT_RECV,
SRPT_SEND,
@@ -139,6 +150,7 @@ enum srpt_opcode {
SRPT_RDMA_ABORT,
SRPT_RDMA_READ_LAST,
SRPT_RDMA_WRITE_LAST,
SRPT_RDMA_ZEROLENGTH_WRITE,
};
static inline u64 encode_wr_id(enum srpt_opcode opcode, u32 idx)
@@ -240,7 +252,7 @@ struct srpt_tsk_mgmt {
* @req_lim_delta: Value of the req_lim_delta value field in the latest
* SRP response sent.
* @tsk_mgmt: SRPT task management function context information.
* @rdma_ius_buf: DMA mapping context information.
* @rdma_ius_buf: Inline rdma_ius buffer for small requests.
*/
struct srpt_send_ioctx {
struct srpt_ioctx ioctx;
@@ -274,19 +286,20 @@ struct srpt_send_ioctx {
* @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_DRAINING: QP is in ERR state.
* @CH_DISCONNECTED: Last WQE has been received.
*/
enum rdma_ch_state {
CH_CONNECTING,
CH_LIVE,
CH_DISCONNECTING,
CH_DRAINING,
CH_DISCONNECTED,
};
/**
* struct srpt_rdma_ch - RDMA channel.
* @thread: Kernel thread that processes the IB queues associated with
* the channel.
* @nexus: I_T nexus this channel is associated with.
* @cm_id: IB CM ID associated with the channel.
* @qp: IB queue pair used for communicating over this channel.
* @cq: IB completion queue for this channel.
@@ -298,8 +311,6 @@ enum rdma_ch_state {
* @sport: pointer to the information of the HCA port used by this
* channel.
* @srpt_tgt: Target port used by this channel.
* @i_port_id: 128-bit initiator port identifier copied from SRP_LOGIN_REQ.
* @t_port_id: 128-bit target port identifier copied from SRP_LOGIN_REQ.
* @max_ti_iu_len: maximum target-to-initiator information unit length.
* @req_lim: request limit: maximum number of requests that may be sent
* by the initiator without having received a response.
@@ -311,9 +322,8 @@ enum rdma_ch_state {
* @ioctx_ring: Send I/O context ring.
* @wc: Work completion array.
* @state: channel state. See also enum rdma_ch_state.
* @dreq_received: Whether an IB CM DREQ event has been received.
* @last_wqe_received: Whether the Last WQE QP event has been received.
* @list: node for insertion in the srpt_device.rch_list list.
* @processing_wait_list: Whether or not cmd_wait_list is being processed.
* @list: Entry in srpt_nexus.ch_list;
* @cmd_wait_list: list of SCST commands that arrived before the RTU event. This
* list contains struct srpt_ioctx elements and is protected
* against concurrent modification by the cm_id spinlock.
@@ -323,6 +333,7 @@ enum rdma_ch_state {
*/
struct srpt_rdma_ch {
struct task_struct *thread;
struct srpt_nexus *nexus;
struct ib_cm_id *cm_id;
struct ib_qp *qp;
struct ib_cq *cq;
@@ -330,11 +341,9 @@ struct srpt_rdma_ch {
int rq_size;
int max_sge;
int max_rsp_size;
int sq_wr_avail;
atomic_t sq_wr_avail;
struct srpt_port *sport;
struct srpt_tgt *srpt_tgt;
u8 i_port_id[16];
u8 t_port_id[16];
int max_ti_iu_len;
int req_lim;
int req_lim_delta;
@@ -346,25 +355,38 @@ struct srpt_rdma_ch {
struct list_head list;
struct list_head cmd_wait_list;
uint16_t pkey_index;
bool dreq_received;
bool last_wqe_received;
bool processing_wait_list;
struct scst_session *scst_sess;
u8 sess_name[40];
};
/**
* struct srpt_nexus - I_T nexus
* @entry: srpt_tgt.nexus_list list node.
* @ch_list: struct srpt_rdma_ch list. Protected by srpt_tgt.spinlock
* @i_port_id: 128-bit initiator port identifier copied from SRP_LOGIN_REQ.
* @t_port_id: 128-bit target port identifier copied from SRP_LOGIN_REQ.
*/
struct srpt_nexus {
struct list_head entry;
struct list_head ch_list;
u8 i_port_id[16];
u8 t_port_id[16];
};
/**
* struct srpt_tgt
* @ch_releaseQ: Enables waiting for removal from rch_list.
* @spinlock: Protects rch_list.
* @rch_list: Per-device channel list -- see also srpt_rdma_ch.list.
* @scst_tgt: SCST target information associated with this HCA.
* @enabled: Whether or not this SCST target is enabled.
* @ch_releaseQ: Enables waiting for removal from nexus_list.
* @spinlock: Protects nexus_list.
* @nexus_list: Per-device I_T nexus list.
* @scst_tgt: SCST target information associated with this HCA.
* @enabled: Whether or not this SCST target is enabled.
*/
struct srpt_tgt {
wait_queue_head_t ch_releaseQ;
spinlock_t spinlock;
struct list_head rch_list;
struct list_head nexus_list;
struct scst_tgt *scst_tgt;
bool enabled;
};
+1 -1
View File
@@ -149,7 +149,7 @@
<h1>Documentation</h1>
<p><a href="scst_pg.html">HTML</a></p>
<p><a href="scst_pg.pdf">PDF</a></p>
<p><a href="Gentoo-HOWTO.pdf">Gentoo HOWTO</a></p>
<p><a href="http://monklinux.blogspot.com/2012/02/scst-configuration-how-to-using-gentoo.html">Gentoo HOWTO</a></p>
<p><a href="iscsi-scst-howto.txt">HOWTO For iSCSI-SCST</a></p>
<p><a href="SCST_Gentoo_HOWTO.txt">Gentoo HOWTO For iSCSI-SCST</a></p>
<p><a href="http://alpinelinux.org/wiki/High_performance_SCST_iSCSI_Target_on_Linux_software_Raid" class="readmore">Alpine Linux HOWTO</a></p>