aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorAnand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com>2013-09-18 01:44:54 -0400
committerJames Bottomley <JBottomley@Parallels.com>2013-10-25 04:58:15 -0400
commit0ecdf00ba6e50eaa452356d0d4e79657dab702a4 (patch)
treecef681a9f28e7bc82314ddf7fe6d81f9c9e1c022 /drivers/scsi
parentf9cd6cbd80d1d5963ffd0eab3970235cd4205984 (diff)
[SCSI] pm80xx: 4G boundary fix.
Firmware is having an issue. When a single IO request crosses 4G boundary, system will crash. To avoid the issue single sg is converted into extended sg. Signed-off-by: Anandkumar.Santhanam@pmcs.com Reviewed-by: Jack Wang <jinpu.wang@profitbricks.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c103
1 files changed, 101 insertions, 2 deletions
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index fa06f24e1656..37ddc5dda7bb 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -3610,7 +3610,8 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,
3610 struct ssp_ini_io_start_req ssp_cmd; 3610 struct ssp_ini_io_start_req ssp_cmd;
3611 u32 tag = ccb->ccb_tag; 3611 u32 tag = ccb->ccb_tag;
3612 int ret; 3612 int ret;
3613 u64 phys_addr; 3613 u64 phys_addr, start_addr, end_addr;
3614 u32 end_addr_high, end_addr_low;
3614 struct inbound_queue_table *circularQ; 3615 struct inbound_queue_table *circularQ;
3615 u32 q_index; 3616 u32 q_index;
3616 u32 opc = OPC_INB_SSPINIIOSTART; 3617 u32 opc = OPC_INB_SSPINIIOSTART;
@@ -3664,6 +3665,30 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,
3664 cpu_to_le32(upper_32_bits(dma_addr)); 3665 cpu_to_le32(upper_32_bits(dma_addr));
3665 ssp_cmd.enc_len = cpu_to_le32(task->total_xfer_len); 3666 ssp_cmd.enc_len = cpu_to_le32(task->total_xfer_len);
3666 ssp_cmd.enc_esgl = 0; 3667 ssp_cmd.enc_esgl = 0;
3668 /* Check 4G Boundary */
3669 start_addr = cpu_to_le64(dma_addr);
3670 end_addr = (start_addr + ssp_cmd.enc_len) - 1;
3671 end_addr_low = cpu_to_le32(lower_32_bits(end_addr));
3672 end_addr_high = cpu_to_le32(upper_32_bits(end_addr));
3673 if (end_addr_high != ssp_cmd.enc_addr_high) {
3674 PM8001_FAIL_DBG(pm8001_ha,
3675 pm8001_printk("The sg list address "
3676 "start_addr=0x%016llx data_len=0x%x "
3677 "end_addr_high=0x%08x end_addr_low="
3678 "0x%08x has crossed 4G boundary\n",
3679 start_addr, ssp_cmd.enc_len,
3680 end_addr_high, end_addr_low));
3681 pm8001_chip_make_sg(task->scatter, 1,
3682 ccb->buf_prd);
3683 phys_addr = ccb->ccb_dma_handle +
3684 offsetof(struct pm8001_ccb_info,
3685 buf_prd[0]);
3686 ssp_cmd.enc_addr_low =
3687 cpu_to_le32(lower_32_bits(phys_addr));
3688 ssp_cmd.enc_addr_high =
3689 cpu_to_le32(upper_32_bits(phys_addr));
3690 ssp_cmd.enc_esgl = cpu_to_le32(1<<31);
3691 }
3667 } else if (task->num_scatter == 0) { 3692 } else if (task->num_scatter == 0) {
3668 ssp_cmd.enc_addr_low = 0; 3693 ssp_cmd.enc_addr_low = 0;
3669 ssp_cmd.enc_addr_high = 0; 3694 ssp_cmd.enc_addr_high = 0;
@@ -3699,6 +3724,30 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,
3699 cpu_to_le32(upper_32_bits(dma_addr)); 3724 cpu_to_le32(upper_32_bits(dma_addr));
3700 ssp_cmd.len = cpu_to_le32(task->total_xfer_len); 3725 ssp_cmd.len = cpu_to_le32(task->total_xfer_len);
3701 ssp_cmd.esgl = 0; 3726 ssp_cmd.esgl = 0;
3727 /* Check 4G Boundary */
3728 start_addr = cpu_to_le64(dma_addr);
3729 end_addr = (start_addr + ssp_cmd.len) - 1;
3730 end_addr_low = cpu_to_le32(lower_32_bits(end_addr));
3731 end_addr_high = cpu_to_le32(upper_32_bits(end_addr));
3732 if (end_addr_high != ssp_cmd.addr_high) {
3733 PM8001_FAIL_DBG(pm8001_ha,
3734 pm8001_printk("The sg list address "
3735 "start_addr=0x%016llx data_len=0x%x "
3736 "end_addr_high=0x%08x end_addr_low="
3737 "0x%08x has crossed 4G boundary\n",
3738 start_addr, ssp_cmd.len,
3739 end_addr_high, end_addr_low));
3740 pm8001_chip_make_sg(task->scatter, 1,
3741 ccb->buf_prd);
3742 phys_addr = ccb->ccb_dma_handle +
3743 offsetof(struct pm8001_ccb_info,
3744 buf_prd[0]);
3745 ssp_cmd.addr_low =
3746 cpu_to_le32(lower_32_bits(phys_addr));
3747 ssp_cmd.addr_high =
3748 cpu_to_le32(upper_32_bits(phys_addr));
3749 ssp_cmd.esgl = cpu_to_le32(1<<31);
3750 }
3702 } else if (task->num_scatter == 0) { 3751 } else if (task->num_scatter == 0) {
3703 ssp_cmd.addr_low = 0; 3752 ssp_cmd.addr_low = 0;
3704 ssp_cmd.addr_high = 0; 3753 ssp_cmd.addr_high = 0;
@@ -3723,7 +3772,8 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
3723 u32 q_index; 3772 u32 q_index;
3724 struct sata_start_req sata_cmd; 3773 struct sata_start_req sata_cmd;
3725 u32 hdr_tag, ncg_tag = 0; 3774 u32 hdr_tag, ncg_tag = 0;
3726 u64 phys_addr; 3775 u64 phys_addr, start_addr, end_addr;
3776 u32 end_addr_high, end_addr_low;
3727 u32 ATAP = 0x0; 3777 u32 ATAP = 0x0;
3728 u32 dir; 3778 u32 dir;
3729 struct inbound_queue_table *circularQ; 3779 struct inbound_queue_table *circularQ;
@@ -3792,6 +3842,31 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
3792 sata_cmd.enc_addr_high = upper_32_bits(dma_addr); 3842 sata_cmd.enc_addr_high = upper_32_bits(dma_addr);
3793 sata_cmd.enc_len = cpu_to_le32(task->total_xfer_len); 3843 sata_cmd.enc_len = cpu_to_le32(task->total_xfer_len);
3794 sata_cmd.enc_esgl = 0; 3844 sata_cmd.enc_esgl = 0;
3845 /* Check 4G Boundary */
3846 start_addr = cpu_to_le64(dma_addr);
3847 end_addr = (start_addr + sata_cmd.enc_len) - 1;
3848 end_addr_low = cpu_to_le32(lower_32_bits(end_addr));
3849 end_addr_high = cpu_to_le32(upper_32_bits(end_addr));
3850 if (end_addr_high != sata_cmd.enc_addr_high) {
3851 PM8001_FAIL_DBG(pm8001_ha,
3852 pm8001_printk("The sg list address "
3853 "start_addr=0x%016llx data_len=0x%x "
3854 "end_addr_high=0x%08x end_addr_low"
3855 "=0x%08x has crossed 4G boundary\n",
3856 start_addr, sata_cmd.enc_len,
3857 end_addr_high, end_addr_low));
3858 pm8001_chip_make_sg(task->scatter, 1,
3859 ccb->buf_prd);
3860 phys_addr = ccb->ccb_dma_handle +
3861 offsetof(struct pm8001_ccb_info,
3862 buf_prd[0]);
3863 sata_cmd.enc_addr_low =
3864 lower_32_bits(phys_addr);
3865 sata_cmd.enc_addr_high =
3866 upper_32_bits(phys_addr);
3867 sata_cmd.enc_esgl =
3868 cpu_to_le32(1 << 31);
3869 }
3795 } else if (task->num_scatter == 0) { 3870 } else if (task->num_scatter == 0) {
3796 sata_cmd.enc_addr_low = 0; 3871 sata_cmd.enc_addr_low = 0;
3797 sata_cmd.enc_addr_high = 0; 3872 sata_cmd.enc_addr_high = 0;
@@ -3833,6 +3908,30 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
3833 sata_cmd.addr_high = upper_32_bits(dma_addr); 3908 sata_cmd.addr_high = upper_32_bits(dma_addr);
3834 sata_cmd.len = cpu_to_le32(task->total_xfer_len); 3909 sata_cmd.len = cpu_to_le32(task->total_xfer_len);
3835 sata_cmd.esgl = 0; 3910 sata_cmd.esgl = 0;
3911 /* Check 4G Boundary */
3912 start_addr = cpu_to_le64(dma_addr);
3913 end_addr = (start_addr + sata_cmd.len) - 1;
3914 end_addr_low = cpu_to_le32(lower_32_bits(end_addr));
3915 end_addr_high = cpu_to_le32(upper_32_bits(end_addr));
3916 if (end_addr_high != sata_cmd.addr_high) {
3917 PM8001_FAIL_DBG(pm8001_ha,
3918 pm8001_printk("The sg list address "
3919 "start_addr=0x%016llx data_len=0x%x"
3920 "end_addr_high=0x%08x end_addr_low="
3921 "0x%08x has crossed 4G boundary\n",
3922 start_addr, sata_cmd.len,
3923 end_addr_high, end_addr_low));
3924 pm8001_chip_make_sg(task->scatter, 1,
3925 ccb->buf_prd);
3926 phys_addr = ccb->ccb_dma_handle +
3927 offsetof(struct pm8001_ccb_info,
3928 buf_prd[0]);
3929 sata_cmd.addr_low =
3930 lower_32_bits(phys_addr);
3931 sata_cmd.addr_high =
3932 upper_32_bits(phys_addr);
3933 sata_cmd.esgl = cpu_to_le32(1 << 31);
3934 }
3836 } else if (task->num_scatter == 0) { 3935 } else if (task->num_scatter == 0) {
3837 sata_cmd.addr_low = 0; 3936 sata_cmd.addr_low = 0;
3838 sata_cmd.addr_high = 0; 3937 sata_cmd.addr_high = 0;