diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-09-29 03:35:27 +0200 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-10-02 20:07:17 +0200 |
commit | 54b5e3a4bfa3452bc10cd4da672099ccc46b8c09 (patch) | |
tree | f07de6264a0ffb59845f8dfb62d2f158ba50e012 /drivers/scsi/isci/request.c | |
parent | [SCSI] pm8001: missing break statements (diff) | |
download | linux-54b5e3a4bfa3452bc10cd4da672099ccc46b8c09.tar.xz linux-54b5e3a4bfa3452bc10cd4da672099ccc46b8c09.zip |
[SCSI] isci: fix support for large smp requests
Kill the local smp response buffer.
Besides being unnecessary, it is too small (currently truncates
responses to 60 bytes). The mid-layer will have already allocated a
sufficiently sized buffer, just kmap and copy into it directly.
Cc: <stable@kernel.org>
Reported-by: Derick Marks <derick.w.marks@intel.com>
Tested-by: Derick Marks <derick.w.marks@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/isci/request.c')
-rw-r--r-- | drivers/scsi/isci/request.c | 49 |
1 files changed, 20 insertions, 29 deletions
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index b5d3a8c4d329..225b196800a2 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -1490,29 +1490,30 @@ sci_io_request_frame_handler(struct isci_request *ireq, return SCI_SUCCESS; case SCI_REQ_SMP_WAIT_RESP: { - struct smp_resp *rsp_hdr = &ireq->smp.rsp; - void *frame_header; + struct sas_task *task = isci_request_access_task(ireq); + struct scatterlist *sg = &task->smp_task.smp_resp; + void *frame_header, *kaddr; + u8 *rsp; sci_unsolicited_frame_control_get_header(&ihost->uf_control, - frame_index, - &frame_header); - - /* byte swap the header. */ - word_cnt = SMP_RESP_HDR_SZ / sizeof(u32); - sci_swab32_cpy(rsp_hdr, frame_header, word_cnt); + frame_index, + &frame_header); + kaddr = kmap_atomic(sg_page(sg), KM_IRQ0); + rsp = kaddr + sg->offset; + sci_swab32_cpy(rsp, frame_header, 1); - if (rsp_hdr->frame_type == SMP_RESPONSE) { + if (rsp[0] == SMP_RESPONSE) { void *smp_resp; sci_unsolicited_frame_control_get_buffer(&ihost->uf_control, - frame_index, - &smp_resp); + frame_index, + &smp_resp); - word_cnt = (sizeof(struct smp_resp) - SMP_RESP_HDR_SZ) / - sizeof(u32); - - sci_swab32_cpy(((u8 *) rsp_hdr) + SMP_RESP_HDR_SZ, - smp_resp, word_cnt); + word_cnt = (sg->length/4)-1; + if (word_cnt > 0) + word_cnt = min_t(unsigned int, word_cnt, + SCU_UNSOLICITED_FRAME_BUFFER_SIZE/4); + sci_swab32_cpy(rsp + 4, smp_resp, word_cnt); ireq->scu_status = SCU_TASK_DONE_GOOD; ireq->sci_status = SCI_SUCCESS; @@ -1528,12 +1529,13 @@ sci_io_request_frame_handler(struct isci_request *ireq, __func__, ireq, frame_index, - rsp_hdr->frame_type); + rsp[0]); ireq->scu_status = SCU_TASK_DONE_SMP_FRM_TYPE_ERR; ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); } + kunmap_atomic(kaddr, KM_IRQ0); sci_controller_release_frame(ihost, frame_index); @@ -2603,18 +2605,7 @@ static void isci_request_io_request_complete(struct isci_host *ihost, status = SAM_STAT_GOOD; set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - if (task->task_proto == SAS_PROTOCOL_SMP) { - void *rsp = &request->smp.rsp; - - dev_dbg(&ihost->pdev->dev, - "%s: SMP protocol completion\n", - __func__); - - sg_copy_from_buffer( - &task->smp_task.smp_resp, 1, - rsp, sizeof(struct smp_resp)); - } else if (completion_status - == SCI_IO_SUCCESS_IO_DONE_EARLY) { + if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) { /* This was an SSP / STP / SATA transfer. * There is a possibility that less data than |