Skip to content

Commit

Permalink
[SCSI] lpfc 8.3.29: SLI related fixes
Browse files Browse the repository at this point in the history
SLI related fixes:

- Fix REG_RPI fails on SLI4 HBA putting NPort into NPR state (126230)
- Fix ELS FDISC failing with local reject / invalid RPI. (126350)
- Fix reset port when reset is needed during fw_dump (125807)
- Fix unbounded firmware revision string from port cause panic (126560)
- Fix driver behavior when receiving an ADISC (126654)
- Fix driver not returning when bad ndlp found in abts error event
  handling (126209)
- Add more driver logs in area of SLI4 port error attention and reset
  recovery (126813, 124466)
- Fix failure in handling large CQ/EQ identifiers in an IOV
  environment (126856)
- Fix for driver using duplicate RPIs after lancer port reset (126723)
- Clear vport->fc_myDID in lpfc_els_issue_fdisc to guarentee a
  zero SID (126779, 126897)
- Fix for SLI4 Port delivery for BLS ABORT ACC (126289)

Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
  • Loading branch information
James Smart authored and James Bottomley committed Feb 19, 2012
1 parent 3ef6d24 commit 6b5151f
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 34 deletions.
12 changes: 8 additions & 4 deletions drivers/scsi/lpfc/lpfc_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ lpfc_fwrev_show(struct device *dev, struct device_attribute *attr,
struct lpfc_hba *phba = vport->phba;
uint32_t if_type;
uint8_t sli_family;
char fwrev[32];
char fwrev[FW_REV_STR_SIZE];
int len;

lpfc_decode_firmware_rev(phba, fwrev, 1);
Expand Down Expand Up @@ -922,11 +922,15 @@ lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)
rc = lpfc_sli4_pdev_status_reg_wait(phba);

if (rc == -EPERM) {
/* no privilage for reset, restore if needed */
if (before_fc_flag & FC_OFFLINE_MODE)
goto out;
/* no privilage for reset */
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"3150 No privilage to perform the requested "
"access: x%x\n", reg_val);
} else if (rc == -EIO) {
/* reset failed, there is nothing more we can do */
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"3153 Fail to perform the requested "
"access: x%x\n", reg_val);
return rc;
}

Expand Down
4 changes: 2 additions & 2 deletions drivers/scsi/lpfc/lpfc_bsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -3980,15 +3980,15 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job,
case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES:
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"3106 Handled SLI_CONFIG "
"subsys_fcoe, opcode:x%x\n",
"subsys_comn, opcode:x%x\n",
opcode);
rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job,
nemb_mse, dmabuf);
break;
default:
lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC,
"3107 Reject SLI_CONFIG "
"subsys_fcoe, opcode:x%x\n",
"subsys_comn, opcode:x%x\n",
opcode);
rc = -EPERM;
break;
Expand Down
1 change: 1 addition & 0 deletions drivers/scsi/lpfc/lpfc_crtn.h
Original file line number Diff line number Diff line change
Expand Up @@ -462,3 +462,4 @@ int lpfc_issue_unreg_vfi(struct lpfc_vport *);
int lpfc_selective_reset(struct lpfc_hba *);
int lpfc_sli4_read_config(struct lpfc_hba *phba);
int lpfc_scsi_buf_update(struct lpfc_hba *phba);
void lpfc_sli4_node_prep(struct lpfc_hba *phba);
4 changes: 2 additions & 2 deletions drivers/scsi/lpfc/lpfc_ct.c
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,7 @@ int
lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
size_t size)
{
char fwrev[16];
char fwrev[FW_REV_STR_SIZE];
int n;

lpfc_decode_firmware_rev(vport->phba, fwrev, 0);
Expand Down Expand Up @@ -1834,7 +1834,7 @@ lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
uint8_t *fwname;

if (phba->sli_rev == LPFC_SLI_REV4)
sprintf(fwrevision, "%s", vp->rev.opFwName);
snprintf(fwrevision, FW_REV_STR_SIZE, "%s", vp->rev.opFwName);
else if (vp->rev.rBit) {
if (psli->sli_flag & LPFC_SLI_ACTIVE)
rev = vp->rev.sli2FwRev;
Expand Down
3 changes: 2 additions & 1 deletion drivers/scsi/lpfc/lpfc_els.c
Original file line number Diff line number Diff line change
Expand Up @@ -7172,7 +7172,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
goto out;
/* FDISC failed */
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
"0126 FDISC failed. (%d/%d)\n",
"0126 FDISC failed. (x%x/x%x)\n",
irsp->ulpStatus, irsp->un.ulpWord[4]);
goto fdisc_failed;
}
Expand Down Expand Up @@ -7283,6 +7283,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
int rc;

