~ubuntu-branches/ubuntu/vivid/linux-ti-omap/vivid

« back to all changes in this revision

Viewing changes to ubuntu/iscsitarget/digest.c

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Bader, Amit Kucheria
  • Date: 2010-03-23 18:05:12 UTC
  • Revision ID: james.westby@ubuntu.com-20100323180512-iavj906ocnphdubp
Tags: 2.6.33-500.3
[ Amit Kucheria ]

* [Config] Fix the debug package name to end in -dbgsym
* SAUCE: Add the ubuntu/ drivers to omap
* SAUCE: Re-export the symbols for aufs
* [Config] Enable AUFS and COMPCACHE

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * iSCSI digest handling.
 
3
 * (C) 2004 - 2006 Xiranet Communications GmbH <arne.redlich@xiranet.com>
 
4
 * This code is licensed under the GPL.
 
5
 */
 
6
 
 
7
#include <linux/types.h>
 
8
 
 
9
#include "iscsi.h"
 
10
#include "digest.h"
 
11
#include "iscsi_dbg.h"
 
12
 
 
13
void digest_alg_available(unsigned int *val)
 
14
{
 
15
        if (*val & DIGEST_CRC32C &&
 
16
            !crypto_has_alg("crc32c", 0, CRYPTO_ALG_ASYNC)) {
 
17
                printk("CRC32C digest algorithm not available in kernel\n");
 
18
                *val |= ~DIGEST_CRC32C;
 
19
        }
 
20
}
 
21
 
 
22
/**
 
23
 * initialize support for digest calculation.
 
24
 *
 
25
 * digest_init -
 
26
 * @conn: ptr to connection to make use of digests
 
27
 *
 
28
 * @return: 0 on success, < 0 on error
 
29
 */
 
30
int digest_init(struct iscsi_conn *conn)
 
31
{
 
32
        int err = 0;
 
33
 
 
34
        if (!(conn->hdigest_type & DIGEST_ALL))
 
35
                conn->hdigest_type = DIGEST_NONE;
 
36
 
 
37
        if (!(conn->ddigest_type & DIGEST_ALL))
 
38
                conn->ddigest_type = DIGEST_NONE;
 
39
 
 
40
        if (conn->hdigest_type & DIGEST_CRC32C ||
 
41
            conn->ddigest_type & DIGEST_CRC32C) {
 
42
                conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
 
43
                                                      CRYPTO_ALG_ASYNC);
 
44
                conn->rx_hash.flags = 0;
 
45
                if (IS_ERR(conn->rx_hash.tfm)) {
 
46
                        conn->rx_hash.tfm = NULL;
 
47
                        err = -ENOMEM;
 
48
                        goto out;
 
49
                }
 
50
 
 
51
                conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
 
52
                                                      CRYPTO_ALG_ASYNC);
 
53
                conn->tx_hash.flags = 0;
 
54
                if (IS_ERR(conn->tx_hash.tfm)) {
 
55
                        conn->tx_hash.tfm = NULL;
 
56
                        err = -ENOMEM;
 
57
                        goto out;
 
58
                }
 
59
        }
 
60
 
 
61
out:
 
62
        if (err)
 
63
                digest_cleanup(conn);
 
64
 
 
65
        return err;
 
66
}
 
67
 
 
68
/**
 
69
 * free resources used for digest calculation.
 
70
 *
 
71
 * digest_cleanup -
 
72
 * @conn: ptr to connection that made use of digests
 
73
 */
 
74
void digest_cleanup(struct iscsi_conn *conn)
 
75
{
 
76
        if (conn->tx_hash.tfm)
 
77
                crypto_free_hash(conn->tx_hash.tfm);
 
78
        if (conn->rx_hash.tfm)
 
79
                crypto_free_hash(conn->rx_hash.tfm);
 
80
}
 
81
 
 
82
/**
 
83
 * debug handling of header digest errors:
 
84
 * simulates a digest error after n PDUs / every n-th PDU of type
 
85
 * HDIGEST_ERR_CORRUPT_PDU_TYPE.
 
86
 */
 
87
static inline void __dbg_simulate_header_digest_error(struct iscsi_cmnd *cmnd)
 
