|
@@ -1870,6 +1870,38 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+_transport_map_smp_buffer(struct device *dev, struct bsg_buffer *buf,
|
|
|
+ dma_addr_t *dma_addr, size_t *dma_len, void **p)
|
|
|
+{
|
|
|
+ /* Check if the request is split across multiple segments */
|
|
|
+ if (buf->sg_cnt > 1) {
|
|
|
+ *p = dma_alloc_coherent(dev, buf->payload_len, dma_addr,
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!*p)
|
|
|
+ return -ENOMEM;
|
|
|
+ *dma_len = buf->payload_len;
|
|
|
+ } else {
|
|
|
+ if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL))
|
|
|
+ return -ENOMEM;
|
|
|
+ *dma_addr = sg_dma_address(buf->sg_list);
|
|
|
+ *dma_len = sg_dma_len(buf->sg_list);
|
|
|
+ *p = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+_transport_unmap_smp_buffer(struct device *dev, struct bsg_buffer *buf,
|
|
|
+ dma_addr_t dma_addr, void *p)
|
|
|
+{
|
|
|
+ if (p)
|
|
|
+ dma_free_coherent(dev, buf->payload_len, p, dma_addr);
|
|
|
+ else
|
|
|
+ dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* _transport_smp_handler - transport portal for smp passthru
|
|
|
* @shost: shost object
|
|
@@ -1880,9 +1912,9 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
|
|
|
* Example:
|
|
|
* smp_rep_general /sys/class/bsg/expander-5:0
|
|
|
*/
|
|
|
-static int
|
|
|
-_transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
|
|
- struct request *req)
|
|
|
+static void
|
|
|
+_transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
|
|
|
+ struct sas_rphy *rphy)
|
|
|
{
|
|
|
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
|
|
|
Mpi2SmpPassthroughRequest_t *mpi_request;
|
|
@@ -1891,33 +1923,25 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
|
|
u16 smid;
|
|
|
u32 ioc_state;
|
|
|
void *psge;
|
|
|
- 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;
|
|
|
+ dma_addr_t dma_addr_in;
|
|
|
+ dma_addr_t dma_addr_out;
|
|
|
+ void *addr_in = NULL;
|
|
|
+ void *addr_out = NULL;
|
|
|
+ size_t dma_len_in;
|
|
|
+ size_t dma_len_out;
|
|
|
u16 wait_state_count;
|
|
|
- struct request *rsp = req->next_rq;
|
|
|
- struct bio_vec bvec;
|
|
|
- struct bvec_iter iter;
|
|
|
-
|
|
|
- if (!rsp) {
|
|
|
- pr_err(MPT3SAS_FMT "%s: the smp response space is missing\n",
|
|
|
- ioc->name, __func__);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
+ unsigned int reslen = 0;
|
|
|
|
|
|
if (ioc->shost_recovery || ioc->pci_error_recovery) {
|
|
|
pr_info(MPT3SAS_FMT "%s: host reset in progress!\n",
|
|
|
__func__, ioc->name);
|
|
|
- return -EFAULT;
|
|
|
+ rc = -EFAULT;
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);
|
|
|
if (rc)
|
|
|
- return rc;
|
|
|
+ goto out;
|
|
|
|
|
|
if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) {
|
|
|
pr_err(MPT3SAS_FMT "%s: transport_cmds in use\n", ioc->name,
|
|
@@ -1927,58 +1951,20 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
|
|
}
|
|
|
ioc->transport_cmds.status = MPT3_CMD_PENDING;
|
|
|
|
|
|
- /* Check if the request is split across multiple segments */
|
|
|
- if (bio_multiple_segments(req->bio)) {
|
|
|
- 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) {
|
|
|
- pr_info(MPT3SAS_FMT "%s(): PCI Addr out = NULL\n",
|
|
|
- ioc->name, __func__);
|
|
|
- rc = -ENOMEM;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- bio_for_each_segment(bvec, req->bio, iter) {
|
|
|
- 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 (pci_dma_mapping_error(ioc->pdev, dma_addr_out)) {
|
|
|
- pr_info(MPT3SAS_FMT "%s(): DMA Addr out = NULL\n",
|
|
|
- ioc->name, __func__);
|
|
|
- rc = -ENOMEM;
|
|
|
- goto free_pci;
|
|
|
- }
|
|
|
+ rc = _transport_map_smp_buffer(&ioc->pdev->dev, &job->request_payload,
|
|
|
+ &dma_addr_out, &dma_len_out, &addr_out);
|
|
|
+ if (rc)
|
|
|
+ goto out;
|
|
|
+ if (addr_out) {
|
|
|
+ sg_copy_to_buffer(job->request_payload.sg_list,
|
|
|
+ job->request_payload.sg_cnt, addr_out,
|
|
|
+ job->request_payload.payload_len);
|
|
|
}
|
|
|
|
|
|
- /* Check if the response needs to be populated across
|
|
|
- * multiple segments */
|
|
|
- if (bio_multiple_segments(rsp->bio)) {
|
|
|
- pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp),
|
|
|
- &pci_dma_in);
|
|
|
- if (!pci_addr_in) {
|
|
|
- pr_info(MPT3SAS_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 (pci_dma_mapping_error(ioc->pdev, dma_addr_in)) {
|
|
|
- pr_info(MPT3SAS_FMT "%s(): DMA Addr in = NULL\n",
|
|
|
- ioc->name, __func__);
|
|
|
- rc = -ENOMEM;
|
|
|
- goto unmap;
|
|
|
- }
|
|
|
- }
|
|
|
+ rc = _transport_map_smp_buffer(&ioc->pdev->dev, &job->reply_payload,
|
|
|
+ &dma_addr_in, &dma_len_in, &addr_in);
|
|
|
+ if (rc)
|
|
|
+ goto unmap_out;
|
|
|
|
|
|
wait_state_count = 0;
|
|
|
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
|
|
@@ -1988,7 +1974,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 unmap;
|
|
|
+ goto unmap_in;
|
|
|
}
|
|
|
ssleep(1);
|
|
|
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
|
|
@@ -2005,7 +1991,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
|
|
pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
|
|
|
ioc->name, __func__);
|
|
|
rc = -EAGAIN;
|
|
|
- goto unmap;
|
|
|
+ goto unmap_in;
|
|
|
}
|
|
|
|
|
|
rc = 0;
|
|
@@ -2018,15 +2004,11 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
|
|
mpi_request->SASAddress = (rphy) ?
|
|
|
cpu_to_le64(rphy->identify.sas_address) :
|
|
|
cpu_to_le64(ioc->sas_hba.sas_address);
|
|
|
- mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
|
|
|
+ mpi_request->RequestDataLength = cpu_to_le16(dma_len_out - 4);
|
|
|
psge = &mpi_request->SGL;
|
|
|
|
|
|
- if (bio_multiple_segments(req->bio))
|
|
|
- ioc->build_sg(ioc, psge, pci_dma_out, (blk_rq_bytes(req) - 4),
|
|
|
- pci_dma_in, (blk_rq_bytes(rsp) + 4));
|
|
|
- else
|
|
|
- ioc->build_sg(ioc, psge, dma_addr_out, (blk_rq_bytes(req) - 4),
|
|
|
- dma_addr_in, (blk_rq_bytes(rsp) + 4));
|
|
|
+ ioc->build_sg(ioc, psge, dma_addr_out, dma_len_out - 4, dma_addr_in,
|
|
|
+ dma_len_in - 4);
|
|
|
|
|
|
dtransportprintk(ioc, pr_info(MPT3SAS_FMT
|
|
|
"%s - sending smp request\n", ioc->name, __func__));
|
|
@@ -2040,83 +2022,51 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
|
|
|
__func__, ioc->name);
|
|
|
_debug_dump_mf(mpi_request,
|
|
|
sizeof(Mpi2SmpPassthroughRequest_t)/4);
|
|
|
- if (!(ioc->transport_cmds.status & MPT3_CMD_RESET))
|
|
|
- issue_reset = 1;
|
|
|
- goto issue_host_reset;
|
|
|
+ if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) {
|
|
|
+ mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
|
|
+ rc = -ETIMEDOUT;
|
|
|
+ goto unmap_in;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
dtransportprintk(ioc, pr_info(MPT3SAS_FMT
|
|
|
"%s - complete\n", ioc->name, __func__));
|
|
|
|
|
|
- if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) {
|
|
|
-
|
|
|
- mpi_reply = ioc->transport_cmds.reply;
|
|
|
-
|
|
|
- dtransportprintk(ioc, pr_info(MPT3SAS_FMT
|
|
|
- "%s - reply data transfer size(%d)\n",
|
|
|
- ioc->name, __func__,
|
|
|
- le16_to_cpu(mpi_reply->ResponseDataLength)));
|
|
|
-
|
|
|
- memcpy(scsi_req(req)->sense, mpi_reply, sizeof(*mpi_reply));
|
|
|
- scsi_req(req)->sense_len = sizeof(*mpi_reply);
|
|
|
- scsi_req(req)->resid_len = 0;
|
|
|
- scsi_req(rsp)->resid_len -=
|
|
|
- le16_to_cpu(mpi_reply->ResponseDataLength);
|
|
|
-
|
|
|
- /* check if the resp needs to be copied from the allocated
|
|
|
- * pci mem */
|
|
|
- if (bio_multiple_segments(rsp->bio)) {
|
|
|
- u32 offset = 0;
|
|
|
- u32 bytes_to_copy =
|
|
|
- le16_to_cpu(mpi_reply->ResponseDataLength);
|
|
|
- bio_for_each_segment(bvec, rsp->bio, iter) {
|
|
|
- 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 {
|
|
|
+ if (!(ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID)) {
|
|
|
dtransportprintk(ioc, pr_info(MPT3SAS_FMT
|
|
|
"%s - no reply\n", ioc->name, __func__));
|
|
|
rc = -ENXIO;
|
|
|
+ goto unmap_in;
|
|
|
}
|
|
|
|
|
|
- issue_host_reset:
|
|
|
- if (issue_reset) {
|
|
|
- mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
|
|
|
- rc = -ETIMEDOUT;
|
|
|
- }
|
|
|
+ mpi_reply = ioc->transport_cmds.reply;
|
|
|
|
|
|
- unmap:
|
|
|
- if (dma_addr_out)
|
|
|
- pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req),
|
|
|
- PCI_DMA_BIDIRECTIONAL);
|
|
|
- if (dma_addr_in)
|
|
|
- pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp),
|
|
|
- PCI_DMA_BIDIRECTIONAL);
|
|
|
+ dtransportprintk(ioc,
|
|
|
+ pr_info(MPT3SAS_FMT "%s - reply data transfer size(%d)\n",
|
|
|
+ ioc->name, __func__,
|
|
|
+ le16_to_cpu(mpi_reply->ResponseDataLength)));
|
|
|
|
|
|
- free_pci:
|
|
|
- if (pci_addr_out)
|
|
|
- pci_free_consistent(ioc->pdev, blk_rq_bytes(req), pci_addr_out,
|
|
|
- pci_dma_out);
|
|
|
+ memcpy(job->reply, mpi_reply, sizeof(*mpi_reply));
|
|
|
+ job->reply_len = sizeof(*mpi_reply);
|
|
|
+ reslen = le16_to_cpu(mpi_reply->ResponseDataLength);
|
|
|
|
|
|
- if (pci_addr_in)
|
|
|
- pci_free_consistent(ioc->pdev, blk_rq_bytes(rsp), pci_addr_in,
|
|
|
- pci_dma_in);
|
|
|
+ if (addr_in) {
|
|
|
+ sg_copy_to_buffer(job->reply_payload.sg_list,
|
|
|
+ job->reply_payload.sg_cnt, addr_in,
|
|
|
+ job->reply_payload.payload_len);
|
|
|
+ }
|
|
|
|
|
|
+ rc = 0;
|
|
|
+ unmap_in:
|
|
|
+ _transport_unmap_smp_buffer(&ioc->pdev->dev, &job->reply_payload,
|
|
|
+ dma_addr_in, addr_in);
|
|
|
+ unmap_out:
|
|
|
+ _transport_unmap_smp_buffer(&ioc->pdev->dev, &job->request_payload,
|
|
|
+ dma_addr_out, addr_out);
|
|
|
out:
|
|
|
ioc->transport_cmds.status = MPT3_CMD_NOT_USED;
|
|
|
mutex_unlock(&ioc->transport_cmds.mutex);
|
|
|
- return rc;
|
|
|
+ bsg_job_done(job, rc, reslen);
|
|
|
}
|
|
|
|
|
|
struct sas_function_template mpt3sas_transport_functions = {
|