From: Rob Evers <revers@redhat.com> Date: Tue, 7 Apr 2009 15:24:32 -0400 Subject: [scsi] lpfc: update to version 8.2.0.40 Message-id: 20090407192200.14572.14086.sendpatchset@localhost.localdomain O-Subject: [RHEL5.4 PATCH V3 3/4] Update lpfc to version 8.2.0.40 Bugzilla: 476738 https://bugzilla.redhat.com/show_bug.cgi?id=476738 Update lpfc from 8.2.0.39 to 8.2.0.40 -- diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 75262ab..ee5ac6a 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -56,6 +56,9 @@ struct lpfc_sli2_slim; #define LPFC_HB_MBOX_INTERVAL 5 /* Heart beat interval in seconds. */ #define LPFC_HB_MBOX_TIMEOUT 30 /* Heart beat timeout in seconds. */ +/* Error Attention event polling interval */ +#define LPFC_ERATT_POLL_INTERVAL 5 /* EATT poll interval in seconds */ + /* Define macros for 64 bit support */ #define putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr))) #define putPaddrHigh(addr) ((uint32_t) (0xffffffff & (((u64)(addr))>>32))) @@ -570,6 +573,10 @@ struct lpfc_hba { #define LS_NPIV_FAB_SUPPORTED 0x2 /* Fabric supports NPIV */ #define LS_IGNORE_ERATT 0x4 /* intr handler should ignore ERATT */ + uint32_t hba_flag; /* hba generic flags */ +#define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */ +#define DEFER_ERATT 0x80 /* Deferred error attention in progress */ + struct lpfc_sli2_slim *slim2p; struct lpfc_dmabuf hbqslimp; @@ -687,6 +694,7 @@ struct lpfc_hba { uint8_t soft_wwn_enable; struct timer_list fcp_poll_timer; + struct timer_list eratt_poll; /* Error attention polling timer.*/ /* * stat counters @@ -818,3 +826,24 @@ lpfc_worker_wake_up(struct lpfc_hba *phba) return; } +static inline void +lpfc_sli_read_hs(struct lpfc_hba *phba) +{ + /* + * There was a link/board error. Read the status register to retrieve + * the error event and process it. + */ + phba->sli.slistat.err_attn_event++; + + /* Save status info */ + phba->work_hs = readl(phba->HSregaddr); + phba->work_status[0] = readl(phba->MBslimaddr + 0xa8); + phba->work_status[1] = readl(phba->MBslimaddr + 0xac); + + /* Clear chip Host Attention error bit */ + writel(HA_ERATT, phba->HAregaddr); + readl(phba->HAregaddr); /* flush */ + phba->pport->stopped = 1; + + return; +} diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index e70c034..2f6b285 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1893,7 +1893,7 @@ lpfc_stat_data_ctrl_store(struct class_device *cdev, const char *buf, unsigned long base, step, bucket_type; if (!strncmp(buf, "setbucket", strlen("setbucket"))) { - if (strlen(buf) > LPFC_MAX_DATA_CTRL_LEN) + if (strlen(buf) > (LPFC_MAX_DATA_CTRL_LEN - 1)) return -EINVAL; strcpy(bucket_data,buf); diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 198707c..81c0949 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -201,7 +201,7 @@ void lpfc_els_hbq_free(struct lpfc_hba *, struct hbq_dmabuf *); int lpfc_mem_alloc(struct lpfc_hba *); void lpfc_mem_free(struct lpfc_hba *); void lpfc_stop_vport_timers(struct lpfc_vport *); - +void lpfc_poll_eratt(unsigned long); void lpfc_poll_timeout(unsigned long ptr); void lpfc_poll_start_timer(struct lpfc_hba * phba); void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index a4521d2..694e415 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -2318,9 +2318,13 @@ lpfc_unreg_all_rpis(struct lpfc_vport *vport) mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mbox->context1 = NULL; rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); - if (rc == MBX_NOT_FINISHED) { + if (rc != MBX_TIMEOUT) mempool_free(mbox, phba->mbox_mem_pool); - } + + if ((rc == MBX_TIMEOUT) || (rc == MBX_NOT_FINISHED)) + lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, + "1836 Could not issue " + "unreg_login(all_rpis) status %d\n", rc); } } @@ -2338,12 +2342,14 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport) mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mbox->context1 = NULL; rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); - if (rc == MBX_NOT_FINISHED) { + if (rc != MBX_TIMEOUT) + mempool_free(mbox, phba->mbox_mem_pool); + + if ((rc == MBX_TIMEOUT) || (rc == MBX_NOT_FINISHED)) lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, "1815 Could not issue " - "unreg_did (default rpis)\n"); - mempool_free(mbox, phba->mbox_mem_pool); - } + "unreg_did (default rpis) status %d\n", + rc); } } diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index ef0e329..a507695 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -463,6 +463,9 @@ lpfc_config_port_post(struct lpfc_hba *phba) if (phba->sli_rev != 3) lpfc_post_rcv_buf(phba); + /* Initialize ERATT handling flag */ + phba->hba_flag &= ~HBA_ERATT_HANDLED; + /* Enable appropriate host interrupts */ spin_lock_irq(&phba->hbalock); status = readl(phba->HCregaddr); @@ -505,6 +508,9 @@ lpfc_config_port_post(struct lpfc_hba *phba) } } + /* Set up error attention (ERATT) polling timer */ + mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); + lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; lpfc_set_loopback_flag(phba); @@ -816,6 +822,63 @@ lpfc_offline_eratt(struct lpfc_hba *phba) return; } +static void +lpfc_handle_deferred_eratt(struct lpfc_hba *phba) +{ + uint32_t old_host_status = phba->work_hs; + struct lpfc_sli_ring *pring; + struct lpfc_sli *psli = &phba->sli; + + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0473 Deferred Adapter Hardware Error " + "Data: x%x x%x x%x\n", + phba->work_hs, + phba->work_status[0], phba->work_status[1]); + + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + spin_unlock_irq(&phba->hbalock); + + + /* + * Firmware stops when it triggred erratt. That could cause the I/Os + * dropped by the firmware. Error iocb (I/O) on txcmplq and let the + * SCSI layer retry it after re-establishing link. + */ + pring = &psli->ring[psli->fcp_ring]; + lpfc_sli_abort_iocb_ring(phba, pring); + + /* + * There was a firmware error. Take the hba offline and then + * attempt to restart it. + */ + lpfc_offline_prep(phba); + lpfc_offline(phba); + + /* Wait for the ER1 bit to clear.*/ + while (phba->work_hs & HS_FFER1) { + msleep(100); + phba->work_hs = readl(phba->HSregaddr); + /* If driver is unloading let the worker thread continue */ + if (phba->pport->load_flag & FC_UNLOADING) { + phba->work_hs = 0; + break; + } + } + + /* + * This is to ptrotect against a race condition in which + * first write to the host attention register clear the + * host status register. + */ + if ((!phba->work_hs) && (!(phba->pport->load_flag & FC_UNLOADING))) + phba->work_hs = old_host_status & ~HS_FFER1; + + phba->hba_flag &= ~DEFER_ERATT; + phba->work_status[0] = readl(phba->MBslimaddr + 0xa8); + phba->work_status[1] = readl(phba->MBslimaddr + 0xac); +} + /************************************************************************/ /* */ /* lpfc_handle_eratt */ @@ -854,6 +917,9 @@ lpfc_handle_eratt(struct lpfc_hba *phba) (char *) &board_event, LPFC_NL_VENDOR_ID); + if (phba->hba_flag & DEFER_ERATT) + lpfc_handle_deferred_eratt(phba); + if (phba->work_hs & HS_FFER6) { /* Re-establishing Link */ lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, @@ -1260,7 +1326,8 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) m = (typeof(m)){"LPe11000", max_speed, "PCIe"}; break; case PCI_DEVICE_ID_ZEPHYR_DCSP: - m = (typeof(m)){"LPe11002-SP", max_speed, "PCIe"}; + m = (typeof(m)){"LP2105", max_speed, "PCIe"}; + GE = 1; break; case PCI_DEVICE_ID_ZMID: m = (typeof(m)){"LPe1150", max_speed, "PCIe"}; @@ -1658,6 +1725,7 @@ lpfc_stop_phba_timers(struct lpfc_hba *phba) del_timer_sync(&phba->fabric_block_timer); phba->hb_outstanding = 0; del_timer_sync(&phba->hb_tmofunc); + del_timer_sync(&phba->eratt_poll); return; } @@ -2200,6 +2268,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) init_timer(&phba->fabric_block_timer); phba->fabric_block_timer.function = lpfc_fabric_block_timeout; phba->fabric_block_timer.data = (unsigned long) phba; + /* EA polling mode timer */ + init_timer(&phba->eratt_poll); + phba->eratt_poll.function = lpfc_poll_eratt; + phba->eratt_poll.data = (unsigned long) phba; + pci_set_master(pdev); retval = pci_set_mwi(pdev); diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 8f548ad..3016c8d 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -493,6 +493,7 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_iocbq *cmdiocb, uint32_t els_cmd) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct ls_rjt stat; /* Put ndlp in NPR state with 1 sec timeout for plogi, ACC logo */ /* Only call LOGO ACC for first LOGO, this avoids sending unnecessary @@ -503,8 +504,24 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_unlock_irq(shost->host_lock); if (els_cmd == ELS_CMD_PRLO) lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); - else - lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); + else { + /* + * Send a reject for a LOGO from a Fabric Nport. This + * will cause a link bounce and force re-discovery of + * the targets. + */ + if ((ndlp->nlp_type & NLP_FABRIC) && + (ndlp->nlp_DID == Fabric_DID)) { + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; + stat.un.b.vendorUnique = 0; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, + ndlp, NULL); + } else + lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, + ndlp, NULL); + } if ((!(ndlp->nlp_type & NLP_FABRIC) && ((ndlp->nlp_type & NLP_FCP_TARGET) || @@ -658,11 +675,27 @@ lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; + struct ls_rjt stat; spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_LOGO_ACC; spin_unlock_irq(shost->host_lock); - lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); + + /* + * Send a reject for a LOGO from a Fabric Nport. This + * will cause a link bounce and force re-discovery of + * the targets. + */ + if ((ndlp->nlp_type & NLP_FABRIC) && + (ndlp->nlp_DID == Fabric_DID)) { + stat.un.b.lsRjtRsvd0 = 0; + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; + stat.un.b.vendorUnique = 0; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, + ndlp, NULL); + } else + lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); return ndlp->nlp_state; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index eeeb142..546db87 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1288,6 +1288,107 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) return; } +/** + * lpfc_sli_check_eratt - check error attention events + * @phba: Pointer to HBA context. + * + * This function is called form timer soft interrupt context to check HBA's + * error attention register bit for error attention events. + * + * This fucntion returns 1 when there is Error Attention in the Host Attention + * Register and returns 0 otherwise. + **/ +int +lpfc_sli_check_eratt(struct lpfc_hba *phba) +{ + uint32_t ha_copy; + + /* If PCI channel is offline, don't process it */ + if (unlikely(phba->pcidev->error_state != pci_channel_io_normal)) + return 0; + + /* If somebody is waiting to handle an eratt, don't process it + * here. The brdkill function will do this. + */ + if (phba->link_flag & LS_IGNORE_ERATT) + return 0; + + /* Check if interrupt handler handles this ERATT */ + spin_lock_irq(&phba->hbalock); + if (phba->hba_flag & HBA_ERATT_HANDLED) { + /* Interrupt handler has handled ERATT */ + spin_unlock_irq(&phba->hbalock); + return 0; + } + + /* + * If there is deferred error attention, do not check for error + * attention + */ + if (unlikely(phba->hba_flag & DEFER_ERATT)) { + spin_unlock_irq(&phba->hbalock); + return 0; + } + + + /* Read chip Host Attention (HA) register */ + ha_copy = readl(phba->HAregaddr); + + if (ha_copy & HA_ERATT) { + /* Read host status register to retrieve error event */ + lpfc_sli_read_hs(phba); + + /* Check if there is a deferred error condition is active */ + if ((HS_FFER1 & phba->work_hs) && + ((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 | + HS_FFER6 | HS_FFER7) & phba->work_hs)) { + phba->hba_flag |= DEFER_ERATT; + /* Clear all interrupt enable conditions */ + writel(0, phba->HCregaddr); + readl(phba->HCregaddr); + } + /* Set the driver HA work bitmap */ + phba->work_ha |= HA_ERATT; + /* Indicate polling handles this ERATT */ + phba->hba_flag |= HBA_ERATT_HANDLED; + spin_unlock_irq(&phba->hbalock); + return 1; + } + spin_unlock_irq(&phba->hbalock); + return 0; +} + +/** + * lpfc_poll_eratt - Error attention polling timer timeout handler + * @ptr: Pointer to address of HBA context object. + * + * This function is invoked by the Error Attention polling timer when the + * timer times out. It will check the SLI Error Attention register for + * possible attention events. If so, it will post an Error Attention event + * and wake up worker thread to process it. Otherwise, it will set up the + * Error Attention polling timer for the next poll. + **/ +void lpfc_poll_eratt(unsigned long ptr) +{ + struct lpfc_hba *phba; + uint32_t eratt = 0; + + phba = (struct lpfc_hba *)ptr; + + /* Check chip HA register for error event */ + eratt = lpfc_sli_check_eratt(phba); + + if (eratt) + /* Tell the worker thread there is work to do */ + lpfc_worker_wake_up(phba); + /* If the error attention is already handled do not poll */ + else if (!(phba->hba_flag & HBA_ERATT_HANDLED)) + /* Restart the timer for next eratt poll */ + mod_timer(&phba->eratt_poll, jiffies + + HZ * LPFC_ERATT_POLL_INTERVAL); + return; +} + void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; @@ -2823,6 +2924,12 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) goto out_not_finished; } + /* If HBA has a deferred error attention, fail the iocb. */ + if (unlikely(phba->hba_flag & DEFER_ERATT)) { + spin_unlock_irqrestore(&phba->hbalock, drvr_flag); + goto out_not_finished; + } + psli = &phba->sli; mb = &pmbox->mb; @@ -3178,6 +3285,10 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (unlikely(phba->pcidev->error_state != pci_channel_io_normal)) return IOCB_ERROR; + /* If HBA has a deferred error attention, fail the iocb. */ + if (unlikely(phba->hba_flag & DEFER_ERATT)) + return IOCB_ERROR; + /* * We should never get an IOCB if we are in a < LINK_DOWN state */ @@ -3320,6 +3431,7 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba, uint16_t temp; struct temp_event temp_event_data; struct Scsi_Host *shost; + uint32_t *iocb_w; icmd = &iocbq->iocb; evt_code = icmd->un.asyncstat.evt_code; @@ -3327,13 +3439,23 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba, if ((evt_code != ASYNC_TEMP_WARN) && (evt_code != ASYNC_TEMP_SAFE)) { + iocb_w = (uint32_t *) icmd; lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0346 Ring %d handler: unexpected ASYNC_STATUS" - " evt_code 0x%x\n", + " evt_code 0x%x \n" + "W0 0x%08x W1 0x%08x W2 0x%08x W3 0x%08x\n" + "W4 0x%08x W5 0x%08x W6 0x%08x W7 0x%08x\n" + "W8 0x%08x W9 0x%08x W10 0x%08x W11 0x%08x\n" + "W12 0x%08x W13 0x%08x W14 0x%08x W15 0x%08x\n", pring->ringno, - icmd->un.asyncstat.evt_code); + icmd->un.asyncstat.evt_code, + iocb_w[0], iocb_w[1], iocb_w[2], iocb_w[3], + iocb_w[4], iocb_w[5], iocb_w[6], iocb_w[7], + iocb_w[8], iocb_w[9], iocb_w[10], iocb_w[11], + iocb_w[12], iocb_w[13], iocb_w[14], iocb_w[15]); + return; } temp_event_data.data = (uint32_t)temp; @@ -4274,6 +4396,25 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs) */ if (phba->link_flag & LS_IGNORE_ERATT) ha_copy &= ~HA_ERATT; + + /* Check the need for handling ERATT in interrupt handler */ + if (ha_copy & HA_ERATT) { + if (phba->hba_flag & HBA_ERATT_HANDLED) + /* ERATT polling has handled ERATT */ + ha_copy &= ~HA_ERATT; + else + /* Indicate interrupt handler handles ERATT */ + phba->hba_flag |= HBA_ERATT_HANDLED; + } + + /* + * If there is deferred error attention, do not check for any interrupt. + */ + if (unlikely(phba->hba_flag & DEFER_ERATT)) { + spin_unlock_irq(&phba->hbalock); + return IRQ_NONE; + } + writel((ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr); readl(phba->HAregaddr); /* flush */ spin_unlock(&phba->hbalock); @@ -4344,25 +4485,20 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs) } } + spin_lock(&phba->hbalock); if (work_ha_copy & HA_ERATT) { - /* - * There was a link/board error. Read the - * status register to retrieve the error event - * and process it. - */ - phba->sli.slistat.err_attn_event++; - /* Save status info */ - phba->work_hs = readl(phba->HSregaddr); - phba->work_status[0] = readl(phba->MBslimaddr + 0xa8); - phba->work_status[1] = readl(phba->MBslimaddr + 0xac); - - /* Clear Chip error bit */ - writel(HA_ERATT, phba->HAregaddr); - readl(phba->HAregaddr); /* flush */ - phba->pport->stopped = 1; + lpfc_sli_read_hs(phba); + /* Check for an active deferred error condition */ + if ((HS_FFER1 & phba->work_hs) && + ((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 | + HS_FFER6 | HS_FFER7) & phba->work_hs)) { + phba->hba_flag |= DEFER_ERATT; + /* Clear all interrupt conditions */ + writel(0, phba->HCregaddr); + readl(phba->HCregaddr); + } } - spin_lock(&phba->hbalock); if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active)) { pmb = phba->sli.mbox_active; diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index f8b9a23..f1e501d 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.2.0.39" +#define LPFC_DRIVER_VERSION "8.2.0.40" #define LPFC_DRIVER_NAME "lpfc"