mirror of
https://github.com/SCST-project/scst.git
synced 2026-07-19 06:22:22 +00:00
Merge branch 'svn-trunk' r6192
Conflicts: scst/include/scst.h scst/src/dev_handlers/scst_vdisk.c
This commit is contained in:
@@ -50,6 +50,7 @@ SRP_DIR=srpt
|
||||
SCST_LOCAL_DIR=scst_local
|
||||
MVSAS_DIR=mvsas_tgt
|
||||
FCST_DIR=fcst
|
||||
EMULEX_DIR=emulex
|
||||
|
||||
ISCSI_DIR=iscsi-scst
|
||||
|
||||
@@ -94,6 +95,12 @@ help:
|
||||
@echo " iscsi_install : ISCSI target: install"
|
||||
@echo " iscsi_uninstall : ISCSI target: uninstall"
|
||||
@echo ""
|
||||
@echo " emulex : make Emulex target"
|
||||
@echo " emulex_clean : Emulex target: clean "
|
||||
@echo " emulex_extraclean : Emulex target: clean + clean dependencies"
|
||||
@echo " emulex_install : Emulex target: install"
|
||||
@echo " emulex_uninstall : Emulex target: uninstall"
|
||||
@echo ""
|
||||
@echo " lsi : make LSI MPT target"
|
||||
@echo " lsi_clean : lsi target: clean "
|
||||
@echo " lsi_extraclean : lsi target: clean + clean dependencies"
|
||||
@@ -148,6 +155,7 @@ all:
|
||||
@if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(SCST_LOCAL_DIR) ]; then cd $(SCST_LOCAL_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(EMULEX_DIR) ]; then cd $(EMULEX_DIR) && $(MAKE) $@; fi
|
||||
|
||||
install:
|
||||
cd $(SCST_DIR) && $(MAKE) $@
|
||||
@@ -159,6 +167,7 @@ install:
|
||||
@if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(SCST_LOCAL_DIR) ]; then cd $(SCST_LOCAL_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(EMULEX_DIR) ]; then cd $(EMULEX_DIR) && $(MAKE) $@; fi
|
||||
|
||||
uninstall:
|
||||
cd $(SCST_DIR) && $(MAKE) $@
|
||||
@@ -170,6 +179,7 @@ uninstall:
|
||||
@if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(SCST_LOCAL_DIR) ]; then cd $(SCST_LOCAL_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(EMULEX_DIR) ]; then cd $(EMULEX_DIR) && $(MAKE) $@; fi
|
||||
|
||||
clean:
|
||||
cd $(SCST_DIR) && $(MAKE) $@
|
||||
@@ -183,6 +193,7 @@ clean:
|
||||
@if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(SCST_LOCAL_DIR) ]; then cd $(SCST_LOCAL_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(EMULEX_DIR) ]; then cd $(EMULEX_DIR) && $(MAKE) $@; fi
|
||||
|
||||
extraclean:
|
||||
-rm -f TAGS
|
||||
@@ -197,6 +208,7 @@ extraclean:
|
||||
@if [ -d $(ISCSI_DIR) ]; then cd $(ISCSI_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(USR_DIR) ]; then cd $(USR_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(SCST_LOCAL_DIR) ]; then cd $(SCST_LOCAL_DIR) && $(MAKE) $@; fi
|
||||
@if [ -d $(EMULEX_DIR) ]; then cd $(EMULEX_DIR) && $(MAKE) $@; fi
|
||||
|
||||
tags:
|
||||
find . -type f -name "*.[ch]" | ctags --c-kinds=+p --fields=+iaS --extra=+q -e -L-
|
||||
@@ -290,6 +302,21 @@ iscsi_clean:
|
||||
iscsi_extraclean:
|
||||
cd $(ISCSI_DIR) && $(MAKE) extraclean
|
||||
|
||||
emulex:
|
||||
cd $(EMULEX_DIR) && $(MAKE) all
|
||||
|
||||
emulex_install:
|
||||
cd $(EMULEX_DIR) && $(MAKE) install
|
||||
|
||||
emulex_uninstall:
|
||||
cd $(EMULEX_DIR) && $(MAKE) uninstall
|
||||
|
||||
emulex_clean:
|
||||
cd $(EMULEX_DIR) && $(MAKE) clean
|
||||
|
||||
emulex_extraclean:
|
||||
cd $(EMULEX_DIR) && $(MAKE) extraclean
|
||||
|
||||
lsi:
|
||||
cd $(LSI_DIR) && $(MAKE) all
|
||||
|
||||
@@ -506,6 +533,7 @@ disable_proc: extraclean
|
||||
qla_old qla_old_install qla_old_uninstall qla_old_clean qla_old_extraclean \
|
||||
lsi lsi_install lsi_uninstall lsi_clean lsi_extraclean \
|
||||
iscsi iscsi_install iscsi_uninstall iscsi_clean iscsi_extraclean \
|
||||
emulex emulex_install emulex_uninstall emulex_clean emulex_extraclean \
|
||||
scst scst_install scst_uninstall scst_clean scst_extraclean \
|
||||
docs docs_clean docs_extraclean \
|
||||
scstadm scstadm_install scstadm_uninstall scstadm_clean scstadm_extraclean \
|
||||
|
||||
+2
-1
@@ -57,7 +57,8 @@ void ft_cmd_dump(struct scst_cmd *cmd, const char *caller)
|
||||
prefix, cmd, fcmd->write_data_len, fcmd->read_data_len);
|
||||
pr_info("%s exp_dir %x exp_xfer_len %d exp_in_len %d\n",
|
||||
prefix, cmd->expected_data_direction,
|
||||
cmd->expected_transfer_len, cmd->expected_out_transfer_len);
|
||||
cmd->expected_transfer_len_full,
|
||||
cmd->expected_out_transfer_len);
|
||||
pr_info("%s dir %x data_len %lld bufflen %d out_bufflen %d\n",
|
||||
prefix, cmd->data_direction, cmd->data_len,
|
||||
cmd->bufflen, cmd->out_bufflen);
|
||||
|
||||
@@ -1270,18 +1270,18 @@ void iscsi_dump_pdu(struct iscsi_pdu *pdu)
|
||||
int i;
|
||||
|
||||
buf = (void *)&pdu->bhs;
|
||||
printk(KERN_DEBUG "BHS: (%p,%zd)\n", buf, sizeof(pdu->bhs));
|
||||
pr_debug("BHS: (%p,%zd)\n", buf, sizeof(pdu->bhs));
|
||||
for (i = 0; i < (int)sizeof(pdu->bhs); i++)
|
||||
iscsi_dump_char(*buf++, text, &pos);
|
||||
iscsi_dump_char(-1, text, &pos);
|
||||
|
||||
buf = (void *)pdu->ahs;
|
||||
printk(KERN_DEBUG "AHS: (%p,%d)\n", buf, pdu->ahssize);
|
||||
pr_debug("AHS: (%p,%d)\n", buf, pdu->ahssize);
|
||||
for (i = 0; i < pdu->ahssize; i++)
|
||||
iscsi_dump_char(*buf++, text, &pos);
|
||||
iscsi_dump_char(-1, text, &pos);
|
||||
|
||||
printk(KERN_DEBUG "Data: (%d)\n", pdu->datasize);
|
||||
pr_debug("Data: (%d)\n", pdu->datasize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1723,7 +1723,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
|
||||
return;
|
||||
}
|
||||
|
||||
lscsi_status = scsi_status & STATUS_MASK;
|
||||
lscsi_status = scsi_status & STATUS_MASK;
|
||||
|
||||
fcport = sp->fcport;
|
||||
|
||||
|
||||
+72
-4
@@ -331,6 +331,11 @@ in/out in Makefile and scst.h:
|
||||
can clear already measured results by writing 0 in each file. Note,
|
||||
you need a non-preemptible kernel to have correct results.
|
||||
|
||||
- CONFIG_SCST_DIF_INJECT_CORRUPTED_TAGS - if defined, allows injection
|
||||
of corrupted DIF tags according to the Oracle specification. This
|
||||
functionality is working only if dif_mode doesn't contain dev_store
|
||||
and dif_type is 1.
|
||||
|
||||
HIGHMEM kernel configurations are fully supported, but not recommended
|
||||
for performance reasons, except for scst_user, where they are not
|
||||
supported, because this module deals with user supplied memory on a
|
||||
@@ -613,6 +618,17 @@ Every target should have at least the following entries:
|
||||
particular target driver or not, you can find out by checking traces
|
||||
or the target driver's source code.
|
||||
|
||||
- dif_capabilities - if this target supports T10-PI, returns which
|
||||
exact DIF capabilities this target supports.
|
||||
|
||||
- dif_checks_failed - if this target supports T10-PI, returns
|
||||
statistics how many DIF errors have been detected on the
|
||||
corresponding processing stages on this target. It returns 3 rows of
|
||||
numbers with 3 numbers in each row: for target driver stage, for SCST
|
||||
stage and for dev handler stage. Numbers in each row: how many errors
|
||||
detected checking application, reference and guard tags
|
||||
correspondingly. Writing to this attribute resets the numbers.
|
||||
|
||||
- cpu_mask - defines CPU affinity mask for threads serving this target.
|
||||
For threads serving LUNs it is used only for devices with
|
||||
threads_pool_type "per_initiator".
|
||||
@@ -671,6 +687,17 @@ following entries:
|
||||
|
||||
- commands - contains overall number of SCSI commands in this session.
|
||||
|
||||
- dif_checks_failed - if target of this session supports T10-PI, returns
|
||||
statistics how many DIF errors have been detected on the
|
||||
corresponding processing stages on all DIF-enabled LUNs in this
|
||||
session. It returns 3 rows of numbers with 3 numbers in each row: for
|
||||
target driver stage, for SCST stage and for dev handler stage.
|
||||
Numbers in each row: how many errors detected checking application,
|
||||
reference and guard tags correspondingly. Writing to this attribute
|
||||
resets the numbers. Similar statistics returned in attribute with the
|
||||
same name for each LUN in this session in this LUN's subdirectory, if
|
||||
its device configured with dif_type > 0.
|
||||
|
||||
- read_cmd_count - number of READ SCSI commands received since beginning
|
||||
or last reset (writing 0 in this attribute)
|
||||
|
||||
@@ -993,6 +1020,47 @@ cache. The following parameters possible for vdisk_fileio:
|
||||
- zero_copy - if set, then this device uses zero copy access to the
|
||||
page cache. At the moment, only read side zero copy is implemented.
|
||||
|
||||
- dif_mode - specifies which T10-PI, or DIF, mode this device will use.
|
||||
See SCSI standards from more info about T10-PI. Available DIF modes
|
||||
(can be combined using '|'):
|
||||
|
||||
* tgt - DIF tags are checked on the target hardware, if supported
|
||||
|
||||
* scst - DIF tags are checked inside SCST core
|
||||
|
||||
* dev_check - DIF tags are checked inside backend device
|
||||
|
||||
* dev_store - DIF tags are stored inside backend device on the WRITE
|
||||
path and read from it on the READ path
|
||||
|
||||
For instance, if only tgt DIF mode specified, then target driver,
|
||||
serving this device, will inside hardware check, then STRIP DIF tags
|
||||
from SCSI commands on the WRITE path and generate, then INSERT DIF
|
||||
tags into SCSI commands on the READ path, so neither SCST core, nor
|
||||
dev handler will see them.
|
||||
|
||||
Similarly, if only scst DIF mode specified, then target driver will
|
||||
PASS DIF tags into SCST core, which then check/STRIP/generate/INSERT
|
||||
them, so dev handler will not see them.
|
||||
|
||||
If only dev_check DIF mode specified, then both target driver and
|
||||
SCST core will PASS DIF tags into the dev handler, which is then
|
||||
responsible to check them in the backend hardware. If only dev_store
|
||||
specified, then DIF tags will only be stored by the dev handler in
|
||||
the backend hardware without checking at any level.
|
||||
|
||||
If all "tgt|scst|dev_check|dev_store" DIF mode specified, then all
|
||||
target driver, SCST core and dev handler will check DIF tags, then
|
||||
dev handler will store them in the backend hardware.
|
||||
|
||||
- dif_type - specifies which DIF SCSI type this device will use.
|
||||
|
||||
- dif_static_app_tag - specifies fixed (static) DIF application tag for
|
||||
this device.
|
||||
|
||||
- dif_filename - specifies full path to filename, where DIF tags will
|
||||
be stored.
|
||||
|
||||
Handler vdisk_blockio provides BLOCKIO mode to create virtual devices.
|
||||
This mode performs direct block I/O with a block device, bypassing the
|
||||
page cache for all operations. This mode works ideally with high-end
|
||||
@@ -1000,10 +1068,10 @@ storage HBAs and for applications that either do not need caching
|
||||
between application and disk or need the large block throughput. See
|
||||
below for more info.
|
||||
|
||||
The following common with vdisk_fileio parameters are possible for
|
||||
vdisk_blockio: filename, blocksize, nv_cache, write_through, read_only,
|
||||
removable, rotational, thin_provisioned, tst. See vdisk_fileio above for
|
||||
description of those parameters.
|
||||
The following parameters possible for vdisk_blockio: filename,
|
||||
blocksize, nv_cache, read_only, removable, rotational, thin_provisioned,
|
||||
tst, dif_mode, dif_type, dif_static_app_tag, dif_filename. See
|
||||
vdisk_fileio above for description of those parameters.
|
||||
|
||||
Handler vdisk_nullio provides NULLIO mode to create virtual devices. In
|
||||
this mode no real I/O is done, but success returned to initiators.
|
||||
|
||||
+72
-4
@@ -233,6 +233,11 @@ your favorite kernel configuration Makefile target, e.g. "make xconfig":
|
||||
can clear already measured results by writing 0 in each file. Note,
|
||||
you need a non-preemptible kernel to have correct results.
|
||||
|
||||
- CONFIG_SCST_DIF_INJECT_CORRUPTED_TAGS - if defined, allows injection
|
||||
of corrupted DIF tags according to the Oracle specification. This
|
||||
functionality is working only if dif_mode doesn't contain dev_store
|
||||
and dif_type is 1.
|
||||
|
||||
HIGHMEM kernel configurations are fully supported, but not recommended
|
||||
for performance reasons.
|
||||
|
||||
@@ -489,6 +494,17 @@ Every target should have at least the following entries:
|
||||
particular target driver or not, you can find out by checking traces
|
||||
or the target driver's source code.
|
||||
|
||||
- dif_capabilities - if this target supports T10-PI, returns which
|
||||
exact DIF capabilities this target supports.
|
||||
|
||||
- dif_checks_failed - if this target supports T10-PI, returns
|
||||
statistics how many DIF errors have been detected on the
|
||||
corresponding processing stages on this target. It returns 3 rows of
|
||||
numbers with 3 numbers in each row: for target driver stage, for SCST
|
||||
stage and for dev handler stage. Numbers in each row: how many errors
|
||||
detected checking application, reference and guard tags
|
||||
correspondingly. Writing to this attribute resets the numbers.
|
||||
|
||||
- cpu_mask - defines CPU affinity mask for threads serving this target.
|
||||
For threads serving LUNs it is used only for devices with
|
||||
threads_pool_type "per_initiator".
|
||||
@@ -547,6 +563,17 @@ following entries:
|
||||
|
||||
- commands - contains overall number of SCSI commands in this session.
|
||||
|
||||
- dif_checks_failed - if target of this session supports T10-PI, returns
|
||||
statistics how many DIF errors have been detected on the
|
||||
corresponding processing stages on all DIF-enabled LUNs in this
|
||||
session. It returns 3 rows of numbers with 3 numbers in each row: for
|
||||
target driver stage, for SCST stage and for dev handler stage.
|
||||
Numbers in each row: how many errors detected checking application,
|
||||
reference and guard tags correspondingly. Writing to this attribute
|
||||
resets the numbers. Similar statistics returned in attribute with the
|
||||
same name for each LUN in this session in this LUN's subdirectory, if
|
||||
its device configured with dif_type > 0.
|
||||
|
||||
- read_cmd_count - number of READ SCSI commands received since beginning
|
||||
or last reset (writing 0 in this attribute)
|
||||
|
||||
@@ -865,6 +892,47 @@ cache. The following parameters possible for vdisk_fileio:
|
||||
- zero_copy - if set, then this device uses zero copy access to the
|
||||
page cache. At the moment, only read side zero copy is implemented.
|
||||
|
||||
- dif_mode - specifies which T10-PI, or DIF, mode this device will use.
|
||||
See SCSI standards from more info about T10-PI. Available DIF modes
|
||||
(can be combined using '|'):
|
||||
|
||||
* tgt - DIF tags are checked on the target hardware, if supported
|
||||
|
||||
* scst - DIF tags are checked inside SCST core
|
||||
|
||||
* dev_check - DIF tags are checked inside backend device
|
||||
|
||||
* dev_store - DIF tags are stored inside backend device on the WRITE
|
||||
path and read from it on the READ path
|
||||
|
||||
For instance, if only tgt DIF mode specified, then target driver,
|
||||
serving this device, will inside hardware check, then STRIP DIF tags
|
||||
from SCSI commands on the WRITE path and generate, then INSERT DIF
|
||||
tags into SCSI commands on the READ path, so neither SCST core, nor
|
||||
dev handler will see them.
|
||||
|
||||
Similarly, if only scst DIF mode specified, then target driver will
|
||||
PASS DIF tags into SCST core, which then check/STRIP/generate/INSERT
|
||||
them, so dev handler will not see them.
|
||||
|
||||
If only dev_check DIF mode specified, then both target driver and
|
||||
SCST core will PASS DIF tags into the dev handler, which is then
|
||||
responsible to check them in the backend hardware. If only dev_store
|
||||
specified, then DIF tags will only be stored by the dev handler in
|
||||
the backend hardware without checking at any level.
|
||||
|
||||
If all "tgt|scst|dev_check|dev_store" DIF mode specified, then all
|
||||
target driver, SCST core and dev handler will check DIF tags, then
|
||||
dev handler will store them in the backend hardware.
|
||||
|
||||
- dif_type - specifies which DIF SCSI type this device will use.
|
||||
|
||||
- dif_static_app_tag - specifies fixed (static) DIF application tag for
|
||||
this device.
|
||||
|
||||
- dif_filename - specifies full path to filename, where DIF tags will
|
||||
be stored.
|
||||
|
||||
Handler vdisk_blockio provides BLOCKIO mode to create virtual devices.
|
||||
This mode performs direct block I/O with a block device, bypassing the
|
||||
page cache for all operations. This mode works ideally with high-end
|
||||
@@ -872,10 +940,10 @@ storage HBAs and for applications that either do not need caching
|
||||
between application and disk or need the large block throughput. See
|
||||
below for more info.
|
||||
|
||||
The following common with vdisk_fileio parameters are possible for
|
||||
vdisk_blockio: filename, blocksize, nv_cache, write_through, read_only,
|
||||
removable, rotational, thin_provisioned, tst. See vdisk_fileio above for
|
||||
description of those parameters.
|
||||
The following parameters possible for vdisk_blockio: filename,
|
||||
blocksize, nv_cache, read_only, removable, rotational, thin_provisioned,
|
||||
tst, dif_mode, dif_type, dif_static_app_tag, dif_filename. See
|
||||
vdisk_fileio above for description of those parameters.
|
||||
|
||||
Handler vdisk_nullio provides NULLIO mode to create virtual devices. In
|
||||
this mode no real I/O is done, but success returned to initiators.
|
||||
|
||||
+845
-18
File diff suppressed because it is too large
Load Diff
@@ -334,6 +334,9 @@ 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_logical_block_guard_check_failed ABORTED_COMMAND, 0x10, 1
|
||||
#define scst_logical_block_app_tag_check_failed ABORTED_COMMAND, 0x10, 2
|
||||
#define scst_logical_block_ref_tag_check_failed ABORTED_COMMAND, 0x10, 3
|
||||
#define scst_sense_internal_failure ABORTED_COMMAND, 0x44, 0 /* retriable */
|
||||
|
||||
/* MISCOMPARE is 0xe */
|
||||
@@ -424,6 +427,13 @@ static inline int scst_sense_response_code(const uint8_t *sense)
|
||||
#define UNMAP 0x42
|
||||
#endif
|
||||
|
||||
/* Subcodes of VARIABLE_LENGTH_CMD (0x7F) */
|
||||
#define SUBCODE_READ_32 0x09
|
||||
#define SUBCODE_VERIFY_32 0x0a
|
||||
#define SUBCODE_WRITE_32 0x0b
|
||||
#define SUBCODE_WRITE_VERIFY_32 0x0c
|
||||
#define SUBCODE_WRITE_SAME_32 0x0d
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0)
|
||||
/*
|
||||
* From <scsi/scsi.h>. See also commit
|
||||
@@ -452,7 +462,6 @@ static inline int scst_sense_response_code(const uint8_t *sense)
|
||||
#define BLKDISCARD _IO(0x12,119)
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************
|
||||
** SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft
|
||||
** T10/1561-D Revision 4 Draft dated 7th November 2002.
|
||||
@@ -527,6 +536,44 @@ enum {
|
||||
#define SCST_QERR_2_RESERVED 2
|
||||
#define SCST_QERR_3_ABORT_THIS_NEXUS_ONLY 3
|
||||
|
||||
/*************************************************************
|
||||
** Values for the control mode page ATO field
|
||||
*************************************************************/
|
||||
|
||||
/* I.e., app tags owned by storage */
|
||||
#define SCST_ATO_0_MODIFIED_BY_STORAGE 0
|
||||
|
||||
/* I.e., app tags owned by application */
|
||||
#define SCST_ATO_1_NOT_MODIFIED_BY_STORAGE 1
|
||||
|
||||
/*************************************************************
|
||||
** Values for the control mode page DPICZ field
|
||||
*************************************************************/
|
||||
#define SCST_DPICZ_CHECK_ON_xPROT_0 0
|
||||
#define SCST_DPICZ_NO_CHECK_ON_xPROT_0 1
|
||||
|
||||
/*************************************************************
|
||||
** APP/REF TAG DIF constants
|
||||
*************************************************************/
|
||||
|
||||
/* Skip all guards checks for this block */
|
||||
#define SCST_DIF_NO_CHECK_ALL_APP_TAG cpu_to_be16(0xFFFF)
|
||||
#define SCST_DIF_NO_CHECK_ALL_REF_TAG cpu_to_be32(0xFFFFFFFF)
|
||||
|
||||
/* Don't check app tag for this block */
|
||||
#define SCST_DIF_NO_CHECK_APP_TAG 0
|
||||
|
||||
/*************************************************************
|
||||
** Shift of size of DIF tag (8 bytes)
|
||||
*************************************************************/
|
||||
#define SCST_DIF_TAG_SHIFT 3
|
||||
|
||||
/*************************************************************
|
||||
** Formats of DIF guard tags
|
||||
*************************************************************/
|
||||
#define SCST_DIF_GUARD_FORMAT_CRC 0
|
||||
#define SCST_DIF_GUARD_FORMAT_IP 1
|
||||
|
||||
/*************************************************************
|
||||
** TransportID protocol identifiers
|
||||
*************************************************************/
|
||||
|
||||
@@ -121,6 +121,7 @@ install: all
|
||||
install -m 644 $(MODULE_SYMVERS) $(INSTALL_DIR_H)
|
||||
-/sbin/depmod -b $(INSTALL_MOD_PATH)/ -a $(KVER)
|
||||
mkdir -p $(DESTDIR)/var/lib/scst/pr
|
||||
mkdir -p $(DESTDIR)/var/lib/scst/dif_tags
|
||||
mkdir -p $(DESTDIR)/var/lib/scst/vdev_mode_pages
|
||||
@echo "****************************************************************"
|
||||
@echo "*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*"
|
||||
|
||||
@@ -814,7 +814,7 @@ static int dev_user_parse(struct scst_cmd *cmd)
|
||||
ucmd->user_cmd.parse_cmd.expected_data_direction =
|
||||
cmd->expected_data_direction;
|
||||
ucmd->user_cmd.parse_cmd.expected_transfer_len =
|
||||
cmd->expected_transfer_len;
|
||||
cmd->expected_transfer_len_full;
|
||||
ucmd->user_cmd.parse_cmd.expected_out_transfer_len =
|
||||
cmd->expected_out_transfer_len;
|
||||
ucmd->user_cmd.parse_cmd.sn = cmd->tgt_sn;
|
||||
|
||||
+1343
-98
File diff suppressed because it is too large
Load Diff
+2717
-82
File diff suppressed because it is too large
Load Diff
@@ -522,6 +522,11 @@ static inline void scst_devt_dev_sysfs_del(struct scst_device *dev) { }
|
||||
|
||||
static inline void scst_dev_sysfs_del(struct scst_device *dev) { }
|
||||
|
||||
static inline int scst_dev_sysfs_dif_create(struct scst_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int scst_tgt_dev_sysfs_create(struct scst_tgt_dev *tgt_dev)
|
||||
{
|
||||
return 0;
|
||||
@@ -570,6 +575,7 @@ int scst_devt_sysfs_create(struct scst_dev_type *devt);
|
||||
void scst_devt_sysfs_del(struct scst_dev_type *devt);
|
||||
int scst_dev_sysfs_create(struct scst_device *dev);
|
||||
void scst_dev_sysfs_del(struct scst_device *dev);
|
||||
int scst_dev_sysfs_dif_create(struct scst_device *dev);
|
||||
int scst_tgt_dev_sysfs_create(struct scst_tgt_dev *tgt_dev);
|
||||
void scst_tgt_dev_sysfs_del(struct scst_tgt_dev *tgt_dev);
|
||||
int scst_devt_dev_sysfs_create(struct scst_device *dev);
|
||||
|
||||
@@ -1033,6 +1033,63 @@ static struct kobj_attribute scst_tgtt_mgmt =
|
||||
__ATTR(mgmt, S_IRUGO | S_IWUSR, scst_tgtt_mgmt_show,
|
||||
scst_tgtt_mgmt_store);
|
||||
|
||||
static ssize_t scst_tgtt_dif_capable_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int pos = 0;
|
||||
struct scst_tgt_template *tgtt;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
tgtt = container_of(kobj, struct scst_tgt_template, tgtt_kobj);
|
||||
|
||||
EXTRACHECKS_BUG_ON(!tgtt->dif_supported);
|
||||
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
"dif_supported");
|
||||
|
||||
if (tgtt->hw_dif_type1_supported)
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
", hw_dif_type1_supported");
|
||||
|
||||
if (tgtt->hw_dif_type2_supported)
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
", hw_dif_type2_supported");
|
||||
|
||||
if (tgtt->hw_dif_type3_supported)
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
", hw_dif_type3_supported");
|
||||
|
||||
if (tgtt->hw_dif_ip_supported)
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
", hw_dif_ip_supported");
|
||||
|
||||
if (tgtt->hw_dif_same_sg_layout_required)
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
", hw_dif_same_sg_layout_required");
|
||||
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos, "\n");
|
||||
|
||||
if (tgtt->supported_dif_block_sizes) {
|
||||
const int *p = tgtt->supported_dif_block_sizes;
|
||||
int j;
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
"Supported blocks: ");
|
||||
j = pos;
|
||||
while (*p != 0) {
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
"%s%d", (j == pos) ? "" : ", ", *p);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static struct kobj_attribute scst_tgtt_dif_capable_attr =
|
||||
__ATTR(dif_capabilities, S_IRUGO, scst_tgtt_dif_capable_show, NULL);
|
||||
|
||||
/*
|
||||
* Creates an attribute entry for target driver.
|
||||
*/
|
||||
@@ -1085,6 +1142,16 @@ int scst_tgtt_sysfs_create(struct scst_tgt_template *tgtt)
|
||||
}
|
||||
}
|
||||
|
||||
if (tgtt->dif_supported) {
|
||||
res = sysfs_create_file(&tgtt->tgtt_kobj,
|
||||
&scst_tgtt_dif_capable_attr.attr);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Can't add attribute %s for target driver %s",
|
||||
scst_tgtt_dif_capable_attr.attr.name, tgtt->name);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
|
||||
if (tgtt->trace_flags != NULL) {
|
||||
res = sysfs_create_file(&tgtt->tgtt_kobj,
|
||||
@@ -2524,6 +2591,114 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL(scst_create_tgt_attr);
|
||||
|
||||
static ssize_t scst_tgt_dif_capable_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int pos = 0;
|
||||
struct scst_tgt *tgt;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
|
||||
|
||||
EXTRACHECKS_BUG_ON(!tgt->tgt_dif_supported);
|
||||
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
"dif_supported");
|
||||
|
||||
if (tgt->tgt_hw_dif_type1_supported)
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
", hw_dif_type1_supported");
|
||||
|
||||
if (tgt->tgt_hw_dif_type2_supported)
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
", hw_dif_type2_supported");
|
||||
|
||||
if (tgt->tgt_hw_dif_type3_supported)
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
", hw_dif_type3_supported");
|
||||
|
||||
if (tgt->tgt_hw_dif_ip_supported)
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
", hw_dif_ip_supported");
|
||||
|
||||
if (tgt->tgt_hw_dif_same_sg_layout_required)
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
", hw_dif_same_sg_layout_required");
|
||||
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos, "\n");
|
||||
|
||||
if (tgt->tgt_supported_dif_block_sizes) {
|
||||
const int *p = tgt->tgt_supported_dif_block_sizes;
|
||||
int j;
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
"Supported blocks: ");
|
||||
j = pos;
|
||||
while (*p != 0) {
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
"%s%d", (j == pos) ? "" : ", ", *p);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static struct kobj_attribute scst_tgt_dif_capable_attr =
|
||||
__ATTR(dif_capabilities, S_IRUGO, scst_tgt_dif_capable_show, NULL);
|
||||
|
||||
static ssize_t scst_tgt_dif_checks_failed_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int pos = 0;
|
||||
struct scst_tgt *tgt;
|
||||
|
||||
tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
|
||||
|
||||
pos = scnprintf(buf, SCST_SYSFS_BLOCK_SIZE, "\tapp\tref\tguard\n"
|
||||
"tgt\t%d\t%d\t%d\nscst\t%d\t%d\t%d\ndev\t%d\t%d\t%d\n",
|
||||
atomic_read(&tgt->tgt_dif_app_failed_tgt),
|
||||
atomic_read(&tgt->tgt_dif_ref_failed_tgt),
|
||||
atomic_read(&tgt->tgt_dif_guard_failed_tgt),
|
||||
atomic_read(&tgt->tgt_dif_app_failed_scst),
|
||||
atomic_read(&tgt->tgt_dif_ref_failed_scst),
|
||||
atomic_read(&tgt->tgt_dif_guard_failed_scst),
|
||||
atomic_read(&tgt->tgt_dif_app_failed_dev),
|
||||
atomic_read(&tgt->tgt_dif_ref_failed_dev),
|
||||
atomic_read(&tgt->tgt_dif_guard_failed_dev));
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static ssize_t scst_tgt_dif_checks_failed_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct scst_tgt *tgt;
|
||||
|
||||
tgt = container_of(kobj, struct scst_tgt, tgt_kobj);
|
||||
|
||||
PRINT_INFO("Zeroing DIF failures statistics for target %s",
|
||||
tgt->tgt_name);
|
||||
|
||||
atomic_set(&tgt->tgt_dif_app_failed_tgt, 0);
|
||||
atomic_set(&tgt->tgt_dif_ref_failed_tgt, 0);
|
||||
atomic_set(&tgt->tgt_dif_guard_failed_tgt, 0);
|
||||
atomic_set(&tgt->tgt_dif_app_failed_scst, 0);
|
||||
atomic_set(&tgt->tgt_dif_ref_failed_scst, 0);
|
||||
atomic_set(&tgt->tgt_dif_guard_failed_scst, 0);
|
||||
atomic_set(&tgt->tgt_dif_app_failed_dev, 0);
|
||||
atomic_set(&tgt->tgt_dif_ref_failed_dev, 0);
|
||||
atomic_set(&tgt->tgt_dif_guard_failed_dev, 0);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct kobj_attribute scst_tgt_dif_checks_failed_attr =
|
||||
__ATTR(dif_checks_failed, S_IRUGO | S_IWUSR,
|
||||
scst_tgt_dif_checks_failed_show,
|
||||
scst_tgt_dif_checks_failed_store);
|
||||
|
||||
#define SCST_TGT_SYSFS_STAT_ATTR(member_name, attr, dir, result_op) \
|
||||
static int scst_tgt_sysfs_##attr##_show_work_fn( \
|
||||
struct scst_sysfs_work_item *work) \
|
||||
@@ -2679,6 +2854,26 @@ int scst_tgt_sysfs_create(struct scst_tgt *tgt)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (tgt->tgt_dif_supported) {
|
||||
res = sysfs_create_file(&tgt->tgt_kobj,
|
||||
&scst_tgt_dif_capable_attr.attr);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Can't add attribute %s for tgt %s",
|
||||
scst_tgt_dif_capable_attr.attr.name,
|
||||
tgt->tgt_name);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
res = sysfs_create_file(&tgt->tgt_kobj,
|
||||
&scst_tgt_dif_checks_failed_attr.attr);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Can't add attribute %s for tgt %s",
|
||||
scst_tgt_dif_checks_failed_attr.attr.name,
|
||||
tgt->tgt_name);
|
||||
goto out_err;
|
||||
}
|
||||
}
|
||||
|
||||
if (tgt->tgtt->tgt_attrs) {
|
||||
res = sysfs_create_files(&tgt->tgt_kobj, tgt->tgtt->tgt_attrs);
|
||||
if (res != 0) {
|
||||
@@ -3397,6 +3592,164 @@ void scst_dev_sysfs_del(struct scst_device *dev)
|
||||
return;
|
||||
}
|
||||
|
||||
static ssize_t scst_dev_dif_mode_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int pos = 0;
|
||||
struct scst_device *dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
|
||||
if (dev->dev_dif_mode == SCST_DIF_MODE_NONE)
|
||||
pos = sprintf(buf, "None\n");
|
||||
else {
|
||||
int j = pos;
|
||||
|
||||
if (dev->dev_dif_mode & SCST_DIF_MODE_TGT)
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
"%s%s", (j == pos) ? "" : "|", SCST_DIF_MODE_TGT_STR);
|
||||
|
||||
if (dev->dev_dif_mode & SCST_DIF_MODE_SCST)
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
"%s%s", (j == pos) ? "" : "|", SCST_DIF_MODE_SCST_STR);
|
||||
|
||||
if (dev->dev_dif_mode & SCST_DIF_MODE_DEV_CHECK)
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
"%s%s", (j == pos) ? "" : "|", SCST_DIF_MODE_DEV_CHECK_STR);
|
||||
|
||||
if (dev->dev_dif_mode & SCST_DIF_MODE_DEV_STORE)
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
"%s%s", (j == pos) ? "" : "|", SCST_DIF_MODE_DEV_STORE_STR);
|
||||
|
||||
pos += scnprintf(&buf[pos], SCST_SYSFS_BLOCK_SIZE - pos,
|
||||
"\n%s", SCST_SYSFS_KEY_MARK "\n");
|
||||
}
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static struct kobj_attribute scst_dev_dif_mode_attr =
|
||||
__ATTR(dif_mode, S_IRUGO, scst_dev_dif_mode_show, NULL);
|
||||
|
||||
static ssize_t scst_dev_dif_type_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int pos = 0;
|
||||
struct scst_device *dev;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
|
||||
pos = sprintf(buf, "%d\n%s", dev->dev_dif_type,
|
||||
(dev->dev_dif_type != 0) ? SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static struct kobj_attribute scst_dev_dif_type_attr =
|
||||
__ATTR(dif_type, S_IRUGO, scst_dev_dif_type_show, NULL);
|
||||
|
||||
static ssize_t scst_dev_sysfs_dif_static_app_tag_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int res;
|
||||
struct scst_device *dev;
|
||||
unsigned long long val;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
|
||||
res = kstrtoull(buf, 0, &val);
|
||||
#else
|
||||
res = strict_strtoull(buf, 0, &val);
|
||||
#endif
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("strtoul() for %s failed: %d (device %s)",
|
||||
buf, res, dev->virt_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
scst_dev_set_dif_static_app_tag_combined(dev, cpu_to_be64(val));
|
||||
|
||||
res = count;
|
||||
|
||||
PRINT_INFO("APP TAG for device %s changed to %llx", dev->virt_name,
|
||||
(long long)be64_to_cpu(scst_dev_get_dif_static_app_tag_combined(dev)));
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t scst_dev_sysfs_dif_static_app_tag_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int pos = 0;
|
||||
struct scst_device *dev;
|
||||
__be64 a;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
dev = container_of(kobj, struct scst_device, dev_kobj);
|
||||
|
||||
a = scst_dev_get_dif_static_app_tag_combined(dev);
|
||||
|
||||
pos = sprintf(buf, "0x%llx\n%s", (unsigned long long)be64_to_cpu(a),
|
||||
(a != SCST_DIF_NO_CHECK_APP_TAG) ? SCST_SYSFS_KEY_MARK "\n" : "");
|
||||
|
||||
TRACE_EXIT_RES(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
static struct kobj_attribute scst_dev_dif_static_app_tag_attr =
|
||||
__ATTR(dif_static_app_tag, S_IWUSR|S_IRUGO,
|
||||
scst_dev_sysfs_dif_static_app_tag_show,
|
||||
scst_dev_sysfs_dif_static_app_tag_store);
|
||||
|
||||
int scst_dev_sysfs_dif_create(struct scst_device *dev)
|
||||
{
|
||||
int res;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
/*
|
||||
* On errors the caller supposed to unregister this device, hence,
|
||||
* perform the cleanup.
|
||||
*/
|
||||
|
||||
res = sysfs_create_file(&dev->dev_kobj, &scst_dev_dif_mode_attr.attr);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Can't create attr %s for dev %s",
|
||||
scst_dev_dif_mode_attr.attr.name, dev->virt_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = sysfs_create_file(&dev->dev_kobj, &scst_dev_dif_type_attr.attr);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Can't create attr %s for dev %s",
|
||||
scst_dev_dif_type_attr.attr.name, dev->virt_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = sysfs_create_file(&dev->dev_kobj, &scst_dev_dif_static_app_tag_attr.attr);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Can't create attr %s for dev %s",
|
||||
scst_dev_dif_static_app_tag_attr.attr.name, dev->virt_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
** Tgt_dev implementation
|
||||
**/
|
||||
@@ -3554,6 +3907,58 @@ static struct kobj_attribute tgt_dev_active_commands_attr =
|
||||
__ATTR(active_commands, S_IRUGO,
|
||||
scst_tgt_dev_active_commands_show, NULL);
|
||||
|
||||
static ssize_t scst_tgt_dev_dif_checks_failed_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int pos = 0;
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
tgt_dev = container_of(kobj, struct scst_tgt_dev, tgt_dev_kobj);
|
||||
|
||||
pos = scnprintf(buf, SCST_SYSFS_BLOCK_SIZE, "\tapp\tref\tguard\n"
|
||||
"tgt\t%d\t%d\t%d\nscst\t%d\t%d\t%d\ndev\t%d\t%d\t%d\n",
|
||||
atomic_read(&tgt_dev->tgt_dev_dif_app_failed_tgt),
|
||||
atomic_read(&tgt_dev->tgt_dev_dif_ref_failed_tgt),
|
||||
atomic_read(&tgt_dev->tgt_dev_dif_guard_failed_tgt),
|
||||
atomic_read(&tgt_dev->tgt_dev_dif_app_failed_scst),
|
||||
atomic_read(&tgt_dev->tgt_dev_dif_ref_failed_scst),
|
||||
atomic_read(&tgt_dev->tgt_dev_dif_guard_failed_scst),
|
||||
atomic_read(&tgt_dev->tgt_dev_dif_app_failed_dev),
|
||||
atomic_read(&tgt_dev->tgt_dev_dif_ref_failed_dev),
|
||||
atomic_read(&tgt_dev->tgt_dev_dif_guard_failed_dev));
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static ssize_t scst_tgt_dev_dif_checks_failed_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
|
||||
tgt_dev = container_of(kobj, struct scst_tgt_dev, tgt_dev_kobj);
|
||||
|
||||
PRINT_INFO("Zeroing DIF failures statistics for initiator "
|
||||
"%s, target %s, LUN %lld", tgt_dev->sess->initiator_name,
|
||||
tgt_dev->sess->tgt->tgt_name, (unsigned long long)tgt_dev->lun);
|
||||
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_app_failed_tgt, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_ref_failed_tgt, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_guard_failed_tgt, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_app_failed_scst, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_ref_failed_scst, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_guard_failed_scst, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_app_failed_dev, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_ref_failed_dev, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_guard_failed_dev, 0);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct kobj_attribute tgt_dev_dif_checks_failed_attr =
|
||||
__ATTR(dif_checks_failed, S_IRUGO | S_IWUSR,
|
||||
scst_tgt_dev_dif_checks_failed_show,
|
||||
scst_tgt_dev_dif_checks_failed_store);
|
||||
|
||||
static struct attribute *scst_tgt_dev_attrs[] = {
|
||||
&tgt_dev_thread_pid_attr.attr,
|
||||
&tgt_dev_active_commands_attr.attr,
|
||||
@@ -3598,9 +4003,25 @@ int scst_tgt_dev_sysfs_create(struct scst_tgt_dev *tgt_dev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tgt_dev->sess->tgt->tgt_dif_supported && (tgt_dev->dev->dev_dif_type != 0)) {
|
||||
res = sysfs_create_file(&tgt_dev->tgt_dev_kobj,
|
||||
&tgt_dev_dif_checks_failed_attr.attr);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Adding %s sysfs attribute to tgt_dev %lld "
|
||||
"failed (%d)", tgt_dev_dif_checks_failed_attr.attr.name,
|
||||
(unsigned long long)tgt_dev->lun, res);
|
||||
goto out_del;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
out_del:
|
||||
kobject_del(&tgt_dev->tgt_dev_kobj);
|
||||
kobject_put(&tgt_dev->tgt_dev_kobj);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3944,6 +4365,161 @@ static struct kobj_attribute session_active_commands_attr =
|
||||
__ATTR(active_commands, S_IRUGO, scst_sess_sysfs_active_commands_show,
|
||||
NULL);
|
||||
|
||||
static int scst_sysfs_sess_get_dif_checks_failed_work_fn(struct scst_sysfs_work_item *work)
|
||||
{
|
||||
int res, t;
|
||||
struct scst_session *sess = work->sess;
|
||||
int app_failed_tgt = 0, ref_failed_tgt = 0, guard_failed_tgt = 0;
|
||||
int app_failed_scst = 0, ref_failed_scst = 0, guard_failed_scst = 0;
|
||||
int app_failed_dev = 0, ref_failed_dev = 0, guard_failed_dev = 0;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
res = mutex_lock_interruptible(&scst_mutex);
|
||||
if (res != 0)
|
||||
goto out_put;
|
||||
|
||||
for (t = SESS_TGT_DEV_LIST_HASH_SIZE-1; t >= 0; t--) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[t];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
app_failed_tgt += atomic_read(&tgt_dev->tgt_dev_dif_app_failed_tgt);
|
||||
ref_failed_tgt += atomic_read(&tgt_dev->tgt_dev_dif_ref_failed_tgt);
|
||||
guard_failed_tgt += atomic_read(&tgt_dev->tgt_dev_dif_guard_failed_tgt);
|
||||
app_failed_scst += atomic_read(&tgt_dev->tgt_dev_dif_app_failed_scst);
|
||||
ref_failed_scst += atomic_read(&tgt_dev->tgt_dev_dif_ref_failed_scst);
|
||||
guard_failed_scst += atomic_read(&tgt_dev->tgt_dev_dif_guard_failed_scst);
|
||||
app_failed_dev += atomic_read(&tgt_dev->tgt_dev_dif_app_failed_dev);
|
||||
ref_failed_dev += atomic_read(&tgt_dev->tgt_dev_dif_ref_failed_dev);
|
||||
guard_failed_dev += atomic_read(&tgt_dev->tgt_dev_dif_guard_failed_dev);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
work->res_buf = kasprintf(GFP_KERNEL, "\tapp\tref\tguard\n"
|
||||
"tgt\t%d\t%d\t%d\nscst\t%d\t%d\t%d\ndev\t%d\t%d\t%d\n",
|
||||
app_failed_tgt, ref_failed_tgt, guard_failed_tgt,
|
||||
app_failed_scst, ref_failed_scst, guard_failed_scst,
|
||||
app_failed_dev, ref_failed_dev, guard_failed_dev);
|
||||
res = work->res_buf ? 0 : -ENOMEM;
|
||||
|
||||
out_put:
|
||||
kobject_put(&sess->sess_kobj);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t scst_sess_sysfs_dif_checks_failed_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int res;
|
||||
struct scst_session *sess;
|
||||
struct scst_sysfs_work_item *work;
|
||||
|
||||
sess = container_of(kobj, struct scst_session, sess_kobj);
|
||||
|
||||
res = scst_alloc_sysfs_work(scst_sysfs_sess_get_dif_checks_failed_work_fn,
|
||||
true, &work);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
work->sess = sess;
|
||||
|
||||
SCST_SET_DEP_MAP(work, &scst_sess_dep_map);
|
||||
kobject_get(&sess->sess_kobj);
|
||||
|
||||
scst_sysfs_work_get(work);
|
||||
|
||||
res = scst_sysfs_queue_wait_work(work);
|
||||
if (res != 0)
|
||||
goto out_put;
|
||||
|
||||
res = snprintf(buf, SCST_SYSFS_BLOCK_SIZE, "%s", work->res_buf);
|
||||
|
||||
out_put:
|
||||
scst_sysfs_work_put(work);
|
||||
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int scst_sess_zero_dif_checks_failed(struct scst_sysfs_work_item *work)
|
||||
{
|
||||
int res, t;
|
||||
struct scst_session *sess = work->sess;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
PRINT_INFO("Zeroing DIF failures statistics for initiator "
|
||||
"%s, target %s", sess->initiator_name, sess->tgt->tgt_name);
|
||||
|
||||
res = mutex_lock_interruptible(&scst_mutex);
|
||||
if (res != 0)
|
||||
goto out_put;
|
||||
|
||||
for (t = SESS_TGT_DEV_LIST_HASH_SIZE-1; t >= 0; t--) {
|
||||
struct list_head *head = &sess->sess_tgt_dev_list[t];
|
||||
struct scst_tgt_dev *tgt_dev;
|
||||
list_for_each_entry(tgt_dev, head, sess_tgt_dev_list_entry) {
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_app_failed_tgt, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_ref_failed_tgt, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_guard_failed_tgt, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_app_failed_scst, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_ref_failed_scst, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_guard_failed_scst, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_app_failed_dev, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_ref_failed_dev, 0);
|
||||
atomic_set(&tgt_dev->tgt_dev_dif_guard_failed_dev, 0);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&scst_mutex);
|
||||
|
||||
res = 0;
|
||||
|
||||
out_put:
|
||||
kobject_put(&sess->sess_kobj);
|
||||
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t scst_sess_sysfs_dif_checks_failed_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int res;
|
||||
struct scst_session *sess;
|
||||
struct scst_sysfs_work_item *work;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
sess = container_of(kobj, struct scst_session, sess_kobj);
|
||||
|
||||
res = scst_alloc_sysfs_work(scst_sess_zero_dif_checks_failed, false, &work);
|
||||
if (res != 0)
|
||||
goto out;
|
||||
|
||||
work->sess = sess;
|
||||
|
||||
SCST_SET_DEP_MAP(work, &scst_sess_dep_map);
|
||||
kobject_get(&sess->sess_kobj);
|
||||
|
||||
res = scst_sysfs_queue_wait_work(work);
|
||||
if (res == 0)
|
||||
res = count;
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct kobj_attribute session_dif_checks_failed_attr =
|
||||
__ATTR(dif_checks_failed, S_IRUGO | S_IWUSR,
|
||||
scst_sess_sysfs_dif_checks_failed_show,
|
||||
scst_sess_sysfs_dif_checks_failed_store);
|
||||
|
||||
static ssize_t scst_sess_sysfs_initiator_name_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -4129,6 +4705,17 @@ int scst_sess_sysfs_create(struct scst_session *sess)
|
||||
}
|
||||
}
|
||||
|
||||
if (sess->tgt->tgt_dif_supported) {
|
||||
res = sysfs_create_file(&sess->sess_kobj,
|
||||
&session_dif_checks_failed_attr.attr);
|
||||
if (res != 0) {
|
||||
PRINT_ERROR("Adding %s sysfs attribute to session %s "
|
||||
"failed (%d)", session_dif_checks_failed_attr.attr.name,
|
||||
name, res);
|
||||
goto out_del;
|
||||
}
|
||||
}
|
||||
|
||||
if (sess->tgt->tgtt->sess_attrs) {
|
||||
res = sysfs_create_files(&sess->sess_kobj,
|
||||
sess->tgt->tgtt->sess_attrs);
|
||||
|
||||
+61
-32
@@ -578,12 +578,14 @@ int scst_pre_parse(struct scst_cmd *cmd)
|
||||
|
||||
TRACE_DBG("op_name <%s> (cmd %p), direction=%d "
|
||||
"(expected %d, set %s), lba %lld, bufflen=%d, data_len %lld, "
|
||||
"out_bufflen=%d (expected len %d, out expected len %d), "
|
||||
"flags=0x%x, naca %d", cmd->op_name, cmd, cmd->data_direction,
|
||||
"out_bufflen=%d (expected len data %d, expected len DIF %d, "
|
||||
"out expected len %d), flags=0x%x, , naca %d",
|
||||
cmd->op_name, cmd, cmd->data_direction,
|
||||
cmd->expected_data_direction,
|
||||
scst_cmd_is_expected_set(cmd) ? "yes" : "no",
|
||||
(long long)cmd->lba, cmd->bufflen, (long long)cmd->data_len,
|
||||
cmd->out_bufflen, cmd->expected_transfer_len,
|
||||
cmd->out_bufflen, scst_cmd_get_expected_transfer_len_data(cmd),
|
||||
scst_cmd_get_expected_transfer_len_dif(cmd),
|
||||
cmd->expected_out_transfer_len, cmd->op_flags, cmd->cmd_naca);
|
||||
|
||||
res = 0;
|
||||
@@ -617,6 +619,16 @@ static bool scst_is_allowed_to_mismatch_cmd(struct scst_cmd *cmd)
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool scst_bufflen_eq_expecten_len(struct scst_cmd *cmd)
|
||||
{
|
||||
int b = cmd->bufflen;
|
||||
|
||||
if (cmd->tgt_dif_data_expected)
|
||||
b += (b >> cmd->dev->block_shift) << SCST_DIF_TAG_SHIFT;
|
||||
|
||||
return b == cmd->expected_transfer_len_full;
|
||||
}
|
||||
|
||||
static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
{
|
||||
int res = SCST_CMD_STATE_RES_CONT_SAME;
|
||||
@@ -679,12 +691,12 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
#ifdef CONFIG_SCST_USE_EXPECTED_VALUES
|
||||
if (scst_cmd_is_expected_set(cmd)) {
|
||||
TRACE(TRACE_MINOR, "Using initiator supplied values: "
|
||||
"direction %d, transfer_len %d/%d",
|
||||
cmd->expected_data_direction,
|
||||
cmd->expected_transfer_len,
|
||||
"direction %d, transfer_len %d/%d/%d",
|
||||
scst_cmd_get_expected_transfer_len_data(cmd),
|
||||
scst_cmd_get_expected_transfer_len_dif(cmd),
|
||||
cmd->expected_out_transfer_len);
|
||||
cmd->data_direction = cmd->expected_data_direction;
|
||||
cmd->bufflen = cmd->expected_transfer_len;
|
||||
cmd->bufflen = scst_cmd_get_expected_transfer_len_data(cmd);
|
||||
cmd->data_len = cmd->bufflen;
|
||||
cmd->out_bufflen = cmd->expected_out_transfer_len;
|
||||
} else {
|
||||
@@ -722,7 +734,7 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
* expected value, but limit it to some
|
||||
* reasonable value (15MB).
|
||||
*/
|
||||
cmd->bufflen = min(cmd->expected_transfer_len,
|
||||
cmd->bufflen = min(scst_cmd_get_expected_transfer_len_data(cmd),
|
||||
15*1024*1024);
|
||||
cmd->data_len = cmd->bufflen;
|
||||
if (cmd->data_direction == SCST_DATA_BIDI)
|
||||
@@ -785,21 +797,22 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
if (scst_cmd_is_expected_set(cmd)) {
|
||||
#ifdef CONFIG_SCST_USE_EXPECTED_VALUES
|
||||
if (unlikely((cmd->data_direction != cmd->expected_data_direction) ||
|
||||
(cmd->bufflen != cmd->expected_transfer_len) ||
|
||||
!scst_bufflen_eq_expecten_len(cmd) ||
|
||||
(cmd->out_bufflen != cmd->expected_out_transfer_len))) {
|
||||
TRACE(TRACE_MINOR, "Expected values don't match "
|
||||
"decoded ones: data_direction %d, "
|
||||
"expected_data_direction %d, "
|
||||
"bufflen %d, expected_transfer_len %d, "
|
||||
"out_bufflen %d, expected_out_transfer_len %d",
|
||||
"bufflen %d, expected len data %d, expected len "
|
||||
"DIF %d, out_bufflen %d, expected_out_transfer_len %d",
|
||||
cmd->data_direction,
|
||||
cmd->expected_data_direction,
|
||||
cmd->bufflen, cmd->expected_transfer_len,
|
||||
cmd->bufflen, scst_cmd_get_expected_transfer_len_data(cmd),
|
||||
scst_cmd_get_expected_transfer_len_dif(cmd),
|
||||
cmd->out_bufflen, cmd->expected_out_transfer_len);
|
||||
PRINT_BUFF_FLAG(TRACE_MINOR, "Suspicious CDB",
|
||||
cmd->cdb, cmd->cdb_len);
|
||||
cmd->data_direction = cmd->expected_data_direction;
|
||||
cmd->bufflen = cmd->expected_transfer_len;
|
||||
cmd->bufflen = scst_cmd_get_expected_transfer_len_data(cmd);
|
||||
cmd->data_len = cmd->bufflen;
|
||||
cmd->out_bufflen = cmd->expected_out_transfer_len;
|
||||
cmd->resid_possible = 1;
|
||||
@@ -823,13 +836,15 @@ static int scst_parse_cmd(struct scst_cmd *cmd)
|
||||
goto out_done;
|
||||
}
|
||||
}
|
||||
if (unlikely(cmd->bufflen != cmd->expected_transfer_len)) {
|
||||
if (unlikely(!scst_bufflen_eq_expecten_len(cmd))) {
|
||||
TRACE(TRACE_MINOR, "Warning: expected "
|
||||
"transfer length %d for opcode %s "
|
||||
"transfer length %d (DIF %d) for opcode %s "
|
||||
"(handler %s, target %s) doesn't match "
|
||||
"decoded value %d",
|
||||
cmd->expected_transfer_len, scst_get_opcode_name(cmd),
|
||||
devt->name, cmd->tgtt->name, cmd->bufflen);
|
||||
scst_cmd_get_expected_transfer_len_data(cmd),
|
||||
scst_cmd_get_expected_transfer_len_dif(cmd),
|
||||
scst_get_opcode_name(cmd), devt->name,
|
||||
cmd->tgtt->name, cmd->bufflen);
|
||||
PRINT_BUFF_FLAG(TRACE_MINOR, "Suspicious CDB",
|
||||
cmd->cdb, cmd->cdb_len);
|
||||
if ((cmd->expected_data_direction & SCST_DATA_READ) ||
|
||||
@@ -878,14 +893,16 @@ set_res:
|
||||
|
||||
TRACE(TRACE_SCSI, "op_name <%s> (cmd %p), direction=%d "
|
||||
"(expected %d, set %s), lba=%lld, bufflen=%d, data len %lld, "
|
||||
"out_bufflen=%d, (expected len %d, out expected len %d), "
|
||||
"flags=0x%x, internal %d, naca %d", cmd->op_name, cmd,
|
||||
cmd->data_direction, cmd->expected_data_direction,
|
||||
"out_bufflen=%d, (expected len data %d, expected len DIF %d, "
|
||||
"out expected len %d), flags=0x%x, internal %d, naca %d",
|
||||
cmd->op_name, cmd, cmd->data_direction, cmd->expected_data_direction,
|
||||
scst_cmd_is_expected_set(cmd) ? "yes" : "no",
|
||||
(unsigned long long)cmd->lba,
|
||||
cmd->bufflen, (long long)cmd->data_len, cmd->out_bufflen,
|
||||
cmd->expected_transfer_len, cmd->expected_out_transfer_len,
|
||||
cmd->op_flags, cmd->internal, cmd->cmd_naca);
|
||||
scst_cmd_get_expected_transfer_len_data(cmd),
|
||||
scst_cmd_get_expected_transfer_len_dif(cmd),
|
||||
cmd->expected_out_transfer_len, cmd->op_flags, cmd->internal,
|
||||
cmd->cmd_naca);
|
||||
|
||||
#ifdef CONFIG_SCST_EXTRACHECKS
|
||||
switch (state) {
|
||||
@@ -1045,7 +1062,7 @@ static void scst_set_write_len(struct scst_cmd *cmd)
|
||||
goto out;
|
||||
} else {
|
||||
cmd->write_len = min(cmd->bufflen,
|
||||
cmd->expected_transfer_len);
|
||||
scst_cmd_get_expected_transfer_len_data(cmd));
|
||||
if (cmd->write_len == cmd->bufflen)
|
||||
goto out;
|
||||
}
|
||||
@@ -1163,13 +1180,18 @@ alloc:
|
||||
TRACE_MEM("tgt_i_data_buf_alloced set (cmd %p)", cmd);
|
||||
cmd->sg = cmd->tgt_i_sg;
|
||||
cmd->sg_cnt = cmd->tgt_i_sg_cnt;
|
||||
cmd->dif_sg = cmd->tgt_i_dif_sg;
|
||||
cmd->dif_sg_cnt = cmd->tgt_i_dif_sg_cnt;
|
||||
cmd->out_sg = cmd->tgt_out_sg;
|
||||
cmd->out_sg_cnt = cmd->tgt_out_sg_cnt;
|
||||
r = 0;
|
||||
} else {
|
||||
TRACE_MEM("Both *_data_buf_alloced set (cmd %p, sg %p, "
|
||||
"sg_cnt %d, tgt_i_sg %p, tgt_i_sg_cnt %d)", cmd, cmd->sg,
|
||||
cmd->sg_cnt, cmd->tgt_i_sg, cmd->tgt_i_sg_cnt);
|
||||
"sg_cnt %d, dif_sg %p, dif_sg_cnt %d, tgt_i_sg %p, "
|
||||
"tgt_i_sg_cnt %d, tgt_i_dif_sg %p, tgt_i_dif_sg_cnt %d)",
|
||||
cmd, cmd->sg, cmd->sg_cnt, cmd->dif_sg, cmd->dif_sg_cnt,
|
||||
cmd->tgt_i_sg, cmd->tgt_i_sg_cnt, cmd->tgt_i_dif_sg,
|
||||
cmd->tgt_i_dif_sg_cnt);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
@@ -3538,6 +3560,7 @@ static int scst_pre_dev_done(struct scst_cmd *cmd)
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
again:
|
||||
rc = scst_check_auto_sense(cmd);
|
||||
if (unlikely(rc)) {
|
||||
if (test_bit(SCST_CMD_ABORTED, &cmd->cmd_flags))
|
||||
@@ -3568,16 +3591,22 @@ next:
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = scsi_status_is_good(cmd->status);
|
||||
if (likely(rc)) {
|
||||
unsigned char type = cmd->dev->type;
|
||||
if (likely(cmd->status == SAM_STAT_GOOD)) {
|
||||
if (cmd->deferred_dif_read_check) {
|
||||
int rc = scst_dif_process_read(cmd);
|
||||
if (unlikely(rc != 0)) {
|
||||
cmd->deferred_dif_read_check = 0;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely((cmd->cdb[0] == MODE_SENSE ||
|
||||
cmd->cdb[0] == MODE_SENSE_10)) &&
|
||||
(cmd->tgt_dev->tgt_dev_rd_only || cmd->dev->swp) &&
|
||||
(type == TYPE_DISK ||
|
||||
type == TYPE_WORM ||
|
||||
type == TYPE_MOD ||
|
||||
type == TYPE_TAPE)) {
|
||||
(cmd->dev->type == TYPE_DISK ||
|
||||
cmd->dev->type == TYPE_WORM ||
|
||||
cmd->dev->type == TYPE_MOD ||
|
||||
cmd->dev->type == TYPE_TAPE)) {
|
||||
int32_t length;
|
||||
uint8_t *address;
|
||||
bool err = false;
|
||||
|
||||
+1
-1
@@ -3434,7 +3434,7 @@ static int srpt_xfer_data(struct srpt_rdma_ch *ch,
|
||||
len = scst_get_buf_next(cmd, &buf);
|
||||
}
|
||||
WARN_ON_ONCE(offset !=
|
||||
scst_cmd_get_expected_transfer_len(cmd));
|
||||
scst_cmd_get_expected_transfer_len_full(cmd));
|
||||
}
|
||||
scst_rx_data(cmd, SCST_RX_STATUS_SUCCESS,
|
||||
in_irq() ? SCST_CONTEXT_TASKLET :
|
||||
|
||||
Reference in New Issue
Block a user