diff options
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/Makefile | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 8 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.c | 80 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 17 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 24 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 8 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 41 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 10 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 488 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.h | 13 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 62 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_version.h | 4 |
13 files changed, 488 insertions, 275 deletions
diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile index 88928f00aa2d..fe5d396aca73 100644 --- a/drivers/scsi/lpfc/Makefile +++ b/drivers/scsi/lpfc/Makefile @@ -1,7 +1,7 @@ #/******************************************************************* # * This file is part of the Emulex Linux Device Driver for * # * 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. * # * www.emulex.com * # * * @@ -22,6 +22,8 @@ ccflags-$(GCOV) := -fprofile-arcs -ftest-coverage ccflags-$(GCOV) += -O0 +ccflags-y += -Werror + obj-$(CONFIG_SCSI_LPFC) := lpfc.o lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o \ diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 5fc044ff656e..3a1ffdd6d831 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * 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. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -840,6 +840,8 @@ struct lpfc_hba { struct dentry *debug_dumpData; /* BlockGuard BPL */ struct dentry *debug_dumpDif; /* BlockGuard BPL */ struct dentry *debug_InjErrLBA; /* LBA to inject errors at */ + struct dentry *debug_InjErrNPortID; /* NPortID to inject errors at */ + struct dentry *debug_InjErrWWPN; /* WWPN to inject errors at */ struct dentry *debug_writeGuard; /* inject write guard_tag errors */ struct dentry *debug_writeApp; /* inject write app_tag errors */ struct dentry *debug_writeRef; /* inject write ref_tag errors */ @@ -854,6 +856,8 @@ struct lpfc_hba { uint32_t lpfc_injerr_rgrd_cnt; uint32_t lpfc_injerr_rapp_cnt; uint32_t lpfc_injerr_rref_cnt; + uint32_t lpfc_injerr_nportid; + struct lpfc_name lpfc_injerr_wwpn; sector_t lpfc_injerr_lba; #define LPFC_INJERR_LBA_OFF (sector_t)(-1) @@ -908,6 +912,8 @@ struct lpfc_hba { atomic_t fast_event_count; uint32_t fcoe_eventtag; uint32_t fcoe_eventtag_at_fcf_scan; + uint32_t fcoe_cvl_eventtag; + uint32_t fcoe_cvl_eventtag_attn; struct lpfc_fcf fcf; uint8_t fc_map[3]; uint8_t valid_vlan; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 296ad5bc4240..5eb2bc116183 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * 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. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -2575,7 +2575,7 @@ LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffffffff, # lpfc_enable_da_id: This turns on the DA_ID CT command that deregisters # objects that have been registered with the nameserver after login. */ -LPFC_VPORT_ATTR_R(enable_da_id, 0, 0, 1, +LPFC_VPORT_ATTR_R(enable_da_id, 1, 0, 1, "Deregister nameserver objects before LOGO"); /* diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 22e17be04d8a..5bdf2eecb178 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2007-2011 Emulex. All rights reserved. * + * Copyright (C) 2007-2012 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -1010,25 +1010,35 @@ lpfc_debugfs_dif_err_read(struct file *file, char __user *buf, { struct dentry *dent = file->f_dentry; struct lpfc_hba *phba = file->private_data; - char cbuf[16]; + char cbuf[32]; + uint64_t tmp = 0; int cnt = 0; if (dent == phba->debug_writeGuard) - cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_wgrd_cnt); + cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wgrd_cnt); else if (dent == phba->debug_writeApp) - cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_wapp_cnt); + cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wapp_cnt); else if (dent == phba->debug_writeRef) - cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_wref_cnt); + cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wref_cnt); else if (dent == phba->debug_readGuard) - cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_rgrd_cnt); + cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rgrd_cnt); else if (dent == phba->debug_readApp) - cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_rapp_cnt); + cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rapp_cnt); else if (dent == phba->debug_readRef) - cnt = snprintf(cbuf, 16, "%u\n", phba->lpfc_injerr_rref_cnt); - else if (dent == phba->debug_InjErrLBA) - cnt = snprintf(cbuf, 16, "0x%lx\n", - (unsigned long) phba->lpfc_injerr_lba); - else + cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt); + else if (dent == phba->debug_InjErrNPortID) + cnt = snprintf(cbuf, 32, "0x%06x\n", phba->lpfc_injerr_nportid); + else if (dent == phba->debug_InjErrWWPN) { + memcpy(&tmp, &phba->lpfc_injerr_wwpn, sizeof(struct lpfc_name)); + tmp = cpu_to_be64(tmp); + cnt = snprintf(cbuf, 32, "0x%016llx\n", tmp); + } else if (dent == phba->debug_InjErrLBA) { + if (phba->lpfc_injerr_lba == (sector_t)(-1)) + cnt = snprintf(cbuf, 32, "off\n"); + else + cnt = snprintf(cbuf, 32, "0x%llx\n", + (uint64_t) phba->lpfc_injerr_lba); + } else lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0547 Unknown debugfs error injection entry\n"); @@ -1042,7 +1052,7 @@ lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf, struct dentry *dent = file->f_dentry; struct lpfc_hba *phba = file->private_data; char dstbuf[32]; - unsigned long tmp; + uint64_t tmp = 0; int size; memset(dstbuf, 0, 32); @@ -1050,7 +1060,12 @@ lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf, if (copy_from_user(dstbuf, buf, size)) return 0; - if (strict_strtoul(dstbuf, 0, &tmp)) + if (dent == phba->debug_InjErrLBA) { + if ((buf[0] == 'o') && (buf[1] == 'f') && (buf[2] == 'f')) + tmp = (uint64_t)(-1); + } + + if ((tmp == 0) && (kstrtoull(dstbuf, 0, &tmp))) return 0; if (dent == phba->debug_writeGuard) @@ -1067,7 +1082,12 @@ lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf, phba->lpfc_injerr_rref_cnt = (uint32_t)tmp; else if (dent == phba->debug_InjErrLBA) phba->lpfc_injerr_lba = (sector_t)tmp; - else + else if (dent == phba->debug_InjErrNPortID) + phba->lpfc_injerr_nportid = (uint32_t)(tmp & Mask_DID); + else if (dent == phba->debug_InjErrWWPN) { + tmp = cpu_to_be64(tmp); + memcpy(&phba->lpfc_injerr_wwpn, &tmp, sizeof(struct lpfc_name)); + } else lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0548 Unknown debugfs error injection entry\n"); @@ -3949,6 +3969,28 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) } phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; + snprintf(name, sizeof(name), "InjErrNPortID"); + phba->debug_InjErrNPortID = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dif_err); + if (!phba->debug_InjErrNPortID) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0809 Cannot create debugfs InjErrNPortID\n"); + goto debug_failed; + } + + snprintf(name, sizeof(name), "InjErrWWPN"); + phba->debug_InjErrWWPN = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dif_err); + if (!phba->debug_InjErrWWPN) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0810 Cannot create debugfs InjErrWWPN\n"); + goto debug_failed; + } + snprintf(name, sizeof(name), "writeGuardInjErr"); phba->debug_writeGuard = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, @@ -4321,6 +4363,14 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) debugfs_remove(phba->debug_InjErrLBA); /* InjErrLBA */ phba->debug_InjErrLBA = NULL; } + if (phba->debug_InjErrNPortID) { /* InjErrNPortID */ + debugfs_remove(phba->debug_InjErrNPortID); + phba->debug_InjErrNPortID = NULL; + } + if (phba->debug_InjErrWWPN) { + debugfs_remove(phba->debug_InjErrWWPN); /* InjErrWWPN */ + phba->debug_InjErrWWPN = NULL; + } if (phba->debug_writeGuard) { debugfs_remove(phba->debug_writeGuard); /* writeGuard */ phba->debug_writeGuard = NULL; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 8db2fb3b45ec..3407b39e0a3f 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * 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. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -925,9 +925,17 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * due to new FCF discovery */ if ((phba->hba_flag & HBA_FIP_SUPPORT) && - (phba->fcf.fcf_flag & FCF_DISCOVERY) && - !((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) { + (phba->fcf.fcf_flag & FCF_DISCOVERY)) { + if (phba->link_state < LPFC_LINK_UP) + goto stop_rr_fcf_flogi; + if ((phba->fcoe_cvl_eventtag_attn == + phba->fcoe_cvl_eventtag) && + (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && + (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED)) + goto stop_rr_fcf_flogi; + else + phba->fcoe_cvl_eventtag_attn = + phba->fcoe_cvl_eventtag; lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS, "2611 FLOGI failed on FCF (x%x), " "status:x%x/x%x, tmo:x%x, perform " @@ -943,6 +951,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; } +stop_rr_fcf_flogi: /* FLOGI failure */ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, "2858 FLOGI failure Status:x%x/x%x TMO:x%x\n", diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 343d87ba4df8..b507536dc5b5 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * 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. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -2843,7 +2843,14 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) struct lpfc_vport *vport = mboxq->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (mboxq->u.mb.mbxStatus) { + /* + * VFI not supported for interface type 0, so ignore any mailbox + * error (except VFI in use) and continue with the discovery. + */ + if (mboxq->u.mb.mbxStatus && + (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != + LPFC_SLI_INTF_IF_TYPE_0) && + mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) { lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, "2018 REG_VFI mbxStatus error x%x " "HBA state x%x\n", @@ -5673,14 +5680,13 @@ lpfc_fcf_inuse(struct lpfc_hba *phba) ret = 1; spin_unlock_irq(shost->host_lock); goto out; - } else { + } else if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { + ret = 1; lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "2624 RPI %x DID %x flg %x still " - "logged in\n", - ndlp->nlp_rpi, ndlp->nlp_DID, - ndlp->nlp_flag); - if (ndlp->nlp_flag & NLP_RPI_REGISTERED) - ret = 1; + "2624 RPI %x DID %x flag %x " + "still logged in\n", + ndlp->nlp_rpi, ndlp->nlp_DID, + ndlp->nlp_flag); } } spin_unlock_irq(shost->host_lock); diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 9e2b9b227e1a..91f09761bd32 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009 Emulex. All rights reserved. * + * Copyright (C) 2009-2012 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -338,6 +338,12 @@ struct lpfc_cqe { #define CQE_CODE_XRI_ABORTED 0x5 #define CQE_CODE_RECEIVE_V1 0x9 +/* + * Define mask value for xri_aborted and wcqe completed CQE extended status. + * Currently, extended status is limited to 9 bits (0x0 -> 0x103) . + */ +#define WCQE_PARAM_MASK 0x1FF; + /* completion queue entry for wqe completions */ struct lpfc_wcqe_complete { uint32_t word0; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b38f99f3be32..9598fdcb08ab 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * 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. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -2704,16 +2704,14 @@ lpfc_offline_prep(struct lpfc_hba * phba) } spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; - + spin_unlock_irq(shost->host_lock); /* * Whenever an SLI4 port goes offline, free the - * RPI. A new RPI when the adapter port comes - * back online. + * RPI. Get a new RPI when the adapter port + * comes back online. */ if (phba->sli_rev == LPFC_SLI_REV4) lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi); - - spin_unlock_irq(shost->host_lock); lpfc_unreg_rpi(vports[i], ndlp); } } @@ -2786,9 +2784,13 @@ lpfc_scsi_buf_update(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); spin_lock(&phba->scsi_buf_list_lock); - list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) + list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) { sb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[sb->cur_iocbq.sli4_lxritag]; + set_bit(sb->cur_iocbq.sli4_lxritag, phba->sli4_hba.xri_bmask); + phba->sli4_hba.max_cfg_param.xri_used++; + phba->sli4_hba.xri_count++; + } spin_unlock(&phba->scsi_buf_list_lock); spin_unlock_irq(&phba->hbalock); return 0; @@ -3723,6 +3725,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, break; case LPFC_FIP_EVENT_TYPE_FCF_DEAD: + phba->fcoe_cvl_eventtag = acqe_fip->event_tag; lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, "2549 FCF (x%x) disconnected from network, " "tag:x%x\n", acqe_fip->index, acqe_fip->event_tag); @@ -3784,6 +3787,7 @@ lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, } break; case LPFC_FIP_EVENT_TYPE_CVL: + phba->fcoe_cvl_eventtag = acqe_fip->event_tag; lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, "2718 Clear Virtual Link Received for VPI 0x%x" " tag 0x%x\n", acqe_fip->index, acqe_fip->event_tag); @@ -5226,8 +5230,7 @@ lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba) * rpi is normalized to a zero base because the physical rpi is * port based. */ - curr_rpi_range = phba->sli4_hba.next_rpi - - phba->sli4_hba.max_cfg_param.rpi_base; + curr_rpi_range = phba->sli4_hba.next_rpi; spin_unlock_irq(&phba->hbalock); /* @@ -5818,10 +5821,9 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) readl(phba->sli4_hba.u.if_type2. ERR2regaddr); lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2888 Port Error Detected " - "during POST: " - "port status reg 0x%x, " - "port_smphr reg 0x%x, " + "2888 Unrecoverable port error " + "following POST: port status reg " + "0x%x, port_smphr reg 0x%x, " "error 1=0x%x, error 2=0x%x\n", reg_data.word0, portsmphr_reg.word0, @@ -6142,7 +6144,6 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) phba->sli4_hba.next_xri = phba->sli4_hba.max_cfg_param.xri_base; phba->vpi_base = phba->sli4_hba.max_cfg_param.vpi_base; phba->vfi_base = phba->sli4_hba.max_cfg_param.vfi_base; - phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.rpi_base; phba->max_vpi = (phba->sli4_hba.max_cfg_param.max_vpi > 0) ? (phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0; phba->max_vports = phba->max_vpi; @@ -7231,6 +7232,7 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) uint32_t rdy_chk, num_resets = 0, reset_again = 0; union lpfc_sli4_cfg_shdr *shdr; struct lpfc_register reg_data; + uint16_t devid; if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); switch (if_type) { @@ -7277,7 +7279,9 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) LPFC_SLIPORT_INIT_PORT); writel(reg_data.word0, phba->sli4_hba.u.if_type2. CTRLregaddr); - + /* flush */ + pci_read_config_word(phba->pcidev, + PCI_DEVICE_ID, &devid); /* * Poll the Port Status Register and wait for RDY for * up to 10 seconds. If the port doesn't respond, treat @@ -7315,11 +7319,10 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) phba->work_status[1] = readl( phba->sli4_hba.u.if_type2.ERR2regaddr); lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2890 Port Error Detected " - "during Port Reset: " - "port status reg 0x%x, " + "2890 Port error detected during port " + "reset(%d): port status reg 0x%x, " "error 1=0x%x, error 2=0x%x\n", - reg_data.word0, + num_resets, reg_data.word0, phba->work_status[0], phba->work_status[1]); rc = -ENODEV; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 7b6b2aa5795a..15ca2a9a0cdd 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -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-2012 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -440,11 +440,15 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_unlock_irq(shost->host_lock); stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD; stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, + rc = lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, mbox); + if (rc) + mempool_free(mbox, phba->mbox_mem_pool); return 1; } - lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox); + rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox); + if (rc) + mempool_free(mbox, phba->mbox_mem_pool); return 1; out: stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index efc055b6bac4..88f3a83dbd2e 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -39,8 +39,8 @@ #include "lpfc_sli4.h" #include "lpfc_nl.h" #include "lpfc_disc.h" -#include "lpfc_scsi.h" #include "lpfc.h" +#include "lpfc_scsi.h" #include "lpfc_logmsg.h" #include "lpfc_crtn.h" #include "lpfc_vport.h" @@ -51,13 +51,19 @@ int _dump_buf_done; static char *dif_op_str[] = { - "SCSI_PROT_NORMAL", - "SCSI_PROT_READ_INSERT", - "SCSI_PROT_WRITE_STRIP", - "SCSI_PROT_READ_STRIP", - "SCSI_PROT_WRITE_INSERT", - "SCSI_PROT_READ_PASS", - "SCSI_PROT_WRITE_PASS", + "PROT_NORMAL", + "PROT_READ_INSERT", + "PROT_WRITE_STRIP", + "PROT_READ_STRIP", + "PROT_WRITE_INSERT", + "PROT_READ_PASS", + "PROT_WRITE_PASS", +}; + +static char *dif_grd_str[] = { + "NO_GUARD", + "DIF_CRC", + "DIX_IP", }; struct scsi_dif_tuple { @@ -1281,10 +1287,14 @@ lpfc_cmd_blksize(struct scsi_cmnd *sc) #ifdef CONFIG_SCSI_LPFC_DEBUG_FS -#define BG_ERR_INIT 1 -#define BG_ERR_TGT 2 -#define BG_ERR_SWAP 3 -#define BG_ERR_CHECK 4 +/* Return if if error injection is detected by Initiator */ +#define BG_ERR_INIT 0x1 +/* Return if if error injection is detected by Target */ +#define BG_ERR_TGT 0x2 +/* Return if if swapping CSUM<-->CRC is required for error injection */ +#define BG_ERR_SWAP 0x10 +/* Return if disabling Guard/Ref/App checking is required for error injection */ +#define BG_ERR_CHECK 0x20 /** * lpfc_bg_err_inject - Determine if we should inject an error @@ -1294,10 +1304,7 @@ lpfc_cmd_blksize(struct scsi_cmnd *sc) * @apptag: (out) BlockGuard application tag for transmitted data * @new_guard (in) Value to replace CRC with if needed * - * 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 + * Returns BG_ERR_* bit mask or 0 if request ignored **/ static int lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, @@ -1305,7 +1312,10 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, { struct scatterlist *sgpe; /* s/g prot entry */ struct scatterlist *sgde; /* s/g data entry */ + struct lpfc_scsi_buf *lpfc_cmd = NULL; struct scsi_dif_tuple *src = NULL; + struct lpfc_nodelist *ndlp; + struct lpfc_rport_data *rdata; uint32_t op = scsi_get_prot_op(sc); uint32_t blksize; uint32_t numblks; @@ -1318,8 +1328,9 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, sgpe = scsi_prot_sglist(sc); sgde = scsi_sglist(sc); - lba = scsi_get_lba(sc); + + /* First check if we need to match the LBA */ if (phba->lpfc_injerr_lba != LPFC_INJERR_LBA_OFF) { blksize = lpfc_cmd_blksize(sc); numblks = (scsi_bufflen(sc) + blksize - 1) / blksize; @@ -1334,66 +1345,123 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, sizeof(struct scsi_dif_tuple); if (numblks < blockoff) blockoff = numblks; - src = (struct scsi_dif_tuple *)sg_virt(sgpe); - src += blockoff; } } + /* Next check if we need to match the remote NPortID or WWPN */ + rdata = sc->device->hostdata; + if (rdata && rdata->pnode) { + ndlp = rdata->pnode; + + /* Make sure we have the right NPortID if one is specified */ + if (phba->lpfc_injerr_nportid && + (phba->lpfc_injerr_nportid != ndlp->nlp_DID)) + return 0; + + /* + * Make sure we have the right WWPN if one is specified. + * wwn[0] should be a non-zero NAA in a good WWPN. + */ + if (phba->lpfc_injerr_wwpn.u.wwn[0] && + (memcmp(&ndlp->nlp_portname, &phba->lpfc_injerr_wwpn, + sizeof(struct lpfc_name)) != 0)) + return 0; + } + + /* Setup a ptr to the protection data if the SCSI host provides it */ + if (sgpe) { + src = (struct scsi_dif_tuple *)sg_virt(sgpe); + src += blockoff; + lpfc_cmd = (struct lpfc_scsi_buf *)sc->host_scribble; + } + /* Should we change the Reference Tag */ if (reftag) { if (phba->lpfc_injerr_wref_cnt) { switch (op) { case SCSI_PROT_WRITE_PASS: - if (blockoff && src) { - /* Insert error in middle of the IO */ + if (src) { + /* + * For WRITE_PASS, force the error + * to be sent on the wire. It should + * be detected by the Target. + * If blockoff != 0 error will be + * inserted in middle of the IO. + */ 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); + be32_to_cpu(src->ref_tag)); /* - * NOTE, this will change ref tag in - * the memory location forever! + * Save the old ref_tag so we can + * restore it on completion. */ - src->ref_tag = 0xDEADBEEF; + if (lpfc_cmd) { + lpfc_cmd->prot_data_type = + LPFC_INJERR_REFTAG; + lpfc_cmd->prot_data_segment = + src; + lpfc_cmd->prot_data = + src->ref_tag; + } + src->ref_tag = cpu_to_be32(0xDEADBEEF); phba->lpfc_injerr_wref_cnt--; - phba->lpfc_injerr_lba = - LPFC_INJERR_LBA_OFF; - rc = BG_ERR_CHECK; + if (phba->lpfc_injerr_wref_cnt == 0) { + phba->lpfc_injerr_nportid = 0; + phba->lpfc_injerr_lba = + LPFC_INJERR_LBA_OFF; + memset(&phba->lpfc_injerr_wwpn, + 0, sizeof(struct lpfc_name)); + } + rc = BG_ERR_TGT | BG_ERR_CHECK; + break; } /* Drop thru */ - case SCSI_PROT_WRITE_STRIP: + case SCSI_PROT_WRITE_INSERT: /* - * For WRITE_STRIP and WRITE_PASS, - * force the error on data - * being copied from SLI-Host to SLI-Port. + * 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 */ *reftag = 0xDEADBEEF; phba->lpfc_injerr_wref_cnt--; - phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; - rc = BG_ERR_INIT; + if (phba->lpfc_injerr_wref_cnt == 0) { + phba->lpfc_injerr_nportid = 0; + phba->lpfc_injerr_lba = + LPFC_INJERR_LBA_OFF; + memset(&phba->lpfc_injerr_wwpn, + 0, sizeof(struct lpfc_name)); + } + rc = BG_ERR_TGT | BG_ERR_CHECK; lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9077 BLKGRD: Injecting reftag error: " + "9078 BLKGRD: Injecting reftag error: " "write lba x%lx\n", (unsigned long)lba); break; - case SCSI_PROT_WRITE_INSERT: + case SCSI_PROT_WRITE_STRIP: /* - * For WRITE_INSERT, force the - * error to be sent on the wire. It should be - * detected by the Target. + * For WRITE_STRIP and WRITE_PASS, + * force the error on data + * being copied from SLI-Host to SLI-Port. */ - /* DEADBEEF will be the reftag on the wire */ *reftag = 0xDEADBEEF; phba->lpfc_injerr_wref_cnt--; - phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; - rc = BG_ERR_TGT; + if (phba->lpfc_injerr_wref_cnt == 0) { + phba->lpfc_injerr_nportid = 0; + phba->lpfc_injerr_lba = + LPFC_INJERR_LBA_OFF; + memset(&phba->lpfc_injerr_wwpn, + 0, sizeof(struct lpfc_name)); + } + rc = BG_ERR_INIT; lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9078 BLKGRD: Injecting reftag error: " + "9077 BLKGRD: Injecting reftag error: " "write lba x%lx\n", (unsigned long)lba); break; } @@ -1401,11 +1469,6 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, 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: /* @@ -1415,7 +1478,13 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, */ *reftag = 0xDEADBEEF; phba->lpfc_injerr_rref_cnt--; - phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; + if (phba->lpfc_injerr_rref_cnt == 0) { + phba->lpfc_injerr_nportid = 0; + phba->lpfc_injerr_lba = + LPFC_INJERR_LBA_OFF; + memset(&phba->lpfc_injerr_wwpn, + 0, sizeof(struct lpfc_name)); + } rc = BG_ERR_INIT; lpfc_printf_log(phba, KERN_ERR, LOG_BG, @@ -1431,56 +1500,87 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, if (phba->lpfc_injerr_wapp_cnt) { switch (op) { case SCSI_PROT_WRITE_PASS: - if (blockoff && src) { - /* Insert error in middle of the IO */ + if (src) { + /* + * For WRITE_PASS, force the error + * to be sent on the wire. It should + * be detected by the Target. + * If blockoff != 0 error will be + * inserted in middle of the IO. + */ 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); + be16_to_cpu(src->app_tag)); /* - * NOTE, this will change app tag in - * the memory location forever! + * Save the old app_tag so we can + * restore it on completion. */ - src->app_tag = 0xDEAD; + if (lpfc_cmd) { + lpfc_cmd->prot_data_type = + LPFC_INJERR_APPTAG; + lpfc_cmd->prot_data_segment = + src; + lpfc_cmd->prot_data = + src->app_tag; + } + src->app_tag = cpu_to_be16(0xDEAD); phba->lpfc_injerr_wapp_cnt--; - phba->lpfc_injerr_lba = - LPFC_INJERR_LBA_OFF; - rc = BG_ERR_CHECK; + if (phba->lpfc_injerr_wapp_cnt == 0) { + phba->lpfc_injerr_nportid = 0; + phba->lpfc_injerr_lba = + LPFC_INJERR_LBA_OFF; + memset(&phba->lpfc_injerr_wwpn, + 0, sizeof(struct lpfc_name)); + } + rc = BG_ERR_TGT | BG_ERR_CHECK; break; } /* Drop thru */ - case SCSI_PROT_WRITE_STRIP: + case SCSI_PROT_WRITE_INSERT: /* - * For WRITE_STRIP and WRITE_PASS, - * force the error on data - * being copied from SLI-Host to SLI-Port. + * 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 */ *apptag = 0xDEAD; phba->lpfc_injerr_wapp_cnt--; - phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; - rc = BG_ERR_INIT; + if (phba->lpfc_injerr_wapp_cnt == 0) { + phba->lpfc_injerr_nportid = 0; + phba->lpfc_injerr_lba = + LPFC_INJERR_LBA_OFF; + memset(&phba->lpfc_injerr_wwpn, + 0, sizeof(struct lpfc_name)); + } + rc = BG_ERR_TGT | BG_ERR_CHECK; lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "0812 BLKGRD: Injecting apptag error: " + "0813 BLKGRD: Injecting apptag error: " "write lba x%lx\n", (unsigned long)lba); break; - case SCSI_PROT_WRITE_INSERT: + case SCSI_PROT_WRITE_STRIP: /* - * For WRITE_INSERT, force the - * error to be sent on the wire. It should be - * detected by the Target. + * For WRITE_STRIP and WRITE_PASS, + * force the error on data + * being copied from SLI-Host to SLI-Port. */ - /* DEAD will be the apptag on the wire */ *apptag = 0xDEAD; phba->lpfc_injerr_wapp_cnt--; - phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; - rc = BG_ERR_TGT; + if (phba->lpfc_injerr_wapp_cnt == 0) { + phba->lpfc_injerr_nportid = 0; + phba->lpfc_injerr_lba = + LPFC_INJERR_LBA_OFF; + memset(&phba->lpfc_injerr_wwpn, + 0, sizeof(struct lpfc_name)); + } + rc = BG_ERR_INIT; lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "0813 BLKGRD: Injecting apptag error: " + "0812 BLKGRD: Injecting apptag error: " "write lba x%lx\n", (unsigned long)lba); break; } @@ -1488,11 +1588,6 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, 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: /* @@ -1502,7 +1597,13 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, */ *apptag = 0xDEAD; phba->lpfc_injerr_rapp_cnt--; - phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; + if (phba->lpfc_injerr_rapp_cnt == 0) { + phba->lpfc_injerr_nportid = 0; + phba->lpfc_injerr_lba = + LPFC_INJERR_LBA_OFF; + memset(&phba->lpfc_injerr_wwpn, + 0, sizeof(struct lpfc_name)); + } rc = BG_ERR_INIT; lpfc_printf_log(phba, KERN_ERR, LOG_BG, @@ -1519,57 +1620,51 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, 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); - - /* - * NOTE, this will change guard tag in - * the memory location forever! - */ - src->guard_tag = 0xDEAD; - phba->lpfc_injerr_wgrd_cnt--; - phba->lpfc_injerr_lba = - LPFC_INJERR_LBA_OFF; - rc = BG_ERR_CHECK; - break; - } + rc = BG_ERR_CHECK; /* Drop thru */ - case SCSI_PROT_WRITE_STRIP: + + case SCSI_PROT_WRITE_INSERT: /* - * For WRITE_STRIP and WRITE_PASS, - * force the error on data - * being copied from SLI-Host to SLI-Port. + * For WRITE_INSERT, force the + * error to be sent on the wire. It should be + * detected by the Target. */ phba->lpfc_injerr_wgrd_cnt--; - phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; + if (phba->lpfc_injerr_wgrd_cnt == 0) { + phba->lpfc_injerr_nportid = 0; + phba->lpfc_injerr_lba = + LPFC_INJERR_LBA_OFF; + memset(&phba->lpfc_injerr_wwpn, + 0, sizeof(struct lpfc_name)); + } - rc = BG_ERR_SWAP; + rc |= BG_ERR_TGT | BG_ERR_SWAP; /* Signals the caller to swap CRC->CSUM */ lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "0816 BLKGRD: Injecting guard error: " + "0817 BLKGRD: Injecting guard error: " "write lba x%lx\n", (unsigned long)lba); break; - case SCSI_PROT_WRITE_INSERT: + case SCSI_PROT_WRITE_STRIP: /* - * For WRITE_INSERT, force the - * error to be sent on the wire. It should be - * detected by the Target. + * For WRITE_STRIP and WRITE_PASS, + * force the error on data + * being copied from SLI-Host to SLI-Port. */ phba->lpfc_injerr_wgrd_cnt--; - phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; + if (phba->lpfc_injerr_wgrd_cnt == 0) { + phba->lpfc_injerr_nportid = 0; + phba->lpfc_injerr_lba = + LPFC_INJERR_LBA_OFF; + memset(&phba->lpfc_injerr_wwpn, + 0, sizeof(struct lpfc_name)); + } - rc = BG_ERR_SWAP; + rc = BG_ERR_INIT | BG_ERR_SWAP; /* Signals the caller to swap CRC->CSUM */ lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "0817 BLKGRD: Injecting guard error: " + "0816 BLKGRD: Injecting guard error: " "write lba x%lx\n", (unsigned long)lba); break; } @@ -1577,11 +1672,6 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, 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: /* @@ -1589,11 +1679,16 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, * 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; + if (phba->lpfc_injerr_rgrd_cnt == 0) { + phba->lpfc_injerr_nportid = 0; + phba->lpfc_injerr_lba = + LPFC_INJERR_LBA_OFF; + memset(&phba->lpfc_injerr_wwpn, + 0, sizeof(struct lpfc_name)); + } - rc = BG_ERR_SWAP; + rc = BG_ERR_INIT | BG_ERR_SWAP; /* Signals the caller to swap CRC->CSUM */ lpfc_printf_log(phba, KERN_ERR, LOG_BG, @@ -1629,20 +1724,20 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, switch (scsi_get_prot_op(sc)) { case SCSI_PROT_READ_INSERT: case SCSI_PROT_WRITE_STRIP: - *txop = BG_OP_IN_CSUM_OUT_NODIF; *rxop = BG_OP_IN_NODIF_OUT_CSUM; + *txop = BG_OP_IN_CSUM_OUT_NODIF; break; case SCSI_PROT_READ_STRIP: case SCSI_PROT_WRITE_INSERT: - *txop = BG_OP_IN_NODIF_OUT_CRC; *rxop = BG_OP_IN_CRC_OUT_NODIF; + *txop = BG_OP_IN_NODIF_OUT_CRC; 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; + *txop = BG_OP_IN_CSUM_OUT_CRC; break; case SCSI_PROT_NORMAL: @@ -1658,20 +1753,20 @@ lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, switch (scsi_get_prot_op(sc)) { case SCSI_PROT_READ_STRIP: case SCSI_PROT_WRITE_INSERT: - *txop = BG_OP_IN_NODIF_OUT_CRC; *rxop = BG_OP_IN_CRC_OUT_NODIF; + *txop = BG_OP_IN_NODIF_OUT_CRC; 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; + *txop = BG_OP_IN_CRC_OUT_CRC; break; case SCSI_PROT_READ_INSERT: case SCSI_PROT_WRITE_STRIP: - *txop = BG_OP_IN_CRC_OUT_NODIF; *rxop = BG_OP_IN_NODIF_OUT_CRC; + *txop = BG_OP_IN_CRC_OUT_NODIF; break; case SCSI_PROT_NORMAL: @@ -1710,20 +1805,20 @@ lpfc_bg_err_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, 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; + *txop = BG_OP_IN_CRC_OUT_NODIF; 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; + *txop = BG_OP_IN_NODIF_OUT_CSUM; 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; + *rxop = BG_OP_IN_CSUM_OUT_CRC; + *txop = BG_OP_IN_CRC_OUT_CSUM; break; case SCSI_PROT_NORMAL: @@ -1735,20 +1830,20 @@ lpfc_bg_err_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, 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; + *txop = BG_OP_IN_NODIF_OUT_CSUM; 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; + *rxop = BG_OP_IN_CSUM_OUT_CSUM; + *txop = BG_OP_IN_CSUM_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; + *txop = BG_OP_IN_CSUM_OUT_NODIF; break; case SCSI_PROT_NORMAL: @@ -1817,11 +1912,11 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *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); + rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); if (rc) { - if (rc == BG_ERR_SWAP) + if (rc & BG_ERR_SWAP) lpfc_bg_err_opcodes(phba, sc, &txop, &rxop); - if (rc == BG_ERR_CHECK) + if (rc & BG_ERR_CHECK) checking = 0; } #endif @@ -1964,11 +2059,11 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *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); + rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); if (rc) { - if (rc == BG_ERR_SWAP) + if (rc & BG_ERR_SWAP) lpfc_bg_err_opcodes(phba, sc, &txop, &rxop); - if (rc == BG_ERR_CHECK) + if (rc & BG_ERR_CHECK) checking = 0; } #endif @@ -2172,11 +2267,11 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *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); + rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); if (rc) { - if (rc == BG_ERR_SWAP) + if (rc & BG_ERR_SWAP) lpfc_bg_err_opcodes(phba, sc, &txop, &rxop); - if (rc == BG_ERR_CHECK) + if (rc & BG_ERR_CHECK) checking = 0; } #endif @@ -2312,11 +2407,11 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *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); + rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); if (rc) { - if (rc == BG_ERR_SWAP) + if (rc & BG_ERR_SWAP) lpfc_bg_err_opcodes(phba, sc, &txop, &rxop); - if (rc == BG_ERR_CHECK) + if (rc & BG_ERR_CHECK) checking = 0; } #endif @@ -2788,7 +2883,7 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, /* No error was reported - problem in FW? */ cmd->result = ScsiResult(DID_ERROR, 0); lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9057 BLKGRD: no errors reported!\n"); + "9057 BLKGRD: Unknown error reported!\n"); } out: @@ -3460,6 +3555,37 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, /* pick up SLI4 exhange busy status from HBA */ lpfc_cmd->exch_busy = pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (lpfc_cmd->prot_data_type) { + struct scsi_dif_tuple *src = NULL; + + src = (struct scsi_dif_tuple *)lpfc_cmd->prot_data_segment; + /* + * Used to restore any changes to protection + * data for error injection. + */ + switch (lpfc_cmd->prot_data_type) { + case LPFC_INJERR_REFTAG: + src->ref_tag = + lpfc_cmd->prot_data; + break; + case LPFC_INJERR_APPTAG: + src->app_tag = + (uint16_t)lpfc_cmd->prot_data; + break; + case LPFC_INJERR_GUARD: + src->guard_tag = + (uint16_t)lpfc_cmd->prot_data; + break; + default: + break; + } + + lpfc_cmd->prot_data = 0; + lpfc_cmd->prot_data_type = 0; + lpfc_cmd->prot_data_segment = NULL; + } +#endif if (pnode && NLP_CHK_NODE_ACT(pnode)) atomic_dec(&pnode->cmd_pending); @@ -4061,15 +4187,6 @@ lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) cmnd->result = err; goto out_fail_command; } - /* - * Do not let the mid-layer retry I/O too fast. If an I/O is retried - * without waiting a bit then indicate that the device is busy. - */ - if (cmnd->retries && - time_before(jiffies, (cmnd->jiffies_at_alloc + - msecs_to_jiffies(LPFC_RETRY_PAUSE * - cmnd->retries)))) - return SCSI_MLQUEUE_DEVICE_BUSY; ndlp = rdata->pnode; if ((scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) && @@ -4119,63 +4236,48 @@ lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) if (scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) { if (vport->phba->cfg_enable_bg) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9033 BLKGRD: rcvd protected cmd:%02x op:%02x " - "str=%s\n", - cmnd->cmnd[0], scsi_get_prot_op(cmnd), - dif_op_str[scsi_get_prot_op(cmnd)]); - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9034 BLKGRD: CDB: %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x\n", - cmnd->cmnd[0], cmnd->cmnd[1], cmnd->cmnd[2], - cmnd->cmnd[3], cmnd->cmnd[4], cmnd->cmnd[5], - cmnd->cmnd[6], cmnd->cmnd[7], cmnd->cmnd[8], - cmnd->cmnd[9]); + "9033 BLKGRD: rcvd protected cmd:%02x op=%s " + "guard=%s\n", cmnd->cmnd[0], + dif_op_str[scsi_get_prot_op(cmnd)], + dif_grd_str[scsi_host_get_guard(shost)]); if (cmnd->cmnd[0] == READ_10) lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9035 BLKGRD: READ @ sector %llu, " - "count %u\n", + "cnt %u, rpt %d\n", (unsigned long long)scsi_get_lba(cmnd), - blk_rq_sectors(cmnd->request)); + blk_rq_sectors(cmnd->request), + (cmnd->cmnd[1]>>5)); else if (cmnd->cmnd[0] == WRITE_10) lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9036 BLKGRD: WRITE @ sector %llu, " - "count %u cmd=%p\n", + "cnt %u, wpt %d\n", (unsigned long long)scsi_get_lba(cmnd), blk_rq_sectors(cmnd->request), - cmnd); + (cmnd->cmnd[1]>>5)); } err = lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd); } else { if (vport->phba->cfg_enable_bg) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9038 BLKGRD: rcvd unprotected cmd:" - "%02x op:%02x str=%s\n", - cmnd->cmnd[0], scsi_get_prot_op(cmnd), - dif_op_str[scsi_get_prot_op(cmnd)]); - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9039 BLKGRD: CDB: %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x\n", - cmnd->cmnd[0], cmnd->cmnd[1], - cmnd->cmnd[2], cmnd->cmnd[3], - cmnd->cmnd[4], cmnd->cmnd[5], - cmnd->cmnd[6], cmnd->cmnd[7], - cmnd->cmnd[8], cmnd->cmnd[9]); + "9038 BLKGRD: rcvd unprotected cmd:" + "%02x op=%s guard=%s\n", cmnd->cmnd[0], + dif_op_str[scsi_get_prot_op(cmnd)], + dif_grd_str[scsi_host_get_guard(shost)]); if (cmnd->cmnd[0] == READ_10) lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9040 dbg: READ @ sector %llu, " - "count %u\n", + "cnt %u, rpt %d\n", (unsigned long long)scsi_get_lba(cmnd), - blk_rq_sectors(cmnd->request)); + blk_rq_sectors(cmnd->request), + (cmnd->cmnd[1]>>5)); else if (cmnd->cmnd[0] == WRITE_10) lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9041 dbg: WRITE @ sector %llu, " - "count %u cmd=%p\n", - (unsigned long long)scsi_get_lba(cmnd), - blk_rq_sectors(cmnd->request), cmnd); - else - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9042 dbg: parser not implemented\n"); + "9041 dbg: WRITE @ sector %llu, " + "cnt %u, wpt %d\n", + (unsigned long long)scsi_get_lba(cmnd), + blk_rq_sectors(cmnd->request), + (cmnd->cmnd[1]>>5)); } err = lpfc_scsi_prep_dma_buf(phba, lpfc_cmd); } diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 9075a08cf781..21a2ffe67eac 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2012 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -150,9 +150,18 @@ struct lpfc_scsi_buf { struct lpfc_iocbq cur_iocbq; wait_queue_head_t *waitq; unsigned long start_time; + +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + /* Used to restore any changes to protection data for error injection */ + void *prot_data_segment; + uint32_t prot_data; + uint32_t prot_data_type; +#define LPFC_INJERR_REFTAG 1 +#define LPFC_INJERR_APPTAG 2 +#define LPFC_INJERR_GUARD 3 +#endif }; #define LPFC_SCSI_DMA_EXT_SIZE 264 #define LPFC_BPL_SIZE 1024 -#define LPFC_RETRY_PAUSE 300 #define MDAC_DIRECT_CMD 0x22 diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index e0e4d8d18244..dbaf5b963bff 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * 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. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -5578,8 +5578,6 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) for (i = 0; i < count; i++) phba->sli4_hba.rpi_ids[i] = base + i; - lpfc_sli4_node_prep(phba); - /* VPIs. */ count = phba->sli4_hba.max_cfg_param.max_vpi; base = phba->sli4_hba.max_cfg_param.vpi_base; @@ -5613,6 +5611,8 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) rc = -ENOMEM; goto free_vpi_ids; } + phba->sli4_hba.max_cfg_param.xri_used = 0; + phba->sli4_hba.xri_count = 0; phba->sli4_hba.xri_ids = kzalloc(count * sizeof(uint16_t), GFP_KERNEL); @@ -6147,6 +6147,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = -ENODEV; goto out_free_mbox; } + lpfc_sli4_node_prep(phba); /* Create all the SLI4 queues */ rc = lpfc_sli4_queue_create(phba); @@ -7251,11 +7252,13 @@ lpfc_sli4_post_async_mbox(struct lpfc_hba *phba) out_not_finished: spin_lock_irqsave(&phba->hbalock, iflags); - mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED; - __lpfc_mbox_cmpl_put(phba, mboxq); - /* Release the token */ - psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - phba->sli.mbox_active = NULL; + if (phba->sli.mbox_active) { + mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED; + __lpfc_mbox_cmpl_put(phba, mboxq); + /* Release the token */ + psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + phba->sli.mbox_active = NULL; + } spin_unlock_irqrestore(&phba->hbalock, iflags); return MBX_NOT_FINISHED; @@ -7743,6 +7746,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, if (pcmd && (*pcmd == ELS_CMD_FLOGI || *pcmd == ELS_CMD_SCR || *pcmd == ELS_CMD_FDISC || + *pcmd == ELS_CMD_LOGO || *pcmd == ELS_CMD_PLOGI)) { bf_set(els_req64_sp, &wqe->els_req, 1); bf_set(els_req64_sid, &wqe->els_req, @@ -8385,6 +8389,7 @@ lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, struct sli4_wcqe_xri_aborted *axri) { struct lpfc_vport *vport; + uint32_t ext_status = 0; if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, @@ -8396,12 +8401,20 @@ lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, vport = ndlp->vport; lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "3116 Port generated FCP XRI ABORT event on " - "vpi %d rpi %d xri x%x status 0x%x\n", + "vpi %d rpi %d xri x%x status 0x%x parameter x%x\n", ndlp->vport->vpi, ndlp->nlp_rpi, bf_get(lpfc_wcqe_xa_xri, axri), - bf_get(lpfc_wcqe_xa_status, axri)); + bf_get(lpfc_wcqe_xa_status, axri), + axri->parameter); - if (bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) + /* + * Catch the ABTS protocol failure case. Older OCe FW releases returned + * LOCAL_REJECT and 0 for a failed ABTS exchange and later OCe and + * LPe FW releases returned LOCAL_REJECT and SEQUENCE_TIMEOUT. + */ + ext_status = axri->parameter & WCQE_PARAM_MASK; + if ((bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) && + ((ext_status == IOERR_SEQUENCE_TIMEOUT) || (ext_status == 0))) lpfc_sli_abts_recover_port(vport, ndlp); } @@ -9807,12 +9820,11 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba) unsigned long timeout; timeout = msecs_to_jiffies(LPFC_MBOX_TMO * 1000) + jiffies; + spin_lock_irq(&phba->hbalock); psli->sli_flag |= LPFC_SLI_ASYNC_MBX_BLK; - spin_unlock_irq(&phba->hbalock); if (psli->sli_flag & LPFC_SLI_ACTIVE) { - spin_lock_irq(&phba->hbalock); /* Determine how long we might wait for the active mailbox * command to be gracefully completed by firmware. */ @@ -9831,7 +9843,9 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba) */ break; } - } + } else + spin_unlock_irq(&phba->hbalock); + lpfc_sli_mbox_sys_flush(phba); } @@ -13272,7 +13286,7 @@ lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba) LPFC_MBOXQ_t *mbox; uint32_t reqlen, alloclen, index; uint32_t mbox_tmo; - uint16_t rsrc_start, rsrc_size, els_xri_cnt; + uint16_t rsrc_start, rsrc_size, els_xri_cnt, post_els_xri_cnt; uint16_t xritag_start = 0, lxri = 0; struct lpfc_rsrc_blks *rsrc_blk; int cnt, ttl_cnt, rc = 0; @@ -13294,6 +13308,7 @@ lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba) cnt = 0; ttl_cnt = 0; + post_els_xri_cnt = els_xri_cnt; list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list, list) { rsrc_start = rsrc_blk->rsrc_start; @@ -13303,11 +13318,12 @@ lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba) "3014 Working ELS Extent start %d, cnt %d\n", rsrc_start, rsrc_size); - loop_cnt = min(els_xri_cnt, rsrc_size); - if (ttl_cnt + loop_cnt >= els_xri_cnt) { - loop_cnt = els_xri_cnt - ttl_cnt; - ttl_cnt = els_xri_cnt; - } + loop_cnt = min(post_els_xri_cnt, rsrc_size); + if (loop_cnt < post_els_xri_cnt) { + post_els_xri_cnt -= loop_cnt; + ttl_cnt += loop_cnt; + } else + ttl_cnt += post_els_xri_cnt; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) @@ -14203,15 +14219,14 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, * field and RX_ID from ABTS for RX_ID field. */ bf_set(lpfc_abts_orig, &icmd->un.bls_rsp, LPFC_ABTS_UNSOL_RSP); - bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, rxid); } else { /* ABTS sent by initiator to CT exchange, construction * of BA_ACC will need to allocate a new XRI as for the - * XRI_TAG and RX_ID fields. + * XRI_TAG field. */ bf_set(lpfc_abts_orig, &icmd->un.bls_rsp, LPFC_ABTS_UNSOL_INT); - bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, NO_XRI); } + bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, rxid); bf_set(lpfc_abts_oxid, &icmd->un.bls_rsp, oxid); /* Xmit CT abts response on exchange <xid> */ @@ -15042,6 +15057,7 @@ lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index) LPFC_MBOXQ_t *mboxq; phba->fcoe_eventtag_at_fcf_scan = phba->fcoe_eventtag; + phba->fcoe_cvl_eventtag_attn = phba->fcoe_cvl_eventtag; mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index f2a2602e5c35..25cefc254b76 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * 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. * * www.emulex.com * * * @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.29" +#define LPFC_DRIVER_VERSION "8.3.30" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" |