From: Rob Evers <revers@redhat.com> Date: Thu, 23 Jul 2009 09:50:25 -0400 Subject: [scsi] lpfc: update to 8.2.0.48.2p, fix multiple panics Message-id: 20090723134537.21016.69190.sendpatchset@localhost.localdomain O-Subject: [RHEL5.4 PATCH] lpfc: Update lpfc driver to 8.2.0.48.2p to fix multiple panics Bugzilla: 512266 https://bugzilla.redhat.com/show_bug.cgi?id=512266 Description: Update lpfc from 8.2.0.48.1p to 8.2.0.48.2p From the bugzilla: * Changed version number to 8.2.0.48.2p * Fixed panic in menlo sysfs handler * Fixed unsolicited CT commands crashing kernel * Fixed persistent port state to use config region 23 (CR 91320) * Fixed panic/hang when using polling mode for FCP commands (CR 91684) * Fix crash when "error" is echoed to board_mode sysfs parameter The "persistent port state" change fixes an issue which can cause the lpfc driver not to bring the link up on some older SLI-3 HBAs, which in turn would prevent the system from booting in a boot-from-SAN configuration. Upstream Status: Some of this is posted upstream. Emulex has been doing concurrent updates to upstream and rhel5.4. Brew Build #: 1899364 Testing: Installed x86_64 rpm and ran dt for 2 hours on 4 luns without incident. -- diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 50a1ffc..35b1a1b 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -663,6 +663,7 @@ struct lpfc_hba { #define ASYNC_EVENT 0x80 #define LINK_DISABLED 0x100 /* Link disabled by user */ dma_addr_t slim2p_mapping; + uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ MAILBOX_t *mbox; uint32_t *inb_ha_copy; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 6e62128..052e012 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -708,7 +708,10 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count) else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0) status = lpfc_do_offline(phba, LPFC_EVT_WARM_START); else if (strncmp(buf, "error", sizeof("error") - 1) == 0) - status = lpfc_do_offline(phba, LPFC_EVT_KILL); + if (phba->sli_rev == LPFC_SLI_REV4) + return -EINVAL; + else + status = lpfc_do_offline(phba, LPFC_EVT_KILL); else if (strncmp(buf, "remove", sizeof("remove") - 1) == 0 && vport != phba->pport) { status = lpfc_vport_delete(shost); @@ -1067,6 +1070,9 @@ lpfc_poll_store(struct class_device *cdev, const char *buf, if ((val & 0x3) != val) return -EINVAL; + if (phba->sli_rev == LPFC_SLI_REV4) + val = 0; + spin_lock_irq(&phba->hbalock); old_val = phba->cfg_poll; @@ -5393,7 +5399,10 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat); lpfc_hostmem_hgp_init(phba, lpfc_hostmem_hgp); lpfc_dev_loss_initiator_init(phba, lpfc_dev_loss_initiator); - phba->cfg_poll = lpfc_poll; + if (phba->sli_rev == LPFC_SLI_REV4) + phba->cfg_poll = 0; + else + phba->cfg_poll = lpfc_poll; phba->cfg_soft_wwnn = 0L; phba->cfg_soft_wwpn = 0L; lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 5f90157..646f07d 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -28,9 +28,8 @@ int lpfc_issue_els_auth_reject(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint8_t reason, uint8_t explanation); void lpfc_down_link(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_dump_serdes_param(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_sli_read_serdes_param(struct lpfc_hba *); -void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); +void lpfc_sli_read_link_ste(struct lpfc_hba *); +void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t, uint16_t); void lpfc_dump_wakeup_param(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); int lpfc_dump_fcoe_param(struct lpfc_hba *, struct lpfcMboxq *); @@ -231,7 +230,10 @@ void lpfc_stop_vport_timers(struct lpfc_vport *); void lpfc_poll_timeout(unsigned long ptr); void lpfc_poll_start_timer(struct lpfc_hba *); void lpfc_poll_eratt(unsigned long); -void lpfc_sli_poll_fcp_ring(struct lpfc_hba *); +int +lpfc_sli_handle_fast_ring_event(struct lpfc_hba *, + struct lpfc_sli_ring *, uint32_t); + struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *); uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *); diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 49a860b..2fdfc0c 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -2429,12 +2429,8 @@ typedef struct { #define DMP_VPORT_REGION_SIZE 0x200 #define DMP_MBOX_OFFSET_WORD 0x5 -#define DMP_REGION_SERDES 0x11 /* Serdes param region */ -#define DMP_SERDES_REGION_SIZE 0x64 -#define SERDES_REG_PORT_STATUS 0x80 - -#define DMP_REGION_FCOEPARAM 0x17 /* fcoe param region */ -#define DMP_FCOEPARAM_RGN_SIZE 0x400 +#define DMP_REGION_23 0x17 /* fcoe param and port state region */ +#define DMP_RGN23_SIZE 0x400 #define WAKE_UP_PARMS_REGION_ID 4 #define WAKE_UP_PARMS_WORD_SIZE 15 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 34895f4..5eb4d7d 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -239,7 +239,7 @@ lpfc_config_port_prep(struct lpfc_hba *phba) goto out_free_mbox; do { - lpfc_dump_mem(phba, pmb, offset); + lpfc_dump_mem(phba, pmb, offset, DMP_REGION_VPD); rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); if (rc != MBX_SUCCESS) { @@ -453,6 +453,9 @@ lpfc_config_port_post(struct lpfc_hba *phba) return -EIO; } + /* Check if the port is disabled */ + lpfc_sli_read_link_ste(phba); + /* Reset the DFT_HBA_Q_DEPTH to the max xri */ if (phba->cfg_hba_queue_depth > (mb->un.varRdConfig.max_xri+1)) phba->cfg_hba_queue_depth = @@ -461,9 +464,6 @@ lpfc_config_port_post(struct lpfc_hba *phba) phba->lmt = mb->un.varRdConfig.lmt; - /* Check if the port is disabled */ - lpfc_sli_read_serdes_param(phba); - /* Get the default values for Model Name and Description */ lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc); diff --git a/drivers/scsi/lpfc/lpfc_ioctl.c b/drivers/scsi/lpfc/lpfc_ioctl.c index 132dbac..6247e9a 100644 --- a/drivers/scsi/lpfc/lpfc_ioctl.c +++ b/drivers/scsi/lpfc/lpfc_ioctl.c @@ -1882,6 +1882,11 @@ lpfcdfc_ct_unsol_event(struct lpfc_hba * phba, piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) goto error_unsol_ct_exit; + if (phba->link_state == LPFC_HBA_ERROR || + (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) + goto error_unsol_ct_exit; + + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) dmabuf = bdeBuf1; else { diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index d58ce08..82598a1 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -121,57 +121,20 @@ lpfc_down_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } /** - * lpfc_dump_serdes_param - Dump HBA's serdes parameters. + * lpfc_dump_mem - Prepare a mailbox command for reading a region. * @phba: pointer to lpfc hba data structure. * @pmb: pointer to the driver internal queue element for mailbox command. + * @offset: offset into the region. + * @region_id: config region id. * * The dump mailbox command provides a method for the device driver to obtain * various types of information from the HBA device. * - * This routine prepares the mailbox command for dumping HBA's serdes - * parameter. + * This routine prepares the mailbox command for dumping HBA's config region. **/ void -lpfc_dump_serdes_param(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb; - void *ctx; - - mb = &pmb->u.mb; - ctx = pmb->context2; - - /* Setup to dump vport info region */ - memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); - mb->mbxCommand = MBX_DUMP_MEMORY; - mb->un.varDmp.cv = 1; - mb->un.varDmp.type = DMP_NV_PARAMS; - mb->un.varDmp.entry_index = 0; - mb->un.varDmp.region_id = DMP_REGION_SERDES; - mb->un.varDmp.word_cnt = DMP_RSP_SIZE/sizeof(uint32_t); - mb->un.varDmp.co = 0; - mb->un.varDmp.resp_offset = 0; - pmb->context2 = ctx; - mb->mbxOwner = OWN_HOST; - - return; -} - -/** - * lpfc_dump_mem - Prepare a mailbox command for retrieving HBA's VPD memory - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * @offset: offset for dumping VPD memory mailbox command. - * - * The dump mailbox command provides a method for the device driver to obtain - * various types of information from the HBA device. - * - * This routine prepares the mailbox command for dumping HBA Vital Product - * Data (VPD) memory. This mailbox command is to be used for retrieving a - * portion (DMP_RSP_SIZE bytes) of a HBA's VPD from the HBA at an address - * offset specified by the offset parameter. - **/ -void -lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset) +lpfc_dump_mem(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, uint16_t offset, + uint16_t region_id) { MAILBOX_t *mb; void *ctx; @@ -185,7 +148,7 @@ lpfc_dump_mem(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint16_t offset) mb->un.varDmp.cv = 1; mb->un.varDmp.type = DMP_NV_PARAMS; mb->un.varDmp.entry_index = offset; - mb->un.varDmp.region_id = DMP_REGION_VPD; + mb->un.varDmp.region_id = region_id; mb->un.varDmp.word_cnt = (DMP_RSP_SIZE / sizeof (uint32_t)); mb->un.varDmp.co = 0; mb->un.varDmp.resp_offset = 0; @@ -1974,8 +1937,8 @@ lpfc_dump_fcoe_param(struct lpfc_hba *phba, mb->mbxCommand = MBX_DUMP_MEMORY; mb->un.varDmp.type = DMP_NV_PARAMS; - mb->un.varDmp.region_id = DMP_REGION_FCOEPARAM; - mb->un.varDmp.sli4_length = DMP_FCOEPARAM_RGN_SIZE; + mb->un.varDmp.region_id = DMP_REGION_23; + mb->un.varDmp.sli4_length = DMP_RGN23_SIZE; mb->un.varWords[3] = putPaddrLow(mp->phys); mb->un.varWords[4] = putPaddrHigh(mp->phys); return 0; diff --git a/drivers/scsi/lpfc/lpfc_menlo.c b/drivers/scsi/lpfc/lpfc_menlo.c index abf762b..4d511f5 100644 --- a/drivers/scsi/lpfc/lpfc_menlo.c +++ b/drivers/scsi/lpfc/lpfc_menlo.c @@ -473,6 +473,9 @@ lpfc_menlo_write(struct lpfc_hba *phba, uint32_t addr_low = 0; int hdr_offset = sizeof(struct lpfc_sysfs_menlo_hdr); + if (phba->sli_rev >= LPFC_SLI_REV4) + return -EPERM; + if (off % 4 || count % 4 || (unsigned long)buf % 4) return -EINVAL; @@ -887,6 +890,9 @@ lpfc_menlo_read(struct lpfc_hba *phba, char *buf, loff_t off, size_t count, psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; + if (phba->sli_rev >= LPFC_SLI_REV4) + return -EPERM; + if (off > SYSFS_MENLO_ATTR_SIZE) return -ERANGE; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index ffda039..fc3424b 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1992,7 +1992,9 @@ void lpfc_poll_timeout(unsigned long ptr) struct lpfc_hba *phba = (struct lpfc_hba *) ptr; if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - lpfc_sli_poll_fcp_ring (phba); + lpfc_sli_handle_fast_ring_event(phba, + &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); + if (phba->cfg_poll & DISABLE_FCP_RING_INT) lpfc_poll_rearm_timer(phba); } @@ -2100,7 +2102,11 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) goto out_host_busy_free_buf; } if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - lpfc_sli_poll_fcp_ring(phba); + spin_unlock(shost->host_lock); + lpfc_sli_handle_fast_ring_event(phba, + &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); + + spin_lock(shost->host_lock); if (phba->cfg_poll & DISABLE_FCP_RING_INT) lpfc_poll_rearm_timer(phba); } @@ -2219,7 +2225,8 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) } if (phba->cfg_poll & DISABLE_FCP_RING_INT) - lpfc_sli_poll_fcp_ring (phba); + lpfc_sli_handle_fast_ring_event(phba, + &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); lpfc_cmd->waitq = &waitq; /* Wait for abort to complete */ @@ -2678,7 +2685,8 @@ lpfc_slave_configure(struct scsi_device *sdev) rport->dev_loss_tmo = vport->cfg_devloss_tmo; if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - lpfc_sli_poll_fcp_ring(phba); + lpfc_sli_handle_fast_ring_event(phba, + &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); if (phba->cfg_poll & DISABLE_FCP_RING_INT) lpfc_poll_rearm_timer(phba); } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 55e53d4..30ea884 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2297,172 +2297,6 @@ void lpfc_poll_eratt(unsigned long ptr) return; } -/** - * lpfc_sli_poll_fcp_ring - Handle FCP ring completion in polling mode - * @phba: Pointer to HBA context object. - * - * This function is called from lpfc_queuecommand, lpfc_poll_timeout, - * lpfc_abort_handler and lpfc_slave_configure when FCP_RING_POLLING - * is enabled. - * - * The caller does not hold any lock. - * The function processes each response iocb in the response ring until it - * finds an iocb with LE bit set and chains all the iocbs upto the iocb with - * LE bit set. The function will call the completion handler of the command iocb - * if the response iocb indicates a completion for a command iocb or it is - * an abort completion. - **/ -void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring = &psli->ring[LPFC_FCP_RING]; - IOCB_t *irsp = NULL; - IOCB_t *entry = NULL; - struct lpfc_iocbq *cmdiocbq = NULL; - struct lpfc_iocbq rspiocbq; - struct lpfc_pgp *pgp; - uint32_t status; - uint32_t portRspPut, portRspMax; - int type; - uint32_t rsp_cmpl = 0; - uint32_t ha_copy; - unsigned long iflags; - - pring->stats.iocb_event++; - - pgp = (phba->sli_rev == 3) ? - &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] : - &phba->slim2p->mbx.us.s2.port[pring->ringno]; - - - /* - * The next available response entry should never exceed the maximum - * entries. If it does, treat it as an adapter hardware error. - */ - portRspMax = pring->numRiocb; - portRspPut = le32_to_cpu(pgp->rspPutInx); - if (unlikely(portRspPut >= portRspMax)) { - lpfc_sli_rsp_pointers_error(phba, pring); - return; - } - - rmb(); - while (pring->rspidx != portRspPut) { - entry = lpfc_resp_iocb(phba, pring); - if (++pring->rspidx >= portRspMax) - pring->rspidx = 0; - - lpfc_sli_pcimem_bcopy((uint32_t *) entry, - (uint32_t *) &rspiocbq.iocb, - phba->iocb_rsp_size); - irsp = &rspiocbq.iocb; - type = lpfc_sli_iocb_cmd_type(irsp->ulpCommand & CMD_IOCB_MASK); - pring->stats.iocb_rsp++; - rsp_cmpl++; - - if (unlikely(irsp->ulpStatus)) { - /* Rsp ring <ringno> error: IOCB */ - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0326 Rsp Ring %d error: IOCB Data: " - "x%x x%x x%x x%x x%x x%x x%x x%x\n", - pring->ringno, - irsp->un.ulpWord[0], - irsp->un.ulpWord[1], - irsp->un.ulpWord[2], - irsp->un.ulpWord[3], - irsp->un.ulpWord[4], - irsp->un.ulpWord[5], - *(((uint32_t *) irsp) + 6), - *(((uint32_t *) irsp) + 7)); - } - - switch (type) { - case LPFC_ABORT_IOCB: - case LPFC_SOL_IOCB: - /* - * Idle exchange closed via ABTS from port. No iocb - * resources need to be recovered. - */ - if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) { - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0314 IOCB cmd 0x%x " - "processed. Skipping " - "completion", - irsp->ulpCommand); - break; - } - - spin_lock_irqsave(&phba->hbalock, iflags); - cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring, - &rspiocbq); - spin_unlock_irqrestore(&phba->hbalock, iflags); - if ((cmdiocbq) && (cmdiocbq->iocb_cmpl)) { - (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, - &rspiocbq); - } - break; - default: - if (irsp->ulpCommand == CMD_ADAPTER_MSG) { - char adaptermsg[LPFC_MAX_ADPTMSG]; - memset(adaptermsg, 0, LPFC_MAX_ADPTMSG); - memcpy(&adaptermsg[0], (uint8_t *) irsp, - MAX_MSG_DATA); - dev_warn(&((phba->pcidev)->dev), "lpfc%d: %s", - phba->brd_no, adaptermsg); - } else { - /* Unknown IOCB command */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0321 Unknown IOCB command " - "Data: x%x, x%x x%x x%x x%x\n", - type, irsp->ulpCommand, - irsp->ulpStatus, - irsp->ulpIoTag, - irsp->ulpContext); - } - break; - } - - /* - * The response IOCB has been processed. Update the ring - * pointer in SLIM. If the port response put pointer has not - * been updated, sync the pgp->rspPutInx and fetch the new port - * response put pointer. - */ - writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx); - - if (pring->rspidx == portRspPut) - portRspPut = le32_to_cpu(pgp->rspPutInx); - } - - ha_copy = readl(phba->HAregaddr); - ha_copy >>= (LPFC_FCP_RING * 4); - - if ((rsp_cmpl > 0) && (ha_copy & HA_R0RE_REQ)) { - spin_lock_irqsave(&phba->hbalock, iflags); - pring->stats.iocb_rsp_full++; - status = ((CA_R0ATT | CA_R0RE_RSP) << (LPFC_FCP_RING * 4)); - writel(status, phba->CAregaddr); - readl(phba->CAregaddr); - spin_unlock_irqrestore(&phba->hbalock, iflags); - } - if ((ha_copy & HA_R0CE_RSP) && - (pring->flag & LPFC_CALL_RING_AVAILABLE)) { - spin_lock_irqsave(&phba->hbalock, iflags); - pring->flag &= ~LPFC_CALL_RING_AVAILABLE; - pring->stats.iocb_cmd_empty++; - - /* Force update of the local copy of cmdGetInx */ - pring->local_getidx = le32_to_cpu(pgp->cmdGetInx); - lpfc_sli_resume_iocb(phba, pring); - - if ((pring->lpfc_sli_cmd_available)) - (pring->lpfc_sli_cmd_available) (phba, pring); - - spin_unlock_irqrestore(&phba->hbalock, iflags); - } - - return; -} /** * lpfc_sli_handle_fast_ring_event - Handle ring events on FCP ring @@ -2481,7 +2315,7 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba) * This routine presumes LPFC_FCP_RING handling and doesn't bother * to check it explicitly. */ -static int +int lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint32_t mask) { @@ -2513,6 +2347,11 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, spin_unlock_irqrestore(&phba->hbalock, iflag); return 1; } + if (phba->fcp_ring_in_use) { + spin_unlock_irqrestore(&phba->hbalock, iflag); + return 1; + } else + phba->fcp_ring_in_use = 1; rmb(); while (pring->rspidx != portRspPut) { @@ -2583,10 +2422,6 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring, &rspiocbq); if ((cmdiocbq) && (cmdiocbq->iocb_cmpl)) { - if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, - &rspiocbq); - } else { spin_unlock_irqrestore(&phba->hbalock, iflag); (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, @@ -2594,7 +2429,6 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, spin_lock_irqsave(&phba->hbalock, iflag); } - } break; case LPFC_UNSOL_IOCB: spin_unlock_irqrestore(&phba->hbalock, iflag); @@ -2653,6 +2487,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, } + phba->fcp_ring_in_use = 0; spin_unlock_irqrestore(&phba->hbalock, iflag); return rc; } @@ -4161,7 +3996,7 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba, return -EIO; } data_length = mqe->un.mb_words[5]; - if (data_length > DMP_FCOEPARAM_RGN_SIZE) { + if (data_length > DMP_RGN23_SIZE) { lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); return -EIO; @@ -11688,20 +11523,20 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index) } /** - * lpfc_sli_read_serdes_param - Read region 17 to decide if link is disabled. + * lpfc_sli_read_link_ste - Read region 23 to decide if link is disabled. * @phba: pointer to lpfc hba data structure. * - * This function read region 17 and parse TLV for port status to - * decide if the used disaled the port. If the TLC indicates the + * This function read region 23 and parse TLV for port status to + * decide if the user disaled the port. If the TLV indicates the * port is disabled, the hba_flag is set accordingly. **/ void -lpfc_sli_read_serdes_param(struct lpfc_hba *phba) +lpfc_sli_read_link_ste(struct lpfc_hba *phba) { LPFC_MBOXQ_t *pmb = NULL; MAILBOX_t *mb; - uint8_t *serdes_param; - uint32_t offset = 0; + uint8_t *rgn23_data = NULL; + uint32_t offset = 0, data_size, sub_tlv_len, tlv_offset; int rc; pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -11709,44 +11544,109 @@ lpfc_sli_read_serdes_param(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2600 lpfc_sli_read_serdes_param failed to" " allocate mailbox memory\n"); - return; + goto out; } mb = &pmb->u.mb; - lpfc_dump_serdes_param(phba, pmb); + /* Get adapter Region 23 data */ + rgn23_data = kzalloc(DMP_RGN23_SIZE, GFP_KERNEL); + if (!rgn23_data) + goto out; - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); + do { + lpfc_dump_mem(phba, pmb, offset, DMP_REGION_23); + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); - if ((rc != MBX_SUCCESS) || mb->mbxStatus) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2601 lpfc_sli_read_serdes_param failed to" - " issue dump mailbox command ret 0x%x " - "status 0x%x\n", - rc, mb->mbxStatus); + if (rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2601 lpfc_sli_read_link_ste failed to" + " read config region 23 rc 0x%x Status 0x%x\n", + rc, mb->mbxStatus); + mb->un.varDmp.word_cnt = 0; + } + /* + * dump mem may return a zero when finished or we got a + * mailbox error, either way we are done. + */ + if (mb->un.varDmp.word_cnt == 0) + break; + if (mb->un.varDmp.word_cnt > DMP_RGN23_SIZE - offset) + mb->un.varDmp.word_cnt = DMP_RGN23_SIZE - offset; + + lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, + rgn23_data + offset, + mb->un.varDmp.word_cnt); + offset += mb->un.varDmp.word_cnt; + } while (mb->un.varDmp.word_cnt && offset < DMP_RGN23_SIZE); + + data_size = offset; + offset = 0; + + if (!data_size) goto out; - } - serdes_param = (uint8_t *)mb + DMP_RSP_OFFSET; + /* Check the region signature first */ + if (memcmp(&rgn23_data[offset], LPFC_REGION23_SIGNATURE, 4)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2619 Config region 23 has bad signature\n"); + goto out; + } + offset += 4; - /* Swap the byte ordering to match with Firmware endianess */ - lpfc_sli_bemem_bcopy(serdes_param, serdes_param, - mb->un.varDmp.word_cnt); + /* Check the data structure version */ + if (rgn23_data[offset] != LPFC_REGION23_VERSION) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2620 Config region 23 has bad version\n"); + goto out; + } + offset += 4; /* Parse TLV entries in the region */ - while (offset < mb->un.varDmp.word_cnt) { - if (serdes_param[offset] == 0xff) + while (offset < data_size) { + if (rgn23_data[offset] == LPFC_REGION23_LAST_REC) break; - if (serdes_param[offset] != SERDES_REG_PORT_STATUS) { - offset += serdes_param[offset + 1] + 2; + /* + * If the TLV is not driver specific TLV or driver id is + * not linux driver id, skip the record. + */ + if ((rgn23_data[offset] != DRIVER_SPECIFIC_TYPE) || + (rgn23_data[offset + 2] != LINUX_DRIVER_ID) || + (rgn23_data[offset + 3] != 0)) { + offset += rgn23_data[offset + 1] * 4 + 4; continue; } - /* If port status TLV is zero, disable the port */ - if ((serdes_param[offset + 1] == 1) && - (!serdes_param[offset + 2])) - phba->hba_flag |= LINK_DISABLED; - break; + + /* Driver found a driver specific TLV in the config region */ + sub_tlv_len = rgn23_data[offset + 1] * 4; + offset += 4; + tlv_offset = 0; + + /* + * Search for configured port state sub-TLV. + */ + while ((offset < data_size) && + (tlv_offset < sub_tlv_len)) { + if (rgn23_data[offset] == LPFC_REGION23_LAST_REC) { + offset += 4; + tlv_offset += 4; + break; + } + if (rgn23_data[offset] != PORT_STE_TYPE) { + offset += rgn23_data[offset + 1] * 4 + 4; + tlv_offset += rgn23_data[offset + 1] * 4 + 4; + continue; + } + + /* This HBA contains PORT_STE configured */ + if (!rgn23_data[offset + 2]) + phba->hba_flag |= LINK_DISABLED; + + goto out; + } } out: - mempool_free(pmb, phba->mbox_mem_pool); + if (pmb) + mempool_free(pmb, phba->mbox_mem_pool); + kfree(rgn23_data); return; } diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 7dfc94f..75c840f 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -151,6 +151,10 @@ struct lpfc_fcf { #define LPFC_REGION23_SIGNATURE "RG23" #define LPFC_REGION23_VERSION 1 #define LPFC_REGION23_LAST_REC 0xff +#define DRIVER_SPECIFIC_TYPE 0xA2 +#define LINUX_DRIVER_ID 0x20 +#define PORT_STE_TYPE 0x1 + struct lpfc_fip_param_hdr { uint8_t type; #define FCOE_PARAM_TYPE 0xA0 diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index cb0e96e..aab924d 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.48.1p" +#define LPFC_DRIVER_VERSION "8.2.0.48.2p" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"