Commit 51c928c34fa7cff38df584ad01de988805877dba
Committed by
James Bottomley
1 parent
97af50f60f
Exists in
master
and in
20 other branches
[SCSI] Legacy MegaRAID: Fix READ CAPACITY
Some Legacy megaraid cards can't actually cope with the scatter/gather version of the READ CAPACITY command (which is what we now send them since altering all SCSI internal I/O to go via the block layer). Fix this (and a few other broken megaraid driver assumptions) by sending the non-sg version of the command if the sg list only has a single element. Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Showing 1 changed file with 50 additions and 20 deletions Side-by-side Diff
drivers/scsi/megaraid.c
... | ... | @@ -621,8 +621,6 @@ |
621 | 621 | if(islogical) { |
622 | 622 | switch (cmd->cmnd[0]) { |
623 | 623 | case TEST_UNIT_READY: |
624 | - memset(cmd->request_buffer, 0, cmd->request_bufflen); | |
625 | - | |
626 | 624 | #if MEGA_HAVE_CLUSTERING |
627 | 625 | /* |
628 | 626 | * Do we support clustering and is the support enabled |
629 | 627 | |
630 | 628 | |
... | ... | @@ -652,11 +650,28 @@ |
652 | 650 | return NULL; |
653 | 651 | #endif |
654 | 652 | |
655 | - case MODE_SENSE: | |
653 | + case MODE_SENSE: { | |
654 | + char *buf; | |
655 | + | |
656 | + if (cmd->use_sg) { | |
657 | + struct scatterlist *sg; | |
658 | + | |
659 | + sg = (struct scatterlist *)cmd->request_buffer; | |
660 | + buf = kmap_atomic(sg->page, KM_IRQ0) + | |
661 | + sg->offset; | |
662 | + } else | |
663 | + buf = cmd->request_buffer; | |
656 | 664 | memset(cmd->request_buffer, 0, cmd->cmnd[4]); |
665 | + if (cmd->use_sg) { | |
666 | + struct scatterlist *sg; | |
667 | + | |
668 | + sg = (struct scatterlist *)cmd->request_buffer; | |
669 | + kunmap_atomic(buf - sg->offset, KM_IRQ0); | |
670 | + } | |
657 | 671 | cmd->result = (DID_OK << 16); |
658 | 672 | cmd->scsi_done(cmd); |
659 | 673 | return NULL; |
674 | + } | |
660 | 675 | |
661 | 676 | case READ_CAPACITY: |
662 | 677 | case INQUIRY: |
663 | 678 | |
664 | 679 | |
... | ... | @@ -1685,14 +1700,23 @@ |
1685 | 1700 | static void |
1686 | 1701 | mega_free_scb(adapter_t *adapter, scb_t *scb) |
1687 | 1702 | { |
1703 | + unsigned long length; | |
1704 | + | |
1688 | 1705 | switch( scb->dma_type ) { |
1689 | 1706 | |
1690 | 1707 | case MEGA_DMA_TYPE_NONE: |
1691 | 1708 | break; |
1692 | 1709 | |
1693 | 1710 | case MEGA_BULK_DATA: |
1711 | + if (scb->cmd->use_sg == 0) | |
1712 | + length = scb->cmd->request_bufflen; | |
1713 | + else { | |
1714 | + struct scatterlist *sgl = | |
1715 | + (struct scatterlist *)scb->cmd->request_buffer; | |
1716 | + length = sgl->length; | |
1717 | + } | |
1694 | 1718 | pci_unmap_page(adapter->dev, scb->dma_h_bulkdata, |
1695 | - scb->cmd->request_bufflen, scb->dma_direction); | |
1719 | + length, scb->dma_direction); | |
1696 | 1720 | break; |
1697 | 1721 | |
1698 | 1722 | case MEGA_SGLIST: |
... | ... | @@ -1741,6 +1765,7 @@ |
1741 | 1765 | struct scatterlist *sgl; |
1742 | 1766 | struct page *page; |
1743 | 1767 | unsigned long offset; |
1768 | + unsigned int length; | |
1744 | 1769 | Scsi_Cmnd *cmd; |
1745 | 1770 | int sgcnt; |
1746 | 1771 | int idx; |
1747 | 1772 | |
1748 | 1773 | |
... | ... | @@ -1748,14 +1773,23 @@ |
1748 | 1773 | cmd = scb->cmd; |
1749 | 1774 | |
1750 | 1775 | /* Scatter-gather not used */ |
1751 | - if( !cmd->use_sg ) { | |
1776 | + if( cmd->use_sg == 0 || (cmd->use_sg == 1 && | |
1777 | + !adapter->has_64bit_addr)) { | |
1752 | 1778 | |
1753 | - page = virt_to_page(cmd->request_buffer); | |
1754 | - offset = offset_in_page(cmd->request_buffer); | |
1779 | + if (cmd->use_sg == 0) { | |
1780 | + page = virt_to_page(cmd->request_buffer); | |
1781 | + offset = offset_in_page(cmd->request_buffer); | |
1782 | + length = cmd->request_bufflen; | |
1783 | + } else { | |
1784 | + sgl = (struct scatterlist *)cmd->request_buffer; | |
1785 | + page = sgl->page; | |
1786 | + offset = sgl->offset; | |
1787 | + length = sgl->length; | |
1788 | + } | |
1755 | 1789 | |
1756 | 1790 | scb->dma_h_bulkdata = pci_map_page(adapter->dev, |
1757 | 1791 | page, offset, |
1758 | - cmd->request_bufflen, | |
1792 | + length, | |
1759 | 1793 | scb->dma_direction); |
1760 | 1794 | scb->dma_type = MEGA_BULK_DATA; |
1761 | 1795 | |
1762 | 1796 | |
1763 | 1797 | |
... | ... | @@ -1765,14 +1799,14 @@ |
1765 | 1799 | */ |
1766 | 1800 | if( adapter->has_64bit_addr ) { |
1767 | 1801 | scb->sgl64[0].address = scb->dma_h_bulkdata; |
1768 | - scb->sgl64[0].length = cmd->request_bufflen; | |
1802 | + scb->sgl64[0].length = length; | |
1769 | 1803 | *buf = (u32)scb->sgl_dma_addr; |
1770 | - *len = (u32)cmd->request_bufflen; | |
1804 | + *len = (u32)length; | |
1771 | 1805 | return 1; |
1772 | 1806 | } |
1773 | 1807 | else { |
1774 | 1808 | *buf = (u32)scb->dma_h_bulkdata; |
1775 | - *len = (u32)cmd->request_bufflen; | |
1809 | + *len = (u32)length; | |
1776 | 1810 | } |
1777 | 1811 | return 0; |
1778 | 1812 | } |
1779 | 1813 | |
1780 | 1814 | |
1781 | 1815 | |
... | ... | @@ -1791,26 +1825,22 @@ |
1791 | 1825 | |
1792 | 1826 | if( sgcnt > adapter->sglen ) BUG(); |
1793 | 1827 | |
1828 | + *len = 0; | |
1829 | + | |
1794 | 1830 | for( idx = 0; idx < sgcnt; idx++, sgl++ ) { |
1795 | 1831 | |
1796 | 1832 | if( adapter->has_64bit_addr ) { |
1797 | 1833 | scb->sgl64[idx].address = sg_dma_address(sgl); |
1798 | - scb->sgl64[idx].length = sg_dma_len(sgl); | |
1834 | + *len += scb->sgl64[idx].length = sg_dma_len(sgl); | |
1799 | 1835 | } |
1800 | 1836 | else { |
1801 | 1837 | scb->sgl[idx].address = sg_dma_address(sgl); |
1802 | - scb->sgl[idx].length = sg_dma_len(sgl); | |
1838 | + *len += scb->sgl[idx].length = sg_dma_len(sgl); | |
1803 | 1839 | } |
1804 | 1840 | } |
1805 | 1841 | |
1806 | 1842 | /* Reset pointer and length fields */ |
1807 | 1843 | *buf = scb->sgl_dma_addr; |
1808 | - | |
1809 | - /* | |
1810 | - * For passthru command, dataxferlen must be set, even for commands | |
1811 | - * with a sg list | |
1812 | - */ | |
1813 | - *len = (u32)cmd->request_bufflen; | |
1814 | 1844 | |
1815 | 1845 | /* Return count of SG requests */ |
1816 | 1846 | return sgcnt; |