diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-02-13 17:49:38 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-02-13 21:09:44 -0500 |
commit | f7b7c06f386c5e990acb87a8bc96137b9f978977 (patch) | |
tree | 60a15481f0e470257ec72de21a8dd53b81427b93 /drivers/target/target_core_sbc.c | |
parent | aa179935edea9a64dec4b757090c8106a3907ffa (diff) |
target: Fail I/O with PROTECT bit when protection is unsupported
This patch adds an explicit check for WRPROTECT + RDPROTECT bit usage
within sbc_check_prot(), and fails with TCM_INVALID_CDB_FIELD if the
backend device does not have protection enabled.
Also, update sbc_check_prot() to return sense_reason_t in order to
propigate up the correct sense ASQ.
Cc: Martin Petersen <martin.petersen@oracle.com>
Cc: Sagi Grimberg <sagig@mellanox.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/target_core_sbc.c')
-rw-r--r-- | drivers/target/target_core_sbc.c | 51 |
1 files changed, 32 insertions, 19 deletions
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 17259c05450e..1bb8b4a93a66 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c | |||
@@ -626,14 +626,21 @@ sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type, | |||
626 | return 0; | 626 | return 0; |
627 | } | 627 | } |
628 | 628 | ||
629 | static bool | 629 | static sense_reason_t |
630 | sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, | 630 | sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, |
631 | u32 sectors, bool is_write) | 631 | u32 sectors, bool is_write) |
632 | { | 632 | { |
633 | u8 protect = cdb[1] >> 5; | 633 | u8 protect = cdb[1] >> 5; |
634 | 634 | ||
635 | if ((!cmd->t_prot_sg || !cmd->t_prot_nents) && cmd->prot_pto) | 635 | if (!cmd->t_prot_sg || !cmd->t_prot_nents) { |
636 | return true; | 636 | if (protect && !dev->dev_attrib.pi_prot_type) { |
637 | pr_err("CDB contains protect bit, but device does not" | ||
638 | " advertise PROTECT=1 feature bit\n"); | ||
639 | return TCM_INVALID_CDB_FIELD; | ||
640 | } | ||
641 | if (cmd->prot_pto) | ||
642 | return TCM_NO_SENSE; | ||
643 | } | ||
637 | 644 | ||
638 | switch (dev->dev_attrib.pi_prot_type) { | 645 | switch (dev->dev_attrib.pi_prot_type) { |
639 | case TARGET_DIF_TYPE3_PROT: | 646 | case TARGET_DIF_TYPE3_PROT: |
@@ -641,7 +648,7 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, | |||
641 | break; | 648 | break; |
642 | case TARGET_DIF_TYPE2_PROT: | 649 | case TARGET_DIF_TYPE2_PROT: |
643 | if (protect) | 650 | if (protect) |
644 | return false; | 651 | return TCM_INVALID_CDB_FIELD; |
645 | 652 | ||
646 | cmd->reftag_seed = cmd->t_task_lba; | 653 | cmd->reftag_seed = cmd->t_task_lba; |
647 | break; | 654 | break; |
@@ -650,12 +657,12 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, | |||
650 | break; | 657 | break; |
651 | case TARGET_DIF_TYPE0_PROT: | 658 | case TARGET_DIF_TYPE0_PROT: |
652 | default: | 659 | default: |
653 | return true; | 660 | return TCM_NO_SENSE; |
654 | } | 661 | } |
655 | 662 | ||
656 | if (sbc_set_prot_op_checks(protect, dev->dev_attrib.pi_prot_type, | 663 | if (sbc_set_prot_op_checks(protect, dev->dev_attrib.pi_prot_type, |
657 | is_write, cmd)) | 664 | is_write, cmd)) |
658 | return false; | 665 | return TCM_INVALID_CDB_FIELD; |
659 | 666 | ||
660 | cmd->prot_type = dev->dev_attrib.pi_prot_type; | 667 | cmd->prot_type = dev->dev_attrib.pi_prot_type; |
661 | cmd->prot_length = dev->prot_length * sectors; | 668 | cmd->prot_length = dev->prot_length * sectors; |
@@ -674,7 +681,7 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, | |||
674 | __func__, cmd->prot_type, cmd->data_length, cmd->prot_length, | 681 | __func__, cmd->prot_type, cmd->data_length, cmd->prot_length, |
675 | cmd->prot_op, cmd->prot_checks); | 682 | cmd->prot_op, cmd->prot_checks); |
676 | 683 | ||
677 | return true; | 684 | return TCM_NO_SENSE; |
678 | } | 685 | } |
679 | 686 | ||
680 | sense_reason_t | 687 | sense_reason_t |
@@ -698,8 +705,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
698 | sectors = transport_get_sectors_10(cdb); | 705 | sectors = transport_get_sectors_10(cdb); |
699 | cmd->t_task_lba = transport_lba_32(cdb); | 706 | cmd->t_task_lba = transport_lba_32(cdb); |
700 | 707 | ||
701 | if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) | 708 | ret = sbc_check_prot(dev, cmd, cdb, sectors, false); |
702 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 709 | if (ret) |
710 | return ret; | ||
703 | 711 | ||
704 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | 712 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; |
705 | cmd->execute_rw = ops->execute_rw; | 713 | cmd->execute_rw = ops->execute_rw; |
@@ -709,8 +717,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
709 | sectors = transport_get_sectors_12(cdb); | 717 | sectors = transport_get_sectors_12(cdb); |
710 | cmd->t_task_lba = transport_lba_32(cdb); | 718 | cmd->t_task_lba = transport_lba_32(cdb); |
711 | 719 | ||
712 | if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) | 720 | ret = sbc_check_prot(dev, cmd, cdb, sectors, false); |
713 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 721 | if (ret) |
722 | return ret; | ||
714 | 723 | ||
715 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | 724 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; |
716 | cmd->execute_rw = ops->execute_rw; | 725 | cmd->execute_rw = ops->execute_rw; |
@@ -720,8 +729,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
720 | sectors = transport_get_sectors_16(cdb); | 729 | sectors = transport_get_sectors_16(cdb); |
721 | cmd->t_task_lba = transport_lba_64(cdb); | 730 | cmd->t_task_lba = transport_lba_64(cdb); |
722 | 731 | ||
723 | if (!sbc_check_prot(dev, cmd, cdb, sectors, false)) | 732 | ret = sbc_check_prot(dev, cmd, cdb, sectors, false); |
724 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 733 | if (ret) |
734 | return ret; | ||
725 | 735 | ||
726 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | 736 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; |
727 | cmd->execute_rw = ops->execute_rw; | 737 | cmd->execute_rw = ops->execute_rw; |
@@ -739,8 +749,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
739 | sectors = transport_get_sectors_10(cdb); | 749 | sectors = transport_get_sectors_10(cdb); |
740 | cmd->t_task_lba = transport_lba_32(cdb); | 750 | cmd->t_task_lba = transport_lba_32(cdb); |
741 | 751 | ||
742 | if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) | 752 | ret = sbc_check_prot(dev, cmd, cdb, sectors, true); |
743 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 753 | if (ret) |
754 | return ret; | ||
744 | 755 | ||
745 | if (cdb[1] & 0x8) | 756 | if (cdb[1] & 0x8) |
746 | cmd->se_cmd_flags |= SCF_FUA; | 757 | cmd->se_cmd_flags |= SCF_FUA; |
@@ -752,8 +763,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
752 | sectors = transport_get_sectors_12(cdb); | 763 | sectors = transport_get_sectors_12(cdb); |
753 | cmd->t_task_lba = transport_lba_32(cdb); | 764 | cmd->t_task_lba = transport_lba_32(cdb); |
754 | 765 | ||
755 | if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) | 766 | ret = sbc_check_prot(dev, cmd, cdb, sectors, true); |
756 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 767 | if (ret) |
768 | return ret; | ||
757 | 769 | ||
758 | if (cdb[1] & 0x8) | 770 | if (cdb[1] & 0x8) |
759 | cmd->se_cmd_flags |= SCF_FUA; | 771 | cmd->se_cmd_flags |= SCF_FUA; |
@@ -765,8 +777,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
765 | sectors = transport_get_sectors_16(cdb); | 777 | sectors = transport_get_sectors_16(cdb); |
766 | cmd->t_task_lba = transport_lba_64(cdb); | 778 | cmd->t_task_lba = transport_lba_64(cdb); |
767 | 779 | ||
768 | if (!sbc_check_prot(dev, cmd, cdb, sectors, true)) | 780 | ret = sbc_check_prot(dev, cmd, cdb, sectors, true); |
769 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 781 | if (ret) |
782 | return ret; | ||
770 | 783 | ||
771 | if (cdb[1] & 0x8) | 784 | if (cdb[1] & 0x8) |
772 | cmd->se_cmd_flags |= SCF_FUA; | 785 | cmd->se_cmd_flags |= SCF_FUA; |