Skip to content

Commit

Permalink
isci: fix support for arbitrarily large smp requests
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Dan Williams committed Jul 3, 2011
1 parent ddcc7e3 commit e9bf709
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 85 deletions.
138 changes: 64 additions & 74 deletions drivers/scsi/isci/request.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand All @@ -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",
Expand Down
1 change: 0 additions & 1 deletion drivers/scsi/isci/request.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,6 @@ struct scic_sds_request {
} ssp;

struct {
struct smp_req cmd;
struct smp_resp rsp;
} smp;

Expand Down
11 changes: 1 addition & 10 deletions drivers/scsi/isci/sas.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,6 @@ struct smp_req_phycntl {
u8 _r_h[3]; /* bytes 37-39 */
} __packed;

#define SMP_REQ_VENDOR_SPECIFIC_MAX_LEN 1016

/*
* struct smp_req - This structure simply unionizes the existing request
* structures into a common request type.
Expand All @@ -203,14 +201,7 @@ struct smp_req {
u8 func; /* byte 1 */
u8 alloc_resp_len; /* byte 2 */
u8 req_len; /* byte 3 */

union { /* bytes 4-N */
u32 smp_req_gen;
struct smp_req_phy_id phy_id;
struct smp_req_phycntl phy_cntl;
struct smp_req_conf_rtinfo conf_rt_info;
u8 vendor[SMP_REQ_VENDOR_SPECIFIC_MAX_LEN];
};
u8 req_data[0];
} __packed;

#define SMP_RESP_HDR_SZ 4
Expand Down

0 comments on commit e9bf709

Please sign in to comment.