aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_scsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_scsi.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c43
1 files changed, 31 insertions, 12 deletions
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index bf34178b80b..2b962b020cf 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -1,7 +1,7 @@
1/******************************************************************* 1/*******************************************************************
2 * This file is part of the Emulex Linux Device Driver for * 2 * This file is part of the Emulex Linux Device Driver for *
3 * Fibre Channel Host Bus Adapters. * 3 * Fibre Channel Host Bus Adapters. *
4 * Copyright (C) 2004-2009 Emulex. All rights reserved. * 4 * Copyright (C) 2004-2011 Emulex. All rights reserved. *
5 * EMULEX and SLI are trademarks of Emulex. * 5 * EMULEX and SLI are trademarks of Emulex. *
6 * www.emulex.com * 6 * www.emulex.com *
7 * Portions Copyright (C) 2004-2005 Christoph Hellwig * 7 * Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -1514,10 +1514,11 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
1514 struct scatterlist *sgpe = NULL; /* s/g prot entry */ 1514 struct scatterlist *sgpe = NULL; /* s/g prot entry */
1515 struct lpfc_pde5 *pde5 = NULL; 1515 struct lpfc_pde5 *pde5 = NULL;
1516 struct lpfc_pde6 *pde6 = NULL; 1516 struct lpfc_pde6 *pde6 = NULL;
1517 struct ulp_bde64 *prot_bde = NULL; 1517 struct lpfc_pde7 *pde7 = NULL;
1518 dma_addr_t dataphysaddr, protphysaddr; 1518 dma_addr_t dataphysaddr, protphysaddr;
1519 unsigned short curr_data = 0, curr_prot = 0; 1519 unsigned short curr_data = 0, curr_prot = 0;
1520 unsigned int split_offset, protgroup_len; 1520 unsigned int split_offset;
1521 unsigned int protgroup_len, protgroup_offset = 0, protgroup_remainder;
1521 unsigned int protgrp_blks, protgrp_bytes; 1522 unsigned int protgrp_blks, protgrp_bytes;
1522 unsigned int remainder, subtotal; 1523 unsigned int remainder, subtotal;
1523 int status; 1524 int status;
@@ -1585,23 +1586,33 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
1585 bpl++; 1586 bpl++;
1586 1587
1587 /* setup the first BDE that points to protection buffer */ 1588 /* setup the first BDE that points to protection buffer */
1588 prot_bde = (struct ulp_bde64 *) bpl; 1589 protphysaddr = sg_dma_address(sgpe) + protgroup_offset;
1589 protphysaddr = sg_dma_address(sgpe); 1590 protgroup_len = sg_dma_len(sgpe) - protgroup_offset;
1590 prot_bde->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr));
1591 prot_bde->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr));
1592 protgroup_len = sg_dma_len(sgpe);
1593 1591
1594 /* must be integer multiple of the DIF block length */ 1592 /* must be integer multiple of the DIF block length */
1595 BUG_ON(protgroup_len % 8); 1593 BUG_ON(protgroup_len % 8);
1596 1594
1595 pde7 = (struct lpfc_pde7 *) bpl;
1596 memset(pde7, 0, sizeof(struct lpfc_pde7));
1597 bf_set(pde7_type, pde7, LPFC_PDE7_DESCRIPTOR);
1598
1599 pde7->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr));
1600 pde7->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr));
1601
1597 protgrp_blks = protgroup_len / 8; 1602 protgrp_blks = protgroup_len / 8;
1598 protgrp_bytes = protgrp_blks * blksize; 1603 protgrp_bytes = protgrp_blks * blksize;
1599 1604
1600 prot_bde->tus.f.bdeSize = protgroup_len; 1605 /* check if this pde is crossing the 4K boundary; if so split */
1601 prot_bde->tus.f.bdeFlags = LPFC_PDE7_DESCRIPTOR; 1606 if ((pde7->addrLow & 0xfff) + protgroup_len > 0x1000) {
1602 prot_bde->tus.w = le32_to_cpu(bpl->tus.w); 1607 protgroup_remainder = 0x1000 - (pde7->addrLow & 0xfff);
1608 protgroup_offset += protgroup_remainder;
1609 protgrp_blks = protgroup_remainder / 8;
1610 protgrp_bytes = protgroup_remainder * blksize;
1611 } else {
1612 protgroup_offset = 0;
1613 curr_prot++;
1614 }
1603 1615
1604 curr_prot++;
1605 num_bde++; 1616 num_bde++;
1606 1617
1607 /* setup BDE's for data blocks associated with DIF data */ 1618 /* setup BDE's for data blocks associated with DIF data */
@@ -1653,6 +1664,13 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
1653 1664
1654 } 1665 }
1655 1666
1667 if (protgroup_offset) {
1668 /* update the reference tag */
1669 reftag += protgrp_blks;
1670 bpl++;
1671 continue;
1672 }
1673
1656 /* are we done ? */ 1674 /* are we done ? */
1657 if (curr_prot == protcnt) { 1675 if (curr_prot == protcnt) {
1658 alldone = 1; 1676 alldone = 1;
@@ -1675,6 +1693,7 @@ out:
1675 1693
1676 return num_bde; 1694 return num_bde;
1677} 1695}
1696
1678/* 1697/*
1679 * Given a SCSI command that supports DIF, determine composition of protection 1698 * Given a SCSI command that supports DIF, determine composition of protection
1680 * groups involved in setting up buffer lists 1699 * groups involved in setting up buffer lists