summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_scsi.c
diff options
context:
space:
mode:
authorJames Smart <james.smart@emulex.com>2011-03-11 16:05:52 -0500
committerJames Bottomley <James.Bottomley@suse.de>2011-03-23 11:36:07 -0500
commit7f86059ac016d8662e5fbfab4875529510977b47 (patch)
treed0baa921c2c2b642663d25a615905f7a302f567f /drivers/scsi/lpfc/lpfc_scsi.c
parent5a6f133eea2d0b4f8f75367b803fef0f03acf268 (diff)
[SCSI] lpfc 8.3.22: T10-DIF corrections
T10-DIF corrections - Add selective reset jump table entry - Split T10-DIF BDEs that cross 4K boundary Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com> Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_scsi.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c41
1 files changed, 30 insertions, 11 deletions
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index bf34178b80b..e3a1d295e4d 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -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