Commit 77a6edff authored by nagalakshmi.nandigama@lsi.com's avatar nagalakshmi.nandigama@lsi.com Committed by James Bottomley

[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: default avatarNagalakshmi Nandigama <nagalakshmi.nandigama@lsi.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 913809f6
......@@ -1828,7 +1828,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
Mpi2SmpPassthroughRequest_t *mpi_request;
Mpi2SmpPassthroughReply_t *mpi_reply;
int rc;
int rc, i;
u16 smid;
u32 ioc_state;
unsigned long timeleft;
......@@ -1837,24 +1837,20 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
u8 issue_reset = 0;
dma_addr_t dma_addr_in = 0;
dma_addr_t dma_addr_out = 0;
dma_addr_t pci_dma_in = 0;
dma_addr_t pci_dma_out = 0;
void *pci_addr_in = NULL;
void *pci_addr_out = NULL;
u16 wait_state_count;
struct request *rsp = req->next_rq;
struct bio_vec *bvec = NULL;
if (!rsp) {
printk(MPT2SAS_ERR_FMT "%s: the smp response space is "
"missing\n", ioc->name, __func__);
return -EINVAL;
}
/* do we need to support multiple segments? */
if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, "
"rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt,
blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
return -EINVAL;
}
if (ioc->shost_recovery) {
if (ioc->shost_recovery || ioc->pci_error_recovery) {
printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
__func__, ioc->name);
return -EFAULT;
......@@ -1872,6 +1868,59 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
}
ioc->transport_cmds.status = MPT2_CMD_PENDING;
/* Check if the request is split across multiple segments */
if (req->bio->bi_vcnt > 1) {
u32 offset = 0;
/* Allocate memory and copy the request */
pci_addr_out = pci_alloc_consistent(ioc->pdev,
blk_rq_bytes(req), &pci_dma_out);
if (!pci_addr_out) {
printk(MPT2SAS_INFO_FMT "%s(): PCI Addr out = NULL\n",
ioc->name, __func__);
rc = -ENOMEM;
goto out;
}
bio_for_each_segment(bvec, req->bio, i) {
memcpy(pci_addr_out + offset,
page_address(bvec->bv_page) + bvec->bv_offset,
bvec->bv_len);
offset += bvec->bv_len;
}
} else {
dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
if (!dma_addr_out) {
printk(MPT2SAS_INFO_FMT "%s(): DMA Addr out = NULL\n",
ioc->name, __func__);
rc = -ENOMEM;
goto free_pci;
}
}
/* Check if the response needs to be populated across
* multiple segments */
if (rsp->bio->bi_vcnt > 1) {
pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp),
&pci_dma_in);
if (!pci_addr_in) {
printk(MPT2SAS_INFO_FMT "%s(): PCI Addr in = NULL\n",
ioc->name, __func__);
rc = -ENOMEM;
goto unmap;
}
} else {
dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
if (!dma_addr_in) {
printk(MPT2SAS_INFO_FMT "%s(): DMA Addr in = NULL\n",
ioc->name, __func__);
rc = -ENOMEM;
goto unmap;
}
}
wait_state_count = 0;
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
......@@ -1880,7 +1929,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
"%s: failed due to ioc not operational\n",
ioc->name, __func__);
rc = -EFAULT;
goto out;
goto unmap;
}
ssleep(1);
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
......@@ -1897,7 +1946,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
rc = -EAGAIN;
goto out;
goto unmap;
}
rc = 0;
......@@ -1919,16 +1968,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
if (!dma_addr_out) {
mpt2sas_base_free_smid(ioc, smid);
goto unmap;
if (req->bio->bi_vcnt > 1) {
ioc->base_add_sg_single(psge, sgl_flags |
(blk_rq_bytes(req) - 4), pci_dma_out);
} else {
ioc->base_add_sg_single(psge, sgl_flags |
(blk_rq_bytes(req) - 4), dma_addr_out);
}
ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4),
dma_addr_out);
/* incr sgel */
psge += ioc->sge_size;
......@@ -1937,16 +1984,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
MPI2_SGE_FLAGS_END_OF_LIST);
sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
if (!dma_addr_in) {
mpt2sas_base_free_smid(ioc, smid);
goto unmap;
if (rsp->bio->bi_vcnt > 1) {
ioc->base_add_sg_single(psge, sgl_flags |
(blk_rq_bytes(rsp) + 4), pci_dma_in);
} else {
ioc->base_add_sg_single(psge, sgl_flags |
(blk_rq_bytes(rsp) + 4), dma_addr_in);
}
ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4),
dma_addr_in);
dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
"sending smp request\n", ioc->name, __func__));
......@@ -1982,6 +2027,27 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
req->resid_len = 0;
rsp->resid_len -=
le16_to_cpu(mpi_reply->ResponseDataLength);
/* check if the resp needs to be copied from the allocated
* pci mem */
if (rsp->bio->bi_vcnt > 1) {
u32 offset = 0;
u32 bytes_to_copy =
le16_to_cpu(mpi_reply->ResponseDataLength);
bio_for_each_segment(bvec, rsp->bio, i) {
if (bytes_to_copy <= bvec->bv_len) {
memcpy(page_address(bvec->bv_page) +
bvec->bv_offset, pci_addr_in +
offset, bytes_to_copy);
break;
} else {
memcpy(page_address(bvec->bv_page) +
bvec->bv_offset, pci_addr_in +
offset, bvec->bv_len);
bytes_to_copy -= bvec->bv_len;
}
offset += bvec->bv_len;
}
}
} else {
dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s - no reply\n", ioc->name, __func__));
......@@ -2003,6 +2069,15 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp),
PCI_DMA_BIDIRECTIONAL);
free_pci:
if (pci_addr_out)
pci_free_consistent(ioc->pdev, blk_rq_bytes(req), pci_addr_out,
pci_dma_out);
if (pci_addr_in)
pci_free_consistent(ioc->pdev, blk_rq_bytes(rsp), pci_addr_in,
pci_dma_in);
out:
ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
mutex_unlock(&ioc->transport_cmds.mutex);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment