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

Commit 858c9f6c authored by James Smart's avatar James Smart Committed by James Bottomley
Browse files

[SCSI] lpfc: bug fixes



 Following the NPIV support, the following changes have been accumulated
 in the testing and qualification of the driver:

 - Fix affinity of ELS ring to slow/deferred event processing
 - Fix Ring attention masks
 - Defer dev_loss_tmo timeout handling to worker thread
 - Consolidate link down error classification for better error checking
 - Remove unused/deprecated nlp_initiator_tmr timer
 - Fix for async scan - move adapter init code back into pci_probe_one
   context. Fix async scan interfaces.
 - Expand validation of ability to create vports
 - Extract VPI resource cnt from firmware
 - Tuning of Login/Reject policies to better deal with overwhelmned targets
 - Misc ELS and discovery fixes
 - Export the npiv_enable attribute to sysfs
 - Mailbox handling fix
 - Add debugfs support
 - A few other small misc fixes:
    - wrong return values, double-frees, bad locking
 - Added adapter failure heartbeat

Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 92d7f7b0
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -28,4 +28,4 @@ obj-$(CONFIG_SCSI_LPFC) := lpfc.o

lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o	\
	lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o \
	lpfc_vport.o
	lpfc_vport.o lpfc_debugfs.o
+31 −9
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@

struct lpfc_sli2_slim;


#define LPFC_MAX_TARGET		256	/* max number of targets supported */
#define LPFC_MAX_DISC_THREADS	64	/* max outstanding discovery els
					   requests */
@@ -45,6 +44,9 @@ struct lpfc_sli2_slim;
/* Number of exchanges reserved for discovery to complete */
#define LPFC_DISC_IOCB_BUFF_COUNT 20

