diff options
author | Sagi Grimberg <sagig@mellanox.com> | 2014-02-19 10:50:15 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-03-13 15:03:02 -0400 |
commit | 19f9361af7dfa0bb1f98c7619544ed71d2dded39 (patch) | |
tree | 4afa7db32e56d65500661134906c729699f226bc /drivers/target | |
parent | acb2bde3e32100f1ab50e38f0db03660a1cb0a06 (diff) |
Target/sbc: Set protection operation and relevant checks
SBC-3 mandates the protection checks that must be
performed in the rdprotect/wrprotect field. Use them.
According to backstore device pi_attributes and
cdb rdprotect/wrprotect field.
(Fix incorrect se_cmd->prot_type -> TARGET_PROT_NORMAL
comparision in transport_generic_new_cmd - nab)
(Fix missing break in sbc_set_prot_op_checks - DanC + Sagi)
Signed-off-by: Sagi Grimberg <sagig@mellanox.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/target_core_sbc.c | 87 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 2 |
2 files changed, 74 insertions, 15 deletions
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 77e6531fb0a1..a1e75dd636ac 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c | |||
@@ -569,30 +569,85 @@ sbc_compare_and_write(struct se_cmd *cmd) | |||
569 | return TCM_NO_SENSE; | 569 | return TCM_NO_SENSE; |
570 | } | 570 | } |
571 | 571 | ||
572 | static int | ||
573 | sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type, | ||
574 | bool is_write, struct se_cmd *cmd) | ||
575 | { | ||
576 | if (is_write) { | ||
577 | cmd->prot_op = protect ? TARGET_PROT_DOUT_PASS : | ||
578 | TARGET_PROT_DOUT_INSERT; | ||
579 | switch (protect) { | ||
580 | case 0x0: | ||
581 | case 0x3: | ||
582 | cmd->prot_checks = 0; | ||
583 | break; | ||
584 | case 0x1: | ||
585 | case 0x5: | ||
586 | cmd->prot_checks = TARGET_DIF_CHECK_GUARD; | ||
587 | if (prot_type == TARGET_DIF_TYPE1_PROT) | ||
588 | cmd->prot_checks |= TARGET_DIF_CHECK_REFTAG; | ||
589 | break; | ||
590 | case 0x2: | ||
591 | if (prot_type == TARGET_DIF_TYPE1_PROT) | ||
592 | cmd->prot_checks = TARGET_DIF_CHECK_REFTAG; | ||
593 | break; | ||
594 | case 0x4: | ||
595 | cmd->prot_checks = TARGET_DIF_CHECK_GUARD; | ||
596 | break; | ||
597 | default: | ||
598 | pr_err("Unsupported protect field %d\n", protect); | ||
599 | return -EINVAL; | ||
600 | } | ||
601 | } else { | ||
602 | cmd->prot_op = protect ? TARGET_PROT_DIN_PASS : | ||
603 | TARGET_PROT_DIN_STRIP; | ||
604 | switch (protect) { | ||
605 | case 0x0: | ||
606 | case 0x1: | ||
607 | case 0x5: | ||
608 | cmd->prot_checks = TARGET_DIF_CHECK_GUARD; | ||
609 | if (prot_type == TARGET_DIF_TYPE1_PROT) | ||
610 | cmd->prot_checks |= TARGET_DIF_CHECK_REFTAG; | ||
611 | break; | ||
612 | case 0x2: | ||
613 | if (prot_type == TARGET_DIF_TYPE1_PROT) | ||
614 | cmd->prot_checks = TARGET_DIF_CHECK_REFTAG; | ||
615 | break; | ||
616 | case 0x3: | ||
617 | cmd->prot_checks = 0; | ||
618 | break; | ||
619 | case 0x4: | ||
620 | cmd->prot_checks = TARGET_DIF_CHECK_GUARD; | ||
621 | break; | ||
622 | default: | ||
623 | pr_err("Unsupported protect field %d\n", protect); | ||
624 | return -EINVAL; | ||
625 | } | ||
626 | } | ||
627 | |||
628 | return 0; | ||
629 | } | ||
630 | |||
572 | static bool | 631 | static bool |
573 | sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, | 632 | sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, |
574 | u32 sectors) | 633 | u32 sectors, bool is_write) |
575 | { | 634 | { |
635 | u8 protect = cdb[1] >> 5; | ||
636 | |||
576 | if (!cmd->t_prot_sg || !cmd->t_prot_nents) | 637 | if (!cmd->t_prot_sg || !cmd->t_prot_nents) |
577 | return true; | 638 | return true; |
578 | 639 | ||
579 | switch (dev->dev_attrib.pi_prot_type) { | 640 | switch (dev->dev_attrib.pi_prot_type) { |
580 | case TARGET_DIF_TYPE3_PROT: | 641 | case TARGET_DIF_TYPE3_PROT: |
581 | if (!(cdb[1] & 0xe0)) | ||
582 | return true; | ||
583 | |||
584 | cmd->reftag_seed = 0xffffffff; | 642 | cmd->reftag_seed = 0xffffffff; |
585 | break; | 643 | break; |
586 | case TARGET_DIF_TYPE2_PROT: | 644 | case TARGET_DIF_TYPE2_PROT: |
587 | if (cdb[1] & 0xe0) | 645 | if (protect) |
588 | return false; | 646 | return false; |
589 | 647 | ||
590 | cmd->reftag_seed = cmd->t_task_lba; | 648 | cmd->reftag_seed = cmd->t_task_lba; |
591 | break; | 649 | break; |
592 | case TARGET_DIF_TYPE1_PROT: | 650 | case TARGET_DIF_TYPE1_PROT: |
593 | if (!(cdb[1] & 0xe0)) | ||
594 | return true; | ||
595 | |||
596 | cmd->reftag_seed = cmd->t_task_lba; | 651 | cmd->reftag_seed = cmd->t_task_lba; |
597 | break; | 652 | break; |
598 | case TARGET_DIF_TYPE0_PROT: | 653 | case TARGET_DIF_TYPE0_PROT: |
@@ -600,6 +655,10 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, | |||
600 | return true; | 655 | return true; |
601 | } | 656 | } |
602 | 657 | ||
658 | if (sbc_set_prot_op_checks(protect, dev->dev_attrib.pi_prot_type, | ||
659 | is_write, cmd)) | ||
660 | return false; | ||
661 | |||
603 | cmd->prot_type = dev->dev_attrib.pi_prot_type; | 662 | cmd->prot_type = dev->dev_attrib.pi_prot_type; |
604 | cmd->prot_length = dev->prot_length * sectors; | 663 | cmd->prot_length = dev->prot_length * sectors; |
605 | cmd->prot_handover = PROT_SEPERATED; | 664 | cmd->prot_handover = PROT_SEPERATED; |
@@ -628,7 +687,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
628 | sectors = transport_get_sectors_10(cdb); | 687 | sectors = transport_get_sectors_10(cdb); |
629 | cmd->t_task_lba = transport_lba_32(cdb); | 688 | cmd->t_task_lba = transport_lba_32(cdb); |
630 | 689 | ||
631 | if (!sbc_check_prot(dev, cmd, cdb, sectors)) | 690 | if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) |
632 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 691 | return TCM_UNSUPPORTED_SCSI_OPCODE; |
633 | 692 | ||
634 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | 693 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; |
@@ -639,7 +698,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
639 | sectors = transport_get_sectors_12(cdb); | 698 | sectors = transport_get_sectors_12(cdb); |
640 | cmd->t_task_lba = transport_lba_32(cdb); | 699 | cmd->t_task_lba = transport_lba_32(cdb); |
641 | 700 | ||
642 | if (!sbc_check_prot(dev, cmd, cdb, sectors)) | 701 | if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) |
643 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 702 | return TCM_UNSUPPORTED_SCSI_OPCODE; |
644 | 703 | ||
645 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | 704 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; |
@@ -650,7 +709,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
650 | sectors = transport_get_sectors_16(cdb); | 709 | sectors = transport_get_sectors_16(cdb); |
651 | cmd->t_task_lba = transport_lba_64(cdb); | 710 | cmd->t_task_lba = transport_lba_64(cdb); |
652 | 711 | ||
653 | if (!sbc_check_prot(dev, cmd, cdb, sectors)) | 712 | if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) |
654 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 713 | return TCM_UNSUPPORTED_SCSI_OPCODE; |
655 | 714 | ||
656 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | 715 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; |
@@ -669,7 +728,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
669 | sectors = transport_get_sectors_10(cdb); | 728 | sectors = transport_get_sectors_10(cdb); |
670 | cmd->t_task_lba = transport_lba_32(cdb); | 729 | cmd->t_task_lba = transport_lba_32(cdb); |
671 | 730 | ||
672 | if (!sbc_check_prot(dev, cmd, cdb, sectors)) | 731 | if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) |
673 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 732 | return TCM_UNSUPPORTED_SCSI_OPCODE; |
674 | 733 | ||
675 | if (cdb[1] & 0x8) | 734 | if (cdb[1] & 0x8) |
@@ -682,7 +741,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
682 | sectors = transport_get_sectors_12(cdb); | 741 | sectors = transport_get_sectors_12(cdb); |
683 | cmd->t_task_lba = transport_lba_32(cdb); | 742 | cmd->t_task_lba = transport_lba_32(cdb); |
684 | 743 | ||
685 | if (!sbc_check_prot(dev, cmd, cdb, sectors)) | 744 | if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) |
686 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 745 | return TCM_UNSUPPORTED_SCSI_OPCODE; |
687 | 746 | ||
688 | if (cdb[1] & 0x8) | 747 | if (cdb[1] & 0x8) |
@@ -695,7 +754,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
695 | sectors = transport_get_sectors_16(cdb); | 754 | sectors = transport_get_sectors_16(cdb); |
696 | cmd->t_task_lba = transport_lba_64(cdb); | 755 | cmd->t_task_lba = transport_lba_64(cdb); |
697 | 756 | ||
698 | if (!sbc_check_prot(dev, cmd, cdb, sectors)) | 757 | if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) |
699 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 758 | return TCM_UNSUPPORTED_SCSI_OPCODE; |
700 | 759 | ||
701 | if (cdb[1] & 0x8) | 760 | if (cdb[1] & 0x8) |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 6ddd4cfc53ba..4653d826e595 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -2206,7 +2206,7 @@ transport_generic_new_cmd(struct se_cmd *cmd) | |||
2206 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 2206 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
2207 | } | 2207 | } |
2208 | 2208 | ||
2209 | if (cmd->prot_type != TARGET_PROT_NORMAL) { | 2209 | if (cmd->prot_op != TARGET_PROT_NORMAL) { |
2210 | ret = target_alloc_sgl(&cmd->t_prot_sg, | 2210 | ret = target_alloc_sgl(&cmd->t_prot_sg, |
2211 | &cmd->t_prot_nents, | 2211 | &cmd->t_prot_nents, |
2212 | cmd->prot_length, true); | 2212 | cmd->prot_length, true); |