88
{
 
89
#define HDIGEST_ERR_AFTER_N_CMNDS 1000
 
90
#define HDIGEST_ERR_ONLY_ONCE     1
 
91
#define HDIGEST_ERR_CORRUPT_PDU_TYPE ISCSI_OP_SCSI_CMD
 
92
#define HDIGEST_ERR_CORRUPT_PDU_WITH_DATA_ONLY 0
 
93
 
 
94
        static int num_cmnds = 0;
 
95
        static int num_errs = 0;
 
96
 
 
97
        if (cmnd_opcode(cmnd) == HDIGEST_ERR_CORRUPT_PDU_TYPE) {
 
98
                if (HDIGEST_ERR_CORRUPT_PDU_WITH_DATA_ONLY) {
 
99
                        if (cmnd->pdu.datasize)
 
100
                                num_cmnds++;
 
101
                } else
 
102
                        num_cmnds++;
 
103
        }
 
104
 
 
105
        if ((num_cmnds == HDIGEST_ERR_AFTER_N_CMNDS)
 
106
            && (!(HDIGEST_ERR_ONLY_ONCE && num_errs))) {
 
107
                printk("*** Faking header digest error ***\n");
 
108
                printk("\tcmnd: 0x%x, itt 0x%x, sn 0x%x\n",
 
109
                       cmnd_opcode(cmnd),
 
110
                       be32_to_cpu(cmnd->pdu.bhs.itt),
 
111
                       be32_to_cpu(cmnd->pdu.bhs.sn));
 
112
                cmnd->hdigest = ~cmnd->hdigest;
 
113
                /* make things even worse by manipulating header fields */
 
114
                cmnd->pdu.datasize += 8;
 
115
                num_errs++;
 
116
                num_cmnds = 0;
 
117
        }
 
118
        return;
 
119
}
 
120
 
 
121
/**
 
122
 * debug handling of data digest errors:
 
123
 * simulates a digest error after n PDUs / every n-th PDU of type
 
124
 * DDIGEST_ERR_CORRUPT_PDU_TYPE.
 
125
 */
 
126
static inline void __dbg_simulate_data_digest_error(struct iscsi_cmnd *cmnd)
 
127
{
 
128
#define DDIGEST_ERR_AFTER_N_CMNDS 50
 
129
#define DDIGEST_ERR_ONLY_ONCE     1
 
130
#define DDIGEST_ERR_CORRUPT_PDU_TYPE   ISCSI_OP_SCSI_DATA_OUT
 
131
#define DDIGEST_ERR_CORRUPT_UNSOL_DATA_ONLY 0
 
132
 
 
133
        static int num_cmnds = 0;
 
134
        static int num_errs = 0;
 
135
 
 
136
        if ((cmnd->pdu.datasize)
 
137
            && (cmnd_opcode(cmnd) == DDIGEST_ERR_CORRUPT_PDU_TYPE)) {
 
138
                switch (cmnd_opcode(cmnd)) {
 
139
                case ISCSI_OP_SCSI_DATA_OUT:
 
140
                        if ((DDIGEST_ERR_CORRUPT_UNSOL_DATA_ONLY)
 
141
                            && (cmnd->pdu.bhs.ttt != ISCSI_RESERVED_TAG))
 
142
                                break;
 
143
                default:
 
144
                        num_cmnds++;
 
145
                }
 
146
        }
 
147
 
 
148
        if ((num_cmnds == DDIGEST_ERR_AFTER_N_CMNDS)
 
149
            && (!(DDIGEST_ERR_ONLY_ONCE && num_errs))
 
150
            && (cmnd->pdu.datasize)
 
151
            && (!cmnd->conn->read_overflow)) {
 
152
                printk("*** Faking data digest error: ***");
 
153
                printk("\tcmnd 0x%x, itt 0x%x, sn 0x%x\n",
 
154
                       cmnd_opcode(cmnd),
 
155
                       be32_to_cpu(cmnd->pdu.bhs.itt),
 
156
                       be32_to_cpu(cmnd->pdu.bhs.sn));
 
157
                cmnd->ddigest = ~cmnd->ddigest;
 
158
                num_errs++;
 
159
                num_cmnds = 0;
 
160
        }
 
161
}
 
162
 
 
163
static void digest_header(struct hash_desc *hash, struct iscsi_pdu *pdu,
 
164
                          u8 *crc)
 
165
{
 
166
        struct scatterlist sg[2];
 
167
        unsigned int nbytes = sizeof(struct iscsi_hdr);
 
168
 
 
169
        sg_init_table(sg, pdu->ahssize ? 2 : 1);
 
170
 
 
171
        sg_set_buf(&sg[0], &pdu->bhs, nbytes);
 
172
        if (pdu->ahssize) {
 
173
                sg_set_buf(&sg[1], pdu->ahs, pdu->ahssize);
 
174
                nbytes += pdu->ahssize;
 
175
        }
 
176
 
 
177
        crypto_hash_init(hash);
 
178
        crypto_hash_update(hash, sg, nbytes);
 
179
        crypto_hash_final(hash, crc);
 
180
}
 
