Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_dif.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2015, Emulex
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 /**
34  * @file
35  *
36  */
37 
38 #include "ocs.h"
39 #include "ocs_dif.h"
40 #include "t10crc16.h"
41 
42 /**
43  * @brief Calculate the T10 PI CRC guard value for a block.
44  *
45  * @param buffer Pointer to the data buffer.
46  * @param size Number of bytes.
47  * @param crc Previously-calculated CRC, or 0 for a new block.
48  *
49  * @return Returns the calculated CRC, which may be passed back in for partial blocks.
50  *
51  */
52 
53 uint16_t
54 ocs_scsi_dif_calc_crc(const uint8_t *buffer, uint32_t size, uint16_t crc)
55 {
56  return t10crc16(buffer, size, crc);
57 }
58 
59 /**
60  * @brief Calculate the IP-checksum guard value for a block.
61  *
62  * @param addrlen array of address length pairs
63  * @param addrlen_count number of entries in the addrlen[] array
64  *
65  * Algorithm:
66  * Sum all all the 16-byte words in the block
67  * Add in the "carry", which is everything in excess of 16-bits
68  * Flip all the bits
69  *
70  * @return Returns the calculated checksum
71  */
72 
73 uint16_t
74 ocs_scsi_dif_calc_checksum(ocs_scsi_vaddr_len_t addrlen[], uint32_t addrlen_count)
75 {
76  uint32_t i, j;
77  uint16_t checksum;
78  uint32_t intermediate; /* Use an intermediate to hold more than 16 bits during calculations */
79  uint32_t count;
80  uint16_t *buffer;
81 
82  intermediate = 0;
83  for (j = 0; j < addrlen_count; j++) {
84  buffer = addrlen[j].vaddr;
85  count = addrlen[j].length / 2;
86  for (i=0; i < count; i++) {
87  intermediate += buffer[i];
88  }
89  }
90 
91  /* Carry is everything over 16 bits */
92  intermediate += ((intermediate & 0xffff0000) >> 16);
93 
94  /* Flip all the bits */
95  intermediate = ~intermediate;
96 
97  checksum = intermediate;
98 
99  return checksum;
100 }
101 
102 /**
103  * @brief Return blocksize given SCSI API DIF block size
104  *
105  * Given the DIF block size enumerated value, return the block size value. (e.g.
106  * OCS_SCSI_DIF_BLK_SIZE_512 returns 512)
107  *
108  * @param dif_info Pointer to SCSI API DIF info block
109  *
110  * @return returns block size, or 0 if SCSI API DIF blocksize is invalid
111  */
112 
113 uint32_t
115 {
116  uint32_t blocksize = 0;
117 
118  switch(dif_info->blk_size) {
119  case OCS_SCSI_DIF_BK_SIZE_512: blocksize = 512; break;
120  case OCS_SCSI_DIF_BK_SIZE_1024: blocksize = 1024; break;
121  case OCS_SCSI_DIF_BK_SIZE_2048: blocksize = 2048; break;
122  case OCS_SCSI_DIF_BK_SIZE_4096: blocksize = 4096; break;
123  case OCS_SCSI_DIF_BK_SIZE_520: blocksize = 520; break;
124  case OCS_SCSI_DIF_BK_SIZE_4104: blocksize = 4104; break;
125  default:
126  break;
127  }
128 
129  return blocksize;
130 }
131 
132 /**
133  * @brief Set SCSI API DIF blocksize
134  *
135  * Given a blocksize value (512, 1024, etc.), set the SCSI API DIF blocksize
136  * in the DIF info block
137  *
138  * @param dif_info Pointer to the SCSI API DIF info block
139  * @param blocksize Block size
140  *
141  * @return returns 0 for success, a negative error code value for failure.
142  */
143 
144 int32_t
145 ocs_scsi_dif_set_blocksize(ocs_scsi_dif_info_t *dif_info, uint32_t blocksize)
146 {
147  int32_t rc = 0;
148 
149  switch(blocksize) {
150  case 512: dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_512; break;
151  case 1024: dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_1024; break;
152  case 2048: dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_2048; break;
153  case 4096: dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_4096; break;
154  case 520: dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_520; break;
155  case 4104: dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_4104; break;
156  default:
157  rc = -1;
158  break;
159  }
160  return rc;
161 
162 }
163 
164 /**
165  * @brief Return memory block size given SCSI DIF API
166  *
167  * The blocksize in memory for the DIF transfer is returned, given the SCSI DIF info
168  * block and the direction of transfer.
169  *
170  * @param dif_info Pointer to DIF info block
171  * @param wiretomem Transfer direction, 1 is wire to memory, 0 is memory to wire
172  *
173  * @return Memory blocksize, or negative error value
174  *
175  * WARNING: the order of initialization of the adj[] arrays MUST match the declarations
176  * of OCS_SCSI_DIF_OPER_*
177  */
178 
179 int32_t
181 {
182  uint32_t blocksize;
183  uint8_t wiretomem_adj[] = {
184  0, // OCS_SCSI_DIF_OPER_DISABLED,
185  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CRC,
186  0, // OCS_SCSI_DIF_OPER_IN_CRC_OUT_NODIF,
187  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CHKSUM,
188  0, // OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_NODIF,
189  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CRC_OUT_CRC,
190  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CHKSUM,
191  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CRC_OUT_CHKSUM,
192  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CRC,
193  DIF_SIZE}; // OCS_SCSI_DIF_OPER_IN_RAW_OUT_RAW,
194  uint8_t memtowire_adj[] = {
195  0, // OCS_SCSI_DIF_OPER_DISABLED,
196  0, // OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CRC,
197  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CRC_OUT_NODIF,
198  0, // OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CHKSUM,
199  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_NODIF,
200  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CRC_OUT_CRC,
201  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CHKSUM,
202  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CRC_OUT_CHKSUM,
203  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CRC,
204  DIF_SIZE}; // OCS_SCSI_DIF_OPER_IN_RAW_OUT_RAW,
205 
206  blocksize = ocs_scsi_dif_blocksize(dif_info);
207  if (blocksize == 0) {
208  return -1;
209  }
210 
211  if (wiretomem) {
212  ocs_assert(dif_info->dif_oper < ARRAY_SIZE(wiretomem_adj), 0);
213  blocksize += wiretomem_adj[dif_info->dif_oper];
214  } else { /* mem to wire */
215  ocs_assert(dif_info->dif_oper < ARRAY_SIZE(memtowire_adj), 0);
216  blocksize += memtowire_adj[dif_info->dif_oper];
217  }
218  return blocksize;
219 }
220 
221 /**
222  * @brief Return wire block size given SCSI DIF API
223  *
224  * The blocksize on the wire for the DIF transfer is returned, given the SCSI DIF info
225  * block and the direction of transfer.
226  *
227  * @param dif_info Pointer to DIF info block
228  * @param wiretomem Transfer direction, 1 is wire to memory, 0 is memory to wire
229  *
230  * @return Wire blocksize or negative error value
231  *
232  * WARNING: the order of initialization of the adj[] arrays MUST match the declarations
233  * of OCS_SCSI_DIF_OPER_*
234  */
235 
236 int32_t
238 {
239  uint32_t blocksize;
240  uint8_t wiretomem_adj[] = {
241  0, // OCS_SCSI_DIF_OPER_DISABLED,
242  0, // OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CRC,
243  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CRC_OUT_NODIF,
244  0, // OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CHKSUM,
245  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_NODIF,
246  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CRC_OUT_CRC,
247  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CHKSUM,
248  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CRC_OUT_CHKSUM,
249  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CRC,
250  DIF_SIZE}; // OCS_SCSI_DIF_OPER_IN_RAW_OUT_RAW,
251  uint8_t memtowire_adj[] = {
252  0, // OCS_SCSI_DIF_OPER_DISABLED,
253  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CRC,
254  0, // OCS_SCSI_DIF_OPER_IN_CRC_OUT_NODIF,
255  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CHKSUM,
256  0, // OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_NODIF,
257  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CRC_OUT_CRC,
258  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CHKSUM,
259  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CRC_OUT_CHKSUM,
260  DIF_SIZE, // OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CRC,
261  DIF_SIZE}; // OCS_SCSI_DIF_OPER_IN_RAW_OUT_RAW,
262 
263 
264  blocksize = ocs_scsi_dif_blocksize(dif_info);
265  if (blocksize == 0) {
266  return -1;
267  }
268 
269  if (wiretomem) {
270  ocs_assert(dif_info->dif_oper < ARRAY_SIZE(wiretomem_adj), 0);
271  blocksize += wiretomem_adj[dif_info->dif_oper];
272  } else { /* mem to wire */
273  ocs_assert(dif_info->dif_oper < ARRAY_SIZE(memtowire_adj), 0);
274  blocksize += memtowire_adj[dif_info->dif_oper];
275  }
276 
277  return blocksize;
278 }
279 /**
280  * @brief Return blocksize given HAL API DIF block size
281  *
282  * Given the DIF block size enumerated value, return the block size value. (e.g.
283  * OCS_SCSI_DIF_BLK_SIZE_512 returns 512)
284  *
285  * @param dif_info Pointer to HAL API DIF info block
286  *
287  * @return returns block size, or 0 if HAL API DIF blocksize is invalid
288  */
289 
290 uint32_t
292 {
293  uint32_t blocksize = 0;
294 
295  switch(dif_info->blk_size) {
296  case OCS_HAL_DIF_BK_SIZE_512: blocksize = 512; break;
297  case OCS_HAL_DIF_BK_SIZE_1024: blocksize = 1024; break;
298  case OCS_HAL_DIF_BK_SIZE_2048: blocksize = 2048; break;
299  case OCS_HAL_DIF_BK_SIZE_4096: blocksize = 4096; break;
300  case OCS_HAL_DIF_BK_SIZE_520: blocksize = 520; break;
301  case OCS_HAL_DIF_BK_SIZE_4104: blocksize = 4104; break;
302  default:
303  break;
304  }
305 
306  return blocksize;
307 }
308 
309 /**
310  * @brief Return memory block size given HAL DIF API
311  *
312  * The blocksize in memory for the DIF transfer is returned, given the HAL DIF info
313  * block and the direction of transfer.
314  *
315  * @param dif_info Pointer to DIF info block
316  * @param wiretomem Transfer direction, 1 is wire to memory, 0 is memory to wire
317  *
318  * @return Memory blocksize, or negative error value
319  *
320  * WARNING: the order of initialization of the adj[] arrays MUST match the declarations
321  * of OCS_HAL_DIF_OPER_*
322  */
323 
324 int32_t
326 {
327  uint32_t blocksize;
328  uint8_t wiretomem_adj[] = {
329  0, // OCS_HAL_DIF_OPER_DISABLED,
330  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_NODIF_OUT_CRC,
331  0, // OCS_HAL_DIF_OPER_IN_CRC_OUT_NODIF,
332  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_NODIF_OUT_CHKSUM,
333  0, // OCS_HAL_DIF_OPER_IN_CHKSUM_OUT_NODIF,
334  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CRC_OUT_CRC,
335  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CHKSUM_OUT_CHKSUM,
336  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CRC_OUT_CHKSUM,
337  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CHKSUM_OUT_CRC,
338  DIF_SIZE}; // OCS_HAL_DIF_OPER_IN_RAW_OUT_RAW,
339  uint8_t memtowire_adj[] = {
340  0, // OCS_HAL_DIF_OPER_DISABLED,
341  0, // OCS_HAL_DIF_OPER_IN_NODIF_OUT_CRC,
342  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CRC_OUT_NODIF,
343  0, // OCS_HAL_DIF_OPER_IN_NODIF_OUT_CHKSUM,
344  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CHKSUM_OUT_NODIF,
345  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CRC_OUT_CRC,
346  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CHKSUM_OUT_CHKSUM,
347  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CRC_OUT_CHKSUM,
348  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CHKSUM_OUT_CRC,
349  DIF_SIZE}; // OCS_HAL_DIF_OPER_IN_RAW_OUT_RAW,
350 
351  blocksize = ocs_hal_dif_blocksize(dif_info);
352  if (blocksize == 0) {
353  return -1;
354  }
355 
356  if (wiretomem) {
357  ocs_assert(dif_info->dif_oper < ARRAY_SIZE(wiretomem_adj), 0);
358  blocksize += wiretomem_adj[dif_info->dif_oper];
359  } else { /* mem to wire */
360  ocs_assert(dif_info->dif_oper < ARRAY_SIZE(memtowire_adj), 0);
361  blocksize += memtowire_adj[dif_info->dif_oper];
362  }
363  return blocksize;
364 }
365 
366 /**
367  * @brief Return wire block size given HAL DIF API
368  *
369  * The blocksize on the wire for the DIF transfer is returned, given the HAL DIF info
370  * block and the direction of transfer.
371  *
372  * @param dif_info Pointer to DIF info block
373  * @param wiretomem Transfer direction, 1 is wire to memory, 0 is memory to wire
374  *
375  * @return Wire blocksize or negative error value
376  *
377  * WARNING: the order of initialization of the adj[] arrays MUST match the declarations
378  * of OCS_HAL_DIF_OPER_*
379  */
380 
381 int32_t
383 {
384  uint32_t blocksize;
385  uint8_t wiretomem_adj[] = {
386  0, // OCS_HAL_DIF_OPER_DISABLED,
387  0, // OCS_HAL_DIF_OPER_IN_NODIF_OUT_CRC,
388  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CRC_OUT_NODIF,
389  0, // OCS_HAL_DIF_OPER_IN_NODIF_OUT_CHKSUM,
390  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CHKSUM_OUT_NODIF,
391  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CRC_OUT_CRC,
392  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CHKSUM_OUT_CHKSUM,
393  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CRC_OUT_CHKSUM,
394  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CHKSUM_OUT_CRC,
395  DIF_SIZE}; // OCS_HAL_DIF_OPER_IN_RAW_OUT_RAW,
396  uint8_t memtowire_adj[] = {
397  0, // OCS_HAL_DIF_OPER_DISABLED,
398  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_NODIF_OUT_CRC,
399  0, // OCS_HAL_DIF_OPER_IN_CRC_OUT_NODIF,
400  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_NODIF_OUT_CHKSUM,
401  0, // OCS_HAL_DIF_OPER_IN_CHKSUM_OUT_NODIF,
402  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CRC_OUT_CRC,
403  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CHKSUM_OUT_CHKSUM,
404  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CRC_OUT_CHKSUM,
405  DIF_SIZE, // OCS_HAL_DIF_OPER_IN_CHKSUM_OUT_CRC,
406  DIF_SIZE}; // OCS_HAL_DIF_OPER_IN_RAW_OUT_RAW,
407 
408 
409  blocksize = ocs_hal_dif_blocksize(dif_info);
410  if (blocksize == 0) {
411  return -1;
412  }
413 
414  if (wiretomem) {
415  ocs_assert(dif_info->dif_oper < ARRAY_SIZE(wiretomem_adj), 0);
416  blocksize += wiretomem_adj[dif_info->dif_oper];
417  } else { /* mem to wire */
418  ocs_assert(dif_info->dif_oper < ARRAY_SIZE(memtowire_adj), 0);
419  blocksize += memtowire_adj[dif_info->dif_oper];
420  }
421 
422  return blocksize;
423 }
int32_t ocs_hal_dif_wire_blocksize(ocs_hal_dif_info_t *dif_info, int wiretomem)
Return wire block size given HAL DIF API.
Definition: ocs_dif.c:382
T10 DIF information passed to the transport.
Definition: ocs_scsi.h:229
T10 DIF information passed to the transport.
Definition: ocs_hal.h:400
#define DIF_SIZE
Definition: ocs_scsi.h:179
int32_t ocs_scsi_dif_mem_blocksize(ocs_scsi_dif_info_t *dif_info, int wiretomem)
Return memory block size given SCSI DIF API.
Definition: ocs_dif.c:180
ocs_scsi_dif_blk_size_e blk_size
Definition: ocs_scsi.h:231
uint16_t ocs_scsi_dif_calc_checksum(ocs_scsi_vaddr_len_t addrlen[], uint32_t addrlen_count)
Calculate the IP-checksum guard value for a block.
Definition: ocs_dif.c:74
int32_t ocs_hal_dif_mem_blocksize(ocs_hal_dif_info_t *dif_info, int wiretomem)
Return memory block size given HAL DIF API.
Definition: ocs_dif.c:325
uint32_t ocs_hal_dif_blocksize(ocs_hal_dif_info_t *dif_info)
Return blocksize given HAL API DIF block size.
Definition: ocs_dif.c:291
unsigned short t10crc16(const unsigned char *blk_adr, unsigned long blk_len, unsigned short crc)
Calculate the T10 PI CRC guard value for a block.
Definition: t10crc16.c:120
ocs_hal_dif_oper_e dif_oper
Definition: ocs_hal.h:401
int32_t ocs_scsi_dif_wire_blocksize(ocs_scsi_dif_info_t *dif_info, int wiretomem)
Return wire block size given SCSI DIF API.
Definition: ocs_dif.c:237
#define ocs_assert(cond,...)
Definition: ocs_debug.h:176
uint16_t ocs_scsi_dif_calc_crc(const uint8_t *buffer, uint32_t size, uint16_t crc)
Calculate the T10 PI CRC guard value for a block.
Definition: ocs_dif.c:54
ocs_hal_dif_blk_size_e blk_size
Definition: ocs_hal.h:402
int32_t ocs_scsi_dif_set_blocksize(ocs_scsi_dif_info_t *dif_info, uint32_t blocksize)
Set SCSI API DIF blocksize.
Definition: ocs_dif.c:145
ocs_scsi_dif_oper_e dif_oper
Definition: ocs_scsi.h:230
uint32_t ocs_scsi_dif_blocksize(ocs_scsi_dif_info_t *dif_info)
Return blocksize given SCSI API DIF block size.
Definition: ocs_dif.c:114