aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc
diff options
context:
space:
mode:
authorJames Smart <james.smart@emulex.com>2013-04-17 20:17:26 -0400
committerJames Bottomley <JBottomley@Parallels.com>2013-05-02 16:00:01 -0400
commitd5ce53b7dd497f8e5a5e4bbc736312b34fe452bd (patch)
tree701ec5dd847f2d993a2e2b6ea8f8bddf6f700027 /drivers/scsi/lpfc
parent5688d6705532657af0088148b4f4f620844084cf (diff)
[SCSI] lpfc 8.3.39: Fixed crash when processing bsg's sg list with high memory pages
Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c33
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c3
2 files changed, 24 insertions, 12 deletions
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index f79933366545..094be2cad65b 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -219,26 +219,35 @@ lpfc_bsg_copy_data(struct lpfc_dmabuf *dma_buffers,
219 unsigned int transfer_bytes, bytes_copied = 0; 219 unsigned int transfer_bytes, bytes_copied = 0;
220 unsigned int sg_offset, dma_offset; 220 unsigned int sg_offset, dma_offset;
221 unsigned char *dma_address, *sg_address; 221 unsigned char *dma_address, *sg_address;
222 struct scatterlist *sgel;
223 LIST_HEAD(temp_list); 222 LIST_HEAD(temp_list);
224 223 struct sg_mapping_iter miter;
224 unsigned long flags;
225 unsigned int sg_flags = SG_MITER_ATOMIC;
226 bool sg_valid;
225 227
226 list_splice_init(&dma_buffers->list, &temp_list); 228 list_splice_init(&dma_buffers->list, &temp_list);
227 list_add(&dma_buffers->list, &temp_list); 229 list_add(&dma_buffers->list, &temp_list);
228 sg_offset = 0; 230 sg_offset = 0;
229 sgel = bsg_buffers->sg_list; 231 if (to_buffers)
232 sg_flags |= SG_MITER_FROM_SG;
233 else
234 sg_flags |= SG_MITER_TO_SG;
235 sg_miter_start(&miter, bsg_buffers->sg_list, bsg_buffers->sg_cnt,
236 sg_flags);
237 local_irq_save(flags);
238 sg_valid = sg_miter_next(&miter);
230 list_for_each_entry(mp, &temp_list, list) { 239 list_for_each_entry(mp, &temp_list, list) {
231 dma_offset = 0; 240 dma_offset = 0;
232 while (bytes_to_transfer && sgel && 241 while (bytes_to_transfer && sg_valid &&
233 (dma_offset < LPFC_BPL_SIZE)) { 242 (dma_offset < LPFC_BPL_SIZE)) {
234 dma_address = mp->virt + dma_offset; 243 dma_address = mp->virt + dma_offset;
235 if (sg_offset) { 244 if (sg_offset) {
236 /* Continue previous partial transfer of sg */ 245 /* Continue previous partial transfer of sg */
237 sg_address = sg_virt(sgel) + sg_offset; 246 sg_address = miter.addr + sg_offset;
238 transfer_bytes = sgel->length - sg_offset; 247 transfer_bytes = miter.length - sg_offset;
239 } else { 248 } else {
240 sg_address = sg_virt(sgel); 249 sg_address = miter.addr;
241 transfer_bytes = sgel->length; 250 transfer_bytes = miter.length;
242 } 251 }
243 if (bytes_to_transfer < transfer_bytes) 252 if (bytes_to_transfer < transfer_bytes)
244 transfer_bytes = bytes_to_transfer; 253 transfer_bytes = bytes_to_transfer;
@@ -252,12 +261,14 @@ lpfc_bsg_copy_data(struct lpfc_dmabuf *dma_buffers,
252 sg_offset += transfer_bytes; 261 sg_offset += transfer_bytes;
253 bytes_to_transfer -= transfer_bytes; 262 bytes_to_transfer -= transfer_bytes;
254 bytes_copied += transfer_bytes; 263 bytes_copied += transfer_bytes;
255 if (sg_offset >= sgel->length) { 264 if (sg_offset >= miter.length) {
256 sg_offset = 0; 265 sg_offset = 0;
257 sgel = sg_next(sgel); 266 sg_valid = sg_miter_next(&miter);
258 } 267 }
259 } 268 }
260 } 269 }
270 sg_miter_stop(&miter);
271 local_irq_restore(flags);
261 list_del_init(&dma_buffers->list); 272 list_del_init(&dma_buffers->list);
262 list_splice(&temp_list, &dma_buffers->list); 273 list_splice(&temp_list, &dma_buffers->list);
263 return bytes_copied; 274 return bytes_copied;
@@ -471,6 +482,7 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
471 cmdiocbq->context1 = dd_data; 482 cmdiocbq->context1 = dd_data;
472 cmdiocbq->context2 = cmp; 483 cmdiocbq->context2 = cmp;
473 cmdiocbq->context3 = bmp; 484 cmdiocbq->context3 = bmp;
485 cmdiocbq->context_un.ndlp = ndlp;
474 dd_data->type = TYPE_IOCB; 486 dd_data->type = TYPE_IOCB;
475 dd_data->set_job = job; 487 dd_data->set_job = job;
476 dd_data->context_un.iocb.cmdiocbq = cmdiocbq; 488 dd_data->context_un.iocb.cmdiocbq = cmdiocbq;
@@ -1508,6 +1520,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
1508 ctiocb->context1 = dd_data; 1520 ctiocb->context1 = dd_data;
1509 ctiocb->context2 = cmp; 1521 ctiocb->context2 = cmp;
1510 ctiocb->context3 = bmp; 1522 ctiocb->context3 = bmp;
1523 ctiocb->context_un.ndlp = ndlp;
1511 ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp; 1524 ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp;
1512 1525
1513 dd_data->type = TYPE_IOCB; 1526 dd_data->type = TYPE_IOCB;
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index e9819c6c78b6..c37e70439448 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -927,8 +927,7 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
927 } else if ((piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) && 927 } else if ((piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) &&
928 !(piocbq->iocb_flag & LPFC_IO_LIBDFC)) 928 !(piocbq->iocb_flag & LPFC_IO_LIBDFC))
929 ndlp = piocbq->context_un.ndlp; 929 ndlp = piocbq->context_un.ndlp;
930 else if ((piocbq->iocb.ulpCommand == CMD_ELS_REQUEST64_CR) && 930 else if (piocbq->iocb_flag & LPFC_IO_LIBDFC)
931 (piocbq->iocb_flag & LPFC_IO_LIBDFC))
932 ndlp = piocbq->context_un.ndlp; 931 ndlp = piocbq->context_un.ndlp;
933 else 932 else
934 ndlp = piocbq->context1; 933 ndlp = piocbq->context1;