#define LPFC_HB_MBOX_INTERVAL   5	/* Heart beat interval in seconds. */
#define LPFC_HB_MBOX_TIMEOUT    30 	/* Heart beat timeout  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)))
@@ -308,13 +310,15 @@ struct lpfc_vport {

	spinlock_t work_port_lock;
	uint32_t work_port_events; /* Timeout to be handled  */
#define WORKER_DISC_TMO                0x1	/* Discovery timeout */
#define WORKER_ELS_TMO                 0x2	/* ELS timeout */
#define WORKER_MBOX_TMO                0x4	/* MBOX timeout */
#define WORKER_FDMI_TMO                0x8	/* FDMI timeout */
#define WORKER_FABRIC_BLOCK_TMO        0x10	/* fabric block timout */
#define WORKER_RAMP_DOWN_QUEUE    0x20	/* Decrease Q depth */
#define WORKER_RAMP_UP_QUEUE      0x40	/* Increase Q depth */
#define WORKER_DISC_TMO                0x1	/* vport: Discovery timeout */
#define WORKER_ELS_TMO                 0x2	/* vport: ELS timeout */
#define WORKER_FDMI_TMO                0x4	/* vport: FDMI timeout */

#define WORKER_MBOX_TMO                0x100	/* hba: MBOX timeout */
#define WORKER_HB_TMO                  0x200	/* hba: Heart beat timeout */
#define WORKER_FABRIC_BLOCK_TMO        0x400	/* hba: fabric block timout */
#define WORKER_RAMP_DOWN_QUEUE         0x800	/* hba: Decrease Q depth */
#define WORKER_RAMP_UP_QUEUE           0x1000	/* hba: Increase Q depth */

	struct timer_list fc_fdmitmo;
	struct timer_list els_tmofunc;
@@ -326,6 +330,14 @@ struct lpfc_vport {
#define FC_UNLOADING		0x2	/* HBA in process of unloading drvr */
	char  *vname;		        /* Application assigned name */
	struct fc_vport *fc_vport;

#ifdef CONFIG_LPFC_DEBUG_FS
	struct dentry *debug_disc_trc;
	struct dentry *debug_nodelist;
	struct dentry *vport_debugfs_root;
	struct lpfc_disc_trc *disc_trc;
	atomic_t disc_trc_cnt;
#endif
};

struct hbq_s {
@@ -408,6 +420,7 @@ struct lpfc_hba {
	uint32_t cfg_hba_queue_depth;
	uint32_t cfg_peer_port_login;
	uint32_t cfg_vport_restrict_login;
	uint32_t cfg_npiv_enable;
	uint32_t cfg_fcp_class;
	uint32_t cfg_use_adisc;
	uint32_t cfg_ack0;
@@ -513,10 +526,10 @@ struct lpfc_hba {
	mempool_t *nlp_mem_pool;

	struct fc_host_statistics link_stats;

	struct list_head port_list;
	struct lpfc_vport *pport; /* physical lpfc_vport pointer */
	uint16_t max_vpi;	/* Maximum virtual nports */
	uint16_t vpi_cnt;	/* Nport count */
#define LPFC_MAX_VPI 100  /* Max number of VPorts supported */
	unsigned long *vpi_bmask; /* vpi allocation table */

@@ -531,6 +544,15 @@ struct lpfc_hba {
	unsigned long last_rsrc_error_time;
	unsigned long last_ramp_down_time;
	unsigned long last_ramp_up_time;
#ifdef CONFIG_LPFC_DEBUG_FS
	struct dentry *hba_debugfs_root;
	atomic_t debugfs_vport_count;
#endif

	/* Fields used for heart beat. */
	unsigned long last_completion_time;
	struct timer_list hb_tmofunc;
	uint8_t hb_outstanding;
};

static inline struct Scsi_Host *
+67 −50
Original line number Diff line number Diff line
@@ -282,9 +282,7 @@ lpfc_issue_lip(struct Scsi_Host *shost)
	}

	lpfc_set_loopback_flag(phba);
	if (mbxstatus == MBX_TIMEOUT)
		pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
	else
	if (mbxstatus != MBX_TIMEOUT)
		mempool_free(pmboxq, phba->mbox_mem_pool);

	if (mbxstatus == MBXERR_ERROR)
@@ -439,30 +437,11 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
		return -EIO;
}

static ssize_t
lpfc_max_vpi_show(struct class_device *cdev, char *buf)
{
	struct Scsi_Host  *shost = class_to_shost(cdev);
	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
	struct lpfc_hba   *phba = vport->phba;

	return snprintf(buf, PAGE_SIZE, "%d\n", phba->max_vpi);
}

static ssize_t
lpfc_used_vpi_show(struct class_device *cdev, char *buf)
{
	struct Scsi_Host  *shost = class_to_shost(cdev);
	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
	struct lpfc_hba   *phba = vport->phba;

	/* Don't count the physical port */
	return snprintf(buf, PAGE_SIZE, "%d\n", phba->vpi_cnt-1);
}

int
lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri,
	uint32_t *axri, uint32_t *mrpi, uint32_t *arpi)
lpfc_get_hba_info(struct lpfc_hba *phba,
		  uint32_t *mxri, uint32_t *axri,
		  uint32_t *mrpi, uint32_t *arpi,
		  uint32_t *mvpi, uint32_t *avpi)
{
	struct lpfc_sli   *psli = &phba->sli;
	LPFC_MBOXQ_t *pmboxq;
@@ -498,9 +477,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri,
		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);

	if (rc != MBX_SUCCESS) {
		if (rc == MBX_TIMEOUT)
			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
		else
		if (rc != MBX_TIMEOUT)
			mempool_free(pmboxq, phba->mbox_mem_pool);
		return 0;
	}
@@ -513,6 +490,10 @@ lpfc_get_hba_info(struct lpfc_hba *phba, uint32_t *mxri,
		*mxri = pmb->un.varRdConfig.max_xri;
	if (axri)
		*axri = pmb->un.varRdConfig.avail_xri;
	if (mvpi)
		*mvpi = pmb->un.varRdConfig.max_vpi;
	if (avpi)
		*avpi = pmb->un.varRdConfig.avail_vpi;

	mempool_free(pmboxq, phba->mbox_mem_pool);
	return 1;
@@ -526,7 +507,7 @@ lpfc_max_rpi_show(struct class_device *cdev, char *buf)
	struct lpfc_hba   *phba = vport->phba;
	uint32_t cnt;

	if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL))
	if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL, NULL, NULL))
		return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
	return snprintf(buf, PAGE_SIZE, "Unknown\n");
}
@@ -539,7 +520,7 @@ lpfc_used_rpi_show(struct class_device *cdev, char *buf)
	struct lpfc_hba   *phba = vport->phba;
	uint32_t cnt, acnt;

	if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt))
	if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt, NULL, NULL))
		return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
	return snprintf(buf, PAGE_SIZE, "Unknown\n");
}
@@ -552,7 +533,7 @@ lpfc_max_xri_show(struct class_device *cdev, char *buf)
	struct lpfc_hba   *phba = vport->phba;
	uint32_t cnt;

	if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL))
	if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL, NULL, NULL))
		return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
	return snprintf(buf, PAGE_SIZE, "Unknown\n");
}
@@ -565,7 +546,33 @@ lpfc_used_xri_show(struct class_device *cdev, char *buf)
	struct lpfc_hba   *phba = vport->phba;
	uint32_t cnt, acnt;

	if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL))
	if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL, NULL, NULL))
		return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
	return snprintf(buf, PAGE_SIZE, "Unknown\n");
}

