Merged revisions 5409-5452,5454 via svnmerge from

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

........
  r5409 | bvassche | 2014-04-06 23:13:53 +0300 (Sun, 06 Apr 2014) | 4 lines
  
  scstadmin: Restore LUNs in "scstadmin -list_sessions" output
  
  Signed-off-by: Dave Butler <tears.the@gmail.com>
........
  r5410 | bvassche | 2014-04-06 23:26:08 +0300 (Sun, 06 Apr 2014) | 1 line
  
  scstadmin: List keys alphabetically in the -list_sessions output
........
  r5411 | vlnb | 2014-04-10 02:58:20 +0300 (Thu, 10 Apr 2014) | 10 lines
  
  vdisk_blockio: Specify REQ_SYNC for synchronous I/O requests
  
  Using READ_SYNC instead of READ increases the priority of read requests.
  Using WRITE_SYNC instead of REQ_WRITE increases the priority of write
  requests and avoids that the CFQ scheduler queues such writes waiting
  for further write requests.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5412 | vlnb | 2014-04-10 02:59:02 +0300 (Thu, 10 Apr 2014) | 18 lines
  
  vdisk_blockio: Reenable COMPARE AND WRITE
  
  The COMPARE AND WRITE implementation has been tested as follows against
  an SCST vdisk_blockio device:
  
  lba=7
  bdev=$bdev
  for ((i=0;i<4;i++)); do dd if=/dev/urandom of=b$i bs=8k count=1; done
  for p in "0 1" "1 2" "2 3" "3 0"; do set $p; cat b$1 b$2 >b$1$2; done
  dd if=/dev/urandom of=$bdev
  dd if=b0 of=$bdev seek=$lba
  md5sum $bdev
  for ((i=0;i<10000;i++)); do for f in b01 b12 b23 b30; do sg_compare_and_write -l $lba -i $f -n 16 -x 16384 $bdev; done; done
  md5sum $bdev
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5413 | bvassche | 2014-04-15 09:03:59 +0300 (Tue, 15 Apr 2014) | 1 line
  
  ib_srpt: Fix a sparse warning
........
  r5414 | vlnb | 2014-04-16 00:26:06 +0300 (Wed, 16 Apr 2014) | 5 lines
  
  Fix READ(6)/WRITE(6)
  
  LBA in those commands is 3 bytes long, not 2.
........
  r5415 | vlnb | 2014-04-16 00:30:26 +0300 (Wed, 16 Apr 2014) | 3 lines
  
  Add SYNCHRONIZE_CACHE(16)
........
  r5416 | vlnb | 2014-04-16 01:04:54 +0300 (Wed, 16 Apr 2014) | 6 lines
  
  Make HEAD OF QUEUE requests sync
  
  Since the block layer has no way to specify bio as HQ, there's no
  choice, but to use every measure to approximate it as close as possible.
........
  r5417 | vlnb | 2014-04-16 01:17:34 +0300 (Wed, 16 Apr 2014) | 3 lines
  
  Add NULLIO VERIFY
........
  r5418 | vlnb | 2014-04-16 04:02:50 +0300 (Wed, 16 Apr 2014) | 3 lines
  
  REPORT SUPPORTED OPERATION CODES added
........
  r5419 | vlnb | 2014-04-16 04:05:49 +0300 (Wed, 16 Apr 2014) | 3 lines
  
  Cleanup
........
  r5420 | vlnb | 2014-04-16 05:24:44 +0300 (Wed, 16 Apr 2014) | 3 lines
  
  Follow up for r5418: some cleanups and fixes
........
  r5421 | bvassche | 2014-04-16 09:17:19 +0300 (Wed, 16 Apr 2014) | 6 lines
  
  scst_targ: Fix a checkpatch complaint
  
  Avoid that checkpatch reports the following message:
  
  ERROR: space required before the open parenthesis '('
........
  r5422 | bvassche | 2014-04-16 09:35:19 +0300 (Wed, 16 Apr 2014) | 1 line
  
  scst_vdisk: Build fix for kernels < 2.6.36 (see also r5416)
........
  r5423 | bvassche | 2014-04-16 10:30:34 +0300 (Wed, 16 Apr 2014) | 6 lines
  
  ib_srpt: Disable RDMA access by the initiator
  
  With the SRP protocol all RDMA operations are initiated by the target.
  Since no RDMA operations are initiated by the initiator, do not grant
  the initiator permission to submit RDMA reads or writes to the target.
........
  r5424 | bvassche | 2014-04-16 11:01:58 +0300 (Wed, 16 Apr 2014) | 1 line
  
  ib_srpt: Constify two arguments of srpt_get_nexus()
........
  r5425 | bvassche | 2014-04-16 11:08:50 +0300 (Wed, 16 Apr 2014) | 1 line
  
  ib_srpt: Clean up the code that prints the dgid during login
........
  r5426 | bvassche | 2014-04-16 11:23:11 +0300 (Wed, 16 Apr 2014) | 1 line
  
  ib_srpt: Cache P_Key lookups
........
  r5427 | bvassche | 2014-04-16 12:14:31 +0300 (Wed, 16 Apr 2014) | 1 line
  
  ib_srpt: Remove a superfluous assignment
........
  r5428 | bvassche | 2014-04-16 12:31:56 +0300 (Wed, 16 Apr 2014) | 1 line
  
  scst_vdisk: Avoid that checkpatch complains about unnecessary line continuations
........
  r5429 | bvassche | 2014-04-16 12:35:18 +0300 (Wed, 16 Apr 2014) | 1 line
  
  scst_lib: Avoid that checkpatch complains about unnecessary line continuations
........
  r5430 | bvassche | 2014-04-17 09:09:41 +0300 (Thu, 17 Apr 2014) | 1 line
  
  scst_vdisk: Kernel 2.6.27 build fix
........
  r5431 | bvassche | 2014-04-17 09:12:07 +0300 (Thu, 17 Apr 2014) | 5 lines
  
  scst_vdisk: Fix a kernel 2.6.27 compiler warning
  
  Avoid that the compiler reports that variables 'start_sector' and 'nr_sects'
  are set but not used when building against kernel 2.6.27.
........
  r5432 | vlnb | 2014-04-18 03:32:51 +0300 (Fri, 18 Apr 2014) | 3 lines
  
  Update to kernels 3.14
........
  r5433 | bvassche | 2014-04-18 08:50:04 +0300 (Fri, 18 Apr 2014) | 1 line
  
  nightly build: Add kernel 3.14 build infrastructure
........
  r5434 | bvassche | 2014-04-18 08:54:29 +0300 (Fri, 18 Apr 2014) | 1 line
  
  nightly build: Add kernel version 3.14.1 and update other kernel versions
........
  r5435 | bvassche | 2014-04-18 08:56:35 +0300 (Fri, 18 Apr 2014) | 6 lines
  
  iscsi-scst: Fix a checkpatch warning
  
  Fix the following checkpatch 3.14 warning:
  
  Unnecessary parentheses - maybe == should be = ?
........
  r5436 | bvassche | 2014-04-18 09:03:34 +0300 (Fri, 18 Apr 2014) | 6 lines
  
  scst.h: Fix a checkpatch warning
  
  Fix the following checkpatch 3.14 warning:
  
  Unnecessary space after function pointer name
........
  r5437 | bvassche | 2014-04-18 09:08:07 +0300 (Fri, 18 Apr 2014) | 6 lines
  
  scst: Fix a checkpatch warning
  
  Fix the following checkpatch 3.14 warning:
      
  Unnecessary space after function pointer name
........
  r5438 | bvassche | 2014-04-18 09:13:03 +0300 (Fri, 18 Apr 2014) | 6 lines
  
  scst: Fix a checkpatch 3.14 warning about whitespace
  
  Fix the following checkpatch 3.14 warning:
  
  missing space after return type
........
  r5439 | bvassche | 2014-04-18 14:09:55 +0300 (Fri, 18 Apr 2014) | 1 line
  
  ib_srpt: Update README
........
  r5440 | bvassche | 2014-04-18 15:04:05 +0300 (Fri, 18 Apr 2014) | 2 lines
  
  ib_srpt: Move IB/CM knowledge out of srpt_cm_req_recv()
........
  r5441 | bvassche | 2014-04-18 15:08:00 +0300 (Fri, 18 Apr 2014) | 6 lines
  
  ib_srpt: Remove a superfluous check from the REQ handler
  
  ib_send_cm_rep() checks the connection state before sending a response.
  Hence checking ch->state before calling ib_send_cm_rep() is superfluous,
  so remove that check and also the locking that is no longer needed.
........
  r5442 | bvassche | 2014-04-18 15:09:33 +0300 (Fri, 18 Apr 2014) | 5 lines
  
  ib_srpt: Prepare RDMA/CM support
      
  Move IB/CM members into a new struct. Report channel pointer instead of CM ID
  pointer in diagnostic messages.
........
  r5443 | bvassche | 2014-04-18 15:10:47 +0300 (Fri, 18 Apr 2014) | 5 lines
  
  ib_srpt: Use a mutex instead of a spinlock to protect the channel list
      
  This is allowed because all CM callback functions are invoked from thread
  context.
........
  r5444 | bvassche | 2014-04-18 15:11:18 +0300 (Fri, 18 Apr 2014) | 2 lines
  
  ib_srpt: Move the code for checking the QP timeout
........
  r5445 | bvassche | 2014-04-18 15:22:30 +0300 (Fri, 18 Apr 2014) | 4 lines
  
  ib_srpt: Add RDMA/CM support
  
  Or in other words, add RoCE and iWARP support.
........
  r5446 | bvassche | 2014-04-18 15:38:39 +0300 (Fri, 18 Apr 2014) | 1 line
  
  ib_srpt: Build fix for kernel versions < 3.0
........
  r5447 | bvassche | 2014-04-18 15:44:48 +0300 (Fri, 18 Apr 2014) | 1 line
  
  ib_srpt: RHEL 6.5 build fix
........
  r5448 | bvassche | 2014-04-19 14:48:33 +0300 (Sat, 19 Apr 2014) | 1 line
  
  scst_vdisk, COMPARE AND WRITE: Convert a kernel warning into a SCSI sense code
........
  r5449 | bvassche | 2014-04-19 14:52:34 +0300 (Sat, 19 Apr 2014) | 33 lines
  
  vdisk_blockio: Make COMPARE AND WRITE compatible with the scsi_debug driver
  
  This patch fixes the following kernel oops:
  
  BUG: unable to handle kernel paging request at ffffeae380000690
  Call Trace:
   [<ffffffff812f69f9>] sg_miter_next+0x9/0xd0
   [<ffffffff812f6b60>] sg_copy_buffer+0xa0/0x100
   [<ffffffffa0507fc6>] do_device_access.isra.8+0xa6/0x150 [scsi_debug]
   [<ffffffffa05085f4>] resp_read+0xe4/0x240 [scsi_debug]
   [<ffffffffa050b285>] scsi_debug_queuecommand_lck+0x11e5/0x2060 [scsi_debug]
   [<ffffffffa050c130>] scsi_debug_queuecommand+0x30/0x48 [scsi_debug]
   [<ffffffff813fe23f>] scsi_dispatch_cmd+0xaf/0x260
   [<ffffffff814068ed>] scsi_request_fn+0x32d/0x540
   [<ffffffff812bda2a>] __blk_run_queue+0x2a/0x40
   [<ffffffff812c25a4>] blk_queue_bio+0x274/0x350
   [<ffffffff812bd878>] generic_make_request+0xa8/0xf0
   [<ffffffff812bd92c>] submit_bio+0x6c/0x140
   [<ffffffffa06247f6>] blockio_rw_sync.isra.29+0x106/0x170 [scst_vdisk]
   [<ffffffffa0629bf9>] vdisk_exec_caw+0xd9/0x3c0 [scst_vdisk]
   [<ffffffffa061ff5e>] vdev_do_job+0x9e/0x320 [scst_vdisk]
   [<ffffffffa0622c47>] non_fileio_exec+0x57/0xd0 [scst_vdisk]
   [<ffffffffa054cde2>] scst_do_real_exec+0x92/0x3b0 [scst]
   [<ffffffffa05502d2>] scst_exec_check_blocking+0xe2/0x300 [scst]
   [<ffffffffa055066b>] scst_exec_check_sn+0x17b/0x2d0 [scst]
   [<ffffffffa0553231>] scst_process_active_cmd+0x431/0x770 [scst]
   [<ffffffffa0554a0a>] scst_do_job_active+0xea/0x180 [scst]
   [<ffffffffa0554bc6>] scst_cmd_thread+0x126/0x290 [scst]
   [<ffffffff81075241>] kthread+0xc1/0xe0
   [<ffffffff81598ccc>] ret_from_fork+0x7c/0xb0
  
  Reported-by: Sebastian Herbszt <herbszt@gmx.de>
........
  r5450 | bvassche | 2014-04-20 09:24:23 +0300 (Sun, 20 Apr 2014) | 1 line
  
  iscsi-scst/kernel/patches/put_page_callback-3.2.57.patch: Add
........
  r5451 | bvassche | 2014-04-22 09:56:37 +0300 (Tue, 22 Apr 2014) | 1 line
  
  scst: Revert r5438, a whitespace-only change
........
  r5452 | bvassche | 2014-04-22 10:05:21 +0300 (Tue, 22 Apr 2014) | 1 line
  
  scripts/run-regression-tests: Suppress the checkpatch warning "missing space after return type"
........
  r5454 | bvassche | 2014-04-22 10:32:44 +0300 (Tue, 22 Apr 2014) | 1 line
  
  scst/README: Update the section about Linux initiator ALUA support
........