vport->port_state = LPFC_FDISC;
vport->fc_myDID = 0;
cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
ELS_CMD_FDISC);
Expand Down
1 change: 1 addition & 0 deletions drivers/scsi/lpfc/lpfc_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
/* vendor ID used in SCSI netlink calls */
#define LPFC_NL_VENDOR_ID (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX)

#define FW_REV_STR_SIZE 32
/* Common Transport structures and definitions */

union CtRevisionId {
Expand Down
26 changes: 19 additions & 7 deletions drivers/scsi/lpfc/lpfc_hw4.h
Original file line number Diff line number Diff line change
Expand Up @@ -715,12 +715,20 @@ struct lpfc_register {
#define lpfc_eqcq_doorbell_eqci_SHIFT 9
#define lpfc_eqcq_doorbell_eqci_MASK 0x0001
#define lpfc_eqcq_doorbell_eqci_WORD word0
#define lpfc_eqcq_doorbell_cqid_SHIFT 0
#define lpfc_eqcq_doorbell_cqid_MASK 0x03FF
#define lpfc_eqcq_doorbell_cqid_WORD word0
#define lpfc_eqcq_doorbell_eqid_SHIFT 0
#define lpfc_eqcq_doorbell_eqid_MASK 0x01FF
#define lpfc_eqcq_doorbell_eqid_WORD word0
#define lpfc_eqcq_doorbell_cqid_lo_SHIFT 0
#define lpfc_eqcq_doorbell_cqid_lo_MASK 0x03FF
#define lpfc_eqcq_doorbell_cqid_lo_WORD word0
#define lpfc_eqcq_doorbell_cqid_hi_SHIFT 11
#define lpfc_eqcq_doorbell_cqid_hi_MASK 0x001F
#define lpfc_eqcq_doorbell_cqid_hi_WORD word0
#define lpfc_eqcq_doorbell_eqid_lo_SHIFT 0
#define lpfc_eqcq_doorbell_eqid_lo_MASK 0x01FF
#define lpfc_eqcq_doorbell_eqid_lo_WORD word0
#define lpfc_eqcq_doorbell_eqid_hi_SHIFT 11
#define lpfc_eqcq_doorbell_eqid_hi_MASK 0x001F
#define lpfc_eqcq_doorbell_eqid_hi_WORD word0
#define LPFC_CQID_HI_FIELD_SHIFT 10
#define LPFC_EQID_HI_FIELD_SHIFT 9

#define LPFC_BMBX 0x0160
#define lpfc_bmbx_addr_SHIFT 2
Expand Down Expand Up @@ -3313,7 +3321,11 @@ struct xmit_bls_rsp64_wqe {
uint32_t rsrvd4;
struct wqe_did wqe_dest;
struct wqe_common wqe_com; /* words 6-11 */
uint32_t rsvd_12_15[4];
uint32_t word12;
#define xmit_bls_rsp64_temprpi_SHIFT 0
#define xmit_bls_rsp64_temprpi_MASK 0x0000ffff
#define xmit_bls_rsp64_temprpi_WORD word12
uint32_t rsvd_13_15[3];
};

struct wqe_rctl_dfctl {
Expand Down
64 changes: 57 additions & 7 deletions drivers/scsi/lpfc/lpfc_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -1475,8 +1475,12 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
phba->sli4_hba.u.if_type2.STATUSregaddr,
&portstat_reg.word0);
/* consider PCI bus read error as pci_channel_offline */
if (pci_rd_rc1 == -EIO)
if (pci_rd_rc1 == -EIO) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"3151 PCI bus read access failure: x%x\n",
readl(phba->sli4_hba.u.if_type2.STATUSregaddr));
return;
}
reg_err1 = readl(phba->sli4_hba.u.if_type2.ERR1regaddr);
reg_err2 = readl(phba->sli4_hba.u.if_type2.ERR2regaddr);
if (bf_get(lpfc_sliport_status_oti, &portstat_reg)) {
Expand Down Expand Up @@ -1526,6 +1530,9 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
}
/* fall through for not able to recover */
}
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"3152 Unrecoverable error, bring the port "
"offline\n");
lpfc_sli4_offline_eratt(phba);
break;
case LPFC_SLI_INTF_IF_TYPE_1:
Expand Down Expand Up @@ -2513,6 +2520,42 @@ lpfc_block_mgmt_io(struct lpfc_hba * phba)
}
}

