xref: /openbmc/linux/drivers/scsi/bfa/bfad.c (revision 973464fd)
152fa7bf9SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27725ccfdSJing Huang /*
3889d0d42SAnil Gurumurthy  * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
4889d0d42SAnil Gurumurthy  * Copyright (c) 2014- QLogic Corporation.
57725ccfdSJing Huang  * All rights reserved
6889d0d42SAnil Gurumurthy  * www.qlogic.com
77725ccfdSJing Huang  *
831e1d569SAnil Gurumurthy  * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
97725ccfdSJing Huang  */
107725ccfdSJing Huang 
115fbe25c7SJing Huang /*
127725ccfdSJing Huang  *  bfad.c Linux driver PCI interface module.
137725ccfdSJing Huang  */
147725ccfdSJing Huang #include <linux/module.h>
15e6714324SKrishna Gudipati #include <linux/kthread.h>
16a36c61f9SKrishna Gudipati #include <linux/errno.h>
17a36c61f9SKrishna Gudipati #include <linux/sched.h>
18a36c61f9SKrishna Gudipati #include <linux/init.h>
19a36c61f9SKrishna Gudipati #include <linux/fs.h>
20a36c61f9SKrishna Gudipati #include <linux/pci.h>
21a36c61f9SKrishna Gudipati #include <linux/firmware.h>
227c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
23a36c61f9SKrishna Gudipati #include <asm/fcntl.h>
24a36c61f9SKrishna Gudipati 
257725ccfdSJing Huang #include "bfad_drv.h"
267725ccfdSJing Huang #include "bfad_im.h"
27a36c61f9SKrishna Gudipati #include "bfa_fcs.h"
28a36c61f9SKrishna Gudipati #include "bfa_defs.h"
29a36c61f9SKrishna Gudipati #include "bfa.h"
307725ccfdSJing Huang 
317725ccfdSJing Huang BFA_TRC_FILE(LDRV, BFAD);
3242b426ecSJing Huang DEFINE_MUTEX(bfad_mutex);
337725ccfdSJing Huang LIST_HEAD(bfad_list);
347725ccfdSJing Huang 
35a36c61f9SKrishna Gudipati static int	bfad_inst;
36a36c61f9SKrishna Gudipati static int      num_sgpgs_parm;
37a36c61f9SKrishna Gudipati int		supported_fc4s;
38a36c61f9SKrishna Gudipati char		*host_name, *os_name, *os_patch;
39a36c61f9SKrishna Gudipati int		num_rports, num_ios, num_tms;
40a36c61f9SKrishna Gudipati int		num_fcxps, num_ufbufs;
41a36c61f9SKrishna Gudipati int		reqq_size, rspq_size, num_sgpgs;
42a36c61f9SKrishna Gudipati int		rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT;
437725ccfdSJing Huang int		bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH;
44a36c61f9SKrishna Gudipati int		bfa_io_max_sge = BFAD_IO_MAX_SGE;
4588166242SJing Huang int		bfa_log_level = 3; /* WARNING log level */
46a36c61f9SKrishna Gudipati int		ioc_auto_recover = BFA_TRUE;
477725ccfdSJing Huang int		bfa_linkup_delay = -1;
48a36c61f9SKrishna Gudipati int		fdmi_enable = BFA_TRUE;
49a36c61f9SKrishna Gudipati int		pcie_max_read_reqsz;
50ab2a9ba1SJing Huang int		bfa_debugfs_enable = 1;
51a36c61f9SKrishna Gudipati int		msix_disable_cb = 0, msix_disable_ct = 0;
5261e62e21SKrishna Gudipati int		max_xfer_size = BFAD_MAX_SECTORS >> 1;
534d5956fbSJason Yan static int	max_rport_logins = BFA_FCS_MAX_RPORT_LOGINS;
54a36c61f9SKrishna Gudipati 
5561338a0bSJing Huang /* Firmware releated */
5611189208SKrishna Gudipati u32	bfi_image_cb_size, bfi_image_ct_size, bfi_image_ct2_size;
5711189208SKrishna Gudipati u32	*bfi_image_cb, *bfi_image_ct, *bfi_image_ct2;
58a36c61f9SKrishna Gudipati 
592d1148f0SBenjamin Poirier #define BFAD_FW_FILE_CB		"cbfw-3.2.5.1.bin"
602d1148f0SBenjamin Poirier #define BFAD_FW_FILE_CT		"ctfw-3.2.5.1.bin"
612d1148f0SBenjamin Poirier #define BFAD_FW_FILE_CT2	"ct2fw-3.2.5.1.bin"
6261338a0bSJing Huang 
6361338a0bSJing Huang static u32 *bfad_load_fwimg(struct pci_dev *pdev);
6461338a0bSJing Huang static void bfad_free_fwimg(void);
6561338a0bSJing Huang static void bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
6661338a0bSJing Huang 		u32 *bfi_image_size, char *fw_name);
6761338a0bSJing Huang 
6852f94b6fSMaggie static const char *msix_name_ct[] = {
6911189208SKrishna Gudipati 	"ctrl",
70a36c61f9SKrishna Gudipati 	"cpe0", "cpe1", "cpe2", "cpe3",
7111189208SKrishna Gudipati 	"rme0", "rme1", "rme2", "rme3" };
72a36c61f9SKrishna Gudipati 
7352f94b6fSMaggie static const char *msix_name_cb[] = {
74a36c61f9SKrishna Gudipati 	"cpe0", "cpe1", "cpe2", "cpe3",
75a36c61f9SKrishna Gudipati 	"rme0", "rme1", "rme2", "rme3",
76a36c61f9SKrishna Gudipati 	"eemc", "elpu0", "elpu1", "epss", "mlpu" };
77a36c61f9SKrishna Gudipati 
7811189208SKrishna Gudipati MODULE_FIRMWARE(BFAD_FW_FILE_CB);
7911189208SKrishna Gudipati MODULE_FIRMWARE(BFAD_FW_FILE_CT);
8011189208SKrishna Gudipati MODULE_FIRMWARE(BFAD_FW_FILE_CT2);
817725ccfdSJing Huang 
827725ccfdSJing Huang module_param(os_name, charp, S_IRUGO | S_IWUSR);
83604158adSJing Huang MODULE_PARM_DESC(os_name, "OS name of the hba host machine");
847725ccfdSJing Huang module_param(os_patch, charp, S_IRUGO | S_IWUSR);
85604158adSJing Huang MODULE_PARM_DESC(os_patch, "OS patch level of the hba host machine");
867725ccfdSJing Huang module_param(host_name, charp, S_IRUGO | S_IWUSR);
87604158adSJing Huang MODULE_PARM_DESC(host_name, "Hostname of the hba host machine");
887725ccfdSJing Huang module_param(num_rports, int, S_IRUGO | S_IWUSR);
89604158adSJing Huang MODULE_PARM_DESC(num_rports, "Max number of rports supported per port "
90604158adSJing Huang 				"(physical/logical), default=1024");
917725ccfdSJing Huang module_param(num_ios, int, S_IRUGO | S_IWUSR);
92604158adSJing Huang MODULE_PARM_DESC(num_ios, "Max number of ioim requests, default=2000");
937725ccfdSJing Huang module_param(num_tms, int, S_IRUGO | S_IWUSR);
94604158adSJing Huang MODULE_PARM_DESC(num_tms, "Max number of task im requests, default=128");
957725ccfdSJing Huang module_param(num_fcxps, int, S_IRUGO | S_IWUSR);
96604158adSJing Huang MODULE_PARM_DESC(num_fcxps, "Max number of fcxp requests, default=64");
977725ccfdSJing Huang module_param(num_ufbufs, int, S_IRUGO | S_IWUSR);
98a36c61f9SKrishna Gudipati MODULE_PARM_DESC(num_ufbufs, "Max number of unsolicited frame "
99a36c61f9SKrishna Gudipati 				"buffers, default=64");
1007725ccfdSJing Huang module_param(reqq_size, int, S_IRUGO | S_IWUSR);
101604158adSJing Huang MODULE_PARM_DESC(reqq_size, "Max number of request queue elements, "
102604158adSJing Huang 				"default=256");
1037725ccfdSJing Huang module_param(rspq_size, int, S_IRUGO | S_IWUSR);
104604158adSJing Huang MODULE_PARM_DESC(rspq_size, "Max number of response queue elements, "
105604158adSJing Huang 				"default=64");
1067725ccfdSJing Huang module_param(num_sgpgs, int, S_IRUGO | S_IWUSR);
107604158adSJing Huang MODULE_PARM_DESC(num_sgpgs, "Number of scatter/gather pages, default=2048");
1087725ccfdSJing Huang module_param(rport_del_timeout, int, S_IRUGO | S_IWUSR);
109604158adSJing Huang MODULE_PARM_DESC(rport_del_timeout, "Rport delete timeout, default=90 secs, "
110604158adSJing Huang 					"Range[>0]");
1117725ccfdSJing Huang module_param(bfa_lun_queue_depth, int, S_IRUGO | S_IWUSR);
112a36c61f9SKrishna Gudipati MODULE_PARM_DESC(bfa_lun_queue_depth, "Lun queue depth, default=32, Range[>0]");
1137725ccfdSJing Huang module_param(bfa_io_max_sge, int, S_IRUGO | S_IWUSR);
114604158adSJing Huang MODULE_PARM_DESC(bfa_io_max_sge, "Max io scatter/gather elements, default=255");
11588166242SJing Huang module_param(bfa_log_level, int, S_IRUGO | S_IWUSR);
11688166242SJing Huang MODULE_PARM_DESC(bfa_log_level, "Driver log level, default=3, "
117604158adSJing Huang 				"Range[Critical:1|Error:2|Warning:3|Info:4]");
1187725ccfdSJing Huang module_param(ioc_auto_recover, int, S_IRUGO | S_IWUSR);
119604158adSJing Huang MODULE_PARM_DESC(ioc_auto_recover, "IOC auto recovery, default=1, "
120604158adSJing Huang 				"Range[off:0|on:1]");
1217725ccfdSJing Huang module_param(bfa_linkup_delay, int, S_IRUGO | S_IWUSR);
122a36c61f9SKrishna Gudipati MODULE_PARM_DESC(bfa_linkup_delay, "Link up delay, default=30 secs for "
123a36c61f9SKrishna Gudipati 			"boot port. Otherwise 10 secs in RHEL4 & 0 for "
124a36c61f9SKrishna Gudipati 			"[RHEL5, SLES10, ESX40] Range[>0]");
125a36c61f9SKrishna Gudipati module_param(msix_disable_cb, int, S_IRUGO | S_IWUSR);
12631e1d569SAnil Gurumurthy MODULE_PARM_DESC(msix_disable_cb, "Disable Message Signaled Interrupts for QLogic-415/425/815/825 cards, default=0 Range[false:0|true:1]");
127a36c61f9SKrishna Gudipati module_param(msix_disable_ct, int, S_IRUGO | S_IWUSR);
12831e1d569SAnil Gurumurthy MODULE_PARM_DESC(msix_disable_ct, "Disable Message Signaled Interrupts if possible for QLogic-1010/1020/804/1007/902/1741 cards, default=0, Range[false:0|true:1]");
129604158adSJing Huang module_param(fdmi_enable, int, S_IRUGO | S_IWUSR);
130604158adSJing Huang MODULE_PARM_DESC(fdmi_enable, "Enables fdmi registration, default=1, "
131604158adSJing Huang 				"Range[false:0|true:1]");
132a36c61f9SKrishna Gudipati module_param(pcie_max_read_reqsz, int, S_IRUGO | S_IWUSR);
133a36c61f9SKrishna Gudipati MODULE_PARM_DESC(pcie_max_read_reqsz, "PCIe max read request size, default=0 "
134a36c61f9SKrishna Gudipati 		"(use system setting), Range[128|256|512|1024|2048|4096]");
135ab2a9ba1SJing Huang module_param(bfa_debugfs_enable, int, S_IRUGO | S_IWUSR);
136ab2a9ba1SJing Huang MODULE_PARM_DESC(bfa_debugfs_enable, "Enables debugfs feature, default=1,"
137ab2a9ba1SJing Huang 		" Range[false:0|true:1]");
13861e62e21SKrishna Gudipati module_param(max_xfer_size, int, S_IRUGO | S_IWUSR);
13961e62e21SKrishna Gudipati MODULE_PARM_DESC(max_xfer_size, "default=32MB,"
14061e62e21SKrishna Gudipati 		" Range[64k|128k|256k|512k|1024k|2048k]");
14161ba4394SKrishna Gudipati module_param(max_rport_logins, int, S_IRUGO | S_IWUSR);
14261ba4394SKrishna Gudipati MODULE_PARM_DESC(max_rport_logins, "Max number of logins to initiator and target rports on a port (physical/logical), default=1024");
1437725ccfdSJing Huang 
144a36c61f9SKrishna Gudipati static void
145a36c61f9SKrishna Gudipati bfad_sm_uninit(struct bfad_s *bfad, enum bfad_sm_event event);
146a36c61f9SKrishna Gudipati static void
147a36c61f9SKrishna Gudipati bfad_sm_created(struct bfad_s *bfad, enum bfad_sm_event event);
148a36c61f9SKrishna Gudipati static void
149a36c61f9SKrishna Gudipati bfad_sm_initializing(struct bfad_s *bfad, enum bfad_sm_event event);
150a36c61f9SKrishna Gudipati static void
151a36c61f9SKrishna Gudipati bfad_sm_operational(struct bfad_s *bfad, enum bfad_sm_event event);
152a36c61f9SKrishna Gudipati static void
153a36c61f9SKrishna Gudipati bfad_sm_stopping(struct bfad_s *bfad, enum bfad_sm_event event);
154a36c61f9SKrishna Gudipati static void
155a36c61f9SKrishna Gudipati bfad_sm_failed(struct bfad_s *bfad, enum bfad_sm_event event);
156a36c61f9SKrishna Gudipati static void
157a36c61f9SKrishna Gudipati bfad_sm_fcs_exit(struct bfad_s *bfad, enum bfad_sm_event event);
158a36c61f9SKrishna Gudipati 
1595fbe25c7SJing Huang /*
160a36c61f9SKrishna Gudipati  * Beginning state for the driver instance, awaiting the pci_probe event
1617725ccfdSJing Huang  */
162a36c61f9SKrishna Gudipati static void
bfad_sm_uninit(struct bfad_s * bfad,enum bfad_sm_event event)163a36c61f9SKrishna Gudipati bfad_sm_uninit(struct bfad_s *bfad, enum bfad_sm_event event)
1647725ccfdSJing Huang {
165a36c61f9SKrishna Gudipati 	bfa_trc(bfad, event);
1667725ccfdSJing Huang 
167a36c61f9SKrishna Gudipati 	switch (event) {
168a36c61f9SKrishna Gudipati 	case BFAD_E_CREATE:
169a36c61f9SKrishna Gudipati 		bfa_sm_set_state(bfad, bfad_sm_created);
170a36c61f9SKrishna Gudipati 		bfad->bfad_tsk = kthread_create(bfad_worker, (void *) bfad,
171a36c61f9SKrishna Gudipati 						"%s", "bfad_worker");
172a36c61f9SKrishna Gudipati 		if (IS_ERR(bfad->bfad_tsk)) {
173a36c61f9SKrishna Gudipati 			printk(KERN_INFO "bfad[%d]: Kernel thread "
174a36c61f9SKrishna Gudipati 				"creation failed!\n", bfad->inst_no);
175a36c61f9SKrishna Gudipati 			bfa_sm_send_event(bfad, BFAD_E_KTHREAD_CREATE_FAILED);
176a36c61f9SKrishna Gudipati 		}
177a36c61f9SKrishna Gudipati 		bfa_sm_send_event(bfad, BFAD_E_INIT);
178a36c61f9SKrishna Gudipati 		break;
1797725ccfdSJing Huang 
180a36c61f9SKrishna Gudipati 	case BFAD_E_STOP:
181a36c61f9SKrishna Gudipati 		/* Ignore stop; already in uninit */
182a36c61f9SKrishna Gudipati 		break;
1837725ccfdSJing Huang 
184a36c61f9SKrishna Gudipati 	default:
185a36c61f9SKrishna Gudipati 		bfa_sm_fault(bfad, event);
186a36c61f9SKrishna Gudipati 	}
187a36c61f9SKrishna Gudipati }
188e6714324SKrishna Gudipati 
1895fbe25c7SJing Huang /*
190a36c61f9SKrishna Gudipati  * Driver Instance is created, awaiting event INIT to initialize the bfad
191a36c61f9SKrishna Gudipati  */
192a36c61f9SKrishna Gudipati static void
bfad_sm_created(struct bfad_s * bfad,enum bfad_sm_event event)193a36c61f9SKrishna Gudipati bfad_sm_created(struct bfad_s *bfad, enum bfad_sm_event event)
194a36c61f9SKrishna Gudipati {
195a36c61f9SKrishna Gudipati 	unsigned long flags;
196da3e0beeSVijaya Mohan Guvva 	bfa_status_t ret;
197a36c61f9SKrishna Gudipati 
198a36c61f9SKrishna Gudipati 	bfa_trc(bfad, event);
199a36c61f9SKrishna Gudipati 
200a36c61f9SKrishna Gudipati 	switch (event) {
201a36c61f9SKrishna Gudipati 	case BFAD_E_INIT:
202a36c61f9SKrishna Gudipati 		bfa_sm_set_state(bfad, bfad_sm_initializing);
203a36c61f9SKrishna Gudipati 
204a36c61f9SKrishna Gudipati 		init_completion(&bfad->comp);
205a36c61f9SKrishna Gudipati 
206a36c61f9SKrishna Gudipati 		/* Enable Interrupt and wait bfa_init completion */
207a36c61f9SKrishna Gudipati 		if (bfad_setup_intr(bfad)) {
208a36c61f9SKrishna Gudipati 			printk(KERN_WARNING "bfad%d: bfad_setup_intr failed\n",
209a36c61f9SKrishna Gudipati 					bfad->inst_no);
210da3e0beeSVijaya Mohan Guvva 			bfa_sm_send_event(bfad, BFAD_E_INIT_FAILED);
211a36c61f9SKrishna Gudipati 			break;
212a36c61f9SKrishna Gudipati 		}
213a36c61f9SKrishna Gudipati 
214a36c61f9SKrishna Gudipati 		spin_lock_irqsave(&bfad->bfad_lock, flags);
215f7f73812SMaggie Zhang 		bfa_iocfc_init(&bfad->bfa);
216a36c61f9SKrishna Gudipati 		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
217a36c61f9SKrishna Gudipati 
218a36c61f9SKrishna Gudipati 		/* Set up interrupt handler for each vectors */
219a36c61f9SKrishna Gudipati 		if ((bfad->bfad_flags & BFAD_MSIX_ON) &&
220a36c61f9SKrishna Gudipati 			bfad_install_msix_handler(bfad)) {
221a36c61f9SKrishna Gudipati 			printk(KERN_WARNING "%s: install_msix failed, bfad%d\n",
222a36c61f9SKrishna Gudipati 				__func__, bfad->inst_no);
223a36c61f9SKrishna Gudipati 		}
224a36c61f9SKrishna Gudipati 
225a36c61f9SKrishna Gudipati 		bfad_init_timer(bfad);
226a36c61f9SKrishna Gudipati 
227a36c61f9SKrishna Gudipati 		wait_for_completion(&bfad->comp);
228a36c61f9SKrishna Gudipati 
229a36c61f9SKrishna Gudipati 		if ((bfad->bfad_flags & BFAD_HAL_INIT_DONE)) {
230a36c61f9SKrishna Gudipati 			bfa_sm_send_event(bfad, BFAD_E_INIT_SUCCESS);
231a36c61f9SKrishna Gudipati 		} else {
2327c38c05bSKrishna Gudipati 			printk(KERN_WARNING
2337c38c05bSKrishna Gudipati 				"bfa %s: bfa init failed\n",
2347c38c05bSKrishna Gudipati 				bfad->pci_name);
235da3e0beeSVijaya Mohan Guvva 			spin_lock_irqsave(&bfad->bfad_lock, flags);
236da3e0beeSVijaya Mohan Guvva 			bfa_fcs_init(&bfad->bfa_fcs);
237da3e0beeSVijaya Mohan Guvva 			spin_unlock_irqrestore(&bfad->bfad_lock, flags);
238da3e0beeSVijaya Mohan Guvva 
239da3e0beeSVijaya Mohan Guvva 			ret = bfad_cfg_pport(bfad, BFA_LPORT_ROLE_FCP_IM);
240da3e0beeSVijaya Mohan Guvva 			if (ret != BFA_STATUS_OK) {
241da3e0beeSVijaya Mohan Guvva 				init_completion(&bfad->comp);
242da3e0beeSVijaya Mohan Guvva 
243da3e0beeSVijaya Mohan Guvva 				spin_lock_irqsave(&bfad->bfad_lock, flags);
244da3e0beeSVijaya Mohan Guvva 				bfad->pport.flags |= BFAD_PORT_DELETE;
245da3e0beeSVijaya Mohan Guvva 				bfa_fcs_exit(&bfad->bfa_fcs);
246da3e0beeSVijaya Mohan Guvva 				spin_unlock_irqrestore(&bfad->bfad_lock, flags);
247da3e0beeSVijaya Mohan Guvva 
248da3e0beeSVijaya Mohan Guvva 				wait_for_completion(&bfad->comp);
249da3e0beeSVijaya Mohan Guvva 
250a36c61f9SKrishna Gudipati 				bfa_sm_send_event(bfad, BFAD_E_INIT_FAILED);
251da3e0beeSVijaya Mohan Guvva 				break;
252da3e0beeSVijaya Mohan Guvva 			}
253da3e0beeSVijaya Mohan Guvva 			bfad->bfad_flags |= BFAD_HAL_INIT_FAIL;
254da3e0beeSVijaya Mohan Guvva 			bfa_sm_send_event(bfad, BFAD_E_HAL_INIT_FAILED);
255a36c61f9SKrishna Gudipati 		}
256a36c61f9SKrishna Gudipati 
257a36c61f9SKrishna Gudipati 		break;
258a36c61f9SKrishna Gudipati 
259a36c61f9SKrishna Gudipati 	case BFAD_E_KTHREAD_CREATE_FAILED:
260a36c61f9SKrishna Gudipati 		bfa_sm_set_state(bfad, bfad_sm_uninit);
261a36c61f9SKrishna Gudipati 		break;
262a36c61f9SKrishna Gudipati 
263a36c61f9SKrishna Gudipati 	default:
264a36c61f9SKrishna Gudipati 		bfa_sm_fault(bfad, event);
265a36c61f9SKrishna Gudipati 	}
2667725ccfdSJing Huang }
2677725ccfdSJing Huang 
2687725ccfdSJing Huang static void
bfad_sm_initializing(struct bfad_s * bfad,enum bfad_sm_event event)269a36c61f9SKrishna Gudipati bfad_sm_initializing(struct bfad_s *bfad, enum bfad_sm_event event)
2707725ccfdSJing Huang {
271a36c61f9SKrishna Gudipati 	int	retval;
272a36c61f9SKrishna Gudipati 	unsigned long	flags;
273a36c61f9SKrishna Gudipati 
274a36c61f9SKrishna Gudipati 	bfa_trc(bfad, event);
275a36c61f9SKrishna Gudipati 
276a36c61f9SKrishna Gudipati 	switch (event) {
277a36c61f9SKrishna Gudipati 	case BFAD_E_INIT_SUCCESS:
278a36c61f9SKrishna Gudipati 		kthread_stop(bfad->bfad_tsk);
279a36c61f9SKrishna Gudipati 		spin_lock_irqsave(&bfad->bfad_lock, flags);
280a36c61f9SKrishna Gudipati 		bfad->bfad_tsk = NULL;
281a36c61f9SKrishna Gudipati 		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
282a36c61f9SKrishna Gudipati 
283a36c61f9SKrishna Gudipati 		retval = bfad_start_ops(bfad);
284da3e0beeSVijaya Mohan Guvva 		if (retval != BFA_STATUS_OK) {
285da3e0beeSVijaya Mohan Guvva 			bfa_sm_set_state(bfad, bfad_sm_failed);
286a36c61f9SKrishna Gudipati 			break;
287da3e0beeSVijaya Mohan Guvva 		}
288a36c61f9SKrishna Gudipati 		bfa_sm_set_state(bfad, bfad_sm_operational);
289a36c61f9SKrishna Gudipati 		break;
290a36c61f9SKrishna Gudipati 
291da3e0beeSVijaya Mohan Guvva 	case BFAD_E_INIT_FAILED:
292a36c61f9SKrishna Gudipati 		bfa_sm_set_state(bfad, bfad_sm_uninit);
293a36c61f9SKrishna Gudipati 		kthread_stop(bfad->bfad_tsk);
294a36c61f9SKrishna Gudipati 		spin_lock_irqsave(&bfad->bfad_lock, flags);
295a36c61f9SKrishna Gudipati 		bfad->bfad_tsk = NULL;
296a36c61f9SKrishna Gudipati 		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
297a36c61f9SKrishna Gudipati 		break;
298a36c61f9SKrishna Gudipati 
299da3e0beeSVijaya Mohan Guvva 	case BFAD_E_HAL_INIT_FAILED:
300a36c61f9SKrishna Gudipati 		bfa_sm_set_state(bfad, bfad_sm_failed);
301a36c61f9SKrishna Gudipati 		break;
302a36c61f9SKrishna Gudipati 	default:
303a36c61f9SKrishna Gudipati 		bfa_sm_fault(bfad, event);
304a36c61f9SKrishna Gudipati 	}
305a36c61f9SKrishna Gudipati }
306a36c61f9SKrishna Gudipati 
307a36c61f9SKrishna Gudipati static void
bfad_sm_failed(struct bfad_s * bfad,enum bfad_sm_event event)308a36c61f9SKrishna Gudipati bfad_sm_failed(struct bfad_s *bfad, enum bfad_sm_event event)
309a36c61f9SKrishna Gudipati {
310a36c61f9SKrishna Gudipati 	int	retval;
311a36c61f9SKrishna Gudipati 
312a36c61f9SKrishna Gudipati 	bfa_trc(bfad, event);
313a36c61f9SKrishna Gudipati 
314a36c61f9SKrishna Gudipati 	switch (event) {
315a36c61f9SKrishna Gudipati 	case BFAD_E_INIT_SUCCESS:
316a36c61f9SKrishna Gudipati 		retval = bfad_start_ops(bfad);
317a36c61f9SKrishna Gudipati 		if (retval != BFA_STATUS_OK)
318a36c61f9SKrishna Gudipati 			break;
319a36c61f9SKrishna Gudipati 		bfa_sm_set_state(bfad, bfad_sm_operational);
320a36c61f9SKrishna Gudipati 		break;
321a36c61f9SKrishna Gudipati 
322a36c61f9SKrishna Gudipati 	case BFAD_E_STOP:
323da3e0beeSVijaya Mohan Guvva 		bfa_sm_set_state(bfad, bfad_sm_fcs_exit);
324da3e0beeSVijaya Mohan Guvva 		bfa_sm_send_event(bfad, BFAD_E_FCS_EXIT_COMP);
325a36c61f9SKrishna Gudipati 		break;
3267725ccfdSJing Huang 
327a36c61f9SKrishna Gudipati 	case BFAD_E_EXIT_COMP:
328a36c61f9SKrishna Gudipati 		bfa_sm_set_state(bfad, bfad_sm_uninit);
329a36c61f9SKrishna Gudipati 		bfad_remove_intr(bfad);
330a36c61f9SKrishna Gudipati 		del_timer_sync(&bfad->hal_tmo);
331a36c61f9SKrishna Gudipati 		break;
3327725ccfdSJing Huang 
333a36c61f9SKrishna Gudipati 	default:
334a36c61f9SKrishna Gudipati 		bfa_sm_fault(bfad, event);
3357725ccfdSJing Huang 	}
3367725ccfdSJing Huang }
3377725ccfdSJing Huang 
3387725ccfdSJing Huang static void
bfad_sm_operational(struct bfad_s * bfad,enum bfad_sm_event event)339a36c61f9SKrishna Gudipati bfad_sm_operational(struct bfad_s *bfad, enum bfad_sm_event event)
3407725ccfdSJing Huang {
341a36c61f9SKrishna Gudipati 	bfa_trc(bfad, event);
3427725ccfdSJing Huang 
343a36c61f9SKrishna Gudipati 	switch (event) {
344a36c61f9SKrishna Gudipati 	case BFAD_E_STOP:
345a36c61f9SKrishna Gudipati 		bfa_sm_set_state(bfad, bfad_sm_fcs_exit);
346a36c61f9SKrishna Gudipati 		bfad_fcs_stop(bfad);
347a36c61f9SKrishna Gudipati 		break;
3487725ccfdSJing Huang 
349a36c61f9SKrishna Gudipati 	default:
350a36c61f9SKrishna Gudipati 		bfa_sm_fault(bfad, event);
351a36c61f9SKrishna Gudipati 	}
352a36c61f9SKrishna Gudipati }
353a36c61f9SKrishna Gudipati 
354a36c61f9SKrishna Gudipati static void
bfad_sm_fcs_exit(struct bfad_s * bfad,enum bfad_sm_event event)355a36c61f9SKrishna Gudipati bfad_sm_fcs_exit(struct bfad_s *bfad, enum bfad_sm_event event)
356a36c61f9SKrishna Gudipati {
357a36c61f9SKrishna Gudipati 	bfa_trc(bfad, event);
358a36c61f9SKrishna Gudipati 
359a36c61f9SKrishna Gudipati 	switch (event) {
360a36c61f9SKrishna Gudipati 	case BFAD_E_FCS_EXIT_COMP:
361a36c61f9SKrishna Gudipati 		bfa_sm_set_state(bfad, bfad_sm_stopping);
362a36c61f9SKrishna Gudipati 		bfad_stop(bfad);
363a36c61f9SKrishna Gudipati 		break;
364a36c61f9SKrishna Gudipati 
365a36c61f9SKrishna Gudipati 	default:
366a36c61f9SKrishna Gudipati 		bfa_sm_fault(bfad, event);
367a36c61f9SKrishna Gudipati 	}
368a36c61f9SKrishna Gudipati }
369a36c61f9SKrishna Gudipati 
370a36c61f9SKrishna Gudipati static void
bfad_sm_stopping(struct bfad_s * bfad,enum bfad_sm_event event)371a36c61f9SKrishna Gudipati bfad_sm_stopping(struct bfad_s *bfad, enum bfad_sm_event event)
372a36c61f9SKrishna Gudipati {
373a36c61f9SKrishna Gudipati 	bfa_trc(bfad, event);
374a36c61f9SKrishna Gudipati 
375a36c61f9SKrishna Gudipati 	switch (event) {
376a36c61f9SKrishna Gudipati 	case BFAD_E_EXIT_COMP:
377a36c61f9SKrishna Gudipati 		bfa_sm_set_state(bfad, bfad_sm_uninit);
378a36c61f9SKrishna Gudipati 		bfad_remove_intr(bfad);
379a36c61f9SKrishna Gudipati 		del_timer_sync(&bfad->hal_tmo);
380a36c61f9SKrishna Gudipati 		bfad_im_probe_undo(bfad);
381a36c61f9SKrishna Gudipati 		bfad->bfad_flags &= ~BFAD_FC4_PROBE_DONE;
382a36c61f9SKrishna Gudipati 		bfad_uncfg_pport(bfad);
383a36c61f9SKrishna Gudipati 		break;
384a36c61f9SKrishna Gudipati 
385a36c61f9SKrishna Gudipati 	default:
386a36c61f9SKrishna Gudipati 		bfa_sm_fault(bfad, event);
387a36c61f9SKrishna Gudipati 		break;
388a36c61f9SKrishna Gudipati 	}
3897725ccfdSJing Huang }
3907725ccfdSJing Huang 
3915fbe25c7SJing Huang /*
3927725ccfdSJing Huang  *  BFA callbacks
3937725ccfdSJing Huang  */
3947725ccfdSJing Huang void
bfad_hcb_comp(void * arg,bfa_status_t status)3957725ccfdSJing Huang bfad_hcb_comp(void *arg, bfa_status_t status)
3967725ccfdSJing Huang {
3977725ccfdSJing Huang 	struct bfad_hal_comp *fcomp = (struct bfad_hal_comp *)arg;
3987725ccfdSJing Huang 
3997725ccfdSJing Huang 	fcomp->status = status;
4007725ccfdSJing Huang 	complete(&fcomp->comp);
4017725ccfdSJing Huang }
4027725ccfdSJing Huang 
4035fbe25c7SJing Huang /*
4047725ccfdSJing Huang  * bfa_init callback
4057725ccfdSJing Huang  */
4067725ccfdSJing Huang void
bfa_cb_init(void * drv,bfa_status_t init_status)4077725ccfdSJing Huang bfa_cb_init(void *drv, bfa_status_t init_status)
4087725ccfdSJing Huang {
4097725ccfdSJing Huang 	struct bfad_s	      *bfad = drv;
4107725ccfdSJing Huang 
411e6714324SKrishna Gudipati 	if (init_status == BFA_STATUS_OK) {
4127725ccfdSJing Huang 		bfad->bfad_flags |= BFAD_HAL_INIT_DONE;
4137725ccfdSJing Huang 
414a36c61f9SKrishna Gudipati 		/*
415a36c61f9SKrishna Gudipati 		 * If BFAD_HAL_INIT_FAIL flag is set:
416e6714324SKrishna Gudipati 		 * Wake up the kernel thread to start
417e6714324SKrishna Gudipati 		 * the bfad operations after HAL init done
418e6714324SKrishna Gudipati 		 */
419e6714324SKrishna Gudipati 		if ((bfad->bfad_flags & BFAD_HAL_INIT_FAIL)) {
420e6714324SKrishna Gudipati 			bfad->bfad_flags &= ~BFAD_HAL_INIT_FAIL;
421e6714324SKrishna Gudipati 			wake_up_process(bfad->bfad_tsk);
422e6714324SKrishna Gudipati 		}
423e6714324SKrishna Gudipati 	}
424e6714324SKrishna Gudipati 
4257725ccfdSJing Huang 	complete(&bfad->comp);
4267725ccfdSJing Huang }
4277725ccfdSJing Huang 
4285fbe25c7SJing Huang /*
4297725ccfdSJing Huang  *  BFA_FCS callbacks
4307725ccfdSJing Huang  */
4317725ccfdSJing Huang struct bfad_port_s *
bfa_fcb_lport_new(struct bfad_s * bfad,struct bfa_fcs_lport_s * port,enum bfa_lport_role roles,struct bfad_vf_s * vf_drv,struct bfad_vport_s * vp_drv)432a36c61f9SKrishna Gudipati bfa_fcb_lport_new(struct bfad_s *bfad, struct bfa_fcs_lport_s *port,
433a36c61f9SKrishna Gudipati 		 enum bfa_lport_role roles, struct bfad_vf_s *vf_drv,
4347725ccfdSJing Huang 		 struct bfad_vport_s *vp_drv)
4357725ccfdSJing Huang {
4367725ccfdSJing Huang 	bfa_status_t	rc;
4377725ccfdSJing Huang 	struct bfad_port_s    *port_drv;
4387725ccfdSJing Huang 
4397725ccfdSJing Huang 	if (!vp_drv && !vf_drv) {
4407725ccfdSJing Huang 		port_drv = &bfad->pport;
4417725ccfdSJing Huang 		port_drv->pvb_type = BFAD_PORT_PHYS_BASE;
4427725ccfdSJing Huang 	} else if (!vp_drv && vf_drv) {
4437725ccfdSJing Huang 		port_drv = &vf_drv->base_port;
4447725ccfdSJing Huang 		port_drv->pvb_type = BFAD_PORT_VF_BASE;
4457725ccfdSJing Huang 	} else if (vp_drv && !vf_drv) {
4467725ccfdSJing Huang 		port_drv = &vp_drv->drv_port;
4477725ccfdSJing Huang 		port_drv->pvb_type = BFAD_PORT_PHYS_VPORT;
4487725ccfdSJing Huang 	} else {
4497725ccfdSJing Huang 		port_drv = &vp_drv->drv_port;
4507725ccfdSJing Huang 		port_drv->pvb_type = BFAD_PORT_VF_VPORT;
4517725ccfdSJing Huang 	}
4527725ccfdSJing Huang 
4537725ccfdSJing Huang 	port_drv->fcs_port = port;
4547725ccfdSJing Huang 	port_drv->roles = roles;
455a36c61f9SKrishna Gudipati 
456a36c61f9SKrishna Gudipati 	if (roles & BFA_LPORT_ROLE_FCP_IM) {
457a36c61f9SKrishna Gudipati 		rc = bfad_im_port_new(bfad, port_drv);
4587725ccfdSJing Huang 		if (rc != BFA_STATUS_OK) {
459a36c61f9SKrishna Gudipati 			bfad_im_port_delete(bfad, port_drv);
4607725ccfdSJing Huang 			port_drv = NULL;
4617725ccfdSJing Huang 		}
462a36c61f9SKrishna Gudipati 	}
4637725ccfdSJing Huang 
4647725ccfdSJing Huang 	return port_drv;
4657725ccfdSJing Huang }
4667725ccfdSJing Huang 
4675fbe25c7SJing Huang /*
4687725ccfdSJing Huang  * FCS RPORT alloc callback, after successful PLOGI by FCS
4697725ccfdSJing Huang  */
4707725ccfdSJing Huang bfa_status_t
bfa_fcb_rport_alloc(struct bfad_s * bfad,struct bfa_fcs_rport_s ** rport,struct bfad_rport_s ** rport_drv)4717725ccfdSJing Huang bfa_fcb_rport_alloc(struct bfad_s *bfad, struct bfa_fcs_rport_s **rport,
4727725ccfdSJing Huang 		    struct bfad_rport_s **rport_drv)
4737725ccfdSJing Huang {
4747725ccfdSJing Huang 	bfa_status_t	rc = BFA_STATUS_OK;
4757725ccfdSJing Huang 
4767725ccfdSJing Huang 	*rport_drv = kzalloc(sizeof(struct bfad_rport_s), GFP_ATOMIC);
4777725ccfdSJing Huang 	if (*rport_drv == NULL) {
4787725ccfdSJing Huang 		rc = BFA_STATUS_ENOMEM;
4797725ccfdSJing Huang 		goto ext;
4807725ccfdSJing Huang 	}
4817725ccfdSJing Huang 
4827725ccfdSJing Huang 	*rport = &(*rport_drv)->fcs_rport;
4837725ccfdSJing Huang 
4847725ccfdSJing Huang ext:
4857725ccfdSJing Huang 	return rc;
4867725ccfdSJing Huang }
4877725ccfdSJing Huang 
4885fbe25c7SJing Huang /*
489d9883548SJing Huang  * FCS PBC VPORT Create
490d9883548SJing Huang  */
491d9883548SJing Huang void
bfa_fcb_pbc_vport_create(struct bfad_s * bfad,struct bfi_pbc_vport_s pbc_vport)492d9883548SJing Huang bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s pbc_vport)
493d9883548SJing Huang {
4947725ccfdSJing Huang 
495a36c61f9SKrishna Gudipati 	struct bfa_lport_cfg_s port_cfg = {0};
496a36c61f9SKrishna Gudipati 	struct bfad_vport_s   *vport;
497a36c61f9SKrishna Gudipati 	int rc;
498d9883548SJing Huang 
499dc6d2a0fSAlexey Khoroshilov 	vport = kzalloc(sizeof(struct bfad_vport_s), GFP_ATOMIC);
500a36c61f9SKrishna Gudipati 	if (!vport) {
501d9883548SJing Huang 		bfa_trc(bfad, 0);
502d9883548SJing Huang 		return;
503d9883548SJing Huang 	}
504d9883548SJing Huang 
505a36c61f9SKrishna Gudipati 	vport->drv_port.bfad = bfad;
506a36c61f9SKrishna Gudipati 	port_cfg.roles = BFA_LPORT_ROLE_FCP_IM;
507a36c61f9SKrishna Gudipati 	port_cfg.pwwn = pbc_vport.vp_pwwn;
508a36c61f9SKrishna Gudipati 	port_cfg.nwwn = pbc_vport.vp_nwwn;
509a36c61f9SKrishna Gudipati 	port_cfg.preboot_vp  = BFA_TRUE;
510d9883548SJing Huang 
511a36c61f9SKrishna Gudipati 	rc = bfa_fcs_pbc_vport_create(&vport->fcs_vport, &bfad->bfa_fcs, 0,
512a36c61f9SKrishna Gudipati 				  &port_cfg, vport);
513d9883548SJing Huang 
514a36c61f9SKrishna Gudipati 	if (rc != BFA_STATUS_OK) {
515a36c61f9SKrishna Gudipati 		bfa_trc(bfad, 0);
516d9883548SJing Huang 		return;
517d9883548SJing Huang 	}
5187725ccfdSJing Huang 
519a36c61f9SKrishna Gudipati 	list_add_tail(&vport->list_entry, &bfad->pbc_vport_list);
520a36c61f9SKrishna Gudipati }
521a36c61f9SKrishna Gudipati 
5227725ccfdSJing Huang void
bfad_hal_mem_release(struct bfad_s * bfad)5237725ccfdSJing Huang bfad_hal_mem_release(struct bfad_s *bfad)
5247725ccfdSJing Huang {
5257725ccfdSJing Huang 	struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo;
5264507025dSKrishna Gudipati 	struct bfa_mem_dma_s *dma_info, *dma_elem;
5274507025dSKrishna Gudipati 	struct bfa_mem_kva_s *kva_info, *kva_elem;
5284507025dSKrishna Gudipati 	struct list_head *dm_qe, *km_qe;
5297725ccfdSJing Huang 
5304507025dSKrishna Gudipati 	dma_info = &hal_meminfo->dma_info;
5314507025dSKrishna Gudipati 	kva_info = &hal_meminfo->kva_info;
5324507025dSKrishna Gudipati 
5334507025dSKrishna Gudipati 	/* Iterate through the KVA meminfo queue */
5344507025dSKrishna Gudipati 	list_for_each(km_qe, &kva_info->qe) {
5354507025dSKrishna Gudipati 		kva_elem = (struct bfa_mem_kva_s *) km_qe;
5364507025dSKrishna Gudipati 		vfree(kva_elem->kva);
5374507025dSKrishna Gudipati 	}
5384507025dSKrishna Gudipati 
5394507025dSKrishna Gudipati 	/* Iterate through the DMA meminfo queue */
5404507025dSKrishna Gudipati 	list_for_each(dm_qe, &dma_info->qe) {
5414507025dSKrishna Gudipati 		dma_elem = (struct bfa_mem_dma_s *) dm_qe;
5427725ccfdSJing Huang 		dma_free_coherent(&bfad->pcidev->dev,
5434507025dSKrishna Gudipati 				dma_elem->mem_len, dma_elem->kva,
5444507025dSKrishna Gudipati 				(dma_addr_t) dma_elem->dma);
5457725ccfdSJing Huang 	}
5467725ccfdSJing Huang 
5477725ccfdSJing Huang 	memset(hal_meminfo, 0, sizeof(struct bfa_meminfo_s));
5487725ccfdSJing Huang }
5497725ccfdSJing Huang 
5507725ccfdSJing Huang void
bfad_update_hal_cfg(struct bfa_iocfc_cfg_s * bfa_cfg)5517725ccfdSJing Huang bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg)
5527725ccfdSJing Huang {
5537725ccfdSJing Huang 	if (num_rports > 0)
5547725ccfdSJing Huang 		bfa_cfg->fwcfg.num_rports = num_rports;
5557725ccfdSJing Huang 	if (num_ios > 0)
5567725ccfdSJing Huang 		bfa_cfg->fwcfg.num_ioim_reqs = num_ios;
5577725ccfdSJing Huang 	if (num_tms > 0)
5587725ccfdSJing Huang 		bfa_cfg->fwcfg.num_tskim_reqs = num_tms;
5594507025dSKrishna Gudipati 	if (num_fcxps > 0 && num_fcxps <= BFA_FCXP_MAX)
5607725ccfdSJing Huang 		bfa_cfg->fwcfg.num_fcxp_reqs = num_fcxps;
5614507025dSKrishna Gudipati 	if (num_ufbufs > 0 && num_ufbufs <= BFA_UF_MAX)
5627725ccfdSJing Huang 		bfa_cfg->fwcfg.num_uf_bufs = num_ufbufs;
5637725ccfdSJing Huang 	if (reqq_size > 0)
5647725ccfdSJing Huang 		bfa_cfg->drvcfg.num_reqq_elems = reqq_size;
5657725ccfdSJing Huang 	if (rspq_size > 0)
5667725ccfdSJing Huang 		bfa_cfg->drvcfg.num_rspq_elems = rspq_size;
5674507025dSKrishna Gudipati 	if (num_sgpgs > 0 && num_sgpgs <= BFA_SGPG_MAX)
5687725ccfdSJing Huang 		bfa_cfg->drvcfg.num_sgpgs = num_sgpgs;
5697725ccfdSJing Huang 
5707725ccfdSJing Huang 	/*
5717725ccfdSJing Huang 	 * populate the hal values back to the driver for sysfs use.
5727725ccfdSJing Huang 	 * otherwise, the default values will be shown as 0 in sysfs
5737725ccfdSJing Huang 	 */
5747725ccfdSJing Huang 	num_rports = bfa_cfg->fwcfg.num_rports;
5757725ccfdSJing Huang 	num_ios = bfa_cfg->fwcfg.num_ioim_reqs;
5767725ccfdSJing Huang 	num_tms = bfa_cfg->fwcfg.num_tskim_reqs;
5777725ccfdSJing Huang 	num_fcxps = bfa_cfg->fwcfg.num_fcxp_reqs;
5787725ccfdSJing Huang 	num_ufbufs = bfa_cfg->fwcfg.num_uf_bufs;
5797725ccfdSJing Huang 	reqq_size = bfa_cfg->drvcfg.num_reqq_elems;
5807725ccfdSJing Huang 	rspq_size = bfa_cfg->drvcfg.num_rspq_elems;
5817725ccfdSJing Huang 	num_sgpgs = bfa_cfg->drvcfg.num_sgpgs;
5827725ccfdSJing Huang }
5837725ccfdSJing Huang 
5847725ccfdSJing Huang bfa_status_t
bfad_hal_mem_alloc(struct bfad_s * bfad)5857725ccfdSJing Huang bfad_hal_mem_alloc(struct bfad_s *bfad)
5867725ccfdSJing Huang {
5877725ccfdSJing Huang 	struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo;
5884507025dSKrishna Gudipati 	struct bfa_mem_dma_s *dma_info, *dma_elem;
5894507025dSKrishna Gudipati 	struct bfa_mem_kva_s *kva_info, *kva_elem;
5904507025dSKrishna Gudipati 	struct list_head *dm_qe, *km_qe;
591a36c61f9SKrishna Gudipati 	bfa_status_t	rc = BFA_STATUS_OK;
5924507025dSKrishna Gudipati 	dma_addr_t	phys_addr;
5937725ccfdSJing Huang 
5947725ccfdSJing Huang 	bfa_cfg_get_default(&bfad->ioc_cfg);
5957725ccfdSJing Huang 	bfad_update_hal_cfg(&bfad->ioc_cfg);
5967725ccfdSJing Huang 	bfad->cfg_data.ioc_queue_depth = bfad->ioc_cfg.fwcfg.num_ioim_reqs;
5974507025dSKrishna Gudipati 	bfa_cfg_get_meminfo(&bfad->ioc_cfg, hal_meminfo, &bfad->bfa);
5987725ccfdSJing Huang 
5994507025dSKrishna Gudipati 	dma_info = &hal_meminfo->dma_info;
6004507025dSKrishna Gudipati 	kva_info = &hal_meminfo->kva_info;
6014507025dSKrishna Gudipati 
6024507025dSKrishna Gudipati 	/* Iterate through the KVA meminfo queue */
6034507025dSKrishna Gudipati 	list_for_each(km_qe, &kva_info->qe) {
6044507025dSKrishna Gudipati 		kva_elem = (struct bfa_mem_kva_s *) km_qe;
605bde70f3cSHimanshu Jha 		kva_elem->kva = vzalloc(kva_elem->mem_len);
6064507025dSKrishna Gudipati 		if (kva_elem->kva == NULL) {
6077725ccfdSJing Huang 			bfad_hal_mem_release(bfad);
6087725ccfdSJing Huang 			rc = BFA_STATUS_ENOMEM;
6097725ccfdSJing Huang 			goto ext;
6107725ccfdSJing Huang 		}
6117725ccfdSJing Huang 	}
6124507025dSKrishna Gudipati 
6134507025dSKrishna Gudipati 	/* Iterate through the DMA meminfo queue */
6144507025dSKrishna Gudipati 	list_for_each(dm_qe, &dma_info->qe) {
6154507025dSKrishna Gudipati 		dma_elem = (struct bfa_mem_dma_s *) dm_qe;
6164507025dSKrishna Gudipati 		dma_elem->kva = dma_alloc_coherent(&bfad->pcidev->dev,
6174507025dSKrishna Gudipati 						dma_elem->mem_len,
6184507025dSKrishna Gudipati 						&phys_addr, GFP_KERNEL);
6194507025dSKrishna Gudipati 		if (dma_elem->kva == NULL) {
6204507025dSKrishna Gudipati 			bfad_hal_mem_release(bfad);
6217725ccfdSJing Huang 			rc = BFA_STATUS_ENOMEM;
6227725ccfdSJing Huang 			goto ext;
6237725ccfdSJing Huang 		}
6244507025dSKrishna Gudipati 		dma_elem->dma = phys_addr;
6254507025dSKrishna Gudipati 		memset(dma_elem->kva, 0, dma_elem->mem_len);
6267725ccfdSJing Huang 	}
6277725ccfdSJing Huang ext:
6287725ccfdSJing Huang 	return rc;
6297725ccfdSJing Huang }
6307725ccfdSJing Huang 
6315fbe25c7SJing Huang /*
6327725ccfdSJing Huang  * Create a vport under a vf.
6337725ccfdSJing Huang  */
6347725ccfdSJing Huang bfa_status_t
bfad_vport_create(struct bfad_s * bfad,u16 vf_id,struct bfa_lport_cfg_s * port_cfg,struct device * dev)6357725ccfdSJing Huang bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
636a36c61f9SKrishna Gudipati 		  struct bfa_lport_cfg_s *port_cfg, struct device *dev)
6377725ccfdSJing Huang {
6387725ccfdSJing Huang 	struct bfad_vport_s   *vport;
6397725ccfdSJing Huang 	int		rc = BFA_STATUS_OK;
6407725ccfdSJing Huang 	unsigned long	flags;
6417725ccfdSJing Huang 	struct completion fcomp;
6427725ccfdSJing Huang 
6437725ccfdSJing Huang 	vport = kzalloc(sizeof(struct bfad_vport_s), GFP_KERNEL);
6447725ccfdSJing Huang 	if (!vport) {
6457725ccfdSJing Huang 		rc = BFA_STATUS_ENOMEM;
6467725ccfdSJing Huang 		goto ext;
6477725ccfdSJing Huang 	}
6487725ccfdSJing Huang 
6497725ccfdSJing Huang 	vport->drv_port.bfad = bfad;
6507725ccfdSJing Huang 	spin_lock_irqsave(&bfad->bfad_lock, flags);
651a36c61f9SKrishna Gudipati 	rc = bfa_fcs_vport_create(&vport->fcs_vport, &bfad->bfa_fcs, vf_id,
652a36c61f9SKrishna Gudipati 				  port_cfg, vport);
6537725ccfdSJing Huang 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
6547725ccfdSJing Huang 
6557725ccfdSJing Huang 	if (rc != BFA_STATUS_OK)
6567725ccfdSJing Huang 		goto ext_free_vport;
6577725ccfdSJing Huang 
658a36c61f9SKrishna Gudipati 	if (port_cfg->roles & BFA_LPORT_ROLE_FCP_IM) {
659b504293fSJing Huang 		rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port,
660b504293fSJing Huang 							dev);
6617725ccfdSJing Huang 		if (rc != BFA_STATUS_OK)
6627725ccfdSJing Huang 			goto ext_free_fcs_vport;
6637725ccfdSJing Huang 	}
6647725ccfdSJing Huang 
6657725ccfdSJing Huang 	spin_lock_irqsave(&bfad->bfad_lock, flags);
6667725ccfdSJing Huang 	bfa_fcs_vport_start(&vport->fcs_vport);
6675b7db7afSKrishna Gudipati 	list_add_tail(&vport->list_entry, &bfad->vport_list);
6687725ccfdSJing Huang 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
6697725ccfdSJing Huang 
6707725ccfdSJing Huang 	return BFA_STATUS_OK;
6717725ccfdSJing Huang 
6727725ccfdSJing Huang ext_free_fcs_vport:
6737725ccfdSJing Huang 	spin_lock_irqsave(&bfad->bfad_lock, flags);
6747725ccfdSJing Huang 	vport->comp_del = &fcomp;
6757725ccfdSJing Huang 	init_completion(vport->comp_del);
6767725ccfdSJing Huang 	bfa_fcs_vport_delete(&vport->fcs_vport);
6777725ccfdSJing Huang 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
6787725ccfdSJing Huang 	wait_for_completion(vport->comp_del);
6797725ccfdSJing Huang ext_free_vport:
6807725ccfdSJing Huang 	kfree(vport);
6817725ccfdSJing Huang ext:
6827725ccfdSJing Huang 	return rc;
6837725ccfdSJing Huang }
6847725ccfdSJing Huang 
6857725ccfdSJing Huang void
bfad_bfa_tmo(struct timer_list * t)686e99e88a9SKees Cook bfad_bfa_tmo(struct timer_list *t)
6877725ccfdSJing Huang {
688e99e88a9SKees Cook 	struct bfad_s	      *bfad = from_timer(bfad, t, hal_tmo);
6897725ccfdSJing Huang 	unsigned long	flags;
6907725ccfdSJing Huang 	struct list_head	       doneq;
6917725ccfdSJing Huang 
6927725ccfdSJing Huang 	spin_lock_irqsave(&bfad->bfad_lock, flags);
6937725ccfdSJing Huang 
694f7f73812SMaggie Zhang 	bfa_timer_beat(&bfad->bfa.timer_mod);
6957725ccfdSJing Huang 
6967725ccfdSJing Huang 	bfa_comp_deq(&bfad->bfa, &doneq);
6977725ccfdSJing Huang 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
6987725ccfdSJing Huang 
6997725ccfdSJing Huang 	if (!list_empty(&doneq)) {
7007725ccfdSJing Huang 		bfa_comp_process(&bfad->bfa, &doneq);
7017725ccfdSJing Huang 		spin_lock_irqsave(&bfad->bfad_lock, flags);
7027725ccfdSJing Huang 		bfa_comp_free(&bfad->bfa, &doneq);
7037725ccfdSJing Huang 		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
7047725ccfdSJing Huang 	}
7057725ccfdSJing Huang 
706a36c61f9SKrishna Gudipati 	mod_timer(&bfad->hal_tmo,
707a36c61f9SKrishna Gudipati 		  jiffies + msecs_to_jiffies(BFA_TIMER_FREQ));
7087725ccfdSJing Huang }
7097725ccfdSJing Huang 
7107725ccfdSJing Huang void
bfad_init_timer(struct bfad_s * bfad)7117725ccfdSJing Huang bfad_init_timer(struct bfad_s *bfad)
7127725ccfdSJing Huang {
713e99e88a9SKees Cook 	timer_setup(&bfad->hal_tmo, bfad_bfa_tmo, 0);
7147725ccfdSJing Huang 
715a36c61f9SKrishna Gudipati 	mod_timer(&bfad->hal_tmo,
716a36c61f9SKrishna Gudipati 		  jiffies + msecs_to_jiffies(BFA_TIMER_FREQ));
7177725ccfdSJing Huang }
7187725ccfdSJing Huang 
7197725ccfdSJing Huang int
bfad_pci_init(struct pci_dev * pdev,struct bfad_s * bfad)7207725ccfdSJing Huang bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)
7217725ccfdSJing Huang {
7227725ccfdSJing Huang 	int rc = -ENODEV;
7237725ccfdSJing Huang 
7247725ccfdSJing Huang 	if (pci_enable_device(pdev)) {
725a36c61f9SKrishna Gudipati 		printk(KERN_ERR "pci_enable_device fail %p\n", pdev);
7267725ccfdSJing Huang 		goto out;
7277725ccfdSJing Huang 	}
7287725ccfdSJing Huang 
7297725ccfdSJing Huang 	if (pci_request_regions(pdev, BFAD_DRIVER_NAME))
7307725ccfdSJing Huang 		goto out_disable_device;
7317725ccfdSJing Huang 
7327725ccfdSJing Huang 	pci_set_master(pdev);
7337725ccfdSJing Huang 
73411ea3824SHannes Reinecke 	rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
73511ea3824SHannes Reinecke 	if (rc) {
73611ea3824SHannes Reinecke 		rc = -ENODEV;
737a69b0800SChristoph Hellwig 		printk(KERN_ERR "dma_set_mask_and_coherent fail %p\n", pdev);
7387725ccfdSJing Huang 		goto out_release_region;
7397725ccfdSJing Huang 	}
7407725ccfdSJing Huang 
741b3522f08SJing Huang 	bfad->pci_bar0_kva = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
74211189208SKrishna Gudipati 	bfad->pci_bar2_kva = pci_iomap(pdev, 2, pci_resource_len(pdev, 2));
7437725ccfdSJing Huang 
7447725ccfdSJing Huang 	if (bfad->pci_bar0_kva == NULL) {
745a36c61f9SKrishna Gudipati 		printk(KERN_ERR "Fail to map bar0\n");
746f0f6c3a4SJing Xiangfeng 		rc = -ENODEV;
7477725ccfdSJing Huang 		goto out_release_region;
7487725ccfdSJing Huang 	}
7497725ccfdSJing Huang 
7507725ccfdSJing Huang 	bfad->hal_pcidev.pci_slot = PCI_SLOT(pdev->devfn);
7517725ccfdSJing Huang 	bfad->hal_pcidev.pci_func = PCI_FUNC(pdev->devfn);
7527725ccfdSJing Huang 	bfad->hal_pcidev.pci_bar_kva = bfad->pci_bar0_kva;
7537725ccfdSJing Huang 	bfad->hal_pcidev.device_id = pdev->device;
7541a4d8e1bSKrishna Gudipati 	bfad->hal_pcidev.ssid = pdev->subsystem_device;
7557725ccfdSJing Huang 	bfad->pci_name = pci_name(pdev);
7567725ccfdSJing Huang 
7577725ccfdSJing Huang 	bfad->pci_attr.vendor_id = pdev->vendor;
7587725ccfdSJing Huang 	bfad->pci_attr.device_id = pdev->device;
7597725ccfdSJing Huang 	bfad->pci_attr.ssid = pdev->subsystem_device;
7607725ccfdSJing Huang 	bfad->pci_attr.ssvid = pdev->subsystem_vendor;
7617725ccfdSJing Huang 	bfad->pci_attr.pcifn = PCI_FUNC(pdev->devfn);
7627725ccfdSJing Huang 
7637725ccfdSJing Huang 	bfad->pcidev = pdev;
764a36c61f9SKrishna Gudipati 
765a36c61f9SKrishna Gudipati 	/* Adjust PCIe Maximum Read Request Size */
766c0102c00SYijing Wang 	if (pci_is_pcie(pdev) && pcie_max_read_reqsz) {
767c0102c00SYijing Wang 		if (pcie_max_read_reqsz >= 128 &&
768c0102c00SYijing Wang 		    pcie_max_read_reqsz <= 4096 &&
769c0102c00SYijing Wang 		    is_power_of_2(pcie_max_read_reqsz)) {
770c0102c00SYijing Wang 			int max_rq = pcie_get_readrq(pdev);
771a36c61f9SKrishna Gudipati 			printk(KERN_WARNING "BFA[%s]: "
772a36c61f9SKrishna Gudipati 				"pcie_max_read_request_size is %d, "
773c0102c00SYijing Wang 				"reset to %d\n", bfad->pci_name, max_rq,
774a36c61f9SKrishna Gudipati 				pcie_max_read_reqsz);
775c0102c00SYijing Wang 			pcie_set_readrq(pdev, pcie_max_read_reqsz);
776c0102c00SYijing Wang 		} else {
777c0102c00SYijing Wang 			printk(KERN_WARNING "BFA[%s]: invalid "
778c0102c00SYijing Wang 			       "pcie_max_read_request_size %d ignored\n",
779c0102c00SYijing Wang 			       bfad->pci_name, pcie_max_read_reqsz);
780a36c61f9SKrishna Gudipati 		}
781a36c61f9SKrishna Gudipati 	}
782a36c61f9SKrishna Gudipati 
783881c1b3cSKrishna Gudipati 	pci_save_state(pdev);
784881c1b3cSKrishna Gudipati 
7857725ccfdSJing Huang 	return 0;
7867725ccfdSJing Huang 
7877725ccfdSJing Huang out_release_region:
7887725ccfdSJing Huang 	pci_release_regions(pdev);
7897725ccfdSJing Huang out_disable_device:
7907725ccfdSJing Huang 	pci_disable_device(pdev);
7917725ccfdSJing Huang out:
7927725ccfdSJing Huang 	return rc;
7937725ccfdSJing Huang }
7947725ccfdSJing Huang 
7957725ccfdSJing Huang void
bfad_pci_uninit(struct pci_dev * pdev,struct bfad_s * bfad)7967725ccfdSJing Huang bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad)
7977725ccfdSJing Huang {
7987725ccfdSJing Huang 	pci_iounmap(pdev, bfad->pci_bar0_kva);
79911189208SKrishna Gudipati 	pci_iounmap(pdev, bfad->pci_bar2_kva);
8007725ccfdSJing Huang 	pci_release_regions(pdev);
8017725ccfdSJing Huang 	pci_disable_device(pdev);
8027725ccfdSJing Huang }
8037725ccfdSJing Huang 
8047725ccfdSJing Huang bfa_status_t
bfad_drv_init(struct bfad_s * bfad)8057725ccfdSJing Huang bfad_drv_init(struct bfad_s *bfad)
8067725ccfdSJing Huang {
8077725ccfdSJing Huang 	bfa_status_t	rc;
8087725ccfdSJing Huang 	unsigned long	flags;
8097725ccfdSJing Huang 
8107725ccfdSJing Huang 	bfad->cfg_data.rport_del_timeout = rport_del_timeout;
8117725ccfdSJing Huang 	bfad->cfg_data.lun_queue_depth = bfa_lun_queue_depth;
8127725ccfdSJing Huang 	bfad->cfg_data.io_max_sge = bfa_io_max_sge;
8137725ccfdSJing Huang 	bfad->cfg_data.binding_method = FCP_PWWN_BINDING;
8147725ccfdSJing Huang 
8157725ccfdSJing Huang 	rc = bfad_hal_mem_alloc(bfad);
8167725ccfdSJing Huang 	if (rc != BFA_STATUS_OK) {
8177725ccfdSJing Huang 		printk(KERN_WARNING "bfad%d bfad_hal_mem_alloc failure\n",
8187725ccfdSJing Huang 		       bfad->inst_no);
8197725ccfdSJing Huang 		printk(KERN_WARNING
82031e1d569SAnil Gurumurthy 			"Not enough memory to attach all QLogic BR-series HBA ports. System may need more memory.\n");
821da3e0beeSVijaya Mohan Guvva 		return BFA_STATUS_FAILED;
8227725ccfdSJing Huang 	}
8237725ccfdSJing Huang 
824f7f73812SMaggie Zhang 	bfad->bfa.trcmod = bfad->trcmod;
825f7f73812SMaggie Zhang 	bfad->bfa.plog = &bfad->plog_buf;
8267725ccfdSJing Huang 	bfa_plog_init(&bfad->plog_buf);
8277725ccfdSJing Huang 	bfa_plog_str(&bfad->plog_buf, BFA_PL_MID_DRVR, BFA_PL_EID_DRIVER_START,
8287725ccfdSJing Huang 		     0, "Driver Attach");
8297725ccfdSJing Huang 
8307725ccfdSJing Huang 	bfa_attach(&bfad->bfa, bfad, &bfad->ioc_cfg, &bfad->meminfo,
8317725ccfdSJing Huang 		   &bfad->hal_pcidev);
8327725ccfdSJing Huang 
833a36c61f9SKrishna Gudipati 	/* FCS INIT */
8347725ccfdSJing Huang 	spin_lock_irqsave(&bfad->bfad_lock, flags);
835f7f73812SMaggie Zhang 	bfad->bfa_fcs.trcmod = bfad->trcmod;
83682794a2eSKrishna Gudipati 	bfa_fcs_attach(&bfad->bfa_fcs, &bfad->bfa, bfad, BFA_FALSE);
837f7f73812SMaggie Zhang 	bfad->bfa_fcs.fdmi_enabled = fdmi_enable;
8387725ccfdSJing Huang 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
8397725ccfdSJing Huang 
8407725ccfdSJing Huang 	bfad->bfad_flags |= BFAD_DRV_INIT_DONE;
841a36c61f9SKrishna Gudipati 
8427725ccfdSJing Huang 	return BFA_STATUS_OK;
8437725ccfdSJing Huang }
8447725ccfdSJing Huang 
8457725ccfdSJing Huang void
bfad_drv_uninit(struct bfad_s * bfad)8467725ccfdSJing Huang bfad_drv_uninit(struct bfad_s *bfad)
8477725ccfdSJing Huang {
848e6714324SKrishna Gudipati 	unsigned long   flags;
849e6714324SKrishna Gudipati 
850e6714324SKrishna Gudipati 	spin_lock_irqsave(&bfad->bfad_lock, flags);
851e6714324SKrishna Gudipati 	init_completion(&bfad->comp);
852f7f73812SMaggie Zhang 	bfa_iocfc_stop(&bfad->bfa);
853e6714324SKrishna Gudipati 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
854e6714324SKrishna Gudipati 	wait_for_completion(&bfad->comp);
855e6714324SKrishna Gudipati 
8567725ccfdSJing Huang 	del_timer_sync(&bfad->hal_tmo);
8577725ccfdSJing Huang 	bfa_isr_disable(&bfad->bfa);
8587725ccfdSJing Huang 	bfa_detach(&bfad->bfa);
8597725ccfdSJing Huang 	bfad_remove_intr(bfad);
8607725ccfdSJing Huang 	bfad_hal_mem_release(bfad);
861e6714324SKrishna Gudipati 
862e6714324SKrishna Gudipati 	bfad->bfad_flags &= ~BFAD_DRV_INIT_DONE;
8637725ccfdSJing Huang }
8647725ccfdSJing Huang 
8657725ccfdSJing Huang void
bfad_drv_start(struct bfad_s * bfad)8667725ccfdSJing Huang bfad_drv_start(struct bfad_s *bfad)
8677725ccfdSJing Huang {
8687725ccfdSJing Huang 	unsigned long	flags;
8697725ccfdSJing Huang 
8707725ccfdSJing Huang 	spin_lock_irqsave(&bfad->bfad_lock, flags);
871f7f73812SMaggie Zhang 	bfa_iocfc_start(&bfad->bfa);
87275332a70SKrishna Gudipati 	bfa_fcs_pbc_vport_init(&bfad->bfa_fcs);
873f7f73812SMaggie Zhang 	bfa_fcs_fabric_modstart(&bfad->bfa_fcs);
8747725ccfdSJing Huang 	bfad->bfad_flags |= BFAD_HAL_START_DONE;
8757725ccfdSJing Huang 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
8767725ccfdSJing Huang 
877a36c61f9SKrishna Gudipati 	if (bfad->im)
878a36c61f9SKrishna Gudipati 		flush_workqueue(bfad->im->drv_workq);
8797725ccfdSJing Huang }
8807725ccfdSJing Huang 
8817725ccfdSJing Huang void
bfad_fcs_stop(struct bfad_s * bfad)882a36c61f9SKrishna Gudipati bfad_fcs_stop(struct bfad_s *bfad)
8837725ccfdSJing Huang {
8847725ccfdSJing Huang 	unsigned long	flags;
8857725ccfdSJing Huang 
8867725ccfdSJing Huang 	spin_lock_irqsave(&bfad->bfad_lock, flags);
8877725ccfdSJing Huang 	init_completion(&bfad->comp);
8887725ccfdSJing Huang 	bfad->pport.flags |= BFAD_PORT_DELETE;
8897725ccfdSJing Huang 	bfa_fcs_exit(&bfad->bfa_fcs);
8907725ccfdSJing Huang 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
8917725ccfdSJing Huang 	wait_for_completion(&bfad->comp);
8927725ccfdSJing Huang 
893a36c61f9SKrishna Gudipati 	bfa_sm_send_event(bfad, BFAD_E_FCS_EXIT_COMP);
894a36c61f9SKrishna Gudipati }
895a36c61f9SKrishna Gudipati 
896a36c61f9SKrishna Gudipati void
bfad_stop(struct bfad_s * bfad)897a36c61f9SKrishna Gudipati bfad_stop(struct bfad_s *bfad)
898a36c61f9SKrishna Gudipati {
899a36c61f9SKrishna Gudipati 	unsigned long	flags;
900a36c61f9SKrishna Gudipati 
9017725ccfdSJing Huang 	spin_lock_irqsave(&bfad->bfad_lock, flags);
9027725ccfdSJing Huang 	init_completion(&bfad->comp);
903f7f73812SMaggie Zhang 	bfa_iocfc_stop(&bfad->bfa);
9047725ccfdSJing Huang 	bfad->bfad_flags &= ~BFAD_HAL_START_DONE;
9057725ccfdSJing Huang 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
9067725ccfdSJing Huang 	wait_for_completion(&bfad->comp);
907a36c61f9SKrishna Gudipati 
908a36c61f9SKrishna Gudipati 	bfa_sm_send_event(bfad, BFAD_E_EXIT_COMP);
9097725ccfdSJing Huang }
9107725ccfdSJing Huang 
9117725ccfdSJing Huang bfa_status_t
bfad_cfg_pport(struct bfad_s * bfad,enum bfa_lport_role role)912a36c61f9SKrishna Gudipati bfad_cfg_pport(struct bfad_s *bfad, enum bfa_lport_role role)
9137725ccfdSJing Huang {
9147725ccfdSJing Huang 	int		rc = BFA_STATUS_OK;
9157725ccfdSJing Huang 
916a36c61f9SKrishna Gudipati 	/* Allocate scsi_host for the physical port */
917a36c61f9SKrishna Gudipati 	if ((supported_fc4s & BFA_LPORT_ROLE_FCP_IM) &&
918a36c61f9SKrishna Gudipati 	    (role & BFA_LPORT_ROLE_FCP_IM)) {
9197725ccfdSJing Huang 		if (bfad->pport.im_port == NULL) {
9207725ccfdSJing Huang 			rc = BFA_STATUS_FAILED;
9217725ccfdSJing Huang 			goto out;
9227725ccfdSJing Huang 		}
9237725ccfdSJing Huang 
924b504293fSJing Huang 		rc = bfad_im_scsi_host_alloc(bfad, bfad->pport.im_port,
925b504293fSJing Huang 						&bfad->pcidev->dev);
9267725ccfdSJing Huang 		if (rc != BFA_STATUS_OK)
9277725ccfdSJing Huang 			goto out;
9287725ccfdSJing Huang 
929a36c61f9SKrishna Gudipati 		bfad->pport.roles |= BFA_LPORT_ROLE_FCP_IM;
9307725ccfdSJing Huang 	}
9317725ccfdSJing Huang 
9327725ccfdSJing Huang 	bfad->bfad_flags |= BFAD_CFG_PPORT_DONE;
9337725ccfdSJing Huang 
9347725ccfdSJing Huang out:
9357725ccfdSJing Huang 	return rc;
9367725ccfdSJing Huang }
9377725ccfdSJing Huang 
9387725ccfdSJing Huang void
bfad_uncfg_pport(struct bfad_s * bfad)9397725ccfdSJing Huang bfad_uncfg_pport(struct bfad_s *bfad)
9407725ccfdSJing Huang {
941a36c61f9SKrishna Gudipati 	if ((supported_fc4s & BFA_LPORT_ROLE_FCP_IM) &&
942a36c61f9SKrishna Gudipati 	    (bfad->pport.roles & BFA_LPORT_ROLE_FCP_IM)) {
9437725ccfdSJing Huang 		bfad_im_scsi_host_free(bfad, bfad->pport.im_port);
9447725ccfdSJing Huang 		bfad_im_port_clean(bfad->pport.im_port);
9457725ccfdSJing Huang 		kfree(bfad->pport.im_port);
946a36c61f9SKrishna Gudipati 		bfad->pport.roles &= ~BFA_LPORT_ROLE_FCP_IM;
9477725ccfdSJing Huang 	}
9487725ccfdSJing Huang 
9497725ccfdSJing Huang 	bfad->bfad_flags &= ~BFAD_CFG_PPORT_DONE;
9507725ccfdSJing Huang }
9517725ccfdSJing Huang 
952e6714324SKrishna Gudipati bfa_status_t
bfad_start_ops(struct bfad_s * bfad)953a36c61f9SKrishna Gudipati bfad_start_ops(struct bfad_s *bfad) {
954a36c61f9SKrishna Gudipati 
955e6714324SKrishna Gudipati 	int	retval;
956a36c61f9SKrishna Gudipati 	unsigned long	flags;
957a36c61f9SKrishna Gudipati 	struct bfad_vport_s *vport, *vport_new;
958a36c61f9SKrishna Gudipati 	struct bfa_fcs_driver_info_s driver_info;
959a36c61f9SKrishna Gudipati 
96061e62e21SKrishna Gudipati 	/* Limit min/max. xfer size to [64k-32MB] */
96161e62e21SKrishna Gudipati 	if (max_xfer_size < BFAD_MIN_SECTORS >> 1)
96261e62e21SKrishna Gudipati 		max_xfer_size = BFAD_MIN_SECTORS >> 1;
96361e62e21SKrishna Gudipati 	if (max_xfer_size > BFAD_MAX_SECTORS >> 1)
96461e62e21SKrishna Gudipati 		max_xfer_size = BFAD_MAX_SECTORS >> 1;
96561e62e21SKrishna Gudipati 
966a36c61f9SKrishna Gudipati 	/* Fill the driver_info info to fcs*/
967a36c61f9SKrishna Gudipati 	memset(&driver_info, 0, sizeof(driver_info));
968*973464fdSAzeem Shaikh 	strscpy(driver_info.version, BFAD_DRIVER_VERSION,
9698c5a50e8SArnd Bergmann 		sizeof(driver_info.version));
970a36c61f9SKrishna Gudipati 	if (host_name)
971*973464fdSAzeem Shaikh 		strscpy(driver_info.host_machine_name, host_name,
9728c5a50e8SArnd Bergmann 			sizeof(driver_info.host_machine_name));
973a36c61f9SKrishna Gudipati 	if (os_name)
974*973464fdSAzeem Shaikh 		strscpy(driver_info.host_os_name, os_name,
9758c5a50e8SArnd Bergmann 			sizeof(driver_info.host_os_name));
976a36c61f9SKrishna Gudipati 	if (os_patch)
977*973464fdSAzeem Shaikh 		strscpy(driver_info.host_os_patch, os_patch,
9788c5a50e8SArnd Bergmann 			sizeof(driver_info.host_os_patch));
979a36c61f9SKrishna Gudipati 
980*973464fdSAzeem Shaikh 	strscpy(driver_info.os_device_name, bfad->pci_name,
9818c5a50e8SArnd Bergmann 		sizeof(driver_info.os_device_name));
982a36c61f9SKrishna Gudipati 
98375332a70SKrishna Gudipati 	/* FCS driver info init */
984a36c61f9SKrishna Gudipati 	spin_lock_irqsave(&bfad->bfad_lock, flags);
985a36c61f9SKrishna Gudipati 	bfa_fcs_driver_info_init(&bfad->bfa_fcs, &driver_info);
986da3e0beeSVijaya Mohan Guvva 
987da3e0beeSVijaya Mohan Guvva 	if (bfad->bfad_flags & BFAD_CFG_PPORT_DONE)
988da3e0beeSVijaya Mohan Guvva 		bfa_fcs_update_cfg(&bfad->bfa_fcs);
989da3e0beeSVijaya Mohan Guvva 	else
990da3e0beeSVijaya Mohan Guvva 		bfa_fcs_init(&bfad->bfa_fcs);
991da3e0beeSVijaya Mohan Guvva 
992a36c61f9SKrishna Gudipati 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
993e6714324SKrishna Gudipati 
994da3e0beeSVijaya Mohan Guvva 	if (!(bfad->bfad_flags & BFAD_CFG_PPORT_DONE)) {
995da3e0beeSVijaya Mohan Guvva 		retval = bfad_cfg_pport(bfad, BFA_LPORT_ROLE_FCP_IM);
996da3e0beeSVijaya Mohan Guvva 		if (retval != BFA_STATUS_OK)
997da3e0beeSVijaya Mohan Guvva 			return BFA_STATUS_FAILED;
998da3e0beeSVijaya Mohan Guvva 	}
99975332a70SKrishna Gudipati 
100075332a70SKrishna Gudipati 	/* Setup fc host fixed attribute if the lk supports */
100175332a70SKrishna Gudipati 	bfad_fc_host_init(bfad->pport.im_port);
1002e6714324SKrishna Gudipati 
1003a36c61f9SKrishna Gudipati 	/* BFAD level FC4 IM specific resource allocation */
1004a36c61f9SKrishna Gudipati 	retval = bfad_im_probe(bfad);
1005a36c61f9SKrishna Gudipati 	if (retval != BFA_STATUS_OK) {
1006a36c61f9SKrishna Gudipati 		printk(KERN_WARNING "bfad_im_probe failed\n");
1007a36c61f9SKrishna Gudipati 		if (bfa_sm_cmp_state(bfad, bfad_sm_initializing))
1008a36c61f9SKrishna Gudipati 			bfa_sm_set_state(bfad, bfad_sm_failed);
1009a36c61f9SKrishna Gudipati 		return BFA_STATUS_FAILED;
1010a36c61f9SKrishna Gudipati 	} else
1011a36c61f9SKrishna Gudipati 		bfad->bfad_flags |= BFAD_FC4_PROBE_DONE;
1012a36c61f9SKrishna Gudipati 
1013e6714324SKrishna Gudipati 	bfad_drv_start(bfad);
1014e6714324SKrishna Gudipati 
1015a36c61f9SKrishna Gudipati 	/* Complete pbc vport create */
1016a36c61f9SKrishna Gudipati 	list_for_each_entry_safe(vport, vport_new, &bfad->pbc_vport_list,
1017d9883548SJing Huang 				list_entry) {
1018d9883548SJing Huang 		struct fc_vport_identifiers vid;
1019d9883548SJing Huang 		struct fc_vport *fc_vport;
1020a36c61f9SKrishna Gudipati 		char pwwn_buf[BFA_STRING_32];
1021d9883548SJing Huang 
1022d9883548SJing Huang 		memset(&vid, 0, sizeof(vid));
1023d9883548SJing Huang 		vid.roles = FC_PORT_ROLE_FCP_INITIATOR;
1024d9883548SJing Huang 		vid.vport_type = FC_PORTTYPE_NPIV;
1025d9883548SJing Huang 		vid.disable = false;
1026a36c61f9SKrishna Gudipati 		vid.node_name = wwn_to_u64((u8 *)
1027a36c61f9SKrishna Gudipati 				(&((vport->fcs_vport).lport.port_cfg.nwwn)));
1028a36c61f9SKrishna Gudipati 		vid.port_name = wwn_to_u64((u8 *)
1029a36c61f9SKrishna Gudipati 				(&((vport->fcs_vport).lport.port_cfg.pwwn)));
1030d9883548SJing Huang 		fc_vport = fc_vport_create(bfad->pport.im_port->shost, 0, &vid);
1031a36c61f9SKrishna Gudipati 		if (!fc_vport) {
1032a36c61f9SKrishna Gudipati 			wwn2str(pwwn_buf, vid.port_name);
1033d9883548SJing Huang 			printk(KERN_WARNING "bfad%d: failed to create pbc vport"
1034a36c61f9SKrishna Gudipati 				" %s\n", bfad->inst_no, pwwn_buf);
1035a36c61f9SKrishna Gudipati 		}
1036a36c61f9SKrishna Gudipati 		list_del(&vport->list_entry);
1037a36c61f9SKrishna Gudipati 		kfree(vport);
1038d9883548SJing Huang 	}
1039d9883548SJing Huang 
1040e6714324SKrishna Gudipati 	/*
1041e6714324SKrishna Gudipati 	 * If bfa_linkup_delay is set to -1 default; try to retrive the
1042f16a1750SMaggie Zhang 	 * value using the bfad_get_linkup_delay(); else use the
1043e6714324SKrishna Gudipati 	 * passed in module param value as the bfa_linkup_delay.
1044e6714324SKrishna Gudipati 	 */
1045e6714324SKrishna Gudipati 	if (bfa_linkup_delay < 0) {
1046f16a1750SMaggie Zhang 		bfa_linkup_delay = bfad_get_linkup_delay(bfad);
1047f16a1750SMaggie Zhang 		bfad_rport_online_wait(bfad);
1048e6714324SKrishna Gudipati 		bfa_linkup_delay = -1;
1049a36c61f9SKrishna Gudipati 	} else
1050f16a1750SMaggie Zhang 		bfad_rport_online_wait(bfad);
1051e6714324SKrishna Gudipati 
105288166242SJing Huang 	BFA_LOG(KERN_INFO, bfad, bfa_log_level, "bfa device claimed\n");
1053e6714324SKrishna Gudipati 
1054e6714324SKrishna Gudipati 	return BFA_STATUS_OK;
1055e6714324SKrishna Gudipati }
1056e6714324SKrishna Gudipati 
1057e6714324SKrishna Gudipati int
bfad_worker(void * ptr)1058e6714324SKrishna Gudipati bfad_worker(void *ptr)
1059e6714324SKrishna Gudipati {
10608f7d3f0fSJiri Slaby 	struct bfad_s *bfad = ptr;
1061e6714324SKrishna Gudipati 	unsigned long flags;
1062e6714324SKrishna Gudipati 
10638f7d3f0fSJiri Slaby 	if (kthread_should_stop())
10648f7d3f0fSJiri Slaby 		return 0;
1065e6714324SKrishna Gudipati 
1066a36c61f9SKrishna Gudipati 	/* Send event BFAD_E_INIT_SUCCESS */
1067a36c61f9SKrishna Gudipati 	bfa_sm_send_event(bfad, BFAD_E_INIT_SUCCESS);
1068e6714324SKrishna Gudipati 
1069e6714324SKrishna Gudipati 	spin_lock_irqsave(&bfad->bfad_lock, flags);
1070e6714324SKrishna Gudipati 	bfad->bfad_tsk = NULL;
1071e6714324SKrishna Gudipati 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1072e6714324SKrishna Gudipati 
1073e6714324SKrishna Gudipati 	return 0;
1074e6714324SKrishna Gudipati }
1075e6714324SKrishna Gudipati 
10765fbe25c7SJing Huang /*
1077a36c61f9SKrishna Gudipati  *  BFA driver interrupt functions
10787725ccfdSJing Huang  */
1079a36c61f9SKrishna Gudipati irqreturn_t
bfad_intx(int irq,void * dev_id)1080a36c61f9SKrishna Gudipati bfad_intx(int irq, void *dev_id)
1081a36c61f9SKrishna Gudipati {
1082a36c61f9SKrishna Gudipati 	struct bfad_s	*bfad = dev_id;
1083a36c61f9SKrishna Gudipati 	struct list_head	doneq;
1084a36c61f9SKrishna Gudipati 	unsigned long	flags;
1085a36c61f9SKrishna Gudipati 	bfa_boolean_t rc;
1086a36c61f9SKrishna Gudipati 
1087a36c61f9SKrishna Gudipati 	spin_lock_irqsave(&bfad->bfad_lock, flags);
1088a36c61f9SKrishna Gudipati 	rc = bfa_intx(&bfad->bfa);
1089a36c61f9SKrishna Gudipati 	if (!rc) {
1090a36c61f9SKrishna Gudipati 		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1091a36c61f9SKrishna Gudipati 		return IRQ_NONE;
1092a36c61f9SKrishna Gudipati 	}
1093a36c61f9SKrishna Gudipati 
1094a36c61f9SKrishna Gudipati 	bfa_comp_deq(&bfad->bfa, &doneq);
1095a36c61f9SKrishna Gudipati 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1096a36c61f9SKrishna Gudipati 
1097a36c61f9SKrishna Gudipati 	if (!list_empty(&doneq)) {
1098a36c61f9SKrishna Gudipati 		bfa_comp_process(&bfad->bfa, &doneq);
1099a36c61f9SKrishna Gudipati 
1100a36c61f9SKrishna Gudipati 		spin_lock_irqsave(&bfad->bfad_lock, flags);
1101a36c61f9SKrishna Gudipati 		bfa_comp_free(&bfad->bfa, &doneq);
1102a36c61f9SKrishna Gudipati 		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1103a36c61f9SKrishna Gudipati 	}
1104a36c61f9SKrishna Gudipati 
1105a36c61f9SKrishna Gudipati 	return IRQ_HANDLED;
1106a36c61f9SKrishna Gudipati 
1107a36c61f9SKrishna Gudipati }
1108a36c61f9SKrishna Gudipati 
1109a36c61f9SKrishna Gudipati static irqreturn_t
bfad_msix(int irq,void * dev_id)1110a36c61f9SKrishna Gudipati bfad_msix(int irq, void *dev_id)
1111a36c61f9SKrishna Gudipati {
1112a36c61f9SKrishna Gudipati 	struct bfad_msix_s *vec = dev_id;
1113a36c61f9SKrishna Gudipati 	struct bfad_s *bfad = vec->bfad;
1114a36c61f9SKrishna Gudipati 	struct list_head doneq;
1115a36c61f9SKrishna Gudipati 	unsigned long   flags;
1116a36c61f9SKrishna Gudipati 
1117a36c61f9SKrishna Gudipati 	spin_lock_irqsave(&bfad->bfad_lock, flags);
1118a36c61f9SKrishna Gudipati 
1119a36c61f9SKrishna Gudipati 	bfa_msix(&bfad->bfa, vec->msix.entry);
1120a36c61f9SKrishna Gudipati 	bfa_comp_deq(&bfad->bfa, &doneq);
1121a36c61f9SKrishna Gudipati 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1122a36c61f9SKrishna Gudipati 
1123a36c61f9SKrishna Gudipati 	if (!list_empty(&doneq)) {
1124a36c61f9SKrishna Gudipati 		bfa_comp_process(&bfad->bfa, &doneq);
1125a36c61f9SKrishna Gudipati 
1126a36c61f9SKrishna Gudipati 		spin_lock_irqsave(&bfad->bfad_lock, flags);
1127a36c61f9SKrishna Gudipati 		bfa_comp_free(&bfad->bfa, &doneq);
1128a36c61f9SKrishna Gudipati 		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1129a36c61f9SKrishna Gudipati 	}
1130a36c61f9SKrishna Gudipati 
1131a36c61f9SKrishna Gudipati 	return IRQ_HANDLED;
1132a36c61f9SKrishna Gudipati }
1133a36c61f9SKrishna Gudipati 
11345fbe25c7SJing Huang /*
1135a36c61f9SKrishna Gudipati  * Initialize the MSIX entry table.
1136a36c61f9SKrishna Gudipati  */
1137a36c61f9SKrishna Gudipati static void
bfad_init_msix_entry(struct bfad_s * bfad,struct msix_entry * msix_entries,int mask,int max_bit)1138a36c61f9SKrishna Gudipati bfad_init_msix_entry(struct bfad_s *bfad, struct msix_entry *msix_entries,
1139a36c61f9SKrishna Gudipati 			 int mask, int max_bit)
1140a36c61f9SKrishna Gudipati {
1141a36c61f9SKrishna Gudipati 	int	i;
1142a36c61f9SKrishna Gudipati 	int	match = 0x00000001;
1143a36c61f9SKrishna Gudipati 
1144a36c61f9SKrishna Gudipati 	for (i = 0, bfad->nvec = 0; i < MAX_MSIX_ENTRY; i++) {
1145a36c61f9SKrishna Gudipati 		if (mask & match) {
1146a36c61f9SKrishna Gudipati 			bfad->msix_tab[bfad->nvec].msix.entry = i;
1147a36c61f9SKrishna Gudipati 			bfad->msix_tab[bfad->nvec].bfad = bfad;
1148a36c61f9SKrishna Gudipati 			msix_entries[bfad->nvec].entry = i;
1149a36c61f9SKrishna Gudipati 			bfad->nvec++;
1150a36c61f9SKrishna Gudipati 		}
1151a36c61f9SKrishna Gudipati 
1152a36c61f9SKrishna Gudipati 		match <<= 1;
1153a36c61f9SKrishna Gudipati 	}
1154a36c61f9SKrishna Gudipati 
1155a36c61f9SKrishna Gudipati }
1156a36c61f9SKrishna Gudipati 
1157a36c61f9SKrishna Gudipati int
bfad_install_msix_handler(struct bfad_s * bfad)1158a36c61f9SKrishna Gudipati bfad_install_msix_handler(struct bfad_s *bfad)
1159a36c61f9SKrishna Gudipati {
1160a36c61f9SKrishna Gudipati 	int i, error = 0;
1161a36c61f9SKrishna Gudipati 
1162a36c61f9SKrishna Gudipati 	for (i = 0; i < bfad->nvec; i++) {
1163a36c61f9SKrishna Gudipati 		sprintf(bfad->msix_tab[i].name, "bfa-%s-%s",
1164a36c61f9SKrishna Gudipati 				bfad->pci_name,
116511189208SKrishna Gudipati 				((bfa_asic_id_cb(bfad->hal_pcidev.device_id)) ?
116611189208SKrishna Gudipati 				msix_name_cb[i] : msix_name_ct[i]));
1167a36c61f9SKrishna Gudipati 
1168a36c61f9SKrishna Gudipati 		error = request_irq(bfad->msix_tab[i].msix.vector,
1169a36c61f9SKrishna Gudipati 				    (irq_handler_t) bfad_msix, 0,
1170a36c61f9SKrishna Gudipati 				    bfad->msix_tab[i].name, &bfad->msix_tab[i]);
1171a36c61f9SKrishna Gudipati 		bfa_trc(bfad, i);
1172a36c61f9SKrishna Gudipati 		bfa_trc(bfad, bfad->msix_tab[i].msix.vector);
1173a36c61f9SKrishna Gudipati 		if (error) {
1174a36c61f9SKrishna Gudipati 			int	j;
1175a36c61f9SKrishna Gudipati 
1176a36c61f9SKrishna Gudipati 			for (j = 0; j < i; j++)
1177a36c61f9SKrishna Gudipati 				free_irq(bfad->msix_tab[j].msix.vector,
1178a36c61f9SKrishna Gudipati 						&bfad->msix_tab[j]);
1179a36c61f9SKrishna Gudipati 
118061e62e21SKrishna Gudipati 			bfad->bfad_flags &= ~BFAD_MSIX_ON;
118161e62e21SKrishna Gudipati 			pci_disable_msix(bfad->pcidev);
118261e62e21SKrishna Gudipati 
1183a36c61f9SKrishna Gudipati 			return 1;
1184a36c61f9SKrishna Gudipati 		}
1185a36c61f9SKrishna Gudipati 	}
1186a36c61f9SKrishna Gudipati 
1187a36c61f9SKrishna Gudipati 	return 0;
1188a36c61f9SKrishna Gudipati }
1189a36c61f9SKrishna Gudipati 
11905fbe25c7SJing Huang /*
1191a36c61f9SKrishna Gudipati  * Setup MSIX based interrupt.
1192a36c61f9SKrishna Gudipati  */
1193a36c61f9SKrishna Gudipati int
bfad_setup_intr(struct bfad_s * bfad)1194a36c61f9SKrishna Gudipati bfad_setup_intr(struct bfad_s *bfad)
1195a36c61f9SKrishna Gudipati {
11968cb7f63dSAlexander Gordeev 	int error;
1197a36c61f9SKrishna Gudipati 	u32 mask = 0, i, num_bit = 0, max_bit = 0;
1198a36c61f9SKrishna Gudipati 	struct msix_entry msix_entries[MAX_MSIX_ENTRY];
1199a36c61f9SKrishna Gudipati 	struct pci_dev *pdev = bfad->pcidev;
120010a07379SKrishna Gudipati 	u16	reg;
1201a36c61f9SKrishna Gudipati 
1202a36c61f9SKrishna Gudipati 	/* Call BFA to get the msix map for this PCI function.  */
1203a36c61f9SKrishna Gudipati 	bfa_msix_getvecs(&bfad->bfa, &mask, &num_bit, &max_bit);
1204a36c61f9SKrishna Gudipati 
1205a36c61f9SKrishna Gudipati 	/* Set up the msix entry table */
1206a36c61f9SKrishna Gudipati 	bfad_init_msix_entry(bfad, msix_entries, mask, max_bit);
1207a36c61f9SKrishna Gudipati 
120811189208SKrishna Gudipati 	if ((bfa_asic_id_ctc(pdev->device) && !msix_disable_ct) ||
120911189208SKrishna Gudipati 	   (bfa_asic_id_cb(pdev->device) && !msix_disable_cb)) {
1210a36c61f9SKrishna Gudipati 
1211b427d00fSAlexander Gordeev 		error = pci_enable_msix_exact(bfad->pcidev,
1212b427d00fSAlexander Gordeev 					      msix_entries, bfad->nvec);
1213881c1b3cSKrishna Gudipati 		/* In CT1 & CT2, try to allocate just one vector */
1214b427d00fSAlexander Gordeev 		if (error == -ENOSPC && bfa_asic_id_ctc(pdev->device)) {
1215881c1b3cSKrishna Gudipati 			printk(KERN_WARNING "bfa %s: trying one msix "
1216881c1b3cSKrishna Gudipati 			       "vector failed to allocate %d[%d]\n",
1217881c1b3cSKrishna Gudipati 			       bfad->pci_name, bfad->nvec, error);
1218881c1b3cSKrishna Gudipati 			bfad->nvec = 1;
1219b427d00fSAlexander Gordeev 			error = pci_enable_msix_exact(bfad->pcidev,
1220b427d00fSAlexander Gordeev 						      msix_entries, 1);
1221881c1b3cSKrishna Gudipati 		}
1222881c1b3cSKrishna Gudipati 
1223881c1b3cSKrishna Gudipati 		if (error) {
1224a36c61f9SKrishna Gudipati 			printk(KERN_WARNING "bfad%d: "
1225b427d00fSAlexander Gordeev 			       "pci_enable_msix_exact failed (%d), "
1226881c1b3cSKrishna Gudipati 			       "use line based.\n",
1227881c1b3cSKrishna Gudipati 				bfad->inst_no, error);
1228a36c61f9SKrishna Gudipati 			goto line_based;
1229a36c61f9SKrishna Gudipati 		}
1230a36c61f9SKrishna Gudipati 
123110a07379SKrishna Gudipati 		/* Disable INTX in MSI-X mode */
123210a07379SKrishna Gudipati 		pci_read_config_word(pdev, PCI_COMMAND, &reg);
123310a07379SKrishna Gudipati 
123410a07379SKrishna Gudipati 		if (!(reg & PCI_COMMAND_INTX_DISABLE))
123510a07379SKrishna Gudipati 			pci_write_config_word(pdev, PCI_COMMAND,
123610a07379SKrishna Gudipati 				reg | PCI_COMMAND_INTX_DISABLE);
123710a07379SKrishna Gudipati 
1238a36c61f9SKrishna Gudipati 		/* Save the vectors */
1239a36c61f9SKrishna Gudipati 		for (i = 0; i < bfad->nvec; i++) {
1240a36c61f9SKrishna Gudipati 			bfa_trc(bfad, msix_entries[i].vector);
1241a36c61f9SKrishna Gudipati 			bfad->msix_tab[i].msix.vector = msix_entries[i].vector;
1242a36c61f9SKrishna Gudipati 		}
1243a36c61f9SKrishna Gudipati 
1244a36c61f9SKrishna Gudipati 		bfa_msix_init(&bfad->bfa, bfad->nvec);
1245a36c61f9SKrishna Gudipati 
1246a36c61f9SKrishna Gudipati 		bfad->bfad_flags |= BFAD_MSIX_ON;
1247a36c61f9SKrishna Gudipati 
12488cb7f63dSAlexander Gordeev 		return 0;
1249a36c61f9SKrishna Gudipati 	}
1250a36c61f9SKrishna Gudipati 
1251a36c61f9SKrishna Gudipati line_based:
12528cb7f63dSAlexander Gordeev 	error = request_irq(bfad->pcidev->irq, (irq_handler_t)bfad_intx,
12538cb7f63dSAlexander Gordeev 			    BFAD_IRQ_FLAGS, BFAD_DRIVER_NAME, bfad);
12548cb7f63dSAlexander Gordeev 	if (error)
12558cb7f63dSAlexander Gordeev 		return error;
12568cb7f63dSAlexander Gordeev 
125761e62e21SKrishna Gudipati 	bfad->bfad_flags |= BFAD_INTX_ON;
1258a36c61f9SKrishna Gudipati 
12598cb7f63dSAlexander Gordeev 	return 0;
1260a36c61f9SKrishna Gudipati }
1261a36c61f9SKrishna Gudipati 
1262a36c61f9SKrishna Gudipati void
bfad_remove_intr(struct bfad_s * bfad)1263a36c61f9SKrishna Gudipati bfad_remove_intr(struct bfad_s *bfad)
1264a36c61f9SKrishna Gudipati {
1265a36c61f9SKrishna Gudipati 	int	i;
1266a36c61f9SKrishna Gudipati 
1267a36c61f9SKrishna Gudipati 	if (bfad->bfad_flags & BFAD_MSIX_ON) {
1268a36c61f9SKrishna Gudipati 		for (i = 0; i < bfad->nvec; i++)
1269a36c61f9SKrishna Gudipati 			free_irq(bfad->msix_tab[i].msix.vector,
1270a36c61f9SKrishna Gudipati 					&bfad->msix_tab[i]);
1271a36c61f9SKrishna Gudipati 
1272a36c61f9SKrishna Gudipati 		pci_disable_msix(bfad->pcidev);
1273a36c61f9SKrishna Gudipati 		bfad->bfad_flags &= ~BFAD_MSIX_ON;
127461e62e21SKrishna Gudipati 	} else if (bfad->bfad_flags & BFAD_INTX_ON) {
1275a36c61f9SKrishna Gudipati 		free_irq(bfad->pcidev->irq, bfad);
1276a36c61f9SKrishna Gudipati 	}
1277a36c61f9SKrishna Gudipati }
12787725ccfdSJing Huang 
12795fbe25c7SJing Huang /*
12807725ccfdSJing Huang  * PCI probe entry.
12817725ccfdSJing Huang  */
12827725ccfdSJing Huang int
bfad_pci_probe(struct pci_dev * pdev,const struct pci_device_id * pid)12837725ccfdSJing Huang bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
12847725ccfdSJing Huang {
12857725ccfdSJing Huang 	struct bfad_s	*bfad;
12867826f304SKrishna Gudipati 	int		error = -ENODEV, retval, i;
12877725ccfdSJing Huang 
1288a36c61f9SKrishna Gudipati 	/* For single port cards - only claim function 0 */
12898b070b4aSKrishna Gudipati 	if ((pdev->device == BFA_PCI_DEVICE_ID_FC_8G1P) &&
1290a36c61f9SKrishna Gudipati 		(PCI_FUNC(pdev->devfn) != 0))
12917725ccfdSJing Huang 		return -ENODEV;
12927725ccfdSJing Huang 
12937725ccfdSJing Huang 	bfad = kzalloc(sizeof(struct bfad_s), GFP_KERNEL);
12947725ccfdSJing Huang 	if (!bfad) {
12957725ccfdSJing Huang 		error = -ENOMEM;
12967725ccfdSJing Huang 		goto out;
12977725ccfdSJing Huang 	}
12987725ccfdSJing Huang 
12997725ccfdSJing Huang 	bfad->trcmod = kzalloc(sizeof(struct bfa_trc_mod_s), GFP_KERNEL);
13007725ccfdSJing Huang 	if (!bfad->trcmod) {
13017725ccfdSJing Huang 		printk(KERN_WARNING "Error alloc trace buffer!\n");
13027725ccfdSJing Huang 		error = -ENOMEM;
13037725ccfdSJing Huang 		goto out_alloc_trace_failure;
13047725ccfdSJing Huang 	}
13057725ccfdSJing Huang 
1306a36c61f9SKrishna Gudipati 	/* TRACE INIT */
13077725ccfdSJing Huang 	bfa_trc_init(bfad->trcmod);
13087725ccfdSJing Huang 	bfa_trc(bfad, bfad_inst);
13097725ccfdSJing Huang 
13107826f304SKrishna Gudipati 	/* AEN INIT */
13117826f304SKrishna Gudipati 	INIT_LIST_HEAD(&bfad->free_aen_q);
13127826f304SKrishna Gudipati 	INIT_LIST_HEAD(&bfad->active_aen_q);
13137826f304SKrishna Gudipati 	for (i = 0; i < BFA_AEN_MAX_ENTRY; i++)
13147826f304SKrishna Gudipati 		list_add_tail(&bfad->aen_list[i].qe, &bfad->free_aen_q);
13157826f304SKrishna Gudipati 
13167725ccfdSJing Huang 	if (!(bfad_load_fwimg(pdev))) {
13177725ccfdSJing Huang 		kfree(bfad->trcmod);
13187725ccfdSJing Huang 		goto out_alloc_trace_failure;
13197725ccfdSJing Huang 	}
13207725ccfdSJing Huang 
13217725ccfdSJing Huang 	retval = bfad_pci_init(pdev, bfad);
13227725ccfdSJing Huang 	if (retval) {
13237725ccfdSJing Huang 		printk(KERN_WARNING "bfad_pci_init failure!\n");
13247725ccfdSJing Huang 		error = retval;
13257725ccfdSJing Huang 		goto out_pci_init_failure;
13267725ccfdSJing Huang 	}
13277725ccfdSJing Huang 
13287725ccfdSJing Huang 	mutex_lock(&bfad_mutex);
13297725ccfdSJing Huang 	bfad->inst_no = bfad_inst++;
13307725ccfdSJing Huang 	list_add_tail(&bfad->list_entry, &bfad_list);
13317725ccfdSJing Huang 	mutex_unlock(&bfad_mutex);
13327725ccfdSJing Huang 
1333a36c61f9SKrishna Gudipati 	/* Initializing the state machine: State set to uninit */
1334a36c61f9SKrishna Gudipati 	bfa_sm_set_state(bfad, bfad_sm_uninit);
1335a36c61f9SKrishna Gudipati 
13367725ccfdSJing Huang 	spin_lock_init(&bfad->bfad_lock);
13370b1017aaSKyle McMartin 	spin_lock_init(&bfad->bfad_aen_spinlock);
13380b1017aaSKyle McMartin 
13397725ccfdSJing Huang 	pci_set_drvdata(pdev, bfad);
13407725ccfdSJing Huang 
13417725ccfdSJing Huang 	bfad->ref_count = 0;
13427725ccfdSJing Huang 	bfad->pport.bfad = bfad;
1343a36c61f9SKrishna Gudipati 	INIT_LIST_HEAD(&bfad->pbc_vport_list);
13445b7db7afSKrishna Gudipati 	INIT_LIST_HEAD(&bfad->vport_list);
1345e6714324SKrishna Gudipati 
13467c38c05bSKrishna Gudipati 	/* Setup the debugfs node for this bfad */
13477c38c05bSKrishna Gudipati 	if (bfa_debugfs_enable)
13487c38c05bSKrishna Gudipati 		bfad_debugfs_init(&bfad->pport);
13497c38c05bSKrishna Gudipati 
13507725ccfdSJing Huang 	retval = bfad_drv_init(bfad);
13517725ccfdSJing Huang 	if (retval != BFA_STATUS_OK)
13527725ccfdSJing Huang 		goto out_drv_init_failure;
13537725ccfdSJing Huang 
1354a36c61f9SKrishna Gudipati 	bfa_sm_send_event(bfad, BFAD_E_CREATE);
13557725ccfdSJing Huang 
1356a36c61f9SKrishna Gudipati 	if (bfa_sm_cmp_state(bfad, bfad_sm_uninit))
1357a36c61f9SKrishna Gudipati 		goto out_bfad_sm_failure;
13587725ccfdSJing Huang 
13597725ccfdSJing Huang 	return 0;
13607725ccfdSJing Huang 
1361a36c61f9SKrishna Gudipati out_bfad_sm_failure:
1362a36c61f9SKrishna Gudipati 	bfad_hal_mem_release(bfad);
13637725ccfdSJing Huang out_drv_init_failure:
13647c38c05bSKrishna Gudipati 	/* Remove the debugfs node for this bfad */
13657c38c05bSKrishna Gudipati 	kfree(bfad->regdata);
13667c38c05bSKrishna Gudipati 	bfad_debugfs_exit(&bfad->pport);
13677725ccfdSJing Huang 	mutex_lock(&bfad_mutex);
13687725ccfdSJing Huang 	bfad_inst--;
13697725ccfdSJing Huang 	list_del(&bfad->list_entry);
13707725ccfdSJing Huang 	mutex_unlock(&bfad_mutex);
13717725ccfdSJing Huang 	bfad_pci_uninit(pdev, bfad);
13727725ccfdSJing Huang out_pci_init_failure:
13737725ccfdSJing Huang 	kfree(bfad->trcmod);
13747725ccfdSJing Huang out_alloc_trace_failure:
13757725ccfdSJing Huang 	kfree(bfad);
13767725ccfdSJing Huang out:
13777725ccfdSJing Huang 	return error;
13787725ccfdSJing Huang }
13797725ccfdSJing Huang 
13805fbe25c7SJing Huang /*
13817725ccfdSJing Huang  * PCI remove entry.
13827725ccfdSJing Huang  */
13837725ccfdSJing Huang void
bfad_pci_remove(struct pci_dev * pdev)13847725ccfdSJing Huang bfad_pci_remove(struct pci_dev *pdev)
13857725ccfdSJing Huang {
13867725ccfdSJing Huang 	struct bfad_s	      *bfad = pci_get_drvdata(pdev);
13877725ccfdSJing Huang 	unsigned long	flags;
13887725ccfdSJing Huang 
13897725ccfdSJing Huang 	bfa_trc(bfad, bfad->inst_no);
13907725ccfdSJing Huang 
1391e6714324SKrishna Gudipati 	spin_lock_irqsave(&bfad->bfad_lock, flags);
1392a36c61f9SKrishna Gudipati 	if (bfad->bfad_tsk != NULL) {
1393a36c61f9SKrishna Gudipati 		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1394e6714324SKrishna Gudipati 		kthread_stop(bfad->bfad_tsk);
1395a36c61f9SKrishna Gudipati 	} else {
1396e6714324SKrishna Gudipati 		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
13977725ccfdSJing Huang 	}
13987725ccfdSJing Huang 
1399a36c61f9SKrishna Gudipati 	/* Send Event BFAD_E_STOP */
1400a36c61f9SKrishna Gudipati 	bfa_sm_send_event(bfad, BFAD_E_STOP);
14017725ccfdSJing Huang 
1402a36c61f9SKrishna Gudipati 	/* Driver detach and dealloc mem */
14037725ccfdSJing Huang 	spin_lock_irqsave(&bfad->bfad_lock, flags);
14047725ccfdSJing Huang 	bfa_detach(&bfad->bfa);
14057725ccfdSJing Huang 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
14067725ccfdSJing Huang 	bfad_hal_mem_release(bfad);
14077725ccfdSJing Huang 
14087c38c05bSKrishna Gudipati 	/* Remove the debugfs node for this bfad */
14097c38c05bSKrishna Gudipati 	kfree(bfad->regdata);
14107c38c05bSKrishna Gudipati 	bfad_debugfs_exit(&bfad->pport);
14117c38c05bSKrishna Gudipati 
1412a36c61f9SKrishna Gudipati 	/* Cleaning the BFAD instance */
14137725ccfdSJing Huang 	mutex_lock(&bfad_mutex);
14147725ccfdSJing Huang 	bfad_inst--;
14157725ccfdSJing Huang 	list_del(&bfad->list_entry);
14167725ccfdSJing Huang 	mutex_unlock(&bfad_mutex);
14177725ccfdSJing Huang 	bfad_pci_uninit(pdev, bfad);
14187725ccfdSJing Huang 
14197725ccfdSJing Huang 	kfree(bfad->trcmod);
14207725ccfdSJing Huang 	kfree(bfad);
14217725ccfdSJing Huang }
14227725ccfdSJing Huang 
1423881c1b3cSKrishna Gudipati /*
1424881c1b3cSKrishna Gudipati  * PCI Error Recovery entry, error detected.
1425881c1b3cSKrishna Gudipati  */
1426881c1b3cSKrishna Gudipati static pci_ers_result_t
bfad_pci_error_detected(struct pci_dev * pdev,pci_channel_state_t state)1427881c1b3cSKrishna Gudipati bfad_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
1428881c1b3cSKrishna Gudipati {
1429881c1b3cSKrishna Gudipati 	struct bfad_s *bfad = pci_get_drvdata(pdev);
1430881c1b3cSKrishna Gudipati 	unsigned long	flags;
1431881c1b3cSKrishna Gudipati 	pci_ers_result_t ret = PCI_ERS_RESULT_NONE;
1432881c1b3cSKrishna Gudipati 
1433881c1b3cSKrishna Gudipati 	dev_printk(KERN_ERR, &pdev->dev,
1434881c1b3cSKrishna Gudipati 		   "error detected state: %d - flags: 0x%x\n",
1435881c1b3cSKrishna Gudipati 		   state, bfad->bfad_flags);
1436881c1b3cSKrishna Gudipati 
1437881c1b3cSKrishna Gudipati 	switch (state) {
1438881c1b3cSKrishna Gudipati 	case pci_channel_io_normal: /* non-fatal error */
1439881c1b3cSKrishna Gudipati 		spin_lock_irqsave(&bfad->bfad_lock, flags);
1440881c1b3cSKrishna Gudipati 		bfad->bfad_flags &= ~BFAD_EEH_BUSY;
1441881c1b3cSKrishna Gudipati 		/* Suspend/fail all bfa operations */
1442881c1b3cSKrishna Gudipati 		bfa_ioc_suspend(&bfad->bfa.ioc);
1443881c1b3cSKrishna Gudipati 		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1444881c1b3cSKrishna Gudipati 		del_timer_sync(&bfad->hal_tmo);
1445881c1b3cSKrishna Gudipati 		ret = PCI_ERS_RESULT_CAN_RECOVER;
1446881c1b3cSKrishna Gudipati 		break;
1447881c1b3cSKrishna Gudipati 	case pci_channel_io_frozen: /* fatal error */
1448881c1b3cSKrishna Gudipati 		init_completion(&bfad->comp);
1449881c1b3cSKrishna Gudipati 		spin_lock_irqsave(&bfad->bfad_lock, flags);
1450881c1b3cSKrishna Gudipati 		bfad->bfad_flags |= BFAD_EEH_BUSY;
1451881c1b3cSKrishna Gudipati 		/* Suspend/fail all bfa operations */
1452881c1b3cSKrishna Gudipati 		bfa_ioc_suspend(&bfad->bfa.ioc);
1453881c1b3cSKrishna Gudipati 		bfa_fcs_stop(&bfad->bfa_fcs);
1454881c1b3cSKrishna Gudipati 		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1455881c1b3cSKrishna Gudipati 		wait_for_completion(&bfad->comp);
1456881c1b3cSKrishna Gudipati 
1457881c1b3cSKrishna Gudipati 		bfad_remove_intr(bfad);
1458881c1b3cSKrishna Gudipati 		del_timer_sync(&bfad->hal_tmo);
1459881c1b3cSKrishna Gudipati 		pci_disable_device(pdev);
1460881c1b3cSKrishna Gudipati 		ret = PCI_ERS_RESULT_NEED_RESET;
1461881c1b3cSKrishna Gudipati 		break;
1462881c1b3cSKrishna Gudipati 	case pci_channel_io_perm_failure: /* PCI Card is DEAD */
1463881c1b3cSKrishna Gudipati 		spin_lock_irqsave(&bfad->bfad_lock, flags);
1464881c1b3cSKrishna Gudipati 		bfad->bfad_flags |= BFAD_EEH_BUSY |
1465881c1b3cSKrishna Gudipati 				    BFAD_EEH_PCI_CHANNEL_IO_PERM_FAILURE;
1466881c1b3cSKrishna Gudipati 		spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1467881c1b3cSKrishna Gudipati 
1468881c1b3cSKrishna Gudipati 		/* If the error_detected handler is called with the reason
1469881c1b3cSKrishna Gudipati 		 * pci_channel_io_perm_failure - it will subsequently call
1470881c1b3cSKrishna Gudipati 		 * pci_remove() entry point to remove the pci device from the
1471881c1b3cSKrishna Gudipati 		 * system - So defer the cleanup to pci_remove(); cleaning up
1472881c1b3cSKrishna Gudipati 		 * here causes inconsistent state during pci_remove().
1473881c1b3cSKrishna Gudipati 		 */
1474881c1b3cSKrishna Gudipati 		ret = PCI_ERS_RESULT_DISCONNECT;
1475881c1b3cSKrishna Gudipati 		break;
1476881c1b3cSKrishna Gudipati 	default:
1477881c1b3cSKrishna Gudipati 		WARN_ON(1);
1478881c1b3cSKrishna Gudipati 	}
1479881c1b3cSKrishna Gudipati 
1480881c1b3cSKrishna Gudipati 	return ret;
1481881c1b3cSKrishna Gudipati }
1482881c1b3cSKrishna Gudipati 
restart_bfa(struct bfad_s * bfad)14837cd4cb94SYueHaibing static int restart_bfa(struct bfad_s *bfad)
1484881c1b3cSKrishna Gudipati {
1485881c1b3cSKrishna Gudipati 	unsigned long flags;
1486881c1b3cSKrishna Gudipati 	struct pci_dev *pdev = bfad->pcidev;
1487881c1b3cSKrishna Gudipati 
1488881c1b3cSKrishna Gudipati 	bfa_attach(&bfad->bfa, bfad, &bfad->ioc_cfg,
1489881c1b3cSKrishna Gudipati 		   &bfad->meminfo, &bfad->hal_pcidev);
1490881c1b3cSKrishna Gudipati 
1491881c1b3cSKrishna Gudipati 	/* Enable Interrupt and wait bfa_init completion */
1492881c1b3cSKrishna Gudipati 	if (bfad_setup_intr(bfad)) {
1493881c1b3cSKrishna Gudipati 		dev_printk(KERN_WARNING, &pdev->dev,
1494881c1b3cSKrishna Gudipati 			   "%s: bfad_setup_intr failed\n", bfad->pci_name);
1495da3e0beeSVijaya Mohan Guvva 		bfa_sm_send_event(bfad, BFAD_E_INIT_FAILED);
1496881c1b3cSKrishna Gudipati 		return -1;
1497881c1b3cSKrishna Gudipati 	}
1498881c1b3cSKrishna Gudipati 
1499881c1b3cSKrishna Gudipati 	init_completion(&bfad->comp);
1500881c1b3cSKrishna Gudipati 	spin_lock_irqsave(&bfad->bfad_lock, flags);
1501881c1b3cSKrishna Gudipati 	bfa_iocfc_init(&bfad->bfa);
1502881c1b3cSKrishna Gudipati 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1503881c1b3cSKrishna Gudipati 
1504881c1b3cSKrishna Gudipati 	/* Set up interrupt handler for each vectors */
1505881c1b3cSKrishna Gudipati 	if ((bfad->bfad_flags & BFAD_MSIX_ON) &&
1506881c1b3cSKrishna Gudipati 	    bfad_install_msix_handler(bfad))
1507881c1b3cSKrishna Gudipati 		dev_printk(KERN_WARNING, &pdev->dev,
1508881c1b3cSKrishna Gudipati 			   "%s: install_msix failed.\n", bfad->pci_name);
1509881c1b3cSKrishna Gudipati 
1510881c1b3cSKrishna Gudipati 	bfad_init_timer(bfad);
1511881c1b3cSKrishna Gudipati 	wait_for_completion(&bfad->comp);
1512881c1b3cSKrishna Gudipati 	bfad_drv_start(bfad);
1513881c1b3cSKrishna Gudipati 
1514881c1b3cSKrishna Gudipati 	return 0;
1515881c1b3cSKrishna Gudipati }
1516881c1b3cSKrishna Gudipati 
1517881c1b3cSKrishna Gudipati /*
1518881c1b3cSKrishna Gudipati  * PCI Error Recovery entry, re-initialize the chip.
1519881c1b3cSKrishna Gudipati  */
1520881c1b3cSKrishna Gudipati static pci_ers_result_t
bfad_pci_slot_reset(struct pci_dev * pdev)1521881c1b3cSKrishna Gudipati bfad_pci_slot_reset(struct pci_dev *pdev)
1522881c1b3cSKrishna Gudipati {
1523881c1b3cSKrishna Gudipati 	struct bfad_s *bfad = pci_get_drvdata(pdev);
1524881c1b3cSKrishna Gudipati 	u8 byte;
152511ea3824SHannes Reinecke 	int rc;
1526881c1b3cSKrishna Gudipati 
1527881c1b3cSKrishna Gudipati 	dev_printk(KERN_ERR, &pdev->dev,
1528881c1b3cSKrishna Gudipati 		   "bfad_pci_slot_reset flags: 0x%x\n", bfad->bfad_flags);
1529881c1b3cSKrishna Gudipati 
1530881c1b3cSKrishna Gudipati 	if (pci_enable_device(pdev)) {
1531881c1b3cSKrishna Gudipati 		dev_printk(KERN_ERR, &pdev->dev, "Cannot re-enable "
1532881c1b3cSKrishna Gudipati 			   "PCI device after reset.\n");
1533881c1b3cSKrishna Gudipati 		return PCI_ERS_RESULT_DISCONNECT;
1534881c1b3cSKrishna Gudipati 	}
1535881c1b3cSKrishna Gudipati 
1536881c1b3cSKrishna Gudipati 	pci_restore_state(pdev);
1537881c1b3cSKrishna Gudipati 
1538881c1b3cSKrishna Gudipati 	/*
1539881c1b3cSKrishna Gudipati 	 * Read some byte (e.g. DMA max. payload size which can't
1540881c1b3cSKrishna Gudipati 	 * be 0xff any time) to make sure - we did not hit another PCI error
1541881c1b3cSKrishna Gudipati 	 * in the middle of recovery. If we did, then declare permanent failure.
1542881c1b3cSKrishna Gudipati 	 */
1543881c1b3cSKrishna Gudipati 	pci_read_config_byte(pdev, 0x68, &byte);
1544881c1b3cSKrishna Gudipati 	if (byte == 0xff) {
1545881c1b3cSKrishna Gudipati 		dev_printk(KERN_ERR, &pdev->dev,
1546881c1b3cSKrishna Gudipati 			   "slot_reset failed ... got another PCI error !\n");
1547881c1b3cSKrishna Gudipati 		goto out_disable_device;
1548881c1b3cSKrishna Gudipati 	}
1549881c1b3cSKrishna Gudipati 
1550881c1b3cSKrishna Gudipati 	pci_save_state(pdev);
1551881c1b3cSKrishna Gudipati 	pci_set_master(pdev);
1552881c1b3cSKrishna Gudipati 
155311ea3824SHannes Reinecke 	rc = dma_set_mask_and_coherent(&bfad->pcidev->dev, DMA_BIT_MASK(64));
155411ea3824SHannes Reinecke 	if (rc)
1555881c1b3cSKrishna Gudipati 		goto out_disable_device;
1556881c1b3cSKrishna Gudipati 
1557881c1b3cSKrishna Gudipati 	if (restart_bfa(bfad) == -1)
1558881c1b3cSKrishna Gudipati 		goto out_disable_device;
1559881c1b3cSKrishna Gudipati 
1560881c1b3cSKrishna Gudipati 	dev_printk(KERN_WARNING, &pdev->dev,
1561881c1b3cSKrishna Gudipati 		   "slot_reset completed  flags: 0x%x!\n", bfad->bfad_flags);
1562881c1b3cSKrishna Gudipati 
1563881c1b3cSKrishna Gudipati 	return PCI_ERS_RESULT_RECOVERED;
1564881c1b3cSKrishna Gudipati 
1565881c1b3cSKrishna Gudipati out_disable_device:
1566881c1b3cSKrishna Gudipati 	pci_disable_device(pdev);
1567881c1b3cSKrishna Gudipati 	return PCI_ERS_RESULT_DISCONNECT;
1568881c1b3cSKrishna Gudipati }
1569881c1b3cSKrishna Gudipati 
1570881c1b3cSKrishna Gudipati static pci_ers_result_t
bfad_pci_mmio_enabled(struct pci_dev * pdev)1571881c1b3cSKrishna Gudipati bfad_pci_mmio_enabled(struct pci_dev *pdev)
1572881c1b3cSKrishna Gudipati {
1573881c1b3cSKrishna Gudipati 	unsigned long	flags;
1574881c1b3cSKrishna Gudipati 	struct bfad_s *bfad = pci_get_drvdata(pdev);
1575881c1b3cSKrishna Gudipati 
1576881c1b3cSKrishna Gudipati 	dev_printk(KERN_INFO, &pdev->dev, "mmio_enabled\n");
1577881c1b3cSKrishna Gudipati 
1578881c1b3cSKrishna Gudipati 	/* Fetch FW diagnostic information */
1579881c1b3cSKrishna Gudipati 	bfa_ioc_debug_save_ftrc(&bfad->bfa.ioc);
1580881c1b3cSKrishna Gudipati 
1581881c1b3cSKrishna Gudipati 	/* Cancel all pending IOs */
1582881c1b3cSKrishna Gudipati 	spin_lock_irqsave(&bfad->bfad_lock, flags);
1583881c1b3cSKrishna Gudipati 	init_completion(&bfad->comp);
1584881c1b3cSKrishna Gudipati 	bfa_fcs_stop(&bfad->bfa_fcs);
1585881c1b3cSKrishna Gudipati 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1586881c1b3cSKrishna Gudipati 	wait_for_completion(&bfad->comp);
1587881c1b3cSKrishna Gudipati 
1588881c1b3cSKrishna Gudipati 	bfad_remove_intr(bfad);
1589881c1b3cSKrishna Gudipati 	del_timer_sync(&bfad->hal_tmo);
1590881c1b3cSKrishna Gudipati 	pci_disable_device(pdev);
1591881c1b3cSKrishna Gudipati 
1592881c1b3cSKrishna Gudipati 	return PCI_ERS_RESULT_NEED_RESET;
1593881c1b3cSKrishna Gudipati }
1594881c1b3cSKrishna Gudipati 
1595881c1b3cSKrishna Gudipati static void
bfad_pci_resume(struct pci_dev * pdev)1596881c1b3cSKrishna Gudipati bfad_pci_resume(struct pci_dev *pdev)
1597881c1b3cSKrishna Gudipati {
1598881c1b3cSKrishna Gudipati 	unsigned long	flags;
1599881c1b3cSKrishna Gudipati 	struct bfad_s *bfad = pci_get_drvdata(pdev);
1600881c1b3cSKrishna Gudipati 
1601881c1b3cSKrishna Gudipati 	dev_printk(KERN_WARNING, &pdev->dev, "resume\n");
1602881c1b3cSKrishna Gudipati 
1603881c1b3cSKrishna Gudipati 	/* wait until the link is online */
1604881c1b3cSKrishna Gudipati 	bfad_rport_online_wait(bfad);
1605881c1b3cSKrishna Gudipati 
1606881c1b3cSKrishna Gudipati 	spin_lock_irqsave(&bfad->bfad_lock, flags);
1607881c1b3cSKrishna Gudipati 	bfad->bfad_flags &= ~BFAD_EEH_BUSY;
1608881c1b3cSKrishna Gudipati 	spin_unlock_irqrestore(&bfad->bfad_lock, flags);
1609881c1b3cSKrishna Gudipati }
1610881c1b3cSKrishna Gudipati 
1611a36c61f9SKrishna Gudipati struct pci_device_id bfad_id_table[] = {
16127725ccfdSJing Huang 	{
16137725ccfdSJing Huang 		.vendor = BFA_PCI_VENDOR_ID_BROCADE,
16147725ccfdSJing Huang 		.device = BFA_PCI_DEVICE_ID_FC_8G2P,
16157725ccfdSJing Huang 		.subvendor = PCI_ANY_ID,
16167725ccfdSJing Huang 		.subdevice = PCI_ANY_ID,
16177725ccfdSJing Huang 	},
16187725ccfdSJing Huang 	{
16197725ccfdSJing Huang 		.vendor = BFA_PCI_VENDOR_ID_BROCADE,
16207725ccfdSJing Huang 		.device = BFA_PCI_DEVICE_ID_FC_8G1P,
16217725ccfdSJing Huang 		.subvendor = PCI_ANY_ID,
16227725ccfdSJing Huang 		.subdevice = PCI_ANY_ID,
16237725ccfdSJing Huang 	},
16247725ccfdSJing Huang 	{
16257725ccfdSJing Huang 		.vendor = BFA_PCI_VENDOR_ID_BROCADE,
16267725ccfdSJing Huang 		.device = BFA_PCI_DEVICE_ID_CT,
16277725ccfdSJing Huang 		.subvendor = PCI_ANY_ID,
16287725ccfdSJing Huang 		.subdevice = PCI_ANY_ID,
16297725ccfdSJing Huang 		.class = (PCI_CLASS_SERIAL_FIBER << 8),
16307725ccfdSJing Huang 		.class_mask = ~0,
16317725ccfdSJing Huang 	},
1632293f82d5SJing Huang 	{
1633293f82d5SJing Huang 		.vendor = BFA_PCI_VENDOR_ID_BROCADE,
1634293f82d5SJing Huang 		.device = BFA_PCI_DEVICE_ID_CT_FC,
1635293f82d5SJing Huang 		.subvendor = PCI_ANY_ID,
1636293f82d5SJing Huang 		.subdevice = PCI_ANY_ID,
1637293f82d5SJing Huang 		.class = (PCI_CLASS_SERIAL_FIBER << 8),
1638293f82d5SJing Huang 		.class_mask = ~0,
1639293f82d5SJing Huang 	},
164011189208SKrishna Gudipati 	{
164111189208SKrishna Gudipati 		.vendor = BFA_PCI_VENDOR_ID_BROCADE,
164211189208SKrishna Gudipati 		.device = BFA_PCI_DEVICE_ID_CT2,
164311189208SKrishna Gudipati 		.subvendor = PCI_ANY_ID,
164411189208SKrishna Gudipati 		.subdevice = PCI_ANY_ID,
164511189208SKrishna Gudipati 		.class = (PCI_CLASS_SERIAL_FIBER << 8),
164611189208SKrishna Gudipati 		.class_mask = ~0,
164711189208SKrishna Gudipati 	},
16487725ccfdSJing Huang 
1649f9c867b4SVijaya Mohan Guvva 	{
1650f9c867b4SVijaya Mohan Guvva 		.vendor = BFA_PCI_VENDOR_ID_BROCADE,
1651f9c867b4SVijaya Mohan Guvva 		.device = BFA_PCI_DEVICE_ID_CT2_QUAD,
1652f9c867b4SVijaya Mohan Guvva 		.subvendor = PCI_ANY_ID,
1653f9c867b4SVijaya Mohan Guvva 		.subdevice = PCI_ANY_ID,
1654f9c867b4SVijaya Mohan Guvva 		.class = (PCI_CLASS_SERIAL_FIBER << 8),
1655f9c867b4SVijaya Mohan Guvva 		.class_mask = ~0,
1656f9c867b4SVijaya Mohan Guvva 	},
16577725ccfdSJing Huang 	{0, 0},
16587725ccfdSJing Huang };
16597725ccfdSJing Huang 
16607725ccfdSJing Huang MODULE_DEVICE_TABLE(pci, bfad_id_table);
16617725ccfdSJing Huang 
1662881c1b3cSKrishna Gudipati /*
1663881c1b3cSKrishna Gudipati  * PCI error recovery handlers.
1664881c1b3cSKrishna Gudipati  */
1665881c1b3cSKrishna Gudipati static struct pci_error_handlers bfad_err_handler = {
1666881c1b3cSKrishna Gudipati 	.error_detected = bfad_pci_error_detected,
1667881c1b3cSKrishna Gudipati 	.slot_reset = bfad_pci_slot_reset,
1668881c1b3cSKrishna Gudipati 	.mmio_enabled = bfad_pci_mmio_enabled,
1669881c1b3cSKrishna Gudipati 	.resume = bfad_pci_resume,
1670881c1b3cSKrishna Gudipati };
1671881c1b3cSKrishna Gudipati 
16727725ccfdSJing Huang static struct pci_driver bfad_pci_driver = {
16737725ccfdSJing Huang 	.name = BFAD_DRIVER_NAME,
16747725ccfdSJing Huang 	.id_table = bfad_id_table,
16757725ccfdSJing Huang 	.probe = bfad_pci_probe,
16766f039790SGreg Kroah-Hartman 	.remove = bfad_pci_remove,
1677881c1b3cSKrishna Gudipati 	.err_handler = &bfad_err_handler,
16787725ccfdSJing Huang };
16797725ccfdSJing Huang 
16805fbe25c7SJing Huang /*
16817725ccfdSJing Huang  * Driver module init.
16827725ccfdSJing Huang  */
16837725ccfdSJing Huang static int __init
bfad_init(void)16847725ccfdSJing Huang bfad_init(void)
16857725ccfdSJing Huang {
16867725ccfdSJing Huang 	int		error = 0;
16877725ccfdSJing Huang 
168831e1d569SAnil Gurumurthy 	pr_info("QLogic BR-series BFA FC/FCOE SCSI driver - version: %s\n",
16897725ccfdSJing Huang 			BFAD_DRIVER_VERSION);
16907725ccfdSJing Huang 
16917725ccfdSJing Huang 	if (num_sgpgs > 0)
16927725ccfdSJing Huang 		num_sgpgs_parm = num_sgpgs;
16937725ccfdSJing Huang 
1694a36c61f9SKrishna Gudipati 	error = bfad_im_module_init();
16957725ccfdSJing Huang 	if (error) {
16967725ccfdSJing Huang 		error = -ENOMEM;
1697a36c61f9SKrishna Gudipati 		printk(KERN_WARNING "bfad_im_module_init failure\n");
16987725ccfdSJing Huang 		goto ext;
16997725ccfdSJing Huang 	}
17007725ccfdSJing Huang 
1701a36c61f9SKrishna Gudipati 	if (strcmp(FCPI_NAME, " fcpim") == 0)
1702a36c61f9SKrishna Gudipati 		supported_fc4s |= BFA_LPORT_ROLE_FCP_IM;
17037725ccfdSJing Huang 
1704f7f73812SMaggie Zhang 	bfa_auto_recover = ioc_auto_recover;
17057725ccfdSJing Huang 	bfa_fcs_rport_set_del_timeout(rport_del_timeout);
170661ba4394SKrishna Gudipati 	bfa_fcs_rport_set_max_logins(max_rport_logins);
17077725ccfdSJing Huang 
1708a36c61f9SKrishna Gudipati 	error = pci_register_driver(&bfad_pci_driver);
17097725ccfdSJing Huang 	if (error) {
1710a36c61f9SKrishna Gudipati 		printk(KERN_WARNING "pci_register_driver failure\n");
17117725ccfdSJing Huang 		goto ext;
17127725ccfdSJing Huang 	}
17137725ccfdSJing Huang 
17147725ccfdSJing Huang 	return 0;
17157725ccfdSJing Huang 
17167725ccfdSJing Huang ext:
1717a36c61f9SKrishna Gudipati 	bfad_im_module_exit();
17187725ccfdSJing Huang 	return error;
17197725ccfdSJing Huang }
17207725ccfdSJing Huang 
17215fbe25c7SJing Huang /*
17227725ccfdSJing Huang  * Driver module exit.
17237725ccfdSJing Huang  */
17247725ccfdSJing Huang static void __exit
bfad_exit(void)17257725ccfdSJing Huang bfad_exit(void)
17267725ccfdSJing Huang {
17277725ccfdSJing Huang 	pci_unregister_driver(&bfad_pci_driver);
1728a36c61f9SKrishna Gudipati 	bfad_im_module_exit();
17297725ccfdSJing Huang 	bfad_free_fwimg();
17307725ccfdSJing Huang }
17317725ccfdSJing Huang 
1732a36c61f9SKrishna Gudipati /* Firmware handling */
173361338a0bSJing Huang static void
bfad_read_firmware(struct pci_dev * pdev,u32 ** bfi_image,u32 * bfi_image_size,char * fw_name)1734a36c61f9SKrishna Gudipati bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
1735a36c61f9SKrishna Gudipati 		u32 *bfi_image_size, char *fw_name)
1736a36c61f9SKrishna Gudipati {
1737a36c61f9SKrishna Gudipati 	const struct firmware *fw;
1738a36c61f9SKrishna Gudipati 
1739a36c61f9SKrishna Gudipati 	if (request_firmware(&fw, fw_name, &pdev->dev)) {
1740a36c61f9SKrishna Gudipati 		printk(KERN_ALERT "Can't locate firmware %s\n", fw_name);
174161338a0bSJing Huang 		*bfi_image = NULL;
174261338a0bSJing Huang 		goto out;
1743a36c61f9SKrishna Gudipati 	}
1744a36c61f9SKrishna Gudipati 
1745a36c61f9SKrishna Gudipati 	*bfi_image = vmalloc(fw->size);
1746a36c61f9SKrishna Gudipati 	if (NULL == *bfi_image) {
1747a36c61f9SKrishna Gudipati 		printk(KERN_ALERT "Fail to allocate buffer for fw image "
1748a36c61f9SKrishna Gudipati 			"size=%x!\n", (u32) fw->size);
174961338a0bSJing Huang 		goto out;
1750a36c61f9SKrishna Gudipati 	}
1751a36c61f9SKrishna Gudipati 
1752a36c61f9SKrishna Gudipati 	memcpy(*bfi_image, fw->data, fw->size);
1753a36c61f9SKrishna Gudipati 	*bfi_image_size = fw->size/sizeof(u32);
175461338a0bSJing Huang out:
175561338a0bSJing Huang 	release_firmware(fw);
1756a36c61f9SKrishna Gudipati }
1757a36c61f9SKrishna Gudipati 
175861338a0bSJing Huang static u32 *
bfad_load_fwimg(struct pci_dev * pdev)175961338a0bSJing Huang bfad_load_fwimg(struct pci_dev *pdev)
1760a36c61f9SKrishna Gudipati {
1761dcaf9aedSVijaya Mohan Guvva 	if (bfa_asic_id_ct2(pdev->device)) {
176211189208SKrishna Gudipati 		if (bfi_image_ct2_size == 0)
176311189208SKrishna Gudipati 			bfad_read_firmware(pdev, &bfi_image_ct2,
176411189208SKrishna Gudipati 				&bfi_image_ct2_size, BFAD_FW_FILE_CT2);
176511189208SKrishna Gudipati 		return bfi_image_ct2;
176611189208SKrishna Gudipati 	} else if (bfa_asic_id_ct(pdev->device)) {
176711189208SKrishna Gudipati 		if (bfi_image_ct_size == 0)
176811189208SKrishna Gudipati 			bfad_read_firmware(pdev, &bfi_image_ct,
176911189208SKrishna Gudipati 				&bfi_image_ct_size, BFAD_FW_FILE_CT);
177011189208SKrishna Gudipati 		return bfi_image_ct;
1771dcaf9aedSVijaya Mohan Guvva 	} else if (bfa_asic_id_cb(pdev->device)) {
177211189208SKrishna Gudipati 		if (bfi_image_cb_size == 0)
177311189208SKrishna Gudipati 			bfad_read_firmware(pdev, &bfi_image_cb,
177411189208SKrishna Gudipati 				&bfi_image_cb_size, BFAD_FW_FILE_CB);
177511189208SKrishna Gudipati 		return bfi_image_cb;
1776a36c61f9SKrishna Gudipati 	}
1777dcaf9aedSVijaya Mohan Guvva 
1778dcaf9aedSVijaya Mohan Guvva 	return NULL;
1779a36c61f9SKrishna Gudipati }
17807725ccfdSJing Huang 
178161338a0bSJing Huang static void
bfad_free_fwimg(void)178261338a0bSJing Huang bfad_free_fwimg(void)
178361338a0bSJing Huang {
178411189208SKrishna Gudipati 	if (bfi_image_ct2_size && bfi_image_ct2)
178511189208SKrishna Gudipati 		vfree(bfi_image_ct2);
178611189208SKrishna Gudipati 	if (bfi_image_ct_size && bfi_image_ct)
178711189208SKrishna Gudipati 		vfree(bfi_image_ct);
178811189208SKrishna Gudipati 	if (bfi_image_cb_size && bfi_image_cb)
178911189208SKrishna Gudipati 		vfree(bfi_image_cb);
179061338a0bSJing Huang }
179161338a0bSJing Huang 
17927725ccfdSJing Huang module_init(bfad_init);
17937725ccfdSJing Huang module_exit(bfad_exit);
17947725ccfdSJing Huang MODULE_LICENSE("GPL");
179531e1d569SAnil Gurumurthy MODULE_DESCRIPTION("QLogic BR-series Fibre Channel HBA Driver" BFAD_PROTO_NAME);
179631e1d569SAnil Gurumurthy MODULE_AUTHOR("QLogic Corporation");
17977725ccfdSJing Huang MODULE_VERSION(BFAD_DRIVER_VERSION);
1798