diff --git a/Makefile b/Makefile index 68f2964f9..d3f42b76c 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ help: all: cd $(SCST_DIR) && $(MAKE) $@ # @if [ -d $(DOC_DIR) ]; then cd $(DOC_DIR) && $(MAKE) $@; fi - @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi + @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; else if [ -d $(QLA_OLD_DIR) ]; then cd $(QLA_OLD_DIR) && $(MAKE) $@; fi fi # @if [ -d $(QLA_OLD_DIR) ]; then cd $(QLA_OLD_DIR) && $(MAKE) $@; fi # @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi # @if [ -d $(SRP_DIR) ]; then cd $(SRP_DIR) && $(MAKE) $@; fi @@ -152,7 +152,7 @@ all: install: cd $(SCST_DIR) && $(MAKE) $@ # @if [ -d $(DOC_DIR) ]; then cd $(DOC_DIR) && $(MAKE) $@; fi - @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi + @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; else if [ -d $(QLA_OLD_DIR) ]; then cd $(QLA_OLD_DIR) && $(MAKE) $@; fi fi # @if [ -d $(QLA_OLD_DIR) ]; then cd $(QLA_OLD_DIR) && $(MAKE) $@; fi # @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi # @if [ -d $(SRP_DIR) ]; then cd $(SRP_DIR) && $(MAKE) $@; fi @@ -163,7 +163,7 @@ install: uninstall: cd $(SCST_DIR) && $(MAKE) $@ # @if [ -d $(DOC_DIR) ]; then cd $(DOC_DIR) && $(MAKE) $@; fi - @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; fi + @if [ -d $(QLA_DIR) ]; then cd $(QLA_DIR) && $(MAKE) $@; else if [ -d $(QLA_OLD_DIR) ]; then cd $(QLA_OLD_DIR) && $(MAKE) $@; fi fi # @if [ -d $(QLA_OLD_DIR) ]; then cd $(QLA_OLD_DIR) && $(MAKE) $@; fi # @if [ -d $(LSI_DIR) ]; then cd $(LSI_DIR) && $(MAKE) $@; fi @if [ -d $(SRP_DIR) ]; then cd $(SRP_DIR) && $(MAKE) $@; fi @@ -228,10 +228,10 @@ docs_extraclean: scstadm: cd $(SCSTADM_DIR) && $(MAKE) all -scstadm_install: +scstadm_install: cd $(SCSTADM_DIR) && $(MAKE) install -scstadm_uninstall: +scstadm_uninstall: cd $(SCSTADM_DIR) && $(MAKE) uninstall scstadm_clean: @@ -252,7 +252,7 @@ qla_install: qla_uninstall: cd $(QLA_DIR) && $(MAKE) uninstall -qla_clean: +qla_clean: cd $(QLA_INI_DIR) && $(MAKE) clean cd $(QLA_DIR) && $(MAKE) clean @@ -284,7 +284,7 @@ iscsi_install: iscsi_uninstall: cd $(ISCSI_DIR) && $(MAKE) uninstall -iscsi_clean: +iscsi_clean: cd $(ISCSI_DIR) && $(MAKE) clean iscsi_extraclean: @@ -383,7 +383,13 @@ fcst_extraclean: scst-dist-gzip: name=scst && \ mkdir $${name}-$(VERSION) && \ - { scripts/list-source-files | \ + { if [ -h qla2x00t ] || { mount | grep "on $$PWD/qla2x00t type"; }; \ + then \ + scripts/list-source-files | grep -v ^qla2x00t/; \ + find qla2x00t/ -type f; \ + else \ + scripts/list-source-files; \ + fi | \ grep -E '^doc/|^fcst/|^iscsi-scst/|^Makefile|^qla2x00t/|^scst.spec|^scst/|^scst_local/|^srpt/'|\ tar -T- -cf- | \ tar -C $${name}-$(VERSION) -xf-; } && \ @@ -402,8 +408,9 @@ scst-rpm: cp $${name}-$(VERSION).tar.bz2 $${rpmtopdir}/SOURCES && \ sed "s/@rpm_version@/$(VERSION)/g" \ <$${name}.spec.in >$${name}.spec; \ - MAKE="$(MAKE)" \ - rpmbuild --define="%_topdir $${rpmtopdir}" -ba $${name}.spec && \ + MAKE="$(MAKE)" rpmbuild --define="%_topdir $${rpmtopdir}" \ + $(if $(KVER),--define="%kversion $(KVER)") \ + -ba $${name}.spec && \ rm -f $${name}-$(VERSION).tar.bz2 rpm: diff --git a/doc/Makefile b/doc/Makefile index 44257779d..d2b95bd76 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -8,7 +8,7 @@ RTFS = $(SRCS:.sgml=.rtf) COMMAND=linuxdoc --backend= -all: txt pdf html +all: pdf html txt: $(TXTS) diff --git a/doc/fig2.png b/doc/fig2.png index 3bdf882dc..667e41289 100644 Binary files a/doc/fig2.png and b/doc/fig2.png differ diff --git a/doc/fig3.png b/doc/fig3.png deleted file mode 100644 index e502f2dd3..000000000 Binary files a/doc/fig3.png and /dev/null differ diff --git a/doc/fig4.png b/doc/fig4.png deleted file mode 100644 index 667e41289..000000000 Binary files a/doc/fig4.png and /dev/null differ diff --git a/doc/scst_pg.sgml b/doc/scst_pg.sgml index f690b2536..eb2475b12 100644 --- a/doc/scst_pg.sgml +++ b/doc/scst_pg.sgml @@ -2,135 +2,99 @@
-Generic SCSI Target Middle Level for Linux + +SCST technical description + Vladislav Bolkhovitin -Version 0.9.5 2006/12/01, actual for SCST 0.9.5 and later - - -This document describes SCSI target mid-level for Linux (SCST), its -architecture and drivers from the driver writer's point of view. - + +Version 3.0.0 for SCST 3.0.0 and later + Introduction -

-SCST is a SCSI target mid-level subsystem for Linux. It is designed to -provide unified, consistent interface between SCSI target drivers and -Linux kernel and simplify target drivers development as much as -possible. It has the following features: +

SCST is a SCSI target mid-level subsystem for Linux. It provides +unified consistent interface between SCSI target drivers, backend device +handlers and Linux kernel as well as simplifies target drivers +development as much as possible. - +It has the following features: - Very low overhead, fine-grained locks and simplest commands -processing path, which allow to reach maximum possible performance and -scalability that close to theoretical limit. + - Incoming requests can be processed in the caller's context or in -one of the internal SCST's tasklets, therefore no extra context switches -required. + Very low overhead and fine-grained locks, which allow to reach +maximum possible performance and scalability that close to theoretical +limit. Complete SMP support. - Undertakes most problems, related to execution contexts, thus -practically eliminating one of the most complicated problem in the -kernel drivers development. For example, target drivers for Marvell SAS -adapters or for InfiniBand SRP are less 3000 lines of code long. - Performs all required pre- and post- processing of incoming -requests and all necessary error recovery functionality. +requests and all necessary error recovery functionality. - Emulates necessary functionality of SCSI host adapter, because + Emulates necessary functionality of SCSI host adapters, because from a remote initiator's point of view SCST acts as a SCSI host with its own devices. Some of the emulated functions are the following: - + Generation of necessary UNIT ATTENTIONs, their storage and delivery to all connected remote initiators (sessions). - RESERVE/RELEASE functionality. + RESERVE/RELEASE functionality, including Persistent Reservations. - CA/ACA conditions. - All types of RESETs and other task management functions. - - REPORT LUNS command as well as SCSI address space management - in order to have consistent address space on all remote initiators, - since local SCSI devices could not know about each other to report - via REPORT LUNS command. Additionally, SCST responds with error on - all commands to non-existing devices and provides access control - (not implemented yet), so different remote initiators could see - different set of devices. + + REPORT LUNS command as well as SCSI address space + management in order to have consistent address space on all + remote initiators, since local SCSI devices could not know about + each other to report via REPORT LUNS command. Additionally, SCST + responds with error on all commands to non-existing devices and + provides access control, so different remote initiators could + see different set of devices. Other necessary functionality (task attributes, etc.) as specified in SAM-2, SPC-2, SAM-3, SPC-3 and other SCSI standards. - + - - Device handlers architecture provides extra reliability and -security via verifying all incoming requests and allows to make any -additional requests processing, which is completely independent from -target drivers, for example, data caching or device dependent -exceptional conditions treatment. + + Verifies all incoming requests to ensure commands execution +reliability and security. + + Device handlers architecture provides extra flexibility by +allowing to make additional requests processing, which is completely +independent from target drivers, for example, data caching or device +dependent exceptional conditions treatment. -Interoperability between SCST and local SCSI initiators (like sd, st) is -the additional issue that SCST is going to address (it is not -implemented yet). It is necessary, because local SCSI initiators can -change the state of the device, for example RESERVE the device, or some -of its parameters and that would be done behind SCST, which could lead -to various problems. Thus, RESERVE/RELEASE commands, locally generated -UNIT ATTENTIONs, etc. should be intercepted and processed as if local -SCSI initiators act as remote SCSI initiators connected to SCST. This -feature requires some the kernel modification. Since in the current -version it is not implemented, SCST and the target drivers are able to -work with any unpatched 2.4 kernel version. - -Interface between SCST and the target drivers is based on work, done by -University of New Hampshire Interoperability Labs (UNH IOL). - -All described below data structures and function could be found in -. - Terms and Definitions -

+SCST Architecture +SCST Core Architecture -

+

SCST accepts commands and passes them to SCSI mid-level at the same way as SCSI high-level drivers (sg, sd, st) do. Figure 1 shows interaction between SCST, its drivers and Linux SCSI subsystem. @@ -171,42 +135,61 @@ interaction between SCST, its drivers and Linux SCSI subsystem. -Target driver registration + Target drivers + +struct scst_tgt_template

To work with SCST a target driver must register its template in SCST by -calling scst_register_target_template(). The template lets SCST know the +calling Structure scst_tgt_template - -

-struct scst_tgt_template +struct scst_tgt_template { int sg_tablesize; - const char name[15]; + const char name[SCST_MAX_NAME]; unsigned unchecked_isa_dma:1; unsigned use_clustering:1; + unsigned no_clustering:1; - unsigned xmit_response_atomic:1; + unsigned xmit_response_atomic:1; unsigned rdy_to_xfer_atomic:1; - unsigned report_aen_atomic:1; - int (* detect) (struct scst_tgt_template *tgt_template); - int (* release)(struct scst_tgt *tgt); + unsigned no_proc_entry:1; - int (* xmit_response)(struct scst_cmd *cmd); + int max_hw_pending_time; + + int threads_num; + + int (*detect) (struct scst_tgt_template *tgt_template); + int (*release)(struct scst_tgt *tgt); + + int (*xmit_response)(struct scst_cmd *cmd); int (* rdy_to_xfer)(struct scst_cmd *cmd); - + + void (*on_hw_pending_cmd_timeout) (struct scst_cmd *cmd); + void (*on_free_cmd) (struct scst_cmd *cmd); - void (* task_mgmt_fn_done)(struct scst_mgmt_cmd *mgmt_cmd); - void (* report_aen)(int mgmt_fn, const uint8_t *lun, int lun_len); - - int (*proc_info) (char *buffer, char **start, off_t offset, - int length, int *eof, struct scst_tgt *tgt, int inout); + int (*alloc_data_buf) (struct scst_cmd *cmd); + + void (*preprocessing_done) (struct scst_cmd *cmd); + + int (*pre_exec) (struct scst_cmd *cmd); + + void (*task_mgmt_affected_cmds_done) (struct scst_mgmt_cmd *mgmt_cmd); + void (*task_mgmt_fn_done)(struct scst_mgmt_cmd *mgmt_cmd); + + int (*report_aen) (struct scst_aen *aen); + + int (*read_proc) (struct seq_file *seq, struct scst_tgt *tgt); + int (*write_proc) (char *buffer, char **start, off_t offset, + int length, int *eof, struct scst_tgt *tgt); + + int (*get_initiator_port_transport_id) (struct scst_session *sess, + uint8_t **transport_id); } @@ -225,97 +208,163 @@ the template. Must be defined. unchecked DMA onto an ISA bus. = 0 to signify -the number of detected target adapters. A negative value should be -returned whenever there is an error. Must be defined. += 0 to +signify the number of detected target adapters. A negative value should +be returned whenever there is an error. Must be defined. - +0 if the regular SCST allocation should be done. In case of returning +successfully, scst_cmd->tgt_data_buf_alloced will be set by SCST. It is +possible that both target driver and dev handler request own memory +allocation. If allocation in atomic context, i.e. scst_cmd_atomic() is +true, and < 0 is returned, this function will be recalled in thread +context. Note that the driver will have to handle itself all relevant +details such as scatterlist setup, highmem, freeing the allocated +memory, etc. + + - - + Functions @@ -333,7 +382,7 @@ can return the following error codes: -More about More about xmit_response() -

-As already written above, function +As already written above, function xmit_response() should transmit +the response data and the status from the cmd parameter. - - - - -If Target driver registration functions scst_register_target_template() @@ -416,13 +442,13 @@ Where: Returns 0 on success or appropriate error code otherwise. -scst_register() +scst_register_target()

-Function -struct scst_tgt *scst_register( +struct scst_tgt *scst_register_target( struct scst_tgt_template *vtt) @@ -434,20 +460,20 @@ Where: Returns target structure based on template vtt or NULL in case of error. -Target driver unregistration +Target driver unregistration functions

In order to unregister itself target driver should at first call -scst_unregister() +scst_unregister_target()

-Function -void scst_unregister( +void scst_unregister_target( struct scst_tgt *tgt) @@ -457,7 +483,7 @@ Where: -scst_unregister_target_template() +scst_unregister_target_template()

Function -SCST session registration +Device specific drivers (backend device handlers) -

-When target driver determines that it needs to create new SCST session -(for example, by receiving new TCP connection), it should call - -struct scst_session *scst_register_session( - struct scst_tgt *tgt, - int atomic, - const char *initiator_name, - void *data, - void (*result_fn) ( - struct scst_session *sess, - void *data, - int result)); - - -Where: - - - - - - - - - -A session creation and initialization is a complex task, which requires -sleeping state, so it can't be fully done in interrupt context. -Therefore the "bottom half" of it, if - - - - Session registration when - - -

- - - - Session registration when -
- -SCST session unregistration - -

-SCST session unregistration basically is the same, except that instead of -atomic parameter there is -void scst_unregister_session( - struct scst_session *sess, - int wait, - void (* unreg_done_fn)( - struct scst_session *sess)) - - -Where: - - - - - - - - - -All outstanding commands will be finished regularly. After -The commands processing and interaction between SCST and its drivers - -

-The commands processing by SCST started when target driver calls - - -If the command required no data transfer, it will be passed to -SCSI mid-level directly or via device handler's If the command is a If the command is a - -When the command is finished by SCSI mid-level, device handler's - - - - - The commands processing flow - - - -Additionally, before calling - - Expected transfer length and direction via - - -The commands processing functions - -scst_rx_cmd() - -

-Function -struct scst_cmd *scst_rx_cmd( - struct scst_session *sess, - const uint8_t *lun, - int lun_len, - const uint8_t *cdb, - int cdb_len, - int atomic) - - -Where: - - - - - -scst_cmd_init_done() - -

-Function -void scst_cmd_init_done( - struct scst_cmd *cmd, - int pref_context) - - -Where: - - - - - -scst_rx_data() - -

-Function -void scst_rx_data( - struct scst_cmd *cmd, - int status, - int pref_context) - - -Where: - - - - - -Parameter - - - -scst_tgt_cmd_done() - -

-Function -void scst_tgt_cmd_done( - struct scst_cmd *cmd) - - -Where: - - - -The commands processing context - -

-Execution context often is a major problem in the kernel drivers -development, because many contexts, like IRQ one, greatly limit -available functionality, therefore require additional complex code in -order to pass processing to more simple context. SCST does its best to -undertake most of the context handling. - -On the initialization time SCST creates for internal command processing -as many threads as there are processors in the system or specified by -user via -Directly, i.e. in the caller's context, without limitations -Directly atomically, i.e. with sleeping forbidden -In the SCST's internal per processor or per session thread -In the SCST's per processor tasklet - - -The target driver sets this context as pref_context parameter for -Preferred context constants - -

-There are the following preferred context constants: - - - - - -Task management functions - -

-There are the following task management functions supported: - - - - - -scst_rx_mgmt_fn_tag() - -

-Function -int scst_rx_mgmt_fn_tag( - struct scst_session *sess, - int fn, - uint32_t tag, - int atomic, - void *tgt_specific) - - -Where: - - - - - -Returns 0 if the command was successfully created and scheduled for -execution, error code otherwise. On success, the completion status of -the command will be reported asynchronously via scst_rx_mgmt_fn_lun() - -

-Function -int scst_rx_mgmt_fn_lun( - struct scst_session *sess, - int fn, - const uint8_t *lun, - int lun_len, - int atomic, - void *tgt_specific); - - -Where: - - - - - -Returns 0 if the command was successfully created and scheduled for -execution, error code otherwise. On success, the completion status of -the command will be reported asynchronously via Device specific drivers (device handlers) - -

-Device specific drivers are plugins for SCST, which help SCST to analyze -incoming requests and determine parameters, specific to various types -of devices. Device handlers are intended for the following: +

Device specific drivers are add-ons for SCST, which help SCST to +analyze incoming requests and determine parameters, specific to various +types of devices as well as actually execute specified SCSI commands. +Device handlers are intended for the following: @@ -1013,41 +513,237 @@ current device's configuration exactly as an end-target SCSI device does. This serves two purposes: - + Improves security and reliability by not trusting the data supplied by remote initiator via SCSI low-level protocol. - + Some low-level SCSI protocols don't provide data transfer length and direction, so that information can be get only directly from CDB and current device's configuration. For example, for tape devices to get data transfer size it might be necessary to know block size setting. - + + Execute commands + To process some exceptional conditions, like ILI on tape devices. To initialize incoming commands with some device-specific parameters, like timeout value. -To allow some additional device-specific commands pre-, post- +To allow some additional device-specific commands pre-, post- processing or alternative execution, like copying data from system cache, and do that completely independently from target drivers. -Device handlers performs very lightweight processing and therefore -should not considerably affect performance or CPU load. They are -considered to be part of SCST, so they could directly access any fields -in SCST's structures as well as use the corresponding functions. +Device handlers considered to be part of SCST, so they could directly +access any fields in SCST's structures as well as use the corresponding +functions. Without appropriate device handler SCST hides devices of this type from remote initiators and returns Device specific driver registration +Structure scst_register_dev_driver() +

+Structure +struct scst_dev_type +{ + char name[]; + int type; + + unsigned parse_atomic:1; + unsigned alloc_data_buf_atomic:1; + unsigned dev_done_atomic:1; + + unsigned no_proc:1; + + unsigned exec_sync:1; + + unsigned pr_cmds_notifications:1; + + int threads_num; + enum scst_dev_type_threads_pool_type threads_pool_type; + + int (*attach) (struct scst_device *dev); + void (*detach) (struct scst_device *dev); + + int (*attach_tgt) (struct scst_tgt_device *tgt_dev); + void (*detach_tgt) (struct scst_tgt_device *tgt_dev); + + int (*parse) (struct scst_cmd *cmd); + int (*alloc_data_buf) (struct scst_cmd *cmd); + int (*exec) (struct scst_cmd *cmd); + int (*dev_done) (struct scst_cmd *cmd); + int (*on_free_cmd) (struct scst_cmd *cmd); + + int (*task_mgmt_fn) (struct scst_mgmt_cmd *mgmt_cmd, + struct scst_tgt_dev *tgt_dev); + + int (*read_proc) (struct seq_file *seq, struct scst_dev_type *dev_type); + int (*write_proc) (char *buffer, char **start, off_t offset, + int length, int *eof, struct scst_dev_type *dev_type); +} + + +Where: + + + + 0. Possible values: + + + + + +bufflen/ and data_direction/ (both - REQUIRED). Returns the +command's scst_cmd_done()/ callback. + +Returns: + + + + +If this function provides sync execution, you should set +exec_sync flag and consider to setup dedicated threads by +setting 0. + +Optional, if not set, the commands will be sent directly to SCSI +device. + + + + + + + +Device specific drivers registration + + scst_register_dev_driver()

To work with SCST a device specific driver must register itself in SCST by @@ -1066,256 +762,57 @@ Where: The function returns 0 on success or appropriate error code otherwise. -Structure scst_register_virtual_device()

-Structure -struct scst_dev_type -{ - char name[15]; - int type; - - unsigned parse_atomic:1; - unsigned exec_atomic:1; - unsigned dev_done_atomic:1; - - int (*init) (struct scst_dev_type *dev_type); - void (*release) (struct scst_dev_type *dev_type); - - int (*attach) (struct scst_device *dev); - void (*detach) (struct scst_device *dev); - - int (*attach_tgt) (struct scst_tgt_device *tgt_dev); - void (*detach_tgt) (struct scst_tgt_device *tgt_dev); - - int (*parse) (struct scst_cmd *cmd); - int (*exec) (struct scst_cmd *cmd, - void (*scst_cmd_done)(struct scsi_cmnd *cmd, int next_state)); - int (*dev_done) (struct scst_cmd *cmd); - int (*task_mgmt_fn) (struct scst_mgmt_cmd *mgmt_cmd, - struct scst_tgt_dev *tgt_dev, struct scst_cmd *cmd_to_abort); - int (*on_free_cmd) (struct scst_cmd *cmd); - - int (*proc_info) (char *buffer, char **start, off_t offset, - int length, int *eof, struct scst_dev_type *dev_type, - int inout) - - struct module *module; -} +int scst_register_virtual_device( + struct scst_dev_type *dev_handler, + const char *dev_name) Where: -bufflen/ and data_direction/ (see below - - - - - - - - - - - - -If the driver needs to create additional files in its /proc -subdirectory, it can use -Structure Device specific drivers unregistration + + scst_unregister_virtual_device() + +

+Virtual devices unregistered by calling + -struct scst_info_cdb -{ - enum scst_cdb_flags flags; - scst_data_direction direction; - unsigned int transfer_len; - unsigned short cdb_len; - const char *op_name; -} +void scst_unregister_virtual_device( + int id) Where: - - - - - - -Field data_direction/, set by - - - -Device specific driver unregistration + scst_unregister_dev_driver()

Device specific driver is unregistered by calling @@ -1332,968 +829,1350 @@ Where: -SCST commands' states +SCST sessions -

-There are the following states, which a SCST command passes through -during execution and which could be returned by device handler's -SCST sessions registration + +

+When target driver determines that it needs to create new SCST session +(for example, by receiving new TCP connection), it should call + +struct scst_session *scst_register_session( + struct scst_tgt *tgt, + int atomic, + const char *initiator_name, + void *tgt_priv, + void *result_fn_data, + void (*result_fn) ( + struct scst_session *sess, + void *data, + int result)) + + +Where: -tgt_dev/ + + + + + + +A session creation and initialization is a complex task, which requires +sleeping state, so it can't be fully done in interrupt context. +Therefore the "bottom half" of it, if scst_register_session() is +called from atomic context, will be done in SCST thread context. In this +case scst_register_session() will return not completely initialized +session, but the target driver can supply commands to this session via +scst_rx_cmd(). Those commands processing will be delayed inside +SCST until the session initialization is finished, then their processing +will be restarted. The target driver will be notified about finish of +the session initialization by function SCST sessions unregistration + +

+SCST session unregistration basically is the same, except that instead of +atomic parameter there is +void scst_unregister_session( + struct scst_session *sess, + int wait, + void (*unreg_done_fn)( + struct scst_session *sess)) + + +Where: + + + + + + + + + +All outstanding commands will be finished regularly. After +scst_unregister_session() returned no new commands must be sent to SCST +via scst_rx_cmd(). Also, the caller must ensure that no scst_rx_cmd() or +scst_rx_mgmt_fn_*() is called in parallel with +scst_unregister_session(). + +Function scst_unregister_session()/ can be called before result_fn() of +scst_register_session() called, i.e. during the session +registration/initialization. + + +Commands processing and interaction between SCST core and its drivers + +

+Consider simplified commands processing example. It assumes that target +driver doesn't need own memory allocation, i.e. not defined +alloc_data_buf() callback. Example of such target driver is qla2x00t. + +The commands processing by SCST started when target driver calls + + +If the command required no data transfer, it will be passed to +SCSI mid-level directly or via device handler's If the command is a If the command is a + +When the command is finished by SCSI mid-level, device handler's + + + + + The commands processing flow + + + +The commands processing functions + +scst_rx_cmd() + +

+Function +struct scst_cmd *scst_rx_cmd( + struct scst_session *sess, + const uint8_t *lun, + int lun_len, + const uint8_t *cdb, + int cdb_len, + int atomic) + + +Where: + + + + + +scst_cmd_init_done() + +

+Function +void scst_cmd_init_done( + struct scst_cmd *cmd, + enum scst_exec_context pref_context) + + +Where: + + + + + +scst_rx_data() + +

+Function +void scst_rx_data( + struct scst_cmd *cmd, + int status, + enum scst_exec_context pref_context) + + +Where: + + + + + +Parameter + + + +scst_tgt_cmd_done() + +

+Function +void scst_tgt_cmd_done( + struct scst_cmd *cmd, + enum scst_exec_context pref_context) + + +Where: + + + + +The commands processing context + +

+Execution context often is a major problem in the kernel drivers +development, because many contexts, like IRQ context, greatly limit +available functionality, therefore require additional complex code in +order to pass processing to more simple context. SCST does its best to +undertake most of the context handling. + +On the initialization time SCST creates for internal command processing +as many threads as there are processors in the system or specified by +user via +Directly, i.e. in the caller's context, without limitations +Directly atomically, i.e. with sleeping forbidden +In the SCST's internal threads +In the SCST's per processor tasklets + + +The target driver sets this context as pref_context parameter for SCST +functions. Additionally, target's template's Preferred context constants + +

+There are the following preferred context constants: + + + + + +SCST commands' processing states + +

+There are the following processing states, which a SCST command passes +through during execution and which could be returned by device handler's + + +tgt_dev/ assignment) state - -SCST's structures manipulation functions + +Task management functions

-Target drivers must not directly access any fields in SCST's structures, -they must use only described below functions. - -SCST target driver manipulation functions - -scst_tgt_get_tgt_specific() and scst_tgt_set_tgt_specific() - -

-Function -void *scst_tgt_get_tgt_specific( - struct scst_tgt *tgt) - - -Function -void scst_tgt_set_tgt_specific( - struct scst_tgt *tgt, - void *val) - - -Where: +There are the following task management functions supported: - -SCST session manipulation functions +All task management functions return completion status via +scst_sess_get_tgt_specific() and scst_sess_set_tgt_specific() +scst_rx_mgmt_fn_tag()

-Function -void *scst_sess_get_tgt_specific( - struct scst_session *sess) - - -Function -void scst_sess_set_tgt_specific( +int scst_rx_mgmt_fn_tag( struct scst_session *sess, - void *val) + int fn, + uint32_t tag, + int atomic, + void *tgt_priv) Where: - -SCST command manipulation functions +Returns 0 if the command was successfully created and scheduled for +execution, error code otherwise. On success, the completion status of +the command will be reported asynchronously via task_mgmt_fn_done() +driver's callback. -scst_cmd_atomic() +scst_rx_mgmt_fn_lun()

-Function -int scst_cmd_atomic( - struct scst_cmd *cmd) - - -Where: - - - - -scst_cmd_get_session() - -

-Function -struct scst_session *scst_cmd_get_session( - struct scst_cmd *cmd) - - -Where: - - - - -scst_cmd_get_resp_data_len() - -

-Function -unsigned int scst_cmd_get_resp_data_len( - struct scst_cmd *cmd) - - -Where: - - - - -scst_cmd_get_tgt_resp_flags() - -

-Function -int scst_cmd_get_tgt_resp_flags( - struct scst_cmd *cmd) - - -Where: - - - - -scst_cmd_get_buffer() - -

-Function -void *scst_cmd_get_buffer( - struct scst_cmd *cmd) - - -Where: - - - - -It is recommended to use scst_cmd_get_bufflen() - -

-Function -unsigned int scst_cmd_get_bufflen( - struct scst_cmd *cmd) - - -Where: - - - - -It is recommended to use scst_cmd_get_use_sg() - -

-Function -unsigned short scst_cmd_get_use_sg( - struct scst_cmd *cmd) - - -Where: - - - - -It is recommended to use scst_cmd_get_data_direction() - -

-Function -scst_data_direction scst_cmd_get_data_direction( - struct scst_cmd *cmd) - - -Where: - - - - -scst_cmd_get_status() - -

-Functions -uint8_t scst_cmd_get_status( - struct scst_cmd *cmd) - - -Where: - - - - -scst_cmd_get_masked_status() - -

-Functions -uint8_t scst_cmd_get_masked_status( - struct scst_cmd *cmd) - - -Where: - - - - -scst_cmd_get_msg_status() - -

-Functions -uint8_t scst_cmd_get_msg_status( - struct scst_cmd *cmd) - - -Where: - - - - -scst_cmd_get_host_status() - -

-Functions -uint16_t scst_cmd_get_host_status( - struct scst_cmd *cmd) - - -Where: - - - - -scst_cmd_get_driver_status() - -

-Functions -uint16_t scst_cmd_get_driver_status( - struct scst_cmd *cmd) - - -Where: - - - - -scst_cmd_get_sense_buffer() - -

-Functions -uint8_t *scst_cmd_get_sense_buffer( - struct scst_cmd *cmd) - - -Where: - - - - -scst_cmd_get_sense_buffer_len() - -

-Functions -int scst_cmd_get_sense_buffer_len( - struct scst_cmd *cmd) - - -Where: - - - - -scst_cmd_get_tag() and scst_cmd_set_tag() - -

Function -uint32_t scst_cmd_get_tag( - struct scst_cmd *cmd) - - -Function -void scst_cmd_set_tag( - struct scst_cmd *cmd, - uint32_t tag) - - -Where: - - - - -scst_cmd_get_tgt_specific() and scst_cmd_get_tgt_specific_lock() - -

-Functions -void *scst_cmd_get_tgt_specific( - struct scst_cmd *cmd) - - - -void *scst_cmd_get_tgt_specific_lock( - struct scst_cmd *cmd) - - -Where: - - - - -scst_cmd_set_tgt_specific() and scst_cmd_set_tgt_specific_lock() - -

-Functions -void *scst_cmd_set_tgt_specific( - struct scst_cmd *cmd, - void *val) - - - -void *scst_cmd_set_tgt_specific_lock( - struct scst_cmd *cmd, - void *val) - - -Where: - - - - -scst_cmd_get_data_buff_alloced() and scst_cmd_set_data_buff_alloced() - -

-Function -int scst_cmd_get_data_buff_alloced( - struct scst_cmd *cmd) - - -Function -void scst_cmd_set_data_buff_alloced( - struct scst_cmd *cmd) - - -Where: - - - - -scst_cmd_set_expected(), scst_cmd_is_expected_set(), -scst_cmd_get_expected_data_direction() and -scst_cmd_get_expected_transfer_len() - -

-Function -void scst_cmd_set_expected( - struct scst_cmd *cmd, - scst_data_direction expected_data_direction, - unsigned int expected_transfer_len) - - -Function -int scst_cmd_is_expected_set( - struct scst_cmd *cmd) - - -Function -scst_data_direction scst_cmd_get_expected_data_direction( - struct scst_cmd *cmd) - - -Function -unsigned int scst_cmd_get_expected_transfer_len( - struct scst_cmd *cmd) - - -Where: - - - - -scst_get_buf_first(), scst_get_buf_next(), -scst_put_buf() and scst_get_buf_count() - -

-These functions are designed to simplify and unify access to the -commands data (SG vector or plain data buffer) in all possible -conditions, including HIGHMEM environment, and should be used instead of -direct access. - -Function -int scst_get_buf_first( - struct scst_cmd *cmd, - uint8_t **buf) - - -Where: - - - - -Returns the length of the chunk of data for success, 0 for the end of -data, negative error code otherwise. - -Function -int scst_get_buf_next( - struct scst_cmd *cmd, - uint8_t **buf) - - -Where: - - - - -Returns the length of the chunk of data for success, 0 for the end of -data, negative error code otherwise. - -Function -void scst_put_buf( - struct scst_cmd *cmd, - uint8_t *buf) - - -Where: - - - - -Function -int scst_get_buf_count( - struct scst_cmd *cmd) - - -Where: - - - - -SCST task management commands manipulation functions - -scst_mgmt_cmd_get_tgt_specific() - -

-Function -void *scst_mgmt_cmd_get_tgt_specific( - struct scst_mgmt_cmd *mcmd) - - -Where: - - - - -scst_mgmt_cmd_get_status() - -

-Functions -void *scst_mgmt_cmd_get_status( - struct scst_mgmt_cmd *mcmd) - - -Where: - - - - -The following status values are possible: - - - - SCST_MGMT_STATUS_SUCCESS - the task management command completed -successfully - - SCST_MGMT_STATUS_FAILED - the task management command failed. - - - -Miscellaneous functions - -scst_find_cmd_by_tag() - -

-Function -struct scst_cmd *scst_find_cmd_by_tag( - struct scst_session *sess, - uint32_t tag) +int scst_rx_mgmt_fn_lun( + struct scst_session *sess, + int fn, + const uint8_t *lun, + int lun_len, + int atomic, + void *tgt_priv); Where: - -Returns found command or NULL otherwise. +Returns 0 if the command was successfully created and scheduled for +execution, error code otherwise. On success, the completion status of +the command will be reported asynchronously via task_mgmt_fn_done() +driver's callback. -scst_find_cmd() +Possible status constants which can be returned by + + + + +SGV cache

-Function -struct scst_cmd *scst_find_cmd( - struct scst_session *sess, - void *data, - int (*cmp_fn)(struct scst_cmd *cmd, void *data)) - - -Where: +SCST SGV cache is a memory management subsystem in SCST. One can call it +a "memory pool", but Linux kernel already have a mempool interface, +which serves different purposes. SGV cache provides to SCST core, target +drivers and backend dev handlers facilities to allocate, build and cache +SG vectors for data buffers. The main advantage of it is the caching +facility, when it doesn't free to the system each vector, which is not +used anymore, but keeps it for a while (possibly indefinitely) to let it +be reused by the next consecutive command. This allows to: - Reduce commands processing latencies and, hence, improve performance; - - + Make commands processing latencies predictable, which is essential + for RT applications. -Returns found command or NULL otherwise. +The freed SG vectors are kept by the SGV cache either for some (possibly +indefinite) time, or, optionally, until the system needs more memory and +asks to free some using the set_shrinker() interface. Also the SGV cache +allows to: - -SCST is designed in a such way that any command is always processed only -by one thread at any time, so no locking is necessary. But there is one -exception from that rule, it is Cluster pages together. "Cluster" means merging adjacent pages in a +single SG entry. It allows to have less SG entries in the resulting SG +vector, hence improve performance handling it as well as allow to +work with bigger buffers on hardware with limited SG capabilities. -scst_get_cdb_info() + Set custom page allocator functions. For instance, scst_user device +handler uses this facility to eliminate unneeded mapping/unmapping of +user space pages and avoid unneeded IOCTL calls for buffers allocations. +In fileio_tgt application, which uses a regular malloc() function to +allocate data buffers, this facility allows ~30% less CPU load and +considerable performance increase. + + Prevent each initiator or all initiators altogether to allocate too +much memory and DoS the target. Consider 10 initiators, which can have +access to 10 devices each. Any of them can queue up to 64 commands, each +can transfer up to 1MB of data. So, all of them in a peak can allocate +up to 10*10*64 = ~6.5GB of memory for data buffers. This amount must be +limited somehow and the SGV cache performs this function. + + + + Implementation

-Function -int scst_get_cdb_info( - const uint8_t *cdb_p, - int dev_type, - struct scst_info_cdb *info_p) - + -Where: + With fixed size buffers. - + With a set of power 2 size buffers. In this mode each SGV cache +(struct sgv_pool) has SGV_POOL_ELEMENTS (11 currently) of kmem caches. +Each of those kmem caches keeps SGV cache objects (struct sgv_pool_obj) +corresponding to SG vectors with size of order X pages. For instance, +request to allocate 4 pages will be served from kmem cache[2&rsqb, since the +order of the of number of requested pages is 2. If later request to +allocate 11KB comes, the same SG vector with 4 pages will be reused (see +below). This mode is in average allows less memory overhead comparing +with the fixed size buffers mode. - - +In both modes, if size of a request exceeds the maximum allowed for +caching buffer size, the requested buffer will be allocated, but not +cached. -Returns 0 on success, -1 otherwise. +Freed cached sgv_pool_obj objects are actually freed to the system +either by the purge work, which is scheduled once in 60 seconds, or in +sgv_shrink() called by system, when it's asking for memory. -scst_to_dma_dir() + Interface + + sgv_pool *sgv_pool_create()

-Function -int scst_to_dma_dir( - int scst_dir) +struct sgv_pool *sgv_pool_create( + const char *name, + enum sgv_clustering_types clustered, int single_alloc_pages, + bool shared, int purge_interval) -Where: +This function creates and initializes an SGV cache. It has the following +arguments: - + + + + 0, then the SGV cache will work in the + fixed size buffers mode. In this case single_alloc_pages sets the + size of each buffer in pages. + + -Returns the corresponding scst_is_cmd_local() + void sgv_pool_del()

-Function -int scst_is_cmd_local( - struct scst_cmd *cmd) +void sgv_pool_del( + struct sgv_pool *pool) -Where: +This function deletes the corresponding SGV cache. If the cache is +shared, it will decrease its reference counter. If the reference counter +reaches 0, the cache will be destroyed. - - - -Returns 1, if the command's CDB is locally handled by SCST or 0 -otherwise - -scst_register_virtual_device() and scst_unregister_virtual_device() + void sgv_pool_flush()

-These functions provide a way for device handlers to register a virtual -(emulated) device, which will be visible only by remote initiators. For -example, FILEIO device handler uses files on file system to makes from -them virtual remotely available SCSI disks. - -Function -int scst_register_virtual_device( - struct scst_dev_type *dev_handler) +void sgv_pool_flush( + struct sgv_pool *pool) -Where: +This function flushes, i.e. frees, all the cached entries in the SGV +cache. - - - -Returns assigned to the device ID on success, or negative value otherwise. - -Function -void scst_unregister_virtual_device( - int id) - - -Where: - - - - -scst_add_threads() and scst_del_threads() + void sgv_pool_set_allocator()

-These functions allows to add or delete some SCST threads. For example, -if -int scst_add_threads( - int num) +void sgv_pool_set_allocator( + struct sgv_pool *pool, + struct page *(*alloc_pages_fn)(struct scatterlist *sg, gfp_t gfp, void *priv), + void (*free_pages_fn)(struct scatterlist *sg, int sg_count, void *priv)); -Where: +This function allows to set for the SGV cache a custom pages allocator. For +instance, scst_user uses such function to supply to the cache mapped from +user space pages. + + - -Returns 0 on success, error code otherwise. +This function should return the allocated page or NULL, if no page was +allocated. -Function -void scst_del_threads( - int num) - - -Where: + - -scst_proc_get_tgt_root() + struct scatterlist *sgv_pool_alloc()

-Function -struct proc_dir_entry *scst_proc_get_tgt_root( - struct scst_tgt_template *vtt) +struct scatterlist *sgv_pool_alloc( + struct sgv_pool *pool, + unsigned int size, + gfp_t gfp_mask, + int flags, + int *count, + struct sgv_pool_obj **sgv, + struct scst_mem_lim *mem_lim, + void *priv) -Where: +This function allocates an SG vector from the SGV cache. It has the +following parameters: - + + + + -Returns proc_dir_entry on success, NULL otherwise. +This function returns pointer to the resulting SG vector or NULL in case +of any error. -scst_proc_get_dev_type_root() + void sgv_pool_free()

-Function -struct proc_dir_entry *scst_proc_get_dev_type_root( - struct scst_dev_type *dtt) +void sgv_pool_free( + struct sgv_pool_obj *sgv, + struct scst_mem_lim *mem_lim) -Where: +This function frees previously allocated SG vector, referenced by SGV +cache object sgv. + + void *sgv_get_priv(struct sgv_pool_obj *sgv) + +

+ +void *sgv_get_priv( + struct sgv_pool_obj *sgv) + + +This function allows to get the allocation private data for this SGV +cache object sgv. The private data are set by sgv_pool_alloc(). + + void scst_init_mem_lim() + +

+ +void scst_init_mem_lim( + struct scst_mem_lim *mem_lim) + + +This function initializes memory limits structure mem_lim according to +the current system configuration. This structure should be latter used +to track and limit allocated by one or more SGV caches memory. + + + Runtime information and statistics. + +

+ SGV cache runtime information and statistics is available in +/proc/scsi_tgt/sgv. + + + Target driver qla2x00t + +

+Target driver qla2x00t allows to use QLogic 2xxx based adapters in +the target (server) mode. + +It consists from two parts: - -Returns proc_dir_entry on success, NULL otherwise. +The initiator driver qla2xxx was changed to: + + + + To provide support for the target mode add-on via a set of +exported callbacks + + To provide extra info and management interface in the driver's +sysfs interface (attributes target_mode_enabled, ports_database, etc.) + + To fix some problems uncovered during target mode development and +usage. + + + +The changes are relatively small (few thousands lines big patch) and local. + +The changed qla2xxx is still capable to work as initiator only. Mode, +when a host acts as initiator and target simultaneously, is supported as +well. + +Since firmware interface for 24xx+ chips is fundamentally different from +earlier versions, qla2x00t generally contains 2 separate drivers sharing +some common processing. + + Driver initialization + +

+On initialization, qla2x00tgt registers its SCST template tgt2x_template +in the SCST core. Then during template registration SCST core calls +detect() callback which is function q2t_target_detect(). + +In this function qla2x00tgt registers its callbacks in qla2xxx by +calling qla2xxx_tgt_register_driver(). Qla2xxx_tgt_register_driver() +stores pointer to the being registered callbacks in variable qla_target. + +Then q2t_target_detect() calls qla2xxx_add_targets(), which calls for +each known local FC port (HBA instance) qla_target.tgt_host_action() +callback with ADD_TARGET action. Then q2t_host_action() calls +q2t_add_target() which registers SCST target for this FC port. + +If later a new FC port is hot added, qla2x00_probe_one() will also call +for all new local ports qla_target.tgt_host_action() with ADD_TARGET +action. + + + Driver unload + +

+When a local FC port is being removed, the Linux kernel calls +qla2x00_remove_one(), which then qla_target.tgt_host_action() with +REMOVE_TARGET action. + +Then q2t_host_action() calls q2t_remove_target(), which unregisters the +corresponding SCST target in SCST. During unregistration SCST core calls +release() callback of tgt2x_template, which is q2t_target_release(). + +Then q2t_target_release() calls q2t_target_stop(). Then +q2t_target_stop() marks this target as stopped by setting flag tgt_stop. +When this flag is set, all incoming from initiators commands are +refused. + +Then q2t_target_stop() schedules deletion of all sessions of the target. + +Then q2t_target_stop() waits until all outstanding commands finished and +sessions deleted. + +Then q2t_target_stop(), if necessary, calls qla2x00_disable_tgt_mode() +to disables target mode, which disables target mode of the corresponding +HBA and resets it. Then qla2x00_disable_tgt_mode() waits until reset +finished. + +Then q2t_target_stop() returns and then q2t_target_release() frees the +target. + + +If module qla2x00tgt is being unloaded, q2t_exit() at first takes +q2t_unreg_rwsem on writing. Taking it is necessary to make sure that +q2t_host_action() will not be active during qla2x00tgt unload. + +Then q2t_exit() calls scst_unregister_target_template() for +tgt2x_template, which then in a loop will unregister all QLA SCST targets +from SCST as described above. + + + Enabling target mode + +

+When command to enable target mode received, +qla_target.tgt_host_action() with action ENABLE_TARGET_MODE called. Then +q2t_host_action() goes over all discovered remote of the being enabled +target and adds SCST sessions for all them. + +Then it calls qla2x00_enable_tgt_mode(), which enables target mode of +the corresponding HBA and resets it. Then qla2x00_enable_tgt_mode() +waits until reset finished. + +During reset firmware initialization functions detect that target mode +is enables and initialize the firmware accordingly. + + + Disabling target mode + +

+When command to disable target mode received, +qla_target.tgt_host_action() with action DISABLE_TARGET_MODE called. Then +q2t_host_action() calls q2t_target_stop(), which processes as describe above. + + + SCST sessions management + +

+As required by SCSI and FC standards, each remote initiator FC port +has the corresponding SCST session. + +Since qla2xxx is not intended to strictly maintain database of remote +initiator FC ports as it is needed for target mode, qla2x00t uses mixed +approach for SCST sessions management, when both qla2xxx and QLogic +firmware generate events and information about currently active remote +FC ports. + +Remote FC ports management also has to handle changing FC and loop IDs +after fabric events, so it needs to constantly monitor FC and loop IDs +of the registered FC ports. This is implemented by checks in +q2t_create_sess() that being registered FC port already has SCST session +and q2t_check_fcport_exist() in q2t_del_sess_work_fn(). See below for +more info. + +Interaction with qla2xxx is implemented using tgt_fc_port_added() and +tgt_fc_port_deleted() qla_target's callbacks. + +Callback tgt_fc_port_added() called by qla2xxx when the target driver +detects new remote FC port. Assigned to it q2t_fc_port_added() checks if +an SCST session already exists for this remote FC port and, if not, +creates it. + +Callback tgt_fc_port_deleted() called by qla2xxx when it deletes a +remote FC port from its database. Assigned to it q2t_fc_port_deleted() +checks if an SCST session already exists for this remote FC port and, if +yes, schedules it for deletion. + +Driver qla2x00tgt has 2 types of SCST sessions: local and not local. +Sessions created by q2t_fc_port_added() are not local. Local sessions +created if qla2x00tgt receives a command from remote initiator for which +there is no know remote FC port and, hence, SCST session. Local sessions +are created in tgt->sess_work (q2t_sess_work_fn()) by calling +q2t_make_local_sess(). All received from remote initiators commands for +local sessions are delayed until the sessions are created. + +To minimize affecting initiators by FC fabric events, qla2x00tgt doesn't +immediately delete SCST sessions scheduled for deletion, but instead +delay them for some time. If during this time a command from an unknown +remote initiator received, q2t_make_local_sess()/q2t_create_sess() at +first check if a session for this initiator already exists and, if yes, +undelete then reuse it after updating its s_id and loop_id to new values. + +If a session not reused during the delete delay time, then +q2t_del_sess_work_fn() asks the firmware internal database if it knows +the corresponding remote FC port. If yes, then this session is undeleted +and its s_id and loop_id updated to new values. If no, the session is +deleted. + + + Handling stuck commands + +

+Driver qla2x00tgt defines in tgt2x_template callback +on_hw_pending_cmd_timeout for handling stuck commands in +q2t_on_hw_pending_cmd_timeout() function, with max_hw_pending_time +timeout set Q2T_MAX_HW_PENDING_TIME (60 seconds). If the firmware +doesn't return reply for one or more IOCBs for the corresponding SCST +command, SCST core calls this callback. + +In this callback all the stuck commands are forcibly finished. + + + + Debugging and troubleshooting + +

+SCST core and its drivers provide excessive debugging and logging +facilities suitable to catch and analyze problems of virtually any level +of complexity. + +Depending from amount debugging and logging facilities available, there +are 3 types of builds: + + + + + +Switch between build modes is done by calling "make x2y", where "x" - +current build mode and "y" - desired build mode. For instance, to switch +from release to debug mode you should run "make release2debug". + + Logging levels management + +

+Logging levels management is done using "trace_level" file located in the +driver's proc interface subdirectory. Each SCST driver has it, except in +the perf build mode. For instance, for SCST core it's located in +/proc/scsi_tgt/. For qla2x00t it's located in /proc/scsi_tgt/qla2x00tgt/. + +Reading from it you can find currently enabled logging levels. + +You can change them by writing in this file, like: + +# echo "add scsi" >/proc/scsi_tgt/trace_level + +The following commands are available: + + + + + +The following trace levels are common for all drivers: + + + + + +The following trace levels are additionally available for SCST core: + + + + + + Preparing a debug kernel + +

+SCST logging can produce huge amount of logging, which default kernel +configuration can't cope with, so it needs some extra adjustments. + +For that you should change in lib/Kconfig.debug or init/Kconfig +depending from your kernel version LOG_BUF_SHIFT from "12 21" to "12 25". + +Then you should in your .config set CONFIG_LOG_BUF_SHIFT to 25. + +Also, Linux kernel has a lot of helpful debug facilities, like lockdep, +which allows to catch various deadlocks, or memory allocation debugging. +It is recommended to enable them during SCST debugging. + +The following options are recommended to be enabled (available depending +from your kernel version): CONFIG_SLUB_DEBUG, CONFIG_PRINTK_TIME, +CONFIG_MAGIC_SYSRQ, CONFIG_DEBUG_FS, CONFIG_DEBUG_KERNEL, +CONFIG_DEBUG_SHIRQ, CONFIG_DETECT_SOFTLOCKUP, CONFIG_DETECT_HUNG_TASK, +CONFIG_SLUB_DEBUG_ON, CONFIG_SLUB_STATS, CONFIG_DEBUG_PREEMPT, +CONFIG_DEBUG_RT_MUTEXES, CONFIG_DEBUG_PI_LIST, CONFIG_DEBUG_SPINLOCK, +CONFIG_DEBUG_MUTEXES, CONFIG_DEBUG_LOCK_ALLOC, CONFIG_PROVE_LOCKING, +CONFIG_LOCKDEP, CONFIG_LOCK_STAT, CONFIG_DEBUG_SPINLOCK_SLEEP, +CONFIG_STACKTRACE, CONFIG_DEBUG_BUGVERBOSE, CONFIG_DEBUG_VM, +CONFIG_DEBUG_VIRTUAL, CONFIG_DEBUG_WRITECOUNT, CONFIG_DEBUG_MEMORY_INIT, +CONFIG_DEBUG_LIST, CONFIG_DEBUG_SG, CONFIG_DEBUG_NOTIFIERS, +CONFIG_FRAME_POINTER, CONFIG_FAULT_INJECTION, CONFIG_FAILSLAB, +CONFIG_FAIL_PAGE_ALLOC, CONFIG_FAIL_MAKE_REQUEST, +CONFIG_FAIL_IO_TIMEOUT, CONFIG_FAULT_INJECTION_DEBUG_FS, +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER. + + Preparing logging subsystem + +

+It is recommended that you system logger daemon on the target configured: + + + + To store kernel logs in separate files on the fastest disk you +have. It will be better if this disk is dedicated for logging or, at +least, doesn't contain your LUNs data. + + To write the kernel logs to the disk in asynchronous manner, i.e. +without calling fsync() after each written message. Usually, you can +achieve it, if you add a '-' sign before the corresponding file path in +your syslog daemon conf file, like: + +kern.* -/var/log/kern.log + + + + Decoding OOPS messages + +

+You can decode an OOPS message to the corresponding line in C file +using gdb "l" command. For example, an OOPS message has a line: + + +[<ffffffff88646174>&rsqb :iscsi_scst:iscsi_extracheck_is_rd_thread+0x94/0xb0 + + +You can decode it by: + + +$ gdb iscsi-scst.ko +(gdb) l *iscsi_scst:iscsi_extracheck_is_rd_thread+0x94 + + +For that the corresponding module (iscsi-scst.ko) should be build with +debug info. But modules not always have debug info built-in. To +workaround it you can add "-g" flag in the corresponding Makefile +(without changing anything else!) or enable in .config using "make +menuconfig" building kernel with debug info. Then rebuild only the .o +file you need. + +For instance, to decode OOPS in mm/filemap.c in the kernel you need +enable in .config building kernel with debug info and then run: + + +$ make mm/filemap.o +... +$ gdb mm/filemap.o +

diff --git a/doc/sgv_cache.sgml b/doc/sgv_cache.sgml deleted file mode 100644 index 4d6240031..000000000 --- a/doc/sgv_cache.sgml +++ /dev/null @@ -1,335 +0,0 @@ - - -
- - -SCST SGV cache description - - - - Vladislav Bolkhovitin - - -Version 2.1.0 - - - -Introduction - -

-SCST SGV cache is a memory management subsystem in SCST. One can call it -a "memory pool", but Linux kernel already have a mempool interface, -which serves different purposes. SGV cache provides to SCST core, target -drivers and backend dev handlers facilities to allocate, build and cache -SG vectors for data buffers. The main advantage of it is the caching -facility, when it doesn't free to the system each vector, which is not -used anymore, but keeps it for a while (possibly indefinitely) to let it -be reused by the next consecutive command. This allows to: - - - - Reduce commands processing latencies and, hence, improve performance; - - Make commands processing latencies predictable, which is essential - for RT applications. - - - -The freed SG vectors are kept by the SGV cache either for some (possibly -indefinite) time, or, optionally, until the system needs more memory and -asks to free some using the set_shrinker() interface. Also the SGV cache -allows to: - - - - Cluster pages together. "Cluster" means merging adjacent pages in a -single SG entry. It allows to have less SG entries in the resulting SG -vector, hence improve performance handling it as well as allow to -work with bigger buffers on hardware with limited SG capabilities. - - Set custom page allocator functions. For instance, scst_user device -handler uses this facility to eliminate unneeded mapping/unmapping of -user space pages and avoid unneeded IOCTL calls for buffers allocations. -In fileio_tgt application, which uses a regular malloc() function to -allocate data buffers, this facility allows ~30% less CPU load and -considerable performance increase. - - Prevent each initiator or all initiators altogether to allocate too -much memory and DoS the target. Consider 10 initiators, which can have -access to 10 devices each. Any of them can queue up to 64 commands, each -can transfer up to 1MB of data. So, all of them in a peak can allocate -up to 10*10*64 = ~6.5GB of memory for data buffers. This amount must be -limited somehow and the SGV cache performs this function. - - - - Implementation - -

-From implementation POV the SGV cache is a simple extension of the kmem -cache. It can work in 2 modes: - - - - With fixed size buffers. - - With a set of power 2 size buffers. In this mode each SGV cache -(struct sgv_pool) has SGV_POOL_ELEMENTS (11 currently) of kmem caches. -Each of those kmem caches keeps SGV cache objects (struct sgv_pool_obj) -corresponding to SG vectors with size of order X pages. For instance, -request to allocate 4 pages will be served from kmem cache[2&rsqb, since the -order of the of number of requested pages is 2. If later request to -allocate 11KB comes, the same SG vector with 4 pages will be reused (see -below). This mode is in average allows less memory overhead comparing -with the fixed size buffers mode. - - - -Consider how the SGV cache works in the set of buffers mode. When a -request to allocate new SG vector comes, sgv_pool_alloc() via -sgv_get_obj() checks if there is already a cached vector with that -order. If yes, then that vector will be reused and its length, if -necessary, will be modified to match the requested size. In the above -example request for 11KB buffer, 4 pages vector will be reused and -modified using trans_tbl to contain 3 pages and the last entry will be -modified to contain the requested length - 2*PAGE_SIZE. If there is no -cached object, then a new sgv_pool_obj will be allocated from the -corresponding kmem cache, chosen by the order of number of requested -pages. Then that vector will be filled by pages and returned. - -In the fixed size buffers mode the SGV cache works similarly, except -that it always allocate buffer with the predefined fixed size. I.e. -even for 4K request the whole buffer with predefined size, say, 1MB, -will be used. - -In both modes, if size of a request exceeds the maximum allowed for -caching buffer size, the requested buffer will be allocated, but not -cached. - -Freed cached sgv_pool_obj objects are actually freed to the system -either by the purge work, which is scheduled once in 60 seconds, or in -sgv_shrink() called by system, when it's asking for memory. - - Interface - - sgv_pool *sgv_pool_create() - -

- -struct sgv_pool *sgv_pool_create( - const char *name, - enum sgv_clustering_types clustered, int single_alloc_pages, - bool shared, int purge_interval) - - -This function creates and initializes an SGV cache. It has the following -arguments: - - - - - - - - 0, then the SGV cache will work in the - fixed size buffers mode. In this case single_alloc_pages sets the - size of each buffer in pages. - - - -Returns the resulting SGV cache or NULL in case of any error. - - void sgv_pool_del() - -

- -void sgv_pool_del( - struct sgv_pool *pool) - - -This function deletes the corresponding SGV cache. If the cache is -shared, it will decrease its reference counter. If the reference counter -reaches 0, the cache will be destroyed. - - void sgv_pool_flush() - -

- -void sgv_pool_flush( - struct sgv_pool *pool) - - -This function flushes, i.e. frees, all the cached entries in the SGV -cache. - - void sgv_pool_set_allocator() - -

- -void sgv_pool_set_allocator( - struct sgv_pool *pool, - struct page *(*alloc_pages_fn)(struct scatterlist *sg, gfp_t gfp, void *priv), - void (*free_pages_fn)(struct scatterlist *sg, int sg_count, void *priv)); - - -This function allows to set for the SGV cache a custom pages allocator. For -instance, scst_user uses such function to supply to the cache mapped from -user space pages. - - - - - -This function should return the allocated page or NULL, if no page was -allocated. - - - - - - - struct scatterlist *sgv_pool_alloc() - -

- -struct scatterlist *sgv_pool_alloc( - struct sgv_pool *pool, - unsigned int size, - gfp_t gfp_mask, - int flags, - int *count, - struct sgv_pool_obj **sgv, - struct scst_mem_lim *mem_lim, - void *priv) - - -This function allocates an SG vector from the SGV cache. It has the -following parameters: - - - - - - - - - -This function returns pointer to the resulting SG vector or NULL in case -of any error. - - void sgv_pool_free() - -

- -void sgv_pool_free( - struct sgv_pool_obj *sgv, - struct scst_mem_lim *mem_lim) - - -This function frees previously allocated SG vector, referenced by SGV -cache object sgv. - - void *sgv_get_priv(struct sgv_pool_obj *sgv) - -

- -void *sgv_get_priv( - struct sgv_pool_obj *sgv) - - -This function allows to get the allocation private data for this SGV -cache object sgv. The private data are set by sgv_pool_alloc(). - - void scst_init_mem_lim() - -

- -void scst_init_mem_lim( - struct scst_mem_lim *mem_lim) - - -This function initializes memory limits structure mem_lim according to -the current system configuration. This structure should be latter used -to track and limit allocated by one or more SGV caches memory. - - - Runtime information and statistics. - -

-Runtime information and statistics is available in /sys/kernel/scst_tgt/sgv. - -

diff --git a/fcst/ft_sess.c b/fcst/ft_sess.c index 1690a87d1..81caf8bae 100644 --- a/fcst/ft_sess.c +++ b/fcst/ft_sess.c @@ -181,7 +181,9 @@ static u32 ft_sess_hash(u32 port_id) LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 41)) && \ ! (LINUX_VERSION_CODE >> 8 == KERNEL_VERSION(3, 2, 0) >> 8 && \ LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 44)) && \ - !defined(CONFIG_SUSE_KERNEL) + !defined(CONFIG_SUSE_KERNEL) && \ + (!defined(RHEL_MAJOR) || RHEL_MAJOR -0 < 6 || \ + (RHEL_MAJOR -0 == 6 && RHEL_MINOR -0 < 6)) /* * See also commit 4b20db3 (kref: Implement kref_get_unless_zero v3 -- v3.8). * See also commit e3a5505 in branch stable/linux-3.4.y (v3.4.41). diff --git a/ibmvstgt/src/Kconfig b/ibmvstgt/src/Kconfig index bbf91aec6..f3f71155e 100644 --- a/ibmvstgt/src/Kconfig +++ b/ibmvstgt/src/Kconfig @@ -206,7 +206,7 @@ config SCSI_MULTI_LUN mobile phone in mass storage mode. This option forces the kernel to probe for all LUNs by default. This setting can be overriden by max_luns boot/module parameter. Note that this option does not affect - devices conforming to SCSI-3 or higher as they can explicitely report + devices conforming to SCSI-3 or higher as they can explicitly report their number of LUNs. It is safe to say Y here unless you have one of those rare devices which reacts in an unexpected way when probed for multiple LUNs. diff --git a/ibmvstgt/src/orig/2.6.35/Kconfig b/ibmvstgt/src/orig/2.6.35/Kconfig index 75f233680..d07f508d1 100644 --- a/ibmvstgt/src/orig/2.6.35/Kconfig +++ b/ibmvstgt/src/orig/2.6.35/Kconfig @@ -206,7 +206,7 @@ config SCSI_MULTI_LUN mobile phone in mass storage mode. This option forces the kernel to probe for all LUNs by default. This setting can be overriden by max_luns boot/module parameter. Note that this option does not affect - devices conforming to SCSI-3 or higher as they can explicitely report + devices conforming to SCSI-3 or higher as they can explicitly report their number of LUNs. It is safe to say Y here unless you have one of those rare devices which reacts in an unexpected way when probed for multiple LUNs. diff --git a/ibmvstgt/src/orig/2.6.36/Kconfig b/ibmvstgt/src/orig/2.6.36/Kconfig index bbf91aec6..f3f71155e 100644 --- a/ibmvstgt/src/orig/2.6.36/Kconfig +++ b/ibmvstgt/src/orig/2.6.36/Kconfig @@ -206,7 +206,7 @@ config SCSI_MULTI_LUN mobile phone in mass storage mode. This option forces the kernel to probe for all LUNs by default. This setting can be overriden by max_luns boot/module parameter. Note that this option does not affect - devices conforming to SCSI-3 or higher as they can explicitely report + devices conforming to SCSI-3 or higher as they can explicitly report their number of LUNs. It is safe to say Y here unless you have one of those rare devices which reacts in an unexpected way when probed for multiple LUNs. diff --git a/iscsi-scst/README b/iscsi-scst/README index ad1ff5bdc..db82baa7e 100644 --- a/iscsi-scst/README +++ b/iscsi-scst/README @@ -413,7 +413,7 @@ echo 1 >/sys/kernel/scst_tgt/targets/iscsi/enabled Below is an advanced sample script, which configures more virtual devices of various types, including virtual CDROM and 2 targets, one with all default parameters, another one with some not default -parameters, incoming and outgoing user names for CHAP authentification, +parameters, incoming and outgoing user names for CHAP authentication, and special permissions for initiator iqn.2005-03.org.open-iscsi:cacdcd2520, which will see another set of devices. Also this sample configures CHAP authentication for discovery sessions and iSNS server with access diff --git a/iscsi-scst/README_in-tree b/iscsi-scst/README_in-tree index e76287e91..db41e2db6 100644 --- a/iscsi-scst/README_in-tree +++ b/iscsi-scst/README_in-tree @@ -242,7 +242,7 @@ echo 1 >/sys/kernel/scst_tgt/targets/iscsi/enabled Below is an advanced sample script, which configures more virtual devices of various types, including virtual CDROM and 2 targets, one with all default parameters, another one with some not default -parameters, incoming and outgoing user names for CHAP authentification, +parameters, incoming and outgoing user names for CHAP authentication, and special permissions for initiator iqn.2005-03.org.open-iscsi:cacdcd2520, which will see another set of devices. Also this sample configures CHAP authentication for discovery sessions and iSNS server with access diff --git a/iscsi-scst/doc/SCST_Gentoo_HOWTO.txt b/iscsi-scst/doc/SCST_Gentoo_HOWTO.txt index cee8e5026..a2549013a 100644 --- a/iscsi-scst/doc/SCST_Gentoo_HOWTO.txt +++ b/iscsi-scst/doc/SCST_Gentoo_HOWTO.txt @@ -40,7 +40,6 @@ work. cd /usr/src/linux-2.6.39-gentoo-r3 patch -p1 < /root/scst/iscsi-scst/kernel/patches/put_page_callback-2.6.39.patch - patch -p1 < /root/scst/scst/kernel/scst_exec_req_fifo-2.6.39.patch make clean diff --git a/iscsi-scst/doc/iscsi-scst-howto.txt b/iscsi-scst/doc/iscsi-scst-howto.txt index 97271f74f..7b9b5fffc 100644 --- a/iscsi-scst/doc/iscsi-scst-howto.txt +++ b/iscsi-scst/doc/iscsi-scst-howto.txt @@ -21,7 +21,6 @@ the example below): cd /usr/src/kernels/linux-2.6.38.8 patch -p1 < $HOME/scst/iscsi-scst/kernel/patches/put_page_callback-2.6.38.patch - patch -p1 < $HOME/scst/scst/kernel/scst_exec_req_fifo-2.6.38.patch make clean Next, build and install the kernel: diff --git a/iscsi-scst/kernel/config.c b/iscsi-scst/kernel/config.c index b51a43293..3ae4e0567 100644 --- a/iscsi-scst/kernel/config.c +++ b/iscsi-scst/kernel/config.c @@ -339,7 +339,7 @@ static int add_conn(void __user *ptr) session = session_lookup(target, info.sid); if (!session) { PRINT_ERROR("Session %lld not found", - (long long unsigned int)info.tid); + (unsigned long long int)info.tid); err = -ENOENT; goto out_unlock; } @@ -383,7 +383,7 @@ static int del_conn(void __user *ptr) session = session_lookup(target, info.sid); if (!session) { PRINT_ERROR("Session %llx not found", - (long long unsigned int)info.sid); + (unsigned long long int)info.sid); err = -ENOENT; goto out_unlock; } diff --git a/iscsi-scst/kernel/conn.c b/iscsi-scst/kernel/conn.c index 5b1865981..b35e03c30 100644 --- a/iscsi-scst/kernel/conn.c +++ b/iscsi-scst/kernel/conn.c @@ -533,7 +533,7 @@ static void conn_rsp_timer_fn(unsigned long arg) "%s (SID %llx), closing connection", iscsi_get_timeout(cmnd)/HZ, conn->session->initiator_name, - (long long unsigned int) + (unsigned long long int) conn->session->sid); /* * We must call mark_conn_closed() outside of @@ -764,13 +764,13 @@ static int conn_setup_sock(struct iscsi_conn *conn) mm_segment_t oldfs; struct iscsi_session *session = conn->session; - TRACE_DBG("%llx", (long long unsigned int)session->sid); + TRACE_DBG("%llx", (unsigned long long int)session->sid); conn->sock = SOCKET_I(conn->file->f_dentry->d_inode); if (conn->sock->ops->sendpage == NULL) { PRINT_ERROR("Socket for sid %llx doesn't support sendpage()", - (long long unsigned int)session->sid); + (unsigned long long int)session->sid); res = -EINVAL; goto out; } @@ -809,7 +809,7 @@ void conn_free(struct iscsi_conn *conn) TRACE_ENTRY(); TRACE_MGMT_DBG("Freeing conn %p (sess=%p, %#Lx %u)", conn, - session, (long long unsigned int)session->sid, conn->cid); + session, (unsigned long long int)session->sid, conn->cid); lockdep_assert_held(&conn->target->target_mutex); @@ -925,7 +925,7 @@ int iscsi_conn_alloc(struct iscsi_session *session, } TRACE_MGMT_DBG("Creating connection %p for sid %#Lx, cid %u", conn, - (long long unsigned int)session->sid, info->cid); + (unsigned long long int)session->sid, info->cid); conn->transport = t; diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index 7e13fffbd..4a8115526 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -2374,8 +2374,8 @@ static int cmnd_abort_pre_checks(struct iscsi_cmnd *req, int *status) if (req_hdr->lun != hdr->lun) { PRINT_ERROR("ABORT TASK: LUN mismatch: req LUN " "%llx, cmd LUN %llx, rtt %u", - (long long unsigned)be64_to_cpu(req_hdr->lun), - (long long unsigned)be64_to_cpu(hdr->lun), + (unsigned long long)be64_to_cpu(req_hdr->lun), + (unsigned long long)be64_to_cpu(hdr->lun), req_hdr->rtt); *status = ISCSI_RESPONSE_FUNCTION_REJECTED; goto out_put; diff --git a/iscsi-scst/kernel/iscsi.h b/iscsi-scst/kernel/iscsi.h index 50bbdee44..c89880f85 100644 --- a/iscsi-scst/kernel/iscsi.h +++ b/iscsi-scst/kernel/iscsi.h @@ -426,7 +426,7 @@ struct iscsi_cmnd { /* * Used only to abort not yet sent responses. Usage in * cmnd_done() is only a side effect to have a lockless - * accesss to this list from always only a single thread + * access to this list from always only a single thread * at any time. So, all responses live in the parent * until it has the last reference put. */ diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index 2b6c03e86..1da884f36 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -1336,7 +1336,7 @@ retry: count, &off); set_fs(oldfs); TRACE_WRITE("sid %#Lx, cid %u, res %d, iov_len %zd", - (long long unsigned int)conn->session->sid, + (unsigned long long int)conn->session->sid, conn->cid, res, iop->iov_len); if (unlikely(res <= 0)) { if (res == -EAGAIN) { @@ -1467,7 +1467,7 @@ retry2: "index %lu, offset %u, size %u, cmd %p, " "page %p)", (sendpage != sock_no_sendpage) ? "sendpage" : "sock_no_sendpage", - (long long unsigned int)conn->session->sid, + (unsigned long long int)conn->session->sid, conn->cid, res, page->index, offset, size, write_cmnd, page); if (unlikely(res <= 0)) { @@ -1553,7 +1553,7 @@ out_err: { #endif PRINT_ERROR("error %d at sid:cid %#Lx:%u, cmnd %p", res, - (long long unsigned int)conn->session->sid, + (unsigned long long int)conn->session->sid, conn->cid, conn->write_cmnd); } if (ref_cmd_to_parent && diff --git a/iscsi-scst/kernel/patches/put_page_callback-3.17.patch b/iscsi-scst/kernel/patches/put_page_callback-3.17.patch new file mode 100644 index 000000000..b049270ea --- /dev/null +++ b/iscsi-scst/kernel/patches/put_page_callback-3.17.patch @@ -0,0 +1,364 @@ +=== modified file 'drivers/block/drbd/drbd_receiver.c' +--- old/drivers/block/drbd/drbd_receiver.c 2014-11-21 03:17:49 +0000 ++++ new/drivers/block/drbd/drbd_receiver.c 2014-11-21 03:51:00 +0000 +@@ -132,7 +132,7 @@ static int page_chain_free(struct page * + struct page *tmp; + int i = 0; + page_chain_for_each_safe(page, tmp) { +- put_page(page); ++ net_put_page(page); + ++i; + } + return i; + +=== modified file 'include/linux/mm_types.h' +--- old/include/linux/mm_types.h 2014-11-21 03:17:49 +0000 ++++ new/include/linux/mm_types.h 2014-11-21 03:51:00 +0000 +@@ -196,6 +196,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-11-21 03:17:49 +0000 ++++ new/include/linux/net.h 2014-11-21 03:51:00 +0000 +@@ -19,6 +19,7 @@ + #define _LINUX_NET_H + + #include ++#include + #include + #include + #include /* For O_CLOEXEC and O_NONBLOCK */ +@@ -285,6 +286,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-11-21 03:17:49 +0000 ++++ new/include/linux/skbuff.h 2014-11-21 03:51:00 +0000 +@@ -2145,7 +2145,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)); + } + + /** +@@ -2168,7 +2168,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-11-21 03:17:49 +0000 ++++ new/net/Kconfig 2014-11-21 03:51:00 +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-11-21 03:17:49 +0000 ++++ new/net/ceph/pagevec.c 2014-11-21 03:51:00 +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]); + } + if (is_vmalloc_addr(pages)) + vfree(pages); + +=== modified file 'net/core/skbuff.c' +--- old/net/core/skbuff.c 2014-11-21 03:17:49 +0000 ++++ new/net/core/skbuff.c 2014-11-21 03:51:00 +0000 +@@ -426,7 +426,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, +@@ -484,7 +484,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); + } +@@ -808,7 +808,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; +@@ -1655,7 +1655,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, +@@ -1708,7 +1708,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; +@@ -2167,7 +2167,7 @@ skb_zerocopy(struct sk_buff *to, struct + page = virt_to_head_page(from->head); + offset = from->data - (unsigned char *)page_address(page); + __skb_fill_page_desc(to, 0, page, offset, plen); +- get_page(page); ++ net_get_page(page); + j = 1; + len -= plen; + } +@@ -2821,7 +2821,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-11-21 03:17:49 +0000 ++++ new/net/core/sock.c 2014-11-21 03:51:00 +0000 +@@ -1881,7 +1881,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); + } + + pfrag->offset = 0; +@@ -2645,7 +2645,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-11-21 03:17:49 +0000 ++++ new/net/ipv4/Makefile 2014-11-21 03:51:00 +0000 +@@ -54,6 +54,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 xfrm4_protocol.o + +=== modified file 'net/ipv4/ip_output.c' +--- old/net/ipv4/ip_output.c 2014-11-21 03:17:49 +0000 ++++ new/net/ipv4/ip_output.c 2014-11-21 03:51:00 +0000 +@@ -1051,7 +1051,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, +@@ -1276,7 +1276,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-11-21 03:17:49 +0000 ++++ new/net/ipv4/tcp.c 2014-11-21 03:51:00 +0000 +@@ -950,7 +950,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; +@@ -1251,7 +1251,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-11-21 03:51:00 +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-11-21 03:17:49 +0000 ++++ new/net/ipv6/ip6_output.c 2014-11-21 03:51:00 +0000 +@@ -1477,7 +1477,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/iscsi-scst/kernel/patches/put_page_callback-3.18.patch b/iscsi-scst/kernel/patches/put_page_callback-3.18.patch new file mode 100644 index 000000000..7f85a7496 --- /dev/null +++ b/iscsi-scst/kernel/patches/put_page_callback-3.18.patch @@ -0,0 +1,387 @@ +Subject: [PATCH] put_page_callback + +--- + drivers/block/drbd/drbd_receiver.c | 2 +- + include/linux/mm_types.h | 11 +++++++++ + include/linux/net.h | 40 ++++++++++++++++++++++++++++++ + include/linux/skbuff.h | 4 +-- + net/Kconfig | 12 +++++++++ + net/ceph/pagevec.c | 2 +- + net/core/skbuff.c | 14 +++++------ + net/core/sock.c | 4 +-- + net/ipv4/Makefile | 1 + + net/ipv4/ip_output.c | 4 +-- + net/ipv4/tcp.c | 4 +-- + net/ipv4/tcp_zero_copy.c | 50 ++++++++++++++++++++++++++++++++++++++ + net/ipv6/ip6_output.c | 2 +- + 13 files changed, 132 insertions(+), 18 deletions(-) + create mode 100644 net/ipv4/tcp_zero_copy.c + +diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c +index 6960fb0..8fa4016 100644 +--- a/drivers/block/drbd/drbd_receiver.c ++++ b/drivers/block/drbd/drbd_receiver.c +@@ -132,7 +132,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/include/linux/mm_types.h b/include/linux/mm_types.h +index 6e0b286..5706a4d 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -196,6 +196,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 +diff --git a/include/linux/net.h b/include/linux/net.h +index 17d8339..f784384 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 */ +@@ -285,6 +286,45 @@ int kernel_sendpage(struct socket *sock, struct page *page, int offset, + 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)) + +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h +index 6c8b6f6..edf6195 100644 +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2250,7 +2250,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)); + } + + /** +@@ -2273,7 +2273,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 99815b5..ac45213 100644 +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -76,6 +76,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 5550130..993f710 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]); + } + if (is_vmalloc_addr(pages)) + vfree(pages); +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 32e31c2..6eb3a9e 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -437,7 +437,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, +@@ -495,7 +495,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); + } +@@ -822,7 +822,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; +@@ -1669,7 +1669,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, +@@ -1722,7 +1722,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; +@@ -2181,7 +2181,7 @@ skb_zerocopy(struct sk_buff *to, 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; + } +@@ -2835,7 +2835,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 15e0c67..e8ea0df 100644 +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -1830,7 +1830,7 @@ bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t gfp) + } + if (pfrag->offset + sz <= pfrag->size) + return true; +- put_page(pfrag->page); ++ net_put_page(pfrag->page); + } + + pfrag->offset = 0; +@@ -2581,7 +2581,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 518c04e..4072a87 100644 +--- a/net/ipv4/Makefile ++++ b/net/ipv4/Makefile +@@ -57,6 +57,7 @@ obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o + obj-$(CONFIG_MEMCG_KMEM) += tcp_memcontrol.o + obj-$(CONFIG_NETLABEL) += cipso_ipv4.o + obj-$(CONFIG_GENEVE) += geneve.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 xfrm4_protocol.o +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index bc6471d..ab9e262 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -1051,7 +1051,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, +@@ -1276,7 +1276,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 38c2bcb..f089a7a 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -949,7 +949,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; +@@ -1250,7 +1250,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 8e950c2..8cb4760 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1472,7 +1472,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, +-- +2.1.2 + diff --git a/iscsi-scst/kernel/patches/rhel/put_page_callback-2.6.32-504.patch b/iscsi-scst/kernel/patches/rhel/put_page_callback-2.6.32-504.patch new file mode 100644 index 000000000..5159dd59f --- /dev/null +++ b/iscsi-scst/kernel/patches/rhel/put_page_callback-2.6.32-504.patch @@ -0,0 +1,453 @@ +[PATCH] put_page_callback-2.6.32-504 + +--- + include/linux/Kbuild | 1 + + include/linux/mm_types.h | 12 +++++++++++ + include/linux/net.h | 40 +++++++++++++++++++++++++++++++++++++ + net/Kconfig | 12 +++++++++++ + net/core/dev.c | 2 +- + net/core/skbuff.c | 34 ++++++++++++++++---------------- + net/ipv4/Makefile | 1 + + net/ipv4/ip_output.c | 4 +- + net/ipv4/tcp.c | 8 +++--- + net/ipv4/tcp_output.c | 2 +- + net/ipv4/tcp_zero_copy.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ + net/ipv6/ip6_output.c | 2 +- + 12 files changed, 141 insertions(+), 26 deletions(-) + create mode 100644 net/ipv4/tcp_zero_copy.c + +diff --git a/include/linux/Kbuild b/include/linux/Kbuild +index 9301043..2870f1a 100644 +--- a/include/linux/Kbuild ++++ b/include/linux/Kbuild +@@ -113,6 +113,7 @@ header-y += map_to_7segment.h + header-y += matroxfb.h + header-y += meye.h + header-y += minix_fs.h ++header-y += mm.h + header-y += mmtimer.h + header-y += mqueue.h + header-y += mtio.h +diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h +index 645f205..7b6de1f 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -106,6 +106,18 @@ struct page { + */ + void *shadow; + #endif ++ ++#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) ++ /* ++ * Used to implement support for notification on zero-copy TCP transfer ++ * completion. It might look as not good to have this field here and ++ * it's better to have it in struct sk_buff, but it would make the code ++ * much more complicated and fragile, since all skb then would have to ++ * contain only pages with the same value in this field. ++ */ ++ void *net_priv; ++#endif ++ + }; + + /* +diff --git a/include/linux/net.h b/include/linux/net.h +index 58ada6b..b0adbdc 100644 +--- a/include/linux/net.h ++++ b/include/linux/net.h +@@ -20,6 +20,7 @@ + + #include + #include ++#include + + #define NPROTO AF_MAX + +@@ -389,5 +390,44 @@ static const struct proto_ops name##_ops = { \ + extern struct ratelimit_state net_ratelimit_state; + #endif + ++#if defined(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) ++/* Support for notification on zero-copy TCP transfer completion */ ++typedef void (*net_get_page_callback_t)(struct page *page); ++typedef void (*net_put_page_callback_t)(struct page *page); ++ ++extern net_get_page_callback_t net_get_page_callback; ++extern net_put_page_callback_t net_put_page_callback; ++ ++extern int net_set_get_put_page_callbacks( ++ net_get_page_callback_t get_callback, ++ net_put_page_callback_t put_callback); ++ ++/* ++ * See comment for net_set_get_put_page_callbacks() why those functions ++ * don't need any protection. ++ */ ++static inline void net_get_page(struct page *page) ++{ ++ if (page->net_priv != 0) ++ net_get_page_callback(page); ++ get_page(page); ++} ++static inline void net_put_page(struct page *page) ++{ ++ if (page->net_priv != 0) ++ net_put_page_callback(page); ++ put_page(page); ++} ++#else ++static inline void net_get_page(struct page *page) ++{ ++ get_page(page); ++} ++static inline void net_put_page(struct page *page) ++{ ++ put_page(page); ++} ++#endif /* CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION */ ++ + #endif /* __KERNEL__ */ + #endif /* _LINUX_NET_H */ +diff --git a/net/Kconfig b/net/Kconfig +index 1d9b405..eedbed6 100644 +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -72,6 +72,18 @@ config INET + + Short answer: say Y. + ++config TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION ++ bool "TCP/IP zero-copy transfer completion notification" ++ depends on INET ++ default SCST_ISCSI ++ ---help--- ++ Adds support for sending a notification upon completion of a ++ zero-copy TCP/IP transfer. This can speed up certain TCP/IP ++ software. Currently this is only used by the iSCSI target driver ++ iSCSI-SCST. ++ ++ If unsure, say N. ++ + if INET + source "net/ipv4/Kconfig" + source "net/ipv6/Kconfig" +diff --git a/net/core/dev.c b/net/core/dev.c +index 61dce2f..25d0826 100644 +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -3655,7 +3655,7 @@ pull: + skb_shinfo(skb)->frags[0].size -= grow; + + if (unlikely(!skb_shinfo(skb)->frags[0].size)) { +- put_page(skb_shinfo(skb)->frags[0].page); ++ net_put_page(skb_shinfo(skb)->frags[0].page); + memmove(skb_shinfo(skb)->frags, + skb_shinfo(skb)->frags + 1, + --skb_shinfo(skb)->nr_frags); +diff --git a/net/core/skbuff.c b/net/core/skbuff.c +index 157dc11..74ac749 100644 +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -78,13 +78,13 @@ static struct kmem_cache *skbuff_fclone_cache __read_mostly; + 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, +@@ -396,7 +396,7 @@ static void skb_release_data(struct sk_buff *skb) + if (skb_shinfo(skb)->nr_frags) { + int i; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) +- put_page(skb_shinfo(skb)->frags[i].page); ++ net_put_page(skb_shinfo(skb)->frags[i].page); + } + + /* +@@ -705,7 +705,7 @@ static 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; +@@ -720,7 +720,7 @@ static int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) + + /* skb frags release userspace buffers */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) +- put_page(skb_shinfo(skb)->frags[i].page); ++ net_put_page(skb_shinfo(skb)->frags[i].page); + + uarg->callback(uarg); + +@@ -886,7 +886,7 @@ struct sk_buff *__pskb_copy(struct sk_buff *skb, int headroom, gfp_t gfp_mask) + } + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; +- get_page(skb_shinfo(n)->frags[i].page); ++ net_get_page(skb_shinfo(n)->frags[i].page); + } + skb_shinfo(n)->nr_frags = i; + } +@@ -967,7 +967,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, + skb_tx(skb)->dev_zerocopy = 0; + } + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) +- get_page(skb_shinfo(skb)->frags[i].page); ++ net_get_page(skb_shinfo(skb)->frags[i].page); + + if (skb_has_frag_list(skb)) + skb_clone_fraglist(skb); +@@ -1246,7 +1246,7 @@ drop_pages: + skb_shinfo(skb)->nr_frags = i; + + for (; i < nfrags; i++) +- put_page(skb_shinfo(skb)->frags[i].page); ++ net_put_page(skb_shinfo(skb)->frags[i].page); + + if (skb_has_frag_list(skb)) + skb_drop_fraglist(skb); +@@ -1415,7 +1415,7 @@ pull_pages: + k = 0; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + if (skb_shinfo(skb)->frags[i].size <= eat) { +- put_page(skb_shinfo(skb)->frags[i].page); ++ net_put_page(skb_shinfo(skb)->frags[i].page); + eat -= skb_shinfo(skb)->frags[i].size; + } else { + skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i]; +@@ -1517,7 +1517,7 @@ EXPORT_SYMBOL(skb_copy_bits); + */ + static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i) + { +- put_page(spd->pages[i]); ++ net_put_page(spd->pages[i]); + } + + static inline struct page *linear_to_page(struct page *page, unsigned int *len, +@@ -1541,7 +1541,7 @@ new_page: + off = sk->sk_sndmsg_off; + mlen = PAGE_SIZE - off; + if (mlen < 64 && mlen < *len) { +- put_page(p); ++ net_put_page(p); + goto new_page; + } + +@@ -1551,7 +1551,7 @@ new_page: + memcpy(page_address(p) + off, page_address(page) + *offset, *len); + sk->sk_sndmsg_off += *len; + *offset = off; +- get_page(p); ++ net_get_page(p); + + return p; + } +@@ -1572,7 +1572,7 @@ static inline int spd_fill_page(struct splice_pipe_desc *spd, struct page *page, + if (!page) + return 1; + } else +- get_page(page); ++ net_get_page(page); + + spd->pages[spd->nr_pages] = page; + spd->partial[spd->nr_pages].len = *len; +@@ -2202,7 +2202,7 @@ static inline void skb_split_no_header(struct sk_buff *skb, + * where splitting is expensive. + * 2. Split is accurately. We make this. + */ +- get_page(skb_shinfo(skb)->frags[i].page); ++ net_get_page(skb_shinfo(skb)->frags[i].page); + skb_shinfo(skb1)->frags[0].page_offset += len - pos; + skb_shinfo(skb1)->frags[0].size -= len - pos; + skb_shinfo(skb)->frags[i].size = len - pos; +@@ -2325,7 +2325,7 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen) + to++; + + } else { +- get_page(fragfrom->page); ++ net_get_page(fragfrom->page); + fragto->page = fragfrom->page; + fragto->page_offset = fragfrom->page_offset; + fragto->size = todo; +@@ -2347,7 +2347,7 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen) + fragto = &skb_shinfo(tgt)->frags[merge]; + + fragto->size += fragfrom->size; +- put_page(fragfrom->page); ++ net_put_page(fragfrom->page); + } + + /* Reposition in the original skb */ +@@ -2760,7 +2760,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) + + while (pos < offset + len && i < nfrags) { + *frag = skb_shinfo(skb)->frags[i]; +- get_page(frag->page); ++ net_get_page(frag->page); + size = frag->size; + + if (pos < offset) { +diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile +index e18daba..65f5371 100644 +--- a/net/ipv4/Makefile ++++ b/net/ipv4/Makefile +@@ -51,6 +51,7 @@ obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o + obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o + obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o + obj-$(CONFIG_NETLABEL) += cipso_ipv4.o ++obj-$(CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION) += tcp_zero_copy.o + + obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ + xfrm4_output.o +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c +index 7ac7cfa..8cda5cc 100644 +--- a/net/ipv4/ip_output.c ++++ b/net/ipv4/ip_output.c +@@ -1000,7 +1000,7 @@ alloc_new_skb: + err = -EMSGSIZE; + goto error; + } +- get_page(page); ++ net_get_page(page); + skb_fill_page_desc(skb, i, page, off, 0); + frag = &skb_shinfo(skb)->frags[i]; + } +@@ -1239,7 +1239,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, + if (skb_can_coalesce(skb, i, page, offset)) { + skb_shinfo(skb)->frags[i-1].size += 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 18d22cf..b5c12fa 100644 +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -821,7 +821,7 @@ new_segment: + if (can_coalesce) { + skb_shinfo(skb)->frags[i - 1].size += copy; + } else { +- get_page(page); ++ net_get_page(page); + skb_fill_page_desc(skb, i, page, offset, copy); + } + skb_tx(skb)->shared_frag = 1; +@@ -1030,7 +1030,7 @@ new_segment: + goto new_segment; + } else if (page) { + if (off == PAGE_SIZE) { +- put_page(page); ++ net_put_page(page); + TCP_PAGE(sk) = page = NULL; + off = 0; + } +@@ -1071,9 +1071,9 @@ new_segment: + } else { + skb_fill_page_desc(skb, i, page, off, copy); + if (TCP_PAGE(sk)) { +- get_page(page); ++ net_get_page(page); + } else if (off + copy < PAGE_SIZE) { +- get_page(page); ++ net_get_page(page); + TCP_PAGE(sk) = page; + } + } +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c +index 255e6e3..5c48819 100644 +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1071,7 +1071,7 @@ static void __pskb_trim_head(struct sk_buff *skb, int len) + k = 0; + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + if (skb_shinfo(skb)->frags[i].size <= eat) { +- put_page(skb_shinfo(skb)->frags[i].page); ++ net_put_page(skb_shinfo(skb)->frags[i].page); + eat -= skb_shinfo(skb)->frags[i].size; + } else { + skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i]; +diff --git a/net/ipv4/tcp_zero_copy.c b/net/ipv4/tcp_zero_copy.c +new file mode 100644 +index 0000000..9cd990c +--- /dev/null ++++ b/net/ipv4/tcp_zero_copy.c +@@ -0,0 +1,49 @@ ++/* ++ * 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 ++ ++net_get_page_callback_t net_get_page_callback __read_mostly; ++EXPORT_SYMBOL(net_get_page_callback); ++ ++net_put_page_callback_t net_put_page_callback __read_mostly; ++EXPORT_SYMBOL(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(net_set_get_put_page_callbacks); +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c +index 0e985f7..22b4529 100644 +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1375,7 +1375,7 @@ alloc_new_skb: + err = -EMSGSIZE; + goto error; + } +- get_page(page); ++ net_get_page(page); + skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0); + frag = &skb_shinfo(skb)->frags[i]; + } +-- +1.7.1 + diff --git a/iscsi-scst/kernel/session.c b/iscsi-scst/kernel/session.c index e75fc8618..121389aab 100644 --- a/iscsi-scst/kernel/session.c +++ b/iscsi-scst/kernel/session.c @@ -374,7 +374,7 @@ int __del_session(struct iscsi_target *target, u64 sid) if (!list_empty(&session->conn_list)) { PRINT_ERROR("%llx still have connections", - (long long unsigned int)session->sid); + (unsigned long long int)session->sid); return -EBUSY; } @@ -391,7 +391,7 @@ void iscsi_sess_force_close(struct iscsi_session *sess) lockdep_assert_held(&sess->target->target_mutex); PRINT_INFO("Deleting session %llx with initiator %s (%p)", - (long long unsigned int)sess->sid, sess->initiator_name, sess); + (unsigned long long int)sess->sid, sess->initiator_name, sess); list_for_each_entry(conn, &sess->conn_list, conn_list_entry) { TRACE_MGMT_DBG("Deleting connection with initiator %p", conn); @@ -415,7 +415,7 @@ static void iscsi_session_info_show(struct seq_file *seq, list_for_each_entry(session, &target->session_list, session_list_entry) { seq_printf(seq, "\tsid:%llx initiator:%s (reinstating %s)\n", - (long long unsigned int)session->sid, + (unsigned long long int)session->sid, session->initiator_name, session->sess_reinstating ? "yes" : "no"); conn_info_show(seq, session); diff --git a/mvsas_tgt/mv_tgt.c b/mvsas_tgt/mv_tgt.c index 86c5a49fa..962c88b13 100644 --- a/mvsas_tgt/mv_tgt.c +++ b/mvsas_tgt/mv_tgt.c @@ -1642,7 +1642,7 @@ static int mvst_handle_task_mgmt(struct mvs_info *mvi, sess = mvst_find_sess_by_lid(tgt, initiator_sas_addr); if (sess == NULL) { TRACE(TRACE_MGMT, "mvsttgt(%ld): task mgmt fn 0x%x for " - "non-existant session", mvi->instance, + "non-existent session", mvi->instance, cmd->save_task_iu.task_fun); res = -EFAULT; goto out; diff --git a/mvsas_tgt/mv_tgt.h b/mvsas_tgt/mv_tgt.h index 0058854f7..6598d1f29 100644 --- a/mvsas_tgt/mv_tgt.h +++ b/mvsas_tgt/mv_tgt.h @@ -478,7 +478,7 @@ struct mvs_tgt_initiator { }; /* - * Equivilant to IT Nexus (Initiator-Target) + * Equivalent to IT Nexus (Initiator-Target) */ struct mvst_sess { struct list_head sess_entry; @@ -558,7 +558,7 @@ struct mvst_tgt { unsigned int tgt_enable_64bit_addr:1; wait_queue_head_t waitQ; int notify_ack_expected; - /* Count of sessions refering q2t_tgt, protected by hardware_lock */ + /* Count of sessions referring q2t_tgt, protected by hardware_lock */ int sess_count; struct list_head sess_list; }; diff --git a/nightly/conf/nightly.conf b/nightly/conf/nightly.conf index b13e569f3..def42025c 100644 --- a/nightly/conf/nightly.conf +++ b/nightly/conf/nightly.conf @@ -3,21 +3,23 @@ ABT_DETAILS="x86_64" ABT_JOBS=5 ABT_KERNELS=" \ -3.16.7 \ +3.18.3 \ +3.17.8-nc \ +3.16.7-nc \ 3.15.10-nc \ -3.14.23-nc \ +3.14.29-nc \ 3.13.11-nc \ -3.12.31-nc \ +3.12.36-nc \ 3.11.10-nc \ -3.10.59-nc \ +3.10.65-nc \ 3.9.11-nc \ 3.8.13-nc \ 3.7.10-nc \ 3.6.11-nc \ 3.5.7-nc \ -3.4.103-nc \ +3.4.105-nc \ 3.3.8-nc \ -3.2.61-nc \ +3.2.66-nc \ 3.1.10-nc \ 3.0.101-nc \ 2.6.39.4-nc \ @@ -26,9 +28,9 @@ ABT_KERNELS=" \ 2.6.36.4-nc \ 2.6.35.14 \ 2.6.35.14-u-nc \ -2.6.34.14-nc \ +2.6.34.15-nc \ 2.6.33.20-nc \ -2.6.32.62-nc \ +2.6.32.65-nc \ 2.6.31.14-nc \ 2.6.30.10-nc \ 2.6.29.6-nc \ diff --git a/qla2x00t/doc/qla2x00t-howto.html b/qla2x00t/doc/qla2x00t-howto.html index 66b418723..4ed582fd4 100644 --- a/qla2x00t/doc/qla2x00t-howto.html +++ b/qla2x00t/doc/qla2x00t-howto.html @@ -80,13 +80,6 @@ Instructions for obtaining a distribution-specific kernel source tree vary. An e [root@proj src ]# tar xjf linux-source-`uname -r`.tar.bz2 -
  • - Patch the kernel that has just been downloaded: -
    [root@proj src ]# ln -s linux-3.11 linux
    -[root@proj src ]# cd linux
    -[root@proj linux ]# patch -p1 < /root/scst/scst/kernel/scst_exec_req_fifo-3.11.patch
    -
  • -
  • The next step is to configure the kernel:
    [root@proj linux ]# pwd
     /usr/src/linux
    diff --git a/qla2x00t/qla2x00-target/Makefile_in-tree-3.17 b/qla2x00t/qla2x00-target/Makefile_in-tree-3.17
    new file mode 100644
    index 000000000..9657aee84
    --- /dev/null
    +++ b/qla2x00t/qla2x00-target/Makefile_in-tree-3.17
    @@ -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/qla2x00-target/Makefile_in-tree-3.18 b/qla2x00t/qla2x00-target/Makefile_in-tree-3.18
    new file mode 100644
    index 000000000..9657aee84
    --- /dev/null
    +++ b/qla2x00t/qla2x00-target/Makefile_in-tree-3.18
    @@ -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/qla2x00-target/README b/qla2x00t/qla2x00-target/README
    index d06a7757a..7cf3c3096 100644
    --- a/qla2x00t/qla2x00-target/README
    +++ b/qla2x00t/qla2x00-target/README
    @@ -565,7 +565,7 @@ Thanks to:
     initiator driver.
     
      * Mark Buechler  for the original
    -WWN-based authentification, a lot of useful suggestions, bug reports and
    +WWN-based authentication, a lot of useful suggestions, bug reports and
     help in debugging.
     
      * Ming Zhang  for fixes.
    diff --git a/qla2x00t/qla2x00-target/qla2x00t.c b/qla2x00t/qla2x00-target/qla2x00t.c
    index 3741f88fa..a66eb3ada 100644
    --- a/qla2x00t/qla2x00-target/qla2x00t.c
    +++ b/qla2x00t/qla2x00-target/qla2x00t.c
    @@ -1547,6 +1547,8 @@ static int q2t_target_release(struct scst_tgt *scst_tgt)
     
     	q2t_target_stop(scst_tgt);
     
    +	cancel_work_sync(&tgt->rscn_reg_work);
    +
     	ha->q2t_tgt = NULL;
     	scst_tgt_set_tgt_priv(scst_tgt, NULL);
     
    @@ -2409,8 +2411,8 @@ static void q2t_load_cont_data_segments(struct q2t_prm *prm)
     			*dword_ptr++ = cpu_to_le32(sg_dma_len(prm->sg));
     
     			TRACE_SG("S/G Segment Cont. phys_addr=%llx:%llx, len=%d",
    -			      (long long unsigned int)pci_dma_hi32(dma_addr),
    -			      (long long unsigned int)pci_dma_lo32(dma_addr),
    +			      (unsigned long long int)pci_dma_hi32(dma_addr),
    +			      (unsigned long long int)pci_dma_lo32(dma_addr),
     			      (int)sg_dma_len(prm->sg));
     
     			prm->sg = __sg_next_inline(prm->sg);
    @@ -2470,8 +2472,8 @@ static void q2x_load_data_segments(struct q2t_prm *prm)
     		*dword_ptr++ = cpu_to_le32(sg_dma_len(prm->sg));
     
     		TRACE_SG("S/G Segment phys_addr=%llx:%llx, len=%d",
    -		      (long long unsigned int)pci_dma_hi32(dma_addr),
    -		      (long long unsigned int)pci_dma_lo32(dma_addr),
    +		      (unsigned long long int)pci_dma_hi32(dma_addr),
    +		      (unsigned long long int)pci_dma_lo32(dma_addr),
     		      (int)sg_dma_len(prm->sg));
     
     		prm->sg = __sg_next_inline(prm->sg);
    @@ -2532,8 +2534,8 @@ static void q24_load_data_segments(struct q2t_prm *prm)
     		*dword_ptr++ = cpu_to_le32(sg_dma_len(prm->sg));
     
     		TRACE_SG("S/G Segment phys_addr=%llx:%llx, len=%d",
    -		      (long long unsigned int)pci_dma_hi32(dma_addr),
    -		      (long long unsigned int)pci_dma_lo32(dma_addr),
    +		      (unsigned long long int)pci_dma_hi32(dma_addr),
    +		      (unsigned long long int)pci_dma_lo32(dma_addr),
     		      (int)sg_dma_len(prm->sg));
     
     		prm->sg = __sg_next_inline(prm->sg);
    @@ -2679,6 +2681,31 @@ out_unlock_free_unmap:
     	goto out;
     }
     
    +/*
    + * Convert sense buffer (byte array) to little endian format as required by
    + * qla24xx firmware.
    + */
    +static void q24_copy_sense_buffer_to_ctio(ctio7_status1_entry_t *ctio,
    +	uint8_t *sense_buf, unsigned int sense_buf_len)
    +{
    +	uint32_t *src = (void *)sense_buf;
    +	uint32_t *end = (void *)sense_buf + sense_buf_len;
    +	uint8_t *p;
    +	__be32 *dst = (void *)ctio->sense_data;
    +
    +	/*
    +	 * The sense buffer allocated by scst_alloc_sense() is zero-filled and
    +	 * has a length that is a multiple of four. This means that it is safe
    +	 * to access the bytes after the end of the sense buffer up to a
    +	 * boundary that is a multiple of four.
    +	 */
    +	for (p = (uint8_t *)end; ((uintptr_t)p & 3) != 0; p++)
    +		WARN_ONCE(*p != 0, "sense_buf[%zd] = %d\n", p - sense_buf, *p);
    +
    +	for ( ; src < end; src++)
    +		*dst++ = cpu_to_be32(*src);
    +}
    +
     static inline int q2t_need_explicit_conf(scsi_qla_host_t *ha,
     	struct q2t_cmd *cmd, int sending_sense)
     {
    @@ -2914,7 +2941,6 @@ static void q24_init_ctio_ret_entry(ctio7_status0_entry_t *ctio,
     	ctio->residual = cpu_to_le32(prm->residual);
     	ctio->scsi_status = cpu_to_le16(prm->rq_result);
     	if (scst_sense_valid(prm->sense_buffer)) {
    -		int i;
     		ctio1 = (ctio7_status1_entry_t *)ctio;
     		if (q2t_need_explicit_conf(prm->tgt->ha, prm->cmd, 1)) {
     			ctio1->flags |= cpu_to_le16(
    @@ -2925,20 +2951,8 @@ static void q24_init_ctio_ret_entry(ctio7_status0_entry_t *ctio,
     		ctio1->flags |= cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1);
     		ctio1->scsi_status |= cpu_to_le16(SS_SENSE_LEN_VALID);
     		ctio1->sense_length = cpu_to_le16(prm->sense_buffer_len);
    -		for (i = 0; i < prm->sense_buffer_len/4; i++)
    -			((uint32_t *)ctio1->sense_data)[i] =
    -				cpu_to_be32(((uint32_t *)prm->sense_buffer)[i]);
    -#if 0
    -		if (unlikely((prm->sense_buffer_len % 4) != 0)) {
    -			static int q;
    -			if (q < 10) {
    -				PRINT_INFO("qla2x00t(%ld): %d bytes of sense "
    -					"lost", prm->tgt->ha->instance,
    -					prm->sense_buffer_len % 4);
    -				q++;
    -			}
    -		}
    -#endif
    +		q24_copy_sense_buffer_to_ctio(ctio1, prm->sense_buffer,
    +					      prm->sense_buffer_len);
     	} else {
     		ctio1 = (ctio7_status1_entry_t *)ctio;
     		ctio1->flags &= ~cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_0);
    @@ -4074,7 +4088,7 @@ static int q2t_handle_task_mgmt(scsi_qla_host_t *ha, void *iocb)
     
     	if (sess == NULL) {
     		TRACE_MGMT_DBG("qla2x00t(%ld): task mgmt fn 0x%x for "
    -			"non-existant session", ha->instance, fn);
    +			"non-existent session", ha->instance, fn);
     		res = q2t_sched_sess_work(tgt, Q2T_SESS_WORK_TM, iocb,
     			IS_FWI2_CAPABLE(ha) ? sizeof(atio7_entry_t) :
     					      sizeof(notify_entry_t));
    @@ -4161,11 +4175,39 @@ out:
     	return res;
     }
     
    +static void q2t_rscn_reg_work(struct work_struct *work)
    +{
    +	struct q2t_tgt *tgt = container_of(work, struct q2t_tgt, rscn_reg_work);
    +	scsi_qla_host_t *ha = tgt->ha;
    +	int ret;
    +
    +	TRACE_ENTRY();
    +
    +	if ((ha->host->active_mode & MODE_INITIATOR) == 0) {
    +		/*
    +		 * The QLogic firmware and qla2xxx do not register for RSCNs in
    +		 * target-only mode, so do that explicitly.
    +		 */
    +		ret = qla2x00_send_change_request(ha, 0x3, ha->vp_idx);
    +		if (ret != QLA_SUCCESS)
    +			PRINT_INFO("qla2x00t(%ld): RSCN registration failed: "
    +				"%#x (OK for non-fabric setups)",
    +				ha->host_no, ret);
    +		else
    +			TRACE_MGMT_DBG("qla2x00t(%ld): RSCN registration succeeded",
    +				ha->host_no);
    +	}
    +
    +	TRACE_EXIT();
    +	return;
    +}
    +
     /*
      * pha->hardware_lock supposed to be held on entry. Might drop it, then reacquire
      */
     static int q24_handle_els(scsi_qla_host_t *ha, notify24xx_entry_t *iocb)
     {
    +	struct q2t_tgt *tgt = ha->tgt;
     	int res = 1; /* send notify ack */
     	struct q2t_sess *sess;
     	int loop_id;
    @@ -4177,6 +4219,13 @@ static int q24_handle_els(scsi_qla_host_t *ha, notify24xx_entry_t *iocb)
     
     	switch (iocb->status_subcode) {
     	case ELS_PLOGI:
    +		/*
    +		 * HACK. Let's do it on PLOGI, because seems there is no other
    +		 * simple place, from where it can be called. In the worst
    +		 * case, we will just reinstall RSCNs once again, it's harmless.
    +		 */
    +		schedule_work(&tgt->rscn_reg_work);
    +		break;
     	case ELS_FLOGI:
     	case ELS_PRLI:
     		break;
    @@ -5297,7 +5346,7 @@ static void q2t_response_pkt(scsi_qla_host_t *ha, response_t *pkt)
     					 * command was sent between the abort request
     					 * was received and processed. Unfortunately,
     					 * the firmware has a silly requirement that
    -					 * all aborted exchanges must be explicitely
    +					 * all aborted exchanges must be explicitly
     					 * terminated, otherwise it refuses to send
     					 * responses for the abort requests. So, we
     					 * have to (re)terminate the exchange and
    @@ -5405,11 +5454,11 @@ static void q2t_async_event(uint16_t code, scsi_qla_host_t *ha,
     	case MBA_RSP_TRANSFER_ERR:	/* Response Transfer Error */
     	case MBA_ATIO_TRANSFER_ERR:	/* ATIO Queue Transfer Error */
     		TRACE(TRACE_MGMT, "qla2x00t(%ld): System error async event %#x "
    -			"occured", ha->instance, code);
    +			"occurred", ha->instance, code);
     		break;
     
     	case MBA_LOOP_UP:
    -		TRACE(TRACE_MGMT, "qla2x00t(%ld): Loop up occured",
    +		TRACE(TRACE_MGMT, "qla2x00t(%ld): Loop up occurred",
     			ha->instance);
     		if (tgt->link_reinit_iocb_pending) {
     			q24_send_notify_ack(ha, &tgt->link_reinit_iocb, 0, 0, 0);
    @@ -5418,28 +5467,28 @@ static void q2t_async_event(uint16_t code, scsi_qla_host_t *ha,
     		break;
     
     	case MBA_LIP_OCCURRED:
    -		TRACE(TRACE_MGMT, "qla2x00t(%ld): LIP occured", ha->instance);
    +		TRACE(TRACE_MGMT, "qla2x00t(%ld): LIP occurred", ha->instance);
     		break;
     
     	case MBA_LOOP_DOWN:
    -		TRACE(TRACE_MGMT, "qla2x00t(%ld): Loop down occured",
    +		TRACE(TRACE_MGMT, "qla2x00t(%ld): Loop down occurred",
     			ha->instance);
     		break;
     
     	case MBA_LIP_RESET:
    -		TRACE(TRACE_MGMT, "qla2x00t(%ld): LIP reset occured",
    +		TRACE(TRACE_MGMT, "qla2x00t(%ld): LIP reset occurred",
     			ha->instance);
     		break;
     
     	case MBA_PORT_UPDATE:
     	case MBA_RSCN_UPDATE:
     		TRACE_MGMT_DBG("qla2x00t(%ld): Port update async event %#x "
    -			"occured", ha->instance, code);
    +			"occurred", ha->instance, code);
     		/* .mark_all_devices_lost() is handled by the initiator driver */
     		break;
     
     	default:
    -		TRACE(TRACE_MGMT, "qla2x00t(%ld): Async event %#x occured: "
    +		TRACE(TRACE_MGMT, "qla2x00t(%ld): Async event %#x occurred: "
     			"ignoring (m[1]=%x, m[2]=%x, m[3]=%x, m[4]=%x)",
     			ha->instance, code,
     			le16_to_cpu(mailbox[1]), le16_to_cpu(mailbox[2]),
    @@ -5823,8 +5872,10 @@ static void q2t_on_hw_pending_cmd_timeout(struct scst_cmd *scst_cmd)
     
     		q2t_cleanup_hw_pending_cmd(ha, cmd);
     
    -		scst_rx_data(scst_cmd, SCST_RX_STATUS_ERROR_FATAL,
    -				SCST_CONTEXT_THREAD);
    +		/* It might be sporadic, hence retriable */
    +		scst_set_cmd_error(scst_cmd,
    +				SCST_LOAD_SENSE(scst_sense_internal_failure));
    +		scst_rx_data(scst_cmd, SCST_RX_STATUS_ERROR_SENSE_SET, SCST_CONTEXT_THREAD);
     		goto out_unlock;
     	} else if (cmd->state == Q2T_STATE_ABORTED) {
     		TRACE_MGMT_DBG("Force finishing aborted cmd %p (tag %d)",
    @@ -5872,6 +5923,7 @@ static int q2t_add_target(scsi_qla_host_t *ha)
     
     	tgt->ha = ha;
     	init_waitqueue_head(&tgt->waitQ);
    +	INIT_WORK(&tgt->rscn_reg_work, q2t_rscn_reg_work);
     	INIT_LIST_HEAD(&tgt->sess_list);
     	INIT_LIST_HEAD(&tgt->del_sess_list);
     	INIT_DELAYED_WORK(&tgt->sess_del_work, q2t_del_sess_work_fn);
    diff --git a/qla2x00t/qla2x00-target/qla2x00t.h b/qla2x00t/qla2x00-target/qla2x00t.h
    index d3d976478..57517046a 100644
    --- a/qla2x00t/qla2x00-target/qla2x00t.h
    +++ b/qla2x00t/qla2x00-target/qla2x00t.h
    @@ -141,7 +141,9 @@ struct q2t_tgt {
     	 */
     	unsigned long tgt_stop; /* the driver is being stopped */
     
    -	/* Count of sessions refering q2t_tgt. Protected by hardware_lock. */
    +	struct work_struct rscn_reg_work;
    +
    +	/* Count of sessions referring q2t_tgt. Protected by hardware_lock. */
     	int sess_count;
     
     	/*
    @@ -177,7 +179,7 @@ struct q2t_tgt {
     };
     
     /*
    - * Equivilant to IT Nexus (Initiator-Target)
    + * Equivalent to IT Nexus (Initiator-Target)
      */
     struct q2t_sess {
     	uint16_t loop_id;
    diff --git a/qla2x00t/qla_init.c b/qla2x00t/qla_init.c
    index b4b745fa8..865c21623 100644
    --- a/qla2x00t/qla_init.c
    +++ b/qla2x00t/qla_init.c
    @@ -2147,7 +2147,7 @@ qla2x00_configure_loop(scsi_qla_host_t *ha)
     		DEBUG3(printk("%s: exiting normally\n", __func__));
     	}
     
    -	/* Restore state if a resync event occured during processing */
    +	/* Restore state if a resync event occurred during processing */
     	if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
     		if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
     			set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
    diff --git a/qla2x00t/qla_iocb.c b/qla2x00t/qla_iocb.c
    index 432a3600e..1d9ea02af 100644
    --- a/qla2x00t/qla_iocb.c
    +++ b/qla2x00t/qla_iocb.c
    @@ -261,7 +261,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
      * qla2x00_start_scsi() - Send a SCSI command to the ISP
      * @sp: command to send to the ISP
      *
    - * Returns non-zero if a failure occured, else zero.
    + * Returns non-zero if a failure occurred, else zero.
      */
     int
     qla2x00_start_scsi(srb_t *sp)
    @@ -407,7 +407,7 @@ queuing_error:
      *
      * Can be called from both normal and interrupt context.
      *
    - * Returns non-zero if a failure occured, else zero.
    + * Returns non-zero if a failure occurred, else zero.
      *
      * Hardware lock must be held on entrance. Might release it, then reacquire.
      */
    @@ -671,7 +671,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
      * qla24xx_start_scsi() - Send a SCSI command to the ISP
      * @sp: command to send to the ISP
      *
    - * Returns non-zero if a failure occured, else zero.
    + * Returns non-zero if a failure occurred, else zero.
      */
     int
     qla24xx_start_scsi(srb_t *sp)
    diff --git a/qla2x00t/qla_isr.c b/qla2x00t/qla_isr.c
    index 8395186d8..233eded41 100644
    --- a/qla2x00t/qla_isr.c
    +++ b/qla2x00t/qla_isr.c
    @@ -419,9 +419,9 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
     		break;
     
     	case MBA_LIP_OCCURRED:		/* Loop Initialization Procedure */
    -		DEBUG2(printk("scsi(%ld): LIP occured (%x).\n", ha->host_no,
    +		DEBUG2(printk("scsi(%ld): LIP occurred (%x).\n", ha->host_no,
     		    mb[1]));
    -		qla_printk(KERN_INFO, ha, "LIP occured (%x).\n", mb[1]);
    +		qla_printk(KERN_INFO, ha, "LIP occurred (%x).\n", mb[1]);
     
     		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
     			atomic_set(&ha->loop_state, LOOP_DOWN);
    @@ -488,7 +488,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
     		DEBUG2(printk("scsi(%ld): Asynchronous LIP RESET (%x).\n",
     		    ha->host_no, mb[1]));
     		qla_printk(KERN_INFO, ha,
    -		    "LIP reset occured (%x).\n", mb[1]);
    +		    "LIP reset occurred (%x).\n", mb[1]);
     
     		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
     			atomic_set(&ha->loop_state, LOOP_DOWN);
    @@ -781,8 +781,8 @@ qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data)
     	fcport->last_ramp_up = jiffies;
     
     	DEBUG2(qla_printk(KERN_INFO, fcport->ha,
    -	    "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
    -	    fcport->ha->host_no, sdev->channel, sdev->id, sdev->lun,
    +	    "scsi(%ld:%d:%d:%lld): Queue depth adjusted-up to %d.\n",
    +	    fcport->ha->host_no, sdev->channel, sdev->id, (unsigned long long)sdev->lun,
     	    sdev->queue_depth));
     }
     
    @@ -795,8 +795,8 @@ qla2x00_adjust_sdev_qdepth_down(struct scsi_device *sdev, void *data)
     		return;
     
     	DEBUG2(qla_printk(KERN_INFO, fcport->ha,
    -	    "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
    -	    fcport->ha->host_no, sdev->channel, sdev->id, sdev->lun,
    +	    "scsi(%ld:%d:%d:%lld): Queue depth adjusted-down to %d.\n",
    +	    fcport->ha->host_no, sdev->channel, sdev->id, (unsigned long long)sdev->lun,
     	    sdev->queue_depth));
     }
     
    @@ -1140,11 +1140,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
     		if (IS_FWI2_CAPABLE(ha))
     			sense_data += rsp_info_len;
     		if (rsp_info_len > 3 && rsp_info[3]) {
    -			DEBUG2(printk("scsi(%ld:%d:%d:%d) FCP I/O protocol "
    +			DEBUG2(printk("scsi(%ld:%d:%d:%lld) FCP I/O protocol "
     			    "failure (%x/%02x%02x%02x%02x%02x%02x%02x%02x)..."
     			    "retrying command\n", ha->host_no,
     			    cp->device->channel, cp->device->id,
    -			    cp->device->lun, rsp_info_len, rsp_info[0],
    +			    (unsigned long long)cp->device->lun, rsp_info_len, rsp_info[0],
     			    rsp_info[1], rsp_info[2], rsp_info[3], rsp_info[4],
     			    rsp_info[5], rsp_info[6], rsp_info[7]));
     
    @@ -1178,11 +1178,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
     			    ((unsigned)(scsi_bufflen(cp) - resid) <
     			     cp->underflow)) {
     				qla_printk(KERN_INFO, ha,
    -					   "scsi(%ld:%d:%d:%d): Mid-layer underflow "
    +					   "scsi(%ld:%d:%d:%lld): Mid-layer underflow "
     					   "detected (%x of %x bytes)...returning "
     					   "error status.\n", ha->host_no,
     					   cp->device->channel, cp->device->id,
    -					   cp->device->lun, resid,
    +					   (unsigned long long)cp->device->lun, resid,
     					   scsi_bufflen(cp));
     
     				cp->result = DID_ERROR << 16;
    @@ -1230,10 +1230,10 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
     			CMD_RESID_LEN(cp) = resid;
     		} else {
     			DEBUG2(printk(KERN_INFO
    -			    "scsi(%ld:%d:%d) UNDERRUN status detected "
    +			    "scsi(%ld:%d:%lld) UNDERRUN status detected "
     			    "0x%x-0x%x. resid=0x%x fw_resid=0x%x cdb=0x%x "
     			    "os_underflow=0x%x\n", ha->host_no,
    -			    cp->device->id, cp->device->lun, comp_status,
    +			    cp->device->id, (unsigned long long)cp->device->lun, comp_status,
     			    scsi_status, resid_len, resid, cp->cmnd[0],
     			    cp->underflow));
     
    @@ -1277,11 +1277,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
     			 * layer to retry it by reporting a bus busy.
     			 */
     			if (!(scsi_status & SS_RESIDUAL_UNDER)) {
    -				DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped "
    +				DEBUG2(printk("scsi(%ld:%d:%d:%lld) Dropped "
     					      "frame(s) detected (%x of %x bytes)..."
     					      "retrying command.\n", ha->host_no,
     					      cp->device->channel, cp->device->id,
    -					      cp->device->lun, resid,
    +					      (unsigned long long)cp->device->lun, resid,
     					      scsi_bufflen(cp)));
     
     				cp->result = DID_BUS_BUSY << 16;
    @@ -1292,11 +1292,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
     			if ((unsigned)(scsi_bufflen(cp) - resid) <
     			    cp->underflow) {
     				qla_printk(KERN_INFO, ha,
    -					   "scsi(%ld:%d:%d:%d): Mid-layer underflow "
    +					   "scsi(%ld:%d:%d:%lld): Mid-layer underflow "
     					   "detected (%x of %x bytes)...returning "
     					   "error status.\n", ha->host_no,
     					   cp->device->channel, cp->device->id,
    -					   cp->device->lun, resid,
    +					   (unsigned long long)cp->device->lun, resid,
     					   scsi_bufflen(cp));
     
     				cp->result = DID_ERROR << 16;
    @@ -1310,9 +1310,9 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
     
     	case CS_DATA_OVERRUN:
     		DEBUG2(printk(KERN_INFO
    -		    "scsi(%ld:%d:%d): OVERRUN status detected 0x%x-0x%x\n",
    -		    ha->host_no, cp->device->id, cp->device->lun, comp_status,
    -		    scsi_status));
    +		    "scsi(%ld:%d:%lld): OVERRUN status detected 0x%x-0x%x\n",
    +		    ha->host_no, cp->device->id, (unsigned long long)cp->device->lun,
    +		    comp_status, scsi_status));
     		DEBUG2(printk(KERN_INFO
     		    "CDB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
     		    cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3],
    @@ -1335,9 +1335,9 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
     		 * Target with DID_NO_CONNECT ELSE Queue the IOs in the
     		 * retry_queue.
     		 */
    -		DEBUG2(printk("scsi(%ld:%d:%d): status_entry: Port Down "
    +		DEBUG2(printk("scsi(%ld:%d:%lld): status_entry: Port Down "
     		    "pid=%ld, compl status=0x%x, port state=0x%x\n",
    -		    ha->host_no, cp->device->id, cp->device->lun,
    +		    ha->host_no, cp->device->id, (unsigned long long)cp->device->lun,
     		    cp->serial_number, comp_status,
     		    atomic_read(&fcport->state)));
     
    @@ -1373,17 +1373,17 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
     
     		if (IS_FWI2_CAPABLE(ha)) {
     			DEBUG2(printk(KERN_INFO
    -			    "scsi(%ld:%d:%d:%d): TIMEOUT status detected "
    +			    "scsi(%ld:%d:%d:%lld): TIMEOUT status detected "
     			    "0x%x-0x%x\n", ha->host_no, cp->device->channel,
    -			    cp->device->id, cp->device->lun, comp_status,
    -			    scsi_status));
    +			    cp->device->id, (unsigned long long)cp->device->lun,
    +			    comp_status, scsi_status));
     			break;
     		}
     		DEBUG2(printk(KERN_INFO
    -		    "scsi(%ld:%d:%d:%d): TIMEOUT status detected 0x%x-0x%x "
    +		    "scsi(%ld:%d:%d:%lld): TIMEOUT status detected 0x%x-0x%x "
     		    "sflags=%x.\n", ha->host_no, cp->device->channel,
    -		    cp->device->id, cp->device->lun, comp_status, scsi_status,
    -		    le16_to_cpu(sts->status_flags)));
    +		    cp->device->id, (unsigned long long)cp->device->lun, comp_status,
    +		    scsi_status, le16_to_cpu(sts->status_flags)));
     
     		/* Check to see if logout occurred. */
     		if ((le16_to_cpu(sts->status_flags) & SF_LOGOUT_SENT))
    diff --git a/qla2x00t/qla_mbx.c b/qla2x00t/qla_mbx.c
    index f87985433..a7c7015ba 100644
    --- a/qla2x00t/qla_mbx.c
    +++ b/qla2x00t/qla_mbx.c
    @@ -232,7 +232,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
     			DEBUG2_3_11(printk("%s(%ld): timeout schedule "
     			    "isp_abort_needed.\n", __func__, ha->host_no));
     			qla_printk(KERN_WARNING, ha,
    -			    "Mailbox command timeout occured. Scheduling ISP "
    +			    "Mailbox command timeout occurred. Scheduling ISP "
     			    "abort.\n");
     			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
     			qla2xxx_wake_dpc(ha);
    @@ -243,7 +243,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
     			DEBUG2_3_11(printk("%s(%ld): timeout calling "
     			    "abort_isp\n", __func__, ha->host_no));
     			qla_printk(KERN_WARNING, ha,
    -			    "Mailbox command timeout occured. Issuing ISP "
    +			    "Mailbox command timeout occurred. Issuing ISP "
     			    "abort.\n");
     
     			set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
    @@ -3035,9 +3035,9 @@ qla2x00_send_change_request(scsi_qla_host_t *ha, uint16_t format,
     
     	/*
     	 * This command is implicitly executed by firmware during login for the
    -	 * physical hosts
    +	 * physical hosts if initiator mode is enabled.
     	 */
    -	if (vp_idx == 0)
    +	if (vp_idx == 0 && (ha->host->active_mode & MODE_INITIATOR))
     		return QLA_FUNCTION_FAILED;
     
     	mcp->mb[0] = MBC_SEND_CHANGE_REQUEST;
    @@ -3058,6 +3058,7 @@ qla2x00_send_change_request(scsi_qla_host_t *ha, uint16_t format,
     
     	return rval;
     }
    +EXPORT_SYMBOL(qla2x00_send_change_request);
     
     int
     qla2x00_dump_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t addr,
    diff --git a/qla2x00t/qla_os.c b/qla2x00t/qla_os.c
    index b2b105615..5c7018eaf 100644
    --- a/qla2x00t/qla_os.c
    +++ b/qla2x00t/qla_os.c
    @@ -909,8 +909,8 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
     	if (!fcport)
     		return FAILED;
     
    -	qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET ISSUED.\n",
    -	    ha->host_no, cmd->device->id, cmd->device->lun, name);
    +	qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%lld): %s RESET ISSUED.\n",
    +	    ha->host_no, cmd->device->id, (unsigned long long)cmd->device->lun, name);
     
     	err = 0;
     	if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
    @@ -926,14 +926,14 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
     	    cmd->device->lun, type) != QLA_SUCCESS)
     		goto eh_reset_failed;
     
    -	qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n",
    -	    ha->host_no, cmd->device->id, cmd->device->lun, name);
    +	qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%lld): %s RESET SUCCEEDED.\n",
    +	    ha->host_no, cmd->device->id, (unsigned long long)cmd->device->lun, name);
     
     	return SUCCESS;
     
      eh_reset_failed:
    -	qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET FAILED: %s.\n",
    -	    ha->host_no, cmd->device->id, cmd->device->lun, name,
    +	qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%lld): %s RESET FAILED: %s.\n",
    +	    ha->host_no, cmd->device->id, (unsigned long long)cmd->device->lun, name,
     	    reset_errors[err]);
     	return FAILED;
     }
    @@ -1228,8 +1228,8 @@ static void qla2x00_handle_queue_full(struct scsi_device *sdev, int qdepth)
     		return;
     
     	DEBUG2(qla_printk(KERN_INFO, ha,
    -		"scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
    -		ha->host_no, sdev->channel, sdev->id, sdev->lun,
    +		"scsi(%ld:%d:%d:%lld): Queue depth adjusted-down to %d.\n",
    +		ha->host_no, sdev->channel, sdev->id, (unsigned long long)sdev->lun,
     		sdev->queue_depth));
     }
     
    @@ -1246,8 +1246,8 @@ static void qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, int qdepth)
     		scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, qdepth);
     
     	DEBUG2(qla_printk(KERN_INFO, ha,
    -	       "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
    -	       ha->host_no, sdev->channel, sdev->id, sdev->lun,
    +	       "scsi(%ld:%d:%d:%lld): Queue depth adjusted-up to %d.\n",
    +	       ha->host_no, sdev->channel, sdev->id, (unsigned long long)sdev->lun,
     	       sdev->queue_depth));
     }
     
    diff --git a/scripts/generate-kernel-patch b/scripts/generate-kernel-patch
    index d41d188e9..dbcf623fe 100755
    --- a/scripts/generate-kernel-patch
    +++ b/scripts/generate-kernel-patch
    @@ -107,16 +107,16 @@ EOF
     # passed via stdin and send the specialized patch to stdout.
     function specialize_patch {
       if [ "${enable_specialize}" = "true" ]; then
    +    if [ "${generating_upstream_patch}" = "true" ]; then
    +      scripts/filter-trace-entry-exit
    +    else
    +      cat
    +    fi |
         "$(dirname $0)/specialize-patch" \
              ${specialize_patch_options} \
              -v kernel_version="${kver3}" \
              -v SCSI_EXEC_REQ_FIFO_DEFINED="${scsi_exec_req_fifo_defined}" \
    -         -v SCST_IO_CONTEXT="${scst_io_context}" \
    -    | if [ "${generating_upstream_patch}" = "true" ]; then
    -        scripts/filter-trace-entry-exit
    -      else
    -        cat
    -      fi
    +         -v SCST_IO_CONTEXT="${scst_io_context}"
       else
         cat
       fi
    @@ -282,6 +282,7 @@ for p in scst/kernel/*-${kver}.patch \
     		echo iscsi-scst/kernel/patches/*-${kver}.patch;
     	   fi)
     do
    +  [ -e "$p" ] || continue
       # Exclude the put_page_callback patch when command-line option -u has been
       # specified since the current approach is not considered acceptable for
       # upstream kernel inclusion. See also http://lkml.org/lkml/2008/12/11/213.
    @@ -309,7 +310,7 @@ scst_07_pres="scst/src/scst_pres.h scst/src/scst_pres.c"
     scst_08_sysfs="scst/src/scst_sysfs.c"
     scst_09_debug="scst/include/scst_debug.h scst/src/scst_debug.c"
     scst_proc="scst/src/scst_proc.c"
    -scst_10_sgv="scst/include/scst_sgv.h scst/src/scst_mem.h scst/src/scst_mem.c doc/sgv_cache.sgml"
    +scst_10_sgv="scst/include/scst_sgv.h scst/src/scst_mem.h scst/src/scst_mem.c doc/scst_pg.sgml"
     scst_user="scst/include/scst_user.h scst/src/dev_handlers/scst_user.c"
     scst_13_vdisk="scst/src/dev_handlers/scst_vdisk.c"
     scst_14_tg="scst/src/scst_tg.c"
    diff --git a/scripts/generate-release-archive b/scripts/generate-release-archive
    index 1c4fe2d75..3980ac7dd 100755
    --- a/scripts/generate-release-archive
    +++ b/scripts/generate-release-archive
    @@ -4,15 +4,19 @@ usage() {
         echo "Usage: $(basename $0) name version"
     }
     
    -if [ $# != 2 ]; then
    +if [ $# -lt 2 ]; then
         usage
         exit 1
     fi
     
     scriptdir="$(dirname "$0")"
    -name="$1"
    -version="$2"
    +name="$1"; shift
    +version="$1"; shift
    +files="$*"
    +if [ -z "$files" ]; then
    +    files=$($scriptdir/list-source-files)
    +fi
     
     tar --owner=root --group=root --transform="s|^|$name-$version/|" \
    -  -cjf $name-$version.tar.bz2 $($scriptdir/list-source-files) &&
    +  -cjf $name-$version.tar.bz2 $files &&
     ls -l $name-$version.tar.bz2
    diff --git a/scripts/rebuild-rhel-kernel-rpm b/scripts/rebuild-rhel-kernel-rpm
    index e4a96c1d7..5e92901df 100755
    --- a/scripts/rebuild-rhel-kernel-rpm
    +++ b/scripts/rebuild-rhel-kernel-rpm
    @@ -220,14 +220,10 @@ cd SPECS
     log "Copying SCST patches to the SOURCES directory"
     
     cd ${rpmbuild_dir}/SOURCES
    -copy_best_matching_patch $scst_dir/scst/kernel/rhel/scst_exec_req_fifo scst_exec_req_fifo.patch ||
    -{
    -    echo "No matching scst_exec_req_fifo patch found for kernel version $kver";
    -    exit 1;
    -}
    +copy_best_matching_patch $scst_dir/scst/kernel/rhel/scst_exec_req_fifo scst_exec_req_fifo.patch
     copy_best_matching_patch $scst_dir/iscsi-scst/kernel/patches/rhel/put_page_callback put_page_callback.patch ||
     {
    -    echo "No matching scst_exec_req_fifo patch found for kernel version $kver";
    +    echo "No matching put_page_callback patch found for kernel version $kver";
         exit 1;
     }
     
    @@ -300,7 +296,7 @@ diff -u SPECS/kernel.spec{.orig,}
      Source82: config-s390x-debug
      Source83: config-s390x-debug-rhel
      
    -+Patch200: scst_exec_req_fifo.patch
    ++#Patch200: scst_exec_req_fifo.patch
     +Patch201: put_page_callback.patch
     +
      # empty final patch file to facilitate testing of kernel patches
    @@ -310,7 +306,7 @@ diff -u SPECS/kernel.spec{.orig,}
      # Dynamically generate kernel .config files from config-* files
      make -f %{SOURCE20} VERSION=%{version} configs
      
    -+ApplyPatch scst_exec_req_fifo.patch
    ++#ApplyPatch scst_exec_req_fifo.patch
     +ApplyPatch put_page_callback.patch
     +
      ApplyOptionalPatch linux-kernel-test.patch
    @@ -339,7 +335,7 @@ diff -u SPECS/kernel.spec{.orig,}
      Source82: config-generic
      Source83: config-x86_64-debug-rhel
      
    -+Patch200: scst_exec_req_fifo.patch
    ++#Patch200: scst_exec_req_fifo.patch
     +Patch201: put_page_callback.patch
     +
      # empty final patch file to facilitate testing of kernel patches
    @@ -349,7 +345,7 @@ diff -u SPECS/kernel.spec{.orig,}
      # Dynamically generate kernel .config files from config-* files
      make -f %{SOURCE20} VERSION=%{version} configs
      
    -+ApplyPatch scst_exec_req_fifo.patch
    ++#ApplyPatch scst_exec_req_fifo.patch
     +ApplyPatch put_page_callback.patch
     +
      ApplyOptionalPatch linux-kernel-test.patch
    @@ -365,6 +361,42 @@ diff -u SPECS/kernel.spec{.orig,}
        make ARCH=$Arch %{oldconfig_target} > /dev/null
        echo "# $Arch" > configs/$i
     EOF
    +elif [ ${kver#2.6.32-504.} != $kver ]; then
    +# RHEL/CentOS/SL 6.6
    +patch -p1 ${rpmbuild_dir}/SPECS/kernel.spec <<'EOF' || exit $?
    +diff -u SPECS/kernel.spec{.orig,}
    +--- kernel.spec.orig	2014-12-03 16:20:14.764118318 +0100
    ++++ kernel.spec	2014-12-03 16:21:36.606089530 +0100
    +@@ -610,6 +610,9 @@
    + Source85: config-powerpc64-debug-rhel
    + Source86: config-s390x-debug-rhel
    + 
    ++#Patch200: scst_exec_req_fifo.patch
    ++Patch201: put_page_callback.patch
    ++
    + # empty final patch file to facilitate testing of kernel patches
    + Patch999999: linux-kernel-test.patch
    + 
    +@@ -932,6 +935,9 @@
    + # Dynamically generate kernel .config files from config-* files
    + make -f %{SOURCE20} VERSION=%{version} configs
    + 
    ++#ApplyPatch scst_exec_req_fifo.patch
    ++ApplyPatch put_page_callback.patch
    ++
    + ApplyOptionalPatch linux-kernel-test.patch
    + 
    + # Any further pre-build tree manipulations happen here.
    +@@ -958,6 +964,8 @@
    + for i in *.config
    + do
    +   mv $i .config
    ++  echo "CONFIG_TCP_ZERO_COPY_TRANSFER_COMPLETION_NOTIFICATION=y" >> .config
    ++  sed -i.tmp -e 's/^CONFIG_SCSI_QLA_FC=.*/CONFIG_SCSI_QLA_FC=n/' .config
    +   Arch=`head -1 .config | cut -b 3-`
    +   make ARCH=$Arch %{oldconfig_target} > /dev/null
    +   echo "# $Arch" > configs/$i
    +EOF
     elif [ ${kver#3.10.0-12[13]} != $kver ]; then
     # RHEL/CentOS/SL 7.0
     patch -p1 ${rpmbuild_dir}/SPECS/kernel.spec <<'EOF' || exit $?
    @@ -382,7 +414,7 @@ patch -p1 ${rpmbuild_dir}/SPECS/kernel.spec <<'EOF' || exit $?
      Source2000: cpupower.service
      Source2001: cpupower.config
      
    -+Patch200: scst_exec_req_fifo.patch
    ++#Patch200: scst_exec_req_fifo.patch
     +Patch201: put_page_callback.patch
     +
      # empty final patch to facilitate testing of kernel patches
    @@ -392,7 +424,7 @@ patch -p1 ${rpmbuild_dir}/SPECS/kernel.spec <<'EOF' || exit $?
      # Drop some necessary files from the source dir into the buildroot
      cp $RPM_SOURCE_DIR/kernel-%{version}-*.config .
      
    -+ApplyPatch scst_exec_req_fifo.patch
    ++#ApplyPatch scst_exec_req_fifo.patch
     +ApplyPatch put_page_callback.patch
     +
      ApplyOptionalPatch linux-kernel-test.patch
    diff --git a/scripts/specialize-patch b/scripts/specialize-patch
    index ede8b0a19..dd0c842f2 100755
    --- a/scripts/specialize-patch
    +++ b/scripts/specialize-patch
    @@ -251,7 +251,7 @@ function evaluate(stmnt, pattern, arg, op, result) {
           sub(pattern, op[1] == 0 ? op[2] : op[1], stmnt)
         }
       
    -    pattern="\\((-*[0-9]+)\\)"
    +    pattern="\\([[:blank:]]*(-*[0-9]+)[[:blank:]]*\\)"
         while (match(stmnt, pattern, op) != 0)
         {
           sub(pattern, op[1], stmnt)
    @@ -545,11 +545,17 @@ BEGIN {
         reset_hunk_state_variables()
         match($0, "^@@ -([0-9]*),([0-9]*) \\+([0-9]*),([0-9]*) @@(.*)$", h)
       }
    -  else if (delete_next_blank_line && match($0, "^+$"))
    +  else if (delete_next_blank_line && $0 == "+")
       {
         discard = 1
         delete_next_blank_line = 0
       }
    +  else if (lines >= 2 && !match(line[lines-2], ":$") &&
    +           line[lines-1] == "+\x9return;" && $0 == "+}")
    +  {
    +    line[lines-1] = $0
    +    lines_less_added++
    +  }
       else
       {
         delete_next_blank_line = 0
    diff --git a/scst.spec.in b/scst.spec.in
    index 7eebbc592..1e5786cf0 100644
    --- a/scst.spec.in
    +++ b/scst.spec.in
    @@ -1,25 +1,66 @@
     %define kmod_name scst
    -%define kver %{expand:%%(echo ${KVER:-$(uname -r)})}
    -%define kernel_rpm %{expand:%%(						\
    -	  krpm="$(rpm -qf /boot/vmlinuz-%{kver} 2>/dev/null |		\
    -		grep -v 'is not owned by any package' | head -n 1)";	\
    -	  if [ -n "$krpm" ]; then					\
    -	    echo "/boot/vmlinuz-%{kver}";				\
    -	  else								\
    -	    echo "%{nil}";					 	\
    -	  fi								\
    +# kversion: Kernel version as it appears under /lib/modules.
    +# The algorithm for setting the variable kversion is as follows:
    +# - If the variable kversion has been set, use its value.
    +# - If an RPM with the name kernel-headers exists (RHEL / CentOS), use the
    +#   version number of the kernel that package is based on. This provides the
    +#   version number when building on a koji build server.
    +# - Otherwise use the version number of the running kernel.
    +%{!?kversion:%define kversion %{expand:%%(
    +	    if rpm --quiet -q kernel-headers; then
    +		rpm -q --qf '%%%%{version}-%%%%{release}.%%%%{arch}' \\
    +		    kernel-headers;
    +	    else
    +		uname -r;
    +	    fi
    +	)}}
    +%{echo:kversion=%{kversion}
    +}
    +# kernel_rpm: Name of the kernel RPM if the kernel is available as an RPM.
    +%if %{expand:%%(rpm --quiet -q kernel-headers ||
    +	        rpm --quiet -qf /lib/modules/%{kversion}/kernel/arch 2>/dev/null;
    +		echo $((1-$?)))}
    +%define kernel_rpm %{expand:%%(
    +	    if rpm --quiet -q kernel-headers; then
    +		echo kernel;
    +	    else
    +		rpm -q --qf '%%%%{name}\\n' \\
    +		    "$(rpm -qf /lib/modules/%%{kversion}/kernel/arch | head -n1)";
    +	    fi
     	)}
    +%endif
    +# krpmver: Version of the kernel RPM. Not necessarily identical to %{kversion}.
    +%{?kernel_rpm:%define krpmver %{expand:%%(
    +	    if rpm --quiet -q %%{kernel_rpm}; then
    +		rpm -q --qf '%%%%{version}-%%%%{release}\\n' "%%{kernel_rpm}";
    +	    else
    +		rpm -q --qf '%%%%{version}-%%%%{release}\\n' kernel-headers;
    +	    fi |
    +	    head -n1
    +	)}}
    +%{echo:krpmver=%{krpmver}
    +}
    +# kernel_devel_rpm: Name of the kernel development RPM.
    +%{?kernel_rpm:%define kernel_devel_rpm %{kernel_rpm}-devel}
    +# Version of the RPM that is being built.
     %define rpm_version @rpm_version@
    +# Make command with or without flags.
     %define make %{expand:%%(echo ${MAKE:-make})}
    +%define pkgrel 1
    +%define dkms_version %{rpm_version}-%{pkgrel}%{?dist}
     
    -Name:		%{kmod_name}-%{kver}
    -Version:        %{rpm_version}
    -Release:        1
    -Summary:	SCST mid-layer kernel driver
    +Name:		%{kmod_name}
    +Version:	%{rpm_version}
    +Release:	%{pkgrel}%{?dist}
    +Summary:	SCST mid-layer kernel drivers
     Group:		System/Kernel
     License:	GPLv2
     Vendor:		http://scst.sourceforge.net/
     URL:		http://scst.sourceforge.net/
    +# Unfortunately the Red Hat / CentOS kernel-debug-devel RPM provides
    +# kernel-devel so a workaround is needed to match the kernel-devel RPM.
    +%{?kernel_rpm:Requires:	%{kernel_rpm} = %{krpmver}}
    +BuildRequires:	%{?kernel_rpm:%{kernel_rpm} = %{krpmver} %{kernel_devel_rpm} = %{krpmver}} gcc make
     
     Source:		%{kmod_name}-%{version}.tar.bz2
     BuildRoot:	%{_tmppath}/%{name}-%{version}-build
    @@ -40,10 +81,26 @@ Authors:
     --------
         Vladislav Bolkhovitin, Bart Van Assche and others
     
    +%package userspace
    +Summary:	SCST mid-layer user space software
    +Group:		Development/Kernel
    +Requires:	scst-dkms
    +
    +%description userspace
    +A generic SCSI target subsystem for Linux that allows to convert any Linux
    +server into a sophisticated storage server. The three layers in SCST are the
    +target driver layer; the SCSI target core and the device handler layer. SCST
    +target drivers realize communication with an initiator and implement a storage
    +protocol like iSCSI, FC or SRP. SCST device handlers implement a SCSI
    +interface on top of local storage. Examples of such local storage are SCSI
    +RAID controller (dev_disk handler), block device (vdisk_blockio handler), file
    +(vdisk_fileio handler) or custom block device behavior implemented in user
    +space (scst_user).
    +
     %package devel
     Summary:	SCST mid-layer kernel driver development package
     Group:		Development/Kernel
    -AutoReqProv:	no
    +BuildArch:	noarch
     
     %description devel
     A generic SCSI target subsystem for Linux (SCST) that allows to convert
    @@ -53,6 +110,25 @@ provide access to a local SCSI RAID controller (dev_disk), block device
     (vdisk_blockio), file (vdisk_fileio) or custom block device behavior
     implemented in user space (scst_user).
     
    +Authors:
    +--------
    +    Vladislav Bolkhovitin, Bart Van Assche and others
    +
    +%package dkms
    +Summary:	DKMS-enabled SCST source code package
    +Group:		System/Kernel
    +BuildArch:	noarch
    +Requires(pre):	dkms gcc make
    +Requires(post):	dkms
    +
    +%description dkms
    +A generic SCSI target subsystem for Linux (SCST) that allows to convert
    +any Linux server into a sophisticated storage server. SCST target drivers
    +implement protocols like iSCSI, FC or SRP. SCST device handlers either
    +provide access to a local SCSI RAID controller (dev_disk), block device
    +(vdisk_blockio), file (vdisk_fileio) or custom block device behavior
    +implemented in user space (scst_user).
    +
     Authors:
     --------
         Vladislav Bolkhovitin, Bart Van Assche and others
    @@ -62,14 +138,14 @@ Authors:
     %setup -q -n %{kmod_name}-%{version}
     
     %build
    -export KVER=%{kver} PREFIX=%{_prefix}
    +export KVER=%{kversion} PREFIX=%{_prefix}
     export BUILD_2X_MODULE=y CONFIG_SCSI_QLA_FC=y CONFIG_SCSI_QLA2XXX_TARGET=y
     for d in scst fcst iscsi-scst qla2x00t/qla2x00-target scst_local srpt; do
         %{make} -C $d
     done
     
     %install
    -export KVER=%{kver} PREFIX=%{_prefix} MANDIR=%{_mandir}
    +export KVER=%{kversion} PREFIX=%{_prefix} MANDIR=%{_mandir}
     export BUILD_2X_MODULE=y CONFIG_SCSI_QLA_FC=y CONFIG_SCSI_QLA2XXX_TARGET=y
     for d in scst; do
         DESTDIR=%{buildroot} %{make} -C $d install
    @@ -77,12 +153,72 @@ done
     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*
    +rm -f %{buildroot}/lib/modules/%{kversion}/[Mm]odule*
    +
    +install -d -m 755 %{buildroot}/usr/src/%{kmod_name}-%{dkms_version}
    +(
    +    cd %{buildroot}/usr/src/%{kmod_name}-%{dkms_version} &&
    +    tar --strip-components=1 -xaf %{SOURCE0}
    +)
    +cat >%{buildroot}/usr/src/%{kmod_name}-%{dkms_version}/dkms.conf <<"EOF"
    +PACKAGE_VERSION="%{dkms_version}"
    +PACKAGE_NAME="%{kmod_name}"
    +AUTOINSTALL=yes
    +MAKE[0]="export KVER=${kernelver} KDIR=${kernel_source_dir} BUILD_2X_MODULE=y CONFIG_SCSI_QLA_FC=y CONFIG_SCSI_QLA2XXX_TARGET=y && make -sC scst && make -sC fcst && make -sC iscsi-scst && make -sC qla2x00t/qla2x00-target && make -sC scst_local && make -sC srpt && cp */*.ko */*/*.ko */*/*/*.ko ."
    +CLEAN="make clean"
    +# Remove any existing ib_srpt.ko kernel modules
    +PRE_INSTALL="find /lib/modules/${kernelver} -name ib_srpt.ko -exec rm {} \;"
    +BUILT_MODULE_NAME[ 0]="fcst"
    +BUILT_MODULE_NAME[ 1]="ib_srpt"
    +BUILT_MODULE_NAME[ 2]="iscsi-scst"
    +BUILT_MODULE_NAME[ 3]="qla2x00tgt"
    +BUILT_MODULE_NAME[ 4]="qla2xxx_scst"
    +BUILT_MODULE_NAME[ 5]="scst"
    +BUILT_MODULE_NAME[ 6]="scst_local"
    +BUILT_MODULE_NAME[ 7]="scst_cdrom"
    +BUILT_MODULE_NAME[ 8]="scst_changer"
    +BUILT_MODULE_NAME[ 9]="scst_disk"
    +BUILT_MODULE_NAME[10]="scst_modisk"
    +BUILT_MODULE_NAME[11]="scst_processor"
    +BUILT_MODULE_NAME[12]="scst_raid"
    +BUILT_MODULE_NAME[13]="scst_tape"
    +BUILT_MODULE_NAME[14]="scst_user"
    +BUILT_MODULE_NAME[15]="scst_vdisk"
    +BUILT_MODULE_NAME[16]="isert-scst"
    +DEST_MODULE_LOCATION[ 0]="/extra"
    +DEST_MODULE_LOCATION[ 1]="/extra"
    +DEST_MODULE_LOCATION[ 2]="/extra"
    +DEST_MODULE_LOCATION[ 3]="/extra"
    +DEST_MODULE_LOCATION[ 4]="/extra"
    +DEST_MODULE_LOCATION[ 5]="/extra"
    +DEST_MODULE_LOCATION[ 6]="/extra"
    +DEST_MODULE_LOCATION[ 7]="/extra/dev_handlers"
    +DEST_MODULE_LOCATION[ 8]="/extra/dev_handlers"
    +DEST_MODULE_LOCATION[ 9]="/extra/dev_handlers"
    +DEST_MODULE_LOCATION[10]="/extra/dev_handlers"
    +DEST_MODULE_LOCATION[11]="/extra/dev_handlers"
    +DEST_MODULE_LOCATION[12]="/extra/dev_handlers"
    +DEST_MODULE_LOCATION[13]="/extra/dev_handlers"
    +DEST_MODULE_LOCATION[14]="/extra/dev_handlers"
    +DEST_MODULE_LOCATION[15]="/extra/dev_handlers"
    +DEST_MODULE_LOCATION[16]="/extra"
    +EOF
     
     %clean
     rm -rf %{buildroot}
     
     %pre
    +# Remove any existing ib_srpt.ko kernel modules
    +find /lib/modules/%{kversion} -name ib_srpt.ko -exec rm {} \;
    +# Remove files installed by "make install"
    +rm -f /usr/local/man/man5/iscsi-scstd.conf.5
    +rm -f /usr/local/man/man8/iscsi-scst-adm.8
    +rm -f /usr/local/man/man8/iscsi-scstd.8
    +rm -f /usr/local/sbin/iscsi-scst-adm
    +rm -f /usr/local/sbin/iscsi-scstd
    +rm -rf /usr/local/include/scst
    +
    +%pre userspace
     # Remove files installed by "make install"
     rm -f /usr/local/man/man5/iscsi-scstd.conf.5
     rm -f /usr/local/man/man8/iscsi-scst-adm.8
    @@ -90,33 +226,49 @@ rm -f /usr/local/man/man8/iscsi-scstd.8
     rm -f /usr/local/sbin/iscsi-scst-adm
     rm -f /usr/local/sbin/iscsi-scstd
     rm -rf /usr/local/include/scst
    -# Remove existing ib_srpt.ko kernel modules
    -find /lib/modules/%{kver} -name ib_srpt.ko -exec rm {} \;
     
     %post
    -/sbin/depmod -a %{kver}
    +/sbin/depmod -a %{kversion}
    +
    +%post dkms
    +dkms add -m %{kmod_name} -v %{dkms_version} --rpm_safe_upgrade
    +dkms build -m %{kmod_name} -v %{dkms_version}
    +dkms install -m %{kmod_name} -v %{dkms_version}
    +
    +%preun dkms
    +dkms remove -m %{kmod_name} -v %{dkms_version} --rpm_safe_upgrade --all
    +true
     
     %files
     %defattr(-,root,root)
    -%dir /lib/modules/%{kver}/extra
    -/lib/modules/%{kver}/extra/fcst.ko
    -/lib/modules/%{kver}/extra/ib_srpt.ko
    -/lib/modules/%{kver}/extra/iscsi-scst.ko
    -/lib/modules/%{kver}/extra/isert-scst.ko
    -/lib/modules/%{kver}/extra/qla2x00tgt.ko
    -/lib/modules/%{kver}/extra/qla2xxx_scst.ko
    -/lib/modules/%{kver}/extra/scst.ko
    -/lib/modules/%{kver}/extra/scst_local.ko
    -%dir /lib/modules/%{kver}/extra/dev_handlers
    -/lib/modules/%{kver}/extra/dev_handlers/scst_cdrom.ko
    -/lib/modules/%{kver}/extra/dev_handlers/scst_changer.ko
    -/lib/modules/%{kver}/extra/dev_handlers/scst_disk.ko
    -/lib/modules/%{kver}/extra/dev_handlers/scst_modisk.ko
    -/lib/modules/%{kver}/extra/dev_handlers/scst_processor.ko
    -/lib/modules/%{kver}/extra/dev_handlers/scst_raid.ko
    -/lib/modules/%{kver}/extra/dev_handlers/scst_tape.ko
    -/lib/modules/%{kver}/extra/dev_handlers/scst_user.ko
    -/lib/modules/%{kver}/extra/dev_handlers/scst_vdisk.ko
    +%dir /lib/modules/%{kversion}/extra
    +/lib/modules/%{kversion}/extra/fcst.ko
    +/lib/modules/%{kversion}/extra/ib_srpt.ko
    +/lib/modules/%{kversion}/extra/iscsi-scst.ko
    +/lib/modules/%{kversion}/extra/isert-scst.ko
    +/lib/modules/%{kversion}/extra/qla2x00tgt.ko
    +/lib/modules/%{kversion}/extra/qla2xxx_scst.ko
    +/lib/modules/%{kversion}/extra/scst.ko
    +/lib/modules/%{kversion}/extra/scst_local.ko
    +%dir /lib/modules/%{kversion}/extra/dev_handlers
    +/lib/modules/%{kversion}/extra/dev_handlers/scst_cdrom.ko
    +/lib/modules/%{kversion}/extra/dev_handlers/scst_changer.ko
    +/lib/modules/%{kversion}/extra/dev_handlers/scst_disk.ko
    +/lib/modules/%{kversion}/extra/dev_handlers/scst_modisk.ko
    +/lib/modules/%{kversion}/extra/dev_handlers/scst_processor.ko
    +/lib/modules/%{kversion}/extra/dev_handlers/scst_raid.ko
    +/lib/modules/%{kversion}/extra/dev_handlers/scst_tape.ko
    +/lib/modules/%{kversion}/extra/dev_handlers/scst_user.ko
    +/lib/modules/%{kversion}/extra/dev_handlers/scst_vdisk.ko
    +%{_mandir}/man5/iscsi-scstd.conf.5.gz
    +%{_mandir}/man8/iscsi-scst-adm.8.gz
    +%{_mandir}/man8/iscsi-scstd.8.gz
    +%{_sbindir}/iscsi-scst-adm
    +%{_sbindir}/iscsi-scstd
    +%dir /var/lib/scst/pr
    +%dir /var/lib/scst/vdev_mode_pages
    +
    +%files userspace
     %{_mandir}/man5/iscsi-scstd.conf.5.gz
     %{_mandir}/man8/iscsi-scst-adm.8.gz
     %{_mandir}/man8/iscsi-scstd.8.gz
    @@ -136,6 +288,12 @@ find /lib/modules/%{kver} -name ib_srpt.ko -exec rm {} \;
     /usr/include/scst/scst_sgv.h
     /usr/include/scst/scst_user.h
     
    +%files dkms
    +%defattr(-,root,root)
    +/usr/src/%{kmod_name}-%{dkms_version}/
    +
     %changelog
    +* Fri Jan 16 2015 Bart Van Assche 
    +- Added DKMS support.
     * Fri Nov 22 2013 Bart Van Assche 
     - Initial spec file.
    diff --git a/scst/Makefile b/scst/Makefile
    index bcd0770e4..44cdd1cdd 100644
    --- a/scst/Makefile
    +++ b/scst/Makefile
    @@ -54,7 +54,9 @@ enable_proc:
     	cd $(SCST_DIR) && $(MAKE) $@
     
     release-archive:
    -	../scripts/generate-release-archive scst "$$(sed -n 's/^#define[[:blank:]]SCST_VERSION_NAME[[:blank:]]*\"\([^\"]*\)\".*/\1/p' include/scst_const.h)"
    +	../scripts/generate-release-archive scst \
    +	  "$$(sed -n 's/^#define[[:blank:]]SCST_VERSION_NAME[[:blank:]]*\"\([^\"]*\)\".*/\1/p' include/scst_const.h)" \
    +	  $(shell list-source-files) ../scripts/rebuild-rhel-kernel-rpm
     
     help:
     	@echo "		all (the default) : make all"
    diff --git a/scst/README b/scst/README
    index c2d6555c5..b7eff48e0 100644
    --- a/scst/README
    +++ b/scst/README
    @@ -70,27 +70,13 @@ following patches for the kernel in the "kernel" subdirectory. All of
     them are optional, so, if you don't need the corresponding
     functionality, you may not apply them.
     
    -1. scst_exec_req_fifo-2.6.X.patch. This patch is necessary for
    -pass-through dev handlers, because in the mainstream kernels
    -scsi_do_req()/scsi_execute_async() work in LIFO order, instead of
    -expected and required FIFO. So SCST needs new functions
    -scsi_do_req_fifo() or scsi_execute_async_fifo() to be added in the
    -kernel. This patch does that. You may not patch the kernel if you don't
    -need the pass-through support. Alternatively, you can define
    -CONFIG_SCST_STRICT_SERIALIZING compile option during the compilation
    -(see description below). Unfortunately, the CONFIG_SCST_STRICT_SERIALIZING
    -trick doesn't work on kernels starting from 2.6.30, because those
    -kernels don't have the required functionality (scsi_execute_async())
    -anymore. So, on them to have pass-through working you have to apply
    -scst_exec_req_fifo-2.6.X.patch.
    -
    -2. readahead-2.6.X.patch. This patch fixes problem in Linux readahead
    +1. readahead-2.6.X.patch. This patch fixes problem in Linux readahead
     subsystem and greatly improves performance for software RAIDs. See
     http://sourceforge.net/mailarchive/forum.php?thread_name=a0272b440906030714g67eabc5k8f847fb1e538cc62%40mail.gmail.com&forum_name=scst-devel
     thread for more details. It is included in the mainstream kernels 2.6.33
     and 2.6.32.11.
     
    -3. readahead-context-2.6.X.patch. This is backported from 2.6.31 version
    +2. readahead-context-2.6.X.patch. This is backported from 2.6.31 version
     of the context readahead patch http://lkml.org/lkml/2009/4/12/9, big
     thanks to Wu Fengguang. This is a performance improvement patch. It is
     included in the mainstream kernel 2.6.31.
    @@ -1088,7 +1074,7 @@ Each vdisk_fileio's device has the following attributes in
        reported in the SCSI device identification VPD page. If eui64_id has
        been set the value of this attribute is reported as the EUI-64 ID. The
        first three bytes of an EUI-64 ID are a so-called organizationally
    -   unique identifier (OUI). The remaining bytes may be choosen by the
    +   unique identifier (OUI). The remaining bytes may be chosen by the
        organization that owns the OUI. For more information about OUIs, see
        also http://standards.ieee.org/develop/regauth/oui/public.html.
     
    diff --git a/scst/README_in-tree b/scst/README_in-tree
    index 67210ed60..553fac3e6 100644
    --- a/scst/README_in-tree
    +++ b/scst/README_in-tree
    @@ -935,7 +935,7 @@ Each vdisk_fileio's device has the following attributes in
        reported in the SCSI device identification VPD page. If eui64_id has
        been set the value of this attribute is reported as the EUI-64 ID. The
        first three bytes of an EUI-64 ID are a so-called organizationally
    -   unique identifier (OUI). The remaining bytes may be choosen by the
    +   unique identifier (OUI). The remaining bytes may be chosen by the
        organization that owns the OUI. For more information about OUIs, see
        also http://standards.ieee.org/develop/regauth/oui/public.html.
     
    diff --git a/scst/include/scst.h b/scst/include/scst.h
    index b47ce4b7e..51b84bc59 100644
    --- a/scst/include/scst.h
    +++ b/scst/include/scst.h
    @@ -128,6 +128,14 @@ char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap);
     #define nr_cpu_ids NR_CPUS
     #endif
     
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
    +/*
    + * See also patch "fix abuses of ptrdiff_t" (commit ID
    + * 142956af525002c5378e7d91d81a01189841a785).
    + */
    +typedef unsigned long uintptr_t;
    +#endif
    +
     #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
     #define cpumask_bits(maskp) ((maskp)->bits)
     #ifdef CONFIG_CPUMASK_OFFSTACK
    @@ -1404,7 +1412,7 @@ struct scst_dev_type {
     	int (*dev_done)(struct scst_cmd *cmd);
     
     	/*
    -	 * Called to notify dev hander that the command is about to be freed.
    +	 * Called to notify dev handler that the command is about to be freed.
     	 *
     	 * Could be called on IRQ context.
     	 *
    @@ -2505,7 +2513,7 @@ struct scst_device {
     
     	/*
     	 * Set, if this device is being unregistered. Useful to let sysfs
    -	 * attributes know when they should exit immediatelly to prevent
    +	 * attributes know when they should exit immediately to prevent
     	 * possible deadlocks with their device unregistration waiting for
     	 * their kobj last put.
     	 */
    @@ -4373,9 +4381,12 @@ static inline int cancel_delayed_work_sync(struct delayed_work *work)
     #endif
     #endif
     
    +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) && defined(CONFIG_LOCKDEP)
    +extern struct lockdep_map scst_suspend_dep_map;
    +#endif
    +
     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) && \
     	defined(CONFIG_DEBUG_LOCK_ALLOC)
    -extern struct lockdep_map scst_suspend_dep_map;
     #define scst_assert_activity_suspended()		\
     	WARN_ON(debug_locks && !lock_is_held(&scst_suspend_dep_map))
     #else
    @@ -4848,7 +4859,7 @@ void scst_init_threads(struct scst_cmd_threads *cmd_threads);
     void scst_deinit_threads(struct scst_cmd_threads *cmd_threads);
     
     void scst_pass_through_cmd_done(void *data, char *sense, int result, int resid);
    -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)
    +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
     int scst_scsi_exec_async(struct scst_cmd *cmd, void *data,
     	void (*done)(void *data, char *sense, int result, int resid));
     #endif
    diff --git a/scst/include/scst_const.h b/scst/include/scst_const.h
    index 0250c4a1c..022f0ec77 100644
    --- a/scst/include/scst_const.h
    +++ b/scst/include/scst_const.h
    @@ -292,7 +292,6 @@ static inline int scst_sense_response_code(const uint8_t *sense)
     #define scst_sense_format_in_progress		NOT_READY,       0x04, 0x04
     #define scst_sense_tp_transitioning		NOT_READY,	 0x04, 0x0A
     #define scst_sense_tp_unav			NOT_READY,	 0x04, 0x0C
    -#define scst_sense_not_ready			NOT_READY,       0x04, 0x10
     #define scst_sense_no_medium			NOT_READY,       0x3a, 0
     
     /* MEDIUM_ERROR is 3 */
    @@ -300,7 +299,7 @@ static inline int scst_sense_response_code(const uint8_t *sense)
     #define scst_sense_read_error			MEDIUM_ERROR,    0x11, 0
     
     /* HARDWARE_ERROR is 4 */
    -#define scst_sense_hardw_error			HARDWARE_ERROR,  0x44, 0
    +#define scst_sense_hardw_error			HARDWARE_ERROR,  0x44, 0 /* non-retriable */
     
     /* ILLEGAL_REQUEST is 5 */
     #define scst_sense_invalid_opcode		ILLEGAL_REQUEST, 0x20, 0
    @@ -335,6 +334,7 @@ static inline int scst_sense_response_code(const uint8_t *sense)
     
     /* ABORTED_COMMAND is 0xb */
     #define scst_sense_aborted_command		ABORTED_COMMAND, 0x00, 0
    +#define scst_sense_internal_failure		ABORTED_COMMAND, 0x44, 0 /* retriable */
     
     /* MISCOMPARE is 0xe */
     #define scst_sense_miscompare_error		MISCOMPARE,      0x1D, 0
    diff --git a/scst/kernel/in-tree/Kconfig.drivers.Linux-3.17.patch b/scst/kernel/in-tree/Kconfig.drivers.Linux-3.17.patch
    new file mode 100644
    index 000000000..0d5a19f0f
    --- /dev/null
    +++ b/scst/kernel/in-tree/Kconfig.drivers.Linux-3.17.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/Kconfig.drivers.Linux-3.18.patch b/scst/kernel/in-tree/Kconfig.drivers.Linux-3.18.patch
    new file mode 100644
    index 000000000..0d5a19f0f
    --- /dev/null
    +++ b/scst/kernel/in-tree/Kconfig.drivers.Linux-3.18.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.17 b/scst/kernel/in-tree/Makefile.dev_handlers-3.17
    new file mode 100644
    index 000000000..f933b36f7
    --- /dev/null
    +++ b/scst/kernel/in-tree/Makefile.dev_handlers-3.17
    @@ -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.dev_handlers-3.18 b/scst/kernel/in-tree/Makefile.dev_handlers-3.18
    new file mode 100644
    index 000000000..f933b36f7
    --- /dev/null
    +++ b/scst/kernel/in-tree/Makefile.dev_handlers-3.18
    @@ -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.17.patch b/scst/kernel/in-tree/Makefile.drivers.Linux-3.17.patch
    new file mode 100644
    index 000000000..f7213ed4c
    --- /dev/null
    +++ b/scst/kernel/in-tree/Makefile.drivers.Linux-3.17.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.drivers.Linux-3.18.patch b/scst/kernel/in-tree/Makefile.drivers.Linux-3.18.patch
    new file mode 100644
    index 000000000..4d482c340
    --- /dev/null
    +++ b/scst/kernel/in-tree/Makefile.drivers.Linux-3.18.patch
    @@ -0,0 +1,12 @@
    +diff --git a/drivers/Makefile b/drivers/Makefile
    +index ebee555..17f67ae 100644
    +--- a/drivers/Makefile
    ++++ b/drivers/Makefile
    +@@ -134,6 +134,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-3.17 b/scst/kernel/in-tree/Makefile.scst-3.17
    new file mode 100644
    index 000000000..53af5f388
    --- /dev/null
    +++ b/scst/kernel/in-tree/Makefile.scst-3.17
    @@ -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/in-tree/Makefile.scst-3.18 b/scst/kernel/in-tree/Makefile.scst-3.18
    new file mode 100644
    index 000000000..53af5f388
    --- /dev/null
    +++ b/scst/kernel/in-tree/Makefile.scst-3.18
    @@ -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/rhel/scst_exec_req_fifo-2.6.32.patch b/scst/kernel/rhel/scst_exec_req_fifo-2.6.32.patch
    deleted file mode 100644
    index bcb3b02e2..000000000
    --- a/scst/kernel/rhel/scst_exec_req_fifo-2.6.32.patch
    +++ /dev/null
    @@ -1,529 +0,0 @@
    -diff -upkr linux-2.6.32/block/blk-map.c linux-2.6.32/block/blk-map.c
    ---- linux-2.6.32/block/blk-map.c	2009-12-02 22:51:21.000000000 -0500
    -+++ linux-2.6.32/block/blk-map.c	2011-05-17 20:56:18.341812997 -0400
    -@@ -5,6 +5,7 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -271,6 +272,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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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 = 0;
    -+	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 |= 1 << BIO_RW;
    -+
    -+				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;
    -+		}
    -+	}
    -+
    -+	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
    -diff -upkr linux-2.6.32/include/linux/blkdev.h linux-2.6.32/include/linux/blkdev.h
    ---- linux-2.6.32/include/linux/blkdev.h	2009-12-02 22:51:21.000000000 -0500
    -+++ linux-2.6.32/include/linux/blkdev.h	2009-12-16 07:21:35.000000000 -0500
    -@@ -708,6 +708,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);
    -@@ -812,6 +814,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 *,
    -diff -upkr linux-2.6.32/include/linux/scatterlist.h linux-2.6.32/include/linux/scatterlist.h
    ---- linux-2.6.32/include/linux/scatterlist.h	2009-12-02 22:51:21.000000000 -0500
    -+++ linux-2.6.32/include/linux/scatterlist.h	2009-12-16 07:21:35.000000000 -0500
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * Maximum number of entries that will be allocated in one piece, if
    -  * a list larger than this is required then chaining will be utilized.
    -diff -upkr linux-2.6.32/lib/scatterlist.c linux-2.6.32/lib/scatterlist.c
    ---- linux-2.6.32/lib/scatterlist.c	2009-12-02 22:51:21.000000000 -0500
    -+++ linux-2.6.32/lib/scatterlist.c	2009-12-16 07:21:35.000000000 -0500
    -@@ -493,3 +493,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/rhel/scst_exec_req_fifo-3.10.0-121.patch b/scst/kernel/rhel/scst_exec_req_fifo-3.10.0-121.patch
    deleted file mode 120000
    index 6a3acd053..000000000
    --- a/scst/kernel/rhel/scst_exec_req_fifo-3.10.0-121.patch
    +++ /dev/null
    @@ -1 +0,0 @@
    -../scst_exec_req_fifo-3.10.patch
    \ No newline at end of file
    diff --git a/scst/kernel/rhel/scst_exec_req_fifo-3.10.0-123.patch b/scst/kernel/rhel/scst_exec_req_fifo-3.10.0-123.patch
    deleted file mode 100644
    index d60ddd1de..000000000
    --- a/scst/kernel/rhel/scst_exec_req_fifo-3.10.0-123.patch
    +++ /dev/null
    @@ -1,524 +0,0 @@
    -diff -rup ../../centos-7-orig/linux-3.10.0-123.6.3.el7/block/blk-map.c ./block/blk-map.c
    ---- ../../centos-7-orig/linux-3.10.0-123.6.3.el7/block/blk-map.c	2014-07-16 20:25:31.000000000 +0200
    -+++ ./block/blk-map.c	2014-08-07 09:09:11.751302961 +0200
    -@@ -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
    -diff -rup ../../centos-7-orig/linux-3.10.0-123.6.3.el7/include/linux/blkdev.h ./include/linux/blkdev.h
    ---- ../../centos-7-orig/linux-3.10.0-123.6.3.el7/include/linux/blkdev.h	2014-07-16 20:25:31.000000000 +0200
    -+++ ./include/linux/blkdev.h	2014-08-07 09:09:11.751302961 +0200
    -@@ -719,6 +719,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);
    -@@ -838,6 +840,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 *,
    -diff -rup ../../centos-7-orig/linux-3.10.0-123.6.3.el7/include/linux/scatterlist.h ./include/linux/scatterlist.h
    ---- ../../centos-7-orig/linux-3.10.0-123.6.3.el7/include/linux/scatterlist.h	2014-07-16 20:25:31.000000000 +0200
    -+++ ./include/linux/scatterlist.h	2014-08-07 09:09:11.751302961 +0200
    -@@ -8,6 +8,7 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    - 
    - struct sg_table {
    - 	struct scatterlist *sgl;	/* the list */
    -@@ -244,6 +245,9 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+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.
    -diff -rup ../../centos-7-orig/linux-3.10.0-123.6.3.el7/lib/scatterlist.c ./lib/scatterlist.c
    ---- ../../centos-7-orig/linux-3.10.0-123.6.3.el7/lib/scatterlist.c	2014-07-16 20:25:31.000000000 +0200
    -+++ ./lib/scatterlist.c	2014-08-07 09:09:11.751302961 +0200
    -@@ -628,3 +628,126 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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/kernel/scst_exec_req_fifo-2.6.30.patch b/scst/kernel/scst_exec_req_fifo-2.6.30.patch
    deleted file mode 100644
    index 9b9cb78e1..000000000
    --- a/scst/kernel/scst_exec_req_fifo-2.6.30.patch
    +++ /dev/null
    @@ -1,529 +0,0 @@
    -diff -upkr linux-2.6.30/block/blk-map.c linux-2.6.30/block/blk-map.c
    ---- linux-2.6.30/block/blk-map.c	2009-06-09 23:05:27.000000000 -0400
    -+++ linux-2.6.30/block/blk-map.c	2011-05-17 21:03:29.661813000 -0400
    -@@ -5,6 +5,7 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -272,6 +273,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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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 |= 1 << BIO_RW;
    -+
    -+				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;
    -+		}
    -+	}
    -+
    -+	rq->buffer = rq->data = 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 = rq->data = 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 = 0;
    -+
    -+	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
    -diff -upkr linux-2.6.30/include/linux/blkdev.h linux-2.6.30/include/linux/blkdev.h
    ---- linux-2.6.30/include/linux/blkdev.h	2009-06-09 23:05:27.000000000 -0400
    -+++ linux-2.6.30/include/linux/blkdev.h	2009-08-12 11:48:06.000000000 -0400
    -@@ -704,6 +704,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);
    -@@ -807,6 +809,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 *,
    -diff -upkr linux-2.6.30/include/linux/scatterlist.h linux-2.6.30/include/linux/scatterlist.h
    ---- linux-2.6.30/include/linux/scatterlist.h	2009-06-09 23:05:27.000000000 -0400
    -+++ linux-2.6.30/include/linux/scatterlist.h	2009-08-12 11:50:02.000000000 -0400
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * Maximum number of entries that will be allocated in one piece, if
    -  * a list larger than this is required then chaining will be utilized.
    -diff -upkr linux-2.6.30/lib/scatterlist.c linux-2.6.30/lib/scatterlist.c
    ---- linux-2.6.30/lib/scatterlist.c	2009-06-09 23:05:27.000000000 -0400
    -+++ linux-2.6.30/lib/scatterlist.c	2009-08-12 11:56:04.000000000 -0400
    -@@ -485,3 +485,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/scst_exec_req_fifo-2.6.31.patch b/scst/kernel/scst_exec_req_fifo-2.6.31.patch
    deleted file mode 100644
    index 0d9c06e6d..000000000
    --- a/scst/kernel/scst_exec_req_fifo-2.6.31.patch
    +++ /dev/null
    @@ -1,529 +0,0 @@
    -diff -upkr linux-2.6.31/block/blk-map.c linux-2.6.31/block/blk-map.c
    ---- linux-2.6.31/block/blk-map.c	2009-09-09 18:13:59.000000000 -0400
    -+++ linux-2.6.31/block/blk-map.c	2011-05-17 21:05:32.669812993 -0400
    -@@ -5,6 +5,7 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -271,6 +272,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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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 |= 1 << BIO_RW;
    -+
    -+				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;
    -+		}
    -+	}
    -+
    -+	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
    -diff -upkr linux-2.6.31/include/linux/blkdev.h linux-2.6.31/include/linux/blkdev.h
    ---- linux-2.6.31/include/linux/blkdev.h	2009-09-09 18:13:59.000000000 -0400
    -+++ linux-2.6.31/include/linux/blkdev.h	2009-09-23 06:17:33.000000000 -0400
    -@@ -699,6 +699,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);
    -@@ -803,6 +805,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 *,
    -diff -upkr linux-2.6.31/include/linux/scatterlist.h linux-2.6.31/include/linux/scatterlist.h
    ---- linux-2.6.31/include/linux/scatterlist.h	2009-09-09 18:13:59.000000000 -0400
    -+++ linux-2.6.31/include/linux/scatterlist.h	2009-09-23 06:17:33.000000000 -0400
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * Maximum number of entries that will be allocated in one piece, if
    -  * a list larger than this is required then chaining will be utilized.
    -diff -upkr linux-2.6.31/lib/scatterlist.c linux-2.6.31/lib/scatterlist.c
    ---- linux-2.6.31/lib/scatterlist.c	2009-09-09 18:13:59.000000000 -0400
    -+++ linux-2.6.31/lib/scatterlist.c	2009-09-23 06:17:33.000000000 -0400
    -@@ -493,3 +493,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/scst_exec_req_fifo-2.6.32.patch b/scst/kernel/scst_exec_req_fifo-2.6.32.patch
    deleted file mode 100644
    index bc0171019..000000000
    --- a/scst/kernel/scst_exec_req_fifo-2.6.32.patch
    +++ /dev/null
    @@ -1,529 +0,0 @@
    -diff -upkr linux-2.6.32/block/blk-map.c linux-2.6.32/block/blk-map.c
    ---- linux-2.6.32/block/blk-map.c	2009-12-02 22:51:21.000000000 -0500
    -+++ linux-2.6.32/block/blk-map.c	2011-05-17 20:56:18.341812997 -0400
    -@@ -5,6 +5,7 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -271,6 +272,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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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 |= 1 << BIO_RW;
    -+
    -+				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;
    -+		}
    -+	}
    -+
    -+	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
    -diff -upkr linux-2.6.32/include/linux/blkdev.h linux-2.6.32/include/linux/blkdev.h
    ---- linux-2.6.32/include/linux/blkdev.h	2009-12-02 22:51:21.000000000 -0500
    -+++ linux-2.6.32/include/linux/blkdev.h	2009-12-16 07:21:35.000000000 -0500
    -@@ -708,6 +708,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);
    -@@ -812,6 +814,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 *,
    -diff -upkr linux-2.6.32/include/linux/scatterlist.h linux-2.6.32/include/linux/scatterlist.h
    ---- linux-2.6.32/include/linux/scatterlist.h	2009-12-02 22:51:21.000000000 -0500
    -+++ linux-2.6.32/include/linux/scatterlist.h	2009-12-16 07:21:35.000000000 -0500
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * Maximum number of entries that will be allocated in one piece, if
    -  * a list larger than this is required then chaining will be utilized.
    -diff -upkr linux-2.6.32/lib/scatterlist.c linux-2.6.32/lib/scatterlist.c
    ---- linux-2.6.32/lib/scatterlist.c	2009-12-02 22:51:21.000000000 -0500
    -+++ linux-2.6.32/lib/scatterlist.c	2009-12-16 07:21:35.000000000 -0500
    -@@ -493,3 +493,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/scst_exec_req_fifo-2.6.33.patch b/scst/kernel/scst_exec_req_fifo-2.6.33.patch
    deleted file mode 100644
    index fee571fce..000000000
    --- a/scst/kernel/scst_exec_req_fifo-2.6.33.patch
    +++ /dev/null
    @@ -1,529 +0,0 @@
    -diff -upkr linux-2.6.33/block/blk-map.c linux-2.6.33/block/blk-map.c
    ---- linux-2.6.33/block/blk-map.c	2010-02-24 13:52:17.000000000 -0500
    -+++ linux-2.6.33/block/blk-map.c	2011-05-17 21:09:00.317812998 -0400
    -@@ -5,6 +5,7 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -271,6 +272,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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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 |= 1 << BIO_RW;
    -+
    -+				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;
    -+		}
    -+	}
    -+
    -+	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
    -diff -upkr linux-2.6.33/include/linux/blkdev.h linux-2.6.33/include/linux/blkdev.h
    ---- linux-2.6.33/include/linux/blkdev.h	2010-02-24 13:52:17.000000000 -0500
    -+++ linux-2.6.33/include/linux/blkdev.h	2010-03-01 07:41:59.000000000 -0500
    -@@ -710,6 +710,8 @@ extern unsigned long blk_max_low_pfn, bl
    - #define BLK_DEFAULT_SG_TIMEOUT	(60 * HZ)
    - #define BLK_MIN_SG_TIMEOUT	(7 * HZ)
    - 
    -+#define SCSI_EXEC_REQ_FIFO_DEFINED
    -+
    - #ifdef CONFIG_BOUNCE
    - extern int init_emergency_isa_pool(void);
    - extern void blk_queue_bounce(struct request_queue *q, struct bio **bio);
    -@@ -825,6 +827,9 @@ extern int blk_rq_map_kern(struct reques
    - extern int blk_rq_map_user_iov(struct request_queue *, struct request *,
    - 			       struct rq_map_data *, struct sg_iovec *, int,
    - 			       unsigned int, gfp_t);
    -+extern int blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl,
    -+			      int nents, gfp_t gfp);
    -+extern void blk_rq_unmap_kern_sg(struct request *rq, int err);
    - extern int blk_execute_rq(struct request_queue *, struct gendisk *,
    - 			  struct request *, int);
    - extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
    -diff -upkr linux-2.6.33/include/linux/scatterlist.h linux-2.6.33/include/linux/scatterlist.h
    ---- linux-2.6.33/include/linux/scatterlist.h	2010-02-24 13:52:17.000000000 -0500
    -+++ linux-2.6.33/include/linux/scatterlist.h	2010-03-01 07:41:59.000000000 -0500
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * Maximum number of entries that will be allocated in one piece, if
    -  * a list larger than this is required then chaining will be utilized.
    -diff -upkr linux-2.6.33/lib/scatterlist.c linux-2.6.33/lib/scatterlist.c
    ---- linux-2.6.33/lib/scatterlist.c	2010-02-24 13:52:17.000000000 -0500
    -+++ linux-2.6.33/lib/scatterlist.c	2010-03-01 07:41:59.000000000 -0500
    -@@ -493,3 +493,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/scst_exec_req_fifo-2.6.34.patch b/scst/kernel/scst_exec_req_fifo-2.6.34.patch
    deleted file mode 100644
    index c7021f573..000000000
    --- a/scst/kernel/scst_exec_req_fifo-2.6.34.patch
    +++ /dev/null
    @@ -1,530 +0,0 @@
    -diff -upkr linux-2.6.34/block/blk-map.c linux-2.6.34/block/blk-map.c
    ---- linux-2.6.34/block/blk-map.c	2010-05-16 17:17:36.000000000 -0400
    -+++ linux-2.6.34/block/blk-map.c	2011-05-17 21:10:43.745812995 -0400
    -@@ -5,6 +5,8 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -271,6 +273,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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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 |= 1 << BIO_RW;
    -+
    -+				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;
    -+		}
    -+	}
    -+
    -+	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
    -diff -upkr linux-2.6.34/include/linux/blkdev.h linux-2.6.34/include/linux/blkdev.h
    ---- linux-2.6.34/include/linux/blkdev.h	2010-05-16 17:17:36.000000000 -0400
    -+++ linux-2.6.34/include/linux/blkdev.h	2010-05-24 06:51:22.000000000 -0400
    -@@ -713,6 +713,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);
    -@@ -828,6 +830,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 *,
    -diff -upkr linux-2.6.34/include/linux/scatterlist.h linux-2.6.34/include/linux/scatterlist.h
    ---- linux-2.6.34/include/linux/scatterlist.h	2010-05-16 17:17:36.000000000 -0400
    -+++ linux-2.6.34/include/linux/scatterlist.h	2010-05-24 06:51:22.000000000 -0400
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * Maximum number of entries that will be allocated in one piece, if
    -  * a list larger than this is required then chaining will be utilized.
    -diff -upkr linux-2.6.34/lib/scatterlist.c linux-2.6.34/lib/scatterlist.c
    ---- linux-2.6.34/lib/scatterlist.c	2010-05-16 17:17:36.000000000 -0400
    -+++ linux-2.6.34/lib/scatterlist.c	2010-05-24 06:51:22.000000000 -0400
    -@@ -494,3 +494,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/scst_exec_req_fifo-2.6.35.patch b/scst/kernel/scst_exec_req_fifo-2.6.35.patch
    deleted file mode 100644
    index b10ae1b5a..000000000
    --- a/scst/kernel/scst_exec_req_fifo-2.6.35.patch
    +++ /dev/null
    @@ -1,530 +0,0 @@
    -diff -upkr linux-2.6.35/block/blk-map.c linux-2.6.35/block/blk-map.c
    ---- linux-2.6.35/block/blk-map.c	2010-08-01 18:11:14.000000000 -0400
    -+++ linux-2.6.35/block/blk-map.c	2011-05-17 21:12:23.125813000 -0400
    -@@ -5,6 +5,8 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -271,6 +273,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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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 |= 1 << BIO_RW;
    -+
    -+				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;
    -+		}
    -+	}
    -+
    -+	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
    -diff -upkr linux-2.6.35/include/linux/blkdev.h linux-2.6.35/include/linux/blkdev.h
    ---- linux-2.6.35/include/linux/blkdev.h	2010-08-01 18:11:14.000000000 -0400
    -+++ linux-2.6.35/include/linux/blkdev.h	2010-08-04 04:21:59.737128732 -0400
    -@@ -717,6 +717,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);
    -@@ -832,6 +834,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 *,
    -diff -upkr linux-2.6.35/include/linux/scatterlist.h linux-2.6.35/include/linux/scatterlist.h
    ---- linux-2.6.35/include/linux/scatterlist.h	2010-08-01 18:11:14.000000000 -0400
    -+++ linux-2.6.35/include/linux/scatterlist.h	2010-08-04 04:21:59.741129485 -0400
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * Maximum number of entries that will be allocated in one piece, if
    -  * a list larger than this is required then chaining will be utilized.
    -diff -upkr linux-2.6.35/lib/scatterlist.c linux-2.6.35/lib/scatterlist.c
    ---- linux-2.6.35/lib/scatterlist.c	2010-08-01 18:11:14.000000000 -0400
    -+++ linux-2.6.35/lib/scatterlist.c	2010-08-04 04:21:59.741129485 -0400
    -@@ -494,3 +494,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/scst_exec_req_fifo-2.6.36.patch b/scst/kernel/scst_exec_req_fifo-2.6.36.patch
    deleted file mode 100644
    index d90bdcb8e..000000000
    --- a/scst/kernel/scst_exec_req_fifo-2.6.36.patch
    +++ /dev/null
    @@ -1,532 +0,0 @@
    -diff -upkr linux-2.6.36/block/blk-map.c linux-2.6.36/block/blk-map.c
    ---- linux-2.6.36/block/blk-map.c	2010-10-20 16:30:22.000000000 -0400
    -+++ linux-2.6.36/block/blk-map.c	2011-05-17 21:13:42.301812997 -0400
    -@@ -5,6 +5,8 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -271,6 +273,339 @@ 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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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
    -diff -upkr linux-2.6.36/include/linux/blkdev.h linux-2.6.36/include/linux/blkdev.h
    ---- linux-2.6.36/include/linux/blkdev.h	2010-10-20 16:30:22.000000000 -0400
    -+++ linux-2.6.36/include/linux/blkdev.h	2010-10-26 04:00:15.899759399 -0400
    -@@ -629,6 +629,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);
    -@@ -746,6 +748,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 *,
    -diff -upkr linux-2.6.36/include/linux/scatterlist.h linux-2.6.36/include/linux/scatterlist.h
    ---- linux-2.6.36/include/linux/scatterlist.h	2010-10-20 16:30:22.000000000 -0400
    -+++ linux-2.6.36/include/linux/scatterlist.h	2010-10-26 04:00:15.899759399 -0400
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * Maximum number of entries that will be allocated in one piece, if
    -  * a list larger than this is required then chaining will be utilized.
    -diff -upkr linux-2.6.36/lib/scatterlist.c linux-2.6.36/lib/scatterlist.c
    ---- linux-2.6.36/lib/scatterlist.c	2010-10-20 16:30:22.000000000 -0400
    -+++ linux-2.6.36/lib/scatterlist.c	2010-10-26 04:00:15.899759399 -0400
    -@@ -517,3 +517,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/scst_exec_req_fifo-2.6.37.patch b/scst/kernel/scst_exec_req_fifo-2.6.37.patch
    deleted file mode 100644
    index ab94c18ae..000000000
    --- a/scst/kernel/scst_exec_req_fifo-2.6.37.patch
    +++ /dev/null
    @@ -1,532 +0,0 @@
    -diff -upkr linux-2.6.37/block/blk-map.c linux-2.6.37/block/blk-map.c
    ---- linux-2.6.37/block/blk-map.c	2011-01-04 19:50:19.000000000 -0500
    -+++ linux-2.6.37/block/blk-map.c	2011-05-17 21:15:14.329812999 -0400
    -@@ -5,6 +5,8 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -274,6 +276,339 @@ 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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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
    -diff -upkr linux-2.6.37/include/linux/blkdev.h linux-2.6.37/include/linux/blkdev.h
    ---- linux-2.6.37/include/linux/blkdev.h	2011-01-04 19:50:19.000000000 -0500
    -+++ linux-2.6.37/include/linux/blkdev.h	2011-01-08 08:45:54.350430208 -0500
    -@@ -592,6 +592,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);
    -@@ -709,6 +711,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 *,
    -diff -upkr linux-2.6.37/include/linux/scatterlist.h linux-2.6.37/include/linux/scatterlist.h
    ---- linux-2.6.37/include/linux/scatterlist.h	2011-01-04 19:50:19.000000000 -0500
    -+++ linux-2.6.37/include/linux/scatterlist.h	2011-01-08 08:45:54.354431761 -0500
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * Maximum number of entries that will be allocated in one piece, if
    -  * a list larger than this is required then chaining will be utilized.
    -diff -upkr linux-2.6.37/lib/scatterlist.c linux-2.6.37/lib/scatterlist.c
    ---- linux-2.6.37/lib/scatterlist.c	2011-01-04 19:50:19.000000000 -0500
    -+++ linux-2.6.37/lib/scatterlist.c	2011-01-08 08:45:54.401930472 -0500
    -@@ -517,3 +517,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/scst_exec_req_fifo-2.6.38.patch b/scst/kernel/scst_exec_req_fifo-2.6.38.patch
    deleted file mode 100644
    index 4561ba2e9..000000000
    --- a/scst/kernel/scst_exec_req_fifo-2.6.38.patch
    +++ /dev/null
    @@ -1,532 +0,0 @@
    -diff -upkr linux-2.6.38/block/blk-map.c linux-2.6.38/block/blk-map.c
    ---- linux-2.6.38/block/blk-map.c	2011-03-14 21:20:32.000000000 -0400
    -+++ linux-2.6.38/block/blk-map.c	2011-05-11 22:07:37.589813000 -0400
    -@@ -5,6 +5,8 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -274,6 +276,339 @@ 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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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
    -diff -upkr linux-2.6.38/include/linux/blkdev.h linux-2.6.38/include/linux/blkdev.h
    ---- linux-2.6.38/include/linux/blkdev.h	2011-03-14 21:20:32.000000000 -0400
    -+++ linux-2.6.38/include/linux/blkdev.h	2011-03-18 10:19:00.000000000 -0400
    -@@ -593,6 +593,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);
    -@@ -709,6 +711,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 *,
    -diff -upkr linux-2.6.38/include/linux/scatterlist.h linux-2.6.38/include/linux/scatterlist.h
    ---- linux-2.6.38/include/linux/scatterlist.h	2011-03-14 21:20:32.000000000 -0400
    -+++ linux-2.6.38/include/linux/scatterlist.h	2011-03-18 10:19:00.000000000 -0400
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * Maximum number of entries that will be allocated in one piece, if
    -  * a list larger than this is required then chaining will be utilized.
    -diff -upkr linux-2.6.38/lib/scatterlist.c linux-2.6.38/lib/scatterlist.c
    ---- linux-2.6.38/lib/scatterlist.c	2011-03-14 21:20:32.000000000 -0400
    -+++ linux-2.6.38/lib/scatterlist.c	2011-03-18 10:46:41.000000000 -0400
    -@@ -517,3 +517,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/scst_exec_req_fifo-2.6.39.patch b/scst/kernel/scst_exec_req_fifo-2.6.39.patch
    deleted file mode 100644
    index 7ecca2958..000000000
    --- a/scst/kernel/scst_exec_req_fifo-2.6.39.patch
    +++ /dev/null
    @@ -1,532 +0,0 @@
    -diff -upkr linux-2.6.39/block/blk-map.c linux-2.6.39/block/blk-map.c
    ---- linux-2.6.39/block/blk-map.c	2011-05-19 00:06:34.000000000 -0400
    -+++ linux-2.6.39/block/blk-map.c	2011-05-19 10:49:02.753812997 -0400
    -@@ -5,6 +5,8 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -274,6 +276,339 @@ 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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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
    -diff -upkr linux-2.6.39/include/linux/blkdev.h linux-2.6.39/include/linux/blkdev.h
    ---- linux-2.6.39/include/linux/blkdev.h	2011-05-19 00:06:34.000000000 -0400
    -+++ linux-2.6.39/include/linux/blkdev.h	2011-05-19 10:49:02.753812997 -0400
    -@@ -592,6 +592,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);
    -@@ -707,6 +709,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 *,
    -diff -upkr linux-2.6.39/include/linux/scatterlist.h linux-2.6.39/include/linux/scatterlist.h
    ---- linux-2.6.39/include/linux/scatterlist.h	2011-05-19 00:06:34.000000000 -0400
    -+++ linux-2.6.39/include/linux/scatterlist.h	2011-05-19 10:49:02.753812997 -0400
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * Maximum number of entries that will be allocated in one piece, if
    -  * a list larger than this is required then chaining will be utilized.
    -diff -upkr linux-2.6.39/lib/scatterlist.c linux-2.6.39/lib/scatterlist.c
    ---- linux-2.6.39/lib/scatterlist.c	2011-05-19 00:06:34.000000000 -0400
    -+++ linux-2.6.39/lib/scatterlist.c	2011-05-19 10:49:02.753812997 -0400
    -@@ -517,3 +517,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/scst_exec_req_fifo-3.0.patch b/scst/kernel/scst_exec_req_fifo-3.0.patch
    deleted file mode 100644
    index 998f4a32c..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.0.patch
    +++ /dev/null
    @@ -1,532 +0,0 @@
    -diff -upkr linux-3.0.0-orig/block/blk-map.c linux-3.0.0-scst-dbg/block/blk-map.c
    ---- linux-3.0.0-orig/block/blk-map.c	2011-07-21 22:17:23.000000000 -0400
    -+++ linux-3.0.0-scst-dbg/block/blk-map.c	2011-07-22 19:40:27.131230804 -0400
    -@@ -5,6 +5,8 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -274,6 +276,339 @@ 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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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
    -diff -upkr linux-3.0.0-orig/include/linux/blkdev.h linux-3.0.0-scst-dbg/include/linux/blkdev.h
    ---- linux-3.0.0-orig/include/linux/blkdev.h	2011-07-21 22:17:23.000000000 -0400
    -+++ linux-3.0.0-scst-dbg/include/linux/blkdev.h	2011-07-22 19:24:27.803231156 -0400
    -@@ -594,6 +594,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);
    -@@ -709,6 +711,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 *,
    -diff -upkr linux-3.0.0-orig/include/linux/scatterlist.h linux-3.0.0-scst-dbg/include/linux/scatterlist.h
    ---- linux-3.0.0-orig/include/linux/scatterlist.h	2011-07-21 22:17:23.000000000 -0400
    -+++ linux-3.0.0-scst-dbg/include/linux/scatterlist.h	2011-07-22 19:24:27.803231156 -0400
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * Maximum number of entries that will be allocated in one piece, if
    -  * a list larger than this is required then chaining will be utilized.
    -diff -upkr linux-3.0.0-orig/lib/scatterlist.c linux-3.0.0-scst-dbg/lib/scatterlist.c
    ---- linux-3.0.0-orig/lib/scatterlist.c	2011-07-21 22:17:23.000000000 -0400
    -+++ linux-3.0.0-scst-dbg/lib/scatterlist.c	2011-07-22 19:40:27.131230804 -0400
    -@@ -517,3 +517,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/scst_exec_req_fifo-3.1.patch b/scst/kernel/scst_exec_req_fifo-3.1.patch
    deleted file mode 100644
    index d6bb5346b..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.1.patch
    +++ /dev/null
    @@ -1,536 +0,0 @@
    -=== modified file 'linux-3.1-scst/block/blk-map.c'
    ---- linux-3.1-orig/block/blk-map.c	2011-10-26 20:34:50 +0000
    -+++ linux-3.1-scst/block/blk-map.c	2011-10-26 20:58:56 +0000
    -@@ -5,6 +5,8 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -274,6 +276,339 @@ 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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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 'linux-3.1-scst/include/linux/blkdev.h'
    ---- linux-3.1-orig/include/linux/blkdev.h	2011-10-26 20:34:50 +0000
    -+++ linux-3.1-scst/include/linux/blkdev.h	2011-10-26 20:58:56 +0000
    -@@ -599,6 +599,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);
    -@@ -714,6 +716,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 'linux-3.1-scst/include/linux/scatterlist.h'
    ---- linux-3.1-orig/include/linux/scatterlist.h	2011-10-26 20:34:50 +0000
    -+++ linux-3.1-scst/include/linux/scatterlist.h	2011-10-26 20:58:56 +0000
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * 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 'linux-3.1-scst/lib/scatterlist.c'
    ---- linux-3.1-orig/lib/scatterlist.c	2011-10-26 20:34:50 +0000
    -+++ linux-3.1-scst/lib/scatterlist.c	2011-10-26 20:58:56 +0000
    -@@ -517,3 +517,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/scst_exec_req_fifo-3.10.patch b/scst/kernel/scst_exec_req_fifo-3.10.patch
    deleted file mode 100644
    index 69fce3a5f..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.10.patch
    +++ /dev/null
    @@ -1,527 +0,0 @@
    -=== modified file 'block/blk-map.c'
    ---- old/block/blk-map.c	2013-07-23 02:45:53 +0000
    -+++ new/block/blk-map.c	2013-07-23 02:50:11 +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	2013-07-23 02:45:53 +0000
    -+++ new/include/linux/blkdev.h	2013-07-23 02:50:11 +0000
    -@@ -676,6 +676,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);
    -@@ -795,6 +797,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	2013-07-23 02:45:53 +0000
    -+++ new/include/linux/scatterlist.h	2013-07-23 02:50:11 +0000
    -@@ -8,6 +8,7 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    - 
    - struct sg_table {
    - 	struct scatterlist *sgl;	/* the list */
    -@@ -244,6 +245,9 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+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	2013-07-23 02:45:53 +0000
    -+++ new/lib/scatterlist.c	2013-07-23 02:50:11 +0000
    -@@ -627,3 +627,126 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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/kernel/scst_exec_req_fifo-3.11.patch b/scst/kernel/scst_exec_req_fifo-3.11.patch
    deleted file mode 100644
    index 63b2da453..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.11.patch
    +++ /dev/null
    @@ -1,528 +0,0 @@
    -=== modified file 'block/blk-map.c'
    ---- old/block/blk-map.c	2013-09-28 00:14:38 +0000
    -+++ new/block/blk-map.c	2013-09-28 00:23:26 +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	2013-09-28 00:14:38 +0000
    -+++ new/include/linux/blkdev.h	2013-09-28 00:23:26 +0000
    -@@ -676,6 +676,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);
    -@@ -795,6 +797,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	2013-09-28 00:14:38 +0000
    -+++ new/include/linux/scatterlist.h	2013-09-28 00:23:26 +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	2013-09-28 00:14:38 +0000
    -+++ new/lib/scatterlist.c	2013-09-28 00:23:26 +0000
    -@@ -716,3 +716,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/kernel/scst_exec_req_fifo-3.12.patch b/scst/kernel/scst_exec_req_fifo-3.12.patch
    deleted file mode 100644
    index b08d43f3e..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.12.patch
    +++ /dev/null
    @@ -1,528 +0,0 @@
    -=== modified file 'block/blk-map.c'
    ---- old/block/blk-map.c	2013-11-30 00:34:22 +0000
    -+++ new/block/blk-map.c	2013-11-30 00:39:53 +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	2013-11-30 00:34:22 +0000
    -+++ new/include/linux/blkdev.h	2013-11-30 00:39:53 +0000
    -@@ -676,6 +676,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);
    -@@ -795,6 +797,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	2013-11-30 00:34:22 +0000
    -+++ new/include/linux/scatterlist.h	2013-11-30 00:39:53 +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	2013-11-30 00:34:22 +0000
    -+++ new/lib/scatterlist.c	2013-11-30 00:39:53 +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/kernel/scst_exec_req_fifo-3.13.patch b/scst/kernel/scst_exec_req_fifo-3.13.patch
    deleted file mode 100644
    index 84980e46a..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.13.patch
    +++ /dev/null
    @@ -1,528 +0,0 @@
    -=== 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/kernel/scst_exec_req_fifo-3.14.patch b/scst/kernel/scst_exec_req_fifo-3.14.patch
    deleted file mode 100644
    index 70c47797d..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.14.patch
    +++ /dev/null
    @@ -1,528 +0,0 @@
    -=== modified file 'block/blk-map.c'
    ---- old/block/blk-map.c	2014-04-17 22:02:06 +0000
    -+++ new/block/blk-map.c	2014-04-17 22:08:48 +0000
    -@@ -5,6 +5,8 @@
    - #include 
    - #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-04-17 22:02:06 +0000
    -+++ new/include/linux/blkdev.h	2014-04-17 22:08:48 +0000
    -@@ -705,6 +705,8 @@ extern unsigned long blk_max_low_pfn, bl
    - #define BLK_DEFAULT_SG_TIMEOUT	(60 * HZ)
    - #define BLK_MIN_SG_TIMEOUT	(7 * HZ)
    - 
    -+#define SCSI_EXEC_REQ_FIFO_DEFINED
    -+
    - #ifdef CONFIG_BOUNCE
    - extern int init_emergency_isa_pool(void);
    - extern void blk_queue_bounce(struct request_queue *q, struct bio **bio);
    -@@ -825,6 +827,9 @@ extern int blk_rq_map_kern(struct reques
    - extern int blk_rq_map_user_iov(struct request_queue *, struct request *,
    - 			       struct rq_map_data *, struct sg_iovec *, int,
    - 			       unsigned int, gfp_t);
    -+extern int blk_rq_map_kern_sg(struct request *rq, struct scatterlist *sgl,
    -+			      int nents, gfp_t gfp);
    -+extern void blk_rq_unmap_kern_sg(struct request *rq, int err);
    - extern int blk_execute_rq(struct request_queue *, struct gendisk *,
    - 			  struct request *, int);
    - extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
    -
    -=== modified file 'include/linux/scatterlist.h'
    ---- old/include/linux/scatterlist.h	2014-04-17 22:02:06 +0000
    -+++ new/include/linux/scatterlist.h	2014-04-17 22:08:48 +0000
    -@@ -8,6 +8,7 @@
    - #include 
    - #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-04-17 22:02:06 +0000
    -+++ new/lib/scatterlist.c	2014-04-17 22:08:48 +0000
    -@@ -718,3 +718,127 @@ size_t sg_pcopy_to_buffer(struct scatter
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, skip, true);
    - }
    - EXPORT_SYMBOL(sg_pcopy_to_buffer);
    -+
    -+
    -+/*
    -+ * Can switch to the next dst_sg element, so, to copy to strictly only
    -+ * one dst_sg element, it must be either last in the chain, or
    -+ * copy_len == dst_sg->length.
    -+ */
    -+static int sg_copy_elem(struct scatterlist **pdst_sg, size_t *pdst_len,
    -+			size_t *pdst_offs, struct scatterlist *src_sg,
    -+			size_t copy_len)
    -+{
    -+	int res = 0;
    -+	struct scatterlist *dst_sg;
    -+	size_t src_len, dst_len, src_offs, dst_offs;
    -+	struct page *src_page, *dst_page;
    -+
    -+	dst_sg = *pdst_sg;
    -+	dst_len = *pdst_len;
    -+	dst_offs = *pdst_offs;
    -+	dst_page = sg_page(dst_sg);
    -+
    -+	src_page = sg_page(src_sg);
    -+	src_len = src_sg->length;
    -+	src_offs = src_sg->offset;
    -+
    -+	do {
    -+		void *saddr, *daddr;
    -+		size_t n;
    -+
    -+		saddr = kmap_atomic(src_page + (src_offs >> PAGE_SHIFT)) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page + (dst_offs >> PAGE_SHIFT)) +
    -+				    (dst_offs & ~PAGE_MASK);
    -+
    -+		if (((src_offs & ~PAGE_MASK) == 0) &&
    -+		    ((dst_offs & ~PAGE_MASK) == 0) &&
    -+		    (src_len >= PAGE_SIZE) && (dst_len >= PAGE_SIZE) &&
    -+		    (copy_len >= PAGE_SIZE)) {
    -+			copy_page(daddr, saddr);
    -+			n = PAGE_SIZE;
    -+		} else {
    -+			n = min_t(size_t, PAGE_SIZE - (dst_offs & ~PAGE_MASK),
    -+					  PAGE_SIZE - (src_offs & ~PAGE_MASK));
    -+			n = min(n, src_len);
    -+			n = min(n, dst_len);
    -+			n = min_t(size_t, n, copy_len);
    -+			memcpy(daddr, saddr, n);
    -+		}
    -+		dst_offs += n;
    -+		src_offs += n;
    -+
    -+		kunmap_atomic(saddr);
    -+		kunmap_atomic(daddr);
    -+
    -+		res += n;
    -+		copy_len -= n;
    -+		if (copy_len == 0)
    -+			goto out;
    -+
    -+		src_len -= n;
    -+		dst_len -= n;
    -+		if (dst_len == 0) {
    -+			dst_sg = sg_next(dst_sg);
    -+			if (dst_sg == NULL)
    -+				goto out;
    -+			dst_page = sg_page(dst_sg);
    -+			dst_len = dst_sg->length;
    -+			dst_offs = dst_sg->offset;
    -+		}
    -+	} while (src_len > 0);
    -+
    -+out:
    -+	*pdst_sg = dst_sg;
    -+	*pdst_len = dst_len;
    -+	*pdst_offs = dst_offs;
    -+	return res;
    -+}
    -+
    -+/**
    -+ * sg_copy - copy one SG vector to another
    -+ * @dst_sg:	destination SG
    -+ * @src_sg:	source SG
    -+ * @nents_to_copy: maximum number of entries to copy
    -+ * @copy_len:	maximum amount of data to copy. If 0, then copy all.
    -+ *
    -+ * Description:
    -+ *    Data from the source SG vector will be copied to the destination SG
    -+ *    vector. End of the vectors will be determined by sg_next() returning
    -+ *    NULL. Returns number of bytes copied.
    -+ */
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len)
    -+{
    -+	int res = 0;
    -+	size_t dst_len, dst_offs;
    -+
    -+	if (copy_len == 0)
    -+		copy_len = 0x7FFFFFFF; /* copy all */
    -+
    -+	if (nents_to_copy == 0)
    -+		nents_to_copy = 0x7FFFFFFF; /* copy all */
    -+
    -+	dst_len = dst_sg->length;
    -+	dst_offs = dst_sg->offset;
    -+
    -+	do {
    -+		int copied = sg_copy_elem(&dst_sg, &dst_len, &dst_offs,
    -+				src_sg, copy_len);
    -+		copy_len -= copied;
    -+		res += copied;
    -+		if ((copy_len == 0) || (dst_sg == NULL))
    -+			goto out;
    -+
    -+		nents_to_copy--;
    -+		if (nents_to_copy == 0)
    -+			goto out;
    -+
    -+		src_sg = sg_next(src_sg);
    -+	} while (src_sg != NULL);
    -+
    -+out:
    -+	return res;
    -+}
    -+EXPORT_SYMBOL(sg_copy);
    -
    diff --git a/scst/kernel/scst_exec_req_fifo-3.15.patch b/scst/kernel/scst_exec_req_fifo-3.15.patch
    deleted file mode 100644
    index 665cc2606..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.15.patch
    +++ /dev/null
    @@ -1,528 +0,0 @@
    -=== modified file 'block/blk-map.c'
    ---- old/block/blk-map.c	2014-06-18 01:32:48 +0000
    -+++ new/block/blk-map.c	2014-06-18 01:40:34 +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-06-18 01:32:48 +0000
    -+++ new/include/linux/blkdev.h	2014-06-18 01:40:34 +0000
    -@@ -717,6 +717,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);
    -@@ -837,6 +839,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 *, const 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-06-18 01:32:48 +0000
    -+++ new/include/linux/scatterlist.h	2014-06-18 01:40:34 +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-06-18 01:32:48 +0000
    -+++ new/lib/scatterlist.c	2014-06-18 01:40:34 +0000
    -@@ -718,3 +718,127 @@ size_t sg_pcopy_to_buffer(struct scatter
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, skip, true);
    - }
    - EXPORT_SYMBOL(sg_pcopy_to_buffer);
    -+
    -+
    -+/*
    -+ * Can switch to the next dst_sg element, so, to copy to strictly only
    -+ * one dst_sg element, it must be either last in the chain, or
    -+ * copy_len == dst_sg->length.
    -+ */
    -+static int sg_copy_elem(struct scatterlist **pdst_sg, size_t *pdst_len,
    -+			size_t *pdst_offs, struct scatterlist *src_sg,
    -+			size_t copy_len)
    -+{
    -+	int res = 0;
    -+	struct scatterlist *dst_sg;
    -+	size_t src_len, dst_len, src_offs, dst_offs;
    -+	struct page *src_page, *dst_page;
    -+
    -+	dst_sg = *pdst_sg;
    -+	dst_len = *pdst_len;
    -+	dst_offs = *pdst_offs;
    -+	dst_page = sg_page(dst_sg);
    -+
    -+	src_page = sg_page(src_sg);
    -+	src_len = src_sg->length;
    -+	src_offs = src_sg->offset;
    -+
    -+	do {
    -+		void *saddr, *daddr;
    -+		size_t n;
    -+
    -+		saddr = kmap_atomic(src_page + (src_offs >> PAGE_SHIFT)) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page + (dst_offs >> PAGE_SHIFT)) +
    -+				    (dst_offs & ~PAGE_MASK);
    -+
    -+		if (((src_offs & ~PAGE_MASK) == 0) &&
    -+		    ((dst_offs & ~PAGE_MASK) == 0) &&
    -+		    (src_len >= PAGE_SIZE) && (dst_len >= PAGE_SIZE) &&
    -+		    (copy_len >= PAGE_SIZE)) {
    -+			copy_page(daddr, saddr);
    -+			n = PAGE_SIZE;
    -+		} else {
    -+			n = min_t(size_t, PAGE_SIZE - (dst_offs & ~PAGE_MASK),
    -+					  PAGE_SIZE - (src_offs & ~PAGE_MASK));
    -+			n = min(n, src_len);
    -+			n = min(n, dst_len);
    -+			n = min_t(size_t, n, copy_len);
    -+			memcpy(daddr, saddr, n);
    -+		}
    -+		dst_offs += n;
    -+		src_offs += n;
    -+
    -+		kunmap_atomic(saddr);
    -+		kunmap_atomic(daddr);
    -+
    -+		res += n;
    -+		copy_len -= n;
    -+		if (copy_len == 0)
    -+			goto out;
    -+
    -+		src_len -= n;
    -+		dst_len -= n;
    -+		if (dst_len == 0) {
    -+			dst_sg = sg_next(dst_sg);
    -+			if (dst_sg == NULL)
    -+				goto out;
    -+			dst_page = sg_page(dst_sg);
    -+			dst_len = dst_sg->length;
    -+			dst_offs = dst_sg->offset;
    -+		}
    -+	} while (src_len > 0);
    -+
    -+out:
    -+	*pdst_sg = dst_sg;
    -+	*pdst_len = dst_len;
    -+	*pdst_offs = dst_offs;
    -+	return res;
    -+}
    -+
    -+/**
    -+ * sg_copy - copy one SG vector to another
    -+ * @dst_sg:	destination SG
    -+ * @src_sg:	source SG
    -+ * @nents_to_copy: maximum number of entries to copy
    -+ * @copy_len:	maximum amount of data to copy. If 0, then copy all.
    -+ *
    -+ * Description:
    -+ *    Data from the source SG vector will be copied to the destination SG
    -+ *    vector. End of the vectors will be determined by sg_next() returning
    -+ *    NULL. Returns number of bytes copied.
    -+ */
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len)
    -+{
    -+	int res = 0;
    -+	size_t dst_len, dst_offs;
    -+
    -+	if (copy_len == 0)
    -+		copy_len = 0x7FFFFFFF; /* copy all */
    -+
    -+	if (nents_to_copy == 0)
    -+		nents_to_copy = 0x7FFFFFFF; /* copy all */
    -+
    -+	dst_len = dst_sg->length;
    -+	dst_offs = dst_sg->offset;
    -+
    -+	do {
    -+		int copied = sg_copy_elem(&dst_sg, &dst_len, &dst_offs,
    -+				src_sg, copy_len);
    -+		copy_len -= copied;
    -+		res += copied;
    -+		if ((copy_len == 0) || (dst_sg == NULL))
    -+			goto out;
    -+
    -+		nents_to_copy--;
    -+		if (nents_to_copy == 0)
    -+			goto out;
    -+
    -+		src_sg = sg_next(src_sg);
    -+	} while (src_sg != NULL);
    -+
    -+out:
    -+	return res;
    -+}
    -+EXPORT_SYMBOL(sg_copy);
    -
    diff --git a/scst/kernel/scst_exec_req_fifo-3.16.patch b/scst/kernel/scst_exec_req_fifo-3.16.patch
    deleted file mode 100644
    index a08921920..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.16.patch
    +++ /dev/null
    @@ -1,524 +0,0 @@
    -=== modified file 'block/blk-map.c'
    ---- old/block/blk-map.c	2014-08-19 01:00:36 +0000
    -+++ new/block/blk-map.c	2014-08-19 01:37:01 +0000
    -@@ -5,6 +5,8 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -273,6 +275,333 @@ 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;
    -+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;
    -+		}
    -+	}
    -+
    -+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-08-19 01:00:36 +0000
    -+++ new/include/linux/blkdev.h	2014-08-19 01:06:48 +0000
    -@@ -735,6 +735,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);
    -@@ -856,6 +858,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 *, const 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-08-19 01:00:36 +0000
    -+++ new/include/linux/scatterlist.h	2014-08-19 01:06:48 +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-08-19 01:00:36 +0000
    -+++ new/lib/scatterlist.c	2014-08-19 01:06:48 +0000
    -@@ -718,3 +718,127 @@ size_t sg_pcopy_to_buffer(struct scatter
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, skip, true);
    - }
    - EXPORT_SYMBOL(sg_pcopy_to_buffer);
    -+
    -+
    -+/*
    -+ * Can switch to the next dst_sg element, so, to copy to strictly only
    -+ * one dst_sg element, it must be either last in the chain, or
    -+ * copy_len == dst_sg->length.
    -+ */
    -+static int sg_copy_elem(struct scatterlist **pdst_sg, size_t *pdst_len,
    -+			size_t *pdst_offs, struct scatterlist *src_sg,
    -+			size_t copy_len)
    -+{
    -+	int res = 0;
    -+	struct scatterlist *dst_sg;
    -+	size_t src_len, dst_len, src_offs, dst_offs;
    -+	struct page *src_page, *dst_page;
    -+
    -+	dst_sg = *pdst_sg;
    -+	dst_len = *pdst_len;
    -+	dst_offs = *pdst_offs;
    -+	dst_page = sg_page(dst_sg);
    -+
    -+	src_page = sg_page(src_sg);
    -+	src_len = src_sg->length;
    -+	src_offs = src_sg->offset;
    -+
    -+	do {
    -+		void *saddr, *daddr;
    -+		size_t n;
    -+
    -+		saddr = kmap_atomic(src_page + (src_offs >> PAGE_SHIFT)) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page + (dst_offs >> PAGE_SHIFT)) +
    -+				    (dst_offs & ~PAGE_MASK);
    -+
    -+		if (((src_offs & ~PAGE_MASK) == 0) &&
    -+		    ((dst_offs & ~PAGE_MASK) == 0) &&
    -+		    (src_len >= PAGE_SIZE) && (dst_len >= PAGE_SIZE) &&
    -+		    (copy_len >= PAGE_SIZE)) {
    -+			copy_page(daddr, saddr);
    -+			n = PAGE_SIZE;
    -+		} else {
    -+			n = min_t(size_t, PAGE_SIZE - (dst_offs & ~PAGE_MASK),
    -+					  PAGE_SIZE - (src_offs & ~PAGE_MASK));
    -+			n = min(n, src_len);
    -+			n = min(n, dst_len);
    -+			n = min_t(size_t, n, copy_len);
    -+			memcpy(daddr, saddr, n);
    -+		}
    -+		dst_offs += n;
    -+		src_offs += n;
    -+
    -+		kunmap_atomic(saddr);
    -+		kunmap_atomic(daddr);
    -+
    -+		res += n;
    -+		copy_len -= n;
    -+		if (copy_len == 0)
    -+			goto out;
    -+
    -+		src_len -= n;
    -+		dst_len -= n;
    -+		if (dst_len == 0) {
    -+			dst_sg = sg_next(dst_sg);
    -+			if (dst_sg == NULL)
    -+				goto out;
    -+			dst_page = sg_page(dst_sg);
    -+			dst_len = dst_sg->length;
    -+			dst_offs = dst_sg->offset;
    -+		}
    -+	} while (src_len > 0);
    -+
    -+out:
    -+	*pdst_sg = dst_sg;
    -+	*pdst_len = dst_len;
    -+	*pdst_offs = dst_offs;
    -+	return res;
    -+}
    -+
    -+/**
    -+ * sg_copy - copy one SG vector to another
    -+ * @dst_sg:	destination SG
    -+ * @src_sg:	source SG
    -+ * @nents_to_copy: maximum number of entries to copy
    -+ * @copy_len:	maximum amount of data to copy. If 0, then copy all.
    -+ *
    -+ * Description:
    -+ *    Data from the source SG vector will be copied to the destination SG
    -+ *    vector. End of the vectors will be determined by sg_next() returning
    -+ *    NULL. Returns number of bytes copied.
    -+ */
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len)
    -+{
    -+	int res = 0;
    -+	size_t dst_len, dst_offs;
    -+
    -+	if (copy_len == 0)
    -+		copy_len = 0x7FFFFFFF; /* copy all */
    -+
    -+	if (nents_to_copy == 0)
    -+		nents_to_copy = 0x7FFFFFFF; /* copy all */
    -+
    -+	dst_len = dst_sg->length;
    -+	dst_offs = dst_sg->offset;
    -+
    -+	do {
    -+		int copied = sg_copy_elem(&dst_sg, &dst_len, &dst_offs,
    -+				src_sg, copy_len);
    -+		copy_len -= copied;
    -+		res += copied;
    -+		if ((copy_len == 0) || (dst_sg == NULL))
    -+			goto out;
    -+
    -+		nents_to_copy--;
    -+		if (nents_to_copy == 0)
    -+			goto out;
    -+
    -+		src_sg = sg_next(src_sg);
    -+	} while (src_sg != NULL);
    -+
    -+out:
    -+	return res;
    -+}
    -+EXPORT_SYMBOL(sg_copy);
    -
    diff --git a/scst/kernel/scst_exec_req_fifo-3.2.patch b/scst/kernel/scst_exec_req_fifo-3.2.patch
    deleted file mode 100644
    index 2b8257ce3..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.2.patch
    +++ /dev/null
    @@ -1,536 +0,0 @@
    -=== modified file 'block/blk-map.c'
    ---- old/block/blk-map.c	2012-01-10 22:58:17 +0000
    -+++ new/block/blk-map.c	2012-01-10 23:01:21 +0000
    -@@ -5,6 +5,8 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -275,6 +277,339 @@ 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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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	2012-01-10 22:58:17 +0000
    -+++ new/include/linux/blkdev.h	2012-01-10 23:01:21 +0000
    -@@ -599,6 +599,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);
    -@@ -716,6 +718,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	2012-01-10 22:58:17 +0000
    -+++ new/include/linux/scatterlist.h	2012-01-10 23:01:21 +0000
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * 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	2012-01-10 22:58:17 +0000
    -+++ new/lib/scatterlist.c	2012-01-10 23:01:21 +0000
    -@@ -517,3 +517,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/scst_exec_req_fifo-3.3.patch b/scst/kernel/scst_exec_req_fifo-3.3.patch
    deleted file mode 100644
    index 293d96633..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.3.patch
    +++ /dev/null
    @@ -1,536 +0,0 @@
    -=== modified file 'block/blk-map.c'
    ---- old/block/blk-map.c	2012-03-19 23:46:01 +0000
    -+++ new/block/blk-map.c	2012-03-20 00:10:37 +0000
    -@@ -5,6 +5,8 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    -+#include 
    - #include 		/* for struct sg_iovec */
    - 
    - #include "blk.h"
    -@@ -275,6 +277,339 @@ 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,
    -+					KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ);
    -+				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,
    -+			KM_USER0, KM_USER1);
    -+	}
    -+
    -+	*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	2012-03-19 23:46:01 +0000
    -+++ new/include/linux/blkdev.h	2012-03-20 00:10:37 +0000
    -@@ -612,6 +612,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);
    -@@ -731,6 +733,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	2012-03-19 23:46:01 +0000
    -+++ new/include/linux/scatterlist.h	2012-03-20 00:10:37 +0000
    -@@ -3,6 +3,7 @@
    - 
    - #include 
    - #include 
    -+#include 
    - #include 
    - #include 
    - #include 
    -@@ -218,6 +219,10 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
    -+	    int nents_to_copy, size_t copy_len,
    -+	    enum km_type d_km_type, enum km_type s_km_type);
    -+
    - /*
    -  * 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	2012-03-19 23:46:01 +0000
    -+++ new/lib/scatterlist.c	2012-03-20 00:10:37 +0000
    -@@ -517,3 +517,132 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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,
    -+			enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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), s_km_type) +
    -+				    (src_offs & ~PAGE_MASK);
    -+		daddr = kmap_atomic(dst_page +
    -+					(dst_offs >> PAGE_SHIFT), d_km_type) +
    -+				    (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, s_km_type);
    -+		kunmap_atomic(daddr, d_km_type);
    -+
    -+		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.
    -+ * @d_km_type:	kmap_atomic type for the destination SG
    -+ * @s_km_type:	kmap_atomic type for the source SG
    -+ *
    -+ * 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,
    -+	    enum km_type d_km_type, enum km_type s_km_type)
    -+{
    -+	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, d_km_type, s_km_type);
    -+		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/kernel/scst_exec_req_fifo-3.4.patch b/scst/kernel/scst_exec_req_fifo-3.4.patch
    deleted file mode 100644
    index 53ac80d0c..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.4.patch
    +++ /dev/null
    @@ -1,528 +0,0 @@
    -diff --git a/block/blk-map.c b/block/blk-map.c
    -index 623e1cd..20349d0 100644
    ---- a/block/blk-map.c
    -+++ b/block/blk-map.c
    -@@ -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
    -diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
    -index 4d4ac24..3fa6a30 100644
    ---- a/include/linux/blkdev.h
    -+++ b/include/linux/blkdev.h
    -@@ -609,6 +609,8 @@ extern unsigned long blk_max_low_pfn, blk_max_pfn;
    - #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);
    -@@ -728,6 +730,9 @@ extern int blk_rq_map_kern(struct request_queue *, struct request *, void *, uns
    - 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 *,
    -diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
    -index ac9586d..4b743d7 100644
    ---- a/include/linux/scatterlist.h
    -+++ b/include/linux/scatterlist.h
    -@@ -8,6 +8,7 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    - 
    - struct sg_table {
    - 	struct scatterlist *sgl;	/* the list */
    -@@ -220,6 +221,9 @@ size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+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.
    -diff --git a/lib/scatterlist.c b/lib/scatterlist.c
    -index 6096e89..1786ca9 100644
    ---- a/lib/scatterlist.c
    -+++ b/lib/scatterlist.c
    -@@ -517,3 +517,126 @@ size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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/kernel/scst_exec_req_fifo-3.5.patch b/scst/kernel/scst_exec_req_fifo-3.5.patch
    deleted file mode 100644
    index 78c3f0720..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.5.patch
    +++ /dev/null
    @@ -1,527 +0,0 @@
    -=== modified file 'block/blk-map.c'
    ---- old/block/blk-map.c	2012-08-08 02:57:29 +0000
    -+++ new/block/blk-map.c	2012-08-08 03:02:56 +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	2012-08-08 02:57:29 +0000
    -+++ new/include/linux/blkdev.h	2012-08-08 03:02:56 +0000
    -@@ -627,6 +627,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);
    -@@ -746,6 +748,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	2012-08-08 02:57:29 +0000
    -+++ new/include/linux/scatterlist.h	2012-08-08 03:02:56 +0000
    -@@ -8,6 +8,7 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    - 
    - struct sg_table {
    - 	struct scatterlist *sgl;	/* the list */
    -@@ -220,6 +221,9 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+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	2012-08-08 02:57:29 +0000
    -+++ new/lib/scatterlist.c	2012-08-08 03:02:56 +0000
    -@@ -517,3 +517,126 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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/kernel/scst_exec_req_fifo-3.6.patch b/scst/kernel/scst_exec_req_fifo-3.6.patch
    deleted file mode 100644
    index bf9cf76c0..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.6.patch
    +++ /dev/null
    @@ -1,527 +0,0 @@
    -=== modified file 'block/blk-map.c'
    ---- old/block/blk-map.c	2012-10-01 18:39:34 +0000
    -+++ new/block/blk-map.c	2012-10-01 20:50:07 +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	2012-10-01 18:39:34 +0000
    -+++ new/include/linux/blkdev.h	2012-10-01 18:45:47 +0000
    -@@ -638,6 +638,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);
    -@@ -757,6 +759,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	2012-10-01 18:39:34 +0000
    -+++ new/include/linux/scatterlist.h	2012-10-01 18:45:47 +0000
    -@@ -8,6 +8,7 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    - 
    - struct sg_table {
    - 	struct scatterlist *sgl;	/* the list */
    -@@ -224,6 +225,9 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+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	2012-10-01 18:39:34 +0000
    -+++ new/lib/scatterlist.c	2012-10-01 20:50:07 +0000
    -@@ -573,3 +573,126 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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/kernel/scst_exec_req_fifo-3.7.patch b/scst/kernel/scst_exec_req_fifo-3.7.patch
    deleted file mode 100644
    index 465558d8f..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.7.patch
    +++ /dev/null
    @@ -1,527 +0,0 @@
    -=== modified file 'block/blk-map.c'
    ---- old/block/blk-map.c	2012-12-17 19:41:04 +0000
    -+++ new/block/blk-map.c	2012-12-17 22:29:54 +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	2012-12-17 19:41:04 +0000
    -+++ new/include/linux/blkdev.h	2012-12-17 22:29:54 +0000
    -@@ -660,6 +660,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);
    -@@ -779,6 +781,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	2012-12-17 19:41:04 +0000
    -+++ new/include/linux/scatterlist.h	2012-12-17 22:29:54 +0000
    -@@ -8,6 +8,7 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    - 
    - struct sg_table {
    - 	struct scatterlist *sgl;	/* the list */
    -@@ -225,6 +226,9 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+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	2012-12-17 19:41:04 +0000
    -+++ new/lib/scatterlist.c	2012-12-17 22:29:54 +0000
    -@@ -592,3 +592,126 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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/kernel/scst_exec_req_fifo-3.8.patch b/scst/kernel/scst_exec_req_fifo-3.8.patch
    deleted file mode 100644
    index 0476a9331..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.8.patch
    +++ /dev/null
    @@ -1,527 +0,0 @@
    -=== modified file 'block/blk-map.c'
    ---- old/block/blk-map.c	2013-02-22 21:12:31 +0000
    -+++ new/block/blk-map.c	2013-02-23 00:07:57 +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	2013-02-22 21:12:31 +0000
    -+++ new/include/linux/blkdev.h	2013-02-22 21:21:51 +0000
    -@@ -668,6 +668,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);
    -@@ -787,6 +789,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	2013-02-22 21:12:31 +0000
    -+++ new/include/linux/scatterlist.h	2013-02-22 21:21:51 +0000
    -@@ -8,6 +8,7 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    - 
    - struct sg_table {
    - 	struct scatterlist *sgl;	/* the list */
    -@@ -225,6 +226,9 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+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	2013-02-22 21:12:31 +0000
    -+++ new/lib/scatterlist.c	2013-02-23 00:07:57 +0000
    -@@ -593,3 +593,126 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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/kernel/scst_exec_req_fifo-3.9.patch b/scst/kernel/scst_exec_req_fifo-3.9.patch
    deleted file mode 100644
    index fca368b29..000000000
    --- a/scst/kernel/scst_exec_req_fifo-3.9.patch
    +++ /dev/null
    @@ -1,527 +0,0 @@
    -=== modified file 'block/blk-map.c'
    ---- old/block/blk-map.c	2013-05-11 05:39:14 +0000
    -+++ new/block/blk-map.c	2013-05-14 01:25:01 +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	2013-05-11 05:39:14 +0000
    -+++ new/include/linux/blkdev.h	2013-05-11 05:48:04 +0000
    -@@ -670,6 +670,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);
    -@@ -789,6 +791,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	2013-05-11 05:39:14 +0000
    -+++ new/include/linux/scatterlist.h	2013-05-11 05:48:04 +0000
    -@@ -8,6 +8,7 @@
    - #include 
    - #include 
    - #include 
    -+#include 
    - 
    - struct sg_table {
    - 	struct scatterlist *sgl;	/* the list */
    -@@ -225,6 +226,9 @@ size_t sg_copy_from_buffer(struct scatte
    - size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
    - 			 void *buf, size_t buflen);
    - 
    -+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	2013-05-11 05:39:14 +0000
    -+++ new/lib/scatterlist.c	2013-05-14 01:25:01 +0000
    -@@ -629,3 +629,126 @@ size_t sg_copy_to_buffer(struct scatterl
    - 	return sg_copy_buffer(sgl, nents, buf, buflen, 1);
    - }
    - EXPORT_SYMBOL(sg_copy_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/dev_handlers/scst_disk.c b/scst/src/dev_handlers/scst_disk.c
    index 684aca4ff..ad58fc438 100644
    --- a/scst/src/dev_handlers/scst_disk.c
    +++ b/scst/src/dev_handlers/scst_disk.c
    @@ -47,7 +47,7 @@ static void disk_detach(struct scst_device *dev);
     static int disk_parse(struct scst_cmd *cmd);
     static int disk_perf_exec(struct scst_cmd *cmd);
     static int disk_done(struct scst_cmd *cmd);
    -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)
    +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
     static int disk_exec(struct scst_cmd *cmd);
     static bool disk_on_sg_tablesize_low(struct scst_cmd *cmd);
     #endif
    @@ -61,7 +61,7 @@ static struct scst_dev_type disk_devtype = {
     	.attach =		disk_attach,
     	.detach =		disk_detach,
     	.parse =		disk_parse,
    -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)
    +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
     	.exec =			disk_exec,
     	.on_sg_tablesize_low = disk_on_sg_tablesize_low,
     #endif
    @@ -82,7 +82,7 @@ static struct scst_dev_type disk_devtype_perf = {
     	.parse =		disk_parse,
     	.exec =			disk_perf_exec,
     	.dev_done =		disk_done,
    -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)
    +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
     	.on_sg_tablesize_low = disk_on_sg_tablesize_low,
     #endif
     #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
    @@ -293,7 +293,7 @@ static int disk_done(struct scst_cmd *cmd)
     	return res;
     }
     
    -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)
    +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
     
     static bool disk_on_sg_tablesize_low(struct scst_cmd *cmd)
     {
    @@ -536,7 +536,7 @@ out:
     	return res;
     
     out_err_restore:
    -	scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
    +	scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_internal_failure));
     	goto out_restore;
     
     out_error:
    @@ -544,7 +544,7 @@ out_error:
     	goto out_done;
     }
     
    -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED) */
    +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) */
     
     static int disk_perf_exec(struct scst_cmd *cmd)
     {
    diff --git a/scst/src/dev_handlers/scst_tape.c b/scst/src/dev_handlers/scst_tape.c
    index ec4e85bc8..4aeba2417 100644
    --- a/scst/src/dev_handlers/scst_tape.c
    +++ b/scst/src/dev_handlers/scst_tape.c
    @@ -291,7 +291,7 @@ static int tape_done(struct scst_cmd *cmd)
     			PRINT_ERROR("Sense format 0x%x is not supported",
     				scst_sense_response_code(cmd->sense));
     			scst_set_cmd_error(cmd,
    -				SCST_LOAD_SENSE(scst_sense_hardw_error));
    +				SCST_LOAD_SENSE(scst_sense_internal_failure));
     			goto out;
     		}
     
    diff --git a/scst/src/dev_handlers/scst_user.c b/scst/src/dev_handlers/scst_user.c
    index 9f8d9e316..5dabae13d 100644
    --- a/scst/src/dev_handlers/scst_user.c
    +++ b/scst/src/dev_handlers/scst_user.c
    @@ -1155,7 +1155,7 @@ static void dev_user_add_to_ready(struct scst_user_cmd *ucmd)
     		/*
     		 * If we don't put such commands in the queue head, then under
     		 * high load we might delay threads, waiting for memory
    -		 * allocations, for too long and start loosing NOPs, which
    +		 * allocations, for too long and start losing NOPs, which
     		 * would lead to consider us by remote initiators as
     		 * unresponsive and stuck => broken connections, etc. If none
     		 * of our commands completed in NOP timeout to allow the head
    @@ -1259,7 +1259,7 @@ out_unmap:
     	ucmd->data_pages = NULL;
     	res = -EFAULT;
     	if (ucmd->cmd != NULL)
    -		scst_set_cmd_error(ucmd->cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
    +		scst_set_cmd_error(ucmd->cmd, SCST_LOAD_SENSE(scst_sense_internal_failure));
     	goto out_err;
     }
     
    @@ -1370,14 +1370,14 @@ out_process:
     
     out_inval:
     	PRINT_ERROR("Invalid parse_reply parameters (LUN %lld, op %s, cmd %p)",
    -		(long long unsigned int)cmd->lun, scst_get_opcode_name(cmd), cmd);
    +		(unsigned long long int)cmd->lun, scst_get_opcode_name(cmd), cmd);
     	PRINT_BUFFER("Invalid parse_reply", reply, sizeof(*reply));
     	scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
     	res = -EINVAL;
     	goto out_abnormal;
     
    -out_hwerr_res_set:
    -	scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
    +out_intern_fail_res_set:
    +	scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_internal_failure));
     
     out_abnormal:
     	scst_set_cmd_abnormal_done_state(cmd);
    @@ -1392,7 +1392,7 @@ out_status:
     
     		res = scst_alloc_sense(cmd, 0);
     		if (res != 0)
    -			goto out_hwerr_res_set;
    +			goto out_intern_fail_res_set;
     
     		sense_len = min_t(int, cmd->sense_buflen, preply->sense_len);
     
    @@ -1402,7 +1402,7 @@ out_status:
     		if (rc != 0) {
     			PRINT_ERROR("Failed to copy %d sense's bytes", rc);
     			res = -EFAULT;
    -			goto out_hwerr_res_set;
    +			goto out_intern_fail_res_set;
     		}
     		cmd->sense_valid_len = sense_len;
     	}
    @@ -1494,7 +1494,7 @@ static int dev_user_process_reply_exec(struct scst_user_cmd *ucmd,
     				if (unlikely((ereply->pbuf & ~PAGE_MASK) != 0)) {
     					PRINT_ERROR("Supplied pbuf %llx isn't "
     						"page aligned", ereply->pbuf);
    -					goto out_hwerr;
    +					goto out_intern_fail;
     				}
     				pages = cmd->sg_cnt;
     			} else
    @@ -1539,7 +1539,7 @@ static int dev_user_process_reply_exec(struct scst_user_cmd *ucmd,
     		if (rc != 0) {
     			PRINT_ERROR("Failed to copy %d sense's bytes", rc);
     			res = -EFAULT;
    -			goto out_hwerr_res_set;
    +			goto out_intern_fail_res_set;
     		}
     		cmd->sense_valid_len = sense_len;
     	}
    @@ -1556,19 +1556,19 @@ out:
     
     out_inval:
     	PRINT_ERROR("Invalid exec_reply parameters (LUN %lld, op %s, cmd %p)",
    -		(long long unsigned int)cmd->lun, scst_get_opcode_name(cmd), cmd);
    +		(unsigned long long int)cmd->lun, scst_get_opcode_name(cmd), cmd);
     	PRINT_BUFFER("Invalid exec_reply", reply, sizeof(*reply));
     
    -out_hwerr:
    +out_intern_fail:
     	res = -EINVAL;
     
    -out_hwerr_res_set:
    +out_intern_fail_res_set:
     	if (ucmd->background_exec) {
     		ucmd_put(ucmd);
     		goto out;
     	} else {
     		scst_set_cmd_error(cmd,
    -				   SCST_LOAD_SENSE(scst_sense_hardw_error));
    +				   SCST_LOAD_SENSE(scst_sense_internal_failure));
     		goto out_compl;
     	}
     
    @@ -1996,7 +1996,7 @@ static int dev_user_reply_get_cmd(struct file *file, void __user *arg)
     		goto out_up;
     	}
     
    -	TRACE_DBG("ureply %lld (dev %s)", (long long unsigned int)ureply,
    +	TRACE_DBG("ureply %lld (dev %s)", (unsigned long long int)ureply,
     		dev->name);
     
     	cmd = kmem_cache_alloc(user_get_cmd_cachep, GFP_KERNEL);
    @@ -2260,7 +2260,7 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
     				scst_set_busy(ucmd->cmd);
     			else
     				scst_set_cmd_error(ucmd->cmd,
    -				       SCST_LOAD_SENSE(scst_sense_hardw_error));
    +				       SCST_LOAD_SENSE(scst_sense_lun_not_supported));
     		}
     		scst_set_cmd_abnormal_done_state(ucmd->cmd);
     
    @@ -2291,7 +2291,7 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy,
     				scst_set_busy(ucmd->cmd);
     			else
     				scst_set_cmd_error(ucmd->cmd,
    -				       SCST_LOAD_SENSE(scst_sense_hardw_error));
    +				       SCST_LOAD_SENSE(scst_sense_lun_not_supported));
     		}
     
     		ucmd->cmd->scst_cmd_done(ucmd->cmd, SCST_CMD_STATE_DEFAULT,
    diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c
    index 3e45ec1b2..165ec00cc 100644
    --- a/scst/src/dev_handlers/scst_vdisk.c
    +++ b/scst/src/dev_handlers/scst_vdisk.c
    @@ -184,7 +184,7 @@ struct scst_vdisk_dev {
     	uint64_t format_progress_to_do, format_progress_done;
     
     	int virt_id;
    -	char name[16+1];	/* Name of the virtual device,
    +	char name[64+1];	/* Name of the virtual device,
     				   must be <= SCSI Model + 1 */
     	char *filename;		/* File name, protected by
     				   scst_mutex and suspended activities */
    @@ -1387,8 +1387,8 @@ static int vdisk_attach(struct scst_device *dev)
     		      (dev->type == TYPE_DISK) ? "disk" : "cdrom",
     		      virt_dev->name, vdev_get_filename(virt_dev),
     		      virt_dev->file_size >> 20, dev->block_size,
    -		      (long long unsigned int)virt_dev->nblocks,
    -		      (long long unsigned int)virt_dev->nblocks/64/32,
    +		      (unsigned long long int)virt_dev->nblocks,
    +		      (unsigned long long int)virt_dev->nblocks/64/32,
     		      virt_dev->nblocks < 64*32
     		      ? " !WARNING! cyln less than 1" : "");
     	} else {
    @@ -1541,8 +1541,8 @@ static enum compl_status_e vdisk_synchronize_cache(struct vdisk_cmd_params *p)
     
     	TRACE(TRACE_ORDER, "SYNCHRONIZE_CACHE: "
     	      "loff=%lld, data_len=%lld, immed=%d",
    -	      (long long unsigned int)loff,
    -	      (long long unsigned int)data_len, immed);
    +	      (unsigned long long int)loff,
    +	      (unsigned long long int)data_len, immed);
     
     	if (data_len == 0) {
     		struct scst_vdisk_dev *virt_dev = dev->dh_priv;
    @@ -2326,9 +2326,9 @@ static bool vdisk_parse_offset(struct vdisk_cmd_params *p, struct scst_cmd *cmd)
     
     	loff = (loff_t)lba_start << dev->block_shift;
     	TRACE_DBG("cmd %p, lba_start %lld, loff %lld, data_len %lld", cmd,
    -		  (long long unsigned int)lba_start,
    -		  (long long unsigned int)loff,
    -		  (long long unsigned int)data_len);
    +		  (unsigned long long int)lba_start,
    +		  (unsigned long long int)loff,
    +		  (unsigned long long int)data_len);
     
     	EXTRACHECKS_BUG_ON((loff < 0) || unlikely(data_len < 0));
     
    @@ -2340,9 +2340,9 @@ static bool vdisk_parse_offset(struct vdisk_cmd_params *p, struct scst_cmd *cmd)
     		} else {
     			PRINT_INFO("Access beyond the end of device %s "
     				"(%lld of %lld, data len %lld)", virt_dev->name,
    -				(long long unsigned int)loff,
    -				(long long unsigned int)virt_dev->file_size,
    -				(long long unsigned int)data_len);
    +				(unsigned long long int)loff,
    +				(unsigned long long int)virt_dev->file_size,
    +				(unsigned long long int)data_len);
     			scst_set_cmd_error(cmd, SCST_LOAD_SENSE(
     					scst_sense_block_out_range_error));
     		}
    @@ -2358,8 +2358,8 @@ static bool vdisk_parse_offset(struct vdisk_cmd_params *p, struct scst_cmd *cmd)
     		fua = (cdb[1] & 0x8);
     		if (fua) {
     			TRACE(TRACE_ORDER, "FUA: loff=%lld, "
    -				"data_len=%lld", (long long unsigned int)loff,
    -				(long long unsigned int)data_len);
    +				"data_len=%lld", (unsigned long long int)loff,
    +				(unsigned long long int)data_len);
     		}
     		break;
     	}
    @@ -2777,7 +2777,8 @@ static int fileio_alloc_data_buf(struct scst_cmd *cmd)
     	 * copy.
     	 */
     	if (cmd->tgt_i_data_buf_alloced ||
    -	    (cmd->data_direction & SCST_DATA_READ) == 0) {
    +	    (cmd->data_direction & SCST_DATA_READ) == 0 ||
    +	    (virt_dev->fd && !virt_dev->fd->f_mapping->a_ops->readpage)) {
     		p->use_zero_copy = false;
     	}
     	if (!p->use_zero_copy)
    @@ -3119,7 +3120,7 @@ static int vdisk_unmap_range(struct scst_cmd *cmd,
     #endif
     	} else {
     		loff_t off = start_lba << cmd->dev->block_shift;
    -		loff_t len = blocks << cmd->dev->block_shift;
    +		loff_t len = (u64)blocks << cmd->dev->block_shift;
     
     		res = vdisk_unmap_file_range(cmd, virt_dev, off, len, fd);
     		if (unlikely(res != 0))
    @@ -3847,16 +3848,21 @@ static int vdisk_format_pg(unsigned char *p, int pcontrol,
     
     static int vdisk_caching_pg(unsigned char *p, int pcontrol,
     			     struct scst_vdisk_dev *virt_dev)
    -{	/* Caching page for mode_sense */
    -	unsigned char caching_pg[] = {0x8, 0x12, 0x0, 0, 0, 0, 0, 0,
    -		0, 0, 0, 0, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
    +{
    +	/* Caching page for mode_sense */
    +	static const unsigned char caching_pg[] = {
    +		0x8, 0x12, 0x0, 0, 0, 0, 0, 0,
    +		0, 0, 0, 0, 0x80, 0x14, 0, 0,
    +		0, 0, 0, 0
    +	};
    +
    +	memcpy(p, caching_pg, sizeof(caching_pg));
     
     	if (!virt_dev->nv_cache && vdev_saved_mode_pages_enabled)
    -		caching_pg[0] |= 0x80;
    +		p[0] |= 0x80;
     
     	switch (pcontrol) {
     	case 0: /* current */
    -		memcpy(p, caching_pg, sizeof(caching_pg));
     		p[2] |= (virt_dev->wt_flag || virt_dev->nv_cache) ? 0 : WCE;
     		break;
     	case 1: /* changeable */
    @@ -3865,11 +3871,9 @@ static int vdisk_caching_pg(unsigned char *p, int pcontrol,
     			p[2] |= WCE;
     		break;
     	case 2: /* default */
    -		memcpy(p, caching_pg, sizeof(caching_pg));
     		p[2] |= (DEF_WRITE_THROUGH || virt_dev->nv_cache) ? 0 : WCE;
     		break;
     	case 3: /* saved */
    -		memcpy(p, caching_pg, sizeof(caching_pg));
     		p[2] |= (virt_dev->wt_flag_saved || virt_dev->nv_cache) ? 0 : WCE;
     		break;
     	default:
    @@ -4923,7 +4927,7 @@ static enum compl_status_e fileio_exec_read(struct vdisk_cmd_params *p)
     	if (unlikely(length < 0)) {
     		PRINT_ERROR("scst_get_buf_first() failed: %zd", length);
     		scst_set_cmd_error(cmd,
    -		    SCST_LOAD_SENSE(scst_sense_hardw_error));
    +		    SCST_LOAD_SENSE(scst_sense_internal_failure));
     		goto out;
     	}
     
    @@ -4952,7 +4956,7 @@ static enum compl_status_e fileio_exec_read(struct vdisk_cmd_params *p)
     		} else if (unlikely(length < 0)) {
     			PRINT_ERROR("scst_get_buf_next() failed: %zd", length);
     			scst_set_cmd_error(cmd,
    -			    SCST_LOAD_SENSE(scst_sense_hardw_error));
    +			    SCST_LOAD_SENSE(scst_sense_internal_failure));
     			goto out_set_fs;
     		}
     
    @@ -4964,7 +4968,7 @@ static enum compl_status_e fileio_exec_read(struct vdisk_cmd_params *p)
     
     		if ((err < 0) || (err < full_len)) {
     			PRINT_ERROR("readv() returned %lld from %zd",
    -				    (long long unsigned int)err,
    +				    (unsigned long long int)err,
     				    full_len);
     			if (err == -EAGAIN)
     				scst_set_busy(cmd);
    @@ -5046,7 +5050,7 @@ static enum compl_status_e fileio_exec_write(struct vdisk_cmd_params *p)
     	if (unlikely(length < 0)) {
     		PRINT_ERROR("scst_get_buf_first() failed: %zd", length);
     		scst_set_cmd_error(cmd,
    -		    SCST_LOAD_SENSE(scst_sense_hardw_error));
    +		    SCST_LOAD_SENSE(scst_sense_internal_failure));
     		goto out;
     	}
     
    @@ -5074,7 +5078,7 @@ static enum compl_status_e fileio_exec_write(struct vdisk_cmd_params *p)
     		} else if (unlikely(length < 0)) {
     			PRINT_ERROR("scst_get_buf_next() failed: %zd", length);
     			scst_set_cmd_error(cmd,
    -			    SCST_LOAD_SENSE(scst_sense_hardw_error));
    +			    SCST_LOAD_SENSE(scst_sense_internal_failure));
     			goto out_set_fs;
     		}
     
    @@ -5089,7 +5093,7 @@ restart:
     
     		if (err < 0) {
     			PRINT_ERROR("write() returned %lld from %zd",
    -				    (long long unsigned int)err,
    +				    (unsigned long long int)err,
     				    full_len);
     			if (err == -EAGAIN)
     				scst_set_busy(cmd);
    @@ -5319,15 +5323,18 @@ static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua)
     
     	/* Allocate and initialize blockio_work struct */
     	blockio_work = kmem_cache_alloc(blockio_work_cachep, gfp_mask);
    -	if (blockio_work == NULL)
    -		goto out_no_mem;
    +	if (blockio_work == NULL) {
    +		scst_set_busy(cmd);
    +		goto finish_cmd;
    +	}
     
     #if 0
     	{
     		static int err_inj_cntr;
     		if (++err_inj_cntr % 256 == 0) {
     			PRINT_INFO("blockio_exec_rw() error injection");
    -			goto out_no_bio;
    +			scst_set_busy(cmd);
    +			goto free_bio;
     		}
     	}
     #endif
    @@ -5345,6 +5352,18 @@ static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua)
     	need_new_bio = 1;
     
     	length = scst_get_sg_page_first(cmd, &page, &offset);
    +	/*
    +	 * bv_len and bv_offset must be a multiple of 512 (SECTOR_SIZE), so
    +	 * check this here.
    +	 */
    +	if (WARN_ONCE((length & 511) != 0 || (offset & 511) != 0,
    +		      "Refused bio with invalid length %d and/or offset %d.\n",
    +		      length, offset)) {
    +		scst_set_cmd_error(cmd,
    +				   SCST_LOAD_SENSE(scst_sense_hardw_error));
    +		goto free_bio;
    +	}
    +
     	while (length > 0) {
     		int len, bytes, off, thislen;
     		struct page *pg;
    @@ -5370,7 +5389,8 @@ static void blockio_exec_rw(struct vdisk_cmd_params *p, bool write, bool fua)
     					PRINT_ERROR("Failed to create bio "
     						"for data segment %d (cmd %p)",
     						cmd->get_sg_buf_entry_num, cmd);
    -					goto out_no_bio;
    +					scst_set_busy(cmd);
    +					goto free_bio;
     				}
     
     				bios++;
    @@ -5457,7 +5477,7 @@ out:
     	TRACE_EXIT();
     	return;
     
    -out_no_bio:
    +free_bio:
     	while (hbio) {
     		bio = hbio;
     		hbio = hbio->bi_next;
    @@ -5465,8 +5485,7 @@ out_no_bio:
     	}
     	kmem_cache_free(blockio_work_cachep, blockio_work);
     
    -out_no_mem:
    -	scst_set_busy(cmd);
    +finish_cmd:
     	cmd->completed = 1;
     	cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME);
     	goto out;
    @@ -5703,17 +5722,7 @@ static ssize_t fileio_read_sync(struct file *fd, void *buf, size_t len,
     
     	old_fs = get_fs();
     	set_fs(get_ds());
    -
    -	if (fd->f_op->llseek)
    -		ret = fd->f_op->llseek(fd, *loff, 0/*SEEK_SET*/);
    -	else
    -		ret = default_llseek(fd, *loff, 0/*SEEK_SET*/);
    -	if (ret < 0)
    -		goto out;
    -
     	ret = vfs_read(fd, (char __force __user *)buf, len, loff);
    -
    -out:
     	set_fs(old_fs);
     
     	return ret;
    @@ -5728,17 +5737,7 @@ static ssize_t fileio_write_sync(struct file *fd, void *buf, size_t len,
     
     	old_fs = get_fs();
     	set_fs(get_ds());
    -
    -	if (fd->f_op->llseek)
    -		ret = fd->f_op->llseek(fd, *loff, 0/*SEEK_SET*/);
    -	else
    -		ret = default_llseek(fd, *loff, 0/*SEEK_SET*/);
    -	if (ret < 0)
    -		goto out;
    -
     	ret = vfs_write(fd, (char __force __user *)buf, len, loff);
    -
    -out:
     	set_fs(old_fs);
     
     	return ret;
    @@ -5837,7 +5836,7 @@ static enum compl_status_e vdev_exec_verify(struct vdisk_cmd_params *p)
     		err = vdev_read_sync(virt_dev, mem_verify, len_mem, &loff);
     		if ((err < 0) || (err < len_mem)) {
     			PRINT_ERROR("verify() returned %lld from %zd",
    -				    (long long unsigned int)err, len_mem);
    +				    (unsigned long long int)err, len_mem);
     			if (err == -EAGAIN)
     				scst_set_busy(cmd);
     			else {
    @@ -5868,7 +5867,7 @@ static enum compl_status_e vdev_exec_verify(struct vdisk_cmd_params *p)
     	if (length < 0) {
     		PRINT_ERROR("scst_get_buf_() failed: %zd", length);
     		scst_set_cmd_error(cmd,
    -		    SCST_LOAD_SENSE(scst_sense_hardw_error));
    +		    SCST_LOAD_SENSE(scst_sense_internal_failure));
     	}
     
     out_free:
    @@ -5926,7 +5925,7 @@ static enum compl_status_e vdisk_exec_caw(struct vdisk_cmd_params *p)
     			scst_set_busy(cmd);
     		else
     			scst_set_cmd_error(cmd,
    -				SCST_LOAD_SENSE(scst_sense_hardw_error));
    +				SCST_LOAD_SENSE(scst_sense_internal_failure));
     		goto out;
     	}
     
    @@ -6067,64 +6066,69 @@ static void vdisk_task_mgmt_fn_done(struct scst_mgmt_cmd *mcmd,
     
     static void vdisk_report_registering(const struct scst_vdisk_dev *virt_dev)
     {
    -	char buf[128];
    +	enum { buf_size = 256 };
    +	char *buf = kmalloc(buf_size, GFP_KERNEL);
     	int i, j;
     
    -	i = snprintf(buf, sizeof(buf), "Registering virtual %s device %s ",
    +	if (!buf) {
    +		PRINT_ERROR("%s: out of memory", __func__);
    +		return;
    +	}
    +
    +	i = snprintf(buf, buf_size, "Registering virtual %s device %s ",
     		virt_dev->vdev_devt->name, virt_dev->name);
     	j = i;
     
     	if (virt_dev->wt_flag)
    -		i += snprintf(&buf[i], sizeof(buf) - i, "(WRITE_THROUGH");
    +		i += snprintf(&buf[i], buf_size - i, "(WRITE_THROUGH");
     
     	if (virt_dev->nv_cache)
    -		i += snprintf(&buf[i], sizeof(buf) - i, "%sNV_CACHE",
    +		i += snprintf(&buf[i], buf_size - i, "%sNV_CACHE",
     			(j == i) ? "(" : ", ");
     
     	if (virt_dev->rd_only)
    -		i += snprintf(&buf[i], sizeof(buf) - i, "%sREAD_ONLY",
    +		i += snprintf(&buf[i], buf_size - i, "%sREAD_ONLY",
     			(j == i) ? "(" : ", ");
     
     	if (virt_dev->o_direct_flag)
    -		i += snprintf(&buf[i], sizeof(buf) - i, "%sO_DIRECT",
    +		i += snprintf(&buf[i], buf_size - i, "%sO_DIRECT",
     			(j == i) ? "(" : ", ");
     
     	if (virt_dev->nullio)
    -		i += snprintf(&buf[i], sizeof(buf) - i, "%sNULLIO",
    +		i += snprintf(&buf[i], buf_size - i, "%sNULLIO",
     			(j == i) ? "(" : ", ");
     
     	if (virt_dev->blockio)
    -		i += snprintf(&buf[i], sizeof(buf) - i, "%sBLOCKIO",
    +		i += snprintf(&buf[i], buf_size - i, "%sBLOCKIO",
     			(j == i) ? "(" : ", ");
     
     	if (virt_dev->removable)
    -		i += snprintf(&buf[i], sizeof(buf) - i, "%sREMOVABLE",
    +		i += snprintf(&buf[i], buf_size - i, "%sREMOVABLE",
     			(j == i) ? "(" : ", ");
     
     	if (virt_dev->tst != DEF_TST)
    -		i += snprintf(&buf[i], sizeof(buf) - i, "%sTST %d",
    +		i += snprintf(&buf[i], buf_size - i, "%sTST %d",
     			(j == i) ? "(" : ", ", virt_dev->tst);
     
     	if (virt_dev->rotational)
    -		i += snprintf(&buf[i], sizeof(buf) - i, "%sROTATIONAL",
    +		i += snprintf(&buf[i], buf_size - i, "%sROTATIONAL",
     			(j == i) ? "(" : ", ");
     
     	if (virt_dev->thin_provisioned)
    -		i += snprintf(&buf[i], sizeof(buf) - i, "%sTHIN_PROVISIONED",
    +		i += snprintf(&buf[i], buf_size - i, "%sTHIN_PROVISIONED",
     			(j == i) ? "(" : ", ");
     
     	if (virt_dev->zero_copy)
    -		i += snprintf(&buf[i], sizeof(buf) - i, "%sZERO_COPY",
    +		i += snprintf(&buf[i], buf_size - i, "%sZERO_COPY",
     			(j == i) ? "(" : ", ");
     
     	if (virt_dev->dummy)
    -		i += snprintf(&buf[i], sizeof(buf) - i, "%sDUMMY",
    +		i += snprintf(&buf[i], buf_size - i, "%sDUMMY",
     			(j == i) ? "(" : ", ");
     
    -	if (j == i)
    -		PRINT_INFO("%s", buf);
    -	else
    -		PRINT_INFO("%s)", buf);
    +	PRINT_INFO("%s%s", buf, j == i ? "" : ")");
    +
    +	kfree(buf);
     
     	return;
     }
    @@ -6159,8 +6163,8 @@ static int vdisk_resync_size(struct scst_vdisk_dev *virt_dev)
     		"(fs=%lldMB, bs=%d, nblocks=%lld, cyln=%lld%s)",
     		virt_dev->name, virt_dev->file_size >> 20,
     		virt_dev->dev->block_size,
    -		(long long unsigned int)virt_dev->nblocks,
    -		(long long unsigned int)virt_dev->nblocks/64/32,
    +		(unsigned long long int)virt_dev->nblocks,
    +		(unsigned long long int)virt_dev->nblocks/64/32,
     		virt_dev->nblocks < 64*32 ? " !WARNING! cyln less "
     						"than 1" : "");
     
    @@ -6959,8 +6963,8 @@ static int vcdrom_change(struct scst_vdisk_dev *virt_dev,
     			" cyln=%lld%s)", virt_dev->name,
     			vdev_get_filename(virt_dev),
     			virt_dev->file_size >> 20, virt_dev->dev->block_size,
    -			(long long unsigned int)virt_dev->nblocks,
    -			(long long unsigned int)virt_dev->nblocks/64/32,
    +			(unsigned long long int)virt_dev->nblocks,
    +			(unsigned long long int)virt_dev->nblocks/64/32,
     			virt_dev->nblocks < 64*32 ? " !WARNING! cyln less "
     							"than 1" : "");
     	} else {
    @@ -8033,7 +8037,7 @@ static ssize_t vdev_sysfs_naa_id_store(struct kobject *kobj,
     	switch (c) {
     	case 0:
     	case 2 * 8:
    -		if (strchr("1235cCdDeEfF", buf[0]))
    +		if (strchr("235", buf[0]))
     			break;
     		else
     			goto out;
    diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c
    index f05ac814e..5bd950d06 100644
    --- a/scst/src/scst_lib.c
    +++ b/scst/src/scst_lib.c
    @@ -109,17 +109,18 @@ char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
      */
     int hex_to_bin(char ch)
     {
    -        if (ch >= '0' && ch <= '9')
    -                return ch - '0';
    -        ch = tolower(ch);
    -        if (ch >= 'a' && ch <= 'f')
    -                return ch - 'a' + 10;
    -        return -1;
    +	if (ch >= '0' && ch <= '9')
    +		return ch - '0';
    +	ch = tolower(ch);
    +	if (ch >= 'a' && ch <= 'f')
    +		return ch - 'a' + 10;
    +	return -1;
     }
     EXPORT_SYMBOL(hex_to_bin);
     #endif
     
    -#if !((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)) && !defined(HAVE_SG_COPY)
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) || \
    +	!defined(SCSI_EXEC_REQ_FIFO_DEFINED)
     static int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
     #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
     	    int nents_to_copy, size_t copy_len,
    @@ -554,17 +555,17 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
     	{.ops = 0x04, .devkey = "M    O O        ",
     	 .info_op_name = "FORMAT UNIT",
     	 .info_data_direction = SCST_DATA_NONE,
    -	 .info_op_flags = SCST_LONG_TIMEOUT|SCST_WRITE_MEDIUM,
    +	 .info_op_flags = SCST_LONG_TIMEOUT|SCST_WRITE_MEDIUM|SCST_STRICTLY_SERIALIZED,
     	 .get_cdb_info = get_cdb_info_fmt},
     	{.ops = 0x04, .devkey = " O              ",
     	 .info_op_name = "FORMAT MEDIUM",
     	 .info_data_direction = SCST_DATA_WRITE,
    -	 .info_op_flags = SCST_LONG_TIMEOUT|SCST_WRITE_MEDIUM,
    +	 .info_op_flags = SCST_LONG_TIMEOUT|SCST_WRITE_MEDIUM|SCST_STRICTLY_SERIALIZED,
     	 .info_len_off = 3, .get_cdb_info = get_cdb_info_len_2},
     	{.ops = 0x04, .devkey = "  O             ",
     	 .info_op_name = "FORMAT",
     	 .info_data_direction = SCST_DATA_NONE,
    -	 .info_op_flags = SCST_WRITE_MEDIUM,
    +	 .info_op_flags = SCST_WRITE_MEDIUM|SCST_STRICTLY_SERIALIZED,
     	 .get_cdb_info = get_cdb_info_none},
     	{.ops = 0x05, .devkey = "VMVVVV  V       ",
     	 .info_op_name = "READ BLOCK LIMITS",
    @@ -952,15 +953,15 @@ static const struct scst_sdbops scst_scsi_op_table[] = {
     	 .info_op_name = "WRITE BUFFER",
     	 .info_data_direction = SCST_DATA_WRITE,
     	 .info_op_flags = SCST_SMALL_TIMEOUT,
    -	 .info_len_off = 5, .info_len_len = 2,
    -	 .get_cdb_info = get_cdb_info_len_2},
    +	 .info_len_off = 6, .info_len_len = 3,
    +	 .get_cdb_info = get_cdb_info_len_3},
     	{.ops = 0x3C, .devkey = "OOOOOOOOOOOOOOOO",
     	 .info_op_name = "READ BUFFER",
     	 .info_data_direction = SCST_DATA_READ,
     	 .info_op_flags = SCST_SMALL_TIMEOUT |
     		 SCST_WRITE_EXCL_ALLOWED,
    -	 .info_len_off = 5, .info_len_len = 2,
    -	 .get_cdb_info = get_cdb_info_len_2},
    +	 .info_len_off = 6, .info_len_len = 3,
    +	 .get_cdb_info = get_cdb_info_len_3},
     	{.ops = 0x3D, .devkey = "    O  O        ",
     	 .info_op_name = "UPDATE BLOCK",
     	 .info_data_direction = SCST_DATA_WRITE,
    @@ -3176,7 +3177,7 @@ static bool __scst_adjust_sg(struct scst_cmd *cmd, struct scatterlist *sg,
     			TRACE_DBG_FLAG(TRACE_SG_OP|TRACE_MEMORY|TRACE_DEBUG,
     				"cmd %p (tag %llu), sg %p, sg_cnt %d, "
     				"adjust_len %d, i %d, sg[j].length %d, left %d",
    -				cmd, (long long unsigned int)cmd->tag,
    +				cmd, (unsigned long long int)cmd->tag,
     				sg, *sg_cnt, adjust_len, i,
     				sgi->length, left);
     
    @@ -4642,7 +4643,7 @@ static int scst_alloc_add_tgt_dev(struct scst_session *sess,
     		scst_sgv_pool_use_dma(tgt_dev);
     
     	TRACE_MGMT_DBG("Device %s on SCST lun=%lld",
    -	       dev->virt_name, (long long unsigned int)tgt_dev->lun);
    +	       dev->virt_name, (unsigned long long int)tgt_dev->lun);
     
     	spin_lock_init(&tgt_dev->tgt_dev_lock);
     	INIT_LIST_HEAD(&tgt_dev->UA_list);
    @@ -5128,7 +5129,7 @@ static void scst_complete_request_sense(struct scst_cmd *req_cmd)
     			PRINT_ERROR("%s", "Unable to get the sense via "
     				"REQUEST SENSE, returning HARDWARE ERROR");
     			scst_set_cmd_error(orig_cmd,
    -				SCST_LOAD_SENSE(scst_sense_hardw_error));
    +				SCST_LOAD_SENSE(scst_sense_internal_failure));
     		}
     	}
     
    @@ -5917,7 +5918,7 @@ void scst_free_cmd(struct scst_cmd *cmd)
     	TRACE_ENTRY();
     
     	TRACE_DBG("Freeing cmd %p (tag %llu)",
    -		  cmd, (long long unsigned int)cmd->tag);
    +		  cmd, (unsigned long long int)cmd->tag);
     
     	if (unlikely(test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags)))
     		TRACE_MGMT_DBG("Freeing aborted cmd %p", cmd);
    @@ -5958,7 +5959,7 @@ void scst_free_cmd(struct scst_cmd *cmd)
     					&cmd->cmd_flags);
     			TRACE_SN("Out of SN cmd %p (tag %llu, sn %d), "
     				"destroy=%d", cmd,
    -				(long long unsigned int)cmd->tag,
    +				(unsigned long long int)cmd->tag,
     				cmd->sn, destroy);
     		}
     	}
    @@ -6221,8 +6222,373 @@ out:
     	return;
     }
     
    -#if !((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)) && !defined(HAVE_SG_COPY)
    +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
    +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;
    +	struct page *pg;
    +	int i;
    +
    +	for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) {
    +		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
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
    +					, KM_BIO_DST_IRQ, KM_BIO_SRC_IRQ
    +#endif
    +					);
    +				local_irq_restore(flags);
    +			}
    +			blk_free_kern_sg_work(bw);
    +		}
    +	}
    +
    +	bio_put(bio);
    +	return;
    +}
    +
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
    +/*
    + * See also patch "block: Add blk_make_request(), takes bio, returns a
    + * request" (commit 79eb63e9e5875b84341a3a05f8e6ae9cdb4bb6f6).
    + */
    +static struct request *blk_make_request(struct request_queue *q,
    +					struct bio *bio,
    +					gfp_t gfp_mask)
    +{
    +	struct request *rq = blk_get_request(q, bio_data_dir(bio), gfp_mask);
    +
    +	if (unlikely(!rq))
    +		return ERR_PTR(-ENOMEM);
    +
    +	rq->cmd_type = REQ_TYPE_BLOCK_PC;
    +
    +	for ( ; bio; bio = bio->bi_next) {
    +		struct bio *bounce_bio = bio;
    +		int ret;
    +
    +		blk_queue_bounce(q, &bounce_bio);
    +		ret = blk_rq_append_bio(q, rq, bounce_bio);
    +		if (unlikely(ret)) {
    +			blk_put_request(rq);
    +			return ERR_PTR(ret);
    +		}
    +	}
    +
    +	return rq;
    +}
    +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
    +
    +/*
    + * Copy an sg-list. This function is related to bio_copy_kern() but duplicates
    + * an sg-list instead of creating a bio out of a single kernel address range.
    + */
    +static struct blk_kern_sg_work *blk_copy_kern_sg(struct request_queue *q,
    +	struct scatterlist *sgl, int nents, gfp_t gfp_mask, bool reading)
    +{
    +	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;
    +
    +	res = -ENOMEM;
    +	bw = kzalloc(sizeof(*bw), gfp_mask);
    +	if (bw == NULL)
    +		goto err;
    +
    +	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_mask);
    +	if (res != 0)
    +		goto err_free_bw;
    +
    +	new_sgl = bw->sg_table.sgl;
    +
    +	res = -ENOMEM;
    +	for_each_sg(new_sgl, sg, new_sgl_nents, i) {
    +		struct page *pg;
    +
    +		pg = alloc_page(q->bounce_gfp | gfp_mask);
    +		if (pg == NULL)
    +			goto err_free_table;
    +
    +		sg_assign_page(sg, pg);
    +		sg->length = min_t(size_t, PAGE_SIZE, len);
    +
    +		len -= PAGE_SIZE;
    +	}
    +
    +	if (!reading) {
    +		/*
    +		 * 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
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
    +			, KM_USER0, KM_USER1
    +#endif
    +			);
    +	}
    +
    +out:
    +	return bw;
    +
    +err_free_table:
    +	sg_free_table(&bw->sg_table);
    +
    +err_free_bw:
    +	blk_free_kern_sg_work(bw);
    +
    +err:
    +	sBUG_ON(res == 0);
    +	bw = ERR_PTR(res);
    +	goto out;
    +}
    +
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
    +static void bio_kmalloc_destructor(struct bio *bio)
    +{
    +	kfree(bio->bi_io_vec);
    +	kfree(bio);
    +}
    +#endif
    +
    +/* __blk_map_kern_sg - map kernel data to a request for REQ_TYPE_BLOCK_PC */
    +static struct request *__blk_map_kern_sg(struct request_queue *q,
    +	struct scatterlist *sgl, int nents, struct blk_kern_sg_work *bw,
    +	gfp_t gfp_mask, bool reading)
    +{
    +	struct request *rq;
    +	int max_nr_vecs, i;
    +	size_t tot_len;
    +	bool need_new_bio;
    +	struct scatterlist *sg;
    +	struct bio *bio = NULL, *hbio = NULL, *tbio = NULL;
    +	int bios;
    +
    +	if (unlikely(sgl == NULL || sgl->length == 0 || nents <= 0)) {
    +		WARN_ON_ONCE(true);
    +		rq = ERR_PTR(-EINVAL);
    +		goto out;
    +	}
    +
    +	/*
    +	 * Restrict bio size to a single page to minimize the probability that
    +	 * bio allocation fails.
    +	 */
    +	max_nr_vecs = min_t(int,
    +		(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;
    +
    +		/*
    +		 * Each segment must be DMA-aligned and must not reside not on
    +		 * the stack. The last segment may have unaligned length as
    +		 * long as the total length satisfies the DMA padding
    +		 * alignment requirements.
    +		 */
    +		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))) {
    +			rq = ERR_PTR(-EINVAL);
    +			goto out_free_bios;
    +		}
    +
    +		while (len > 0) {
    +			size_t bytes;
    +			int rc;
    +
    +			if (need_new_bio) {
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
    +				bio = bio_alloc_bioset(gfp_mask, max_nr_vecs, NULL);
    +				if (bio)
    +					bio->bi_destructor =
    +						bio_kmalloc_destructor;
    +#else
    +				bio = bio_kmalloc(gfp_mask, max_nr_vecs);
    +#endif
    +				if (bio == NULL) {
    +					rq = ERR_PTR(-ENOMEM);
    +					goto out_free_bios;
    +				}
    +
    +				if (!reading)
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
    +					bio->bi_rw |= 1 << BIO_RW;
    +#else
    +					bio->bi_rw |= REQ_WRITE;
    +#endif
    +				bios++;
    +				bio->bi_private = bw;
    +				bio->bi_end_io = blk_bio_map_kern_endio;
    +
    +				if (hbio == NULL)
    +					hbio = bio;
    +				else
    +					tbio->bi_next = bio;
    +				tbio = 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)) {
    +					rq = ERR_PTR(rc < 0 ? rc : -EIO);
    +					goto out_free_bios;
    +				} else {
    +					need_new_bio = true;
    +					len -= rc;
    +					offset += rc;
    +				}
    +			} else {
    +				need_new_bio = false;
    +				offset = 0;
    +				len -= bytes;
    +				page = nth_page(page, 1);
    +			}
    +		}
    +	}
    +
    +	if (hbio == NULL) {
    +		rq = ERR_PTR(-EINVAL);
    +		goto out_free_bios;
    +	}
    +
    +	/* Total length must satisfy DMA padding alignment */
    +	if ((tot_len & q->dma_pad_mask) && bw != NULL) {
    +		rq = ERR_PTR(-EINVAL);
    +		goto out_free_bios;
    +	}
    +
    +	rq = blk_make_request(q, hbio, gfp_mask);
    +	if (unlikely(IS_ERR(rq)))
    +		goto out_free_bios;
    +
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)
    +	/*
    +	 * See also patch "block: add blk_rq_set_block_pc()" (commit
    +	 * f27b087b81b7).
    +	 */
    +	rq->cmd_type = REQ_TYPE_BLOCK_PC;
    +#endif
    +
    +	if (bw != NULL) {
    +		atomic_set(&bw->bios_inflight, bios);
    +		rq->cmd_flags |= REQ_COPY_USER;
    +	}
    +
    +out:
    +	return rq;
    +
    +out_free_bios:
    +	while (hbio != NULL) {
    +		bio = hbio;
    +		hbio = hbio->bi_next;
    +		bio_put(bio);
    +	}
    +	goto out;
    +}
    +
    +/**
    + * blk_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.
    + */
    +static struct request *blk_map_kern_sg(struct request_queue *q,
    +		struct scatterlist *sgl, int nents, gfp_t gfp, bool reading)
    +{
    +	struct request *rq;
    +
    +	if (!sgl) {
    +		rq = blk_get_request(q, reading ? READ : WRITE, gfp);
    +		if (unlikely(!rq))
    +			return ERR_PTR(-ENOMEM);
    +
    +		rq->cmd_type = REQ_TYPE_BLOCK_PC;
    +		goto out;
    +	}
    +
    +	rq = __blk_map_kern_sg(q, sgl, nents, NULL, gfp, reading);
    +	if (unlikely(IS_ERR(rq))) {
    +		struct blk_kern_sg_work *bw;
    +
    +		bw = blk_copy_kern_sg(q, sgl, nents, gfp, reading);
    +		if (unlikely(IS_ERR(bw))) {
    +			rq = ERR_PTR(PTR_ERR(bw));
    +			goto out;
    +		}
    +
    +		rq = __blk_map_kern_sg(q, bw->sg_table.sgl, bw->sg_table.nents,
    +				       bw, gfp, reading);
    +		if (IS_ERR(rq)) {
    +			blk_free_kern_sg_work(bw);
    +			goto out;
    +		}
    +	}
    +
    +out:
    +	return rq;
    +}
    +#endif
    +
    +#if !defined(SCSI_EXEC_REQ_FIFO_DEFINED)
     /*
      * 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
    @@ -6374,16 +6740,22 @@ static int sg_copy(struct scatterlist *dst_sg, struct scatterlist *src_sg,
     out:
     	return res;
     }
    +#endif /* !defined(SCSI_EXEC_REQ_FIFO_DEFINED) */
     
    -#endif /* !((LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)) */
    -
    -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)) && defined(SCSI_EXEC_REQ_FIFO_DEFINED)
    +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
     static void scsi_end_async(struct request *req, int error)
     {
     	struct scsi_io_context *sioc = req->end_io_data;
     
     	TRACE_DBG("sioc %p, cmd %p", sioc, sioc->data);
     
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
    +	lockdep_assert_held(req->q->queue_lock);
    +#else
    +	if (!req->q->mq_ops)
    +		lockdep_assert_held(req->q->queue_lock);
    +#endif
    +
     	if (sioc->done)
     #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30)
     		sioc->done(sioc->data, sioc->sense, req->errors, req->data_len);
    @@ -6410,7 +6782,7 @@ int scst_scsi_exec_async(struct scst_cmd *cmd, void *data,
     	struct request_queue *q = cmd->dev->scsi_dev->request_queue;
     	struct request *rq;
     	struct scsi_io_context *sioc;
    -	int write = (cmd->data_direction & SCST_DATA_WRITE) ? WRITE : READ;
    +	bool reading = !(cmd->data_direction & SCST_DATA_WRITE);
     	gfp_t gfp = cmd->cmd_gfp_mask;
     	int cmd_len = cmd->cdb_len;
     
    @@ -6420,54 +6792,38 @@ int scst_scsi_exec_async(struct scst_cmd *cmd, void *data,
     		goto out;
     	}
     
    -	rq = blk_get_request(q, write, gfp);
    -	if (rq == NULL) {
    -		res = -ENOMEM;
    -		goto out_free_sioc;
    -	}
    -
    -	rq->cmd_type = REQ_TYPE_BLOCK_PC;
    -	rq->cmd_flags |= REQ_QUIET;
    -
    -	if (cmd->sg == NULL)
    -		goto done;
    -
     	if (cmd->data_direction == SCST_DATA_BIDI) {
     		struct request *next_rq;
     
     		if (!test_bit(QUEUE_FLAG_BIDI, &q->queue_flags)) {
     			res = -EOPNOTSUPP;
    -			goto out_free_rq;
    +			goto out;
     		}
     
    -		res = blk_rq_map_kern_sg(rq, cmd->out_sg, cmd->out_sg_cnt, gfp);
    -		if (res != 0) {
    -			TRACE_DBG("blk_rq_map_kern_sg() failed: %d", res);
    -			goto out_free_rq;
    +		rq = blk_map_kern_sg(q, cmd->out_sg, cmd->out_sg_cnt, gfp,
    +				     reading);
    +		if (IS_ERR(rq)) {
    +			res = PTR_ERR(rq);
    +			TRACE_DBG("blk_map_kern_sg() failed: %d", res);
    +			goto out;
     		}
     
    -		next_rq = blk_get_request(q, READ, gfp);
    -		if (next_rq == NULL) {
    -			res = -ENOMEM;
    +		next_rq = blk_map_kern_sg(q, cmd->sg, cmd->sg_cnt, gfp, false);
    +		if (IS_ERR(next_rq)) {
    +			res = PTR_ERR(next_rq);
    +			TRACE_DBG("blk_map_kern_sg() failed: %d", res);
     			goto out_free_unmap;
     		}
     		rq->next_rq = next_rq;
    -		next_rq->cmd_type = rq->cmd_type;
    -
    -		res = blk_rq_map_kern_sg(next_rq, cmd->sg, cmd->sg_cnt, gfp);
    -		if (res != 0) {
    -			TRACE_DBG("blk_rq_map_kern_sg() failed: %d", res);
    -			goto out_free_unmap;
    -		}
     	} else {
    -		res = blk_rq_map_kern_sg(rq, cmd->sg, cmd->sg_cnt, gfp);
    -		if (res != 0) {
    -			TRACE_DBG("blk_rq_map_kern_sg() failed: %d", res);
    -			goto out_free_rq;
    +		rq = blk_map_kern_sg(q, cmd->sg, cmd->sg_cnt, gfp, reading);
    +		if (IS_ERR(rq)) {
    +			res = PTR_ERR(rq);
    +			TRACE_DBG("blk_map_kern_sg() failed: %d", res);
    +			goto out;
     		}
     	}
     
    -done:
     	TRACE_DBG("sioc %p, cmd %p", sioc, cmd);
     
     	sioc->data = data;
    @@ -6485,6 +6841,7 @@ done:
     	rq->timeout = cmd->timeout;
     	rq->retries = cmd->retries;
     	rq->end_io_data = sioc;
    +	rq->cmd_flags |= REQ_QUIET;
     
     	blk_execute_rq_nowait(rq->q, NULL, rq,
     		(cmd->queue_type == SCST_CMD_QUEUE_HEAD_OF_QUEUE), scsi_end_async);
    @@ -6492,22 +6849,23 @@ out:
     	return res;
     
     out_free_unmap:
    -	if (rq->next_rq != NULL) {
    -		blk_put_request(rq->next_rq);
    -		rq->next_rq = NULL;
    +	{
    +	struct bio *bio = rq->bio, *b;
    +
    +	while (bio) {
    +		b = bio;
    +		bio = bio->bi_next;
    +		b->bi_end_io(b, res);
     	}
    -	blk_rq_unmap_kern_sg(rq, res);
    +	}
    +	rq->bio = NULL;
     
    -out_free_rq:
     	blk_put_request(rq);
    -
    -out_free_sioc:
    -	kmem_cache_free(scsi_io_context_cache, sioc);
     	goto out;
     }
     EXPORT_SYMBOL(scst_scsi_exec_async);
     
    -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) && defined(SCSI_EXEC_REQ_FIFO_DEFINED) */
    +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) */
     
     /**
      * scst_copy_sg() - copy data between the command's SGs
    @@ -6657,7 +7015,7 @@ int scst_get_buf_full_sense(struct scst_cmd *cmd, uint8_t **buf)
     			scst_set_busy(cmd);
     		else
     			scst_set_cmd_error(cmd,
    -				SCST_LOAD_SENSE(scst_sense_hardw_error));
    +				SCST_LOAD_SENSE(scst_sense_internal_failure));
     		goto out;
     	}
     
    @@ -7523,7 +7881,8 @@ int scst_calc_block_shift(int sector_size)
     		sector_size = 512;
     
     	block_shift = ilog2(sector_size);
    -	WARN_ON(1 << block_shift != sector_size);
    +	WARN_ONCE(1 << block_shift != sector_size, "1 << %d != %d\n",
    +		  block_shift, sector_size);
     
     	if (block_shift < 9) {
     		PRINT_ERROR("Wrong sector size %d", sector_size);
    @@ -8600,7 +8959,7 @@ static void scst_free_all_UA(struct scst_tgt_dev *tgt_dev)
     	list_for_each_entry_safe(UA_entry, t,
     				 &tgt_dev->UA_list, UA_list_entry) {
     		TRACE_MGMT_DBG("Clearing UA for tgt_dev LUN %lld",
    -			       (long long unsigned int)tgt_dev->lun);
    +			       (unsigned long long int)tgt_dev->lun);
     		list_del(&UA_entry->UA_list_entry);
     		mempool_free(UA_entry, scst_ua_mempool);
     	}
    @@ -8683,7 +9042,7 @@ restart:
     			 * !! destroyed!				     !!
     			 */
     			TRACE_SN("cmd %p (tag %llu) with skipped sn %d found",
    -				 cmd, (long long unsigned int)cmd->tag, cmd->sn);
    +				 cmd, (unsigned long long int)cmd->tag, cmd->sn);
     			order_data->def_cmd_count--;
     			list_del(&cmd->deferred_cmd_list_entry);
     			spin_unlock_irq(&order_data->sn_lock);
    @@ -8783,13 +9142,13 @@ bool __scst_check_blocked_dev(struct scst_cmd *cmd)
     	if (dev->block_count > 0) {
     		TRACE_BLOCK("Delaying cmd %p due to blocking "
     			"(tag %llu, op %s, dev %s)", cmd,
    -			(long long unsigned int)cmd->tag,
    +			(unsigned long long int)cmd->tag,
     			scst_get_opcode_name(cmd), dev->virt_name);
     		goto out_block;
     	} else if ((cmd->op_flags & SCST_STRICTLY_SERIALIZED) == SCST_STRICTLY_SERIALIZED) {
     		TRACE_BLOCK("cmd %p (tag %llu, op %s): blocking further "
     			"cmds on dev %s due to strict serialization", cmd,
    -			(long long unsigned int)cmd->tag,
    +			(unsigned long long int)cmd->tag,
     			scst_get_opcode_name(cmd), dev->virt_name);
     		scst_block_dev(dev);
     		if (dev->on_dev_cmd_count > 1) {
    @@ -8804,7 +9163,7 @@ bool __scst_check_blocked_dev(struct scst_cmd *cmd)
     	} else if ((dev->dev_double_ua_possible) ||
     		   ((cmd->op_flags & SCST_SERIALIZED) != 0)) {
     		TRACE_BLOCK("cmd %p (tag %llu, op %s): blocking further cmds "
    -			"on dev %s due to %s", cmd, (long long unsigned int)cmd->tag,
    +			"on dev %s due to %s", cmd, (unsigned long long int)cmd->tag,
     			scst_get_opcode_name(cmd), dev->virt_name,
     			dev->dev_double_ua_possible ? "possible double reset UA" :
     						      "serialized cmd");
    @@ -9253,13 +9612,13 @@ void scst_xmit_process_aborted_cmd(struct scst_cmd *cmd)
     		if (test_bit(SCST_CMD_DEVICE_TAS, &cmd->cmd_flags)) {
     			TRACE_MGMT_DBG("Flag ABORTED OTHER set for cmd %p "
     				"(tag %llu), returning TASK ABORTED ", cmd,
    -				(long long unsigned int)cmd->tag);
    +				(unsigned long long int)cmd->tag);
     			scst_set_cmd_error_status(cmd, SAM_STAT_TASK_ABORTED);
     		} else {
     			TRACE_MGMT_DBG("Flag ABORTED OTHER set for cmd %p "
     				"(tag %llu), aborting without delivery or "
     				"notification",
    -				cmd, (long long unsigned int)cmd->tag);
    +				cmd, (unsigned long long int)cmd->tag);
     			/*
     			 * There is no need to check/requeue possible UA,
     			 * because, if it exists, it will be delivered
    @@ -10680,7 +11039,7 @@ void tm_dbg_release_cmd(struct scst_cmd *cmd)
     				if (((scst_random() % 10) == 5)) {
     					scst_set_cmd_error(cmd,
     						SCST_LOAD_SENSE(
    -						scst_sense_hardw_error));
    +							scst_sense_internal_failure));
     					/* It's completed now */
     				}
     			}
    diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c
    index 14fa55849..6c40d22ea 100644
    --- a/scst/src/scst_main.c
    +++ b/scst/src/scst_main.c
    @@ -47,18 +47,13 @@ option or use a 64-bit configuration instead. See README file for \
     details.
     #endif
     
    -#if !defined(SCSI_EXEC_REQ_FIFO_DEFINED)
    -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
    -#if !defined(CONFIG_SCST_STRICT_SERIALIZING)
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) && \
    +	!defined(SCSI_EXEC_REQ_FIFO_DEFINED) &&	     \
    +	!defined(CONFIG_SCST_STRICT_SERIALIZING)
     #warning Patch scst_exec_req_fifo- was not applied on \
     your kernel and CONFIG_SCST_STRICT_SERIALIZING is not defined. \
     Pass-through dev handlers will not work.
    -#endif /* !defined(CONFIG_SCST_STRICT_SERIALIZING) */
    -#else  /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) */
    -#warning Patch scst_exec_req_fifo- was not applied on \
    -your kernel. Pass-through dev handlers will not work.
    -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) */
    -#endif /* !defined(SCSI_EXEC_REQ_FIFO_DEFINED) */
    +#endif
     
     /**
      ** SCST global variables. They are all uninitialized to have their layout in
    @@ -1607,26 +1602,18 @@ int __scst_register_dev_driver(struct scst_dev_type *dev_type,
     	if (res != 0)
     		goto out;
     
    -#if !defined(SCSI_EXEC_REQ_FIFO_DEFINED)
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) && \
    +	!defined(SCSI_EXEC_REQ_FIFO_DEFINED) && \
    +	!defined(CONFIG_SCST_STRICT_SERIALIZING)
     	if (dev_type->exec == NULL) {
    -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
    -#if !defined(CONFIG_SCST_STRICT_SERIALIZING)
     		PRINT_ERROR("Pass-through dev handlers (handler \"%s\") not "
     			"supported. Consider applying on your kernel patch "
     			"scst_exec_req_fifo- or define "
     			"CONFIG_SCST_STRICT_SERIALIZING", dev_type->name);
     		res = -EINVAL;
     		goto out;
    -#endif /* !defined(CONFIG_SCST_STRICT_SERIALIZING) */
    -#else  /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) */
    -		PRINT_ERROR("Pass-through dev handlers (handler \"%s\") not "
    -			"supported. Consider applying on your kernel patch "
    -			"scst_exec_req_fifo-", dev_type->name);
    -		res = -EINVAL;
    -		goto out;
    -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) */
     	}
    -#endif /* !defined(SCSI_EXEC_REQ_FIFO_DEFINED) */
    +#endif
     
     #ifdef CONFIG_SCST_PROC
     	res = scst_suspend_activity(SCST_SUSPEND_TIMEOUT_USER);
    @@ -2513,55 +2500,59 @@ static int __init init_scst(void)
     	}
     
     /* Used for rarely used or read-mostly on fast path structures */
    -#define INIT_CACHEP(p, s, o) do {					\
    -		p = KMEM_CACHE(s, SCST_SLAB_FLAGS);			\
    -		TRACE_MEM("Slab create: %s at %p size %zd", #s, p,	\
    +#define INIT_CACHEP(p, s) ({						\
    +		(p) = KMEM_CACHE(s, SCST_SLAB_FLAGS);			\
    +		TRACE_MEM("Slab create: %s at %p size %zd", #s, (p),	\
     			  sizeof(struct s));				\
    -		if (p == NULL) {					\
    -			res = -ENOMEM;					\
    -			goto o;						\
    -		}							\
    -	} while (0)
    +		(p);							\
    +	})
     
     /* Used for structures with fast path write access */
    -#define INIT_CACHEP_ALIGN(p, s, o) do {					\
    -		p = KMEM_CACHE(s, SCST_SLAB_FLAGS|SLAB_HWCACHE_ALIGN);	\
    -		TRACE_MEM("Slab create: %s at %p size %zd", #s, p,	\
    +#define INIT_CACHEP_ALIGN(p, s) ({					\
    +		(p) = KMEM_CACHE(s, SCST_SLAB_FLAGS|SLAB_HWCACHE_ALIGN);\
    +		TRACE_MEM("Slab create: %s at %p size %zd", #s, (p),	\
     			  sizeof(struct s));				\
    -		if (p == NULL) {					\
    -			res = -ENOMEM;					\
    -			goto o;						\
    -		}							\
    -	} while (0)
    +		(p);							\
    +	})
     
    -	INIT_CACHEP(scst_mgmt_cachep, scst_mgmt_cmd, out_lib_exit);
    -	INIT_CACHEP(scst_mgmt_stub_cachep, scst_mgmt_cmd_stub,
    -			out_destroy_mgmt_cache);
    -	INIT_CACHEP(scst_ua_cachep, scst_tgt_dev_UA,
    -			out_destroy_mgmt_stub_cache);
    +	res = -ENOMEM;
    +	if (!INIT_CACHEP(scst_mgmt_cachep, scst_mgmt_cmd))
    +		goto out_lib_exit;
    +	if (!INIT_CACHEP(scst_mgmt_stub_cachep, scst_mgmt_cmd_stub))
    +		goto out_destroy_mgmt_cache;
    +	if (!INIT_CACHEP(scst_ua_cachep, scst_tgt_dev_UA))
    +		goto out_destroy_mgmt_stub_cache;
     	{
     		struct scst_sense { uint8_t s[SCST_SENSE_BUFFERSIZE]; };
    -		INIT_CACHEP(scst_sense_cachep, scst_sense,
    -			    out_destroy_ua_cache);
    +		if (!INIT_CACHEP(scst_sense_cachep, scst_sense))
    +			goto out_destroy_ua_cache;
     	}
    -	INIT_CACHEP(scst_aen_cachep, scst_aen, out_destroy_sense_cache); /* read-mostly */
    -	INIT_CACHEP_ALIGN(scst_cmd_cachep, scst_cmd, out_destroy_aen_cache);
    +	if (!INIT_CACHEP(scst_aen_cachep, scst_aen)) /* read-mostly */
    +		goto out_destroy_sense_cache;
    +	if (!INIT_CACHEP_ALIGN(scst_cmd_cachep, scst_cmd))
    +		goto out_destroy_aen_cache;
     #ifdef CONFIG_SCST_MEASURE_LATENCY
    -	INIT_CACHEP_ALIGN(scst_sess_cachep, scst_session,
    -			  out_destroy_cmd_cache);
    +	if (!INIT_CACHEP_ALIGN(scst_sess_cachep, scst_session))
    +		goto out_destroy_cmd_cache;
     #else
     	/* Big enough with read-mostly head and tail */
    -	INIT_CACHEP(scst_sess_cachep, scst_session, out_destroy_cmd_cache);
    +	if (!INIT_CACHEP(scst_sess_cachep, scst_session))
    +		goto out_destroy_cmd_cache;
     #endif
    -	INIT_CACHEP(scst_dev_cachep, scst_device, out_destroy_sess_cache); /* big enough */
    -	INIT_CACHEP(scst_tgt_cachep, scst_tgt, out_destroy_dev_cache); /* read-mostly */
    +	if (!INIT_CACHEP(scst_dev_cachep, scst_device)) /* big enough */
    +		goto out_destroy_sess_cache;
    +	if (!INIT_CACHEP(scst_tgt_cachep, scst_tgt)) /* read-mostly */
    +		goto out_destroy_dev_cache;
     #ifdef CONFIG_SCST_MEASURE_LATENCY
    -	INIT_CACHEP_ALIGN(scst_tgtd_cachep, scst_tgt_dev, out_destroy_tgt_cache); /* big enough */
    +	if (!INIT_CACHEP_ALIGN(scst_tgtd_cachep, scst_tgt_dev)) /* big enough */
    +		goto out_destroy_tgt_cache;
     #else
     	/* Big enough with read-mostly head and tail */
    -	INIT_CACHEP(scst_tgtd_cachep, scst_tgt_dev, out_destroy_tgt_cache); /* big enough */
    +	if (!INIT_CACHEP(scst_tgtd_cachep, scst_tgt_dev)) /* big enough */
    +		goto out_destroy_tgt_cache;
     #endif
    -	INIT_CACHEP(scst_acgd_cachep, scst_acg_dev, out_destroy_tgtd_cache); /* read-mostly */
    +	if (!INIT_CACHEP(scst_acgd_cachep, scst_acg_dev)) /* read-mostly */
    +		goto out_destroy_tgtd_cache;
     
     	scst_mgmt_mempool = mempool_create(64, mempool_alloc_slab,
     		mempool_free_slab, scst_mgmt_cachep);
    @@ -2571,7 +2562,7 @@ static int __init init_scst(void)
     	}
     
     	/*
    -	 * All mgmt stubs, UAs and sense buffers are bursty and loosing them
    +	 * All mgmt stubs, UAs and sense buffers are bursty and losing them
     	 * may have fatal consequences, so let's have big pools for them.
     	 */
     
    diff --git a/scst/src/scst_mem.c b/scst/src/scst_mem.c
    index 7bc6b4418..b3ab75e1a 100644
    --- a/scst/src/scst_mem.c
    +++ b/scst/src/scst_mem.c
    @@ -350,7 +350,7 @@ out_unlock_put:
     	goto out;
     }
     
    -static unsigned long __sgv_can_be_shrinked(void)
    +static unsigned long __sgv_can_be_shrunk(void)
     {
     	unsigned long res;
     	struct sgv_pool *pool;
    @@ -374,10 +374,10 @@ static unsigned long __sgv_can_be_shrinked(void)
     }
     
     #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
    -static unsigned long sgv_can_be_shrinked(struct shrinker *shrinker,
    +static unsigned long sgv_can_be_shrunk(struct shrinker *shrinker,
     					 struct shrink_control *sc)
     {
    -	return __sgv_can_be_shrinked();
    +	return __sgv_can_be_shrunk();
     }
     
     static unsigned long sgv_scan_shrink(struct shrinker *shrinker,
    @@ -413,7 +413,7 @@ static int sgv_shrink(struct shrinker *shrinker, struct shrink_control *sc)
     		nr = __sgv_shrink(nr, SGV_MIN_SHRINK_INTERVAL, &freed);
     		TRACE_MEM("Left %d", nr);
     	} else
    -		nr = __sgv_can_be_shrinked();
    +		nr = __sgv_can_be_shrunk();
     
     	TRACE_EXIT_RES(nr);
     	return nr;
    @@ -1809,7 +1809,7 @@ int scst_sgv_pools_init(unsigned long mem_hwmark, unsigned long mem_lwmark)
     	sgv_shrinker = set_shrinker(DEFAULT_SEEKS, sgv_shrink);
     #else
     #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
    -	sgv_shrinker.count_objects = sgv_can_be_shrinked;
    +	sgv_shrinker.count_objects = sgv_can_be_shrunk;
     	sgv_shrinker.scan_objects = sgv_scan_shrink;
     #else
     	sgv_shrinker.shrink = sgv_shrink;
    diff --git a/scst/src/scst_pres.c b/scst/src/scst_pres.c
    index 9e862bbcf..2f5ecbdbe 100644
    --- a/scst/src/scst_pres.c
    +++ b/scst/src/scst_pres.c
    @@ -1036,7 +1036,7 @@ out:
            * the affected initiator.
            */
     		if (cmd != NULL)
    -			scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
    +			scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_internal_failure));
     #endif
     	}
     
    diff --git a/scst/src/scst_priv.h b/scst/src/scst_priv.h
    index 4f742c8a0..fce62d9af 100644
    --- a/scst/src/scst_priv.h
    +++ b/scst/src/scst_priv.h
    @@ -412,15 +412,6 @@ static inline int scst_exec_req(struct scsi_device *sdev,
     	    (void *)sgl, bufflen, nents, timeout, retries, privdata, done, gfp);
     #endif
     }
    -#else /* i.e. LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30) */
    -#if !defined(SCSI_EXEC_REQ_FIFO_DEFINED)
    -static inline int scst_scsi_exec_async(struct scst_cmd *cmd, void *data,
    -	void (*done)(void *data, char *sense, int result, int resid))
    -{
    -	WARN_ON_ONCE(1);
    -	return -1;
    -}
    -#endif
     #endif
     
     int scst_alloc_space(struct scst_cmd *cmd);
    diff --git a/scst/src/scst_proc.c b/scst/src/scst_proc.c
    index d00101511..e1b458bcb 100644
    --- a/scst/src/scst_proc.c
    +++ b/scst/src/scst_proc.c
    @@ -2546,7 +2546,7 @@ static int scst_groups_devices_show(struct seq_file *seq, void *v)
     	list_for_each_entry(acg_dev, &acg->acg_dev_list, acg_dev_list_entry) {
     		seq_printf(seq, "%-60s%-13lld%s\n",
     			       acg_dev->dev->virt_name,
    -			       (long long unsigned int)acg_dev->lun,
    +			       (unsigned long long int)acg_dev->lun,
     			       acg_dev->acg_dev_rd_only ? "RO" : "");
     	}
     	mutex_unlock(&scst_mutex);
    diff --git a/scst/src/scst_sysfs.c b/scst/src/scst_sysfs.c
    index ac28b01b5..71be58f89 100644
    --- a/scst/src/scst_sysfs.c
    +++ b/scst/src/scst_sysfs.c
    @@ -313,7 +313,9 @@ out:
     
     #endif /* defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) */
     
    -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34) &&	\
    +	(!defined(RHEL_MAJOR) || RHEL_MAJOR -0 < 6 ||	\
    +	 (RHEL_MAJOR -0 == 6 && RHEL_MINOR -0 < 6))
     /**
      ** Backported sysfs functions.
      **/
    @@ -1266,6 +1268,7 @@ static int __scst_process_luns_mgmt_store(char *buffer,
     			goto out_unlock;
     		} else if (virt_lun > SCST_MAX_LUN) {
     			PRINT_ERROR("Too big LUN %ld (max %d)", virt_lun, SCST_MAX_LUN);
    +			res = -EINVAL;
     			goto out_unlock;
     		}
     
    diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c
    index eda3226b8..8980b9b5e 100644
    --- a/scst/src/scst_targ.c
    +++ b/scst/src/scst_targ.c
    @@ -157,7 +157,7 @@ static void scst_check_unblock_dev(struct scst_cmd *cmd)
     
     	if (unlikely(cmd->unblock_dev)) {
     		TRACE_BLOCK("cmd %p (tag %llu): unblocking dev %s", cmd,
    -			(long long unsigned int)cmd->tag, dev->virt_name);
    +			(unsigned long long int)cmd->tag, dev->virt_name);
     		cmd->unblock_dev = 0;
     		scst_unblock_dev(dev);
     	} else if (unlikely(dev->strictly_serialized_cmd_waiting)) {
    @@ -416,9 +416,9 @@ void scst_cmd_init_done(struct scst_cmd *cmd,
     	TRACE_DBG("Preferred context: %d (cmd %p)", pref_context, cmd);
     	TRACE(TRACE_SCSI, "NEW CDB: len %d, lun %lld, initiator %s, "
     		"target %s, queue_type %x, tag %llu (cmd %p, sess %p)",
    -		cmd->cdb_len, (long long unsigned int)cmd->lun,
    +		cmd->cdb_len, (unsigned long long int)cmd->lun,
     		cmd->sess->initiator_name, cmd->tgt->tgt_name, cmd->queue_type,
    -		(long long unsigned int)cmd->tag, cmd, sess);
    +		(unsigned long long int)cmd->tag, cmd, sess);
     	PRINT_BUFF_FLAG(TRACE_SCSI, "CDB", cmd->cdb, cmd->cdb_len);
     
     #ifdef CONFIG_SCST_EXTRACHECKS
    @@ -655,6 +655,9 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
     			goto out;
     
     		case SCST_CMD_STATE_STOP:
    +			/*
    +			 * !! cmd can be dead now!
    +			 */
     			TRACE_DBG("Dev handler %s parse() requested stop "
     				"processing", devt->name);
     			res = SCST_CMD_STATE_RES_CONT_NEXT;
    @@ -939,11 +942,11 @@ set_res:
     		TRACE_DBG_FLAG(TRACE_DEBUG|TRACE_MINOR, "Atomic context and "
     			"non-WRITE data direction, rescheduling (cmd %p)", cmd);
     		res = SCST_CMD_STATE_RES_NEED_THREAD;
    -		goto out;
    +		/* go through */
     	}
     #endif
     
    -out:
    +out_check_compl:
     #ifdef CONFIG_SCST_EXTRACHECKS
     	if (unlikely(cmd->completed)) {
     		/* Command completed with error */
    @@ -1000,6 +1003,7 @@ out:
     		}
     	}
     
    +out:
     	TRACE_EXIT_HRES(res);
     	return res;
     
    @@ -1010,7 +1014,7 @@ out_hw_error:
     out_done:
     	scst_set_cmd_abnormal_done_state(cmd);
     	res = SCST_CMD_STATE_RES_CONT_SAME;
    -	goto out;
    +	goto out_check_compl;
     }
     
     static void scst_set_write_len(struct scst_cmd *cmd)
    @@ -1259,7 +1263,7 @@ void scst_restart_cmd(struct scst_cmd *cmd, int status,
     
     	TRACE_DBG("Preferred context: %d", pref_context);
     	TRACE_DBG("tag=%llu, status=%#x",
    -		  (long long unsigned int)scst_cmd_get_tag(cmd),
    +		  (unsigned long long int)scst_cmd_get_tag(cmd),
     		  status);
     
     #ifdef CONFIG_SCST_EXTRACHECKS
    @@ -1774,14 +1778,16 @@ static inline enum scst_exec_context scst_optimize_post_exec_context(
      */
     void scst_pass_through_cmd_done(void *data, char *sense, int result, int resid)
     {
    -	struct scst_cmd *cmd;
    +	struct scst_cmd *cmd = data;
     
     	TRACE_ENTRY();
     
    -	cmd = (struct scst_cmd *)data;
     	if (cmd == NULL)
     		goto out;
     
    +	TRACE_DBG("cmd %p; CDB[0/%d] %#x: result %d; resid %d", cmd,
    +		  cmd->cdb_len, cmd->cdb[0], result, resid);
    +
     	scst_do_cmd_done(cmd, result, sense, SCSI_SENSE_BUFFERSIZE, resid);
     
     	cmd->state = SCST_CMD_STATE_PRE_DEV_DONE;
    @@ -2348,7 +2354,7 @@ static int scst_reserve_local(struct scst_cmd *cmd)
     
     	if ((cmd->cdb[0] == RESERVE_10) && (cmd->cdb[2] & SCST_RES_3RDPTY)) {
     		PRINT_ERROR("RESERVE_10: 3rdPty RESERVE not implemented "
    -		     "(lun=%lld)", (long long unsigned int)cmd->lun);
    +		     "(lun=%lld)", (unsigned long long int)cmd->lun);
     		scst_set_invalid_field_in_cdb(cmd, 2,
     			SCST_INVAL_FIELD_BIT_OFFS_VALID | 4);
     		goto out_done;
    @@ -2983,14 +2989,16 @@ static int scst_do_real_exec(struct scst_cmd *cmd)
     		sBUG_ON(res != SCST_EXEC_NOT_COMPLETED);
     	}
     
    -	TRACE_DBG("Sending cmd %p to SCSI mid-level", cmd);
    -
     	scsi_dev = dev->scsi_dev;
     
    +	TRACE_DBG("Sending cmd %p to SCSI mid-level dev %d:%d:%d:%lld", cmd,
    +		  scsi_dev->host->host_no, scsi_dev->channel, scsi_dev->id,
    +		  (u64)scsi_dev->lun);
    +
     	if (unlikely(scsi_dev == NULL)) {
     		PRINT_ERROR("Command for virtual device must be "
     			"processed by device handler (LUN %lld)!",
    -			(long long unsigned int)cmd->lun);
    +			(unsigned long long int)cmd->lun);
     		goto out_error;
     	}
     
    @@ -3334,7 +3342,7 @@ static int scst_exec_check_sn(struct scst_cmd **active_cmd)
     				/* Necessary to allow aborting out of sn cmds */
     				TRACE_MGMT_DBG("Aborting out of sn cmd %p "
     					"(tag %llu, sn %u)", cmd,
    -					(long long unsigned)cmd->tag, cmd->sn);
    +					(unsigned long long)cmd->tag, cmd->sn);
     				order_data->def_cmd_count--;
     				scst_set_cmd_abnormal_done_state(cmd);
     				res = SCST_CMD_STATE_RES_CONT_SAME;
    @@ -3414,7 +3422,7 @@ static int scst_check_sense(struct scst_cmd *cmd)
     						"detected for device %p", dev);
     					TRACE_DBG("Retrying cmd"
     						" %p (tag %llu)", cmd,
    -						(long long unsigned)cmd->tag);
    +						(unsigned long long)cmd->tag);
     
     					cmd->status = 0;
     					cmd->msg_status = 0;
    @@ -3513,7 +3521,7 @@ static bool scst_check_auto_sense(struct scst_cmd *cmd)
     				"%s)", cmd->host_status, cmd, scst_get_opcode_name(cmd),
     				cmd->tgt->tgt_name, cmd->dev->virt_name);
     			scst_set_cmd_error(cmd,
    -				SCST_LOAD_SENSE(scst_sense_hardw_error));
    +				SCST_LOAD_SENSE(scst_sense_internal_failure));
     		}
     	}
     
    @@ -3541,7 +3549,7 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
     			PRINT_ERROR("%s", "Unable to issue REQUEST SENSE, "
     				    "returning HARDWARE ERROR");
     			scst_set_cmd_error(cmd,
    -				SCST_LOAD_SENSE(scst_sense_hardw_error));
    +				SCST_LOAD_SENSE(scst_sense_internal_failure));
     		}
     		goto out;
     	}
    @@ -3577,7 +3585,7 @@ next:
     					"MODE_SENSE buffer");
     				scst_set_cmd_error(cmd,
     					SCST_LOAD_SENSE(
    -						scst_sense_hardw_error));
    +						scst_sense_internal_failure));
     				err = true;
     			} else if (length > 2 && cmd->cdb[0] == MODE_SENSE)
     				address[2] |= 0x80;   /* Write Protect*/
    @@ -3609,7 +3617,7 @@ next:
     					PRINT_INFO("NormACA set for device: "
     						"lun=%lld, type 0x%02x. Clear it, "
     						"since it's unsupported.",
    -						(long long unsigned int)cmd->lun,
    +						(unsigned long long int)cmd->lun,
     						buffer[0]);
     				}
     #endif
    @@ -3618,7 +3626,7 @@ next:
     				PRINT_ERROR("%s", "Unable to get INQUIRY "
     				    "buffer");
     				scst_set_cmd_error(cmd,
    -				       SCST_LOAD_SENSE(scst_sense_hardw_error));
    +				       SCST_LOAD_SENSE(scst_sense_internal_failure));
     				err = true;
     			}
     			if (buflen > 0)
    @@ -3632,7 +3640,7 @@ next:
     		    (cmd->cdb[0] == MODE_SELECT_10) ||
     		    (cmd->cdb[0] == LOG_SELECT))) {
     			TRACE(TRACE_SCSI, "MODE/LOG SELECT succeeded (LUN %lld)",
    -				(long long unsigned int)cmd->lun);
    +				(unsigned long long int)cmd->lun);
     			cmd->state = SCST_CMD_STATE_MODE_SELECT_CHECKS;
     			goto out;
     		}
    @@ -3645,7 +3653,7 @@ next:
     					SCST_SENSE_ASCx_VALID,
     					0, 0x2a, 0x01)) {
     			TRACE(TRACE_SCSI, "MODE PARAMETERS CHANGED UA (lun "
    -				"%lld)", (long long unsigned int)cmd->lun);
    +				"%lld)", (unsigned long long int)cmd->lun);
     			cmd->state = SCST_CMD_STATE_MODE_SELECT_CHECKS;
     			goto out;
     		}
    @@ -3682,7 +3690,7 @@ static int scst_mode_select_checks(struct scst_cmd *cmd)
     
     			TRACE(TRACE_SCSI, "MODE/LOG SELECT succeeded, "
     				"setting the SELECT UA (lun=%lld)",
    -				(long long unsigned int)cmd->lun);
    +				(unsigned long long int)cmd->lun);
     
     			spin_lock_bh(&dev->dev_lock);
     			if (cmd->cdb[0] == LOG_SELECT) {
    @@ -3728,7 +3736,7 @@ static int scst_mode_select_checks(struct scst_cmd *cmd)
     
     		TRACE(TRACE_SCSI, "Possible parameters changed UA %x "
     			"(LUN %lld): getting new parameters", cmd->sense[12],
    -			(long long unsigned int)cmd->lun);
    +			(unsigned long long int)cmd->lun);
     
     		scst_obtain_device_parameters(cmd->dev, NULL);
     	} else
    @@ -3885,7 +3893,7 @@ again:
     	if (unlikely(test_bit(SCST_CMD_NO_RESP, &cmd->cmd_flags))) {
     		EXTRACHECKS_BUG_ON(!test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags));
     		TRACE_MGMT_DBG("Flag NO_RESP set for cmd %p (tag %llu), "
    -			"skipping", cmd, (long long unsigned int)cmd->tag);
    +			"skipping", cmd, (unsigned long long int)cmd->tag);
     		cmd->state = SCST_CMD_STATE_FINISHED;
     		goto out_same;
     	}
    @@ -4390,7 +4398,7 @@ static int scst_translate_lun(struct scst_cmd *cmd)
     
     	if (likely(!test_bit(SCST_FLAG_SUSPENDED, &scst_flags))) {
     		TRACE_DBG("Finding tgt_dev for cmd %p (lun %lld)", cmd,
    -			(long long unsigned int)cmd->lun);
    +			(unsigned long long int)cmd->lun);
     		res = -1;
     		tgt_dev = scst_lookup_tgt_dev(cmd->sess, cmd->lun);
     		if (tgt_dev) {
    @@ -4407,7 +4415,7 @@ static int scst_translate_lun(struct scst_cmd *cmd)
     			} else {
     				PRINT_INFO("Dev handler for device %lld is NULL, "
     					"the device will not be visible remotely",
    -					(long long unsigned int)cmd->lun);
    +					(unsigned long long int)cmd->lun);
     				nul_dev = true;
     			}
     		}
    @@ -4416,7 +4424,7 @@ static int scst_translate_lun(struct scst_cmd *cmd)
     				TRACE(TRACE_MINOR,
     					"tgt_dev for LUN %lld not found, command to "
     					"unexisting LU (initiator %s, target %s)?",
    -					(long long unsigned int)cmd->lun,
    +					(unsigned long long int)cmd->lun,
     					cmd->sess->initiator_name, cmd->tgt->tgt_name);
     			}
     			scst_put(cmd->cpu_cmd_counter);
    @@ -4559,7 +4567,7 @@ restart:
     			}
     		} else {
     			TRACE_MGMT_DBG("Aborting not inited cmd %p (tag %llu)",
    -				       cmd, (long long unsigned int)cmd->tag);
    +				       cmd, (unsigned long long int)cmd->tag);
     			scst_set_cmd_abnormal_done_state(cmd);
     		}
     
    @@ -4781,7 +4789,7 @@ void scst_process_active_cmd(struct scst_cmd *cmd, bool atomic)
     				res = SCST_CMD_STATE_RES_CONT_NEXT;
     				TRACE_MGMT_DBG("Skipping cmd %p (tag %llu), "
     					"because of TM DBG delay", cmd,
    -					(long long unsigned int)cmd->tag);
    +					(unsigned long long int)cmd->tag);
     				break;
     			}
     			res = scst_exec_check_sn(&cmd);
    @@ -5029,7 +5037,7 @@ static int scst_mgmt_translate_lun(struct scst_mgmt_cmd *mcmd)
     	TRACE_ENTRY();
     
     	TRACE_DBG("Finding tgt_dev for mgmt cmd %p (lun %lld)", mcmd,
    -	      (long long unsigned int)mcmd->lun);
    +	      (unsigned long long int)mcmd->lun);
     
     	res = scst_get_mgmt(mcmd);
     	if (unlikely(res != 0))
    @@ -5060,7 +5068,7 @@ void scst_done_cmd_mgmt(struct scst_cmd *cmd)
     	TRACE_ENTRY();
     
     	TRACE_MGMT_DBG("cmd %p done (tag %llu)",
    -		       cmd, (long long unsigned int)cmd->tag);
    +		       cmd, (unsigned long long int)cmd->tag);
     
     	spin_lock_irqsave(&scst_mcmd_lock, flags);
     
    @@ -5216,7 +5224,7 @@ void scst_finish_cmd_mgmt(struct scst_cmd *cmd)
     	TRACE_ENTRY();
     
     	TRACE(TRACE_MGMT, "Aborted cmd %p finished (tag %llu, ref %d)", cmd,
    -		(long long unsigned int)cmd->tag, atomic_read(&cmd->cmd_ref));
    +		(unsigned long long int)cmd->tag, atomic_read(&cmd->cmd_ref));
     
     	spin_lock_irqsave(&scst_mcmd_lock, flags);
     
    @@ -5317,7 +5325,7 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
     		EXTRACHECKS_BUG_ON(!mcmd);
     
     	TRACE(TRACE_SCSI|TRACE_MGMT_DEBUG, "Aborting cmd %p (tag %llu, op %s)",
    -		cmd, (long long unsigned int)cmd->tag, scst_get_opcode_name(cmd));
    +		cmd, (unsigned long long int)cmd->tag, scst_get_opcode_name(cmd));
     
     	/* To protect from concurrent aborts */
     	spin_lock_irqsave(&other_ini_lock, flags);
    @@ -5399,7 +5407,7 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
     
     		if (cmd->sent_for_exec && !cmd->done) {
     			TRACE_MGMT_DBG("cmd %p (tag %llu) is being executed",
    -				cmd, (long long unsigned int)cmd->tag);
    +				cmd, (unsigned long long int)cmd->tag);
     			mstb->done_counted = 1;
     			mcmd->cmd_done_wait_count++;
     		}
    @@ -5425,7 +5433,7 @@ void scst_abort_cmd(struct scst_cmd *cmd, struct scst_mgmt_cmd *mcmd,
     				"deferring ABORT (cmd_done_wait_count %d, "
     				"cmd_finish_wait_count %d, internal %d, mcmd "
     				"fn %d (mcmd %p), initiator %s, target %s)",
    -				cmd, (long long unsigned int)cmd->tag,
    +				cmd, (unsigned long long int)cmd->tag,
     				cmd->sn, cmd->state, scst_get_opcode_name(cmd),
     				(long)(jiffies - cmd->start_time) / HZ,
     				cmd->timeout / HZ, mcmd->cmd_done_wait_count,
    @@ -5649,7 +5657,7 @@ static int scst_abort_task_set(struct scst_mgmt_cmd *mcmd)
     	struct scst_tgt_dev *tgt_dev = mcmd->mcmd_tgt_dev;
     
     	TRACE(TRACE_MGMT, "Aborting task set (lun=%lld, mcmd=%p)",
    -	      (long long unsigned int)tgt_dev->lun, mcmd);
    +	      (unsigned long long int)tgt_dev->lun, mcmd);
     
     	__scst_abort_task_set(mcmd, tgt_dev);
     
    @@ -5681,7 +5689,7 @@ static bool scst_is_cmd_belongs_to_dev(struct scst_cmd *cmd,
     	TRACE_ENTRY();
     
     	TRACE_DBG("Finding match for dev %s and cmd %p (lun %lld)",
    -		  dev->virt_name, cmd, (long long unsigned int)cmd->lun);
    +		  dev->virt_name, cmd, (unsigned long long int)cmd->lun);
     
     	tgt_dev = scst_lookup_tgt_dev(cmd->sess, cmd->lun);
     	res = tgt_dev && tgt_dev->dev == dev;
    @@ -5701,7 +5709,7 @@ static int scst_clear_task_set(struct scst_mgmt_cmd *mcmd)
     	TRACE_ENTRY();
     
     	TRACE(TRACE_MGMT, "Clearing task set (lun=%lld, mcmd=%p)",
    -		(long long unsigned int)mcmd->lun, mcmd);
    +		(unsigned long long int)mcmd->lun, mcmd);
     
     #if 0 /* we are SAM-3 */
     	/*
    @@ -5816,7 +5824,7 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
     		if (cmd == NULL) {
     			TRACE_MGMT_DBG("ABORT TASK: command "
     			      "for tag %llu not found",
    -			      (long long unsigned int)mcmd->tag);
    +			      (unsigned long long int)mcmd->tag);
     			scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_TASK_NOT_EXIST);
     			spin_unlock_irq(&sess->sess_list_lock);
     			res = scst_set_mcmd_next_state(mcmd);
    @@ -5828,7 +5836,7 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
     			mcmd->cpu_cmd_counter = scst_get();
     		spin_unlock_irq(&sess->sess_list_lock);
     		TRACE_DBG("Cmd to abort %p for tag %llu found (tgt_dev %p)",
    -			cmd, (long long unsigned int)mcmd->tag, tgt_dev);
    +			cmd, (unsigned long long int)mcmd->tag, tgt_dev);
     		mcmd->cmd_to_abort = cmd;
     		sBUG_ON(mcmd->mcmd_tgt_dev != NULL);
     		mcmd->mcmd_tgt_dev = tgt_dev;
    @@ -5870,7 +5878,7 @@ static int scst_mgmt_cmd_init(struct scst_mgmt_cmd *mcmd)
     			mcmd->state = SCST_MCMD_STATE_EXEC;
     		else if (rc < 0) {
     			PRINT_ERROR("Corresponding device for LUN %lld not "
    -				"found", (long long unsigned int)mcmd->lun);
    +				"found", (unsigned long long int)mcmd->lun);
     			scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_LUN_NOT_EXIST);
     			res = scst_set_mcmd_next_state(mcmd);
     		} else
    @@ -6000,7 +6008,7 @@ static int scst_lun_reset(struct scst_mgmt_cmd *mcmd)
     	TRACE_ENTRY();
     
     	TRACE(TRACE_MGMT, "Resetting LUN %lld (mcmd %p)",
    -	      (long long unsigned int)tgt_dev->lun, mcmd);
    +	      (unsigned long long int)tgt_dev->lun, mcmd);
     
     	mcmd->needs_unblocking = 1;
     
    @@ -6185,21 +6193,21 @@ static int scst_abort_task(struct scst_mgmt_cmd *mcmd)
     
     	TRACE_MGMT_DBG("Aborting task (cmd %p, sn %d, set %d, tag %llu, "
     		"queue_type %x)", cmd, cmd->sn, cmd->sn_set,
    -		(long long unsigned int)mcmd->tag, cmd->queue_type);
    +		(unsigned long long int)mcmd->tag, cmd->queue_type);
     
     	if (mcmd->lun_set && (mcmd->lun != cmd->lun)) {
     		PRINT_ERROR("ABORT TASK: LUN mismatch: mcmd LUN %llx, "
     			"cmd LUN %llx, cmd tag %llu",
    -			(long long unsigned int)mcmd->lun,
    -			(long long unsigned int)cmd->lun,
    -			(long long unsigned int)mcmd->tag);
    +			(unsigned long long int)mcmd->lun,
    +			(unsigned long long int)cmd->lun,
    +			(unsigned long long int)mcmd->tag);
     		scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_REJECTED);
     	} else if (mcmd->cmd_sn_set &&
     		   (scst_sn_before(mcmd->cmd_sn, cmd->tgt_sn) ||
     		    (mcmd->cmd_sn == cmd->tgt_sn))) {
     		PRINT_ERROR("ABORT TASK: SN mismatch: mcmd SN %x, "
     			"cmd SN %x, cmd tag %llu", mcmd->cmd_sn,
    -			cmd->tgt_sn, (long long unsigned int)mcmd->tag);
    +			cmd->tgt_sn, (unsigned long long int)mcmd->tag);
     		scst_mgmt_cmd_set_status(mcmd, SCST_MGMT_STATUS_REJECTED);
     	} else {
     		spin_lock_irq(&cmd->sess->sess_list_lock);
    @@ -6758,9 +6766,9 @@ int scst_rx_mgmt_fn(struct scst_session *sess,
     	TRACE_MGMT_DBG("sess=%p, tag_set %d, tag %lld, lun_set %d, "
     		"lun=%lld, cmd_sn_set %d, cmd_sn %d, priv %p", sess,
     		params->tag_set,
    -		(long long unsigned int)params->tag,
    +		(unsigned long long int)params->tag,
     		params->lun_set,
    -		(long long unsigned int)mcmd->lun,
    +		(unsigned long long int)mcmd->lun,
     		params->cmd_sn_set,
     		params->cmd_sn,
     		params->tgt_priv);
    @@ -7451,7 +7459,7 @@ static struct scst_cmd *__scst_find_cmd_by_tag(struct scst_session *sess,
     	/* ToDo: hash list */
     
     	TRACE_DBG("%s (sess=%p, tag=%llu)", "Searching in sess cmd list",
    -		  sess, (long long unsigned int)tag);
    +		  sess, (unsigned long long int)tag);
     
     	list_for_each_entry(cmd, &sess->sess_cmd_list,
     			sess_cmd_list_entry) {
    diff --git a/scst_local/in-tree/Makefile-3.17 b/scst_local/in-tree/Makefile-3.17
    new file mode 100644
    index 000000000..8cbbbff63
    --- /dev/null
    +++ b/scst_local/in-tree/Makefile-3.17
    @@ -0,0 +1,2 @@
    +obj-$(CONFIG_SCST_LOCAL) += scst_local.o
    +
    diff --git a/scst_local/in-tree/Makefile-3.18 b/scst_local/in-tree/Makefile-3.18
    new file mode 100644
    index 000000000..8cbbbff63
    --- /dev/null
    +++ b/scst_local/in-tree/Makefile-3.18
    @@ -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 d17fc9d47..8f3e182f8 100644
    --- a/scst_local/scst_local.c
    +++ b/scst_local/scst_local.c
    @@ -229,7 +229,7 @@ static int scst_local_get_sas_transport_id(struct scst_local_sess *sess,
     	tr_id[5]  = 0xEE;
     	tr_id[6]  = 0xDE;
     	tr_id[7]  = 0x40 | ((sess->number >> 4) & 0x0F);
    -	tr_id[8]  = 0x0F | (sess->number & 0xF0);
    +	tr_id[8]  = 0x0F | ((sess->number & 0x0F) << 4);
     	tr_id[9]  = 0xAD;
     	tr_id[10] = 0xE0;
     	tr_id[11] = 0x50;
    @@ -1068,22 +1068,8 @@ static int scst_local_queuecommand_lck(struct scsi_cmnd *SCpnt,
     	sgl_count = scsi_sg_count(SCpnt);
     #endif
     
    -	dir = SCST_DATA_NONE;
    -	switch (SCpnt->sc_data_direction) {
    -	case DMA_TO_DEVICE:
    -		dir = SCST_DATA_WRITE;
    -		scst_cmd_set_expected(scst_cmd, dir, scsi_bufflen(SCpnt));
    -		scst_cmd_set_noio_mem_alloc(scst_cmd);
    -		scst_cmd_set_tgt_sg(scst_cmd, sgl, sgl_count);
    -		break;
    -	case DMA_FROM_DEVICE:
    -		dir = SCST_DATA_READ;
    -		scst_cmd_set_expected(scst_cmd, dir, scsi_bufflen(SCpnt));
    -		scst_cmd_set_noio_mem_alloc(scst_cmd);
    -		scst_cmd_set_tgt_sg(scst_cmd, sgl, sgl_count);
    -		break;
    -	case DMA_BIDIRECTIONAL:
    -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 24))
    +	if (scsi_bidi_cmnd(SCpnt)) {
    +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 24)
     		/* Some of these symbols are only defined after 2.6.24 */
     		dir = SCST_DATA_BIDI;
     		scst_cmd_set_expected(scst_cmd, dir, scsi_bufflen(SCpnt));
    @@ -1093,13 +1079,20 @@ static int scst_local_queuecommand_lck(struct scsi_cmnd *SCpnt,
     		scst_cmd_set_tgt_sg(scst_cmd, scsi_in(SCpnt)->table.sgl,
     			scsi_in(SCpnt)->table.nents);
     		scst_cmd_set_tgt_out_sg(scst_cmd, sgl, sgl_count);
    -		break;
     #endif
    -	case DMA_NONE:
    -	default:
    +	} else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
    +		dir = SCST_DATA_WRITE;
    +		scst_cmd_set_expected(scst_cmd, dir, scsi_bufflen(SCpnt));
    +		scst_cmd_set_noio_mem_alloc(scst_cmd);
    +		scst_cmd_set_tgt_sg(scst_cmd, sgl, sgl_count);
    +	} else if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
    +		dir = SCST_DATA_READ;
    +		scst_cmd_set_expected(scst_cmd, dir, scsi_bufflen(SCpnt));
    +		scst_cmd_set_noio_mem_alloc(scst_cmd);
    +		scst_cmd_set_tgt_sg(scst_cmd, sgl, sgl_count);
    +	} else {
     		dir = SCST_DATA_NONE;
     		scst_cmd_set_expected(scst_cmd, dir, 0);
    -		break;
     	}
     
     	/* Save the correct thing below depending on version */
    diff --git a/scstadmin/init.d/scst b/scstadmin/init.d/scst
    index eb32774b5..99bc1f6ce 100755
    --- a/scstadmin/init.d/scst
    +++ b/scstadmin/init.d/scst
    @@ -211,7 +211,7 @@ unload_scst() {
     start_scst() {
             if [ -e /sys/module/scst -a -e /sys/module/scst/refcnt ]; then
                 echo Already started
    -            return 1
    +            return 0
             fi
     
             parse_scst_conf
    diff --git a/scstadmin/scstadmin.procfs/scst-0.8.22/lib/SCST/SCST.pm b/scstadmin/scstadmin.procfs/scst-0.8.22/lib/SCST/SCST.pm
    index e69905653..4476df3df 100644
    --- a/scstadmin/scstadmin.procfs/scst-0.8.22/lib/SCST/SCST.pm
    +++ b/scstadmin/scstadmin.procfs/scst-0.8.22/lib/SCST/SCST.pm
    @@ -534,7 +534,7 @@ sub openDevice {
     	$rc = !$self->handlerDeviceExists($handler, $device);
     
     	if ($rc) {
    -		$self->{'error'} = "openDevice(): An error occured while opening device '$device'. ".
    +		$self->{'error'} = "openDevice(): An error occurred while opening device '$device'. ".
     		  "See dmesg/kernel log for more information.";
     	}
     
    @@ -575,7 +575,7 @@ sub closeDevice {
     	$rc = $self->handlerDeviceExists($handler, $device);
     
     	if ($rc) {
    -		$self->{'error'} = "closeDevice(): An error occured while closing device '$device'. ".
    +		$self->{'error'} = "closeDevice(): An error occurred while closing device '$device'. ".
     		  "See dmesg/kernel log for more information.";
     	}
     
    @@ -647,7 +647,7 @@ sub setT10DeviceId {
     	my $devices = $self->handlerDevices($handler);
     
     	if ($$devices{$device}->{'T10_DEVICE_ID'} ne $t10_id) {
    -                $self->{'error'} = "setT10DeviceId(): An error occured while setting T10 device ID to '$t10_id' ".
    +                $self->{'error'} = "setT10DeviceId(): An error occurred while setting T10 device ID to '$t10_id' ".
     		  "for device '$device'. See dmesg/kernel log for more information.";
     		return 1;
     	}
    @@ -720,7 +720,7 @@ sub addUser {
     	$rc = !$self->userExists($user, $group);
     
     	if ($rc) {
    -		$self->{'error'} = "addUser(): An error occured while adding user '$user' to group '$group'. ".
    +		$self->{'error'} = "addUser(): An error occurred while adding user '$user' to group '$group'. ".
     		  "See dmesg/kernel log for more information.";
     	}
     
    @@ -752,7 +752,7 @@ sub removeUser {
     	$rc = $self->userExists($user, $group);
     
     	if ($rc) {
    -		$self->{'error'} = "removeUser(): An error occured while removing user '$user' ".
    +		$self->{'error'} = "removeUser(): An error occurred while removing user '$user' ".
     		  "from group '$group'. See dmesg/kernel log for more information.";
     	}
     
    @@ -795,7 +795,7 @@ sub moveUser {
     	$rc = !$self->userExists($user, $toGroup);
     
     	if ($rc) {
    -		$self->{'error'} = "addUser(): An error occured while moving user '$user' from group '$fromGroup' ".
    +		$self->{'error'} = "addUser(): An error occurred while moving user '$user' from group '$fromGroup' ".
     		  "to group '$toGroup'. See dmesg/kernel log for more information.";
     	}
     
    @@ -818,7 +818,7 @@ sub clearUsers {
     	return 0 if ($self->{'debug'});
     
     	if ($rc) {
    -		$self->{'error'} = "clearUsers(): An error occured while clearing users from ".
    +		$self->{'error'} = "clearUsers(): An error occurred while clearing users from ".
     		  "group '$group'. See dmesg/kernel log for more information.";
     		return $rc;
     	}
    @@ -956,7 +956,7 @@ sub assignDeviceToGroup {
     	$rc = !$self->groupDeviceExists($device, $group, $lun);
     
     	if ($rc) {
    -		$self->{'error'} = "assignDeviceToGroup(): An error occured while assigning device '$device' ".
    +		$self->{'error'} = "assignDeviceToGroup(): An error occurred while assigning device '$device' ".
     		  "to group '$group'. See dmesg/kernel log for more information.";
     	}
     
    @@ -1003,7 +1003,7 @@ sub replaceDeviceInGroup {
     	$rc = !$self->groupDeviceExists($newDevice, $group, $lun);
     
     	if ($rc) {
    -		$self->{'error'} = "replaceDeviceInGroup(): An error occured while replacing lun '$lun' with ".
    +		$self->{'error'} = "replaceDeviceInGroup(): An error occurred while replacing lun '$lun' with ".
     		  " device '$newDevice' in group '$group'. See dmesg/kernel log for more information.";
     	}
     
    @@ -1044,7 +1044,7 @@ sub assignDeviceToHandler {
     	$rc = !$self->handlerDeviceExists($handler, $device);
     
     	if ($rc) {
    -		$self->{'error'} = "assignDeviceToHandler(): An error occured while assigning device '$device' ".
    +		$self->{'error'} = "assignDeviceToHandler(): An error occurred while assigning device '$device' ".
     		  "to handler '$handler_name' ($handler). See dmesg/kernel log for more information.";
     	}
     
    @@ -1076,7 +1076,7 @@ sub removeDeviceFromGroup {
     	$rc = $self->groupDeviceExists($device, $group);
     
     	if ($rc) {
    -		$self->{'error'} = "removeDeviceFromGroup(): An error occured while removing device '$device' ".
    +		$self->{'error'} = "removeDeviceFromGroup(): An error occurred while removing device '$device' ".
     		  "from group '$group'. See dmesg/kernel log for more information.";
     	}
     
    @@ -1096,7 +1096,7 @@ sub clearGroupDevices {
     	return 0 if ($self->{'debug'});
     
     	if ($rc) {
    -		$self->{'error'} = "clearGroupDevices(): An error occured while clearing devices from ".
    +		$self->{'error'} = "clearGroupDevices(): An error occurred while clearing devices from ".
     		  "group '$group'. See dmesg/kernel log for more information.";
     		return $rc;
     	}
    @@ -1544,8 +1544,8 @@ Returns: (int) $success
     
     =item SCST::SCST->errorString();
     
    -Contains a description of the last error occured or undef if no error
    -has occured or if this method has already been called once since the
    +Contains a description of the last error occurred or undef if no error
    +has occurred or if this method has already been called once since the
     last error.
     
     Arguments: (void)
    diff --git a/scstadmin/scstadmin.procfs/scstadmin b/scstadmin/scstadmin.procfs/scstadmin
    index 9cb546a3b..f5c4181f0 100755
    --- a/scstadmin/scstadmin.procfs/scstadmin
    +++ b/scstadmin/scstadmin.procfs/scstadmin
    @@ -1074,7 +1074,7 @@ sub applyConfiguration {
     		}
     
     		if (!defined($GROUPS{$group})) {
    -			print "\t-> WARNING: Unable to assign to non-existant group '$group'.\n";
    +			print "\t-> WARNING: Unable to assign to non-existent group '$group'.\n";
     			$errs += 1;
     			next;
     		}
    @@ -1265,7 +1265,7 @@ sub addDevice {
     	my $htype = $SCST->handlerType($_handler);
     
     	if (!$htype) {
    -		print "WARNING: Internal error occured: ".$SCST->errorString()."\n";
    +		print "WARNING: Internal error occurred: ".$SCST->errorString()."\n";
     		return $TRUE;
     	}
     
    @@ -1327,7 +1327,7 @@ sub removeDevice {
     	my $htype = $SCST->handlerType($_handler);
     
     	if (!$htype) {
    -		print "WARNING: Internal error occured: ".$SCST->errorString()."\n";
    +		print "WARNING: Internal error occurred: ".$SCST->errorString()."\n";
     		return $TRUE;
     	}
     
    @@ -1586,7 +1586,7 @@ sub assignDevice {
     	}
     
     	if (!defined($$DEVICES{$device})) {
    -		print "WARNING: Unable to assign non-existant device '$device' to group '$group'.\n";
    +		print "WARNING: Unable to assign non-existent device '$device' to group '$group'.\n";
     		return $TRUE;
     	}
     
    @@ -1632,7 +1632,7 @@ sub replaceDevice {
     	}
     			
     	if (!defined($$DEVICES{$newDevice})) {
    -		print "WARNING: Unable to assign non-existant device '$newDevice' to group '$group'.\n";
    +		print "WARNING: Unable to assign non-existent device '$newDevice' to group '$group'.\n";
     		return $TRUE;
     	}
     
    diff --git a/scstadmin/scstadmin.sysfs/scst-0.9.10/lib/SCST/SCST.pm b/scstadmin/scstadmin.sysfs/scst-0.9.10/lib/SCST/SCST.pm
    index 11370124c..0b2bb7065 100644
    --- a/scstadmin/scstadmin.sysfs/scst-0.9.10/lib/SCST/SCST.pm
    +++ b/scstadmin/scstadmin.sysfs/scst-0.9.10/lib/SCST/SCST.pm
    @@ -176,7 +176,7 @@ SCST_C_TGRP_TGT_SETATTR_FAIL => 172,
     };
     
     my %VERBOSE_ERROR = (
    -(SCST_C_FATAL_ERROR)          => 'A fatal error occured. See "dmesg" for more information.',
    +(SCST_C_FATAL_ERROR)          => 'A fatal error occurred. See "dmesg" for more information.',
     (SCST_C_BAD_ATTRIBUTES)       => 'Bad attributes given for SCST.',
     (SCST_C_ATTRIBUTE_STATIC)     => 'SCST attribute specified is static',
     (SCST_C_SETATTR_FAIL)         => 'Failed to set a SCST attribute. See "dmesg" for more information.',
    diff --git a/srpt/Makefile b/srpt/Makefile
    index 555525018..62e680454 100644
    --- a/srpt/Makefile
    +++ b/srpt/Makefile
    @@ -43,7 +43,7 @@ SRC_FILES=$(wildcard */*.[ch])
     
     # The file Modules.symvers has been renamed in the 2.6.18 kernel to
     # Module.symvers. Find out which name to use by looking in $(KDIR).
    -MODULE_SYMVERS:=$(shell if [ -e $(KDIR)/Module.symvers ]; then \
    +MODULE_SYMVERS:=$(shell if [ -e "$(KDIR)/Module.symvers" ]; then \
     		       echo Module.symvers; else echo Modules.symvers; fi)
     
     # Name of the OFED kernel RPM.
    @@ -52,7 +52,7 @@ OFED_KERNEL_IB_RPM:=$(shell for r in mlnx-ofa_kernel compat-rdma kernel-ib; do r
     # Name of the OFED kernel development RPM.
     OFED_KERNEL_IB_DEVEL_RPM:=$(shell for r in mlnx-ofa_kernel-devel compat-rdma-devel kernel-ib-devel; do rpm -q $$r 2>/dev/null | grep -q "^$$r" && echo $$r && break; done)
     
    -OFED_FLAVOR=$(shell /usr/bin/ofed_info 2>/dev/null | head -n1 | sed -n 's/^MLNX_OFED.*/MOFED/p;s/^OFED-.*/OFED/p')
    +OFED_FLAVOR=$(shell /usr/bin/ofed_info 2>/dev/null | head -n1 | sed -n 's/^\(MLNX_OFED\|OFED-internal\).*/MOFED/p;s/^OFED-.*/OFED/p')
     
     ifneq ($(OFED_KERNEL_IB_RPM),)
     ifeq ($(OFED_KERNEL_IB_RPM),compat-rdma)
    diff --git a/srpt/README b/srpt/README
    index 0d805bdb3..b051f835f 100644
    --- a/srpt/README
    +++ b/srpt/README
    @@ -56,10 +56,10 @@ The ib_srpt kernel module supports the following parameters:
          GUID (e.g. 0002:c903:0005:f34a).
       3. Access control configuration per HCA port and referring to a HCA via its
          port GID (e.g. fe80:0000:0000:0000:0002:c903:0005:f34b).
    -  Mode (1) is choosen if both one_target_per_port and
    -  use_node_guid_in_target_name are false. Mode (2) is choosen if
    +  Mode (1) is chosen if both one_target_per_port and
    +  use_node_guid_in_target_name are false. Mode (2) is chosen if
       one_target_per_port is false and use_node_guid_in_target_name is true. Mode
    -  (3) is choosen if one_target_per_port is true. This last mode is the
    +  (3) is chosen if one_target_per_port is true. This last mode is the
       default mode.
     * rdma_cm_port (number)
       A 16-bit number that specifies the port number to be registered via the
    @@ -362,7 +362,7 @@ Performance Notes - Target Side
       improves performance compared to debug mode.
     
     * When using high-latency storage devices (hard disks), the default value
    -  choosen by SCST for DEVICE.threads_num should be fine. When using
    +  chosen by SCST for DEVICE.threads_num should be fine. When using
       low-latency storage devices though (SSDs), DEVICE.threads_num should be set
       to 1 or 2 in /etc/scst.conf in order to reach optimal performance for small
       block sizes (e.g. 4 KB).
    diff --git a/srpt/patches/kernel-3.17-pre-cflags.patch b/srpt/patches/kernel-3.17-pre-cflags.patch
    new file mode 100644
    index 000000000..3964ee179
    --- /dev/null
    +++ b/srpt/patches/kernel-3.17-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/patches/kernel-3.18-pre-cflags.patch b/srpt/patches/kernel-3.18-pre-cflags.patch
    new file mode 100644
    index 000000000..a6adaf47b
    --- /dev/null
    +++ b/srpt/patches/kernel-3.18-pre-cflags.patch
    @@ -0,0 +1,12 @@
    +diff --git a/Makefile b/Makefile
    +index fd80c6e..09ca4ea 100644
    +--- a/Makefile
    ++++ b/Makefile
    +@@ -390,6 +390,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 437aa5e83..63a861e36 100644
    --- a/srpt/src/ib_srpt.c
    +++ b/srpt/src/ib_srpt.c
    @@ -50,6 +50,7 @@
     #endif
     #endif
     #include "ib_srpt.h"
    +#include "srp-ext.h"
     #define LOG_PREFIX "ib_srpt" /* Prefix for SCST tracing macros. */
     #if defined(INSIDE_KERNEL_TREE)
     #include 
    @@ -118,6 +119,16 @@ module_param(srp_max_rsp_size, int, S_IRUGO | S_IWUSR);
     MODULE_PARM_DESC(srp_max_rsp_size,
     		 "Maximum size of SRP response messages in bytes.");
     
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) \
    +    || defined(RHEL_MAJOR) && RHEL_MAJOR -0 <= 5
    +static int use_srq = true;
    +#else
    +static bool use_srq = true;
    +#endif
    +module_param(use_srq, bool, S_IRUGO | S_IWUSR);
    +MODULE_PARM_DESC(use_srq,
    +		 "Whether or not to use SRQ");
    +
     static int srpt_srq_size = DEFAULT_SRPT_SRQ_SIZE;
     module_param(srpt_srq_size, int, S_IRUGO | S_IWUSR);
     MODULE_PARM_DESC(srpt_srq_size,
    @@ -459,6 +470,7 @@ static void srpt_get_ioc(struct srpt_device *sdev, u32 slot,
     			 struct ib_dm_mad *mad)
     {
     	struct ib_dm_ioc_profile *iocp;
    +	int send_queue_depth;
     
     	iocp = (struct ib_dm_ioc_profile *)mad->data;
     
    @@ -472,6 +484,11 @@ static void srpt_get_ioc(struct srpt_device *sdev, u32 slot,
     		return;
     	}
     
    +	if (sdev->use_srq)
    +		send_queue_depth = sdev->srq_size;
    +	else
    +		send_queue_depth = min(SRPT_RQ_SIZE, sdev->dev_attr.max_qp_wr);
    +
     	memset(iocp, 0, sizeof(*iocp));
     	strcpy(iocp->id_string, SRPT_ID_STRING);
     	iocp->guid = cpu_to_be64(srpt_service_guid);
    @@ -484,7 +501,8 @@ static void srpt_get_ioc(struct srpt_device *sdev, u32 slot,
     	iocp->io_subclass = cpu_to_be16(SRP_IO_SUBCLASS);
     	iocp->protocol = cpu_to_be16(SRP_PROTOCOL);
     	iocp->protocol_version = cpu_to_be16(SRP_PROTOCOL_VERSION);
    -	iocp->send_queue_depth = cpu_to_be16(sdev->srq_size);
    +	iocp->send_queue_depth = cpu_to_be16(send_queue_depth);
    +
     	iocp->rdma_read_depth = 4;
     	iocp->send_size = cpu_to_be32(srp_max_req_size);
     	iocp->rdma_size = cpu_to_be32(min(max(srp_max_rdma_size, 256U),
    @@ -772,21 +790,27 @@ static void srpt_unregister_mad_agent(struct srpt_device *sdev)
      */
     static struct srpt_ioctx *srpt_alloc_ioctx(struct srpt_device *sdev,
     					   int ioctx_size, int dma_size,
    +					   int alignment_offset,
     					   enum dma_data_direction dir)
     {
     	struct srpt_ioctx *ioctx;
     
    -	ioctx = kmalloc(ioctx_size, GFP_KERNEL);
    +	ioctx = kzalloc(ioctx_size, GFP_KERNEL);
     	if (!ioctx)
     		goto err;
     
    -	ioctx->buf = kmalloc(dma_size, GFP_KERNEL);
    +	ioctx->buf = kmalloc(dma_size + alignment_offset, GFP_KERNEL);
     	if (!ioctx->buf)
     		goto err_free_ioctx;
     
    -	ioctx->dma = ib_dma_map_single(sdev->device, ioctx->buf, dma_size, dir);
    +	/* Complain if it is not safe to use zero-copy */
    +	WARN_ON_ONCE(alignment_offset && ((uintptr_t)ioctx->buf & 511));
    +
    +	ioctx->dma = ib_dma_map_single(sdev->device, ioctx->buf,
    +				       dma_size + alignment_offset, dir);
     	if (ib_dma_mapping_error(sdev->device, ioctx->dma))
     		goto err_free_buf;
    +	ioctx->offset = alignment_offset;
     
     	return ioctx;
     
    @@ -822,7 +846,8 @@ static void srpt_free_ioctx(struct srpt_device *sdev, struct srpt_ioctx *ioctx,
      */
     static struct srpt_ioctx **srpt_alloc_ioctx_ring(struct srpt_device *sdev,
     				int ring_size, int ioctx_size,
    -				int dma_size, enum dma_data_direction dir)
    +				int dma_size, int alignment_offset,
    +				enum dma_data_direction dir)
     {
     	struct srpt_ioctx **ring;
     	int i;
    @@ -836,7 +861,8 @@ static struct srpt_ioctx **srpt_alloc_ioctx_ring(struct srpt_device *sdev,
     	if (!ring)
     		goto out;
     	for (i = 0; i < ring_size; ++i) {
    -		ring[i] = srpt_alloc_ioctx(sdev, ioctx_size, dma_size, dir);
    +		ring[i] = srpt_alloc_ioctx(sdev, ioctx_size, dma_size,
    +					   alignment_offset, dir);
     		if (!ring[i])
     			goto err;
     		ring[i]->index = i;
    @@ -845,7 +871,7 @@ static struct srpt_ioctx **srpt_alloc_ioctx_ring(struct srpt_device *sdev,
     
     err:
     	while (--i >= 0)
    -		srpt_free_ioctx(sdev, ring[i], dma_size, dir);
    +		srpt_free_ioctx(sdev, ring[i], dma_size + ring[i]->offset, dir);
     	kfree(ring);
     	ring = NULL;
     out:
    @@ -862,8 +888,12 @@ static void srpt_free_ioctx_ring(struct srpt_ioctx **ioctx_ring,
     {
     	int i;
     
    +	if (!ioctx_ring)
    +		return;
    +
     	for (i = 0; i < ring_size; ++i)
    -		srpt_free_ioctx(sdev, ioctx_ring[i], dma_size, dir);
    +		srpt_free_ioctx(sdev, ioctx_ring[i],
    +				dma_size + ioctx_ring[i]->offset, dir);
     	kfree(ioctx_ring);
     }
     
    @@ -913,16 +943,17 @@ static bool srpt_test_and_set_cmd_state(struct srpt_send_ioctx *ioctx,
     /**
      * srpt_post_recv() - Post an IB receive request.
      */
    -static int srpt_post_recv(struct srpt_device *sdev,
    +static int srpt_post_recv(struct srpt_device *sdev, struct srpt_rdma_ch *ch,
     			  struct srpt_recv_ioctx *ioctx)
     {
     	struct ib_sge list;
     	struct ib_recv_wr wr, *bad_wr;
    +	int status;
     
     	BUG_ON(!sdev);
     	wr.wr_id = encode_wr_id(SRPT_RECV, ioctx->ioctx.index);
     
    -	list.addr = ioctx->ioctx.dma;
    +	list.addr = ioctx->ioctx.dma + ioctx->ioctx.offset;
     	list.length = srp_max_req_size;
     	list.lkey = sdev->mr->lkey;
     
    @@ -930,10 +961,14 @@ static int srpt_post_recv(struct srpt_device *sdev,
     	wr.sg_list = &list;
     	wr.num_sge = 1;
     
    -	return ib_post_srq_recv(sdev->srq, &wr, &bad_wr);
    +	if (sdev->use_srq)
    +		status = ib_post_srq_recv(sdev->srq, &wr, &bad_wr);
    +	else
    +		status = ib_post_recv(ch->qp, &wr, &bad_wr);
    +	return status;
     }
     
    -static int srpt_adjust_srq_wr_avail(struct srpt_rdma_ch *ch, int delta)
    +static int srpt_adjust_sq_wr_avail(struct srpt_rdma_ch *ch, int delta)
     {
     	return atomic_add_return(delta, &ch->sq_wr_avail);
     }
    @@ -952,8 +987,9 @@ static int srpt_post_send(struct srpt_rdma_ch *ch,
     	int ret;
     
     	ret = -ENOMEM;
    -	if (srpt_adjust_srq_wr_avail(ch, -1) < 0) {
    -		PRINT_WARNING("IB send queue full (needed 1)");
    +	if (srpt_adjust_sq_wr_avail(ch, -1) < 0) {
    +		PRINT_WARNING("ch %s-%d send queue full (needed 1)",
    +			      ch->sess_name, ch->qp->qp_num);
     		goto out;
     	}
     
    @@ -975,7 +1011,7 @@ static int srpt_post_send(struct srpt_rdma_ch *ch,
     
     out:
     	if (ret < 0)
    -		srpt_adjust_srq_wr_avail(ch, 1);
    +		srpt_adjust_sq_wr_avail(ch, 1);
     	return ret;
     }
     
    @@ -1012,7 +1048,8 @@ static int srpt_zerolength_write(struct srpt_rdma_ch *ch)
      * Returns -EINVAL when the SRP_CMD request contains inconsistent descriptors;
      * -ENOMEM when memory allocation fails and zero upon success.
      */
    -static int srpt_get_desc_tbl(struct srpt_send_ioctx *ioctx,
    +static int srpt_get_desc_tbl(struct srpt_recv_ioctx *recv_ioctx,
    +			     struct srpt_send_ioctx *ioctx,
     			     struct srp_cmd *srp_cmd,
     			     scst_data_direction *dir, u64 *data_len)
     {
    @@ -1064,7 +1101,38 @@ static int srpt_get_desc_tbl(struct srpt_send_ioctx *ioctx,
     	 * is four times the value specified in bits 3..7. Hence the "& ~3".
     	 */
     	add_cdb_offset = srp_cmd->add_cdb_len & ~3;
    -	if (fmt == SRP_DATA_DESC_DIRECT) {
    +	if (fmt == SRP_DATA_DESC_IMM) {
    +		struct srp_imm_buf *imm_buf = (void *)(srp_cmd->add_data
    +						       + add_cdb_offset);
    +		void *data;
    +		uint32_t header_size;
    +		uint64_t req_size;
    +
    +		header_size = be32_to_cpu(imm_buf->offset);
    +		*data_len = be32_to_cpu(imm_buf->len);
    +		req_size = header_size + *data_len;
    +		data = (void *)srp_cmd + header_size;
    +		if (req_size > srp_max_req_size) {
    +			PRINT_ERROR("Immediate data (length %d + %lld) exceeds"
    +				    " request size %d", header_size, *data_len,
    +				    srp_max_req_size);
    +			ret = -EINVAL;
    +			goto out;
    +		}
    +		if (WARN_ONCE(recv_ioctx->byte_len < req_size,
    +			      "received too few data - %d < %lld\n",
    +			      recv_ioctx->byte_len, req_size)) {
    +			print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16,
    +				       1, srp_cmd, recv_ioctx->byte_len, 1);
    +			ret = -EIO;
    +		}
    +		ioctx->imm_data = data;
    +		ioctx->recv_ioctx = recv_ioctx;
    +		if (((uintptr_t)data & 511) == 0) {
    +			sg_init_one(&ioctx->imm_sg, ioctx->imm_data, *data_len);
    +			scst_cmd_set_tgt_sg(&ioctx->scmnd, &ioctx->imm_sg, 1);
    +		}
    +	} else if (fmt == SRP_DATA_DESC_DIRECT) {
     		ioctx->n_rbuf = 1;
     		ioctx->rbufs = &ioctx->single_rbuf;
     
    @@ -1260,8 +1328,10 @@ static struct srpt_send_ioctx *srpt_get_send_ioctx(struct srpt_rdma_ch *ch)
     	BUG_ON(ioctx->ch != ch);
     	spin_lock_init(&ioctx->spinlock);
     	ioctx->state = SRPT_STATE_NEW;
    +	EXTRACHECKS_WARN_ON(ioctx->recv_ioctx);
     	ioctx->n_rbuf = 0;
     	ioctx->rbufs = NULL;
    +	ioctx->imm_data = NULL;
     	ioctx->n_rdma = 0;
     	ioctx->n_rdma_ius = 0;
     	ioctx->rdma_ius = NULL;
    @@ -1276,12 +1346,15 @@ static struct srpt_send_ioctx *srpt_get_send_ioctx(struct srpt_rdma_ch *ch)
      */
     static void srpt_put_send_ioctx(struct srpt_send_ioctx *ioctx)
     {
    -	struct srpt_rdma_ch *ch;
    +	struct srpt_rdma_ch *ch = ioctx->ch;
    +	struct srpt_recv_ioctx *recv_ioctx = ioctx->recv_ioctx;
     	unsigned long flags;
     
    -	BUG_ON(!ioctx);
    -	ch = ioctx->ch;
    -	BUG_ON(!ch);
    +	if (recv_ioctx) {
    +		EXTRACHECKS_WARN_ON(!list_empty(&recv_ioctx->wait_list));
    +		ioctx->recv_ioctx = NULL;
    +		srpt_post_recv(ch->sport->sdev, ch, recv_ioctx);
    +	}
     
     	/*
     	 * If the WARN_ON() below gets triggered this means that
    @@ -1411,7 +1484,7 @@ static void srpt_handle_send_err_comp(struct srpt_rdma_ch *ch, u64 wr_id,
     	struct srpt_send_ioctx *ioctx = ch->ioctx_ring[index];
     	enum srpt_command_state state = ioctx->state;
     
    -	srpt_adjust_srq_wr_avail(ch, 1);
    +	srpt_adjust_sq_wr_avail(ch, 1);
     
     	switch (state) {
     	case SRPT_STATE_NEED_DATA:
    @@ -1442,7 +1515,7 @@ static void srpt_handle_send_comp(struct srpt_rdma_ch *ch,
     				  struct srpt_send_ioctx *ioctx,
     				  enum scst_exec_context context)
     {
    -	srpt_adjust_srq_wr_avail(ch, 1);
    +	srpt_adjust_sq_wr_avail(ch, 1);
     
     	switch (srpt_set_cmd_state(ioctx, SRPT_STATE_DONE)) {
     	case SRPT_STATE_CMD_RSP_SENT:
    @@ -1472,7 +1545,7 @@ static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch,
     	struct scst_cmd *scmnd = &ioctx->scmnd;
     
     	EXTRACHECKS_WARN_ON(ioctx->n_rdma <= 0);
    -	srpt_adjust_srq_wr_avail(ch, ioctx->n_rdma);
    +	srpt_adjust_sq_wr_avail(ch, ioctx->n_rdma);
     
     	if (opcode == SRPT_RDMA_READ_LAST && scmnd) {
     		if (srpt_test_and_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA,
    @@ -1507,7 +1580,7 @@ static void srpt_handle_rdma_err_comp(struct srpt_rdma_ch *ch,
     				    ioctx->ioctx.index);
     			break;
     		}
    -		srpt_adjust_srq_wr_avail(ch, ioctx->n_rdma);
    +		srpt_adjust_sq_wr_avail(ch, ioctx->n_rdma);
     		if (state == SRPT_STATE_NEED_DATA)
     			srpt_abort_cmd(ioctx, context);
     		else
    @@ -1661,7 +1734,7 @@ static int srpt_handle_cmd(struct srpt_rdma_ch *ch,
     
     	BUG_ON(!send_ioctx);
     
    -	srp_cmd = recv_ioctx->ioctx.buf;
    +	srp_cmd = recv_ioctx->ioctx.buf + recv_ioctx->ioctx.offset;
     
     	scmnd = &send_ioctx->scmnd;
     	ret = scst_rx_cmd_prealloced(scmnd, ch->scst_sess, (u8 *) &srp_cmd->lun,
    @@ -1673,7 +1746,8 @@ static int srpt_handle_cmd(struct srpt_rdma_ch *ch,
     		goto err;
     	}
     
    -	ret = srpt_get_desc_tbl(send_ioctx, srp_cmd, &dir, &data_len);
    +	ret = srpt_get_desc_tbl(recv_ioctx, send_ioctx, srp_cmd, &dir,
    +				&data_len);
     	if (ret) {
     		PRINT_ERROR("0x%llx: parsing SRP descriptor table failed.",
     			    srp_cmd->tag);
    @@ -1739,7 +1813,7 @@ static void srpt_handle_tsk_mgmt(struct srpt_rdma_ch *ch,
     
     	srpt_set_cmd_state(send_ioctx, SRPT_STATE_MGMT);
     
    -	srp_tsk = recv_ioctx->ioctx.buf;
    +	srp_tsk = recv_ioctx->ioctx.buf + recv_ioctx->ioctx.offset;
     
     	TRACE_DBG("recv_tsk_mgmt= %d for task_tag= %lld"
     		  " using tag= %lld ch= %p sess= %p",
    @@ -1829,10 +1903,11 @@ srpt_handle_new_iu(struct srpt_rdma_ch *ch,
     		goto push;
     
     	ib_dma_sync_single_for_cpu(ch->sport->sdev->device,
    -				   recv_ioctx->ioctx.dma, srp_max_req_size,
    +				   recv_ioctx->ioctx.dma,
    +				   recv_ioctx->ioctx.offset + srp_max_req_size,
     				   DMA_FROM_DEVICE);
     
    -	srp_cmd = recv_ioctx->ioctx.buf;
    +	srp_cmd = recv_ioctx->ioctx.buf + recv_ioctx->ioctx.offset;
     	opcode = srp_cmd->opcode;
     	if (opcode == SRP_CMD || opcode == SRP_TSK_MGMT) {
     		send_ioctx = srpt_get_send_ioctx(ch);
    @@ -1867,7 +1942,8 @@ srpt_handle_new_iu(struct srpt_rdma_ch *ch,
     		break;
     	}
     
    -	srpt_post_recv(ch->sport->sdev, recv_ioctx);
    +	if (!send_ioctx || !send_ioctx->recv_ioctx)
    +		srpt_post_recv(ch->sport->sdev, ch, recv_ioctx);
     
     out:
     	return send_ioctx;
    @@ -1883,7 +1959,6 @@ static void srpt_process_rcv_completion(struct ib_cq *cq,
     					struct srpt_rdma_ch *ch,
     					struct ib_wc *wc)
     {
    -	struct srpt_device *sdev = ch->sport->sdev;
     	struct srpt_recv_ioctx *ioctx;
     	u32 index;
     
    @@ -1894,7 +1969,11 @@ static void srpt_process_rcv_completion(struct ib_cq *cq,
     		req_lim = srpt_adjust_req_lim(ch, -1, 0);
     		if (unlikely(req_lim < 0))
     			PRINT_ERROR("req_lim = %d < 0", req_lim);
    -		ioctx = sdev->ioctx_ring[index];
    +		if (ch->sport->sdev->use_srq)
    +			ioctx = ch->sport->sdev->ioctx_ring[index];
    +		else
    +			ioctx = ch->ioctx_recv_ring[index];
    +		ioctx->byte_len = wc->byte_len;
     		srpt_handle_new_iu(ch, ioctx, srpt_new_iu_context);
     	} else {
     		PRINT_INFO("receiving failed for idx %u with status %d",
    @@ -2057,6 +2136,10 @@ static void srpt_unreg_sess(struct scst_session *scst_sess)
     			     sdev, ch->rq_size,
     			     ch->max_rsp_size, DMA_TO_DEVICE);
     
    +	srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_recv_ring,
    +			     sdev, ch->rq_size,
    +			     srp_max_req_size, DMA_FROM_DEVICE);
    +
     	/* Wait until CM callbacks have finished and prevent new callbacks. */
     	if (ch->using_rdma_cm)
     		rdma_destroy_id(ch->rdma_cm.cm_id);
    @@ -2122,7 +2205,7 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch)
     {
     	struct ib_qp_init_attr *qp_init;
     	struct srpt_device *sdev = ch->sport->sdev;
    -	int ret;
    +	int i, ret;
     
     	EXTRACHECKS_WARN_ON(ch->rq_size < 1);
     
    @@ -2151,12 +2234,25 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch)
     		= (void(*)(struct ib_event *, void*))srpt_qp_event;
     	qp_init->send_cq = ch->cq;
     	qp_init->recv_cq = ch->cq;
    -	qp_init->srq = sdev->srq;
     	qp_init->sq_sig_type = IB_SIGNAL_REQ_WR;
     	qp_init->qp_type = IB_QPT_RC;
     	qp_init->cap.max_send_wr = srpt_sq_size;
    -	ch->max_sge = max_t(int, 1, sdev->dev_attr.max_sge - max_sge_delta);
    +	/*
    +	 * For max_sge values > 2 * max_sge_delta, subtract max_sge_delta. For
    +	 * max_sge values < max_sge_delta, use max_sge. For intermediate
    +	 * max_sge values, use max_sge_delta.
    +	 */
    +	ch->max_sge = sdev->dev_attr.max_sge -
    +		min(max_sge_delta,
    +		    max_t(unsigned, 0, sdev->dev_attr.max_sge - max_sge_delta));
     	qp_init->cap.max_send_sge = ch->max_sge;
    +	qp_init->cap.max_recv_sge = ch->max_sge;
    +	if (sdev->use_srq) {
    +		qp_init->srq = sdev->srq;
    +	} else {
    +		qp_init->cap.max_recv_wr = ch->rq_size;
    +		qp_init->cap.max_recv_sge = ch->max_sge;
    +	}
     
     	if (ch->using_rdma_cm) {
     		ret = rdma_create_qp(ch->rdma_cm.cm_id, sdev->pd, qp_init);
    @@ -2182,6 +2278,10 @@ static int srpt_create_ch_ib(struct srpt_rdma_ch *ch)
     
     	TRACE_DBG("qp_num = %#x", ch->qp->qp_num);
     
    +	if (!sdev->use_srq)
    +		for (i = 0; i < ch->rq_size; i++)
    +			srpt_post_recv(sdev, ch, ch->ioctx_recv_ring[i]);
    +
     	atomic_set(&ch->sq_wr_avail, qp_init->cap.max_send_wr);
     
     	TRACE_DBG("%s: max_cqe= %d max_sge= %d sq_size = %d ch= %p", __func__,
    @@ -2465,7 +2565,8 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
     		   " %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x,"
     		   " t_port_id %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x and"
     		   " it_iu_len %d on port %d"
    -		   " (guid=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x)",
    +		   " (guid=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x);"
    +		   " pkey %#04x",
     	    be16_to_cpu(*(__be16 *)&req->initiator_port_id[0]),
     	    be16_to_cpu(*(__be16 *)&req->initiator_port_id[2]),
     	    be16_to_cpu(*(__be16 *)&req->initiator_port_id[4]),
    @@ -2491,7 +2592,8 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
     	    be16_to_cpu(raw_port_gid[4]),
     	    be16_to_cpu(raw_port_gid[5]),
     	    be16_to_cpu(raw_port_gid[6]),
    -	    be16_to_cpu(raw_port_gid[7]));
    +	    be16_to_cpu(raw_port_gid[7]),
    +	    be16_to_cpu(pkey));
     
     	nexus = srpt_get_nexus(srpt_tgt, req->initiator_port_id,
     			       req->target_port_id);
    @@ -2568,8 +2670,10 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
     	ch->ioctx_ring = (struct srpt_send_ioctx **)
     		srpt_alloc_ioctx_ring(ch->sport->sdev, ch->rq_size,
     				      sizeof(*ch->ioctx_ring[0]),
    -				      ch->max_rsp_size, DMA_TO_DEVICE);
    +				      ch->max_rsp_size, 0, DMA_TO_DEVICE);
     	if (!ch->ioctx_ring) {
    +		PRINT_ERROR("rejected SRP_LOGIN_REQ because creating"
    +			    " a new QP SQ ring failed.");
     		rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
     		goto free_ch;
     	}
    @@ -2579,6 +2683,23 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
     		ch->ioctx_ring[i]->ch = ch;
     		list_add_tail(&ch->ioctx_ring[i]->free_list, &ch->free_list);
     	}
    +	if (!sdev->use_srq) {
    +		ch->ioctx_recv_ring = (struct srpt_recv_ioctx **)
    +			srpt_alloc_ioctx_ring(ch->sport->sdev, ch->rq_size,
    +					      sizeof(*ch->ioctx_recv_ring[0]),
    +					      srp_max_req_size,
    +					      DATA_ALIGNMENT_OFFSET,
    +					      DMA_FROM_DEVICE);
    +		if (!ch->ioctx_recv_ring) {
    +			PRINT_ERROR("rejected SRP_LOGIN_REQ because creating"
    +				    " a new QP RQ ring failed.");
    +			rej->reason =
    +			    cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
    +			goto free_ring;
    +		}
    +		for (i = 0; i < ch->rq_size; i++)
    +			INIT_LIST_HEAD(&ch->ioctx_recv_ring[i]->wait_list);
    +	}
     
     	ch->comp_vector = srpt_next_comp_vector(srpt_tgt);
     
    @@ -2587,7 +2708,7 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
     		rej->reason = cpu_to_be32(SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES);
     		PRINT_ERROR("rejected SRP_LOGIN_REQ because creating"
     			    " a new RDMA channel failed.");
    -		goto free_ring;
    +		goto free_recv_ring;
     	}
     
     	if (one_target_per_port) {
    @@ -2683,11 +2804,12 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
     	/* create srp_login_response */
     	rsp->opcode = SRP_LOGIN_RSP;
     	rsp->tag = req->tag;
    -	rsp->max_it_iu_len = req->req_it_iu_len;
    +	rsp->max_it_iu_len = cpu_to_be32(srp_max_req_size);
     	rsp->max_ti_iu_len = req->req_it_iu_len;
     	ch->max_ti_iu_len = it_iu_len;
     	rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
    -				   SRP_BUF_FORMAT_INDIRECT);
    +				   SRP_BUF_FORMAT_INDIRECT |
    +				   SRP_BUF_FORMAT_IMM);
     	rsp->req_lim_delta = cpu_to_be32(ch->rq_size);
     	ch->req_lim = ch->rq_size;
     	ch->req_lim_delta = 0;
    @@ -2747,6 +2869,11 @@ unreg_ch:
     destroy_ib:
     	srpt_destroy_ch_ib(ch);
     
    +free_recv_ring:
    +	srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_recv_ring,
    +			     ch->sport->sdev, ch->rq_size,
    +			     srp_max_req_size, DMA_FROM_DEVICE);
    +
     free_ring:
     	srpt_free_ioctx_ring((struct srpt_ioctx **)ch->ioctx_ring,
     			     ch->sport->sdev, ch->rq_size,
    @@ -2859,10 +2986,22 @@ static int srpt_rdma_cm_req_recv(struct rdma_cm_id *cm_id,
     				cm_id->route.path_rec->pkey, &req, src_addr);
     }
     
    -static void srpt_cm_rej_recv(struct srpt_rdma_ch *ch)
    +static void srpt_cm_rej_recv(struct srpt_rdma_ch *ch,
    +			     enum ib_cm_rej_reason reason,
    +			     const u8 *private_data,
    +			     u8 private_data_len)
     {
    -	PRINT_INFO("Received CM REJ for ch %s-%d.", ch->sess_name,
    -		   ch->qp->qp_num);
    +	char *priv = kmalloc(private_data_len * 3 + 1, GFP_KERNEL);
    +	int i;
    +
    +	if (priv) {
    +		priv[0] = '\0';
    +		for (i = 0; i < private_data_len; i++)
    +			sprintf(priv + 3 * i, "%02x ", private_data[i]);
    +	}
    +	PRINT_INFO("Received CM REJ for ch %s-%d; reason %d; private data %s.",
    +		   ch->sess_name, ch->qp->qp_num, reason, priv ? : "(?)");
    +	kfree(priv);
     }
     
     static void srpt_check_timeout(struct srpt_rdma_ch *ch)
    @@ -2989,7 +3128,9 @@ static int srpt_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
     					  event->private_data);
     		break;
     	case IB_CM_REJ_RECEIVED:
    -		srpt_cm_rej_recv(ch);
    +		srpt_cm_rej_recv(ch, event->param.rej_rcvd.reason,
    +				 event->private_data,
    +				 IB_CM_REJ_PRIVATE_DATA_SIZE);
     		break;
     	case IB_CM_RTU_RECEIVED:
     	case IB_CM_USER_ESTABLISHED:
    @@ -3033,7 +3174,9 @@ static int srpt_rdma_cm_handler(struct rdma_cm_id *cm_id,
     		ret = srpt_rdma_cm_req_recv(cm_id, event);
     		break;
     	case RDMA_CM_EVENT_REJECTED:
    -		srpt_cm_rej_recv(ch);
    +		srpt_cm_rej_recv(ch, event->status,
    +				 event->param.conn.private_data,
    +				 event->param.conn.private_data_len);
     		break;
     	case RDMA_CM_EVENT_ESTABLISHED:
     		srpt_cm_rtu_recv(ch);
    @@ -3201,7 +3344,7 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch,
     	dma_len = ib_sg_dma_len(dev, &sg[0]);
     	dma_addr = ib_sg_dma_address(dev, &sg[0]);
     
    -	/* this second loop is really mapped sg_addres to rdma_iu->ib_sge */
    +	/* this second loop is really mapped sg_address to rdma_iu->ib_sge */
     	for (i = 0, j = 0, cur_sg = sg;
     	     j < count && i < ioctx->n_rbuf && tsize > 0; ++i, ++riu, ++db) {
     		rsize = be32_to_cpu(db->len);
    @@ -3266,6 +3409,10 @@ static void srpt_unmap_sg_to_ib_sge(struct srpt_rdma_ch *ch,
     
     	EXTRACHECKS_BUG_ON(!ch);
     	EXTRACHECKS_BUG_ON(!ioctx);
    +
    +	if (ioctx->imm_data)
    +		return;
    +
     	EXTRACHECKS_BUG_ON(ioctx->n_rdma && !ioctx->rdma_ius);
     
     	if (ioctx->rdma_ius != (void *)ioctx->rdma_ius_buf)
    @@ -3305,10 +3452,10 @@ static int srpt_perform_rdmas(struct srpt_rdma_ch *ch,
     
     	if (dir == SCST_DATA_WRITE) {
     		ret = -ENOMEM;
    -		sq_wr_avail = srpt_adjust_srq_wr_avail(ch, -n_rdma);
    +		sq_wr_avail = srpt_adjust_sq_wr_avail(ch, -n_rdma);
     		if (sq_wr_avail < 0) {
    -			PRINT_WARNING("IB send queue full (needed %d)",
    -				      n_rdma);
    +			PRINT_WARNING("ch %s-%d send queue full (needed %d)",
    +				      ch->sess_name, ch->qp->qp_num, n_rdma);
     			goto out;
     		}
     	}
    @@ -3374,7 +3521,7 @@ static int srpt_perform_rdmas(struct srpt_rdma_ch *ch,
     
     out:
     	if (unlikely(dir == SCST_DATA_WRITE && ret < 0))
    -		srpt_adjust_srq_wr_avail(ch, n_rdma);
    +		srpt_adjust_sq_wr_avail(ch, n_rdma);
     	return ret;
     }
     
    @@ -3391,6 +3538,30 @@ static int srpt_xfer_data(struct srpt_rdma_ch *ch,
     {
     	int ret;
     
    +	if (ioctx->imm_data) {
    +		BUG_ON(!srpt_test_and_set_cmd_state(ioctx, SRPT_STATE_NEED_DATA,
    +						    SRPT_STATE_DATA_IN));
    +		if (unlikely(!scst_cmd_get_tgt_data_buff_alloced(scmnd))) {
    +			unsigned offset = 0, len;
    +			uint8_t *buf;
    +
    +			len = scst_get_buf_first(scmnd, &buf);
    +			while (len > 0) {
    +				memcpy(buf, ioctx->imm_data + offset, len);
    +				offset += len;
    +				len = scst_get_buf_next(scmnd, &buf);
    +			}
    +			WARN_ON_ONCE(offset !=
    +				scst_cmd_get_expected_transfer_len(scmnd));
    +		}
    +		scst_rx_data(scmnd, SCST_RX_STATUS_SUCCESS,
    +			     in_irq() ? SCST_CONTEXT_TASKLET :
    +			     in_softirq() ? SCST_CONTEXT_DIRECT_ATOMIC :
    +			     SCST_CONTEXT_DIRECT);
    +		ret = SCST_TGT_RES_SUCCESS;
    +		goto out;
    +	}
    +
     	ret = srpt_map_sg_to_ib_sge(ch, ioctx, scmnd);
     	if (ret) {
     		PRINT_ERROR("%s[%d] ret=%d", __func__, __LINE__, ret);
    @@ -4173,14 +4344,37 @@ static void srpt_add_one(struct ib_device *device)
     	srq_attr.srq_type = IB_SRQT_BASIC;
     #endif
     
    -	sdev->srq = ib_create_srq(sdev->pd, &srq_attr);
    +	sdev->srq = use_srq ? ib_create_srq(sdev->pd, &srq_attr) :
    +		ERR_PTR(-ENOSYS);
     	if (IS_ERR(sdev->srq)) {
    -		PRINT_ERROR("ib_create_srq() failed: %ld", PTR_ERR(sdev->srq));
    -		goto err_mr;
    -	}
    +		TRACE_DBG("%s: ib_create_srq() failed: %ld", __func__,
    +			  PTR_ERR(sdev->srq));
     
    -	TRACE_DBG("%s: create SRQ #wr= %d max_allow=%d dev= %s", __func__,
    -		  sdev->srq_size, sdev->dev_attr.max_srq_wr, device->name);
    +		/* SRQ not supported. */
    +		sdev->use_srq = false;
    +	} else {
    +		TRACE_DBG("%s: create SRQ #wr= %d max_allow=%d dev= %s",
    +			  __func__, sdev->srq_size, sdev->dev_attr.max_srq_wr,
    +			  device->name);
    +
    +		sdev->use_srq = true;
    +
    +		sdev->ioctx_ring = (struct srpt_recv_ioctx **)
    +			srpt_alloc_ioctx_ring(sdev, sdev->srq_size,
    +					      sizeof(*sdev->ioctx_ring[0]),
    +					      srp_max_req_size,
    +					      DATA_ALIGNMENT_OFFSET,
    +					      DMA_FROM_DEVICE);
    +		if (!sdev->ioctx_ring) {
    +			PRINT_ERROR("srpt_alloc_ioctx_ring() failed");
    +			goto err_mr;
    +		}
    +
    +		for (i = 0; i < sdev->srq_size; ++i) {
    +			INIT_LIST_HEAD(&sdev->ioctx_ring[i]->wait_list);
    +			srpt_post_recv(sdev, NULL, sdev->ioctx_ring[i]);
    +		}
    +	}
     
     	if (!srpt_service_guid)
     		srpt_service_guid = be64_to_cpu(device->node_guid) &
    @@ -4189,7 +4383,7 @@ static void srpt_add_one(struct ib_device *device)
     	cm_id = ib_create_cm_id(device, srpt_cm_handler, sdev);
     	if (IS_ERR(cm_id)) {
     		PRINT_ERROR("ib_create_cm_id() failed: %ld", PTR_ERR(cm_id));
    -		goto err_srq;
    +		goto err_ring;
     	}
     	sdev->cm_id = cm_id;
     
    @@ -4220,20 +4414,6 @@ static void srpt_add_one(struct ib_device *device)
     		goto err_cm;
     	}
     
    -	sdev->ioctx_ring = (struct srpt_recv_ioctx **)
    -		srpt_alloc_ioctx_ring(sdev, sdev->srq_size,
    -				      sizeof(*sdev->ioctx_ring[0]),
    -				      srp_max_req_size, DMA_FROM_DEVICE);
    -	if (!sdev->ioctx_ring) {
    -		PRINT_ERROR("srpt_alloc_ioctx_ring() failed");
    -		goto err_event;
    -	}
    -
    -	for (i = 0; i < sdev->srq_size; ++i) {
    -		INIT_LIST_HEAD(&sdev->ioctx_ring[i]->wait_list);
    -		srpt_post_recv(sdev, sdev->ioctx_ring[i]);
    -	}
    -
     	WARN_ON(sdev->device->phys_port_cnt > ARRAY_SIZE(sdev->port));
     
     	for (i = 1; i <= sdev->device->phys_port_cnt; i++) {
    @@ -4254,7 +4434,7 @@ static void srpt_add_one(struct ib_device *device)
     		if (srpt_refresh_port(sport)) {
     			PRINT_ERROR("MAD registration failed for %s-%d.",
     				    sdev->device->name, i);
    -			goto err_ring;
    +			goto err_event;
     		}
     	}
     
    @@ -4265,16 +4445,16 @@ out:
     	TRACE_EXIT();
     	return;
     
    -err_ring:
    -	srpt_free_ioctx_ring((struct srpt_ioctx **)sdev->ioctx_ring, sdev,
    -			     sdev->srq_size, srp_max_req_size,
    -			     DMA_FROM_DEVICE);
     err_event:
     	ib_unregister_event_handler(&sdev->event_handler);
     err_cm:
     	ib_destroy_cm_id(sdev->cm_id);
    -err_srq:
    -	ib_destroy_srq(sdev->srq);
    +err_ring:
    +	srpt_free_ioctx_ring((struct srpt_ioctx **)sdev->ioctx_ring, sdev,
    +			     sdev->srq_size, srp_max_req_size,
    +			     DMA_FROM_DEVICE);
    +	if (sdev->use_srq)
    +		ib_destroy_srq(sdev->srq);
     err_mr:
     	ib_dereg_mr(sdev->mr);
     err_pd:
    @@ -4347,13 +4527,15 @@ static void srpt_remove_one(struct ib_device *device)
     		sdev->srpt_tgt.scst_tgt = NULL;
     	}
     
    -	ib_destroy_srq(sdev->srq);
    -	ib_dereg_mr(sdev->mr);
    -	ib_dealloc_pd(sdev->pd);
    -
     	srpt_free_ioctx_ring((struct srpt_ioctx **)sdev->ioctx_ring, sdev,
     			     sdev->srq_size, srp_max_req_size, DMA_FROM_DEVICE);
     	sdev->ioctx_ring = NULL;
    +
    +	if (sdev->use_srq)
    +		ib_destroy_srq(sdev->srq);
    +	ib_dereg_mr(sdev->mr);
    +	ib_dealloc_pd(sdev->pd);
    +
     	kfree(sdev);
     
     	TRACE_EXIT();
    @@ -4428,6 +4610,8 @@ static int __init srpt_init_module(void)
     {
     	int ret;
     
    +	BUILD_BUG_ON(sizeof(struct srp_imm_buf) != 8);
    +
     	ret = -EINVAL;
     	if (srp_max_req_size < MIN_MAX_REQ_SIZE) {
     		PRINT_ERROR("invalid value %d for kernel module parameter"
    diff --git a/srpt/src/ib_srpt.h b/srpt/src/ib_srpt.h
    index 49d2a9b9f..30abefbeb 100644
    --- a/srpt/src/ib_srpt.h
    +++ b/srpt/src/ib_srpt.h
    @@ -56,6 +56,7 @@
     #endif
     #include 
     #include 
    +#include "srp-ext.h"
     #include "ib_dm_mad.h"
     
     /*
    @@ -128,10 +129,9 @@ enum {
     	MAX_SRPT_SRQ_SIZE = 65535,
     
     	MIN_MAX_REQ_SIZE = 996,
    -	DEFAULT_MAX_REQ_SIZE
    -		= sizeof(struct srp_cmd)/*48*/
    -		+ sizeof(struct srp_indirect_buf)/*20*/
    -		+ 255 * sizeof(struct srp_direct_buf)/*16*/,
    +	SRP_IMM_DATA_OUT_OFFSET = 80,
    +	DEFAULT_MAX_REQ_SIZE = SRP_IMM_DATA_OUT_OFFSET + 8192,
    +	DATA_ALIGNMENT_OFFSET = 512 - SRP_IMM_DATA_OUT_OFFSET,
     
     	MIN_MAX_RSP_SIZE = sizeof(struct srp_rsp)/*36*/ + 4,
     	DEFAULT_MAX_RSP_SIZE = 256, /* leaves 220 bytes for sense data */
    @@ -207,13 +207,15 @@ enum srpt_command_state {
     
     /**
      * struct srpt_ioctx - Shared SRPT I/O context information.
    - * @buf:   Pointer to the buffer.
    - * @dma:   DMA address of the buffer.
    - * @index: Index of the I/O context in its ioctx_ring array.
    + * @buf:    Pointer to the buffer.
    + * @dma:    DMA address of the buffer.
    + * @offset: Offset of the first byte in @buf and @dma that is actually used.
    + * @index:  Index of the I/O context in its ioctx_ring array.
      */
     struct srpt_ioctx {
     	void			*buf;
     	dma_addr_t		dma;
    +	uint32_t		offset;
     	uint32_t		index;
     };
     
    @@ -221,10 +223,12 @@ struct srpt_ioctx {
      * struct srpt_recv_ioctx - SRPT receive I/O context.
      * @ioctx:     See above.
      * @wait_list: Node for insertion in srpt_rdma_ch.cmd_wait_list.
    + * @byte_len:  Number of bytes in @ioctx.buf.
      */
     struct srpt_recv_ioctx {
     	struct srpt_ioctx	ioctx;
     	struct list_head	wait_list;
    +	int			byte_len;
     };
     
     /**
    @@ -239,7 +243,10 @@ struct srpt_tsk_mgmt {
      * struct srpt_send_ioctx - SRPT send I/O context.
      * @ioctx:       See above.
      * @ch:          Channel pointer.
    + * @recv_ioctx:  Receive I/O context associated with this send I/O context.
      * @rdma_ius:    Array with information about the RDMA mapping.
    + * @imm_data:    Pointer to immediate data when using the immediate data format.
    + * @imm_sg:      Scatterlist for immediate data.
      * @rbufs:       Pointer to SRP data buffer array.
      * @single_rbuf: SRP data buffer if the command has only a single buffer.
      * @sg:          Pointer to sg-list associated with this I/O context.
    @@ -263,7 +270,10 @@ struct srpt_tsk_mgmt {
     struct srpt_send_ioctx {
     	struct srpt_ioctx	ioctx;
     	struct srpt_rdma_ch	*ch;
    +	struct srpt_recv_ioctx	*recv_ioctx;
     	struct rdma_iu		*rdma_ius;
    +	void			*imm_data;
    +	struct scatterlist	imm_sg;
     	struct srp_direct_buf	*rbufs;
     	struct srp_direct_buf	single_rbuf;
     	struct scatterlist	*sg;
    @@ -366,6 +376,7 @@ struct srpt_rdma_ch {
     	spinlock_t		spinlock;
     	struct list_head	free_list;
     	struct srpt_send_ioctx	**ioctx_ring;
    +	struct srpt_recv_ioctx	**ioctx_recv_ring;
     	struct ib_wc		wc[16];
     	enum rdma_ch_state	state;
     	struct list_head	list;
    @@ -448,6 +459,7 @@ struct srpt_port {
      * @dev_attr:      Attributes of the InfiniBand device as obtained during the
      *                 ib_client.add() callback.
      * @srq_size:      SRQ size.
    + * @use_srq:       Whether or not to use SRQ.
      * @ioctx_ring:    Per-HCA SRQ.
      * @port:	   Information about the ports owned by this HCA.
      * @event_handler: Per-HCA asynchronous IB event handler.
    @@ -462,6 +474,7 @@ struct srpt_device {
     	struct ib_cm_id		*cm_id;
     	struct ib_device_attr	dev_attr;
     	int			srq_size;
    +	bool			use_srq;
     	struct srpt_recv_ioctx	**ioctx_ring;
     	struct srpt_port	port[2];
     	struct ib_event_handler	event_handler;
    diff --git a/srpt/src/srp-ext.h b/srpt/src/srp-ext.h
    new file mode 100644
    index 000000000..3e6752cec
    --- /dev/null
    +++ b/srpt/src/srp-ext.h
    @@ -0,0 +1,22 @@
    +/*
    + * Extensions to the SRPr16a protocol
    + *
    + * Copyright (C) 2013 Fusion-io, Inc. All rights reserved.
    + */
    +
    +#ifndef _SRP_EXT_H_
    +#define _SRP_EXT_H_
    +
    +/*
    + * Data is present as immediate data instead of being referred to via a
    + * descriptor.
    + */
    +enum { SRP_DATA_DESC_IMM = 3 };
    +enum { SRP_BUF_FORMAT_IMM = 1 << 3 };
    +
    +struct srp_imm_buf {
    +	__be32	len;
    +	__be32	offset;
    +};
    +
    +#endif /* _SRP_EXT_H_ */
    diff --git a/usr/fileio/common.c b/usr/fileio/common.c
    index ac98120af..75d09a7d7 100644
    --- a/usr/fileio/common.c
    +++ b/usr/fileio/common.c
    @@ -209,7 +209,7 @@ static int do_exec(struct vdisk_cmd *vcmd)
     
     #ifdef DEBUG_SENSE
     	if ((random() % 100000) == 75) {
    -		set_cmd_error(vcmd, SCST_LOAD_SENSE(scst_sense_hardw_error));
    +		set_cmd_error(vcmd, SCST_LOAD_SENSE(scst_sense_internal_failure));
     		goto out;
     	}
     #endif
    diff --git a/www/comparison.html b/www/comparison.html
    index 561be60d9..5f00293ea 100644
    --- a/www/comparison.html
    +++ b/www/comparison.html
    @@ -130,7 +130,7 @@ transfer values (Wide (parallel) SCSI, SAS)			 + 		 - 
     
     Automatic sessions reassignment (changes in the
    -access control immediatelly seen by initiators)		 + 		 - 		 - 		 - 
    +access control immediately seen by initiators)		 + 		 - 		 - 		 - 
     
                                                                                                 
     Support for Asynchronous Event Notifications
    @@ -243,22 +243,22 @@ apply changes in the config file on fly without any restarts	 scsta
     iSCSI					 + 		 + 		 + 		 + 
                                                                                                                                
                                                                                                 
    -QLogic (Fibre Channel and FCoE)		 + 		 - 		 - 		 Preliminary
    +QLogic (Fibre Channel and FCoE)		 + 		 - 		 - 		 +
     
     
    -Emulex (Fibre Channel and FCoE)		 + 		 - 		 - 		 - 
    +Emulex (Fibre Channel and FCoE)		 + 		 - 		 - 		 + 
     
                                                                                                                                
     SRP					 + 		 - 		 - 		 Preliminary 
                                                                                                                                
                                                                                                                                 
    -iSER					 - 		 + 		 - 		 Preliminary 		
    +iSER					 + 		 + 		 - 		 + 		
      
                                                                                                                               
     Marvell (SAS)				 Beta 		 - 		 - 		 - 		
     
     
    -FCoE					 Beta 		Under
    +FCoE					 + 		Under
     									 			 development	 - 		 Alpha