Merge branch 'svn-trunk' r6192

Conflicts:
	scst/include/scst.h
	scst/src/dev_handlers/scst_vdisk.c
This commit is contained in:
Bart Van Assche
2015-05-01 08:15:50 +02:00
16 changed files with 5788 additions and 246 deletions
+28
View File
@@ -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
View File
@@ -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);
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+48 -1
View File
@@ -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
*************************************************************/
+1
View File
@@ -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 "*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*"
+1 -1
View File
@@ -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;
File diff suppressed because it is too large Load Diff
+2717 -82
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -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);
+587
View File
@@ -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
View File
@@ -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
View File
@@ -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 :