/**
* lpfc_sli4_node_prep - Assign RPIs for active nodes.
* @phba: pointer to lpfc hba data structure.
*
* Allocate RPIs for all active remote nodes. This is needed whenever
* an SLI4 adapter is reset and the driver is not unloading. Its purpose
* is to fixup the temporary rpi assignments.
**/
void
lpfc_sli4_node_prep(struct lpfc_hba *phba)
{
struct lpfc_nodelist *ndlp, *next_ndlp;
struct lpfc_vport **vports;
int i;

if (phba->sli_rev != LPFC_SLI_REV4)
return;

vports = lpfc_create_vport_work_array(phba);
if (vports != NULL) {
for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
if (vports[i]->load_flag & FC_UNLOADING)
continue;

list_for_each_entry_safe(ndlp, next_ndlp,
&vports[i]->fc_nodes,
nlp_listp) {
if (NLP_CHK_NODE_ACT(ndlp))
ndlp->nlp_rpi =
lpfc_sli4_alloc_rpi(phba);
}
}
}
lpfc_destroy_vport_work_array(phba, vports);
}

/**
* lpfc_online - Initialize and bring a HBA online
* @phba: pointer to lpfc hba data structure.
Expand Down Expand Up @@ -2654,6 +2697,15 @@ lpfc_offline_prep(struct lpfc_hba * phba)
}
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_ADISC;

/*
* Whenever an SLI4 port goes offline, free the
* RPI. 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);
}
Expand Down Expand Up @@ -7224,19 +7276,17 @@ lpfc_pci_function_reset(struct lpfc_hba *phba)
rc = -ENODEV;
goto out;
}
if (bf_get(lpfc_sliport_status_rdy, &reg_data))
break;
if (bf_get(lpfc_sliport_status_rn, &reg_data)) {
if (bf_get(lpfc_sliport_status_rn, &reg_data))
reset_again++;
if (bf_get(lpfc_sliport_status_rdy, &reg_data))
break;
}
}

/*
* If the port responds to the init request with
* reset needed, delay for a bit and restart the loop.
*/
if (reset_again) {
if (reset_again && (rdy_chk < 1000)) {
msleep(10);
reset_again = 0;
continue;
Expand Down Expand Up @@ -9059,7 +9109,7 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba)
int
lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw)
{
char fwrev[32];
char fwrev[FW_REV_STR_SIZE];
struct lpfc_grp_hdr *image = (struct lpfc_grp_hdr *)fw->data;
struct list_head dma_buffer_list;
int i, rc = 0;
Expand Down
76 changes: 73 additions & 3 deletions drivers/scsi/lpfc/lpfc_nportdisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ static int
lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct lpfc_name *nn, struct lpfc_name *pn)
{
/* First, we MUST have a RPI registered */
if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED))
return 0;

