Commit 51c928c34fa7cff38df584ad01de988805877dba

Authored by James Bottomley
Committed by James Bottomley
1 parent 97af50f60f

[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;