static ssize_t
lpfc_max_vpi_show(struct class_device *cdev, char *buf)
{
	struct Scsi_Host  *shost = class_to_shost(cdev);
	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
	struct lpfc_hba   *phba = vport->phba;
	uint32_t cnt;

	if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, NULL))
		return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
	return snprintf(buf, PAGE_SIZE, "Unknown\n");
}

static ssize_t
lpfc_used_vpi_show(struct class_device *cdev, char *buf)
{
	struct Scsi_Host  *shost = class_to_shost(cdev);
	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
	struct lpfc_hba   *phba = vport->phba;
	uint32_t cnt, acnt;

	if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, &acnt))
		return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
	return snprintf(buf, PAGE_SIZE, "Unknown\n");
}
@@ -995,9 +1002,7 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
		 " 2 - select SLI-2 even on SLI-3 capable HBAs,"
		 " 3 - select SLI-3");

int  lpfc_npiv_enable = 0;
module_param(lpfc_npiv_enable, int, 0);
MODULE_PARM_DESC(lpfc_npiv_enable, "Enable NPIV functionality");
LPFC_ATTR_R(npiv_enable, 0, 0, 1, "Enable NPIV functionality");

/*
# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
@@ -1052,6 +1057,24 @@ lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
	return -EINVAL;
}

static void
lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba)
{
	struct lpfc_vport *vport;
	struct Scsi_Host  *shost;
	struct lpfc_nodelist  *ndlp;

	list_for_each_entry(vport, &phba->port_list, listentry) {
		shost = lpfc_shost_from_vport(vport);
		spin_lock_irq(shost->host_lock);
		list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
			if (ndlp->rport)
				ndlp->rport->dev_loss_tmo =
					phba->cfg_devloss_tmo;
		spin_unlock_irq(shost->host_lock);
	}
}

static int
lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
{
@@ -1067,6 +1090,7 @@ lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
	if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
		phba->cfg_nodev_tmo = val;
		phba->cfg_devloss_tmo = val;
		lpfc_update_rport_devloss_tmo(phba);
		return 0;
	}

@@ -1102,6 +1126,7 @@ lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val)
		phba->cfg_nodev_tmo = val;
		phba->cfg_devloss_tmo = val;
		phba->dev_loss_tmo_changed = 1;
		lpfc_update_rport_devloss_tmo(phba);
		return 0;
	}

@@ -1358,6 +1383,7 @@ struct class_device_attribute *lpfc_hba_attrs[] = {
	&class_device_attr_lpfc_multi_ring_type,
	&class_device_attr_lpfc_fdmi_on,
	&class_device_attr_lpfc_max_luns,
	&class_device_attr_lpfc_npiv_enable,
	&class_device_attr_nport_evt_cnt,
	&class_device_attr_management_version,
	&class_device_attr_board_mode,
@@ -1641,8 +1667,6 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)

		if (rc != MBX_SUCCESS) {
			if (rc == MBX_TIMEOUT) {
				phba->sysfs_mbox.mbox->mbox_cmpl =
					lpfc_sli_def_mbox_cmpl;
				phba->sysfs_mbox.mbox = NULL;
			}
			sysfs_mbox_idle(phba);
@@ -1886,9 +1910,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);

	if (rc != MBX_SUCCESS) {
		if (rc == MBX_TIMEOUT)
			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
		else
		if (rc != MBX_TIMEOUT)
			mempool_free(pmboxq, phba->mbox_mem_pool);
		return NULL;
	}
@@ -1913,9 +1935,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);

	if (rc != MBX_SUCCESS) {
		if (rc == MBX_TIMEOUT)
			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
		else
		if (rc != MBX_TIMEOUT)
			mempool_free(pmboxq, phba->mbox_mem_pool);
		return NULL;
	}
@@ -1993,9 +2013,7 @@ lpfc_reset_stats(struct Scsi_Host *shost)
		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);

	if (rc != MBX_SUCCESS) {
		if (rc == MBX_TIMEOUT)
			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
		else
		if (rc != MBX_TIMEOUT)
			mempool_free(pmboxq, phba->mbox_mem_pool);
		return;
	}
@@ -2013,9 +2031,7 @@ lpfc_reset_stats(struct Scsi_Host *shost)
		rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);

	if (rc != MBX_SUCCESS) {
		if (rc == MBX_TIMEOUT)
			pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
		else
		if (rc != MBX_TIMEOUT)
			mempool_free( pmboxq, phba->mbox_mem_pool);
		return;
	}
@@ -2253,6 +2269,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
	lpfc_max_luns_init(phba, lpfc_max_luns);
	lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
	lpfc_peer_port_login_init(phba, lpfc_peer_port_login);
	lpfc_npiv_enable_init(phba, lpfc_npiv_enable);
	lpfc_vport_restrict_login_init(phba, lpfc_vport_restrict_login);
	lpfc_use_msi_init(phba, lpfc_use_msi);
	lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo);
+13 −3
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param);
struct fc_rport;
void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
		 struct lpfc_dmabuf *mp);
void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -45,6 +46,7 @@ void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);

void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -85,6 +87,7 @@ void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
		     struct serv_parm *, uint32_t);
int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
int lpfc_els_chk_latt(struct lpfc_vport *);
int lpfc_els_abort_flogi(struct lpfc_hba *);
int lpfc_initial_flogi(struct lpfc_vport *);
int lpfc_initial_fdisc(struct lpfc_vport *);
@@ -96,10 +99,11 @@ int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *);
int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t);
int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
		     struct lpfc_nodelist *, LPFC_MBOXQ_t *, uint8_t);
int lpfc_els_rsp_reject(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
			struct lpfc_nodelist *);
			struct lpfc_nodelist *, LPFC_MBOXQ_t *);
int lpfc_els_rsp_adisc_acc(struct lpfc_vport *, struct lpfc_iocbq *,
			   struct lpfc_nodelist *);
int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *,
@@ -107,6 +111,7 @@ int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *,
void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *);
void lpfc_els_retry_delay(unsigned long);
void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
void lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *);
void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
			  struct lpfc_iocbq *);
int lpfc_els_handle_rscn(struct lpfc_vport *);
@@ -117,6 +122,8 @@ int lpfc_els_disc_adisc(struct lpfc_vport *);
int lpfc_els_disc_plogi(struct lpfc_vport *);
void lpfc_els_timeout(unsigned long);
void lpfc_els_timeout_handler(struct lpfc_vport *);
void lpfc_hb_timeout(unsigned long);
void lpfc_hb_timeout_handler(struct lpfc_hba *);

void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
			 struct lpfc_iocbq *);
@@ -238,7 +245,6 @@ void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
void lpfc_in_buf_free(struct lpfc_hba *, struct lpfc_dmabuf *);
/* Function prototypes. */
const char* lpfc_info(struct Scsi_Host *);
void lpfc_scan_start(struct Scsi_Host *);
int lpfc_scan_finished(struct Scsi_Host *, unsigned long);

void lpfc_get_cfgparam(struct lpfc_hba *);
@@ -249,7 +255,6 @@ extern struct scsi_host_template lpfc_template;
extern struct fc_function_template lpfc_transport_functions;
extern struct fc_function_template lpfc_vport_transport_functions;
extern int lpfc_sli_mode;
extern int lpfc_npiv_enable;

int  lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
void lpfc_terminate_rport_io(struct fc_rport *);
@@ -262,6 +267,11 @@ void destroy_port(struct lpfc_vport *);
int lpfc_get_instance(void);
void lpfc_host_attrib_init(struct Scsi_Host *);

extern void lpfc_debugfs_initialize(struct lpfc_vport *);
extern void lpfc_debugfs_terminate(struct lpfc_vport *);
extern void lpfc_debugfs_disc_trc(struct lpfc_vport *, int, char *, uint32_t,
	uint32_t, uint32_t);

/* Interface exported by fabric iocb scheduler */
int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
void lpfc_fabric_abort_vport(struct lpfc_vport *);
Loading