Files
scst/iscsi-scst/kernel/digest.c
T
Yan Burman 6c2a375768 Merged revisions 5833-5835,5844,5847-5856 via svnmerge from
svn+ssh://yanb123@svn.code.sf.net/p/scst/svn/trunk

........
  r5833 | bvassche | 2014-10-07 08:02:20 +0200 (Tue, 07 Oct 2014) | 1 line
  
  nightly build: Update kernel versions
........
  r5834 | bvassche | 2014-10-10 18:36:24 +0200 (Fri, 10 Oct 2014) | 1 line
  
  nightly build: Update kernel versions
........
  r5835 | bvassche | 2014-10-10 18:36:59 +0200 (Fri, 10 Oct 2014) | 1 line
  
  nightly build: Update kernel versions
........
  r5844 | vlnb | 2014-10-17 04:13:17 +0200 (Fri, 17 Oct 2014) | 3 lines
  
  iSER web updates
........
  r5847 | vlnb | 2014-10-17 04:22:23 +0200 (Fri, 17 Oct 2014) | 19 lines
  
  scst_vdisk: Remove a superfluous cast
  
  The 'iov_base' member of 'struct iovec' is declared in
  <uapi/linux/uio.h> with type 'void __user *'. Adding an integer
  to a void pointer has the same effect as adding an integer to
  a char pointer in the C language. This means that it is safe to
  remove the cast in front of the eiv->iov_base pointer.
  
  Please note that a similar construct already exists in the iSCSI
  target driver. From the nthread.c source file:
  
  			iop->iov_base += rest;
  			iop->iov_len -= rest;
  
  This patch does not change any functionality.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5848 | vlnb | 2014-10-17 04:24:07 +0200 (Fri, 17 Oct 2014) | 12 lines
  
  scst_vdisk: Reduce number of casts
  
  Since 'address' points at kernel space memory, change its type
  from uint8_t __user * into uint8_t *. This change reduces the
  number of casts between uint8_t __user * to uint8_t * in
  fileio_exec_write().
  
  This patch does not change any functionality.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5849 | vlnb | 2014-10-17 04:30:12 +0200 (Fri, 17 Oct 2014) | 10 lines
  
  scst_vdisk, MODE SELECT(10): Interpret both bytes of the BLOCK DESCRIPTOR LENGTH field
  
  While the BLOCK DESCRIPTOR LENGTH field spans a single byte in the
  Mode parameter header(6), the size of this field in the Mode parameter
  header(10) is two bytes. Interpret both bytes while executing a MODE
  SELECT(10) command.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5850 | vlnb | 2014-10-17 04:32:28 +0200 (Fri, 17 Oct 2014) | 8 lines
  
  scst/README: Document the lun<X> sysfs attributes
  
  The sessions/<sess>/lun<X> sysfs attribute "active_commands" is not
  yet documented. Hence add documentation for that sysfs attribute.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5851 | vlnb | 2014-10-17 04:35:01 +0200 (Fri, 17 Oct 2014) | 12 lines
  
  scst, iscsi-scst: Add thread_pid attribute
  
  For SCST devices with a short name determining which SCST command
  threads serve a given LUN requires an (expensive) walk of the
  process table. For SCST devices with a long name it is not possible
  to determine unambiguously which command threads serve a given
  LUN. Hence add a thread_pid sysfs attribute that makes it easy to
  figure out which command threads serve a LUN.
  
  Signed-off-by: Bart Van Assche <bvanassche@acm.org>
........
  r5852 | bvassche | 2014-10-18 10:56:23 +0200 (Sat, 18 Oct 2014) | 5 lines
  
  iscsi-scst: Make iscsi_thread_pool locking more fine-grained
  
  Protect iscsi_thread_pool.threads_list via tp_mutex instead of
  scst_mutex.
........
  r5853 | bvassche | 2014-10-24 09:12:39 +0200 (Fri, 24 Oct 2014) | 1 line
  
  nightly build: Update kernel versions
........
  r5854 | bvassche | 2014-11-01 10:30:20 +0200 (Sat, 01 Nov 2014) | 1 line
  
  nightly build: Update kernel versions
........
  r5855 | vlnb | 2014-11-15 03:44:06 +0200 (Sat, 15 Nov 2014) | 3 lines
  
  Ease severity of reporting unsupported REPORT LUNS SELECT REPORT value
........
  r5856 | vlnb | 2014-11-15 03:55:27 +0200 (Sat, 15 Nov 2014) | 3 lines
  
  Report RX data digest failures by default
........


git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/iser@5873 d57e44dd-8a1f-0410-8b47-8ef2f437770f
2014-11-16 13:51:38 +00:00

244 lines
6.1 KiB
C

/*
* iSCSI digest handling.
*
* Copyright (C) 2004 - 2006 Xiranet Communications GmbH
* <arne.redlich@xiranet.com>
* Copyright (C) 2007 - 2014 Vladislav Bolkhovitin
* Copyright (C) 2007 - 2014 Fusion-io, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/types.h>
#include <linux/scatterlist.h>
#include "iscsi.h"
#include "digest.h"
#include <linux/crc32c.h>
void digest_alg_available(int *val)
{
#if defined(CONFIG_LIBCRC32C_MODULE) || defined(CONFIG_LIBCRC32C)
int crc32c = 1;
#else
int crc32c = 0;
#endif
if ((*val & DIGEST_CRC32C) && !crc32c) {
PRINT_ERROR("%s", "CRC32C digest algorithm not available "
"in kernel");
*val |= ~DIGEST_CRC32C;
}
}
/**
* initialize support for digest calculation.
*
* digest_init -
* @conn: ptr to connection to make use of digests
*
* @return: 0 on success, < 0 on error
*/
int digest_init(struct iscsi_conn *conn)
{
if (!(conn->hdigest_type & DIGEST_ALL))
conn->hdigest_type = DIGEST_NONE;
if (!(conn->ddigest_type & DIGEST_ALL))
conn->ddigest_type = DIGEST_NONE;
return 0;
}
static __be32 evaluate_crc32_from_sg(struct scatterlist *sg, int nbytes,
uint32_t padding)
{
u32 crc = ~0;
int pad_bytes = ((nbytes + 3) & -4) - nbytes;
#ifdef CONFIG_SCST_ISCSI_DEBUG_DIGEST_FAILURES
if (((scst_random() % 100000) == 752)) {
PRINT_INFO("%s", "Simulating digest failure");
return 0;
}
#endif
#if defined(CONFIG_LIBCRC32C_MODULE) || defined(CONFIG_LIBCRC32C)
while (nbytes > 0) {
int d = min(nbytes, (int)(sg->length));
crc = crc32c(crc, sg_virt(sg), d);
nbytes -= d;
sg++;
}
if (pad_bytes)
crc = crc32c(crc, (u8 *)&padding, pad_bytes);
#endif
return (__force __be32)~cpu_to_le32(crc);
}
static __be32 digest_header(struct iscsi_pdu *pdu)
{
struct scatterlist sg[2];
unsigned int nbytes = sizeof(struct iscsi_hdr);
int asize = (pdu->ahssize + 3) & -4;
sg_init_table(sg, 2);
sg_set_buf(&sg[0], &pdu->bhs, nbytes);
if (pdu->ahssize) {
sg_set_buf(&sg[1], pdu->ahs, asize);
nbytes += asize;
}
EXTRACHECKS_BUG_ON((nbytes & 3) != 0);
return evaluate_crc32_from_sg(sg, nbytes, 0);
}
static __be32 digest_data(struct iscsi_cmnd *cmd, u32 size, u32 offset,
uint32_t padding)
{
struct scatterlist *sg = cmd->sg;
int idx, count;
struct scatterlist saved_sg;
__be32 crc;
offset += sg[0].offset;
idx = offset >> PAGE_SHIFT;
offset &= ~PAGE_MASK;
count = get_pgcnt(size, offset);
TRACE_DBG("req %p, idx %d, count %d, sg_cnt %d, size %d, "
"offset %d", cmd, idx, count, cmd->sg_cnt, size, offset);
sBUG_ON(idx + count > cmd->sg_cnt);
saved_sg = sg[idx];
sg[idx].offset = offset;
sg[idx].length -= offset - saved_sg.offset;
crc = evaluate_crc32_from_sg(sg + idx, size, padding);
sg[idx] = saved_sg;
return crc;
}
int digest_rx_header(struct iscsi_cmnd *cmnd)
{
__be32 crc;
crc = digest_header(&cmnd->pdu);
if (unlikely(crc != cmnd->hdigest)) {
PRINT_ERROR("%s", "RX header digest failed");
return -EIO;
} else
TRACE_DBG("RX header digest OK for cmd %p", cmnd);
return 0;
}
void digest_tx_header(struct iscsi_cmnd *cmnd)
{
cmnd->hdigest = digest_header(&cmnd->pdu);
TRACE_DBG("TX header digest for cmd %p: %x", cmnd, cmnd->hdigest);
}
int digest_rx_data(struct iscsi_cmnd *cmnd)
{
struct iscsi_cmnd *req;
struct iscsi_data_out_hdr *req_hdr;
u32 offset;
__be32 crc;
int res = 0;
switch (cmnd_opcode(cmnd)) {
case ISCSI_OP_SCSI_DATA_OUT:
req = cmnd->cmd_req;
if (unlikely(req == NULL)) {
/* It can be for prelim completed commands */
req = cmnd;
goto out;
}
req_hdr = (struct iscsi_data_out_hdr *)&cmnd->pdu.bhs;
offset = be32_to_cpu(req_hdr->buffer_offset);
break;
default:
req = cmnd;
offset = 0;
}
/*
* We need to skip the digest check for prelim completed commands,
* because we use shared data buffer for them, so, most likely, the
* check will fail. Plus, for such commands we sometimes don't have
* sg_cnt set correctly (cmnd_prepare_get_rejected_cmd_data() doesn't
* do it).
*/
if (unlikely(req->prelim_compl_flags != 0))
goto out;
/*
* Temporary to not crash with write residual overflows. ToDo. Until
* that let's always have succeeded data digests for such overflows.
* In ideal, we should allocate additional one or more sg's for the
* overflowed data and free them here or on req release. It's quite
* not trivial for such virtually never used case, so let's do it,
* when it gets needed.
*/
if (unlikely(offset + cmnd->pdu.datasize > req->bufflen)) {
PRINT_WARNING("Skipping RX data digest check for residual "
"overflow command op %x (data size %d, buffer size %d)",
cmnd_hdr(req)->scb[0], offset + cmnd->pdu.datasize,
req->bufflen);
goto out;
}
crc = digest_data(req, cmnd->pdu.datasize, offset,
cmnd->conn->rpadding);
if (unlikely(crc != cmnd->ddigest)) {
PRINT_ERROR("RX data digest failed, stable pages disabled?");
TRACE_MGMT_DBG("Calculated crc %x, ddigest %x, offset %d", crc,
cmnd->ddigest, offset);
iscsi_dump_pdu(&cmnd->pdu);
res = -EIO;
} else
TRACE_DBG("RX data digest OK for cmd %p", cmnd);
out:
return res;
}
void digest_tx_data(struct iscsi_cmnd *cmnd)
{
struct iscsi_data_in_hdr *hdr;
u32 offset;
TRACE_DBG("%s:%d req %p, own_sg %d, sg %p, sgcnt %d cmnd %p, "
"own_sg %d, sg %p, sgcnt %d", __func__, __LINE__,
cmnd->parent_req, cmnd->parent_req->own_sg,
cmnd->parent_req->sg, cmnd->parent_req->sg_cnt,
cmnd, cmnd->own_sg, cmnd->sg, cmnd->sg_cnt);
switch (cmnd_opcode(cmnd)) {
case ISCSI_OP_SCSI_DATA_IN:
hdr = (struct iscsi_data_in_hdr *)&cmnd->pdu.bhs;
offset = be32_to_cpu(hdr->buffer_offset);
break;
default:
offset = 0;
}
cmnd->ddigest = digest_data(cmnd, cmnd->pdu.datasize, offset, 0);
TRACE_DBG("TX data digest for cmd %p: %x (offset %d, opcode %x)", cmnd,
cmnd->ddigest, offset, cmnd_opcode(cmnd));
}