diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_init.c')
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 530 | 
1 files changed, 437 insertions, 93 deletions
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 647f5bfb3bd..06f9a5b79e6 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@  /*******************************************************************   * This file is part of the Emulex Linux Device Driver for         *   * Fibre Channel Host Bus Adapters.                                * - * Copyright (C) 2004-2013 Emulex.  All rights reserved.           * + * Copyright (C) 2004-2014 Emulex.  All rights reserved.           *   * EMULEX and SLI are trademarks of Emulex.                        *   * www.emulex.com                                                  *   * Portions Copyright (C) 2004-2005 Christoph Hellwig              * @@ -80,6 +80,7 @@ static void lpfc_sli4_cq_event_pool_destroy(struct lpfc_hba *);  static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *);  static void lpfc_sli4_disable_intr(struct lpfc_hba *);  static uint32_t lpfc_sli4_enable_intr(struct lpfc_hba *, uint32_t); +static void lpfc_sli4_oas_verify(struct lpfc_hba *phba);  static struct scsi_transport_template *lpfc_transport_template = NULL;  static struct scsi_transport_template *lpfc_vport_transport_template = NULL; @@ -819,57 +820,153 @@ lpfc_hba_down_prep(struct lpfc_hba *phba)  }  /** - * lpfc_hba_down_post_s3 - Perform lpfc uninitialization after HBA reset + * lpfc_sli4_free_sp_events - Cleanup sp_queue_events to free + * rspiocb which got deferred + *   * @phba: pointer to lpfc HBA data structure.   * - * This routine will do uninitialization after the HBA is reset when bring - * down the SLI Layer. + * This routine will cleanup completed slow path events after HBA is reset + * when bringing down the SLI Layer. + *   *   * Return codes - *   0 - success. - *   Any other value - error. + *   void.   **/ -static int -lpfc_hba_down_post_s3(struct lpfc_hba *phba) +static void +lpfc_sli4_free_sp_events(struct lpfc_hba *phba) +{ +	struct lpfc_iocbq *rspiocbq; +	struct hbq_dmabuf *dmabuf; +	struct lpfc_cq_event *cq_event; + +	spin_lock_irq(&phba->hbalock); +	phba->hba_flag &= ~HBA_SP_QUEUE_EVT; +	spin_unlock_irq(&phba->hbalock); + +	while (!list_empty(&phba->sli4_hba.sp_queue_event)) { +		/* Get the response iocb from the head of work queue */ +		spin_lock_irq(&phba->hbalock); +		list_remove_head(&phba->sli4_hba.sp_queue_event, +				 cq_event, struct lpfc_cq_event, list); +		spin_unlock_irq(&phba->hbalock); + +		switch (bf_get(lpfc_wcqe_c_code, &cq_event->cqe.wcqe_cmpl)) { +		case CQE_CODE_COMPL_WQE: +			rspiocbq = container_of(cq_event, struct lpfc_iocbq, +						 cq_event); +			lpfc_sli_release_iocbq(phba, rspiocbq); +			break; +		case CQE_CODE_RECEIVE: +		case CQE_CODE_RECEIVE_V1: +			dmabuf = container_of(cq_event, struct hbq_dmabuf, +					      cq_event); +			lpfc_in_buf_free(phba, &dmabuf->dbuf); +		} +	} +} + +/** + * lpfc_hba_free_post_buf - Perform lpfc uninitialization after HBA reset + * @phba: pointer to lpfc HBA data structure. + * + * This routine will cleanup posted ELS buffers after the HBA is reset + * when bringing down the SLI Layer. + * + * + * Return codes + *   void. + **/ +static void +lpfc_hba_free_post_buf(struct lpfc_hba *phba)  {  	struct lpfc_sli *psli = &phba->sli;  	struct lpfc_sli_ring *pring;  	struct lpfc_dmabuf *mp, *next_mp; -	LIST_HEAD(completions); -	int i; +	LIST_HEAD(buflist); +	int count;  	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)  		lpfc_sli_hbqbuf_free_all(phba);  	else {  		/* Cleanup preposted buffers on the ELS ring */  		pring = &psli->ring[LPFC_ELS_RING]; -		list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { +		spin_lock_irq(&phba->hbalock); +		list_splice_init(&pring->postbufq, &buflist); +		spin_unlock_irq(&phba->hbalock); + +		count = 0; +		list_for_each_entry_safe(mp, next_mp, &buflist, list) {  			list_del(&mp->list); -			pring->postbufq_cnt--; +			count++;  			lpfc_mbuf_free(phba, mp->virt, mp->phys);  			kfree(mp);  		} + +		spin_lock_irq(&phba->hbalock); +		pring->postbufq_cnt -= count; +		spin_unlock_irq(&phba->hbalock);  	} +} + +/** + * lpfc_hba_clean_txcmplq - Perform lpfc uninitialization after HBA reset + * @phba: pointer to lpfc HBA data structure. + * + * This routine will cleanup the txcmplq after the HBA is reset when bringing + * down the SLI Layer. + * + * Return codes + *   void + **/ +static void +lpfc_hba_clean_txcmplq(struct lpfc_hba *phba) +{ +	struct lpfc_sli *psli = &phba->sli; +	struct lpfc_sli_ring *pring; +	LIST_HEAD(completions); +	int i; -	spin_lock_irq(&phba->hbalock);  	for (i = 0; i < psli->num_rings; i++) {  		pring = &psli->ring[i]; - +		if (phba->sli_rev >= LPFC_SLI_REV4) +			spin_lock_irq(&pring->ring_lock); +		else +			spin_lock_irq(&phba->hbalock);  		/* At this point in time the HBA is either reset or DOA. Either  		 * way, nothing should be on txcmplq as it will NEVER complete.  		 */  		list_splice_init(&pring->txcmplq, &completions); -		spin_unlock_irq(&phba->hbalock); +		pring->txcmplq_cnt = 0; + +		if (phba->sli_rev >= LPFC_SLI_REV4) +			spin_unlock_irq(&pring->ring_lock); +		else +			spin_unlock_irq(&phba->hbalock);  		/* Cancel all the IOCBs from the completions list */  		lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,  				      IOERR_SLI_ABORTED); -  		lpfc_sli_abort_iocb_ring(phba, pring); -		spin_lock_irq(&phba->hbalock);  	} -	spin_unlock_irq(&phba->hbalock); +} +/** + * lpfc_hba_down_post_s3 - Perform lpfc uninitialization after HBA reset +	int i; + * @phba: pointer to lpfc HBA data structure. + * + * This routine will do uninitialization after the HBA is reset when bring + * down the SLI Layer. + * + * Return codes + *   0 - success. + *   Any other value - error. + **/ +static int +lpfc_hba_down_post_s3(struct lpfc_hba *phba) +{ +	lpfc_hba_free_post_buf(phba); +	lpfc_hba_clean_txcmplq(phba);  	return 0;  } @@ -889,13 +986,12 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba)  {  	struct lpfc_scsi_buf *psb, *psb_next;  	LIST_HEAD(aborts); -	int ret;  	unsigned long iflag = 0;  	struct lpfc_sglq *sglq_entry = NULL; -	ret = lpfc_hba_down_post_s3(phba); -	if (ret) -		return ret; +	lpfc_hba_free_post_buf(phba); +	lpfc_hba_clean_txcmplq(phba); +  	/* At this point in time the HBA is either reset or DOA. Either  	 * way, nothing should be on lpfc_abts_els_sgl_list, it needs to be  	 * on the lpfc_sgl_list so that it can either be freed if the @@ -931,6 +1027,8 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba)  	spin_lock_irqsave(&phba->scsi_buf_list_put_lock, iflag);  	list_splice(&aborts, &phba->lpfc_scsi_buf_list_put);  	spin_unlock_irqrestore(&phba->scsi_buf_list_put_lock, iflag); + +	lpfc_sli4_free_sp_events(phba);  	return 0;  } @@ -1005,9 +1103,14 @@ lpfc_rrq_timeout(unsigned long ptr)  	phba = (struct lpfc_hba *)ptr;  	spin_lock_irqsave(&phba->pport->work_port_lock, iflag); -	phba->hba_flag |= HBA_RRQ_ACTIVE; +	if (!(phba->pport->load_flag & FC_UNLOADING)) +		phba->hba_flag |= HBA_RRQ_ACTIVE; +	else +		phba->hba_flag &= ~HBA_RRQ_ACTIVE;  	spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); -	lpfc_worker_wake_up(phba); + +	if (!(phba->pport->load_flag & FC_UNLOADING)) +		lpfc_worker_wake_up(phba);  }  /** @@ -1244,7 +1347,6 @@ static void  lpfc_handle_deferred_eratt(struct lpfc_hba *phba)  {  	uint32_t old_host_status = phba->work_hs; -	struct lpfc_sli_ring  *pring;  	struct lpfc_sli *psli = &phba->sli;  	/* If the pci channel is offline, ignore possible errors, @@ -1273,8 +1375,7 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba)  	 * dropped by the firmware. Error iocb (I/O) on txcmplq and let the  	 * SCSI layer retry it after re-establishing link.  	 */ -	pring = &psli->ring[psli->fcp_ring]; -	lpfc_sli_abort_iocb_ring(phba, pring); +	lpfc_sli_abort_fcp_rings(phba);  	/*  	 * There was a firmware error. Take the hba offline and then @@ -1342,7 +1443,6 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba)  {  	struct lpfc_vport *vport = phba->pport;  	struct lpfc_sli   *psli = &phba->sli; -	struct lpfc_sli_ring  *pring;  	uint32_t event_data;  	unsigned long temperature;  	struct temp_event temp_event_data; @@ -1394,8 +1494,7 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba)  		* Error iocb (I/O) on txcmplq and let the SCSI layer  		* retry it after re-establishing link.  		*/ -		pring = &psli->ring[psli->fcp_ring]; -		lpfc_sli_abort_iocb_ring(phba, pring); +		lpfc_sli_abort_fcp_rings(phba);  		/*  		 * There was a firmware error.  Take the hba offline and then @@ -1468,7 +1567,8 @@ lpfc_handle_eratt_s3(struct lpfc_hba *phba)   * for handling possible port resource change.   **/  static int -lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action) +lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, +			    bool en_rn_msg)  {  	int rc;  	uint32_t intr_mode; @@ -1480,9 +1580,10 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action)  	rc = lpfc_sli4_pdev_status_reg_wait(phba);  	if (!rc) {  		/* need reset: attempt for port recovery */ -		lpfc_printf_log(phba, KERN_ERR, LOG_INIT, -				"2887 Reset Needed: Attempting Port " -				"Recovery...\n"); +		if (en_rn_msg) +			lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +					"2887 Reset Needed: Attempting Port " +					"Recovery...\n");  		lpfc_offline_prep(phba, mbx_action);  		lpfc_offline(phba);  		/* release interrupt for possible resource change */ @@ -1522,6 +1623,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)  	uint32_t reg_err1, reg_err2;  	uint32_t uerrlo_reg, uemasklo_reg;  	uint32_t pci_rd_rc1, pci_rd_rc2; +	bool en_rn_msg = true;  	int rc;  	/* If the pci channel is offline, ignore possible errors, since @@ -1572,10 +1674,12 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)  			break;  		}  		if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && -		    reg_err2 == SLIPORT_ERR2_REG_FW_RESTART) +		    reg_err2 == SLIPORT_ERR2_REG_FW_RESTART) {  			lpfc_printf_log(phba, KERN_ERR, LOG_INIT, -					"3143 Port Down: Firmware Restarted\n"); -		else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && +					"3143 Port Down: Firmware Update " +					"Detected\n"); +			en_rn_msg = false; +		} else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 &&  			 reg_err2 == SLIPORT_ERR2_REG_FORCED_DUMP)  			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,  					"3144 Port Down: Debug Dump\n"); @@ -1585,7 +1689,8 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)  					"3145 Port Down: Provisioning\n");  		/* Check port status register for function reset */ -		rc = lpfc_sli4_port_sta_fn_reset(phba, LPFC_MBX_NO_WAIT); +		rc = lpfc_sli4_port_sta_fn_reset(phba, LPFC_MBX_NO_WAIT, +				en_rn_msg);  		if (rc == 0) {  			/* don't report event on forced debug dump */  			if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && @@ -1928,78 +2033,81 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)  	switch (dev_id) {  	case PCI_DEVICE_ID_FIREFLY: -		m = (typeof(m)){"LP6000", "PCI", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LP6000", "PCI", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_SUPERFLY:  		if (vp->rev.biuRev >= 1 && vp->rev.biuRev <= 3) -			m = (typeof(m)){"LP7000", "PCI", -					"Fibre Channel Adapter"}; +			m = (typeof(m)){"LP7000", "PCI", ""};  		else -			m = (typeof(m)){"LP7000E", "PCI", -					"Fibre Channel Adapter"}; +			m = (typeof(m)){"LP7000E", "PCI", ""}; +		m.function = "Obsolete, Unsupported Fibre Channel Adapter";  		break;  	case PCI_DEVICE_ID_DRAGONFLY:  		m = (typeof(m)){"LP8000", "PCI", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_CENTAUR:  		if (FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID) -			m = (typeof(m)){"LP9002", "PCI", -					"Fibre Channel Adapter"}; +			m = (typeof(m)){"LP9002", "PCI", ""};  		else -			m = (typeof(m)){"LP9000", "PCI", -					"Fibre Channel Adapter"}; +			m = (typeof(m)){"LP9000", "PCI", ""}; +		m.function = "Obsolete, Unsupported Fibre Channel Adapter";  		break;  	case PCI_DEVICE_ID_RFLY:  		m = (typeof(m)){"LP952", "PCI", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_PEGASUS:  		m = (typeof(m)){"LP9802", "PCI-X", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_THOR:  		m = (typeof(m)){"LP10000", "PCI-X", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_VIPER:  		m = (typeof(m)){"LPX1000",  "PCI-X", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_PFLY:  		m = (typeof(m)){"LP982", "PCI-X", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_TFLY:  		m = (typeof(m)){"LP1050", "PCI-X", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_HELIOS:  		m = (typeof(m)){"LP11000", "PCI-X2", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_HELIOS_SCSP:  		m = (typeof(m)){"LP11000-SP", "PCI-X2", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_HELIOS_DCSP:  		m = (typeof(m)){"LP11002-SP",  "PCI-X2", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_NEPTUNE: -		m = (typeof(m)){"LPe1000", "PCIe", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LPe1000", "PCIe", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_NEPTUNE_SCSP: -		m = (typeof(m)){"LPe1000-SP", "PCIe", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LPe1000-SP", "PCIe", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_NEPTUNE_DCSP: -		m = (typeof(m)){"LPe1002-SP", "PCIe", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LPe1002-SP", "PCIe", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_BMID:  		m = (typeof(m)){"LP1150", "PCI-X2", "Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_BSMB: -		m = (typeof(m)){"LP111", "PCI-X2", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LP111", "PCI-X2", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_ZEPHYR:  		m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"}; @@ -2018,16 +2126,20 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)  		m = (typeof(m)){"LPe111", "PCIe", "Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_LP101: -		m = (typeof(m)){"LP101", "PCI-X", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LP101", "PCI-X", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_LP10000S: -		m = (typeof(m)){"LP10000-S", "PCI", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LP10000-S", "PCI", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_LP11000S: -		m = (typeof(m)){"LP11000-S", "PCI-X2", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LP11000-S", "PCI-X2", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_LPE11000S: -		m = (typeof(m)){"LPe11000-S", "PCIe", "Fibre Channel Adapter"}; +		m = (typeof(m)){"LPe11000-S", "PCIe", +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_SAT:  		m = (typeof(m)){"LPe12000", "PCIe", "Fibre Channel Adapter"}; @@ -2048,20 +2160,21 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)  		m = (typeof(m)){"LPe12000-S", "PCIe", "Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_HORNET: -		m = (typeof(m)){"LP21000", "PCIe", "FCoE Adapter"}; +		m = (typeof(m)){"LP21000", "PCIe", +				"Obsolete, Unsupported FCoE Adapter"};  		GE = 1;  		break;  	case PCI_DEVICE_ID_PROTEUS_VF:  		m = (typeof(m)){"LPev12000", "PCIe IOV", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_PROTEUS_PF:  		m = (typeof(m)){"LPev12000", "PCIe IOV", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_PROTEUS_S:  		m = (typeof(m)){"LPemv12002-S", "PCIe IOV", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_TIGERSHARK:  		oneConnect = 1; @@ -2077,17 +2190,24 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)  		break;  	case PCI_DEVICE_ID_BALIUS:  		m = (typeof(m)){"LPVe12002", "PCIe Shared I/O", -				"Fibre Channel Adapter"}; +				"Obsolete, Unsupported Fibre Channel Adapter"};  		break;  	case PCI_DEVICE_ID_LANCER_FC: -	case PCI_DEVICE_ID_LANCER_FC_VF:  		m = (typeof(m)){"LPe16000", "PCIe", "Fibre Channel Adapter"};  		break; +	case PCI_DEVICE_ID_LANCER_FC_VF: +		m = (typeof(m)){"LPe16000", "PCIe", +				"Obsolete, Unsupported Fibre Channel Adapter"}; +		break;  	case PCI_DEVICE_ID_LANCER_FCOE: -	case PCI_DEVICE_ID_LANCER_FCOE_VF:  		oneConnect = 1;  		m = (typeof(m)){"OCe15100", "PCIe", "FCoE"};  		break; +	case PCI_DEVICE_ID_LANCER_FCOE_VF: +		oneConnect = 1; +		m = (typeof(m)){"OCe15100", "PCIe", +				"Obsolete, Unsupported FCoE"}; +		break;  	case PCI_DEVICE_ID_SKYHAWK:  	case PCI_DEVICE_ID_SKYHAWK_VF:  		oneConnect = 1; @@ -4545,7 +4665,7 @@ lpfc_enable_pci_dev(struct lpfc_hba *phba)  	pci_save_state(pdev);  	/* PCIe EEH recovery on powerpc platforms needs fundamental reset */ -	if (pci_find_capability(pdev, PCI_CAP_ID_EXP)) +	if (pci_is_pcie(pdev))  		pdev->needs_freset = 1;  	return 0; @@ -4581,8 +4701,6 @@ lpfc_disable_pci_dev(struct lpfc_hba *phba)  	/* Release PCI resource and disable PCI device */  	pci_release_selected_regions(pdev, bars);  	pci_disable_device(pdev); -	/* Null out PCI private reference to driver */ -	pci_set_drvdata(pdev, NULL);  	return;  } @@ -4604,7 +4722,10 @@ lpfc_reset_hba(struct lpfc_hba *phba)  		phba->link_state = LPFC_HBA_ERROR;  		return;  	} -	lpfc_offline_prep(phba, LPFC_MBX_WAIT); +	if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) +		lpfc_offline_prep(phba, LPFC_MBX_WAIT); +	else +		lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT);  	lpfc_offline(phba);  	lpfc_sli_brdrestart(phba);  	lpfc_online(phba); @@ -4858,6 +4979,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)  	uint8_t pn_page[LPFC_MAX_SUPPORTED_PAGES] = {0};  	struct lpfc_mqe *mqe;  	int longs; +	int fof_vectors = 0;  	/* Get all the module params for configuring this host */  	lpfc_get_cfgparam(phba); @@ -5063,6 +5185,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)  	rc = lpfc_sli4_read_config(phba);  	if (unlikely(rc))  		goto out_free_bsmbx; +	rc = lpfc_mem_alloc_active_rrq_pool_s4(phba); +	if (unlikely(rc)) +		goto out_free_bsmbx;  	/* IF Type 0 ports get initialized now. */  	if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == @@ -5120,6 +5245,12 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)  		}  	}  	mempool_free(mboxq, phba->mbox_mem_pool); + +	/* Verify OAS is supported */ +	lpfc_sli4_oas_verify(phba); +	if (phba->cfg_fof) +		fof_vectors = 1; +  	/* Verify all the SLI4 queues */  	rc = lpfc_sli4_queue_verify(phba);  	if (rc) @@ -5161,7 +5292,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)  	phba->sli4_hba.fcp_eq_hdl =  			kzalloc((sizeof(struct lpfc_fcp_eq_hdl) * -			    phba->cfg_fcp_io_channel), GFP_KERNEL); +			    (fof_vectors + phba->cfg_fcp_io_channel)), +			    GFP_KERNEL);  	if (!phba->sli4_hba.fcp_eq_hdl) {  		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,  				"2572 Failed allocate memory for " @@ -5171,7 +5303,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)  	}  	phba->sli4_hba.msix_entries = kzalloc((sizeof(struct msix_entry) * -				      phba->cfg_fcp_io_channel), GFP_KERNEL); +				  (fof_vectors + +				   phba->cfg_fcp_io_channel)), GFP_KERNEL);  	if (!phba->sli4_hba.msix_entries) {  		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,  				"2573 Failed allocate memory for msi-x " @@ -5269,6 +5402,7 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)  	kfree(phba->sli4_hba.cpu_map);  	phba->sli4_hba.num_present_cpu = 0;  	phba->sli4_hba.num_online_cpu = 0; +	phba->sli4_hba.curr_disp_cpu = 0;  	/* Free memory allocated for msi-x interrupt vector entries */  	kfree(phba->sli4_hba.msix_entries); @@ -5392,6 +5526,10 @@ lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba)  	/* Initialize FCF connection rec list */  	INIT_LIST_HEAD(&phba->fcf_conn_rec_list); +	/* Initialize OAS configuration list */ +	spin_lock_init(&phba->devicelock); +	INIT_LIST_HEAD(&phba->luns); +  	return 0;  } @@ -6818,6 +6956,7 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)  	int cfg_fcp_io_channel;  	uint32_t cpu;  	uint32_t i = 0; +	int fof_vectors = phba->cfg_fof ? 1 : 0;  	/*  	 * Sanity check for configured queue parameters against the run-time @@ -6834,6 +6973,7 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)  	}  	phba->sli4_hba.num_online_cpu = i;  	phba->sli4_hba.num_present_cpu = lpfc_present_cpu; +	phba->sli4_hba.curr_disp_cpu = 0;  	if (i < cfg_fcp_io_channel) {  		lpfc_printf_log(phba, @@ -6844,7 +6984,7 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)  		cfg_fcp_io_channel = i;  	} -	if (cfg_fcp_io_channel > +	if (cfg_fcp_io_channel + fof_vectors >  	    phba->sli4_hba.max_cfg_param.max_eq) {  		if (phba->sli4_hba.max_cfg_param.max_eq <  		    LPFC_FCP_IO_CHAN_MIN) { @@ -6861,7 +7001,8 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba)  				"available EQs: from %d to %d\n",  				cfg_fcp_io_channel,  				phba->sli4_hba.max_cfg_param.max_eq); -		cfg_fcp_io_channel = phba->sli4_hba.max_cfg_param.max_eq; +		cfg_fcp_io_channel = phba->sli4_hba.max_cfg_param.max_eq - +			fof_vectors;  	}  	/* The actual number of FCP event queues adopted */ @@ -7072,6 +7213,9 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba)  	}  	phba->sli4_hba.dat_rq = qdesc; +	/* Create the Queues needed for Flash Optimized Fabric operations */ +	if (phba->cfg_fof) +		lpfc_fof_queue_create(phba);  	return 0;  out_error: @@ -7096,6 +7240,9 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba)  {  	int idx; +	if (phba->cfg_fof) +		lpfc_fof_queue_destroy(phba); +  	if (phba->sli4_hba.hba_eq != NULL) {  		/* Release HBA event queue */  		for (idx = 0; idx < phba->cfg_fcp_io_channel; idx++) { @@ -7480,8 +7627,20 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba)  			phba->sli4_hba.hdr_rq->queue_id,  			phba->sli4_hba.dat_rq->queue_id,  			phba->sli4_hba.els_cq->queue_id); + +	if (phba->cfg_fof) { +		rc = lpfc_fof_queue_setup(phba); +		if (rc) { +			lpfc_printf_log(phba, KERN_ERR, LOG_INIT, +					"0549 Failed setup of FOF Queues: " +					"rc = 0x%x\n", rc); +			goto out_destroy_els_rq; +		} +	}  	return 0; +out_destroy_els_rq: +	lpfc_rq_destroy(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq);  out_destroy_els_wq:  	lpfc_wq_destroy(phba, phba->sli4_hba.els_wq);  out_destroy_mbx_wq: @@ -7520,6 +7679,9 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba)  {  	int fcp_qidx; +	/* Unset the queues created for Flash Optimized Fabric operations */ +	if (phba->cfg_fof) +		lpfc_fof_queue_destroy(phba);  	/* Unset mailbox command work queue */  	lpfc_mq_destroy(phba, phba->sli4_hba.mbx_wq);  	/* Unset ELS work queue */ @@ -8637,6 +8799,10 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)  	/* Configure MSI-X capability structure */  	vectors = phba->cfg_fcp_io_channel; +	if (phba->cfg_fof) { +		phba->sli4_hba.msix_entries[index].entry = index; +		vectors++; +	}  enable_msix_vectors:  	rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries,  			     vectors); @@ -8666,7 +8832,15 @@ enable_msix_vectors:  		phba->sli4_hba.fcp_eq_hdl[index].idx = index;  		phba->sli4_hba.fcp_eq_hdl[index].phba = phba;  		atomic_set(&phba->sli4_hba.fcp_eq_hdl[index].fcp_eq_in_use, 1); -		rc = request_irq(phba->sli4_hba.msix_entries[index].vector, +		if (phba->cfg_fof && (index == (vectors - 1))) +			rc = request_irq( +				phba->sli4_hba.msix_entries[index].vector, +				 &lpfc_sli4_fof_intr_handler, IRQF_SHARED, +				 (char *)&phba->sli4_hba.handler_name[index], +				 &phba->sli4_hba.fcp_eq_hdl[index]); +		else +			rc = request_irq( +				phba->sli4_hba.msix_entries[index].vector,  				 &lpfc_sli4_hba_intr_handler, IRQF_SHARED,  				 (char *)&phba->sli4_hba.handler_name[index],  				 &phba->sli4_hba.fcp_eq_hdl[index]); @@ -8678,6 +8852,9 @@ enable_msix_vectors:  		}  	} +	if (phba->cfg_fof) +		vectors--; +  	if (vectors != phba->cfg_fcp_io_channel) {  		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,  				"3238 Reducing IO channels to match number of " @@ -8723,7 +8900,10 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba)  		free_irq(phba->sli4_hba.msix_entries[index].vector,  			 &phba->sli4_hba.fcp_eq_hdl[index]);  	} - +	if (phba->cfg_fof) { +		free_irq(phba->sli4_hba.msix_entries[index].vector, +			 &phba->sli4_hba.fcp_eq_hdl[index]); +	}  	/* Disable MSI-X */  	pci_disable_msix(phba->pcidev); @@ -8773,6 +8953,10 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba)  		phba->sli4_hba.fcp_eq_hdl[index].phba = phba;  	} +	if (phba->cfg_fof) { +		phba->sli4_hba.fcp_eq_hdl[index].idx = index; +		phba->sli4_hba.fcp_eq_hdl[index].phba = phba; +	}  	return 0;  } @@ -8855,6 +9039,12 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode)  				atomic_set(&phba->sli4_hba.fcp_eq_hdl[index].  					fcp_eq_in_use, 1);  			} +			if (phba->cfg_fof) { +				phba->sli4_hba.fcp_eq_hdl[index].idx = index; +				phba->sli4_hba.fcp_eq_hdl[index].phba = phba; +				atomic_set(&phba->sli4_hba.fcp_eq_hdl[index]. +					fcp_eq_in_use, 1); +			}  		}  	}  	return intr_mode; @@ -9165,6 +9355,7 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)  		phba->sli3_options &= ~LPFC_SLI4_PHWQ_ENABLED;  	sli4_params->sge_supp_len = mbx_sli4_parameters->sge_supp_len;  	sli4_params->loopbk_scope = bf_get(loopbk_scope, mbx_sli4_parameters); +	sli4_params->oas_supported = bf_get(cfg_oas, mbx_sli4_parameters);  	sli4_params->cqv = bf_get(cfg_cqv, mbx_sli4_parameters);  	sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters);  	sli4_params->wqv = bf_get(cfg_wqv, mbx_sli4_parameters); @@ -9429,7 +9620,6 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev)  	/* Disable interrupt */  	lpfc_sli_disable_intr(phba); -	pci_set_drvdata(pdev, NULL);  	scsi_host_put(shost);  	/* @@ -9584,9 +9774,6 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev)  static void  lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba)  { -	struct lpfc_sli *psli = &phba->sli; -	struct lpfc_sli_ring  *pring; -  	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,  			"2723 PCI channel I/O abort preparing for recovery\n"); @@ -9594,8 +9781,7 @@ lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba)  	 * There may be errored I/Os through HBA, abort all I/Os on txcmplq  	 * and let the SCSI mid-layer to retry them to recover.  	 */ -	pring = &psli->ring[psli->fcp_ring]; -	lpfc_sli_abort_iocb_ring(phba, pring); +	lpfc_sli_abort_fcp_rings(phba);  }  /** @@ -10338,17 +10524,13 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev)  static void  lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba)  { -	struct lpfc_sli *psli = &phba->sli; -	struct lpfc_sli_ring  *pring; -  	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,  			"2828 PCI channel I/O abort preparing for recovery\n");  	/*  	 * There may be errored I/Os through HBA, abort all I/Os on txcmplq  	 * and let the SCSI mid-layer to retry them to recover.  	 */ -	pring = &psli->ring[psli->fcp_ring]; -	lpfc_sli_abort_iocb_ring(phba, pring); +	lpfc_sli_abort_fcp_rings(phba);  }  /** @@ -10799,6 +10981,168 @@ lpfc_io_resume(struct pci_dev *pdev)  	return;  } +/** + * lpfc_sli4_oas_verify - Verify OAS is supported by this adapter + * @phba: pointer to lpfc hba data structure. + * + * This routine checks to see if OAS is supported for this adapter. If + * supported, the configure Flash Optimized Fabric flag is set.  Otherwise, + * the enable oas flag is cleared and the pool created for OAS device data + * is destroyed. + * + **/ +void +lpfc_sli4_oas_verify(struct lpfc_hba *phba) +{ + +	if (!phba->cfg_EnableXLane) +		return; + +	if (phba->sli4_hba.pc_sli4_params.oas_supported) { +		phba->cfg_fof = 1; +	} else { +		phba->cfg_fof = 0; +		if (phba->device_data_mem_pool) +			mempool_destroy(phba->device_data_mem_pool); +		phba->device_data_mem_pool = NULL; +	} + +	return; +} + +/** + * lpfc_fof_queue_setup - Set up all the fof queues + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to set up all the fof queues for the FC HBA + * operation. + * + * Return codes + *      0 - successful + *      -ENOMEM - No available memory + **/ +int +lpfc_fof_queue_setup(struct lpfc_hba *phba) +{ +	struct lpfc_sli *psli = &phba->sli; +	int rc; + +	rc = lpfc_eq_create(phba, phba->sli4_hba.fof_eq, LPFC_MAX_IMAX); +	if (rc) +		return -ENOMEM; + +	if (phba->cfg_fof) { + +		rc = lpfc_cq_create(phba, phba->sli4_hba.oas_cq, +				    phba->sli4_hba.fof_eq, LPFC_WCQ, LPFC_FCP); +		if (rc) +			goto out_oas_cq; + +		rc = lpfc_wq_create(phba, phba->sli4_hba.oas_wq, +				    phba->sli4_hba.oas_cq, LPFC_FCP); +		if (rc) +			goto out_oas_wq; + +		phba->sli4_hba.oas_cq->pring = &psli->ring[LPFC_FCP_OAS_RING]; +		phba->sli4_hba.oas_ring = &psli->ring[LPFC_FCP_OAS_RING]; +	} + +	return 0; + +out_oas_wq: +	lpfc_cq_destroy(phba, phba->sli4_hba.oas_cq); +out_oas_cq: +	lpfc_eq_destroy(phba, phba->sli4_hba.fof_eq); +	return rc; + +} + +/** + * lpfc_fof_queue_create - Create all the fof queues + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to allocate all the fof queues for the FC HBA + * operation. For each SLI4 queue type, the parameters such as queue entry + * count (queue depth) shall be taken from the module parameter. For now, + * we just use some constant number as place holder. + * + * Return codes + *      0 - successful + *      -ENOMEM - No availble memory + *      -EIO - The mailbox failed to complete successfully. + **/ +int +lpfc_fof_queue_create(struct lpfc_hba *phba) +{ +	struct lpfc_queue *qdesc; + +	/* Create FOF EQ */ +	qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize, +				      phba->sli4_hba.eq_ecount); +	if (!qdesc) +		goto out_error; + +	phba->sli4_hba.fof_eq = qdesc; + +	if (phba->cfg_fof) { + +		/* Create OAS CQ */ +		qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, +						      phba->sli4_hba.cq_ecount); +		if (!qdesc) +			goto out_error; + +		phba->sli4_hba.oas_cq = qdesc; + +		/* Create OAS WQ */ +		qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize, +					      phba->sli4_hba.wq_ecount); +		if (!qdesc) +			goto out_error; + +		phba->sli4_hba.oas_wq = qdesc; + +	} +	return 0; + +out_error: +	lpfc_fof_queue_destroy(phba); +	return -ENOMEM; +} + +/** + * lpfc_fof_queue_destroy - Destroy all the fof queues + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to release all the SLI4 queues with the FC HBA + * operation. + * + * Return codes + *      0 - successful + **/ +int +lpfc_fof_queue_destroy(struct lpfc_hba *phba) +{ +	/* Release FOF Event queue */ +	if (phba->sli4_hba.fof_eq != NULL) { +		lpfc_sli4_queue_free(phba->sli4_hba.fof_eq); +		phba->sli4_hba.fof_eq = NULL; +	} + +	/* Release OAS Completion queue */ +	if (phba->sli4_hba.oas_cq != NULL) { +		lpfc_sli4_queue_free(phba->sli4_hba.oas_cq); +		phba->sli4_hba.oas_cq = NULL; +	} + +	/* Release OAS Work queue */ +	if (phba->sli4_hba.oas_wq != NULL) { +		lpfc_sli4_queue_free(phba->sli4_hba.oas_wq); +		phba->sli4_hba.oas_wq = NULL; +	} +	return 0; +} +  static struct pci_device_id lpfc_id_table[] = {  	{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER,  		PCI_ANY_ID, PCI_ANY_ID, },  | 
