Commit acd6859b authored by James Smart's avatar James Smart Committed by James Bottomley

[SCSI] lpfc 8.3.29: T10 Diff fixes and enhancements

T10 Diff fixes and enhancements:

- Add SLI4 Lancer support for T10 DIF / BlockGuard (121980)
- Fix SLI4 BlockGuard behavior when protection data is generated by HBA (121980)
- Enhance debugfs for injecting T10 DIF errors (123966, 132966)
- Fix Incorrect usage of bghm for BlockGuard errors (127022)
Signed-off-by: default avatarAlex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: default avatarJames Smart <james.smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 6b5151fd
...@@ -534,6 +534,7 @@ struct lpfc_hba { ...@@ -534,6 +534,7 @@ struct lpfc_hba {
void (*lpfc_scsi_prep_cmnd) void (*lpfc_scsi_prep_cmnd)
(struct lpfc_vport *, struct lpfc_scsi_buf *, (struct lpfc_vport *, struct lpfc_scsi_buf *,
struct lpfc_nodelist *); struct lpfc_nodelist *);
/* IOCB interface function jump table entries */ /* IOCB interface function jump table entries */
int (*__lpfc_sli_issue_iocb) int (*__lpfc_sli_issue_iocb)
(struct lpfc_hba *, uint32_t, (struct lpfc_hba *, uint32_t,
...@@ -541,8 +542,6 @@ struct lpfc_hba { ...@@ -541,8 +542,6 @@ struct lpfc_hba {
void (*__lpfc_sli_release_iocbq)(struct lpfc_hba *, void (*__lpfc_sli_release_iocbq)(struct lpfc_hba *,
struct lpfc_iocbq *); struct lpfc_iocbq *);
int (*lpfc_hba_down_post)(struct lpfc_hba *phba); int (*lpfc_hba_down_post)(struct lpfc_hba *phba);
IOCB_t * (*lpfc_get_iocb_from_iocbq) IOCB_t * (*lpfc_get_iocb_from_iocbq)
(struct lpfc_iocbq *); (struct lpfc_iocbq *);
void (*lpfc_scsi_cmd_iocb_cmpl) void (*lpfc_scsi_cmd_iocb_cmpl)
...@@ -551,10 +550,12 @@ struct lpfc_hba { ...@@ -551,10 +550,12 @@ struct lpfc_hba {
/* MBOX interface function jump table entries */ /* MBOX interface function jump table entries */
int (*lpfc_sli_issue_mbox) int (*lpfc_sli_issue_mbox)
(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); (struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
/* Slow-path IOCB process function jump table entries */ /* Slow-path IOCB process function jump table entries */
void (*lpfc_sli_handle_slow_ring_event) void (*lpfc_sli_handle_slow_ring_event)
(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, (struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
uint32_t mask); uint32_t mask);
/* INIT device interface function jump table entries */ /* INIT device interface function jump table entries */
int (*lpfc_sli_hbq_to_firmware) int (*lpfc_sli_hbq_to_firmware)
(struct lpfc_hba *, uint32_t, struct hbq_dmabuf *); (struct lpfc_hba *, uint32_t, struct hbq_dmabuf *);
...@@ -573,6 +574,10 @@ struct lpfc_hba { ...@@ -573,6 +574,10 @@ struct lpfc_hba {
int (*lpfc_selective_reset) int (*lpfc_selective_reset)
(struct lpfc_hba *); (struct lpfc_hba *);
int (*lpfc_bg_scsi_prep_dma_buf)
(struct lpfc_hba *, struct lpfc_scsi_buf *);
/* Add new entries here */
/* SLI4 specific HBA data structure */ /* SLI4 specific HBA data structure */
struct lpfc_sli4_hba sli4_hba; struct lpfc_sli4_hba sli4_hba;
...@@ -838,6 +843,7 @@ struct lpfc_hba { ...@@ -838,6 +843,7 @@ struct lpfc_hba {
struct dentry *debug_writeGuard; /* inject write guard_tag errors */ struct dentry *debug_writeGuard; /* inject write guard_tag errors */
struct dentry *debug_writeApp; /* inject write app_tag errors */ struct dentry *debug_writeApp; /* inject write app_tag errors */
struct dentry *debug_writeRef; /* inject write ref_tag errors */ struct dentry *debug_writeRef; /* inject write ref_tag errors */
struct dentry *debug_readGuard; /* inject read guard_tag errors */
struct dentry *debug_readApp; /* inject read app_tag errors */ struct dentry *debug_readApp; /* inject read app_tag errors */
struct dentry *debug_readRef; /* inject read ref_tag errors */ struct dentry *debug_readRef; /* inject read ref_tag errors */
...@@ -845,10 +851,11 @@ struct lpfc_hba { ...@@ -845,10 +851,11 @@ struct lpfc_hba {
uint32_t lpfc_injerr_wgrd_cnt; uint32_t lpfc_injerr_wgrd_cnt;
uint32_t lpfc_injerr_wapp_cnt; uint32_t lpfc_injerr_wapp_cnt;
uint32_t lpfc_injerr_wref_cnt; uint32_t lpfc_injerr_wref_cnt;
uint32_t lpfc_injerr_rgrd_cnt;
uint32_t lpfc_injerr_rapp_cnt; uint32_t lpfc_injerr_rapp_cnt;
uint32_t lpfc_injerr_rref_cnt; uint32_t lpfc_injerr_rref_cnt;
sector_t lpfc_injerr_lba; sector_t lpfc_injerr_lba;
#define LPFC_INJERR_LBA_OFF (sector_t)0xffffffffffffffff #define LPFC_INJERR_LBA_OFF (sector_t)(-1)
struct dentry *debug_slow_ring_trc; struct dentry *debug_slow_ring_trc;
struct lpfc_debugfs_trc *slow_ring_trc; struct lpfc_debugfs_trc *slow_ring_trc;
......
...@@ -1019,6 +1019,8 @@ lpfc_debugfs_dif_err_read(struct file *file, char __user *buf, ...@@ -1019,6 +1019,8 @@ lpfc_debugfs_dif_err_read(struct file *file, char __user *buf,
cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_wapp_cnt); cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_wapp_cnt);
else if (dent == phba->debug_writeRef) else if (dent == phba->debug_writeRef)
cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_wref_cnt); cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_wref_cnt);
else if (dent == phba->debug_readGuard)
cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_rgrd_cnt);
else if (dent == phba->debug_readApp) else if (dent == phba->debug_readApp)
cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_rapp_cnt); cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_rapp_cnt);
else if (dent == phba->debug_readRef) else if (dent == phba->debug_readRef)
...@@ -1057,6 +1059,8 @@ lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf, ...@@ -1057,6 +1059,8 @@ lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf,
phba->lpfc_injerr_wapp_cnt = (uint32_t)tmp; phba->lpfc_injerr_wapp_cnt = (uint32_t)tmp;
else if (dent == phba->debug_writeRef) else if (dent == phba->debug_writeRef)
phba->lpfc_injerr_wref_cnt = (uint32_t)tmp; phba->lpfc_injerr_wref_cnt = (uint32_t)tmp;
else if (dent == phba->debug_readGuard)
phba->lpfc_injerr_rgrd_cnt = (uint32_t)tmp;
else if (dent == phba->debug_readApp) else if (dent == phba->debug_readApp)
phba->lpfc_injerr_rapp_cnt = (uint32_t)tmp; phba->lpfc_injerr_rapp_cnt = (uint32_t)tmp;
else if (dent == phba->debug_readRef) else if (dent == phba->debug_readRef)
...@@ -3978,6 +3982,17 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) ...@@ -3978,6 +3982,17 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport)
goto debug_failed; goto debug_failed;
} }
snprintf(name, sizeof(name), "readGuardInjErr");
phba->debug_readGuard =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
phba->hba_debugfs_root,
phba, &lpfc_debugfs_op_dif_err);
if (!phba->debug_readGuard) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
"0808 Cannot create debugfs readGuard\n");
goto debug_failed;
}
snprintf(name, sizeof(name), "readAppInjErr"); snprintf(name, sizeof(name), "readAppInjErr");
phba->debug_readApp = phba->debug_readApp =
debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
...@@ -4318,6 +4333,10 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) ...@@ -4318,6 +4333,10 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport)
debugfs_remove(phba->debug_writeRef); /* writeRef */ debugfs_remove(phba->debug_writeRef); /* writeRef */
phba->debug_writeRef = NULL; phba->debug_writeRef = NULL;
} }
if (phba->debug_readGuard) {
debugfs_remove(phba->debug_readGuard); /* readGuard */
phba->debug_readGuard = NULL;
}
if (phba->debug_readApp) { if (phba->debug_readApp) {
debugfs_remove(phba->debug_readApp); /* readApp */ debugfs_remove(phba->debug_readApp); /* readApp */
phba->debug_readApp = NULL; phba->debug_readApp = NULL;
......
...@@ -321,6 +321,10 @@ struct lpfc_cqe { ...@@ -321,6 +321,10 @@ struct lpfc_cqe {
#define CQE_STATUS_CMD_REJECT 0xb #define CQE_STATUS_CMD_REJECT 0xb
#define CQE_STATUS_FCP_TGT_LENCHECK 0xc #define CQE_STATUS_FCP_TGT_LENCHECK 0xc
#define CQE_STATUS_NEED_BUFF_ENTRY 0xf #define CQE_STATUS_NEED_BUFF_ENTRY 0xf
#define CQE_STATUS_DI_ERROR 0x16
/* Used when mapping CQE status to IOCB */
#define LPFC_IOCB_STATUS_MASK 0xf
/* Status returned by hardware (valid only if status = CQE_STATUS_SUCCESS). */ /* Status returned by hardware (valid only if status = CQE_STATUS_SUCCESS). */
#define CQE_HW_STATUS_NO_ERR 0x0 #define CQE_HW_STATUS_NO_ERR 0x0
...@@ -348,6 +352,21 @@ struct lpfc_wcqe_complete { ...@@ -348,6 +352,21 @@ struct lpfc_wcqe_complete {
#define lpfc_wcqe_c_hw_status_WORD word0 #define lpfc_wcqe_c_hw_status_WORD word0
uint32_t total_data_placed; uint32_t total_data_placed;
uint32_t parameter; uint32_t parameter;
#define lpfc_wcqe_c_bg_edir_SHIFT 5
#define lpfc_wcqe_c_bg_edir_MASK 0x00000001
#define lpfc_wcqe_c_bg_edir_WORD parameter
#define lpfc_wcqe_c_bg_tdpv_SHIFT 3
#define lpfc_wcqe_c_bg_tdpv_MASK 0x00000001
#define lpfc_wcqe_c_bg_tdpv_WORD parameter
#define lpfc_wcqe_c_bg_re_SHIFT 2
#define lpfc_wcqe_c_bg_re_MASK 0x00000001
#define lpfc_wcqe_c_bg_re_WORD parameter
#define lpfc_wcqe_c_bg_ae_SHIFT 1
#define lpfc_wcqe_c_bg_ae_MASK 0x00000001
#define lpfc_wcqe_c_bg_ae_WORD parameter
#define lpfc_wcqe_c_bg_ge_SHIFT 0
#define lpfc_wcqe_c_bg_ge_MASK 0x00000001
#define lpfc_wcqe_c_bg_ge_WORD parameter
uint32_t word3; uint32_t word3;
#define lpfc_wcqe_c_valid_SHIFT lpfc_cqe_valid_SHIFT #define lpfc_wcqe_c_valid_SHIFT lpfc_cqe_valid_SHIFT
#define lpfc_wcqe_c_valid_MASK lpfc_cqe_valid_MASK #define lpfc_wcqe_c_valid_MASK lpfc_cqe_valid_MASK
...@@ -359,8 +378,8 @@ struct lpfc_wcqe_complete { ...@@ -359,8 +378,8 @@ struct lpfc_wcqe_complete {
#define lpfc_wcqe_c_pv_MASK 0x00000001 #define lpfc_wcqe_c_pv_MASK 0x00000001
#define lpfc_wcqe_c_pv_WORD word3 #define lpfc_wcqe_c_pv_WORD word3
#define lpfc_wcqe_c_priority_SHIFT 24 #define lpfc_wcqe_c_priority_SHIFT 24
#define lpfc_wcqe_c_priority_MASK 0x00000007 #define lpfc_wcqe_c_priority_MASK 0x00000007
#define lpfc_wcqe_c_priority_WORD word3 #define lpfc_wcqe_c_priority_WORD word3
#define lpfc_wcqe_c_code_SHIFT lpfc_cqe_code_SHIFT #define lpfc_wcqe_c_code_SHIFT lpfc_cqe_code_SHIFT
#define lpfc_wcqe_c_code_MASK lpfc_cqe_code_MASK #define lpfc_wcqe_c_code_MASK lpfc_cqe_code_MASK
#define lpfc_wcqe_c_code_WORD lpfc_cqe_code_WORD #define lpfc_wcqe_c_code_WORD lpfc_cqe_code_WORD
......
...@@ -4380,6 +4380,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) ...@@ -4380,6 +4380,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
uint8_t pn_page[LPFC_MAX_SUPPORTED_PAGES] = {0}; uint8_t pn_page[LPFC_MAX_SUPPORTED_PAGES] = {0};
struct lpfc_mqe *mqe; struct lpfc_mqe *mqe;
int longs, sli_family; int longs, sli_family;
int sges_per_segment;
/* Before proceed, wait for POST done and device ready */ /* Before proceed, wait for POST done and device ready */
rc = lpfc_sli4_post_status_check(phba); rc = lpfc_sli4_post_status_check(phba);
...@@ -4443,6 +4444,11 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) ...@@ -4443,6 +4444,11 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
phba->fc_map[1] = LPFC_FCOE_FCF_MAP1; phba->fc_map[1] = LPFC_FCOE_FCF_MAP1;
phba->fc_map[2] = LPFC_FCOE_FCF_MAP2; phba->fc_map[2] = LPFC_FCOE_FCF_MAP2;
/* With BlockGuard we can have multiple SGEs per Data Segemnt */
sges_per_segment = 1;
if (phba->cfg_enable_bg)
sges_per_segment = 2;
/* /*
* Since the sg_tablesize is module parameter, the sg_dma_buf_size * Since the sg_tablesize is module parameter, the sg_dma_buf_size
* used to create the sg_dma_buf_pool must be dynamically calculated. * used to create the sg_dma_buf_pool must be dynamically calculated.
...@@ -4451,7 +4457,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) ...@@ -4451,7 +4457,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
* sgl sizes of must be a power of 2. * sgl sizes of must be a power of 2.
*/ */
buf_size = (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp) + buf_size = (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp) +
((phba->cfg_sg_seg_cnt + 2) * sizeof(struct sli4_sge))); (((phba->cfg_sg_seg_cnt * sges_per_segment) + 2) *
sizeof(struct sli4_sge)));
sli_family = bf_get(lpfc_sli_intf_sli_family, &phba->sli4_hba.sli_intf); sli_family = bf_get(lpfc_sli_intf_sli_family, &phba->sli4_hba.sli_intf);
max_buf_size = LPFC_SLI4_MAX_BUF_SIZE; max_buf_size = LPFC_SLI4_MAX_BUF_SIZE;
...@@ -4468,6 +4475,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) ...@@ -4468,6 +4475,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
default: default:
break; break;
} }
for (dma_buf_size = LPFC_SLI4_MIN_BUF_SIZE; for (dma_buf_size = LPFC_SLI4_MIN_BUF_SIZE;
dma_buf_size < max_buf_size && buf_size > dma_buf_size; dma_buf_size < max_buf_size && buf_size > dma_buf_size;
dma_buf_size = dma_buf_size << 1) dma_buf_size = dma_buf_size << 1)
......
/******************************************************************* /*******************************************************************
* This file is part of the Emulex Linux Device Driver for * * This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. * * Fibre Channel Host Bus Adapters. *
* Copyright (C) 2004-2011 Emulex. All rights reserved. * * Copyright (C) 2004-2012 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. * * EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com * * www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig * * Portions Copyright (C) 2004-2005 Christoph Hellwig *
...@@ -1280,31 +1280,45 @@ lpfc_cmd_blksize(struct scsi_cmnd *sc) ...@@ -1280,31 +1280,45 @@ lpfc_cmd_blksize(struct scsi_cmnd *sc)
} }
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
/*
* Given a scsi cmnd, determine the BlockGuard tags to be used with it #define BG_ERR_INIT 1
#define BG_ERR_TGT 2
#define BG_ERR_SWAP 3
#define BG_ERR_CHECK 4
/**
* lpfc_bg_err_inject - Determine if we should inject an error
* @phba: The Hba for which this call is being executed.
* @sc: The SCSI command to examine * @sc: The SCSI command to examine
* @reftag: (out) BlockGuard reference tag for transmitted data * @reftag: (out) BlockGuard reference tag for transmitted data
* @apptag: (out) BlockGuard application tag for transmitted data * @apptag: (out) BlockGuard application tag for transmitted data
* @new_guard (in) Value to replace CRC with if needed * @new_guard (in) Value to replace CRC with if needed
* *
* Returns (1) if error injection was performed, (0) otherwise * Returns (1) if error injection is detected by Initiator
*/ * Returns (2) if error injection is detected by Target
* Returns (3) if swapping CSUM->CRC is required for error injection
* Returns (4) disabling Guard/Ref/App checking is required for error injection
**/
static int static int
lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc,
uint32_t *reftag, uint16_t *apptag, uint32_t new_guard) uint32_t *reftag, uint16_t *apptag, uint32_t new_guard)
{ {
struct scatterlist *sgpe; /* s/g prot entry */ struct scatterlist *sgpe; /* s/g prot entry */
struct scatterlist *sgde; /* s/g data entry */ struct scatterlist *sgde; /* s/g data entry */
struct scsi_dif_tuple *src; struct scsi_dif_tuple *src = NULL;
uint32_t op = scsi_get_prot_op(sc); uint32_t op = scsi_get_prot_op(sc);
uint32_t blksize; uint32_t blksize;
uint32_t numblks; uint32_t numblks;
sector_t lba; sector_t lba;
int rc = 0; int rc = 0;
int blockoff = 0;
if (op == SCSI_PROT_NORMAL) if (op == SCSI_PROT_NORMAL)
return 0; return 0;
sgpe = scsi_prot_sglist(sc);
sgde = scsi_sglist(sc);
lba = scsi_get_lba(sc); lba = scsi_get_lba(sc);
if (phba->lpfc_injerr_lba != LPFC_INJERR_LBA_OFF) { if (phba->lpfc_injerr_lba != LPFC_INJERR_LBA_OFF) {
blksize = lpfc_cmd_blksize(sc); blksize = lpfc_cmd_blksize(sc);
...@@ -1314,142 +1328,296 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, ...@@ -1314,142 +1328,296 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc,
if ((phba->lpfc_injerr_lba < lba) || if ((phba->lpfc_injerr_lba < lba) ||
(phba->lpfc_injerr_lba >= (lba + numblks))) (phba->lpfc_injerr_lba >= (lba + numblks)))
return 0; return 0;
if (sgpe) {
blockoff = phba->lpfc_injerr_lba - lba;
numblks = sg_dma_len(sgpe) /
sizeof(struct scsi_dif_tuple);
if (numblks < blockoff)
blockoff = numblks;
src = (struct scsi_dif_tuple *)sg_virt(sgpe);
src += blockoff;
}
} }
sgpe = scsi_prot_sglist(sc);
sgde = scsi_sglist(sc);
/* Should we change the Reference Tag */ /* Should we change the Reference Tag */
if (reftag) { if (reftag) {
/* if (phba->lpfc_injerr_wref_cnt) {
* If we are SCSI_PROT_WRITE_STRIP, the protection data is switch (op) {
* being stripped from the wire, thus it doesn't matter. case SCSI_PROT_WRITE_PASS:
*/ if (blockoff && src) {
if ((op == SCSI_PROT_WRITE_PASS) || /* Insert error in middle of the IO */
(op == SCSI_PROT_WRITE_INSERT)) {
if (phba->lpfc_injerr_wref_cnt) { lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9076 BLKGRD: Injecting reftag error: "
"write lba x%lx + x%x oldrefTag x%x\n",
(unsigned long)lba, blockoff,
src->ref_tag);
/*
* NOTE, this will change ref tag in
* the memory location forever!
*/
src->ref_tag = 0xDEADBEEF;
phba->lpfc_injerr_wref_cnt--;
phba->lpfc_injerr_lba =
LPFC_INJERR_LBA_OFF;
rc = BG_ERR_CHECK;
break;
}
/* Drop thru */
case SCSI_PROT_WRITE_STRIP:
/*
* For WRITE_STRIP and WRITE_PASS,
* force the error on data
* being copied from SLI-Host to SLI-Port.
*/
*reftag = 0xDEADBEEF;
phba->lpfc_injerr_wref_cnt--;
phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
rc = BG_ERR_INIT;
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9077 BLKGRD: Injecting reftag error: "
"write lba x%lx\n", (unsigned long)lba);
break;
case SCSI_PROT_WRITE_INSERT:
/*
* For WRITE_INSERT, force the
* error to be sent on the wire. It should be
* detected by the Target.
*/
/* DEADBEEF will be the reftag on the wire */ /* DEADBEEF will be the reftag on the wire */
*reftag = 0xDEADBEEF; *reftag = 0xDEADBEEF;
phba->lpfc_injerr_wref_cnt--; phba->lpfc_injerr_wref_cnt--;
phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
rc = 1; rc = BG_ERR_TGT;
lpfc_printf_log(phba, KERN_ERR, LOG_BG, lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9081 BLKGRD: Injecting reftag error: " "9078 BLKGRD: Injecting reftag error: "
"write lba x%lx\n", (unsigned long)lba); "write lba x%lx\n", (unsigned long)lba);
break;
} }
} else { }
if (phba->lpfc_injerr_rref_cnt) { if (phba->lpfc_injerr_rref_cnt) {
switch (op) {
case SCSI_PROT_READ_INSERT:
/*
* For READ_INSERT, it doesn't make sense
* to change the reftag.
*/
break;
case SCSI_PROT_READ_STRIP:
case SCSI_PROT_READ_PASS:
/*
* For READ_STRIP and READ_PASS, force the
* error on data being read off the wire. It
* should force an IO error to the driver.
*/
*reftag = 0xDEADBEEF; *reftag = 0xDEADBEEF;
phba->lpfc_injerr_rref_cnt--; phba->lpfc_injerr_rref_cnt--;
phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
rc = 1; rc = BG_ERR_INIT;
lpfc_printf_log(phba, KERN_ERR, LOG_BG, lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9076 BLKGRD: Injecting reftag error: " "9079 BLKGRD: Injecting reftag error: "
"read lba x%lx\n", (unsigned long)lba); "read lba x%lx\n", (unsigned long)lba);
break;
} }
} }
} }
/* Should we change the Application Tag */ /* Should we change the Application Tag */
if (apptag) { if (apptag) {
/* if (phba->lpfc_injerr_wapp_cnt) {
* If we are SCSI_PROT_WRITE_STRIP, the protection data is switch (op) {
* being stripped from the wire, thus it doesn't matter. case SCSI_PROT_WRITE_PASS:
*/ if (blockoff && src) {
if ((op == SCSI_PROT_WRITE_PASS) || /* Insert error in middle of the IO */
(op == SCSI_PROT_WRITE_INSERT)) {
if (phba->lpfc_injerr_wapp_cnt) { lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9080 BLKGRD: Injecting apptag error: "
"write lba x%lx + x%x oldappTag x%x\n",
(unsigned long)lba, blockoff,
src->app_tag);
/*
* NOTE, this will change app tag in
* the memory location forever!
*/
src->app_tag = 0xDEAD;
phba->lpfc_injerr_wapp_cnt--;
phba->lpfc_injerr_lba =
LPFC_INJERR_LBA_OFF;
rc = BG_ERR_CHECK;
break;
}
/* Drop thru */
case SCSI_PROT_WRITE_STRIP:
/*
* For WRITE_STRIP and WRITE_PASS,
* force the error on data
* being copied from SLI-Host to SLI-Port.
*/
*apptag = 0xDEAD;
phba->lpfc_injerr_wapp_cnt--;
phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
rc = BG_ERR_INIT;
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"0812 BLKGRD: Injecting apptag error: "
"write lba x%lx\n", (unsigned long)lba);
break;
case SCSI_PROT_WRITE_INSERT:
/*
* For WRITE_INSERT, force the
* error to be sent on the wire. It should be
* detected by the Target.
*/
/* DEAD will be the apptag on the wire */ /* DEAD will be the apptag on the wire */
*apptag = 0xDEAD; *apptag = 0xDEAD;
phba->lpfc_injerr_wapp_cnt--; phba->lpfc_injerr_wapp_cnt--;
phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
rc = 1; rc = BG_ERR_TGT;
lpfc_printf_log(phba, KERN_ERR, LOG_BG, lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9077 BLKGRD: Injecting apptag error: " "0813 BLKGRD: Injecting apptag error: "
"write lba x%lx\n", (unsigned long)lba); "write lba x%lx\n", (unsigned long)lba);
break;
} }
} else { }
if (phba->lpfc_injerr_rapp_cnt) { if (phba->lpfc_injerr_rapp_cnt) {
switch (op) {
case SCSI_PROT_READ_INSERT:
/*
* For READ_INSERT, it doesn't make sense
* to change the apptag.
*/
break;
case SCSI_PROT_READ_STRIP:
case SCSI_PROT_READ_PASS:
/*
* For READ_STRIP and READ_PASS, force the
* error on data being read off the wire. It
* should force an IO error to the driver.
*/
*apptag = 0xDEAD; *apptag = 0xDEAD;
phba->lpfc_injerr_rapp_cnt--; phba->lpfc_injerr_rapp_cnt--;
phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
rc = 1; rc = BG_ERR_INIT;
lpfc_printf_log(phba, KERN_ERR, LOG_BG, lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9078 BLKGRD: Injecting apptag error: " "0814 BLKGRD: Injecting apptag error: "
"read lba x%lx\n", (unsigned long)lba); "read lba x%lx\n", (unsigned long)lba);
break;
} }
} }
} }
/* Should we change the Guard Tag */ /* Should we change the Guard Tag */
if (new_guard) {
if (phba->lpfc_injerr_wgrd_cnt) {
switch (op) {
case SCSI_PROT_WRITE_PASS:
if (blockoff && src) {
/* Insert error in middle of the IO */
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"0815 BLKGRD: Injecting guard error: "
"write lba x%lx + x%x oldgrdTag x%x\n",
(unsigned long)lba, blockoff,
src->guard_tag);
/* /*
* If we are SCSI_PROT_WRITE_INSERT, the protection data is * NOTE, this will change guard tag in
* being on the wire is being fully generated on the HBA. * the memory location forever!
* The host cannot change it or force an error. */
*/ src->guard_tag = 0xDEAD;
if (((op == SCSI_PROT_WRITE_STRIP) || phba->lpfc_injerr_wgrd_cnt--;
(op == SCSI_PROT_WRITE_PASS)) && phba->lpfc_injerr_lba =
phba->lpfc_injerr_wgrd_cnt) { LPFC_INJERR_LBA_OFF;
if (sgpe) { rc = BG_ERR_CHECK;
src = (struct scsi_dif_tuple *)sg_virt(sgpe); break;
/* }
* Just inject an error in the first /* Drop thru */
* prot block. case SCSI_PROT_WRITE_STRIP:
*/ /*
lpfc_printf_log(phba, KERN_ERR, LOG_BG, * For WRITE_STRIP and WRITE_PASS,
"9079 BLKGRD: Injecting guard error: " * force the error on data
"write lba x%lx oldGuard x%x refTag x%x\n", * being copied from SLI-Host to SLI-Port.
(unsigned long)lba, src->guard_tag, */
src->ref_tag); phba->lpfc_injerr_wgrd_cnt--;
phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
src->guard_tag = (uint16_t)new_guard; rc = BG_ERR_SWAP;
phba->lpfc_injerr_wgrd_cnt--; /* Signals the caller to swap CRC->CSUM */
phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
rc = 1;
} else { lpfc_printf_log(phba, KERN_ERR, LOG_BG,
blksize = lpfc_cmd_blksize(sc); "0816 BLKGRD: Injecting guard error: "
/* "write lba x%lx\n", (unsigned long)lba);
* Jump past the first data block break;
* and inject an error in the case SCSI_PROT_WRITE_INSERT:
* prot data. The prot data is already /*
* embedded after the regular data. * For WRITE_INSERT, force the
*/ * error to be sent on the wire. It should be
src = (struct scsi_dif_tuple *) * detected by the Target.
(sg_virt(sgde) + blksize); */
phba->lpfc_injerr_wgrd_cnt--;
phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
lpfc_printf_log(phba, KERN_ERR, LOG_BG, rc = BG_ERR_SWAP;
"9080 BLKGRD: Injecting guard error: " /* Signals the caller to swap CRC->CSUM */
"write lba x%lx oldGuard x%x refTag x%x\n",
(unsigned long)lba, src->guard_tag, lpfc_printf_log(phba, KERN_ERR, LOG_BG,
src->ref_tag); "0817 BLKGRD: Injecting guard error: "
"write lba x%lx\n", (unsigned long)lba);
src->guard_tag = (uint16_t)new_guard; break;
phba->lpfc_injerr_wgrd_cnt--; }
phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; }
rc = 1; if (phba->lpfc_injerr_rgrd_cnt) {
switch (op) {
case SCSI_PROT_READ_INSERT:
/*
* For READ_INSERT, it doesn't make sense
* to change the guard tag.
*/
break;
case SCSI_PROT_READ_STRIP:
case SCSI_PROT_READ_PASS:
/*
* For READ_STRIP and READ_PASS, force the
* error on data being read off the wire. It
* should force an IO error to the driver.
*/
*apptag = 0xDEAD;
phba->lpfc_injerr_rgrd_cnt--;
phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF;
rc = BG_ERR_SWAP;
/* Signals the caller to swap CRC->CSUM */
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"0818 BLKGRD: Injecting guard error: "
"read lba x%lx\n", (unsigned long)lba);
}
} }
} }
return rc; return rc;
} }
#endif #endif
/* /**
* Given a scsi cmnd, determine the BlockGuard opcodes to be used with it * lpfc_sc_to_bg_opcodes - Determine the BlockGuard opcodes to be used with
* the specified SCSI command.
* @phba: The Hba for which this call is being executed.
* @sc: The SCSI command to examine * @sc: The SCSI command to examine
* @txopt: (out) BlockGuard operation for transmitted data * @txopt: (out) BlockGuard operation for transmitted data
* @rxopt: (out) BlockGuard operation for received data * @rxopt: (out) BlockGuard operation for received data
* *
* Returns: zero on success; non-zero if tx and/or rx op cannot be determined * Returns: zero on success; non-zero if tx and/or rx op cannot be determined
* *
*/ **/
static int static int
lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,
uint8_t *txop, uint8_t *rxop) uint8_t *txop, uint8_t *rxop)
...@@ -1519,8 +1687,88 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, ...@@ -1519,8 +1687,88 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,
return ret; return ret;
} }
/* #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
* This function sets up buffer list for protection groups of /**
* lpfc_bg_err_opcodes - reDetermine the BlockGuard opcodes to be used with
* the specified SCSI command in order to force a guard tag error.
* @phba: The Hba for which this call is being executed.
* @sc: The SCSI command to examine
* @txopt: (out) BlockGuard operation for transmitted data
* @rxopt: (out) BlockGuard operation for received data
*
* Returns: zero on success; non-zero if tx and/or rx op cannot be determined
*
**/
static int
lpfc_bg_err_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,
uint8_t *txop, uint8_t *rxop)
{
uint8_t guard_type = scsi_host_get_guard(sc->device->host);
uint8_t ret = 0;
if (guard_type == SHOST_DIX_GUARD_IP) {
switch (scsi_get_prot_op(sc)) {
case SCSI_PROT_READ_INSERT:
case SCSI_PROT_WRITE_STRIP:
*txop = BG_OP_IN_CRC_OUT_NODIF;
*rxop = BG_OP_IN_NODIF_OUT_CRC;
break;
case SCSI_PROT_READ_STRIP:
case SCSI_PROT_WRITE_INSERT:
*txop = BG_OP_IN_NODIF_OUT_CSUM;
*rxop = BG_OP_IN_CSUM_OUT_NODIF;
break;
case SCSI_PROT_READ_PASS:
case SCSI_PROT_WRITE_PASS:
*txop = BG_OP_IN_CRC_OUT_CRC;
*rxop = BG_OP_IN_CRC_OUT_CRC;
break;
case SCSI_PROT_NORMAL:
default:
break;
}
} else {
switch (scsi_get_prot_op(sc)) {
case SCSI_PROT_READ_STRIP:
case SCSI_PROT_WRITE_INSERT:
*txop = BG_OP_IN_NODIF_OUT_CSUM;
*rxop = BG_OP_IN_CSUM_OUT_NODIF;
break;
case SCSI_PROT_READ_PASS:
case SCSI_PROT_WRITE_PASS:
*txop = BG_OP_IN_CSUM_OUT_CRC;
*rxop = BG_OP_IN_CRC_OUT_CSUM;
break;
case SCSI_PROT_READ_INSERT:
case SCSI_PROT_WRITE_STRIP:
*txop = BG_OP_IN_CSUM_OUT_NODIF;
*rxop = BG_OP_IN_NODIF_OUT_CSUM;
break;
case SCSI_PROT_NORMAL:
default:
break;
}
}
return ret;
}
#endif
/**
* lpfc_bg_setup_bpl - Setup BlockGuard BPL with no protection data
* @phba: The Hba for which this call is being executed.
* @sc: pointer to scsi command we're working on
* @bpl: pointer to buffer list for protection groups
* @datacnt: number of segments of data that have been dma mapped
*
* This function sets up BPL buffer list for protection groups of
* type LPFC_PG_TYPE_NO_DIF * type LPFC_PG_TYPE_NO_DIF
* *
* This is usually used when the HBA is instructed to generate * This is usually used when the HBA is instructed to generate
...@@ -1539,12 +1787,11 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, ...@@ -1539,12 +1787,11 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc,
* |more Data BDE's ... (opt)| * |more Data BDE's ... (opt)|
* +-------------------------+ * +-------------------------+
* *
* @sc: pointer to scsi command we're working on
* @bpl: pointer to buffer list for protection groups
* @datacnt: number of segments of data that have been dma mapped
* *
* Note: Data s/g buffers have been dma mapped * Note: Data s/g buffers have been dma mapped
*/ *
* Returns the number of BDEs added to the BPL.
**/
static int static int
lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
struct ulp_bde64 *bpl, int datasegcnt) struct ulp_bde64 *bpl, int datasegcnt)
...@@ -1555,6 +1802,8 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, ...@@ -1555,6 +1802,8 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
dma_addr_t physaddr; dma_addr_t physaddr;
int i = 0, num_bde = 0, status; int i = 0, num_bde = 0, status;
int datadir = sc->sc_data_direction; int datadir = sc->sc_data_direction;
uint32_t rc;
uint32_t checking = 1;
uint32_t reftag; uint32_t reftag;
unsigned blksize; unsigned blksize;
uint8_t txop, rxop; uint8_t txop, rxop;
...@@ -1565,11 +1814,16 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, ...@@ -1565,11 +1814,16 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
/* extract some info from the scsi command for pde*/ /* extract some info from the scsi command for pde*/
blksize = lpfc_cmd_blksize(sc); blksize = lpfc_cmd_blksize(sc);
reftag = scsi_get_lba(sc) & 0xffffffff; reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
/* reftag is the only error we can inject here */ rc = lpfc_bg_err_inject(phba, sc, &reftag, 0, 1);
lpfc_bg_err_inject(phba, sc, &reftag, 0, 0); if (rc) {
if (rc == BG_ERR_SWAP)
lpfc_bg_err_opcodes(phba, sc, &txop, &rxop);
if (rc == BG_ERR_CHECK)
checking = 0;
}
#endif #endif
/* setup PDE5 with what we have */ /* setup PDE5 with what we have */
...@@ -1592,8 +1846,8 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, ...@@ -1592,8 +1846,8 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
bf_set(pde6_optx, pde6, txop); bf_set(pde6_optx, pde6, txop);
bf_set(pde6_oprx, pde6, rxop); bf_set(pde6_oprx, pde6, rxop);
if (datadir == DMA_FROM_DEVICE) { if (datadir == DMA_FROM_DEVICE) {
bf_set(pde6_ce, pde6, 1); bf_set(pde6_ce, pde6, checking);
bf_set(pde6_re, pde6, 1); bf_set(pde6_re, pde6, checking);
} }
bf_set(pde6_ai, pde6, 1); bf_set(pde6_ai, pde6, 1);
bf_set(pde6_ae, pde6, 0); bf_set(pde6_ae, pde6, 0);
...@@ -1627,9 +1881,16 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, ...@@ -1627,9 +1881,16 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
return num_bde; return num_bde;
} }
/* /**
* This function sets up buffer list for protection groups of * lpfc_bg_setup_bpl_prot - Setup BlockGuard BPL with protection data
* type LPFC_PG_TYPE_DIF_BUF * @phba: The Hba for which this call is being executed.
* @sc: pointer to scsi command we're working on
* @bpl: pointer to buffer list for protection groups
* @datacnt: number of segments of data that have been dma mapped
* @protcnt: number of segment of protection data that have been dma mapped
*
* This function sets up BPL buffer list for protection groups of
* type LPFC_PG_TYPE_DIF
* *
* This is usually used when DIFs are in their own buffers, * This is usually used when DIFs are in their own buffers,
* separate from the data. The HBA can then by instructed * separate from the data. The HBA can then by instructed
...@@ -1654,14 +1915,11 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, ...@@ -1654,14 +1915,11 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
* | ... | * | ... |
* +-------------------------+ * +-------------------------+
* *
* @sc: pointer to scsi command we're working on
* @bpl: pointer to buffer list for protection groups
* @datacnt: number of segments of data that have been dma mapped
* @protcnt: number of segment of protection data that have been dma mapped
*
* Note: It is assumed that both data and protection s/g buffers have been * Note: It is assumed that both data and protection s/g buffers have been
* mapped for DMA * mapped for DMA
*/ *
* Returns the number of BDEs added to the BPL.
**/
static int static int
lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
struct ulp_bde64 *bpl, int datacnt, int protcnt) struct ulp_bde64 *bpl, int datacnt, int protcnt)
...@@ -1681,6 +1939,8 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, ...@@ -1681,6 +1939,8 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
int datadir = sc->sc_data_direction; int datadir = sc->sc_data_direction;
unsigned char pgdone = 0, alldone = 0; unsigned char pgdone = 0, alldone = 0;
unsigned blksize; unsigned blksize;
uint32_t rc;
uint32_t checking = 1;
uint32_t reftag; uint32_t reftag;
uint8_t txop, rxop; uint8_t txop, rxop;
int num_bde = 0; int num_bde = 0;
...@@ -1690,7 +1950,355 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, ...@@ -1690,7 +1950,355 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
if (!sgpe || !sgde) { if (!sgpe || !sgde) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP, lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
"9020 Invalid s/g entry: data=0x%p prot=0x%p\n", "9020 Invalid s/g entry: data=0x%p prot=0x%p\n",
sgpe, sgde);
return 0;
}
status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop);
if (status)
goto out;
/* extract some info from the scsi command */
blksize = lpfc_cmd_blksize(sc);
reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
rc = lpfc_bg_err_inject(phba, sc, &reftag, 0, 1);
if (rc) {
if (rc == BG_ERR_SWAP)
lpfc_bg_err_opcodes(phba, sc, &txop, &rxop);
if (rc == BG_ERR_CHECK)
checking = 0;
}
#endif
split_offset = 0;
do {
/* setup PDE5 with what we have */
pde5 = (struct lpfc_pde5 *) bpl;
memset(pde5, 0, sizeof(struct lpfc_pde5));
bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR);
/* Endianness conversion if necessary for PDE5 */
pde5->word0 = cpu_to_le32(pde5->word0);
pde5->reftag = cpu_to_le32(reftag);
/* advance bpl and increment bde count */
num_bde++;
bpl++;
pde6 = (struct lpfc_pde6 *) bpl;
/* setup PDE6 with the rest of the info */
memset(pde6, 0, sizeof(struct lpfc_pde6));
bf_set(pde6_type, pde6, LPFC_PDE6_DESCRIPTOR);
bf_set(pde6_optx, pde6, txop);
bf_set(pde6_oprx, pde6, rxop);
bf_set(pde6_ce, pde6, checking);
bf_set(pde6_re, pde6, checking);
bf_set(pde6_ai, pde6, 1);
bf_set(pde6_ae, pde6, 0);
bf_set(pde6_apptagval, pde6, 0);
/* Endianness conversion if necessary for PDE6 */
pde6->word0 = cpu_to_le32(pde6->word0);
pde6->word1 = cpu_to_le32(pde6->word1);
pde6->word2 = cpu_to_le32(pde6->word2);
/* advance bpl and increment bde count */
num_bde++;
bpl++;
/* setup the first BDE that points to protection buffer */
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(putPaddrHigh(protphysaddr));
pde7->addrLow = le32_to_cpu(putPaddrLow(protphysaddr));
protgrp_blks = protgroup_len / 8;
protgrp_bytes = protgrp_blks * blksize;
/* 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 = protgrp_blks * blksize;
} else {
protgroup_offset = 0;
curr_prot++;
}
num_bde++;
/* setup BDE's for data blocks associated with DIF data */
pgdone = 0;
subtotal = 0; /* total bytes processed for current prot grp */
while (!pgdone) {
if (!sgde) {
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9065 BLKGRD:%s Invalid data segment\n",
__func__);
return 0;
}
bpl++;
dataphysaddr = sg_dma_address(sgde) + split_offset;
bpl->addrLow = le32_to_cpu(putPaddrLow(dataphysaddr));
bpl->addrHigh = le32_to_cpu(putPaddrHigh(dataphysaddr));
remainder = sg_dma_len(sgde) - split_offset;
if ((subtotal + remainder) <= protgrp_bytes) {
/* we can use this whole buffer */
bpl->tus.f.bdeSize = remainder;
split_offset = 0;
if ((subtotal + remainder) == protgrp_bytes)
pgdone = 1;
} else {
/* must split this buffer with next prot grp */
bpl->tus.f.bdeSize = protgrp_bytes - subtotal;
split_offset += bpl->tus.f.bdeSize;
}
subtotal += bpl->tus.f.bdeSize;
if (datadir == DMA_TO_DEVICE)
bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
else
bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I;
bpl->tus.w = le32_to_cpu(bpl->tus.w);
num_bde++;
curr_data++;
if (split_offset)
break;
/* Move to the next s/g segment if possible */
sgde = sg_next(sgde);
}
if (protgroup_offset) {
/* update the reference tag */
reftag += protgrp_blks;
bpl++;
continue;
}
/* are we done ? */
if (curr_prot == protcnt) {
alldone = 1;
} else if (curr_prot < protcnt) {
/* advance to next prot buffer */
sgpe = sg_next(sgpe);
bpl++;
/* update the reference tag */
reftag += protgrp_blks;
} else {
/* if we're here, we have a bug */
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9054 BLKGRD: bug in %s\n", __func__);
}
} while (!alldone);
out:
return num_bde;
}
/**
* lpfc_bg_setup_sgl - Setup BlockGuard SGL with no protection data
* @phba: The Hba for which this call is being executed.
* @sc: pointer to scsi command we're working on
* @sgl: pointer to buffer list for protection groups
* @datacnt: number of segments of data that have been dma mapped
*
* This function sets up SGL buffer list for protection groups of
* type LPFC_PG_TYPE_NO_DIF
*
* This is usually used when the HBA is instructed to generate
* DIFs and insert them into data stream (or strip DIF from
* incoming data stream)
*
* The buffer list consists of just one protection group described
* below:
* +-------------------------+
* start of prot group --> | DI_SEED |
* +-------------------------+
* | Data SGE |
* +-------------------------+
* |more Data SGE's ... (opt)|
* +-------------------------+
*
*
* Note: Data s/g buffers have been dma mapped
*
* Returns the number of SGEs added to the SGL.
**/
static int
lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
struct sli4_sge *sgl, int datasegcnt)
{
struct scatterlist *sgde = NULL; /* s/g data entry */
struct sli4_sge_diseed *diseed = NULL;
dma_addr_t physaddr;
int i = 0, num_sge = 0, status;
int datadir = sc->sc_data_direction;
uint32_t reftag;
unsigned blksize;
uint8_t txop, rxop;
uint32_t rc;
uint32_t checking = 1;
uint32_t dma_len;
uint32_t dma_offset = 0;
status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop);
if (status)
goto out;
/* extract some info from the scsi command for pde*/
blksize = lpfc_cmd_blksize(sc);
reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS
rc = lpfc_bg_err_inject(phba, sc, &reftag, 0, 1);
if (rc) {
if (rc == BG_ERR_SWAP)
lpfc_bg_err_opcodes(phba, sc, &txop, &rxop);
if (rc == BG_ERR_CHECK)
checking = 0;
}
#endif
/* setup DISEED with what we have */
diseed = (struct sli4_sge_diseed *) sgl;
memset(diseed, 0, sizeof(struct sli4_sge_diseed));
bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DISEED);
/* Endianness conversion if necessary */
diseed->ref_tag = cpu_to_le32(reftag);
diseed->ref_tag_tran = diseed->ref_tag;
/* setup DISEED with the rest of the info */
bf_set(lpfc_sli4_sge_dif_optx, diseed, txop);
bf_set(lpfc_sli4_sge_dif_oprx, diseed, rxop);
if (datadir == DMA_FROM_DEVICE) {
bf_set(lpfc_sli4_sge_dif_ce, diseed, checking);
bf_set(lpfc_sli4_sge_dif_re, diseed, checking);
}
bf_set(lpfc_sli4_sge_dif_ai, diseed, 1);
bf_set(lpfc_sli4_sge_dif_me, diseed, 0);
/* Endianness conversion if necessary for DISEED */
diseed->word2 = cpu_to_le32(diseed->word2);
diseed->word3 = cpu_to_le32(diseed->word3);
/* advance bpl and increment sge count */
num_sge++;
sgl++;
/* assumption: caller has already run dma_map_sg on command data */
scsi_for_each_sg(sc, sgde, datasegcnt, i) {
physaddr = sg_dma_address(sgde);
dma_len = sg_dma_len(sgde);
sgl->addr_lo = cpu_to_le32(putPaddrLow(physaddr));
sgl->addr_hi = cpu_to_le32(putPaddrHigh(physaddr));
if ((i + 1) == datasegcnt)
bf_set(lpfc_sli4_sge_last, sgl, 1);
else
bf_set(lpfc_sli4_sge_last, sgl, 0);
bf_set(lpfc_sli4_sge_offset, sgl, dma_offset);
bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA);
sgl->sge_len = cpu_to_le32(dma_len);
dma_offset += dma_len;
sgl++;
num_sge++;
}
out:
return num_sge;
}
/**
* lpfc_bg_setup_sgl_prot - Setup BlockGuard SGL with protection data
* @phba: The Hba for which this call is being executed.
* @sc: pointer to scsi command we're working on
* @sgl: pointer to buffer list for protection groups
* @datacnt: number of segments of data that have been dma mapped
* @protcnt: number of segment of protection data that have been dma mapped
*
* This function sets up SGL buffer list for protection groups of
* type LPFC_PG_TYPE_DIF
*
* This is usually used when DIFs are in their own buffers,
* separate from the data. The HBA can then by instructed
* to place the DIFs in the outgoing stream. For read operations,
* The HBA could extract the DIFs and place it in DIF buffers.
*
* The buffer list for this type consists of one or more of the
* protection groups described below:
* +-------------------------+
* start of first prot group --> | DISEED |
* +-------------------------+
* | DIF (Prot SGE) |
* +-------------------------+
* | Data SGE |
* +-------------------------+
* |more Data SGE's ... (opt)|
* +-------------------------+
* start of new prot group --> | DISEED |
* +-------------------------+
* | ... |
* +-------------------------+
*
* Note: It is assumed that both data and protection s/g buffers have been
* mapped for DMA
*
* Returns the number of SGEs added to the SGL.
**/
static int
lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
struct sli4_sge *sgl, int datacnt, int protcnt)
{
struct scatterlist *sgde = NULL; /* s/g data entry */
struct scatterlist *sgpe = NULL; /* s/g prot entry */
struct sli4_sge_diseed *diseed = NULL;
dma_addr_t dataphysaddr, protphysaddr;
unsigned short curr_data = 0, curr_prot = 0;
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;
unsigned char pgdone = 0, alldone = 0;
unsigned blksize;
uint32_t reftag;
uint8_t txop, rxop;
uint32_t dma_len;
uint32_t rc;
uint32_t checking = 1;
uint32_t dma_offset = 0;
int num_sge = 0;
sgpe = scsi_prot_sglist(sc);
sgde = scsi_sglist(sc);
if (!sgpe || !sgde) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
"9082 Invalid s/g entry: data=0x%p prot=0x%p\n",
sgpe, sgde); sgpe, sgde);
return 0; return 0;
} }
...@@ -1701,48 +2309,44 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, ...@@ -1701,48 +2309,44 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
/* extract some info from the scsi command */ /* extract some info from the scsi command */
blksize = lpfc_cmd_blksize(sc); blksize = lpfc_cmd_blksize(sc);
reftag = scsi_get_lba(sc) & 0xffffffff; reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */
#ifdef CONFIG_SCSI_LPFC_DEBUG_FS #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
/* reftag / guard tag are the only errors we can inject here */ rc = lpfc_bg_err_inject(phba, sc, &reftag, 0, 1);
lpfc_bg_err_inject(phba, sc, &reftag, 0, 0xDEAD); if (rc) {
if (rc == BG_ERR_SWAP)
lpfc_bg_err_opcodes(phba, sc, &txop, &rxop);
if (rc == BG_ERR_CHECK)
checking = 0;
}
#endif #endif
split_offset = 0; split_offset = 0;
do { do {
/* setup PDE5 with what we have */ /* setup DISEED with what we have */
pde5 = (struct lpfc_pde5 *) bpl; diseed = (struct sli4_sge_diseed *) sgl;
memset(pde5, 0, sizeof(struct lpfc_pde5)); memset(diseed, 0, sizeof(struct sli4_sge_diseed));
bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR); bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DISEED);
/* Endianness conversion if necessary for PDE5 */ /* Endianness conversion if necessary */
pde5->word0 = cpu_to_le32(pde5->word0); diseed->ref_tag = cpu_to_le32(reftag);
pde5->reftag = cpu_to_le32(reftag); diseed->ref_tag_tran = diseed->ref_tag;
/* advance bpl and increment bde count */ /* setup DISEED with the rest of the info */
num_bde++; bf_set(lpfc_sli4_sge_dif_optx, diseed, txop);
bpl++; bf_set(lpfc_sli4_sge_dif_oprx, diseed, rxop);
pde6 = (struct lpfc_pde6 *) bpl; bf_set(lpfc_sli4_sge_dif_ce, diseed, checking);
bf_set(lpfc_sli4_sge_dif_re, diseed, checking);
/* setup PDE6 with the rest of the info */ bf_set(lpfc_sli4_sge_dif_ai, diseed, 1);
memset(pde6, 0, sizeof(struct lpfc_pde6)); bf_set(lpfc_sli4_sge_dif_me, diseed, 0);
bf_set(pde6_type, pde6, LPFC_PDE6_DESCRIPTOR);
bf_set(pde6_optx, pde6, txop); /* Endianness conversion if necessary for DISEED */
bf_set(pde6_oprx, pde6, rxop); diseed->word2 = cpu_to_le32(diseed->word2);
bf_set(pde6_ce, pde6, 1); diseed->word3 = cpu_to_le32(diseed->word3);
bf_set(pde6_re, pde6, 1);
bf_set(pde6_ai, pde6, 1); /* advance sgl and increment bde count */
bf_set(pde6_ae, pde6, 0); num_sge++;
bf_set(pde6_apptagval, pde6, 0); sgl++;
/* Endianness conversion if necessary for PDE6 */
pde6->word0 = cpu_to_le32(pde6->word0);
pde6->word1 = cpu_to_le32(pde6->word1);
pde6->word2 = cpu_to_le32(pde6->word2);
/* advance bpl and increment bde count */
num_bde++;
bpl++;
/* setup the first BDE that points to protection buffer */ /* setup the first BDE that points to protection buffer */
protphysaddr = sg_dma_address(sgpe) + protgroup_offset; protphysaddr = sg_dma_address(sgpe) + protgroup_offset;
...@@ -1751,19 +2355,19 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, ...@@ -1751,19 +2355,19 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
/* must be integer multiple of the DIF block length */ /* must be integer multiple of the DIF block length */
BUG_ON(protgroup_len % 8); BUG_ON(protgroup_len % 8);
pde7 = (struct lpfc_pde7 *) bpl; /* Now setup DIF SGE */
memset(pde7, 0, sizeof(struct lpfc_pde7)); sgl->word2 = 0;
bf_set(pde7_type, pde7, LPFC_PDE7_DESCRIPTOR); bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DIF);
sgl->addr_hi = le32_to_cpu(putPaddrHigh(protphysaddr));
pde7->addrHigh = le32_to_cpu(putPaddrHigh(protphysaddr)); sgl->addr_lo = le32_to_cpu(putPaddrLow(protphysaddr));
pde7->addrLow = le32_to_cpu(putPaddrLow(protphysaddr)); sgl->word2 = cpu_to_le32(sgl->word2);
protgrp_blks = protgroup_len / 8; protgrp_blks = protgroup_len / 8;
protgrp_bytes = protgrp_blks * blksize; protgrp_bytes = protgrp_blks * blksize;
/* check if this pde is crossing the 4K boundary; if so split */ /* check if DIF SGE is crossing the 4K boundary; if so split */
if ((pde7->addrLow & 0xfff) + protgroup_len > 0x1000) { if ((sgl->addr_lo & 0xfff) + protgroup_len > 0x1000) {
protgroup_remainder = 0x1000 - (pde7->addrLow & 0xfff); protgroup_remainder = 0x1000 - (sgl->addr_lo & 0xfff);
protgroup_offset += protgroup_remainder; protgroup_offset += protgroup_remainder;
protgrp_blks = protgroup_remainder / 8; protgrp_blks = protgroup_remainder / 8;
protgrp_bytes = protgrp_blks * blksize; protgrp_bytes = protgrp_blks * blksize;
...@@ -1772,47 +2376,48 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, ...@@ -1772,47 +2376,48 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
curr_prot++; curr_prot++;
} }
num_bde++; num_sge++;
/* setup BDE's for data blocks associated with DIF data */ /* setup SGE's for data blocks associated with DIF data */
pgdone = 0; pgdone = 0;
subtotal = 0; /* total bytes processed for current prot grp */ subtotal = 0; /* total bytes processed for current prot grp */
while (!pgdone) { while (!pgdone) {
if (!sgde) { if (!sgde) {
lpfc_printf_log(phba, KERN_ERR, LOG_BG, lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9065 BLKGRD:%s Invalid data segment\n", "9086 BLKGRD:%s Invalid data segment\n",
__func__); __func__);
return 0; return 0;
} }
bpl++; sgl++;
dataphysaddr = sg_dma_address(sgde) + split_offset; dataphysaddr = sg_dma_address(sgde) + split_offset;
bpl->addrLow = le32_to_cpu(putPaddrLow(dataphysaddr));
bpl->addrHigh = le32_to_cpu(putPaddrHigh(dataphysaddr));
remainder = sg_dma_len(sgde) - split_offset; remainder = sg_dma_len(sgde) - split_offset;
if ((subtotal + remainder) <= protgrp_bytes) { if ((subtotal + remainder) <= protgrp_bytes) {
/* we can use this whole buffer */ /* we can use this whole buffer */
bpl->tus.f.bdeSize = remainder; dma_len = remainder;
split_offset = 0; split_offset = 0;
if ((subtotal + remainder) == protgrp_bytes) if ((subtotal + remainder) == protgrp_bytes)
pgdone = 1; pgdone = 1;
} else { } else {
/* must split this buffer with next prot grp */ /* must split this buffer with next prot grp */
bpl->tus.f.bdeSize = protgrp_bytes - subtotal; dma_len = protgrp_bytes - subtotal;
split_offset += bpl->tus.f.bdeSize; split_offset += dma_len;
} }
subtotal += bpl->tus.f.bdeSize; subtotal += dma_len;
if (datadir == DMA_TO_DEVICE) sgl->addr_lo = cpu_to_le32(putPaddrLow(dataphysaddr));
bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; sgl->addr_hi = cpu_to_le32(putPaddrHigh(dataphysaddr));
else bf_set(lpfc_sli4_sge_last, sgl, 0);
bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; bf_set(lpfc_sli4_sge_offset, sgl, dma_offset);
bpl->tus.w = le32_to_cpu(bpl->tus.w); bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA);
num_bde++; sgl->sge_len = cpu_to_le32(dma_len);
dma_offset += dma_len;
num_sge++;
curr_data++; curr_data++;
if (split_offset) if (split_offset)
...@@ -1820,45 +2425,50 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, ...@@ -1820,45 +2425,50 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
/* Move to the next s/g segment if possible */ /* Move to the next s/g segment if possible */
sgde = sg_next(sgde); sgde = sg_next(sgde);
} }
if (protgroup_offset) { if (protgroup_offset) {
/* update the reference tag */ /* update the reference tag */
reftag += protgrp_blks; reftag += protgrp_blks;
bpl++; sgl++;
continue; continue;
} }
/* are we done ? */ /* are we done ? */
if (curr_prot == protcnt) { if (curr_prot == protcnt) {
bf_set(lpfc_sli4_sge_last, sgl, 1);
alldone = 1; alldone = 1;
} else if (curr_prot < protcnt) { } else if (curr_prot < protcnt) {
/* advance to next prot buffer */ /* advance to next prot buffer */
sgpe = sg_next(sgpe); sgpe = sg_next(sgpe);
bpl++; sgl++;
/* update the reference tag */ /* update the reference tag */
reftag += protgrp_blks; reftag += protgrp_blks;
} else { } else {
/* if we're here, we have a bug */ /* if we're here, we have a bug */
lpfc_printf_log(phba, KERN_ERR, LOG_BG, lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9054 BLKGRD: bug in %s\n", __func__); "9085 BLKGRD: bug in %s\n", __func__);
} }
} while (!alldone); } while (!alldone);
out: out:
return num_bde; return num_sge;
} }
/* /**
* lpfc_prot_group_type - Get prtotection group type of SCSI command
* @phba: The Hba for which this call is being executed.
* @sc: pointer to scsi command we're working on
*
* Given a SCSI command that supports DIF, determine composition of protection * Given a SCSI command that supports DIF, determine composition of protection
* groups involved in setting up buffer lists * groups involved in setting up buffer lists
* *
* Returns: * Returns: Protection group type (with or without DIF)
* for DIF (for both read and write) *
* */ **/
static int static int
lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc) lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc)
{ {
...@@ -1885,13 +2495,17 @@ lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc) ...@@ -1885,13 +2495,17 @@ lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc)
return ret; return ret;
} }
/* /**
* lpfc_bg_scsi_prep_dma_buf_s3 - DMA mapping for scsi buffer to SLI3 IF spec
* @phba: The Hba for which this call is being executed.
* @lpfc_cmd: The scsi buffer which is going to be prep'ed.
*
* This is the protection/DIF aware version of * This is the protection/DIF aware version of
* lpfc_scsi_prep_dma_buf(). It may be a good idea to combine the * lpfc_scsi_prep_dma_buf(). It may be a good idea to combine the
* two functions eventually, but for now, it's here * two functions eventually, but for now, it's here
*/ **/
static int static int
lpfc_bg_scsi_prep_dma_buf(struct lpfc_hba *phba, lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba,
struct lpfc_scsi_buf *lpfc_cmd) struct lpfc_scsi_buf *lpfc_cmd)
{ {
struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
...@@ -2147,7 +2761,21 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, ...@@ -2147,7 +2761,21 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
cmd->sense_buffer[8] = 0; /* Information descriptor type */ cmd->sense_buffer[8] = 0; /* Information descriptor type */
cmd->sense_buffer[9] = 0xa; /* Additional descriptor length */ cmd->sense_buffer[9] = 0xa; /* Additional descriptor length */
cmd->sense_buffer[10] = 0x80; /* Validity bit */ cmd->sense_buffer[10] = 0x80; /* Validity bit */
bghm /= cmd->device->sector_size;
/* bghm is a "on the wire" FC frame based count */
switch (scsi_get_prot_op(cmd)) {
case SCSI_PROT_READ_INSERT:
case SCSI_PROT_WRITE_STRIP:
bghm /= cmd->device->sector_size;
break;
case SCSI_PROT_READ_STRIP:
case SCSI_PROT_WRITE_INSERT:
case SCSI_PROT_READ_PASS:
case SCSI_PROT_WRITE_PASS:
bghm /= (cmd->device->sector_size +
sizeof(struct scsi_dif_tuple));
break;
}
failing_sector = scsi_get_lba(cmd); failing_sector = scsi_get_lba(cmd);
failing_sector += bghm; failing_sector += bghm;
...@@ -2291,6 +2919,180 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) ...@@ -2291,6 +2919,180 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
return 0; return 0;
} }
/**
* lpfc_bg_scsi_adjust_dl - Adjust SCSI data length for BlockGuard
* @phba: The Hba for which this call is being executed.
* @lpfc_cmd: The scsi buffer which is going to be adjusted.
*
* Adjust the data length to account for how much data
* is actually on the wire.
*
* returns the adjusted data length
**/
static int
lpfc_bg_scsi_adjust_dl(struct lpfc_hba *phba,
struct lpfc_scsi_buf *lpfc_cmd)
{
struct scsi_cmnd *sc = lpfc_cmd->pCmd;
int diflen, fcpdl;
unsigned blksize;
fcpdl = scsi_bufflen(sc);
/* Check if there is protection data on the wire */
if (sc->sc_data_direction == DMA_FROM_DEVICE) {
/* Read */
if (scsi_get_prot_op(sc) == SCSI_PROT_READ_INSERT)
return fcpdl;
} else {
/* Write */
if (scsi_get_prot_op(sc) == SCSI_PROT_WRITE_STRIP)
return fcpdl;
}
/* If protection data on the wire, adjust the count accordingly */
blksize = lpfc_cmd_blksize(sc);
diflen = (fcpdl / blksize) * 8;
fcpdl += diflen;
return fcpdl;
}
/**
* lpfc_bg_scsi_prep_dma_buf_s4 - DMA mapping for scsi buffer to SLI4 IF spec
* @phba: The Hba for which this call is being executed.
* @lpfc_cmd: The scsi buffer which is going to be mapped.
*
* This is the protection/DIF aware version of
* lpfc_scsi_prep_dma_buf(). It may be a good idea to combine the
* two functions eventually, but for now, it's here
**/
static int
lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba,
struct lpfc_scsi_buf *lpfc_cmd)
{
struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd;
struct sli4_sge *sgl = (struct sli4_sge *)(lpfc_cmd->fcp_bpl);
IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
uint32_t num_bde = 0;
int datasegcnt, protsegcnt, datadir = scsi_cmnd->sc_data_direction;
int prot_group_type = 0;
int fcpdl;
/*
* Start the lpfc command prep by bumping the sgl beyond fcp_cmnd
* fcp_rsp regions to the first data bde entry
*/
if (scsi_sg_count(scsi_cmnd)) {
/*
* The driver stores the segment count returned from pci_map_sg
* because this a count of dma-mappings used to map the use_sg
* pages. They are not guaranteed to be the same for those
* architectures that implement an IOMMU.
*/
datasegcnt = dma_map_sg(&phba->pcidev->dev,
scsi_sglist(scsi_cmnd),
scsi_sg_count(scsi_cmnd), datadir);
if (unlikely(!datasegcnt))
return 1;
sgl += 1;
/* clear the last flag in the fcp_rsp map entry */
sgl->word2 = le32_to_cpu(sgl->word2);
bf_set(lpfc_sli4_sge_last, sgl, 0);
sgl->word2 = cpu_to_le32(sgl->word2);
sgl += 1;
lpfc_cmd->seg_cnt = datasegcnt;
if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9087 BLKGRD: %s: Too many sg segments"
" from dma_map_sg. Config %d, seg_cnt"
" %d\n",
__func__, phba->cfg_sg_seg_cnt,
lpfc_cmd->seg_cnt);
scsi_dma_unmap(scsi_cmnd);
return 1;
}
prot_group_type = lpfc_prot_group_type(phba, scsi_cmnd);
switch (prot_group_type) {
case LPFC_PG_TYPE_NO_DIF:
num_bde = lpfc_bg_setup_sgl(phba, scsi_cmnd, sgl,
datasegcnt);
/* we should have 2 or more entries in buffer list */
if (num_bde < 2)
goto err;
break;
case LPFC_PG_TYPE_DIF_BUF:{
/*
* This type indicates that protection buffers are
* passed to the driver, so that needs to be prepared
* for DMA
*/
protsegcnt = dma_map_sg(&phba->pcidev->dev,
scsi_prot_sglist(scsi_cmnd),
scsi_prot_sg_count(scsi_cmnd), datadir);
if (unlikely(!protsegcnt)) {
scsi_dma_unmap(scsi_cmnd);
return 1;
}
lpfc_cmd->prot_seg_cnt = protsegcnt;
if (lpfc_cmd->prot_seg_cnt
> phba->cfg_prot_sg_seg_cnt) {
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9088 BLKGRD: %s: Too many prot sg "
"segments from dma_map_sg. Config %d,"
"prot_seg_cnt %d\n", __func__,
phba->cfg_prot_sg_seg_cnt,
lpfc_cmd->prot_seg_cnt);
dma_unmap_sg(&phba->pcidev->dev,
scsi_prot_sglist(scsi_cmnd),
scsi_prot_sg_count(scsi_cmnd),
datadir);
scsi_dma_unmap(scsi_cmnd);
return 1;
}
num_bde = lpfc_bg_setup_sgl_prot(phba, scsi_cmnd, sgl,
datasegcnt, protsegcnt);
/* we should have 3 or more entries in buffer list */
if (num_bde < 3)
goto err;
break;
}
case LPFC_PG_TYPE_INVALID:
default:
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
"9083 Unexpected protection group %i\n",
prot_group_type);
return 1;
}
}
fcpdl = lpfc_bg_scsi_adjust_dl(phba, lpfc_cmd);
fcp_cmnd->fcpDl = be32_to_cpu(fcpdl);
/*
* Due to difference in data length between DIF/non-DIF paths,
* we need to set word 4 of IOCB here
*/
iocb_cmd->un.fcpi.fcpi_parm = fcpdl;
lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_DIF;
return 0;
err:
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
"9084 Could not setup all needed BDE's"
"prot_group_type=%d, num_bde=%d\n",
prot_group_type, num_bde);
return 1;
}
/** /**
* lpfc_scsi_prep_dma_buf - Wrapper function for DMA mapping of scsi buffer * lpfc_scsi_prep_dma_buf - Wrapper function for DMA mapping of scsi buffer
* @phba: The Hba for which this call is being executed. * @phba: The Hba for which this call is being executed.
...@@ -2309,6 +3111,25 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) ...@@ -2309,6 +3111,25 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
return phba->lpfc_scsi_prep_dma_buf(phba, lpfc_cmd); return phba->lpfc_scsi_prep_dma_buf(phba, lpfc_cmd);
} }
/**
* lpfc_bg_scsi_prep_dma_buf - Wrapper function for DMA mapping of scsi buffer
* using BlockGuard.
* @phba: The Hba for which this call is being executed.
* @lpfc_cmd: The scsi buffer which is going to be mapped.
*
* This routine wraps the actual DMA mapping function pointer from the
* lpfc_hba struct.
*
* Return codes:
* 1 - Error
* 0 - Success
**/
static inline int
lpfc_bg_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
{
return phba->lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd);
}
/** /**
* lpfc_send_scsi_error_event - Posts an event when there is SCSI error * lpfc_send_scsi_error_event - Posts an event when there is SCSI error
* @phba: Pointer to hba context object. * @phba: Pointer to hba context object.
...@@ -3072,12 +3893,14 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) ...@@ -3072,12 +3893,14 @@ lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
case LPFC_PCI_DEV_LP: case LPFC_PCI_DEV_LP:
phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s3; phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s3;
phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s3; phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s3;
phba->lpfc_bg_scsi_prep_dma_buf = lpfc_bg_scsi_prep_dma_buf_s3;
phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s3; phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s3;
phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s3; phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s3;
break; break;
case LPFC_PCI_DEV_OC: case LPFC_PCI_DEV_OC:
phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s4; phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s4;
phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s4; phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s4;
phba->lpfc_bg_scsi_prep_dma_buf = lpfc_bg_scsi_prep_dma_buf_s4;
phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s4; phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s4;
phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s4; phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s4;
break; break;
...@@ -3250,8 +4073,7 @@ lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) ...@@ -3250,8 +4073,7 @@ lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
ndlp = rdata->pnode; ndlp = rdata->pnode;
if ((scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) && if ((scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) &&
(!(phba->sli3_options & LPFC_SLI3_BG_ENABLED) || (!(phba->sli3_options & LPFC_SLI3_BG_ENABLED))) {
(phba->sli_rev == LPFC_SLI_REV4))) {
lpfc_printf_log(phba, KERN_ERR, LOG_BG, lpfc_printf_log(phba, KERN_ERR, LOG_BG,
"9058 BLKGRD: ERROR: rcvd protected cmd:%02x" "9058 BLKGRD: ERROR: rcvd protected cmd:%02x"
......
...@@ -7839,12 +7839,16 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, ...@@ -7839,12 +7839,16 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
bf_set(wqe_lnk, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpXS); bf_set(wqe_lnk, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpXS);
/* Always open the exchange */ /* Always open the exchange */
bf_set(wqe_xc, &wqe->fcp_iwrite.wqe_com, 0); bf_set(wqe_xc, &wqe->fcp_iwrite.wqe_com, 0);
bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1);
bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE); bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE);
bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com, bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com,
LPFC_WQE_LENLOC_WORD4); LPFC_WQE_LENLOC_WORD4);
bf_set(wqe_ebde_cnt, &wqe->fcp_iwrite.wqe_com, 0); bf_set(wqe_ebde_cnt, &wqe->fcp_iwrite.wqe_com, 0);
bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU); bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU);
if (iocbq->iocb_flag & LPFC_IO_DIF) {
iocbq->iocb_flag &= ~LPFC_IO_DIF;
bf_set(wqe_dif, &wqe->generic.wqe_com, 1);
}
bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1);
break; break;
case CMD_FCP_IREAD64_CR: case CMD_FCP_IREAD64_CR:
/* word3 iocb=iotag wqe=payload_offset_len */ /* word3 iocb=iotag wqe=payload_offset_len */
...@@ -7858,12 +7862,16 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, ...@@ -7858,12 +7862,16 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq,
bf_set(wqe_lnk, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpXS); bf_set(wqe_lnk, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpXS);
/* Always open the exchange */ /* Always open the exchange */
bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0); bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0);
bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1);
bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ); bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ);
bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com,
LPFC_WQE_LENLOC_WORD4); LPFC_WQE_LENLOC_WORD4);
bf_set(wqe_ebde_cnt, &wqe->fcp_iread.wqe_com, 0); bf_set(wqe_ebde_cnt, &wqe->fcp_iread.wqe_com, 0);
bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU); bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU);
if (iocbq->iocb_flag & LPFC_IO_DIF) {
iocbq->iocb_flag &= ~LPFC_IO_DIF;
bf_set(wqe_dif, &wqe->generic.wqe_com, 1);
}
bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1);
break; break;
case CMD_FCP_ICMND64_CR: case CMD_FCP_ICMND64_CR:
/* word3 iocb=IO_TAG wqe=reserved */ /* word3 iocb=IO_TAG wqe=reserved */
...@@ -10672,12 +10680,14 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba, ...@@ -10672,12 +10680,14 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba,
struct lpfc_wcqe_complete *wcqe) struct lpfc_wcqe_complete *wcqe)
{ {
unsigned long iflags; unsigned long iflags;
uint32_t status;
size_t offset = offsetof(struct lpfc_iocbq, iocb); size_t offset = offsetof(struct lpfc_iocbq, iocb);
memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset, memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset,
sizeof(struct lpfc_iocbq) - offset); sizeof(struct lpfc_iocbq) - offset);
/* Map WCQE parameters into irspiocb parameters */ /* Map WCQE parameters into irspiocb parameters */
pIocbIn->iocb.ulpStatus = bf_get(lpfc_wcqe_c_status, wcqe); status = bf_get(lpfc_wcqe_c_status, wcqe);
pIocbIn->iocb.ulpStatus = (status & LPFC_IOCB_STATUS_MASK);
if (pIocbOut->iocb_flag & LPFC_IO_FCP) if (pIocbOut->iocb_flag & LPFC_IO_FCP)
if (pIocbIn->iocb.ulpStatus == IOSTAT_FCP_RSP_ERROR) if (pIocbIn->iocb.ulpStatus == IOSTAT_FCP_RSP_ERROR)
pIocbIn->iocb.un.fcpi.fcpi_parm = pIocbIn->iocb.un.fcpi.fcpi_parm =
...@@ -10690,6 +10700,44 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba, ...@@ -10690,6 +10700,44 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba,
pIocbIn->iocb.un.genreq64.bdl.bdeSize = wcqe->total_data_placed; pIocbIn->iocb.un.genreq64.bdl.bdeSize = wcqe->total_data_placed;
} }
/* Convert BG errors for completion status */
if (status == CQE_STATUS_DI_ERROR) {
pIocbIn->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
if (bf_get(lpfc_wcqe_c_bg_edir, wcqe))
pIocbIn->iocb.un.ulpWord[4] = IOERR_RX_DMA_FAILED;
else
pIocbIn->iocb.un.ulpWord[4] = IOERR_TX_DMA_FAILED;
pIocbIn->iocb.unsli3.sli3_bg.bgstat = 0;
if (bf_get(lpfc_wcqe_c_bg_ge, wcqe)) /* Guard Check failed */
pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
BGS_GUARD_ERR_MASK;
if (bf_get(lpfc_wcqe_c_bg_ae, wcqe)) /* App Tag Check failed */
pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
BGS_APPTAG_ERR_MASK;
if (bf_get(lpfc_wcqe_c_bg_re, wcqe)) /* Ref Tag Check failed */
pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
BGS_REFTAG_ERR_MASK;
/* Check to see if there was any good data before the error */
if (bf_get(lpfc_wcqe_c_bg_tdpv, wcqe)) {
pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
BGS_HI_WATER_MARK_PRESENT_MASK;
pIocbIn->iocb.unsli3.sli3_bg.bghm =
wcqe->total_data_placed;
}
/*
* Set ALL the error bits to indicate we don't know what
* type of error it is.
*/
if (!pIocbIn->iocb.unsli3.sli3_bg.bgstat)
pIocbIn->iocb.unsli3.sli3_bg.bgstat |=
(BGS_REFTAG_ERR_MASK | BGS_APPTAG_ERR_MASK |
BGS_GUARD_ERR_MASK);
}
/* Pick up HBA exchange busy condition */ /* Pick up HBA exchange busy condition */
if (bf_get(lpfc_wcqe_c_xb, wcqe)) { if (bf_get(lpfc_wcqe_c_xb, wcqe)) {
spin_lock_irqsave(&phba->hbalock, iflags); spin_lock_irqsave(&phba->hbalock, iflags);
......
...@@ -69,6 +69,7 @@ struct lpfc_iocbq { ...@@ -69,6 +69,7 @@ struct lpfc_iocbq {
#define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */ #define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */
#define DSS_SECURITY_OP 0x100 /* security IO */ #define DSS_SECURITY_OP 0x100 /* security IO */
#define LPFC_IO_ON_Q 0x200 /* The IO is still on the TXCMPLQ */ #define LPFC_IO_ON_Q 0x200 /* The IO is still on the TXCMPLQ */
#define LPFC_IO_DIF 0x400 /* T10 DIF IO */
#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */ #define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */
#define LPFC_FIP_ELS_ID_SHIFT 14 #define LPFC_FIP_ELS_ID_SHIFT 14
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment