xref: /linux/drivers/scsi/qla2xxx/qla_mid.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
177adf3f0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22c3dfe3fSSeokmann Ju /*
301e58d8eSAndrew Vasquez  * QLogic Fibre Channel HBA Driver
4bd21eaf9SArmen Baloyan  * Copyright (c)  2003-2014 QLogic Corporation
52c3dfe3fSSeokmann Ju  */
62c3dfe3fSSeokmann Ju #include "qla_def.h"
77b867cf7SAnirban Chakraborty #include "qla_gbl.h"
82d70c103SNicholas Bellinger #include "qla_target.h"
92c3dfe3fSSeokmann Ju 
102c3dfe3fSSeokmann Ju #include <linux/moduleparam.h>
112c3dfe3fSSeokmann Ju #include <linux/vmalloc.h>
125a0e3ad6STejun Heo #include <linux/slab.h>
132c3dfe3fSSeokmann Ju #include <linux/list.h>
142c3dfe3fSSeokmann Ju 
152c3dfe3fSSeokmann Ju #include <scsi/scsi_tcq.h>
162c3dfe3fSSeokmann Ju #include <scsi/scsicam.h>
172c3dfe3fSSeokmann Ju #include <linux/delay.h>
182c3dfe3fSSeokmann Ju 
192c3dfe3fSSeokmann Ju void
qla2x00_vp_stop_timer(scsi_qla_host_t * vha)202c3dfe3fSSeokmann Ju qla2x00_vp_stop_timer(scsi_qla_host_t *vha)
212c3dfe3fSSeokmann Ju {
227b867cf7SAnirban Chakraborty 	if (vha->vp_idx && vha->timer_active) {
232c3dfe3fSSeokmann Ju 		del_timer_sync(&vha->timer);
242c3dfe3fSSeokmann Ju 		vha->timer_active = 0;
252c3dfe3fSSeokmann Ju 	}
262c3dfe3fSSeokmann Ju }
272c3dfe3fSSeokmann Ju 
28a824ebb3SAdrian Bunk static uint32_t
qla24xx_allocate_vp_id(scsi_qla_host_t * vha)292c3dfe3fSSeokmann Ju qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
302c3dfe3fSSeokmann Ju {
312c3dfe3fSSeokmann Ju 	uint32_t vp_id;
327b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
33feafb7b1SArun Easi 	unsigned long flags;
342c3dfe3fSSeokmann Ju 
352c3dfe3fSSeokmann Ju 	/* Find an empty slot and assign an vp_id */
366c2f527cSmatthias@kaehlcke.net 	mutex_lock(&ha->vport_lock);
37eb66dc60SAndrew Vasquez 	vp_id = find_first_zero_bit(ha->vp_idx_map, ha->max_npiv_vports + 1);
38eb66dc60SAndrew Vasquez 	if (vp_id > ha->max_npiv_vports) {
397c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_vport, vha, 0xa000,
407c3df132SSaurav Kashyap 		    "vp_id %d is bigger than max-supported %d.\n",
417c3df132SSaurav Kashyap 		    vp_id, ha->max_npiv_vports);
426c2f527cSmatthias@kaehlcke.net 		mutex_unlock(&ha->vport_lock);
432c3dfe3fSSeokmann Ju 		return vp_id;
442c3dfe3fSSeokmann Ju 	}
452c3dfe3fSSeokmann Ju 
46eb66dc60SAndrew Vasquez 	set_bit(vp_id, ha->vp_idx_map);
472c3dfe3fSSeokmann Ju 	ha->num_vhosts++;
482c3dfe3fSSeokmann Ju 	vha->vp_idx = vp_id;
49feafb7b1SArun Easi 
50feafb7b1SArun Easi 	spin_lock_irqsave(&ha->vport_slock, flags);
517b867cf7SAnirban Chakraborty 	list_add_tail(&vha->list, &ha->vp_list);
52feafb7b1SArun Easi 	spin_unlock_irqrestore(&ha->vport_slock, flags);
53feafb7b1SArun Easi 
549d1aa4e1SQuinn Tran 	spin_lock_irqsave(&ha->hardware_lock, flags);
55430eef03SQuinn Tran 	qla_update_vp_map(vha, SET_VP_IDX);
569d1aa4e1SQuinn Tran 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
579d1aa4e1SQuinn Tran 
586c2f527cSmatthias@kaehlcke.net 	mutex_unlock(&ha->vport_lock);
592c3dfe3fSSeokmann Ju 	return vp_id;
602c3dfe3fSSeokmann Ju }
612c3dfe3fSSeokmann Ju 
622c3dfe3fSSeokmann Ju void
qla24xx_deallocate_vp_id(scsi_qla_host_t * vha)632c3dfe3fSSeokmann Ju qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
642c3dfe3fSSeokmann Ju {
652c3dfe3fSSeokmann Ju 	uint16_t vp_id;
667b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
67feafb7b1SArun Easi 	unsigned long flags = 0;
680c9a5f3eSQuinn Tran 	u32 i, bailout;
692c3dfe3fSSeokmann Ju 
706c2f527cSmatthias@kaehlcke.net 	mutex_lock(&ha->vport_lock);
71feafb7b1SArun Easi 	/*
72feafb7b1SArun Easi 	 * Wait for all pending activities to finish before removing vport from
73feafb7b1SArun Easi 	 * the list.
74feafb7b1SArun Easi 	 * Lock needs to be held for safe removal from the list (it
75feafb7b1SArun Easi 	 * ensures no active vp_list traversal while the vport is removed
76feafb7b1SArun Easi 	 * from the queue)
77feafb7b1SArun Easi 	 */
780c9a5f3eSQuinn Tran 	bailout = 0;
790c9a5f3eSQuinn Tran 	for (i = 0; i < 500; i++) {
80feafb7b1SArun Easi 		spin_lock_irqsave(&ha->vport_slock, flags);
810c9a5f3eSQuinn Tran 		if (atomic_read(&vha->vref_count) == 0) {
820c9a5f3eSQuinn Tran 			list_del(&vha->list);
83430eef03SQuinn Tran 			qla_update_vp_map(vha, RESET_VP_IDX);
840c9a5f3eSQuinn Tran 			bailout = 1;
85feafb7b1SArun Easi 		}
860c9a5f3eSQuinn Tran 		spin_unlock_irqrestore(&ha->vport_slock, flags);
870c9a5f3eSQuinn Tran 
880c9a5f3eSQuinn Tran 		if (bailout)
890c9a5f3eSQuinn Tran 			break;
900c9a5f3eSQuinn Tran 		else
910c9a5f3eSQuinn Tran 			msleep(20);
920c9a5f3eSQuinn Tran 	}
930c9a5f3eSQuinn Tran 	if (!bailout) {
940c9a5f3eSQuinn Tran 		ql_log(ql_log_info, vha, 0xfffa,
950c9a5f3eSQuinn Tran 			"vha->vref_count=%u timeout\n", vha->vref_count.counter);
960c9a5f3eSQuinn Tran 		spin_lock_irqsave(&ha->vport_slock, flags);
97feafb7b1SArun Easi 		list_del(&vha->list);
98430eef03SQuinn Tran 		qla_update_vp_map(vha, RESET_VP_IDX);
99feafb7b1SArun Easi 		spin_unlock_irqrestore(&ha->vport_slock, flags);
1000c9a5f3eSQuinn Tran 	}
101feafb7b1SArun Easi 
1022c3dfe3fSSeokmann Ju 	vp_id = vha->vp_idx;
1032c3dfe3fSSeokmann Ju 	ha->num_vhosts--;
104eb66dc60SAndrew Vasquez 	clear_bit(vp_id, ha->vp_idx_map);
105feafb7b1SArun Easi 
1066c2f527cSmatthias@kaehlcke.net 	mutex_unlock(&ha->vport_lock);
1072c3dfe3fSSeokmann Ju }
1082c3dfe3fSSeokmann Ju 
109a824ebb3SAdrian Bunk static scsi_qla_host_t *
qla24xx_find_vhost_by_name(struct qla_hw_data * ha,uint8_t * port_name)1107b867cf7SAnirban Chakraborty qla24xx_find_vhost_by_name(struct qla_hw_data *ha, uint8_t *port_name)
1112c3dfe3fSSeokmann Ju {
1122c3dfe3fSSeokmann Ju 	scsi_qla_host_t *vha;
113ee546b6eSAnirban Chakraborty 	struct scsi_qla_host *tvha;
114feafb7b1SArun Easi 	unsigned long flags;
1152c3dfe3fSSeokmann Ju 
116feafb7b1SArun Easi 	spin_lock_irqsave(&ha->vport_slock, flags);
1172c3dfe3fSSeokmann Ju 	/* Locate matching device in database. */
118ee546b6eSAnirban Chakraborty 	list_for_each_entry_safe(vha, tvha, &ha->vp_list, list) {
119feafb7b1SArun Easi 		if (!memcmp(port_name, vha->port_name, WWN_SIZE)) {
120feafb7b1SArun Easi 			spin_unlock_irqrestore(&ha->vport_slock, flags);
1212c3dfe3fSSeokmann Ju 			return vha;
1222c3dfe3fSSeokmann Ju 		}
123feafb7b1SArun Easi 	}
124feafb7b1SArun Easi 	spin_unlock_irqrestore(&ha->vport_slock, flags);
1252c3dfe3fSSeokmann Ju 	return NULL;
1262c3dfe3fSSeokmann Ju }
1272c3dfe3fSSeokmann Ju 
1282c3dfe3fSSeokmann Ju /*
1292c3dfe3fSSeokmann Ju  * qla2x00_mark_vp_devices_dead
1302c3dfe3fSSeokmann Ju  *	Updates fcport state when device goes offline.
1312c3dfe3fSSeokmann Ju  *
1322c3dfe3fSSeokmann Ju  * Input:
1332c3dfe3fSSeokmann Ju  *	ha = adapter block pointer.
1342c3dfe3fSSeokmann Ju  *	fcport = port structure pointer.
1352c3dfe3fSSeokmann Ju  *
1362c3dfe3fSSeokmann Ju  * Return:
1372c3dfe3fSSeokmann Ju  *	None.
1382c3dfe3fSSeokmann Ju  *
1392c3dfe3fSSeokmann Ju  * Context:
1402c3dfe3fSSeokmann Ju  */
14126ff776dSAndrew Vasquez static void
qla2x00_mark_vp_devices_dead(scsi_qla_host_t * vha)1422c3dfe3fSSeokmann Ju qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
1432c3dfe3fSSeokmann Ju {
144feafb7b1SArun Easi 	/*
145feafb7b1SArun Easi 	 * !!! NOTE !!!
146feafb7b1SArun Easi 	 * This function, if called in contexts other than vp create, disable
147feafb7b1SArun Easi 	 * or delete, please make sure this is synchronized with the
148feafb7b1SArun Easi 	 * delete thread.
149feafb7b1SArun Easi 	 */
1502c3dfe3fSSeokmann Ju 	fc_port_t *fcport;
1512c3dfe3fSSeokmann Ju 
1527b867cf7SAnirban Chakraborty 	list_for_each_entry(fcport, &vha->vp_fcports, list) {
1537c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_vport, vha, 0xa001,
1547c3df132SSaurav Kashyap 		    "Marking port dead, loop_id=0x%04x : %x.\n",
155c6d39e23SJoe Carnuccio 		    fcport->loop_id, fcport->vha->vp_idx);
1562c3dfe3fSSeokmann Ju 
1573c75ad1dSHimanshu Madhani 		qla2x00_mark_device_lost(vha, fcport, 0);
158ec426e10SChad Dupuis 		qla2x00_set_fcport_state(fcport, FCS_UNCONFIGURED);
1592c3dfe3fSSeokmann Ju 	}
1602c3dfe3fSSeokmann Ju }
1612c3dfe3fSSeokmann Ju 
1622c3dfe3fSSeokmann Ju int
qla24xx_disable_vp(scsi_qla_host_t * vha)1632c3dfe3fSSeokmann Ju qla24xx_disable_vp(scsi_qla_host_t *vha)
1642c3dfe3fSSeokmann Ju {
16529c08cdaSNicholas Bellinger 	unsigned long flags;
16645235022SQuinn Tran 	int ret = QLA_SUCCESS;
167efa93f48SQuinn Tran 	fc_port_t *fcport;
1682c3dfe3fSSeokmann Ju 
169cf79716eSQuinn Tran 	if (vha->hw->flags.edif_enabled) {
170cf79716eSQuinn Tran 		if (DBELL_ACTIVE(vha))
171cf79716eSQuinn Tran 			qla2x00_post_aen_work(vha, FCH_EVT_VENDOR_UNIQUE,
172cf79716eSQuinn Tran 			    FCH_EVT_VENDOR_UNIQUE_VPORT_DOWN);
1739efea843SQuinn Tran 		/* delete sessions and flush sa_indexes */
1749efea843SQuinn Tran 		qla2x00_wait_for_sess_deletion(vha);
175cf79716eSQuinn Tran 	}
1769efea843SQuinn Tran 
17745235022SQuinn Tran 	if (vha->hw->flags.fw_started)
1782c3dfe3fSSeokmann Ju 		ret = qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL);
17945235022SQuinn Tran 
1802c3dfe3fSSeokmann Ju 	atomic_set(&vha->loop_state, LOOP_DOWN);
1812c3dfe3fSSeokmann Ju 	atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
182efa93f48SQuinn Tran 	list_for_each_entry(fcport, &vha->vp_fcports, list)
183*76f480d7SManish Rangankar 		fcport->logout_on_delete = 1;
184efa93f48SQuinn Tran 
1859efea843SQuinn Tran 	if (!vha->hw->flags.edif_enabled)
1869efea843SQuinn Tran 		qla2x00_wait_for_sess_deletion(vha);
1872c3dfe3fSSeokmann Ju 
1882d70c103SNicholas Bellinger 	/* Remove port id from vp target map */
1899d1aa4e1SQuinn Tran 	spin_lock_irqsave(&vha->hw->hardware_lock, flags);
190430eef03SQuinn Tran 	qla_update_vp_map(vha, RESET_AL_PA);
1919d1aa4e1SQuinn Tran 	spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
1922d70c103SNicholas Bellinger 
1932c3dfe3fSSeokmann Ju 	qla2x00_mark_vp_devices_dead(vha);
1942c3dfe3fSSeokmann Ju 	atomic_set(&vha->vp_state, VP_FAILED);
1952c3dfe3fSSeokmann Ju 	vha->flags.management_server_logged_in = 0;
1962c3dfe3fSSeokmann Ju 	if (ret == QLA_SUCCESS) {
1972c3dfe3fSSeokmann Ju 		fc_vport_set_state(vha->fc_vport, FC_VPORT_DISABLED);
1982c3dfe3fSSeokmann Ju 	} else {
1992c3dfe3fSSeokmann Ju 		fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
2002c3dfe3fSSeokmann Ju 		return -1;
2012c3dfe3fSSeokmann Ju 	}
2022c3dfe3fSSeokmann Ju 	return 0;
2032c3dfe3fSSeokmann Ju }
2042c3dfe3fSSeokmann Ju 
2052c3dfe3fSSeokmann Ju int
qla24xx_enable_vp(scsi_qla_host_t * vha)2062c3dfe3fSSeokmann Ju qla24xx_enable_vp(scsi_qla_host_t *vha)
2072c3dfe3fSSeokmann Ju {
2082c3dfe3fSSeokmann Ju 	int ret;
2097b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
2107b867cf7SAnirban Chakraborty 	scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
2112c3dfe3fSSeokmann Ju 
2122c3dfe3fSSeokmann Ju 	/* Check if physical ha port is Up */
2137b867cf7SAnirban Chakraborty 	if (atomic_read(&base_vha->loop_state) == LOOP_DOWN  ||
2143f3b6f98SLalit Chandivade 		atomic_read(&base_vha->loop_state) == LOOP_DEAD ||
2153f3b6f98SLalit Chandivade 		!(ha->current_topology & ISP_CFG_F)) {
2162c3dfe3fSSeokmann Ju 		vha->vp_err_state =  VP_ERR_PORTDWN;
2172c3dfe3fSSeokmann Ju 		fc_vport_set_state(vha->fc_vport, FC_VPORT_LINKDOWN);
2181608cc4aSQuinn Tran 		ql_dbg(ql_dbg_taskm, vha, 0x800b,
2191608cc4aSQuinn Tran 		    "%s skip enable. loop_state %x topo %x\n",
2201608cc4aSQuinn Tran 		    __func__, base_vha->loop_state.counter,
2211608cc4aSQuinn Tran 		    ha->current_topology);
2221608cc4aSQuinn Tran 
2232c3dfe3fSSeokmann Ju 		goto enable_failed;
2242c3dfe3fSSeokmann Ju 	}
2252c3dfe3fSSeokmann Ju 
2262c3dfe3fSSeokmann Ju 	/* Initialize the new vport unless it is a persistent port */
2276c2f527cSmatthias@kaehlcke.net 	mutex_lock(&ha->vport_lock);
2282c3dfe3fSSeokmann Ju 	ret = qla24xx_modify_vp_config(vha);
2296c2f527cSmatthias@kaehlcke.net 	mutex_unlock(&ha->vport_lock);
2302c3dfe3fSSeokmann Ju 
2312c3dfe3fSSeokmann Ju 	if (ret != QLA_SUCCESS) {
2322c3dfe3fSSeokmann Ju 		fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
2332c3dfe3fSSeokmann Ju 		goto enable_failed;
2342c3dfe3fSSeokmann Ju 	}
2352c3dfe3fSSeokmann Ju 
2367c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_taskm, vha, 0x801a,
2377c3df132SSaurav Kashyap 	    "Virtual port with id: %d - Enabled.\n", vha->vp_idx);
2382c3dfe3fSSeokmann Ju 	return 0;
2392c3dfe3fSSeokmann Ju 
2402c3dfe3fSSeokmann Ju enable_failed:
2417c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_taskm, vha, 0x801b,
2427c3df132SSaurav Kashyap 	    "Virtual port with id: %d - Disabled.\n", vha->vp_idx);
2432c3dfe3fSSeokmann Ju 	return 1;
2442c3dfe3fSSeokmann Ju }
2452c3dfe3fSSeokmann Ju 
24626ff776dSAndrew Vasquez static void
qla24xx_configure_vp(scsi_qla_host_t * vha)2472c3dfe3fSSeokmann Ju qla24xx_configure_vp(scsi_qla_host_t *vha)
2482c3dfe3fSSeokmann Ju {
2492c3dfe3fSSeokmann Ju 	struct fc_vport *fc_vport;
2502c3dfe3fSSeokmann Ju 	int ret;
2512c3dfe3fSSeokmann Ju 
2522c3dfe3fSSeokmann Ju 	fc_vport = vha->fc_vport;
2532c3dfe3fSSeokmann Ju 
2547c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_vport, vha, 0xa002,
2557c3df132SSaurav Kashyap 	    "%s: change request #3.\n", __func__);
2562c3dfe3fSSeokmann Ju 	ret = qla2x00_send_change_request(vha, 0x3, vha->vp_idx);
2572c3dfe3fSSeokmann Ju 	if (ret != QLA_SUCCESS) {
2587c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_vport, vha, 0xa003, "Failed to enable "
2597c3df132SSaurav Kashyap 		    "receiving of RSCN requests: 0x%x.\n", ret);
2602c3dfe3fSSeokmann Ju 		return;
2612c3dfe3fSSeokmann Ju 	} else {
2622c3dfe3fSSeokmann Ju 		/* Corresponds to SCR enabled */
2632c3dfe3fSSeokmann Ju 		clear_bit(VP_SCR_NEEDED, &vha->vp_flags);
2642c3dfe3fSSeokmann Ju 	}
2652c3dfe3fSSeokmann Ju 
2662c3dfe3fSSeokmann Ju 	vha->flags.online = 1;
2672c3dfe3fSSeokmann Ju 	if (qla24xx_configure_vhba(vha))
2682c3dfe3fSSeokmann Ju 		return;
2692c3dfe3fSSeokmann Ju 
2702c3dfe3fSSeokmann Ju 	atomic_set(&vha->vp_state, VP_ACTIVE);
2712c3dfe3fSSeokmann Ju 	fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
2722c3dfe3fSSeokmann Ju }
2732c3dfe3fSSeokmann Ju 
2742c3dfe3fSSeokmann Ju void
qla2x00_alert_all_vps(struct rsp_que * rsp,uint16_t * mb)27573208dfdSAnirban Chakraborty qla2x00_alert_all_vps(struct rsp_que *rsp, uint16_t *mb)
2762c3dfe3fSSeokmann Ju {
2770c9a5f3eSQuinn Tran 	scsi_qla_host_t *vha, *tvp;
27873208dfdSAnirban Chakraborty 	struct qla_hw_data *ha = rsp->hw;
2797b867cf7SAnirban Chakraborty 	int i = 0;
280feafb7b1SArun Easi 	unsigned long flags;
2812c3dfe3fSSeokmann Ju 
282feafb7b1SArun Easi 	spin_lock_irqsave(&ha->vport_slock, flags);
2830c9a5f3eSQuinn Tran 	list_for_each_entry_safe(vha, tvp, &ha->vp_list, list) {
2847b867cf7SAnirban Chakraborty 		if (vha->vp_idx) {
285f5187b7dSQuinn Tran 			if (test_bit(VPORT_DELETE, &vha->dpc_flags))
286f5187b7dSQuinn Tran 				continue;
287f5187b7dSQuinn Tran 
288feafb7b1SArun Easi 			atomic_inc(&vha->vref_count);
289feafb7b1SArun Easi 			spin_unlock_irqrestore(&ha->vport_slock, flags);
290feafb7b1SArun Easi 
2912c3dfe3fSSeokmann Ju 			switch (mb[0]) {
2922c3dfe3fSSeokmann Ju 			case MBA_LIP_OCCURRED:
2932c3dfe3fSSeokmann Ju 			case MBA_LOOP_UP:
2942c3dfe3fSSeokmann Ju 			case MBA_LOOP_DOWN:
2952c3dfe3fSSeokmann Ju 			case MBA_LIP_RESET:
2962c3dfe3fSSeokmann Ju 			case MBA_POINT_TO_POINT:
2972c3dfe3fSSeokmann Ju 			case MBA_CHG_IN_CONNECTION:
2987c3df132SSaurav Kashyap 				ql_dbg(ql_dbg_async, vha, 0x5024,
2997c3df132SSaurav Kashyap 				    "Async_event for VP[%d], mb=0x%x vha=%p.\n",
3007c3df132SSaurav Kashyap 				    i, *mb, vha);
30173208dfdSAnirban Chakraborty 				qla2x00_async_event(vha, rsp, mb);
3022c3dfe3fSSeokmann Ju 				break;
30375061750SQuinn Tran 			case MBA_PORT_UPDATE:
30475061750SQuinn Tran 			case MBA_RSCN_UPDATE:
30575061750SQuinn Tran 				if ((mb[3] & 0xff) == vha->vp_idx) {
30675061750SQuinn Tran 					ql_dbg(ql_dbg_async, vha, 0x5024,
30775061750SQuinn Tran 					    "Async_event for VP[%d], mb=0x%x vha=%p\n",
30875061750SQuinn Tran 					    i, *mb, vha);
30975061750SQuinn Tran 					qla2x00_async_event(vha, rsp, mb);
31075061750SQuinn Tran 				}
31175061750SQuinn Tran 				break;
3122c3dfe3fSSeokmann Ju 			}
313feafb7b1SArun Easi 
314feafb7b1SArun Easi 			spin_lock_irqsave(&ha->vport_slock, flags);
315feafb7b1SArun Easi 			atomic_dec(&vha->vref_count);
316c4a9b538SJoe Carnuccio 			wake_up(&vha->vref_waitq);
3172c3dfe3fSSeokmann Ju 		}
3187b867cf7SAnirban Chakraborty 		i++;
3192c3dfe3fSSeokmann Ju 	}
320feafb7b1SArun Easi 	spin_unlock_irqrestore(&ha->vport_slock, flags);
3212c3dfe3fSSeokmann Ju }
3222c3dfe3fSSeokmann Ju 
3237b867cf7SAnirban Chakraborty int
qla2x00_vp_abort_isp(scsi_qla_host_t * vha)3242c3dfe3fSSeokmann Ju qla2x00_vp_abort_isp(scsi_qla_host_t *vha)
3252c3dfe3fSSeokmann Ju {
326f5187b7dSQuinn Tran 	fc_port_t *fcport;
327f5187b7dSQuinn Tran 
328f5187b7dSQuinn Tran 	/*
329f5187b7dSQuinn Tran 	 * To exclusively reset vport, we need to log it out first.
330f5187b7dSQuinn Tran 	 * Note: This control_vp can fail if ISP reset is already
331f5187b7dSQuinn Tran 	 * issued, this is expected, as the vp would be already
332f5187b7dSQuinn Tran 	 * logged out due to ISP reset.
333f5187b7dSQuinn Tran 	 */
334f5187b7dSQuinn Tran 	if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) {
335f5187b7dSQuinn Tran 		qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL);
336f5187b7dSQuinn Tran 		list_for_each_entry(fcport, &vha->vp_fcports, list)
337f5187b7dSQuinn Tran 			fcport->logout_on_delete = 0;
338f5187b7dSQuinn Tran 	}
339f5187b7dSQuinn Tran 
3402c3dfe3fSSeokmann Ju 	/*
3412c3dfe3fSSeokmann Ju 	 * Physical port will do most of the abort and recovery work. We can
3422c3dfe3fSSeokmann Ju 	 * just treat it as a loop down
3432c3dfe3fSSeokmann Ju 	 */
3442c3dfe3fSSeokmann Ju 	if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
3452c3dfe3fSSeokmann Ju 		atomic_set(&vha->loop_state, LOOP_DOWN);
3463c75ad1dSHimanshu Madhani 		qla2x00_mark_all_devices_lost(vha);
3472c3dfe3fSSeokmann Ju 	} else {
3482c3dfe3fSSeokmann Ju 		if (!atomic_read(&vha->loop_down_timer))
3492c3dfe3fSSeokmann Ju 			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
3502c3dfe3fSSeokmann Ju 	}
3512c3dfe3fSSeokmann Ju 
3527c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_taskm, vha, 0x801d,
3537c3df132SSaurav Kashyap 	    "Scheduling enable of Vport %d.\n", vha->vp_idx);
354f5187b7dSQuinn Tran 
3557b867cf7SAnirban Chakraborty 	return qla24xx_enable_vp(vha);
3562c3dfe3fSSeokmann Ju }
3572c3dfe3fSSeokmann Ju 
358a824ebb3SAdrian Bunk static int
qla2x00_do_dpc_vp(scsi_qla_host_t * vha)3592c3dfe3fSSeokmann Ju qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
3602c3dfe3fSSeokmann Ju {
361ded6411fSSawan Chandak 	struct qla_hw_data *ha = vha->hw;
362ded6411fSSawan Chandak 	scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
363ded6411fSSawan Chandak 
3645f28d2d7SSaurav Kashyap 	ql_dbg(ql_dbg_dpc + ql_dbg_verbose, vha, 0x4012,
3655f28d2d7SSaurav Kashyap 	    "Entering %s vp_flags: 0x%lx.\n", __func__, vha->vp_flags);
3667c3df132SSaurav Kashyap 
367ded6411fSSawan Chandak 	/* Check if Fw is ready to configure VP first */
368ded6411fSSawan Chandak 	if (test_bit(VP_CONFIG_OK, &base_vha->vp_flags)) {
3692c3dfe3fSSeokmann Ju 		if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) {
3702c3dfe3fSSeokmann Ju 			/* VP acquired. complete port configuration */
3717c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_dpc, vha, 0x4014,
3727c3df132SSaurav Kashyap 			    "Configure VP scheduled.\n");
3732c3dfe3fSSeokmann Ju 			qla24xx_configure_vp(vha);
3747c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_dpc, vha, 0x4015,
3757c3df132SSaurav Kashyap 			    "Configure VP end.\n");
3762c3dfe3fSSeokmann Ju 			return 0;
3772c3dfe3fSSeokmann Ju 		}
378ded6411fSSawan Chandak 	}
3792c3dfe3fSSeokmann Ju 
380576bfde8SJoe Carnuccio 	if (test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags)) {
381576bfde8SJoe Carnuccio 		if (atomic_read(&vha->loop_state) == LOOP_READY) {
382576bfde8SJoe Carnuccio 			qla24xx_process_purex_list(&vha->purex_list);
383576bfde8SJoe Carnuccio 			clear_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags);
384576bfde8SJoe Carnuccio 		}
385576bfde8SJoe Carnuccio 	}
386576bfde8SJoe Carnuccio 
3874005a995SQuinn Tran 	if (test_bit(RELOGIN_NEEDED, &vha->dpc_flags) &&
3887b867cf7SAnirban Chakraborty 	    !test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) &&
3897b867cf7SAnirban Chakraborty 	    atomic_read(&vha->loop_state) != LOOP_DOWN) {
3907b867cf7SAnirban Chakraborty 
3914005a995SQuinn Tran 		if (!vha->relogin_jif ||
3924005a995SQuinn Tran 		    time_after_eq(jiffies, vha->relogin_jif)) {
3934005a995SQuinn Tran 			vha->relogin_jif = jiffies + HZ;
3944005a995SQuinn Tran 			clear_bit(RELOGIN_NEEDED, &vha->dpc_flags);
3954005a995SQuinn Tran 
3967c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_dpc, vha, 0x4018,
3977c3df132SSaurav Kashyap 			    "Relogin needed scheduled.\n");
3989b3e0f4dSQuinn Tran 			qla24xx_post_relogin_work(vha);
3997b867cf7SAnirban Chakraborty 		}
4004005a995SQuinn Tran 	}
4012c3dfe3fSSeokmann Ju 
4022c3dfe3fSSeokmann Ju 	if (test_and_clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) &&
4032c3dfe3fSSeokmann Ju 	    (!(test_and_set_bit(RESET_ACTIVE, &vha->dpc_flags)))) {
4042c3dfe3fSSeokmann Ju 		clear_bit(RESET_ACTIVE, &vha->dpc_flags);
4052c3dfe3fSSeokmann Ju 	}
4062c3dfe3fSSeokmann Ju 
40773208dfdSAnirban Chakraborty 	if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
4082c3dfe3fSSeokmann Ju 		if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) {
4097c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_dpc, vha, 0x401a,
4107c3df132SSaurav Kashyap 			    "Loop resync scheduled.\n");
4112c3dfe3fSSeokmann Ju 			qla2x00_loop_resync(vha);
4122c3dfe3fSSeokmann Ju 			clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags);
4137c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_dpc, vha, 0x401b,
4147c3df132SSaurav Kashyap 			    "Loop resync end.\n");
4152c3dfe3fSSeokmann Ju 		}
4162c3dfe3fSSeokmann Ju 	}
4172c3dfe3fSSeokmann Ju 
4185f28d2d7SSaurav Kashyap 	ql_dbg(ql_dbg_dpc + ql_dbg_verbose, vha, 0x401c,
4197c3df132SSaurav Kashyap 	    "Exiting %s.\n", __func__);
4202c3dfe3fSSeokmann Ju 	return 0;
4212c3dfe3fSSeokmann Ju }
4222c3dfe3fSSeokmann Ju 
4232c3dfe3fSSeokmann Ju void
qla2x00_do_dpc_all_vps(scsi_qla_host_t * vha)4247b867cf7SAnirban Chakraborty qla2x00_do_dpc_all_vps(scsi_qla_host_t *vha)
4252c3dfe3fSSeokmann Ju {
4267b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
4270c9a5f3eSQuinn Tran 	scsi_qla_host_t *vp, *tvp;
428feafb7b1SArun Easi 	unsigned long flags = 0;
4292c3dfe3fSSeokmann Ju 
4307b867cf7SAnirban Chakraborty 	if (vha->vp_idx)
4312c3dfe3fSSeokmann Ju 		return;
4322c3dfe3fSSeokmann Ju 	if (list_empty(&ha->vp_list))
4332c3dfe3fSSeokmann Ju 		return;
4342c3dfe3fSSeokmann Ju 
4357b867cf7SAnirban Chakraborty 	clear_bit(VP_DPC_NEEDED, &vha->dpc_flags);
4362c3dfe3fSSeokmann Ju 
4370d6e61bcSAndrew Vasquez 	if (!(ha->current_topology & ISP_CFG_F))
4380d6e61bcSAndrew Vasquez 		return;
4390d6e61bcSAndrew Vasquez 
440feafb7b1SArun Easi 	spin_lock_irqsave(&ha->vport_slock, flags);
4410c9a5f3eSQuinn Tran 	list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
442feafb7b1SArun Easi 		if (vp->vp_idx) {
443feafb7b1SArun Easi 			atomic_inc(&vp->vref_count);
444feafb7b1SArun Easi 			spin_unlock_irqrestore(&ha->vport_slock, flags);
445feafb7b1SArun Easi 
44652c82823SBart Van Assche 			qla2x00_do_dpc_vp(vp);
447feafb7b1SArun Easi 
448feafb7b1SArun Easi 			spin_lock_irqsave(&ha->vport_slock, flags);
449feafb7b1SArun Easi 			atomic_dec(&vp->vref_count);
4502c3dfe3fSSeokmann Ju 		}
4512c3dfe3fSSeokmann Ju 	}
452feafb7b1SArun Easi 	spin_unlock_irqrestore(&ha->vport_slock, flags);
453feafb7b1SArun Easi }
4542c3dfe3fSSeokmann Ju 
4552c3dfe3fSSeokmann Ju int
qla24xx_vport_create_req_sanity_check(struct fc_vport * fc_vport)4562c3dfe3fSSeokmann Ju qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
4572c3dfe3fSSeokmann Ju {
4587b867cf7SAnirban Chakraborty 	scsi_qla_host_t *base_vha = shost_priv(fc_vport->shost);
4597b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = base_vha->hw;
4602c3dfe3fSSeokmann Ju 	scsi_qla_host_t *vha;
4612c3dfe3fSSeokmann Ju 	uint8_t port_name[WWN_SIZE];
4622c3dfe3fSSeokmann Ju 
4632c3dfe3fSSeokmann Ju 	if (fc_vport->roles != FC_PORT_ROLE_FCP_INITIATOR)
4642c3dfe3fSSeokmann Ju 		return VPCERR_UNSUPPORTED;
4652c3dfe3fSSeokmann Ju 
4662c3dfe3fSSeokmann Ju 	/* Check up the F/W and H/W support NPIV */
4672c3dfe3fSSeokmann Ju 	if (!ha->flags.npiv_supported)
4682c3dfe3fSSeokmann Ju 		return VPCERR_UNSUPPORTED;
4692c3dfe3fSSeokmann Ju 
4702c3dfe3fSSeokmann Ju 	/* Check up whether npiv supported switch presented */
4712c3dfe3fSSeokmann Ju 	if (!(ha->switch_cap & FLOGI_MID_SUPPORT))
4722c3dfe3fSSeokmann Ju 		return VPCERR_NO_FABRIC_SUPP;
4732c3dfe3fSSeokmann Ju 
4742c3dfe3fSSeokmann Ju 	/* Check up unique WWPN */
4752c3dfe3fSSeokmann Ju 	u64_to_wwn(fc_vport->port_name, port_name);
4767b867cf7SAnirban Chakraborty 	if (!memcmp(port_name, base_vha->port_name, WWN_SIZE))
47750db6b13SSeokmann Ju 		return VPCERR_BAD_WWN;
4782c3dfe3fSSeokmann Ju 	vha = qla24xx_find_vhost_by_name(ha, port_name);
4792c3dfe3fSSeokmann Ju 	if (vha)
4802c3dfe3fSSeokmann Ju 		return VPCERR_BAD_WWN;
4812c3dfe3fSSeokmann Ju 
4822c3dfe3fSSeokmann Ju 	/* Check up max-npiv-supports */
4832c3dfe3fSSeokmann Ju 	if (ha->num_vhosts > ha->max_npiv_vports) {
4847c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_vport, vha, 0xa004,
4857c3df132SSaurav Kashyap 		    "num_vhosts %ud is bigger "
4867c3df132SSaurav Kashyap 		    "than max_npiv_vports %ud.\n",
4877c3df132SSaurav Kashyap 		    ha->num_vhosts, ha->max_npiv_vports);
4882c3dfe3fSSeokmann Ju 		return VPCERR_UNSUPPORTED;
4892c3dfe3fSSeokmann Ju 	}
4902c3dfe3fSSeokmann Ju 	return 0;
4912c3dfe3fSSeokmann Ju }
4922c3dfe3fSSeokmann Ju 
4932c3dfe3fSSeokmann Ju scsi_qla_host_t *
qla24xx_create_vhost(struct fc_vport * fc_vport)4942c3dfe3fSSeokmann Ju qla24xx_create_vhost(struct fc_vport *fc_vport)
4952c3dfe3fSSeokmann Ju {
4967b867cf7SAnirban Chakraborty 	scsi_qla_host_t *base_vha = shost_priv(fc_vport->shost);
4977b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = base_vha->hw;
4982c3dfe3fSSeokmann Ju 	scsi_qla_host_t *vha;
499421c20b7SBart Van Assche 	const struct scsi_host_template *sht = &qla2xxx_driver_template;
5002c3dfe3fSSeokmann Ju 	struct Scsi_Host *host;
5012c3dfe3fSSeokmann Ju 
5027b867cf7SAnirban Chakraborty 	vha = qla2x00_create_host(sht, ha);
5037b867cf7SAnirban Chakraborty 	if (!vha) {
5047c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0xa005,
5057c3df132SSaurav Kashyap 		    "scsi_host_alloc() failed for vport.\n");
5062c3dfe3fSSeokmann Ju 		return(NULL);
5072c3dfe3fSSeokmann Ju 	}
5082c3dfe3fSSeokmann Ju 
5097b867cf7SAnirban Chakraborty 	host = vha->host;
5102c3dfe3fSSeokmann Ju 	fc_vport->dd_data = vha;
5112c3dfe3fSSeokmann Ju 	/* New host info */
5122c3dfe3fSSeokmann Ju 	u64_to_wwn(fc_vport->node_name, vha->node_name);
5132c3dfe3fSSeokmann Ju 	u64_to_wwn(fc_vport->port_name, vha->port_name);
5142c3dfe3fSSeokmann Ju 
5152c3dfe3fSSeokmann Ju 	vha->fc_vport = fc_vport;
5162c3dfe3fSSeokmann Ju 	vha->device_flags = 0;
5172c3dfe3fSSeokmann Ju 	vha->vp_idx = qla24xx_allocate_vp_id(vha);
5182c3dfe3fSSeokmann Ju 	if (vha->vp_idx > ha->max_npiv_vports) {
5197c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_vport, vha, 0xa006,
5207c3df132SSaurav Kashyap 		    "Couldn't allocate vp_id.\n");
5217b867cf7SAnirban Chakraborty 		goto create_vhost_failed;
5222c3dfe3fSSeokmann Ju 	}
523f6602f3bSQuinn Tran 	vha->mgmt_svr_loop_id = qla2x00_reserve_mgmt_server_loop_id(vha);
5242c3dfe3fSSeokmann Ju 
5252c3dfe3fSSeokmann Ju 	vha->dpc_flags = 0L;
526818c7f87SJoe Carnuccio 	ha->dpc_active = 0;
527818c7f87SJoe Carnuccio 	set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
528818c7f87SJoe Carnuccio 	set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
5292c3dfe3fSSeokmann Ju 
5302c3dfe3fSSeokmann Ju 	/*
5312c3dfe3fSSeokmann Ju 	 * To fix the issue of processing a parent's RSCN for the vport before
5322c3dfe3fSSeokmann Ju 	 * its SCR is complete.
5332c3dfe3fSSeokmann Ju 	 */
5342c3dfe3fSSeokmann Ju 	set_bit(VP_SCR_NEEDED, &vha->vp_flags);
5352c3dfe3fSSeokmann Ju 	atomic_set(&vha->loop_state, LOOP_DOWN);
5362c3dfe3fSSeokmann Ju 	atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
5372c3dfe3fSSeokmann Ju 
5388e5f4ba0SKees Cook 	qla2x00_start_timer(vha, WATCH_INTERVAL);
5392c3dfe3fSSeokmann Ju 
5402afa19a9SAnirban Chakraborty 	vha->req = base_vha->req;
541850f6acdSAnil Gurumurthy 	vha->flags.nvme_enabled = base_vha->flags.nvme_enabled;
5422afa19a9SAnirban Chakraborty 	host->can_queue = base_vha->req->length + 128;
5432c3dfe3fSSeokmann Ju 	host->cmd_per_lun = 3;
544e02587d7SArun Easi 	if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif)
5450c470874SArun Easi 		host->max_cmd_len = 32;
5460c470874SArun Easi 	else
5472c3dfe3fSSeokmann Ju 		host->max_cmd_len = MAX_CMDSZ;
5482c3dfe3fSSeokmann Ju 	host->max_channel = MAX_BUSES - 1;
54982515920SAndrew Vasquez 	host->max_lun = ql2xmaxlun;
550711c1d91SSeokmann Ju 	host->unique_id = host->host_no;
551642ef983SChad Dupuis 	host->max_id = ha->max_fibre_devices;
5522c3dfe3fSSeokmann Ju 	host->transportt = qla2xxx_transport_vport_template;
5532c3dfe3fSSeokmann Ju 
5547c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_vport, vha, 0xa007,
5557c3df132SSaurav Kashyap 	    "Detect vport hba %ld at address = %p.\n",
5567c3df132SSaurav Kashyap 	    vha->host_no, vha);
5572c3dfe3fSSeokmann Ju 
5582c3dfe3fSSeokmann Ju 	vha->flags.init_done = 1;
5592c3dfe3fSSeokmann Ju 
5600d6e61bcSAndrew Vasquez 	mutex_lock(&ha->vport_lock);
5610d6e61bcSAndrew Vasquez 	set_bit(vha->vp_idx, ha->vp_idx_map);
5620d6e61bcSAndrew Vasquez 	ha->cur_vport_count++;
5630d6e61bcSAndrew Vasquez 	mutex_unlock(&ha->vport_lock);
5640d6e61bcSAndrew Vasquez 
5652c3dfe3fSSeokmann Ju 	return vha;
5662c3dfe3fSSeokmann Ju 
5677b867cf7SAnirban Chakraborty create_vhost_failed:
5682c3dfe3fSSeokmann Ju 	return NULL;
5692c3dfe3fSSeokmann Ju }
57073208dfdSAnirban Chakraborty 
57173208dfdSAnirban Chakraborty static void
qla25xx_free_req_que(struct scsi_qla_host * vha,struct req_que * req)57273208dfdSAnirban Chakraborty qla25xx_free_req_que(struct scsi_qla_host *vha, struct req_que *req)
57373208dfdSAnirban Chakraborty {
57473208dfdSAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
57573208dfdSAnirban Chakraborty 	uint16_t que_id = req->id;
57673208dfdSAnirban Chakraborty 
57773208dfdSAnirban Chakraborty 	dma_free_coherent(&ha->pdev->dev, (req->length + 1) *
57873208dfdSAnirban Chakraborty 		sizeof(request_t), req->ring, req->dma);
57973208dfdSAnirban Chakraborty 	req->ring = NULL;
58073208dfdSAnirban Chakraborty 	req->dma = 0;
58173208dfdSAnirban Chakraborty 	if (que_id) {
58273208dfdSAnirban Chakraborty 		ha->req_q_map[que_id] = NULL;
58373208dfdSAnirban Chakraborty 		mutex_lock(&ha->vport_lock);
58473208dfdSAnirban Chakraborty 		clear_bit(que_id, ha->req_qid_map);
58573208dfdSAnirban Chakraborty 		mutex_unlock(&ha->vport_lock);
58673208dfdSAnirban Chakraborty 	}
5878d93f550SChad Dupuis 	kfree(req->outstanding_cmds);
58873208dfdSAnirban Chakraborty 	kfree(req);
58973208dfdSAnirban Chakraborty }
59073208dfdSAnirban Chakraborty 
59173208dfdSAnirban Chakraborty static void
qla25xx_free_rsp_que(struct scsi_qla_host * vha,struct rsp_que * rsp)59273208dfdSAnirban Chakraborty qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
59373208dfdSAnirban Chakraborty {
59473208dfdSAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
59573208dfdSAnirban Chakraborty 	uint16_t que_id = rsp->id;
59673208dfdSAnirban Chakraborty 
59773208dfdSAnirban Chakraborty 	if (rsp->msix && rsp->msix->have_irq) {
598d7459527SMichael Hernandez 		free_irq(rsp->msix->vector, rsp->msix->handle);
59973208dfdSAnirban Chakraborty 		rsp->msix->have_irq = 0;
600d7459527SMichael Hernandez 		rsp->msix->in_use = 0;
6014fa18345SMichael Hernandez 		rsp->msix->handle = NULL;
60273208dfdSAnirban Chakraborty 	}
60373208dfdSAnirban Chakraborty 	dma_free_coherent(&ha->pdev->dev, (rsp->length + 1) *
60473208dfdSAnirban Chakraborty 		sizeof(response_t), rsp->ring, rsp->dma);
60573208dfdSAnirban Chakraborty 	rsp->ring = NULL;
60673208dfdSAnirban Chakraborty 	rsp->dma = 0;
60773208dfdSAnirban Chakraborty 	if (que_id) {
60873208dfdSAnirban Chakraborty 		ha->rsp_q_map[que_id] = NULL;
60973208dfdSAnirban Chakraborty 		mutex_lock(&ha->vport_lock);
61073208dfdSAnirban Chakraborty 		clear_bit(que_id, ha->rsp_qid_map);
61173208dfdSAnirban Chakraborty 		mutex_unlock(&ha->vport_lock);
61273208dfdSAnirban Chakraborty 	}
61373208dfdSAnirban Chakraborty 	kfree(rsp);
61473208dfdSAnirban Chakraborty }
61573208dfdSAnirban Chakraborty 
61673208dfdSAnirban Chakraborty int
qla25xx_delete_req_que(struct scsi_qla_host * vha,struct req_que * req)61773208dfdSAnirban Chakraborty qla25xx_delete_req_que(struct scsi_qla_host *vha, struct req_que *req)
61873208dfdSAnirban Chakraborty {
6197867b98dShimanshu.madhani@cavium.com 	int ret = QLA_SUCCESS;
62073208dfdSAnirban Chakraborty 
6217867b98dShimanshu.madhani@cavium.com 	if (req && vha->flags.qpairs_req_created) {
62273208dfdSAnirban Chakraborty 		req->options |= BIT_0;
623618a7523SAnirban Chakraborty 		ret = qla25xx_init_req_que(vha, req);
6247867b98dShimanshu.madhani@cavium.com 		if (ret != QLA_SUCCESS)
6257867b98dShimanshu.madhani@cavium.com 			return QLA_FUNCTION_FAILED;
62662aa2814SHimanshu Madhani 
62773208dfdSAnirban Chakraborty 		qla25xx_free_req_que(vha, req);
62862aa2814SHimanshu Madhani 	}
62973208dfdSAnirban Chakraborty 
63073208dfdSAnirban Chakraborty 	return ret;
63173208dfdSAnirban Chakraborty }
63273208dfdSAnirban Chakraborty 
633d7459527SMichael Hernandez int
qla25xx_delete_rsp_que(struct scsi_qla_host * vha,struct rsp_que * rsp)63473208dfdSAnirban Chakraborty qla25xx_delete_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
63573208dfdSAnirban Chakraborty {
6367867b98dShimanshu.madhani@cavium.com 	int ret = QLA_SUCCESS;
63773208dfdSAnirban Chakraborty 
6387867b98dShimanshu.madhani@cavium.com 	if (rsp && vha->flags.qpairs_rsp_created) {
63973208dfdSAnirban Chakraborty 		rsp->options |= BIT_0;
640618a7523SAnirban Chakraborty 		ret = qla25xx_init_rsp_que(vha, rsp);
6417867b98dShimanshu.madhani@cavium.com 		if (ret != QLA_SUCCESS)
6427867b98dShimanshu.madhani@cavium.com 			return QLA_FUNCTION_FAILED;
64362aa2814SHimanshu Madhani 
64473208dfdSAnirban Chakraborty 		qla25xx_free_rsp_que(vha, rsp);
64562aa2814SHimanshu Madhani 	}
64673208dfdSAnirban Chakraborty 
64773208dfdSAnirban Chakraborty 	return ret;
64873208dfdSAnirban Chakraborty }
64973208dfdSAnirban Chakraborty 
65073208dfdSAnirban Chakraborty /* Delete all queues for a given vhost */
65173208dfdSAnirban Chakraborty int
qla25xx_delete_queues(struct scsi_qla_host * vha)6522afa19a9SAnirban Chakraborty qla25xx_delete_queues(struct scsi_qla_host *vha)
65373208dfdSAnirban Chakraborty {
65473208dfdSAnirban Chakraborty 	int cnt, ret = 0;
65573208dfdSAnirban Chakraborty 	struct req_que *req = NULL;
65673208dfdSAnirban Chakraborty 	struct rsp_que *rsp = NULL;
65773208dfdSAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
658d7459527SMichael Hernandez 	struct qla_qpair *qpair, *tqpair;
65973208dfdSAnirban Chakraborty 
660c38d1bafSHimanshu Madhani 	if (ql2xmqsupport || ql2xnvmeenable) {
661d7459527SMichael Hernandez 		list_for_each_entry_safe(qpair, tqpair, &vha->qp_list,
662d7459527SMichael Hernandez 		    qp_list_elem)
663d7459527SMichael Hernandez 			qla2xxx_delete_qpair(vha, qpair);
664d7459527SMichael Hernandez 	} else {
6652afa19a9SAnirban Chakraborty 		/* Delete request queues */
6662afa19a9SAnirban Chakraborty 		for (cnt = 1; cnt < ha->max_req_queues; cnt++) {
6672afa19a9SAnirban Chakraborty 			req = ha->req_q_map[cnt];
668cb43285fSQuinn Tran 			if (req && test_bit(cnt, ha->req_qid_map)) {
66973208dfdSAnirban Chakraborty 				ret = qla25xx_delete_req_que(vha, req);
67073208dfdSAnirban Chakraborty 				if (ret != QLA_SUCCESS) {
6717c3df132SSaurav Kashyap 					ql_log(ql_log_warn, vha, 0x00ea,
6727c3df132SSaurav Kashyap 					    "Couldn't delete req que %d.\n",
6732afa19a9SAnirban Chakraborty 					    req->id);
67473208dfdSAnirban Chakraborty 					return ret;
67573208dfdSAnirban Chakraborty 				}
6762afa19a9SAnirban Chakraborty 			}
6772afa19a9SAnirban Chakraborty 		}
6782afa19a9SAnirban Chakraborty 
6792afa19a9SAnirban Chakraborty 		/* Delete response queues */
6802afa19a9SAnirban Chakraborty 		for (cnt = 1; cnt < ha->max_rsp_queues; cnt++) {
6812afa19a9SAnirban Chakraborty 			rsp = ha->rsp_q_map[cnt];
682cb43285fSQuinn Tran 			if (rsp && test_bit(cnt, ha->rsp_qid_map)) {
68373208dfdSAnirban Chakraborty 				ret = qla25xx_delete_rsp_que(vha, rsp);
68473208dfdSAnirban Chakraborty 				if (ret != QLA_SUCCESS) {
6857c3df132SSaurav Kashyap 					ql_log(ql_log_warn, vha, 0x00eb,
6867c3df132SSaurav Kashyap 					    "Couldn't delete rsp que %d.\n",
68773208dfdSAnirban Chakraborty 					    rsp->id);
68873208dfdSAnirban Chakraborty 					return ret;
68973208dfdSAnirban Chakraborty 				}
69073208dfdSAnirban Chakraborty 			}
69173208dfdSAnirban Chakraborty 		}
692d7459527SMichael Hernandez 	}
693d7459527SMichael Hernandez 
69473208dfdSAnirban Chakraborty 	return ret;
69573208dfdSAnirban Chakraborty }
69673208dfdSAnirban Chakraborty 
69773208dfdSAnirban Chakraborty int
qla25xx_create_req_que(struct qla_hw_data * ha,uint16_t options,uint8_t vp_idx,uint16_t rid,int rsp_que,uint8_t qos,bool startqp)69873208dfdSAnirban Chakraborty qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
69982de802aSQuinn Tran     uint8_t vp_idx, uint16_t rid, int rsp_que, uint8_t qos, bool startqp)
70073208dfdSAnirban Chakraborty {
70173208dfdSAnirban Chakraborty 	int ret = 0;
70273208dfdSAnirban Chakraborty 	struct req_que *req = NULL;
70373208dfdSAnirban Chakraborty 	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
704d65237c7SSawan Chandak 	struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
70573208dfdSAnirban Chakraborty 	uint16_t que_id = 0;
706f73cb695SChad Dupuis 	device_reg_t *reg;
7072afa19a9SAnirban Chakraborty 	uint32_t cnt;
70873208dfdSAnirban Chakraborty 
70973208dfdSAnirban Chakraborty 	req = kzalloc(sizeof(struct req_que), GFP_KERNEL);
71073208dfdSAnirban Chakraborty 	if (req == NULL) {
7117c3df132SSaurav Kashyap 		ql_log(ql_log_fatal, base_vha, 0x00d9,
7127c3df132SSaurav Kashyap 		    "Failed to allocate memory for request queue.\n");
713c7922a91SAnirban Chakraborty 		goto failed;
71473208dfdSAnirban Chakraborty 	}
71573208dfdSAnirban Chakraborty 
71673208dfdSAnirban Chakraborty 	req->length = REQUEST_ENTRY_CNT_24XX;
71773208dfdSAnirban Chakraborty 	req->ring = dma_alloc_coherent(&ha->pdev->dev,
71873208dfdSAnirban Chakraborty 			(req->length + 1) * sizeof(request_t),
71973208dfdSAnirban Chakraborty 			&req->dma, GFP_KERNEL);
72073208dfdSAnirban Chakraborty 	if (req->ring == NULL) {
7217c3df132SSaurav Kashyap 		ql_log(ql_log_fatal, base_vha, 0x00da,
722d6a03581SMasanari Iida 		    "Failed to allocate memory for request_ring.\n");
72373208dfdSAnirban Chakraborty 		goto que_failed;
72473208dfdSAnirban Chakraborty 	}
72573208dfdSAnirban Chakraborty 
7268d93f550SChad Dupuis 	ret = qla2x00_alloc_outstanding_cmds(ha, req);
7278d93f550SChad Dupuis 	if (ret != QLA_SUCCESS)
7288d93f550SChad Dupuis 		goto que_failed;
7298d93f550SChad Dupuis 
730d7459527SMichael Hernandez 	mutex_lock(&ha->mq_lock);
7312afa19a9SAnirban Chakraborty 	que_id = find_first_zero_bit(ha->req_qid_map, ha->max_req_queues);
7322afa19a9SAnirban Chakraborty 	if (que_id >= ha->max_req_queues) {
733d7459527SMichael Hernandez 		mutex_unlock(&ha->mq_lock);
7347c3df132SSaurav Kashyap 		ql_log(ql_log_warn, base_vha, 0x00db,
7357c3df132SSaurav Kashyap 		    "No resources to create additional request queue.\n");
73673208dfdSAnirban Chakraborty 		goto que_failed;
73773208dfdSAnirban Chakraborty 	}
73873208dfdSAnirban Chakraborty 	set_bit(que_id, ha->req_qid_map);
73973208dfdSAnirban Chakraborty 	ha->req_q_map[que_id] = req;
74073208dfdSAnirban Chakraborty 	req->rid = rid;
74173208dfdSAnirban Chakraborty 	req->vp_idx = vp_idx;
74273208dfdSAnirban Chakraborty 	req->qos = qos;
74373208dfdSAnirban Chakraborty 
7447c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_multiq, base_vha, 0xc002,
7457c3df132SSaurav Kashyap 	    "queue_id=%d rid=%d vp_idx=%d qos=%d.\n",
7467c3df132SSaurav Kashyap 	    que_id, req->rid, req->vp_idx, req->qos);
7477c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_init, base_vha, 0x00dc,
7487c3df132SSaurav Kashyap 	    "queue_id=%d rid=%d vp_idx=%d qos=%d.\n",
7497c3df132SSaurav Kashyap 	    que_id, req->rid, req->vp_idx, req->qos);
7502afa19a9SAnirban Chakraborty 	if (rsp_que < 0)
7512afa19a9SAnirban Chakraborty 		req->rsp = NULL;
7522afa19a9SAnirban Chakraborty 	else
75373208dfdSAnirban Chakraborty 		req->rsp = ha->rsp_q_map[rsp_que];
75473208dfdSAnirban Chakraborty 	/* Use alternate PCI bus number */
75573208dfdSAnirban Chakraborty 	if (MSB(req->rid))
75673208dfdSAnirban Chakraborty 		options |= BIT_4;
75773208dfdSAnirban Chakraborty 	/* Use alternate PCI devfn */
75873208dfdSAnirban Chakraborty 	if (LSB(req->rid))
75973208dfdSAnirban Chakraborty 		options |= BIT_5;
76073208dfdSAnirban Chakraborty 	req->options = options;
7612afa19a9SAnirban Chakraborty 
7627c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_multiq, base_vha, 0xc003,
7637c3df132SSaurav Kashyap 	    "options=0x%x.\n", req->options);
7647c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_init, base_vha, 0x00dd,
7657c3df132SSaurav Kashyap 	    "options=0x%x.\n", req->options);
7668d93f550SChad Dupuis 	for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++)
7672afa19a9SAnirban Chakraborty 		req->outstanding_cmds[cnt] = NULL;
7682afa19a9SAnirban Chakraborty 	req->current_outstanding_cmd = 1;
7692afa19a9SAnirban Chakraborty 
77073208dfdSAnirban Chakraborty 	req->ring_ptr = req->ring;
77173208dfdSAnirban Chakraborty 	req->ring_index = 0;
77273208dfdSAnirban Chakraborty 	req->cnt = req->length;
77373208dfdSAnirban Chakraborty 	req->id = que_id;
77408029990SAndrew Vasquez 	reg = ISP_QUE_REG(ha, que_id);
775da9b1d5cSAndrew Vasquez 	req->req_q_in = &reg->isp25mq.req_q_in;
776da9b1d5cSAndrew Vasquez 	req->req_q_out = &reg->isp25mq.req_q_out;
77729bdccbeSAnirban Chakraborty 	req->max_q_depth = ha->req_q_map[0]->max_q_depth;
778ab053c09SBart Van Assche 	req->out_ptr = (uint16_t *)(req->ring + req->length);
779d7459527SMichael Hernandez 	mutex_unlock(&ha->mq_lock);
7807c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_multiq, base_vha, 0xc004,
7817c3df132SSaurav Kashyap 	    "ring_ptr=%p ring_index=%d, "
7827c3df132SSaurav Kashyap 	    "cnt=%d id=%d max_q_depth=%d.\n",
7837c3df132SSaurav Kashyap 	    req->ring_ptr, req->ring_index,
7847c3df132SSaurav Kashyap 	    req->cnt, req->id, req->max_q_depth);
7857c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_init, base_vha, 0x00de,
7867c3df132SSaurav Kashyap 	    "ring_ptr=%p ring_index=%d, "
7877c3df132SSaurav Kashyap 	    "cnt=%d id=%d max_q_depth=%d.\n",
7887c3df132SSaurav Kashyap 	    req->ring_ptr, req->ring_index, req->cnt,
7897c3df132SSaurav Kashyap 	    req->id, req->max_q_depth);
79073208dfdSAnirban Chakraborty 
79182de802aSQuinn Tran 	if (startqp) {
792618a7523SAnirban Chakraborty 		ret = qla25xx_init_req_que(base_vha, req);
79373208dfdSAnirban Chakraborty 		if (ret != QLA_SUCCESS) {
7947c3df132SSaurav Kashyap 			ql_log(ql_log_fatal, base_vha, 0x00df,
7957c3df132SSaurav Kashyap 			    "%s failed.\n", __func__);
796d7459527SMichael Hernandez 			mutex_lock(&ha->mq_lock);
79773208dfdSAnirban Chakraborty 			clear_bit(que_id, ha->req_qid_map);
798d7459527SMichael Hernandez 			mutex_unlock(&ha->mq_lock);
79973208dfdSAnirban Chakraborty 			goto que_failed;
80073208dfdSAnirban Chakraborty 		}
801d65237c7SSawan Chandak 		vha->flags.qpairs_req_created = 1;
80282de802aSQuinn Tran 	}
80373208dfdSAnirban Chakraborty 
80473208dfdSAnirban Chakraborty 	return req->id;
80573208dfdSAnirban Chakraborty 
80673208dfdSAnirban Chakraborty que_failed:
80773208dfdSAnirban Chakraborty 	qla25xx_free_req_que(base_vha, req);
808c7922a91SAnirban Chakraborty failed:
80973208dfdSAnirban Chakraborty 	return 0;
81073208dfdSAnirban Chakraborty }
81173208dfdSAnirban Chakraborty 
qla_do_work(struct work_struct * work)81268ca949cSAnirban Chakraborty static void qla_do_work(struct work_struct *work)
81368ca949cSAnirban Chakraborty {
814a67093d4SAnirban Chakraborty 	unsigned long flags;
815d7459527SMichael Hernandez 	struct qla_qpair *qpair = container_of(work, struct qla_qpair, q_work);
81649db4d4eSQuinn Tran 	struct scsi_qla_host *vha = qpair->vha;
81768ca949cSAnirban Chakraborty 
818d7459527SMichael Hernandez 	spin_lock_irqsave(&qpair->qp_lock, flags);
819d7459527SMichael Hernandez 	qla24xx_process_response_queue(vha, qpair->rsp);
820d7459527SMichael Hernandez 	spin_unlock_irqrestore(&qpair->qp_lock, flags);
821cf19c45dSDuane Grigsby 
82268ca949cSAnirban Chakraborty }
82368ca949cSAnirban Chakraborty 
82473208dfdSAnirban Chakraborty /* create response queue */
82573208dfdSAnirban Chakraborty int
qla25xx_create_rsp_que(struct qla_hw_data * ha,uint16_t options,uint8_t vp_idx,uint16_t rid,struct qla_qpair * qpair,bool startqp)82673208dfdSAnirban Chakraborty qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
82782de802aSQuinn Tran     uint8_t vp_idx, uint16_t rid, struct qla_qpair *qpair, bool startqp)
82873208dfdSAnirban Chakraborty {
82973208dfdSAnirban Chakraborty 	int ret = 0;
83073208dfdSAnirban Chakraborty 	struct rsp_que *rsp = NULL;
83173208dfdSAnirban Chakraborty 	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
832d65237c7SSawan Chandak 	struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
83308029990SAndrew Vasquez 	uint16_t que_id = 0;
834f73cb695SChad Dupuis 	device_reg_t *reg;
83573208dfdSAnirban Chakraborty 
83673208dfdSAnirban Chakraborty 	rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL);
83773208dfdSAnirban Chakraborty 	if (rsp == NULL) {
8387c3df132SSaurav Kashyap 		ql_log(ql_log_warn, base_vha, 0x0066,
8397c3df132SSaurav Kashyap 		    "Failed to allocate memory for response queue.\n");
840c7922a91SAnirban Chakraborty 		goto failed;
84173208dfdSAnirban Chakraborty 	}
84273208dfdSAnirban Chakraborty 
8432afa19a9SAnirban Chakraborty 	rsp->length = RESPONSE_ENTRY_CNT_MQ;
84473208dfdSAnirban Chakraborty 	rsp->ring = dma_alloc_coherent(&ha->pdev->dev,
84573208dfdSAnirban Chakraborty 			(rsp->length + 1) * sizeof(response_t),
84673208dfdSAnirban Chakraborty 			&rsp->dma, GFP_KERNEL);
84773208dfdSAnirban Chakraborty 	if (rsp->ring == NULL) {
8487c3df132SSaurav Kashyap 		ql_log(ql_log_warn, base_vha, 0x00e1,
8497c3df132SSaurav Kashyap 		    "Failed to allocate memory for response ring.\n");
85073208dfdSAnirban Chakraborty 		goto que_failed;
85173208dfdSAnirban Chakraborty 	}
85273208dfdSAnirban Chakraborty 
853d7459527SMichael Hernandez 	mutex_lock(&ha->mq_lock);
8542afa19a9SAnirban Chakraborty 	que_id = find_first_zero_bit(ha->rsp_qid_map, ha->max_rsp_queues);
8552afa19a9SAnirban Chakraborty 	if (que_id >= ha->max_rsp_queues) {
856d7459527SMichael Hernandez 		mutex_unlock(&ha->mq_lock);
8577c3df132SSaurav Kashyap 		ql_log(ql_log_warn, base_vha, 0x00e2,
8587c3df132SSaurav Kashyap 		    "No resources to create additional request queue.\n");
85973208dfdSAnirban Chakraborty 		goto que_failed;
86073208dfdSAnirban Chakraborty 	}
86173208dfdSAnirban Chakraborty 	set_bit(que_id, ha->rsp_qid_map);
86273208dfdSAnirban Chakraborty 
863d7459527SMichael Hernandez 	rsp->msix = qpair->msix;
86473208dfdSAnirban Chakraborty 
86573208dfdSAnirban Chakraborty 	ha->rsp_q_map[que_id] = rsp;
86673208dfdSAnirban Chakraborty 	rsp->rid = rid;
86773208dfdSAnirban Chakraborty 	rsp->vp_idx = vp_idx;
86873208dfdSAnirban Chakraborty 	rsp->hw = ha;
8697c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_init, base_vha, 0x00e4,
870d7459527SMichael Hernandez 	    "rsp queue_id=%d rid=%d vp_idx=%d hw=%p.\n",
8717c3df132SSaurav Kashyap 	    que_id, rsp->rid, rsp->vp_idx, rsp->hw);
87273208dfdSAnirban Chakraborty 	/* Use alternate PCI bus number */
87373208dfdSAnirban Chakraborty 	if (MSB(rsp->rid))
87473208dfdSAnirban Chakraborty 		options |= BIT_4;
87573208dfdSAnirban Chakraborty 	/* Use alternate PCI devfn */
87673208dfdSAnirban Chakraborty 	if (LSB(rsp->rid))
87773208dfdSAnirban Chakraborty 		options |= BIT_5;
8783155754aSAnirban Chakraborty 	/* Enable MSIX handshake mode on for uncapable adapters */
8793155754aSAnirban Chakraborty 	if (!IS_MSIX_NACK_CAPABLE(ha))
8803155754aSAnirban Chakraborty 		options |= BIT_6;
8813155754aSAnirban Chakraborty 
882d7459527SMichael Hernandez 	/* Set option to indicate response queue creation */
883d7459527SMichael Hernandez 	options |= BIT_1;
884d7459527SMichael Hernandez 
88573208dfdSAnirban Chakraborty 	rsp->options = options;
88673208dfdSAnirban Chakraborty 	rsp->id = que_id;
88708029990SAndrew Vasquez 	reg = ISP_QUE_REG(ha, que_id);
88808029990SAndrew Vasquez 	rsp->rsp_q_in = &reg->isp25mq.rsp_q_in;
88908029990SAndrew Vasquez 	rsp->rsp_q_out = &reg->isp25mq.rsp_q_out;
890ab053c09SBart Van Assche 	rsp->in_ptr = (uint16_t *)(rsp->ring + rsp->length);
891d7459527SMichael Hernandez 	mutex_unlock(&ha->mq_lock);
8927c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_multiq, base_vha, 0xc00b,
893d7459527SMichael Hernandez 	    "options=%x id=%d rsp_q_in=%p rsp_q_out=%p\n",
8947c3df132SSaurav Kashyap 	    rsp->options, rsp->id, rsp->rsp_q_in,
8957c3df132SSaurav Kashyap 	    rsp->rsp_q_out);
8967c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_init, base_vha, 0x00e5,
897d7459527SMichael Hernandez 	    "options=%x id=%d rsp_q_in=%p rsp_q_out=%p\n",
8987c3df132SSaurav Kashyap 	    rsp->options, rsp->id, rsp->rsp_q_in,
8997c3df132SSaurav Kashyap 	    rsp->rsp_q_out);
90073208dfdSAnirban Chakraborty 
901d7459527SMichael Hernandez 	ret = qla25xx_request_irq(ha, qpair, qpair->msix,
9027b2a7396SAndrew Vasquez 		ha->flags.disable_msix_handshake ?
9037b2a7396SAndrew Vasquez 		QLA_MSIX_QPAIR_MULTIQ_RSP_Q : QLA_MSIX_QPAIR_MULTIQ_RSP_Q_HS);
90473208dfdSAnirban Chakraborty 	if (ret)
90573208dfdSAnirban Chakraborty 		goto que_failed;
90673208dfdSAnirban Chakraborty 
90782de802aSQuinn Tran 	if (startqp) {
908618a7523SAnirban Chakraborty 		ret = qla25xx_init_rsp_que(base_vha, rsp);
90973208dfdSAnirban Chakraborty 		if (ret != QLA_SUCCESS) {
9107c3df132SSaurav Kashyap 			ql_log(ql_log_fatal, base_vha, 0x00e7,
9117c3df132SSaurav Kashyap 			    "%s failed.\n", __func__);
912d7459527SMichael Hernandez 			mutex_lock(&ha->mq_lock);
91373208dfdSAnirban Chakraborty 			clear_bit(que_id, ha->rsp_qid_map);
914d7459527SMichael Hernandez 			mutex_unlock(&ha->mq_lock);
91573208dfdSAnirban Chakraborty 			goto que_failed;
91673208dfdSAnirban Chakraborty 		}
917d65237c7SSawan Chandak 		vha->flags.qpairs_rsp_created = 1;
91882de802aSQuinn Tran 	}
9192afa19a9SAnirban Chakraborty 	rsp->req = NULL;
92073208dfdSAnirban Chakraborty 
92173208dfdSAnirban Chakraborty 	qla2x00_init_response_q_entries(rsp);
922d7459527SMichael Hernandez 	if (qpair->hw->wq)
923d7459527SMichael Hernandez 		INIT_WORK(&qpair->q_work, qla_do_work);
92473208dfdSAnirban Chakraborty 	return rsp->id;
92573208dfdSAnirban Chakraborty 
92673208dfdSAnirban Chakraborty que_failed:
92773208dfdSAnirban Chakraborty 	qla25xx_free_rsp_que(base_vha, rsp);
928c7922a91SAnirban Chakraborty failed:
92973208dfdSAnirban Chakraborty 	return 0;
93073208dfdSAnirban Chakraborty }
9312853192eSQuinn Tran 
qla_ctrlvp_sp_done(srb_t * sp,int res)9326c18a43eSBart Van Assche static void qla_ctrlvp_sp_done(srb_t *sp, int res)
9332853192eSQuinn Tran {
934982cc4beSBart Van Assche 	if (sp->comp)
935982cc4beSBart Van Assche 		complete(sp->comp);
9362853192eSQuinn Tran 	/* don't free sp here. Let the caller do the free */
9372853192eSQuinn Tran }
9382853192eSQuinn Tran 
9392853192eSQuinn Tran /**
9402853192eSQuinn Tran  * qla24xx_control_vp() - Enable a virtual port for given host
9412853192eSQuinn Tran  * @vha:	adapter block pointer
9422853192eSQuinn Tran  * @cmd:	command type to be sent for enable virtual port
9432853192eSQuinn Tran  *
9442853192eSQuinn Tran  * Return:	qla2xxx local function return status code.
9452853192eSQuinn Tran  */
qla24xx_control_vp(scsi_qla_host_t * vha,int cmd)9462853192eSQuinn Tran int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
9472853192eSQuinn Tran {
9482853192eSQuinn Tran 	int rval = QLA_MEMORY_ALLOC_FAILED;
9492853192eSQuinn Tran 	struct qla_hw_data *ha = vha->hw;
9502853192eSQuinn Tran 	int	vp_index = vha->vp_idx;
9512853192eSQuinn Tran 	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
952982cc4beSBart Van Assche 	DECLARE_COMPLETION_ONSTACK(comp);
9532853192eSQuinn Tran 	srb_t *sp;
9542853192eSQuinn Tran 
9552853192eSQuinn Tran 	ql_dbg(ql_dbg_vport, vha, 0x10c1,
9562853192eSQuinn Tran 	    "Entered %s cmd %x index %d.\n", __func__, cmd, vp_index);
9572853192eSQuinn Tran 
9582853192eSQuinn Tran 	if (vp_index == 0 || vp_index >= ha->max_npiv_vports)
9592853192eSQuinn Tran 		return QLA_PARAMETER_ERROR;
9602853192eSQuinn Tran 
96131e6cdbeSSaurav Kashyap 	/* ref: INIT */
9622853192eSQuinn Tran 	sp = qla2x00_get_sp(base_vha, NULL, GFP_KERNEL);
9632853192eSQuinn Tran 	if (!sp)
964af2a0c51SQuinn Tran 		return rval;
9652853192eSQuinn Tran 
9662853192eSQuinn Tran 	sp->type = SRB_CTRL_VP;
9672853192eSQuinn Tran 	sp->name = "ctrl_vp";
968982cc4beSBart Van Assche 	sp->comp = &comp;
969d4523bd6SDaniel Wagner 	qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2,
970d4523bd6SDaniel Wagner 			      qla_ctrlvp_sp_done);
9712853192eSQuinn Tran 	sp->u.iocb_cmd.u.ctrlvp.cmd = cmd;
9722853192eSQuinn Tran 	sp->u.iocb_cmd.u.ctrlvp.vp_index = vp_index;
9732853192eSQuinn Tran 
9742853192eSQuinn Tran 	rval = qla2x00_start_sp(sp);
9752853192eSQuinn Tran 	if (rval != QLA_SUCCESS) {
9762853192eSQuinn Tran 		ql_dbg(ql_dbg_async, vha, 0xffff,
9772853192eSQuinn Tran 		    "%s: %s Failed submission. %x.\n",
9782853192eSQuinn Tran 		    __func__, sp->name, rval);
979af2a0c51SQuinn Tran 		goto done;
9802853192eSQuinn Tran 	}
9812853192eSQuinn Tran 
9822853192eSQuinn Tran 	ql_dbg(ql_dbg_vport, vha, 0x113f, "%s hndl %x submitted\n",
9832853192eSQuinn Tran 	    sp->name, sp->handle);
9842853192eSQuinn Tran 
985982cc4beSBart Van Assche 	wait_for_completion(&comp);
986982cc4beSBart Van Assche 	sp->comp = NULL;
987982cc4beSBart Van Assche 
9882853192eSQuinn Tran 	rval = sp->rc;
9892853192eSQuinn Tran 	switch (rval) {
9902853192eSQuinn Tran 	case QLA_FUNCTION_TIMEOUT:
9912853192eSQuinn Tran 		ql_dbg(ql_dbg_vport, vha, 0xffff, "%s: %s Timeout. %x.\n",
9922853192eSQuinn Tran 		    __func__, sp->name, rval);
9932853192eSQuinn Tran 		break;
9942853192eSQuinn Tran 	case QLA_SUCCESS:
9952853192eSQuinn Tran 		ql_dbg(ql_dbg_vport, vha, 0xffff, "%s: %s done.\n",
9962853192eSQuinn Tran 		    __func__, sp->name);
997af2a0c51SQuinn Tran 		break;
9982853192eSQuinn Tran 	default:
9992853192eSQuinn Tran 		ql_dbg(ql_dbg_vport, vha, 0xffff, "%s: %s Failed. %x.\n",
10002853192eSQuinn Tran 		    __func__, sp->name, rval);
1001af2a0c51SQuinn Tran 		break;
10022853192eSQuinn Tran 	}
10032853192eSQuinn Tran done:
100431e6cdbeSSaurav Kashyap 	/* ref: INIT */
100531e6cdbeSSaurav Kashyap 	kref_put(&sp->cmd_kref, qla2x00_sp_release);
10062853192eSQuinn Tran 	return rval;
10072853192eSQuinn Tran }
1008430eef03SQuinn Tran 
qla_find_host_by_vp_idx(struct scsi_qla_host * vha,uint16_t vp_idx)1009430eef03SQuinn Tran struct scsi_qla_host *qla_find_host_by_vp_idx(struct scsi_qla_host *vha, uint16_t vp_idx)
1010430eef03SQuinn Tran {
1011430eef03SQuinn Tran 	struct qla_hw_data *ha = vha->hw;
1012430eef03SQuinn Tran 
1013430eef03SQuinn Tran 	if (vha->vp_idx == vp_idx)
1014430eef03SQuinn Tran 		return vha;
1015430eef03SQuinn Tran 
1016430eef03SQuinn Tran 	BUG_ON(ha->vp_map == NULL);
1017430eef03SQuinn Tran 	if (likely(test_bit(vp_idx, ha->vp_idx_map)))
1018430eef03SQuinn Tran 		return ha->vp_map[vp_idx].vha;
1019430eef03SQuinn Tran 
1020430eef03SQuinn Tran 	return NULL;
1021430eef03SQuinn Tran }
1022430eef03SQuinn Tran 
1023430eef03SQuinn Tran /* vport_slock to be held by the caller */
1024430eef03SQuinn Tran void
qla_update_vp_map(struct scsi_qla_host * vha,int cmd)1025430eef03SQuinn Tran qla_update_vp_map(struct scsi_qla_host *vha, int cmd)
1026430eef03SQuinn Tran {
1027430eef03SQuinn Tran 	void *slot;
1028430eef03SQuinn Tran 	u32 key;
1029430eef03SQuinn Tran 	int rc;
1030430eef03SQuinn Tran 
1031430eef03SQuinn Tran 	if (!vha->hw->vp_map)
1032430eef03SQuinn Tran 		return;
1033430eef03SQuinn Tran 
1034430eef03SQuinn Tran 	key = vha->d_id.b24;
1035430eef03SQuinn Tran 
1036430eef03SQuinn Tran 	switch (cmd) {
1037430eef03SQuinn Tran 	case SET_VP_IDX:
1038430eef03SQuinn Tran 		vha->hw->vp_map[vha->vp_idx].vha = vha;
1039430eef03SQuinn Tran 		break;
1040430eef03SQuinn Tran 	case SET_AL_PA:
1041430eef03SQuinn Tran 		slot = btree_lookup32(&vha->hw->host_map, key);
1042430eef03SQuinn Tran 		if (!slot) {
1043430eef03SQuinn Tran 			ql_dbg(ql_dbg_disc, vha, 0xf018,
1044430eef03SQuinn Tran 			    "Save vha in host_map %p %06x\n", vha, key);
1045430eef03SQuinn Tran 			rc = btree_insert32(&vha->hw->host_map,
1046430eef03SQuinn Tran 			    key, vha, GFP_ATOMIC);
1047430eef03SQuinn Tran 			if (rc)
1048430eef03SQuinn Tran 				ql_log(ql_log_info, vha, 0xd03e,
1049430eef03SQuinn Tran 				    "Unable to insert s_id into host_map: %06x\n",
1050430eef03SQuinn Tran 				    key);
1051430eef03SQuinn Tran 			return;
1052430eef03SQuinn Tran 		}
1053430eef03SQuinn Tran 		ql_dbg(ql_dbg_disc, vha, 0xf019,
1054430eef03SQuinn Tran 		    "replace existing vha in host_map %p %06x\n", vha, key);
1055430eef03SQuinn Tran 		btree_update32(&vha->hw->host_map, key, vha);
1056430eef03SQuinn Tran 		break;
1057430eef03SQuinn Tran 	case RESET_VP_IDX:
1058430eef03SQuinn Tran 		vha->hw->vp_map[vha->vp_idx].vha = NULL;
1059430eef03SQuinn Tran 		break;
1060430eef03SQuinn Tran 	case RESET_AL_PA:
1061430eef03SQuinn Tran 		ql_dbg(ql_dbg_disc, vha, 0xf01a,
1062430eef03SQuinn Tran 		    "clear vha in host_map %p %06x\n", vha, key);
1063430eef03SQuinn Tran 		slot = btree_lookup32(&vha->hw->host_map, key);
1064430eef03SQuinn Tran 		if (slot)
1065430eef03SQuinn Tran 			btree_remove32(&vha->hw->host_map, key);
1066430eef03SQuinn Tran 		vha->d_id.b24 = 0;
1067430eef03SQuinn Tran 		break;
1068430eef03SQuinn Tran 	}
1069430eef03SQuinn Tran }
1070430eef03SQuinn Tran 
qla_update_host_map(struct scsi_qla_host * vha,port_id_t id)1071430eef03SQuinn Tran void qla_update_host_map(struct scsi_qla_host *vha, port_id_t id)
1072430eef03SQuinn Tran {
1073430eef03SQuinn Tran 
1074430eef03SQuinn Tran 	if (!vha->d_id.b24) {
1075430eef03SQuinn Tran 		vha->d_id = id;
1076430eef03SQuinn Tran 		qla_update_vp_map(vha, SET_AL_PA);
1077430eef03SQuinn Tran 	} else if (vha->d_id.b24 != id.b24) {
1078430eef03SQuinn Tran 		qla_update_vp_map(vha, RESET_AL_PA);
1079430eef03SQuinn Tran 		vha->d_id = id;
1080430eef03SQuinn Tran 		qla_update_vp_map(vha, SET_AL_PA);
1081430eef03SQuinn Tran 	}
1082430eef03SQuinn Tran }
108382d8dfd2SQuinn Tran 
qla_create_buf_pool(struct scsi_qla_host * vha,struct qla_qpair * qp)108482d8dfd2SQuinn Tran int qla_create_buf_pool(struct scsi_qla_host *vha, struct qla_qpair *qp)
108582d8dfd2SQuinn Tran {
108682d8dfd2SQuinn Tran 	int sz;
108782d8dfd2SQuinn Tran 
108882d8dfd2SQuinn Tran 	qp->buf_pool.num_bufs = qp->req->length;
108982d8dfd2SQuinn Tran 
109082d8dfd2SQuinn Tran 	sz = BITS_TO_LONGS(qp->req->length);
109182d8dfd2SQuinn Tran 	qp->buf_pool.buf_map   = kcalloc(sz, sizeof(long), GFP_KERNEL);
109282d8dfd2SQuinn Tran 	if (!qp->buf_pool.buf_map) {
109382d8dfd2SQuinn Tran 		ql_log(ql_log_warn, vha, 0x0186,
1094d794a231SArnd Bergmann 		    "Failed to allocate buf_map(%zd).\n", sz * sizeof(unsigned long));
109582d8dfd2SQuinn Tran 		return -ENOMEM;
109682d8dfd2SQuinn Tran 	}
109782d8dfd2SQuinn Tran 	sz = qp->req->length * sizeof(void *);
109882d8dfd2SQuinn Tran 	qp->buf_pool.buf_array = kcalloc(qp->req->length, sizeof(void *), GFP_KERNEL);
109982d8dfd2SQuinn Tran 	if (!qp->buf_pool.buf_array) {
110082d8dfd2SQuinn Tran 		ql_log(ql_log_warn, vha, 0x0186,
110182d8dfd2SQuinn Tran 		    "Failed to allocate buf_array(%d).\n", sz);
110282d8dfd2SQuinn Tran 		kfree(qp->buf_pool.buf_map);
110382d8dfd2SQuinn Tran 		return -ENOMEM;
110482d8dfd2SQuinn Tran 	}
110582d8dfd2SQuinn Tran 	sz = qp->req->length * sizeof(dma_addr_t);
110682d8dfd2SQuinn Tran 	qp->buf_pool.dma_array = kcalloc(qp->req->length, sizeof(dma_addr_t), GFP_KERNEL);
110782d8dfd2SQuinn Tran 	if (!qp->buf_pool.dma_array) {
110882d8dfd2SQuinn Tran 		ql_log(ql_log_warn, vha, 0x0186,
110982d8dfd2SQuinn Tran 		    "Failed to allocate dma_array(%d).\n", sz);
111082d8dfd2SQuinn Tran 		kfree(qp->buf_pool.buf_map);
111182d8dfd2SQuinn Tran 		kfree(qp->buf_pool.buf_array);
111282d8dfd2SQuinn Tran 		return -ENOMEM;
111382d8dfd2SQuinn Tran 	}
111482d8dfd2SQuinn Tran 	set_bit(0, qp->buf_pool.buf_map);
111582d8dfd2SQuinn Tran 	return 0;
111682d8dfd2SQuinn Tran }
111782d8dfd2SQuinn Tran 
qla_free_buf_pool(struct qla_qpair * qp)111882d8dfd2SQuinn Tran void qla_free_buf_pool(struct qla_qpair *qp)
111982d8dfd2SQuinn Tran {
112082d8dfd2SQuinn Tran 	int i;
112182d8dfd2SQuinn Tran 	struct qla_hw_data *ha = qp->vha->hw;
112282d8dfd2SQuinn Tran 
112382d8dfd2SQuinn Tran 	for (i = 0; i < qp->buf_pool.num_bufs; i++) {
112482d8dfd2SQuinn Tran 		if (qp->buf_pool.buf_array[i] && qp->buf_pool.dma_array[i])
112582d8dfd2SQuinn Tran 			dma_pool_free(ha->fcp_cmnd_dma_pool, qp->buf_pool.buf_array[i],
112682d8dfd2SQuinn Tran 			    qp->buf_pool.dma_array[i]);
112782d8dfd2SQuinn Tran 		qp->buf_pool.buf_array[i] = NULL;
112882d8dfd2SQuinn Tran 		qp->buf_pool.dma_array[i] = 0;
112982d8dfd2SQuinn Tran 	}
113082d8dfd2SQuinn Tran 
113182d8dfd2SQuinn Tran 	kfree(qp->buf_pool.dma_array);
113282d8dfd2SQuinn Tran 	kfree(qp->buf_pool.buf_array);
113382d8dfd2SQuinn Tran 	kfree(qp->buf_pool.buf_map);
113482d8dfd2SQuinn Tran }
113582d8dfd2SQuinn Tran 
113682d8dfd2SQuinn Tran /* it is assume qp->qp_lock is held at this point */
qla_get_buf(struct scsi_qla_host * vha,struct qla_qpair * qp,struct qla_buf_dsc * dsc)113782d8dfd2SQuinn Tran int qla_get_buf(struct scsi_qla_host *vha, struct qla_qpair *qp, struct qla_buf_dsc *dsc)
113882d8dfd2SQuinn Tran {
113982d8dfd2SQuinn Tran 	u16 tag, i = 0;
114082d8dfd2SQuinn Tran 	void *buf;
114182d8dfd2SQuinn Tran 	dma_addr_t buf_dma;
114282d8dfd2SQuinn Tran 	struct qla_hw_data *ha = vha->hw;
114382d8dfd2SQuinn Tran 
114482d8dfd2SQuinn Tran 	dsc->tag = TAG_FREED;
114582d8dfd2SQuinn Tran again:
114682d8dfd2SQuinn Tran 	tag = find_first_zero_bit(qp->buf_pool.buf_map, qp->buf_pool.num_bufs);
114782d8dfd2SQuinn Tran 	if (tag >= qp->buf_pool.num_bufs) {
114882d8dfd2SQuinn Tran 		ql_dbg(ql_dbg_io, vha, 0x00e2,
114982d8dfd2SQuinn Tran 		    "qp(%d) ran out of buf resource.\n", qp->id);
115082d8dfd2SQuinn Tran 		return  -EIO;
115182d8dfd2SQuinn Tran 	}
115282d8dfd2SQuinn Tran 	if (tag == 0) {
115382d8dfd2SQuinn Tran 		set_bit(0, qp->buf_pool.buf_map);
115482d8dfd2SQuinn Tran 		i++;
115582d8dfd2SQuinn Tran 		if (i == 5) {
115682d8dfd2SQuinn Tran 			ql_dbg(ql_dbg_io, vha, 0x00e3,
115782d8dfd2SQuinn Tran 			    "qp(%d) unable to get tag.\n", qp->id);
115882d8dfd2SQuinn Tran 			return -EIO;
115982d8dfd2SQuinn Tran 		}
116082d8dfd2SQuinn Tran 		goto again;
116182d8dfd2SQuinn Tran 	}
116282d8dfd2SQuinn Tran 
116382d8dfd2SQuinn Tran 	if (!qp->buf_pool.buf_array[tag]) {
116482d8dfd2SQuinn Tran 		buf = dma_pool_zalloc(ha->fcp_cmnd_dma_pool, GFP_ATOMIC, &buf_dma);
116582d8dfd2SQuinn Tran 		if (!buf) {
116682d8dfd2SQuinn Tran 			ql_log(ql_log_fatal, vha, 0x13b1,
116782d8dfd2SQuinn Tran 			    "Failed to allocate buf.\n");
116882d8dfd2SQuinn Tran 			return -ENOMEM;
116982d8dfd2SQuinn Tran 		}
117082d8dfd2SQuinn Tran 
117182d8dfd2SQuinn Tran 		dsc->buf = qp->buf_pool.buf_array[tag] = buf;
117282d8dfd2SQuinn Tran 		dsc->buf_dma = qp->buf_pool.dma_array[tag] = buf_dma;
11731f8f9c34SQuinn Tran 		qp->buf_pool.num_alloc++;
117482d8dfd2SQuinn Tran 	} else {
117582d8dfd2SQuinn Tran 		dsc->buf = qp->buf_pool.buf_array[tag];
117682d8dfd2SQuinn Tran 		dsc->buf_dma = qp->buf_pool.dma_array[tag];
117782d8dfd2SQuinn Tran 		memset(dsc->buf, 0, FCP_CMND_DMA_POOL_SIZE);
117882d8dfd2SQuinn Tran 	}
117982d8dfd2SQuinn Tran 
118082d8dfd2SQuinn Tran 	qp->buf_pool.num_active++;
118182d8dfd2SQuinn Tran 	if (qp->buf_pool.num_active > qp->buf_pool.max_used)
118282d8dfd2SQuinn Tran 		qp->buf_pool.max_used = qp->buf_pool.num_active;
118382d8dfd2SQuinn Tran 
118482d8dfd2SQuinn Tran 	dsc->tag = tag;
118582d8dfd2SQuinn Tran 	set_bit(tag, qp->buf_pool.buf_map);
118682d8dfd2SQuinn Tran 	return 0;
118782d8dfd2SQuinn Tran }
118882d8dfd2SQuinn Tran 
qla_trim_buf(struct qla_qpair * qp,u16 trim)118954c51253STom Rix static void qla_trim_buf(struct qla_qpair *qp, u16 trim)
11901f8f9c34SQuinn Tran {
11911f8f9c34SQuinn Tran 	int i, j;
11921f8f9c34SQuinn Tran 	struct qla_hw_data *ha = qp->vha->hw;
11931f8f9c34SQuinn Tran 
11941f8f9c34SQuinn Tran 	if (!trim)
11951f8f9c34SQuinn Tran 		return;
11961f8f9c34SQuinn Tran 
11971f8f9c34SQuinn Tran 	for (i = 0; i < trim; i++) {
11981f8f9c34SQuinn Tran 		j = qp->buf_pool.num_alloc - 1;
11991f8f9c34SQuinn Tran 		if (test_bit(j, qp->buf_pool.buf_map)) {
12001f8f9c34SQuinn Tran 			ql_dbg(ql_dbg_io + ql_dbg_verbose, qp->vha, 0x300b,
12011f8f9c34SQuinn Tran 			       "QP id(%d): trim active buf[%d]. Remain %d bufs\n",
12021f8f9c34SQuinn Tran 			       qp->id, j, qp->buf_pool.num_alloc);
12031f8f9c34SQuinn Tran 			return;
12041f8f9c34SQuinn Tran 		}
12051f8f9c34SQuinn Tran 
12061f8f9c34SQuinn Tran 		if (qp->buf_pool.buf_array[j]) {
12071f8f9c34SQuinn Tran 			dma_pool_free(ha->fcp_cmnd_dma_pool, qp->buf_pool.buf_array[j],
12081f8f9c34SQuinn Tran 				      qp->buf_pool.dma_array[j]);
12091f8f9c34SQuinn Tran 			qp->buf_pool.buf_array[j] = NULL;
12101f8f9c34SQuinn Tran 			qp->buf_pool.dma_array[j] = 0;
12111f8f9c34SQuinn Tran 		}
12121f8f9c34SQuinn Tran 		qp->buf_pool.num_alloc--;
12131f8f9c34SQuinn Tran 		if (!qp->buf_pool.num_alloc)
12141f8f9c34SQuinn Tran 			break;
12151f8f9c34SQuinn Tran 	}
12161f8f9c34SQuinn Tran 	ql_dbg(ql_dbg_io + ql_dbg_verbose, qp->vha, 0x3010,
12171f8f9c34SQuinn Tran 	       "QP id(%d): trimmed %d bufs. Remain %d bufs\n",
12181f8f9c34SQuinn Tran 	       qp->id, trim, qp->buf_pool.num_alloc);
12191f8f9c34SQuinn Tran }
12201f8f9c34SQuinn Tran 
__qla_adjust_buf(struct qla_qpair * qp)122154c51253STom Rix static void __qla_adjust_buf(struct qla_qpair *qp)
12221f8f9c34SQuinn Tran {
12231f8f9c34SQuinn Tran 	u32 trim;
12241f8f9c34SQuinn Tran 
12251f8f9c34SQuinn Tran 	qp->buf_pool.take_snapshot = 0;
12261f8f9c34SQuinn Tran 	qp->buf_pool.prev_max = qp->buf_pool.max_used;
12271f8f9c34SQuinn Tran 	qp->buf_pool.max_used = qp->buf_pool.num_active;
12281f8f9c34SQuinn Tran 
12291f8f9c34SQuinn Tran 	if (qp->buf_pool.prev_max > qp->buf_pool.max_used &&
12301f8f9c34SQuinn Tran 	    qp->buf_pool.num_alloc > qp->buf_pool.max_used) {
12311f8f9c34SQuinn Tran 		/* down trend */
12321f8f9c34SQuinn Tran 		trim = qp->buf_pool.num_alloc - qp->buf_pool.max_used;
12331f8f9c34SQuinn Tran 		trim  = (trim * 10) / 100;
12341f8f9c34SQuinn Tran 		trim = trim ? trim : 1;
12351f8f9c34SQuinn Tran 		qla_trim_buf(qp, trim);
12361f8f9c34SQuinn Tran 	} else if (!qp->buf_pool.prev_max  && !qp->buf_pool.max_used) {
12371f8f9c34SQuinn Tran 		/* 2 periods of no io */
12381f8f9c34SQuinn Tran 		qla_trim_buf(qp, qp->buf_pool.num_alloc);
12391f8f9c34SQuinn Tran 	}
12401f8f9c34SQuinn Tran }
124182d8dfd2SQuinn Tran 
124282d8dfd2SQuinn Tran /* it is assume qp->qp_lock is held at this point */
qla_put_buf(struct qla_qpair * qp,struct qla_buf_dsc * dsc)124382d8dfd2SQuinn Tran void qla_put_buf(struct qla_qpair *qp, struct qla_buf_dsc *dsc)
124482d8dfd2SQuinn Tran {
124582d8dfd2SQuinn Tran 	if (dsc->tag == TAG_FREED)
124682d8dfd2SQuinn Tran 		return;
12471f8f9c34SQuinn Tran 	lockdep_assert_held(qp->qp_lock_ptr);
124882d8dfd2SQuinn Tran 
124982d8dfd2SQuinn Tran 	clear_bit(dsc->tag, qp->buf_pool.buf_map);
125082d8dfd2SQuinn Tran 	qp->buf_pool.num_active--;
125182d8dfd2SQuinn Tran 	dsc->tag = TAG_FREED;
12521f8f9c34SQuinn Tran 
12531f8f9c34SQuinn Tran 	if (qp->buf_pool.take_snapshot)
12541f8f9c34SQuinn Tran 		__qla_adjust_buf(qp);
12551f8f9c34SQuinn Tran }
12561f8f9c34SQuinn Tran 
12571f8f9c34SQuinn Tran #define EXPIRE (60 * HZ)
qla_adjust_buf(struct scsi_qla_host * vha)12581f8f9c34SQuinn Tran void qla_adjust_buf(struct scsi_qla_host *vha)
12591f8f9c34SQuinn Tran {
12601f8f9c34SQuinn Tran 	unsigned long flags;
12611f8f9c34SQuinn Tran 	int i;
12621f8f9c34SQuinn Tran 	struct qla_qpair *qp;
12631f8f9c34SQuinn Tran 
12641f8f9c34SQuinn Tran 	if (vha->vp_idx)
12651f8f9c34SQuinn Tran 		return;
12661f8f9c34SQuinn Tran 
12671f8f9c34SQuinn Tran 	if (!vha->buf_expired) {
12681f8f9c34SQuinn Tran 		vha->buf_expired = jiffies + EXPIRE;
12691f8f9c34SQuinn Tran 		return;
12701f8f9c34SQuinn Tran 	}
12711f8f9c34SQuinn Tran 	if (time_before(jiffies, vha->buf_expired))
12721f8f9c34SQuinn Tran 		return;
12731f8f9c34SQuinn Tran 
12741f8f9c34SQuinn Tran 	vha->buf_expired = jiffies + EXPIRE;
12751f8f9c34SQuinn Tran 
12761f8f9c34SQuinn Tran 	for (i = 0; i < vha->hw->num_qpairs; i++) {
12771f8f9c34SQuinn Tran 		qp = vha->hw->queue_pair_map[i];
12781f8f9c34SQuinn Tran 		if (!qp)
12791f8f9c34SQuinn Tran 			continue;
12801f8f9c34SQuinn Tran 		if (!qp->buf_pool.num_alloc)
12811f8f9c34SQuinn Tran 			continue;
12821f8f9c34SQuinn Tran 
12831f8f9c34SQuinn Tran 		if (qp->buf_pool.take_snapshot) {
12841f8f9c34SQuinn Tran 			/* no io has gone through in the last EXPIRE period */
12851f8f9c34SQuinn Tran 			spin_lock_irqsave(qp->qp_lock_ptr, flags);
12861f8f9c34SQuinn Tran 			__qla_adjust_buf(qp);
12871f8f9c34SQuinn Tran 			spin_unlock_irqrestore(qp->qp_lock_ptr, flags);
12881f8f9c34SQuinn Tran 		} else {
12891f8f9c34SQuinn Tran 			qp->buf_pool.take_snapshot = 1;
12901f8f9c34SQuinn Tran 		}
12911f8f9c34SQuinn Tran 	}
129282d8dfd2SQuinn Tran }
1293