git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/iser@5455 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Yan Burman
2014-04-22 07:50:34 +00:00
parent 67e83b5458
commit de6aa12e9c
28 changed files with 2733 additions and 376 deletions
+1 -1
View File
@@ -475,7 +475,7 @@ void __iscsi_write_space_ready(struct iscsi_conn *conn)
spin_lock_bh(&p->wr_lock);
conn->wr_space_ready = 1;
if ((conn->wr_state == ISCSI_CONN_WR_STATE_SPACE_WAIT)) {
if (conn->wr_state == ISCSI_CONN_WR_STATE_SPACE_WAIT) {
TRACE_DBG("wr space ready (conn %p)", conn);
list_add_tail(&conn->wr_list_entry, &p->wr_list);
conn->wr_state = ISCSI_CONN_WR_STATE_IN_LIST;
@@ -0,0 +1,364 @@
=== modified file 'drivers/block/drbd/drbd_receiver.c'
--- old/drivers/block/drbd/drbd_receiver.c 2014-04-17 22:02:06 +0000
+++ new/drivers/block/drbd/drbd_receiver.c 2014-04-17 22:48:38 +0000
@@ -130,7 +130,7 @@ static int page_chain_free(struct page *
struct page *tmp;
int i = 0;
page_chain_for_each_safe(page, tmp) {
- put_page(page);
+ net_put_page(page);
++i;
}
return i;
=== modified file 'include/linux/mm_types.h'
--- old/include/linux/mm_types.h 2014-04-17 22:02:06 +0000
+++ new/include/linux/mm_types.h 2014-04-17 22:48:38 +0000
@@ -195,6 +195,17 @@ struct page {
#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
int _last_cpupid;
#endif
+
+#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
+ /*
+ * Used to implement support for notification on zero-copy TCP transfer
+ * completion. It might look as not good to have this field here and
+ * it's better to have it in struct sk_buff, but it would make the code
+ * much more complicated and fragile, since all skb then would have to
+ * contain only pages with the same value in this field.
+ */
+ void *net_priv;
+#endif
}
/*
* The struct page can be forced to be double word aligned so that atomic ops
=== modified file 'include/linux/net.h'
--- old/include/linux/net.h 2014-04-17 22:02:06 +0000
+++ new/include/linux/net.h 2014-04-17 22:48:38 +0000
@@ -19,6 +19,7 @@
#define _LINUX_NET_H
#include <linux/stringify.h>
+#include <linux/mm.h>
#include <linux/random.h>
#include <linux/wait.h>
#include <linux/fcntl.h> /* For O_CLOEXEC and O_NONBLOCK */
@@ -292,6 +293,45 @@ int kernel_sendpage(struct socket *sock,
int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how);
+#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
+/* Support for notification on zero-copy TCP transfer completion */
+typedef void (*net_get_page_callback_t)(struct page *page);
+typedef void (*net_put_page_callback_t)(struct page *page);
+
+extern net_get_page_callback_t net_get_page_callback;
+extern net_put_page_callback_t net_put_page_callback;
+
+extern int net_set_get_put_page_callbacks(
+ net_get_page_callback_t get_callback,
+ net_put_page_callback_t put_callback);
+
+/*
+ * See comment for net_set_get_put_page_callbacks() why those functions
+ * don't need any protection.
+ */
+static inline void net_get_page(struct page *page)
+{
+ if (page->net_priv != 0)
+ net_get_page_callback(page);
+ get_page(page);
+}
+static inline void net_put_page(struct page *page)
+{
+ if (page->net_priv != 0)
+ net_put_page_callback(page);
+ put_page(page);
+}
+#else
+static inline void net_get_page(struct page *page)
+{
+ get_page(page);
+}
+static inline void net_put_page(struct page *page)
+{
+ put_page(page);
+}
+#endif /* CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION */
+
#define MODULE_ALIAS_NETPROTO(proto) \
MODULE_ALIAS("net-pf-" __stringify(proto))
=== modified file 'include/linux/skbuff.h'
--- old/include/linux/skbuff.h 2014-04-17 22:02:06 +0000
+++ new/include/linux/skbuff.h 2014-04-17 22:48:38 +0000
@@ -2056,7 +2056,7 @@ static inline struct page *skb_frag_page
*/
static inline void __skb_frag_ref(skb_frag_t *frag)
{
- get_page(skb_frag_page(frag));
+ net_get_page(skb_frag_page(frag));
}
/**
@@ -2079,7 +2079,7 @@ static inline void skb_frag_ref(struct s
*/
static inline void __skb_frag_unref(skb_frag_t *frag)
{
- put_page(skb_frag_page(frag));
+ net_put_page(skb_frag_page(frag));
}
/**
=== modified file 'net/Kconfig'
--- old/net/Kconfig 2014-04-17 22:02:06 +0000
+++ new/net/Kconfig 2014-04-17 22:48:38 +0000
@@ -75,6 +75,18 @@ config INET
Short answer: say Y.
+config TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
+ bool "TCP/IP zero-copy transfer completion notification"
+ depends on INET
+ default SCST_ISCSI
+ ---help---
+ Adds support for sending a notification upon completion of a
+ zero-copy TCP/IP transfer. This can speed up certain TCP/IP
+ software. Currently this is only used by the iSCSI target driver
+ iSCSI-SCST.
+
+ If unsure, say N.
+
if INET
source "net/ipv4/Kconfig"
source "net/ipv6/Kconfig"
=== modified file 'net/ceph/pagevec.c'
--- old/net/ceph/pagevec.c 2014-04-17 22:02:06 +0000
+++ new/net/ceph/pagevec.c 2014-04-17 22:48:38 +0000
@@ -51,7 +51,7 @@ void ceph_put_page_vector(struct page **
for (i = 0; i < num_pages; i++) {
if (dirty)
set_page_dirty_lock(pages[i]);
- put_page(pages[i]);
+ net_put_page(pages[i]);
}
kfree(pages);
}
=== modified file 'net/core/skbuff.c'
--- old/net/core/skbuff.c 2014-04-17 22:02:06 +0000
+++ new/net/core/skbuff.c 2014-04-17 22:48:38 +0000
@@ -425,7 +425,7 @@ struct sk_buff *__netdev_alloc_skb(struc
if (likely(data)) {
skb = build_skb(data, fragsz);
if (unlikely(!skb))
- put_page(virt_to_head_page(data));
+ net_put_page(virt_to_head_page(data));
}
} else {
skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask,
@@ -483,7 +483,7 @@ static void skb_clone_fraglist(struct sk
static void skb_free_head(struct sk_buff *skb)
{
if (skb->head_frag)
- put_page(virt_to_head_page(skb->head));
+ net_put_page(virt_to_head_page(skb->head));
else
kfree(skb->head);
}
@@ -804,7 +804,7 @@ int skb_copy_ubufs(struct sk_buff *skb,
if (!page) {
while (head) {
struct page *next = (struct page *)page_private(head);
- put_page(head);
+ net_put_page(head);
head = next;
}
return -ENOMEM;
@@ -1647,7 +1647,7 @@ EXPORT_SYMBOL(skb_copy_bits);
*/
static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i)
{
- put_page(spd->pages[i]);
+ net_put_page(spd->pages[i]);
}
static struct page *linear_to_page(struct page *page, unsigned int *len,
@@ -1700,7 +1700,7 @@ static bool spd_fill_page(struct splice_
spd->partial[spd->nr_pages - 1].len += *len;
return false;
}
- get_page(page);
+ net_get_page(page);
spd->pages[spd->nr_pages] = page;
spd->partial[spd->nr_pages].len = *len;
spd->partial[spd->nr_pages].offset = offset;
@@ -2159,7 +2159,7 @@ skb_zerocopy(struct sk_buff *to, struct
page = virt_to_head_page(from->head);
offset = from->data - (unsigned char *)page_address(page);
__skb_fill_page_desc(to, 0, page, offset, plen);
- get_page(page);
+ net_get_page(page);
j = 1;
len -= plen;
}
@@ -2813,7 +2813,7 @@ int skb_append_datato_frags(struct sock
copy);
frg_cnt++;
pfrag->offset += copy;
- get_page(pfrag->page);
+ net_get_page(pfrag->page);
skb->truesize += copy;
atomic_add(copy, &sk->sk_wmem_alloc);
=== modified file 'net/core/sock.c'
--- old/net/core/sock.c 2014-04-17 22:02:06 +0000
+++ new/net/core/sock.c 2014-04-17 22:48:38 +0000
@@ -1839,7 +1839,7 @@ bool skb_page_frag_refill(unsigned int s
}
if (pfrag->offset + sz <= pfrag->size)
return true;
- put_page(pfrag->page);
+ net_put_page(pfrag->page);
}
order = SKB_FRAG_PAGE_ORDER;
@@ -2602,7 +2602,7 @@ void sk_common_release(struct sock *sk)
sk_refcnt_debug_release(sk);
if (sk->sk_frag.page) {
- put_page(sk->sk_frag.page);
+ net_put_page(sk->sk_frag.page);
sk->sk_frag.page = NULL;
}
=== modified file 'net/ipv4/Makefile'
--- old/net/ipv4/Makefile 2014-04-17 22:02:06 +0000
+++ new/net/ipv4/Makefile 2014-04-17 22:48:38 +0000
@@ -53,6 +53,7 @@ obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.
obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o
obj-$(CONFIG_MEMCG_KMEM) += tcp_memcontrol.o
obj-$(CONFIG_NETLABEL) += cipso_ipv4.o
+obj-$(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) += tcp_zero_copy.o
obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
xfrm4_output.o
=== modified file 'net/ipv4/ip_output.c'
--- old/net/ipv4/ip_output.c 2014-04-17 22:02:06 +0000
+++ new/net/ipv4/ip_output.c 2014-04-17 22:48:38 +0000
@@ -1004,7 +1004,7 @@ alloc_new_skb:
__skb_fill_page_desc(skb, i, pfrag->page,
pfrag->offset, 0);
skb_shinfo(skb)->nr_frags = ++i;
- get_page(pfrag->page);
+ net_get_page(pfrag->page);
}
copy = min_t(int, copy, pfrag->size - pfrag->offset);
if (getfrag(from,
@@ -1230,7 +1230,7 @@ ssize_t ip_append_page(struct sock *sk,
if (skb_can_coalesce(skb, i, page, offset)) {
skb_frag_size_add(&skb_shinfo(skb)->frags[i-1], len);
} else if (i < MAX_SKB_FRAGS) {
- get_page(page);
+ net_get_page(page);
skb_fill_page_desc(skb, i, page, offset, len);
} else {
err = -EMSGSIZE;
=== modified file 'net/ipv4/tcp.c'
--- old/net/ipv4/tcp.c 2014-04-17 22:02:06 +0000
+++ new/net/ipv4/tcp.c 2014-04-17 22:48:38 +0000
@@ -939,7 +939,7 @@ new_segment:
if (can_coalesce) {
skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
} else {
- get_page(page);
+ net_get_page(page);
skb_fill_page_desc(skb, i, page, offset, copy);
}
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
@@ -1238,7 +1238,7 @@ new_segment:
} else {
skb_fill_page_desc(skb, i, pfrag->page,
pfrag->offset, copy);
- get_page(pfrag->page);
+ net_get_page(pfrag->page);
}
pfrag->offset += copy;
}
=== added file 'net/ipv4/tcp_zero_copy.c'
--- old/net/ipv4/tcp_zero_copy.c 1970-01-01 00:00:00 +0000
+++ new/net/ipv4/tcp_zero_copy.c 2014-04-17 22:48:38 +0000
@@ -0,0 +1,50 @@
+/*
+ * Support routines for TCP zero copy transmit
+ *
+ * Created by Vladislav Bolkhovitin
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/export.h>
+#include <linux/skbuff.h>
+
+net_get_page_callback_t net_get_page_callback __read_mostly;
+EXPORT_SYMBOL_GPL(net_get_page_callback);
+
+net_put_page_callback_t net_put_page_callback __read_mostly;
+EXPORT_SYMBOL_GPL(net_put_page_callback);
+
+/*
+ * Caller of this function must ensure that at the moment when it's called
+ * there are no pages in the system with net_priv field set to non-zero
+ * value. Hence, this function, as well as net_get_page() and net_put_page(),
+ * don't need any protection.
+ */
+int net_set_get_put_page_callbacks(
+ net_get_page_callback_t get_callback,
+ net_put_page_callback_t put_callback)
+{
+ int res = 0;
+
+ if ((net_get_page_callback != NULL) && (get_callback != NULL) &&
+ (net_get_page_callback != get_callback)) {
+ res = -EBUSY;
+ goto out;
+ }
+
+ if ((net_put_page_callback != NULL) && (put_callback != NULL) &&
+ (net_put_page_callback != put_callback)) {
+ res = -EBUSY;
+ goto out;
+ }
+
+ net_get_page_callback = get_callback;
+ net_put_page_callback = put_callback;
+
+out:
+ return res;
+}
+EXPORT_SYMBOL_GPL(net_set_get_put_page_callbacks);
=== modified file 'net/ipv6/ip6_output.c'
--- old/net/ipv6/ip6_output.c 2014-04-17 22:02:06 +0000
+++ new/net/ipv6/ip6_output.c 2014-04-17 22:48:38 +0000
@@ -1455,7 +1455,7 @@ alloc_new_skb:
__skb_fill_page_desc(skb, i, pfrag->page,
pfrag->offset, 0);
skb_shinfo(skb)->nr_frags = ++i;
- get_page(pfrag->page);
+ net_get_page(pfrag->page);
}
copy = min_t(int, copy, pfrag->size - pfrag->offset);
if (getfrag(from,
@@ -0,0 +1,287 @@
=== modified file 'include/linux/mm_types.h'
--- old/include/linux/mm_types.h 2012-01-10 22:58:17 +0000
+++ new/include/linux/mm_types.h 2012-01-10 23:02:48 +0000
@@ -149,6 +149,17 @@ struct page {
*/
void *shadow;
#endif
+
+#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
+ /*
+ * Used to implement support for notification on zero-copy TCP transfer
+ * completion. It might look as not good to have this field here and
+ * it's better to have it in struct sk_buff, but it would make the code
+ * much more complicated and fragile, since all skb then would have to
+ * contain only pages with the same value in this field.
+ */
+ void *net_priv;
+#endif
}
/*
* If another subsystem starts using the double word pairing for atomic
=== modified file 'include/linux/net.h'
--- old/include/linux/net.h 2012-01-10 22:58:17 +0000
+++ new/include/linux/net.h 2012-01-10 23:02:48 +0000
@@ -61,6 +61,7 @@ typedef enum {
#include <linux/fcntl.h> /* For O_CLOEXEC and O_NONBLOCK */
#include <linux/kmemcheck.h>
#include <linux/rcupdate.h>
+#include <linux/mm.h>
struct poll_table_struct;
struct pipe_inode_info;
@@ -289,5 +290,44 @@ extern int kernel_sock_shutdown(struct s
MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto) \
"-type-" __stringify(type))
+#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION)
+/* Support for notification on zero-copy TCP transfer completion */
+typedef void (*net_get_page_callback_t)(struct page *page);
+typedef void (*net_put_page_callback_t)(struct page *page);
+
+extern net_get_page_callback_t net_get_page_callback;
+extern net_put_page_callback_t net_put_page_callback;
+
+extern int net_set_get_put_page_callbacks(
+ net_get_page_callback_t get_callback,
+ net_put_page_callback_t put_callback);
+
+/*
+ * See comment for net_set_get_put_page_callbacks() why those functions
+ * don't need any protection.
+ */
+static inline void net_get_page(struct page *page)
+{
+ if (page->net_priv != 0)
+ net_get_page_callback(page);
+ get_page(page);
+}
+static inline void net_put_page(struct page *page)
+{
+ if (page->net_priv != 0)
+ net_put_page_callback(page);
+ put_page(page);
+}
+#else
+static inline void net_get_page(struct page *page)
+{
+ get_page(page);
+}
+static inline void net_put_page(struct page *page)
+{
+ put_page(page);
+}
+#endif /* CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION */
+
#endif /* __KERNEL__ */
#endif /* _LINUX_NET_H */
=== modified file 'include/linux/skbuff.h'
--- old/include/linux/skbuff.h 2012-01-10 22:58:17 +0000
+++ new/include/linux/skbuff.h 2012-01-10 23:15:31 +0000
@@ -1712,7 +1712,7 @@ static inline struct page *skb_frag_page
*/
static inline void __skb_frag_ref(skb_frag_t *frag)
{
- get_page(skb_frag_page(frag));
+ net_get_page(skb_frag_page(frag));
}
/**
@@ -1735,7 +1735,7 @@ static inline void skb_frag_ref(struct s
*/
static inline void __skb_frag_unref(skb_frag_t *frag)
{
- put_page(skb_frag_page(frag));
+ net_put_page(skb_frag_page(frag));
}
/**
=== modified file 'net/Kconfig'
--- old/net/Kconfig 2012-01-10 22:58:17 +0000
+++ new/net/Kconfig 2012-01-10 23:02:48 +0000
@@ -72,6 +72,18 @@ config INET
Short answer: say Y.
+config TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION
+ bool "TCP/IP zero-copy transfer completion notification"
+ depends on INET
+ default SCST_ISCSI
+ ---help---
+ Adds support for sending a notification upon completion of a
+ zero-copy TCP/IP transfer. This can speed up certain TCP/IP
+ software. Currently this is only used by the iSCSI target driver
+ iSCSI-SCST.
+
+ If unsure, say N.
+
if INET
source "net/ipv4/Kconfig"
source "net/ipv6/Kconfig"
=== modified file 'net/core/skbuff.c'
--- old/net/core/skbuff.c 2012-01-10 22:58:17 +0000
+++ new/net/core/skbuff.c 2012-01-10 23:02:48 +0000
@@ -654,7 +654,7 @@ int skb_copy_ubufs(struct sk_buff *skb,
if (!page) {
while (head) {
struct page *next = (struct page *)head->private;
- put_page(head);
+ net_put_page(head);
head = next;
}
return -ENOMEM;
@@ -1493,7 +1493,7 @@ EXPORT_SYMBOL(skb_copy_bits);
*/
static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i)
{
- put_page(spd->pages[i]);
+ net_put_page(spd->pages[i]);
}
static inline struct page *linear_to_page(struct page *page, unsigned int *len,
@@ -1517,7 +1517,7 @@ new_page:
off = sk->sk_sndmsg_off;
mlen = PAGE_SIZE - off;
if (mlen < 64 && mlen < *len) {
- put_page(p);
+ net_put_page(p);
goto new_page;
}
@@ -1527,7 +1527,7 @@ new_page:
memcpy(page_address(p) + off, page_address(page) + *offset, *len);
sk->sk_sndmsg_off += *len;
*offset = off;
- get_page(p);
+ net_get_page(p);
return p;
}
@@ -1549,7 +1549,7 @@ static inline int spd_fill_page(struct s
if (!page)
return 1;
} else
- get_page(page);
+ net_get_page(page);
spd->pages[spd->nr_pages] = page;
spd->partial[spd->nr_pages].len = *len;
=== modified file 'net/ipv4/Makefile'
--- old/net/ipv4/Makefile 2012-01-10 22:58:17 +0000
+++ new/net/ipv4/Makefile 2012-01-10 23:02:48 +0000
@@ -48,6 +48,7 @@ obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o
obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o
obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o
obj-$(CONFIG_NETLABEL) += cipso_ipv4.o
+obj-$(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) += tcp_zero_copy.o
obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
xfrm4_output.o
=== modified file 'net/ipv4/ip_output.c'
--- old/net/ipv4/ip_output.c 2012-01-10 22:58:17 +0000
+++ new/net/ipv4/ip_output.c 2012-01-10 23:02:48 +0000
@@ -1232,7 +1232,7 @@ ssize_t ip_append_page(struct sock *sk,
if (skb_can_coalesce(skb, i, page, offset)) {
skb_frag_size_add(&skb_shinfo(skb)->frags[i-1], len);
} else if (i < MAX_SKB_FRAGS) {
- get_page(page);
+ net_get_page(page);
skb_fill_page_desc(skb, i, page, offset, len);
} else {
err = -EMSGSIZE;
=== modified file 'net/ipv4/tcp.c'
--- old/net/ipv4/tcp.c 2012-01-10 22:58:17 +0000
+++ new/net/ipv4/tcp.c 2012-01-10 23:02:48 +0000
@@ -815,7 +815,7 @@ new_segment:
if (can_coalesce) {
skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy);
} else {
- get_page(page);
+ net_get_page(page);
skb_fill_page_desc(skb, i, page, offset, copy);
}
@@ -1022,7 +1022,7 @@ new_segment:
goto new_segment;
} else if (page) {
if (off == PAGE_SIZE) {
- put_page(page);
+ net_put_page(page);
TCP_PAGE(sk) = page = NULL;
off = 0;
}
@@ -1062,9 +1062,9 @@ new_segment:
} else {
skb_fill_page_desc(skb, i, page, off, copy);
if (TCP_PAGE(sk)) {
- get_page(page);
+ net_get_page(page);
} else if (off + copy < PAGE_SIZE) {
- get_page(page);
+ net_get_page(page);
TCP_PAGE(sk) = page;
}
}
=== added file 'net/ipv4/tcp_zero_copy.c'
--- old/net/ipv4/tcp_zero_copy.c 1970-01-01 00:00:00 +0000
+++ new/net/ipv4/tcp_zero_copy.c 2012-01-10 23:43:22 +0000
@@ -0,0 +1,50 @@
+/*
+ * Support routines for TCP zero copy transmit
+ *
+ * Created by Vladislav Bolkhovitin
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/export.h>
+#include <linux/skbuff.h>
+
+net_get_page_callback_t net_get_page_callback __read_mostly;
+EXPORT_SYMBOL_GPL(net_get_page_callback);
+
+net_put_page_callback_t net_put_page_callback __read_mostly;
+EXPORT_SYMBOL_GPL(net_put_page_callback);
+
+/*
+ * Caller of this function must ensure that at the moment when it's called
+ * there are no pages in the system with net_priv field set to non-zero
+ * value. Hence, this function, as well as net_get_page() and net_put_page(),
+ * don't need any protection.
+ */
+int net_set_get_put_page_callbacks(
+ net_get_page_callback_t get_callback,
+ net_put_page_callback_t put_callback)
+{
+ int res = 0;
+
+ if ((net_get_page_callback != NULL) && (get_callback != NULL) &&
+ (net_get_page_callback != get_callback)) {
+ res = -EBUSY;
+ goto out;
+ }
+
+ if ((net_put_page_callback != NULL) && (put_callback != NULL) &&
+ (net_put_page_callback != put_callback)) {
+ res = -EBUSY;
+ goto out;
+ }
+
+ net_get_page_callback = get_callback;
+ net_put_page_callback = put_callback;
+
+out:
+ return res;
+}
+EXPORT_SYMBOL_GPL(net_set_get_put_page_callbacks);
+7 -6
View File
@@ -3,18 +3,19 @@
ABT_DETAILS="x86_64"
ABT_JOBS=5
ABT_KERNELS=" \
3.13.9 \
3.12.13-nc \
3.14.1 \
3.13.10 \
3.12.17-nc \
3.11.10-nc \
3.10.36-nc \
3.10.37-nc \
3.9.11-nc \
3.8.13-nc \
3.8.14-nc \
3.7.10-nc \
3.6.11-nc \
3.5.7-nc \
3.4.86-nc \
3.4.87-nc \
3.3.8-nc \
3.2.53-nc \
3.2.57-nc \
3.1.10-nc \
3.0.101-nc \
2.6.39.4-nc \
@@ -0,0 +1,5 @@
ccflags-y += -Idrivers/scsi/qla2xxx
qla2x00tgt-y := qla2x00t.o
obj-$(CONFIG_SCST_QLA_TGT_ADDON) += qla2x00tgt.o
+3 -1
View File
@@ -268,7 +268,9 @@ done
scsi_exec_req_fifo_defined=0
scst_io_context=0
for p in scst/kernel/*-${kver}.patch \
$(if [ "${1#3.7.}" != "$1" ] && [ "${1#3.7.}" -ge 10 ]; then
$(if [ "${1#3.2.}" != "$1" ] && [ "${1#3.2.}" -ge 57 ]; then
echo iscsi-scst/kernel/patches/*-3.2.57.patch;
elif [ "${1#3.7.}" != "$1" ] && [ "${1#3.7.}" -ge 10 ]; then
echo iscsi-scst/kernel/patches/*-3.7.10.patch;
elif [ "${1#3.10.}" != "$1" ] && [ "${1#3.10.}" -ge 30 ]; then
echo iscsi-scst/kernel/patches/*-3.10.30.patch;
+1
View File
@@ -213,6 +213,7 @@ function run_checkpatch {
echo "${errors} errors / ${warnings} warnings."
grep -E '^WARNING|^ERROR' "${outputfile}" |
sort |
grep -v 'WARNING: missing space after return type' |
sed 's/^WARNING: Avoid CamelCase:.*/WARNING: Avoid CamelCase/' |
uniq -c
else
+17 -22
View File
@@ -1466,34 +1466,29 @@ Report target port groups:
Initiator Support
.................
On Linux systems implicit ALUA support is provided by the scsi_dh_alua driver
of the device mapper. You will have to modify at least the following in
/etc/multipath.conf:
* path_checker scsi_dh_alua
* prio_callout "/sbin/mpath_prio_alua /dev/%n"
On Linux systems implicit ALUA support is provided by the scsi_dh_alua kernel
driver in combination with the user space multipathd daemon. You will have to
modify at least the following in /etc/multipath.conf to enable implicit ALUA:
* hardware_handler "1 alua"
* prio alua
* path_grouping_policy group_by_prio
If your distribution does not provide a /sbin/mpath_prio_alua script, you can
use the following implementation:
$ cat /sbin/mpath_prio_alua
#!/bin/bash
# Given a SCSI device node, query the target port group asymmetric access
# state and report it in numeric form.
tpg_id="$(sg_vpd --page=di "$1" | sed -n 's/.*Target port group: //p')"
aas="$(sg_rtpg "$1" \
| grep -A1 "target port group id : $tpg_id" \
| tail -n 1 \
| sed 's/.*target port group asymmetric access state : //')"
echo $((aas))
Note: newer versions of multipathd support a parameter called
"detect_prio". It can be more convenient to enable this parameter instead of
setting the parameter "prio" to "alua" for only those LUNs that support ALUA.
More information about how to configure the device mapper and the scsi_dh_alua
driver can be found in the manual of your Linux distribution.
driver can be found in the manual of your Linux distribution ("man
multipath.conf").
Windows initiator systems support ALUA from Windows Server 2008 on. For more
information, see also:
* Microsoft, Multipathing Support in Windows Server 2008, MSDN
(http://blogs.msdn.com/b/san/archive/2008/07/27/multipathing-support-in-windows-server-2008.aspx).
information about ALUA support in Windows Server, see also:
* Microsoft, Windows Server 2008 R2 Multipath I/O Overview, MSDN
(http://technet.microsoft.com/en-us/library/cc725907.aspx).
* Microsoft, Multipathing Support in Windows Server 2008, July 2008, MSDN
(http://blogs.msdn.com/b/san/archive/2008/07/27/multipathing-support-in-windows-server-2008.aspx).
* Microsoft, ALUA MPIO Logo Test, MSDN
(http://msdn.microsoft.com/en-us/library/gg607458%28v=vs.85%29.aspx).
(http://msdn.microsoft.com/en-us/library/gg607458%28v=vs.85%29.aspx).
Caching
+125 -49
View File
@@ -661,6 +661,7 @@ struct scst_acg;
struct scst_acg_dev;
struct scst_acn;
struct scst_aen;
struct scst_opcode_descriptor;
/*
* SCST uses 64-bit numbers to represent LUN's internally. The value
@@ -763,7 +764,7 @@ struct scst_tgt_template {
*
* MUST HAVE
*/
int (*xmit_response) (struct scst_cmd *cmd);
int (*xmit_response)(struct scst_cmd *cmd);
/*
* This function informs the driver that data
@@ -787,7 +788,7 @@ struct scst_tgt_template {
*
* OPTIONAL
*/
int (*rdy_to_xfer) (struct scst_cmd *cmd);
int (*rdy_to_xfer)(struct scst_cmd *cmd);
/*
* Called if cmd stays inside the target hardware, i.e. after
@@ -797,7 +798,7 @@ struct scst_tgt_template {
*
* OPTIONAL
*/
void (*on_hw_pending_cmd_timeout) (struct scst_cmd *cmd);
void (*on_hw_pending_cmd_timeout)(struct scst_cmd *cmd);
/*
* Called to notify the driver that the command is about to be freed.
@@ -813,7 +814,7 @@ struct scst_tgt_template {
*
* OPTIONAL
*/
void (*on_free_cmd) (struct scst_cmd *cmd);
void (*on_free_cmd)(struct scst_cmd *cmd);
/*
* This function allows target driver to handle data buffer
@@ -844,7 +845,7 @@ struct scst_tgt_template {
*
* OPTIONAL.
*/
int (*tgt_alloc_data_buf) (struct scst_cmd *cmd);
int (*tgt_alloc_data_buf)(struct scst_cmd *cmd);
/*
* This function informs the driver that data
@@ -871,7 +872,7 @@ struct scst_tgt_template {
*
* OPTIONAL.
*/
void (*preprocessing_done) (struct scst_cmd *cmd);
void (*preprocessing_done)(struct scst_cmd *cmd);
/*
* This function informs the driver that the said command is about
@@ -884,7 +885,7 @@ struct scst_tgt_template {
*
* OPTIONAL
*/
int (*pre_exec) (struct scst_cmd *cmd);
int (*pre_exec)(struct scst_cmd *cmd);
/*
* This function informs the driver that all affected by the
@@ -897,7 +898,7 @@ struct scst_tgt_template {
*
* OPTIONAL
*/
void (*task_mgmt_affected_cmds_done) (struct scst_mgmt_cmd *mgmt_cmd);
void (*task_mgmt_affected_cmds_done)(struct scst_mgmt_cmd *mgmt_cmd);
/*
* This function informs the driver that the corresponding task
@@ -910,7 +911,7 @@ struct scst_tgt_template {
*
* MUST HAVE if the target supports task management.
*/
void (*task_mgmt_fn_done) (struct scst_mgmt_cmd *mgmt_cmd);
void (*task_mgmt_fn_done)(struct scst_mgmt_cmd *mgmt_cmd);
/*
* Called to notify target driver that the command is being aborted.
@@ -919,7 +920,7 @@ struct scst_tgt_template {
*
* OPTIONAL
*/
void (*on_abort_cmd) (struct scst_cmd *cmd);
void (*on_abort_cmd)(struct scst_cmd *cmd);
/*
* This function should detect the target adapters that
@@ -930,7 +931,7 @@ struct scst_tgt_template {
*
* MUST HAVE
*/
int (*detect) (struct scst_tgt_template *tgt_template);
int (*detect)(struct scst_tgt_template *tgt_template);
/*
* This function should free up the resources allocated to the device.
@@ -940,7 +941,7 @@ struct scst_tgt_template {
*
* MUST HAVE
*/
int (*release) (struct scst_tgt *tgt);
int (*release)(struct scst_tgt *tgt);
/*
* This function is used for Asynchronous Event Notifications.
@@ -959,7 +960,7 @@ struct scst_tgt_template {
*
* MUST HAVE, if low-level protocol supports AENs.
*/
int (*report_aen) (struct scst_aen *aen);
int (*report_aen)(struct scst_aen *aen);
#ifdef CONFIG_SCST_PROC
/*
@@ -969,8 +970,8 @@ struct scst_tgt_template {
*
* OPTIONAL
*/
int (*read_proc) (struct seq_file *seq, struct scst_tgt *tgt);
int (*write_proc) (char *buffer, char **start, off_t offset,
int (*read_proc)(struct seq_file *seq, struct scst_tgt *tgt);
int (*write_proc)(char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_tgt *tgt);
#endif
@@ -988,7 +989,7 @@ struct scst_tgt_template {
*
* SHOULD HAVE, because it's required for Persistent Reservations.
*/
int (*get_initiator_port_transport_id) (struct scst_tgt *tgt,
int (*get_initiator_port_transport_id)(struct scst_tgt *tgt,
struct scst_session *sess, uint8_t **transport_id);
/*
@@ -1003,14 +1004,14 @@ struct scst_tgt_template {
* If you are sure your target driver doesn't need enabling target,
* you should set enabled_attr_not_needed in 1.
*/
int (*enable_target) (struct scst_tgt *tgt, bool enable);
int (*enable_target)(struct scst_tgt *tgt, bool enable);
/*
* This function shows if particular target is enabled or not.
*
* SHOULD HAVE, see above why.
*/
bool (*is_target_enabled) (struct scst_tgt *tgt);
bool (*is_target_enabled)(struct scst_tgt *tgt);
/*
* This function adds a virtual target.
@@ -1030,7 +1031,7 @@ struct scst_tgt_template {
*
* MUST HAVE if virtual targets are supported.
*/
ssize_t (*add_target) (const char *target_name, char *params);
ssize_t (*add_target)(const char *target_name, char *params);
/*
* This function deletes a virtual target. See comment for add_target
@@ -1038,7 +1039,7 @@ struct scst_tgt_template {
*
* MUST HAVE if virtual targets are supported.
*/
ssize_t (*del_target) (const char *target_name);
ssize_t (*del_target)(const char *target_name);
/*
* This function called if not "add_target" or "del_target" command is
@@ -1047,7 +1048,7 @@ struct scst_tgt_template {
*
* OPTIONAL.
*/
ssize_t (*mgmt_cmd) (char *cmd);
ssize_t (*mgmt_cmd)(char *cmd);
/*
* Forcibly close a session. Note: this function may operate
@@ -1068,7 +1069,7 @@ struct scst_tgt_template {
*
* OPTIONAL
*/
uint16_t (*get_phys_transport_version) (struct scst_tgt *tgt);
uint16_t (*get_phys_transport_version)(struct scst_tgt *tgt);
/*
* Should return SCSI transport version. Used in the corresponding
@@ -1076,7 +1077,7 @@ struct scst_tgt_template {
*
* OPTIONAL
*/
uint16_t (*get_scsi_transport_version) (struct scst_tgt *tgt);
uint16_t (*get_scsi_transport_version)(struct scst_tgt *tgt);
/*
* Name of the template. Must be unique to identify
@@ -1244,7 +1245,7 @@ struct scst_dev_type {
*
* MUST HAVE
*/
int (*parse) (struct scst_cmd *cmd);
int (*parse)(struct scst_cmd *cmd);
/*
* This function allows dev handler to handle data buffer
@@ -1264,7 +1265,7 @@ struct scst_dev_type {
*
* OPTIONAL
*/
int (*dev_alloc_data_buf) (struct scst_cmd *cmd);
int (*dev_alloc_data_buf)(struct scst_cmd *cmd);
/*
* Called to execute CDB. Useful, for instance, to implement
@@ -1286,7 +1287,7 @@ struct scst_dev_type {
* OPTIONAL, if not set, the commands will be sent directly to SCSI
* device.
*/
int (*exec) (struct scst_cmd *cmd);
int (*exec)(struct scst_cmd *cmd);
/*
* Called to notify dev handler about the result of cmd execution
@@ -1305,7 +1306,7 @@ struct scst_dev_type {
*
* OPTIONAL
*/
int (*dev_done) (struct scst_cmd *cmd);
int (*dev_done)(struct scst_cmd *cmd);
/*
* Called to notify dev hander that the command is about to be freed.
@@ -1314,7 +1315,7 @@ struct scst_dev_type {
*
* OPTIONAL
*/
void (*on_free_cmd) (struct scst_cmd *cmd);
void (*on_free_cmd)(struct scst_cmd *cmd);
/*
* Called to notify dev handler that a task management command received
@@ -1329,7 +1330,7 @@ struct scst_dev_type {
*
* OPTIONAL
*/
void (*task_mgmt_fn_received) (struct scst_mgmt_cmd *mgmt_cmd,
void (*task_mgmt_fn_received)(struct scst_mgmt_cmd *mgmt_cmd,
struct scst_tgt_dev *tgt_dev);
/*
@@ -1347,7 +1348,7 @@ struct scst_dev_type {
*
* OPTIONAL
*/
void (*task_mgmt_fn_done) (struct scst_mgmt_cmd *mgmt_cmd,
void (*task_mgmt_fn_done)(struct scst_mgmt_cmd *mgmt_cmd,
struct scst_tgt_dev *tgt_dev);
/*
@@ -1359,7 +1360,7 @@ struct scst_dev_type {
*
* OPTIONAL
*/
void (*reassign_retained_states) (struct scst_tgt_dev *new_tgt_dev,
void (*reassign_retained_states)(struct scst_tgt_dev *new_tgt_dev,
struct scst_tgt_dev *old_tgt_dev);
/*
@@ -1372,7 +1373,30 @@ struct scst_dev_type {
*
* MUST HAVE, if dev handler supports CDB splitting.
*/
bool (*on_sg_tablesize_low) (struct scst_cmd *cmd);
bool (*on_sg_tablesize_low)(struct scst_cmd *cmd);
/*
* Called to return array of supported opcodes in out_supp_opcodes
* argument with out_supp_opcodes_cnt elements count or execute
* REPORT SUPPORTED OPERATION CODES command in place. Must return
* 0 on success or any other code otherwise. In the latter case,
* cmd supposed to have correct sense set.
*
* OPTIONAL
*/
int (*get_supported_opcodes)(struct scst_cmd *cmd,
const struct scst_opcode_descriptor ***out_supp_opcodes,
int *out_supp_opcodes_cnt);
/*
* Called to put (release) array of supported opcodes returned
* by get_supported_opcodes() callback.
*
* OPTIONAL
*/
void (*put_supported_opcodes)(struct scst_cmd *cmd,
const struct scst_opcode_descriptor **supp_opcodes,
int supp_opcodes_cnt);
/*
* Called when new device is attaching to the dev handler
@@ -1380,14 +1404,14 @@ struct scst_dev_type {
*
* OPTIONAL
*/
int (*attach) (struct scst_device *dev);
int (*attach)(struct scst_device *dev);
/*
* Called when a device is detaching from the dev handler.
*
* OPTIONAL
*/
void (*detach) (struct scst_device *dev);
void (*detach)(struct scst_device *dev);
/*
* Called when new tgt_dev (session) is attaching to the dev handler.
@@ -1395,14 +1419,14 @@ struct scst_dev_type {
*
* OPTIONAL
*/
int (*attach_tgt) (struct scst_tgt_dev *tgt_dev);
int (*attach_tgt)(struct scst_tgt_dev *tgt_dev);
/*
* Called when tgt_dev (session) is detaching from the dev handler.
*
* OPTIONAL
*/
void (*detach_tgt) (struct scst_tgt_dev *tgt_dev);
void (*detach_tgt)(struct scst_tgt_dev *tgt_dev);
#ifdef CONFIG_SCST_PROC
/*
@@ -1412,8 +1436,8 @@ struct scst_dev_type {
*
* OPTIONAL
*/
int (*read_proc) (struct seq_file *seq, struct scst_dev_type *dev_type);
int (*write_proc) (char *buffer, char **start, off_t offset,
int (*read_proc)(struct seq_file *seq, struct scst_dev_type *dev_type);
int (*write_proc)(char *buffer, char **start, off_t offset,
int length, int *eof, struct scst_dev_type *dev_type);
#else
/*
@@ -1434,7 +1458,7 @@ struct scst_dev_type {
*
* MUST HAVE if virtual devices are supported.
*/
ssize_t (*add_device) (const char *device_name, char *params);
ssize_t (*add_device)(const char *device_name, char *params);
/*
* This function deletes a virtual device. See comment for add_device
@@ -1442,7 +1466,7 @@ struct scst_dev_type {
*
* MUST HAVE if virtual devices are supported.
*/
ssize_t (*del_device) (const char *device_name);
ssize_t (*del_device)(const char *device_name);
/*
* This function called if not "add_device" or "del_device" command is
@@ -1451,7 +1475,7 @@ struct scst_dev_type {
*
* OPTIONAL.
*/
ssize_t (*mgmt_cmd) (char *cmd);
ssize_t (*mgmt_cmd)(char *cmd);
#endif
/*
@@ -1778,9 +1802,9 @@ struct scst_session {
* and scst_unregister_session()
*/
void *reg_sess_data;
void (*init_result_fn) (struct scst_session *sess, void *data,
void (*init_result_fn)(struct scst_session *sess, void *data,
int result);
void (*unreg_done_fn) (struct scst_session *sess);
void (*unreg_done_fn)(struct scst_session *sess);
#ifdef CONFIG_SCST_MEASURE_LATENCY
spinlock_t lat_lock;
@@ -1803,7 +1827,7 @@ struct scst_pr_abort_all_pending_mgmt_cmds_counter {
atomic_t pr_abort_pending_cnt;
/* Saved completion routine */
void (*saved_cmd_done) (struct scst_cmd *cmd, int next_state,
void (*saved_cmd_done)(struct scst_cmd *cmd, int next_state,
enum scst_exec_context pref_context);
/*
@@ -2111,7 +2135,7 @@ struct scst_cmd {
int64_t data_len;
/* Completion routine */
void (*scst_cmd_done) (struct scst_cmd *cmd, int next_state,
void (*scst_cmd_done)(struct scst_cmd *cmd, int next_state,
enum scst_exec_context pref_context);
struct sgv_pool_obj *sgv; /* sgv object */
@@ -2896,6 +2920,58 @@ struct scst_aen {
int delivery_status;
};
#define SCST_OD_DEFAULT_CONTROL_BYTE 0
struct scst_opcode_descriptor {
uint16_t od_serv_action;
uint8_t od_opcode;
uint8_t od_serv_action_valid:1;
uint8_t od_support:3; /* SUPPORT bits */
uint16_t od_cdb_size;
uint8_t od_comm_specific_timeout;
uint32_t od_nominal_timeout;
uint32_t od_recommended_timeout;
uint8_t od_cdb_usage_bits[];
} __packed;
extern const struct scst_opcode_descriptor scst_op_descr_log_select;
extern const struct scst_opcode_descriptor scst_op_descr_log_sense;
extern const struct scst_opcode_descriptor scst_op_descr_mode_select6;
extern const struct scst_opcode_descriptor scst_op_descr_mode_sense6;
extern const struct scst_opcode_descriptor scst_op_descr_mode_select10;
extern const struct scst_opcode_descriptor scst_op_descr_mode_sense10;
extern const struct scst_opcode_descriptor scst_op_descr_rtpg;
extern const struct scst_opcode_descriptor scst_op_descr_stpg;
extern const struct scst_opcode_descriptor scst_op_descr_send_diagnostic;
extern const struct scst_opcode_descriptor scst_op_descr_inquiry;
extern const struct scst_opcode_descriptor scst_op_descr_tur;
extern const struct scst_opcode_descriptor scst_op_descr_reserve6;
extern const struct scst_opcode_descriptor scst_op_descr_release6;
extern const struct scst_opcode_descriptor scst_op_descr_reserve10;
extern const struct scst_opcode_descriptor scst_op_descr_release10;
extern const struct scst_opcode_descriptor scst_op_descr_pr_in;
extern const struct scst_opcode_descriptor scst_op_descr_pr_out;
extern const struct scst_opcode_descriptor scst_op_descr_report_luns;
extern const struct scst_opcode_descriptor scst_op_descr_request_sense;
extern const struct scst_opcode_descriptor scst_op_descr_report_supp_tm_fns;
extern const struct scst_opcode_descriptor scst_op_descr_report_supp_opcodes;
#define SCST_OPCODE_DESCRIPTORS \
&scst_op_descr_inquiry, \
&scst_op_descr_tur, \
&scst_op_descr_reserve6, \
&scst_op_descr_release6, \
&scst_op_descr_reserve10, \
&scst_op_descr_release10, \
&scst_op_descr_pr_in, \
&scst_op_descr_pr_out, \
&scst_op_descr_report_luns, \
&scst_op_descr_request_sense, \
&scst_op_descr_report_supp_opcodes, \
&scst_op_descr_report_supp_tm_fns,
#ifndef smp_mb__after_set_bit
/* There is no smp_mb__after_set_bit() in the kernel */
#define smp_mb__after_set_bit() smp_mb()
@@ -2935,11 +3011,11 @@ void scst_unregister_target(struct scst_tgt *tgt);
struct scst_session *scst_register_session(struct scst_tgt *tgt, int atomic,
const char *initiator_name, void *tgt_priv, void *result_fn_data,
void (*result_fn) (struct scst_session *sess, void *data, int result));
void (*result_fn)(struct scst_session *sess, void *data, int result));
struct scst_session *scst_register_session_non_gpl(struct scst_tgt *tgt,
const char *initiator_name, void *tgt_priv);
void scst_unregister_session(struct scst_session *sess, int wait,
void (*unreg_done_fn) (struct scst_session *sess));
void (*unreg_done_fn)(struct scst_session *sess));
void scst_unregister_session_non_gpl(struct scst_session *sess);
int __scst_register_dev_driver(struct scst_dev_type *dev_type,
@@ -3078,8 +3154,8 @@ void scst_capacity_data_changed(struct scst_device *dev);
struct scst_cmd *scst_find_cmd_by_tag(struct scst_session *sess, uint64_t tag);
struct scst_cmd *scst_find_cmd(struct scst_session *sess, void *data,
int (*cmp_fn) (struct scst_cmd *cmd,
void *data));
int (*cmp_fn)(struct scst_cmd *cmd,
void *data));
enum dma_data_direction scst_to_dma_dir(int scst_dir);
enum dma_data_direction scst_to_tgt_dma_dir(int scst_dir);
+7 -2
View File
@@ -413,6 +413,10 @@ static inline int scst_sense_response_code(const uint8_t *sense)
#define WRITE_SAME_16 0x93
#endif
#ifndef SYNCHRONIZE_CACHE_16
#define SYNCHRONIZE_CACHE_16 0x91
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
/*
* From <scsi/scsi.h>. See also commit
@@ -567,6 +571,7 @@ enum scst_tg_sup {
** Various timeouts
*************************************************************/
#define SCST_DEFAULT_TIMEOUT (30 * HZ)
#define SCST_DEFAULT_NOMINAL_TIMEOUT_SEC 1
#define SCST_GENERIC_CHANGER_TIMEOUT (3 * HZ)
#define SCST_GENERIC_CHANGER_LONG_TIMEOUT (14000 * HZ)
@@ -582,8 +587,8 @@ enum scst_tg_sup {
#define SCST_GENERIC_MODISK_REG_TIMEOUT (900 * HZ)
#define SCST_GENERIC_MODISK_LONG_TIMEOUT (14000 * HZ)
#define SCST_GENERIC_DISK_SMALL_TIMEOUT (3 * HZ)
#define SCST_GENERIC_DISK_REG_TIMEOUT (30 * HZ)
#define SCST_GENERIC_DISK_SMALL_TIMEOUT (10 * HZ)
#define SCST_GENERIC_DISK_REG_TIMEOUT (60 * HZ)
#define SCST_GENERIC_DISK_LONG_TIMEOUT (3600 * HZ)
#define SCST_GENERIC_RAID_TIMEOUT (3 * HZ)
@@ -0,0 +1,13 @@
diff --git a/drivers/Kconfig b/drivers/Kconfig
index aa43b91..c96860e 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -24,6 +24,8 @@ source "drivers/ide/Kconfig"
source "drivers/scsi/Kconfig"
+source "drivers/scst/Kconfig"
+
source "drivers/ata/Kconfig"
source "drivers/md/Kconfig"
@@ -0,0 +1,14 @@
ccflags-y += -Wno-unused-parameter
obj-m := scst_cdrom.o scst_changer.o scst_disk.o scst_modisk.o scst_tape.o \
scst_vdisk.o scst_raid.o scst_processor.o scst_user.o
obj-$(CONFIG_SCST_DISK) += scst_disk.o
obj-$(CONFIG_SCST_TAPE) += scst_tape.o
obj-$(CONFIG_SCST_CDROM) += scst_cdrom.o
obj-$(CONFIG_SCST_MODISK) += scst_modisk.o
obj-$(CONFIG_SCST_CHANGER) += scst_changer.o
obj-$(CONFIG_SCST_RAID) += scst_raid.o
obj-$(CONFIG_SCST_PROCESSOR) += scst_processor.o
obj-$(CONFIG_SCST_VDISK) += scst_vdisk.o
obj-$(CONFIG_SCST_USER) += scst_user.o
@@ -0,0 +1,12 @@
diff --git a/drivers/Makefile b/drivers/Makefile
index ab93de8..45077ec 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -128,6 +128,7 @@ obj-$(CONFIG_SSB) += ssb/
obj-$(CONFIG_BCMA) += bcma/
obj-$(CONFIG_VHOST_RING) += vhost/
obj-$(CONFIG_VLYNQ) += vlynq/
+obj-$(CONFIG_SCST) += scst/
obj-$(CONFIG_STAGING) += staging/
obj-y += platform/
#common clk code
+13
View File
@@ -0,0 +1,13 @@
ccflags-y += -Wno-unused-parameter
scst-y += scst_main.o
scst-y += scst_pres.o
scst-y += scst_targ.o
scst-y += scst_lib.o
scst-y += scst_sysfs.o
scst-y += scst_mem.o
scst-y += scst_tg.o
scst-y += scst_debug.o
obj-$(CONFIG_SCST) += scst.o dev_handlers/ fcst/ iscsi-scst/ qla2xxx-target/ \
srpt/ scst_local/
+528
View File
@@ -0,0 +1,528 @@
=== modified file 'block/blk-map.c'
--- old/block/blk-map.c 2014-04-17 22:02:06 +0000
+++ new/block/blk-map.c 2014-04-17 22:08:48 +0000
@@ -5,6 +5,8 @@
#include <linux/module.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
#include <scsi/sg.h> /* for struct sg_iovec */
#include "blk.h"
@@ -275,6 +277,337 @@ int blk_rq_unmap_user(struct bio *bio)
}
EXPORT_SYMBOL(blk_rq_unmap_user);
+struct blk_kern_sg_work {
+ atomic_t bios_inflight;
+ struct sg_table sg_table;
+ struct scatterlist *src_sgl;
+};
+
+static void blk_free_kern_sg_work(struct blk_kern_sg_work *bw)
+{
+ struct sg_table *sgt = &bw->sg_table;
+ struct scatterlist *sg;
+ int i;
+
+ for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) {
+ struct page *pg = sg_page(sg);
+ if (pg == NULL)
+ break;
+ __free_page(pg);
+ }
+
+ sg_free_table(sgt);
+ kfree(bw);
+ return;
+}
+
+static void blk_bio_map_kern_endio(struct bio *bio, int err)
+{
+ struct blk_kern_sg_work *bw = bio->bi_private;
+
+ if (bw != NULL) {
+ /* Decrement the bios in processing and, if zero, free */
+ BUG_ON(atomic_read(&bw->bios_inflight) <= 0);
+ if (atomic_dec_and_test(&bw->bios_inflight)) {
+ if ((bio_data_dir(bio) == READ) && (err == 0)) {
+ unsigned long flags;
+
+ local_irq_save(flags); /* to protect KMs */
+ sg_copy(bw->src_sgl, bw->sg_table.sgl, 0, 0);
+ local_irq_restore(flags);
+ }
+ blk_free_kern_sg_work(bw);
+ }
+ }
+
+ bio_put(bio);
+ return;
+}
+
+static int blk_rq_copy_kern_sg(struct request *rq, struct scatterlist *sgl,
+ int nents, struct blk_kern_sg_work **pbw,
+ gfp_t gfp, gfp_t page_gfp)
+{
+ int res = 0, i;
+ struct scatterlist *sg;
+ struct scatterlist *new_sgl;
+ int new_sgl_nents;
+ size_t len = 0, to_copy;
+ struct blk_kern_sg_work *bw;
+
+ bw = kzalloc(sizeof(*bw), gfp);
+ if (bw == NULL)
+ goto out;
+
+ bw->src_sgl = sgl;
+
+ for_each_sg(sgl, sg, nents, i)
+ len += sg->length;
+ to_copy = len;
+
+ new_sgl_nents = PFN_UP(len);
+
+ res = sg_alloc_table(&bw->sg_table, new_sgl_nents, gfp);
+ if (res != 0)
+ goto err_free;
+
+ new_sgl = bw->sg_table.sgl;
+
+ for_each_sg(new_sgl, sg, new_sgl_nents, i) {
+ struct page *pg;
+
+ pg = alloc_page(page_gfp);
+ if (pg == NULL)
+ goto err_free;
+
+ sg_assign_page(sg, pg);
+ sg->length = min_t(size_t, PAGE_SIZE, len);
+
+ len -= PAGE_SIZE;
+ }
+
+ if (rq_data_dir(rq) == WRITE) {
+ /*
+ * We need to limit amount of copied data to to_copy, because
+ * sgl might have the last element in sgl not marked as last in
+ * SG chaining.
+ */
+ sg_copy(new_sgl, sgl, 0, to_copy);
+ }
+
+ *pbw = bw;
+ /*
+ * REQ_COPY_USER name is misleading. It should be something like
+ * REQ_HAS_TAIL_SPACE_FOR_PADDING.
+ */
+ rq->cmd_flags |= REQ_COPY_USER;
+
+out:
+ return res;
+
+err_free:
+ blk_free_kern_sg_work(bw);
+ res = -ENOMEM;
+ goto out;
+}
+
+static int __blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl,
+ int nents, struct blk_kern_sg_work *bw, gfp_t gfp)
+{
+ int res;
+ struct request_queue *q = rq->q;
+ int rw = rq_data_dir(rq);
+ int max_nr_vecs, i;
+ size_t tot_len;
+ bool need_new_bio;
+ struct scatterlist *sg, *prev_sg = NULL;
+ struct bio *bio = NULL, *hbio = NULL, *tbio = NULL;
+ int bios;
+
+ if (unlikely((sgl == NULL) || (sgl->length == 0) || (nents <= 0))) {
+ WARN_ON(1);
+ res = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * Let's keep each bio allocation inside a single page to decrease
+ * probability of failure.
+ */
+ max_nr_vecs = min_t(size_t,
+ ((PAGE_SIZE - sizeof(struct bio)) / sizeof(struct bio_vec)),
+ BIO_MAX_PAGES);
+
+ need_new_bio = true;
+ tot_len = 0;
+ bios = 0;
+ for_each_sg(sgl, sg, nents, i) {
+ struct page *page = sg_page(sg);
+ void *page_addr = page_address(page);
+ size_t len = sg->length, l;
+ size_t offset = sg->offset;
+
+ tot_len += len;
+ prev_sg = sg;
+
+ /*
+ * Each segment must be aligned on DMA boundary and
+ * not on stack. The last one may have unaligned
+ * length as long as the total length is aligned to
+ * DMA padding alignment.
+ */
+ if (i == nents - 1)
+ l = 0;
+ else
+ l = len;
+ if (((sg->offset | l) & queue_dma_alignment(q)) ||
+ (page_addr && object_is_on_stack(page_addr + sg->offset))) {
+ res = -EINVAL;
+ goto out_free_bios;
+ }
+
+ while (len > 0) {
+ size_t bytes;
+ int rc;
+
+ if (need_new_bio) {
+ bio = bio_kmalloc(gfp, max_nr_vecs);
+ if (bio == NULL) {
+ res = -ENOMEM;
+ goto out_free_bios;
+ }
+
+ if (rw == WRITE)
+ bio->bi_rw |= REQ_WRITE;
+
+ bios++;
+ bio->bi_private = bw;
+ bio->bi_end_io = blk_bio_map_kern_endio;
+
+ if (hbio == NULL)
+ hbio = tbio = bio;
+ else
+ tbio = tbio->bi_next = bio;
+ }
+
+ bytes = min_t(size_t, len, PAGE_SIZE - offset);
+
+ rc = bio_add_pc_page(q, bio, page, bytes, offset);
+ if (rc < bytes) {
+ if (unlikely(need_new_bio || (rc < 0))) {
+ if (rc < 0)
+ res = rc;
+ else
+ res = -EIO;
+ goto out_free_bios;
+ } else {
+ need_new_bio = true;
+ len -= rc;
+ offset += rc;
+ continue;
+ }
+ }
+
+ need_new_bio = false;
+ offset = 0;
+ len -= bytes;
+ page = nth_page(page, 1);
+ }
+ }
+
+ if (hbio == NULL) {
+ res = -EINVAL;
+ goto out_free_bios;
+ }
+
+ /* Total length must be aligned on DMA padding alignment */
+ if ((tot_len & q->dma_pad_mask) &&
+ !(rq->cmd_flags & REQ_COPY_USER)) {
+ res = -EINVAL;
+ goto out_free_bios;
+ }
+
+ if (bw != NULL)
+ atomic_set(&bw->bios_inflight, bios);
+
+ while (hbio != NULL) {
+ bio = hbio;
+ hbio = hbio->bi_next;
+ bio->bi_next = NULL;
+
+ blk_queue_bounce(q, &bio);
+
+ res = blk_rq_append_bio(q, rq, bio);
+ if (unlikely(res != 0)) {
+ bio->bi_next = hbio;
+ hbio = bio;
+ /* We can have one or more bios bounced */
+ goto out_unmap_bios;
+ }
+ }
+
+ res = 0;
+
+ rq->buffer = NULL;
+out:
+ return res;
+
+out_unmap_bios:
+ blk_rq_unmap_kern_sg(rq, res);
+
+out_free_bios:
+ while (hbio != NULL) {
+ bio = hbio;
+ hbio = hbio->bi_next;
+ bio_put(bio);
+ }
+ goto out;
+}
+
+/**
+ * blk_rq_map_kern_sg - map kernel data to a request, for REQ_TYPE_BLOCK_PC
+ * @rq: request to fill
+ * @sgl: area to map
+ * @nents: number of elements in @sgl
+ * @gfp: memory allocation flags
+ *
+ * Description:
+ * Data will be mapped directly if possible. Otherwise a bounce
+ * buffer will be used.
+ */
+int blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl,
+ int nents, gfp_t gfp)
+{
+ int res;
+
+ res = __blk_rq_map_kern_sg(rq, sgl, nents, NULL, gfp);
+ if (unlikely(res != 0)) {
+ struct blk_kern_sg_work *bw = NULL;
+
+ res = blk_rq_copy_kern_sg(rq, sgl, nents, &bw,
+ gfp, rq->q->bounce_gfp | gfp);
+ if (unlikely(res != 0))
+ goto out;
+
+ res = __blk_rq_map_kern_sg(rq, bw->sg_table.sgl,
+ bw->sg_table.nents, bw, gfp);
+ if (res != 0) {
+ blk_free_kern_sg_work(bw);
+ goto out;
+ }
+ }
+
+ rq->buffer = NULL;
+
+out:
+ return res;
+}
+EXPORT_SYMBOL(blk_rq_map_kern_sg);
+
+/**
+ * blk_rq_unmap_kern_sg - unmap a request with kernel sg
+ * @rq: request to unmap
+ * @err: non-zero error code
+ *
+ * Description:
+ * Unmap a rq previously mapped by blk_rq_map_kern_sg(). Must be called
+ * only in case of an error!
+ */
+void blk_rq_unmap_kern_sg(struct request *rq, int err)
+{
+ struct bio *bio = rq->bio;
+
+ while (bio) {
+ struct bio *b = bio;
+ bio = bio->bi_next;
+ b->bi_end_io(b, err);
+ }
+ rq->bio = NULL;
+
+ return;
+}
+EXPORT_SYMBOL(blk_rq_unmap_kern_sg);
+
/**
* blk_rq_map_kern - map kernel data to a request, for REQ_TYPE_BLOCK_PC usage
* @q: request queue where request should be inserted
=== modified file 'include/linux/blkdev.h'
--- old/include/linux/blkdev.h 2014-04-17 22:02:06 +0000
+++ new/include/linux/blkdev.h 2014-04-17 22:08:48 +0000
@@ -705,6 +705,8 @@ extern unsigned long blk_max_low_pfn, bl
#define BLK_DEFAULT_SG_TIMEOUT (60 * HZ)
#define BLK_MIN_SG_TIMEOUT (7 * HZ)
+#define SCSI_EXEC_REQ_FIFO_DEFINED
+
#ifdef CONFIG_BOUNCE
extern int init_emergency_isa_pool(void);
extern void blk_queue_bounce(struct request_queue *q, struct bio **bio);
@@ -825,6 +827,9 @@ extern int blk_rq_map_kern(struct reques
extern int blk_rq_map_user_iov(struct request_queue *, struct request *,
struct rq_map_data *, struct sg_iovec *, int,
unsigned int, gfp_t);
+extern int blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl,
+ int nents, gfp_t gfp);
+extern void blk_rq_unmap_kern_sg(struct request *rq, int err);
extern int blk_execute_rq(struct request_queue *, struct gendisk *,
struct request *, int);
extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
=== modified file 'include/linux/scatterlist.h'
--- old/include/linux/scatterlist.h 2014-04-17 22:02:06 +0000
+++ new/include/linux/scatterlist.h 2014-04-17 22:08:48 +0000
@@ -8,6 +8,7 @@
#include <asm/types.h>
#include <asm/scatterlist.h>
#include <asm/io.h>
+#include <asm/kmap_types.h>
struct sg_table {
struct scatterlist *sgl; /* the list */
@@ -249,6 +250,9 @@ size_t sg_pcopy_from_buffer(struct scatt
size_t sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents,
void *buf, size_t buflen, off_t skip);
+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
+ int nents_to_copy, size_t copy_len);
+
/*
* Maximum number of entries that will be allocated in one piece, if
* a list larger than this is required then chaining will be utilized.
=== modified file 'lib/scatterlist.c'
--- old/lib/scatterlist.c 2014-04-17 22:02:06 +0000
+++ new/lib/scatterlist.c 2014-04-17 22:08:48 +0000
@@ -718,3 +718,127 @@ size_t sg_pcopy_to_buffer(struct scatter
return sg_copy_buffer(sgl, nents, buf, buflen, skip, true);
}
EXPORT_SYMBOL(sg_pcopy_to_buffer);
+
+
+/*
+ * Can switch to the next dst_sg element, so, to copy to strictly only
+ * one dst_sg element, it must be either last in the chain, or
+ * copy_len == dst_sg->length.
+ */
+static int sg_copy_elem(struct scatterlist **pdst_sg, size_t *pdst_len,
+ size_t *pdst_offs, struct scatterlist *src_sg,
+ size_t copy_len)
+{
+ int res = 0;
+ struct scatterlist *dst_sg;
+ size_t src_len, dst_len, src_offs, dst_offs;
+ struct page *src_page, *dst_page;
+
+ dst_sg = *pdst_sg;
+ dst_len = *pdst_len;
+ dst_offs = *pdst_offs;
+ dst_page = sg_page(dst_sg);
+
+ src_page = sg_page(src_sg);
+ src_len = src_sg->length;
+ src_offs = src_sg->offset;
+
+ do {
+ void *saddr, *daddr;
+ size_t n;
+
+ saddr = kmap_atomic(src_page + (src_offs >> PAGE_SHIFT)) +
+ (src_offs & ~PAGE_MASK);
+ daddr = kmap_atomic(dst_page + (dst_offs >> PAGE_SHIFT)) +
+ (dst_offs & ~PAGE_MASK);
+
+ if (((src_offs & ~PAGE_MASK) == 0) &&
+ ((dst_offs & ~PAGE_MASK) == 0) &&
+ (src_len >= PAGE_SIZE) && (dst_len >= PAGE_SIZE) &&
+ (copy_len >= PAGE_SIZE)) {
+ copy_page(daddr, saddr);
+ n = PAGE_SIZE;
+ } else {
+ n = min_t(size_t, PAGE_SIZE - (dst_offs & ~PAGE_MASK),
+ PAGE_SIZE - (src_offs & ~PAGE_MASK));
+ n = min(n, src_len);
+ n = min(n, dst_len);
+ n = min_t(size_t, n, copy_len);
+ memcpy(daddr, saddr, n);
+ }
+ dst_offs += n;
+ src_offs += n;
+
+ kunmap_atomic(saddr);
+ kunmap_atomic(daddr);
+
+ res += n;
+ copy_len -= n;
+ if (copy_len == 0)
+ goto out;
+
+ src_len -= n;
+ dst_len -= n;
+ if (dst_len == 0) {
+ dst_sg = sg_next(dst_sg);
+ if (dst_sg == NULL)
+ goto out;
+ dst_page = sg_page(dst_sg);
+ dst_len = dst_sg->length;
+ dst_offs = dst_sg->offset;
+ }
+ } while (src_len > 0);
+
+out:
+ *pdst_sg = dst_sg;
+ *pdst_len = dst_len;
+ *pdst_offs = dst_offs;
+ return res;
+}
+
+/**
+ * sg_copy - copy one SG vector to another
+ * @dst_sg: destination SG
+ * @src_sg: source SG
+ * @nents_to_copy: maximum number of entries to copy
+ * @copy_len: maximum amount of data to copy. If 0, then copy all.
+ *
+ * Description:
+ * Data from the source SG vector will be copied to the destination SG
+ * vector. End of the vectors will be determined by sg_next() returning
+ * NULL. Returns number of bytes copied.
+ */
+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
+ int nents_to_copy, size_t copy_len)
+{
+ int res = 0;
+ size_t dst_len, dst_offs;
+
+ if (copy_len == 0)
+ copy_len = 0x7FFFFFFF; /* copy all */
+
+ if (nents_to_copy == 0)
+ nents_to_copy = 0x7FFFFFFF; /* copy all */
+
+ dst_len = dst_sg->length;
+ dst_offs = dst_sg->offset;
+
+ do {
+ int copied = sg_copy_elem(&dst_sg, &dst_len, &dst_offs,
+ src_sg, copy_len);
+ copy_len -= copied;
+ res += copied;
+ if ((copy_len == 0) || (dst_sg == NULL))
+ goto out;
+
+ nents_to_copy--;
+ if (nents_to_copy == 0)
+ goto out;
+
+ src_sg = sg_next(src_sg);
+ } while (src_sg != NULL);
+
+out:
+ return res;
+}
+EXPORT_SYMBOL(sg_copy);
+422 -19
View File
@@ -244,6 +244,12 @@ static int vdisk_attach(struct scst_device *dev);
static void vdisk_detach(struct scst_device *dev);
static int vdisk_attach_tgt(struct scst_tgt_dev *tgt_dev);
static void vdisk_detach_tgt(struct scst_tgt_dev *tgt_dev);
static int vdisk_get_supported_opcodes(struct scst_cmd *cmd,
const struct scst_opcode_descriptor ***out_supp_opcodes,
int *out_supp_opcodes_cnt);
static int vcdrom_get_supported_opcodes(struct scst_cmd *cmd,
const struct scst_opcode_descriptor ***out_supp_opcodes,
int *out_supp_opcodes_cnt);
static int fileio_alloc_data_buf(struct scst_cmd *cmd);
static int vdisk_parse(struct scst_cmd *);
static int vcdrom_parse(struct scst_cmd *);
@@ -265,6 +271,7 @@ 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);
static enum compl_status_e nullio_exec_verify(struct vdisk_cmd_params *p);
static enum compl_status_e vdisk_exec_read_capacity(struct vdisk_cmd_params *p);
static enum compl_status_e vdisk_exec_read_capacity16(struct vdisk_cmd_params *p);
static enum compl_status_e vdisk_exec_get_lba_status(struct vdisk_cmd_params *p);
@@ -564,6 +571,7 @@ static struct scst_dev_type vdisk_file_devtype = {
.exec = vdisk_exec,
.on_free_cmd = fileio_on_free_cmd,
.task_mgmt_fn_done = vdisk_task_mgmt_fn_done,
.get_supported_opcodes = vdisk_get_supported_opcodes,
.devt_priv = (void *)fileio_ops,
#ifdef CONFIG_SCST_PROC
.read_proc = vdisk_read_proc,
@@ -612,6 +620,7 @@ static struct scst_dev_type vdisk_blk_devtype = {
.parse = non_fileio_parse,
.exec = non_fileio_exec,
.task_mgmt_fn_done = vdisk_task_mgmt_fn_done,
.get_supported_opcodes = vdisk_get_supported_opcodes,
.devt_priv = (void *)blockio_ops,
#ifndef CONFIG_SCST_PROC
.add_device = vdisk_add_blockio_device,
@@ -654,6 +663,7 @@ static struct scst_dev_type vdisk_null_devtype = {
.exec = non_fileio_exec,
.task_mgmt_fn_done = vdisk_task_mgmt_fn_done,
.devt_priv = (void *)nullio_ops,
.get_supported_opcodes = vdisk_get_supported_opcodes,
#ifndef CONFIG_SCST_PROC
.add_device = vdisk_add_nullio_device,
.del_device = vdisk_del_device,
@@ -693,6 +703,7 @@ static struct scst_dev_type vcdrom_devtype = {
.exec = vcdrom_exec,
.on_free_cmd = fileio_on_free_cmd,
.task_mgmt_fn_done = vdisk_task_mgmt_fn_done,
.get_supported_opcodes = vcdrom_get_supported_opcodes,
#ifdef CONFIG_SCST_PROC
.read_proc = vcdrom_read_proc,
.write_proc = vcdrom_write_proc,
@@ -1397,8 +1408,314 @@ static enum compl_status_e vdisk_invalid_opcode(struct vdisk_cmd_params *p)
return INVALID_OPCODE;
}
#define VDEV_DEF_RDPROTECT 0
#define VDEV_DEF_WRPROTECT 0
#define VDEV_DEF_VRPROTECT 0
#define VDEF_DEF_GROUP_NUM 0
static const struct scst_opcode_descriptor scst_op_descr_cwr = {
.od_opcode = COMPARE_AND_WRITE,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { COMPARE_AND_WRITE, VDEV_DEF_WRPROTECT | 0x18,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0, 0, 0, 0xFF, VDEF_DEF_GROUP_NUM,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_format_unit = {
.od_opcode = FORMAT_UNIT,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_LONG_TIMEOUT/HZ,
.od_cdb_usage_bits = { FORMAT_UNIT, 0xF0, 0, 0, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_get_lba_status = {
.od_opcode = SERVICE_ACTION_IN,
.od_serv_action = SAI_GET_LBA_STATUS,
.od_serv_action_valid = 1,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { SERVICE_ACTION_IN, SAI_GET_LBA_STATUS,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_allow_medium_removal = {
.od_opcode = ALLOW_MEDIUM_REMOVAL,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 3, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_read6 = {
.od_opcode = READ_6,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { READ_6, 0x1F,
0xFF, 0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_read10 = {
.od_opcode = READ_10,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { READ_10, VDEV_DEF_RDPROTECT | 0x18,
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM,
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_read12 = {
.od_opcode = READ_12,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { READ_12, VDEV_DEF_RDPROTECT | 0x18,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
VDEF_DEF_GROUP_NUM, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_read16 = {
.od_opcode = READ_16,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { READ_16, VDEV_DEF_RDPROTECT | 0x18,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_read_capacity = {
.od_opcode = READ_CAPACITY,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { READ_CAPACITY, 0, 0, 0, 0, 0, 0,
0, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_read_capacity16 = {
.od_opcode = SERVICE_ACTION_IN,
.od_serv_action = SAI_READ_CAPACITY_16,
.od_serv_action_valid = 1,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { SERVICE_ACTION_IN, SAI_READ_CAPACITY_16,
0, 0, 0, 0, 0, 0, 0, 0,
0xFF, 0xFF, 0xFF, 0xFF, 0,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_start_stop_unit = {
.od_opcode = START_STOP,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { START_STOP, 1, 0, 0xF, 0xF7, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_sync_cache10 = {
.od_opcode = SYNCHRONIZE_CACHE,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { SYNCHRONIZE_CACHE, 2,
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM,
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_sync_cache16 = {
.od_opcode = SYNCHRONIZE_CACHE_16,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { SYNCHRONIZE_CACHE_16, 2,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_unmap = {
.od_opcode = UNMAP,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { UNMAP, 0, 0, 0, 0, 0, VDEF_DEF_GROUP_NUM,
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_verify10 = {
.od_opcode = VERIFY,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { VERIFY, VDEV_DEF_VRPROTECT | 0x16,
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM,
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_verify12 = {
.od_opcode = VERIFY_12,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { VERIFY_12, VDEV_DEF_VRPROTECT | 0x16,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
VDEF_DEF_GROUP_NUM, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_verify16 = {
.od_opcode = VERIFY_16,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { VERIFY_16, VDEV_DEF_VRPROTECT | 0x16,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write6 = {
.od_opcode = WRITE_6,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_6, 0x1F,
0xFF, 0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write10 = {
.od_opcode = WRITE_10,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_10, VDEV_DEF_WRPROTECT | 0x1A,
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM,
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write12 = {
.od_opcode = WRITE_12,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_12, VDEV_DEF_WRPROTECT | 0x1A,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
VDEF_DEF_GROUP_NUM, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write16 = {
.od_opcode = WRITE_16,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_16, VDEV_DEF_WRPROTECT | 0x1A,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write_verify10 = {
.od_opcode = WRITE_VERIFY,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_VERIFY, VDEV_DEF_WRPROTECT | 0x16,
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM,
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write_verify12 = {
.od_opcode = WRITE_VERIFY_12,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_VERIFY_12, VDEV_DEF_WRPROTECT | 0x16,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
VDEF_DEF_GROUP_NUM, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write_verify16 = {
.od_opcode = WRITE_VERIFY_16,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_VERIFY_16, VDEV_DEF_WRPROTECT | 0x16,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write_same10 = {
.od_opcode = WRITE_SAME,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_SAME, VDEV_DEF_WRPROTECT | 0x8,
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM,
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_write_same16 = {
.od_opcode = WRITE_SAME_16,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 16,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { WRITE_SAME_16, VDEV_DEF_WRPROTECT | 0x8,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, VDEF_DEF_GROUP_NUM,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
static const struct scst_opcode_descriptor scst_op_descr_read_toc = {
.od_opcode = READ_TOC,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_REG_TIMEOUT/HZ,
.od_cdb_usage_bits = { READ_TOC, 0, 0xF, 0, 0, 0, 0xFF,
0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
#define SHARED_OPS \
[SYNCHRONIZE_CACHE] = vdisk_synchronize_cache, \
[SYNCHRONIZE_CACHE_16] = vdisk_synchronize_cache, \
[MODE_SENSE] = vdisk_exec_mode_sense, \
[MODE_SENSE_10] = vdisk_exec_mode_sense, \
[MODE_SELECT] = vdisk_exec_mode_select, \
@@ -1420,10 +1737,39 @@ static enum compl_status_e vdisk_invalid_opcode(struct vdisk_cmd_params *p)
[UNMAP] = vdisk_exec_unmap, \
[WRITE_SAME] = vdisk_exec_write_same, \
[WRITE_SAME_16] = vdisk_exec_write_same, \
[COMPARE_AND_WRITE] = vdisk_exec_caw, \
[MAINTENANCE_IN] = vdisk_exec_maintenance_in, \
[SEND_DIAGNOSTIC] = vdisk_exec_send_diagnostic, \
[FORMAT_UNIT] = vdisk_exec_format_unit,
#define SHARED_OPCODE_DESCRIPTORS \
&scst_op_descr_sync_cache10, \
&scst_op_descr_sync_cache16, \
&scst_op_descr_mode_sense6, \
&scst_op_descr_mode_sense10, \
&scst_op_descr_mode_select6, \
&scst_op_descr_mode_select10, \
&scst_op_descr_log_select, \
&scst_op_descr_log_sense, \
&scst_op_descr_start_stop_unit, \
&scst_op_descr_read_capacity, \
&scst_op_descr_send_diagnostic, \
&scst_op_descr_rtpg, \
&scst_op_descr_read6, \
&scst_op_descr_read10, \
&scst_op_descr_read12, \
&scst_op_descr_read16, \
&scst_op_descr_write6, \
&scst_op_descr_write10, \
&scst_op_descr_write12, \
&scst_op_descr_write16, \
&scst_op_descr_write_verify10, \
&scst_op_descr_write_verify12, \
&scst_op_descr_write_verify16, \
&scst_op_descr_verify10, \
&scst_op_descr_verify12, \
&scst_op_descr_verify16,
static vdisk_op_fn blockio_ops[256] = {
[READ_6] = blockio_exec_read,
[READ_10] = blockio_exec_read,
@@ -1451,7 +1797,6 @@ 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,
@@ -1473,9 +1818,52 @@ static vdisk_op_fn nullio_ops[256] = {
[WRITE_VERIFY] = nullio_exec_write_verify,
[WRITE_VERIFY_12] = nullio_exec_write_verify,
[WRITE_VERIFY_16] = nullio_exec_write_verify,
[VERIFY] = nullio_exec_verify,
[VERIFY_12] = nullio_exec_verify,
[VERIFY_16] = nullio_exec_verify,
SHARED_OPS
};
#define VDISK_OPCODE_DESCRIPTORS \
/* &scst_op_descr_get_lba_status, */ \
&scst_op_descr_read_capacity16, \
&scst_op_descr_write_same10, \
&scst_op_descr_write_same16, \
&scst_op_descr_unmap, \
&scst_op_descr_format_unit, \
&scst_op_descr_cwr,
static const struct scst_opcode_descriptor *vdisk_opcode_descriptors[] = {
SHARED_OPCODE_DESCRIPTORS
VDISK_OPCODE_DESCRIPTORS
SCST_OPCODE_DESCRIPTORS
};
static const struct scst_opcode_descriptor *vcdrom_opcode_descriptors[] = {
SHARED_OPCODE_DESCRIPTORS
&scst_op_descr_allow_medium_removal,
&scst_op_descr_read_toc,
SCST_OPCODE_DESCRIPTORS
};
static int vdisk_get_supported_opcodes(struct scst_cmd *cmd,
const struct scst_opcode_descriptor ***out_supp_opcodes,
int *out_supp_opcodes_cnt)
{
*out_supp_opcodes = vdisk_opcode_descriptors;
*out_supp_opcodes_cnt = ARRAY_SIZE(vdisk_opcode_descriptors);
return 0;
}
static int vcdrom_get_supported_opcodes(struct scst_cmd *cmd,
const struct scst_opcode_descriptor ***out_supp_opcodes,
int *out_supp_opcodes_cnt)
{
*out_supp_opcodes = vcdrom_opcode_descriptors;
*out_supp_opcodes_cnt = ARRAY_SIZE(vcdrom_opcode_descriptors);
return 0;
}
/*
* Compute p->loff and p->fua.
* Returns true for success or false otherwise and set error in the commeand.
@@ -2248,9 +2636,9 @@ static int vdisk_unmap_range(struct scst_cmd *cmd,
(unsigned long long)start_lba, (unsigned long long)blocks);
if (virt_dev->blockio) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)
sector_t start_sector = start_lba << (cmd->dev->block_shift - 9);
sector_t nr_sects = blocks << (cmd->dev->block_shift - 9);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)
struct inode *inode = fd->f_dentry->d_inode;
gfp_t gfp = cmd->cmd_gfp_mask;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)
@@ -3530,6 +3918,7 @@ out:
static enum compl_status_e vdisk_exec_get_lba_status(struct vdisk_cmd_params *p)
{
/* Changing it don't forget to add it to vdisk_opcode_descriptors! */
return INVALID_OPCODE;
}
@@ -4237,7 +4626,11 @@ static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua)
bios++;
need_new_bio = 0;
bio->bi_end_io = blockio_endio;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
bio->bi_iter.bi_sector = lba_start0 << (block_shift - 9);
#else
bio->bi_sector = lba_start0 << (block_shift - 9);
#endif
bio->bi_bdev = bdev;
bio->bi_private = blockio_work;
/*
@@ -4262,6 +4655,14 @@ static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua)
bio->bi_rw |= REQ_FUA;
if (cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) || \
defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 6
bio->bi_rw |= REQ_SYNC;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
bio->bi_rw |= 1 << BIO_RW_SYNCIO;
#else
bio->bi_rw |= 1 << BIO_RW_SYNC;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) || \
defined(RHEL_MAJOR) && RHEL_MAJOR -0 >= 6
bio->bi_rw |= REQ_META;
@@ -4469,8 +4870,10 @@ static ssize_t blockio_rw_sync(struct scst_vdisk_dev *virt_dev, void *buf,
{
DECLARE_COMPLETION_ONSTACK(c);
struct block_device *bdev = virt_dev->bdev;
const bool is_vmalloc = is_vmalloc_addr(buf);
struct bio *bio;
void *p;
struct page *q;
int max_nr_vecs, rc;
unsigned bytes, off;
ssize_t ret = -ENOMEM;
@@ -4497,8 +4900,9 @@ static ssize_t blockio_rw_sync(struct scst_vdisk_dev *virt_dev, void *buf,
#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);
bytes = min_t(size_t, PAGE_SIZE - off, buf + len - p);
q = is_vmalloc ? vmalloc_to_page(p) : virt_to_page(p);
rc = bio_add_page(bio, q, bytes, off);
if (WARN_ON_ONCE(rc < bytes))
goto free;
}
@@ -4566,7 +4970,7 @@ static ssize_t vdev_read_sync(struct scst_vdisk_dev *virt_dev, void *buf,
if (virt_dev->nullio)
return len;
else if (virt_dev->blockio)
return blockio_rw_sync(virt_dev, buf, len, loff, 0/*read*/);
return blockio_rw_sync(virt_dev, buf, len, loff, READ_SYNC);
else
return fileio_read_sync(virt_dev->fd, buf, len, loff);
}
@@ -4574,21 +4978,12 @@ static ssize_t vdev_read_sync(struct scst_vdisk_dev *virt_dev, void *buf,
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) {
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 {
else if (virt_dev->blockio)
return blockio_rw_sync(virt_dev, buf, len, loff, WRITE_SYNC);
else
return fileio_write_sync(virt_dev->fd, buf, len, loff);
}
}
static enum compl_status_e vdev_exec_verify(struct vdisk_cmd_params *p)
@@ -4725,7 +5120,10 @@ static enum compl_status_e vdisk_exec_caw(struct vdisk_cmd_params *p)
goto out;
}
WARN_ON_ONCE(length != 2 * data_len);
if (length != 2 * data_len) {
scst_set_invalid_field_in_cdb(cmd, 13, 0);
goto out;
}
loff = p->loff;
read = vdev_read_sync(virt_dev, read_buf, data_len, &loff);
@@ -4806,6 +5204,11 @@ static enum compl_status_e nullio_exec_write_verify(struct vdisk_cmd_params *p)
return CMD_SUCCEEDED;
}
static enum compl_status_e nullio_exec_verify(struct vdisk_cmd_params *p)
{
return CMD_SUCCEEDED;
}
static void vdisk_task_mgmt_fn_done(struct scst_mgmt_cmd *mcmd,
struct scst_tgt_dev *tgt_dev)
{
+244 -8
View File
@@ -88,6 +88,240 @@ static int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
static void scst_free_descriptors(struct scst_cmd *cmd);
const struct scst_opcode_descriptor scst_op_descr_inquiry = {
.od_opcode = INQUIRY,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { INQUIRY, 1, 0xFF, 0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_inquiry);
const struct scst_opcode_descriptor scst_op_descr_tur = {
.od_opcode = TEST_UNIT_READY,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { TEST_UNIT_READY, 0, 0, 0, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_tur);
const struct scst_opcode_descriptor scst_op_descr_log_select = {
.od_opcode = LOG_SELECT,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { LOG_SELECT, 3, 0xFF, 0xFF, 0, 0, 0, 0xFF, 0xFF,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_log_select);
const struct scst_opcode_descriptor scst_op_descr_log_sense = {
.od_opcode = LOG_SENSE,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { LOG_SENSE, 1, 0xFF, 0xFF, 0, 0xFF, 0xFF, 0xFF, 0xFF,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_log_sense);
const struct scst_opcode_descriptor scst_op_descr_mode_select6 = {
.od_opcode = MODE_SELECT,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MODE_SELECT, 0x11, 0, 0, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_mode_select6);
const struct scst_opcode_descriptor scst_op_descr_mode_sense6 = {
.od_opcode = MODE_SENSE,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MODE_SENSE, 8, 0xFF, 0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_mode_sense6);
const struct scst_opcode_descriptor scst_op_descr_mode_select10 = {
.od_opcode = MODE_SELECT_10,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MODE_SELECT_10, 0x11, 0, 0, 0, 0, 0, 0xFF, 0xFF,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_mode_select10);
const struct scst_opcode_descriptor scst_op_descr_mode_sense10 = {
.od_opcode = MODE_SENSE_10,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MODE_SENSE_10, 0x18, 0xFF, 0xFF, 0, 0, 0, 0xFF, 0xFF,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_mode_sense10);
const struct scst_opcode_descriptor scst_op_descr_rtpg = {
.od_opcode = MAINTENANCE_IN,
.od_serv_action = MI_REPORT_TARGET_PGS,
.od_serv_action_valid = 1,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MAINTENANCE_IN, 0xE0|MI_REPORT_TARGET_PGS, 0, 0,
0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_rtpg);
const struct scst_opcode_descriptor scst_op_descr_stpg = {
.od_opcode = MAINTENANCE_OUT,
.od_serv_action = MO_SET_TARGET_PGS,
.od_serv_action_valid = 1,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MAINTENANCE_IN, MO_SET_TARGET_PGS, 0, 0, 0, 0,
0xFF, 0xFF, 0xFF, 0xFF, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_stpg);
const struct scst_opcode_descriptor scst_op_descr_send_diagnostic = {
.od_opcode = SEND_DIAGNOSTIC,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { SEND_DIAGNOSTIC, 0xF7, 0, 0xFF, 0xFF,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_send_diagnostic);
const struct scst_opcode_descriptor scst_op_descr_reserve6 = {
.od_opcode = RESERVE,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { RESERVE, 0, 0, 0, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_reserve6);
const struct scst_opcode_descriptor scst_op_descr_release6 = {
.od_opcode = RELEASE,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { RELEASE, 0, 0, 0, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_release6);
const struct scst_opcode_descriptor scst_op_descr_reserve10 = {
.od_opcode = RESERVE_10,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { RESERVE_10, 0, 0, 0, 0, 0, 0, 0, 0,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_reserve10);
const struct scst_opcode_descriptor scst_op_descr_release10 = {
.od_opcode = RELEASE_10,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { RELEASE_10, 0, 0, 0, 0, 0, 0, 0, 0,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_release10);
const struct scst_opcode_descriptor scst_op_descr_pr_in = {
.od_opcode = PERSISTENT_RESERVE_IN,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { PERSISTENT_RESERVE_IN, 0x1F, 0, 0, 0, 0, 0, 0xFF, 0xFF,
SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_pr_in);
const struct scst_opcode_descriptor scst_op_descr_pr_out = {
.od_opcode = PERSISTENT_RESERVE_OUT,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 10,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { PERSISTENT_RESERVE_OUT, 0x1F, 0xFF, 0, 0, 0xFF,
0xFF, 0xFF, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_pr_out);
const struct scst_opcode_descriptor scst_op_descr_report_luns = {
.od_opcode = REPORT_LUNS,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { REPORT_LUNS, 0, 0xFF, 0, 0, 0, 0xFF, 0xFF,
0xFF, 0xFF, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_report_luns);
const struct scst_opcode_descriptor scst_op_descr_request_sense = {
.od_opcode = REQUEST_SENSE,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 6,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { REQUEST_SENSE, 1, 0, 0, 0xFF, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_request_sense);
const struct scst_opcode_descriptor scst_op_descr_report_supp_tm_fns = {
.od_opcode = MAINTENANCE_IN,
.od_serv_action = MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS,
.od_serv_action_valid = 1,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MAINTENANCE_IN, MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS,
0x80, 0, 0, 0, 0xFF, 0xFF, 0xFF,
0xFF, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_report_supp_tm_fns);
const struct scst_opcode_descriptor scst_op_descr_report_supp_opcodes = {
.od_opcode = MAINTENANCE_IN,
.od_serv_action = MI_REPORT_SUPPORTED_OPERATION_CODES,
.od_serv_action_valid = 1,
.od_support = 3, /* supported as in the standard */
.od_cdb_size = 12,
.od_nominal_timeout = SCST_DEFAULT_NOMINAL_TIMEOUT_SEC,
.od_recommended_timeout = SCST_GENERIC_DISK_SMALL_TIMEOUT/HZ,
.od_cdb_usage_bits = { MAINTENANCE_IN, MI_REPORT_SUPPORTED_OPERATION_CODES,
0x87, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0, SCST_OD_DEFAULT_CONTROL_BYTE },
};
EXPORT_SYMBOL(scst_op_descr_report_supp_opcodes);
struct scst_sdbops;
static int get_cdb_info_len_10(struct scst_cmd *cmd,
@@ -122,7 +356,7 @@ static int get_cdb_info_verify16(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops);
static int get_cdb_info_len_1(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops);
static int get_cdb_info_lba_2_len_1_256(struct scst_cmd *cmd,
static int get_cdb_info_lba_3_len_1_256(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops);
static int get_cdb_info_bidi_lba_4_len_2(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops);
@@ -313,9 +547,9 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
SCST_TEST_IO_IN_SIRQ_ALLOWED|
#endif
SCST_WRITE_EXCL_ALLOWED,
.info_lba_off = 2, .info_lba_len = 2,
.info_lba_off = 1, .info_lba_len = 3,
.info_len_off = 4, .info_len_len = 1,
.get_cdb_info = get_cdb_info_lba_2_len_1_256},
.get_cdb_info = get_cdb_info_lba_3_len_1_256},
{.ops = 0x08, .devkey = " MV O OV ",
.info_op_name = "READ(6)",
.info_data_direction = SCST_DATA_READ,
@@ -343,9 +577,9 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
SCST_TEST_IO_IN_SIRQ_ALLOWED|
#endif
SCST_WRITE_MEDIUM,
.info_lba_off = 2, .info_lba_len = 2,
.info_lba_off = 1, .info_lba_len = 3,
.info_len_off = 4, .info_len_len = 1,
.get_cdb_info = get_cdb_info_lba_2_len_1_256},
.get_cdb_info = get_cdb_info_lba_3_len_1_256},
{.ops = 0x0A, .devkey = " M O OV ",
.info_op_name = "WRITE(6)",
.info_data_direction = SCST_DATA_WRITE,
@@ -6618,10 +6852,11 @@ static int get_cdb_info_len_1(struct scst_cmd *cmd,
return 0;
}
static int get_cdb_info_lba_2_len_1_256(struct scst_cmd *cmd,
static int get_cdb_info_lba_3_len_1_256(struct scst_cmd *cmd,
const struct scst_sdbops *sdbops)
{
cmd->lba = get_unaligned_be16(cmd->cdb + sdbops->info_lba_off);
cmd->lba = (cmd->cdb[sdbops->info_lba_off] & 0x1F) << 16;
cmd->lba |= get_unaligned_be16(cmd->cdb + sdbops->info_lba_off + 1);
/*
* From the READ(6) specification: a TRANSFER LENGTH field set to zero
* specifies that 256 logical blocks shall be read.
@@ -6900,7 +7135,8 @@ static int get_cdb_info_min(struct scst_cmd *cmd,
break;
case MI_REPORT_SUPPORTED_OPERATION_CODES:
cmd->op_name = "REPORT SUPPORTED OPERATION CODES";
cmd->op_flags |= SCST_WRITE_EXCL_ALLOWED;
cmd->op_flags |= SCST_WRITE_EXCL_ALLOWED |
SCST_LOCAL_CMD | SCST_FULLY_LOCAL_CMD;
break;
case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS:
cmd->op_name = "REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS";
+1 -1
View File
@@ -2201,7 +2201,7 @@ void scst_pr_preempt(struct scst_cmd *cmd, uint8_t *buffer, int buffer_size)
static void scst_cmd_done_pr_preempt(struct scst_cmd *cmd, int next_state,
enum scst_exec_context pref_context)
{
void (*saved_cmd_done) (struct scst_cmd *cmd, int next_state,
void (*saved_cmd_done)(struct scst_cmd *cmd, int next_state,
enum scst_exec_context pref_context);
TRACE_ENTRY();
+209 -4
View File
@@ -2111,6 +2111,208 @@ out_compl:
return res;
}
static int scst_report_supported_opcodes(struct scst_cmd *cmd)
{
int res = SCST_EXEC_COMPLETED;
int length, buf_len, i, offs;
uint8_t *address;
uint8_t *buf;
bool inline_buf;
bool rctd = cmd->cdb[2] >> 7;
int options = cmd->cdb[2] & 7;
int req_opcode = cmd->cdb[3];
int req_sa = get_unaligned_be16(&cmd->cdb[4]);
const struct scst_opcode_descriptor *op = NULL;
const struct scst_opcode_descriptor **supp_opcodes = NULL;
int supp_opcodes_cnt;
TRACE_ENTRY();
if (cmd->devt->get_supported_opcodes == NULL) {
TRACE(TRACE_MINOR, "Unknown opcode 0x%02x", cmd->cdb[0]);
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode));
goto out_compl;
} else {
int rc = cmd->devt->get_supported_opcodes(cmd, &supp_opcodes,
&supp_opcodes_cnt);
if (rc != 0)
goto out_compl;
}
TRACE_DBG("cmd %p, options %d, req_opcode %x, req_sa %x, rctd %d",
cmd, options, req_opcode, req_sa, rctd);
switch (options) {
case 0: /* all */
buf_len = 4;
for (i = 0; i < supp_opcodes_cnt; i++) {
buf_len += 8;
if (rctd)
buf_len += 12;
}
break;
case 1:
buf_len = 0;
for (i = 0; i < supp_opcodes_cnt; i++) {
if (req_opcode == supp_opcodes[i]->od_opcode) {
op = supp_opcodes[i];
if (op->od_serv_action_valid) {
TRACE(TRACE_MINOR, "Requested opcode %x "
"with unexpected service action "
"(dev %s, initiator %s)",
req_opcode, cmd->dev->virt_name,
cmd->sess->initiator_name);
scst_set_invalid_field_in_cdb(cmd, 2,
SCST_INVAL_FIELD_BIT_OFFS_VALID | 0);
goto out_compl;
}
buf_len = 4 + op->od_cdb_size;
if (rctd)
buf_len += 12;
break;
}
}
if (op == NULL) {
TRACE(TRACE_MINOR, "Requested opcode %x not found "
"(dev %s, initiator %s)", req_opcode,
cmd->dev->virt_name, cmd->sess->initiator_name);
buf_len = 4;
}
break;
case 2:
buf_len = 0;
for (i = 0; i < supp_opcodes_cnt; i++) {
if (req_opcode == supp_opcodes[i]->od_opcode) {
op = supp_opcodes[i];
if (!op->od_serv_action_valid) {
TRACE(TRACE_MINOR, "Requested opcode %x "
"without expected service action "
"(dev %s, initiator %s)",
req_opcode, cmd->dev->virt_name,
cmd->sess->initiator_name);
scst_set_invalid_field_in_cdb(cmd, 2,
SCST_INVAL_FIELD_BIT_OFFS_VALID | 0);
goto out_compl;
}
if (req_sa != op->od_serv_action) {
op = NULL; /* reset it */
continue;
}
buf_len = 4 + op->od_cdb_size;
if (rctd)
buf_len += 12;
break;
}
}
if (op == NULL) {
TRACE(TRACE_MINOR, "Requested opcode %x/%x not found "
"(dev %s, initiator %s)", req_opcode, req_sa,
cmd->dev->virt_name, cmd->sess->initiator_name);
buf_len = 4;
}
break;
default:
PRINT_ERROR("REPORT SUPPORTED OPERATION CODES: REPORTING OPTIONS "
"%x not supported (dev %s, initiator %s)", options,
cmd->dev->virt_name, cmd->sess->initiator_name);
scst_set_invalid_field_in_cdb(cmd, 2,
SCST_INVAL_FIELD_BIT_OFFS_VALID | 0);
goto out_compl;
}
length = scst_get_buf_full_sense(cmd, &address);
TRACE_DBG("length %d, buf_len %d, op %p", length, buf_len, op);
if (unlikely(length <= 0))
goto out_compl;
if (length >= buf_len) {
buf = address;
inline_buf = true;
} else {
buf = vmalloc(buf_len); /* it can be big */
if (buf == NULL) {
PRINT_ERROR("Unable to allocate REPORT SUPPORTED "
"OPERATION CODES buffer with size %d", buf_len);
scst_set_busy(cmd);
goto out_err_put;
}
inline_buf = false;
}
memset(buf, 0, buf_len);
switch (options) {
case 0: /* all */
put_unaligned_be32(buf_len - 3, &buf[0]);
offs = 4;
for (i = 0; i < supp_opcodes_cnt; i++) {
op = supp_opcodes[i];
buf[offs] = op->od_opcode;
if (op->od_serv_action_valid) {
put_unaligned_be16(op->od_serv_action, &buf[offs + 2]);
buf[offs + 5] |= 1;
}
put_unaligned_be16(op->od_cdb_size, &buf[offs + 6]);
offs += 8;
if (rctd) {
buf[(offs - 8) + 5] |= 2;
buf[offs + 1] = 0xA;
buf[offs + 3] = op->od_comm_specific_timeout;
put_unaligned_be32(op->od_nominal_timeout, &buf[offs + 4]);
put_unaligned_be32(op->od_recommended_timeout, &buf[offs + 8]);
offs += 12;
}
}
break;
case 1:
case 2:
if (op != NULL) {
buf[1] |= op->od_support;
put_unaligned_be16(op->od_cdb_size, &buf[2]);
memcpy(&buf[4], op->od_cdb_usage_bits, op->od_cdb_size);
if (rctd) {
buf[1] |= 0x80;
offs = 4 + op->od_cdb_size;
buf[offs + 1] = 0xA;
buf[offs + 3] = op->od_comm_specific_timeout;
put_unaligned_be32(op->od_nominal_timeout, &buf[offs + 4]);
put_unaligned_be32(op->od_recommended_timeout, &buf[offs + 8]);
}
}
break;
default:
sBUG_ON(1);
goto out_compl;
}
if (length > buf_len)
length = buf_len;
if (!inline_buf) {
memcpy(address, buf, length);
vfree(buf);
}
scst_put_buf_full(cmd, address);
if (length < cmd->resp_data_len)
scst_set_resp_data_len(cmd, length);
out_compl:
if ((supp_opcodes != NULL) && (cmd->devt->put_supported_opcodes != NULL))
cmd->devt->put_supported_opcodes(cmd, supp_opcodes, supp_opcodes_cnt);
cmd->completed = 1;
/* Report the result */
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME);
TRACE_EXIT_RES(res);
return res;
out_err_put:
scst_put_buf_full(cmd, address);
goto out_compl;
}
static int scst_maintenance_in(struct scst_cmd *cmd)
{
int res;
@@ -2121,6 +2323,9 @@ static int scst_maintenance_in(struct scst_cmd *cmd)
case MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS:
res = scst_report_supported_tm_fns(cmd);
break;
case MI_REPORT_SUPPORTED_OPERATION_CODES:
res = scst_report_supported_opcodes(cmd);
break;
default:
res = SCST_EXEC_NOT_COMPLETED;
break;
@@ -6880,7 +7085,7 @@ restart:
*/
struct scst_session *scst_register_session(struct scst_tgt *tgt, int atomic,
const char *initiator_name, void *tgt_priv, void *result_fn_data,
void (*result_fn) (struct scst_session *sess, void *data, int result))
void (*result_fn)(struct scst_session *sess, void *data, int result))
{
struct scst_session *sess;
int res;
@@ -6978,7 +7183,7 @@ EXPORT_SYMBOL(scst_register_session_non_gpl);
* Otherwise, your target driver could wait for those commands forever.
*/
void scst_unregister_session(struct scst_session *sess, int wait,
void (*unreg_done_fn) (struct scst_session *sess))
void (*unreg_done_fn)(struct scst_session *sess))
{
unsigned long flags;
DECLARE_COMPLETION_ONSTACK(c);
@@ -7191,8 +7396,8 @@ static struct scst_cmd *__scst_find_cmd_by_tag(struct scst_session *sess,
* Returns the command on success or NULL otherwise.
*/
struct scst_cmd *scst_find_cmd(struct scst_session *sess, void *data,
int (*cmp_fn) (struct scst_cmd *cmd,
void *data))
int (*cmp_fn)(struct scst_cmd *cmd,
void *data))
{
struct scst_cmd *cmd = NULL;
unsigned long flags = 0;
+2
View File
@@ -0,0 +1,2 @@
obj-$(CONFIG_SCST_LOCAL) += scst_local.o
@@ -741,7 +741,7 @@ sub luns {
close $lHandle;
return (\%luns, undef);
return \%luns;
}
sub aluaAttributes {
+2 -2
View File
@@ -3414,11 +3414,11 @@ sub listAttributes {
my $found = FALSE;
foreach my $attribute (keys %{$attributes}) {
foreach my $attribute (sort keys %{$attributes}) {
my $first = TRUE;
if (defined($$attributes{$attribute}->{'keys'})) {
foreach my $key (keys %{$$attributes{$attribute}->{'keys'}}) {
foreach my $key (sort keys %{$$attributes{$attribute}->{'keys'}}) {
my $value = $$attributes{$attribute}->{'keys'}->{$key}->{'value'};
my $static = ($$attributes{$attribute}->{'static'}) ? 'No' : 'Yes';
$value = '<not set>' if ($value eq '');
+44 -17
View File
@@ -1,11 +1,10 @@
SCSI RDMA Protocol (SRP) Target driver for Linux
=================================================
The SRP target driver has been designed to work on top of the Linux
InfiniBand kernel drivers -- either the InfiniBand drivers included
with a Linux distribution or the OFED InfiniBand drivers. For more
information about using the SRP target driver in combination with
OFED, see also README.ofed.
The SRP target driver has been designed to work on top of the Linux RDMA
kernel drivers -- either the RDMA drivers included with a Linux distribution
or the OFED RDMA drivers. For more information about using the SRP target
driver in combination with OFED, see also README.ofed.
The SRP target driver has been implemented as an SCST driver. This
makes it possible to support a lot of I/O modes on real and virtual
@@ -30,9 +29,13 @@ Installation
Building and installing the SRP target driver is possible as follows:
cd ${SCST_DIR}
make -s scst_clean scst scst_install
make -s srpt_clean srpt srpt_install
make -s scstadm scstadm_install
if type -p rpm >/dev/null; then
make -s rpm
sudo rpm -U rpmbuilddir/RPMS/*/*rpm scstadmin/rpmbuilddir/RPMS/*/*rpm
else
make -s scst_clean srpt_clean scst srpt scstadmin
sudo make -s scst_install srpt_install scstadm_install
fi
The ib_srpt kernel module supports the following parameters:
* one_target_per_port (boolean) and
@@ -48,6 +51,11 @@ The ib_srpt kernel module supports the following parameters:
use_node_guid_in_target_name are false. Mode (2) is choosen if
one_target_per_port is false and use_node_guid_in_target_name is true. Mode
(3) is choosen if one_target_per_port is true.
* rdma_cm_port (number)
A 16-bit number that specifies the port number to be registered via the
RDMA/CM. Must be specified to make communication over RoCE or iWARP
possible. If this parameter is zero (the default value) the SRP target
driver does not register with the RDMA/CM.
* srp_max_req_size (number)
Maximum size of an SRP control message in bytes. Examples of SRP control
messages are: login request, logout request, data transfer request, ...
@@ -109,6 +117,11 @@ Now verify that loading the configuration from file works correctly:
/etc/init.d/scst reload
Note: when using InfiniBand loading the ib_ipoib kernel module and assigning
an IP address to each IPoIB interface is only needed when using the RDMA/CM.
When using the IB/CM however, it is allowed but not necessary to load the
ib_ipoib kernel module.
Configuring the SRP Initiator System
------------------------------------
@@ -117,7 +130,8 @@ First of all, load the SRP kernel module as follows:
modprobe ib_srp
Next, discover the new SRP target by running the srp_daemon command:
Next, when using InfiniBand, discover the new SRP target by running the
srp_daemon command:
for d in /dev/infiniband/umad*; do srp_daemon -oacd$d; done
@@ -138,7 +152,20 @@ The meaning of the parameters in the above command is as follows:
* pkey: IB partition key (P_Key) of the target to connect to.
* service_id: must match ioc_guid.
Target GIDs can be queried e.g. via sysfs:
When using RoCE or iWARP, log in to the target system to determine the id_ext
and ioc_guid parameters and use these to log in. An example:
[ target system ]
# sed 's/,\(pkey\|dgid\|ioc_guid\)=[^,]*//g' $(find /sys/kernel/scst_tgt/targets/ib_srpt -name login_info) | uniq
id_ext=0002c90300a34270,ioc_guid=0002c90300a34270
[ initiator system ]
echo dest=192.168.5.1:5000,id_ext=0002c90300a34270,ioc_guid=0002c90300a34270
>/sys/class/infiniband_srp/srp-mlx4_0-1/add_target
echo dest=192.168.6.1:5000,id_ext=0002c90300a34270,ioc_guid=0002c90300a34270
>/sys/class/infiniband_srp/srp-mlx4_0-2/add_target
Initiator port GIDs can be queried e.g. via sysfs:
$ for f in /sys/devices/*/*/*/infiniband/*/ports/*/gids/0; do echo $f; \
cat $f | sed 's/://g'; done
@@ -166,9 +193,9 @@ Target names
The name assigned by the ib_srpt target driver to an SCST target is either
ib_srpt_target_<n>, the node GUID of a HCA in hexadecimal form with a colon
after every fourth digit or the port GUID with a colon afer every fourth
digit. The HCA node and port GUIDs can be obtained via the ibv_devinfo
command. An example:
after every fourth digit or the port GID with a colon afer every fourth
digit. The HCA node GUID and the port GIDs can be obtained via the
ibv_devinfo command. An example:
# ibv_devinfo -v | grep -E '[^a-z]port:|guid|GID'
node_guid: 0002:c903:0005:f34e
@@ -359,7 +386,8 @@ Performance Notes - Initiator Side
* The SRP initiator limits by default the queue depth to 64 commands. If your
workload benefits from a larger queue depth, enlarge the queue depth by
setting the max_cmd_per_lun parameter in the SRP login string.
setting the max_cmd_per_lun and queue_size parameters in the SRP login
string.
* The following parameters have a small but measurable impact on SRP
performance:
@@ -372,7 +400,7 @@ Performance Notes - Both Sides
------------------------------
* Disabling CONFIG_SCHED_DEBUG and CONFIG_SCHEDSTATS in the kernel config
helps.
improves performance.
* Disable CONFIG_IRQSOFF_TRACER such that CONFIG_TRACE_IRQFLAGS is disabled.
@@ -421,5 +449,4 @@ A: This means that you are using a system on which OFED has been installed but
Feedback
--------
Send questions about this driver to scst-devel@lists.sourceforge.net, CC:
Vu Pham <vuhuong@mellanox.com> and Bart Van Assche <bvanassche@acm.org>.
Send questions about this driver to scst-devel@lists.sourceforge.net.
+12
View File
@@ -0,0 +1,12 @@
diff --git a/Makefile b/Makefile
index 540f7b2..078307f 100644
--- a/Makefile
+++ b/Makefile
@@ -361,6 +361,7 @@ USERINCLUDE := \
# Use LINUXINCLUDE when you must reference the include/ directory.
# Needed to be compatible with the O= option
LINUXINCLUDE := \
+ $(PRE_CFLAGS) \
-I$(srctree)/arch/$(hdr-arch)/include \
-Iarch/$(hdr-arch)/include/generated \
$(if $(KBUILD_SRC), -I$(srctree)/include) \
+6 -7
View File
@@ -2,7 +2,8 @@
==============================
The following actions related to SRP sessions can all occur concurrently:
* IB communication manager (CM) invokes srpt_cm_handler().
* The communication manager invokes either srpt_ib_cm_handler() or
srpt_rdma_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.
@@ -11,7 +12,7 @@ The following actions related to SRP sessions can all occur concurrently:
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
- srpt_cm_req_recv() is invoked, 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
@@ -21,14 +22,12 @@ The actions that occur over the lifetime of a session are as follows:
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.
received or sent. A DREQ is sent 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_cm_drep_recv() and srpt_cm_timewait_exit() 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
+358 -230
View File
File diff suppressed because it is too large Load Diff
+34 -6
View File
@@ -41,6 +41,7 @@
#include <rdma/ib_verbs.h>
#include <rdma/ib_sa.h>
#include <rdma/ib_cm.h>
#include <rdma/rdma_cm.h>
#include <scsi/srp.h>
#if defined(INSIDE_KERNEL_TREE)
#include <scst/scst.h>
@@ -327,15 +328,22 @@ enum rdma_ch_state {
* @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.
* @pkey_index: P_Key index of the IB partition for this SRP channel.
* @pkey: P_Key of the IB partition for this SRP channel.
* @scst_sess: SCST session information associated with this SRP channel.
* @sess_name: SCST session name.
*/
struct srpt_rdma_ch {
struct task_struct *thread;
struct srpt_nexus *nexus;
struct ib_cm_id *cm_id;
struct ib_qp *qp;
union {
struct {
struct ib_cm_id *cm_id;
} ib_cm;
struct {
struct rdma_cm_id *cm_id;
} rdma_cm;
};
struct ib_cq *cq;
struct kref kref;
int rq_size;
@@ -354,7 +362,8 @@ struct srpt_rdma_ch {
enum rdma_ch_state state;
struct list_head list;
struct list_head cmd_wait_list;
uint16_t pkey_index;
uint16_t pkey;
bool using_rdma_cm;
bool processing_wait_list;
struct scst_session *scst_sess;
@@ -364,7 +373,7 @@ struct srpt_rdma_ch {
/**
* 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
* @ch_list: struct srpt_rdma_ch list. Protected by srpt_tgt.mutex.
* @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.
*/
@@ -378,14 +387,14 @@ struct srpt_nexus {
/**
* struct srpt_tgt
* @ch_releaseQ: Enables waiting for removal from nexus_list.
* @spinlock: Protects nexus_list.
* @mutex: Protects @nexus_list and srpt_nexus.ch_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 mutex mutex;
struct list_head nexus_list;
struct scst_tgt *scst_tgt;
bool enabled;
@@ -444,6 +453,25 @@ struct srpt_device {
struct srpt_tgt srpt_tgt;
};
/**
* struct srp_login_req_rdma - RDMA/CM login parameters.
*
* RDMA/CM over InfiniBand can only carry 92 - 36 = 56 bytes of private
* data. srp_login_req_rdma contains the same information as
* struct srp_login_req but with the reserved data removed.
*
* To do: Move this structure to <scsi/srp.h>.
*/
struct srp_login_req_rdma {
u64 tag;
__be16 req_buf_fmt;
u8 req_flags;
u8 opcode;
__be32 req_it_iu_len;
u8 initiator_port_id[16];
u8 target_port_id[16];
};
#endif /* IB_SRPT_H */
/*
+1
View File
@@ -335,6 +335,7 @@ static int do_exec(struct vdisk_cmd *vcmd)
}
break;
case SYNCHRONIZE_CACHE:
case SYNCHRONIZE_CACHE_16:
{
int immed = cdb[1] & 0x2;
if (data_len == 0)