summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci/request.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-06-16 16:59:56 -0700
committerDan Williams <dan.j.williams@intel.com>2011-07-03 04:04:51 -0700
commite9bf709564e90abea25ca7aeae8c3de5cc6468d7 (patch)
treee4569a311fd0181109ad7b265425a74af2a41553 /drivers/scsi/isci/request.c
parentddcc7e347a891937be65358b43f40b7f81185f8f (diff)
downloadblackbird-op-linux-e9bf709564e90abea25ca7aeae8c3de5cc6468d7.tar.gz
blackbird-op-linux-e9bf709564e90abea25ca7aeae8c3de5cc6468d7.zip
isci: fix support for arbitrarily large smp requests
Instead of duplicating the smp request buffer reuse the one provided by libsas. This future proofs the driver to support arbitrarily large smp requests, and shrinks the request structure size by ~700 bytes. Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci/request.c')
-rw-r--r--drivers/scsi/isci/request.c138
1 files changed, 64 insertions, 74 deletions
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 395084955150..1043fed2a40a 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2943,6 +2943,20 @@ static void isci_request_io_request_complete(struct isci_host *isci_host,
dma_unmap_sg(&isci_host->pdev->dev, task->scatter,
request->num_sg_entries, task->data_dir);
break;
+ case SAS_PROTOCOL_SMP: {
+ struct scatterlist *sg = &task->smp_task.smp_req;
+ struct smp_req *smp_req;
+ void *kaddr;
+
+ dma_unmap_sg(&isci_host->pdev->dev, sg, 1, DMA_TO_DEVICE);
+
+ /* need to swab it back in case the command buffer is re-used */
+ kaddr = kmap_atomic(sg_page(sg), KM_IRQ0);
+ smp_req = kaddr + sg->offset;
+ sci_swab32_cpy(smp_req, smp_req, sg->length / sizeof(u32));
+ kunmap_atomic(kaddr, KM_IRQ0);
+ break;
+ }
default:
break;
}
@@ -3160,7 +3174,7 @@ scic_io_request_construct(struct scic_sds_controller *scic,
else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP))
memset(&sci_req->stp.cmd, 0, sizeof(sci_req->stp.cmd));
else if (dev_is_expander(dev))
- memset(&sci_req->smp.cmd, 0, sizeof(sci_req->smp.cmd));
+ /* pass */;
else
return SCI_FAILURE_UNSUPPORTED_PROTOCOL;
@@ -3236,30 +3250,54 @@ static enum sci_status isci_request_stp_request_construct(
return status;
}
-/*
- * This function will fill in the SCU Task Context for a SMP request. The
- * following important settings are utilized: -# task_type ==
- * SCU_TASK_TYPE_SMP. This simply indicates that a normal request type
- * (i.e. non-raw frame) is being utilized to perform task management. -#
- * control_frame == 1. This ensures that the proper endianess is set so
- * that the bytes are transmitted in the right order for a smp request frame.
- * @sci_req: This parameter specifies the smp request object being
- * constructed.
- *
- */
-static void
-scu_smp_request_construct_task_context(struct scic_sds_request *sci_req,
- ssize_t req_len)
+static enum sci_status
+scic_io_request_construct_smp(struct device *dev,
+ struct scic_sds_request *sci_req,
+ struct sas_task *task)
{
- dma_addr_t dma_addr;
+ struct scatterlist *sg = &task->smp_task.smp_req;
struct scic_sds_remote_device *sci_dev;
- struct scic_sds_port *sci_port;
struct scu_task_context *task_context;
- ssize_t word_cnt = sizeof(struct smp_req) / sizeof(u32);
+ struct scic_sds_port *sci_port;
+ struct smp_req *smp_req;
+ void *kaddr;
+ u8 req_len;
+ u32 cmd;
+
+ kaddr = kmap_atomic(sg_page(sg), KM_IRQ0);
+ smp_req = kaddr + sg->offset;
+ /*
+ * Look at the SMP requests' header fields; for certain SAS 1.x SMP
+ * functions under SAS 2.0, a zero request length really indicates
+ * a non-zero default length.
+ */
+ if (smp_req->req_len == 0) {
+ switch (smp_req->func) {
+ case SMP_DISCOVER:
+ case SMP_REPORT_PHY_ERR_LOG:
+ case SMP_REPORT_PHY_SATA:
+ case SMP_REPORT_ROUTE_INFO:
+ smp_req->req_len = 2;
+ break;
+ case SMP_CONF_ROUTE_INFO:
+ case SMP_PHY_CONTROL:
+ case SMP_PHY_TEST_FUNCTION:
+ smp_req->req_len = 9;
+ break;
+ /* Default - zero is a valid default for 2.0. */
+ }
+ }
+ req_len = smp_req->req_len;
+ sci_swab32_cpy(smp_req, smp_req, sg->length / sizeof(u32));
+ cmd = *(u32 *) smp_req;
+ kunmap_atomic(kaddr, KM_IRQ0);
+
+ if (!dma_map_sg(dev, sg, 1, DMA_TO_DEVICE))
+ return SCI_FAILURE;
+
+ sci_req->protocol = SCIC_SMP_PROTOCOL;
/* byte swap the smp request. */
- sci_swab32_cpy(&sci_req->smp.cmd, &sci_req->smp.cmd,
- word_cnt);
task_context = scic_sds_request_get_task_context(sci_req);
@@ -3307,7 +3345,7 @@ scu_smp_request_construct_task_context(struct scic_sds_request *sci_req,
* 18h ~ 30h, protocol specific
* since commandIU has been build by framework at this point, we just
* copy the frist DWord from command IU to this location. */
- memcpy(&task_context->type.smp, &sci_req->smp.cmd, sizeof(u32));
+ memcpy(&task_context->type.smp, &cmd, sizeof(u32));
/*
* 40h
@@ -3347,48 +3385,12 @@ scu_smp_request_construct_task_context(struct scic_sds_request *sci_req,
* Copy the physical address for the command buffer to the SCU Task
* Context command buffer should not contain command header.
*/
- dma_addr = scic_io_request_get_dma_addr(sci_req,
- ((char *) &sci_req->smp.cmd) +
- sizeof(u32));
-
- task_context->command_iu_upper = upper_32_bits(dma_addr);
- task_context->command_iu_lower = lower_32_bits(dma_addr);
+ task_context->command_iu_upper = upper_32_bits(sg_dma_address(sg));
+ task_context->command_iu_lower = lower_32_bits(sg_dma_address(sg) + sizeof(u32));
/* SMP response comes as UF, so no need to set response IU address. */
task_context->response_iu_upper = 0;
task_context->response_iu_lower = 0;
-}
-
-static enum sci_status
-scic_io_request_construct_smp(struct scic_sds_request *sci_req)
-{
- struct smp_req *smp_req = &sci_req->smp.cmd;
-
- sci_req->protocol = SCIC_SMP_PROTOCOL;
-
- /*
- * Look at the SMP requests' header fields; for certain SAS 1.x SMP
- * functions under SAS 2.0, a zero request length really indicates
- * a non-zero default length.
- */
- if (smp_req->req_len == 0) {
- switch (smp_req->func) {
- case SMP_DISCOVER:
- case SMP_REPORT_PHY_ERR_LOG:
- case SMP_REPORT_PHY_SATA:
- case SMP_REPORT_ROUTE_INFO:
- smp_req->req_len = 2;
- break;
- case SMP_CONF_ROUTE_INFO:
- case SMP_PHY_CONTROL:
- case SMP_PHY_TEST_FUNCTION:
- smp_req->req_len = 9;
- break;
- /* Default - zero is a valid default for 2.0. */
- }
- }
-
- scu_smp_request_construct_task_context(sci_req, smp_req->req_len);
sci_change_state(&sci_req->sm, SCI_REQ_CONSTRUCTED);
@@ -3404,24 +3406,12 @@ scic_io_request_construct_smp(struct scic_sds_request *sci_req)
*/
static enum sci_status isci_smp_request_build(struct isci_request *ireq)
{
- enum sci_status status = SCI_FAILURE;
struct sas_task *task = isci_request_access_task(ireq);
+ struct device *dev = &ireq->isci_host->pdev->dev;
struct scic_sds_request *sci_req = &ireq->sci;
+ enum sci_status status = SCI_FAILURE;
- dev_dbg(&ireq->isci_host->pdev->dev,
- "%s: request = %p\n", __func__, ireq);
-
- dev_dbg(&ireq->isci_host->pdev->dev,
- "%s: smp_req len = %d\n",
- __func__,
- task->smp_task.smp_req.length);
-
- /* copy the smp_command to the address; */
- sg_copy_to_buffer(&task->smp_task.smp_req, 1,
- &sci_req->smp.cmd,
- sizeof(struct smp_req));
-
- status = scic_io_request_construct_smp(sci_req);
+ status = scic_io_request_construct_smp(dev, sci_req, task);
if (status != SCI_SUCCESS)
dev_warn(&ireq->isci_host->pdev->dev,
"%s: failed with status = %d\n",
OpenPOWER on IntegriCloud