2 * iSCSI digest handling.
4 * Copyright (C) 2004 - 2006 Xiranet Communications GmbH <arne.redlich@xiranet.com>
5 * Copyright (C) 2007 Vladislav Bolkhovitin
6 * Copyright (C) 2007 CMS Distribution Limited
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
18 #include <linux/types.h>
19 #include <linux/scatterlist.h>
23 #include <linux/crc32c.h>
25 void digest_alg_available(unsigned int *val)
27 #if defined(CONFIG_LIBCRC32C_MODULE) || defined(CONFIG_LIBCRC32C)
33 if ((*val & DIGEST_CRC32C) && !crc32c) {
34 PRINT_ERROR("%s", "CRC32C digest algorithm not available "
36 *val |= ~DIGEST_CRC32C;
41 * initialize support for digest calculation.
44 * @conn: ptr to connection to make use of digests
46 * @return: 0 on success, < 0 on error
48 int digest_init(struct iscsi_conn *conn)
50 if (!(conn->hdigest_type & DIGEST_ALL))
51 conn->hdigest_type = DIGEST_NONE;
53 if (!(conn->ddigest_type & DIGEST_ALL))
54 conn->ddigest_type = DIGEST_NONE;
59 static u32 evaluate_crc32_from_sg(struct scatterlist *sg, int total,
64 #ifdef DEBUG_DIGEST_FAILURES
65 if (((scst_random() % 100000) == 752)) {
66 PRINT_INFO("%s", "Simulating digest failure");
71 #if defined(CONFIG_LIBCRC32C_MODULE) || defined(CONFIG_LIBCRC32C)
73 int d = min(min(total, (int)(sg->length)),
74 (int)(PAGE_SIZE - sg->offset));
76 crc = crc32c(crc, sg_virt(sg), d);
84 * Digest includes also padding for aligned pdu length, hopefully
85 * it is always filled with 0s in pdu (according to crypto/crc32c.c
87 crc = crc32c(crc, (u8 *)&padding, pad_bytes);
91 return ~cpu_to_le32(crc);
94 static u32 digest_header(struct iscsi_pdu *pdu)
96 struct scatterlist sg[2];
97 unsigned int nbytes = sizeof(struct iscsi_hdr);
101 sg_set_buf(&sg[0], &pdu->bhs, nbytes);
103 sg_set_buf(&sg[1], pdu->ahs, pdu->ahssize);
104 nbytes += pdu->ahssize;
106 return evaluate_crc32_from_sg(sg, nbytes, 0);
109 static u32 digest_data(struct iscsi_cmnd *cmd, u32 osize, u32 offset)
111 struct scatterlist *sg = cmd->sg;
113 struct scatterlist saved_sg;
114 u32 size = (osize + 3) & ~3;
117 offset += sg[0].offset;
118 idx = offset >> PAGE_SHIFT;
119 offset &= ~PAGE_MASK;
121 count = get_pgcnt(size, offset);
123 TRACE_DBG("req %p, idx %d, count %d, sg_cnt %d, size %d, "
124 "offset %d", cmd, idx, count, cmd->sg_cnt, size, offset);
125 sBUG_ON(idx + count > cmd->sg_cnt);
126 sBUG_ON(count > ISCSI_CONN_IOV_MAX);
129 sg[idx].offset = offset;
130 sg[idx].length -= offset - saved_sg.offset;
132 crc = evaluate_crc32_from_sg(sg + idx, osize, size - osize);
138 int digest_rx_header(struct iscsi_cmnd *cmnd)
142 crc = digest_header(&cmnd->pdu);
143 if (unlikely(crc != cmnd->hdigest)) {
144 PRINT_ERROR("%s", "RX header digest failed");
147 TRACE_DBG("RX header digest OK for cmd %p", cmnd);
152 void digest_tx_header(struct iscsi_cmnd *cmnd)
154 cmnd->hdigest = digest_header(&cmnd->pdu);
155 TRACE_DBG("TX header digest for cmd %p: %x", cmnd, cmnd->hdigest);
158 int digest_rx_data(struct iscsi_cmnd *cmnd)
160 struct iscsi_cmnd *req;
161 struct iscsi_data_out_hdr *req_hdr;
165 if (unlikely(cmnd->rejected))
168 switch (cmnd_opcode(cmnd)) {
169 case ISCSI_OP_SCSI_DATA_OUT:
171 req_hdr = (struct iscsi_data_out_hdr *)&cmnd->pdu.bhs;
172 offset = be32_to_cpu(req_hdr->buffer_offset);
180 crc = digest_data(req, cmnd->pdu.datasize, offset);
182 if (unlikely(crc != cmnd->ddigest)) {
183 PRINT_ERROR("%s", "RX data digest failed");
186 TRACE_DBG("RX data digest OK for cmd %p", cmnd);
192 void digest_tx_data(struct iscsi_cmnd *cmnd)
194 struct iscsi_data_in_hdr *hdr;
197 TRACE_DBG("%s:%d req %p, own_sg %d, sg %p, sgcnt %d cmnd %p, "
198 "own_sg %d, sg %p, sgcnt %d", __func__, __LINE__,
199 cmnd->parent_req, cmnd->parent_req->own_sg,
200 cmnd->parent_req->sg, cmnd->parent_req->sg_cnt,
201 cmnd, cmnd->own_sg, cmnd->sg, cmnd->sg_cnt);
203 switch (cmnd_opcode(cmnd)) {
204 case ISCSI_OP_SCSI_DATA_IN:
205 hdr = (struct iscsi_data_in_hdr *)&cmnd->pdu.bhs;
206 offset = be32_to_cpu(hdr->buffer_offset);
213 * cmnd is used here regardless of its sg comes from parent or was
214 * allocated for this cmnd only, see cmnd_send_pdu()
216 cmnd->ddigest = digest_data(cmnd, cmnd->pdu.datasize, offset);
217 TRACE_DBG("TX data digest for cmd %p: %x (offset %d, opcode %x)", cmnd,
218 cmnd->ddigest, offset, cmnd_opcode(cmnd));