diff --git a/Makefile b/Makefile index 01742ad63..3e3637749 100644 --- a/Makefile +++ b/Makefile @@ -19,19 +19,21 @@ SHELL = /bin/bash # Define the location to the kernel src. Can be defined here or on -# the command line during the build process. If KDIR is defined, -# we will set an appropriate value for KVER by running "make -# kernelversion" in the kernel source tree. KVER can still be -# overrode by the user via the command line or by defining it in -# this Makefile. If KDIR and KVER are not defined by the user, -# the current running kernel version is used to define KVER. +# the command line during the build process. If KDIR is defined, +# we will determine an appropriate value for KVER from the kernel +# source tree. KVER can still be overridden by the user via the +# command line or by defining it in this Makefile. If KDIR and KVER +# are not defined by the user, the current running kernel version is +# used to define KVER. #export KDIR=/usr/src/linux-2.6 #export KVER=2.6.x ifdef KDIR ifndef KVER - export KVER = $(strip $(shell make -s -C $(KDIR) kernelversion)) + export KVER = $(strip $(shell \ + cat $(KDIR)/include/config/kernel.release 2>/dev/null || \ + make -s -C $(KDIR) kernelversion)) endif endif @@ -49,7 +51,6 @@ MVSAS_DIR=mvsas_tgt FCST_DIR=fcst ISCSI_DIR=iscsi-scst -#ISCSI_DESTDIR=../../../iscsi_scst_inst VERSION = $(shell echo -n "$$(sed -n 's/^\#define[[:blank:]]SCST_VERSION_NAME[[:blank:]]*\"\([^-]*\).*\"/\1/p' scst/include/scst_const.h)."; \ if svn info >/dev/null 2>&1; \ @@ -153,7 +154,7 @@ install: # @if [ -d $(QLA_ISP_DIR) ]; then cd $(QLA_ISP_DIR) && $(MAKE) $@; fi # @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi # @if [ -d $(SRP_DIR) ]; then cd $(SRP_DIR) && $(MAKE) $@; fi - @if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) DESTDIR=$(ISCSI_DESTDIR) $@; fi + @if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) $@; fi @if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi @if [ -d $(SCST_LOCAL_DIR) ]; then cd $(SCST_LOCAL_DIR) && $(MAKE) $@; fi @@ -271,7 +272,7 @@ iscsi: cd $(ISCSI_DIR) && $(MAKE) all iscsi_install: - cd $(ISCSI_DIR) && $(MAKE) DESTDIR=$(ISCSI_DESTDIR) install + cd $(ISCSI_DIR) && $(MAKE) install iscsi_uninstall: cd $(ISCSI_DIR) && $(MAKE) uninstall @@ -388,7 +389,6 @@ scst-rpm: rpmtopdir="$$(if [ $$(id -u) = 0 ]; then echo /usr/src/packages;\ else echo $$PWD/rpmbuilddir; fi)" && \ $(MAKE) scst-dist-gzip && \ - rm -rf $${rpmtopdir} && \ for d in BUILD RPMS SOURCES SPECS SRPMS; do \ mkdir -p $${rpmtopdir}/$$d; \ done && \ diff --git a/fcst/Makefile b/fcst/Makefile index c82997771..5939c958a 100644 --- a/fcst/Makefile +++ b/fcst/Makefile @@ -26,19 +26,6 @@ # - install and uninstall must be made as root # -ifndef PREFIX - PREFIX=/usr/local -endif - -ifeq ($(KVER),) - ifeq ($(KDIR),) - KVER = $(shell uname -r) - KDIR := /lib/modules/$(KVER)/build - endif -else - KDIR := /lib/modules/$(KVER)/build -endif - export PWD := $(shell pwd) export CONFIG_FCST := m @@ -55,16 +42,39 @@ EXTRA_CFLAGS += -I$(SCST_INC_DIR) $(FCSTFLAGS$(BUILDMODE)) MODULE_NAME = fcst -INSTALL_DIR := /lib/modules/$(KVER)/extra - ifneq ($(KERNELRELEASE),) include $(SUBDIRS)/Makefile_in-tree else +######### BEGIN OUT-OF-TREE RULES ######### + +ifndef PREFIX + PREFIX=/usr/local +endif + +ifeq ($(KVER),) + ifeq ($(KDIR),) + KVER := $(shell uname -r) + KDIR := /lib/modules/$(KVER)/build + else + KVER := $(strip $(shell \ + cat $(KDIR)/include/config/kernel.release 2>/dev/null || \ + make -s -C $(KDIR) kernelversion)) + endif +else + KDIR := /lib/modules/$(KVER)/build +endif + +ifeq ($(INSTALL_MOD_PATH),) + export INSTALL_MOD_PATH := $(DESTDIR) +endif + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra + SCST_INC_DIR := $(shell if [ -e "$$PWD/../scst" ]; \ then echo "$$PWD/../scst/include"; \ - else echo "$(PREFIX)/include/scst"; fi) + else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi) SCST_DIR := $(shell if [ -e "$$PWD/../scst" ]; then echo "$$PWD/../scst/src"; \ - else echo "$(PREFIX)/include/scst"; fi) + else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi) all: Modules.symvers Module.symvers $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ @@ -77,7 +87,6 @@ tgt: Modules.symvers Module.symvers install: all $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ SCST_INC_DIR=$(SCST_INC_DIR) modules_install - -depmod -a $(KVER) ins: ./config @@ -102,7 +111,9 @@ endif uninstall: rm -f $(INSTALL_DIR)/$(MODULE_NAME).ko - -/sbin/depmod -a $(KVER) + -/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER) + +########## END OUT-OF-TREE RULES ########## endif clean: diff --git a/ibmvstgt/Makefile b/ibmvstgt/Makefile index bcfa95657..daaf57f4e 100644 --- a/ibmvstgt/Makefile +++ b/ibmvstgt/Makefile @@ -7,15 +7,27 @@ SUBDIRS := $(shell pwd) ifeq ($(KVER),) ifeq ($(KDIR),) - KVER = $(shell uname -r) - KDIR ?= /lib/modules/$(KVER)/build + KVER := $(shell uname -r) + KDIR := /lib/modules/$(KVER)/build else - KVER = $$KERNELRELEASE + ifeq ($(KERNELRELEASE),) + KVER := $(strip $(shell \ + cat $(KDIR)/include/config/kernel.release 2>/dev/null || \ + make -s -C $(KDIR) kernelversion)) + else + KVER := $(KERNELRELEASE) + endif endif else - KDIR ?= /lib/modules/$(KVER)/build + KDIR := /lib/modules/$(KVER)/build endif +ifeq ($(INSTALL_MOD_PATH),) + export INSTALL_MOD_PATH := $(DESTDIR) +endif + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra + # The file Modules.symvers has been renamed in the 2.6.18 kernel to # Module.symvers. Find out which name to use by looking in $(KDIR). MODULE_SYMVERS:=$(shell if [ -e $(KDIR)/Module.symvers ]; then \ @@ -26,11 +38,11 @@ all: src/$(MODULE_SYMVERS) $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/src modules install: all src/ibmvstgt.ko - @eval `sed -n 's/#define UTS_RELEASE /KERNELRELEASE=/p' $(KDIR)/include/linux/version.h $(KDIR)/include/linux/utsrelease.h 2>/dev/null`; \ - for m in libsrp.ko ibmvstgt.ko; do \ - install -vD -m 644 src/$$m \ - $(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra/$$m; done - -/sbin/depmod -aq $(KVER) + $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/src modules_install + +uninstall: + rm -f $(INSTALL_DIR)/libsrp.ko $(INSTALL_DIR)/ibmvstgt.ko + -/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER) src/Module.symvers src/Modules.symvers: $(SCST_DIR)/$(MODULE_SYMVERS) cp $< $@; diff --git a/ibmvstgt/README.sysfs b/ibmvstgt/README.sysfs index 1ffc5ad35..cd27fe19a 100644 --- a/ibmvstgt/README.sysfs +++ b/ibmvstgt/README.sysfs @@ -32,6 +32,17 @@ more information): 2:0:0:0 ram000 ram001 ram002 ram003 ram004 ram005 ram006 ram007 ram008 ram009 ram010 ram011 ram012 ram013 ram014 ram015 +Next, set the vendor ID, product ID etc. fields via sysfs. These fields +must be set to the following values to allow AIX initiators to recognize +SCST devices: +* The Vendor ID (t10_vend_id) must be set to "IBM". +* The Product ID (prod_id) must be set either to "VDASD blkdev" for SCSI disks + or "VOPTA blkdev" for a SCSI CD-ROM. +* The Product Revision Level (prod_rev_lvl) must be set to "0001". +* The Vendor Specific Information in the INQUIRY response (inq_vend_specific) + must be set to the serial number. The serial number is available in the + "usn" sysfs attribute. + After this step a LUN has to be assigned to each exported SCSI device. Some non-Linux initiator operating systems only accept LUN numbes that are multiples of 256 and require that the LUN addressing method is used. diff --git a/ibmvstgt/src/ibmvstgt.c b/ibmvstgt/src/ibmvstgt.c index 39d2eaa1a..1dd4dbc7e 100644 --- a/ibmvstgt/src/ibmvstgt.c +++ b/ibmvstgt/src/ibmvstgt.c @@ -1069,28 +1069,6 @@ static void handle_crq(struct work_struct *work) } } -static void ibmvstgt_get_product_id(const struct scst_tgt_dev *tgt_dev, - char *buf, const int size) -{ - WARN_ON(size != 16); - - /* - * AIX uses hardcoded device names. The AIX SCSI initiator even won't - * work unless we use the names VDASD and VOPTA. - */ - switch (tgt_dev->dev->type) { - case TYPE_DISK: - memcpy(buf, "VDASD blkdev ", 16); - break; - case TYPE_ROM: - memcpy(buf, "VOPTA blkdev ", 16); - break; - default: - snprintf(buf, size, "(devtype %d) ", tgt_dev->dev->type); - break; - } -} - /* * Extract target, bus and LUN information from a 64-bit LUN in CPU-order. */ @@ -1236,12 +1214,8 @@ static struct scst_tgt_template ibmvstgt_template = { #else .sg_tablesize = SCSI_MAX_SG_SEGMENTS, #endif - .vendor = "IBM ", - .revision = "0001", .fake_aca = true, - .get_product_id = ibmvstgt_get_product_id, .get_serial = ibmvstgt_get_serial, - .get_vend_specific = ibmvstgt_get_serial, #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) .default_trace_flags = DEFAULT_IBMVSTGT_TRACE_FLAGS, diff --git a/iscsi-scst/Makefile b/iscsi-scst/Makefile index ed288354c..aa2053136 100644 --- a/iscsi-scst/Makefile +++ b/iscsi-scst/Makefile @@ -15,9 +15,9 @@ SUBDIRS := $(shell pwd) SCST_INC_DIR := $(shell if [ -e "$$PWD/../scst" ]; \ then echo "$$PWD/../scst/include"; \ - else echo "$(PREFIX)/include/scst"; fi) + else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi) SCST_DIR := $(shell if [ -e "$$PWD/../scst" ]; then echo "$$PWD/../scst/src"; \ - else echo "$(PREFIX)/include/scst"; fi) + else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi) SBINDIR := $(PREFIX)/sbin INITDIR := /etc/init.d RCDIR := /etc/rc.d @@ -28,15 +28,27 @@ ISERTMOD := $(KMOD)/isert-scst ifeq ($(KVER),) ifeq ($(KDIR),) - KVER = $(shell uname -r) - KDIR ?= /lib/modules/$(KVER)/build + KVER := $(shell uname -r) + KDIR := /lib/modules/$(KVER)/build else - KVER = $$KERNELRELEASE + ifeq ($(KERNELRELEASE),) + KVER := $(strip $(shell \ + cat $(KDIR)/include/config/kernel.release 2>/dev/null || \ + make -s -C $(KDIR) kernelversion)) + else + KVER := $(KERNELRELEASE) + endif endif else - KDIR ?= /lib/modules/$(KVER)/build + KDIR := /lib/modules/$(KVER)/build endif +ifeq ($(INSTALL_MOD_PATH),) + export INSTALL_MOD_PATH := $(DESTDIR) +endif + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra + all: include/iscsi_scst_itf_ver.h progs mods ISER_SYMVERS:=$(KMOD)/Module.symvers @@ -99,12 +111,20 @@ install: all @install -vD -m 644 doc/manpages/iscsi-scstd.8 $(DESTDIR)$(MANDIR)/man8/iscsi-scstd.8 @install -vD -m 755 usr/iscsi-scst-adm $(DESTDIR)$(SBINDIR)/iscsi-scst-adm @install -vD -m 644 doc/manpages/iscsi-scst-adm.8 $(DESTDIR)$(MANDIR)/man8/iscsi-scst-adm.8 - @eval `sed -n 's/#define UTS_RELEASE /KERNELRELEASE=/p' $(KDIR)/include/linux/version.h $(KDIR)/include/linux/utsrelease.h 2>/dev/null`; \ - install -vD -m 644 kernel/iscsi-scst.ko \ - $(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra/iscsi-scst.ko - install -vD -m 644 kernel/isert-scst/isert-scst.ko \ - $(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra/isert-scst.ko - -/sbin/depmod -aq $(KVER) + $(MAKE) -C $(KDIR) SCST_INC_DIR=$(SCST_INC_DIR) SUBDIRS=$(KMOD) \ + modules_install + $(MAKE) -C $(KDIR) SCST_INC_DIR=$(SCST_INC_DIR) SUBDIRS=$(ISERTMOD) \ + modules_install + +uninstall: + rm -f $(DESTDIR)$(SBINDIR)/iscsi-scstd \ + $(DESTDIR)$(MANDIR)/man5/iscsi-scstd.conf.5 \ + $(DESTDIR)$(MANDIR)/man8/iscsi-scstd.8 \ + $(DESTDIR)$(SBINDIR)/iscsi-scst-adm \ + $(DESTDIR)$(MANDIR)/man8/iscsi-scst-adm.8 \ + $(INSTALL_DIR)/iscsi-scst.ko \ + $(INSTALL_DIR)/isert-scst.ko + -/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER) SCST_MOD_VERS := $(shell ls $(SCST_DIR)/Modules.symvers 2>/dev/null) ifneq ($(SCST_MOD_VERS),) diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index 33e73f064..fb8d153ec 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -1584,6 +1584,8 @@ static int cmnd_prepare_recv_pdu(struct iscsi_conn *conn, buff_offs = offset; idx = (offset + sg[0].offset) >> PAGE_SHIFT; + if (offset + sg[0].offset >= PAGE_SIZE) + offset += sg[0].offset; offset &= ~PAGE_MASK; conn->read_msg.msg_iov = conn->read_iov; diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index 09e3a8cc2..04d6875a8 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -1403,6 +1403,8 @@ retry: if (sg != write_cmnd->rsp_sg) { offset = conn->write_offset + sg[0].offset; idx = offset >> PAGE_SHIFT; + if (offset + sg[0].offset >= PAGE_SIZE) + offset += sg[0].offset; offset &= ~PAGE_MASK; length = min(size, (int)PAGE_SIZE - offset); TRACE_WRITE("write_offset %d, sg_size %d, idx %d, offset %d, " diff --git a/iscsi-scst/kernel/patches/put_page_callback-3.10.30.patch b/iscsi-scst/kernel/patches/put_page_callback-3.10.30.patch new file mode 100644 index 000000000..6470f52fc --- /dev/null +++ b/iscsi-scst/kernel/patches/put_page_callback-3.10.30.patch @@ -0,0 +1,420 @@ +diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c +index 4222aff..0d2ac7d 100644 +--- a/drivers/block/drbd/drbd_receiver.c ++++ b/drivers/block/drbd/drbd_receiver.c +@@ -130,7 +130,7 @@ static int page_chain_free(struct page *page) + struct page *tmp; + int i = 0; + page_chain_for_each_safe(page, tmp) { +- put_page(page); ++ net_put_page(page); + ++i; + } + return i; +diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c +index 9e56eb4..74fe728 100644 +--- a/drivers/net/macvtap.c ++++ b/drivers/net/macvtap.c +@@ -527,7 +527,7 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from, + int j; + + for (j = 0; j < num_pages; j++) +- put_page(page[i + j]); ++ net_put_page(page[i + j]); + return -EFAULT; + } + truesize = size * PAGE_SIZE; +diff --git a/drivers/net/tun.c b/drivers/net/tun.c +index 5824971..83e0eaa 100644 +--- a/drivers/net/tun.c ++++ b/drivers/net/tun.c +@@ -1013,7 +1013,7 @@ static int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from, + int j; + + for (j = 0; j < num_pages; j++) +- put_page(page[i + j]); ++ net_put_page(page[i + j]); + return -EFAULT; + } + truesize = size * PAGE_SIZE; +diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c +index 55a62ca..dcb9fdf 100644 +--- a/drivers/net/vmxnet3/vmxnet3_drv.c ++++ b/drivers/net/vmxnet3/vmxnet3_drv.c +@@ -1360,7 +1360,7 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_queue *rq, + rq->buf_info[ring_idx][i].page) { + pci_unmap_page(adapter->pdev, rxd->addr, + rxd->len, PCI_DMA_FROMDEVICE); +- put_page(rq->buf_info[ring_idx][i].page); ++ net_put_page(rq->buf_info[ring_idx][i].page); + rq->buf_info[ring_idx][i].page = NULL; + } + } +diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c +index 36efb41..019681c 100644 +--- a/drivers/net/xen-netback/netback.c ++++ b/drivers/net/xen-netback/netback.c +@@ -1292,7 +1292,7 @@ static void xen_netbk_fill_frags(struct xen_netbk *netbk, struct sk_buff *skb) + skb->truesize += txp->size; + + /* Take an extra reference to offset xen_netbk_idx_release */ +- get_page(netbk->mmap_pages[pending_idx]); ++ net_get_page(netbk->mmap_pages[pending_idx]); + xen_netbk_idx_release(netbk, pending_idx, XEN_NETIF_RSP_OKAY); + } + } +@@ -1774,7 +1774,7 @@ static void xen_netbk_idx_release(struct xen_netbk *netbk, u16 pending_idx, + } while (!pending_tx_is_head(netbk, peek)); + + netbk->mmap_pages[pending_idx]->mapping = 0; +- put_page(netbk->mmap_pages[pending_idx]); ++ net_put_page(netbk->mmap_pages[pending_idx]); + netbk->mmap_pages[pending_idx] = NULL; + } + +diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h +index 10a9a17..1a01f46 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -177,6 +177,17 @@ struct page { + #ifdef LAST_NID_NOT_IN_PAGE_FLAGS + int _last_nid; + #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 +diff --git a/include/linux/net.h b/include/linux/net.h +index 65545ac..288d185 100644 +--- a/include/linux/net.h ++++ b/include/linux/net.h +@@ -19,6 +19,7 @@ + #define _LINUX_NET_H + + #include ++#include + #include + #include + #include /* For O_CLOEXEC and O_NONBLOCK */ +@@ -278,6 +279,45 @@ extern int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg); + extern 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)) + +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index ded45ec..b5c6dda 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2075,7 +2075,7 @@ static inline struct page *skb_frag_page(const skb_frag_t *frag) + */ + static inline void __skb_frag_ref(skb_frag_t *frag) + { +- get_page(skb_frag_page(frag)); ++ net_get_page(skb_frag_page(frag)); + } + + /** +@@ -2098,7 +2098,7 @@ static inline void skb_frag_ref(struct sk_buff *skb, int f) + */ + static inline void __skb_frag_unref(skb_frag_t *frag) + { +- put_page(skb_frag_page(frag)); ++ net_put_page(skb_frag_page(frag)); + } + + /** +diff --git a/net/Kconfig b/net/Kconfig +index 2ddc904..ec9bfbd 100644 +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -74,6 +74,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" +diff --git a/net/ceph/pagevec.c b/net/ceph/pagevec.c +index 815a224..f53c802 100644 +--- a/net/ceph/pagevec.c ++++ b/net/ceph/pagevec.c +@@ -51,7 +51,7 @@ void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty) + 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); + } +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 20ee14d..e3734cf 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -427,7 +427,7 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, + 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, +@@ -473,7 +473,7 @@ static void skb_clone_fraglist(struct sk_buff *skb) + 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); + } +@@ -793,7 +793,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) + if (!page) { + while (head) { + struct page *next = (struct page *)head->private; +- put_page(head); ++ net_put_page(head); + head = next; + } + return -ENOMEM; +@@ -1629,7 +1629,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, +@@ -1682,7 +1682,7 @@ static bool spd_fill_page(struct splice_pipe_desc *spd, + 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; +@@ -2681,7 +2681,7 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, + 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); +diff --git a/net/core/sock.c b/net/core/sock.c +index 50a345e..f9fba8e 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -1804,7 +1804,7 @@ bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag) + } + if (pfrag->offset < pfrag->size) + return true; +- put_page(pfrag->page); ++ net_put_page(pfrag->page); + } + + /* We restrict high order allocations to users that can afford to wait */ +@@ -2505,7 +2505,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; + } + +diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile +index 089cb9f..bc38b0e 100644 +--- a/net/ipv4/Makefile ++++ b/net/ipv4/Makefile +@@ -52,6 +52,7 @@ obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o + 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 +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index 6ca5873..014503d2 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -1006,7 +1006,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, +@@ -1227,7 +1227,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, + 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; +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index 1a2e249..b512ddc 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -897,7 +897,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; +@@ -1193,7 +1193,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; + } +diff --git a/net/ipv4/tcp_zero_copy.c b/net/ipv4/tcp_zero_copy.c +new file mode 100644 +index 0000000..99d41fa +--- /dev/null ++++ b/net/ipv4/tcp_zero_copy.c +@@ -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 ++#include ++ ++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); +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index b98b8e0..2df0fda 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1432,7 +1432,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, +-- +1.8.4.5 + diff --git a/iscsi-scst/kernel/patches/put_page_callback-3.12.11.patch b/iscsi-scst/kernel/patches/put_page_callback-3.12.11.patch new file mode 100644 index 000000000..41658111f --- /dev/null +++ b/iscsi-scst/kernel/patches/put_page_callback-3.12.11.patch @@ -0,0 +1,407 @@ +diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c +index cc29cd3..ba34c70 100644 +--- a/drivers/block/drbd/drbd_receiver.c ++++ b/drivers/block/drbd/drbd_receiver.c +@@ -130,7 +130,7 @@ static int page_chain_free(struct page *page) + struct page *tmp; + int i = 0; + page_chain_for_each_safe(page, tmp) { +- put_page(page); ++ net_put_page(page); + ++i; + } + return i; +diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c +index 7e2788c..70d390c 100644 +--- a/drivers/net/vmxnet3/vmxnet3_drv.c ++++ b/drivers/net/vmxnet3/vmxnet3_drv.c +@@ -1369,7 +1369,7 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_queue *rq, + rq->buf_info[ring_idx][i].page) { + dma_unmap_page(&adapter->pdev->dev, rxd->addr, + rxd->len, PCI_DMA_FROMDEVICE); +- put_page(rq->buf_info[ring_idx][i].page); ++ net_put_page(rq->buf_info[ring_idx][i].page); + rq->buf_info[ring_idx][i].page = NULL; + } + } +diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c +index 6255850..12a6f14 100644 +--- a/drivers/net/xen-netback/netback.c ++++ b/drivers/net/xen-netback/netback.c +@@ -1055,7 +1055,7 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb) + skb->truesize += txp->size; + + /* Take an extra reference to offset xenvif_idx_release */ +- get_page(vif->mmap_pages[pending_idx]); ++ net_get_page(vif->mmap_pages[pending_idx]); + xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); + } + } +@@ -1525,7 +1525,7 @@ static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx, + + } while (!pending_tx_is_head(vif, peek)); + +- put_page(vif->mmap_pages[pending_idx]); ++ net_put_page(vif->mmap_pages[pending_idx]); + vif->mmap_pages[pending_idx] = NULL; + } + +diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h +index 8e082f1..15f10c8 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -177,6 +177,17 @@ struct page { + #ifdef LAST_NID_NOT_IN_PAGE_FLAGS + int _last_nid; + #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 +diff --git a/include/linux/net.h b/include/linux/net.h +index 41103f8..54c2bffb 100644 +--- a/include/linux/net.h ++++ b/include/linux/net.h +@@ -19,6 +19,7 @@ + #define _LINUX_NET_H + + #include ++#include + #include + #include + #include /* For O_CLOEXEC and O_NONBLOCK */ +@@ -278,6 +279,45 @@ extern int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg); + extern 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)) + +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index efa1649..5efff79 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -1975,7 +1975,7 @@ static inline struct page *skb_frag_page(const skb_frag_t *frag) + */ + static inline void __skb_frag_ref(skb_frag_t *frag) + { +- get_page(skb_frag_page(frag)); ++ net_get_page(skb_frag_page(frag)); + } + + /** +@@ -1998,7 +1998,7 @@ static inline void skb_frag_ref(struct sk_buff *skb, int f) + */ + static inline void __skb_frag_unref(skb_frag_t *frag) + { +- put_page(skb_frag_page(frag)); ++ net_put_page(skb_frag_page(frag)); + } + + /** +diff --git a/net/Kconfig b/net/Kconfig +index b50dacc..88ed9df 100644 +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -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" +diff --git a/net/ceph/pagevec.c b/net/ceph/pagevec.c +index 815a224..f53c802 100644 +--- a/net/ceph/pagevec.c ++++ b/net/ceph/pagevec.c +@@ -51,7 +51,7 @@ void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty) + 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); + } +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 2c7baa8..3196557 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -422,7 +422,7 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, + 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, +@@ -468,7 +468,7 @@ static void skb_clone_fraglist(struct sk_buff *skb) + 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); + } +@@ -793,7 +793,7 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) + if (!page) { + while (head) { + struct page *next = (struct page *)page_private(head); +- put_page(head); ++ net_put_page(head); + head = next; + } + return -ENOMEM; +@@ -1618,7 +1618,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, +@@ -1671,7 +1671,7 @@ static bool spd_fill_page(struct splice_pipe_desc *spd, + 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; +@@ -2675,7 +2675,7 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, + 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); +diff --git a/net/core/sock.c b/net/core/sock.c +index 5cec994..c756279 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -1847,7 +1847,7 @@ bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag) + } + if (pfrag->offset < pfrag->size) + return true; +- put_page(pfrag->page); ++ net_put_page(pfrag->page); + } + + /* We restrict high order allocations to users that can afford to wait */ +@@ -2599,7 +2599,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; + } + +diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile +index 4b81e91..b88113f 100644 +--- a/net/ipv4/Makefile ++++ b/net/ipv4/Makefile +@@ -53,6 +53,7 @@ obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o + 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 +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index 3982eab..d37f078 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -1003,7 +1003,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, +@@ -1224,7 +1224,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, + 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; +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c +index be5246e..a349ddd 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -896,7 +896,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; +@@ -1192,7 +1192,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; + } +diff --git a/net/ipv4/tcp_zero_copy.c b/net/ipv4/tcp_zero_copy.c +new file mode 100644 +index 0000000..430147e +--- /dev/null ++++ b/net/ipv4/tcp_zero_copy.c +@@ -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 ++#include ++ ++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); +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index b6fa35e..b6f3389 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1413,7 +1413,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, +diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c +index ae2e5c1..2ad9e87 100644 +--- a/net/netfilter/nfnetlink_queue_core.c ++++ b/net/netfilter/nfnetlink_queue_core.c +@@ -258,7 +258,7 @@ nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen) + 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; + } +-- +1.8.4.5 + diff --git a/iscsi-scst/kernel/patches/put_page_callback-3.13.3.patch b/iscsi-scst/kernel/patches/put_page_callback-3.13.3.patch new file mode 100644 index 000000000..19b900310 --- /dev/null +++ b/iscsi-scst/kernel/patches/put_page_callback-3.13.3.patch @@ -0,0 +1,403 @@ +=== modified file 'drivers/block/drbd/drbd_receiver.c' +--- old/drivers/block/drbd/drbd_receiver.c 2014-02-20 05:26:12 +0000 ++++ new/drivers/block/drbd/drbd_receiver.c 2014-02-20 05:35:42 +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 'drivers/net/vmxnet3/vmxnet3_drv.c' +--- old/drivers/net/vmxnet3/vmxnet3_drv.c 2014-02-20 05:26:12 +0000 ++++ new/drivers/net/vmxnet3/vmxnet3_drv.c 2014-02-20 05:35:42 +0000 +@@ -1369,7 +1369,7 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_que + rq->buf_info[ring_idx][i].page) { + dma_unmap_page(&adapter->pdev->dev, rxd->addr, + rxd->len, PCI_DMA_FROMDEVICE); +- put_page(rq->buf_info[ring_idx][i].page); ++ net_put_page(rq->buf_info[ring_idx][i].page); + rq->buf_info[ring_idx][i].page = NULL; + } + } + +=== modified file 'drivers/net/xen-netback/netback.c' +--- old/drivers/net/xen-netback/netback.c 2014-02-20 05:26:12 +0000 ++++ new/drivers/net/xen-netback/netback.c 2014-02-20 05:35:42 +0000 +@@ -1080,7 +1080,7 @@ static void xenvif_fill_frags(struct xen + skb->truesize += txp->size; + + /* Take an extra reference to offset xenvif_idx_release */ +- get_page(vif->mmap_pages[pending_idx]); ++ net_get_page(vif->mmap_pages[pending_idx]); + xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); + } + } +@@ -1760,7 +1760,7 @@ static void xenvif_idx_release(struct xe + + } while (!pending_tx_is_head(vif, peek)); + +- put_page(vif->mmap_pages[pending_idx]); ++ net_put_page(vif->mmap_pages[pending_idx]); + vif->mmap_pages[pending_idx] = NULL; + } + + +=== modified file 'include/linux/mm_types.h' +--- old/include/linux/mm_types.h 2014-02-20 05:26:12 +0000 ++++ new/include/linux/mm_types.h 2014-02-20 05:35:42 +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-02-20 05:26:12 +0000 ++++ new/include/linux/net.h 2014-02-20 05:35:42 +0000 +@@ -19,6 +19,7 @@ + #define _LINUX_NET_H + + #include ++#include + #include + #include + #include /* For O_CLOEXEC and O_NONBLOCK */ +@@ -295,6 +296,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-02-20 05:26:12 +0000 ++++ new/include/linux/skbuff.h 2014-02-20 05:35:42 +0000 +@@ -1974,7 +1974,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)); + } + + /** +@@ -1997,7 +1997,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-02-20 05:26:12 +0000 ++++ new/net/Kconfig 2014-02-20 05:35:42 +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-02-20 05:26:12 +0000 ++++ new/net/ceph/pagevec.c 2014-02-20 05:35:42 +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-02-20 05:26:12 +0000 ++++ new/net/core/skbuff.c 2014-02-20 05:35:42 +0000 +@@ -422,7 +422,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, +@@ -480,7 +480,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); + } +@@ -805,7 +805,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; +@@ -1648,7 +1648,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, +@@ -1701,7 +1701,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; +@@ -2716,7 +2716,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-02-20 05:26:12 +0000 ++++ new/net/core/sock.c 2014-02-20 05:35:42 +0000 +@@ -1862,7 +1862,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); + } + + /* We restrict high order allocations to users that can afford to wait */ +@@ -2624,7 +2624,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-02-20 05:26:12 +0000 ++++ new/net/ipv4/Makefile 2014-02-20 05:35:42 +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-02-20 05:26:12 +0000 ++++ new/net/ipv4/ip_output.c 2014-02-20 05:35:42 +0000 +@@ -1005,7 +1005,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, +@@ -1231,7 +1231,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-02-20 05:26:12 +0000 ++++ new/net/ipv4/tcp.c 2014-02-20 05:35:42 +0000 +@@ -898,7 +898,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; +@@ -1194,7 +1194,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-02-20 05:35:42 +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 ++#include ++ ++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-02-20 05:26:12 +0000 ++++ new/net/ipv6/ip6_output.c 2014-02-20 05:35:42 +0000 +@@ -1431,7 +1431,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, + +=== modified file 'net/netfilter/nfnetlink_queue_core.c' +--- old/net/netfilter/nfnetlink_queue_core.c 2014-02-20 05:26:12 +0000 ++++ new/net/netfilter/nfnetlink_queue_core.c 2014-02-20 05:35:42 +0000 +@@ -258,7 +258,7 @@ nfqnl_zcopy(struct sk_buff *to, const st + 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; + } + diff --git a/iscsi-scst/kernel/patches/put_page_callback-3.13.patch b/iscsi-scst/kernel/patches/put_page_callback-3.13.patch new file mode 100644 index 000000000..67aece596 --- /dev/null +++ b/iscsi-scst/kernel/patches/put_page_callback-3.13.patch @@ -0,0 +1,419 @@ +=== modified file 'drivers/block/drbd/drbd_receiver.c' +--- old/drivers/block/drbd/drbd_receiver.c 2014-01-30 00:25:53 +0000 ++++ new/drivers/block/drbd/drbd_receiver.c 2014-01-30 01:02:34 +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 'drivers/net/vmxnet3/vmxnet3_drv.c' +--- old/drivers/net/vmxnet3/vmxnet3_drv.c 2014-01-30 00:25:53 +0000 ++++ new/drivers/net/vmxnet3/vmxnet3_drv.c 2014-01-30 01:02:34 +0000 +@@ -1369,7 +1369,7 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_que + rq->buf_info[ring_idx][i].page) { + dma_unmap_page(&adapter->pdev->dev, rxd->addr, + rxd->len, PCI_DMA_FROMDEVICE); +- put_page(rq->buf_info[ring_idx][i].page); ++ net_put_page(rq->buf_info[ring_idx][i].page); + rq->buf_info[ring_idx][i].page = NULL; + } + } + +=== modified file 'drivers/net/xen-netback/netback.c' +--- old/drivers/net/xen-netback/netback.c 2014-01-30 00:25:53 +0000 ++++ new/drivers/net/xen-netback/netback.c 2014-01-30 01:02:34 +0000 +@@ -1080,7 +1080,7 @@ static void xenvif_fill_frags(struct xen + skb->truesize += txp->size; + + /* Take an extra reference to offset xenvif_idx_release */ +- get_page(vif->mmap_pages[pending_idx]); ++ net_get_page(vif->mmap_pages[pending_idx]); + xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); + } + } +@@ -1760,7 +1760,7 @@ static void xenvif_idx_release(struct xe + + } while (!pending_tx_is_head(vif, peek)); + +- put_page(vif->mmap_pages[pending_idx]); ++ net_put_page(vif->mmap_pages[pending_idx]); + vif->mmap_pages[pending_idx] = NULL; + } + + +=== modified file 'include/linux/mm_types.h' +--- old/include/linux/mm_types.h 2014-01-30 00:25:53 +0000 ++++ new/include/linux/mm_types.h 2014-01-30 01:02:34 +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-01-30 00:25:53 +0000 ++++ new/include/linux/net.h 2014-01-30 01:02:34 +0000 +@@ -19,6 +19,7 @@ + #define _LINUX_NET_H + + #include ++#include + #include + #include + #include /* For O_CLOEXEC and O_NONBLOCK */ +@@ -295,6 +296,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-01-30 00:25:53 +0000 ++++ new/include/linux/skbuff.h 2014-01-30 01:02:34 +0000 +@@ -1974,7 +1974,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)); + } + + /** +@@ -1997,7 +1997,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-01-30 00:25:53 +0000 ++++ new/net/Kconfig 2014-01-30 01:02:34 +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-01-30 00:25:53 +0000 ++++ new/net/ceph/pagevec.c 2014-01-30 01:02:34 +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-01-30 00:25:53 +0000 ++++ new/net/core/skbuff.c 2014-01-30 01:02:34 +0000 +@@ -77,13 +77,13 @@ static struct kmem_cache *skbuff_fclone_ + static void sock_pipe_buf_release(struct pipe_inode_info *pipe, + struct pipe_buffer *buf) + { +- put_page(buf->page); ++ net_put_page(buf->page); + } + + static void sock_pipe_buf_get(struct pipe_inode_info *pipe, + struct pipe_buffer *buf) + { +- get_page(buf->page); ++ net_get_page(buf->page); + } + + static int sock_pipe_buf_steal(struct pipe_inode_info *pipe, +@@ -452,7 +452,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, +@@ -510,7 +510,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); + } +@@ -835,7 +835,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; +@@ -1678,7 +1678,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, +@@ -1731,7 +1731,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; +@@ -2746,7 +2746,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-01-30 00:25:53 +0000 ++++ new/net/core/sock.c 2014-01-30 01:02:34 +0000 +@@ -1862,7 +1862,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); + } + + /* We restrict high order allocations to users that can afford to wait */ +@@ -2624,7 +2624,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-01-30 00:25:53 +0000 ++++ new/net/ipv4/Makefile 2014-01-30 01:02:34 +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-01-30 00:25:53 +0000 ++++ new/net/ipv4/ip_output.c 2014-01-30 01:02:34 +0000 +@@ -1005,7 +1005,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, +@@ -1231,7 +1231,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-01-30 00:25:53 +0000 ++++ new/net/ipv4/tcp.c 2014-01-30 01:02:34 +0000 +@@ -898,7 +898,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; +@@ -1194,7 +1194,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-01-30 01:02:34 +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 ++#include ++ ++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-01-30 00:25:53 +0000 ++++ new/net/ipv6/ip6_output.c 2014-01-30 01:02:34 +0000 +@@ -1431,7 +1431,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, + +=== modified file 'net/netfilter/nfnetlink_queue_core.c' +--- old/net/netfilter/nfnetlink_queue_core.c 2014-01-30 00:25:53 +0000 ++++ new/net/netfilter/nfnetlink_queue_core.c 2014-01-30 01:02:34 +0000 +@@ -258,7 +258,7 @@ nfqnl_zcopy(struct sk_buff *to, const st + 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; + } + diff --git a/mpt/Makefile b/mpt/Makefile index 13fc36172..957c39a1e 100644 --- a/mpt/Makefile +++ b/mpt/Makefile @@ -38,18 +38,33 @@ EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG ifeq ($(KVER),) ifeq ($(KDIR),) - KDIR := /lib/modules/$(shell uname -r)/build + KVER := $(shell uname -r) + KDIR := /lib/modules/$(KVER)/build + else + ifeq ($(KERNELRELEASE),) + KVER := $(strip $(shell \ + cat $(KDIR)/include/config/kernel.release 2>/dev/null || \ + make -s -C $(KDIR) kernelversion)) + else + KVER := $(KERNELRELEASE) + endif endif else KDIR := /lib/modules/$(KVER)/build endif +ifeq ($(INSTALL_MOD_PATH),) + export INSTALL_MOD_PATH := $(DESTDIR) +endif + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra LSI_INC_DIR := $(KDIR)/drivers/message/fusion EXTRA_CFLAGS += -I$(LSI_INC_DIR) ifneq ($(PATCHLEVEL),) obj-m += mpt_scst.o else +######### BEGIN OUT-OF-TREE RULES ######### all: Modules.symvers Module.symvers $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m @@ -60,7 +75,6 @@ tgt: Modules.symvers Module.symvers install: all $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ modules_install - -/sbin/depmod -a SCST_MOD_VERS := $(shell ls $(SCST_DIR)/Modules.symvers 2>/dev/null) ifneq ($(SCST_MOD_VERS),) @@ -81,7 +95,9 @@ endif uninstall: rm -f $(INSTALL_DIR)/mpt_scst.ko - -/sbin/depmod -a + -/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER) + +########## END OUT-OF-TREE RULES ########## endif clean: diff --git a/mvsas_tgt/Makefile b/mvsas_tgt/Makefile index 35b8a878a..5b4db8d9c 100644 --- a/mvsas_tgt/Makefile +++ b/mvsas_tgt/Makefile @@ -31,13 +31,25 @@ endif ifeq ($(KVER),) ifeq ($(KDIR),) - KVER = $(shell uname -r) + KVER := $(shell uname -r) KDIR := /lib/modules/$(KVER)/build + else + ifeq ($(KERNELRELEASE),) + KVER := $(strip $(shell \ + cat $(KDIR)/include/config/kernel.release 2>/dev/null || \ + make -s -C $(KDIR) kernelversion)) + else + KVER := $(KERNELRELEASE) + endif endif else KDIR := /lib/modules/$(KVER)/build endif +ifeq ($(INSTALL_MOD_PATH),) + export INSTALL_MOD_PATH := $(DESTDIR) +endif + export PWD := $(shell pwd) export LIBSAS := m @@ -49,11 +61,10 @@ SCST_DIR := $(shell pwd)/../scst/src EXTRA_CFLAGS += -I$(SCST_INC_DIR) EXTRA_CFLAGS += -DSUPPORT_TARGET -MODULE_NAME = mvsas_tgt EXTRA_CFLAGS += -DMV_DEBUG -INSTALL_DIR := /lib/modules/$(shell uname -r)/extra +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra #EXTRA_CFLAGS += -DCONFIG_SCST_TRACING #EXTRA_CFLAGS += -DDEBUG_WORK_IN_THREAD @@ -68,6 +79,8 @@ mvsas-y := mv_init.o \ mv_94xx.o \ mv_spi.o else +######### BEGIN OUT-OF-TREE RULES ######### + all: Modules.symvers Module.symvers $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m @@ -77,12 +90,11 @@ tgt: Modules.symvers Module.symvers install: all $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ modules_install - -depmod -a $(KVER) ins: ./config insmod mvsas.ko - + SCST_MOD_VERS := $(shell ls $(SCST_DIR)/Modules.symvers 2>/dev/null) ifneq ($(SCST_MOD_VERS),) Modules.symvers: $(SCST_DIR)/Modules.symvers @@ -101,8 +113,10 @@ else endif uninstall: - rm -f $(INSTALL_DIR)/$(MODULE_NAME).ko - -/sbin/depmod -a $(KVER) + rm -f $(INSTALL_DIR)/mvsas.ko + -/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER) + +########## END OUT-OF-TREE RULES ########## endif clean: diff --git a/mvsas_tgt/README b/mvsas_tgt/README index ab25f400e..314fedde4 100644 --- a/mvsas_tgt/README +++ b/mvsas_tgt/README @@ -100,7 +100,7 @@ note: 2. In example "add 2:0:0:0 1" the '1' is the LUN in the target, LUN 0 must exist with a target. 3. When one device is added to target disk group, target driver will notify - initator the changing of the phy mode and arriving of the disk, but some + initiator the changing of the phy mode and arriving of the disk, but some initiator driver don't support phy mode changing well, so 'rmmod' and 'modprobe'/'insmod' the initiator driver is neccessary. diff --git a/nightly/conf/nightly.conf b/nightly/conf/nightly.conf index b1486e905..1b8d709e1 100644 --- a/nightly/conf/nightly.conf +++ b/nightly/conf/nightly.conf @@ -3,15 +3,16 @@ ABT_DETAILS="x86_64" ABT_JOBS=5 ABT_KERNELS=" \ -3.12.9 \ +3.13.5 \ +3.12.13-nc \ 3.11.10-nc \ -3.10.28-nc \ +3.10.32-nc \ 3.9.11-nc \ 3.8.13-nc \ 3.7.10-nc \ 3.6.11-nc \ 3.5.7-nc \ -3.4.77-nc \ +3.4.81-nc \ 3.3.8-nc \ 3.2.53-nc \ 3.1.10-nc \ diff --git a/qla2x00t/Makefile b/qla2x00t/Makefile index 24e811095..ac628ce9b 100644 --- a/qla2x00t/Makefile +++ b/qla2x00t/Makefile @@ -16,6 +16,7 @@ extraclean: clean .PHONY: clean extraclean else +######### BEGIN OUT-OF-TREE RULES ######### SHELL=/bin/bash @@ -32,12 +33,23 @@ endif ifeq ($(KVER),) ifeq ($(KDIR),) - KDIR := /lib/modules/$(shell uname -r)/build + KVER := $(shell uname -r) + KDIR := /lib/modules/$(KVER)/build + else + KVER := $(strip $(shell \ + cat $(KDIR)/include/config/kernel.release 2>/dev/null || \ + make -s -C $(KDIR) kernelversion)) endif else KDIR := /lib/modules/$(KVER)/build endif +ifeq ($(INSTALL_MOD_PATH),) + export INSTALL_MOD_PATH := $(DESTDIR) +endif + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra + ifneq ($(PATCHLEVEL),) obj-m := qla2xxx_scst.o qla2xxx_scst-objs := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ @@ -50,11 +62,12 @@ all: install: all $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ modules_install - -/sbin/depmod -aq $(KVER) uninstall: - rm -f $(INSTALL_DIR)/qla2xxxt.ko - -/sbin/depmod -a $(KVER) + rm -f $(INSTALL_DIR)/qla2xxx_scst.ko + -/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER) + +########## END OUT-OF-TREE RULES ########## endif clean: diff --git a/qla2x00t/qla2x00-target/ChangeLog b/qla2x00t/qla2x00-target/ChangeLog index 587f02587..90bc489f9 100644 --- a/qla2x00t/qla2x00-target/ChangeLog +++ b/qla2x00t/qla2x00-target/ChangeLog @@ -159,7 +159,7 @@ Summary of changes between versions 0.9.3.4 and 0.9.3.5 ------------------------------------------------------- Patch vs: qla2xxx v8.01.03-k (in kernels 2.6.15.x) - - Reset chip when switching from initiator to initator/target and back + - Reset chip when switching from initiator to initiator/target and back implemented - Use 2K loop_id's for 23xx chips and thus change how sessions are diff --git a/qla2x00t/qla2x00-target/Makefile b/qla2x00t/qla2x00-target/Makefile index c2ec8a50d..7dbbf0117 100644 --- a/qla2x00t/qla2x00-target/Makefile +++ b/qla2x00t/qla2x00-target/Makefile @@ -27,16 +27,10 @@ # - install and uninstall must be made as root # -ifndef PREFIX - PREFIX=/usr/local -endif - SHELL=/bin/bash EXTRA_CFLAGS += -I$(SCST_INC_DIR) -INSTALL_DIR := /lib/modules/$(shell uname -r)/extra - EXTRA_CFLAGS += -W -Wno-unused-parameter -Wno-missing-field-initializers EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS @@ -47,13 +41,25 @@ EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions ifeq ($(KVER),) ifeq ($(KDIR),) - KVER = $(shell uname -r) + KVER := $(shell uname -r) KDIR := /lib/modules/$(KVER)/build + else + ifeq ($(KERNELRELEASE),) + KVER := $(strip $(shell \ + cat $(KDIR)/include/config/kernel.release 2>/dev/null || \ + make -s -C $(KDIR) kernelversion)) + else + KVER := $(KERNELRELEASE) + endif endif else KDIR := /lib/modules/$(KVER)/build endif +ifeq ($(INSTALL_MOD_PATH),) + export INSTALL_MOD_PATH := $(DESTDIR) +endif + ifeq ($(BUILD_2X_MODULE),) QLA2XXX_INC_DIR := $(KDIR)/drivers/scsi/qla2xxx else @@ -69,13 +75,20 @@ ifneq ($(PATCHLEVEL),) obj-m := qla2x00tgt.o qla2x00tgt-objs := qla2x00t.o else +######### BEGIN OUT-OF-TREE RULES ######### + +ifndef PREFIX + PREFIX=/usr/local +endif + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra SCST_INC_DIR := $(shell if [ -e "$$PWD/../../scst" ]; \ then echo "$$PWD/../../scst/include"; \ - else echo "$(PREFIX)/include/scst"; fi) + else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi) SCST_DIR := $(shell if [ -e "$$PWD/../../scst" ]; \ then echo "$$PWD/../../scst/src"; \ - else echo "$(PREFIX)/include/scst"; fi) + else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi) ifneq ($(BUILD_2X_MODULE),) # We need to make qla2xxx_scst before Module.symvers @@ -93,14 +106,13 @@ ifneq ($(BUILD_2X_MODULE),) endif $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ SCST_INC_DIR=$(SCST_INC_DIR) modules_install - -/sbin/depmod -a $(KVER) uninstall: ifneq ($(BUILD_2X_MODULE),) $(MAKE) SUBDIRS=$(QLA2XXX_DIR) -C $(QLA2XXX_DIR) $@ endif rm -f $(INSTALL_DIR)/qla2[23x]00tgt.ko - -/sbin/depmod -a $(KVER) + -/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER) ifneq ($(BUILD_2X_MODULE),) qla2xxx_scst: @@ -131,6 +143,7 @@ else .PHONY: Module.symvers endif +########## END OUT-OF-TREE RULES ########## endif clean: diff --git a/qla2x00t/qla2x00-target/Makefile_in-tree-3.13 b/qla2x00t/qla2x00-target/Makefile_in-tree-3.13 new file mode 100644 index 000000000..9657aee84 --- /dev/null +++ b/qla2x00t/qla2x00-target/Makefile_in-tree-3.13 @@ -0,0 +1,5 @@ +ccflags-y += -Idrivers/scsi/qla2xxx + +qla2x00tgt-y := qla2x00t.o + +obj-$(CONFIG_SCST_QLA_TGT_ADDON) += qla2x00tgt.o diff --git a/qla2x00t/qla_inline.h b/qla2x00t/qla_inline.h index 19820a804..9b5e618ef 100644 --- a/qla2x00t/qla_inline.h +++ b/qla2x00t/qla_inline.h @@ -36,9 +36,19 @@ qla2x00_poll(scsi_qla_host_t *ha) { unsigned long flags; +#ifdef CONFIG_PREEMPT_RT_FULL + local_irq_save_nort(flags); +#else local_irq_save(flags); +#endif + ha->isp_ops->intr_handler(0, ha); + +#ifdef CONFIG_PREEMPT_RT_FULL + local_irq_restore_nort(flags); +#else local_irq_restore(flags); +#endif } static __inline__ scsi_qla_host_t * diff --git a/qla2x00t/qla_os.c b/qla2x00t/qla_os.c index c37bc7b46..b2b105615 100644 --- a/qla2x00t/qla_os.c +++ b/qla2x00t/qla_os.c @@ -112,8 +112,8 @@ static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha); int ql2xfdmienable=1; module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xfdmienable, - "Enables FDMI registratons " - "Default is 0 - no FDMI. 1 - perfom FDMI."); + "Enables FDMI registrations " + "Default is 1 - perform FDMI. 0 - no FDMI."); #define MAX_Q_DEPTH 32 static int ql2xmaxqdepth = MAX_Q_DEPTH; diff --git a/qla_isp/README.scst b/qla_isp/README.scst index 9109f8ed2..f5de8f662 100644 --- a/qla_isp/README.scst +++ b/qla_isp/README.scst @@ -122,7 +122,7 @@ activating channels/LUNs in /proc/scsi_tgt/qla_isp/N . The driver can also work as both a target and an initiator simultaneously, but this will probably only function for P2P connections. To make the driver work -as a target/initator on one port with a FC switch, you can use N_PORT ID +as a target/initiator on one port with a FC switch, you can use N_PORT ID virtualization, as seen below. N_PORT ID VIRTUALIZATION diff --git a/scripts/blockdev-perftest b/scripts/blockdev-perftest index 4b1db9a1b..db240ef36 100755 --- a/scripts/blockdev-perftest +++ b/scripts/blockdev-perftest @@ -76,11 +76,11 @@ set_frequency_scaling() { if [ ! -e $syscpu/cpufreq ]; then return fi - local governor=$(<$syscpu/cpu0/cpufreq/scaling_governor) - local cpuinfo_min_freq=$(<$syscpu/cpu0/cpufreq/cpuinfo_min_freq) - local cpuinfo_max_freq=$(<$syscpu/cpu0/cpufreq/cpuinfo_max_freq) - local scaling_min_freq=$(<$syscpu/cpu0/cpufreq/scaling_min_freq) - local scaling_max_freq=$(<$syscpu/cpu0/cpufreq/scaling_max_freq) + local governor=$(cat $syscpu/cpu0/cpufreq/scaling_governor) + local cpuinfo_min_freq=$(cat $syscpu/cpu0/cpufreq/cpuinfo_min_freq) + local cpuinfo_max_freq=$(cat $syscpu/cpu0/cpufreq/cpuinfo_max_freq) + local scaling_min_freq=$(cat $syscpu/cpu0/cpufreq/scaling_min_freq) + local scaling_max_freq=$(cat $syscpu/cpu0/cpufreq/scaling_max_freq) if [ -w $syscpu/cpu0/cpufreq/scaling_governor ]; then for d in $syscpu/cpu*/cpufreq do @@ -210,7 +210,7 @@ if [ "${perform_write_test}" = "true" -a ! -w "${device}" ]; then fi if [ "${perform_read_test}" = "true" -a \ - "$(($(" "3.7.10" ]; - then echo iscsi-scst/kernel/patches/*-3.7.10.patch; - else echo iscsi-scst/kernel/patches/*-${kver}.patch; fi) + $(if [ ${kver} = 3.7 ] && [ "${1#3.7.}" -ge 10 ]; then + echo iscsi-scst/kernel/patches/*-3.7.10.patch; + elif [ ${kver} = 3.10 ] && [ "${1#3.10.}" -ge 30 ]; then + echo iscsi-scst/kernel/patches/*-3.10.30.patch; + elif [ ${kver} = 3.12 ] && [ "${1#3.12.}" -ge 11 ]; then + echo iscsi-scst/kernel/patches/*-3.12.11.patch; + elif [ ${kver} = 3.13 ] && [ "${1#3.13.}" -ge 3 ]; then + echo iscsi-scst/kernel/patches/*-3.13.3.patch; + else + echo iscsi-scst/kernel/patches/*-${kver}.patch; + fi) do # Exclude the put_page_callback patch when command-line option -u has been # specified since the current approach is not considered acceptable for diff --git a/scripts/kernel-functions b/scripts/kernel-functions index 7bfdf7133..0bc0584a9 100644 --- a/scripts/kernel-functions +++ b/scripts/kernel-functions @@ -172,6 +172,45 @@ Get rid of sparse errors on sk_buff.protocol. void (*destructor)(struct sk_buff *skb); #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) +EOF + fi + if [ "${1#3.13}" != "$1" ]; then + patch -f -s -p1 <<'EOF' +From 7b4ec8dd7d4ac467e9eee4d49f2c9574d773efbb Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Thu, 16 Jan 2014 10:18:48 +1030 +Subject: [PATCH] export: declare ksymtab symbols + +sparse complains about any __ksymtab symbols with the following: + + warning: symbol '__ksymtab_...' was not declared. Should it be static? + +due to Andi's patch making it non-static. + +Mollify sparse by declaring the symbol extern, otherwise we get +drowned in sparse warnings for anything that uses EXPORT_SYMBOL +in the sources, making it easy to miss real warnings. + +Fixes: e0f244c63fc9 ("asmlinkage, module: Make ksymtab [...] __visible") +Signed-off-by: Johannes Berg +Acked-by: Andi Kleen +Signed-off-by: Rusty Russell +--- + include/linux/export.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/linux/export.h b/include/linux/export.h +index 3f2793d..96e45ea 100644 +--- a/include/linux/export.h ++++ b/include/linux/export.h +@@ -59,6 +59,7 @@ extern struct module __this_module; + static const char __kstrtab_##sym[] \ + __attribute__((section("__ksymtab_strings"), aligned(1))) \ + = VMLINUX_SYMBOL_STR(sym); \ ++ extern const struct kernel_symbol __ksymtab_##sym; \ + __visible const struct kernel_symbol __ksymtab_##sym \ + __used \ + __attribute__((section("___ksymtab" sec "+" #sym), unused)) \ EOF fi ) diff --git a/scripts/list-source-files b/scripts/list-source-files index a14307b3b..4a2eed863 100755 --- a/scripts/list-source-files +++ b/scripts/list-source-files @@ -29,7 +29,13 @@ list_source_files() { echo "Ignored directory $1" >&2 fi elif [ -e "$r/.hg" ]; then - hg manifest + subdir="${d#${r}}" + if [ -n "${subdir}" ]; then + subdir="${subdir#/}/" + hg manifest | sed -n "s|^$subdir||p" + else + hg manifest + fi else echo "Not under source control: $1 ?" >&2 fi diff --git a/scst.spec.in b/scst.spec.in index 3608a72a9..579888487 100644 --- a/scst.spec.in +++ b/scst.spec.in @@ -71,11 +71,11 @@ done %install export KVER=%{kver} PREFIX=%{_prefix} MANDIR=%{_mandir} export BUILD_2X_MODULE=y CONFIG_SCSI_QLA_FC=y CONFIG_SCSI_QLA2XXX_TARGET=y -for d in scst iscsi-scst srpt; do +for d in scst; do DESTDIR=%{buildroot} %{make} -C $d install done -for d in fcst qla2x00t/qla2x00-target scst_local; do - INSTALL_MOD_PATH=%{buildroot} %{make} -C $d install +for d in fcst iscsi-scst qla2x00t/qla2x00-target scst_local srpt; do + DESTDIR=%{buildroot} INSTALL_MOD_PATH=%{buildroot} %{make} -C $d install done rm -f %{buildroot}/lib/modules/%{kver}/[Mm]odule* diff --git a/scst/ChangeLog b/scst/ChangeLog index 8e92bcc7f..949ddc4a9 100644 --- a/scst/ChangeLog +++ b/scst/ChangeLog @@ -75,7 +75,7 @@ Summary of changes between versions 1.0.1 and 1.0.2 - Automatic sessions reassignment implemented with corresponding atomic management commands added - - Generation of INQUERY DATA HAS CHANGED Unit Attention or AEN for + - Generation of INQUIRY DATA HAS CHANGED Unit Attention or AEN for changed devices during automatic sessions reassignment added - Requeue global Unit Attentions on delivery failure added diff --git a/scst/README b/scst/README index f9419e25e..9e91bcc65 100644 --- a/scst/README +++ b/scst/README @@ -953,8 +953,18 @@ Each vdisk_fileio's device has the following attributes in - o_direct - contains O_DIRECT status of this virtual device. + - inq_vend_specific - Vendor specific data that will be reported via + either bytes 36..55 or bytes 96..256 of the INQUIRY response, depending + on whether this field is <= 20 or > 20 bytes long. + - nv_cache - contains NV_CACHE status of this virtual device. + - prod_id - PRODUCT IDENTIFICATION as reported via the INQUIRY response. + The default value for this field is the SCST device name. + + - prod_rev_lvl - PRODUCT REVISION LEVEL as reported via the INQUIRY + response. The default value for this field is " 300". + - thin_provisioned - contains thin provisioning status of this virtual device. @@ -975,6 +985,10 @@ Each vdisk_fileio's device has the following attributes in that these first eight characters are unique or VMware will consider these devices as identical. + - t10_vend_id - Contents of the T10 VENDOR IDENTIFICATION field of the + INQUIRY response. The default value for this field is "SCST_BIO" for + vdisk_block devices and "SCST_FIO" for vdisk_fileio devices. + - usn - contains the virtual device's serial number of INQUIRY data. It is created at the device creation time based on the device name and scst_vdisk_ID scst_vdisk.ko module parameter for procfs (see below) @@ -986,6 +1000,10 @@ Each vdisk_fileio's device has the following attributes in rescan size of the backend file. It is useful if you changed it, for instance, if you resized it. + - vend_specific_id - Vendor specific ID as reported via the Device + Identification VPD page (83h). The default value for this attribute + is the value of the t10_dev_id attribute. + For example: /sys/kernel/scst_tgt/devices/disk1 diff --git a/scst/README_in-tree b/scst/README_in-tree index 055802881..7ff520b93 100644 --- a/scst/README_in-tree +++ b/scst/README_in-tree @@ -811,8 +811,18 @@ Each vdisk_fileio's device has the following attributes in - o_direct - contains O_DIRECT status of this virtual device. + - inq_vend_specific - Vendor specific data that will be reported via + either bytes 36..55 or bytes 96..256 of the INQUIRY response, depending + on whether this field is <= 20 or > 20 bytes long. + - nv_cache - contains NV_CACHE status of this virtual device. + - prod_id - PRODUCT IDENTIFICATION as reported via the INQUIRY response. + The default value for this field is the SCST device name. + + - prod_rev_lvl - PRODUCT REVISION LEVEL as reported via the INQUIRY + response. The default value for this field is " 300". + - thin_provisioned - contains thin provisioning status of this virtual device. @@ -828,6 +838,10 @@ Each vdisk_fileio's device has the following attributes in created device at creation time based on the device name and scst_vdisk_ID scst_vdisk.ko module parameter (see below). + - t10_vend_id - Contents of the T10 VENDOR IDENTIFICATION field of the + INQUIRY response. The default value for this field is "SCST_BIO" for + vdisk_block devices and "SCST_FIO" for vdisk_fileio devices. + - usn - contains the virtual device's serial number of INQUIRY data. It is created at the device creation time based on the device name and scst_vdisk_ID scst_vdisk.ko module parameter (see below). @@ -838,6 +852,10 @@ Each vdisk_fileio's device has the following attributes in rescan size of the backend file. It is useful if you changed it, for instance, if you resized it. + - vend_specific_id - Vendor specific ID as reported via the Device + Identification VPD page (83h). The default value for this attribute + is the value of the t10_dev_id attribute. + For example: /sys/kernel/scst_tgt/devices/disk1 diff --git a/scst/SysfsRules b/scst/SysfsRules index 182c2ecba..3014c285e 100644 --- a/scst/SysfsRules +++ b/scst/SysfsRules @@ -266,7 +266,11 @@ Identifier attribute. To provide OPTIONAL force close session functionality target drivers MUST implement it using "force_close" write only session's attribute, -which on write to it MUST close the corresponding session. +which on write to it MUST close the corresponding session. The +recommended way to implement it is to add close_session callback to the +target driver's struct scst_tgt_template. This way allows SCST on +initiators' security groups deletion to automatically force close +sessions in those groups. See SCST core's README for more info about those attributes. diff --git a/scst/include/scst.h b/scst/include/scst.h index af3afebc0..229720009 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -119,6 +119,13 @@ typedef _Bool bool; #define nr_cpumask_bits NR_CPUS #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) +#ifndef swap +#define swap(a, b) \ + do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) +#endif +#endif + /* verify cpu argument to cpumask_* operators */ static inline unsigned int cpumask_check(unsigned int cpu) { @@ -179,6 +186,16 @@ static inline unsigned int queue_max_hw_sectors(struct request_queue *q) } #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) +/* + * See also patch "sched: Fix softirq time accounting" (commit ID + * 75e1056f5c57050415b64cb761a3acc35d91f013). + */ +#ifndef in_serving_softirq +#define in_serving_softirq() in_softirq() +#endif +#endif + #ifndef __list_for_each /* ToDo: cleanup when both are the same for all relevant kernels */ #define __list_for_each list_for_each @@ -1139,29 +1156,6 @@ struct scst_tgt_template { struct completion *tgtt_kobj_release_cmpl; #endif - /* - * Optional vendor to be reported via the SCSI inquiry data. If NULL, - * an SCST device handler specific default value will be used, e.g. - * "SCST_FIO" for scst_vdisk file I/O. - */ - const char *vendor; - - /* - * Optional method that sets the product ID in [buf, buf+size) based - * on the device type (byte 0 of the SCSI inquiry data, which contains - * the peripheral qualifier in the highest three bits and the - * peripheral device type in the lower five bits). - */ - void (*get_product_id)(const struct scst_tgt_dev *tgt_dev, - char *buf, int size); - - /* - * Optional revision to be reported in the SCSI inquiry response. If - * NULL, an SCST device handler specific default value will be used, - * e.g. " 210" for scst_vdisk file I/O. - */ - const char *revision; - /* * Optional method that writes the serial number of a target device in * [buf, buf+size) and returns the number of bytes written. @@ -1175,13 +1169,6 @@ struct scst_tgt_template { */ int (*get_serial)(const struct scst_tgt_dev *tgt_dev, char *buf, int size); - - /* - * Optional method that writes the SCSI inquiry vendor-specific data in - * [buf, buf+size) and returns the number of bytes written. - */ - int (*get_vend_specific)(const struct scst_tgt_dev *tgt_dev, char *buf, - int size); }; /* @@ -1942,15 +1929,15 @@ struct scst_cmd { /* Set if the device was blocked by scst_check_blocked_dev() */ unsigned int unblock_dev:1; - /* Set if this cmd incremented dev->pr_readers_count */ - unsigned int dec_pr_readers_count_needed:1; - /* Set if scst_dec_on_dev_cmd() call is needed on the cmd's finish */ unsigned int dec_on_dev_needed:1; /* Set if cmd is queued as hw pending */ unsigned int cmd_hw_pending:1; + /* Set if cmd has NACA bit set in CDB */ + unsigned int cmd_naca:1; + /* * Set if the target driver wants to alloc data buffers on its own. * In this case tgt_alloc_data_buf() must be provided in the target @@ -2030,6 +2017,9 @@ struct scst_cmd { /* Set if scst_cmd_set_write_not_received_data_len() was called */ unsigned int write_not_received_set:1; + /* Set if cmd has LINK bit set in CDB */ + unsigned int cmd_linked:1; + /**************************************************************/ /* cmd's async flags */ @@ -2359,9 +2349,6 @@ struct scst_dev_registrant { struct scst_device { unsigned int type; /* SCSI type of the device */ - /* Set if reserved via the SPC-2 SCSI RESERVE command. */ - struct scst_session *reserved_by; - /************************************************************* ** Dev's flags. Updates serialized by dev_lock or suspended ** activity @@ -2414,18 +2401,6 @@ struct scst_device { int block_size; int block_shift; - /* - * Set if dev is persistently reserved. Protected by dev_pr_mutex. - * Modified independently to the above field, hence the alignment. - */ - unsigned int pr_is_set:1 __aligned(sizeof(long)); - - /* - * Set if there is a thread changing or going to change PR state(s). - * Protected by dev_pr_mutex. - */ - unsigned int pr_writer_active:1; - struct scst_dev_type *handler; /* corresponding dev handler */ /* Used for storage of dev handler private stuff */ @@ -2454,27 +2429,31 @@ struct scst_device { */ int on_dev_cmd_count; - /* - * How many threads are checking commands for PR allowance. - * Protected by dev_lock. - */ - int pr_readers_count; - /* Memory limits for this device */ struct scst_mem_lim dev_mem_lim; /* List of commands with lock, if dedicated threads are used */ struct scst_cmd_threads dev_cmd_threads; - /************************************************************* - ** Persistent reservation fields. Protected by dev_pr_mutex. - *************************************************************/ + /* Set if reserved via the SPC-2 SCSI RESERVE command. */ + struct scst_session *reserved_by; + + /********************************************************************** + * Persistent reservation fields. Protected as follows: + * - Reading PR data must be protected via scst_pr_read_lock() / + * scst_pr_read_unlock(). + * - Modifying PR data modifications must be protected via + * scst_pr_write_lock() / scst_pr_write_unlock(). + **********************************************************************/ /* - * True if persist through power loss is activated. Modified - * independently to the above field, hence the alignment. + * Set if dev is persistently reserved. Modified independently + * to the above field, hence the alignment. */ - unsigned short pr_aptpl:1 __aligned(sizeof(long)); + unsigned short pr_is_set:1 __aligned(sizeof(long)); + + /* True if persist through power loss is activated. */ + unsigned short pr_aptpl:1; /* Persistent reservation type */ uint8_t pr_type; @@ -2494,6 +2473,8 @@ struct scst_device { /* List of dev's registrants */ struct list_head dev_registrants_list; + /* End of persistent reservation fields protected by dev_pr_mutex. */ + /* * Count of connected tgt_devs from transports, which don't support * PRs, i.e. don't have get_initiator_port_transport_id(). Protected diff --git a/scst/include/scst_debug.h b/scst/include/scst_debug.h index d7c689bf1..29b7c6c5f 100644 --- a/scst/include/scst_debug.h +++ b/scst/include/scst_debug.h @@ -80,6 +80,14 @@ #if !defined(INSIDE_KERNEL_TREE) #ifdef CONFIG_SCST_DEBUG +#ifdef __CHECKER__ +/* + * Avoid that the while (...) local_bh_enable() loop confuses the lock checking + * code in smatch. + */ +#define sBUG() BUG() +#define sBUG_ON(p) BUG_ON((p)) +#else #define sBUG() do { \ pr_crit("BUG at %s:%d\n", __FILE__, __LINE__); \ local_irq_enable(); \ @@ -98,6 +106,7 @@ BUG(); \ } \ } while (0) +#endif #else diff --git a/scst/kernel/in-tree/Kconfig.drivers.Linux-3.13.patch b/scst/kernel/in-tree/Kconfig.drivers.Linux-3.13.patch new file mode 100644 index 000000000..0d5a19f0f --- /dev/null +++ b/scst/kernel/in-tree/Kconfig.drivers.Linux-3.13.patch @@ -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" diff --git a/scst/kernel/in-tree/Makefile.dev_handlers-3.13 b/scst/kernel/in-tree/Makefile.dev_handlers-3.13 new file mode 100644 index 000000000..f933b36f7 --- /dev/null +++ b/scst/kernel/in-tree/Makefile.dev_handlers-3.13 @@ -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 diff --git a/scst/kernel/in-tree/Makefile.drivers.Linux-3.13.patch b/scst/kernel/in-tree/Makefile.drivers.Linux-3.13.patch new file mode 100644 index 000000000..f7213ed4c --- /dev/null +++ b/scst/kernel/in-tree/Makefile.drivers.Linux-3.13.patch @@ -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 diff --git a/scst/kernel/in-tree/Makefile.scst-2.6.26 b/scst/kernel/in-tree/Makefile.scst-2.6.26 index e040252e4..1379402be 100644 --- a/scst/kernel/in-tree/Makefile.scst-2.6.26 +++ b/scst/kernel/in-tree/Makefile.scst-2.6.26 @@ -4,7 +4,7 @@ scst-y += scst_main.o scst-y += scst_pres.o scst-y += scst_targ.o scst-y += scst_lib.o -scst-y += scst_proc.o +scst-y += scst_sysfs.o scst-y += scst_mem.o scst-y += scst_tg.o scst-y += scst_debug.o diff --git a/scst/kernel/in-tree/Makefile.scst-2.6.27 b/scst/kernel/in-tree/Makefile.scst-2.6.27 index e040252e4..1379402be 100644 --- a/scst/kernel/in-tree/Makefile.scst-2.6.27 +++ b/scst/kernel/in-tree/Makefile.scst-2.6.27 @@ -4,7 +4,7 @@ scst-y += scst_main.o scst-y += scst_pres.o scst-y += scst_targ.o scst-y += scst_lib.o -scst-y += scst_proc.o +scst-y += scst_sysfs.o scst-y += scst_mem.o scst-y += scst_tg.o scst-y += scst_debug.o diff --git a/scst/kernel/in-tree/Makefile.scst-2.6.28 b/scst/kernel/in-tree/Makefile.scst-2.6.28 index e040252e4..1379402be 100644 --- a/scst/kernel/in-tree/Makefile.scst-2.6.28 +++ b/scst/kernel/in-tree/Makefile.scst-2.6.28 @@ -4,7 +4,7 @@ scst-y += scst_main.o scst-y += scst_pres.o scst-y += scst_targ.o scst-y += scst_lib.o -scst-y += scst_proc.o +scst-y += scst_sysfs.o scst-y += scst_mem.o scst-y += scst_tg.o scst-y += scst_debug.o diff --git a/scst/kernel/in-tree/Makefile.scst-2.6.29 b/scst/kernel/in-tree/Makefile.scst-2.6.29 index e040252e4..1379402be 100644 --- a/scst/kernel/in-tree/Makefile.scst-2.6.29 +++ b/scst/kernel/in-tree/Makefile.scst-2.6.29 @@ -4,7 +4,7 @@ scst-y += scst_main.o scst-y += scst_pres.o scst-y += scst_targ.o scst-y += scst_lib.o -scst-y += scst_proc.o +scst-y += scst_sysfs.o scst-y += scst_mem.o scst-y += scst_tg.o scst-y += scst_debug.o diff --git a/scst/kernel/in-tree/Makefile.scst-2.6.30 b/scst/kernel/in-tree/Makefile.scst-2.6.30 index e040252e4..1379402be 100644 --- a/scst/kernel/in-tree/Makefile.scst-2.6.30 +++ b/scst/kernel/in-tree/Makefile.scst-2.6.30 @@ -4,7 +4,7 @@ scst-y += scst_main.o scst-y += scst_pres.o scst-y += scst_targ.o scst-y += scst_lib.o -scst-y += scst_proc.o +scst-y += scst_sysfs.o scst-y += scst_mem.o scst-y += scst_tg.o scst-y += scst_debug.o diff --git a/scst/kernel/in-tree/Makefile.scst-2.6.31 b/scst/kernel/in-tree/Makefile.scst-2.6.31 index e040252e4..1379402be 100644 --- a/scst/kernel/in-tree/Makefile.scst-2.6.31 +++ b/scst/kernel/in-tree/Makefile.scst-2.6.31 @@ -4,7 +4,7 @@ scst-y += scst_main.o scst-y += scst_pres.o scst-y += scst_targ.o scst-y += scst_lib.o -scst-y += scst_proc.o +scst-y += scst_sysfs.o scst-y += scst_mem.o scst-y += scst_tg.o scst-y += scst_debug.o diff --git a/scst/kernel/in-tree/Makefile.scst-2.6.32 b/scst/kernel/in-tree/Makefile.scst-2.6.32 index e040252e4..1379402be 100644 --- a/scst/kernel/in-tree/Makefile.scst-2.6.32 +++ b/scst/kernel/in-tree/Makefile.scst-2.6.32 @@ -4,7 +4,7 @@ scst-y += scst_main.o scst-y += scst_pres.o scst-y += scst_targ.o scst-y += scst_lib.o -scst-y += scst_proc.o +scst-y += scst_sysfs.o scst-y += scst_mem.o scst-y += scst_tg.o scst-y += scst_debug.o diff --git a/scst/kernel/in-tree/Makefile.scst-3.13 b/scst/kernel/in-tree/Makefile.scst-3.13 new file mode 100644 index 000000000..53af5f388 --- /dev/null +++ b/scst/kernel/in-tree/Makefile.scst-3.13 @@ -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/ diff --git a/scst/kernel/scst_exec_req_fifo-3.13.patch b/scst/kernel/scst_exec_req_fifo-3.13.patch new file mode 100644 index 000000000..84980e46a --- /dev/null +++ b/scst/kernel/scst_exec_req_fifo-3.13.patch @@ -0,0 +1,528 @@ +=== modified file 'block/blk-map.c' +--- old/block/blk-map.c 2014-01-30 00:25:53 +0000 ++++ new/block/blk-map.c 2014-01-30 00:44:50 +0000 +@@ -5,6 +5,8 @@ + #include + #include + #include ++#include ++#include + #include /* 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-01-30 00:25:53 +0000 ++++ new/include/linux/blkdev.h 2014-01-30 00:44:50 +0000 +@@ -712,6 +712,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); +@@ -831,6 +833,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-01-30 00:25:53 +0000 ++++ new/include/linux/scatterlist.h 2014-01-30 00:44:50 +0000 +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + 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-01-30 00:25:53 +0000 ++++ new/lib/scatterlist.c 2014-01-30 00:44:50 +0000 +@@ -717,3 +717,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); + diff --git a/scst/src/Makefile b/scst/src/Makefile index 9b6a55862..5d268577b 100644 --- a/scst/src/Makefile +++ b/scst/src/Makefile @@ -54,15 +54,25 @@ obj-$(CONFIG_SCST) += scst.o dev_handlers/ obj-$(BUILD_DEV) += $(DEV_HANDLERS_DIR)/ else +######### BEGIN OUT-OF-TREE RULES ######### + ifeq ($(KVER),) ifeq ($(KDIR),) - KVER = $(shell uname -r) + KVER := $(shell uname -r) KDIR := /lib/modules/$(KVER)/build + else + KVER := $(strip $(shell \ + cat $(KDIR)/include/config/kernel.release 2>/dev/null || \ + make -s -C $(KDIR) kernelversion)) endif else KDIR := /lib/modules/$(KVER)/build endif +ifeq ($(INSTALL_MOD_PATH),) + export INSTALL_MOD_PATH := $(DESTDIR) +endif + all: $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_DEV=m @@ -97,7 +107,7 @@ ifneq ($(MOD_VERS),) rm -f $(INSTALL_DIR_H)/Modules.symvers install -m 644 Module.symvers $(INSTALL_DIR_H) endif - -/sbin/depmod -a $(KVER) + -/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER) mkdir -p $(DESTDIR)/var/lib/scst/pr @echo "****************************************************************" @echo "*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*" @@ -106,7 +116,7 @@ endif @echo "*!! target drivers, custom dev handlers and necessary user !!*" @echo "*!! space applications. Otherwise, because of the versions !!*" @echo "*!! mismatch, you could have many problems and crashes. !!*" - @echo "*!! See IMPORTANT note in the \"Installation\" section of !!*" + @echo "*!! See IMPORTANT note in the \"Installation\" section of !!*" @echo "*!! SCST's README file for more info. !!*" @echo "*!! !!*" @echo "*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*" @@ -116,15 +126,13 @@ uninstall: cd $(DEV_HANDLERS_DIR) && $(MAKE) $@ rm -f $(INSTALL_DIR)/scst.ko -rmdir $(INSTALL_DIR) 2>/dev/null - -/sbin/depmod -a $(KVER) + -/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER) rm -rf $(INSTALL_DIR_H) + +########## END OUT-OF-TREE RULES ########## endif -ifeq ($(KVER),) -INSTALL_DIR := $(DESTDIR)/lib/modules/$(shell uname -r)/extra -else -INSTALL_DIR := $(DESTDIR)/lib/modules/$(KVER)/extra -endif +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra INSTALL_DIR_H := $(DESTDIR)$(PREFIX)/include/scst enable-Wextra = $(shell uname_r="$$(uname -r)"; if [ "$${uname_r%.el5}" = "$${uname_r}" ]; then echo "$(1)"; fi) diff --git a/scst/src/dev_handlers/Makefile b/scst/src/dev_handlers/Makefile index a460ce1a6..3ae5471d6 100644 --- a/scst/src/dev_handlers/Makefile +++ b/scst/src/dev_handlers/Makefile @@ -46,27 +46,38 @@ obj-$(CONFIG_SCST_VDISK) += scst_vdisk.o obj-$(CONFIG_SCST_USER) += scst_user.o else -ifeq ($(KDIR),) - KVER = $(shell uname -r) +######### BEGIN OUT-OF-TREE RULES ######### + +ifeq ($(KVER),) + ifeq ($(KDIR),) + KVER := $(shell uname -r) + KDIR := /lib/modules/$(KVER)/build + else + KVER := $(strip $(shell \ + cat $(KDIR)/include/config/kernel.release 2>/dev/null || \ + make -s -C $(KDIR) kernelversion)) + endif +else KDIR := /lib/modules/$(KVER)/build endif +ifeq ($(INSTALL_MOD_PATH),) + export INSTALL_MOD_PATH := $(DESTDIR) +endif + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra + all: $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) install: all $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) \ modules_install - -/sbin/depmod -a $(KVER) uninstall: rm -f $(INSTALL_DIR)/dev_handlers/scst_*.ko -endif -ifeq ($(KVER),) -INSTALL_DIR := /lib/modules/$(shell uname -r)/extra -else -INSTALL_DIR := /lib/modules/$(KVER)/extra +########## END OUT-OF-TREE RULES ########## endif enable-Wextra = $(shell uname_r="$$(uname -r)"; if [ "$${uname_r%.el5}" = "$${uname_r}" ]; then echo "$(1)"; fi) diff --git a/scst/src/dev_handlers/scst_user.c b/scst/src/dev_handlers/scst_user.c index 6c05b876c..962a496b7 100644 --- a/scst/src/dev_handlers/scst_user.c +++ b/scst/src/dev_handlers/scst_user.c @@ -691,6 +691,9 @@ static int dev_user_alloc_space(struct scst_user_cmd *ucmd) ucmd->user_cmd.alloc_cmd.data_direction = cmd->data_direction; ucmd->user_cmd.alloc_cmd.sn = cmd->tgt_sn; + TRACE_DBG("Preparing ALLOC_MEM for user space (ucmd=%p, h=%d, " + "alloc_len %d)", ucmd, ucmd->h, ucmd->user_cmd.alloc_cmd.alloc_len); + dev_user_add_to_ready(ucmd); res = SCST_CMD_STATE_STOP; @@ -987,6 +990,7 @@ static void dev_user_on_free_cmd(struct scst_cmd *cmd) goto out_reply; } + TRACE_DBG("Preparing ON_FREE_CMD (pbuff 0x%lx)", ucmd->ubuff); ucmd->user_cmd_payload_len = offsetof(struct scst_user_get_cmd, on_free_cmd) + sizeof(ucmd->user_cmd.on_free_cmd); @@ -1129,7 +1133,12 @@ static void dev_user_add_to_ready(struct scst_user_cmd *ucmd) { struct scst_user_dev *dev = ucmd->dev; unsigned long flags; - int do_wake = in_interrupt(); + /* + * Note, a separate softIRQ check is required for real-time kernels + * (CONFIG_PREEMPT_RT_FULL=y) since on such kernels softIRQ's are + * served in thread context. See also http://lwn.net/Articles/302043/. + */ + int do_wake = in_interrupt() || in_serving_softirq(); TRACE_ENTRY(); @@ -1286,6 +1295,7 @@ out_process: scst_post_alloc_data_buf(cmd); scst_process_active_cmd(cmd, false); + TRACE_DBG("%s", "ALLOC_MEM finished"); TRACE_EXIT_RES(res); return res; @@ -1350,6 +1360,8 @@ static int dev_user_process_reply_parse(struct scst_user_cmd *ucmd, out_process: scst_post_parse(cmd); + TRACE_DBG("%s", "PARSE finished"); + scst_process_active_cmd(cmd, false); TRACE_EXIT_RES(res); @@ -1408,6 +1420,7 @@ static int dev_user_process_reply_on_free(struct scst_user_cmd *ucmd) dev_user_free_sgv(ucmd); ucmd_put(ucmd); + TRACE_DBG("%s", "ON_FREE_CMD finished"); TRACE_EXIT_RES(res); return res; } @@ -1422,6 +1435,7 @@ static int dev_user_process_reply_on_cache_free(struct scst_user_cmd *ucmd) ucmd_put(ucmd); + TRACE_MEM("%s", "ON_CACHED_MEM_FREE finished"); TRACE_EXIT_RES(res); return res; } @@ -1535,6 +1549,7 @@ out_compl: /* !! At this point cmd can be already freed !! */ out: + TRACE_DBG("%s", "EXEC finished"); TRACE_EXIT_RES(res); return res; @@ -2968,7 +2983,7 @@ static int dev_user_register_dev(struct file *file, dev->pool = sgv_pool_create(dev->devtype.name, sgv_no_clustering, dev_desc->sgv_single_alloc_pages, dev_desc->sgv_shared, - dev_desc->sgv_purge_interval); + dev_desc->sgv_purge_interval * HZ); if (dev->pool == NULL) { res = -ENOMEM; goto out_deinit_threads; @@ -2985,7 +3000,7 @@ static int dev_user_register_dev(struct file *file, sgv_tail_clustering, dev_desc->sgv_single_alloc_pages, dev_desc->sgv_shared, - dev_desc->sgv_purge_interval); + dev_desc->sgv_purge_interval * HZ); if (dev->pool_clust == NULL) { res = -ENOMEM; goto out_free0; diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index d6bd45ebf..e1ce52a4c 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -82,6 +82,7 @@ static struct scst_trace_log vdisk_local_trace_tbl[] = { #define SCST_FIO_REV " 300" #define MAX_USN_LEN (20+1) /* For '\0' */ +#define MAX_INQ_VEND_SPECIFIC_LEN (INQ_BUF_SZ - 96) #define INQ_BUF_SZ 256 #define EVPD 0x01 @@ -175,11 +176,22 @@ struct scst_vdisk_dev { scst_mutex and suspended activities */ uint16_t command_set_version; - /* All 4 protected by vdisk_serial_rwlock */ + /* All 14 protected by vdisk_serial_rwlock */ + unsigned int t10_vend_id_set:1; /* true if t10_vend_id manually set */ + /* true if vend_specific_id manually set */ + unsigned int vend_specific_id_set:1; + unsigned int prod_id_set:1; /* true if prod_id manually set */ + unsigned int prod_rev_lvl_set:1; /* true if prod_rev_lvl manually set */ unsigned int t10_dev_id_set:1; /* true if t10_dev_id manually set */ unsigned int usn_set:1; /* true if usn manually set */ + char t10_vend_id[8 + 1]; + char vend_specific_id[32 + 1]; + char prod_id[16 + 1]; + char prod_rev_lvl[4 + 1]; char t10_dev_id[16+8+2]; /* T10 device ID */ char usn[MAX_USN_LEN]; + uint8_t inq_vend_specific[MAX_INQ_VEND_SPECIFIC_LEN]; + int inq_vend_specific_len; struct scst_device *dev; struct list_head vdev_list_entry; @@ -319,6 +331,22 @@ static ssize_t vdev_sysfs_filename_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); static ssize_t vdisk_sysfs_resync_size_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); +static ssize_t vdev_sysfs_t10_vend_id_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); +static ssize_t vdev_sysfs_t10_vend_id_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); +static ssize_t vdev_sysfs_vend_specific_id_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); +static ssize_t vdev_sysfs_vend_specific_id_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); +static ssize_t vdev_sysfs_prod_id_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); +static ssize_t vdev_sysfs_prod_id_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); +static ssize_t vdev_sysfs_prod_rev_lvl_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); +static ssize_t vdev_sysfs_prod_rev_lvl_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); static ssize_t vdev_sysfs_t10_dev_id_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); static ssize_t vdev_sysfs_t10_dev_id_show(struct kobject *kobj, @@ -327,6 +355,10 @@ static ssize_t vdev_sysfs_usn_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); static ssize_t vdev_sysfs_usn_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); +static ssize_t vdev_sysfs_inq_vend_specific_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); +static ssize_t vdev_sysfs_inq_vend_specific_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); static ssize_t vdev_zero_copy_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); @@ -357,11 +389,28 @@ static struct kobj_attribute vdisk_filename_attr = __ATTR(filename, S_IRUGO, vdev_sysfs_filename_show, NULL); static struct kobj_attribute vdisk_resync_size_attr = __ATTR(resync_size, S_IWUSR, NULL, vdisk_sysfs_resync_size_store); +static struct kobj_attribute vdev_t10_vend_id_attr = + __ATTR(t10_vend_id, S_IWUSR|S_IRUGO, vdev_sysfs_t10_vend_id_show, + vdev_sysfs_t10_vend_id_store); +static struct kobj_attribute vdev_vend_specific_id_attr = + __ATTR(vend_specific_id, S_IWUSR|S_IRUGO, + vdev_sysfs_vend_specific_id_show, + vdev_sysfs_vend_specific_id_store); +static struct kobj_attribute vdev_prod_id_attr = + __ATTR(prod_id, S_IWUSR|S_IRUGO, vdev_sysfs_prod_id_show, + vdev_sysfs_prod_id_store); +static struct kobj_attribute vdev_prod_rev_lvl_attr = + __ATTR(prod_rev_lvl, S_IWUSR|S_IRUGO, vdev_sysfs_prod_rev_lvl_show, + vdev_sysfs_prod_rev_lvl_store); static struct kobj_attribute vdev_t10_dev_id_attr = __ATTR(t10_dev_id, S_IWUSR|S_IRUGO, vdev_sysfs_t10_dev_id_show, vdev_sysfs_t10_dev_id_store); static struct kobj_attribute vdev_usn_attr = __ATTR(usn, S_IWUSR|S_IRUGO, vdev_sysfs_usn_show, vdev_sysfs_usn_store); +static struct kobj_attribute vdev_inq_vend_specific_attr = + __ATTR(inq_vend_specific, S_IWUSR|S_IRUGO, + vdev_sysfs_inq_vend_specific_show, + vdev_sysfs_inq_vend_specific_store); static struct kobj_attribute vdev_zero_copy_attr = __ATTR(zero_copy, S_IRUGO, vdev_zero_copy_show, NULL); @@ -381,8 +430,13 @@ static const struct attribute *vdisk_fileio_attrs[] = { &vdisk_removable_attr.attr, &vdisk_filename_attr.attr, &vdisk_resync_size_attr.attr, + &vdev_t10_vend_id_attr.attr, + &vdev_vend_specific_id_attr.attr, + &vdev_prod_id_attr.attr, + &vdev_prod_rev_lvl_attr.attr, &vdev_t10_dev_id_attr.attr, &vdev_usn_attr.attr, + &vdev_inq_vend_specific_attr.attr, &vdev_zero_copy_attr.attr, NULL, }; @@ -397,8 +451,13 @@ static const struct attribute *vdisk_blockio_attrs[] = { &vdisk_rotational_attr.attr, &vdisk_filename_attr.attr, &vdisk_resync_size_attr.attr, + &vdev_t10_vend_id_attr.attr, + &vdev_vend_specific_id_attr.attr, + &vdev_prod_id_attr.attr, + &vdev_prod_rev_lvl_attr.attr, &vdev_t10_dev_id_attr.attr, &vdev_usn_attr.attr, + &vdev_inq_vend_specific_attr.attr, &vdisk_tp_attr.attr, NULL, }; @@ -409,8 +468,13 @@ static const struct attribute *vdisk_nullio_attrs[] = { &vdisk_rd_only_attr.attr, &vdev_dummy_attr.attr, &vdisk_removable_attr.attr, + &vdev_t10_vend_id_attr.attr, + &vdev_vend_specific_id_attr.attr, + &vdev_prod_id_attr.attr, + &vdev_prod_rev_lvl_attr.attr, &vdev_t10_dev_id_attr.attr, &vdev_usn_attr.attr, + &vdev_inq_vend_specific_attr.attr, &vdisk_rotational_attr.attr, NULL, }; @@ -418,8 +482,13 @@ static const struct attribute *vdisk_nullio_attrs[] = { static const struct attribute *vcdrom_attrs[] = { &vdev_size_attr.attr, &vcdrom_filename_attr.attr, + &vdev_t10_vend_id_attr.attr, + &vdev_vend_specific_id_attr.attr, + &vdev_prod_id_attr.attr, + &vdev_prod_rev_lvl_attr.attr, &vdev_t10_dev_id_attr.attr, &vdev_usn_attr.attr, + &vdev_inq_vend_specific_attr.attr, NULL, }; @@ -428,7 +497,10 @@ static const struct attribute *vcdrom_attrs[] = { /* Protects vdisks addition/deletion and related activities, like search */ static DEFINE_MUTEX(scst_vdisk_mutex); -/* Protects devices t10_dev_id and usn */ +/* + * Protects the device attributes t10_vend_id, vend_specific_id, prod_id, + * prod_rev_lvl, t10_dev_id, usn and inq_vend_specific. + */ static DEFINE_RWLOCK(vdisk_serial_rwlock); /* Protected by scst_vdisk_mutex */ @@ -469,9 +541,17 @@ static struct scst_dev_type vdisk_file_devtype = { .add_device = vdisk_add_fileio_device, .del_device = vdisk_del_device, .dev_attrs = vdisk_fileio_attrs, - .add_device_parameters = "filename, blocksize, write_through, " - "nv_cache, o_direct, read_only, removable, rotational, " - "thin_provisioned, zero_copy", + .add_device_parameters = + "blocksize, " + "filename, " + "nv_cache, " + "o_direct, " + "read_only, " + "removable, " + "rotational, " + "thin_provisioned, " + "write_through, " + "zero_copy", #endif #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) .default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS, @@ -506,9 +586,15 @@ static struct scst_dev_type vdisk_blk_devtype = { .add_device = vdisk_add_blockio_device, .del_device = vdisk_del_device, .dev_attrs = vdisk_blockio_attrs, - .add_device_parameters = "filename, blocksize, write_through, " - "nv_cache, read_only, removable, rotational, " - "thin_provisioned", + .add_device_parameters = + "blocksize, " + "filename, " + "nv_cache, " + "read_only, " + "removable, " + "rotational, " + "thin_provisioned, " + "write_through", #endif #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) .default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS, @@ -541,8 +627,12 @@ static struct scst_dev_type vdisk_null_devtype = { .add_device = vdisk_add_nullio_device, .del_device = vdisk_del_device, .dev_attrs = vdisk_nullio_attrs, - .add_device_parameters = "blocksize, read_only, dummy, removable," - " rotational", + .add_device_parameters = + "blocksize, " + "dummy, " + "read_only, " + "removable, " + "rotational", #endif #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) .default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS, @@ -1529,7 +1619,7 @@ out: return res; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) /** * finish_read - Release the pages referenced by prepare_read(). */ @@ -2125,21 +2215,23 @@ static int vdisk_unmap_range(struct scst_cmd *cmd, (unsigned long long)start_lba, (unsigned long long)blocks); if (virt_dev->blockio) { + 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) - err = blkdev_issue_discard(inode->i_bdev, start_lba, blocks, gfp); + err = blkdev_issue_discard(inode->i_bdev, start_sector, nr_sects, gfp); #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) \ && !(LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 34) \ && defined(CONFIG_SUSE_KERNEL)) - err = blkdev_issue_discard(inode->i_bdev, start_lba, blocks, + err = blkdev_issue_discard(inode->i_bdev, start_sector, nr_sects, gfp, DISCARD_FL_WAIT); #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) - err = blkdev_issue_discard(inode->i_bdev, start_lba, blocks, + err = blkdev_issue_discard(inode->i_bdev, start_sector, nr_sects, gfp, BLKDEV_IFL_WAIT); #else - err = blkdev_issue_discard(inode->i_bdev, start_lba, blocks, gfp, 0); + err = blkdev_issue_discard(inode->i_bdev, start_sector, nr_sects, gfp, 0); #endif if (unlikely(err != 0)) { PRINT_ERROR("blkdev_issue_discard() for " @@ -2215,6 +2307,28 @@ out: return; } +/* + * Copy a zero-terminated string into a fixed-size byte array and fill the + * trailing bytes with @fill_byte. + */ +static void scst_copy_and_fill_b(char *dst, const char *src, int len, + uint8_t fill_byte) +{ + int cpy_len = min_t(int, strlen(src), len); + + memcpy(dst, src, cpy_len); + memset(dst + cpy_len, fill_byte, len - cpy_len); +} + +/* + * Copy a zero-terminated string into a fixed-size char array and fill the + * trailing characters with spaces. + */ +static void scst_copy_and_fill(char *dst, const char *src, int len) +{ + scst_copy_and_fill_b(dst, src, len, ' '); +} + static enum compl_status_e vdisk_exec_write_same(struct vdisk_cmd_params *p) { struct scst_cmd *cmd = p->cmd; @@ -2425,16 +2539,10 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p) /* T10 vendor identifier field format (faked) */ buf[num + 0] = 0x2; /* ASCII */ buf[num + 1] = 0x1; /* Vendor ID */ - if (cmd->tgtt->vendor) - memcpy(&buf[num + 4], cmd->tgtt->vendor, 8); - else if (virt_dev->blockio) - memcpy(&buf[num + 4], SCST_BIO_VENDOR, 8); - else - memcpy(&buf[num + 4], SCST_FIO_VENDOR, 8); - read_lock(&vdisk_serial_rwlock); - i = strlen(virt_dev->t10_dev_id); - memcpy(&buf[num + 12], virt_dev->t10_dev_id, i); + scst_copy_and_fill(&buf[num + 4], virt_dev->t10_vend_id, 8); + i = strlen(virt_dev->vend_specific_id); + memcpy(&buf[num + 12], virt_dev->vend_specific_id, i); read_unlock(&vdisk_serial_rwlock); buf[num + 3] = 8 + i; @@ -2588,7 +2696,7 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p) goto out_put; } } else { - int len, num; + int num; if (cmd->cdb[2] != 0) { TRACE_DBG("INQUIRY: Unsupported page %x", cmd->cdb[2]); @@ -2608,37 +2716,30 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p) buf[6] = 0x10; /* MultiP 1 */ buf[7] = 2; /* CMDQUE 1, BQue 0 => commands queuing supported */ + read_lock(&vdisk_serial_rwlock); + /* * 8 byte ASCII Vendor Identification of the target * - left aligned. */ - if (cmd->tgtt->vendor) - memcpy(&buf[8], cmd->tgtt->vendor, 8); - else if (virt_dev->blockio) - memcpy(&buf[8], SCST_BIO_VENDOR, 8); - else - memcpy(&buf[8], SCST_FIO_VENDOR, 8); + scst_copy_and_fill(&buf[8], virt_dev->t10_vend_id, 8); /* * 16 byte ASCII Product Identification of the target - left * aligned. */ - memset(&buf[16], ' ', 16); - if (cmd->tgtt->get_product_id) - cmd->tgtt->get_product_id(cmd->tgt_dev, &buf[16], 16); - else { - len = min_t(size_t, strlen(virt_dev->name), 16); - memcpy(&buf[16], virt_dev->name, len); - } + scst_copy_and_fill(&buf[16], virt_dev->prod_id, 16); /* * 4 byte ASCII Product Revision Level of the target - left * aligned. */ - if (cmd->tgtt->revision) - memcpy(&buf[32], cmd->tgtt->revision, 4); - else - memcpy(&buf[32], SCST_FIO_REV, 4); + scst_copy_and_fill(&buf[32], virt_dev->prod_rev_lvl, 4); + + /* Vendor specific information. */ + if (virt_dev->inq_vend_specific_len <= 20) + memcpy(&buf[36], virt_dev->inq_vend_specific, + virt_dev->inq_vend_specific_len); /** Version descriptors **/ @@ -2679,13 +2780,14 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p) } /* Vendor specific information. */ - if (cmd->tgtt->get_vend_specific) { - /* Skip to byte 96. */ - num = 96 - 58; - num += cmd->tgtt->get_vend_specific(cmd->tgt_dev, - &buf[96], INQ_BUF_SZ - 96); + if (virt_dev->inq_vend_specific_len > 20) { + memcpy(&buf[96], virt_dev->inq_vend_specific, + virt_dev->inq_vend_specific_len); + num = 96 - 58 + virt_dev->inq_vend_specific_len; } + read_unlock(&vdisk_serial_rwlock); + buf[4] += num; resp_len = buf[4] + 5; } @@ -4620,6 +4722,20 @@ static int vdev_create(struct scst_dev_type *devt, "%llx-%s", dev_id_num, virt_dev->name); TRACE_DBG("t10_dev_id %s", virt_dev->t10_dev_id); + sprintf(virt_dev->t10_vend_id, "%.*s", + (int)(sizeof(virt_dev->t10_vend_id) - 1), + virt_dev->blockio ? SCST_BIO_VENDOR : SCST_FIO_VENDOR); + + sprintf(virt_dev->vend_specific_id, "%.*s", + (int)(sizeof(virt_dev->vend_specific_id) - 1), + virt_dev->t10_dev_id); + + sprintf(virt_dev->prod_id, "%.*s", (int)(sizeof(virt_dev->prod_id) - 1), + virt_dev->name); + + sprintf(virt_dev->prod_rev_lvl, "%.*s", + (int)(sizeof(virt_dev->prod_rev_lvl) - 1), SCST_FIO_REV); + scnprintf(virt_dev->usn, sizeof(virt_dev->usn), "%llx", dev_id_num); TRACE_DBG("usn %s", virt_dev->usn); @@ -4710,6 +4826,12 @@ static int vdev_parse_add_dev_params(struct scst_vdisk_dev *virt_dev, } if (!strcasecmp("filename", p)) { + if (virt_dev->filename) { + PRINT_ERROR("%s specified more than once" + " (device %s)", p, virt_dev->name); + res = -EINVAL; + goto out; + } if (*pp != '/') { PRINT_ERROR("Filename %s must be global " "(device %s)", pp, virt_dev->name); @@ -5713,6 +5835,239 @@ out: return res; } +static ssize_t vdev_sysfs_t10_vend_id_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct scst_device *dev; + struct scst_vdisk_dev *virt_dev; + char *p; + int res, len; + + TRACE_ENTRY(); + + dev = container_of(kobj, struct scst_device, dev_kobj); + virt_dev = dev->dh_priv; + p = memchr(buf, '\n', count); + len = p ? p - buf : count; + + if (len >= sizeof(virt_dev->t10_vend_id)) { + PRINT_ERROR("T10 vendor id is too long (max %zd characters)", + sizeof(virt_dev->t10_vend_id)); + res = -EINVAL; + goto out; + } + + write_lock(&vdisk_serial_rwlock); + sprintf(virt_dev->t10_vend_id, "%.*s", len, buf); + virt_dev->t10_vend_id_set = 1; + write_unlock(&vdisk_serial_rwlock); + + res = count; + +out: + TRACE_EXIT_RES(res); + return res; +} + +static ssize_t vdev_sysfs_t10_vend_id_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + int pos; + struct scst_device *dev; + struct scst_vdisk_dev *virt_dev; + + TRACE_ENTRY(); + + dev = container_of(kobj, struct scst_device, dev_kobj); + virt_dev = dev->dh_priv; + + read_lock(&vdisk_serial_rwlock); + pos = sprintf(buf, "%s\n%s", virt_dev->t10_vend_id, + virt_dev->t10_vend_id_set ? SCST_SYSFS_KEY_MARK "\n" : + ""); + read_unlock(&vdisk_serial_rwlock); + + TRACE_EXIT_RES(pos); + return pos; +} + +static ssize_t vdev_sysfs_vend_specific_id_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct scst_device *dev; + struct scst_vdisk_dev *virt_dev; + char *p; + int res, len; + + TRACE_ENTRY(); + + dev = container_of(kobj, struct scst_device, dev_kobj); + virt_dev = dev->dh_priv; + p = memchr(buf, '\n', count); + len = p ? p - buf : count; + + if (len >= sizeof(virt_dev->vend_specific_id)) { + PRINT_ERROR("Vendor specific id is too long (max %zd" + " characters)", + sizeof(virt_dev->vend_specific_id) - 1); + res = -EINVAL; + goto out; + } + + write_lock(&vdisk_serial_rwlock); + sprintf(virt_dev->vend_specific_id, "%.*s", len, buf); + virt_dev->vend_specific_id_set = 1; + write_unlock(&vdisk_serial_rwlock); + + res = count; + +out: + TRACE_EXIT_RES(res); + return res; +} + +static ssize_t vdev_sysfs_vend_specific_id_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + int pos; + struct scst_device *dev; + struct scst_vdisk_dev *virt_dev; + + TRACE_ENTRY(); + + dev = container_of(kobj, struct scst_device, dev_kobj); + virt_dev = dev->dh_priv; + + read_lock(&vdisk_serial_rwlock); + pos = sprintf(buf, "%s\n%s", virt_dev->vend_specific_id, + virt_dev->vend_specific_id_set ? + SCST_SYSFS_KEY_MARK "\n" : ""); + read_unlock(&vdisk_serial_rwlock); + + TRACE_EXIT_RES(pos); + return pos; +} + +static ssize_t vdev_sysfs_prod_id_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct scst_device *dev; + struct scst_vdisk_dev *virt_dev; + char *p; + int res, len; + + TRACE_ENTRY(); + + dev = container_of(kobj, struct scst_device, dev_kobj); + virt_dev = dev->dh_priv; + p = memchr(buf, '\n', count); + len = p ? p - buf : count; + + if (len >= sizeof(virt_dev->prod_id)) { + PRINT_ERROR("Product id is too long (max %zd characters)", + sizeof(virt_dev->prod_id)); + res = -EINVAL; + goto out; + } + + write_lock(&vdisk_serial_rwlock); + sprintf(virt_dev->prod_id, "%.*s", len, buf); + virt_dev->prod_id_set = 1; + write_unlock(&vdisk_serial_rwlock); + + res = count; + +out: + TRACE_EXIT_RES(res); + return res; +} + +static ssize_t vdev_sysfs_prod_id_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + int pos; + struct scst_device *dev; + struct scst_vdisk_dev *virt_dev; + + TRACE_ENTRY(); + + dev = container_of(kobj, struct scst_device, dev_kobj); + virt_dev = dev->dh_priv; + + read_lock(&vdisk_serial_rwlock); + pos = sprintf(buf, "%s\n%s", virt_dev->prod_id, + virt_dev->prod_id_set ? SCST_SYSFS_KEY_MARK "\n" : ""); + read_unlock(&vdisk_serial_rwlock); + + TRACE_EXIT_RES(pos); + return pos; +} + +static ssize_t vdev_sysfs_prod_rev_lvl_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct scst_device *dev; + struct scst_vdisk_dev *virt_dev; + char *p; + int res, len; + + TRACE_ENTRY(); + + dev = container_of(kobj, struct scst_device, dev_kobj); + virt_dev = dev->dh_priv; + p = memchr(buf, '\n', count); + len = p ? p - buf : count; + + if (len >= sizeof(virt_dev->prod_rev_lvl)) { + PRINT_ERROR("Product revision level is too long (max %zd" + " characters)", + sizeof(virt_dev->prod_rev_lvl)); + res = -EINVAL; + goto out; + } + + write_lock(&vdisk_serial_rwlock); + sprintf(virt_dev->prod_rev_lvl, "%.*s", len, buf); + virt_dev->prod_rev_lvl_set = 1; + write_unlock(&vdisk_serial_rwlock); + + res = count; + +out: + TRACE_EXIT_RES(res); + return res; +} + +static ssize_t vdev_sysfs_prod_rev_lvl_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + int pos; + struct scst_device *dev; + struct scst_vdisk_dev *virt_dev; + + TRACE_ENTRY(); + + dev = container_of(kobj, struct scst_device, dev_kobj); + virt_dev = dev->dh_priv; + + read_lock(&vdisk_serial_rwlock); + pos = sprintf(buf, "%s\n%s", virt_dev->prod_rev_lvl, + virt_dev->prod_rev_lvl_set ? SCST_SYSFS_KEY_MARK "\n" : + ""); + read_unlock(&vdisk_serial_rwlock); + + TRACE_EXIT_RES(pos); + return pos; +} + static ssize_t vdev_sysfs_t10_dev_id_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { @@ -5853,6 +6208,55 @@ static ssize_t vdev_sysfs_usn_show(struct kobject *kobj, return pos; } +static ssize_t vdev_sysfs_inq_vend_specific_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct scst_device *dev; + struct scst_vdisk_dev *virt_dev; + char *p; + int res = -EINVAL, len; + + dev = container_of(kobj, struct scst_device, dev_kobj); + virt_dev = dev->dh_priv; + p = memchr(buf, '\n', count); + len = p ? p - buf : count; + if (len > MAX_INQ_VEND_SPECIFIC_LEN) + goto out; + + write_lock(&vdisk_serial_rwlock); + memcpy(virt_dev->inq_vend_specific, buf, len); + virt_dev->inq_vend_specific_len = len; + write_unlock(&vdisk_serial_rwlock); + + res = count; + +out: + return res; +} + +static ssize_t vdev_sysfs_inq_vend_specific_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + int pos; + struct scst_device *dev; + struct scst_vdisk_dev *virt_dev; + + dev = container_of(kobj, struct scst_device, dev_kobj); + virt_dev = dev->dh_priv; + + read_lock(&vdisk_serial_rwlock); + pos = snprintf(buf, PAGE_SIZE, "%.*s\n%s", + virt_dev->inq_vend_specific_len, + virt_dev->inq_vend_specific, + virt_dev->inq_vend_specific_len ? + SCST_SYSFS_KEY_MARK "\n" : ""); + read_unlock(&vdisk_serial_rwlock); + + return pos; +} + static ssize_t vdev_zero_copy_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index c845d4f54..6c86a813f 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -4645,7 +4645,7 @@ static int scst_ws_push_single_write(struct scst_write_same_priv *wsp, uint8_t write16_cdb[16]; struct scatterlist *sg; int sg_cnt, len = blocks << ws_cmd->dev->block_shift; - struct sgv_pool_obj *sgv; + struct sgv_pool_obj *sgv = NULL; struct scst_cmd *cmd; int64_t cur_lba; @@ -4686,7 +4686,6 @@ static int scst_ws_push_single_write(struct scst_write_same_priv *wsp, goto set_add; } - sgv = NULL; /* we don't supply sgv */ sg = sgv_pool_alloc(ws_cmd->tgt_dev->pool, len, GFP_KERNEL, 0, &sg_cnt, &sgv, &cmd->dev->dev_mem_lim, NULL); if (sg == NULL) { @@ -5433,8 +5432,7 @@ void scst_free_cmd(struct scst_cmd *cmd) if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) TRACE_MGMT_DBG("Freeing aborted cmd %p", cmd); - EXTRACHECKS_BUG_ON(cmd->unblock_dev || cmd->dec_on_dev_needed || - cmd->dec_pr_readers_count_needed); + EXTRACHECKS_BUG_ON(cmd->unblock_dev || cmd->dec_on_dev_needed); /* * Target driver can already free sg buffer before calling @@ -6687,7 +6685,7 @@ static int get_cdb_info_write_same16(struct scst_cmd *cmd, } /** - * scst_get_cdb_info_apt() - Parse ATA PASS-THROUGH CDB. + * get_cdb_info_apt() - Parse ATA PASS-THROUGH CDB. * * Parse ATA PASS-THROUGH(12) and ATA PASS-THROUGH(16). See also SAT-3 for a * detailed description of these commands. @@ -6870,6 +6868,8 @@ int scst_get_cdb_info(struct scst_cmd *cmd) } cmd->cdb_len = SCST_GET_CDB_LEN(op); + cmd->cmd_naca = (cmd->cdb[cmd->cdb_len - 1] & CONTROL_BYTE_NACA_BIT); + cmd->cmd_linked = (cmd->cdb[cmd->cdb_len - 1] & CONTROL_BYTE_LINK_BIT); cmd->op_name = ptr->info_op_name; cmd->data_direction = ptr->info_data_direction; cmd->op_flags = ptr->info_op_flags | SCST_INFO_VALID; @@ -8267,7 +8267,7 @@ void scst_unblock_dev(struct scst_device *dev) struct scst_cmd *cmd, *tcmd; unsigned long flags; - local_irq_save(flags); + local_irq_save_nort(flags); list_for_each_entry_safe(cmd, tcmd, &dev->blocked_cmd_list, blocked_cmd_list_entry) { bool strictly_serialized; @@ -8287,7 +8287,7 @@ void scst_unblock_dev(struct scst_device *dev) if (dev->strictly_serialized_cmd_waiting && strictly_serialized) break; } - local_irq_restore(flags); + local_irq_restore_nort(flags); dev->strictly_serialized_cmd_waiting = 0; } diff --git a/scst/src/scst_pres.c b/scst/src/scst_pres.c index c08378e01..e7210d433 100644 --- a/scst/src/scst_pres.c +++ b/scst/src/scst_pres.c @@ -1126,15 +1126,16 @@ out: /* Called under scst_mutex */ void scst_pr_clear_tgt_dev(struct scst_tgt_dev *tgt_dev) { + struct scst_device *dev = tgt_dev->dev; + struct scst_dev_registrant *reg; + struct scst_tgt_dev *t; + TRACE_ENTRY(); - if (tgt_dev->registrant != NULL) { - struct scst_dev_registrant *reg = tgt_dev->registrant; - struct scst_device *dev = tgt_dev->dev; - struct scst_tgt_dev *t; - - scst_pr_write_lock(dev); + scst_pr_write_lock(dev); + reg = tgt_dev->registrant; + if (reg) { tgt_dev->registrant = NULL; reg->tgt_dev = NULL; @@ -1155,10 +1156,10 @@ void scst_pr_clear_tgt_dev(struct scst_tgt_dev *tgt_dev) break; } } - - scst_pr_write_unlock(dev); } + scst_pr_write_unlock(dev); + TRACE_EXIT(); return; } @@ -2324,11 +2325,10 @@ bool scst_pr_is_cmd_allowed(struct scst_cmd *cmd) struct scst_tgt_dev *tgt_dev = cmd->tgt_dev; struct scst_dev_registrant *reg; uint8_t type; - bool unlock; TRACE_ENTRY(); - unlock = scst_pr_read_lock(cmd); + scst_pr_read_lock(dev); TRACE_DBG("Testing if command %s (0x%x) from %s allowed to execute", cmd->op_name, cmd->cdb[0], cmd->sess->initiator_name); @@ -2388,7 +2388,7 @@ bool scst_pr_is_cmd_allowed(struct scst_cmd *cmd) cmd->op_name, cmd->cdb[0], cmd->sess->initiator_name); out_unlock: - scst_pr_read_unlock(cmd, unlock); + scst_pr_read_unlock(dev); TRACE_EXIT_RES(allowed); return allowed; diff --git a/scst/src/scst_pres.h b/scst/src/scst_pres.h index 9829d4fac..acb0e7e49 100644 --- a/scst/src/scst_pres.h +++ b/scst/src/scst_pres.h @@ -54,63 +54,6 @@ /* Persistent reservation SCOPE field */ #define SCOPE_LU 0x00 -static inline void scst_inc_pr_readers_count(struct scst_cmd *cmd, - bool locked) -{ - struct scst_device *dev = cmd->dev; - - EXTRACHECKS_BUG_ON(cmd->dec_pr_readers_count_needed); - - if (!locked) - spin_lock_bh(&dev->dev_lock); - -#ifdef CONFIG_SMP - EXTRACHECKS_BUG_ON(!spin_is_locked(&dev->dev_lock)); -#endif - - dev->pr_readers_count++; - cmd->dec_pr_readers_count_needed = 1; - TRACE_DBG("New inc pr_readers_count %d (cmd %p)", dev->pr_readers_count, - cmd); - - if (!locked) - spin_unlock_bh(&dev->dev_lock); - return; -} - -static inline void scst_dec_pr_readers_count(struct scst_cmd *cmd, - bool locked) -{ - struct scst_device *dev = cmd->dev; - - if (unlikely(!cmd->dec_pr_readers_count_needed)) { - PRINT_ERROR("__scst_check_local_events(x, false) should not " - "be called twice (cmd %p, op %x)! Use " - "scst_check_local_events() instead.", cmd, cmd->cdb[0]); - WARN_ON(1); - goto out; - } - - if (!locked) - spin_lock_bh(&dev->dev_lock); - -#ifdef CONFIG_SMP - EXTRACHECKS_BUG_ON(!spin_is_locked(&dev->dev_lock)); -#endif - - dev->pr_readers_count--; - cmd->dec_pr_readers_count_needed = 0; - TRACE_DBG("New dec pr_readers_count %d (cmd %p)", dev->pr_readers_count, - cmd); - - if (!locked) - spin_unlock_bh(&dev->dev_lock); - -out: - EXTRACHECKS_BUG_ON(dev->pr_readers_count < 0); - return; -} - static inline bool scst_pr_type_valid(uint8_t type) { switch (type) { @@ -126,73 +69,24 @@ static inline bool scst_pr_type_valid(uint8_t type) } } -static inline bool scst_pr_read_lock(struct scst_cmd *cmd) +static inline void scst_pr_read_lock(struct scst_device *dev) { - struct scst_device *dev = cmd->dev; - bool unlock = false; - - TRACE_ENTRY(); - - smp_mb(); /* to sync with scst_pr_write_lock() */ - if (unlikely(dev->pr_writer_active)) { - unlock = true; - scst_dec_pr_readers_count(cmd, false); - mutex_lock(&dev->dev_pr_mutex); - } - - TRACE_EXIT_RES(unlock); - return unlock; + mutex_lock(&dev->dev_pr_mutex); } -static inline void scst_pr_read_unlock(struct scst_cmd *cmd, bool unlock) +static inline void scst_pr_read_unlock(struct scst_device *dev) { - struct scst_device *dev = cmd->dev; - - TRACE_ENTRY(); - - if (unlikely(unlock)) - mutex_unlock(&dev->dev_pr_mutex); - else - scst_dec_pr_readers_count(cmd, false); - - TRACE_EXIT(); - return; + mutex_unlock(&dev->dev_pr_mutex); } static inline void scst_pr_write_lock(struct scst_device *dev) { - TRACE_ENTRY(); - mutex_lock(&dev->dev_pr_mutex); - - dev->pr_writer_active = 1; - /* to sync with scst_pr_read_lock() and unlock() */ - smp_mb(); - - while (true) { - int readers; - spin_lock_bh(&dev->dev_lock); - readers = dev->pr_readers_count; - spin_unlock_bh(&dev->dev_lock); - if (readers == 0) - break; - TRACE_DBG("Waiting for %d readers (dev %p)", readers, dev); - msleep(1); - } - - TRACE_EXIT(); - return; } static inline void scst_pr_write_unlock(struct scst_device *dev) { - TRACE_ENTRY(); - - dev->pr_writer_active = 0; mutex_unlock(&dev->dev_pr_mutex); - - TRACE_EXIT(); - return; } int scst_pr_init_dev(struct scst_device *dev); diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h index 74d041000..f56d185be 100644 --- a/scst/src/scst_priv.h +++ b/scst/src/scst_priv.h @@ -120,6 +120,26 @@ extern unsigned long scst_trace_flag; #define SCST_MAX_EACH_INTERNAL_IO_SIZE (128*1024) #define SCST_MAX_IN_FLIGHT_INTERNAL_COMMANDS 32 +/* + * Compatibility with real-time (CONFIG_PREEMPT_RT_FULL) kernels. + * In such kernels: + * - Interrupt handlers run in kernel thread context (see e.g. + * http://lwn.net/Articles/302043/). + * - spin_lock() calls can sleep (see e.g. http://lwn.net/Articles/271817/). + * - local_irq functions manipulate preemptibility, not HW interruptibility + * (see also http://lwn.net/Articles/146861). + * For the upstream kernels up to at least kernel 3.14 _nort functions are + * only defined if a CONFIG PREEMPT RT patch has been applied to the kernel. + * See https://rt.wiki.kernel.org/index.php/CONFIG_PREEMPT_RT_Patch. + */ +#ifndef local_irq_enable_nort +/* Kernel does not have CONFIG_PREEMPT_RT patch */ +#define local_irq_enable_nort() local_irq_enable() +#define local_irq_disable_nort() local_irq_disable() +#define local_irq_save_nort(flags) local_irq_save(flags) +#define local_irq_restore_nort(flags) local_irq_restore(flags) +#endif + typedef void (*scst_i_finish_fn_t) (struct scst_cmd *cmd); extern struct mutex scst_mutex2; diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c index 7f4a89d37..c7e08ab7d 100644 --- a/scst/src/scst_sysfs.c +++ b/scst/src/scst_sysfs.c @@ -1185,11 +1185,6 @@ static void scst_tgt_release(struct kobject *kobj) return; } -static struct kobj_type tgt_ktype = { - .sysfs_ops = &scst_sysfs_ops, - .release = scst_tgt_release, -}; - static int __scst_process_luns_mgmt_store(char *buffer, struct scst_tgt *tgt, struct scst_acg *acg, bool tgt_kobj) { @@ -2405,6 +2400,97 @@ out: } EXPORT_SYMBOL(scst_create_tgt_attr); +#define SCST_TGT_SYSFS_STAT_ATTR(member_name, attr, dir, result_op) \ +static int scst_tgt_sysfs_##attr##_show_work_fn( \ + struct scst_sysfs_work_item *work) \ +{ \ + struct scst_tgt *tgt = work->tgt; \ + struct scst_session *sess; \ + int res; \ + uint64_t c = 0; \ + \ + BUILD_BUG_ON((unsigned)(dir) >= ARRAY_SIZE(sess->io_stats)); \ + \ + res = mutex_lock_interruptible(&scst_mutex); \ + if (res) \ + goto out; \ + list_for_each_entry(sess, &tgt->sess_list, sess_list_entry) \ + c += sess->io_stats[(dir)].member_name; \ + mutex_unlock(&scst_mutex); \ + \ + work->res_buf = kasprintf(GFP_KERNEL, "%llu\n", c result_op); \ + res = work->res_buf ? 0 : -ENOMEM; \ + \ +out: \ + kobject_put(&tgt->tgt_kobj); \ + return res; \ +} \ + \ +static ssize_t scst_tgt_sysfs_##attr##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, \ + char *buf) \ +{ \ + struct scst_tgt *tgt = \ + container_of(kobj, struct scst_tgt, tgt_kobj); \ + struct scst_sysfs_work_item *work; \ + int res; \ + \ + res = scst_alloc_sysfs_work(scst_tgt_sysfs_##attr##_show_work_fn, \ + true, &work); \ + if (res) \ + goto out; \ + \ + work->tgt = tgt; \ + SCST_SET_DEP_MAP(work, &scst_tgt_dep_map); \ + kobject_get(&tgt->tgt_kobj); \ + scst_sysfs_work_get(work); \ + res = scst_sysfs_queue_wait_work(work); \ + if (res == 0) \ + res = scnprintf(buf, PAGE_SIZE, "%s", work->res_buf); \ + scst_sysfs_work_put(work); \ + \ +out: \ + return res; \ +} \ + \ +static struct kobj_attribute scst_tgt_##attr##_attr = \ + __ATTR(attr, S_IRUGO, scst_tgt_sysfs_##attr##_show, NULL); + +SCST_TGT_SYSFS_STAT_ATTR(cmd_count, unknown_cmd_count, SCST_DATA_UNKNOWN, >> 0); +SCST_TGT_SYSFS_STAT_ATTR(cmd_count, write_cmd_count, SCST_DATA_WRITE, >> 0); +SCST_TGT_SYSFS_STAT_ATTR(io_byte_count, write_io_count_kb, SCST_DATA_WRITE, + >> 10); +SCST_TGT_SYSFS_STAT_ATTR(cmd_count, read_cmd_count, SCST_DATA_READ, >> 0); +SCST_TGT_SYSFS_STAT_ATTR(io_byte_count, read_io_count_kb, SCST_DATA_READ, + >> 10); +SCST_TGT_SYSFS_STAT_ATTR(cmd_count, bidi_cmd_count, SCST_DATA_BIDI, >> 0); +SCST_TGT_SYSFS_STAT_ATTR(io_byte_count, bidi_io_count_kb, SCST_DATA_BIDI, + >> 10); +SCST_TGT_SYSFS_STAT_ATTR(cmd_count, none_cmd_count, SCST_DATA_NONE, >> 0); + +static struct attribute *scst_tgt_attrs[] = { + &scst_rel_tgt_id.attr, + &scst_tgt_comment.attr, + &scst_tgt_addr_method.attr, + &scst_tgt_io_grouping_type.attr, + &scst_tgt_cpu_mask.attr, + &scst_tgt_unknown_cmd_count_attr.attr, + &scst_tgt_write_cmd_count_attr.attr, + &scst_tgt_write_io_count_kb_attr.attr, + &scst_tgt_read_cmd_count_attr.attr, + &scst_tgt_read_io_count_kb_attr.attr, + &scst_tgt_bidi_cmd_count_attr.attr, + &scst_tgt_bidi_io_count_kb_attr.attr, + &scst_tgt_none_cmd_count_attr.attr, + NULL, +}; + +static struct kobj_type tgt_ktype = { + .sysfs_ops = &scst_sysfs_ops, + .release = scst_tgt_release, + .default_attrs = scst_tgt_attrs, +}; + /* * Supposed to be called under scst_mutex. In case of error will drop, * then reacquire it. @@ -2468,45 +2554,6 @@ int scst_tgt_sysfs_create(struct scst_tgt *tgt) goto out_err; } - res = sysfs_create_file(&tgt->tgt_kobj, - &scst_rel_tgt_id.attr); - if (res != 0) { - PRINT_ERROR("Can't add attribute %s for tgt %s", - scst_rel_tgt_id.attr.name, tgt->tgt_name); - goto out_err; - } - - res = sysfs_create_file(&tgt->tgt_kobj, - &scst_tgt_comment.attr); - if (res != 0) { - PRINT_ERROR("Can't add attribute %s for tgt %s", - scst_tgt_comment.attr.name, tgt->tgt_name); - goto out_err; - } - - res = sysfs_create_file(&tgt->tgt_kobj, - &scst_tgt_addr_method.attr); - if (res != 0) { - PRINT_ERROR("Can't add attribute %s for tgt %s", - scst_tgt_addr_method.attr.name, tgt->tgt_name); - goto out_err; - } - - res = sysfs_create_file(&tgt->tgt_kobj, - &scst_tgt_io_grouping_type.attr); - if (res != 0) { - PRINT_ERROR("Can't add attribute %s for tgt %s", - scst_tgt_io_grouping_type.attr.name, tgt->tgt_name); - goto out_err; - } - - res = sysfs_create_file(&tgt->tgt_kobj, &scst_tgt_cpu_mask.attr); - if (res != 0) { - PRINT_ERROR("Can't add attribute %s for tgt %s", - scst_tgt_cpu_mask.attr.name, tgt->tgt_name); - goto out_err; - } - if (tgt->tgtt->tgt_attrs) { res = sysfs_create_files(&tgt->tgt_kobj, tgt->tgtt->tgt_attrs); if (res != 0) { diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 35be2e746..697083bf6 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -119,8 +119,6 @@ static bool scst_check_blocked_dev(struct scst_cmd *cmd) cmd->dec_on_dev_needed = 1; TRACE_DBG("New inc on_dev_count %d (cmd %p)", dev->on_dev_cmd_count, cmd); - scst_inc_pr_readers_count(cmd, true); - if (unlikely(dev->block_count > 0) || unlikely(dev->dev_double_ua_possible) || unlikely((cmd->op_flags & SCST_SERIALIZED) != 0)) @@ -134,8 +132,6 @@ static bool scst_check_blocked_dev(struct scst_cmd *cmd) cmd->dec_on_dev_needed = 0; TRACE_DBG("New dec on_dev_count %d (cmd %p)", dev->on_dev_cmd_count, cmd); - - scst_dec_pr_readers_count(cmd, true); } spin_unlock_bh(&dev->dev_lock); @@ -159,9 +155,6 @@ static void scst_check_unblock_dev(struct scst_cmd *cmd) dev->on_dev_cmd_count, cmd); } - if (unlikely(cmd->dec_pr_readers_count_needed)) - scst_dec_pr_readers_count(cmd, true); - if (unlikely(cmd->unblock_dev)) { TRACE_BLOCK("cmd %p (tag %llu): unblocking dev %s", cmd, (long long unsigned int)cmd->tag, dev->virt_name); @@ -744,7 +737,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd) cmd->op_flags &= ~SCST_UNKNOWN_LENGTH; } - if (unlikely(cmd->cdb[cmd->cdb_len - 1] & CONTROL_BYTE_NACA_BIT)) { + if (unlikely(cmd->cmd_naca)) { PRINT_ERROR("NACA bit in control byte CDB is not supported " "(opcode 0x%02x)", cmd->cdb[0]); scst_set_cmd_error(cmd, @@ -752,7 +745,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd) goto out_done; } - if (unlikely(cmd->cdb[cmd->cdb_len-1] & CONTROL_BYTE_LINK_BIT)) { + if (unlikely(cmd->cmd_linked)) { PRINT_ERROR("Linked commands are not supported " "(opcode 0x%02x)", cmd->cdb[0]); scst_set_invalid_field_in_cdb(cmd, cmd->cdb_len-1, @@ -948,23 +941,34 @@ set_res: out: #ifdef CONFIG_SCST_EXTRACHECKS - /* - * At this point either both lba and data_len must be initialized to - * at least 0 for not data transfer commands, or cmd must be - * completed (with an error) and have correct state set. - */ - if (unlikely((((cmd->lba == SCST_DEF_LBA_DATA_LEN) && - !(cmd->op_flags & SCST_LBA_NOT_VALID)) || - (cmd->data_len == SCST_DEF_LBA_DATA_LEN)) && - (!cmd->completed || - (((cmd->state < SCST_CMD_STATE_PRE_XMIT_RESP) || - (cmd->state >= SCST_CMD_STATE_LAST_ACTIVE)) && - (cmd->state != SCST_CMD_STATE_PREPROCESSING_DONE))))) { - PRINT_CRIT_ERROR("Not initialized data_len for going to " - "execute command or bad state (cmd %p, data_len %lld, " - "completed %d, state %d)", cmd, - (long long)cmd->data_len, cmd->completed, cmd->state); - sBUG(); + if (unlikely(cmd->completed)) { + /* Command completed with error */ + bool valid_state = (cmd->state == SCST_CMD_STATE_PREPROCESSING_DONE) || + ((cmd->state >= SCST_CMD_STATE_PRE_XMIT_RESP) && + (cmd->state < SCST_CMD_STATE_LAST_ACTIVE)); + + if (!valid_state) { + PRINT_CRIT_ERROR("Bad state for completed cmd " + "(cmd %p, state %d)", cmd, cmd->state); + sBUG(); + } + } else if (cmd->state != SCST_CMD_STATE_PARSE) { + /* + * Ready to execute. At this point both lba and data_len must + * be initialized or marked non-applicable. + */ + bool bad_lba = (cmd->lba == SCST_DEF_LBA_DATA_LEN) && + !(cmd->op_flags & SCST_LBA_NOT_VALID); + bool bad_data_len = (cmd->data_len == SCST_DEF_LBA_DATA_LEN); + + if (unlikely(bad_lba || bad_data_len)) { + PRINT_CRIT_ERROR("Uninitialized lba or data_len for " + "ready-to-execute command (cmd %p, lba %lld, " + "data_len %lld, state %d)", cmd, + (long long)cmd->lba, (long long)cmd->data_len, + cmd->state); + sBUG(); + } } #endif @@ -2211,7 +2215,7 @@ static int scst_persistent_reserve_in_local(struct scst_cmd *cmd) if (unlikely(buffer_size <= 0)) goto out_done; - scst_pr_write_lock(dev); + scst_pr_read_lock(dev); /* We can be aborted by another PR command while waiting for the lock */ if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))) { @@ -2246,7 +2250,7 @@ out_complete: cmd->completed = 1; out_unlock: - scst_pr_write_unlock(dev); + scst_pr_read_unlock(dev); scst_put_buf_full(cmd, buffer); @@ -2303,6 +2307,12 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd) goto out_done; } + buffer_size = scst_get_buf_full_sense(cmd, &buffer); + if (unlikely(buffer_size <= 0)) + goto out_done; + + scst_pr_write_lock(dev); + /* * Check if tgt_dev already registered. Also by this check we make * sure that table "PERSISTENT RESERVE OUT service actions that are @@ -2314,20 +2324,16 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd) (tgt_dev->registrant == NULL)) { TRACE_PR("'%s' not registered", cmd->sess->initiator_name); scst_set_cmd_error_status(cmd, SAM_STAT_RESERVATION_CONFLICT); - goto out_done; + goto out_unlock; } - buffer_size = scst_get_buf_full_sense(cmd, &buffer); - if (unlikely(buffer_size <= 0)) - goto out_done; - /* Check scope */ if ((action != PR_REGISTER) && (action != PR_REGISTER_AND_IGNORE) && (action != PR_CLEAR) && (cmd->cdb[2] >> 4) != SCOPE_LU) { TRACE_PR("Scope must be SCOPE_LU for action %x", action); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); - goto out_put_buf_full; + goto out_unlock; } /* Check SPEC_I_PT (PR_REGISTER_AND_MOVE has another format) */ @@ -2336,7 +2342,7 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd) TRACE_PR("SPEC_I_PT must be zero for action %x", action); scst_set_cmd_error(cmd, SCST_LOAD_SENSE( scst_sense_invalid_field_in_cdb)); - goto out_put_buf_full; + goto out_unlock; } /* Check ALL_TG_PT (PR_REGISTER_AND_MOVE has another format) */ @@ -2345,11 +2351,9 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd) TRACE_PR("ALL_TG_PT must be zero for action %x", action); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); - goto out_put_buf_full; + goto out_unlock; } - scst_pr_write_lock(dev); - /* We can be aborted by another PR command while waiting for the lock */ aborted = test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags); if (unlikely(aborted)) { @@ -2400,7 +2404,6 @@ static int scst_persistent_reserve_out_local(struct scst_cmd *cmd) out_unlock: scst_pr_write_unlock(dev); -out_put_buf_full: scst_put_buf_full(cmd, buffer); out_done: @@ -2438,7 +2441,6 @@ int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only) /* * The original command passed all checks and not finished yet */ - sBUG_ON(cmd->dec_pr_readers_count_needed); res = 0; goto out; } @@ -2455,7 +2457,7 @@ int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only) if ((cmd->op_flags & SCST_REG_RESERVE_ALLOWED) == 0) { scst_set_cmd_error_status(cmd, SAM_STAT_RESERVATION_CONFLICT); - goto out_dec_pr_readers_count; + goto out_complete; } } @@ -2466,8 +2468,7 @@ int __scst_check_local_events(struct scst_cmd *cmd, bool preempt_tests_only) SAM_STAT_RESERVATION_CONFLICT); goto out_complete; } - } else - scst_dec_pr_readers_count(cmd, false); + } } /* @@ -2521,10 +2522,6 @@ out: TRACE_EXIT_RES(res); return res; -out_dec_pr_readers_count: - if (cmd->dec_pr_readers_count_needed) - scst_dec_pr_readers_count(cmd, false); - out_complete: res = 1; sBUG_ON(!cmd->completed); @@ -5163,7 +5160,7 @@ void scst_unblock_aborted_cmds(const struct scst_tgt *tgt, continue; spin_lock_bh(&dev->dev_lock); - local_irq_disable(); + local_irq_disable_nort(); list_for_each_entry_safe(cmd, tcmd, &dev->blocked_cmd_list, blocked_cmd_list_entry) { @@ -5177,10 +5174,10 @@ void scst_unblock_aborted_cmds(const struct scst_tgt *tgt, TRACE_MGMT_DBG("Unblock aborted blocked cmd %p", cmd); } } - local_irq_enable(); + local_irq_enable_nort(); spin_unlock_bh(&dev->dev_lock); - local_irq_disable(); + local_irq_disable_nort(); list_for_each_entry(tgt_dev, &dev->dev_tgt_dev_list, dev_tgt_dev_list_entry) { struct scst_order_data *order_data = tgt_dev->curr_order_data; @@ -5203,7 +5200,7 @@ void scst_unblock_aborted_cmds(const struct scst_tgt *tgt, } spin_unlock(&order_data->sn_lock); } - local_irq_enable(); + local_irq_enable_nort(); } if (!scst_mutex_held) @@ -6241,7 +6238,7 @@ static int scst_post_rx_mgmt_cmd(struct scst_session *sess, sBUG(); } - local_irq_save(flags); + local_irq_save_nort(flags); spin_lock(&sess->sess_list_lock); @@ -6270,7 +6267,7 @@ static int scst_post_rx_mgmt_cmd(struct scst_session *sess, list_add_tail(&mcmd->mgmt_cmd_list_entry, &scst_active_mgmt_cmd_list); spin_unlock(&scst_mcmd_lock); - local_irq_restore(flags); + local_irq_restore_nort(flags); wake_up(&scst_mgmt_cmd_list_waitQ); @@ -6280,7 +6277,7 @@ out: out_unlock: spin_unlock(&sess->sess_list_lock); - local_irq_restore(flags); + local_irq_restore_nort(flags); goto out; } diff --git a/scst_local/Makefile b/scst_local/Makefile index 7d7e318e2..2dee7552a 100644 --- a/scst_local/Makefile +++ b/scst_local/Makefile @@ -2,10 +2,6 @@ # A Makefile for the scst-local ... # -ifndef PREFIX - PREFIX=/usr/local -endif - SHELL=/bin/bash KMOD := $(shell pwd)/kernel @@ -24,24 +20,40 @@ EXTRA_CFLAGS += -DCONFIG_SCST_EXTRACHECKS EXTRA_CFLAGS += -DCONFIG_SCST_DEBUG -g -fno-inline -fno-inline-functions +ifneq ($(PATCHLEVEL),) +obj-m := scst_local.o +else +######### BEGIN OUT-OF-TREE RULES ######### + +ifndef PREFIX + PREFIX=/usr/local +endif + ifeq ($(KVER),) ifeq ($(KDIR),) - KDIR := /lib/modules/$(shell uname -r)/build + KVER := $(shell uname -r) + KDIR := /lib/modules/$(KVER)/build + else + KVER := $(strip $(shell \ + cat $(KDIR)/include/config/kernel.release 2>/dev/null || \ + make -s -C $(KDIR) kernelversion)) endif else KDIR := /lib/modules/$(KVER)/build endif -ifneq ($(PATCHLEVEL),) -obj-m := scst_local.o -else +ifeq ($(INSTALL_MOD_PATH),) + export INSTALL_MOD_PATH := $(DESTDIR) +endif + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra SCST_INC_DIR := $(shell if [ -e "$$PWD/../scst" ]; \ then echo "$$PWD/../scst/include"; \ - else echo "$(PREFIX)/include/scst"; fi) + else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi) SCST_DIR := $(shell if [ -e "$$PWD/../scst" ]; \ then echo "$$PWD/../scst/src"; \ - else echo "$(PREFIX)/include/scst"; fi) + else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi) all: Modules.symvers Module.symvers $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ @@ -50,7 +62,6 @@ all: Modules.symvers Module.symvers install: all $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd) BUILD_INI=m \ SCST_INC_DIR=$(SCST_INC_DIR) modules_install - -/sbin/depmod -aq $(KVER) SCST_MOD_VERS := $(shell ls $(SCST_DIR)/Modules.symvers 2>/dev/null) ifneq ($(SCST_MOD_VERS),) @@ -71,7 +82,9 @@ endif uninstall: rm -f $(INSTALL_DIR)/scst_local.ko - -/sbin/depmod -a $(KVER) + -/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER) + +########## END OUT-OF-TREE RULES ########## endif clean: diff --git a/scst_local/in-tree/Makefile-3.13 b/scst_local/in-tree/Makefile-3.13 new file mode 100644 index 000000000..8cbbbff63 --- /dev/null +++ b/scst_local/in-tree/Makefile-3.13 @@ -0,0 +1,2 @@ +obj-$(CONFIG_SCST_LOCAL) += scst_local.o + diff --git a/scst_local/scst_local.c b/scst_local/scst_local.c index ed46a8527..5953ae38e 100644 --- a/scst_local/scst_local.c +++ b/scst_local/scst_local.c @@ -375,9 +375,10 @@ static ssize_t scst_local_stats_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - return sprintf(buf, "Aborts: %d, Device Resets: %d, Target Resets: %d", - atomic_read(&num_aborts), atomic_read(&num_dev_resets), - atomic_read(&num_target_resets)); + return sprintf(buf, + "Aborts: %d, Device Resets: %d, Target Resets: %d\n", + atomic_read(&num_aborts), atomic_read(&num_dev_resets), + atomic_read(&num_target_resets)); } static struct kobj_attribute scst_local_stats_attr = @@ -960,6 +961,14 @@ static int scst_local_queuecommand_lck(struct scsi_cmnd *SCpnt, TRACE_DBG("lun %d, cmd: 0x%02X", SCpnt->device->lun, SCpnt->cmnd[0]); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) + /* + * We save a pointer to the done routine in SCpnt->scsi_done and + * we save that as tgt specific stuff below. + */ + SCpnt->scsi_done = done; +#endif + sess = to_scst_lcl_sess(scsi_get_device(SCpnt->device->host)); if (sess->unregistering) { @@ -983,12 +992,6 @@ static int scst_local_queuecommand_lck(struct scsi_cmnd *SCpnt, } tgt_specific->cmnd = SCpnt; tgt_specific->done = done; -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) - /* - * We save a pointer to the done routine in SCpnt->scsi_done and - * we save that as tgt specific stuff below. - */ - SCpnt->scsi_done = done; #endif /* diff --git a/scstadmin/Makefile b/scstadmin/Makefile index 53821b3a8..5d7b1be0a 100644 --- a/scstadmin/Makefile +++ b/scstadmin/Makefile @@ -136,7 +136,6 @@ rpm: rpmtopdir="$$(if [ $$(id -u) = 0 ]; then echo /usr/src/packages;\ else echo $$PWD/rpmbuilddir; fi)" && \ $(MAKE) dist-gzip && \ - rm -rf $${rpmtopdir} && \ for d in BUILD RPMS SOURCES SPECS SRPMS; do \ mkdir -p $${rpmtopdir}/$$d; \ done && \ diff --git a/scstadmin/scstadmin.sysfs/scst-0.9.10/t/after-restore.conf b/scstadmin/scstadmin.sysfs/scst-0.9.10/t/after-restore.conf index 9bcda73e5..5e248d128 100644 --- a/scstadmin/scstadmin.sysfs/scst-0.9.10/t/after-restore.conf +++ b/scstadmin/scstadmin.sysfs/scst-0.9.10/t/after-restore.conf @@ -14,7 +14,7 @@ TARGET_DRIVER scst_local { LUN 0 disk01 LUN 1 disk01 - GROUP initator_group { + GROUP initiator_group { LUN 0 disk01 LUN 1 disk01 { read_only 1 diff --git a/scstadmin/scstadmin.sysfs/scst-0.9.10/t/to-be-restored.conf b/scstadmin/scstadmin.sysfs/scst-0.9.10/t/to-be-restored.conf index c5c3d6320..b4988b721 100644 --- a/scstadmin/scstadmin.sysfs/scst-0.9.10/t/to-be-restored.conf +++ b/scstadmin/scstadmin.sysfs/scst-0.9.10/t/to-be-restored.conf @@ -20,7 +20,7 @@ TARGET_DRIVER scst_local { LUN 0 disk01 LUN 1 disk01 - GROUP initator_group { + GROUP initiator_group { LUN 0 disk01 LUN 1 disk01 { read_only 1 diff --git a/srpt/Makefile b/srpt/Makefile index 046026325..3a5c1c8c7 100644 --- a/srpt/Makefile +++ b/srpt/Makefile @@ -7,23 +7,35 @@ endif SCST_INC_DIR := $(shell if [ -e "$$PWD/../scst" ]; \ then echo "$$PWD/../scst/include"; \ - else echo "$(PREFIX)/include/scst"; fi) + else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi) SCST_SYMVERS_DIR := $(shell if [ -e $$PWD/../scst ]; then \ echo $$PWD/../scst/src; \ - else echo $(PREFIX)/include/scst; fi) + else echo $(DESTDIR)$(PREFIX)/include/scst; fi) SUBDIRS := $(shell pwd) ifeq ($(KVER),) ifeq ($(KDIR),) - KVER = $(shell uname -r) - KDIR ?= /lib/modules/$(KVER)/build + KVER := $(shell uname -r) + KDIR := /lib/modules/$(KVER)/build else - KVER = $$KERNELRELEASE + ifeq ($(KERNELRELEASE),) + KVER := $(strip $(shell \ + cat $(KDIR)/include/config/kernel.release 2>/dev/null || \ + make -s -C $(KDIR) kernelversion)) + else + KVER := $(KERNELRELEASE) + endif endif else - KDIR ?= /lib/modules/$(KVER)/build + KDIR := /lib/modules/$(KVER)/build endif +ifeq ($(INSTALL_MOD_PATH),) + export INSTALL_MOD_PATH := $(DESTDIR) +endif + +INSTALL_DIR := $(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra + # Set variable $(2) to value $(3) in file $(1). set_var = $(shell { if [ -e "$(1)" ]; then grep -v '^$(2)=' "$(1)"; fi; echo "$(2)=$(3)"; } >/tmp/$(1)-$$$$.tmp && mv /tmp/$(1)-$$$$.tmp $(1)) @@ -59,10 +71,13 @@ all: src/$(MODULE_SYMVERS) PRE_CFLAGS="$(OFED_CFLAGS)" SCST_INC_DIR=$(SCST_INC_DIR) modules install: all src/ib_srpt.ko - @eval `sed -n 's/#define UTS_RELEASE /KERNELRELEASE=/p' $(KDIR)/include/linux/version.h $(KDIR)/include/linux/utsrelease.h 2>/dev/null`; \ - install -vD -m 644 src/ib_srpt.ko \ - $(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/$(KVER)/extra/ib_srpt.ko - -/sbin/depmod -aq $(KVER) + $(MAKE) -C $(KDIR) SUBDIRS=$(shell pwd)/src \ + PRE_CFLAGS="$(OFED_CFLAGS)" SCST_INC_DIR=$(SCST_INC_DIR) \ + modules_install + +uninstall: + rm -f $(INSTALL_DIR)/ib_srpt.ko + -/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER) src/Module.symvers src/Modules.symvers: $(SCST_SYMVERS_DIR)/$(MODULE_SYMVERS) @if $(OFED_KERNEL_IB_RPM_INSTALLED); then \ diff --git a/srpt/patches/kernel-3.13-pre-cflags.patch b/srpt/patches/kernel-3.13-pre-cflags.patch new file mode 100644 index 000000000..3964ee179 --- /dev/null +++ b/srpt/patches/kernel-3.13-pre-cflags.patch @@ -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) \ diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index 67c8c6424..6b9b54fa8 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -2340,17 +2340,21 @@ static void srpt_drain_channel(struct ib_cm_id *cm_id) static void __srpt_close_all_ch(struct srpt_tgt *srpt_tgt) { - struct srpt_rdma_ch *ch, *next_ch; + struct srpt_rdma_ch *ch; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) lockdep_assert_held(&srpt_tgt->spinlock); #endif - list_for_each_entry_safe(ch, next_ch, &srpt_tgt->rch_list, list) { +restart: + list_for_each_entry(ch, &srpt_tgt->rch_list, list) { + if (ch->state >= CH_DISCONNECTING) + continue; PRINT_INFO("Closing channel %s because target %s has been" " disabled", ch->sess_name, srpt_tgt->scst_tgt->tgt_name); - __srpt_close_ch(ch); + WARN_ON_ONCE(!__srpt_close_ch(ch)); + goto restart; } } diff --git a/usr/fileio/Makefile b/usr/fileio/Makefile index 5cdb3e3ed..6b193e219 100644 --- a/usr/fileio/Makefile +++ b/usr/fileio/Makefile @@ -28,7 +28,7 @@ OBJS_F = $(SRCS_F:.c=.o) SCST_INC_DIR := ../../scst/include #SCST_INC_DIR := $(PREFIX)/include/scst -INSTALL_DIR := $(PREFIX)/bin/scst +INSTALL_DIR := $(DESTDIR)$(PREFIX)/bin/scst CFLAGS += -O2 -Wall -Wextra -Wno-unused-parameter -Wstrict-prototypes \ -I$(SCST_INC_DIR) -D_GNU_SOURCE -D__USE_FILE_OFFSET64 \ diff --git a/www/handler_fileio_tgt.html b/www/handler_fileio_tgt.html index c6c9a56b0..f1e1c52c4 100644 --- a/www/handler_fileio_tgt.html +++ b/www/handler_fileio_tgt.html @@ -41,7 +41,7 @@
  • QLogic FC qla2x00t
  • SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters
  • FCoE Target
  • Local Target Driver
  • diff --git a/www/scst_admin.html b/www/scst_admin.html index 51735b0c0..fe75d019d 100644 --- a/www/scst_admin.html +++ b/www/scst_admin.html @@ -41,7 +41,7 @@
  • QLogic FC qla2x00t
  • SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters
  • FCoE Target
  • Local Target Driver
  • diff --git a/www/target_emulex.html b/www/target_emulex.html index 020666203..9d5668bca 100644 --- a/www/target_emulex.html +++ b/www/target_emulex.html @@ -6,7 +6,7 @@ -Emulex lpfc FC/FCoE target driver +Emulex FC/FCoE target driver @@ -41,7 +41,7 @@
  • QLogic FC qla2x00t
  • SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters
  • FCoE Target
  • Local Target Driver
  • @@ -56,17 +56,17 @@
    -

    Target driver for Emulex lpfc FC/FCoE adapters

    +

    Target driver for Emulex FC/FCoE adapters

    SCST Emulex -

    The ocs_fc_scst target driver for Emulex lpfc FC/FCoE adapters is developed by the Emulex team - and is available at the Emulex OneCore SDK - developer site. Register for free at the Developer Portal Access +

    The ocs_fc_scst target driver for Emulex FC/FCoE adapters is developed by the Emulex team + and is available at the Emulex OneCore SDK + developer site. Register for free at the Developer Portal Access page to get the source code and documentation. The Emulex OneCore SDK is built around the Emulex SLI-4 (Service Level Interface) API and is compatible with Emulex 16 Gb/s Fibre Channel HBAs (LPe16000 series) and Ethernet based target mode FCoE UCNAs (OCe11102-F series).

    -

    The ocs_fc_scst driver allows for lpfc adapters to be placed in initiator and/or target mode. +

    The ocs_fc_scst driver allows for Emulex adapters to be placed in initiator and/or target mode. The driver effectively maps SCST to the Emulex SLI-4 interface allowing a simple transition to Emulex 16Gb/s fibre channel technology for existing or new SCST users. NPIV is also supported, allowing virtual ports to be created with individual SCST target instances bound to them. @@ -79,7 +79,7 @@

     
    diff --git a/www/target_fcoe.html b/www/target_fcoe.html index 732ebfd3f..cdf4ae8f8 100644 --- a/www/target_fcoe.html +++ b/www/target_fcoe.html @@ -41,7 +41,7 @@
  • QLogic FC qla2x00t
  • SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters
  • FCoE Target
  • Local Target Driver
  • diff --git a/www/target_ibmvscsi.html b/www/target_ibmvscsi.html index 2d4ffa74d..6b01c9621 100644 --- a/www/target_ibmvscsi.html +++ b/www/target_ibmvscsi.html @@ -41,7 +41,7 @@
  • QLogic FC qla2x00t
  • SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters
  • FCoE Target
  • Local Target Driver
  • diff --git a/www/target_iscsi.html b/www/target_iscsi.html index a683a1889..3a7c7ecd0 100644 --- a/www/target_iscsi.html +++ b/www/target_iscsi.html @@ -41,7 +41,7 @@
  • QLogic FC qla2x00t
  • SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters
  • FCoE Target
  • Local Target Driver
  • diff --git a/www/target_iser.html b/www/target_iser.html index 72d237ba2..cc9448569 100644 --- a/www/target_iser.html +++ b/www/target_iser.html @@ -41,7 +41,7 @@
  • QLogic FC qla2x00t
  • SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters
  • FCoE Target
  • Local Target Driver
  • diff --git a/www/target_local.html b/www/target_local.html index acd8fc022..dffa4e96b 100644 --- a/www/target_local.html +++ b/www/target_local.html @@ -41,7 +41,7 @@
  • QLogic FC qla2x00t
  • SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters
  • FCoE Target
  • Local Target Driver
  • diff --git a/www/target_lsi.html b/www/target_lsi.html index 96ec00043..1f8ab013b 100644 --- a/www/target_lsi.html +++ b/www/target_lsi.html @@ -41,7 +41,7 @@
  • QLogic FC qla2x00t
  • SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters
  • FCoE Target
  • Local Target Driver
  • diff --git a/www/target_mvsas.html b/www/target_mvsas.html index 2e7fd2722..4941e8751 100644 --- a/www/target_mvsas.html +++ b/www/target_mvsas.html @@ -41,7 +41,7 @@
  • QLogic FC qla2x00t
  • SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters
  • FCoE Target
  • Local Target Driver
  • diff --git a/www/target_old.html b/www/target_old.html index 78da83f27..6de51239b 100644 --- a/www/target_old.html +++ b/www/target_old.html @@ -41,7 +41,7 @@
  • QLogic FC qla2x00t
  • SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters
  • FCoE Target
  • Local Target Driver
  • diff --git a/www/target_qla2x00t.html b/www/target_qla2x00t.html index 9f992ccdf..d804fdbf1 100644 --- a/www/target_qla2x00t.html +++ b/www/target_qla2x00t.html @@ -41,7 +41,7 @@
  • QLogic FC qla2x00t
  • SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters
  • FCoE Target
  • Local Target Driver
  • diff --git a/www/target_srp.html b/www/target_srp.html index 2a7326cdc..53ae21f5e 100644 --- a/www/target_srp.html +++ b/www/target_srp.html @@ -41,7 +41,7 @@
  • QLogic FC qla2x00t
  • SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters
  • FCoE Target
  • Local Target Driver
  • diff --git a/www/targets.html b/www/targets.html index f0eefddcb..892d9afdc 100644 --- a/www/targets.html +++ b/www/targets.html @@ -41,7 +41,7 @@
  • QLogic FC qla2x00t
  • SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters
  • FCoE Target
  • Local Target Driver
  • @@ -64,7 +64,7 @@
  • Fibre Channel QLogic qla2xxx series
  • Infiniband SCSI RDMA Protocol (SRP)
  • Marvell SAS adapters
  • -
  • Emulex lpfc FC/FCoE adapters
  • +
  • Emulex FC/FCoE adapters
  • LSI/MPT adapters (parallel SCSI, including Wide Ultra320, SAS, Fibre Channel)
  • FCoE
  • Local access