forked from Minki/linux
[SCSI] lpfc 8.3.39: Fixed BlockGuard error reporting
Signed-off-by: James Smart <james.smart@emulex.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
16a3a20842
commit
737d42483e
@ -37,6 +37,7 @@
|
||||
#define LOG_EVENT 0x00010000 /* CT,TEMP,DUMP, logging */
|
||||
#define LOG_FIP 0x00020000 /* FIP events */
|
||||
#define LOG_FCP_UNDER 0x00040000 /* FCP underruns errors */
|
||||
#define LOG_SCSI_CMD 0x00080000 /* ALL SCSI commands */
|
||||
#define LOG_ALL_MSG 0xffffffff /* LOG all messages */
|
||||
|
||||
#define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/crc-t10dif.h>
|
||||
#include <net/checksum.h>
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
@ -48,7 +50,7 @@
|
||||
#define LPFC_RESET_WAIT 2
|
||||
#define LPFC_ABORT_WAIT 2
|
||||
|
||||
int _dump_buf_done;
|
||||
int _dump_buf_done = 1;
|
||||
|
||||
static char *dif_op_str[] = {
|
||||
"PROT_NORMAL",
|
||||
@ -2819,6 +2821,214 @@ err:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function calcuates the T10 DIF guard tag
|
||||
* on the specified data using a CRC algorithmn
|
||||
* using crc_t10dif.
|
||||
*/
|
||||
uint16_t
|
||||
lpfc_bg_crc(uint8_t *data, int count)
|
||||
{
|
||||
uint16_t crc = 0;
|
||||
uint16_t x;
|
||||
|
||||
crc = crc_t10dif(data, count);
|
||||
x = cpu_to_be16(crc);
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function calcuates the T10 DIF guard tag
|
||||
* on the specified data using a CSUM algorithmn
|
||||
* using ip_compute_csum.
|
||||
*/
|
||||
uint16_t
|
||||
lpfc_bg_csum(uint8_t *data, int count)
|
||||
{
|
||||
uint16_t ret;
|
||||
|
||||
ret = ip_compute_csum(data, count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function examines the protection data to try to determine
|
||||
* what type of T10-DIF error occurred.
|
||||
*/
|
||||
void
|
||||
lpfc_calc_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
|
||||
{
|
||||
struct scatterlist *sgpe; /* s/g prot entry */
|
||||
struct scatterlist *sgde; /* s/g data entry */
|
||||
struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
|
||||
struct scsi_dif_tuple *src = NULL;
|
||||
uint8_t *data_src = NULL;
|
||||
uint16_t guard_tag, guard_type;
|
||||
uint16_t start_app_tag, app_tag;
|
||||
uint32_t start_ref_tag, ref_tag;
|
||||
int prot, protsegcnt;
|
||||
int err_type, len, data_len;
|
||||
int chk_ref, chk_app, chk_guard;
|
||||
uint16_t sum;
|
||||
unsigned blksize;
|
||||
|
||||
err_type = BGS_GUARD_ERR_MASK;
|
||||
sum = 0;
|
||||
guard_tag = 0;
|
||||
|
||||
/* First check to see if there is protection data to examine */
|
||||
prot = scsi_get_prot_op(cmd);
|
||||
if ((prot == SCSI_PROT_READ_STRIP) ||
|
||||
(prot == SCSI_PROT_WRITE_INSERT) ||
|
||||
(prot == SCSI_PROT_NORMAL))
|
||||
goto out;
|
||||
|
||||
/* Currently the driver just supports ref_tag and guard_tag checking */
|
||||
chk_ref = 1;
|
||||
chk_app = 0;
|
||||
chk_guard = 0;
|
||||
|
||||
/* Setup a ptr to the protection data provided by the SCSI host */
|
||||
sgpe = scsi_prot_sglist(cmd);
|
||||
protsegcnt = lpfc_cmd->prot_seg_cnt;
|
||||
|
||||
if (sgpe && protsegcnt) {
|
||||
|
||||
/*
|
||||
* We will only try to verify guard tag if the segment
|
||||
* data length is a multiple of the blksize.
|
||||
*/
|
||||
sgde = scsi_sglist(cmd);
|
||||
blksize = lpfc_cmd_blksize(cmd);
|
||||
data_src = (uint8_t *)sg_virt(sgde);
|
||||
data_len = sgde->length;
|
||||
if ((data_len & (blksize - 1)) == 0)
|
||||
chk_guard = 1;
|
||||
guard_type = scsi_host_get_guard(cmd->device->host);
|
||||
|
||||
start_ref_tag = scsi_get_lba(cmd);
|
||||
start_app_tag = src->app_tag;
|
||||
src = (struct scsi_dif_tuple *)sg_virt(sgpe);
|
||||
len = sgpe->length;
|
||||
while (src && protsegcnt) {
|
||||
while (len) {
|
||||
|
||||
/*
|
||||
* First check to see if a protection data
|
||||
* check is valid
|
||||
*/
|
||||
if ((src->ref_tag == 0xffffffff) ||
|
||||
(src->app_tag == 0xffff)) {
|
||||
start_ref_tag++;
|
||||
goto skipit;
|
||||
}
|
||||
|
||||
/* App Tag checking */
|
||||
app_tag = src->app_tag;
|
||||
if (chk_app && (app_tag != start_app_tag)) {
|
||||
err_type = BGS_APPTAG_ERR_MASK;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Reference Tag checking */
|
||||
ref_tag = be32_to_cpu(src->ref_tag);
|
||||
if (chk_ref && (ref_tag != start_ref_tag)) {
|
||||
err_type = BGS_REFTAG_ERR_MASK;
|
||||
goto out;
|
||||
}
|
||||
start_ref_tag++;
|
||||
|
||||
/* Guard Tag checking */
|
||||
if (chk_guard) {
|
||||
guard_tag = src->guard_tag;
|
||||
if (guard_type == SHOST_DIX_GUARD_IP)
|
||||
sum = lpfc_bg_csum(data_src,
|
||||
blksize);
|
||||
else
|
||||
sum = lpfc_bg_crc(data_src,
|
||||
blksize);
|
||||
if ((guard_tag != sum)) {
|
||||
err_type = BGS_GUARD_ERR_MASK;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
skipit:
|
||||
len -= sizeof(struct scsi_dif_tuple);
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
src++;
|
||||
|
||||
data_src += blksize;
|
||||
data_len -= blksize;
|
||||
|
||||
/*
|
||||
* Are we at the end of the Data segment?
|
||||
* The data segment is only used for Guard
|
||||
* tag checking.
|
||||
*/
|
||||
if (chk_guard && (data_len == 0)) {
|
||||
chk_guard = 0;
|
||||
sgde = sg_next(sgde);
|
||||
if (!sgde)
|
||||
goto out;
|
||||
|
||||
data_src = (uint8_t *)sg_virt(sgde);
|
||||
data_len = sgde->length;
|
||||
if ((data_len & (blksize - 1)) == 0)
|
||||
chk_guard = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Goto the next Protection data segment */
|
||||
sgpe = sg_next(sgpe);
|
||||
if (sgpe) {
|
||||
src = (struct scsi_dif_tuple *)sg_virt(sgpe);
|
||||
len = sgpe->length;
|
||||
} else {
|
||||
src = NULL;
|
||||
}
|
||||
protsegcnt--;
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (err_type == BGS_GUARD_ERR_MASK) {
|
||||
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
|
||||
0x10, 0x1);
|
||||
cmd->result = DRIVER_SENSE << 24
|
||||
| ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION);
|
||||
phba->bg_guard_err_cnt++;
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
|
||||
"9069 BLKGRD: LBA %lx grd_tag error %x != %x\n",
|
||||
(unsigned long)scsi_get_lba(cmd),
|
||||
sum, guard_tag);
|
||||
|
||||
} else if (err_type == BGS_REFTAG_ERR_MASK) {
|
||||
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
|
||||
0x10, 0x3);
|
||||
cmd->result = DRIVER_SENSE << 24
|
||||
| ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION);
|
||||
|
||||
phba->bg_reftag_err_cnt++;
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
|
||||
"9066 BLKGRD: LBA %lx ref_tag error %x != %x\n",
|
||||
(unsigned long)scsi_get_lba(cmd),
|
||||
ref_tag, start_ref_tag);
|
||||
|
||||
} else if (err_type == BGS_APPTAG_ERR_MASK) {
|
||||
scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
|
||||
0x10, 0x2);
|
||||
cmd->result = DRIVER_SENSE << 24
|
||||
| ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION);
|
||||
|
||||
phba->bg_apptag_err_cnt++;
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
|
||||
"9041 BLKGRD: LBA %lx app_tag error %x != %x\n",
|
||||
(unsigned long)scsi_get_lba(cmd),
|
||||
app_tag, start_app_tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function checks for BlockGuard errors detected by
|
||||
* the HBA. In case of errors, the ASC/ASCQ fields in the
|
||||
@ -2842,12 +3052,6 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
|
||||
uint32_t bgstat = bgf->bgstat;
|
||||
uint64_t failing_sector = 0;
|
||||
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9069 BLKGRD: BG ERROR in cmd"
|
||||
" 0x%x lba 0x%llx blk cnt 0x%x "
|
||||
"bgstat=0x%x bghm=0x%x\n",
|
||||
cmd->cmnd[0], (unsigned long long)scsi_get_lba(cmd),
|
||||
blk_rq_sectors(cmd->request), bgstat, bghm);
|
||||
|
||||
spin_lock(&_dump_buf_lock);
|
||||
if (!_dump_buf_done) {
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9070 BLKGRD: Saving"
|
||||
@ -2870,18 +3074,24 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
|
||||
|
||||
if (lpfc_bgs_get_invalid_prof(bgstat)) {
|
||||
cmd->result = ScsiResult(DID_ERROR, 0);
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9072 BLKGRD: Invalid"
|
||||
" BlockGuard profile. bgstat:0x%x\n",
|
||||
bgstat);
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
|
||||
"9072 BLKGRD: Invalid BG Profile in cmd"
|
||||
" 0x%x lba 0x%llx blk cnt 0x%x "
|
||||
"bgstat=x%x bghm=x%x\n", cmd->cmnd[0],
|
||||
(unsigned long long)scsi_get_lba(cmd),
|
||||
blk_rq_sectors(cmd->request), bgstat, bghm);
|
||||
ret = (-1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lpfc_bgs_get_uninit_dif_block(bgstat)) {
|
||||
cmd->result = ScsiResult(DID_ERROR, 0);
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9073 BLKGRD: "
|
||||
"Invalid BlockGuard DIF Block. bgstat:0x%x\n",
|
||||
bgstat);
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
|
||||
"9073 BLKGRD: Invalid BG PDIF Block in cmd"
|
||||
" 0x%x lba 0x%llx blk cnt 0x%x "
|
||||
"bgstat=x%x bghm=x%x\n", cmd->cmnd[0],
|
||||
(unsigned long long)scsi_get_lba(cmd),
|
||||
blk_rq_sectors(cmd->request), bgstat, bghm);
|
||||
ret = (-1);
|
||||
goto out;
|
||||
}
|
||||
@ -2894,8 +3104,12 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
|
||||
cmd->result = DRIVER_SENSE << 24
|
||||
| ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION);
|
||||
phba->bg_guard_err_cnt++;
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
|
||||
"9055 BLKGRD: guard_tag error\n");
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
|
||||
"9055 BLKGRD: Guard Tag error in cmd"
|
||||
" 0x%x lba 0x%llx blk cnt 0x%x "
|
||||
"bgstat=x%x bghm=x%x\n", cmd->cmnd[0],
|
||||
(unsigned long long)scsi_get_lba(cmd),
|
||||
blk_rq_sectors(cmd->request), bgstat, bghm);
|
||||
}
|
||||
|
||||
if (lpfc_bgs_get_reftag_err(bgstat)) {
|
||||
@ -2907,8 +3121,12 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
|
||||
| ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION);
|
||||
|
||||
phba->bg_reftag_err_cnt++;
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
|
||||
"9056 BLKGRD: ref_tag error\n");
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
|
||||
"9056 BLKGRD: Ref Tag error in cmd"
|
||||
" 0x%x lba 0x%llx blk cnt 0x%x "
|
||||
"bgstat=x%x bghm=x%x\n", cmd->cmnd[0],
|
||||
(unsigned long long)scsi_get_lba(cmd),
|
||||
blk_rq_sectors(cmd->request), bgstat, bghm);
|
||||
}
|
||||
|
||||
if (lpfc_bgs_get_apptag_err(bgstat)) {
|
||||
@ -2920,8 +3138,12 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
|
||||
| ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION);
|
||||
|
||||
phba->bg_apptag_err_cnt++;
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
|
||||
"9061 BLKGRD: app_tag error\n");
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
|
||||
"9061 BLKGRD: App Tag error in cmd"
|
||||
" 0x%x lba 0x%llx blk cnt 0x%x "
|
||||
"bgstat=x%x bghm=x%x\n", cmd->cmnd[0],
|
||||
(unsigned long long)scsi_get_lba(cmd),
|
||||
blk_rq_sectors(cmd->request), bgstat, bghm);
|
||||
}
|
||||
|
||||
if (lpfc_bgs_get_hi_water_mark_present(bgstat)) {
|
||||
@ -2960,11 +3182,16 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd,
|
||||
|
||||
if (!ret) {
|
||||
/* No error was reported - problem in FW? */
|
||||
cmd->result = ScsiResult(DID_ERROR, 0);
|
||||
lpfc_printf_log(phba, KERN_ERR, LOG_BG,
|
||||
"9057 BLKGRD: Unknown error reported!\n");
|
||||
}
|
||||
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG,
|
||||
"9057 BLKGRD: Unknown error in cmd"
|
||||
" 0x%x lba 0x%llx blk cnt 0x%x "
|
||||
"bgstat=x%x bghm=x%x\n", cmd->cmnd[0],
|
||||
(unsigned long long)scsi_get_lba(cmd),
|
||||
blk_rq_sectors(cmd->request), bgstat, bghm);
|
||||
|
||||
/* Calcuate what type of error it was */
|
||||
lpfc_calc_bg_err(phba, lpfc_cmd);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@ -4357,7 +4584,8 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
|
||||
|
||||
if (scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) {
|
||||
if (vport->phba->cfg_enable_bg) {
|
||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_BG,
|
||||
lpfc_printf_vlog(vport,
|
||||
KERN_INFO, LOG_SCSI_CMD,
|
||||
"9033 BLKGRD: rcvd %s cmd:x%x "
|
||||
"sector x%llx cnt %u pt %x\n",
|
||||
dif_op_str[scsi_get_prot_op(cmnd)],
|
||||
@ -4369,7 +4597,8 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
|
||||
err = lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd);
|
||||
} else {
|
||||
if (vport->phba->cfg_enable_bg) {
|
||||
lpfc_printf_vlog(vport, KERN_INFO, LOG_BG,
|
||||
lpfc_printf_vlog(vport,
|
||||
KERN_INFO, LOG_SCSI_CMD,
|
||||
"9038 BLKGRD: rcvd PROT_NORMAL cmd: "
|
||||
"x%x sector x%llx cnt %u pt %x\n",
|
||||
cmnd->cmnd[0],
|
||||
|
Loading…
Reference in New Issue
Block a user