/*
 *  iSCSI digest handling.
 *
 *  Copyright (C) 2004 - 2006 Xiranet Communications GmbH
 *                            <arne.redlich@xiranet.com>
 *  Copyright (C) 2007 - 2018 Vladislav Bolkhovitin
 *  Copyright (C) 2007 - 2018 Western Digital Corporation
 *
 *  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_trace_flag.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("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;

#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)
	{
		int pad_bytes = ((nbytes + 3) & -4) - nbytes;

		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));
}
