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

Commit 46fa311e authored by James Smart's avatar James Smart Committed by James Bottomley
Browse files

[SCSI] lpfc 8.1.12 : Rework offline path to solve HBA reset issues



Rework offline path to solve HBA reset issues

Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 07951076
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -244,6 +244,7 @@ struct lpfc_hba {
#define FC_FABRIC               0x100	/* We are fabric attached */
#define FC_ESTABLISH_LINK       0x200	/* Reestablish Link */
#define FC_RSCN_DISCOVERY       0x400	/* Authenticate all devices after RSCN*/
#define FC_BLOCK_MGMT_IO        0x800   /* Don't allow mgmt mbx or iocb cmds */
#define FC_LOADING		0x1000	/* HBA in process of loading drvr */
#define FC_UNLOADING		0x2000	/* HBA in process of unloading drvr */
#define FC_SCSI_SCAN_TMO        0x4000	/* scsi scan timer running */
+67 −16
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
 *******************************************************************/

#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/interrupt.h>

@@ -213,6 +214,7 @@ lpfc_issue_lip(struct Scsi_Host *host)
	int mbxstatus = MBXERR_ERROR;

	if ((phba->fc_flag & FC_OFFLINE_MODE) ||
	    (phba->fc_flag & FC_BLOCK_MGMT_IO) ||
	    (phba->hba_state != LPFC_HBA_READY))
		return -EPERM;

@@ -247,19 +249,62 @@ lpfc_issue_lip(struct Scsi_Host *host)
}

static int
lpfc_selective_reset(struct lpfc_hba *phba)
lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
{
	struct completion online_compl;
	struct lpfc_sli_ring *pring;
	struct lpfc_sli *psli;
	int status = 0;
	int cnt = 0;
	int i;

	init_completion(&online_compl);
	lpfc_workq_post_event(phba, &status, &online_compl,
			      LPFC_EVT_OFFLINE);
			      LPFC_EVT_OFFLINE_PREP);
	wait_for_completion(&online_compl);

	if (status != 0)
		return -EIO;

	psli = &phba->sli;

	for (i = 0; i < psli->num_rings; i++) {
		pring = &psli->ring[i];
		/* The linkdown event takes 30 seconds to timeout. */
		while (pring->txcmplq_cnt) {
			msleep(10);
			if (cnt++ > 3000) {
				lpfc_printf_log(phba,
					KERN_WARNING, LOG_INIT,
					"%d:0466 Outstanding IO when "
					"bringing Adapter offline\n",
					phba->brd_no);
				break;
			}
		}
	}

	init_completion(&online_compl);
	lpfc_workq_post_event(phba, &status, &online_compl, type);
	wait_for_completion(&online_compl);

	if (status != 0)
		return -EIO;

	return 0;
}

static int
lpfc_selective_reset(struct lpfc_hba *phba)
{
	struct completion online_compl;
	int status = 0;

	status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);

	if (status != 0)
		return status;

	init_completion(&online_compl);
	lpfc_workq_post_event(phba, &status, &online_compl,
			      LPFC_EVT_ONLINE);
@@ -324,23 +369,19 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)

	init_completion(&online_compl);

	if(strncmp(buf, "online", sizeof("online") - 1) == 0)
	if(strncmp(buf, "online", sizeof("online") - 1) == 0) {
		lpfc_workq_post_event(phba, &status, &online_compl,
				      LPFC_EVT_ONLINE);
	else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
		lpfc_workq_post_event(phba, &status, &online_compl,
				      LPFC_EVT_OFFLINE);
		wait_for_completion(&online_compl);
	} else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
		status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
	else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0)
		lpfc_workq_post_event(phba, &status, &online_compl,
				      LPFC_EVT_WARM_START);
		status = lpfc_do_offline(phba, LPFC_EVT_WARM_START);
	else if (strncmp(buf, "error", sizeof("error") - 1) == 0)
		lpfc_workq_post_event(phba, &status, &online_compl,
				      LPFC_EVT_KILL);
		status = lpfc_do_offline(phba, LPFC_EVT_KILL);
	else
		return -EINVAL;

	wait_for_completion(&online_compl);

	if (!status)
		return strlen(buf);
	else
