aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci
diff options
context:
space:
mode:
authorDave Jiang <dave.jiang@intel.com>2012-02-10 04:18:34 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-19 10:14:24 -0500
commit3d2d752549150c2706f6bf8d8a2cceb89ef9f42e (patch)
treeb50821eef1f21902c5d22263001e202b65c3d680 /drivers/scsi/isci
parenta6fe35c052c4fdd1e8e21251f14eea0bd4bbd25b (diff)
[SCSI] isci: T10 DIF support
This allows the controller to do WRITE_INSERT and READ_STRIP for SAS disks that support protection information. SAS disks must be formatted with protection information to use this feature via sg_format. sg3_utils-1.32 -- sg_format version 1.19 20110730 sg_format usage: sg_format --format --verbose --pinfo /dev/sda Acked-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Dave Jiang <dave.jiang@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/isci')
-rw-r--r--drivers/scsi/isci/init.c7
-rw-r--r--drivers/scsi/isci/request.c147
-rw-r--r--drivers/scsi/isci/scu_task_context.h55
3 files changed, 193 insertions, 16 deletions
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 17c4c2c89c2e..6b911e0aea3f 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -528,6 +528,13 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
528 goto err_host_alloc; 528 goto err_host_alloc;
529 } 529 }
530 pci_info->hosts[i] = h; 530 pci_info->hosts[i] = h;
531
532 /* turn on DIF support */
533 scsi_host_set_prot(h->shost,
534 SHOST_DIF_TYPE1_PROTECTION |
535 SHOST_DIF_TYPE2_PROTECTION |
536 SHOST_DIF_TYPE3_PROTECTION);
537 scsi_host_set_guard(h->shost, SHOST_DIX_GUARD_CRC);
531 } 538 }
532 539
533 err = isci_setup_interrupts(pdev); 540 err = isci_setup_interrupts(pdev);
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 192cb48d849a..751368b46b44 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -53,6 +53,7 @@
53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54 */ 54 */
55 55
56#include <scsi/scsi_cmnd.h>
56#include "isci.h" 57#include "isci.h"
57#include "task.h" 58#include "task.h"
58#include "request.h" 59#include "request.h"
@@ -264,6 +265,141 @@ static void scu_ssp_reqeust_construct_task_context(
264 task_context->response_iu_lower = lower_32_bits(dma_addr); 265 task_context->response_iu_lower = lower_32_bits(dma_addr);
265} 266}
266 267
268static u8 scu_bg_blk_size(struct scsi_device *sdp)
269{
270 switch (sdp->sector_size) {
271 case 512:
272 return 0;
273 case 1024:
274 return 1;
275 case 4096:
276 return 3;
277 default:
278 return 0xff;
279 }
280}
281
282static u32 scu_dif_bytes(u32 len, u32 sector_size)
283{
284 return (len >> ilog2(sector_size)) * 8;
285}
286
287static void scu_ssp_ireq_dif_insert(struct isci_request *ireq, u8 type, u8 op)
288{
289 struct scu_task_context *tc = ireq->tc;
290 struct scsi_cmnd *scmd = ireq->ttype_ptr.io_task_ptr->uldd_task;
291 u8 blk_sz = scu_bg_blk_size(scmd->device);
292
293 tc->block_guard_enable = 1;
294 tc->blk_prot_en = 1;
295 tc->blk_sz = blk_sz;
296 /* DIF write insert */
297 tc->blk_prot_func = 0x2;
298
299 tc->transfer_length_bytes += scu_dif_bytes(tc->transfer_length_bytes,
300 scmd->device->sector_size);
301
302 /* always init to 0, used by hw */
303 tc->interm_crc_val = 0;
304
305 tc->init_crc_seed = 0;
306 tc->app_tag_verify = 0;
307 tc->app_tag_gen = 0;
308 tc->ref_tag_seed_verify = 0;
309
310 /* always init to same as bg_blk_sz */
311 tc->UD_bytes_immed_val = scmd->device->sector_size;
312
313 tc->reserved_DC_0 = 0;
314
315 /* always init to 8 */
316 tc->DIF_bytes_immed_val = 8;
317
318 tc->reserved_DC_1 = 0;
319 tc->bgc_blk_sz = scmd->device->sector_size;
320 tc->reserved_E0_0 = 0;
321 tc->app_tag_gen_mask = 0;
322
323 /** setup block guard control **/
324 tc->bgctl = 0;
325
326 /* DIF write insert */
327 tc->bgctl_f.op = 0x2;
328
329 tc->app_tag_verify_mask = 0;
330
331 /* must init to 0 for hw */
332 tc->blk_guard_err = 0;
333
334 tc->reserved_E8_0 = 0;
335
336 if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2))
337 tc->ref_tag_seed_gen = scsi_get_lba(scmd) & 0xffffffff;
338 else if (type & SCSI_PROT_DIF_TYPE3)
339 tc->ref_tag_seed_gen = 0;
340}
341
342static void scu_ssp_ireq_dif_strip(struct isci_request *ireq, u8 type, u8 op)
343{
344 struct scu_task_context *tc = ireq->tc;
345 struct scsi_cmnd *scmd = ireq->ttype_ptr.io_task_ptr->uldd_task;
346 u8 blk_sz = scu_bg_blk_size(scmd->device);
347
348 tc->block_guard_enable = 1;
349 tc->blk_prot_en = 1;
350 tc->blk_sz = blk_sz;
351 /* DIF read strip */
352 tc->blk_prot_func = 0x1;
353
354 tc->transfer_length_bytes += scu_dif_bytes(tc->transfer_length_bytes,
355 scmd->device->sector_size);
356
357 /* always init to 0, used by hw */
358 tc->interm_crc_val = 0;
359
360 tc->init_crc_seed = 0;
361 tc->app_tag_verify = 0;
362 tc->app_tag_gen = 0;
363
364 if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2))
365 tc->ref_tag_seed_verify = scsi_get_lba(scmd) & 0xffffffff;
366 else if (type & SCSI_PROT_DIF_TYPE3)
367 tc->ref_tag_seed_verify = 0;
368
369 /* always init to same as bg_blk_sz */
370 tc->UD_bytes_immed_val = scmd->device->sector_size;
371
372 tc->reserved_DC_0 = 0;
373
374 /* always init to 8 */
375 tc->DIF_bytes_immed_val = 8;
376
377 tc->reserved_DC_1 = 0;
378 tc->bgc_blk_sz = scmd->device->sector_size;
379 tc->reserved_E0_0 = 0;
380 tc->app_tag_gen_mask = 0;
381
382 /** setup block guard control **/
383 tc->bgctl = 0;
384
385 /* DIF read strip */
386 tc->bgctl_f.crc_verify = 1;
387 tc->bgctl_f.op = 0x1;
388 if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2)) {
389 tc->bgctl_f.ref_tag_chk = 1;
390 tc->bgctl_f.app_f_detect = 1;
391 } else if (type & SCSI_PROT_DIF_TYPE3)
392 tc->bgctl_f.app_ref_f_detect = 1;
393
394 tc->app_tag_verify_mask = 0;
395
396 /* must init to 0 for hw */
397 tc->blk_guard_err = 0;
398
399 tc->reserved_E8_0 = 0;
400 tc->ref_tag_seed_gen = 0;
401}
402
267/** 403/**
268 * This method is will fill in the SCU Task Context for a SSP IO request. 404 * This method is will fill in the SCU Task Context for a SSP IO request.
269 * @sci_req: 405 * @sci_req:
@@ -274,6 +410,10 @@ static void scu_ssp_io_request_construct_task_context(struct isci_request *ireq,
274 u32 len) 410 u32 len)
275{ 411{
276 struct scu_task_context *task_context = ireq->tc; 412 struct scu_task_context *task_context = ireq->tc;
413 struct sas_task *sas_task = ireq->ttype_ptr.io_task_ptr;
414 struct scsi_cmnd *scmd = sas_task->uldd_task;
415 u8 prot_type = scsi_get_prot_type(scmd);
416 u8 prot_op = scsi_get_prot_op(scmd);
277 417
278 scu_ssp_reqeust_construct_task_context(ireq, task_context); 418 scu_ssp_reqeust_construct_task_context(ireq, task_context);
279 419
@@ -296,6 +436,13 @@ static void scu_ssp_io_request_construct_task_context(struct isci_request *ireq,
296 436
297 if (task_context->transfer_length_bytes > 0) 437 if (task_context->transfer_length_bytes > 0)
298 sci_request_build_sgl(ireq); 438 sci_request_build_sgl(ireq);
439
440 if (prot_type != SCSI_PROT_DIF_TYPE0) {
441 if (prot_op == SCSI_PROT_READ_STRIP)
442 scu_ssp_ireq_dif_strip(ireq, prot_type, prot_op);
443 else if (prot_op == SCSI_PROT_WRITE_INSERT)
444 scu_ssp_ireq_dif_insert(ireq, prot_type, prot_op);
445 }
299} 446}
300 447
301/** 448/**
diff --git a/drivers/scsi/isci/scu_task_context.h b/drivers/scsi/isci/scu_task_context.h
index 7df87d923285..869a979eb5b2 100644
--- a/drivers/scsi/isci/scu_task_context.h
+++ b/drivers/scsi/isci/scu_task_context.h
@@ -866,9 +866,9 @@ struct scu_task_context {
866 struct transport_snapshot snapshot; /* read only set to 0 */ 866 struct transport_snapshot snapshot; /* read only set to 0 */
867 867
868 /* OFFSET 0x5C */ 868 /* OFFSET 0x5C */
869 u32 block_protection_enable:1; 869 u32 blk_prot_en:1;
870 u32 block_size:2; 870 u32 blk_sz:2;
871 u32 block_protection_function:2; 871 u32 blk_prot_func:2;
872 u32 reserved_5C_0:9; 872 u32 reserved_5C_0:9;
873 u32 active_sgl_element:2; /* read only set to 0 */ 873 u32 active_sgl_element:2; /* read only set to 0 */
874 u32 sgl_exhausted:1; /* read only set to 0 */ 874 u32 sgl_exhausted:1; /* read only set to 0 */
@@ -896,33 +896,56 @@ struct scu_task_context {
896 u32 reserved_C4_CC[3]; 896 u32 reserved_C4_CC[3];
897 897
898 /* OFFSET 0xD0 */ 898 /* OFFSET 0xD0 */
899 u32 intermediate_crc_value:16; 899 u32 interm_crc_val:16;
900 u32 initial_crc_seed:16; 900 u32 init_crc_seed:16;
901 901
902 /* OFFSET 0xD4 */ 902 /* OFFSET 0xD4 */
903 u32 application_tag_for_verify:16; 903 u32 app_tag_verify:16;
904 u32 application_tag_for_generate:16; 904 u32 app_tag_gen:16;
905 905
906 /* OFFSET 0xD8 */ 906 /* OFFSET 0xD8 */
907 u32 reference_tag_seed_for_verify_function; 907 u32 ref_tag_seed_verify;
908 908
909 /* OFFSET 0xDC */ 909 /* OFFSET 0xDC */
910 u32 reserved_DC; 910 u32 UD_bytes_immed_val:13;
911 u32 reserved_DC_0:3;
912 u32 DIF_bytes_immed_val:4;
913 u32 reserved_DC_1:12;
911 914
912 /* OFFSET 0xE0 */ 915 /* OFFSET 0xE0 */
913 u32 reserved_E0_0:16; 916 u32 bgc_blk_sz:13;
914 u32 application_tag_mask_for_generate:16; 917 u32 reserved_E0_0:3;
918 u32 app_tag_gen_mask:16;
915 919
916 /* OFFSET 0xE4 */ 920 /* OFFSET 0xE4 */
917 u32 block_protection_control:16; 921 union {
918 u32 application_tag_mask_for_verify:16; 922 u16 bgctl;
923 struct {
924 u16 crc_verify:1;
925 u16 app_tag_chk:1;
926 u16 ref_tag_chk:1;
927 u16 op:2;
928 u16 legacy:1;
929 u16 invert_crc_seed:1;
930 u16 ref_tag_gen:1;
931 u16 fixed_ref_tag:1;
932 u16 invert_crc:1;
933 u16 app_ref_f_detect:1;
934 u16 uninit_dif_check_err:1;
935 u16 uninit_dif_bypass:1;
936 u16 app_f_detect:1;
937 u16 reserved_0:2;
938 } bgctl_f;
939 };
940
941 u16 app_tag_verify_mask;
919 942
920 /* OFFSET 0xE8 */ 943 /* OFFSET 0xE8 */
921 u32 block_protection_error:8; 944 u32 blk_guard_err:8;
922 u32 reserved_E8_0:24; 945 u32 reserved_E8_0:24;
923 946
924 /* OFFSET 0xEC */ 947 /* OFFSET 0xEC */
925 u32 reference_tag_seed_for_verify; 948 u32 ref_tag_seed_gen;
926 949
927 /* OFFSET 0xF0 */ 950 /* OFFSET 0xF0 */
928 u32 intermediate_crc_valid_snapshot:16; 951 u32 intermediate_crc_valid_snapshot:16;
@@ -937,6 +960,6 @@ struct scu_task_context {
937 /* OFFSET 0xFC */ 960 /* OFFSET 0xFC */
938 u32 reference_tag_seed_for_generate_function_snapshot; 961 u32 reference_tag_seed_for_generate_function_snapshot;
939 962
940}; 963} __packed;
941 964
942#endif /* _SCU_TASK_CONTEXT_H_ */ 965#endif /* _SCU_TASK_CONTEXT_H_ */