Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/vapier...
[cascardo/linux.git] / drivers / scsi / lpfc / lpfc_scsi.c
index bf34178..2b962b0 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************
  * This file is part of the Emulex Linux Device Driver for         *
  * Fibre Channel Host Bus Adapters.                                *
- * Copyright (C) 2004-2009 Emulex.  All rights reserved.           *
+ * Copyright (C) 2004-2011 Emulex.  All rights reserved.           *
  * EMULEX and SLI are trademarks of Emulex.                        *
  * www.emulex.com                                                  *
  * Portions Copyright (C) 2004-2005 Christoph Hellwig              *
@@ -1514,10 +1514,11 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
        struct scatterlist *sgpe = NULL; /* s/g prot entry */
        struct lpfc_pde5 *pde5 = NULL;
        struct lpfc_pde6 *pde6 = NULL;
-       struct ulp_bde64 *prot_bde = NULL;
+       struct lpfc_pde7 *pde7 = NULL;
        dma_addr_t dataphysaddr, protphysaddr;
        unsigned short curr_data = 0, curr_prot = 0;
-       unsigned int split_offset, protgroup_len;
+       unsigned int split_offset;
+       unsigned int protgroup_len, protgroup_offset = 0, protgroup_remainder;
        unsigned int protgrp_blks, protgrp_bytes;
        unsigned int remainder, subtotal;
        int status;
@@ -1585,23 +1586,33 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
                bpl++;
 
                /* setup the first BDE that points to protection buffer */
-               prot_bde = (struct ulp_bde64 *) bpl;
-               protphysaddr = sg_dma_address(sgpe);
-               prot_bde->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr));
-               prot_bde->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr));
-               protgroup_len = sg_dma_len(sgpe);
+               protphysaddr = sg_dma_address(sgpe) + protgroup_offset;
+               protgroup_len = sg_dma_len(sgpe) - protgroup_offset;
 
                /* must be integer multiple of the DIF block length */
                BUG_ON(protgroup_len % 8);
 
+               pde7 = (struct lpfc_pde7 *) bpl;
+               memset(pde7, 0, sizeof(struct lpfc_pde7));
+               bf_set(pde7_type, pde7, LPFC_PDE7_DESCRIPTOR);
+
+               pde7->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr));
+               pde7->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr));
+
                protgrp_blks = protgroup_len / 8;
                protgrp_bytes = protgrp_blks * blksize;
 
-               prot_bde->tus.f.bdeSize = protgroup_len;
-               prot_bde->tus.f.bdeFlags = LPFC_PDE7_DESCRIPTOR;
-               prot_bde->tus.w = le32_to_cpu(bpl->tus.w);
+               /* check if this pde is crossing the 4K boundary; if so split */
+               if ((pde7->addrLow & 0xfff) + protgroup_len > 0x1000) {
+                       protgroup_remainder = 0x1000 - (pde7->addrLow & 0xfff);
+                       protgroup_offset += protgroup_remainder;
+                       protgrp_blks = protgroup_remainder / 8;
+                       protgrp_bytes = protgroup_remainder * blksize;
+               } else {
+                       protgroup_offset = 0;
+                       curr_prot++;
+               }
 
-               curr_prot++;
                num_bde++;
 
                /* 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,
 
                }
 
+               if (protgroup_offset) {
+                       /* update the reference tag */
+                       reftag += protgrp_blks;
+                       bpl++;
+                       continue;
+               }
+
                /* are we done ? */
                if (curr_prot == protcnt) {
                        alldone = 1;
@@ -1675,6 +1693,7 @@ out:
 
        return num_bde;
 }
+
 /*
  * Given a SCSI command that supports DIF, determine composition of protection
  * groups involved in setting up buffer lists