Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 549e55cd authored by James Smart's avatar James Smart Committed by James Bottomley
Browse files

[SCSI] lpfc 8.2.2 : Fix locking around HBA's port_list



Cleans up a lot of bad behaviors that have been in this area a while

Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent a58cbd52
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -530,7 +530,8 @@ struct lpfc_hba {
	struct list_head port_list;
	struct lpfc_vport *pport;	/* physical lpfc_vport pointer */
	uint16_t max_vpi;		/* Maximum virtual nports */
#define LPFC_MAX_VPI 100  /* Max number of VPorts supported */
#define LPFC_MAX_VPI 100		/* Max number of VPI supported */
#define LPFC_MAX_VPORTS (LPFC_MAX_VPI+1)/* Max number of VPorts supported */
	unsigned long *vpi_bmask;	/* vpi allocation table */

	/* Data structure used by fabric iocb scheduler */
+13 −8
Original line number Diff line number Diff line
@@ -1060,19 +1060,24 @@ lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
static void
lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba)
{
	struct lpfc_vport *vport;
	struct lpfc_vport **vports;
	struct Scsi_Host  *shost;
	struct lpfc_nodelist  *ndlp;
	int i;

	list_for_each_entry(vport, &phba->port_list, listentry) {
		shost = lpfc_shost_from_vport(vport);
	vports = lpfc_create_vport_work_array(phba);
	if (vports != NULL)
		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
			shost = lpfc_shost_from_vport(vports[i]);
			spin_lock_irq(shost->host_lock);
		list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
			list_for_each_entry(ndlp, &vports[i]->fc_nodes,
					    nlp_listp)
			if (ndlp->rport)
				ndlp->rport->dev_loss_tmo =
						phba->cfg_devloss_tmo;
			spin_unlock_irq(shost->host_lock);
		}
	lpfc_destroy_vport_work_array(vports);
}

static int
+2 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ void lpfc_reg_vpi(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *);
void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);

struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove);
int lpfc_linkdown(struct lpfc_hba *);
void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -117,6 +118,7 @@ void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
int lpfc_els_handle_rscn(struct lpfc_vport *);
void lpfc_els_flush_rscn(struct lpfc_vport *);
int lpfc_rscn_payload_check(struct lpfc_vport *, uint32_t);
void lpfc_els_flush_all_cmd(struct lpfc_hba *);
void lpfc_els_flush_cmd(struct lpfc_vport *);
int lpfc_els_disc_adisc(struct lpfc_vport *);
int lpfc_els_disc_plogi(struct lpfc_vport *);
+7 −5
Original line number Diff line number Diff line
@@ -390,17 +390,19 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
	return 0;
}

static struct lpfc_vport *
struct lpfc_vport *
lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) {

	struct lpfc_vport *vport_curr;
	unsigned long flags;

	spin_lock_irqsave(&phba->hbalock, flags);
	list_for_each_entry(vport_curr, &phba->port_list, listentry) {
		if ((vport_curr->fc_myDID) &&
			(vport_curr->fc_myDID == did))
		if ((vport_curr->fc_myDID) && (vport_curr->fc_myDID == did)) {
			spin_unlock_irqrestore(&phba->hbalock, flags);
			return vport_curr;
		}

	}
	spin_unlock_irqrestore(&phba->hbalock, flags);
	return NULL;
}

+52 −9
Original line number Diff line number Diff line
@@ -2800,7 +2800,6 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
	struct lpfc_hba  *phba = vport->phba;
	struct lpfc_dmabuf *pcmd;
	struct lpfc_vport *next_vport;
	uint32_t *lp, *datap;
	IOCB_t *icmd;
	uint32_t payload_len, length, nportid, *cmd;
@@ -2850,13 +2849,8 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
			nportid = ((be32_to_cpu(nportid)) & Mask_DID);
			i -= sizeof(uint32_t);
			rscn_id++;
			list_for_each_entry(next_vport, &phba->port_list,
				listentry) {
				if (nportid == next_vport->fc_myDID) {
			if (lpfc_find_vport_by_did(phba, nportid))
				hba_id++;
					break;
				}
			}
		}
		if (rscn_id == hba_id) {
			/* ALL NPortIDs in RSCN are on HBA */
@@ -3740,6 +3734,50 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport)
	return;
}

void
lpfc_els_flush_all_cmd(struct lpfc_hba  *phba)
{
	LIST_HEAD(completions);
	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
	struct lpfc_iocbq *tmp_iocb, *piocb;
	IOCB_t *cmd = NULL;

	lpfc_fabric_abort_hba(phba);
	spin_lock_irq(&phba->hbalock);
	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
		cmd = &piocb->iocb;
		if (piocb->iocb_flag & LPFC_IO_LIBDFC)
			continue;
		/* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
		if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
		    cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
		    cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
		    cmd->ulpCommand == CMD_ABORT_XRI_CN)
			continue;
		list_move_tail(&piocb->list, &completions);
		pring->txq_cnt--;
	}
	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
		if (piocb->iocb_flag & LPFC_IO_LIBDFC)
			continue;
		lpfc_sli_issue_abort_iotag(phba, pring, piocb);
	}
	spin_unlock_irq(&phba->hbalock);
	while (!list_empty(&completions)) {
		piocb = list_get_first(&completions, struct lpfc_iocbq, list);
		cmd = &piocb->iocb;
		list_del_init(&piocb->list);
		if (!piocb->iocb_cmpl)
			lpfc_sli_release_iocbq(phba, piocb);
		else {
			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
			cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
			(piocb->iocb_cmpl) (phba, piocb, piocb);
		}
	}
	return;
}

static void
lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
		      struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
@@ -4009,11 +4047,16 @@ static struct lpfc_vport *
lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
{
	struct lpfc_vport *vport;
	unsigned long flags;

	spin_lock_irqsave(&phba->hbalock, flags);
	list_for_each_entry(vport, &phba->port_list, listentry) {
		if (vport->vpi == vpi)
		if (vport->vpi == vpi) {
			spin_unlock_irqrestore(&phba->hbalock, flags);
			return vport;
		}
	}
	spin_unlock_irqrestore(&phba->hbalock, flags);
	return NULL;
}

Loading