@@ -645,9 +686,7 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
	dev_printk(KERN_NOTICE, &phba->pcidev->dev,
		   "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no);

	init_completion(&online_compl);
	lpfc_workq_post_event(phba, &stat1, &online_compl, LPFC_EVT_OFFLINE);
	wait_for_completion(&online_compl);
	stat1 = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
	if (stat1)
		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
			"%d:0463 lpfc_soft_wwpn attribute set failed to reinit "
@@ -1307,6 +1346,12 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
			return -EPERM;
		}

		if (phba->fc_flag & FC_BLOCK_MGMT_IO) {
			sysfs_mbox_idle(phba);
			spin_unlock_irq(host->host_lock);
			return  -EAGAIN;
		}

		if ((phba->fc_flag & FC_OFFLINE_MODE) ||
		    (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE))){

@@ -1551,6 +1596,9 @@ lpfc_get_stats(struct Scsi_Host *shost)
	unsigned long seconds;
	int rc = 0;

	if (phba->fc_flag & FC_BLOCK_MGMT_IO)
		return NULL;

	pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
	if (!pmboxq)
		return NULL;
@@ -1651,6 +1699,9 @@ lpfc_reset_stats(struct Scsi_Host *shost)
	MAILBOX_t *pmb;
	int rc = 0;

	if (phba->fc_flag & FC_BLOCK_MGMT_IO)
		return;

	pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
	if (!pmboxq)
		return;
+4 −1
Original line number Diff line number Diff line
@@ -112,7 +112,10 @@ void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
int lpfc_online(struct lpfc_hba *);
int lpfc_offline(struct lpfc_hba *);
void lpfc_block_mgmt_io(struct lpfc_hba *);
void lpfc_unblock_mgmt_io(struct lpfc_hba *);
void lpfc_offline_prep(struct lpfc_hba *);
void lpfc_offline(struct lpfc_hba *);

int lpfc_sli_setup(struct lpfc_hba *);
int lpfc_sli_queue_setup(struct lpfc_hba *);
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
/* worker thread events */
enum lpfc_work_type {
	LPFC_EVT_ONLINE,
	LPFC_EVT_OFFLINE_PREP,
	LPFC_EVT_OFFLINE,
	LPFC_EVT_WARM_START,
	LPFC_EVT_KILL,
+13 −7
Original line number Diff line number Diff line
@@ -185,29 +185,35 @@ lpfc_work_list_done(struct lpfc_hba * phba)
				*(int *)(evtp->evt_arg1)  = 0;
			complete((struct completion *)(evtp->evt_arg2));
			break;
		case LPFC_EVT_OFFLINE:
		case LPFC_EVT_OFFLINE_PREP:
			if (phba->hba_state >= LPFC_LINK_DOWN)
				lpfc_offline_prep(phba);
			*(int *)(evtp->evt_arg1) = 0;
			complete((struct completion *)(evtp->evt_arg2));
			break;
		case LPFC_EVT_OFFLINE:
			lpfc_offline(phba);
			lpfc_sli_brdrestart(phba);
			*(int *)(evtp->evt_arg1) =
				lpfc_sli_brdready(phba, HS_FFRDY | HS_MBRDY);
			lpfc_unblock_mgmt_io(phba);
			complete((struct completion *)(evtp->evt_arg2));
			break;
		case LPFC_EVT_WARM_START:
			if (phba->hba_state >= LPFC_LINK_DOWN)
			lpfc_offline(phba);
			lpfc_reset_barrier(phba);
			lpfc_sli_brdreset(phba);
			lpfc_hba_down_post(phba);
			*(int *)(evtp->evt_arg1) =
				lpfc_sli_brdready(phba, HS_MBRDY);
			lpfc_unblock_mgmt_io(phba);
			complete((struct completion *)(evtp->evt_arg2));
			break;
		case LPFC_EVT_KILL:
			if (phba->hba_state >= LPFC_LINK_DOWN)
			lpfc_offline(phba);
			*(int *)(evtp->evt_arg1)
				= (phba->stopped) ? 0 : lpfc_sli_brdkill(phba);
			lpfc_unblock_mgmt_io(phba);
			complete((struct completion *)(evtp->evt_arg2));
			break;
		}
Loading