diff options
author | Anand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com> | 2013-09-18 01:44:54 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-10-25 04:58:15 -0400 |
commit | 0ecdf00ba6e50eaa452356d0d4e79657dab702a4 (patch) | |
tree | cef681a9f28e7bc82314ddf7fe6d81f9c9e1c022 /drivers/scsi | |
parent | f9cd6cbd80d1d5963ffd0eab3970235cd4205984 (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.c | 103 |
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; |