aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/mpt2sas
diff options
context:
space:
mode:
authornagalakshmi.nandigama@lsi.com <nagalakshmi.nandigama@lsi.com>2012-03-20 02:34:43 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-04-23 14:27:02 -0400
commit77a6edffdf674c65075c409aef00f3b0955b350d (patch)
tree9aef90935e353923619725757240d6de6d17c0a3 /drivers/scsi/mpt2sas
parent913809f6e7bd9714d4e20ae596dd9e2ca7efe9ae (diff)
[SCSI] mpt2sas: Added multisegment mode support for Linux BSG Driver
Added support for Block IO requests with multiple segments (vectors) in the SMP handler of the SAS Transport Class. This is required by the BSG driver. Multisegment support added for both, Request and Response. Signed-off-by: Nagalakshmi Nandigama <nagalakshmi.nandigama@lsi.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/mpt2sas')
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c133
1 files changed, 104 insertions, 29 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index 831047466a5a..8b2a3db9ea69 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -1828,7 +1828,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1828 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); 1828 struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1829 Mpi2SmpPassthroughRequest_t *mpi_request; 1829 Mpi2SmpPassthroughRequest_t *mpi_request;
1830 Mpi2SmpPassthroughReply_t *mpi_reply; 1830 Mpi2SmpPassthroughReply_t *mpi_reply;
1831 int rc; 1831 int rc, i;
1832 u16 smid; 1832 u16 smid;
1833 u32 ioc_state; 1833 u32 ioc_state;
1834 unsigned long timeleft; 1834 unsigned long timeleft;
@@ -1837,24 +1837,20 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1837 u8 issue_reset = 0; 1837 u8 issue_reset = 0;
1838 dma_addr_t dma_addr_in = 0; 1838 dma_addr_t dma_addr_in = 0;
1839 dma_addr_t dma_addr_out = 0; 1839 dma_addr_t dma_addr_out = 0;
1840 dma_addr_t pci_dma_in = 0;
1841 dma_addr_t pci_dma_out = 0;
1842 void *pci_addr_in = NULL;
1843 void *pci_addr_out = NULL;
1840 u16 wait_state_count; 1844 u16 wait_state_count;
1841 struct request *rsp = req->next_rq; 1845 struct request *rsp = req->next_rq;
1846 struct bio_vec *bvec = NULL;
1842 1847
1843 if (!rsp) { 1848 if (!rsp) {
1844 printk(MPT2SAS_ERR_FMT "%s: the smp response space is " 1849 printk(MPT2SAS_ERR_FMT "%s: the smp response space is "
1845 "missing\n", ioc->name, __func__); 1850 "missing\n", ioc->name, __func__);
1846 return -EINVAL; 1851 return -EINVAL;
1847 } 1852 }
1848 1853 if (ioc->shost_recovery || ioc->pci_error_recovery) {
1849 /* do we need to support multiple segments? */
1850 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
1851 printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, "
1852 "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt,
1853 blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
1854 return -EINVAL;
1855 }
1856
1857 if (ioc->shost_recovery) {
1858 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", 1854 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
1859 __func__, ioc->name); 1855 __func__, ioc->name);
1860 return -EFAULT; 1856 return -EFAULT;
@@ -1872,6 +1868,59 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1872 } 1868 }
1873 ioc->transport_cmds.status = MPT2_CMD_PENDING; 1869 ioc->transport_cmds.status = MPT2_CMD_PENDING;
1874 1870
1871 /* Check if the request is split across multiple segments */
1872 if (req->bio->bi_vcnt > 1) {
1873 u32 offset = 0;
1874
1875 /* Allocate memory and copy the request */
1876 pci_addr_out = pci_alloc_consistent(ioc->pdev,
1877 blk_rq_bytes(req), &pci_dma_out);
1878 if (!pci_addr_out) {
1879 printk(MPT2SAS_INFO_FMT "%s(): PCI Addr out = NULL\n",
1880 ioc->name, __func__);
1881 rc = -ENOMEM;
1882 goto out;
1883 }
1884
1885 bio_for_each_segment(bvec, req->bio, i) {
1886 memcpy(pci_addr_out + offset,
1887 page_address(bvec->bv_page) + bvec->bv_offset,
1888 bvec->bv_len);
1889 offset += bvec->bv_len;
1890 }
1891 } else {
1892 dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
1893 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
1894 if (!dma_addr_out) {
1895 printk(MPT2SAS_INFO_FMT "%s(): DMA Addr out = NULL\n",
1896 ioc->name, __func__);
1897 rc = -ENOMEM;
1898 goto free_pci;
1899 }
1900 }
1901
1902 /* Check if the response needs to be populated across
1903 * multiple segments */
1904 if (rsp->bio->bi_vcnt > 1) {
1905 pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp),
1906 &pci_dma_in);
1907 if (!pci_addr_in) {
1908 printk(MPT2SAS_INFO_FMT "%s(): PCI Addr in = NULL\n",
1909 ioc->name, __func__);
1910 rc = -ENOMEM;
1911 goto unmap;
1912 }
1913 } else {
1914 dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
1915 blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
1916 if (!dma_addr_in) {
1917 printk(MPT2SAS_INFO_FMT "%s(): DMA Addr in = NULL\n",
1918 ioc->name, __func__);
1919 rc = -ENOMEM;
1920 goto unmap;
1921 }
1922 }
1923
1875 wait_state_count = 0; 1924 wait_state_count = 0;
1876 ioc_state = mpt2sas_base_get_iocstate(ioc, 1); 1925 ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
1877 while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { 1926 while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
@@ -1880,7 +1929,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1880 "%s: failed due to ioc not operational\n", 1929 "%s: failed due to ioc not operational\n",
1881 ioc->name, __func__); 1930 ioc->name, __func__);
1882 rc = -EFAULT; 1931 rc = -EFAULT;
1883 goto out; 1932 goto unmap;
1884 } 1933 }
1885 ssleep(1); 1934 ssleep(1);
1886 ioc_state = mpt2sas_base_get_iocstate(ioc, 1); 1935 ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
@@ -1897,7 +1946,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1897 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", 1946 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
1898 ioc->name, __func__); 1947 ioc->name, __func__);
1899 rc = -EAGAIN; 1948 rc = -EAGAIN;
1900 goto out; 1949 goto unmap;
1901 } 1950 }
1902 1951
1903 rc = 0; 1952 rc = 0;
@@ -1919,16 +1968,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1919 sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | 1968 sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1920 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); 1969 MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
1921 sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; 1970 sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1922 dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), 1971 if (req->bio->bi_vcnt > 1) {
1923 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); 1972 ioc->base_add_sg_single(psge, sgl_flags |
1924 if (!dma_addr_out) { 1973 (blk_rq_bytes(req) - 4), pci_dma_out);
1925 mpt2sas_base_free_smid(ioc, smid); 1974 } else {
1926 goto unmap; 1975 ioc->base_add_sg_single(psge, sgl_flags |
1976 (blk_rq_bytes(req) - 4), dma_addr_out);
1927 } 1977 }
1928 1978
1929 ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4),
1930 dma_addr_out);
1931
1932 /* incr sgel */ 1979 /* incr sgel */
1933 psge += ioc->sge_size; 1980 psge += ioc->sge_size;
1934 1981
@@ -1937,16 +1984,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1937 MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | 1984 MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
1938 MPI2_SGE_FLAGS_END_OF_LIST); 1985 MPI2_SGE_FLAGS_END_OF_LIST);
1939 sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; 1986 sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1940 dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), 1987 if (rsp->bio->bi_vcnt > 1) {
1941 blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); 1988 ioc->base_add_sg_single(psge, sgl_flags |
1942 if (!dma_addr_in) { 1989 (blk_rq_bytes(rsp) + 4), pci_dma_in);
1943 mpt2sas_base_free_smid(ioc, smid); 1990 } else {
1944 goto unmap; 1991 ioc->base_add_sg_single(psge, sgl_flags |
1992 (blk_rq_bytes(rsp) + 4), dma_addr_in);
1945 } 1993 }
1946 1994
1947 ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4),
1948 dma_addr_in);
1949
1950 dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - " 1995 dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
1951 "sending smp request\n", ioc->name, __func__)); 1996 "sending smp request\n", ioc->name, __func__));
1952 1997
@@ -1982,6 +2027,27 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1982 req->resid_len = 0; 2027 req->resid_len = 0;
1983 rsp->resid_len -= 2028 rsp->resid_len -=
1984 le16_to_cpu(mpi_reply->ResponseDataLength); 2029 le16_to_cpu(mpi_reply->ResponseDataLength);
2030 /* check if the resp needs to be copied from the allocated
2031 * pci mem */
2032 if (rsp->bio->bi_vcnt > 1) {
2033 u32 offset = 0;
2034 u32 bytes_to_copy =
2035 le16_to_cpu(mpi_reply->ResponseDataLength);
2036 bio_for_each_segment(bvec, rsp->bio, i) {
2037 if (bytes_to_copy <= bvec->bv_len) {
2038 memcpy(page_address(bvec->bv_page) +
2039 bvec->bv_offset, pci_addr_in +
2040 offset, bytes_to_copy);
2041 break;
2042 } else {
2043 memcpy(page_address(bvec->bv_page) +
2044 bvec->bv_offset, pci_addr_in +
2045 offset, bvec->bv_len);
2046 bytes_to_copy -= bvec->bv_len;
2047 }
2048 offset += bvec->bv_len;
2049 }
2050 }
1985 } else { 2051 } else {
1986 dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT 2052 dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
1987 "%s - no reply\n", ioc->name, __func__)); 2053 "%s - no reply\n", ioc->name, __func__));
@@ -2003,6 +2069,15 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2003 pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp), 2069 pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp),
2004 PCI_DMA_BIDIRECTIONAL); 2070 PCI_DMA_BIDIRECTIONAL);
2005 2071
2072 free_pci:
2073 if (pci_addr_out)
2074 pci_free_consistent(ioc->pdev, blk_rq_bytes(req), pci_addr_out,
2075 pci_dma_out);
2076
2077 if (pci_addr_in)
2078 pci_free_consistent(ioc->pdev, blk_rq_bytes(rsp), pci_addr_in,
2079 pci_dma_in);
2080
2006 out: 2081 out:
2007 ioc->transport_cmds.status = MPT2_CMD_NOT_USED; 2082 ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
2008 mutex_unlock(&ioc->transport_cmds.mutex); 2083 mutex_unlock(&ioc->transport_cmds.mutex);