181
 
 
182
int digest_rx_header(struct iscsi_cmnd *cmnd)
 
183
{
 
184
        u32 crc;
 
185
 
 
186
        digest_header(&cmnd->conn->rx_hash, &cmnd->pdu, (u8 *) &crc);
 
187
        if (crc != cmnd->hdigest)
 
188
                return -EIO;
 
189
 
 
190
        return 0;
 
191
}
 
192
 
 
193
void digest_tx_header(struct iscsi_cmnd *cmnd)
 
194
{
 
195
        digest_header(&cmnd->conn->tx_hash, &cmnd->pdu, (u8 *) &cmnd->hdigest);
 
196
}
 
197
 
 
198
static void digest_data(struct hash_desc *hash, struct iscsi_cmnd *cmnd,
 
199
                        struct tio *tio, u32 offset, u8 *crc)
 
200
{
 
201
        struct scatterlist *sg = cmnd->conn->hash_sg;
 
202
        u32 size, length;
 
203
        int i, idx, count;
 
204
        unsigned int nbytes;
 
205
 
 
206
        size = cmnd->pdu.datasize;
 
207
        nbytes = size = (size + 3) & ~3;
 
208
 
 
209
        offset += tio->offset;
 
210
        idx = offset >> PAGE_CACHE_SHIFT;
 
211
        offset &= ~PAGE_CACHE_MASK;
 
212
        count = get_pgcnt(size, offset);
 
213
        assert(idx + count <= tio->pg_cnt);
 
214
 
 
215
        assert(count <= ISCSI_CONN_IOV_MAX);
 
216
 
 
217
        sg_init_table(sg, ARRAY_SIZE(cmnd->conn->hash_sg));
 
218
        crypto_hash_init(hash);
 
219
 
 
220
        for (i = 0; size; i++) {
 
221
                if (offset + size > PAGE_CACHE_SIZE)
 
222
                        length = PAGE_CACHE_SIZE - offset;
 
223
                else
 
224
                        length = size;
 
225
 
 
226
                sg_set_page(&sg[i], tio->pvec[idx + i], length, offset);
 
227
                size -= length;
 
228
                offset = 0;
 
229
        }
 
230
 
 
231
        sg_mark_end(&sg[i - 1]);
 
232
 
 
233
        crypto_hash_update(hash, sg, nbytes);
 
234
        crypto_hash_final(hash, crc);
 
235
}
 
236
 
 
237
int digest_rx_data(struct iscsi_cmnd *cmnd)
 
238
{
 
239
        struct tio *tio;
 
240
        struct iscsi_cmnd *scsi_cmnd;
 
241
        struct iscsi_data_out_hdr *req;
 
242
        u32 offset, crc;
 
243
 
 
244
        switch (cmnd_opcode(cmnd)) {
 
245
        case ISCSI_OP_SCSI_REJECT:
 
246
        case ISCSI_OP_PDU_REJECT:
 
247
        case ISCSI_OP_DATA_REJECT:
 
248
                return 0;
 
249
        case ISCSI_OP_SCSI_DATA_OUT:
 
250
                scsi_cmnd = cmnd->req;
 
251
                req = (struct iscsi_data_out_hdr *) &cmnd->pdu.bhs;
 
252
                tio = scsi_cmnd->tio;
 
253
                offset = be32_to_cpu(req->buffer_offset);
 
254
                break;
 
255
        default:
 
256
                tio = cmnd->tio;
 
257
                offset = 0;
 
258
        }
 
259
 
 
260
        digest_data(&cmnd->conn->rx_hash, cmnd, tio, offset, (u8 *) &crc);
 
261
 
 
262
        if (!cmnd->conn->read_overflow &&
 
263
            (cmnd_opcode(cmnd) != ISCSI_OP_PDU_REJECT)) {
 
264
                if (crc != cmnd->ddigest)
 
265
                        return -EIO;
 
266
        }
 
267
 
 
268
        return 0;
 
269
}
 
270
 
 
271
void digest_tx_data(struct iscsi_cmnd *cmnd)
 
272
{
 
273
        struct tio *tio = cmnd->tio;
 
274
        struct iscsi_data_out_hdr *req = (struct iscsi_data_out_hdr *)&cmnd->pdu.bhs;
 
275
 
 
276
        assert(tio);
 
277
        digest_data(&cmnd->conn->tx_hash, cmnd, tio,
 
278
                    be32_to_cpu(req->buffer_offset), (u8 *) &cmnd->ddigest);
 
279
}