diff options
author | Dave Jiang <dave.jiang@intel.com> | 2012-02-10 04:18:34 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-19 10:14:24 -0500 |
commit | 3d2d752549150c2706f6bf8d8a2cceb89ef9f42e (patch) | |
tree | b50821eef1f21902c5d22263001e202b65c3d680 /drivers/scsi/isci | |
parent | a6fe35c052c4fdd1e8e21251f14eea0bd4bbd25b (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.c | 7 | ||||
-rw-r--r-- | drivers/scsi/isci/request.c | 147 | ||||
-rw-r--r-- | drivers/scsi/isci/scu_task_context.h | 55 |
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 | ||
268 | static 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 | |||
282 | static u32 scu_dif_bytes(u32 len, u32 sector_size) | ||
283 | { | ||
284 | return (len >> ilog2(sector_size)) * 8; | ||
285 | } | ||
286 | |||
287 | static 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 | |||
342 | static 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_ */ |