aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_scsi.c
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2008-08-24 21:49:55 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-10-13 09:28:53 -0400
commit34b02dcdcf1865405f4762b991965c0c3b8a3ae0 (patch)
tree00829334c2813d30e574a5f1290fbf7dd210d1cb /drivers/scsi/lpfc/lpfc_scsi.c
parent90160e010b6f3a91a9bb044bbe6723731e6f366c (diff)
[SCSI] lpfc 8.2.8 : Update driver for new SLI-3 features
Update driver for new SLI-3 features: - interrupt enhancements - lose adapter doorbell writes - inlining support for FCP_Ixx cmds Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_scsi.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c163
1 files changed, 119 insertions, 44 deletions
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index a22bdf9548a6..c1bb90cf0d06 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -198,7 +198,9 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport)
198 struct lpfc_scsi_buf *psb; 198 struct lpfc_scsi_buf *psb;
199 struct ulp_bde64 *bpl; 199 struct ulp_bde64 *bpl;
200 IOCB_t *iocb; 200 IOCB_t *iocb;
201 dma_addr_t pdma_phys; 201 dma_addr_t pdma_phys_fcp_cmd;
202 dma_addr_t pdma_phys_fcp_rsp;
203 dma_addr_t pdma_phys_bpl;
202 uint16_t iotag; 204 uint16_t iotag;
203 205
204 psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); 206 psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL);
@@ -238,40 +240,60 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport)
238 240
239 /* Initialize local short-hand pointers. */ 241 /* Initialize local short-hand pointers. */
240 bpl = psb->fcp_bpl; 242 bpl = psb->fcp_bpl;
241 pdma_phys = psb->dma_handle; 243 pdma_phys_fcp_cmd = psb->dma_handle;
244 pdma_phys_fcp_rsp = psb->dma_handle + sizeof(struct fcp_cmnd);
245 pdma_phys_bpl = psb->dma_handle + sizeof(struct fcp_cmnd) +
246 sizeof(struct fcp_rsp);
242 247
243 /* 248 /*
244 * The first two bdes are the FCP_CMD and FCP_RSP. The balance are sg 249 * The first two bdes are the FCP_CMD and FCP_RSP. The balance are sg
245 * list bdes. Initialize the first two and leave the rest for 250 * list bdes. Initialize the first two and leave the rest for
246 * queuecommand. 251 * queuecommand.
247 */ 252 */
248 bpl->addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys)); 253 bpl[0].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_cmd));
249 bpl->addrLow = le32_to_cpu(putPaddrLow(pdma_phys)); 254 bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd));
250 bpl->tus.f.bdeSize = sizeof (struct fcp_cmnd); 255 bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd);
251 bpl->tus.f.bdeFlags = BUFF_USE_CMND; 256 bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
252 bpl->tus.w = le32_to_cpu(bpl->tus.w); 257 bpl[0].tus.w = le32_to_cpu(bpl->tus.w);
253 bpl++;
254 258
255 /* Setup the physical region for the FCP RSP */ 259 /* Setup the physical region for the FCP RSP */
256 pdma_phys += sizeof (struct fcp_cmnd); 260 bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp));
257 bpl->addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys)); 261 bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp));
258 bpl->addrLow = le32_to_cpu(putPaddrLow(pdma_phys)); 262 bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp);
259 bpl->tus.f.bdeSize = sizeof (struct fcp_rsp); 263 bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
260 bpl->tus.f.bdeFlags = (BUFF_USE_CMND | BUFF_USE_RCV); 264 bpl[1].tus.w = le32_to_cpu(bpl->tus.w);
261 bpl->tus.w = le32_to_cpu(bpl->tus.w);
262 265
263 /* 266 /*
264 * Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf, 267 * Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf,
265 * initialize it with all known data now. 268 * initialize it with all known data now.
266 */ 269 */
267 pdma_phys += (sizeof (struct fcp_rsp));
268 iocb = &psb->cur_iocbq.iocb; 270 iocb = &psb->cur_iocbq.iocb;
269 iocb->un.fcpi64.bdl.ulpIoTag32 = 0; 271 iocb->un.fcpi64.bdl.ulpIoTag32 = 0;
270 iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys); 272 if (phba->sli_rev == 3) {
271 iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys); 273 /* fill in immediate fcp command BDE */
272 iocb->un.fcpi64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64)); 274 iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_IMMED;
273 iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDL; 275 iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd);
274 iocb->ulpBdeCount = 1; 276 iocb->un.fcpi64.bdl.addrLow = offsetof(IOCB_t,
277 unsli3.fcp_ext.icd);
278 iocb->un.fcpi64.bdl.addrHigh = 0;
279 iocb->ulpBdeCount = 0;
280 iocb->ulpLe = 0;
281 /* fill in responce BDE */
282 iocb->unsli3.fcp_ext.rbde.tus.f.bdeFlags = BUFF_TYPE_BDE_64;
283 iocb->unsli3.fcp_ext.rbde.tus.f.bdeSize =
284 sizeof(struct fcp_rsp);
285 iocb->unsli3.fcp_ext.rbde.addrLow =
286 putPaddrLow(pdma_phys_fcp_rsp);
287 iocb->unsli3.fcp_ext.rbde.addrHigh =
288 putPaddrHigh(pdma_phys_fcp_rsp);
289 } else {
290 iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BLP_64;
291 iocb->un.fcpi64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64));
292 iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys_bpl);
293 iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys_bpl);
294 iocb->ulpBdeCount = 1;
295 iocb->ulpLe = 1;
296 }
275 iocb->ulpClass = CLASS3; 297 iocb->ulpClass = CLASS3;
276 298
277 return psb; 299 return psb;
@@ -313,8 +335,9 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
313 struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; 335 struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd;
314 struct ulp_bde64 *bpl = lpfc_cmd->fcp_bpl; 336 struct ulp_bde64 *bpl = lpfc_cmd->fcp_bpl;
315 IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; 337 IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
338 struct ulp_bde64 *data_bde = iocb_cmd->unsli3.fcp_ext.dbde;
316 dma_addr_t physaddr; 339 dma_addr_t physaddr;
317 uint32_t i, num_bde = 0; 340 uint32_t num_bde = 0;
318 int nseg, datadir = scsi_cmnd->sc_data_direction; 341 int nseg, datadir = scsi_cmnd->sc_data_direction;
319 342
320 /* 343 /*
@@ -352,33 +375,64 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
352 * during probe that limits the number of sg elements in any 375 * during probe that limits the number of sg elements in any
353 * single scsi command. Just run through the seg_cnt and format 376 * single scsi command. Just run through the seg_cnt and format
354 * the bde's. 377 * the bde's.
378 * When using SLI-3 the driver will try to fit all the BDEs into
379 * the IOCB. If it can't then the BDEs get added to a BPL as it
380 * does for SLI-2 mode.
355 */ 381 */
356 scsi_for_each_sg(scsi_cmnd, sgel, nseg, i) { 382 scsi_for_each_sg(scsi_cmnd, sgel, nseg, num_bde) {
357 physaddr = sg_dma_address(sgel); 383 physaddr = sg_dma_address(sgel);
358 bpl->addrLow = le32_to_cpu(putPaddrLow(physaddr)); 384 if (phba->sli_rev == 3 &&
359 bpl->addrHigh = le32_to_cpu(putPaddrHigh(physaddr)); 385 nseg <= LPFC_EXT_DATA_BDE_COUNT) {
360 bpl->tus.f.bdeSize = sg_dma_len(sgel); 386 data_bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
361 if (datadir == DMA_TO_DEVICE) 387 data_bde->tus.f.bdeSize = sg_dma_len(sgel);
362 bpl->tus.f.bdeFlags = 0; 388 data_bde->addrLow = putPaddrLow(physaddr);
363 else 389 data_bde->addrHigh = putPaddrHigh(physaddr);
364 bpl->tus.f.bdeFlags = BUFF_USE_RCV; 390 data_bde++;
365 bpl->tus.w = le32_to_cpu(bpl->tus.w); 391 } else {
366 bpl++; 392 bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
367 num_bde++; 393 bpl->tus.f.bdeSize = sg_dma_len(sgel);
394 bpl->tus.w = le32_to_cpu(bpl->tus.w);
395 bpl->addrLow =
396 le32_to_cpu(putPaddrLow(physaddr));
397 bpl->addrHigh =
398 le32_to_cpu(putPaddrHigh(physaddr));
399 bpl++;
400 }
368 } 401 }
369 } 402 }
370 403
371 /* 404 /*
372 * Finish initializing those IOCB fields that are dependent on the 405 * Finish initializing those IOCB fields that are dependent on the
373 * scsi_cmnd request_buffer. Note that the bdeSize is explicitly 406 * scsi_cmnd request_buffer. Note that for SLI-2 the bdeSize is
374 * reinitialized since all iocb memory resources are used many times 407 * explicitly reinitialized and for SLI-3 the extended bde count is
375 * for transmit, receive, and continuation bpl's. 408 * explicitly reinitialized since all iocb memory resources are reused.
376 */ 409 */
377 iocb_cmd->un.fcpi64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64)); 410 if (phba->sli_rev == 3) {
378 iocb_cmd->un.fcpi64.bdl.bdeSize += 411 if (num_bde > LPFC_EXT_DATA_BDE_COUNT) {
379 (num_bde * sizeof (struct ulp_bde64)); 412 /*
380 iocb_cmd->ulpBdeCount = 1; 413 * The extended IOCB format can only fit 3 BDE or a BPL.
381 iocb_cmd->ulpLe = 1; 414 * This I/O has more than 3 BDE so the 1st data bde will
415 * be a BPL that is filled in here.
416 */
417 physaddr = lpfc_cmd->dma_handle;
418 data_bde->tus.f.bdeFlags = BUFF_TYPE_BLP_64;
419 data_bde->tus.f.bdeSize = (num_bde *
420 sizeof(struct ulp_bde64));
421 physaddr += (sizeof(struct fcp_cmnd) +
422 sizeof(struct fcp_rsp) +
423 (2 * sizeof(struct ulp_bde64)));
424 data_bde->addrHigh = putPaddrHigh(physaddr);
425 data_bde->addrLow = putPaddrLow(physaddr);
426 /* ebde count includes the responce bde and data bpl */
427 iocb_cmd->unsli3.fcp_ext.ebde_count = 2;
428 } else {
429 /* ebde count includes the responce bde and data bdes */
430 iocb_cmd->unsli3.fcp_ext.ebde_count = (num_bde + 1);
431 }
432 } else {
433 iocb_cmd->un.fcpi64.bdl.bdeSize =
434 ((num_bde + 2) * sizeof(struct ulp_bde64));
435 }
382 fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd)); 436 fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd));
383 return 0; 437 return 0;
384} 438}
@@ -692,6 +746,24 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
692 lpfc_release_scsi_buf(phba, lpfc_cmd); 746 lpfc_release_scsi_buf(phba, lpfc_cmd);
693} 747}
694 748
749/**
750 * lpfc_fcpcmd_to_iocb - copy the fcp_cmd data into the IOCB.
751 * @data: A pointer to the immediate command data portion of the IOCB.
752 * @fcp_cmnd: The FCP Command that is provided by the SCSI layer.
753 *
754 * The routine copies the entire FCP command from @fcp_cmnd to @data while
755 * byte swapping the data to big endian format for transmission on the wire.
756 **/
757static void
758lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd)
759{
760 int i, j;
761 for (i = 0, j = 0; i < sizeof(struct fcp_cmnd);
762 i += sizeof(uint32_t), j++) {
763 ((uint32_t *)data)[j] = cpu_to_be32(((uint32_t *)fcp_cmnd)[j]);
764 }
765}
766
695static void 767static void
696lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, 768lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
697 struct lpfc_nodelist *pnode) 769 struct lpfc_nodelist *pnode)
@@ -758,7 +830,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
758 fcp_cmnd->fcpCntl3 = 0; 830 fcp_cmnd->fcpCntl3 = 0;
759 phba->fc4ControlRequests++; 831 phba->fc4ControlRequests++;
760 } 832 }
761 833 if (phba->sli_rev == 3)
834 lpfc_fcpcmd_to_iocb(iocb_cmd->unsli3.fcp_ext.icd, fcp_cmnd);
762 /* 835 /*
763 * Finish initializing those IOCB fields that are independent 836 * Finish initializing those IOCB fields that are independent
764 * of the scsi_cmnd request_buffer 837 * of the scsi_cmnd request_buffer
@@ -798,11 +871,13 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport,
798 piocb = &piocbq->iocb; 871 piocb = &piocbq->iocb;
799 872
800 fcp_cmnd = lpfc_cmd->fcp_cmnd; 873 fcp_cmnd = lpfc_cmd->fcp_cmnd;
801 int_to_scsilun(lun, &lpfc_cmd->fcp_cmnd->fcp_lun); 874 /* Clear out any old data in the FCP command area */
875 memset(fcp_cmnd, 0, sizeof(struct fcp_cmnd));
876 int_to_scsilun(lun, &fcp_cmnd->fcp_lun);
802 fcp_cmnd->fcpCntl2 = task_mgmt_cmd; 877 fcp_cmnd->fcpCntl2 = task_mgmt_cmd;
803 878 if (vport->phba->sli_rev == 3)
879 lpfc_fcpcmd_to_iocb(piocb->unsli3.fcp_ext.icd, fcp_cmnd);
804 piocb->ulpCommand = CMD_FCP_ICMND64_CR; 880 piocb->ulpCommand = CMD_FCP_ICMND64_CR;
805
806 piocb->ulpContext = ndlp->nlp_rpi; 881 piocb->ulpContext = ndlp->nlp_rpi;
807 if (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) { 882 if (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
808 piocb->ulpFCP2Rcvy = 1; 883 piocb->ulpFCP2Rcvy = 1;