/* Compare the ADISC rsp WWNN / WWPN matches our internal node
* table entry for that node.
*/
Expand Down Expand Up @@ -385,6 +389,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (!mbox)
goto out;

/* Registering an existing RPI behaves differently for SLI3 vs SLI4 */
if (phba->sli_rev == LPFC_SLI_REV4)
lpfc_unreg_rpi(vport, ndlp);

rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
(uint8_t *) sp, mbox, ndlp->nlp_rpi);
if (rc) {
Expand Down Expand Up @@ -445,11 +453,42 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
return 0;
}

/**
* lpfc_mbx_cmpl_resume_rpi - Resume RPI completion routine
* @phba: pointer to lpfc hba data structure.
* @mboxq: pointer to mailbox object
*
* This routine is invoked to issue a completion to a rcv'ed
* ADISC or PDISC after the paused RPI has been resumed.
**/
static void
lpfc_mbx_cmpl_resume_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
{
struct lpfc_vport *vport;
struct lpfc_iocbq *elsiocb;
struct lpfc_nodelist *ndlp;
uint32_t cmd;

elsiocb = (struct lpfc_iocbq *)mboxq->context1;
ndlp = (struct lpfc_nodelist *) mboxq->context2;
vport = mboxq->vport;
cmd = elsiocb->drvrTimeout;

if (cmd == ELS_CMD_ADISC) {
lpfc_els_rsp_adisc_acc(vport, elsiocb, ndlp);
} else {
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, elsiocb,
ndlp, NULL);
}
kfree(elsiocb);
}

static int
lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct lpfc_iocbq *cmdiocb)
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_iocbq *elsiocb;
struct lpfc_dmabuf *pcmd;
struct serv_parm *sp;
struct lpfc_name *pnn, *ppn;
Expand All @@ -475,12 +514,43 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,

icmd = &cmdiocb->iocb;
if (icmd->ulpStatus == 0 && lpfc_check_adisc(vport, ndlp, pnn, ppn)) {

/*
* As soon as we send ACC, the remote NPort can
* start sending us data. Thus, for SLI4 we must
* resume the RPI before the ACC goes out.
*/
if (vport->phba->sli_rev == LPFC_SLI_REV4) {
elsiocb = kmalloc(sizeof(struct lpfc_iocbq),
GFP_KERNEL);
if (elsiocb) {

/* Save info from cmd IOCB used in rsp */
memcpy((uint8_t *)elsiocb, (uint8_t *)cmdiocb,
sizeof(struct lpfc_iocbq));

/* Save the ELS cmd */
elsiocb->drvrTimeout = cmd;

lpfc_sli4_resume_rpi(ndlp,
lpfc_mbx_cmpl_resume_rpi, elsiocb);
goto out;
}
}

if (cmd == ELS_CMD_ADISC) {
lpfc_els_rsp_adisc_acc(vport, cmdiocb, ndlp);
} else {
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp,
NULL);
lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb,
ndlp, NULL);
}
out:
/* If we are authenticated, move to the proper state */
if (ndlp->nlp_type & NLP_FCP_TARGET)
lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
else
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);

return 1;
}
/* Reject this request because invalid parameters */
Expand Down Expand Up @@ -1229,7 +1299,7 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport,
}

if (phba->sli_rev == LPFC_SLI_REV4) {
rc = lpfc_sli4_resume_rpi(ndlp);
rc = lpfc_sli4_resume_rpi(ndlp, NULL, NULL);
if (rc) {
/* Stay in state and retry. */
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
Expand Down
Loading

0 comments on commit 6b5151f

Please sign in to comment.